diff options
| author | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
|---|---|---|
| committer | Raghu Gandham <raghu@mips.com> | 2012-05-02 14:27:16 -0700 |
| commit | a8b91c52fd8a90b784835dfe1f8898035266c4dd (patch) | |
| tree | 8a9bb58ee3b78c10cf88a3bac21b7f96d75cd1f7 /vm/compiler/codegen/mips/CodegenFactory.cpp | |
| parent | a14639df65cc0aefafcddda5aae8b591204e45f9 (diff) | |
[MIPS] Dalvik fast interpreter support and JIT implementation
Change-Id: I9bb4f6875b7061d3ffaee73f204026cb8ba3ed39
Signed-off-by: Raghu Gandham <raghu@mips.com>
Signed-off-by: Chris Dearman <chris@mips.com>
Signed-off-by: Douglas Leung <douglas@mips.com>
Signed-off-by: Don Padgett <don@mips.com>
Diffstat (limited to 'vm/compiler/codegen/mips/CodegenFactory.cpp')
| -rw-r--r-- | vm/compiler/codegen/mips/CodegenFactory.cpp | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/vm/compiler/codegen/mips/CodegenFactory.cpp b/vm/compiler/codegen/mips/CodegenFactory.cpp new file mode 100644 index 000000000..1b604ec98 --- /dev/null +++ b/vm/compiler/codegen/mips/CodegenFactory.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file contains codegen and support common to all supported + * Mips variants. It is included by: + * + * Codegen-$(TARGET_ARCH_VARIANT).c + * + * which combines this common code with specific support found in the + * applicable directory below this one. + */ + + +/* Load a word at base + displacement. Displacement must be word multiple */ +static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, + int rDest) +{ + return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, + INVALID_SREG); +} + +static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase, + int displacement, int rSrc) +{ + return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord); +} + +/* + * Load a Dalvik register into a physical register. Take care when + * using this routine, as it doesn't perform any bookkeeping regarding + * register liveness. That is the responsibility of the caller. + */ +static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc, + int reg1) +{ + rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc); + if (rlSrc.location == kLocPhysReg) { + genRegCopy(cUnit, reg1, rlSrc.lowReg); + } else if (rlSrc.location == kLocRetval) { + loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1); + } else { + assert(rlSrc.location == kLocDalvikFrame); + loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2, + reg1); + } +} + +/* + * Similar to loadValueDirect, but clobbers and allocates the target + * register. Should be used when loading to a fixed register (for example, + * loading arguments to an out of line call. + */ +static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc, + int reg1) +{ + dvmCompilerClobber(cUnit, reg1); + dvmCompilerMarkInUse(cUnit, reg1); + loadValueDirect(cUnit, rlSrc, reg1); +} + +/* + * Load a Dalvik register pair into a physical register[s]. Take care when + * using this routine, as it doesn't perform any bookkeeping regarding + * register liveness. That is the responsibility of the caller. + */ +static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc, + int regLo, int regHi) +{ + rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc); + if (rlSrc.location == kLocPhysReg) { + genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg); + } else if (rlSrc.location == kLocRetval) { + loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval), + regLo, regHi, INVALID_SREG); + } else { + assert(rlSrc.location == kLocDalvikFrame); + loadBaseDispWide(cUnit, NULL, rFP, + dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2, + regLo, regHi, INVALID_SREG); + } +} + +/* + * Similar to loadValueDirect, but clobbers and allocates the target + * registers. Should be used when loading to a fixed registers (for example, + * loading arguments to an out of line call. + */ +static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc, + int regLo, int regHi) +{ + dvmCompilerClobber(cUnit, regLo); + dvmCompilerClobber(cUnit, regHi); + dvmCompilerMarkInUse(cUnit, regLo); + dvmCompilerMarkInUse(cUnit, regHi); + loadValueDirectWide(cUnit, rlSrc, regLo, regHi); +} + +static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc, + RegisterClass opKind) +{ + rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false); + if (rlSrc.location == kLocDalvikFrame) { + loadValueDirect(cUnit, rlSrc, rlSrc.lowReg); + rlSrc.location = kLocPhysReg; + dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); + } else if (rlSrc.location == kLocRetval) { + loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), rlSrc.lowReg); + rlSrc.location = kLocPhysReg; + dvmCompilerClobber(cUnit, rlSrc.lowReg); + } + return rlSrc; +} + +static void storeValue(CompilationUnit *cUnit, RegLocation rlDest, + RegLocation rlSrc) +{ + LIR *defStart; + LIR *defEnd; + assert(!rlDest.wide); + assert(!rlSrc.wide); + dvmCompilerKillNullCheckedLoc(cUnit, rlDest); + rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc); + rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); + if (rlSrc.location == kLocPhysReg) { + if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) || + (rlDest.location == kLocPhysReg)) { + // Src is live or Dest has assigned reg. + rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); + genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg); + } else { + // Just re-assign the registers. Dest gets Src's regs + rlDest.lowReg = rlSrc.lowReg; + dvmCompilerClobber(cUnit, rlSrc.lowReg); + } + } else { + // Load Src either into promoted Dest or temps allocated for Dest + rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); + loadValueDirect(cUnit, rlSrc, rlDest.lowReg); + } + + // Dest is now live and dirty (until/if we flush it to home location) + dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); + dvmCompilerMarkDirty(cUnit, rlDest.lowReg); + + + if (rlDest.location == kLocRetval) { + storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), + rlDest.lowReg, kWord); + dvmCompilerClobber(cUnit, rlDest.lowReg); + } else { + dvmCompilerResetDefLoc(cUnit, rlDest); + if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) { + defStart = (LIR *)cUnit->lastLIRInsn; + int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow); + storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord); + dvmCompilerMarkClean(cUnit, rlDest.lowReg); + defEnd = (LIR *)cUnit->lastLIRInsn; + dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd); + } + } +} + +static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc, + RegisterClass opKind) +{ + assert(rlSrc.wide); + rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false); + if (rlSrc.location == kLocDalvikFrame) { + loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg); + rlSrc.location = kLocPhysReg; + dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); + dvmCompilerMarkLive(cUnit, rlSrc.highReg, + dvmCompilerSRegHi(rlSrc.sRegLow)); + } else if (rlSrc.location == kLocRetval) { + loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval), + rlSrc.lowReg, rlSrc.highReg, INVALID_SREG); + rlSrc.location = kLocPhysReg; + dvmCompilerClobber(cUnit, rlSrc.lowReg); + dvmCompilerClobber(cUnit, rlSrc.highReg); + } + return rlSrc; +} + +static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest, + RegLocation rlSrc) +{ + LIR *defStart; + LIR *defEnd; + assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg)); + assert(rlDest.wide); + assert(rlSrc.wide); + dvmCompilerKillNullCheckedLoc(cUnit, rlDest); + if (rlSrc.location == kLocPhysReg) { + if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) || + dvmCompilerIsLive(cUnit, rlSrc.highReg) || + (rlDest.location == kLocPhysReg)) { + // Src is live or Dest has assigned reg. + rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); + genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg, + rlSrc.lowReg, rlSrc.highReg); + } else { + // Just re-assign the registers. Dest gets Src's regs + rlDest.lowReg = rlSrc.lowReg; + rlDest.highReg = rlSrc.highReg; + dvmCompilerClobber(cUnit, rlSrc.lowReg); + dvmCompilerClobber(cUnit, rlSrc.highReg); + } + } else { + // Load Src either into promoted Dest or temps allocated for Dest + rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); + loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg, + rlDest.highReg); + } + + // Dest is now live and dirty (until/if we flush it to home location) + dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); + dvmCompilerMarkLive(cUnit, rlDest.highReg, + dvmCompilerSRegHi(rlDest.sRegLow)); + dvmCompilerMarkDirty(cUnit, rlDest.lowReg); + dvmCompilerMarkDirty(cUnit, rlDest.highReg); + dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg); + + + if (rlDest.location == kLocRetval) { + storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval), + rlDest.lowReg, rlDest.highReg); + dvmCompilerClobber(cUnit, rlDest.lowReg); + dvmCompilerClobber(cUnit, rlDest.highReg); + } else { + dvmCompilerResetDefLocWide(cUnit, rlDest); + if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) || + dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) { + defStart = (LIR *)cUnit->lastLIRInsn; + int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow); + assert((vReg+1) == dvmCompilerS2VReg(cUnit, + dvmCompilerSRegHi(rlDest.sRegLow))); + storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg, + rlDest.highReg); + dvmCompilerMarkClean(cUnit, rlDest.lowReg); + dvmCompilerMarkClean(cUnit, rlDest.highReg); + defEnd = (LIR *)cUnit->lastLIRInsn; + dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd); + } + } +} +/* + * Perform null-check on a register. sReg is the ssa register being checked, + * and mReg is the machine register holding the actual value. If internal state + * indicates that sReg has been checked before the check request is ignored. + */ +static MipsLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg, + int dOffset, MipsLIR *pcrLabel) +{ + /* This particular Dalvik register has been null-checked */ + if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) { + return pcrLabel; + } + dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg); + return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel); +} + + + +/* + * Perform a "reg cmp reg" operation and jump to the PCR region if condition + * satisfies. + */ +static MipsLIR *genRegRegCheck(CompilationUnit *cUnit, + MipsConditionCode cond, + int reg1, int reg2, int dOffset, + MipsLIR *pcrLabel) +{ + MipsLIR *res = NULL; + if (cond == kMipsCondGe) { /* signed >= case */ + int tReg = dvmCompilerAllocTemp(cUnit); + res = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2); + MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1); + genCheckCommon(cUnit, dOffset, branch, pcrLabel); + } else if (cond == kMipsCondCs) { /* unsigned >= case */ + int tReg = dvmCompilerAllocTemp(cUnit); + res = newLIR3(cUnit, kMipsSltu, tReg, reg1, reg2); + MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1); + genCheckCommon(cUnit, dOffset, branch, pcrLabel); + } else { + LOGE("Unexpected condition in genRegRegCheck: %d\n", (int) cond); + dvmAbort(); + } + return res; +} + +/* + * Perform zero-check on a register. Similar to genNullCheck but the value being + * checked does not have a corresponding Dalvik register. + */ +static MipsLIR *genZeroCheck(CompilationUnit *cUnit, int mReg, + int dOffset, MipsLIR *pcrLabel) +{ + return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel); +} + +/* Perform bound check on two registers */ +static MipsLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex, + int rBound, int dOffset, MipsLIR *pcrLabel) +{ + return genRegRegCheck(cUnit, kMipsCondCs, rIndex, rBound, dOffset, + pcrLabel); +} + +/* + * Jump to the out-of-line handler to finish executing the + * remaining of more complex instructions. + */ +static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opCode) +{ + /* + * We're jumping from a trace to a template. Using jal is preferable to jalr, + * but we need to ensure source and target addresses allow the use of jal. + * This should almost always be the case, but if source and target are in + * different 256mb regions then use jalr. The test below is very conservative + * since we don't have a source address yet, but this is ok for now given that + * we expect this case to be very rare. The test can be made less conservative + * as needed in the future in coordination with address assignment during + * the assembly process. + */ + dvmCompilerClobberHandlerRegs(cUnit); + int targetAddr = (int) gDvmJit.codeCache + templateEntryOffsets[opCode]; + int maxSourceAddr = (int) gDvmJit.codeCache + gDvmJit.codeCacheSize; + + if ((targetAddr & 0xF0000000) == (maxSourceAddr & 0xF0000000)) { + newLIR1(cUnit, kMipsJal, targetAddr); + } else { + loadConstant(cUnit, r_T9, targetAddr); + newLIR2(cUnit, kMipsJalr, r_RA, r_T9); + } +} |
