aboutsummaryrefslogtreecommitdiff
path: root/vm/compiler/codegen/mips/CodegenFactory.cpp
diff options
context:
space:
mode:
authorRaghu Gandham <raghu@mips.com>2012-05-02 14:27:16 -0700
committerRaghu Gandham <raghu@mips.com>2012-05-02 14:27:16 -0700
commita8b91c52fd8a90b784835dfe1f8898035266c4dd (patch)
tree8a9bb58ee3b78c10cf88a3bac21b7f96d75cd1f7 /vm/compiler/codegen/mips/CodegenFactory.cpp
parenta14639df65cc0aefafcddda5aae8b591204e45f9 (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.cpp349
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);
+ }
+}