/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.common.assembler.ppc;
import static org.jikesrvm.VM.NOT_REACHED;
import static org.jikesrvm.compilers.common.assembler.ppc.AssemblerConstants.EQ;
import static org.jikesrvm.compilers.common.assembler.ppc.AssemblerConstants.GE;
import static org.jikesrvm.compilers.common.assembler.ppc.AssemblerConstants.GT;
import static org.jikesrvm.compilers.common.assembler.ppc.AssemblerConstants.LE;
import static org.jikesrvm.compilers.common.assembler.ppc.AssemblerConstants.LT;
import static org.jikesrvm.compilers.common.assembler.ppc.AssemblerConstants.NE;
import static org.jikesrvm.ppc.BaselineConstants.FP;
import static org.jikesrvm.ppc.BaselineConstants.JTOC;
import static org.jikesrvm.ppc.BaselineConstants.S0;
import static org.jikesrvm.ppc.BaselineConstants.T1;
import static org.jikesrvm.ppc.RegisterConstants.LG_INSTRUCTION_WIDTH;
import static org.jikesrvm.ppc.RegisterConstants.THREAD_REGISTER;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACK_SIZE_JNINATIVE;
import org.jikesrvm.VM;
import org.jikesrvm.architecture.MachineRegister;
import org.jikesrvm.compilers.baseline.ppc.BaselineCompilerImpl;
import org.jikesrvm.compilers.common.CodeArray;
import org.jikesrvm.compilers.common.assembler.AbstractAssembler;
import org.jikesrvm.compilers.common.assembler.ForwardReference;
import org.jikesrvm.objectmodel.JavaHeader;
import org.jikesrvm.ppc.Disassembler;
import org.jikesrvm.ppc.RegisterConstants.CR;
import org.jikesrvm.ppc.RegisterConstants.FPR;
import org.jikesrvm.ppc.RegisterConstants.GPR;
import org.jikesrvm.runtime.Entrypoints;
import org.jikesrvm.util.Services;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;
/**
* Machine code generators:
* <p>
* Corresponding to a PowerPC assembler instruction of the form
* <pre>
* xx A,B,C
* </pre>
* there will be a method
* <pre>
* void emitXX (GPR A, GPR B, GPR C).
* </pre>
* <p>
* 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).
* <p>
* mIP will be incremented to point to the next machine instruction.
* <p>
* Machine code generators:
*/
public final class Assembler extends AbstractAssembler {
/**
* The array holding the generated binary code.
*/
private int[] machineCodes;
/** 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;
/** Should the generated code be regarded as hot? */
private final boolean isHot = false;
/**
* Heuristic constant used to calculate initial size of the machine
* code buffer. This is an average of how many bytes of generated
* code come from a given bytecode in the baseline compiler.
*/
private static final int CODE_EXPANSION_FACTOR = 4;
/**
* Heuristic constant used to calculate initial size of the machine
* code buffer. This is an estimate of the fixed method overhead
* code generated by the baseline compiler, such as method
* prologue.
*/
private static final int CODE_OVERHEAD_TERM = 30;
private final Lister lister;
public Assembler(int length) {
this(length, false, null, null);
}
public Assembler(int bytecodeSize, boolean sp, BaselineCompilerImpl comp, int[] bytecodeMap) {
machineCodes = new int[bytecodeSize * CODE_EXPANSION_FACTOR + CODE_OVERHEAD_TERM];
shouldPrint = sp;
compiler = comp;
mIP = 0;
lister = new Lister(bytecodeMap);
}
public Assembler(int length, boolean sp) {
this(length, sp, null, 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 - 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);
}
public Lister getLister() {
return lister;
}
/**
* Return a copy of the generated code as a CodeArray.
* @return a copy of the generated code as a CodeArray.
*/
@Override
public CodeArray getMachineCodes() {
int len = getMachineCodeIndex();
CodeArray trimmed = CodeArray.Factory.create(len, isHot);
for (int i = 0; i < len; i++) {
trimmed.set(i, machineCodes[i]);
}
return trimmed;
}
@Override
public int getMachineCodeIndex() {
return mIP;
}
private void appendInstruction(int instr) {
if (mIP < machineCodes.length) {
machineCodes[mIP] = instr;
} else {
growMachineCodes(mIP, instr);
}
mIP++;
}
private void growMachineCodes(int index, int instr) {
int [] old = machineCodes;
machineCodes = new int [2 * old.length];
System.arraycopy(old, 0, machineCodes, 0, old.length);
machineCodes[index] = instr;
}
/* Handling forward branch references */
ForwardReference forwardRefs = null;
/* call before emiting code for the branch */
void reserveForwardBranch(int where) {
ForwardReference fr = new ForwardReference.UnconditionalBranch(mIP, where);
forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
}
/* call before emiting code for the branch */
void reserveForwardConditionalBranch(int where) {
emitNOP();
ForwardReference fr = new ForwardReference.ConditionalBranch(mIP, where);
forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
}
/* call before emiting code for the branch */
void reserveShortForwardConditionalBranch(int where) {
ForwardReference fr = new ForwardReference.ConditionalBranch(mIP, where);
forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
}
/* call before emiting data for the case branch */
void reserveForwardCase(int where) {
ForwardReference fr = new ForwardReference.SwitchCase(mIP, where);
forwardRefs = ForwardReference.enqueue(forwardRefs, fr);
}
/* call before emiting code for the target */
@Override
public void resolveForwardReferences(int label) {
if (forwardRefs == null) return;
forwardRefs = ForwardReference.resolveMatching(this, forwardRefs, label);
}
@Override
public void patchUnconditionalBranch(int sourceMachinecodeIndex) {
int delta = mIP - sourceMachinecodeIndex;
int instr = machineCodes[sourceMachinecodeIndex];
if (VM.VerifyAssertions) VM._assert((delta >>> 23) == 0); // delta (positive) fits in 24 bits
instr |= (delta << 2);
machineCodes[sourceMachinecodeIndex] = instr;
}
@Override
public void patchConditionalBranch(int sourceMachinecodeIndex) {
final int Btemplate = 18 << 26;
int delta = mIP - sourceMachinecodeIndex;
int instr = machineCodes[sourceMachinecodeIndex];
if ((delta >>> 13) == 0) { // delta (positive) fits in 14 bits
instr |= (delta << 2);
machineCodes[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
machineCodes[sourceMachinecodeIndex - 1] = instr; // skip unconditional branch to target
machineCodes[sourceMachinecodeIndex] = Btemplate | (delta & 0xFFFFFF) << 2;
}
}
@Override
public void patchShortBranch(int sourceMachinecodeIndex) {
int delta = mIP - sourceMachinecodeIndex;
int instr = machineCodes[sourceMachinecodeIndex];
if ((delta >>> 13) == 0) { // delta (positive) fits in 14 bits
instr |= (delta << 2);
machineCodes[sourceMachinecodeIndex] = instr;
} else {
throw new InternalError("Long offset doesn't fit in short branch\n");
}
}
public 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;
*/
@Override
public void patchLoadReturnAddress(int sourceIndex) {
int offset = (mIP - sourceIndex + 1) * 4;
int mi = ADDI(T1, offset, T1);
machineCodes[sourceIndex] = mi;
}
int ADDI(GPR RT, int D, GPR RA) {
final int ADDItemplate = 14 << 26;
return ADDItemplate | RT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
}
public ForwardReference generatePendingJMP(int bTarget) {
return this.emitForwardB();
}
/************ OSR Support */
@Override
public void patchSwitchCase(int sourceMachinecodeIndex) {
int delta = (mIP - sourceMachinecodeIndex) << 2;
// correction is number of bytes of source off switch base
int correction = machineCodes[sourceMachinecodeIndex];
int offset = delta + correction;
machineCodes[sourceMachinecodeIndex] = offset;
}
/* machine instructions */
public void emitADD(GPR RT, GPR RA, GPR RB) {
final int ADDtemplate = 31 << 26 | 10 << 1;
int mi = ADDtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitADDE(GPR RT, GPR RA, GPR RB) {
final int ADDEtemplate = 31 << 26 | 138 << 1;
int mi = ADDEtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitADDME(GPR RT, GPR RA) {
final int ADDMEtemplate = 31 << 26 | 234 << 1;
int mi = ADDMEtemplate | RT.value() << 21 | RA.value() << 16;
appendInstruction(mi);
}
public void emitADDICr(GPR RT, GPR RA, int SI) {
final int ADDICrtemplate = 13 << 26;
if (VM.VerifyAssertions) VM._assert(fits(SI, 16));
int mi = ADDICrtemplate | RT.value() << 21 | RA.value() << 16 | (SI & 0xFFFF);
appendInstruction(mi);
}
public void emitAND(GPR RA, GPR RS, GPR RB) {
final int ANDtemplate = 31 << 26 | 28 << 1;
int mi = ANDtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitANDI(GPR RA, GPR RS, int U) {
if (VM.VerifyAssertions) VM._assert((U >>> 16) == 0);
final int ANDItemplate = 28 << 26;
int mi = ANDItemplate | RS.value() << 21 | RA.value() << 16 | U;
appendInstruction(mi);
}
public void emitANDIS(GPR RA, GPR RS, int U) {
if (VM.VerifyAssertions) VM._assert((U & 0xffff) == 0);
final int ANDIStemplate = 29 << 26;
int mi = ANDIStemplate | RS.value() << 21 | RA.value() << 16 | (U >>> 16);
appendInstruction(mi);
}
private void _emitB(int relative_address) {
if (VM.VerifyAssertions) VM._assert(fits(relative_address, 24));
final int Btemplate = 18 << 26;
int mi = Btemplate | (relative_address & 0xFFFFFF) << 2;
appendInstruction(mi);
}
public void emitB(int relative_address, int label) {
if (relative_address == 0) {
reserveForwardBranch(label);
} else {
relative_address -= mIP;
}
_emitB(relative_address);
}
public void emitB(int relative_address) {
relative_address -= mIP;
if (VM.VerifyAssertions) VM._assert(relative_address < 0);
_emitB(relative_address);
}
public ForwardReference emitForwardB() {
ForwardReference fr;
if (compiler != null) {
fr = new AssemblerShortBranch(mIP, compiler.spTopOffset);
} else {
fr = new ForwardReference.ShortBranch(mIP);
}
_emitB(0);
return fr;
}
public void emitBLA(int address) {
final int BLAtemplate = 18 << 26 | 3;
if (VM.VerifyAssertions) VM._assert(fits(address, 24));
int mi = BLAtemplate | (address & 0xFFFFFF) << 2;
appendInstruction(mi);
}
private void _emitBL(int relative_address) {
final int BLtemplate = 18 << 26 | 1;
if (VM.VerifyAssertions) VM._assert(fits(relative_address, 24));
int mi = BLtemplate | (relative_address & 0xFFFFFF) << 2;
appendInstruction(mi);
}
public void emitBL(int relative_address, int label) {
if (relative_address == 0) {
reserveForwardBranch(label);
} else {
relative_address -= mIP;
}
_emitBL(relative_address);
}
public ForwardReference emitForwardBL() {
ForwardReference fr;
if (compiler != null) {
fr = new AssemblerShortBranch(mIP, compiler.spTopOffset);
} else {
fr = new ForwardReference.ShortBranch(mIP);
}
_emitBL(0);
return fr;
}
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(VM.NOT_REACHED);
return -1;
}
private void _emitBC(int cc, int relative_address) {
final int BCtemplate = 16 << 26;
if (fits(relative_address, 14)) {
int mi = BCtemplate | cc | (relative_address & 0x3FFF) << 2;
appendInstruction(mi);
} else {
_emitBC(flipCode(cc), 2);
_emitB(relative_address - 1);
}
}
public void emitBC(int cc, int relative_address, int label) {
if (relative_address == 0) {
reserveForwardConditionalBranch(label);
} else {
relative_address -= mIP;
}
_emitBC(cc, relative_address);
}
public void emitShortBC(int cc, int relative_address, int label) {
if (relative_address == 0) {
reserveShortForwardConditionalBranch(label);
} else {
relative_address -= mIP;
}
_emitBC(cc, relative_address);
}
public void emitBC(int cc, int relative_address) {
relative_address -= mIP;
if (VM.VerifyAssertions) VM._assert(relative_address < 0);
_emitBC(cc, relative_address);
}
public 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 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);
}
appendInstruction(data);
}
public void emitBCLR() {
final int BCLRtemplate = 19 << 26 | 0x14 << 21 | 16 << 1;
int mi = BCLRtemplate;
appendInstruction(mi);
}
public void emitBCLRL() {
final int BCLRLtemplate = 19 << 26 | 0x14 << 21 | 16 << 1 | 1;
int mi = BCLRLtemplate;
appendInstruction(mi);
}
public void emitBCCTR() {
final int BCCTRtemplate = 19 << 26 | 0x14 << 21 | 528 << 1;
int mi = BCCTRtemplate;
appendInstruction(mi);
}
public void emitBCCTRL() {
final int BCCTRLtemplate = 19 << 26 | 0x14 << 21 | 528 << 1 | 1;
int mi = BCCTRLtemplate;
appendInstruction(mi);
}
public void emitADDI(GPR RT, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
_emitADDI(RT, D & 0xFFFF, RA);
}
private void _emitADDI(GPR RT, int D, GPR RA) {
final int ADDItemplate = 14 << 26;
//D has already been masked
int mi = ADDItemplate | RT.value() << 21 | RA.value() << 16 | D;
appendInstruction(mi);
}
public void emitADDI(GPR RT, Offset off, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(off, 16));
_emitADDI(RT, maskLower16(off), RA);
}
public void emitADDIS(GPR RT, GPR RA, int UI) {
if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
_emitADDIS(RT, RA, UI);
}
private void _emitADDIS(GPR RT, GPR RA, int UI) {
final int ADDIStemplate = 15 << 26;
//UI has already been masked
int mi = ADDIStemplate | RT.value() << 21 | RA.value() << 16 | UI;
appendInstruction(mi);
}
public void emitADDIS(GPR RT, int UI) {
if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
_emitADDIS(RT, UI);
}
private void _emitADDIS(GPR RT, int UI) {
final int ADDIStemplate = 15 << 26;
//UI has already been masked
int mi = ADDIStemplate | RT.value() << 21 | UI;
appendInstruction(mi);
}
public void emitCMP(int BF, GPR RA, GPR RB) {
final int CMPtemplate = 31 << 26;
int mi = CMPtemplate | BF << 23 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitCMP(GPR RA, GPR RB) {
final int CMPtemplate = 31 << 26;
int mi = CMPtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitCMPD(GPR RA, GPR RB) {
final int CMPtemplate = 31 << 26;
final int CMPDtemplate = CMPtemplate | 1 << 21;
int mi = CMPDtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitCMPI(int BF, GPR RA, int V) {
final int CMPItemplate = 11 << 26;
if (VM.VerifyAssertions) VM._assert(fits(V, 16));
int mi = CMPItemplate | BF << 23 | RA.value() << 16 | (V & 0xFFFF);
appendInstruction(mi);
}
public void emitCMPI(GPR RA, int V) {
final int CMPItemplate = 11 << 26;
if (VM.VerifyAssertions) VM._assert(fits(V, 16));
int mi = CMPItemplate | RA.value() << 16 | (V & 0xFFFF);
appendInstruction(mi);
}
public void emitCMPDI(GPR RA, int V) {
final int CMPItemplate = 11 << 26;
final int CMPDItemplate = CMPItemplate | 1 << 21;
if (VM.VerifyAssertions) VM._assert(fits(V, 16));
int mi = CMPDItemplate | RA.value() << 16 | (V & 0xFFFF);
appendInstruction(mi);
}
public void emitCMPL(int BF, GPR RA, GPR RB) {
final int CMPLtemplate = 31 << 26 | 32 << 1;
int mi = CMPLtemplate | BF << 23 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitCMPL(GPR RA, GPR RB) {
final int CMPLtemplate = 31 << 26 | 32 << 1;
int mi = CMPLtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitCMPLD(GPR RA, GPR RB) {
final int CMPLtemplate = 31 << 26 | 32 << 1;
final int CMPLDtemplate = CMPLtemplate | 1 << 21;
int mi = CMPLDtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitCRAND(CR BT, CR BA, CR BB) {
final int CRANDtemplate = 19 << 26 | 257 << 1;
int mi = CRANDtemplate | BT.value() << 21 | BA.value() << 16 | BB.value() << 11;
appendInstruction(mi);
}
public void emitCRANDC(CR BT, CR BA, CR BB) {
final int CRANDCtemplate = 19 << 26 | 129 << 1;
int mi = CRANDCtemplate | BT.value() << 21 | BA.value() << 16 | BB.value() << 11;
appendInstruction(mi);
}
public void emitCROR(CR BT, CR BA, CR BB) {
final int CRORtemplate = 19 << 26 | 449 << 1;
int mi = CRORtemplate | BT.value() << 21 | BA.value() << 16 | BB.value() << 11;
appendInstruction(mi);
}
public void emitCRORC(CR BT, CR BA, CR BB) {
final int CRORCtemplate = 19 << 26 | 417 << 1;
int mi = CRORCtemplate | BT.value() << 21 | BA.value() << 16 | BB.value() << 11;
appendInstruction(mi);
}
public void emitFADD(FPR FRT, FPR FRA, FPR FRB) {
final int FADDtemplate = 63 << 26 | 21 << 1;
int mi = FADDtemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFADDS(FPR FRT, FPR FRA, FPR FRB) {
final int FADDStemplate = 59 << 26 | 21 << 1; // single-percision add
int mi = FADDStemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFABS(FPR FRT, FPR FRB) {
final int FABStemplate = 63 << 26 | 264 << 1;
int mi = FABStemplate | FRT.value() << 21 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFCMPU(FPR FRA, FPR FRB) {
final int FCMPUtemplate = 63 << 26;
int mi = FCMPUtemplate | FRA.value() << 16 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFDIV(FPR FRT, FPR FRA, FPR FRB) {
final int FDIVtemplate = 63 << 26 | 18 << 1;
int mi = FDIVtemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFDIVS(FPR FRT, FPR FRA, FPR FRB) {
final int FDIVStemplate = 59 << 26 | 18 << 1; // single-precision divide
int mi = FDIVStemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFMUL(FPR FRT, FPR FRA, FPR FRB) {
final int FMULtemplate = 63 << 26 | 25 << 1;
int mi = FMULtemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 6;
appendInstruction(mi);
}
public void emitFMULS(FPR FRT, FPR FRA, FPR FRB) {
final int FMULStemplate = 59 << 26 | 25 << 1; // single-precision fm
int mi = FMULStemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 6;
appendInstruction(mi);
}
public void emitFMADD(FPR FRT, FPR FRA, FPR FRC, FPR FRB) {
final int FMADDtemplate = 63 << 26 | 29 << 1;
int mi = FMADDtemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11 | FRC.value() << 6;
appendInstruction(mi);
}
public void emitFNMSUB(FPR FRT, FPR FRA, FPR FRC, FPR FRB) {
final int FNMSUBtemplate = 63 << 26 | 30 << 1;
int mi = FNMSUBtemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11 | FRC.value() << 6;
appendInstruction(mi);
}
public void emitFNEG(FPR FRT, FPR FRB) {
final int FNEGtemplate = 63 << 26 | 40 << 1;
int mi = FNEGtemplate | FRT.value() << 21 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFSQRT(FPR FRT, FPR FRB) {
final int FSQRTtemplate = 63 << 26 | 22 << 1;
int mi = FSQRTtemplate | FRT.value() << 21 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFSQRTS(FPR FRT, FPR FRB) {
final int FSQRTStemplate = 59 << 26 | 22 << 1;
int mi = FSQRTStemplate | FRT.value() << 21 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFSUB(FPR FRT, FPR FRA, FPR FRB) {
final int FSUBtemplate = 63 << 26 | 20 << 1;
int mi = FSUBtemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFSUBS(FPR FRT, FPR FRA, FPR FRB) {
final int FSUBStemplate = 59 << 26 | 20 << 1;
int mi = FSUBStemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFSEL(FPR FRT, FPR FRA, FPR FRC, FPR FRB) {
final int FSELtemplate = 63 << 26 | 23 << 1;
int mi = FSELtemplate | FRT.value() << 21 | FRA.value() << 16 | FRB.value() << 11 | FRC.value() << 6;
appendInstruction(mi);
}
// LOAD/ STORE MULTIPLE
// TODO!! verify that D is sign extended
// (the Assembler Language Reference seems ambiguous)
//
public void emitLMW(GPR RT, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = (46 << 26) | RT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
// TODO!! verify that D is sign extended
// (the Assembler Language Reference seems ambiguous)
//
public void emitSTMW(GPR RT, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = (47 << 26) | RT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitLWZ(GPR RT, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
_emitLWZ(RT, D & 0xFFFF, RA);
}
private void _emitLWZ(GPR RT, int D, GPR RA) {
final int LWZtemplate = 32 << 26;
//D has already been masked
int mi = LWZtemplate | RT.value() << 21 | RA.value() << 16 | D;
appendInstruction(mi);
}
public void emitLBZ(GPR RT, int D, GPR RA) {
final int LBZtemplate = 34 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LBZtemplate | RT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitLBZoffset(GPR RT, GPR RA, Offset D) {
final int LBZtemplate = 34 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LBZtemplate | RT.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitLBZX(GPR RT, GPR RA, GPR RB) {
final int LBZXtemplate = 31 << 26 | 87 << 1;
int mi = LBZXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLHA(GPR RT, int D, GPR RA) {
final int LHAtemplate = 42 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LHAtemplate | RT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitLHAoffset(GPR RT, GPR RA, Offset D) {
final int LHAtemplate = 42 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LHAtemplate | RT.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitLHZ(GPR RT, int D, GPR RA) {
final int LHZtemplate = 40 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LHZtemplate | RT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitLHZoffset(GPR RT, GPR RA, Offset D) {
final int LHZtemplate = 40 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LHZtemplate | RT.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitLFD(FPR FRT, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
_emitLFD(FRT, D & 0xFFFF, RA);
}
private void _emitLFD(FPR FRT, int D, GPR RA) {
final int LFDtemplate = 50 << 26;
//D has already been masked
int mi = LFDtemplate | FRT.value() << 21 | RA.value() << 16 | D;
appendInstruction(mi);
}
public void emitLFDoffset(FPR FRT, GPR RA, Offset D) {
final int LFDtemplate = 50 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LFDtemplate | FRT.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitLFDU(FPR FRT, int D, GPR RA) {
final int LFDUtemplate = 51 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = LFDUtemplate | FRT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitLFDX(FPR FRT, GPR RA, GPR RB) {
final int LFDXtemplate = 31 << 26 | 599 << 1;
int mi = LFDXtemplate | FRT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLFS(FPR FRT, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
_emitLFS(FRT, D & 0xFFFF, RA);
}
private void _emitLFS(FPR FRT, int D, GPR RA) {
final int LFStemplate = 48 << 26;
//D has already been masked
int mi = LFStemplate | FRT.value() << 21 | RA.value() << 16 | D;
appendInstruction(mi);
}
public static int LFSX(FPR FRT, GPR RA, GPR RB) {
return 31 << 26 | FRT.value() << 21 | RA.value() << 16 | RB.value() << 11 | 535 << 1;
}
public void emitLFSX(FPR FRT, GPR RA, GPR RB) {
final int LFSXtemplate = 31 << 26 | 535 << 1;
int mi = LFSXtemplate | FRT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLHAX(GPR RT, GPR RA, GPR RB) {
final int LHAXtemplate = 31 << 26 | 343 << 1;
int mi = LHAXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLHZX(GPR RT, GPR RA, GPR RB) {
final int LHZXtemplate = 31 << 26 | 279 << 1;
int mi = LHZXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
private void _emitLI(GPR RT, int D) {
final int ADDItemplate = 14 << 26;
//D has already been masked
int mi = ADDItemplate | RT.value() << 21 | D;
appendInstruction(mi);
}
public void emitLWZU(GPR RT, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
final int LWZUtemplate = 33 << 26;
int mi = LWZUtemplate | RT.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitLWZX(GPR RT, GPR RA, GPR RB) {
final int LWZXtemplate = 31 << 26 | 23 << 1;
int mi = LWZXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLWZUX(GPR RT, GPR RA, GPR RB) {
final int LWZUXtemplate = 31 << 26 | 55 << 1;
int mi = LWZUXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLWARX(GPR RT, GPR RA, GPR RB) {
final int LWARXtemplate = 31 << 26 | 20 << 1;
int mi = LWARXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitMFLR(GPR RT) {
final int MFLRtemplate = 31 << 26 | 0x08 << 16 | 339 << 1;
int mi = MFLRtemplate | RT.value() << 21;
appendInstruction(mi);
}
public void emitMFSPR(GPR RT, int SPR) {
final int MFSPRtemplate = 31 << 26 | 339 << 1;
int mi = MFSPRtemplate | RT.value() << 21 | SPR << 11;
appendInstruction(mi);
}
public void emitMTSPR(GPR RT, int SPR) {
final int MFSPRtemplate = 31 << 26 | 467 << 1;
int mi = MFSPRtemplate | RT.value() << 21 | SPR << 11;
appendInstruction(mi);
}
public void emitMTLR(GPR RS) {
final int MTLRtemplate = 31 << 26 | 0x08 << 16 | 467 << 1;
int mi = MTLRtemplate | RS.value() << 21;
appendInstruction(mi);
}
public void emitMTCTR(GPR RS) {
final int MTCTRtemplate = 31 << 26 | 0x09 << 16 | 467 << 1;
int mi = MTCTRtemplate | RS.value() << 21;
appendInstruction(mi);
}
public void emitFMR(FPR RA, FPR RB) {
final int FMRtemplate = 63 << 26 | 72 << 1;
int mi = FMRtemplate | RA.value() << 21 | RB.value() << 11;
appendInstruction(mi);
}
public void emitFRSP(FPR RT, FPR RB) {
final int FRSPtemplate = 63 << 26 | 12 << 1;
int mi = FRSPtemplate | RT.value() << 21 | RB.value() << 11;
appendInstruction(mi);
}
public void emitMULHWU(GPR RT, GPR RA, GPR RB) {
final int MULHWUtemplate = 31 << 26 | 11 << 1;
int mi = MULHWUtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitDIVW(GPR RT, GPR RA, GPR RB) {
final int DIVWtemplate = 31 << 26 | 491 << 1;
int mi = DIVWtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitMULLW(GPR RT, GPR RA, GPR RB) {
final int MULLWtemplate = 31 << 26 | 235 << 1;
int mi = MULLWtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitNEG(GPR RT, GPR RA) {
final int NEGtemplate = 31 << 26 | 104 << 1;
int mi = NEGtemplate | RT.value() << 21 | RA.value() << 16;
appendInstruction(mi);
}
public void emitOR(GPR RA, GPR RS, GPR RB) {
final int ORtemplate = 31 << 26 | 444 << 1;
int mi = ORtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
// move register RT <- RS
public void emitMR(GPR RT, GPR RS) {
emitOR(RT, RS, RS);
}
public void emitORI(GPR RA, GPR RS, int UI) {
if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
final int ORItemplate = 24 << 26;
int mi = ORItemplate | RS.value() << 21 | RA.value() << 16 | (UI & 0xFFFF);
appendInstruction(mi);
}
public void emitORIS(GPR RA, GPR RS, int UI) {
if (VM.VerifyAssertions) VM._assert(UI == (UI & 0xFFFF));
final int ORIStemplate = 25 << 26;
int mi = ORIStemplate | RS.value() << 21 | RA.value() << 16 | (UI & 0xFFFF);
appendInstruction(mi);
}
public void emitRLWINM(GPR RA, GPR RS, int SH, int MB, int ME) {
final int RLWINM_template = 21 << 26;
int mi = RLWINM_template | RS.value() << 21 | RA.value() << 16 | SH << 11 | MB << 6 | ME << 1;
appendInstruction(mi);
}
public void emitSUBFCr(GPR RT, GPR RA, GPR RB) {
final int SUBFCrtemplate = 31 << 26 | 8 << 1 | 1;
int mi = SUBFCrtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSUBFC(GPR RT, GPR RA, GPR RB) {
final int SUBFCtemplate = 31 << 26 | 8 << 1;
int mi = SUBFCtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSUBFIC(GPR RA, GPR RS, int S) {
final int SUBFICtemplate = 8 << 26;
if (VM.VerifyAssertions) VM._assert(fits(S, 16));
int mi = SUBFICtemplate | RS.value() << 21 | RA.value() << 16 | S;
appendInstruction(mi);
}
public void emitSUBFEr(GPR RT, GPR RA, GPR RB) {
final int SUBFErtemplate = 31 << 26 | 136 << 1 | 1;
int mi = SUBFErtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSUBFE(GPR RT, GPR RA, GPR RB) {
final int SUBFEtemplate = 31 << 26 | 136 << 1;
int mi = SUBFEtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSUBFZE(GPR RT, GPR RA) {
final int SUBFZEtemplate = 31 << 26 | 200 << 1;
int mi = SUBFZEtemplate | RT.value() << 21 | RA.value() << 16;
appendInstruction(mi);
}
public void emitSLW(GPR RA, GPR RS, GPR RB) {
final int SLWtemplate = 31 << 26 | 24 << 1;
int mi = SLWtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSLWI(GPR RA, GPR RS, int N) {
final int SLWItemplate = 21 << 26;
int mi = SLWItemplate | RS.value() << 21 | RA.value() << 16 | N << 11 | (31 - N) << 1;
appendInstruction(mi);
}
public void emitSRW(GPR RA, GPR RS, GPR RB) {
final int SRWtemplate = 31 << 26 | 536 << 1;
int mi = SRWtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSRAW(GPR RA, GPR RS, GPR RB) {
final int SRAWtemplate = 31 << 26 | 792 << 1;
int mi = SRAWtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSRAWI(GPR RA, GPR RS, int SH) {
final int SRAWItemplate = 31 << 26 | 824 << 1;
int mi = SRAWItemplate | RS.value() << 21 | RA.value() << 16 | SH << 11;
appendInstruction(mi);
}
public void emitSRAWIr(GPR RA, GPR RS, int SH) {
final int SRAWIrtemplate = 31 << 26 | 824 << 1 | 1;
int mi = SRAWIrtemplate | RS.value() << 21 | RA.value() << 16 | SH << 11;
appendInstruction(mi);
}
public void emitSTW(GPR RS, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
_emitSTW(RS, D & 0xFFFF, RA);
}
private void _emitSTW(GPR RS, int D, GPR RA) {
final int STWtemplate = 36 << 26;
//D has already been masked
int mi = STWtemplate | RS.value() << 21 | RA.value() << 16 | D;
appendInstruction(mi);
}
public void emitSTWoffset(GPR RS, GPR RA, Offset D) {
final int STWtemplate = 36 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STWtemplate | RS.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitSTB(GPR RS, int D, GPR RA) {
final int STBtemplate = 38 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STBtemplate | RS.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitSTBoffset(GPR RS, GPR RA, Offset D) {
final int STBtemplate = 38 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STBtemplate | RS.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitSTH(GPR RS, int D, GPR RA) {
final int STHtemplate = 44 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STHtemplate | RS.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitSTHoffset(GPR RS, GPR RA, Offset D) {
final int STHtemplate = 44 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STHtemplate | RS.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitSTBX(GPR RS, GPR RA, GPR RB) {
final int STBXtemplate = 31 << 26 | 215 << 1;
int mi = STBXtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTHX(GPR RS, GPR RA, GPR RB) {
final int STHXtemplate = 31 << 26 | 407 << 1;
int mi = STHXtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTWX(GPR RS, GPR RA, GPR RB) {
final int STWXtemplate = 31 << 26 | 151 << 1;
int mi = STWXtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTFSX(FPR FRS, GPR RA, GPR RB) {
final int STFSXtemplate = 31 << 26 | 663 << 1;
int mi = STFSXtemplate | FRS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTFD(FPR FRS, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
_emitSTFD(FRS, D & 0xFFFF, RA);
}
private void _emitSTFD(FPR FRS, int D, GPR RA) {
final int STFDtemplate = 54 << 26;
//D has already been masked
int mi = STFDtemplate | FRS.value() << 21 | RA.value() << 16 | D;
appendInstruction(mi);
}
public void emitSTFDoffset(FPR FRS, GPR RA, Offset D) {
final int STFDtemplate = 54 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STFDtemplate | FRS.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitSTFDU(FPR FRS, int D, GPR RA) {
final int STFDUtemplate = 55 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STFDUtemplate | FRS.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitSTFDX(FPR FRS, GPR RA, GPR RB) {
final int STFDXtemplate = 31 << 26 | 727 << 1;
int mi = STFDXtemplate | FRS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTFS(FPR FRS, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
_emitSTFS(FRS, D & 0xFFFF, RA);
}
private void _emitSTFS(FPR FRS, int D, GPR RA) {
final int STFStemplate = 52 << 26;
//D has already been masked
int mi = STFStemplate | FRS.value() << 21 | RA.value() << 16 | D;
appendInstruction(mi);
}
public void emitSTFSoffset(FPR FRS, GPR RA, Offset D) {
final int STFStemplate = 52 << 26;
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
int mi = STFStemplate | FRS.value() << 21 | RA.value() << 16 | maskLower16(D);
appendInstruction(mi);
}
public void emitSTFSU(FPR FRS, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
final int STFSUtemplate = 53 << 26;
int mi = STFSUtemplate | FRS.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitSTWU(GPR RS, int D, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(D, 16));
final int STWUtemplate = 37 << 26;
int mi = STWUtemplate | RS.value() << 21 | RA.value() << 16 | (D & 0xFFFF);
appendInstruction(mi);
}
public void emitSTWUX(GPR RS, GPR RA, GPR RB) {
final int STWUXtemplate = 31 << 26 | 183 << 1;
int mi = STWUXtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTWCXr(GPR RS, GPR RA, GPR RB) {
final int STWCXrtemplate = 31 << 26 | 150 << 1 | 1;
int mi = STWCXrtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTWLE(GPR RA, GPR RB) {
final int TWtemplate = 31 << 26 | 4 << 1;
final int TWLEtemplate = TWtemplate | 0x14 << 21;
int mi = TWLEtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTWLT(GPR RA, GPR RB) {
final int TWtemplate = 31 << 26 | 4 << 1;
final int TWLTtemplate = TWtemplate | 0x10 << 21;
int mi = TWLTtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTWNE(GPR RA, GPR RB) {
final int TWtemplate = 31 << 26 | 4 << 1;
final int TWNEtemplate = TWtemplate | 0x18 << 21;
int mi = TWNEtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTWLLE(GPR RA, GPR RB) {
final int TWtemplate = 31 << 26 | 4 << 1;
final int TWLLEtemplate = TWtemplate | 0x6 << 21;
int mi = TWLLEtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTWI(int TO, GPR RA, int SI) {
final int TWItemplate = 3 << 26;
int mi = TWItemplate | TO << 21 | RA.value() << 16 | SI & 0xFFFF;
appendInstruction(mi);
}
public void emitTWEQ0(GPR RA) {
final int TWItemplate = 3 << 26;
final int TWEQItemplate = TWItemplate | 0x4 << 21;
int mi = TWEQItemplate | RA.value() << 16;
appendInstruction(mi);
}
public void emitTWWI(int imm) {
final int TWItemplate = 3 << 26;
final int TWWItemplate = TWItemplate | 0x3EC << 16; // RA == 12
int mi = TWWItemplate | imm;
appendInstruction(mi);
}
public void emitXOR(GPR RA, GPR RS, GPR RB) {
final int XORtemplate = 31 << 26 | 316 << 1;
int mi = XORtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitXORI(GPR RA, GPR RS, int V) {
final int XORItemplate = 26 << 26;
if (VM.VerifyAssertions) VM._assert(fits(V, 16));
int mi = XORItemplate | RS.value() << 21 | RA.value() << 16 | V & 0xFFFF;
appendInstruction(mi);
}
public void emitXORIS(GPR RA, GPR RS, int V) {
final int XORIStemplate = 27 << 26;
if (VM.VerifyAssertions) VM._assert(fits(V, 16));
int mi = XORIStemplate | RS.value() << 21 | RA.value() << 16 | V & 0xFFFF;
appendInstruction(mi);
}
/* macro instructions */
/**
* Emits a no-op.
* <p>
* In terms of the Power ISA, this is an optimized no-op
* that consumes minimal processor resources (in contrast
* to the executed form of a no-op which is designed to
* consume as much resources as a real instruction).
*/
public void emitNOP() {
int mi = 24 << 26; //ORI 0,0,0
appendInstruction(mi);
}
//private: use emitLIntOffset or emitLAddrOffset instead
private void emitLDoffset(GPR RT, GPR 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(GPR RT, GPR 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(GPR RT, GPR 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 void emitSTDtoc(GPR RT, Offset offset, GPR 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 void emitSTWtoc(GPR RT, Offset offset, GPR 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 void emitLFDtoc(FPR FRT, Offset offset, GPR 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 void emitSTFDtoc(FPR FRT, Offset offset, GPR 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 void emitLFStoc(FPR FRT, Offset offset, GPR 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 void emitSTFStoc(FPR FRT, Offset offset, GPR 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 void emitLVALAddr(GPR RT, Offset off) {
emitLVALAddr(RT, off.toWord().toAddress());
}
public void emitLVALAddr(GPR 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 void emitLVAL(GPR RT, int val) {
if (fits(val, 16)) {
_emitLI(RT, val & 0xFFFF);
} else {
_emitADDIS(RT, val >>> 16);
emitORI(RT, RT, val & 0xFFFF);
}
}
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(machineCodes[i], false));
VM.sysWrite(" ");
VM.sysWrite(Disassembler.disasm(machineCodes[i], i << LG_INSTRUCTION_WIDTH));
VM.sysWriteln();
}
}
/**
* Append a CodeArray to the current machine code
*/
public void appendInstructions(CodeArray instructionSegment) {
for (int i = 0; i < instructionSegment.length(); i++) {
appendInstruction(instructionSegment.get(i));
}
}
// new PowerPC instructions
/**
* Emits an LWSYNC. The "sync" on Power 4 architectures are expensive
* and so we use "lwsync" instead to implement SYNC. On older architectures,
* there is no problem because lwsync will get mapped to (hw)sync.
* On newer architectures, the weaker semantics of lwsync means that there
* are memory consistency bugs we might need to flush out.
*/
public void emitSYNC() {
final int LWSYNCtemplate = 31 << 26 | 1 << 21 | 598 << 1;
int mi = LWSYNCtemplate;
appendInstruction(mi);
}
public void emitHWSYNC() {
final int HWSYNCtemplate = 31 << 26 | 598 << 1;
int mi = HWSYNCtemplate;
appendInstruction(mi);
}
public void emitICBI(GPR RA, GPR RB) {
final int ICBItemplate = 31 << 26 | 982 << 1;
int mi = ICBItemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitISYNC() {
final int ISYNCtemplate = 19 << 26 | 150 << 1;
int mi = ISYNCtemplate;
appendInstruction(mi);
}
public void emitDCBF(GPR RA, GPR RB) {
final int DCBFtemplate = 31 << 26 | 86 << 1;
int mi = DCBFtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitDCBST(GPR RA, GPR RB) {
final int DCBSTtemplate = 31 << 26 | 54 << 1;
int mi = DCBSTtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitDCBT(GPR RA, GPR RB) {
final int DCBTtemplate = 31 << 26 | 278 << 1;
int mi = DCBTtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitDCBTST(GPR RA, GPR RB) {
final int DCBTSTtemplate = 31 << 26 | 246 << 1;
int mi = DCBTSTtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitDCBZ(GPR RA, GPR RB) {
final int DCBZtemplate = 31 << 26 | 1014 << 1;
int mi = DCBZtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitDCBZL(GPR RA, GPR RB) {
final int DCBZLtemplate = 31 << 26 | 1 << 21 | 1014 << 1;
int mi = DCBZLtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitMFTB(GPR RT) {
final int MFTBtemplate = 31 << 26 | 392 << 11 | 371 << 1;
int mi = MFTBtemplate | RT.value() << 21;
appendInstruction(mi);
}
public void emitMFTBU(GPR RT) {
final int MFTBUtemplate = 31 << 26 | 424 << 11 | 371 << 1;
int mi = MFTBUtemplate | RT.value() << 21;
appendInstruction(mi);
}
public void emitFCTIWZ(FPR FRT, FPR FRB) {
final int FCTIWZtemplate = 63 << 26 | 15 << 1;
int mi = FCTIWZtemplate | FRT.value() << 21 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitEXTSB(GPR RA, GPR RS) {
final int EXTSBtemplate = 31 << 26 | 954 << 1;
int mi = EXTSBtemplate | RS.value() << 21 | RA.value() << 16;
appendInstruction(mi);
}
// PowerPC 64-bit instructions
public void emitDIVD(GPR RT, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int DIVDtemplate = 31 << 26 | 489 << 1;
int mi = DIVDtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitEXTSW(GPR RA, GPR RS) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int EXTSWtemplate = 31 << 26 | 986 << 1;
int mi = EXTSWtemplate | RS.value() << 21 | RA.value() << 16;
appendInstruction(mi);
}
public void emitFCTIDZ(FPR FRT, FPR FRB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int FCTIDZtemplate = 63 << 26 | 815 << 1;
int mi = FCTIDZtemplate | FRT.value() << 21 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitFCFID(FPR FRT, FPR FRB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int FCFIDtemplate = 63 << 26 | 846 << 1;
int mi = FCFIDtemplate | FRT.value() << 21 | FRB.value() << 11;
appendInstruction(mi);
}
public void emitLD(GPR RT, int DS, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
_emitLD(RT, DS, RA);
}
private void _emitLD(GPR RT, int DS, GPR RA) {
//DS is already checked to fit 16 bits
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int LDtemplate = 58 << 26;
int mi = LDtemplate | RT.value() << 21 | RA.value() << 16 | (DS & 0xFFFC);
appendInstruction(mi);
}
public void emitLDARX(GPR RT, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int LDARXtemplate = 31 << 26 | 84 << 1;
int mi = LDARXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLDU(GPR RT, int DS, GPR RA) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
final int LDUtemplate = 58 << 26 | 1;
int mi = LDUtemplate | RT.value() << 21 | RA.value() << 16 | (DS & 0xFFFC);
appendInstruction(mi);
}
public void emitLDUX(GPR RT, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int LDUXtemplate = 31 << 26 | 53 << 1;
int mi = LDUXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLDX(GPR RT, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int LDXtemplate = 31 << 26 | 21 << 1;
int mi = LDXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitLWA(GPR RT, int DS, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
_emitLWA(RT, DS, RA);
}
private void _emitLWA(GPR RT, int DS, GPR RA) {
//DS is already checked to fit 16 bits
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int LWAtemplate = 58 << 26 | 2;
int mi = LWAtemplate | RT.value() << 21 | RA.value() << 16 | (DS & 0xFFFC);
appendInstruction(mi);
}
public void emitLWAX(GPR RT, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int LWAXtemplate = 31 << 26 | 341 << 1;
int mi = LWAXtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitMULHDU(GPR RT, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int MULHDUtemplate = 31 << 26 | 9 << 1;
int mi = MULHDUtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitMULLD(GPR RT, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int MULLDtemplate = 31 << 26 | 233 << 1;
int mi = MULLDtemplate | RT.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSLDI(GPR RA, GPR RS, int N) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int SLDItemplate = 30 << 26 | 1 << 2;
int mi =
SLDItemplate |
RS.value() << 21 |
RA.value() << 16 |
(N & 0x1F) << 11 |
((63 - N) & 0x1F) << 6 |
((63 - N) & 0x20) |
(N & 0x20) >> 4;
appendInstruction(mi);
}
public void emitRLDINM(GPR RA, GPR RS, int SH, int MB, int ME) {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED, "PLEASE IMPLEMENT ME");
}
public void emitSLD(GPR RA, GPR RS, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int SLDtemplate = 31 << 26 | 27 << 1;
int mi = SLDtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSRAD(GPR RA, GPR RS, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int SRADtemplate = 31 << 26 | 794 << 1;
int mi = SRADtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSRADI(GPR RA, GPR RS, int SH) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int SRADItemplate = 31 << 26 | 413 << 2;
int mi = SRADItemplate | RS.value() << 21 | RA.value() << 16 | (SH & 0x1F) << 11 | (SH & 0x20) >> 4;
appendInstruction(mi);
}
public void emitSRADIr(GPR RA, GPR RS, int SH) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int SRADItemplate = 31 << 26 | 413 << 2;
final int SRADIrtemplate = SRADItemplate | 1;
int mi = SRADIrtemplate | RS.value() << 21 | RA.value() << 16 | (SH & 0x1F) << 11 | (SH & 0x20) >> 4;
appendInstruction(mi);
}
public void emitSRD(GPR RA, GPR RS, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int SRDtemplate = 31 << 26 | 539 << 1;
int mi = SRDtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTD(GPR RS, int DS, GPR RA) {
if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
_emitSTD(RS, DS, RA);
}
private void _emitSTD(GPR RS, int DS, GPR RA) {
//DS is already checked to fit 16 bits
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int STDtemplate = 62 << 26;
int mi = STDtemplate | RS.value() << 21 | RA.value() << 16 | (DS & 0xFFFC);
appendInstruction(mi);
}
//private: use emitSTWOffset or emitSTAddrOffset instead
private void emitSTDoffset(GPR RS, GPR RA, Offset Dis) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
if (VM.VerifyAssertions) VM._assert(fits(Dis, 16));
final int STDtemplate = 62 << 26;
int DS = maskLower16(Dis);
int mi = STDtemplate | RS.value() << 21 | RA.value() << 16 | (DS & 0xFFFC);
appendInstruction(mi);
}
public void emitSTDCXr(GPR RS, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int STDCXrtemplate = 31 << 26 | 214 << 1 | 1;
int mi = STDCXrtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTDU(GPR RS, int DS, GPR RA) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
if (VM.VerifyAssertions) VM._assert(fits(DS, 16));
final int STDUtemplate = 62 << 26 | 1;
int mi = STDUtemplate | RS.value() << 21 | RA.value() << 16 | (DS & 0xFFFC);
appendInstruction(mi);
}
public void emitSTDUX(GPR RS, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int STDUXtemplate = 31 << 26 | 181 << 1;
int mi = STDUXtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitSTDX(GPR RS, GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int STDXtemplate = 31 << 26 | 149 << 1;
int mi = STDXtemplate | RS.value() << 21 | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTDLE(GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int TDtemplate = 31 << 26 | 68 << 1;
final int TDLEtemplate = TDtemplate | 0x14 << 21;
int mi = TDLEtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTDLT(GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int TDtemplate = 31 << 26 | 68 << 1;
final int TDLTtemplate = TDtemplate | 0x10 << 21;
int mi = TDLTtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTDLLE(GPR RA, GPR RB) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int TDtemplate = 31 << 26 | 68 << 1;
final int TDLLEtemplate = TDtemplate | 0x6 << 21;
int mi = TDLLEtemplate | RA.value() << 16 | RB.value() << 11;
appendInstruction(mi);
}
public void emitTDI(int TO, GPR RA, int SI) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int TDItemplate = 2 << 26;
int mi = TDItemplate | TO << 21 | RA.value() << 16 | SI & 0xFFFF;
appendInstruction(mi);
}
public void emitTDEQ0(GPR RA) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int TDItemplate = 2 << 26;
final int TDEQItemplate = TDItemplate | 0x4 << 21;
int mi = TDEQItemplate | RA.value() << 16;
appendInstruction(mi);
}
public void emitTDWI(int SI) {
if (!VM.BuildFor64Addr && VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
final int TDItemplate = 2 << 26;
final int TDWItemplate = TDItemplate | 0x1F << 21 | 0xC << 16;
int mi = TDWItemplate | SI & 0xFFFF;
appendInstruction(mi);
}
// -------------------------------------------------------------- //
// The following section contains macros to handle address values //
// -------------------------------------------------------------- //
public void emitCMPLAddr(GPR reg1, GPR reg2) {
if (VM.BuildFor64Addr) {
emitCMPLD(reg1, reg2);
} else {
emitCMPL(reg1, reg2);
}
}
public void emitCMPAddr(GPR reg1, GPR reg2) {
if (VM.BuildFor64Addr) {
emitCMPD(reg1, reg2);
} else {
emitCMP(reg1, reg2);
}
}
public void emitCMPAddrI(GPR RA, int V) {
if (VM.BuildFor64Addr) {
emitCMPDI(RA, V);
} else {
emitCMPI(RA, V);
}
}
public void emitSRAddr(GPR RA, GPR RS, GPR RB) {
if (VM.BuildFor64Addr) {
emitSRD(RA, RS, RB);
} else {
emitSRW(RA, RS, RB);
}
}
public void emitSRA_Addr(GPR RA, GPR RS, GPR RB) {
if (VM.BuildFor64Addr) {
emitSRAD(RA, RS, RB);
} else {
emitSRAW(RA, RS, RB);
}
}
public void emitSRA_AddrI(GPR RA, GPR RS, int SH) {
if (VM.BuildFor64Addr) {
emitSRADI(RA, RS, SH);
} else {
emitSRAWI(RA, RS, SH);
}
}
public void emitSLAddr(GPR RA, GPR RS, GPR RB) {
if (VM.BuildFor64Addr) {
emitSLD(RA, RS, RB);
} else {
emitSLW(RA, RS, RB);
}
}
public void emitSLAddrI(GPR RA, GPR RS, int N) {
if (VM.BuildFor64Addr) {
emitSLDI(RA, RS, N);
} else {
emitSLWI(RA, RS, N);
}
}
public void emitTAddrLT(GPR RA, GPR RB) {
if (VM.BuildFor64Addr) {
emitTDLT(RA, RB);
} else {
emitTWLT(RA, RB);
}
}
public void emitTAddrLE(GPR RA, GPR RB) {
if (VM.BuildFor64Addr) {
emitTDLE(RA, RB);
} else {
emitTWLE(RA, RB);
}
}
public void emitTAddrLLE(GPR RA, GPR RB) {
if (VM.BuildFor64Addr) {
emitTDLLE(RA, RB);
} else {
emitTWLLE(RA, RB);
}
}
public void emitTAddrI(int TO, GPR RA, int SI) {
if (VM.BuildFor64Addr) {
emitTDI(TO, RA, SI);
} else {
emitTWI(TO, RA, SI);
}
}
public void emitTAddrEQ0(GPR RA) {
if (VM.BuildFor64Addr) {
emitTDEQ0(RA);
} else {
emitTWEQ0(RA);
}
}
public void emitTAddrWI(int SI) {
if (VM.BuildFor64Addr) {
emitTDWI(SI);
} else {
emitTWWI(SI);
}
}
public void emitSTAddr(GPR src_reg, int offset, GPR dest_reg) {
if (VM.BuildFor64Addr) {
emitSTD(src_reg, offset, dest_reg);
} else {
emitSTW(src_reg, offset, dest_reg);
}
}
public void emitSTAddrOffset(GPR src_reg, GPR dest_reg, Offset offset) {
if (VM.BuildFor64Addr) {
emitSTDoffset(src_reg, dest_reg, offset);
} else {
emitSTWoffset(src_reg, dest_reg, offset);
}
}
public void emitSTAddrX(GPR src_reg, GPR offset_reg, GPR dest_reg) {
if (VM.BuildFor64Addr) {
emitSTDX(src_reg, offset_reg, dest_reg);
} else {
emitSTWX(src_reg, offset_reg, dest_reg);
}
}
public void emitSTAddrU(GPR src_reg, int offset, GPR dest_reg) {
if (VM.BuildFor64Addr) {
emitSTDU(src_reg, offset, dest_reg);
} else {
emitSTWU(src_reg, offset, dest_reg);
}
}
public void emitLAddr(GPR dest_reg, int offset, GPR src_reg) {
if (VM.BuildFor64Addr) {
emitLD(dest_reg, offset, src_reg);
} else {
emitLWZ(dest_reg, offset, src_reg);
}
}
public void emitLAddrX(GPR dest_reg, GPR offset_reg, GPR src_reg) {
if (VM.BuildFor64Addr) {
emitLDX(dest_reg, offset_reg, src_reg);
} else {
emitLWZX(dest_reg, offset_reg, src_reg);
}
}
public void emitLAddrU(GPR dest_reg, int offset, GPR src_reg) {
if (VM.BuildFor64Addr) {
emitLDU(dest_reg, offset, src_reg);
} else {
emitLWZU(dest_reg, offset, src_reg);
}
}
public void emitLAddrToc(GPR dest_reg, Offset TOCoffset) {
if (VM.BuildFor64Addr) {
emitLDoffset(dest_reg, JTOC, TOCoffset);
} else {
emitLWZoffset(dest_reg, JTOC, TOCoffset);
}
}
void emitRLAddrINM(GPR RA, GPR RS, int SH, int MB, int ME) {
if (VM.BuildFor64Addr) {
emitRLDINM(RA, RS, SH, MB, ME);
} else {
emitRLWINM(RA, RS, SH, MB, ME);
}
}
public void emitLInt(GPR dest_reg, int offset, GPR src_reg) {
if (VM.BuildFor64Addr) {
emitLWA(dest_reg, offset, src_reg);
} else {
emitLWZ(dest_reg, offset, src_reg);
}
}
public void emitLIntX(GPR dest_reg, GPR offset_reg, GPR src_reg) {
if (VM.BuildFor64Addr) {
emitLWAX(dest_reg, offset_reg, src_reg);
} else {
emitLWZX(dest_reg, offset_reg, src_reg);
}
}
public void emitLIntToc(GPR dest_reg, Offset TOCoffset) {
if (VM.BuildFor64Addr) {
emitLWAoffset(dest_reg, JTOC, TOCoffset);
} else {
emitLWZoffset(dest_reg, JTOC, TOCoffset);
}
}
public void emitLIntOffset(GPR RT, GPR RA, Offset offset) {
if (VM.BuildFor64Addr) {
emitLWAoffset(RT, RA, offset);
} else {
emitLWZoffset(RT, RA, offset);
}
}
public void emitLAddrOffset(GPR RT, GPR RA, Offset offset) {
if (VM.BuildFor64Addr) {
emitLDoffset(RT, RA, offset);
} else {
emitLWZoffset(RT, RA, offset);
}
}
/**
* Emits an illegal instruction.
* <p>
* The only instruction that is guaranteed to be illegal in all
* future versions of the PowerISA consists entirely of zeros.
* It currently doesn't have a name.
*/
public void emitIllegalInstruction() {
final int mi = 0;
appendInstruction(mi);
}
// -----------------------------------------------------------//
// The following section contains assembler "macros" used by: //
// BaselineCompilerImpl //
// Barriers //
// -----------------------------------------------------------//
// Emit baseline stack overflow instruction sequence.
// Before: FP is current (calling) frame
// TR is the current RVMThread
// After: R0, S0 destroyed
//
public void emitStackOverflowCheck(int frameSize) {
emitLAddrOffset(GPR.R0,
THREAD_REGISTER,
Entrypoints.stackLimitField.getOffset()); // R0 := &stack guard page
emitADDI(S0, -frameSize, FP); // S0 := &new frame
emitTAddrLT(S0, GPR.R0); // 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(GPR RA) {
// TDLLT 1 or TWLLT 1
final int TDItemplate = 2 << 26;
final int TWItemplate = 3 << 26;
int mi = (VM.BuildFor64Addr ? TDItemplate : TWItemplate) | 0x2 << 21 | RA.value() << 16 | 1;
appendInstruction(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
* <pre>
* Before: FP is current (calling) frame
* TR is the current RVMThread
* After: R0, S0 destroyed
* </pre>
*
* @param frameSize the frame's size
*/
public void emitNativeStackOverflowCheck(int frameSize) {
emitLAddrOffset(S0,
THREAD_REGISTER,
Entrypoints.jniEnvField.getOffset()); // S0 := thread.jniEnv
emitLIntOffset(GPR.R0, S0, Entrypoints.JNIRefsTopField.getOffset()); // R0 := thread.jniEnv.JNIRefsTop
emitCMPI(GPR.R0, 0); // check if S0 == 0 -> first native frame on stack
ForwardReference fr1 = emitForwardBC(EQ);
// check for enough space for requested frame size
emitLAddrOffset(GPR.R0,
THREAD_REGISTER,
Entrypoints.stackLimitField.getOffset()); // R0 := &stack guard page
emitADDI(S0, -frameSize, FP); // S0 := &new frame pointer
emitTAddrLT(S0, GPR.R0); // trap if new frame below guard page
ForwardReference fr2 = emitForwardB();
// check for enough space for STACK_SIZE_JNINATIVE
fr1.resolve(this);
emitLAddrOffset(GPR.R0,
THREAD_REGISTER,
Entrypoints.stackLimitField.getOffset()); // R0 := &stack guard page
emitLVAL(S0, STACK_SIZE_JNINATIVE);
emitSUBFC(S0, S0, FP); // S0 := &new frame pointer
emitCMPLAddr(GPR.R0, 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 = machineCodes[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);
machineCodes[mcIndex] = instr;
return true;
}
/************************************************************************
* Stub/s added for IA32 compatability
*/
public static void patchCode(CodeArray code, int indexa, int indexb) {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
}
/**
* The following method will emit code that moves a reference to an
* object's TIB into a destination register.
*
* @param dest the number of the destination register
* @param object the number of the register holding the object reference
*/
@Override
public void baselineEmitLoadTIB(MachineRegister dest, MachineRegister object) {
Offset tibOffset = JavaHeader.getTibOffset();
emitLAddrOffset((GPR)dest, (GPR)object, tibOffset);
}
public void noteEndOfBytecodes() {
if (shouldPrint) {
lister.addLinesForCode(machineCodes, getMachineCodeIndex());
lister.endAndPrintListing();
}
}
}