ifeq ($(WITH_JIT),true)
LOCAL_SRC_FILES += \
- compiler/codegen/arm/Codegen-$(dvm_arch_variant).c \
+ compiler/codegen/arm/RallocUtil.c \
+ compiler/codegen/arm/$(dvm_arch_variant)/Codegen.c \
compiler/codegen/arm/Assemble.c \
compiler/codegen/arm/ArchUtility.c \
compiler/codegen/arm/LocalOptimizations.c \
#ifndef _DALVIK_VM_COMPILER_UTILITY
#define _DALVIK_VM_COMPILER_UTILITY
+#include "Dalvik.h"
+
/* Each arena page has some overhead, so take a few bytes off 8k */
#define ARENA_DEFAULT_SIZE 8100
}
/* Set the instruction set to use (NOTE: later components may change it) */
- cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
+ cUnit.instructionSet = dvmCompilerInstructionSet();
/* Allocate Registers */
dvmCompilerRegAlloc(&cUnit);
}
/* Set the instruction set to use (NOTE: later components may change it) */
- cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
+ cUnit.instructionSet = dvmCompilerInstructionSet();
dvmCompilerMIR2LIR(&cUnit);
void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit);
/* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */
-JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit);
+JitInstructionSetType dvmCompilerInstructionSet(void);
+
+/*
+ * Implemented in codegen/<target>/<target_variant>/ArchVariant.c
+ * Architecture-specific initializations and checks
+ */
+bool dvmCompilerArchVariantInit(void);
#endif /* _DALVIK_VM_COMPILERCODEGEN_H_ */
#define CHAIN_CELL_OFFSET_TAG 0xcdab
-ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-
#endif /* _DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H */
+++ /dev/null
-/*
- * 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.
- */
-
-#include "Dalvik.h"
-#include "interp/InterpDefs.h"
-#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
-#include "vm/compiler/CompilerInternals.h"
-#include "ArmLIR.h"
-#include "vm/mterp/common/FindInterface.h"
-
-#include "armv5te-vfp/ArchVariant.h"
-
-#include "RallocUtil.c"
-#include "ThumbUtil.c"
-#include "Codegen.c"
-#include "armv5te-vfp/ArchVariant.c"
+++ /dev/null
-/*
- * 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.
- */
-
-#include "Dalvik.h"
-#include "interp/InterpDefs.h"
-#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
-#include "vm/compiler/CompilerInternals.h"
-#include "ArmLIR.h"
-#include "vm/mterp/common/FindInterface.h"
-
-#include "armv5te/ArchVariant.h"
-
-#include "RallocUtil.c"
-#include "ThumbUtil.c"
-#include "Codegen.c"
-#include "armv5te/ArchVariant.c"
+++ /dev/null
-/*
- * 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.
- */
-#include "Dalvik.h"
-#include "interp/InterpDefs.h"
-#include "libdex/OpCode.h"
-#include "dexdump/OpCodeNames.h"
-#include "vm/compiler/CompilerInternals.h"
-#include "ArmLIR.h"
-#include "vm/mterp/common/FindInterface.h"
-
-#include "armv7-a/ArchVariant.h"
-
-#include "RallocUtil.c"
-#include "Thumb2Util.c"
-#include "Codegen.c"
-#include "armv7-a/ArchVariant.c"
* limitations under the License.
*/
-#ifndef _DALVIK_VM_COMPILER_CODEGEN_ARM_CODEGEN_H
-#define _DALVIK_VM_COMPILER_CODEGEN_ARM_CODEGEN_H
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerIR.h"
+
+/*
+ * loadConstant() sometimes needs to add a small imm to a pre-existing constant
+ */
+static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int value);
+static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+ int rSrc2);
+
+/* Forward decalraton the portable versions due to circular dependency */
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2);
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2);
+
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir);
+
+static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir);
+
/*
- * Forward declarations for common routines in Codegen.c used by ISA
- * variant code such as ThumbUtilty.c
+ * Architecture-dependent register allocation routines implemented in
+ * Thumb[2]/Ralloc.c
*/
+extern int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit,
+ bool fpHint, int regClass);
+
+extern int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint,
+ int regClass);
+
+extern ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest,
+ int rSrc);
+
+extern ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad);
-static void setupResourceMasks(ArmLIR *lir);
-static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode);
-static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest);
-static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest, int src1);
-static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest, int src1, int src2);
-static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest, int src1, int src2, int info);
-static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
- unsigned int delta);
-static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace);
-static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
- ArmLIR *branch,
- ArmLIR *pcrLabel);
-static void genBarrier(CompilationUnit *cUnit);
-static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
- RegisterClass opKind);
-static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
- RegisterClass opKind);
-static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
-static void storeValue(CompilationUnit *cUnit, RegLocation rlDst,
- RegLocation rlSrc);
-static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDst,
- RegLocation rlSrc);
-static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
- int reg1);
-static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
- int regLo, int regHi);
-static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
- int regLo, int regHi);
-static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
- int dOffset, ArmLIR *pcrLabel);
-static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
- int displacement, int rDest);
-static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
- int displacement, int rDest);
-static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir, bool fpHint);
-static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
- bool fpHint);
-static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
- int rBound, int dOffset, ArmLIR *pcrLabel);
-static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir);
-static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
- ArmConditionCode cond,
- int reg1, int reg2, int dOffset,
- ArmLIR *pcrLabel);
+extern void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo,
+ int destHi, int srcLo, int srcHi);
-/* Routines which must be supplied by the variant-specific code */
-static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode);
-static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir);
-static bool genInlineCos(CompilationUnit *cUnit, MIR *mir);
-static bool genInlineSin(CompilationUnit *cUnit, MIR *mir);
-static bool handleConversion(CompilationUnit *cUnit, MIR *mir);
-static bool compilerArchVariantInit();
-static bool handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2);
-static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2);
-static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2);
+extern void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, OpSize size);
-#endif /* _DALVIK_VM_COMPILER_CODEGEN_ARM_CODEGEN_H */
+extern void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrcLo,
+ int rSrcHi);
--- /dev/null
+/*
+ * 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
+ * ARM 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.
+ */
+
+#include "compiler/Loop.h"
+
+/* Array holding the entry offset of each template relative to the first one */
+static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
+
+/* Track exercised opcodes */
+static int opcodeCoverage[256];
+
+/*
+ * Mark load/store instructions that access Dalvik registers through rFP +
+ * offset.
+ */
+static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
+{
+ if (isLoad) {
+ lir->useMask |= ENCODE_DALVIK_REG;
+ } else {
+ lir->defMask |= ENCODE_DALVIK_REG;
+ }
+
+ /*
+ * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
+ * access.
+ */
+ lir->aliasInfo = regId;
+ if (DOUBLEREG(lir->operands[0])) {
+ lir->aliasInfo |= 0x80000000;
+ }
+}
+
+/*
+ * Decode the register id and mark the corresponding bit(s).
+ */
+static inline void setupRegMask(u8 *mask, int reg)
+{
+ u8 seed;
+ int shift;
+ int regId = reg & 0x1f;
+
+ /*
+ * Each double register is equal to a pair of single-precision FP registers
+ */
+ seed = DOUBLEREG(reg) ? 3 : 1;
+ /* FP register starts at bit position 16 */
+ shift = FPREG(reg) ? kFPReg0 : 0;
+ /* Expand the double register id into single offset */
+ shift += regId;
+ *mask |= seed << shift;
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+static void setupResourceMasks(ArmLIR *lir)
+{
+ int opCode = lir->opCode;
+ int flags;
+
+ if (opCode <= 0) {
+ lir->useMask = lir->defMask = 0;
+ return;
+ }
+
+ flags = EncodingMap[lir->opCode].flags;
+
+ /* Set up the mask for resources that are updated */
+ if (flags & IS_BRANCH) {
+ lir->defMask |= ENCODE_REG_PC;
+ lir->useMask |= ENCODE_REG_PC;
+ }
+
+ if (flags & REG_DEF0) {
+ setupRegMask(&lir->defMask, lir->operands[0]);
+ }
+
+ if (flags & REG_DEF1) {
+ setupRegMask(&lir->defMask, lir->operands[1]);
+ }
+
+ if (flags & REG_DEF_SP) {
+ lir->defMask |= ENCODE_REG_SP;
+ }
+
+ if (flags & REG_DEF_SP) {
+ lir->defMask |= ENCODE_REG_LR;
+ }
+
+ if (flags & REG_DEF_LIST0) {
+ lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
+ }
+
+ if (flags & REG_DEF_LIST1) {
+ lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
+ }
+
+ if (flags & SETS_CCODES) {
+ lir->defMask |= ENCODE_CCODE;
+ }
+
+ /* Conservatively treat the IT block */
+ if (flags & IS_IT) {
+ lir->defMask = ENCODE_ALL;
+ }
+
+ /* Set up the mask for resources that are used */
+ if (flags & IS_BRANCH) {
+ lir->useMask |= ENCODE_REG_PC;
+ }
+
+ if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (flags & (1 << (kRegUse0 + i))) {
+ setupRegMask(&lir->useMask, lir->operands[i]);
+ }
+ }
+ }
+
+ if (flags & REG_USE_PC) {
+ lir->useMask |= ENCODE_REG_PC;
+ }
+
+ if (flags & REG_USE_SP) {
+ lir->useMask |= ENCODE_REG_SP;
+ }
+
+ if (flags & REG_USE_LIST0) {
+ lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
+ }
+
+ if (flags & REG_USE_LIST1) {
+ lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
+ }
+
+ if (flags & USES_CCODES) {
+ lir->useMask |= ENCODE_CCODE;
+ }
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
+{
+ ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
+ assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
+ insn->opCode = opCode;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
+ int dest)
+{
+ ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
+ assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
+ insn->opCode = opCode;
+ insn->operands[0] = dest;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
+ int dest, int src1)
+{
+ ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
+ assert(isPseudoOpCode(opCode) ||
+ (EncodingMap[opCode].flags & IS_BINARY_OP));
+ insn->opCode = opCode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
+ int dest, int src1, int src2)
+{
+ ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
+ if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
+ LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
+ }
+ assert(isPseudoOpCode(opCode) ||
+ (EncodingMap[opCode].flags & IS_TERTIARY_OP));
+ insn->opCode = opCode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ insn->operands[2] = src2;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
+ int dest, int src1, int src2, int info)
+{
+ ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
+ assert(isPseudoOpCode(opCode) ||
+ (EncodingMap[opCode].flags & IS_QUAD_OP));
+ insn->opCode = opCode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ insn->operands[2] = src2;
+ insn->operands[3] = info;
+ setupResourceMasks(insn);
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+/*
+ * If the next instruction is a move-result or move-result-long,
+ * return the target Dalvik sReg[s] and convert the next to a
+ * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
+ */
+static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
+ bool fpHint)
+{
+ if (mir->next &&
+ ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
+ (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
+ mir->next->dalvikInsn.opCode = OP_NOP;
+ return getDestLoc(cUnit, mir->next, 0);
+ } else {
+ RegLocation res = LOC_DALVIK_RETURN_VAL;
+ res.fp = fpHint;
+ return res;
+ }
+}
+
+/*
+ * Search the existing constants in the literal pool for an exact or close match
+ * within specified delta (greater or equal to 0).
+ */
+static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
+ unsigned int delta)
+{
+ LIR *dataTarget = cUnit->wordList;
+ while (dataTarget) {
+ if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
+ delta)
+ return (ArmLIR *) dataTarget;
+ dataTarget = dataTarget->next;
+ }
+ return NULL;
+}
+
+/*
+ * The following are building blocks to insert constants into the pool or
+ * instruction streams.
+ */
+
+/* Add a 32-bit constant either in the constant pool or mixed with code */
+static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
+{
+ /* Add the constant to the literal pool */
+ if (!inPlace) {
+ ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
+ newValue->operands[0] = value;
+ newValue->generic.next = cUnit->wordList;
+ cUnit->wordList = (LIR *) newValue;
+ return newValue;
+ } else {
+ /* Add the constant in the middle of code stream */
+ newLIR1(cUnit, kArm16BitData, (value & 0xffff));
+ newLIR1(cUnit, kArm16BitData, (value >> 16));
+ }
+ return NULL;
+}
+
+static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
+ bool fpHint)
+{
+ if (mir->next &&
+ (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
+ mir->next->dalvikInsn.opCode = OP_NOP;
+ return getDestLocWide(cUnit, mir->next, 0, 1);
+ } else {
+ RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
+ res.fp = fpHint;
+ return res;
+ }
+}
+
+
+/*
+ * Generate an kArmPseudoBarrier marker to indicate the boundary of special
+ * blocks.
+ */
+static void genBarrier(CompilationUnit *cUnit)
+{
+ ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
+ /* Mark all resources as being clobbered */
+ barrier->defMask = -1;
+}
+
+/* Create the PC reconstruction slot if not already done */
+extern ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
+ ArmLIR *branch,
+ ArmLIR *pcrLabel)
+{
+ /* Set up the place holder to reconstruct this Dalvik PC */
+ if (pcrLabel == NULL) {
+ int dPC = (int) (cUnit->method->insns + dOffset);
+ pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
+ pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = dOffset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
+ }
+ /* Branch to the PC reconstruction code */
+ branch->generic.target = (LIR *) pcrLabel;
+ return pcrLabel;
+}
* applicable directory below this one.
*/
-#include "compiler/Loop.h"
+static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
+ int srcSize, int tgtSize)
+{
+ /*
+ * Don't optimize the register usage since it calls out to template
+ * functions
+ */
+ RegLocation rlSrc;
+ RegLocation rlDest;
+ flushAllRegs(cUnit); /* Send everything to home location */
+ if (srcSize == 1) {
+ rlSrc = getSrcLoc(cUnit, mir, 0);
+ loadValueDirectFixed(cUnit, rlSrc, r0);
+ } else {
+ rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
+ }
+ loadConstant(cUnit, r2, (int)funct);
+ opReg(cUnit, kOpBlx, r2);
+ clobberCallRegs(cUnit);
+ if (tgtSize == 1) {
+ RegLocation rlResult;
+ rlDest = getDestLoc(cUnit, mir, 0);
+ rlResult = getReturnLoc(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+ } else {
+ RegLocation rlResult;
+ rlDest = getDestLocWide(cUnit, mir, 0, 1);
+ rlResult = getReturnLocWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+ }
+ return false;
+}
+
+
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ void* funct;
+
+ /* TODO: use a proper include file to define these */
+ float __aeabi_fadd(float a, float b);
+ float __aeabi_fsub(float a, float b);
+ float __aeabi_fdiv(float a, float b);
+ float __aeabi_fmul(float a, float b);
+ float fmodf(float a, float b);
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ funct = (void*) __aeabi_fadd;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ funct = (void*) __aeabi_fsub;
+ break;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ funct = (void*) __aeabi_fdiv;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ funct = (void*) __aeabi_fmul;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ funct = (void*) fmodf;
+ break;
+ case OP_NEG_FLOAT: {
+ genNegFloat(cUnit, rlDest, rlSrc1);
+ return false;
+ }
+ default:
+ return true;
+ }
+ flushAllRegs(cUnit); /* Send everything to home location */
+ loadValueDirectFixed(cUnit, rlSrc1, r0);
+ loadValueDirectFixed(cUnit, rlSrc2, r1);
+ loadConstant(cUnit, r2, (int)funct);
+ opReg(cUnit, kOpBlx, r2);
+ clobberCallRegs(cUnit);
+ rlResult = getReturnLoc(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ void* funct;
+
+ /* TODO: use a proper include file to define these */
+ double __aeabi_dadd(double a, double b);
+ double __aeabi_dsub(double a, double b);
+ double __aeabi_ddiv(double a, double b);
+ double __aeabi_dmul(double a, double b);
+ double fmod(double a, double b);
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ funct = (void*) __aeabi_dadd;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ funct = (void*) __aeabi_dsub;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ funct = (void*) __aeabi_ddiv;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ funct = (void*) __aeabi_dmul;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ funct = (void*) fmod;
+ break;
+ case OP_NEG_DOUBLE: {
+ genNegDouble(cUnit, rlDest, rlSrc1);
+ return false;
+ }
+ default:
+ return true;
+ }
+ flushAllRegs(cUnit); /* Send everything to home location */
+ loadConstant(cUnit, rlr, (int)funct);
+ loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+ opReg(cUnit, kOpBlx, rlr);
+ clobberCallRegs(cUnit);
+ rlResult = getReturnLocWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
-/* Array holding the entry offset of each template relative to the first one */
-static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
-/* Track exercised opcodes */
-static int opcodeCoverage[256];
+ float __aeabi_i2f( int op1 );
+ int __aeabi_f2iz( float op1 );
+ float __aeabi_d2f( double op1 );
+ double __aeabi_f2d( float op1 );
+ double __aeabi_i2d( int op1 );
+ int __aeabi_d2iz( double op1 );
+ float __aeabi_l2f( long op1 );
+ double __aeabi_l2d( long op1 );
+ s8 dvmJitf2l( float op1 );
+ s8 dvmJitd2l( double op1 );
+
+ switch (opCode) {
+ case OP_INT_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
+ case OP_FLOAT_TO_INT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
+ case OP_DOUBLE_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
+ case OP_FLOAT_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
+ case OP_INT_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
+ case OP_DOUBLE_TO_INT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
+ case OP_FLOAT_TO_LONG:
+ return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
+ case OP_LONG_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
+ case OP_DOUBLE_TO_LONG:
+ return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
+ case OP_LONG_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
+ default:
+ return true;
+ }
+ return false;
+}
#if defined(WITH_SELF_VERIFICATION)
/* Prevent certain opcodes from being jitted */
if (!store1) {
shadowSpace->heapSpaceTail->addr = addr;
shadowSpace->heapSpaceTail->data = data;
- shadowSpace->heapSpaceTail++;
- }
- if (!store2) {
- shadowSpace->heapSpaceTail->addr = addr2;
- shadowSpace->heapSpaceTail->data = data2;
- shadowSpace->heapSpaceTail++;
- }
-}
-
-/* Common wrapper function for all memory operations */
-static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
- void* funct)
-{
- /* push r0 and r7 to give us a foothold */
- newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
-
- /* Let the save handler know where the save record is */
- loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
-
- /* Load the regMap and call the save handler [note: handler pops r0/r7] */
- loadConstant(cUnit, r7, regMap);
- genDispatchToHandler(cUnit, TEMPLATE_SAVE_STATE);
-
- /* Set function pointer, pass rGLUE and branch */
- loadConstant(cUnit, r1, (int) funct);
- newLIR2(cUnit, kThumbMovRR, r0, rGLUE);
- newLIR1(cUnit, kThumbBlxR, r1);
-
- /* Let the recover handler know where coreRegs[0] and restore regs */
- loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace) +
- offsetof(HeapArgSpace, coreRegs));
- genDispatchToHandler(cUnit, TEMPLATE_RESTORE_STATE);
-}
-#endif
-
-/*
- * 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 = updateLoc(cUnit, rlSrc); /* Is our value hiding in a live temp? */
- if (rlSrc.location == kLocPhysReg) {
- genRegCopy(cUnit, reg1, rlSrc.lowReg);
- } else if (rlSrc.location == kLocRetval) {
- loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), reg1);
- } else {
- assert(rlSrc.location == kLocDalvikFrame);
- loadWordDisp(cUnit, rFP, sReg2vReg(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)
-{
- clobberReg(cUnit, reg1);
- markRegInUse(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 = updateLocWide(cUnit, rlSrc);
- if (rlSrc.location == kLocPhysReg) {
- genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
- } else if (rlSrc.location == kLocRetval) {
- loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
- regLo, regHi, false, INVALID_SREG);
- } else {
- assert(rlSrc.location == kLocDalvikFrame);
- loadBaseDispWide(cUnit, NULL, rFP,
- sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
- regLo, regHi, false, 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)
-{
- clobberReg(cUnit, regLo);
- clobberReg(cUnit, regHi);
- markRegInUse(cUnit, regLo);
- markRegInUse(cUnit, regHi);
- loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
-}
-
-static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
- RegisterClass opKind)
-{
- RegisterInfo *pReg;
- rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
- if (rlSrc.location == kLocDalvikFrame) {
- loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
- rlSrc.location = kLocPhysReg;
- markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
- } else if (rlSrc.location == kLocRetval) {
- loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
- rlSrc.location = kLocPhysReg;
- clobberReg(cUnit, rlSrc.lowReg);
- }
- return rlSrc;
-}
-
-static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
- RegisterClass opKind)
-{
- RegisterInfo *pRegLo;
- RegisterInfo *pRegHi;
- assert(rlSrc.wide);
- rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
- if (rlSrc.location == kLocDalvikFrame) {
- loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
- rlSrc.location = kLocPhysReg;
- markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
- markRegLive(cUnit, rlSrc.highReg, hiSReg(rlSrc.sRegLow));
- } else if (rlSrc.location == kLocRetval) {
- loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
- rlSrc.lowReg, rlSrc.highReg, false, INVALID_SREG);
- rlSrc.location = kLocPhysReg;
- clobberReg(cUnit, rlSrc.lowReg);
- clobberReg(cUnit, rlSrc.highReg);
- }
- return rlSrc;
-}
-
-static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc)
-{
- RegisterInfo *pRegLo;
- LIR *defStart;
- LIR *defEnd;
- assert(!rlDest.wide);
- assert(!rlSrc.wide);
- killNullCheckedLocation(cUnit, rlDest);
- rlSrc = updateLoc(cUnit, rlSrc);
- rlDest = updateLoc(cUnit, rlDest);
- if (rlSrc.location == kLocPhysReg) {
- if (isLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) {
- // Src is live or Dest has assigned reg.
- rlDest = evalLoc(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;
- clobberReg(cUnit, rlSrc.lowReg);
- }
- } else {
- // Load Src either into promoted Dest or temps allocated for Dest
- rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
- loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
- }
-
- // Dest is now live and dirty (until/if we flush it to home location)
- markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
- markRegDirty(cUnit, rlDest.lowReg);
-
-
- if (rlDest.location == kLocRetval) {
- storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
- rlDest.lowReg, kWord);
- clobberReg(cUnit, rlDest.lowReg);
- } else {
- resetDefLoc(cUnit, rlDest);
- if (liveOut(cUnit, rlDest.sRegLow)) {
- defStart = (LIR *)cUnit->lastLIRInsn;
- int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
- storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
- markRegClean(cUnit, rlDest.lowReg);
- defEnd = (LIR *)cUnit->lastLIRInsn;
- markDef(cUnit, rlDest, defStart, defEnd);
- }
- }
-}
-
-static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc)
-{
- RegisterInfo *pRegLo;
- RegisterInfo *pRegHi;
- LIR *defStart;
- LIR *defEnd;
- bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
- assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
- assert(rlDest.wide);
- assert(rlSrc.wide);
- killNullCheckedLocation(cUnit, rlDest);
- if (rlSrc.location == kLocPhysReg) {
- if (isLive(cUnit, rlSrc.lowReg) || isLive(cUnit, rlSrc.highReg) ||
- (rlDest.location == kLocPhysReg)) {
- // Src is live or Dest has assigned reg.
- rlDest = evalLoc(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;
- clobberReg(cUnit, rlSrc.lowReg);
- clobberReg(cUnit, rlSrc.highReg);
- }
- } else {
- // Load Src either into promoted Dest or temps allocated for Dest
- rlDest = evalLoc(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)
- markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
- markRegLive(cUnit, rlDest.highReg, hiSReg(rlDest.sRegLow));
- markRegDirty(cUnit, rlDest.lowReg);
- markRegDirty(cUnit, rlDest.highReg);
- markRegPair(cUnit, rlDest.lowReg, rlDest.highReg);
-
-
- if (rlDest.location == kLocRetval) {
- storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval),
- rlDest.lowReg, rlDest.highReg);
- clobberReg(cUnit, rlDest.lowReg);
- clobberReg(cUnit, rlDest.highReg);
- } else {
- resetDefLocWide(cUnit, rlDest);
- if (liveOut(cUnit, rlDest.sRegLow) ||
- liveOut(cUnit, hiSReg(rlDest.sRegLow))) {
- defStart = (LIR *)cUnit->lastLIRInsn;
- int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
- assert((vReg+1) == sReg2vReg(cUnit, hiSReg(rlDest.sRegLow)));
- storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
- rlDest.highReg);
- markRegClean(cUnit, rlDest.lowReg);
- markRegClean(cUnit, rlDest.highReg);
- defEnd = (LIR *)cUnit->lastLIRInsn;
- markDefWide(cUnit, rlDest, defStart, defEnd);
- }
- }
-}
-
-/*
- * Load an immediate value into a fixed or temp register. Target
- * register is clobbered, and marked inUse.
- */
-static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
-{
- if (isTemp(cUnit, rDest)) {
- clobberReg(cUnit, rDest);
- markRegInUse(cUnit, rDest);
- }
- return loadConstantValue(cUnit, rDest, value);
-}
-
-/*
- * Mark load/store instructions that access Dalvik registers through rFP +
- * offset.
- */
-static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
-{
- if (isLoad) {
- lir->useMask |= ENCODE_DALVIK_REG;
- } else {
- lir->defMask |= ENCODE_DALVIK_REG;
- }
-
- /*
- * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
- * access.
- */
- lir->aliasInfo = regId;
- if (DOUBLEREG(lir->operands[0])) {
- lir->aliasInfo |= 0x80000000;
- }
-}
-
-/*
- * Decode the register id and mark the corresponding bit(s).
- */
-static inline void setupRegMask(u8 *mask, int reg)
-{
- u8 seed;
- int shift;
- int regId = reg & 0x1f;
-
- /*
- * Each double register is equal to a pair of single-precision FP registers
- */
- seed = DOUBLEREG(reg) ? 3 : 1;
- /* FP register starts at bit position 16 */
- shift = FPREG(reg) ? kFPReg0 : 0;
- /* Expand the double register id into single offset */
- shift += regId;
- *mask |= seed << shift;
-}
-
-/*
- * Set up the proper fields in the resource mask
- */
-static void setupResourceMasks(ArmLIR *lir)
-{
- int opCode = lir->opCode;
- int flags;
-
- if (opCode <= 0) {
- lir->useMask = lir->defMask = 0;
- return;
- }
-
- flags = EncodingMap[lir->opCode].flags;
-
- /* Set up the mask for resources that are updated */
- if (flags & IS_BRANCH) {
- lir->defMask |= ENCODE_REG_PC;
- lir->useMask |= ENCODE_REG_PC;
- }
-
- if (flags & REG_DEF0) {
- setupRegMask(&lir->defMask, lir->operands[0]);
- }
-
- if (flags & REG_DEF1) {
- setupRegMask(&lir->defMask, lir->operands[1]);
- }
-
- if (flags & REG_DEF_SP) {
- lir->defMask |= ENCODE_REG_SP;
- }
-
- if (flags & REG_DEF_SP) {
- lir->defMask |= ENCODE_REG_LR;
- }
-
- if (flags & REG_DEF_LIST0) {
- lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
- }
-
- if (flags & REG_DEF_LIST1) {
- lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
- }
-
- if (flags & SETS_CCODES) {
- lir->defMask |= ENCODE_CCODE;
- }
-
- /* Conservatively treat the IT block */
- if (flags & IS_IT) {
- lir->defMask = ENCODE_ALL;
- }
-
- /* Set up the mask for resources that are used */
- if (flags & IS_BRANCH) {
- lir->useMask |= ENCODE_REG_PC;
- }
-
- if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
- int i;
-
- for (i = 0; i < 4; i++) {
- if (flags & (1 << (kRegUse0 + i))) {
- setupRegMask(&lir->useMask, lir->operands[i]);
- }
- }
- }
-
- if (flags & REG_USE_PC) {
- lir->useMask |= ENCODE_REG_PC;
- }
-
- if (flags & REG_USE_SP) {
- lir->useMask |= ENCODE_REG_SP;
- }
-
- if (flags & REG_USE_LIST0) {
- lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
- }
-
- if (flags & REG_USE_LIST1) {
- lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
- }
-
- if (flags & USES_CCODES) {
- lir->useMask |= ENCODE_CCODE;
- }
-}
-
-/*
- * The following are building blocks to construct low-level IRs with 0 - 4
- * operands.
- */
-static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
-{
- ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
- assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
- insn->opCode = opCode;
- setupResourceMasks(insn);
- dvmCompilerAppendLIR(cUnit, (LIR *) insn);
- return insn;
-}
-
-static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest)
-{
- ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
- assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
- insn->opCode = opCode;
- insn->operands[0] = dest;
- setupResourceMasks(insn);
- dvmCompilerAppendLIR(cUnit, (LIR *) insn);
- return insn;
-}
-
-static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest, int src1)
-{
- ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
- assert(isPseudoOpCode(opCode) ||
- (EncodingMap[opCode].flags & IS_BINARY_OP));
- insn->opCode = opCode;
- insn->operands[0] = dest;
- insn->operands[1] = src1;
- setupResourceMasks(insn);
- dvmCompilerAppendLIR(cUnit, (LIR *) insn);
- return insn;
-}
-
-static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest, int src1, int src2)
-{
- ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
- if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
- LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
- }
- assert(isPseudoOpCode(opCode) ||
- (EncodingMap[opCode].flags & IS_TERTIARY_OP));
- insn->opCode = opCode;
- insn->operands[0] = dest;
- insn->operands[1] = src1;
- insn->operands[2] = src2;
- setupResourceMasks(insn);
- dvmCompilerAppendLIR(cUnit, (LIR *) insn);
- return insn;
-}
-
-static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
- int dest, int src1, int src2, int info)
-{
- ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
- assert(isPseudoOpCode(opCode) ||
- (EncodingMap[opCode].flags & IS_QUAD_OP));
- insn->opCode = opCode;
- insn->operands[0] = dest;
- insn->operands[1] = src1;
- insn->operands[2] = src2;
- insn->operands[3] = info;
- setupResourceMasks(insn);
- dvmCompilerAppendLIR(cUnit, (LIR *) insn);
- return insn;
-}
-
-/*
- * If the next instruction is a move-result or move-result-long,
- * return the target Dalvik sReg[s] and convert the next to a
- * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
- */
-static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
- bool fpHint)
-{
- if (mir->next &&
- ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
- (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
- mir->next->dalvikInsn.opCode = OP_NOP;
- return getDestLoc(cUnit, mir->next, 0);
- } else {
- RegLocation res = LOC_DALVIK_RETURN_VAL;
- res.fp = fpHint;
- return res;
- }
-}
-
-static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
- bool fpHint)
-{
- if (mir->next &&
- (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
- mir->next->dalvikInsn.opCode = OP_NOP;
- return getDestLocWide(cUnit, mir->next, 0, 1);
- } else {
- RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
- res.fp = fpHint;
- return res;
- }
-}
-
-/*
- * The following are building blocks to insert constants into the pool or
- * instruction streams.
- */
-
-/* Add a 32-bit constant either in the constant pool or mixed with code */
-static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
-{
- /* Add the constant to the literal pool */
- if (!inPlace) {
- ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
- newValue->operands[0] = value;
- newValue->generic.next = cUnit->wordList;
- cUnit->wordList = (LIR *) newValue;
- return newValue;
- } else {
- /* Add the constant in the middle of code stream */
- newLIR1(cUnit, kArm16BitData, (value & 0xffff));
- newLIR1(cUnit, kArm16BitData, (value >> 16));
- }
- return NULL;
-}
-
-/*
- * Search the existing constants in the literal pool for an exact or close match
- * within specified delta (greater or equal to 0).
- */
-static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
- unsigned int delta)
-{
- LIR *dataTarget = cUnit->wordList;
- while (dataTarget) {
- if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
- delta)
- return (ArmLIR *) dataTarget;
- dataTarget = dataTarget->next;
- }
- return NULL;
-}
-
-/* Create the PC reconstruction slot if not already done */
-static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
- ArmLIR *branch,
- ArmLIR *pcrLabel)
-{
- /* Set up the place holder to reconstruct this Dalvik PC */
- if (pcrLabel == NULL) {
- int dPC = (int) (cUnit->method->insns + dOffset);
- pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
- pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
- pcrLabel->operands[0] = dPC;
- pcrLabel->operands[1] = dOffset;
- /* Insert the place holder to the growable list */
- dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
+ shadowSpace->heapSpaceTail++;
+ }
+ if (!store2) {
+ shadowSpace->heapSpaceTail->addr = addr2;
+ shadowSpace->heapSpaceTail->data = data2;
+ shadowSpace->heapSpaceTail++;
}
- /* Branch to the PC reconstruction code */
- branch->generic.target = (LIR *) pcrLabel;
- return pcrLabel;
}
-
-/*
- * Perform a "reg cmp reg" operation and jump to the PCR region if condition
- * satisfies.
- */
-static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
- ArmConditionCode cond,
- int reg1, int reg2, int dOffset,
- ArmLIR *pcrLabel)
+/* Common wrapper function for all memory operations */
+static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
+ void* funct)
{
- ArmLIR *res;
- res = opRegReg(cUnit, kOpCmp, reg1, reg2);
- ArmLIR *branch = opCondBranch(cUnit, cond);
- genCheckCommon(cUnit, dOffset, branch, pcrLabel);
- return res;
-}
+ /* push r0 and r7 to give us a foothold */
+ newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
-/*
- * 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 ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
- int dOffset, ArmLIR *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, kArmCondEq, mReg, 0, dOffset, pcrLabel);
-}
+ /* Let the save handler know where the save record is */
+ loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
-/*
- * Perform zero-check on a register. Similar to genNullCheck but the value being
- * checked does not have a corresponding Dalvik register.
- */
-static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
- int dOffset, ArmLIR *pcrLabel)
-{
- return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
-}
+ /* Load the regMap and call the save handler [note: handler pops r0/r7] */
+ loadConstant(cUnit, r7, regMap);
+ genDispatchToHandler(cUnit, TEMPLATE_SAVE_STATE);
-/* Perform bound check on two registers */
-static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
- int rBound, int dOffset, ArmLIR *pcrLabel)
-{
- return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
- pcrLabel);
+ /* Set function pointer, pass rGLUE and branch */
+ loadConstant(cUnit, r1, (int) funct);
+ newLIR2(cUnit, kThumbMovRR, r0, rGLUE);
+ newLIR1(cUnit, kThumbBlxR, r1);
+
+ /* Let the recover handler know where coreRegs[0] and restore regs */
+ loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace) +
+ offsetof(HeapArgSpace, coreRegs));
+ genDispatchToHandler(cUnit, TEMPLATE_RESTORE_STATE);
}
+#endif
+
/* Generate a unconditional branch to go to the interpreter */
static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
ArmLIR *pcrLabel)
RegLocation rlDest = getDestLoc(cUnit, mir, 0);
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
#if !defined(WITH_SELF_VERIFICATION)
loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
- size, true, rlObj.sRegLow);
+ size, rlObj.sRegLow);
#else
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
/* Combine address and offset */
regPtr = allocTemp(cUnit);
opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
#endif
}
-static bool handleShiftOpLong(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlShift)
+static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlShift)
{
/*
* Don't mess with the regsiters here as there is a particular calling
storeValueWide(cUnit, rlDest, rlResult);
return false;
}
-bool handleArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- RegLocation rlResult;
- void* funct;
-
- /* TODO: use a proper include file to define these */
- float __aeabi_fadd(float a, float b);
- float __aeabi_fsub(float a, float b);
- float __aeabi_fdiv(float a, float b);
- float __aeabi_fmul(float a, float b);
- float fmodf(float a, float b);
-
- switch (mir->dalvikInsn.opCode) {
- case OP_ADD_FLOAT_2ADDR:
- case OP_ADD_FLOAT:
- funct = (void*) __aeabi_fadd;
- break;
- case OP_SUB_FLOAT_2ADDR:
- case OP_SUB_FLOAT:
- funct = (void*) __aeabi_fsub;
- break;
- case OP_DIV_FLOAT_2ADDR:
- case OP_DIV_FLOAT:
- funct = (void*) __aeabi_fdiv;
- break;
- case OP_MUL_FLOAT_2ADDR:
- case OP_MUL_FLOAT:
- funct = (void*) __aeabi_fmul;
- break;
- case OP_REM_FLOAT_2ADDR:
- case OP_REM_FLOAT:
- funct = (void*) fmodf;
- break;
- case OP_NEG_FLOAT: {
- genNegFloat(cUnit, rlDest, rlSrc1);
- return false;
- }
- default:
- return true;
- }
- flushAllRegs(cUnit); /* Send everything to home location */
- loadValueDirectFixed(cUnit, rlSrc1, r0);
- loadValueDirectFixed(cUnit, rlSrc2, r1);
- loadConstant(cUnit, r2, (int)funct);
- opReg(cUnit, kOpBlx, r2);
- clobberCallRegs(cUnit);
- rlResult = getReturnLoc(cUnit);
- storeValue(cUnit, rlDest, rlResult);
- return false;
-}
-
-bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- RegLocation rlResult;
- void* funct;
-
- /* TODO: use a proper include file to define these */
- double __aeabi_dadd(double a, double b);
- double __aeabi_dsub(double a, double b);
- double __aeabi_ddiv(double a, double b);
- double __aeabi_dmul(double a, double b);
- double fmod(double a, double b);
-
- switch (mir->dalvikInsn.opCode) {
- case OP_ADD_DOUBLE_2ADDR:
- case OP_ADD_DOUBLE:
- funct = (void*) __aeabi_dadd;
- break;
- case OP_SUB_DOUBLE_2ADDR:
- case OP_SUB_DOUBLE:
- funct = (void*) __aeabi_dsub;
- break;
- case OP_DIV_DOUBLE_2ADDR:
- case OP_DIV_DOUBLE:
- funct = (void*) __aeabi_ddiv;
- break;
- case OP_MUL_DOUBLE_2ADDR:
- case OP_MUL_DOUBLE:
- funct = (void*) __aeabi_dmul;
- break;
- case OP_REM_DOUBLE_2ADDR:
- case OP_REM_DOUBLE:
- funct = (void*) fmod;
- break;
- case OP_NEG_DOUBLE: {
- genNegDouble(cUnit, rlDest, rlSrc1);
- return false;
- }
- default:
- return true;
- }
- flushAllRegs(cUnit); /* Send everything to home location */
- loadConstant(cUnit, rlr, (int)funct);
- loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
- loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
- opReg(cUnit, kOpBlx, rlr);
- clobberCallRegs(cUnit);
- rlResult = getReturnLocWide(cUnit);
- storeValueWide(cUnit, rlDest, rlResult);
- return false;
-}
-static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
+static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
{
RegLocation rlResult;
OpKind firstOp = kOpBkpt;
return false;
}
-static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
+static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
{
OpKind op = kOpBkpt;
bool callOut = false;
return false;
}
-static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
+static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
{
OpCode opCode = mir->dalvikInsn.opCode;
RegLocation rlDest;
}
if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
- return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
- return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
- return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
- return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
- return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
- return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
- return handleArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
- return handleArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
- return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
- return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
+ return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
}
return true;
}
return branch;
}
-/*
- * Generate an kArmPseudoBarrier marker to indicate the boundary of special
- * blocks.
- */
-static void genBarrier(CompilationUnit *cUnit)
-{
- ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
- /* Mark all resources as being clobbered */
- barrier->defMask = -1;
-}
-
/* Perform the actual operation for OP_RETURN_* */
static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
{
branch->generic.target = (LIR *) pcrLabel;
}
-static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
- int srcSize, int tgtSize)
-{
- /*
- * Don't optimize the register usage since it calls out to template
- * functions
- */
- RegLocation rlSrc;
- RegLocation rlDest;
- flushAllRegs(cUnit); /* Send everything to home location */
- if (srcSize == 1) {
- rlSrc = getSrcLoc(cUnit, mir, 0);
- loadValueDirectFixed(cUnit, rlSrc, r0);
- } else {
- rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
- }
- loadConstant(cUnit, r2, (int)funct);
- opReg(cUnit, kOpBlx, r2);
- clobberCallRegs(cUnit);
- if (tgtSize == 1) {
- RegLocation rlResult;
- rlDest = getDestLoc(cUnit, mir, 0);
- rlResult = getReturnLoc(cUnit);
- storeValue(cUnit, rlDest, rlResult);
- } else {
- RegLocation rlResult;
- rlDest = getDestLocWide(cUnit, mir, 0, 1);
- rlResult = getReturnLocWide(cUnit);
- storeValueWide(cUnit, rlDest, rlResult);
- }
- return false;
-}
-
static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
DecodedInstruction *dInsn,
ArmLIR **pcrLabel)
opReg(cUnit, kOpBlx, r2);
}
-static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
+static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
{
bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
flushAllRegs(cUnit); /* Send everything to home location */
clobberCallRegs(cUnit);
}
-/* Load a word at base + displacement. Displacement must be word multiple */
-static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
- int rDest)
-{
- return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, false,
- INVALID_SREG);
-}
-
-static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
- int displacement, int rSrc)
-{
- return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
-}
-
-static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
-{
- ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
- dvmCompilerAppendLIR(cUnit, (LIR*)res);
- return res;
-}
-
/*
* The following are the first-level codegen routines that analyze the format
* of each bytecode then either dispatch special purpose codegen routines
case OP_MONITOR_EXIT:
case OP_MONITOR_ENTER:
#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
- handleMonitorPortable(cUnit, mir);
+ genMonitorPortable(cUnit, mir);
#else
- handleMonitor(cUnit, mir);
+ genMonitor(cUnit, mir);
#endif
break;
case OP_THROW: {
return false;
}
-static bool handleConversionPortable(CompilationUnit *cUnit, MIR *mir)
-{
- OpCode opCode = mir->dalvikInsn.opCode;
-
- float __aeabi_i2f( int op1 );
- int __aeabi_f2iz( float op1 );
- float __aeabi_d2f( double op1 );
- double __aeabi_f2d( float op1 );
- double __aeabi_i2d( int op1 );
- int __aeabi_d2iz( double op1 );
- float __aeabi_l2f( long op1 );
- double __aeabi_l2d( long op1 );
- s8 dvmJitf2l( float op1 );
- s8 dvmJitd2l( double op1 );
-
- switch (opCode) {
- case OP_INT_TO_FLOAT:
- return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
- case OP_FLOAT_TO_INT:
- return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
- case OP_DOUBLE_TO_FLOAT:
- return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
- case OP_FLOAT_TO_DOUBLE:
- return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
- case OP_INT_TO_DOUBLE:
- return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
- case OP_DOUBLE_TO_INT:
- return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
- case OP_FLOAT_TO_LONG:
- return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
- case OP_LONG_TO_FLOAT:
- return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
- case OP_DOUBLE_TO_LONG:
- return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
- case OP_LONG_TO_DOUBLE:
- return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
- default:
- return true;
- }
- return false;
-}
-
static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
{
OpCode opCode = mir->dalvikInsn.opCode;
RegLocation rlResult;
if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
- return handleArithOp( cUnit, mir );
+ return genArithOp( cUnit, mir );
}
if (mir->ssaRep->numUses == 2)
case OP_LONG_TO_FLOAT:
case OP_DOUBLE_TO_LONG:
case OP_LONG_TO_DOUBLE:
- return handleConversion(cUnit, mir);
+ return genConversion(cUnit, mir);
case OP_NEG_INT:
case OP_NOT_INT:
- return handleArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
+ return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
case OP_NEG_LONG:
case OP_NOT_LONG:
- return handleArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
+ return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
case OP_NEG_FLOAT:
- return handleArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
+ return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
case OP_NEG_DOUBLE:
- return handleArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
+ return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
case OP_MOVE_WIDE:
storeValueWide(cUnit, rlDest, rlSrc);
break;
RegLocation rlDest;
if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
- return handleArithOp( cUnit, mir );
+ return genArithOp( cUnit, mir );
}
/* APUTs have 3 sources and no targets */
case OP_CMPG_FLOAT:
case OP_CMPL_DOUBLE:
case OP_CMPG_DOUBLE:
- return handleCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
case OP_CMP_LONG:
genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
break;
}
}
- return compilerArchVariantInit();
+ return dvmCompilerArchVariantInit();
+}
+
+void *dvmCompilerGetInterpretTemplate()
+{
+ return (void*) ((int)gDvmJit.codeCache +
+ templateEntryOffsets[TEMPLATE_INTERPRET]);
+}
+
+/* Needed by the ld/st optmizatons */
+ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ return genRegCopyNoInsert(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+ return genRegCopy(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+ int srcLo, int srcHi)
+{
+ genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
+}
+
+void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc, OpSize size)
+{
+ storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
+}
+
+void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrcLo, int rSrcHi)
+{
+ storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
}
--- /dev/null
+/*
+ * 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
+ * ARM 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 ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+ int rDest)
+{
+ return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
+ INVALID_SREG);
+}
+
+static ArmLIR *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 = updateLoc(cUnit, rlSrc); /* Is our value hiding in a live temp? */
+ if (rlSrc.location == kLocPhysReg) {
+ genRegCopy(cUnit, reg1, rlSrc.lowReg);
+ } else if (rlSrc.location == kLocRetval) {
+ loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), reg1);
+ } else {
+ assert(rlSrc.location == kLocDalvikFrame);
+ loadWordDisp(cUnit, rFP, sReg2vReg(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)
+{
+ clobberReg(cUnit, reg1);
+ markRegInUse(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 = updateLocWide(cUnit, rlSrc);
+ if (rlSrc.location == kLocPhysReg) {
+ genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
+ } else if (rlSrc.location == kLocRetval) {
+ loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
+ regLo, regHi, INVALID_SREG);
+ } else {
+ assert(rlSrc.location == kLocDalvikFrame);
+ loadBaseDispWide(cUnit, NULL, rFP,
+ sReg2vReg(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)
+{
+ clobberReg(cUnit, regLo);
+ clobberReg(cUnit, regHi);
+ markRegInUse(cUnit, regLo);
+ markRegInUse(cUnit, regHi);
+ loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
+}
+
+static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
+ RegisterClass opKind)
+{
+ RegisterInfo *pReg;
+ rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
+ if (rlSrc.location == kLocDalvikFrame) {
+ loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
+ rlSrc.location = kLocPhysReg;
+ markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+ } else if (rlSrc.location == kLocRetval) {
+ loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
+ rlSrc.location = kLocPhysReg;
+ clobberReg(cUnit, rlSrc.lowReg);
+ }
+ return rlSrc;
+}
+
+static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegisterInfo *pRegLo;
+ LIR *defStart;
+ LIR *defEnd;
+ assert(!rlDest.wide);
+ assert(!rlSrc.wide);
+ killNullCheckedLocation(cUnit, rlDest);
+ rlSrc = updateLoc(cUnit, rlSrc);
+ rlDest = updateLoc(cUnit, rlDest);
+ if (rlSrc.location == kLocPhysReg) {
+ if (isLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) {
+ // Src is live or Dest has assigned reg.
+ rlDest = evalLoc(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;
+ clobberReg(cUnit, rlSrc.lowReg);
+ }
+ } else {
+ // Load Src either into promoted Dest or temps allocated for Dest
+ rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
+ loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
+ }
+
+ // Dest is now live and dirty (until/if we flush it to home location)
+ markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+ markRegDirty(cUnit, rlDest.lowReg);
+
+
+ if (rlDest.location == kLocRetval) {
+ storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
+ rlDest.lowReg, kWord);
+ clobberReg(cUnit, rlDest.lowReg);
+ } else {
+ resetDefLoc(cUnit, rlDest);
+ if (liveOut(cUnit, rlDest.sRegLow)) {
+ defStart = (LIR *)cUnit->lastLIRInsn;
+ int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
+ storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
+ markRegClean(cUnit, rlDest.lowReg);
+ defEnd = (LIR *)cUnit->lastLIRInsn;
+ markDef(cUnit, rlDest, defStart, defEnd);
+ }
+ }
+}
+
+static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
+ RegisterClass opKind)
+{
+ RegisterInfo *pRegLo;
+ RegisterInfo *pRegHi;
+ assert(rlSrc.wide);
+ rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
+ if (rlSrc.location == kLocDalvikFrame) {
+ loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
+ rlSrc.location = kLocPhysReg;
+ markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+ markRegLive(cUnit, rlSrc.highReg, hiSReg(rlSrc.sRegLow));
+ } else if (rlSrc.location == kLocRetval) {
+ loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
+ rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
+ rlSrc.location = kLocPhysReg;
+ clobberReg(cUnit, rlSrc.lowReg);
+ clobberReg(cUnit, rlSrc.highReg);
+ }
+ return rlSrc;
+}
+
+static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegisterInfo *pRegLo;
+ RegisterInfo *pRegHi;
+ LIR *defStart;
+ LIR *defEnd;
+ bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
+ assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
+ assert(rlDest.wide);
+ assert(rlSrc.wide);
+ killNullCheckedLocation(cUnit, rlDest);
+ if (rlSrc.location == kLocPhysReg) {
+ if (isLive(cUnit, rlSrc.lowReg) || isLive(cUnit, rlSrc.highReg) ||
+ (rlDest.location == kLocPhysReg)) {
+ // Src is live or Dest has assigned reg.
+ rlDest = evalLoc(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;
+ clobberReg(cUnit, rlSrc.lowReg);
+ clobberReg(cUnit, rlSrc.highReg);
+ }
+ } else {
+ // Load Src either into promoted Dest or temps allocated for Dest
+ rlDest = evalLoc(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)
+ markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+ markRegLive(cUnit, rlDest.highReg, hiSReg(rlDest.sRegLow));
+ markRegDirty(cUnit, rlDest.lowReg);
+ markRegDirty(cUnit, rlDest.highReg);
+ markRegPair(cUnit, rlDest.lowReg, rlDest.highReg);
+
+
+ if (rlDest.location == kLocRetval) {
+ storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval),
+ rlDest.lowReg, rlDest.highReg);
+ clobberReg(cUnit, rlDest.lowReg);
+ clobberReg(cUnit, rlDest.highReg);
+ } else {
+ resetDefLocWide(cUnit, rlDest);
+ if (liveOut(cUnit, rlDest.sRegLow) ||
+ liveOut(cUnit, hiSReg(rlDest.sRegLow))) {
+ defStart = (LIR *)cUnit->lastLIRInsn;
+ int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
+ assert((vReg+1) == sReg2vReg(cUnit, hiSReg(rlDest.sRegLow)));
+ storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
+ rlDest.highReg);
+ markRegClean(cUnit, rlDest.lowReg);
+ markRegClean(cUnit, rlDest.highReg);
+ defEnd = (LIR *)cUnit->lastLIRInsn;
+ markDefWide(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 ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
+ int dOffset, ArmLIR *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, kArmCondEq, mReg, 0, dOffset, pcrLabel);
+}
+
+
+
+/*
+ * Perform a "reg cmp reg" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
+ ArmConditionCode cond,
+ int reg1, int reg2, int dOffset,
+ ArmLIR *pcrLabel)
+{
+ ArmLIR *res;
+ res = opRegReg(cUnit, kOpCmp, reg1, reg2);
+ ArmLIR *branch = opCondBranch(cUnit, cond);
+ genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+ return res;
+}
+
+/*
+ * Perform zero-check on a register. Similar to genNullCheck but the value being
+ * checked does not have a corresponding Dalvik register.
+ */
+static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
+ int dOffset, ArmLIR *pcrLabel)
+{
+ return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
+}
+
+/* Perform bound check on two registers */
+static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
+ int rBound, int dOffset, ArmLIR *pcrLabel)
+{
+ return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
+ pcrLabel);
+}
+
+/*
+ * Jump to the out-of-line handler in ARM mode to finish executing the
+ * remaining of more complex instructions.
+ */
+static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
+{
+ /*
+ * NOTE - In practice BLX only needs one operand, but since the assembler
+ * may abort itself and retry due to other out-of-range conditions we
+ * cannot really use operand[0] to store the absolute target address since
+ * it may get clobbered by the final relative offset. Therefore,
+ * we fake BLX_1 is a two operand instruction and the absolute target
+ * address is stored in operand[1].
+ */
+ clobberHandlerRegs(cUnit);
+ newLIR2(cUnit, kThumbBlx1,
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
+ newLIR2(cUnit, kThumbBlx2,
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include <math.h> // for double sqrt(double)
+
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ int op = kThumbBkpt;
+ RegLocation rlResult;
+
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ op = kThumb2Vadds;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ op = kThumb2Vsubs;
+ break;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ op = kThumb2Vdivs;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ op = kThumb2Vmuls;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ case OP_NEG_FLOAT: {
+ return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1,
+ rlSrc2);
+ }
+ default:
+ return true;
+ }
+ rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+ rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+ rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR3(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ int op = kThumbBkpt;
+ RegLocation rlResult;
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ op = kThumb2Vaddd;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ op = kThumb2Vsubd;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ op = kThumb2Vdivd;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ op = kThumb2Vmuld;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ case OP_NEG_DOUBLE: {
+ return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+ rlSrc2);
+ }
+ default:
+ return true;
+ }
+
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+ assert(rlSrc1.wide);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+ assert(rlSrc2.wide);
+ rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ assert(rlDest.wide);
+ assert(rlResult.wide);
+ newLIR3(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg),
+ S2D(rlSrc1.lowReg, rlSrc1.highReg),
+ S2D(rlSrc2.lowReg, rlSrc2.highReg));
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+ int op = kThumbBkpt;
+ bool longSrc = false;
+ bool longDest = false;
+ int srcReg;
+ RegLocation rlSrc;
+ RegLocation rlDest;
+ RegLocation rlResult;
+
+ switch (opCode) {
+ case OP_INT_TO_FLOAT:
+ longSrc = false;
+ longDest = false;
+ op = kThumb2VcvtIF;
+ break;
+ case OP_FLOAT_TO_INT:
+ longSrc = false;
+ longDest = false;
+ op = kThumb2VcvtFI;
+ break;
+ case OP_DOUBLE_TO_FLOAT:
+ longSrc = true;
+ longDest = false;
+ op = kThumb2VcvtDF;
+ break;
+ case OP_FLOAT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ op = kThumb2VcvtFd;
+ break;
+ case OP_INT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ op = kThumb2VcvtID;
+ break;
+ case OP_DOUBLE_TO_INT:
+ longSrc = true;
+ longDest = false;
+ op = kThumb2VcvtDI;
+ break;
+ case OP_LONG_TO_DOUBLE:
+ case OP_FLOAT_TO_LONG:
+ case OP_LONG_TO_FLOAT:
+ case OP_DOUBLE_TO_LONG:
+ return genConversionPortable(cUnit, mir);
+ default:
+ return true;
+ }
+ if (longSrc) {
+ rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+ srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
+ } else {
+ rlSrc = getSrcLoc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+ srcReg = rlSrc.lowReg;
+ }
+ if (longDest) {
+ rlDest = getDestLocWide(cUnit, mir, 0, 1);
+ rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else {
+ rlDest = getDestLoc(cUnit, mir, 0);
+ rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, op, rlResult.lowReg, srcReg);
+ storeValue(cUnit, rlDest, rlResult);
+ }
+ return false;
+}
+
+static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
+{
+ ArmLIR *branch;
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
+ rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+ RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg),
+ S2D(rlSrc.lowReg, rlSrc.highReg));
+ newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg),
+ S2D(rlResult.lowReg, rlResult.highReg));
+ newLIR0(cUnit, kThumb2Fmstat);
+ branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
+ clobberCallRegs(cUnit);
+ loadConstant(cUnit, r2, (int)sqrt);
+ newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg));
+ newLIR1(cUnit, kThumbBlxR, r2);
+ newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg),
+ r0, r1);
+ ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel);
+ label->defMask = ENCODE_ALL;
+ branch->generic.target = (LIR *)label;
+ storeValueWide(cUnit, rlDest, rlResult);
+ return true;
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ bool isDouble;
+ int defaultResult;
+ bool ltNaNBias;
+ RegLocation rlResult;
+
+ switch(mir->dalvikInsn.opCode) {
+ case OP_CMPL_FLOAT:
+ isDouble = false;
+ defaultResult = -1;
+ break;
+ case OP_CMPG_FLOAT:
+ isDouble = false;
+ defaultResult = 1;
+ break;
+ case OP_CMPL_DOUBLE:
+ isDouble = true;
+ defaultResult = -1;
+ break;
+ case OP_CMPG_DOUBLE:
+ isDouble = true;
+ defaultResult = 1;
+ break;
+ default:
+ return true;
+ }
+ if (isDouble) {
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+ clobberSReg(cUnit, rlDest.sRegLow);
+ rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ loadConstant(cUnit, rlResult.lowReg, defaultResult);
+ newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg),
+ S2D(rlSrc2.lowReg, rlSrc2.highReg));
+ } else {
+ rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+ rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+ clobberSReg(cUnit, rlDest.sRegLow);
+ rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ loadConstant(cUnit, rlResult.lowReg, defaultResult);
+ newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
+ }
+ assert(!FPREG(rlResult.lowReg));
+ newLIR0(cUnit, kThumb2Fmstat);
+ genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
+ newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
+ modifiedImmediate(-defaultResult)); // Must not alter ccodes
+ genIT(cUnit, kArmCondEq, "");
+ loadConstant(cUnit, rlResult.lowReg, 0);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/* Forward decalraton the portable versions due to circular dependency */
+static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2);
+
+static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2);
+
+static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir);
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ return genConversionPortable(cUnit, mir);
+}
+
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+}
+
+static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
+{
+ return false; /* punt to C handler */
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult = LOC_C_RETURN;
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opCode) {
+ case OP_CMPL_FLOAT:
+ loadValueDirectFixed(cUnit, rlSrc1, r0);
+ loadValueDirectFixed(cUnit, rlSrc2, r1);
+ genDispatchToHandler(cUnit, TEMPLATE_CMPL_FLOAT);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ case OP_CMPG_FLOAT:
+ loadValueDirectFixed(cUnit, rlSrc1, r0);
+ loadValueDirectFixed(cUnit, rlSrc2, r1);
+ genDispatchToHandler(cUnit, TEMPLATE_CMPG_FLOAT);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ case OP_CMPL_DOUBLE:
+ loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+ genDispatchToHandler(cUnit, TEMPLATE_CMPL_DOUBLE);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ case OP_CMPG_DOUBLE:
+ loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+ genDispatchToHandler(cUnit, TEMPLATE_CMPG_DOUBLE);
+ storeValue(cUnit, rlDest, rlResult);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
--- /dev/null
+/*
+ * 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 is included by Codegen-armv5te-vfp.c, and implements architecture
+ * variant-specific code.
+ */
+
+/* FIXME */
+extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
+ int reg1, int reg2);
+extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg);
+
+/* First, flush any registers associated with this value */
+static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
+ int rDest)
+{
+ rlSrc = rlSrc.wide ? updateLocWide(cUnit, rlSrc) : updateLoc(cUnit, rlSrc);
+ if (rlSrc.location == kLocPhysReg) {
+ if (rlSrc.wide) {
+ dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg,
+ rlSrc.highReg);
+ } else {
+ dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg);
+ }
+ }
+ opRegRegImm(cUnit, kOpAdd, rDest, rFP,
+ sReg2vReg(cUnit, rlSrc.sRegLow) << 2);
+}
+
+static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ RegLocation rlResult = LOC_C_RETURN_WIDE;
+ RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
+ loadValueAddress(cUnit, rlSrc, r2);
+ genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
+
+/*
+ * TUNING: On some implementations, it is quicker to pass addresses
+ * to the handlers rather than load the operands into core registers
+ * and then move the values to FP regs in the handlers. Other implementations
+ * may prefer passing data in registers (and the latter approach would
+ * yeild cleaner register handling - avoiding the requirement that operands
+ * be flushed to memory prior to the call).
+ */
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ TemplateOpCode opCode;
+
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ opCode = TEMPLATE_ADD_FLOAT_VFP;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ opCode = TEMPLATE_SUB_FLOAT_VFP;
+ break;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ opCode = TEMPLATE_DIV_FLOAT_VFP;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ opCode = TEMPLATE_MUL_FLOAT_VFP;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ case OP_NEG_FLOAT: {
+ return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+ }
+ default:
+ return true;
+ }
+ loadValueAddress(cUnit, rlDest, r0);
+ clobberReg(cUnit, r0);
+ loadValueAddress(cUnit, rlSrc1, r1);
+ clobberReg(cUnit, r1);
+ loadValueAddress(cUnit, rlSrc2, r2);
+ genDispatchToHandler(cUnit, opCode);
+ rlDest = updateLoc(cUnit, rlDest);
+ if (rlDest.location == kLocPhysReg) {
+ clobberReg(cUnit, rlDest.lowReg);
+ }
+ return false;
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ TemplateOpCode opCode;
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ opCode = TEMPLATE_ADD_DOUBLE_VFP;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ opCode = TEMPLATE_SUB_DOUBLE_VFP;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ opCode = TEMPLATE_DIV_DOUBLE_VFP;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ opCode = TEMPLATE_MUL_DOUBLE_VFP;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ case OP_NEG_DOUBLE: {
+ return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+ rlSrc2);
+ }
+ default:
+ return true;
+ }
+ loadValueAddress(cUnit, rlDest, r0);
+ clobberReg(cUnit, r0);
+ loadValueAddress(cUnit, rlSrc1, r1);
+ clobberReg(cUnit, r1);
+ loadValueAddress(cUnit, rlSrc2, r2);
+ genDispatchToHandler(cUnit, opCode);
+ rlDest = updateLocWide(cUnit, rlDest);
+ if (rlDest.location == kLocPhysReg) {
+ clobberReg(cUnit, rlDest.lowReg);
+ clobberReg(cUnit, rlDest.highReg);
+ }
+ return false;
+}
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+ bool longSrc = false;
+ bool longDest = false;
+ RegLocation rlSrc;
+ RegLocation rlDest;
+ TemplateOpCode template;
+ switch (opCode) {
+ case OP_INT_TO_FLOAT:
+ longSrc = false;
+ longDest = false;
+ template = TEMPLATE_INT_TO_FLOAT_VFP;
+ break;
+ case OP_FLOAT_TO_INT:
+ longSrc = false;
+ longDest = false;
+ template = TEMPLATE_FLOAT_TO_INT_VFP;
+ break;
+ case OP_DOUBLE_TO_FLOAT:
+ longSrc = true;
+ longDest = false;
+ template = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
+ break;
+ case OP_FLOAT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ template = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
+ break;
+ case OP_INT_TO_DOUBLE:
+ longSrc = false;
+ longDest = true;
+ template = TEMPLATE_INT_TO_DOUBLE_VFP;
+ break;
+ case OP_DOUBLE_TO_INT:
+ longSrc = true;
+ longDest = false;
+ template = TEMPLATE_DOUBLE_TO_INT_VFP;
+ break;
+ case OP_LONG_TO_DOUBLE:
+ case OP_FLOAT_TO_LONG:
+ case OP_LONG_TO_FLOAT:
+ case OP_DOUBLE_TO_LONG:
+ return genConversionPortable(cUnit, mir);
+ default:
+ return true;
+ }
+
+ if (longSrc) {
+ rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ } else {
+ rlSrc = getSrcLoc(cUnit, mir, 0);
+ }
+
+ if (longDest) {
+ rlDest = getDestLocWide(cUnit, mir, 0, 1);
+ } else {
+ rlDest = getDestLoc(cUnit, mir, 0);
+ }
+ loadValueAddress(cUnit, rlDest, r0);
+ clobberReg(cUnit, r0);
+ loadValueAddress(cUnit, rlSrc, r1);
+ genDispatchToHandler(cUnit, template);
+ if (rlDest.wide) {
+ rlDest = updateLocWide(cUnit, rlDest);
+ clobberReg(cUnit, rlDest.highReg);
+ } else {
+ rlDest = updateLoc(cUnit, rlDest);
+ }
+ clobberReg(cUnit, rlDest.lowReg);
+ return false;
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ TemplateOpCode template;
+ RegLocation rlResult = getReturnLoc(cUnit);
+ bool wide = true;
+
+ switch(mir->dalvikInsn.opCode) {
+ case OP_CMPL_FLOAT:
+ template = TEMPLATE_CMPL_FLOAT_VFP;
+ wide = false;
+ break;
+ case OP_CMPG_FLOAT:
+ template = TEMPLATE_CMPG_FLOAT_VFP;
+ wide = false;
+ break;
+ case OP_CMPL_DOUBLE:
+ template = TEMPLATE_CMPL_DOUBLE_VFP;
+ break;
+ case OP_CMPG_DOUBLE:
+ template = TEMPLATE_CMPG_DOUBLE_VFP;
+ break;
+ default:
+ return true;
+ }
+ loadValueAddress(cUnit, rlSrc1, r0);
+ clobberReg(cUnit, r0);
+ loadValueAddress(cUnit, rlSrc2, r1);
+ genDispatchToHandler(cUnit, template);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
#include "Dalvik.h"
#include "vm/compiler/CompilerInternals.h"
#include "ArmLIR.h"
+#include "Codegen.h"
#define DEBUG_OPT(X)
/* Insert a move to replace the load */
if (checkLIR->operands[0] != nativeRegId) {
ArmLIR *moveLIR;
- moveLIR = dvmCompilerRegCopy(cUnit,
- checkLIR->operands[0],
- nativeRegId);
+ moveLIR = dvmCompilerRegCopyNoInsert(
+ cUnit, checkLIR->operands[0], nativeRegId);
/*
* Insertion is guaranteed to succeed since checkLIR
* is never the first LIR on the list
/* Insert a move to replace the load */
if (checkLIR->operands[0] != nativeRegId) {
ArmLIR *moveLIR;
- moveLIR = dvmCompilerRegCopy(cUnit,
- nativeRegId,
- checkLIR->operands[0]);
+ moveLIR = dvmCompilerRegCopyNoInsert(
+ cUnit, nativeRegId, checkLIR->operands[0]);
/*
* Convert *thisLIR* load into a move
*/
--- /dev/null
+The codegen file for the ARM-based JIT is composed by files broken by
+functionality hierarchies. The goal is to separate architectural dependent
+and independent components to facilitate maintenance and future extension.
+
+For example, the codegen file for armv7-a is assembled by the following
+components:
+
+--
+
+/* Architectural independent building blocks */
+#include "../CodegenCommon.c"
+
+/* Thumb2-specific factory utilities */
+#include "../Thumb2/Factory.c"
+/* Factory utilities dependent on arch-specific features */
+#include "../CodegenFactory.c"
+
+/* Thumb2-specific codegen routines */
+#include "../Thumb2/Gen.c"
+/* Thumb2+VFP codegen routines */
+#include "../FP/Thumb2VFP.c"
+
+/* Thumb2-specific register allocation */
+#include "../Thumb2/Ralloc.c"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.c"
+
+/* Architecture manifest */
+#include "ArchVariant.c"
+
+--
+
+For the Thumb/Thumb2 directories, each contain the followin three files:
+
+- Factory.c (low-level routines for instruction selections)
+- Gen.c (invoke the ISA-specific instruction selection routines)
+- Ralloc.c (arch-dependent register pools)
+
+The FP directory contains FP-specific codegen routines depending on
+Thumb/Thumb2/VFP/PortableFP:
+
+- Thumb2VFP.c
+- ThumbVFP.c
+- ThumbPortableFP.c
+
+In this way the dependency between generic and specific code tied to
+particular architectures can be explicitly represented.
+
--- /dev/null
+/*
+ * 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 register alloction support and is intended to be
+ * included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include "compiler/Dataflow.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+
+/*
+ * The following are register allocation routines exposed to the code generator
+ * FIXME - dvmCompiler prefixes are not added yet
+ */
+
+static inline int sReg2vReg(CompilationUnit *cUnit, int sReg)
+{
+ assert(sReg != INVALID_SREG);
+ return DECODE_REG(dvmConvertSSARegToDalvik(cUnit, sReg));
+}
+
+/* Reset the tracker to unknown state */
+static inline void resetNullCheckTracker(CompilationUnit *cUnit)
+{
+ dvmClearAllBits(cUnit->regPool->nullCheckedRegs);
+}
+
+/*
+ * Get the "real" sreg number associated with an sReg slot. In general,
+ * sReg values passed through codegen are the SSA names created by
+ * dataflow analysis and refer to slot numbers in the cUnit->regLocation
+ * array. However, renaming is accomplished by simply replacing RegLocation
+ * entries in the cUnit->reglocation[] array. Therefore, when location
+ * records for operands are first created, we need to ask the locRecord
+ * identified by the dataflow pass what it's new name is.
+ */
+
+static inline int hiSReg(int lowSreg) {
+ return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
+}
+
+
+static inline bool liveOut(CompilationUnit *cUnit, int sReg)
+{
+ //TODO: fully implement
+ return true;
+}
+
+static inline int getSrcSSAName(MIR *mir, int num)
+{
+ assert(mir->ssaRep->numUses > num);
+ return mir->ssaRep->uses[num];
+}
+
+extern RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
+ int regClass, bool update);
+/* Mark a temp register as dead. Does not affect allocation state. */
+extern void clobberReg(CompilationUnit *cUnit, int reg);
+
+extern RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc);
+
+/* see comments for updateLoc */
+extern RegLocation updateLocWide(CompilationUnit *cUnit, RegLocation loc);
+
+/* Clobber all of the temps that might be used by a handler. */
+extern void clobberHandlerRegs(CompilationUnit *cUnit);
+
+extern void markRegLive(CompilationUnit *cUnit, int reg, int sReg);
+
+extern void markRegDirty(CompilationUnit *cUnit, int reg);
+
+extern void markRegPair(CompilationUnit *cUnit, int lowReg, int highReg);
+
+extern void markRegClean(CompilationUnit *cUnit, int reg);
+
+extern void resetDef(CompilationUnit *cUnit, int reg);
+
+extern void resetDefLoc(CompilationUnit *cUnit, RegLocation rl);
+
+/* Set up temp & preserved register pools specialized by target */
+extern void initPool(RegisterInfo *regs, int *regNums, int num);
+
+/*
+ * Mark the beginning and end LIR of a def sequence. Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void markDef(CompilationUnit *cUnit, RegLocation rl,
+ LIR *start, LIR *finish);
+/*
+ * Mark the beginning and end LIR of a def sequence. Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+extern void markDefWide(CompilationUnit *cUnit, RegLocation rl,
+ LIR *start, LIR *finish);
+
+extern RegLocation getSrcLocWide(CompilationUnit *cUnit, MIR *mir,
+ int low, int high);
+
+extern RegLocation getDestLocWide(CompilationUnit *cUnit, MIR *mir,
+ int low, int high);
+// Get the LocRecord associated with an SSA name use.
+extern RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num);
+
+// Get the LocRecord associated with an SSA name def.
+extern RegLocation getDestLoc(CompilationUnit *cUnit, MIR *mir, int num);
+
+extern RegLocation getReturnLocWide(CompilationUnit *cUnit);
+
+/* Clobber all regs that might be used by an external C call */
+extern void clobberCallRegs(CompilationUnit *cUnit);
+
+extern RegisterInfo *isTemp(CompilationUnit *cUnit, int reg);
+
+extern void markRegInUse(CompilationUnit *cUnit, int reg);
+
+extern int allocTemp(CompilationUnit *cUnit);
+
+extern int allocTempFloat(CompilationUnit *cUnit);
+
+//REDO: too many assumptions.
+extern int allocTempDouble(CompilationUnit *cUnit);
+
+extern void freeTemp(CompilationUnit *cUnit, int reg);
+
+extern void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl);
+
+extern void resetDefTracking(CompilationUnit *cUnit);
+
+/* Kill the corresponding bit in the null-checked register list */
+extern void killNullCheckedLocation(CompilationUnit *cUnit, RegLocation loc);
+
+//FIXME - this needs to also check the preserved pool.
+extern RegisterInfo *isLive(CompilationUnit *cUnit, int reg);
+
+/* To be used when explicitly managing register use */
+extern void lockAllTemps(CompilationUnit *cUnit);
+
+extern void flushAllRegs(CompilationUnit *cUnit);
+
+extern RegLocation getReturnLocWideAlt(CompilationUnit *cUnit);
+
+extern RegLocation getReturnLoc(CompilationUnit *cUnit);
+
+extern RegLocation getReturnLocAlt(CompilationUnit *cUnit);
+
+/* Clobber any temp associated with an sReg. Could be in either class */
+extern void clobberSReg(CompilationUnit *cUnit, int sReg);
+
+/* Return a temp if one is available, -1 otherwise */
+extern int allocFreeTemp(CompilationUnit *cUnit);
+
+/*
+ * Similar to allocTemp(), but forces the allocation of a specific
+ * register. No check is made to see if the register was previously
+ * allocated. Use with caution.
+ */
+extern void lockTemp(CompilationUnit *cUnit, int reg);
+
+extern RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl);
+
+/*
+ * Free all allocated temps in the temp pools. Note that this does
+ * not affect the "liveness" of a temp register, which will stay
+ * live until it is either explicitly killed or reallocated.
+ */
+extern void resetRegPool(CompilationUnit *cUnit);
+
+extern void clobberAllRegs(CompilationUnit *cUnit);
+
+extern void resetDefTracking(CompilationUnit *cUnit);
*
*/
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include "compiler/Dataflow.h"
+#include "ArmLIR.h"
#include "Codegen.h"
-#include "../../Dataflow.h"
+#include "Ralloc.h"
+
+/*
+ * FIXME - dvmCompiler prefixes are not added yet to routines exposed to the
+ * code generator.
+ */
/*
* Register usage for 16-bit Thumb systems:
*
*/
-static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
- int displacement, int rSrc, OpSize size);
-static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
- int displacement, int rSrcLo, int rSrcHi);
-static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
- int regClass);
-static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass);
-void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
- int srcLo, int srcHi);
-static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-static void clobberReg(CompilationUnit *cUnit, int reg);
-static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg);
-
#define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
/*
* Get the "real" sreg number associated with an sReg slot. In general,
* identified by the dataflow pass what it's new name is.
*/
-static inline int hiSReg(int lowSreg) {
- return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
-}
-
-static int sReg2vReg(CompilationUnit *cUnit, int sReg)
-{
- assert(sReg != INVALID_SREG);
- return DECODE_REG(dvmConvertSSARegToDalvik(cUnit, sReg));
-}
-
-static bool liveOut(CompilationUnit *cUnit, int sReg)
-{
- //TODO: fully implement
- return true;
-}
-
/*
* Free all allocated temps in the temp pools. Note that this does
* not affect the "liveness" of a temp register, which will stay
* live until it is either explicitly killed or reallocated.
*/
-static void resetRegPool(CompilationUnit *cUnit)
+extern void resetRegPool(CompilationUnit *cUnit)
{
int i;
for (i=0; i < cUnit->regPool->numCoreTemps; i++) {
}
/* Set up temp & preserved register pools specialized by target */
-static void initPool(RegisterInfo *regs, int *regNums, int num)
+extern void initPool(RegisterInfo *regs, int *regNums, int num)
{
int i;
for (i=0; i < num; i++) {
LOGE("================================================");
}
+static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
+{
+ int numTemps = cUnit->regPool->numCoreTemps;
+ RegisterInfo *p = cUnit->regPool->coreTemps;
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ p = cUnit->regPool->FPTemps;
+ numTemps = cUnit->regPool->numFPTemps;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ LOGE("Tried to get info on a non-existant temp: r%d",reg);
+ dvmAbort();
+ return NULL;
+}
+
+static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
+{
+ RegisterInfo *info1 = getRegInfo(cUnit, reg1);
+ RegisterInfo *info2 = getRegInfo(cUnit, reg2);
+ assert(info1 && info2 && info1->pair && info2->pair &&
+ (info1->partner == info2->reg) &&
+ (info2->partner == info1->reg));
+ if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+ info1->dirty = false;
+ info2->dirty = false;
+ if (sReg2vReg(cUnit, info2->sReg) < sReg2vReg(cUnit, info1->sReg))
+ info1 = info2;
+ dvmCompilerFlushRegWideImpl(cUnit, rFP,
+ sReg2vReg(cUnit, info1->sReg) << 2,
+ info1->reg, info1->partner);
+ }
+}
+
+static void flushReg(CompilationUnit *cUnit, int reg)
+{
+ RegisterInfo *info = getRegInfo(cUnit, reg);
+ if (info->live && info->dirty) {
+ info->dirty = false;
+ dvmCompilerFlushRegImpl(cUnit, rFP, sReg2vReg(cUnit, info->sReg) << 2,
+ reg, kWord);
+ }
+}
+
+/* return true if found reg to clobber */
+static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
+ int numTemps, int reg)
+{
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].reg == reg) {
+ if (p[i].live && p[i].dirty) {
+ if (p[i].pair) {
+ flushRegWide(cUnit, p[i].reg, p[i].partner);
+ } else {
+ flushReg(cUnit, p[i].reg);
+ }
+ }
+ p[i].live = false;
+ p[i].sReg = INVALID_SREG;
+ p[i].defStart = NULL;
+ p[i].defEnd = NULL;
+ if (p[i].pair) {
+ p[i].pair = false;
+ /* partners should be in same pool */
+ clobberRegBody(cUnit, p, numTemps, p[i].partner);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Mark a temp register as dead. Does not affect allocation state. */
+void clobberReg(CompilationUnit *cUnit, int reg)
+{
+ if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps, reg)) {
+ clobberRegBody(cUnit, cUnit->regPool->FPTemps,
+ cUnit->regPool->numFPTemps, reg);
+ }
+}
+
+static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
+{
+ int i;
+ for (i=0; i< numTemps; i++) {
+ if (p[i].sReg == sReg) {
+ p[i].live = false;
+ p[i].defStart = NULL;
+ p[i].defEnd = NULL;
+ }
+ }
+}
+
+/* Clobber any temp associated with an sReg. Could be in either class */
+extern void clobberSReg(CompilationUnit *cUnit, int sReg)
+{
+ clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
+ sReg);
+ clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
+ sReg);
+}
+
static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
bool required)
{
}
//REDO: too many assumptions.
-static int allocTempDouble(CompilationUnit *cUnit)
+extern int allocTempDouble(CompilationUnit *cUnit)
{
RegisterInfo *p = cUnit->regPool->FPTemps;
int numTemps = cUnit->regPool->numFPTemps;
}
/* Return a temp if one is available, -1 otherwise */
-static int allocFreeTemp(CompilationUnit *cUnit)
+extern int allocFreeTemp(CompilationUnit *cUnit)
{
return allocTempBody(cUnit, cUnit->regPool->coreTemps,
cUnit->regPool->numCoreTemps, true);
}
-static int allocTemp(CompilationUnit *cUnit)
+extern int allocTemp(CompilationUnit *cUnit)
{
return allocTempBody(cUnit, cUnit->regPool->coreTemps,
cUnit->regPool->numCoreTemps, true);
}
-static int allocTempFloat(CompilationUnit *cUnit)
+extern int allocTempFloat(CompilationUnit *cUnit)
{
return allocTempBody(cUnit, cUnit->regPool->FPTemps,
cUnit->regPool->numFPTemps, true);
return res;
}
-static void freeTemp(CompilationUnit *cUnit, int reg)
+extern void freeTemp(CompilationUnit *cUnit, int reg)
{
RegisterInfo *p = cUnit->regPool->coreTemps;
int numTemps = cUnit->regPool->numCoreTemps;
}
//FIXME - this needs to also check the preserved pool.
-static RegisterInfo *isLive(CompilationUnit *cUnit, int reg)
+extern RegisterInfo *isLive(CompilationUnit *cUnit, int reg)
{
RegisterInfo *p = cUnit->regPool->coreTemps;
int numTemps = cUnit->regPool->numCoreTemps;
return NULL;
}
-static RegisterInfo *isTemp(CompilationUnit *cUnit, int reg)
+extern RegisterInfo *isTemp(CompilationUnit *cUnit, int reg)
{
RegisterInfo *p = cUnit->regPool->coreTemps;
int numTemps = cUnit->regPool->numCoreTemps;
return NULL;
}
-static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
-{
- RegisterInfo *info1 = getRegInfo(cUnit, reg1);
- RegisterInfo *info2 = getRegInfo(cUnit, reg2);
- assert(info1 && info2 && info1->pair && info2->pair &&
- (info1->partner == info2->reg) &&
- (info2->partner == info1->reg));
- if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
- info1->dirty = false;
- info2->dirty = false;
- if (sReg2vReg(cUnit, info2->sReg) < sReg2vReg(cUnit, info1->sReg))
- info1 = info2;
- storeBaseDispWide(cUnit, rFP, sReg2vReg(cUnit, info1->sReg) << 2,
- info1->reg, info1->partner);
- }
-}
-
-static void flushReg(CompilationUnit *cUnit, int reg)
-{
- RegisterInfo *info = getRegInfo(cUnit, reg);
- if (info->live && info->dirty) {
- info->dirty = false;
- storeBaseDisp(cUnit, rFP, sReg2vReg(cUnit, info->sReg) << 2, reg,
- kWord);
- }
-}
-
-/* return true if found reg to clobber */
-static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
- int numTemps, int reg)
-{
- int i;
- for (i=0; i< numTemps; i++) {
- if (p[i].reg == reg) {
- if (p[i].live && p[i].dirty) {
- if (p[i].pair) {
- flushRegWide(cUnit, p[i].reg, p[i].partner);
- } else {
- flushReg(cUnit, p[i].reg);
- }
- }
- p[i].live = false;
- p[i].sReg = INVALID_SREG;
- p[i].defStart = NULL;
- p[i].defEnd = NULL;
- if (p[i].pair) {
- p[i].pair = false;
- clobberReg(cUnit, p[i].partner);
- }
- return true;
- }
- }
- return false;
-}
-
-/* Mark a temp register as dead. Does not affect allocation state. */
-static void clobberReg(CompilationUnit *cUnit, int reg)
-{
- if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
- cUnit->regPool->numCoreTemps, reg)) {
- clobberRegBody(cUnit, cUnit->regPool->FPTemps,
- cUnit->regPool->numFPTemps, reg);
- }
-}
-
-static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
-{
- int i;
- for (i=0; i< numTemps; i++) {
- if (p[i].sReg == sReg) {
- p[i].live = false;
- p[i].defStart = NULL;
- p[i].defEnd = NULL;
- }
- }
-}
-
-/* Clobber any temp associated with an sReg. Could be in either class */
-static void clobberSReg(CompilationUnit *cUnit, int sReg)
-{
- clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
- sReg);
- clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
- sReg);
-}
-
-static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
-{
- int numTemps = cUnit->regPool->numCoreTemps;
- RegisterInfo *p = cUnit->regPool->coreTemps;
- int i;
- for (i=0; i< numTemps; i++) {
- if (p[i].reg == reg) {
- return &p[i];
- }
- }
- p = cUnit->regPool->FPTemps;
- numTemps = cUnit->regPool->numFPTemps;
- for (i=0; i< numTemps; i++) {
- if (p[i].reg == reg) {
- return &p[i];
- }
- }
- LOGE("Tried to get info on a non-existant temp: r%d",reg);
- dvmAbort();
- return NULL;
-}
-
/*
* Similar to allocTemp(), but forces the allocation of a specific
* register. No check is made to see if the register was previously
* allocated. Use with caution.
*/
-static void lockTemp(CompilationUnit *cUnit, int reg)
+extern void lockTemp(CompilationUnit *cUnit, int reg)
{
RegisterInfo *p = cUnit->regPool->coreTemps;
int numTemps = cUnit->regPool->numCoreTemps;
}
/* Clobber all regs that might be used by an external C call */
-static void clobberCallRegs(CompilationUnit *cUnit)
+extern void clobberCallRegs(CompilationUnit *cUnit)
{
clobberReg(cUnit, r0);
clobberReg(cUnit, r1);
}
/* Clobber all of the temps that might be used by a handler. */
-static void clobberHandlerRegs(CompilationUnit *cUnit)
+extern void clobberHandlerRegs(CompilationUnit *cUnit)
{
//TUNING: reduce the set of regs used by handlers. Only a few need lots.
clobberCallRegs(cUnit);
clobberReg(cUnit, r10);
}
-static void resetDef(CompilationUnit *cUnit, int reg)
+extern void resetDef(CompilationUnit *cUnit, int reg)
{
RegisterInfo *p = getRegInfo(cUnit, reg);
p->defStart = NULL;
* on entry start points to the LIR prior to the beginning of the
* sequence.
*/
-static void markDef(CompilationUnit *cUnit, RegLocation rl,
+extern void markDef(CompilationUnit *cUnit, RegLocation rl,
LIR *start, LIR *finish)
{
assert(!rl.wide);
* on entry start points to the LIR prior to the beginning of the
* sequence.
*/
-static void markDefWide(CompilationUnit *cUnit, RegLocation rl,
+extern void markDefWide(CompilationUnit *cUnit, RegLocation rl,
LIR *start, LIR *finish)
{
assert(rl.wide);
p->defEnd = finish;
}
-static RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl)
+extern RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl)
{
assert(rl.wide);
if (rl.location == kLocPhysReg) {
RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
if (!infoLo->pair) {
- dumpRegPool(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps);
+ dumpRegPool(cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps);
assert(infoLo->pair);
}
if (!infoHi->pair) {
- dumpRegPool(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps);
+ dumpRegPool(cUnit->regPool->coreTemps,
+ cUnit->regPool->numCoreTemps);
assert(infoHi->pair);
}
assert(infoLo->pair);
return rl;
}
-static void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
+extern void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
{
assert(!rl.wide);
if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
resetDef(cUnit, rl.lowReg);
}
-static void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
+extern void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
{
assert(rl.wide);
if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
resetDef(cUnit, rl.highReg);
}
-static void resetDefTracking(CompilationUnit *cUnit)
+extern void resetDefTracking(CompilationUnit *cUnit)
{
int i;
for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
}
}
-static void clobberAllRegs(CompilationUnit *cUnit)
+extern void clobberAllRegs(CompilationUnit *cUnit)
{
int i;
for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
}
/* To be used when explicitly managing register use */
-static void lockAllTemps(CompilationUnit *cUnit)
+extern void lockAllTemps(CompilationUnit *cUnit)
{
int i;
for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
}
}
-static void flushAllRegs(CompilationUnit *cUnit)
+extern void flushAllRegs(CompilationUnit *cUnit)
{
flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
cUnit->regPool->numCoreTemps);
}
}
-static void markRegLive(CompilationUnit *cUnit, int reg, int sReg)
+extern void markRegLive(CompilationUnit *cUnit, int reg, int sReg)
{
RegisterInfo *info = getRegInfo(cUnit, reg);
if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
info->sReg = sReg;
}
-static void markRegPair(CompilationUnit *cUnit, int lowReg, int highReg)
+extern void markRegPair(CompilationUnit *cUnit, int lowReg, int highReg)
{
RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
info->pair = false;
}
-static void markRegClean(CompilationUnit *cUnit, int reg)
+extern void markRegClean(CompilationUnit *cUnit, int reg)
{
RegisterInfo *info = getRegInfo(cUnit, reg);
info->dirty = false;
}
-static void markRegDirty(CompilationUnit *cUnit, int reg)
+extern void markRegDirty(CompilationUnit *cUnit, int reg)
{
RegisterInfo *info = getRegInfo(cUnit, reg);
info->dirty = true;
}
-static void markRegInUse(CompilationUnit *cUnit, int reg)
+extern void markRegInUse(CompilationUnit *cUnit, int reg)
{
- RegisterInfo *info = getRegInfo(cUnit, reg);
- info->inUse = true;
+ RegisterInfo *info = getRegInfo(cUnit, reg);
+ info->inUse = true;
}
/* Return true if live & dirty */
* is a bit complex when dealing with FP regs. Examine code to see
* if it's worthwhile trying to be more clever here.
*/
-static RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc)
+extern RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc)
{
assert(!loc.wide);
if (loc.location == kLocDalvikFrame) {
}
/* see comments for updateLoc */
-static RegLocation updateLocWide(CompilationUnit *cUnit, RegLocation loc)
+extern RegLocation updateLocWide(CompilationUnit *cUnit, RegLocation loc)
{
assert(loc.wide);
if (loc.location == kLocDalvikFrame) {
assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
if (!regClassMatches(regClass, loc.lowReg)) {
/* Wrong register class. Reallocate and copy */
- newRegs = allocTypedTempPair(cUnit, loc.fp, regClass);
+ newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
lowReg = newRegs & 0xff;
highReg = (newRegs >> 8) & 0xff;
- genRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
- loc.highReg);
+ dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
+ loc.highReg);
copyRegInfo(cUnit, lowReg, loc.lowReg);
copyRegInfo(cUnit, highReg, loc.highReg);
clobberReg(cUnit, loc.lowReg);
}
assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
- assert((loc.location != kLocRetval) || (hiSReg(loc.sRegLow) == INVALID_SREG));
+ assert((loc.location != kLocRetval) ||
+ (hiSReg(loc.sRegLow) == INVALID_SREG));
- newRegs = allocTypedTempPair(cUnit, loc.fp, regClass);
+ newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
loc.lowReg = newRegs & 0xff;
loc.highReg = (newRegs >> 8) & 0xff;
return loc;
}
-static RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
+extern RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
int regClass, bool update)
{
RegisterInfo *infoLo = NULL;
if (loc.location == kLocPhysReg) {
if (!regClassMatches(regClass, loc.lowReg)) {
/* Wrong register class. Realloc, copy and transfer ownership */
- newReg = allocTypedTemp(cUnit, loc.fp, regClass);
- genRegCopy(cUnit, newReg, loc.lowReg);
+ newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
+ dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
copyRegInfo(cUnit, newReg, loc.lowReg);
clobberReg(cUnit, loc.lowReg);
loc.lowReg = newReg;
assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
- newReg = allocTypedTemp(cUnit, loc.fp, regClass);
+ newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
loc.lowReg = newReg;
if (update) {
return loc;
}
-static inline int getSrcSSAName(MIR *mir, int num)
-{
- assert(mir->ssaRep->numUses > num);
- return mir->ssaRep->uses[num];
-}
-
static inline int getDestSSAName(MIR *mir, int num)
{
assert(mir->ssaRep->numDefs > num);
}
// Get the LocRecord associated with an SSA name use.
-static inline RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num)
+extern RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num)
{
RegLocation loc = cUnit->regLocation[SREG(cUnit, getSrcSSAName(mir, num))];
loc.fp = cUnit->regLocation[getSrcSSAName(mir, num)].fp;
}
// Get the LocRecord associated with an SSA name def.
-static inline RegLocation getDestLoc(CompilationUnit *cUnit, MIR *mir, int num)
+extern RegLocation getDestLoc(CompilationUnit *cUnit, MIR *mir, int num)
{
RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
lowLoc.highReg = highLoc.lowReg;
return lowLoc;
}
-static RegLocation getDestLocWide(CompilationUnit *cUnit, MIR *mir,
+
+extern RegLocation getDestLocWide(CompilationUnit *cUnit, MIR *mir,
int low, int high)
{
return getLocWide(cUnit, mir, low, high, false);
}
-static RegLocation getSrcLocWide(CompilationUnit *cUnit, MIR *mir,
+extern RegLocation getSrcLocWide(CompilationUnit *cUnit, MIR *mir,
int low, int high)
{
return getLocWide(cUnit, mir, low, high, true);
}
-/* Reset the tracker to unknown state */
-static inline void resetNullCheckTracker(CompilationUnit *cUnit)
-{
- dvmClearAllBits(cUnit->regPool->nullCheckedRegs);
-}
-
-static RegLocation getReturnLocWide(CompilationUnit *cUnit)
+extern RegLocation getReturnLocWide(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN_WIDE;
clobberReg(cUnit, r0);
return res;
}
-static RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
+extern RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN_WIDE;
res.lowReg = r2;
return res;
}
-static RegLocation getReturnLoc(CompilationUnit *cUnit)
+extern RegLocation getReturnLoc(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN;
clobberReg(cUnit, r0);
return res;
}
-static RegLocation getReturnLocAlt(CompilationUnit *cUnit)
+extern RegLocation getReturnLocAlt(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN;
res.lowReg = r1;
}
/* Kill the corresponding bit in the null-checked register list */
-static inline void killNullCheckedLocation(CompilationUnit *cUnit,
+extern void killNullCheckedLocation(CompilationUnit *cUnit,
RegLocation loc)
{
if (loc.location != kLocRetval) {
}
}
}
+
+extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
+ int reg1, int reg2)
+{
+ flushRegWide(cUnit, reg1, reg2);
+}
+
+extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
+{
+ flushReg(cUnit, reg);
+}
*
*/
-#include "Codegen.h"
-
static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
static int corePreserved[] = {};
-void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
-{
- int i;
- int numTemps = sizeof(coreTemps)/sizeof(int);
- RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
- cUnit->regPool = pool;
- pool->numCoreTemps = numTemps;
- pool->coreTemps =
- dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
- pool->numFPTemps = 0;
- pool->FPTemps = NULL;
- pool->numCoreRegs = 0;
- pool->coreRegs = NULL;
- pool->numFPRegs = 0;
- pool->FPRegs = NULL;
- initPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
- initPool(pool->FPTemps, NULL, 0);
- initPool(pool->coreRegs, NULL, 0);
- initPool(pool->FPRegs, NULL, 0);
- pool->nullCheckedRegs =
- dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
-}
-/*
- * Alloc a pair of core registers, or a double. Low reg in low byte,
- * high reg in next byte.
- */
-static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint, int regClass)
-{
- int highReg;
- int lowReg;
- int res = 0;
- lowReg = allocTemp(cUnit);
- highReg = allocTemp(cUnit);
- res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
- return res;
-}
+/* FIXME - circular dependency */
+static void storePair(CompilationUnit *cUnit, int base, int lowReg,
+ int highReg);
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
+static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+ int rDest);
+static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+ int displacement, int rSrc);
+static ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
+ ArmConditionCode cond,
+ int reg1, int reg2, int dOffset,
+ ArmLIR *pcrLabel);
-static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
-{
- return allocTemp(cUnit);
-}
-ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool. If target is
+ * a high register, build constant into a low register and copy.
+ */
+static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
{
- ArmLIR* res;
- ArmOpCode opCode;
- res = dvmCompilerNew(sizeof(ArmLIR), true);
- if (LOWREG(rDest) && LOWREG(rSrc))
- opCode = kThumbMovRR;
- else if (!LOWREG(rDest) && !LOWREG(rSrc))
- opCode = kThumbMovRR_H2H;
- else if (LOWREG(rDest))
- opCode = kThumbMovRR_H2L;
- else
- opCode = kThumbMovRR_L2H;
+ ArmLIR *res;
+ int tDest = LOWREG(rDest) ? rDest : allocTemp(cUnit);
+ /* See if the value can be constructed cheaply */
+ if ((value >= 0) && (value <= 255)) {
+ res = newLIR2(cUnit, kThumbMovImm, tDest, value);
+ if (rDest != tDest) {
+ opRegReg(cUnit, kOpMov, rDest, tDest);
+ freeTemp(cUnit, tDest);
+ }
+ return res;
+ } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
+ res = newLIR2(cUnit, kThumbMovImm, tDest, ~value);
+ newLIR2(cUnit, kThumbMvn, tDest, tDest);
+ if (rDest != tDest) {
+ opRegReg(cUnit, kOpMov, rDest, tDest);
+ freeTemp(cUnit, tDest);
+ }
+ return res;
+ }
+ /* No shortcut - go ahead and use literal pool */
+ ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
+ if (dataTarget == NULL) {
+ dataTarget = addWordData(cUnit, value, false);
+ }
+ ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
+ loadPcRel->opCode = kThumbLdrPcRel;
+ loadPcRel->generic.target = (LIR *) dataTarget;
+ loadPcRel->operands[0] = tDest;
+ setupResourceMasks(loadPcRel);
+ res = loadPcRel;
+ dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
- res->operands[0] = rDest;
- res->operands[1] = rSrc;
- res->opCode = opCode;
- setupResourceMasks(res);
- if (rDest == rSrc) {
- res->isNop = true;
+ /*
+ * To save space in the constant pool, we use the ADD_RRI8 instruction to
+ * add up to 255 to an existing constant value.
+ */
+ if (dataTarget->operands[0] != value) {
+ newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]);
+ }
+ if (rDest != tDest) {
+ opRegReg(cUnit, kOpMov, rDest, tDest);
+ freeTemp(cUnit, tDest);
}
return res;
}
-void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
- int srcLo, int srcHi)
+/*
+ * Load an immediate value into a fixed or temp register. Target
+ * register is clobbered, and marked inUse.
+ */
+static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
{
- // Handle overlap
- if (srcHi == destLo) {
- genRegCopy(cUnit, destHi, srcHi);
- genRegCopy(cUnit, destLo, srcLo);
- } else {
- genRegCopy(cUnit, destLo, srcLo);
- genRegCopy(cUnit, destHi, srcHi);
+ if (isTemp(cUnit, rDest)) {
+ clobberReg(cUnit, rDest);
+ markRegInUse(cUnit, rDest);
}
-}
-
-/* Export the Dalvik PC assicated with an instruction to the StackSave area */
-static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
-{
- ArmLIR *res;
- int rDPC = allocTemp(cUnit);
- int rAddr = allocTemp(cUnit);
- int offset = offsetof(StackSaveArea, xtra.currentPc);
- res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
- newLIR2(cUnit, kThumbMovRR, rAddr, rFP);
- newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset);
- storeWordDisp( cUnit, rAddr, 0, rDPC);
- return res;
+ return loadConstantValue(cUnit, rDest, value);
}
static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
return res;
}
-static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
- int rSrc);
-
static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
int rSrc1, int rSrc2)
{
return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
}
-static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
- OpKind secondOp, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
-{
- RegLocation rlResult;
- if (rlDest.sRegLow == rlSrc1.sRegLow) {
- // Already 2-operand
- rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
- rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
- opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
- opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
- storeValueWide(cUnit, rlDest, rlResult);
- } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
- // Bad case - must use/clobber Src1 and reassign Dest
- rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
- rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
- opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg);
- opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg);
- // Old reg assignments are now invalid
- clobberReg(cUnit, rlResult.lowReg);
- clobberReg(cUnit, rlResult.highReg);
- clobberReg(cUnit, rlSrc1.lowReg);
- clobberReg(cUnit, rlSrc1.highReg);
- rlDest.location = kLocDalvikFrame;
- assert(rlSrc1.location == kLocPhysReg);
- // Reassign registers - rlDest will now get rlSrc1's old regs
- storeValueWide(cUnit, rlDest, rlSrc1);
- } else {
- // Copy Src1 to Dest
- rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
- rlResult = evalLoc(cUnit, rlDest, kCoreReg, false);
- loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg,
- rlResult.highReg);
- rlResult.location = kLocPhysReg;
- opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
- opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
- storeValueWide(cUnit, rlDest, rlResult);
- }
-}
-
static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
int rSrc1, int value)
{
return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
}
-
-static void handleMonitor(CompilationUnit *cUnit, MIR *mir)
-{
- handleMonitorPortable(cUnit, mir);
-}
-
-static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc)
-{
- RegLocation rlResult;
- rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
- rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
- rlSrc.lowReg, 0x80000000);
- storeValue(cUnit, rlDest, rlResult);
-}
-
-static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc)
-{
- RegLocation rlResult;
- rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
- rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
- 0x80000000);
- genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
- storeValueWide(cUnit, rlDest, rlResult);
-}
-
-static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
-{
- RegLocation rlResult;
- loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
- loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
- genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
- rlResult = getReturnLocWide(cUnit);
- storeValueWide(cUnit, rlDest, rlResult);
-}
-
-static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
+static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+ int rDestHi, int valLo, int valHi)
{
- RegLocation rlResult;
- loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
- loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
- genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
- rlResult = getReturnLoc(cUnit);
- storeValue(cUnit, rlDest, rlResult);
+ ArmLIR *res;
+ res = loadConstantValue(cUnit, rDestLo, valLo);
+ loadConstantValue(cUnit, rDestHi, valHi);
+ return res;
}
/* Load value from base + scaled index. */
return res;
}
-
-static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
-{
- if (lowReg < highReg) {
- loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
- } else {
- loadWordDisp(cUnit, base, 0 , lowReg);
- loadWordDisp(cUnit, base, 4 , highReg);
- }
-}
-
static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
int displacement, int rDest, int rDestHi,
- OpSize size, bool nullCheck, int sReg)
+ OpSize size, int sReg)
/*
* Load value from base + displacement. Optionally perform null check
* on base (which must have an associated sReg and MIR). If not
* rlp and then restore.
*/
{
- ArmLIR *first = NULL;
ArmLIR *res;
ArmLIR *load = NULL;
ArmLIR *load2 = NULL;
default:
assert(0);
}
- if (nullCheck)
- first = genNullCheck(cUnit, sReg, rBase, mir->offset, NULL);
if (shortForm) {
load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
if (pair) {
}
}
- return (first) ? first : res;
+ return res;
}
static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
int displacement, int rDest, OpSize size,
- bool nullCheck, int sReg)
+ int sReg)
{
return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
- size, nullCheck, sReg);
+ size, sReg);
}
static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
int displacement, int rDestLo, int rDestHi,
- bool nullCheck, int sReg)
+ int sReg)
{
return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
- kLong, nullCheck, sReg);
+ kLong, sReg);
}
-static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
-{
- if (lowReg < highReg) {
- storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
- } else {
- storeWordDisp(cUnit, base, 0, lowReg);
- storeWordDisp(cUnit, base, 4, highReg);
- }
-}
-
-
static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
int displacement, int rSrc, int rSrcHi,
OpSize size)
return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
}
-
-/*
- * Perform a "reg cmp imm" operation and jump to the PCR region if condition
- * satisfies.
- */
-static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
- ArmConditionCode cond, int reg,
- int checkValue, int dOffset,
- ArmLIR *pcrLabel)
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
{
- int tReg;
- ArmLIR *res;
- if ((checkValue & 0xff) != checkValue) {
- tReg = allocTemp(cUnit);
- loadConstant(cUnit, tReg, checkValue);
- res = genRegRegCheck(cUnit, cond, reg, tReg, dOffset, pcrLabel);
- freeTemp(cUnit, tReg);
- return res;
+ if (lowReg < highReg) {
+ storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
+ } else {
+ storeWordDisp(cUnit, base, 0, lowReg);
+ storeWordDisp(cUnit, base, 4, highReg);
}
- newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
- ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond);
- return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
-}
-
-static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
-{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
- int offset = offsetof(InterpState, retval);
- RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
- int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
- int reg1 = allocTemp(cUnit);
- genNullCheck(cUnit, getSrcSSAName(mir, 0), regObj, mir->offset, NULL);
- loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
- storeWordDisp(cUnit, rGLUE, offset, reg1);
- return false;
}
-static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
-{
- DecodedInstruction *dInsn = &mir->dalvikInsn;
- int offset = offsetof(InterpState, retval);
- int contents = offsetof(ArrayObject, contents);
- RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
- RegLocation rlIdx = getSrcLoc(cUnit, mir, 1);
- int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
- int regIdx = loadValue(cUnit, rlIdx, kCoreReg).lowReg;
- int regMax = allocTemp(cUnit);
- int regOff = allocTemp(cUnit);
- ArmLIR * pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0),
- regObj, mir->offset, NULL);
- loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
- loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
- loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
- genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
-
- newLIR2(cUnit, kThumbAddRI8, regObj, contents);
- newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regOff);
- newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regIdx);
- newLIR3(cUnit, kThumbLdrhRRR, regMax, regObj, regIdx);
- freeTemp(cUnit, regOff);
- storeWordDisp(cUnit, rGLUE, offset, regMax);
-//FIXME: rewrite this to not clobber
- clobberReg(cUnit, regObj);
- clobberReg(cUnit, regIdx);
- return false;
-}
-
-static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
{
- int offset = offsetof(InterpState, retval);
- RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
- int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
- int sign = allocTemp(cUnit);
- /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
- newLIR3(cUnit, kThumbAsrRRI5, sign, reg0, 31);
- newLIR3(cUnit, kThumbAddRRR, reg0, reg0, sign);
- newLIR2(cUnit, kThumbEorRR, reg0, sign);
- freeTemp(cUnit, sign);
- storeWordDisp(cUnit, rGLUE, offset, reg0);
-//FIXME: rewrite this to not clobber
- clobberReg(cUnit, reg0);
- return false;
+ if (lowReg < highReg) {
+ loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
+ } else {
+ loadWordDisp(cUnit, base, 0 , lowReg);
+ loadWordDisp(cUnit, base, 4 , highReg);
+ }
}
-static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
+static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
{
- int offset = offsetof(InterpState, retval);
- RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
- int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
- int signMask = allocTemp(cUnit);
- loadConstant(cUnit, signMask, 0x7fffffff);
- newLIR2(cUnit, kThumbAndRR, reg0, signMask);
- freeTemp(cUnit, signMask);
- storeWordDisp(cUnit, rGLUE, offset, reg0);
-//FIXME: rewrite this to not clobber
- clobberReg(cUnit, reg0);
- return true;
-}
+ ArmLIR* res;
+ ArmOpCode opCode;
+ res = dvmCompilerNew(sizeof(ArmLIR), true);
+ if (LOWREG(rDest) && LOWREG(rSrc))
+ opCode = kThumbMovRR;
+ else if (!LOWREG(rDest) && !LOWREG(rSrc))
+ opCode = kThumbMovRR_H2H;
+ else if (LOWREG(rDest))
+ opCode = kThumbMovRR_H2L;
+ else
+ opCode = kThumbMovRR_L2H;
-static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
-{
- int offset = offsetof(InterpState, retval);
- RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
- int reglo = regSrc.lowReg;
- int reghi = regSrc.highReg;
- int signMask = allocTemp(cUnit);
- loadConstant(cUnit, signMask, 0x7fffffff);
- storeWordDisp(cUnit, rGLUE, offset, reglo);
- newLIR2(cUnit, kThumbAndRR, reghi, signMask);
- freeTemp(cUnit, signMask);
- storeWordDisp(cUnit, rGLUE, offset + 4, reghi);
-//FIXME: rewrite this to not clobber
- clobberReg(cUnit, reghi);
- return true;
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ res->opCode = opCode;
+ setupResourceMasks(res);
+ if (rDest == rSrc) {
+ res->isNop = true;
+ }
+ return res;
}
-/* No select in thumb, so we need to branch. Thumb2 will do better */
-static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
+static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
{
- int offset = offsetof(InterpState, retval);
- RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
- RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
- int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
- int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
- newLIR2(cUnit, kThumbCmpRR, reg0, reg1);
- ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2,
- isMin ? kArmCondLt : kArmCondGt);
- newLIR2(cUnit, kThumbMovRR, reg0, reg1);
- ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
- target->defMask = ENCODE_ALL;
- newLIR3(cUnit, kThumbStrRRI5, reg0, rGLUE, offset >> 2);
- branch1->generic.target = (LIR *)target;
-//FIXME: rewrite this to not clobber
- clobberReg(cUnit,reg0);
- return false;
+ ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+ dvmCompilerAppendLIR(cUnit, (LIR*)res);
+ return res;
}
-static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+ int srcLo, int srcHi)
{
- int offset = offsetof(InterpState, retval);
- RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
- int oplo = regSrc.lowReg;
- int ophi = regSrc.highReg;
- int sign = allocTemp(cUnit);
- /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
- newLIR3(cUnit, kThumbAsrRRI5, sign, ophi, 31);
- newLIR3(cUnit, kThumbAddRRR, oplo, oplo, sign);
- newLIR2(cUnit, kThumbAdcRR, ophi, sign);
- newLIR2(cUnit, kThumbEorRR, oplo, sign);
- newLIR2(cUnit, kThumbEorRR, ophi, sign);
- freeTemp(cUnit, sign);
- storeWordDisp(cUnit, rGLUE, offset, oplo);
- storeWordDisp(cUnit, rGLUE, offset + 4, ophi);
-//FIXME: rewrite this to not clobber
- clobberReg(cUnit, oplo);
- clobberReg(cUnit, ophi);
- return false;
+ // Handle overlap
+ if (srcHi == destLo) {
+ genRegCopy(cUnit, destHi, srcHi);
+ genRegCopy(cUnit, destLo, srcLo);
+ } else {
+ genRegCopy(cUnit, destLo, srcLo);
+ genRegCopy(cUnit, destHi, srcHi);
+ }
}
-
-/*
- * Load a immediate using a shortcut if possible; otherwise
- * grab from the per-translation literal pool. If target is
- * a high register, build constant into a low register and copy.
- */
-static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
+static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
+ ArmConditionCode cond, int reg,
+ int checkValue, int dOffset,
+ ArmLIR *pcrLabel)
{
+ int tReg;
ArmLIR *res;
- int tDest = LOWREG(rDest) ? rDest : allocTemp(cUnit);
- /* See if the value can be constructed cheaply */
- if ((value >= 0) && (value <= 255)) {
- res = newLIR2(cUnit, kThumbMovImm, tDest, value);
- if (rDest != tDest) {
- opRegReg(cUnit, kOpMov, rDest, tDest);
- freeTemp(cUnit, tDest);
- }
- return res;
- } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
- res = newLIR2(cUnit, kThumbMovImm, tDest, ~value);
- newLIR2(cUnit, kThumbMvn, tDest, tDest);
- if (rDest != tDest) {
- opRegReg(cUnit, kOpMov, rDest, tDest);
- freeTemp(cUnit, tDest);
- }
+ if ((checkValue & 0xff) != checkValue) {
+ tReg = allocTemp(cUnit);
+ loadConstant(cUnit, tReg, checkValue);
+ res = genRegRegCheck(cUnit, cond, reg, tReg, dOffset, pcrLabel);
+ freeTemp(cUnit, tReg);
return res;
}
- /* No shortcut - go ahead and use literal pool */
- ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
- if (dataTarget == NULL) {
- dataTarget = addWordData(cUnit, value, false);
- }
- ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
- loadPcRel->opCode = kThumbLdrPcRel;
- loadPcRel->generic.target = (LIR *) dataTarget;
- loadPcRel->operands[0] = tDest;
- setupResourceMasks(loadPcRel);
- res = loadPcRel;
- dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
-
- /*
- * To save space in the constant pool, we use the ADD_RRI8 instruction to
- * add up to 255 to an existing constant value.
- */
- if (dataTarget->operands[0] != value) {
- newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]);
- }
- if (rDest != tDest) {
- opRegReg(cUnit, kOpMov, rDest, tDest);
- freeTemp(cUnit, tDest);
- }
- return res;
-}
-
-static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
- int rDestHi, int valLo, int valHi)
-{
- ArmLIR *res;
- res = loadConstantValue(cUnit, rDestLo, valLo);
- loadConstantValue(cUnit, rDestHi, valHi);
- return res;
+ newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
+ ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond);
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
}
--- /dev/null
+/*
+ * 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 for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
+ rlSrc.lowReg, 0x80000000);
+ storeValue(cUnit, rlDest, rlResult);
+}
+
+static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
+ 0x80000000);
+ genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+ genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+ rlResult = getReturnLocWide(cUnit);
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
+ OpKind secondOp, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ if (rlDest.sRegLow == rlSrc1.sRegLow) {
+ // Already 2-operand
+ rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
+ opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
+ // Bad case - must use/clobber Src1 and reassign Dest
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+ opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg);
+ opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg);
+ // Old reg assignments are now invalid
+ clobberReg(cUnit, rlResult.lowReg);
+ clobberReg(cUnit, rlResult.highReg);
+ clobberReg(cUnit, rlSrc1.lowReg);
+ clobberReg(cUnit, rlSrc1.highReg);
+ rlDest.location = kLocDalvikFrame;
+ assert(rlSrc1.location == kLocPhysReg);
+ // Reassign registers - rlDest will now get rlSrc1's old regs
+ storeValueWide(cUnit, rlDest, rlSrc1);
+ } else {
+ // Copy Src1 to Dest
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ rlResult = evalLoc(cUnit, rlDest, kCoreReg, false);
+ loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg,
+ rlResult.highReg);
+ rlResult.location = kLocPhysReg;
+ opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
+ opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ }
+}
+
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
+{
+ int i;
+ int numTemps = sizeof(coreTemps)/sizeof(int);
+ RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
+ cUnit->regPool = pool;
+ pool->numCoreTemps = numTemps;
+ pool->coreTemps =
+ dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
+ pool->numFPTemps = 0;
+ pool->FPTemps = NULL;
+ pool->numCoreRegs = 0;
+ pool->coreRegs = NULL;
+ pool->numFPRegs = 0;
+ pool->FPRegs = NULL;
+ initPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
+ initPool(pool->FPTemps, NULL, 0);
+ initPool(pool->coreRegs, NULL, 0);
+ initPool(pool->FPRegs, NULL, 0);
+ pool->nullCheckedRegs =
+ dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
+}
+
+/* Export the Dalvik PC assicated with an instruction to the StackSave area */
+static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
+{
+ ArmLIR *res;
+ int rDPC = allocTemp(cUnit);
+ int rAddr = allocTemp(cUnit);
+ int offset = offsetof(StackSaveArea, xtra.currentPc);
+ res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
+ newLIR2(cUnit, kThumbMovRR, rAddr, rFP);
+ newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset);
+ storeWordDisp( cUnit, rAddr, 0, rDPC);
+ return res;
+}
+
+static void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+ genMonitorPortable(cUnit, mir);
+}
+
+static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+ loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+ genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
+ rlResult = getReturnLoc(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+}
+
+static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int offset = offsetof(InterpState, retval);
+ RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+ int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
+ int reg1 = allocTemp(cUnit);
+ genNullCheck(cUnit, getSrcSSAName(mir, 0), regObj, mir->offset, NULL);
+ loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
+ storeWordDisp(cUnit, rGLUE, offset, reg1);
+ return false;
+}
+
+static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int offset = offsetof(InterpState, retval);
+ int contents = offsetof(ArrayObject, contents);
+ RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+ RegLocation rlIdx = getSrcLoc(cUnit, mir, 1);
+ int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
+ int regIdx = loadValue(cUnit, rlIdx, kCoreReg).lowReg;
+ int regMax = allocTemp(cUnit);
+ int regOff = allocTemp(cUnit);
+ ArmLIR * pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0),
+ regObj, mir->offset, NULL);
+ loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
+ loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
+ loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
+ genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
+
+ newLIR2(cUnit, kThumbAddRI8, regObj, contents);
+ newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regOff);
+ newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regIdx);
+ newLIR3(cUnit, kThumbLdrhRRR, regMax, regObj, regIdx);
+ freeTemp(cUnit, regOff);
+ storeWordDisp(cUnit, rGLUE, offset, regMax);
+//FIXME: rewrite this to not clobber
+ clobberReg(cUnit, regObj);
+ clobberReg(cUnit, regIdx);
+ return false;
+}
+
+static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
+{
+ int offset = offsetof(InterpState, retval);
+ RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+ int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
+ int sign = allocTemp(cUnit);
+ /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
+ newLIR3(cUnit, kThumbAsrRRI5, sign, reg0, 31);
+ newLIR3(cUnit, kThumbAddRRR, reg0, reg0, sign);
+ newLIR2(cUnit, kThumbEorRR, reg0, sign);
+ freeTemp(cUnit, sign);
+ storeWordDisp(cUnit, rGLUE, offset, reg0);
+//FIXME: rewrite this to not clobber
+ clobberReg(cUnit, reg0);
+ return false;
+}
+
+static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
+{
+ int offset = offsetof(InterpState, retval);
+ RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+ int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
+ int signMask = allocTemp(cUnit);
+ loadConstant(cUnit, signMask, 0x7fffffff);
+ newLIR2(cUnit, kThumbAndRR, reg0, signMask);
+ freeTemp(cUnit, signMask);
+ storeWordDisp(cUnit, rGLUE, offset, reg0);
+//FIXME: rewrite this to not clobber
+ clobberReg(cUnit, reg0);
+ return true;
+}
+
+static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
+{
+ int offset = offsetof(InterpState, retval);
+ RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ int reglo = regSrc.lowReg;
+ int reghi = regSrc.highReg;
+ int signMask = allocTemp(cUnit);
+ loadConstant(cUnit, signMask, 0x7fffffff);
+ storeWordDisp(cUnit, rGLUE, offset, reglo);
+ newLIR2(cUnit, kThumbAndRR, reghi, signMask);
+ freeTemp(cUnit, signMask);
+ storeWordDisp(cUnit, rGLUE, offset + 4, reghi);
+//FIXME: rewrite this to not clobber
+ clobberReg(cUnit, reghi);
+ return true;
+}
+
+/* No select in thumb, so we need to branch. Thumb2 will do better */
+static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
+{
+ int offset = offsetof(InterpState, retval);
+ RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
+ RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
+ int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
+ int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
+ newLIR2(cUnit, kThumbCmpRR, reg0, reg1);
+ ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2,
+ isMin ? kArmCondLt : kArmCondGt);
+ newLIR2(cUnit, kThumbMovRR, reg0, reg1);
+ ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ newLIR3(cUnit, kThumbStrRRI5, reg0, rGLUE, offset >> 2);
+ branch1->generic.target = (LIR *)target;
+//FIXME: rewrite this to not clobber
+ clobberReg(cUnit,reg0);
+ return false;
+}
+
+static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
+{
+ int offset = offsetof(InterpState, retval);
+ RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ int oplo = regSrc.lowReg;
+ int ophi = regSrc.highReg;
+ int sign = allocTemp(cUnit);
+ /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
+ newLIR3(cUnit, kThumbAsrRRI5, sign, ophi, 31);
+ newLIR3(cUnit, kThumbAddRRR, oplo, oplo, sign);
+ newLIR2(cUnit, kThumbAdcRR, ophi, sign);
+ newLIR2(cUnit, kThumbEorRR, oplo, sign);
+ newLIR2(cUnit, kThumbEorRR, ophi, sign);
+ freeTemp(cUnit, sign);
+ storeWordDisp(cUnit, rGLUE, offset, oplo);
+ storeWordDisp(cUnit, rGLUE, offset + 4, ophi);
+//FIXME: rewrite this to not clobber
+ clobberReg(cUnit, oplo);
+ clobberReg(cUnit, ophi);
+ return false;
+}
--- /dev/null
+/*
+ * 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 for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Alloc a pair of core registers, or a double. Low reg in low byte,
+ * high reg in next byte.
+ */
+int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
+ int regClass)
+{
+ int highReg;
+ int lowReg;
+ int res = 0;
+ lowReg = allocTemp(cUnit);
+ highReg = allocTemp(cUnit);
+ res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+ return res;
+}
+
+int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+ return allocTemp(cUnit);
+}
*
*/
-#include "Codegen.h"
+static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
+static int corePreserved[] = {};
+static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
+ fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
+static int fpPreserved[] = {};
+
+static int encodeImmSingle(int value)
+{
+ int res;
+ int bitA = (value & 0x80000000) >> 31;
+ int notBitB = (value & 0x40000000) >> 30;
+ int bitB = (value & 0x20000000) >> 29;
+ int bSmear = (value & 0x3e000000) >> 25;
+ int slice = (value & 0x01f80000) >> 19;
+ int zeroes = (value & 0x0007ffff);
+ if (zeroes != 0)
+ return -1;
+ if (bitB) {
+ if ((notBitB != 0) || (bSmear != 0x1f))
+ return -1;
+ } else {
+ if ((notBitB != 1) || (bSmear != 0x0))
+ return -1;
+ }
+ res = (bitA << 7) | (bitB << 6) | slice;
+ return res;
+}
+
+static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
+ int value)
+{
+ int encodedImm = encodeImmSingle(value);
+ assert(SINGLEREG(rDest));
+ if (encodedImm >= 0) {
+ return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
+ }
+ ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
+ if (dataTarget == NULL) {
+ dataTarget = addWordData(cUnit, value, false);
+ }
+ ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
+ loadPcRel->opCode = kThumb2Vldrs;
+ loadPcRel->generic.target = (LIR *) dataTarget;
+ loadPcRel->operands[0] = rDest;
+ loadPcRel->operands[1] = rpc;
+ setupResourceMasks(loadPcRel);
+ dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+ return loadPcRel;
+}
static int leadingZeros(u4 val)
{
}
/*
- * Determine whether value can be encoded as a Thumb2 floating point
- * immediate. If not, return -1. If so return encoded 8-bit value.
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool.
*/
-static int encodeImmDoubleHigh(int value)
+static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
{
- int res;
- int bitA = (value & 0x80000000) >> 31;
- int notBitB = (value & 0x40000000) >> 30;
- int bitB = (value & 0x20000000) >> 29;
- int bSmear = (value & 0x3fc00000) >> 22;
- int slice = (value & 0x003f0000) >> 16;
- int zeroes = (value & 0x0000ffff);
- if (zeroes != 0)
- return -1;
- if (bitB) {
- if ((notBitB != 0) || (bSmear != 0x1f))
- return -1;
- } else {
- if ((notBitB != 1) || (bSmear != 0x0))
- return -1;
- }
- res = (bitA << 7) | (bitB << 6) | slice;
- return res;
-}
+ ArmLIR *res;
+ int modImm;
-static int encodeImmSingle(int value)
-{
- int res;
- int bitA = (value & 0x80000000) >> 31;
- int notBitB = (value & 0x40000000) >> 30;
- int bitB = (value & 0x20000000) >> 29;
- int bSmear = (value & 0x3e000000) >> 25;
- int slice = (value & 0x01f80000) >> 19;
- int zeroes = (value & 0x0007ffff);
- if (zeroes != 0)
- return -1;
- if (bitB) {
- if ((notBitB != 0) || (bSmear != 0x1f))
- return -1;
- } else {
- if ((notBitB != 1) || (bSmear != 0x0))
- return -1;
+ if (FPREG(rDest)) {
+ return loadFPConstantValue(cUnit, rDest, value);
}
- res = (bitA << 7) | (bitB << 6) | slice;
- return res;
-}
-static int encodeImmDouble(int valLo, int valHi)
-{
- int res = -1;
- if (valLo == 0)
- res = encodeImmDoubleHigh(valHi);
- return res;
-}
-void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
- int srcLo, int srcHi)
-{
- bool destFP = FPREG(destLo) && FPREG(destHi);
- bool srcFP = FPREG(srcLo) && FPREG(srcHi);
- assert(FPREG(srcLo) == FPREG(srcHi));
- assert(FPREG(destLo) == FPREG(destHi));
- if (destFP) {
- if (srcFP) {
- genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
- } else {
- newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
- }
- } else {
- if (srcFP) {
- newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
- } else {
- // Handle overlap
- if (srcHi == destLo) {
- genRegCopy(cUnit, destHi, srcHi);
- genRegCopy(cUnit, destLo, srcLo);
- } else {
- genRegCopy(cUnit, destLo, srcLo);
- genRegCopy(cUnit, destHi, srcHi);
- }
- }
+ /* See if the value can be constructed cheaply */
+ if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
+ return newLIR2(cUnit, kThumbMovImm, rDest, value);
}
-}
-
-
-static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
-static int corePreserved[] = {};
-static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
- fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
-static int fpPreserved[] = {};
-void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
-{
- int i;
- int numTemps = sizeof(coreTemps)/sizeof(int);
- int numFPTemps = sizeof(fpTemps)/sizeof(int);
- RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
- cUnit->regPool = pool;
- pool->numCoreTemps = numTemps;
- pool->coreTemps =
- dvmCompilerNew(numTemps * sizeof(*cUnit->regPool->coreTemps), true);
- pool->numFPTemps = numFPTemps;
- pool->FPTemps =
- dvmCompilerNew(numFPTemps * sizeof(*cUnit->regPool->FPTemps), true);
- pool->numCoreRegs = 0;
- pool->coreRegs = NULL;
- pool->numFPRegs = 0;
- pool->FPRegs = NULL;
- initPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
- initPool(pool->FPTemps, fpTemps, pool->numFPTemps);
- initPool(pool->coreRegs, NULL, 0);
- initPool(pool->FPRegs, NULL, 0);
- pool->nullCheckedRegs =
- dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
-}
-
-
-/*
- * Alloc a pair of core registers, or a double. Low reg in low byte,
- * high reg in next byte.
- */
-static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint, int regClass)
-{
- int highReg;
- int lowReg;
- int res = 0;
- if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
- lowReg = allocTempDouble(cUnit);
- highReg = lowReg + 1;
- } else {
- lowReg = allocTemp(cUnit);
- highReg = allocTemp(cUnit);
+ /* Check Modified immediate special cases */
+ modImm = modifiedImmediate(value);
+ if (modImm >= 0) {
+ res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
+ return res;
}
- res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
- return res;
-}
-
-static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
-{
- if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
- return allocTempFloat(cUnit);
- return allocTemp(cUnit);
-}
-
-static int encodeShift(int code, int amount) {
- return ((amount & 0x1f) << 2) | code;
-}
-
-/*
- * Generate a Thumb2 IT instruction, which can nullify up to
- * four subsequent instructions based on a condition and its
- * inverse. The condition applies to the first instruction, which
- * is executed if the condition is met. The string "guide" consists
- * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
- * A "T" means the instruction is executed if the condition is
- * met, and an "E" means the instruction is executed if the condition
- * is not met.
- */
-static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
- char *guide)
-{
- int mask;
- int condBit = code & 1;
- int altBit = condBit ^ 1;
- int mask3 = 0;
- int mask2 = 0;
- int mask1 = 0;
-
- //Note: case fallthroughs intentional
- switch(strlen(guide)) {
- case 3:
- mask1 = (guide[2] == 'T') ? condBit : altBit;
- case 2:
- mask2 = (guide[1] == 'T') ? condBit : altBit;
- case 1:
- mask3 = (guide[0] == 'T') ? condBit : altBit;
- break;
- case 0:
- break;
- default:
- assert(0);
- dvmAbort();
+ modImm = modifiedImmediate(~value);
+ if (modImm >= 0) {
+ res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
+ return res;
}
- mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
- (1 << (3 - strlen(guide)));
- return newLIR2(cUnit, kThumb2It, code, mask);
-}
-
-
-static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
-{
- ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
- res->operands[0] = rDest;
- res->operands[1] = rSrc;
- if (rDest == rSrc) {
- res->isNop = true;
- } else {
- assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
- if (DOUBLEREG(rDest)) {
- res->opCode = kThumb2Vmovd;
- } else {
- if (SINGLEREG(rDest)) {
- res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
- } else {
- assert(SINGLEREG(rSrc));
- res->opCode = kThumb2Fmrs;
- }
- }
- res->operands[0] = rDest;
- res->operands[1] = rSrc;
+ /* 16-bit immediate? */
+ if ((value & 0xffff) == value) {
+ res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
+ return res;
}
- setupResourceMasks(res);
- return res;
-}
-
-ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
-{
- ArmLIR* res;
- ArmOpCode opCode;
- if (FPREG(rDest) || FPREG(rSrc))
- return fpRegCopy(cUnit, rDest, rSrc);
- res = dvmCompilerNew(sizeof(ArmLIR), true);
- if (LOWREG(rDest) && LOWREG(rSrc))
- opCode = kThumbMovRR;
- else if (!LOWREG(rDest) && !LOWREG(rSrc))
- opCode = kThumbMovRR_H2H;
- else if (LOWREG(rDest))
- opCode = kThumbMovRR_H2L;
- else
- opCode = kThumbMovRR_L2H;
+ /* No shortcut - go ahead and use literal pool */
+ ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
+ if (dataTarget == NULL) {
+ dataTarget = addWordData(cUnit, value, false);
+ }
+ ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
+ loadPcRel->opCode = LOWREG(rDest) ? kThumbLdrPcRel : kThumb2LdrPcRel12;
+ loadPcRel->generic.target = (LIR *) dataTarget;
+ loadPcRel->operands[0] = rDest;
+ setupResourceMasks(loadPcRel);
+ res = loadPcRel;
+ dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
- res->operands[0] = rDest;
- res->operands[1] = rSrc;
- res->opCode = opCode;
- setupResourceMasks(res);
- if (rDest == rSrc) {
- res->isNop = true;
+ /*
+ * To save space in the constant pool, we use the ADD_RRI8 instruction to
+ * add up to 255 to an existing constant value.
+ */
+ if (dataTarget->operands[0] != value) {
+ opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
}
return res;
}
-/* Export the Dalvik PC assicated with an instruction to the StackSave area */
-static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
+/*
+ * Load an immediate value into a fixed or temp register. Target
+ * register is clobbered, and marked inUse.
+ */
+static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
{
- ArmLIR *res;
- int offset = offsetof(StackSaveArea, xtra.currentPc);
- int rDPC = allocTemp(cUnit);
- res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
- newLIR3(cUnit, kThumb2StrRRI8Predec, rDPC, rFP,
- sizeof(StackSaveArea) - offset);
- freeTemp(cUnit, rDPC);
- return res;
+ if (isTemp(cUnit, rDest)) {
+ clobberReg(cUnit, rDest);
+ markRegInUse(cUnit, rDest);
+ }
+ return loadConstantValue(cUnit, rDest, value);
}
static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
}
-static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
- OpKind secondOp, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
-{
- RegLocation rlResult;
- rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
- rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
- rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
- opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
- rlSrc2.highReg);
- storeValueWide(cUnit, rlDest, rlResult);
-}
-
static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
int rSrc1, int value)
{
}
}
-static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc)
-{
- RegLocation rlResult;
- rlSrc = loadValue(cUnit, rlSrc, kFPReg);
- rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
- storeValue(cUnit, rlDest, rlResult);
-}
-
-static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc)
-{
- RegLocation rlResult;
- rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
- rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
- S2D(rlSrc.lowReg, rlSrc.highReg));
- storeValueWide(cUnit, rlDest, rlResult);
-}
-
-/*
- * To avoid possible conflicts, we use a lot of temps here. Note that
- * our usage of Thumb2 instruction forms avoids the problems with register
- * reuse for multiply instructions prior to arm6.
- */
-static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
-{
- RegLocation rlResult;
- int resLo = allocTemp(cUnit);
- int resHi = allocTemp(cUnit);
- int tmp1 = allocTemp(cUnit);
-
- rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
- rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
-
- newLIR3(cUnit, kThumb2MulRRR, tmp1, rlSrc2.lowReg, rlSrc1.highReg);
- newLIR4(cUnit, kThumb2Umull, resLo, resHi, rlSrc2.lowReg, rlSrc1.lowReg);
- newLIR4(cUnit, kThumb2Mla, tmp1, rlSrc1.lowReg, rlSrc2.highReg, tmp1);
- newLIR4(cUnit, kThumb2AddRRR, resHi, tmp1, resHi, 0);
- freeTemp(cUnit, tmp1);
-
- rlResult = getReturnLocWide(cUnit); // Just as a template, will patch
- rlResult.lowReg = resLo;
- rlResult.highReg = resHi;
- storeValueWide(cUnit, rlDest, rlResult);
-}
-
/*
- * Handle simple case (thin lock) inline. If it's complicated, bail
- * out to the heavyweight lock/unlock routines. We'll use dedicated
- * registers here in order to be in the right position in case we
- * to bail to dvm[Lock/Unlock]Object(self, object)
- *
- * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
- * r1 -> object [arg1 for dvm[Lock/Unlock]Object
- * r2 -> intial contents of object->lock.thin, later result of strex
- * r3 -> self->threadId
- * r7 -> temp to hold new lock value [unlock only]
- * r4 -> allow to be used by utilities as general temp
- *
- * The result of the strex is 0 if we acquire the lock.
+ * Determine whether value can be encoded as a Thumb2 floating point
+ * immediate. If not, return -1. If so return encoded 8-bit value.
*/
-static void handleMonitor(CompilationUnit *cUnit, MIR *mir)
+static int encodeImmDoubleHigh(int value)
{
-#if defined (THIN_LOCKING)
- RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
- bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
- ArmLIR *target;
- ArmLIR *branch;
-
- loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
- lockAllTemps(cUnit); // Prepare for explicit register usage
- freeTemp(cUnit, r4PC); // Free up r4 for general use
- loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); // Get self
- genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
- loadWordDisp(cUnit, r0, offsetof(Thread, threadId), r3); // Get threadId
- newLIR3(cUnit, kThumb2Ldrex, r2, r1,
- offsetof(Object, lock.thin) >> 2); // Get object->lock.thin
- // Is lock.thin unheld on lock or held by us (==threadId) on unlock?
- if (enter) {
- opRegImm(cUnit, kOpSub, r2, DVM_LOCK_INITIAL_THIN_VALUE);
- } else {
- loadConstant(cUnit, r7, DVM_LOCK_INITIAL_THIN_VALUE);
- opRegReg(cUnit, kOpSub, r2, r3);
- }
- // Note: start of IT block. If last sub result != clear, else strex
- genIT(cUnit, kArmCondNe, "E");
- newLIR0(cUnit, kThumb2Clrex);
- if (enter) {
- newLIR4(cUnit, kThumb2Strex, r2, r3, r1,
- offsetof(Object, lock.thin) >> 2);
+ int res;
+ int bitA = (value & 0x80000000) >> 31;
+ int notBitB = (value & 0x40000000) >> 30;
+ int bitB = (value & 0x20000000) >> 29;
+ int bSmear = (value & 0x3fc00000) >> 22;
+ int slice = (value & 0x003f0000) >> 16;
+ int zeroes = (value & 0x0000ffff);
+ if (zeroes != 0)
+ return -1;
+ if (bitB) {
+ if ((notBitB != 0) || (bSmear != 0x1f))
+ return -1;
} else {
- newLIR4(cUnit, kThumb2Strex, r2, r7, r1,
- offsetof(Object, lock.thin) >> 2);
+ if ((notBitB != 1) || (bSmear != 0x0))
+ return -1;
}
- // Note: end of IT block
+ res = (bitA << 7) | (bitB << 6) | slice;
+ return res;
+}
- branch = newLIR2(cUnit, kThumb2Cbz, r2, 0);
+static int encodeImmDouble(int valLo, int valHi)
+{
+ int res = -1;
+ if (valLo == 0)
+ res = encodeImmDoubleHigh(valHi);
+ return res;
+}
- if (enter) {
- loadConstant(cUnit, r7, (int)dvmLockObject);
+static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+ int rDestHi, int valLo, int valHi)
+{
+ int encodedImm = encodeImmDouble(valLo, valHi);
+ ArmLIR *res;
+ if (FPREG(rDestLo) && (encodedImm >= 0)) {
+ res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
+ encodedImm);
} else {
- loadConstant(cUnit, r7, (int)dvmUnlockObject);
+ res = loadConstantValue(cUnit, rDestLo, valLo);
+ loadConstantValue(cUnit, rDestHi, valHi);
}
- genExportPC(cUnit, mir);
- opReg(cUnit, kOpBlx, r7);
-
- clobberCallRegs(cUnit);
-
- // Resume here
- target = newLIR0(cUnit, kArmPseudoTargetLabel);
- target->defMask = ENCODE_ALL;
- branch->generic.target = (LIR *)target;
-#else
- handleMonitorPortable(cUnit, mir);
-#endif
+ return res;
}
-/*
- * 64-bit 3way compare function.
- * mov r7, #-1
- * cmp op1hi, op2hi
- * blt done
- * bgt flip
- * sub r7, op1lo, op2lo (treat as unsigned)
- * beq done
- * ite hi
- * mov(hi) r7, #-1
- * mov(!hi) r7, #1
- * flip:
- * neg r7
- * done:
- */
-static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
- ArmLIR *target1;
- ArmLIR *target2;
- rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
- rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
- rlTemp.lowReg = allocTemp(cUnit);
- loadConstant(cUnit, rlTemp.lowReg, -1);
- opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
- ArmLIR *branch1 = opCondBranch(cUnit, kArmCondLt);
- ArmLIR *branch2 = opCondBranch(cUnit, kArmCondGt);
- opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
- ArmLIR *branch3 = opCondBranch(cUnit, kArmCondEq);
-
- genIT(cUnit, kArmCondHi, "E");
- newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1));
- loadConstant(cUnit, rlTemp.lowReg, 1);
- genBarrier(cUnit);
-
- target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
- target2->defMask = -1;
- opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg);
-
- target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
- target1->defMask = -1;
-
- storeValue(cUnit, rlDest, rlTemp);
-
- branch1->generic.target = (LIR *)target1;
- branch2->generic.target = (LIR *)target2;
- branch3->generic.target = branch1->generic.target;
+static int encodeShift(int code, int amount) {
+ return ((amount & 0x1f) << 2) | code;
}
static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
}
-/* Load a float to a Dalvik register. */
-static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
- int rSrcDest, ArmOpCode opCode)
-{
- ArmLIR *res;
- if (vSrcDest > 255) {
- int rTmp = allocTemp(cUnit);
- opRegRegImm(cUnit, kOpAdd, rTmp, rFP, vSrcDest * 4);
- res = newLIR3(cUnit, opCode, rSrcDest, rTmp, 0);
- freeTemp(cUnit, rTmp);
- } else {
- res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
- }
- return res;
-}
-
/*
* Load value from base + displacement. Optionally perform null check
* on base (which must have an associated sReg and MIR). If not
*/
static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
int displacement, int rDest, int rDestHi,
- OpSize size, bool nullCheck, int sReg)
+ OpSize size, int sReg)
{
- ArmLIR *first = NULL;
ArmLIR *res, *load;
ArmOpCode opCode = kThumbBkpt;
bool shortForm = false;
break;
} else {
res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
- -1, kWord, nullCheck, sReg);
+ -1, kWord, sReg);
loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
- -1, kWord, false, INVALID_SREG);
+ -1, kWord, INVALID_SREG);
return res;
}
case kSingle:
default:
assert(0);
}
- if (nullCheck)
- first = genNullCheck(cUnit, sReg, rBase, mir->offset, NULL);
+
if (shortForm) {
load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
} else {
if (rBase == rFP) {
annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
}
- return (first) ? first : res;
+ return res;
}
static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
int displacement, int rDest, OpSize size,
- bool nullCheck, int sReg)
+ int sReg)
{
return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
- size, nullCheck, sReg);
+ size, sReg);
}
-static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
int displacement, int rDestLo, int rDestHi,
- bool nullCheck, int sReg)
+ int sReg)
{
return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
- kLong, nullCheck, sReg);
+ kLong, sReg);
}
return res;
}
-static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
- int value)
-{
- int encodedImm = encodeImmSingle(value);
- assert(SINGLEREG(rDest));
- if (encodedImm >= 0) {
- return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
- }
- ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
- if (dataTarget == NULL) {
- dataTarget = addWordData(cUnit, value, false);
- }
- ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
- loadPcRel->opCode = kThumb2Vldrs;
- loadPcRel->generic.target = (LIR *) dataTarget;
- loadPcRel->operands[0] = rDest;
- loadPcRel->operands[1] = rpc;
- setupResourceMasks(loadPcRel);
- dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
- return loadPcRel;
-}
-
static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
{
storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
{
- loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, false,
- INVALID_SREG);
+ loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
}
/*
- * Load a immediate using a shortcut if possible; otherwise
- * grab from the per-translation literal pool.
- */
-static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
-{
- ArmLIR *res;
- int modImm;
-
- if (FPREG(rDest)) {
- return loadFPConstantValue(cUnit, rDest, value);
- }
-
- /* See if the value can be constructed cheaply */
- if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
- return newLIR2(cUnit, kThumbMovImm, rDest, value);
- }
- /* Check Modified immediate special cases */
- modImm = modifiedImmediate(value);
- if (modImm >= 0) {
- res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
- return res;
- }
- modImm = modifiedImmediate(~value);
- if (modImm >= 0) {
- res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
- return res;
- }
- /* 16-bit immediate? */
- if ((value & 0xffff) == value) {
- res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
- return res;
- }
- /* No shortcut - go ahead and use literal pool */
- ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
- if (dataTarget == NULL) {
- dataTarget = addWordData(cUnit, value, false);
- }
- ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
- loadPcRel->opCode = LOWREG(rDest) ? kThumbLdrPcRel : kThumb2LdrPcRel12;
- loadPcRel->generic.target = (LIR *) dataTarget;
- loadPcRel->operands[0] = rDest;
- setupResourceMasks(loadPcRel);
- res = loadPcRel;
- dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
-
- /*
- * To save space in the constant pool, we use the ADD_RRI8 instruction to
- * add up to 255 to an existing constant value.
- */
- if (dataTarget->operands[0] != value) {
- opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
- }
- return res;
-}
-
-static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
- int rDestHi, int valLo, int valHi)
-{
- int encodedImm = encodeImmDouble(valLo, valHi);
- ArmLIR *res;
- if (FPREG(rDestLo) && (encodedImm >= 0)) {
- res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
- encodedImm);
- } else {
- res = loadConstantValue(cUnit, rDestLo, valLo);
- loadConstantValue(cUnit, rDestHi, valHi);
- }
- return res;
-}
-
-/*
* Perform a "reg cmp imm" operation and jump to the PCR region if condition
* satisfies.
*/
return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
}
-static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
-{
- RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
- RegLocation rlDest = inlinedTarget(cUnit, mir, false);
- rlObj = loadValue(cUnit, rlObj, kCoreReg);
- RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
- loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
- rlResult.lowReg);
- storeValue(cUnit, rlDest, rlResult);
- return false;
-}
-
-static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
-{
- int contents = offsetof(ArrayObject, contents);
- RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
- RegLocation rlIdx = getSrcLoc(cUnit, mir, 1);
- RegLocation rlDest = inlinedTarget(cUnit, mir, false);
- RegLocation rlResult;
- rlObj = loadValue(cUnit, rlObj, kCoreReg);
- rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
- int regMax = allocTemp(cUnit);
- int regOff = allocTemp(cUnit);
- int regPtr = allocTemp(cUnit);
- ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
- mir->offset, NULL);
- loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
- loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
- loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
- genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
- freeTemp(cUnit, regMax);
- opRegImm(cUnit, kOpAdd, regPtr, contents);
- opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
- rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
- storeValue(cUnit, rlDest, rlResult);
- return false;
-}
-
-static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
+static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
{
- RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
- rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
- RegLocation rlDest = inlinedTarget(cUnit, mir, false);;
- RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- int signReg = allocTemp(cUnit);
- /*
- * abs(x) = y<=x>>31, (x+y)^y.
- * Thumb2's IT block also yields 3 instructions, but imposes
- * scheduling constraints.
- */
- opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
- opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
- opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
- storeValue(cUnit, rlDest, rlResult);
- return false;
+ ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ if (rDest == rSrc) {
+ res->isNop = true;
+ } else {
+ assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
+ if (DOUBLEREG(rDest)) {
+ res->opCode = kThumb2Vmovd;
+ } else {
+ if (SINGLEREG(rDest)) {
+ res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
+ } else {
+ assert(SINGLEREG(rSrc));
+ res->opCode = kThumb2Fmrs;
+ }
+ }
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ }
+ setupResourceMasks(res);
+ return res;
}
-static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
+static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
{
- RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
- RegLocation rlDest = inlinedTarget(cUnit, mir, true);
- rlSrc = loadValue(cUnit, rlSrc, kFPReg);
- RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR2(cUnit, kThumb2Vabss, rlResult.lowReg, rlSrc.lowReg);
- storeValue(cUnit, rlDest, rlResult);
- return true;
-}
+ ArmLIR* res;
+ ArmOpCode opCode;
+ if (FPREG(rDest) || FPREG(rSrc))
+ return fpRegCopy(cUnit, rDest, rSrc);
+ res = dvmCompilerNew(sizeof(ArmLIR), true);
+ if (LOWREG(rDest) && LOWREG(rSrc))
+ opCode = kThumbMovRR;
+ else if (!LOWREG(rDest) && !LOWREG(rSrc))
+ opCode = kThumbMovRR_H2H;
+ else if (LOWREG(rDest))
+ opCode = kThumbMovRR_H2L;
+ else
+ opCode = kThumbMovRR_L2H;
-static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
-{
- RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
- rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
- RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR2(cUnit, kThumb2Vabsd, S2D(rlResult.lowReg, rlResult.highReg),
- S2D(rlSrc.lowReg, rlSrc.highReg));
- storeValueWide(cUnit, rlDest, rlResult);
- return true;
+ res->operands[0] = rDest;
+ res->operands[1] = rSrc;
+ res->opCode = opCode;
+ setupResourceMasks(res);
+ if (rDest == rSrc) {
+ res->isNop = true;
+ }
+ return res;
}
-static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
+static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
{
- RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
- RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
- rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
- rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
- RegLocation rlDest = inlinedTarget(cUnit, mir, false);
- RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
- genIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E");
- opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
- opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
- genBarrier(cUnit);
- storeValue(cUnit, rlDest, rlResult);
- return false;
+ ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+ dvmCompilerAppendLIR(cUnit, (LIR*)res);
+ return res;
}
-static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+ int srcLo, int srcHi)
{
- RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
- rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
- RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- int signReg = allocTemp(cUnit);
- /*
- * abs(x) = y<=x>>31, (x+y)^y.
- * Thumb2 IT block allows slightly shorter sequence,
- * but introduces a scheduling barrier. Stick with this
- * mechanism for now.
- */
- opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
- opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
- opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
- opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
- opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
- storeValueWide(cUnit, rlDest, rlResult);
- return false;
+ bool destFP = FPREG(destLo) && FPREG(destHi);
+ bool srcFP = FPREG(srcLo) && FPREG(srcHi);
+ assert(FPREG(srcLo) == FPREG(srcHi));
+ assert(FPREG(destLo) == FPREG(destHi));
+ if (destFP) {
+ if (srcFP) {
+ genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
+ } else {
+ newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
+ }
+ } else {
+ if (srcFP) {
+ newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
+ } else {
+ // Handle overlap
+ if (srcHi == destLo) {
+ genRegCopy(cUnit, destHi, srcHi);
+ genRegCopy(cUnit, destLo, srcLo);
+ } else {
+ genRegCopy(cUnit, destLo, srcLo);
+ genRegCopy(cUnit, destHi, srcHi);
+ }
+ }
+ }
}
--- /dev/null
+/*
+ * 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 for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+ rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+}
+
+static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc)
+{
+ RegLocation rlResult;
+ rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+ rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
+ S2D(rlSrc.lowReg, rlSrc.highReg));
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+/*
+ * To avoid possible conflicts, we use a lot of temps here. Note that
+ * our usage of Thumb2 instruction forms avoids the problems with register
+ * reuse for multiply instructions prior to arm6.
+ */
+static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ int resLo = allocTemp(cUnit);
+ int resHi = allocTemp(cUnit);
+ int tmp1 = allocTemp(cUnit);
+
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+
+ newLIR3(cUnit, kThumb2MulRRR, tmp1, rlSrc2.lowReg, rlSrc1.highReg);
+ newLIR4(cUnit, kThumb2Umull, resLo, resHi, rlSrc2.lowReg, rlSrc1.lowReg);
+ newLIR4(cUnit, kThumb2Mla, tmp1, rlSrc1.lowReg, rlSrc2.highReg, tmp1);
+ newLIR4(cUnit, kThumb2AddRRR, resHi, tmp1, resHi, 0);
+ freeTemp(cUnit, tmp1);
+
+ rlResult = getReturnLocWide(cUnit); // Just as a template, will patch
+ rlResult.lowReg = resLo;
+ rlResult.highReg = resHi;
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
+ OpKind secondOp, RegLocation rlDest,
+ RegLocation rlSrc1, RegLocation rlSrc2)
+{
+ RegLocation rlResult;
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
+ rlSrc2.highReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+}
+
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
+{
+ int i;
+ int numTemps = sizeof(coreTemps)/sizeof(int);
+ int numFPTemps = sizeof(fpTemps)/sizeof(int);
+ RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
+ cUnit->regPool = pool;
+ pool->numCoreTemps = numTemps;
+ pool->coreTemps =
+ dvmCompilerNew(numTemps * sizeof(*cUnit->regPool->coreTemps), true);
+ pool->numFPTemps = numFPTemps;
+ pool->FPTemps =
+ dvmCompilerNew(numFPTemps * sizeof(*cUnit->regPool->FPTemps), true);
+ pool->numCoreRegs = 0;
+ pool->coreRegs = NULL;
+ pool->numFPRegs = 0;
+ pool->FPRegs = NULL;
+ initPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
+ initPool(pool->FPTemps, fpTemps, pool->numFPTemps);
+ initPool(pool->coreRegs, NULL, 0);
+ initPool(pool->FPRegs, NULL, 0);
+ pool->nullCheckedRegs =
+ dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
+}
+
+/*
+ * Generate a Thumb2 IT instruction, which can nullify up to
+ * four subsequent instructions based on a condition and its
+ * inverse. The condition applies to the first instruction, which
+ * is executed if the condition is met. The string "guide" consists
+ * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
+ * A "T" means the instruction is executed if the condition is
+ * met, and an "E" means the instruction is executed if the condition
+ * is not met.
+ */
+static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
+ char *guide)
+{
+ int mask;
+ int condBit = code & 1;
+ int altBit = condBit ^ 1;
+ int mask3 = 0;
+ int mask2 = 0;
+ int mask1 = 0;
+
+ //Note: case fallthroughs intentional
+ switch(strlen(guide)) {
+ case 3:
+ mask1 = (guide[2] == 'T') ? condBit : altBit;
+ case 2:
+ mask2 = (guide[1] == 'T') ? condBit : altBit;
+ case 1:
+ mask3 = (guide[0] == 'T') ? condBit : altBit;
+ break;
+ case 0:
+ break;
+ default:
+ assert(0);
+ dvmAbort();
+ }
+ mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
+ (1 << (3 - strlen(guide)));
+ return newLIR2(cUnit, kThumb2It, code, mask);
+}
+
+/* Export the Dalvik PC assicated with an instruction to the StackSave area */
+static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
+{
+ ArmLIR *res;
+ int offset = offsetof(StackSaveArea, xtra.currentPc);
+ int rDPC = allocTemp(cUnit);
+ res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
+ newLIR3(cUnit, kThumb2StrRRI8Predec, rDPC, rFP,
+ sizeof(StackSaveArea) - offset);
+ freeTemp(cUnit, rDPC);
+ return res;
+}
+
+/*
+ * Handle simple case (thin lock) inline. If it's complicated, bail
+ * out to the heavyweight lock/unlock routines. We'll use dedicated
+ * registers here in order to be in the right position in case we
+ * to bail to dvm[Lock/Unlock]Object(self, object)
+ *
+ * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
+ * r1 -> object [arg1 for dvm[Lock/Unlock]Object
+ * r2 -> intial contents of object->lock.thin, later result of strex
+ * r3 -> self->threadId
+ * r7 -> temp to hold new lock value [unlock only]
+ * r4 -> allow to be used by utilities as general temp
+ *
+ * The result of the strex is 0 if we acquire the lock.
+ */
+static void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+#if defined (THIN_LOCKING)
+ RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+ bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
+ ArmLIR *target;
+ ArmLIR *branch;
+
+ loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
+ lockAllTemps(cUnit); // Prepare for explicit register usage
+ freeTemp(cUnit, r4PC); // Free up r4 for general use
+ loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); // Get self
+ genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+ loadWordDisp(cUnit, r0, offsetof(Thread, threadId), r3); // Get threadId
+ newLIR3(cUnit, kThumb2Ldrex, r2, r1,
+ offsetof(Object, lock.thin) >> 2); // Get object->lock.thin
+ // Is lock.thin unheld on lock or held by us (==threadId) on unlock?
+ if (enter) {
+ opRegImm(cUnit, kOpSub, r2, DVM_LOCK_INITIAL_THIN_VALUE);
+ } else {
+ loadConstant(cUnit, r7, DVM_LOCK_INITIAL_THIN_VALUE);
+ opRegReg(cUnit, kOpSub, r2, r3);
+ }
+ // Note: start of IT block. If last sub result != clear, else strex
+ genIT(cUnit, kArmCondNe, "E");
+ newLIR0(cUnit, kThumb2Clrex);
+ if (enter) {
+ newLIR4(cUnit, kThumb2Strex, r2, r3, r1,
+ offsetof(Object, lock.thin) >> 2);
+ } else {
+ newLIR4(cUnit, kThumb2Strex, r2, r7, r1,
+ offsetof(Object, lock.thin) >> 2);
+ }
+ // Note: end of IT block
+
+ branch = newLIR2(cUnit, kThumb2Cbz, r2, 0);
+
+ if (enter) {
+ loadConstant(cUnit, r7, (int)dvmLockObject);
+ } else {
+ loadConstant(cUnit, r7, (int)dvmUnlockObject);
+ }
+ genExportPC(cUnit, mir);
+ opReg(cUnit, kOpBlx, r7);
+
+ clobberCallRegs(cUnit);
+
+ // Resume here
+ target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branch->generic.target = (LIR *)target;
+#else
+ genMonitorPortable(cUnit, mir);
+#endif
+}
+
+/*
+ * 64-bit 3way compare function.
+ * mov r7, #-1
+ * cmp op1hi, op2hi
+ * blt done
+ * bgt flip
+ * sub r7, op1lo, op2lo (treat as unsigned)
+ * beq done
+ * ite hi
+ * mov(hi) r7, #-1
+ * mov(!hi) r7, #1
+ * flip:
+ * neg r7
+ * done:
+ */
+static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
+ RegLocation rlDest, RegLocation rlSrc1,
+ RegLocation rlSrc2)
+{
+ RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
+ ArmLIR *target1;
+ ArmLIR *target2;
+ rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+ rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+ rlTemp.lowReg = allocTemp(cUnit);
+ loadConstant(cUnit, rlTemp.lowReg, -1);
+ opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
+ ArmLIR *branch1 = opCondBranch(cUnit, kArmCondLt);
+ ArmLIR *branch2 = opCondBranch(cUnit, kArmCondGt);
+ opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+ ArmLIR *branch3 = opCondBranch(cUnit, kArmCondEq);
+
+ genIT(cUnit, kArmCondHi, "E");
+ newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1));
+ loadConstant(cUnit, rlTemp.lowReg, 1);
+ genBarrier(cUnit);
+
+ target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target2->defMask = -1;
+ opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg);
+
+ target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target1->defMask = -1;
+
+ storeValue(cUnit, rlDest, rlTemp);
+
+ branch1->generic.target = (LIR *)target1;
+ branch2->generic.target = (LIR *)target2;
+ branch3->generic.target = branch1->generic.target;
+}
+
+static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
+ rlResult.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
+{
+ int contents = offsetof(ArrayObject, contents);
+ RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+ RegLocation rlIdx = getSrcLoc(cUnit, mir, 1);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+ RegLocation rlResult;
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
+ int regMax = allocTemp(cUnit);
+ int regOff = allocTemp(cUnit);
+ int regPtr = allocTemp(cUnit);
+ ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
+ mir->offset, NULL);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
+ loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
+ genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
+ freeTemp(cUnit, regMax);
+ opRegImm(cUnit, kOpAdd, regPtr, contents);
+ opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
+ rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+ rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);;
+ RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ int signReg = allocTemp(cUnit);
+ /*
+ * abs(x) = y<=x>>31, (x+y)^y.
+ * Thumb2's IT block also yields 3 instructions, but imposes
+ * scheduling constraints.
+ */
+ opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
+ opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+ opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, true);
+ rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+ RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, kThumb2Vabss, rlResult.lowReg, rlSrc.lowReg);
+ storeValue(cUnit, rlDest, rlResult);
+ return true;
+}
+
+static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
+ rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+ RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+ newLIR2(cUnit, kThumb2Vabsd, S2D(rlResult.lowReg, rlResult.highReg),
+ S2D(rlSrc.lowReg, rlSrc.highReg));
+ storeValueWide(cUnit, rlDest, rlResult);
+ return true;
+}
+
+static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
+{
+ RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
+ RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
+ rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+ rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+ RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+ RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+ genIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E");
+ opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
+ opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
+ genBarrier(cUnit);
+ storeValue(cUnit, rlDest, rlResult);
+ return false;
+}
+
+static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+ RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
+ rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+ RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+ int signReg = allocTemp(cUnit);
+ /*
+ * abs(x) = y<=x>>31, (x+y)^y.
+ * Thumb2 IT block allows slightly shorter sequence,
+ * but introduces a scheduling barrier. Stick with this
+ * mechanism for now.
+ */
+ opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
+ opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+ opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
+ opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+ opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
+ storeValueWide(cUnit, rlDest, rlResult);
+ return false;
+}
--- /dev/null
+/*
+ * 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 for the Thumb ISA and is intended to be
+ * includes by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Alloc a pair of core registers, or a double. Low reg in low byte,
+ * high reg in next byte.
+ */
+int dvmCompilerAllocTypedTempPair(CompilationUnit *cUnit,
+ bool fpHint, int regClass)
+{
+ int highReg;
+ int lowReg;
+ int res = 0;
+ if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
+ lowReg = allocTempDouble(cUnit);
+ highReg = lowReg + 1;
+ } else {
+ lowReg = allocTemp(cUnit);
+ highReg = allocTemp(cUnit);
+ }
+ res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+ return res;
+}
+
+int dvmCompilerAllocTypedTemp(CompilationUnit *cUnit, bool fpHint,
+ int regClass)
+{
+ if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
+ return allocTempFloat(cUnit);
+ return allocTemp(cUnit);
+}
* variant-specific code.
*/
-static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
- int rDest);
/*
* Determine the initial instruction set to be used for this trace.
* Later components may decide to change this.
*/
-JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
+JitInstructionSetType dvmCompilerInstructionSet(void)
{
return DALVIK_JIT_THUMB;
}
-/*
- * Jump to the out-of-line handler in ARM mode to finish executing the
- * remaining of more complex instructions.
- */
-static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
-{
- /*
- * NOTE - In practice BLX only needs one operand, but since the assembler
- * may abort itself and retry due to other out-of-range conditions we
- * cannot really use operand[0] to store the absolute target address since
- * it may get clobbered by the final relative offset. Therefore,
- * we fake BLX_1 is a two operand instruction and the absolute target
- * address is stored in operand[1].
- */
- clobberHandlerRegs(cUnit);
- newLIR2(cUnit, kThumbBlx1,
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
- newLIR2(cUnit, kThumbBlx2,
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-}
-
-void *dvmCompilerGetInterpretTemplate()
-{
- return (void*) ((int)gDvmJit.codeCache +
- templateEntryOffsets[TEMPLATE_INTERPRET]);
-}
-
/* Architecture-specific initializations and checks go here */
-static bool compilerArchVariantInit(void)
+bool dvmCompilerArchVariantInit(void)
{
/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
assert(offsetof(InterpState, jitToInterpEntries) < 108);
return true;
}
-
-/* First, flush any registers associated with this value */
-static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
- int rDest)
-{
- rlSrc = rlSrc.wide ? updateLocWide(cUnit, rlSrc) : updateLoc(cUnit, rlSrc);
- if (rlSrc.location == kLocPhysReg) {
- if (rlSrc.wide) {
- flushRegWide(cUnit, rlSrc.lowReg, rlSrc.highReg);
- } else {
- flushReg(cUnit, rlSrc.lowReg);
- }
- }
- opRegRegImm(cUnit, kOpAdd, rDest, rFP,
- sReg2vReg(cUnit, rlSrc.sRegLow) << 2);
-}
-
-static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
-{
- RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- RegLocation rlResult = LOC_C_RETURN_WIDE;
- RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
- loadValueAddress(cUnit, rlSrc, r2);
- genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
- storeValueWide(cUnit, rlDest, rlResult);
- return false;
-}
-
-/*
- * TUNING: On some implementations, it is quicker to pass addresses
- * to the handlers rather than load the operands into core registers
- * and then move the values to FP regs in the handlers. Other implementations
- * may prefer passing data in registers (and the latter approach would
- * yeild cleaner register handling - avoiding the requirement that operands
- * be flushed to memory prior to the call).
- */
-static bool handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- TemplateOpCode opCode;
-
- /*
- * Don't attempt to optimize register usage since these opcodes call out to
- * the handlers.
- */
- switch (mir->dalvikInsn.opCode) {
- case OP_ADD_FLOAT_2ADDR:
- case OP_ADD_FLOAT:
- opCode = TEMPLATE_ADD_FLOAT_VFP;
- break;
- case OP_SUB_FLOAT_2ADDR:
- case OP_SUB_FLOAT:
- opCode = TEMPLATE_SUB_FLOAT_VFP;
- break;
- case OP_DIV_FLOAT_2ADDR:
- case OP_DIV_FLOAT:
- opCode = TEMPLATE_DIV_FLOAT_VFP;
- break;
- case OP_MUL_FLOAT_2ADDR:
- case OP_MUL_FLOAT:
- opCode = TEMPLATE_MUL_FLOAT_VFP;
- break;
- case OP_REM_FLOAT_2ADDR:
- case OP_REM_FLOAT:
- case OP_NEG_FLOAT: {
- return handleArithOpFloatPortable(cUnit, mir, rlDest,
- rlSrc1, rlSrc2);
- }
- default:
- return true;
- }
- loadValueAddress(cUnit, rlDest, r0);
- clobberReg(cUnit, r0);
- loadValueAddress(cUnit, rlSrc1, r1);
- clobberReg(cUnit, r1);
- loadValueAddress(cUnit, rlSrc2, r2);
- genDispatchToHandler(cUnit, opCode);
- rlDest = updateLoc(cUnit, rlDest);
- if (rlDest.location == kLocPhysReg) {
- clobberReg(cUnit, rlDest.lowReg);
- }
- return false;
-}
-
-static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- TemplateOpCode opCode;
-
- switch (mir->dalvikInsn.opCode) {
- case OP_ADD_DOUBLE_2ADDR:
- case OP_ADD_DOUBLE:
- opCode = TEMPLATE_ADD_DOUBLE_VFP;
- break;
- case OP_SUB_DOUBLE_2ADDR:
- case OP_SUB_DOUBLE:
- opCode = TEMPLATE_SUB_DOUBLE_VFP;
- break;
- case OP_DIV_DOUBLE_2ADDR:
- case OP_DIV_DOUBLE:
- opCode = TEMPLATE_DIV_DOUBLE_VFP;
- break;
- case OP_MUL_DOUBLE_2ADDR:
- case OP_MUL_DOUBLE:
- opCode = TEMPLATE_MUL_DOUBLE_VFP;
- break;
- case OP_REM_DOUBLE_2ADDR:
- case OP_REM_DOUBLE:
- case OP_NEG_DOUBLE: {
- return handleArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
- rlSrc2);
- }
- default:
- return true;
- }
- loadValueAddress(cUnit, rlDest, r0);
- clobberReg(cUnit, r0);
- loadValueAddress(cUnit, rlSrc1, r1);
- clobberReg(cUnit, r1);
- loadValueAddress(cUnit, rlSrc2, r2);
- genDispatchToHandler(cUnit, opCode);
- rlDest = updateLocWide(cUnit, rlDest);
- if (rlDest.location == kLocPhysReg) {
- clobberReg(cUnit, rlDest.lowReg);
- clobberReg(cUnit, rlDest.highReg);
- }
- return false;
-}
-
-static bool handleConversion(CompilationUnit *cUnit, MIR *mir)
-{
- OpCode opCode = mir->dalvikInsn.opCode;
- bool longSrc = false;
- bool longDest = false;
- RegLocation rlSrc;
- RegLocation rlDest;
- TemplateOpCode template;
- switch (opCode) {
- case OP_INT_TO_FLOAT:
- longSrc = false;
- longDest = false;
- template = TEMPLATE_INT_TO_FLOAT_VFP;
- break;
- case OP_FLOAT_TO_INT:
- longSrc = false;
- longDest = false;
- template = TEMPLATE_FLOAT_TO_INT_VFP;
- break;
- case OP_DOUBLE_TO_FLOAT:
- longSrc = true;
- longDest = false;
- template = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
- break;
- case OP_FLOAT_TO_DOUBLE:
- longSrc = false;
- longDest = true;
- template = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
- break;
- case OP_INT_TO_DOUBLE:
- longSrc = false;
- longDest = true;
- template = TEMPLATE_INT_TO_DOUBLE_VFP;
- break;
- case OP_DOUBLE_TO_INT:
- longSrc = true;
- longDest = false;
- template = TEMPLATE_DOUBLE_TO_INT_VFP;
- break;
- case OP_LONG_TO_DOUBLE:
- case OP_FLOAT_TO_LONG:
- case OP_LONG_TO_FLOAT:
- case OP_DOUBLE_TO_LONG:
- return handleConversionPortable(cUnit, mir);
- default:
- return true;
- }
-
- if (longSrc) {
- rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- } else {
- rlSrc = getSrcLoc(cUnit, mir, 0);
- }
-
- if (longDest) {
- rlDest = getDestLocWide(cUnit, mir, 0, 1);
- } else {
- rlDest = getDestLoc(cUnit, mir, 0);
- }
- loadValueAddress(cUnit, rlDest, r0);
- clobberReg(cUnit, r0);
- loadValueAddress(cUnit, rlSrc, r1);
- genDispatchToHandler(cUnit, template);
- if (rlDest.wide) {
- rlDest = updateLocWide(cUnit, rlDest);
- clobberReg(cUnit, rlDest.highReg);
- } else {
- rlDest = updateLoc(cUnit, rlDest);
- }
- clobberReg(cUnit, rlDest.lowReg);
- return false;
-}
-
-static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
-{
- TemplateOpCode template;
- RegLocation rlResult = getReturnLoc(cUnit);
- bool wide = true;
-
- switch(mir->dalvikInsn.opCode) {
- case OP_CMPL_FLOAT:
- template = TEMPLATE_CMPL_FLOAT_VFP;
- wide = false;
- break;
- case OP_CMPG_FLOAT:
- template = TEMPLATE_CMPG_FLOAT_VFP;
- wide = false;
- break;
- case OP_CMPL_DOUBLE:
- template = TEMPLATE_CMPL_DOUBLE_VFP;
- break;
- case OP_CMPG_DOUBLE:
- template = TEMPLATE_CMPG_DOUBLE_VFP;
- break;
- default:
- return true;
- }
- loadValueAddress(cUnit, rlSrc1, r0);
- clobberReg(cUnit, r0);
- loadValueAddress(cUnit, rlSrc2, r1);
- genDispatchToHandler(cUnit, template);
- storeValue(cUnit, rlDest, rlResult);
- return false;
-}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/OpCode.h"
+#include "dexdump/OpCodeNames.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/arm/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Architectural independent building blocks */
+#include "../CodegenCommon.c"
+
+/* Thumb-specific factory utilities */
+#include "../Thumb/Factory.c"
+/* Factory utilities dependent on arch-specific features */
+#include "../CodegenFactory.c"
+
+/* Thumb-specific codegen routines */
+#include "../Thumb/Gen.c"
+/* Thumb+VFP codegen routines */
+#include "../FP/ThumbVFP.c"
+
+/* Thumb-specific register allocation */
+#include "../Thumb/Ralloc.c"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.c"
+
+/* Architecture manifest */
+#include "ArchVariant.c"
* Determine the initial instruction set to be used for this trace.
* Later components may decide to change this.
*/
-JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
+JitInstructionSetType dvmCompilerInstructionSet(void)
{
return DALVIK_JIT_THUMB;
}
-/*
- * Jump to the out-of-line handler in ARM mode to finish executing the
- * remaining of more complex instructions.
- */
-static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
-{
- /*
- * NOTE - In practice BLX only needs one operand, but since the assembler
- * may abort itself and retry due to other out-of-range conditions we
- * cannot really use operand[0] to store the absolute target address since
- * it may get clobbered by the final relative offset. Therefore,
- * we fake BLX_1 is a two operand instruction and the absolute target
- * address is stored in operand[1].
- */
- clobberHandlerRegs(cUnit);
- newLIR2(cUnit, kThumbBlx1,
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
- newLIR2(cUnit, kThumbBlx2,
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-}
-
/* Architecture-specific initializations and checks go here */
-static bool compilerArchVariantInit(void)
+bool dvmCompilerArchVariantInit(void)
{
/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
assert(offsetof(InterpState, jitToInterpEntries) < 108);
return true;
}
-
-void *dvmCompilerGetInterpretTemplate()
-{
- return (void*) ((int)gDvmJit.codeCache +
- templateEntryOffsets[TEMPLATE_INTERPRET]);
-}
-
-static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
-{
- return false; /* punt to C handler */
-}
-
-static bool handleConversion(CompilationUnit *cUnit, MIR *mir)
-{
- return handleConversionPortable(cUnit, mir);
-}
-
-static bool handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- return handleArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
-}
-
-static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- return handleArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
-}
-
-static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
-{
- RegLocation rlResult = LOC_C_RETURN;
- /*
- * Don't attempt to optimize register usage since these opcodes call out to
- * the handlers.
- */
- switch (mir->dalvikInsn.opCode) {
- case OP_CMPL_FLOAT:
- loadValueDirectFixed(cUnit, rlSrc1, r0);
- loadValueDirectFixed(cUnit, rlSrc2, r1);
- genDispatchToHandler(cUnit, TEMPLATE_CMPL_FLOAT);
- storeValue(cUnit, rlDest, rlResult);
- break;
- case OP_CMPG_FLOAT:
- loadValueDirectFixed(cUnit, rlSrc1, r0);
- loadValueDirectFixed(cUnit, rlSrc2, r1);
- genDispatchToHandler(cUnit, TEMPLATE_CMPG_FLOAT);
- storeValue(cUnit, rlDest, rlResult);
- break;
- case OP_CMPL_DOUBLE:
- loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
- loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
- genDispatchToHandler(cUnit, TEMPLATE_CMPL_DOUBLE);
- storeValue(cUnit, rlDest, rlResult);
- break;
- case OP_CMPG_DOUBLE:
- loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
- loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
- genDispatchToHandler(cUnit, TEMPLATE_CMPG_DOUBLE);
- storeValue(cUnit, rlDest, rlResult);
- break;
- default:
- return true;
- }
- return false;
-}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/OpCode.h"
+#include "dexdump/OpCodeNames.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/arm/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Architectural independent building blocks */
+#include "../CodegenCommon.c"
+
+/* Architectural independent building blocks */
+#include "../Thumb/Factory.c"
+/* Factory utilities dependent on arch-specific features */
+#include "../CodegenFactory.c"
+
+/* Thumb-specific codegen routines */
+#include "../Thumb/Gen.c"
+/* Thumb+Portable FP codegen routines */
+#include "../FP/ThumbPortableFP.c"
+
+/* Thumb-specific register allocation */
+#include "../Thumb/Ralloc.c"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.c"
+
+/* Architecture manifest */
+#include "ArchVariant.c"
* limitations under the License.
*/
-#include <math.h> // for double sqrt(double)
-
-
-/*
- * This file is included by Codegen-armv5te-vfp.c, and implements architecture
- * variant-specific code.
- */
/*
* Determine the initial instruction set to be used for this trace.
* Later components may decide to change this.
*/
-JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
+JitInstructionSetType dvmCompilerInstructionSet(void)
{
return DALVIK_JIT_THUMB2;
}
-/*
- * Jump to the out-of-line handler in ARM mode to finish executing the
- * remaining of more complex instructions.
- */
-static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
-{
- /*
- * NOTE - In practice BLX only needs one operand, but since the assembler
- * may abort itself and retry due to other out-of-range conditions we
- * cannot really use operand[0] to store the absolute target address since
- * it may get clobbered by the final relative offset. Therefore,
- * we fake BLX_1 is a two operand instruction and the absolute target
- * address is stored in operand[1].
- */
- clobberHandlerRegs(cUnit);
- newLIR2(cUnit, kThumbBlx1,
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
- newLIR2(cUnit, kThumbBlx2,
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
- (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-}
-
-void *dvmCompilerGetInterpretTemplate()
-{
- return (void*) ((int)gDvmJit.codeCache +
- templateEntryOffsets[TEMPLATE_INTERPRET]);
-}
-
/* Architecture-specific initializations and checks go here */
-static bool compilerArchVariantInit(void)
+bool dvmCompilerArchVariantInit(void)
{
/* First, declare dvmCompiler_TEMPLATE_XXX for each template */
#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
assert(offsetof(InterpState, jitToInterpEntries) < 108);
return true;
}
-
-static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
-{
- ArmLIR *branch;
- DecodedInstruction *dInsn = &mir->dalvikInsn;
- RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
- rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
- RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg),
- S2D(rlSrc.lowReg, rlSrc.highReg));
- newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg),
- S2D(rlResult.lowReg, rlResult.highReg));
- newLIR0(cUnit, kThumb2Fmstat);
- branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
- clobberCallRegs(cUnit);
- loadConstant(cUnit, r2, (int)sqrt);
- newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg));
- newLIR1(cUnit, kThumbBlxR, r2);
- newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg),
- r0, r1);
- ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel);
- label->defMask = ENCODE_ALL;
- branch->generic.target = (LIR *)label;
- storeValueWide(cUnit, rlDest, rlResult);
- return true;
-}
-
-static bool handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- int op = kThumbBkpt;
- RegLocation rlResult;
-
- /*
- * Don't attempt to optimize register usage since these opcodes call out to
- * the handlers.
- */
- switch (mir->dalvikInsn.opCode) {
- case OP_ADD_FLOAT_2ADDR:
- case OP_ADD_FLOAT:
- op = kThumb2Vadds;
- break;
- case OP_SUB_FLOAT_2ADDR:
- case OP_SUB_FLOAT:
- op = kThumb2Vsubs;
- break;
- case OP_DIV_FLOAT_2ADDR:
- case OP_DIV_FLOAT:
- op = kThumb2Vdivs;
- break;
- case OP_MUL_FLOAT_2ADDR:
- case OP_MUL_FLOAT:
- op = kThumb2Vmuls;
- break;
- case OP_REM_FLOAT_2ADDR:
- case OP_REM_FLOAT:
- case OP_NEG_FLOAT: {
- return handleArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1,
- rlSrc2);
- }
- default:
- return true;
- }
- rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
- rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
- rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR3(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
- storeValue(cUnit, rlDest, rlResult);
- return false;
-}
-
-static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
- RegLocation rlDest, RegLocation rlSrc1,
- RegLocation rlSrc2)
-{
- int op = kThumbBkpt;
- RegLocation rlResult;
-
- switch (mir->dalvikInsn.opCode) {
- case OP_ADD_DOUBLE_2ADDR:
- case OP_ADD_DOUBLE:
- op = kThumb2Vaddd;
- break;
- case OP_SUB_DOUBLE_2ADDR:
- case OP_SUB_DOUBLE:
- op = kThumb2Vsubd;
- break;
- case OP_DIV_DOUBLE_2ADDR:
- case OP_DIV_DOUBLE:
- op = kThumb2Vdivd;
- break;
- case OP_MUL_DOUBLE_2ADDR:
- case OP_MUL_DOUBLE:
- op = kThumb2Vmuld;
- break;
- case OP_REM_DOUBLE_2ADDR:
- case OP_REM_DOUBLE:
- case OP_NEG_DOUBLE: {
- return handleArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
- rlSrc2);
- }
- default:
- return true;
- }
-
- rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
- assert(rlSrc1.wide);
- rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
- assert(rlSrc2.wide);
- rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- assert(rlDest.wide);
- assert(rlResult.wide);
- newLIR3(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg),
- S2D(rlSrc1.lowReg, rlSrc1.highReg),
- S2D(rlSrc2.lowReg, rlSrc2.highReg));
- storeValueWide(cUnit, rlDest, rlResult);
- return false;
-}
-
-static bool handleConversion(CompilationUnit *cUnit, MIR *mir)
-{
- OpCode opCode = mir->dalvikInsn.opCode;
- int op = kThumbBkpt;
- bool longSrc = false;
- bool longDest = false;
- int srcReg;
- RegLocation rlSrc;
- RegLocation rlDest;
- RegLocation rlResult;
-
- switch (opCode) {
- case OP_INT_TO_FLOAT:
- longSrc = false;
- longDest = false;
- op = kThumb2VcvtIF;
- break;
- case OP_FLOAT_TO_INT:
- longSrc = false;
- longDest = false;
- op = kThumb2VcvtFI;
- break;
- case OP_DOUBLE_TO_FLOAT:
- longSrc = true;
- longDest = false;
- op = kThumb2VcvtDF;
- break;
- case OP_FLOAT_TO_DOUBLE:
- longSrc = false;
- longDest = true;
- op = kThumb2VcvtFd;
- break;
- case OP_INT_TO_DOUBLE:
- longSrc = false;
- longDest = true;
- op = kThumb2VcvtID;
- break;
- case OP_DOUBLE_TO_INT:
- longSrc = true;
- longDest = false;
- op = kThumb2VcvtDI;
- break;
- case OP_LONG_TO_DOUBLE:
- case OP_FLOAT_TO_LONG:
- case OP_LONG_TO_FLOAT:
- case OP_DOUBLE_TO_LONG:
- return handleConversionPortable(cUnit, mir);
- default:
- return true;
- }
- if (longSrc) {
- rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
- rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
- srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
- } else {
- rlSrc = getSrcLoc(cUnit, mir, 0);
- rlSrc = loadValue(cUnit, rlSrc, kFPReg);
- srcReg = rlSrc.lowReg;
- }
- if (longDest) {
- rlDest = getDestLocWide(cUnit, mir, 0, 1);
- rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR2(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
- storeValueWide(cUnit, rlDest, rlResult);
- } else {
- rlDest = getDestLoc(cUnit, mir, 0);
- rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
- newLIR2(cUnit, op, rlResult.lowReg, srcReg);
- storeValue(cUnit, rlDest, rlResult);
- }
- return false;
-}
-
-static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
- RegLocation rlSrc1, RegLocation rlSrc2)
-{
- bool isDouble;
- int defaultResult;
- bool ltNaNBias;
- RegLocation rlResult;
-
- switch(mir->dalvikInsn.opCode) {
- case OP_CMPL_FLOAT:
- isDouble = false;
- defaultResult = -1;
- break;
- case OP_CMPG_FLOAT:
- isDouble = false;
- defaultResult = 1;
- break;
- case OP_CMPL_DOUBLE:
- isDouble = true;
- defaultResult = -1;
- break;
- case OP_CMPG_DOUBLE:
- isDouble = true;
- defaultResult = 1;
- break;
- default:
- return true;
- }
- if (isDouble) {
- rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
- rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
- clobberSReg(cUnit, rlDest.sRegLow);
- rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstant(cUnit, rlResult.lowReg, defaultResult);
- newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg),
- S2D(rlSrc2.lowReg, rlSrc2.highReg));
- } else {
- rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
- rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
- clobberSReg(cUnit, rlDest.sRegLow);
- rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
- loadConstant(cUnit, rlResult.lowReg, defaultResult);
- newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
- }
- assert(!FPREG(rlResult.lowReg));
- newLIR0(cUnit, kThumb2Fmstat);
- genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
- newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
- modifiedImmediate(-defaultResult)); // Must not alter ccodes
- genIT(cUnit, kArmCondEq, "");
- loadConstant(cUnit, rlResult.lowReg, 0);
- storeValue(cUnit, rlDest, rlResult);
- return false;
-}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/OpCode.h"
+#include "dexdump/OpCodeNames.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/arm/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Architectural independent building blocks */
+#include "../CodegenCommon.c"
+
+/* Thumb2-specific factory utilities */
+#include "../Thumb2/Factory.c"
+/* Factory utilities dependent on arch-specific features */
+#include "../CodegenFactory.c"
+
+/* Thumb2-specific codegen routines */
+#include "../Thumb2/Gen.c"
+/* Thumb2+VFP codegen routines */
+#include "../FP/Thumb2VFP.c"
+
+/* Thumb2-specific register allocation */
+#include "../Thumb2/Ralloc.c"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.c"
+
+/* Architecture manifest */
+#include "ArchVariant.c"
#if defined(WITH_SELF_VERIFICATION)
// Force JIT into blocking, translate everything mode
- gDvmJit.threshold = 1;
+ /*
+ * FIXME
+ * Cannot boot to home with threshold 1
+ * gDvmJit.threshold = 1;
+ */
gDvmJit.blockingMode = true;
#endif