/* * 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(); } } }