/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Common Public License (CPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/cpl1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm.compilers.common.assembler.ppc;

import org.jikesrvm.ArchitectureSpecific;
import org.jikesrvm.VM;
import org.jikesrvm.Services;
import org.jikesrvm.compilers.baseline.BaselineCompiler;
import org.jikesrvm.compilers.baseline.ppc.BaselineCompilerImpl;
import org.jikesrvm.compilers.common.assembler.AbstractAssembler;
import org.jikesrvm.compilers.common.assembler.ForwardReference;
import org.jikesrvm.ppc.BaselineConstants;
import org.jikesrvm.ppc.Disassembler;
import org.jikesrvm.ppc.MachineCode;
import org.jikesrvm.ppc.RegisterConstants;
import org.jikesrvm.ppc.StackframeLayoutConstants;
import org.jikesrvm.runtime.Entrypoints;
import org.vmmagic.pragma.NoInline;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;

/**
 * Machine code generators:
 *
 * Corresponding to a PowerPC assembler instruction of the form
 *    xx A,B,C
 * there will be a method
 *    void emitXX (int A, int B, int C).
 *
 * The emitXX method appends this instruction to an MachineCode object.
 * The name of a method for generating assembler instruction with the record
 * bit set (say xx.) will be end in a lower-case r (emitXXr).
 *
 * mIP will be incremented to point to the next machine instruction.
 *
 * Machine code generators:
 */
public abstract class Assembler extends AbstractAssembler implements BaselineConstants, AssemblerConstants {

  /** Machine code being assembled */
  private final MachineCode mc;
  /** Debug output? */
  private final boolean shouldPrint;
  /**  // Baseline compiler instance for this assembler.  May be null. */
  final BaselineCompilerImpl compiler;
  /** current machine code instruction */
  private int mIP;

  public Assembler(int length) {
    this(length, false, null);
  }

  public Assembler(int length, boolean sp, BaselineCompilerImpl comp) {
    mc = new ArchitectureSpecific.MachineCode();
    shouldPrint = sp;
    compiler = comp;
    mIP = 0;
  }

  public Assembler(int length, boolean sp) {
    this(length, sp, null);
  }

  private static int maskLower16(Offset val) {
    return (val.toInt() & 0xFFFF);
  }

  public static int maskUpper16(Offset val) {
    return maskUpper16(val.toInt());
  }

  public static int maskUpper16(int val) {
    short s = (short) (val & 0xFFFF);
    return ((val - (int) s) >>> 16);
  }

  public static boolean fits(Offset val, int bits) {
    Word o = val.toWord().rsha(bits - 1);
    return (o.isZero() || o.isMax());
  }

  public static boolean fits(long val, int bits) {
    val = val >> bits - 1;
    return (val == 0L || val == -1L);
  }

  public static boolean fits(int val, int bits) {
    val = val >> bits - 1;
    return (val == 0 || val == -1);
  }

  @NoInline
  public void noteBytecode(int i, String bcode) {
    String s1 = Services.getHexString(mIP << LG_INSTRUCTION_WIDTH, true);
    VM.sysWrite(s1 + ": [" + i + "] " + bcode + "\n");
  }

  @NoInline
  public void noteBytecode(int i, String bcode, int x) {
    noteBytecode(i, bcode + " " + x);
  }

  @NoInline
  public void noteBytecode(int i, String bcode, long x) {
    noteBytecode(i, bcode + " " + x);
  }

  @NoInline
  public void noteBytecode(int i, String bcode, Object o) {
    noteBytecode(i, bcode + " " + o);
  }

  @NoInline
  public void noteBytecode(int i, String bcode, int x, int y) {
    noteBytecode(i, bcode + " " + x + " " + y);
  }

  @NoInline
  public void noteBranchBytecode(int i, String bcode, int off, int bt) {
    noteBytecode(i, bcode + " " + off + " [" + bt + "] ");
  }

  @NoInline
  public void noteTableswitchBytecode(int i, int l, int h, int d) {
    noteBytecode(i, "tableswitch [" + l + "--" + h + "] " + d);
  }

  @NoInline
  public void noteLookupswitchBytecode(int i, int n, int d) {
    noteBytecode(i, "lookupswitch [<" + n + ">]" + d);
  }

  /* Handling backward branch references */

  public int getMachineCodeIndex() {
    return mIP;
  }

  /* Handling forward branch references */

  ForwardReference forwardRefs = null;

  /* call before emiting code for the branch */
  final void reserveForwardBranch(int where) {
    ForwardReference fr = new ForwardReference.UnconditionalBranch(mIP, where);
    forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
  }

  /* call before emiting code for the branch */
  final void reserveForwardConditionalBranch(int where) {
    emitNOP();
    ForwardReference fr = new ForwardReference.ConditionalBranch(mIP, where);
    forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
  }

  /* call before emiting code for the branch */
  final void reserveShortForwardConditionalBranch(int where) {
    ForwardReference fr = new ForwardReference.ConditionalBranch(mIP, where);
    forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
  }

  /* call before emiting data for the case branch */
  final void reserveForwardCase(int where) {
    ForwardReference fr = new ForwardReference.SwitchCase(mIP, where);
    forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
  }

  /* call before emiting code for the target */
  public final void resolveForwardReferences(int label) {
    if (forwardRefs == null) return;
    forwardRefs = ForwardReference.resolveMatching(this, forwardRefs, label);
  }

  public final void patchUnconditionalBranch(int sourceMachinecodeIndex) {
    int delta = mIP - sourceMachinecodeIndex;
    int instr = mc.getInstruction(sourceMachinecodeIndex);
    if (VM.VerifyAssertions) VM._assert((delta >>> 23) == 0); // delta (positive) fits in 24 bits
    instr |= (delta << 2);
    mc.putInstruction(sourceMachinecodeIndex, instr);
  }

  public final void patchConditionalBranch(int sourceMachinecodeIndex) {
    int delta = mIP - sourceMachinecodeIndex;
    int instr = mc.getInstruction(sourceMachinecodeIndex);
    if ((delta >>> 13) == 0) { // delta (positive) fits in 14 bits
      instr |= (delta << 2);
      mc.putInstruction(sourceMachinecodeIndex, instr);
    } else {
      if (VM.VerifyAssertions) VM._assert((delta >>> 23) == 0); // delta (positive) fits in 24 bits
      instr ^= 0x01000008; // make skip instruction with opposite sense
      mc.putInstruction(sourceMachinecodeIndex - 1, instr); // skip unconditional branch to target
      mc.putInstruction(sourceMachinecodeIndex, Btemplate | (delta & 0xFFFFFF) << 2);
    }
  }

  public final void patchShortBranch(int sourceMachinecodeIndex) {
    int delta = mIP - sourceMachinecodeIndex;
    int instr = mc.getInstruction(sourceMachinecodeIndex);
    if ((delta >>> 13) == 0) { // delta (positive) fits in 14 bits
      instr |= (delta << 2);
      mc.putInstruction(sourceMachinecodeIndex, instr);
    } else {
      throw new InternalError("Long offset doesn't fit in short branch\n");
    }
  }

  public final void registerLoadReturnAddress(int bReturn) {
    ForwardReference r = new ForwardReference.LoadReturnAddress(mIP, bReturn);
    forwardRefs = ForwardReference.enqueue(forwardRefs, r);
  }

  /* the prologue is always before any real bytecode index.
  *
  * CAUTION: the machine code to be patched has following pattern:
  *          BL 4
  *          MFLR T1                   <- address in LR
  *          ADDI  T1, offset, T1       <- toBePatchedMCAddr
  *          STU
  *
  * The third instruction should be patched with accurate relative address.
  * It is computed by (mIP - sourceIndex + 1)*4;
  */
  public final void patchLoadReturnAddress(int sourceIndex) {
    int offset = (mIP - sourceIndex + 1) * 4;
    int mi = ADDI(T1, offset, T1);
    mc.putInstruction(sourceIndex, mi);
  }

  final int ADDI(int RT, int D, int RA) {
    return ADDItemplate | RT << 21 | RA << 16 | (D & 0xFFFF);
  }

  public final ForwardReference generatePendingJMP(int bTarget) {
    return this.emitForwardB();
  }

  /************ OSR Support */

  public final void patchSwitchCase(int sourceMachinecodeIndex) {
    int delta = (mIP - sourceMachinecodeIndex) << 2;
    // correction is number of bytes of source off switch base
    int correction = (int) mc.getInstruction(sourceMachinecodeIndex);
    int offset = delta + correction;
    mc.putInstruction(sourceMachinecodeIndex, offset);
  }

  /* machine instructions */

  static final int ADDtemplate = 31 << 26 | 10 << 1;

  public final void emitADD(int RT, int RA, int RB) {
    int mi = ADDtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ADDEtemplate = 31 << 26 | 138 << 1;

  public final void emitADDE(int RT, int RA, int RB) {
    int mi = ADDEtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ADDICrtemplate = 13 << 26;

  public final void emitADDICr(int RT, int RA, int SI) {
    if (VM.VerifyAssertions) VM._assert(fits(SI, 16));
    int mi = ADDICrtemplate | RT << 21 | RA << 16 | (SI & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ANDtemplate = 31 << 26 | 28 << 1;

  public final void emitAND(int RA, int RS, int RB) {
    int mi = ANDtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ANDItemplate = 28 << 26;

  public final void emitANDI(int RA, int RS, int U) {
    if (VM.VerifyAssertions) VM._assert((U >>> 16) == 0);
    int mi = ANDItemplate | RS << 21 | RA << 16 | U;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ANDIStemplate = 29 << 26;

  public final void emitANDIS(int RA, int RS, int U) {
    if (VM.VerifyAssertions) VM._assert((U & 0xffff) == 0);
    int mi = ANDIStemplate | RS << 21 | RA << 16 | (U >>> 16);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int Btemplate = 18 << 26;

  private void _emitB(int relative_address) {
    if (VM.VerifyAssertions) VM._assert(fits(relative_address, 24));
    int mi = Btemplate | (relative_address & 0xFFFFFF) << 2;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitB(int relative_address, int label) {
    if (relative_address == 0) {
      reserveForwardBranch(label);
    } else {
      relative_address -= mIP;
    }
    _emitB(relative_address);
  }

  public final void emitB(int relative_address) {
    relative_address -= mIP;
    if (VM.VerifyAssertions) VM._assert(relative_address < 0);
    _emitB(relative_address);
  }

  public final ForwardReference emitForwardB() {
    ForwardReference fr;
    if (compiler != null) {
      fr = new AssemblerShortBranch(mIP, compiler.spTopOffset);
    } else {
      fr = new ForwardReference.ShortBranch(mIP);
    }
    _emitB(0);
    return fr;
  }

  static final int BLAtemplate = 18 << 26 | 3;

  public final void emitBLA(int address) {
    if (VM.VerifyAssertions) VM._assert(fits(address, 24));
    int mi = BLAtemplate | (address & 0xFFFFFF) << 2;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int BLtemplate = 18 << 26 | 1;

  private void _emitBL(int relative_address) {
    if (VM.VerifyAssertions) VM._assert(fits(relative_address, 24));
    int mi = BLtemplate | (relative_address & 0xFFFFFF) << 2;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitBL(int relative_address, int label) {
    if (relative_address == 0) {
      reserveForwardBranch(label);
    } else {
      relative_address -= mIP;
    }
    _emitBL(relative_address);
  }

  public final ForwardReference emitForwardBL() {
    ForwardReference fr;
    if (compiler != null) {
      fr = new AssemblerShortBranch(mIP, compiler.spTopOffset);
    } else {
      fr = new ForwardReference.ShortBranch(mIP);
    }
    _emitBL(0);
    return fr;
  }

  static final int BCtemplate = 16 << 26;

  public static int flipCode(int cc) {
    switch (cc) {
      case LT:
        return GE;
      case GT:
        return LE;
      case EQ:
        return NE;
      case LE:
        return GT;
      case GE:
        return LT;
      case NE:
        return EQ;
    }
    if (VM.VerifyAssertions) VM._assert(false);
    return -1;
  }

  private void _emitBC(int cc, int relative_address) {
    if (fits(relative_address, 14)) {
      int mi = BCtemplate | cc | (relative_address & 0x3FFF) << 2;
      mIP++;
      mc.addInstruction(mi);
    } else {
      _emitBC(flipCode(cc), 2);
      _emitB(relative_address - 1);
    }
  }

  public final void emitBC(int cc, int relative_address, int label) {
    if (relative_address == 0) {
      reserveForwardConditionalBranch(label);
    } else {
      relative_address -= mIP;
    }
    _emitBC(cc, relative_address);
  }

  public final void emitShortBC(int cc, int relative_address, int label) {
    if (relative_address == 0) {
      reserveShortForwardConditionalBranch(label);
    } else {
      relative_address -= mIP;
    }
    _emitBC(cc, relative_address);
  }

  public final void emitBC(int cc, int relative_address) {
    relative_address -= mIP;
    if (VM.VerifyAssertions) VM._assert(relative_address < 0);
    _emitBC(cc, relative_address);
  }

  public final ForwardReference emitForwardBC(int cc) {
    ForwardReference fr;
    if (compiler != null) {
      fr = new AssemblerShortBranch(mIP, compiler.spTopOffset);
    } else {
      fr = new ForwardReference.ShortBranch(mIP);
    }
    _emitBC(cc, 0);
    return fr;
  }

  // delta i: difference between address of case i and of delta 0
  public final void emitSwitchCase(int i, int relative_address, int bTarget) {
    int data = i << 2;
    if (relative_address == 0) {
      reserveForwardCase(bTarget);
    } else {
      data += ((relative_address - mIP) << 2);
    }
    mIP++;
    mc.addInstruction(data);
  }

  static final int BCLRtemplate = 19 << 26 | 0x14 << 21 | 16 << 1;

  public final void emitBCLR() {
    int mi = BCLRtemplate;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int BCLRLtemplate = 19 << 26 | 0x14 << 21 | 16 << 1 | 1;

  public final void emitBCLRL() {
    int mi = BCLRLtemplate;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int BCCTRtemplate = 19 << 26 | 0x14 << 21 | 528 << 1;

  public final void emitBCCTR() {

    int mi = BCCTRtemplate;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int BCCTRLtemplate = 19 << 26 | 0x14 << 21 | 528 << 1 | 1;

  public final void emitBCCTRL() {
    int mi = BCCTRLtemplate;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ADDItemplate = 14 << 26;

  public final void emitADDI(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    _emitADDI(RT, D & 0xFFFF, RA);
  }

  private void _emitADDI(int RT, int D, int RA) {
    //D has already been masked
    int mi = ADDItemplate | RT << 21 | RA << 16 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitADDI(int RT, Offset off, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(off, 16));
    _emitADDI(RT, maskLower16(off), RA);
  }

  static final int ADDIStemplate = 15 << 26;

  public final void emitADDIS(int RT, int RA, int UI) {
    if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
    _emitADDIS(RT, RA, UI);
  }

  private void _emitADDIS(int RT, int RA, int UI) {
    //UI has already been masked
    int mi = ADDIStemplate | RT << 21 | RA << 16 | UI;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitADDIS(int RT, int UI) {
    if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
    _emitADDIS(RT, UI);
  }

  private void _emitADDIS(int RT, int UI) {
    //UI has already been masked
    int mi = ADDIStemplate | RT << 21 | UI;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CMPtemplate = 31 << 26;

  public final void emitCMP(int BF, int RA, int RB) {
    int mi = CMPtemplate | BF << 23 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitCMP(int RA, int RB) {
    int mi = CMPtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CMPDtemplate = CMPtemplate | 1 << 21;

  public final void emitCMPD(int RA, int RB) {
    int mi = CMPDtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CMPItemplate = 11 << 26;

  public final void emitCMPI(int BF, int RA, int V) {
    if (VM.VerifyAssertions) VM._assert(fits(V, 16));
    int mi = CMPItemplate | BF << 23 | RA << 16 | (V & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitCMPI(int RA, int V) {
    if (VM.VerifyAssertions) VM._assert(fits(V, 16));
    int mi = CMPItemplate | RA << 16 | (V & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CMPDItemplate = CMPItemplate | 1 << 21;

  public final void emitCMPDI(int RA, int V) {
    if (VM.VerifyAssertions) VM._assert(fits(V, 16));
    int mi = CMPDItemplate | RA << 16 | (V & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CMPLtemplate = 31 << 26 | 32 << 1;

  public final void emitCMPL(int BF, int RA, int RB) {
    int mi = CMPLtemplate | BF << 23 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitCMPL(int RA, int RB) {
    int mi = CMPLtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CMPLDtemplate = CMPLtemplate | 1 << 21;

  public final void emitCMPLD(int RA, int RB) {
    int mi = CMPLDtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CRANDtemplate = 19 << 26 | 257 << 1;

  public final void emitCRAND(int BT, int BA, int BB) {
    int mi = CRANDtemplate | BT << 21 | BA << 16 | BB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CRANDCtemplate = 19 << 26 | 129 << 1;

  public final void emitCRANDC(int BT, int BA, int BB) {
    int mi = CRANDCtemplate | BT << 21 | BA << 16 | BB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CRORtemplate = 19 << 26 | 449 << 1;

  public final void emitCROR(int BT, int BA, int BB) {
    int mi = CRORtemplate | BT << 21 | BA << 16 | BB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int CRORCtemplate = 19 << 26 | 417 << 1;

  public final void emitCRORC(int BT, int BA, int BB) {
    int mi = CRORCtemplate | BT << 21 | BA << 16 | BB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FADDtemplate = 63 << 26 | 21 << 1;

  public final void emitFADD(int FRT, int FRA, int FRB) {
    int mi = FADDtemplate | FRT << 21 | FRA << 16 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FADDStemplate = 59 << 26 | 21 << 1; // single-percision add

  public final void emitFADDS(int FRT, int FRA, int FRB) {
    int mi = FADDStemplate | FRT << 21 | FRA << 16 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FABStemplate = 63 << 26 | 264 << 1;

  public final void emitFABS(int FRT, int FRB) {
    int mi = FABStemplate | FRT << 21 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FCMPUtemplate = 63 << 26;

  public final void emitFCMPU(int FRA, int FRB) {
    int mi = FCMPUtemplate | FRA << 16 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FDIVtemplate = 63 << 26 | 18 << 1;

  public final void emitFDIV(int FRT, int FRA, int FRB) {
    int mi = FDIVtemplate | FRT << 21 | FRA << 16 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FDIVStemplate = 59 << 26 | 18 << 1; // single-precision divide

  public final void emitFDIVS(int FRT, int FRA, int FRB) {
    int mi = FDIVStemplate | FRT << 21 | FRA << 16 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FMULtemplate = 63 << 26 | 25 << 1;

  public final void emitFMUL(int FRT, int FRA, int FRB) {
    int mi = FMULtemplate | FRT << 21 | FRA << 16 | FRB << 6;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FMULStemplate = 59 << 26 | 25 << 1; // single-precision fm

  public final void emitFMULS(int FRT, int FRA, int FRB) {
    int mi = FMULStemplate | FRT << 21 | FRA << 16 | FRB << 6;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FMADDtemplate = 63 << 26 | 29 << 1;

  public final void emitFMADD(int FRT, int FRA, int FRC, int FRB) {
    int mi = FMADDtemplate | FRT << 21 | FRA << 16 | FRB << 11 | FRC << 6;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FNMSUBtemplate = 63 << 26 | 30 << 1;

  public final void emitFNMSUB(int FRT, int FRA, int FRC, int FRB) {
    int mi = FNMSUBtemplate | FRT << 21 | FRA << 16 | FRB << 11 | FRC << 6;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FNEGtemplate = 63 << 26 | 40 << 1;

  public final void emitFNEG(int FRT, int FRB) {
    int mi = FNEGtemplate | FRT << 21 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FSQRTtemplate = 63 << 26 | 22 << 1;

  public final void emitFSQRT(int FRT, int FRB) {
    int mi = FSQRTtemplate | FRT << 21 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FSQRTStemplate = 59 << 26 | 22 << 1;

  public final void emitFSQRTS(int FRT, int FRB) {
    int mi = FSQRTStemplate | FRT << 21 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FSUBtemplate = 63 << 26 | 20 << 1;

  public final void emitFSUB(int FRT, int FRA, int FRB) {
    int mi = FSUBtemplate | FRT << 21 | FRA << 16 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FSUBStemplate = 59 << 26 | 20 << 1;

  public final void emitFSUBS(int FRT, int FRA, int FRB) {
    int mi = FSUBStemplate | FRT << 21 | FRA << 16 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FSELtemplate = 63 << 26 | 23 << 1;

  public final void emitFSEL(int FRT, int FRA, int FRC, int FRB) {
    int mi = FSELtemplate | FRT << 21 | FRA << 16 | FRB << 11 | FRC << 6;
    mIP++;
    mc.addInstruction(mi);
  }

  // LOAD/ STORE MULTIPLE

  // TODO!! verify that D is sign extended
  // (the Assembler Language Reference seems ambiguous)
  //

  public final void emitLMW(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = (46 << 26) | RT << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  // TODO!! verify that D is sign extended
  // (the Assembler Language Reference seems ambiguous)
  //
  public final void emitSTMW(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = (47 << 26) | RT << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LWZtemplate = 32 << 26;

  public final void emitLWZ(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    _emitLWZ(RT, D & 0xFFFF, RA);
  }

  private void _emitLWZ(int RT, int D, int RA) {
    //D has already been masked
    int mi = LWZtemplate | RT << 21 | RA << 16 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LBZtemplate = 34 << 26;

  public final void emitLBZ(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LBZtemplate | RT << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitLBZoffset(int RT, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LBZtemplate | RT << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LBZXtemplate = 31 << 26 | 87 << 1;

  public final void emitLBZX(int RT, int RA, int RB) {
    int mi = LBZXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LHAtemplate = 42 << 26;

  public final void emitLHA(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LHAtemplate | RT << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitLHAoffset(int RT, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LHAtemplate | RT << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LHZtemplate = 40 << 26;

  public final void emitLHZ(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LHZtemplate | RT << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitLHZoffset(int RT, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LHZtemplate | RT << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LFDtemplate = 50 << 26;

  public final void emitLFD(int FRT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    _emitLFD(FRT, D & 0xFFFF, RA);
  }

  private void _emitLFD(int FRT, int D, int RA) {
    //D has already been masked
    int mi = LFDtemplate | FRT << 21 | RA << 16 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitLFDoffset(int FRT, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LFDtemplate | FRT << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LFDUtemplate = 51 << 26;

  public final void emitLFDU(int FRT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LFDUtemplate | FRT << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LFDXtemplate = 31 << 26 | 599 << 1;

  public final void emitLFDX(int FRT, int RA, int RB) {
    int mi = LFDXtemplate | FRT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LFStemplate = 48 << 26;

  public final void emitLFS(int FRT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    _emitLFS(FRT, D & 0xFFFF, RA);
  }

  private void _emitLFS(int FRT, int D, int RA) {
    //D has already been masked
    int mi = LFStemplate | FRT << 21 | RA << 16 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LFSXtemplate = 31 << 26 | 535 << 1;

  public static int LFSX(int FRT, int RA, int RB) {
    return 31 << 26 | FRT << 21 | RA << 16 | RB << 11 | 535 << 1;
  }

  public final void emitLFSX(int FRT, int RA, int RB) {
    int mi = LFSXtemplate | FRT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LHAXtemplate = 31 << 26 | 343 << 1;

  public final void emitLHAX(int RT, int RA, int RB) {
    int mi = LHAXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LHZXtemplate = 31 << 26 | 279 << 1;

  public final void emitLHZX(int RT, int RA, int RB) {
    int mi = LHZXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  private void _emitLI(int RT, int D) {
    //D has already been masked
    int mi = ADDItemplate | RT << 21 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LWZUtemplate = 33 << 26;

  public final void emitLWZU(int RT, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = LWZUtemplate | RT << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LWZXtemplate = 31 << 26 | 23 << 1;

  public final void emitLWZX(int RT, int RA, int RB) {
    int mi = LWZXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LWZUXtemplate = 31 << 26 | 55 << 1;

  public final void emitLWZUX(int RT, int RA, int RB) {
    int mi = LWZUXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LWARXtemplate = 31 << 26 | 20 << 1;

  public final void emitLWARX(int RT, int RA, int RB) {
    int mi = LWARXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MFLRtemplate = 31 << 26 | 0x08 << 16 | 339 << 1;

  public final void emitMFLR(int RT) {
    int mi = MFLRtemplate | RT << 21;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MFSPRtemplate = 31 << 26 | 339 << 1;

  final void emitMFSPR(int RT, int SPR) {
    int mi = MFSPRtemplate | RT << 21 | SPR << 16;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MTLRtemplate = 31 << 26 | 0x08 << 16 | 467 << 1;

  public final void emitMTLR(int RS) {
    int mi = MTLRtemplate | RS << 21;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MTCTRtemplate = 31 << 26 | 0x09 << 16 | 467 << 1;

  public final void emitMTCTR(int RS) {
    int mi = MTCTRtemplate | RS << 21;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FMRtemplate = 63 << 26 | 72 << 1;

  public final void emitFMR(int RA, int RB) {
    int mi = FMRtemplate | RA << 21 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FRSPtemplate = 63 << 26 | 12 << 1;

  static int FRSP(int RT, int RB) {
    return 63 << 26 | RT << 21 | RB << 11 | 12 << 1;
  }

  public final void emitFRSP(int RT, int RB) {
    int mi = FRSPtemplate | RT << 21 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MULHWUtemplate = 31 << 26 | 11 << 1;

  public final void emitMULHWU(int RT, int RA, int RB) {
    int mi = MULHWUtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int DIVWtemplate = 31 << 26 | 491 << 1;

  public final void emitDIVW(int RT, int RA, int RB) {
    int mi = DIVWtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MULLWtemplate = 31 << 26 | 235 << 1;

  public final void emitMULLW(int RT, int RA, int RB) {
    int mi = MULLWtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int NEGtemplate = 31 << 26 | 104 << 1;

  public final void emitNEG(int RT, int RA) {
    int mi = NEGtemplate | RT << 21 | RA << 16;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ORtemplate = 31 << 26 | 444 << 1;

  public final void emitOR(int RA, int RS, int RB) {
    int mi = ORtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  // move register RT <- RS
  public final void emitMR(int RT, int RS) {
    emitOR(RT, RS, RS);
  }

  static final int ORItemplate = 24 << 26;

  public final void emitORI(int RA, int RS, int UI) {
    if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
    int mi = ORItemplate | RS << 21 | RA << 16 | (UI & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ORIStemplate = 25 << 26;

  public final void emitORIS(int RA, int RS, int UI) {
    if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
    int mi = ORIStemplate | RS << 21 | RA << 16 | (UI & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int RLWINM_template = 21 << 26;

  public final void emitRLWINM(int RA, int RS, int SH, int MB, int ME) {
    int mi = RLWINM_template | RS << 21 | RA << 16 | SH << 11 | MB << 6 | ME << 1;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SUBFCrtemplate = 31 << 26 | 8 << 1 | 1;

  public final void emitSUBFCr(int RT, int RA, int RB) {
    int mi = SUBFCrtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SUBFCtemplate = 31 << 26 | 8 << 1;

  public final void emitSUBFC(int RT, int RA, int RB) {
    int mi = SUBFCtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SUBFICtemplate = 8 << 26;

  public final void emitSUBFIC(int RA, int RS, int S) {
    if (VM.VerifyAssertions) VM._assert(fits(S, 16));
    int mi = SUBFICtemplate | RS << 21 | RA << 16 | S;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SUBFErtemplate = 31 << 26 | 136 << 1 | 1;

  public final void emitSUBFEr(int RT, int RA, int RB) {
    int mi = SUBFErtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SUBFEtemplate = 31 << 26 | 136 << 1;

  public final void emitSUBFE(int RT, int RA, int RB) {
    int mi = SUBFEtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SUBFZEtemplate = 31 << 26 | 200 << 1;

  public final void emitSUBFZE(int RT, int RA) {
    int mi = SUBFZEtemplate | RT << 21 | RA << 16;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SLWtemplate = 31 << 26 | 24 << 1;

  public final void emitSLW(int RA, int RS, int RB) {
    int mi = SLWtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SLWItemplate = 21 << 26;

  public final void emitSLWI(int RA, int RS, int N) {
    int mi = SLWItemplate | RS << 21 | RA << 16 | N << 11 | (31 - N) << 1;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRWtemplate = 31 << 26 | 536 << 1;

  public final void emitSRW(int RA, int RS, int RB) {
    int mi = SRWtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRAWtemplate = 31 << 26 | 792 << 1;

  public final void emitSRAW(int RA, int RS, int RB) {
    int mi = SRAWtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRAWItemplate = 31 << 26 | 824 << 1;

  public final void emitSRAWI(int RA, int RS, int SH) {
    int mi = SRAWItemplate | RS << 21 | RA << 16 | SH << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRAWIrtemplate = 31 << 26 | 824 << 1 | 1;

  public final void emitSRAWIr(int RA, int RS, int SH) {
    int mi = SRAWIrtemplate | RS << 21 | RA << 16 | SH << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STWtemplate = 36 << 26;

  public final void emitSTW(int RS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    _emitSTW(RS, D & 0xFFFF, RA);
  }

  private void _emitSTW(int RS, int D, int RA) {
    //D has already been masked
    int mi = STWtemplate | RS << 21 | RA << 16 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitSTWoffset(int RS, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STWtemplate | RS << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STBtemplate = 38 << 26;

  public final void emitSTB(int RS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STBtemplate | RS << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitSTBoffset(int RS, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STBtemplate | RS << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STHtemplate = 44 << 26;

  public final void emitSTH(int RS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STHtemplate | RS << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitSTHoffset(int RS, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STHtemplate | RS << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STBXtemplate = 31 << 26 | 215 << 1;

  public final void emitSTBX(int RS, int RA, int RB) {
    int mi = STBXtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STHXtemplate = 31 << 26 | 407 << 1;

  public final void emitSTHX(int RS, int RA, int RB) {
    int mi = STHXtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STWXtemplate = 31 << 26 | 151 << 1;

  public final void emitSTWX(int RS, int RA, int RB) {
    int mi = STWXtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STFSXtemplate = 31 << 26 | 663 << 1;

  public static int STFSX(int FRS, int RA, int RB) {
    return 31 << 26 | FRS << 21 | RA << 16 | RB << 11 | 663 << 1;
  }

  public final void emitSTFSX(int FRS, int RA, int RB) {
    int mi = STFSXtemplate | FRS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STFDtemplate = 54 << 26;

  public final void emitSTFD(int FRS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    _emitSTFD(FRS, D & 0xFFFF, RA);
  }

  private void _emitSTFD(int FRS, int D, int RA) {
    //D has already been masked
    int mi = STFDtemplate | FRS << 21 | RA << 16 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitSTFDoffset(int FRS, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STFDtemplate | FRS << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STFDUtemplate = 55 << 26;

  public final void emitSTFDU(int FRS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STFDUtemplate | FRS << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STFDXtemplate = 31 << 26 | 727 << 1;

  public final void emitSTFDX(int FRS, int RA, int RB) {
    int mi = STFDXtemplate | FRS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STFStemplate = 52 << 26;

  public final void emitSTFS(int FRS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    _emitSTFS(FRS, D & 0xFFFF, RA);
  }

  private void _emitSTFS(int FRS, int D, int RA) {
    //D has already been masked
    int mi = STFStemplate | FRS << 21 | RA << 16 | D;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitSTFSoffset(int FRS, int RA, Offset D) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STFStemplate | FRS << 21 | RA << 16 | maskLower16(D);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STFSUtemplate = 53 << 26;

  public final void emitSTFSU(int FRS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STFSUtemplate | FRS << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STWUtemplate = 37 << 26;

  public final void emitSTWU(int RS, int D, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(D, 16));
    int mi = STWUtemplate | RS << 21 | RA << 16 | (D & 0xFFFF);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STWUXtemplate = 31 << 26 | 183 << 1;

  public final void emitSTWUX(int RS, int RA, int RB) {
    int mi = STWUXtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STWCXrtemplate = 31 << 26 | 150 << 1 | 1;

  public final void emitSTWCXr(int RS, int RA, int RB) {
    int mi = STWCXrtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TWtemplate = 31 << 26 | 4 << 1;
  static final int TWLEtemplate = TWtemplate | 0x14 << 21;

  public final void emitTWLE(int RA, int RB) {
    int mi = TWLEtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TWLTtemplate = TWtemplate | 0x10 << 21;

  public final void emitTWLT(int RA, int RB) {
    int mi = TWLTtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TWNEtemplate = TWtemplate | 0x18 << 21;

  public final void emitTWNE(int RA, int RB) {
    int mi = TWNEtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TWLLEtemplate = TWtemplate | 0x6 << 21;

  public final void emitTWLLE(int RA, int RB) {
    int mi = TWLLEtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TWItemplate = 3 << 26;

  public final void emitTWI(int TO, int RA, int SI) {
    int mi = TWItemplate | TO << 21 | RA << 16 | SI & 0xFFFF;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TWEQItemplate = TWItemplate | 0x4 << 21;

  public final void emitTWEQ0(int RA) {
    int mi = TWEQItemplate | RA << 16;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TWWItemplate = TWItemplate | 0x3EC << 16;      // RA == 12

  public final void emitTWWI(int imm) {
    int mi = TWWItemplate | imm;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int XORtemplate = 31 << 26 | 316 << 1;

  public final void emitXOR(int RA, int RS, int RB) {
    int mi = XORtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int XORItemplate = 26 << 26;

  public final void emitXORI(int RA, int RS, int V) {
    if (VM.VerifyAssertions) VM._assert(fits(V, 16));
    int mi = XORItemplate | RS << 21 | RA << 16 | V & 0xFFFF;
    mIP++;
    mc.addInstruction(mi);
  }

  /* macro instructions */

  public final void emitNOP() {
    int mi = 24 << 26; //ORI 0,0,0
    mIP++;
    mc.addInstruction(mi);
  }

  //private: use emitLIntOffset or emitLAddrOffset instead
  private void emitLDoffset(int RT, int RA, Offset offset) {
    if (fits(offset, 16)) {
      _emitLD(RT, maskLower16(offset), RA);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(RT, RA, maskUpper16(offset));
      _emitLD(RT, maskLower16(offset), RT);
    }
  }

  //private: use emitLIntOffset or emitLAddrOffset instead
  private void emitLWAoffset(int RT, int RA, Offset offset) {
    if (fits(offset, 16)) {
      _emitLWA(RT, maskLower16(offset), RA);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(RT, RA, maskUpper16(offset));
      _emitLWA(RT, maskLower16(offset), RT);
    }
  }

  //private: use emitLIntOffset or emitLAddrOffset instead
  private void emitLWZoffset(int RT, int RA, Offset offset) {
    if (fits(offset, 16)) {
      _emitLWZ(RT, maskLower16(offset), RA);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(RT, RA, maskUpper16(offset));
      _emitLWZ(RT, maskLower16(offset), RT);
    }
  }

  public final void emitSTDtoc(int RT, Offset offset, int Rz) {
    if (fits(offset, 16)) {
      _emitSTD(RT, maskLower16(offset), JTOC);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(Rz, JTOC, maskUpper16(offset));
      _emitSTD(RT, maskLower16(offset), Rz);
    }
  }

  public final void emitSTWtoc(int RT, Offset offset, int Rz) {
    if (fits(offset, 16)) {
      _emitSTW(RT, maskLower16(offset), JTOC);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(Rz, JTOC, maskUpper16(offset));
      _emitSTW(RT, maskLower16(offset), Rz);
    }
  }

  public final void emitLFDtoc(int FRT, Offset offset, int Rz) {
    if (fits(offset, 16)) {
      _emitLFD(FRT, maskLower16(offset), JTOC);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(Rz, JTOC, maskUpper16(offset));
      _emitLFD(FRT, maskLower16(offset), Rz);
    }
  }

  public final void emitSTFDtoc(int FRT, Offset offset, int Rz) {
    if (fits(offset, 16)) {
      _emitSTFD(FRT, maskLower16(offset), JTOC);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(Rz, JTOC, maskUpper16(offset));
      _emitSTFD(FRT, maskLower16(offset), Rz);
    }
  }

  public final void emitLFStoc(int FRT, Offset offset, int Rz) {
    if (fits(offset, 16)) {
      _emitLFS(FRT, maskLower16(offset), JTOC);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(Rz, JTOC, maskUpper16(offset));
      _emitLFS(FRT, maskLower16(offset), Rz);
    }
  }

  public final void emitSTFStoc(int FRT, Offset offset, int Rz) {
    if (fits(offset, 16)) {
      _emitSTFS(FRT, maskLower16(offset), JTOC);
    } else {
      if (VM.VerifyAssertions) VM._assert(fits(offset, 32));
      _emitADDIS(Rz, JTOC, maskUpper16(offset));
      _emitSTFS(FRT, maskLower16(offset), Rz);
    }
  }

  public final void emitLVALAddr(int RT, Offset off) {
    emitLVALAddr(RT, off.toWord().toAddress());
  }

  public final void emitLVALAddr(int RT, Address addr) {
    Offset val = addr.toWord().toOffset();
    if (VM.BuildFor64Addr) {
      if (!fits(val, 48)) {
        val = val.toWord().lsh(32).rsha(32).toOffset();
        Offset valHigh = addr.minus(val).toWord().rsha(32).toOffset();
        _emitADDIS(RT, maskUpper16(valHigh));
        _emitADDI(RT, maskLower16(valHigh), RT);
        emitSLDI(RT, RT, 32);
        _emitADDIS(RT, RT, maskUpper16(val));
        _emitADDI(RT, maskLower16(val), RT);
      } else if (!fits(val, 32)) {
        val = val.toWord().lsh(32).rsha(32).toOffset();
        Offset valHigh = addr.minus(val).toWord().rsha(32).toOffset();
        _emitLI(RT, maskLower16(valHigh));
        emitSLDI(RT, RT, 32);
        _emitADDIS(RT, RT, maskUpper16(val));
        _emitADDI(RT, maskLower16(val), RT);
      } else if (!fits(val, 16)) {
        _emitADDIS(RT, maskUpper16(val));
        _emitADDI(RT, maskLower16(val), RT);
      } else {
        _emitLI(RT, maskLower16(val));
      }
    } else {
      if (!fits(val, 16)) {
        _emitADDIS(RT, maskUpper16(val));
        _emitADDI(RT, maskLower16(val), RT);
      } else {
        _emitLI(RT, maskLower16(val));
      }
    }
  }

  public final void emitLVAL(int RT, int val) {
    if (fits(val, 16)) {
      _emitLI(RT, val & 0xFFFF);
    } else {
      _emitADDIS(RT, val >>> 16);
      emitORI(RT, RT, val & 0xFFFF);
    }
  }

  // Convert generated machine code into final form.
  //
  public ArchitectureSpecific.MachineCode finalizeMachineCode(int[] bytecodeMap) {
    mc.setBytecodeMap(bytecodeMap);
    return makeMachineCode();
  }

  public ArchitectureSpecific.MachineCode makeMachineCode() {
    mc.finish();
    if (shouldPrint) {
      VM.sysWriteln();
      ArchitectureSpecific.CodeArray instructions = mc.getInstructions();
      boolean saved = BaselineCompiler.options.PRINT_MACHINECODE;
      try {
        BaselineCompiler.options.PRINT_MACHINECODE = false;
        for (int i = 0; i < instructions.length(); i++) {
          VM.sysWrite(Services.getHexString(i << LG_INSTRUCTION_WIDTH, true));
          VM.sysWrite(" : ");
          VM.sysWrite(Services.getHexString(instructions.get(i), false));
          VM.sysWrite("  ");
          VM.sysWrite(Disassembler.disasm(instructions.get(i), i << LG_INSTRUCTION_WIDTH));
          VM.sysWrite("\n");
        }
      } finally {
        BaselineCompiler.options.PRINT_MACHINECODE = saved;
      }
    }
    return (ArchitectureSpecific.MachineCode) mc;
  }

  public void disassemble(int start, int stop) {
    for (int i = start; i < stop; i++) {
      VM.sysWrite(Services.getHexString(i << LG_INSTRUCTION_WIDTH, true));
      VM.sysWrite(" : ");
      VM.sysWrite(Services.getHexString(mc.getInstruction(i), false));
      VM.sysWrite("  ");
      VM.sysWrite(Disassembler.disasm(mc.getInstruction(i), i << LG_INSTRUCTION_WIDTH));
      VM.sysWrite("\n");
    }
  }

  /**
   * Append a CodeArray to the current machine code
   */
  public void appendInstructions(ArchitectureSpecific.CodeArray instructionSegment) {
    for (int i = 0; i < instructionSegment.length(); i++) {
      mIP++;
      mc.addInstruction(instructionSegment.get(i));
    }
  }

  // new PowerPC instructions

  // The "sync" on Power 4 architectures are expensive and so we use "lwsync" instead to
  //   implement SYNC.  On older arhictectures, there is no problem but the weaker semantics
  //   of lwsync means that there are memory consistency bugs we might need to flush out.
  // static final int SYNCtemplate = 31<<26 | 598<<1;
  // static final int LWSYNCtemplate = 31<<26 | 1 << 21 | 598<<1;
  static final int SYNCtemplate = 31 << 26 | 1 << 21 | 598 << 1;

  public final void emitSYNC() {
    int mi = SYNCtemplate;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ICBItemplate = 31 << 26 | 982 << 1;

  public final void emitICBI(int RA, int RB) {
    int mi = ICBItemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int ISYNCtemplate = 19 << 26 | 150 << 1;

  public final void emitISYNC() {
    int mi = ISYNCtemplate;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int DCBFtemplate = 31 << 26 | 86 << 1;

  public final void emitDCBF(int RA, int RB) {
    int mi = DCBFtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int DCBSTtemplate = 31 << 26 | 54 << 1;

  public final void emitDCBST(int RA, int RB) {
    int mi = DCBSTtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int DCBTtemplate = 31 << 26 | 278 << 1;

  public final void emitDCBT(int RA, int RB) {
    int mi = DCBSTtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int DCBTSTtemplate = 31 << 26 | 246 << 1;

  public final void emitDCBTST(int RA, int RB) {
    int mi = DCBSTtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int DCBZtemplate = 31 << 26 | 1014 << 1;

  public final void emitDCBZ(int RA, int RB) {
    int mi = DCBZtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int DCBZLtemplate = 31 << 26 | 1 << 21 | 1014 << 1;

  public final void emitDCBZL(int RA, int RB) {
    int mi = DCBZLtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MFTBtemplate = 31 << 26 | 392 << 11 | 371 << 1;

  public final void emitMFTB(int RT) {
    int mi = MFTBtemplate | RT << 21;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MFTBUtemplate = 31 << 26 | 424 << 11 | 371 << 1;

  public final void emitMFTBU(int RT) {
    int mi = MFTBUtemplate | RT << 21;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FCTIWZtemplate = 63 << 26 | 15 << 1;

  public final void emitFCTIWZ(int FRT, int FRB) {
    int mi = FCTIWZtemplate | FRT << 21 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int EXTSBtemplate = 31 << 26 | 954 << 1;

  public final void emitEXTSB(int RA, int RS) {
    int mi = EXTSBtemplate | RS << 21 | RA << 16;
    mIP++;
    mc.addInstruction(mi);
  }

  // PowerPC 64-bit instuctions
  static final int DIVDtemplate = 31 << 26 | 489 << 1;

  public final void emitDIVD(int RT, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = DIVDtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int EXTSWtemplate = 31 << 26 | 986 << 1;

  public final void emitEXTSW(int RA, int RS) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = EXTSWtemplate | RS << 21 | RA << 16;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FCTIDZtemplate = 63 << 26 | 815 << 1;

  public final void emitFCTIDZ(int FRT, int FRB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = FCTIDZtemplate | FRT << 21 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int FCFIDtemplate = 63 << 26 | 846 << 1;

  public final void emitFCFID(int FRT, int FRB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = FCFIDtemplate | FRT << 21 | FRB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LDtemplate = 58 << 26;

  public final void emitLD(int RT, int DS, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
    _emitLD(RT, DS, RA);
  }

  private void _emitLD(int RT, int DS, int RA) {
    //DS is already checked to fit 16 bits
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = LDtemplate | RT << 21 | RA << 16 | (DS & 0xFFFC);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LDARXtemplate = 31 << 26 | 84 << 1;

  public final void emitLDARX(int RT, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = LDARXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LDUtemplate = 58 << 26 | 1;

  public final void emitLDU(int RT, int DS, int RA) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
    int mi = LDUtemplate | RT << 21 | RA << 16 | (DS & 0xFFFC);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LDUXtemplate = 31 << 26 | 53 << 1;

  public final void emitLDUX(int RT, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = LDUXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LDXtemplate = 31 << 26 | 21 << 1;

  public final void emitLDX(int RT, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = LDXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LWAtemplate = 58 << 26 | 2;

  public final void emitLWA(int RT, int DS, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
    _emitLWA(RT, DS, RA);
  }

  private void _emitLWA(int RT, int DS, int RA) {
    //DS is already checked to fit 16 bits
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = LWAtemplate | RT << 21 | RA << 16 | (DS & 0xFFFC);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int LWAXtemplate = 31 << 26 | 341 << 1;

  public final void emitLWAX(int RT, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = LWAXtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MULHDUtemplate = 31 << 26 | 9 << 1;

  public final void emitMULHDU(int RT, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = MULHDUtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int MULLDtemplate = 31 << 26 | 233 << 1;

  public final void emitMULLD(int RT, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = MULLDtemplate | RT << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SLDItemplate = 30 << 26 | 1 << 2;

  public final void emitSLDI(int RA, int RS, int N) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi =
        SLDItemplate |
        RS << 21 |
        RA << 16 |
        (N & 0x1F) << 11 |
        ((63 - N) & 0x1F) << 6 |
        ((63 - N) & 0x20) |
        (N & 0x20) >> 4;
    mIP++;
    mc.addInstruction(mi);
  }

  public final void emitRLDINM(int RA, int RS, int SH, int MB, int ME) {
    VM._assert(false, "PLEASE IMPLEMENT ME");
  }

  static final int SLDtemplate = 31 << 26 | 27 << 1;

  public final void emitSLD(int RA, int RS, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = SLDtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRADtemplate = 31 << 26 | 794 << 1;

  public final void emitSRAD(int RA, int RS, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = SRADtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRADItemplate = 31 << 26 | 413 << 2;

  public final void emitSRADI(int RA, int RS, int SH) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = SRADItemplate | RS << 21 | RA << 16 | (SH & 0x1F) << 11 | (SH & 0x20) >> 4;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRADIrtemplate = SRADItemplate | 1;

  public final void emitSRADIr(int RA, int RS, int SH) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = SRADIrtemplate | RS << 21 | RA << 16 | (SH & 0x1F) << 11 | (SH & 0x20) >> 4;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int SRDtemplate = 31 << 26 | 539 << 1;

  public final void emitSRD(int RA, int RS, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = SRDtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STDtemplate = 62 << 26;

  public final void emitSTD(int RS, int DS, int RA) {
    if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
    _emitSTD(RS, DS, RA);
  }

  private void _emitSTD(int RS, int DS, int RA) {
    //DS is already checked to fit 16 bits
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = STDtemplate | RS << 21 | RA << 16 | (DS & 0xFFFC);
    mIP++;
    mc.addInstruction(mi);
  }

  //private: use emitSTWOffset or emitSTAddrOffset instead
  private void emitSTDoffset(int RS, int RA, Offset Dis) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    if (VM.VerifyAssertions) VM._assert(fits(Dis, 16));
    int DS = maskLower16(Dis);
    int mi = STDtemplate | RS << 21 | RA << 16 | (DS & 0xFFFC);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STDCXrtemplate = 31 << 26 | 214 << 1 | 1;

  public final void emitSTDCXr(int RS, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = STDCXrtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STDUtemplate = 62 << 26 | 1;

  public final void emitSTDU(int RS, int DS, int RA) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
    int mi = STDUtemplate | RS << 21 | RA << 16 | (DS & 0xFFFC);
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STDUXtemplate = 31 << 26 | 181 << 1;

  public final void emitSTDUX(int RS, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = STDUXtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int STDXtemplate = 31 << 26 | 149 << 1;

  public final void emitSTDX(int RS, int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = STDXtemplate | RS << 21 | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TDtemplate = 31 << 26 | 68 << 1;
  static final int TDLEtemplate = TDtemplate | 0x14 << 21;

  public final void emitTDLE(int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = TDLEtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TDLTtemplate = TDtemplate | 0x10 << 21;

  public final void emitTDLT(int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = TDLTtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TDLLEtemplate = TDtemplate | 0x6 << 21;

  public final void emitTDLLE(int RA, int RB) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = TDLLEtemplate | RA << 16 | RB << 11;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TDItemplate = 2 << 26;

  public final void emitTDI(int TO, int RA, int SI) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = TDItemplate | TO << 21 | RA << 16 | SI & 0xFFFF;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TDEQItemplate = TDItemplate | 0x4 << 21;

  public final void emitTDEQ0(int RA) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = TDEQItemplate | RA << 16;
    mIP++;
    mc.addInstruction(mi);
  }

  static final int TDWItemplate = TDItemplate | 0x1F << 21 | 0xC << 16;

  public final void emitTDWI(int SI) {
    if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(false);
    int mi = TDWItemplate | SI & 0xFFFF;
    mIP++;
    mc.addInstruction(mi);
  }

  // -------------------------------------------------------------- //
  // The following section contains macros to handle address values //
  // -------------------------------------------------------------- //
  public final void emitCMPLAddr(int reg1, int reg2) {
    if (VM.BuildFor64Addr) {
      emitCMPLD(reg1, reg2);
    } else {
      emitCMPL(reg1, reg2);
    }
  }

  public final void emitCMPAddr(int reg1, int reg2) {

    if (VM.BuildFor64Addr) {
      emitCMPD(reg1, reg2);
    } else {
      emitCMP(reg1, reg2);
    }
  }

  public final void emitCMPAddrI(int RA, int V) {
    if (VM.BuildFor64Addr) {
      emitCMPDI(RA, V);
    } else {
      emitCMPI(RA, V);
    }
  }

  public final void emitSRAddr(int RA, int RS, int RB) {
    if (VM.BuildFor64Addr) {
      emitSRD(RA, RS, RB);
    } else {
      emitSRW(RA, RS, RB);
    }
  }

  public final void emitSRA_Addr(int RA, int RS, int RB) {
    if (VM.BuildFor64Addr) {
      emitSRAD(RA, RS, RB);
    } else {
      emitSRAW(RA, RS, RB);
    }
  }

  public final void emitSRA_AddrI(int RA, int RS, int SH) {
    if (VM.BuildFor64Addr) {
      emitSRADI(RA, RS, SH);
    } else {
      emitSRAWI(RA, RS, SH);
    }
  }

  public final void emitSLAddr(int RA, int RS, int RB) {
    if (VM.BuildFor64Addr) {
      emitSLD(RA, RS, RB);
    } else {
      emitSLW(RA, RS, RB);
    }
  }

  public final void emitSLAddrI(int RA, int RS, int N) {
    if (VM.BuildFor64Addr) {
      emitSLDI(RA, RS, N);
    } else {
      emitSLWI(RA, RS, N);
    }
  }

  public final void emitTAddrLT(int RA, int RB) {
    if (VM.BuildFor64Addr) {
      emitTDLT(RA, RB);
    } else {
      emitTWLT(RA, RB);
    }
  }

  public final void emitTAddrLE(int RA, int RB) {
    if (VM.BuildFor64Addr) {
      emitTDLE(RA, RB);
    } else {
      emitTWLE(RA, RB);
    }
  }

  public final void emitTAddrLLE(int RA, int RB) {
    if (VM.BuildFor64Addr) {
      emitTDLLE(RA, RB);
    } else {
      emitTWLLE(RA, RB);
    }
  }

  public final void emitTAddrI(int TO, int RA, int SI) {
    if (VM.BuildFor64Addr) {
      emitTDI(T0, RA, SI);
    } else {
      emitTWI(T0, RA, SI);
    }
  }

  public final void emitTAddrEQ0(int RA) {
    if (VM.BuildFor64Addr) {
      emitTDEQ0(RA);
    } else {
      emitTWEQ0(RA);
    }
  }

  public final void emitTAddrWI(int SI) {
    if (VM.BuildFor64Addr) {
      emitTDWI(SI);
    } else {
      emitTWWI(SI);
    }
  }

  public final void emitSTAddr(int src_reg, int offset, int dest_reg) {

    if (VM.BuildFor64Addr) {
      emitSTD(src_reg, offset, dest_reg);
    } else {
      emitSTW(src_reg, offset, dest_reg);
    }
  }

  public final void emitSTAddrOffset(int src_reg, int dest_reg, Offset offset) {

    if (VM.BuildFor64Addr) {
      emitSTDoffset(src_reg, dest_reg, offset);
    } else {
      emitSTWoffset(src_reg, dest_reg, offset);
    }
  }

  public final void emitSTAddrX(int src_reg, int offset_reg, int dest_reg) {

    if (VM.BuildFor64Addr) {
      emitSTDX(src_reg, offset_reg, dest_reg);
    } else {
      emitSTWX(src_reg, offset_reg, dest_reg);
    }
  }

  public final void emitSTAddrU(int src_reg, int offset, int dest_reg) {

    if (VM.BuildFor64Addr) {
      emitSTDU(src_reg, offset, dest_reg);
    } else {
      emitSTWU(src_reg, offset, dest_reg);
    }
  }

  public final void emitLAddr(int dest_reg, int offset, int src_reg) {

    if (VM.BuildFor64Addr) {
      emitLD(dest_reg, offset, src_reg);
    } else {
      emitLWZ(dest_reg, offset, src_reg);
    }
  }

  public final void emitLAddrX(int dest_reg, int offset_reg, int src_reg) {

    if (VM.BuildFor64Addr) {
      emitLDX(dest_reg, offset_reg, src_reg);
    } else {
      emitLWZX(dest_reg, offset_reg, src_reg);
    }
  }

  public final void emitLAddrU(int dest_reg, int offset, int src_reg) {

    if (VM.BuildFor64Addr) {
      emitLDU(dest_reg, offset, src_reg);
    } else {
      emitLWZU(dest_reg, offset, src_reg);
    }
  }

  public final void emitLAddrToc(int dest_reg, Offset TOCoffset) {
    if (VM.BuildFor64Addr) {
      emitLDoffset(dest_reg, JTOC, TOCoffset);
    } else {
      emitLWZoffset(dest_reg, JTOC, TOCoffset);
    }
  }

  final void emitRLAddrINM(int RA, int RS, int SH, int MB, int ME) {

    if (VM.BuildFor64Addr) {
      emitRLDINM(RA, RS, SH, MB, ME);
    } else {
      emitRLWINM(RA, RS, SH, MB, ME);
    }
  }

  public final void emitLInt(int dest_reg, int offset, int src_reg) {

    if (VM.BuildFor64Addr) {
      emitLWA(dest_reg, offset, src_reg);
    } else {
      emitLWZ(dest_reg, offset, src_reg);
    }
  }

  public final void emitLIntX(int dest_reg, int offset_reg, int src_reg) {

    if (VM.BuildFor64Addr) {
      emitLWAX(dest_reg, offset_reg, src_reg);
    } else {
      emitLWZX(dest_reg, offset_reg, src_reg);
    }
  }

  public final void emitLIntToc(int dest_reg, Offset TOCoffset) {
    if (VM.BuildFor64Addr) {
      emitLWAoffset(dest_reg, JTOC, TOCoffset);
    } else {
      emitLWZoffset(dest_reg, JTOC, TOCoffset);
    }
  }

  public final void emitLIntOffset(int RT, int RA, Offset offset) {
    if (VM.BuildFor64Addr) {
      emitLWAoffset(RT, RA, offset);
    } else {
      emitLWZoffset(RT, RA, offset);
    }
  }

  public final void emitLAddrOffset(int RT, int RA, Offset offset) {
    if (VM.BuildFor64Addr) {
      emitLDoffset(RT, RA, offset);
    } else {
      emitLWZoffset(RT, RA, offset);
    }
  }

  // -----------------------------------------------------------//
  // The following section contains assembler "macros" used by: //
  //    BaselineCompilerImpl                                             //
  //    Barriers                                             //
  // -----------------------------------------------------------//

  // Emit baseline stack overflow instruction sequence.
  // Before:   FP is current (calling) frame
  //           PR is the current Processor, which contains a pointer to the active thread.
  // After:    R0, S0 destroyed
  //

  public void emitStackOverflowCheck(int frameSize) {
    emitLAddrOffset(0,
                    RegisterConstants.PROCESSOR_REGISTER,
                    Entrypoints.activeThreadStackLimitField.getOffset());   // R0 := &stack guard page
    emitADDI(S0, -frameSize, FP);                        // S0 := &new frame
    emitTAddrLT(S0, 0);                                    // trap if new frame below guard page
  }

  /**
   * Emit the trap pattern (trap LLT 1) we use for nullchecks on reg;
   * @param RA  The register number containing the ptr to null check
   */
  public void emitNullCheck(int RA) {
    // TDLLT 1 or TWLLT 1
    int mi = (VM.BuildFor64Addr ? TDItemplate : TWItemplate) | 0x2 << 21 | RA << 16 | 1;
    mIP++;
    mc.addInstruction(mi);
  }

  // Emit baseline stack overflow instruction sequence for native method prolog.
  // For the lowest Java to C transition frame in the stack, check that there is space of
  // STACK_SIZE_NATIVE words available on the stack;  enlarge stack if necessary.
  // For subsequent Java to C transition frames, check for the requested size and don't resize
  // the stack if overflow
  // Before:   FP is current (calling) frame
  //           PR is the current Processor, which contains a pointer to the active thread.
  // After:    R0, S0 destroyed
  //
  public void emitNativeStackOverflowCheck(int frameSize) {
    emitLAddrOffset(S0,
                    RegisterConstants.PROCESSOR_REGISTER,
                    Entrypoints.activeThreadField.getOffset());   // S0 := thread pointer
    emitLAddrOffset(S0, S0, Entrypoints.jniEnvField.getOffset());      // S0 := thread.jniEnv
    emitLIntOffset(0, S0, Entrypoints.JNIRefsTopField.getOffset());   // R0 := thread.jniEnv.JNIRefsTop
    emitLAddrOffset(S0,
                    RegisterConstants.PROCESSOR_REGISTER,
                    Entrypoints.activeThreadField.getOffset());   // S0 := thread pointer
    emitCMPI(0, 0);                                    // check if S0 == 0 -> first native frame on stack
    ForwardReference fr1 = emitForwardBC(EQ);
    // check for enough space for requested frame size
    emitLAddrOffset(0, S0, Entrypoints.stackLimitField.getOffset());  // R0 := &stack guard page
    emitADDI(S0, -frameSize, FP);                        // S0 := &new frame pointer
    emitTAddrLT(S0, 0);                                    // trap if new frame below guard page
    ForwardReference fr2 = emitForwardB();

    // check for enough space for STACK_SIZE_JNINATIVE
    fr1.resolve(this);
    emitLAddrOffset(0, S0, Entrypoints.stackLimitField.getOffset());  // R0 := &stack guard page
    emitLVAL(S0, StackframeLayoutConstants.STACK_SIZE_JNINATIVE);
    emitSUBFC(S0, S0, FP);             // S0 := &new frame pointer

    emitCMPLAddr(0, S0);
    ForwardReference fr3 = emitForwardBC(LE);
    emitTAddrWI(1);                                    // trap if new frame pointer below guard page
    fr2.resolve(this);
    fr3.resolve(this);
  }

  public static int getTargetOffset(int instr) {
    int opcode = (instr >>> 26) & 0x3F;
    int extendedOpcode;
    switch (opcode) {
      case 63:
        // A-form
        extendedOpcode = 0x1F & (instr >> 1);
        switch (extendedOpcode) {
          case 21:                 // fadd
          case 20:                 // fsub
          case 25:                 // fmul
          case 18:                 // fdiv
            return 21;                // bits 6-11
        }
        // X-form
        extendedOpcode = 0x3FF & (instr >> 1);
        switch (extendedOpcode) {
          case 40:                 // fneg
          case 12:                 // fsrp
            return 21;                // bits 6-11
        }
        break;
      case 59:
        // A-form
        extendedOpcode = 0x1F & (instr >> 1);
        switch (extendedOpcode) {
          case 21:                 // fadds
          case 20:                 // fsubs
          case 25:                 // fmuls
          case 18:                 // fdivs
            return 21;                // bits 6-11
        }
        break;
      case 31:
        // X-form
        extendedOpcode = 0x3FF & (instr >> 1);
        switch (extendedOpcode) {
          case 24:                 // slw
          case 792:                 // sraw
          case 536:                 // srw
          case 28:                 // and
          case 444:                 // or
          case 316:                 // xor
          case 824:                 // srawi
            return 16;              // bits 11-15
        }
        // XO-form
        extendedOpcode = 0x1FF & (instr >> 1);
        switch (extendedOpcode) {
          case 266:                 // add
          case 10:                 // addc
          case 8:                 // subfc
          case 235:                 // mullw
          case 491:                 // divw
          case 104:                 // neg
            return 21;                // bits 6-11
        }
        break;
      case 28:                    // andi
        // D-form
        return 16;
    }
    return -1;
  }

  public boolean retargetInstruction(int mcIndex, int newRegister) {

    int instr = mc.getInstruction(mcIndex);
    int offset = getTargetOffset(instr);
    if (offset < 0) {
      VM.sysWrite("Failed to retarget index=");
      VM.sysWrite(mcIndex);
      VM.sysWrite(", instr=");
      VM.sysWriteHex(instr);
      VM.sysWriteln();
      if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
      return false;
    }

    instr = (instr & ~(0x1F << offset)) | (newRegister << offset);

    mc.putInstruction(mcIndex, instr);
    return true;
  }

  public static String getOpcodeName(int opcode) {
    String s;
    switch (opcode) {
      case 0x00:
        s = "nop";
        break;
      case 0x01:
        s = "aconst_null";
        break;
      case 0x02:
        s = "iconst_m1";
        break;
      case 0x03:
        s = "iconst_0";
        break;
      case 0x04:
        s = "iconst_1";
        break;
      case 0x05:
        s = "iconst_2";
        break;
      case 0x06:
        s = "iconst_3";
        break;
      case 0x07:
        s = "iconst_4";
        break;
      case 0x08:
        s = "iconst_5";
        break;
      case 0x09:
        s = "lconst_0";
        break;
      case 0x0a:
        s = "lconst_1";
        break;
      case 0x0b:
        s = "fconst_0";
        break;
      case 0x0c:
        s = "fconst_1";
        break;
      case 0x0d:
        s = "fconst_2";
        break;
      case 0x0e:
        s = "dconst_0";
        break;
      case 0x0f:
        s = "dconst_1";
        break;
      case 0x10:
        s = "bipush";
        break;
      case 0x11:
        s = "sipush";
        break;
      case 0x12:
        s = "ldc";
        break;
      case 0x13:
        s = "ldc_w";
        break;
      case 0x14:
        s = "ldc2_w";
        break;
      case 0x15:
        s = "iload";
        break;
      case 0x16:
        s = "lload";
        break;
      case 0x17:
        s = "fload";
        break;
      case 0x18:
        s = "dload";
        break;
      case 0x19:
        s = "aload";
        break;
      case 0x1a:
        s = "iload_0";
        break;
      case 0x1b:
        s = "iload_1";
        break;
      case 0x1c:
        s = "iload_2";
        break;
      case 0x1d:
        s = "iload_3";
        break;
      case 0x1e:
        s = "lload_0";
        break;
      case 0x1f:
        s = "lload_1";
        break;
      case 0x20:
        s = "lload_2";
        break;
      case 0x21:
        s = "lload_3";
        break;
      case 0x22:
        s = "fload_0";
        break;
      case 0x23:
        s = "fload_1";
        break;
      case 0x24:
        s = "fload_2";
        break;
      case 0x25:
        s = "fload_3";
        break;
      case 0x26:
        s = "dload_0";
        break;
      case 0x27:
        s = "dload_1";
        break;
      case 0x28:
        s = "dload_2";
        break;
      case 0x29:
        s = "dload_3";
        break;
      case 0x2a:
        s = "aload_0";
        break;
      case 0x2b:
        s = "aload_1";
        break;
      case 0x2c:
        s = "aload_2";
        break;
      case 0x2d:
        s = "aload_3";
        break;
      case 0x2e:
        s = "iaload";
        break;
      case 0x2f:
        s = "laload";
        break;
      case 0x30:
        s = "faload";
        break;
      case 0x31:
        s = "daload";
        break;
      case 0x32:
        s = "aaload";
        break;
      case 0x33:
        s = "baload";
        break;
      case 0x34:
        s = "caload";
        break;
      case 0x35:
        s = "saload";
        break;
      case 0x36:
        s = "istore";
        break;
      case 0x37:
        s = "lstore";
        break;
      case 0x38:
        s = "fstore";
        break;
      case 0x39:
        s = "dstore";
        break;
      case 0x3a:
        s = "astore";
        break;
      case 0x3b:
        s = "istore_0";
        break;
      case 0x3c:
        s = "istore_1";
        break;
      case 0x3d:
        s = "istore_2";
        break;
      case 0x3e:
        s = "istore_3";
        break;
      case 0x3f:
        s = "lstore_0";
        break;
      case 0x40:
        s = "lstore_1";
        break;
      case 0x41:
        s = "lstore_2";
        break;
      case 0x42:
        s = "lstore_3";
        break;
      case 0x43:
        s = "fstore_0";
        break;
      case 0x44:
        s = "fstore_1";
        break;
      case 0x45:
        s = "fstore_2";
        break;
      case 0x46:
        s = "fstore_3";
        break;
      case 0x47:
        s = "dstore_0";
        break;
      case 0x48:
        s = "dstore_1";
        break;
      case 0x49:
        s = "dstore_2";
        break;
      case 0x4a:
        s = "dstore_3";
        break;
      case 0x4b:
        s = "astore_0";
        break;
      case 0x4c:
        s = "astore_1";
        break;
      case 0x4d:
        s = "astore_2";
        break;
      case 0x4e:
        s = "astore_3";
        break;
      case 0x4f:
        s = "iastore";
        break;
      case 0x50:
        s = "lastore";
        break;
      case 0x51:
        s = "fastore";
        break;
      case 0x52:
        s = "dastore";
        break;
      case 0x53:
        s = "aastore";
        break;
      case 0x54:
        s = "bastore";
        break;
      case 0x55:
        s = "castore";
        break;
      case 0x56:
        s = "sastore";
        break;
      case 0x57:
        s = "pop";
        break;
      case 0x58:
        s = "pop2";
        break;
      case 0x59:
        s = "dup";
        break;
      case 0x5a:
        s = "dup_x1";
        break;
      case 0x5b:
        s = "dup_x2";
        break;
      case 0x5c:
        s = "dup2";
        break;
      case 0x5d:
        s = "dup2_x1";
        break;
      case 0x5e:
        s = "dup2_x2";
        break;
      case 0x5f:
        s = "swap";
        break;
      case 0x60:
        s = "iadd";
        break;
      case 0x61:
        s = "ladd";
        break;
      case 0x62:
        s = "fadd";
        break;
      case 0x63:
        s = "dadd";
        break;
      case 0x64:
        s = "isub";
        break;
      case 0x65:
        s = "lsub";
        break;
      case 0x66:
        s = "fsub";
        break;
      case 0x67:
        s = "dsub";
        break;
      case 0x68:
        s = "imul";
        break;
      case 0x69:
        s = "lmul";
        break;
      case 0x6a:
        s = "fmul";
        break;
      case 0x6b:
        s = "dmul";
        break;
      case 0x6c:
        s = "idiv";
        break;
      case 0x6d:
        s = "ldiv";
        break;
      case 0x6e:
        s = "fdiv";
        break;
      case 0x6f:
        s = "ddiv";
        break;
      case 0x70:
        s = "irem";
        break;
      case 0x71:
        s = "lrem";
        break;
      case 0x72:
        s = "frem";
        break;
      case 0x73:
        s = "drem";
        break;
      case 0x74:
        s = "ineg";
        break;
      case 0x75:
        s = "lneg";
        break;
      case 0x76:
        s = "fneg";
        break;
      case 0x77:
        s = "dneg";
        break;
      case 0x78:
        s = "ishl";
        break;
      case 0x79:
        s = "lshl";
        break;
      case 0x7a:
        s = "ishr";
        break;
      case 0x7b:
        s = "lshr";
        break;
      case 0x7c:
        s = "iushr";
        break;
      case 0x7d:
        s = "lushr";
        break;
      case 0x7e:
        s = "iand";
        break;
      case 0x7f:
        s = "land";
        break;
      case 0x80:
        s = "ior";
        break;
      case 0x81:
        s = "lor";
        break;
      case 0x82:
        s = "ixor";
        break;
      case 0x83:
        s = "lxor";
        break;
      case 0x84:
        s = "iinc";
        break;
      case 0x85:
        s = "i2l";
        break;
      case 0x86:
        s = "i2f";
        break;
      case 0x87:
        s = "i2d";
        break;
      case 0x88:
        s = "l2i";
        break;
      case 0x89:
        s = "l2f";
        break;
      case 0x8a:
        s = "l2d";
        break;
      case 0x8b:
        s = "f2i";
        break;
      case 0x8c:
        s = "f2l";
        break;
      case 0x8d:
        s = "f2d";
        break;
      case 0x8e:
        s = "d2i";
        break;
      case 0x8f:
        s = "d2l";
        break;
      case 0x90:
        s = "d2f";
        break;
      case 0x91:
        s = "i2b";
        break;
      case 0x92:
        s = "i2c";
        break;
      case 0x93:
        s = "i2s";
        break;
      case 0x94:
        s = "lcmp";
        break;
      case 0x95:
        s = "fcmpl";
        break;
      case 0x96:
        s = "fcmpg";
        break;
      case 0x97:
        s = "dcmpl";
        break;
      case 0x98:
        s = "dcmpg";
        break;
      case 0x99:
        s = "ifeq";
        break;
      case 0x9a:
        s = "ifne";
        break;
      case 0x9b:
        s = "iflt";
        break;
      case 0x9c:
        s = "ifge";
        break;
      case 0x9d:
        s = "ifgt";
        break;
      case 0x9e:
        s = "ifle";
        break;
      case 0x9f:
        s = "if_icmpeq";
        break;
      case 0xa0:
        s = "if_icmpne";
        break;
      case 0xa1:
        s = "if_icmplt";
        break;
      case 0xa2:
        s = "if_icmpge";
        break;
      case 0xa3:
        s = "if_icmpgt";
        break;
      case 0xa4:
        s = "if_icmple";
        break;
      case 0xa5:
        s = "if_acmpeq";
        break;
      case 0xa6:
        s = "if_acmpne";
        break;
      case 0xa7:
        s = "goto";
        break;
      case 0xa8:
        s = "jsr";
        break;
      case 0xa9:
        s = "ret";
        break;
      case 0xaa:
        s = "tableswitch";
        break;
      case 0xab:
        s = "lookupswitch";
        break;
      case 0xac:
        s = "ireturn";
        break;
      case 0xad:
        s = "lreturn";
        break;
      case 0xae:
        s = "freturn";
        break;
      case 0xaf:
        s = "dreturn";
        break;
      case 0xb0:
        s = "areturn";
        break;
      case 0xb1:
        s = "return";
        break;
      case 0xb2:
        s = "getstatic";
        break;
      case 0xb3:
        s = "putstatic";
        break;
      case 0xb4:
        s = "getfield";
        break;
      case 0xb5:
        s = "putfield";
        break;
      case 0xb6:
        s = "invokevirtual";
        break;
      case 0xb7:
        s = "invokespecial";
        break;
      case 0xb8:
        s = "invokestatic";
        break;
      case 0xb9:
        s = "invokeinterface";
        break;
      case 0xba:
        s = "unused";
        break;
      case 0xbb:
        s = "new";
        break;
      case 0xbc:
        s = "newarray";
        break;
      case 0xbd:
        s = "anewarray";
        break;
      case 0xbe:
        s = "arraylength";
        break;
      case 0xbf:
        s = "athrow";
        break;
      case 0xc0:
        s = "checkcast";
        break;
      case 0xc1:
        s = "instanceof";
        break;
      case 0xc2:
        s = "monitorenter";
        break;
      case 0xc3:
        s = "monitorexit";
        break;
      case 0xc4:
        s = "wide";
        break;
      case 0xc5:
        s = "multianewarray";
        break;
      case 0xc6:
        s = "ifnull";
        break;
      case 0xc7:
        s = "ifnonnull";
        break;
      case 0xc8:
        s = "goto_w";
        break;
      case 0xc9:
        s = "jsr_w";
        break;
      default:
        s = "UNKNOWN";
        break;
    }
    return s;
  }

  /************************************************************************
   * Stub/s added for IA32 compatability
   */
  public static void patchCode(ArchitectureSpecific.CodeArray code, int indexa, int indexb) {
    if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
  }
}
