OSDN Git Service

Restructure the codegen to make architectural depedency explicit.
authorBen Cheng <bccheng@google.com>
Mon, 23 Nov 2009 07:31:11 +0000 (23:31 -0800)
committerBen Cheng <bccheng@google.com>
Mon, 23 Nov 2009 07:31:11 +0000 (23:31 -0800)
The original Codegen.c is broken into three components:

- CodegenCommon.c (arch-independend)
- CodegenFactory.c (Thumb1/2 dependent)
- CodegenDriver.c (Dalvik dependent)

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

Then the hierarchy is formed by stacking these files in the following top-down
order:

1 CodegenCommon.c
2 Thumb[2]/Factory.c
3 CodegenFactory.c
4 Thumb[2]/Gen.c
5 FP stuff
6 Thumb[2]/Ralloc.c
7 CodegenDriver.c

32 files changed:
vm/Dvm.mk
vm/compiler/CompilerUtility.h
vm/compiler/Frontend.c
vm/compiler/codegen/CompilerCodegen.h
vm/compiler/codegen/arm/ArmLIR.h
vm/compiler/codegen/arm/Codegen-armv5te-vfp.c [deleted file]
vm/compiler/codegen/arm/Codegen-armv5te.c [deleted file]
vm/compiler/codegen/arm/Codegen-armv7-a.c [deleted file]
vm/compiler/codegen/arm/Codegen.h
vm/compiler/codegen/arm/CodegenCommon.c [new file with mode: 0644]
vm/compiler/codegen/arm/CodegenDriver.c [moved from vm/compiler/codegen/arm/Codegen.c with 86% similarity]
vm/compiler/codegen/arm/CodegenFactory.c [new file with mode: 0644]
vm/compiler/codegen/arm/FP/Thumb2VFP.c [new file with mode: 0644]
vm/compiler/codegen/arm/FP/ThumbPortableFP.c [new file with mode: 0644]
vm/compiler/codegen/arm/FP/ThumbVFP.c [new file with mode: 0644]
vm/compiler/codegen/arm/LocalOptimizations.c
vm/compiler/codegen/arm/README.txt [new file with mode: 0644]
vm/compiler/codegen/arm/Ralloc.h [new file with mode: 0644]
vm/compiler/codegen/arm/RallocUtil.c
vm/compiler/codegen/arm/Thumb/Factory.c [moved from vm/compiler/codegen/arm/ThumbUtil.c with 68% similarity]
vm/compiler/codegen/arm/Thumb/Gen.c [new file with mode: 0644]
vm/compiler/codegen/arm/Thumb/Ralloc.c [new file with mode: 0644]
vm/compiler/codegen/arm/Thumb2/Factory.c [moved from vm/compiler/codegen/arm/Thumb2Util.c with 68% similarity]
vm/compiler/codegen/arm/Thumb2/Gen.c [new file with mode: 0644]
vm/compiler/codegen/arm/Thumb2/Ralloc.c [new file with mode: 0644]
vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
vm/compiler/codegen/arm/armv5te-vfp/Codegen.c [new file with mode: 0644]
vm/compiler/codegen/arm/armv5te/ArchVariant.c
vm/compiler/codegen/arm/armv5te/Codegen.c [new file with mode: 0644]
vm/compiler/codegen/arm/armv7-a/ArchVariant.c
vm/compiler/codegen/arm/armv7-a/Codegen.c [new file with mode: 0644]
vm/interp/Jit.c

index fa23866..ca89536 100644 (file)
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -275,7 +275,8 @@ ifeq ($(dvm_arch),arm)
 
   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 \
index 1cfc56b..4ab650d 100644 (file)
@@ -17,6 +17,8 @@
 #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
 
index 1cd821f..0683ba2 100644 (file)
@@ -665,7 +665,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
     }
 
     /* Set the instruction set to use (NOTE: later components may change it) */
-    cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
+    cUnit.instructionSet = dvmCompilerInstructionSet();
 
     /* Allocate Registers */
     dvmCompilerRegAlloc(&cUnit);
@@ -873,7 +873,7 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
     }
 
     /* Set the instruction set to use (NOTE: later components may change it) */
-    cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
+    cUnit.instructionSet = dvmCompilerInstructionSet();
 
     dvmCompilerMIR2LIR(&cUnit);
 
index 75307a7..3e9718c 100644 (file)
@@ -46,6 +46,12 @@ void dvmCompilerRegAlloc(CompilationUnit *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_ */
index 6c3a486..1500055 100644 (file)
@@ -757,6 +757,4 @@ typedef struct PredictedChainingCell {
 
 #define CHAIN_CELL_OFFSET_TAG   0xcdab
 
-ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-
 #endif /* _DALVIK_VM_COMPILER_CODEGEN_ARM_ARMLIR_H */
diff --git a/vm/compiler/codegen/arm/Codegen-armv5te-vfp.c b/vm/compiler/codegen/arm/Codegen-armv5te-vfp.c
deleted file mode 100644 (file)
index 506ac9e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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"
diff --git a/vm/compiler/codegen/arm/Codegen-armv5te.c b/vm/compiler/codegen/arm/Codegen-armv5te.c
deleted file mode 100644 (file)
index aec19f2..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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"
diff --git a/vm/compiler/codegen/arm/Codegen-armv7-a.c b/vm/compiler/codegen/arm/Codegen-armv7-a.c
deleted file mode 100644 (file)
index eb18b1a..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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"
index 414c343..b148bda 100644 (file)
  * 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);
diff --git a/vm/compiler/codegen/arm/CodegenCommon.c b/vm/compiler/codegen/arm/CodegenCommon.c
new file mode 100644 (file)
index 0000000..9d2f78a
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * 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;
+}
similarity index 86%
rename from vm/compiler/codegen/arm/Codegen.c
rename to vm/compiler/codegen/arm/CodegenDriver.c
index 370c857..857536f 100644 (file)
  * 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 */
@@ -411,626 +586,42 @@ static void selfVerificationStoreDoubleword(InterpState* interpState)
     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)
@@ -1103,12 +694,12 @@ static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
     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);
@@ -1366,9 +957,9 @@ static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
 #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
@@ -1398,115 +989,10 @@ static bool handleShiftOpLong(CompilationUnit *cUnit, MIR *mir,
     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;
@@ -1601,9 +1087,9 @@ static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
     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;
@@ -1715,7 +1201,7 @@ static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
     return false;
 }
 
-static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
+static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
     RegLocation rlDest;
@@ -1741,34 +1227,34 @@ static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
     }
 
     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;
 }
@@ -1791,17 +1277,6 @@ static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
     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)
 {
@@ -1823,40 +1298,6 @@ 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)
@@ -2243,7 +1684,7 @@ static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
     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 */
@@ -2277,27 +1718,6 @@ static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
     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
@@ -2670,9 +2090,9 @@ static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
         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: {
@@ -2685,48 +2105,6 @@ static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
     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;
@@ -2735,7 +2113,7 @@ static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
     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)
@@ -2758,17 +2136,17 @@ static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
         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;
@@ -3231,7 +2609,7 @@ static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
     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 */
@@ -3270,7 +2648,7 @@ static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
         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;
@@ -4801,5 +4179,42 @@ bool dvmCompilerArchInit()
         }
     }
 
-    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);
 }
diff --git a/vm/compiler/codegen/arm/CodegenFactory.c b/vm/compiler/codegen/arm/CodegenFactory.c
new file mode 100644 (file)
index 0000000..e5a56cc
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * 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]);
+}
diff --git a/vm/compiler/codegen/arm/FP/Thumb2VFP.c b/vm/compiler/codegen/arm/FP/Thumb2VFP.c
new file mode 100644 (file)
index 0000000..c0d5d6b
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * 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;
+}
diff --git a/vm/compiler/codegen/arm/FP/ThumbPortableFP.c b/vm/compiler/codegen/arm/FP/ThumbPortableFP.c
new file mode 100644 (file)
index 0000000..957b4d4
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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;
+}
diff --git a/vm/compiler/codegen/arm/FP/ThumbVFP.c b/vm/compiler/codegen/arm/FP/ThumbVFP.c
new file mode 100644 (file)
index 0000000..099f3c6
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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;
+}
index 86f692f..159c2aa 100644 (file)
@@ -17,6 +17,7 @@
 #include "Dalvik.h"
 #include "vm/compiler/CompilerInternals.h"
 #include "ArmLIR.h"
+#include "Codegen.h"
 
 #define DEBUG_OPT(X)
 
@@ -95,9 +96,8 @@ static void applyLoadStoreElimination(CompilationUnit *cUnit,
                     /* 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
@@ -250,9 +250,8 @@ static void applyLoadHoisting(CompilationUnit *cUnit,
                     /* 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
                          */
diff --git a/vm/compiler/codegen/arm/README.txt b/vm/compiler/codegen/arm/README.txt
new file mode 100644 (file)
index 0000000..6698ac3
--- /dev/null
@@ -0,0 +1,49 @@
+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.
+
diff --git a/vm/compiler/codegen/arm/Ralloc.h b/vm/compiler/codegen/arm/Ralloc.h
new file mode 100644 (file)
index 0000000..dce1939
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * 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);
index 8aa5fc7..ff77002 100644 (file)
  *
  */
 
+#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,
@@ -72,28 +68,12 @@ static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg);
  * 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++) {
@@ -105,7 +85,7 @@ static void resetRegPool(CompilationUnit *cUnit)
 }
 
  /* 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++) {
@@ -130,6 +110,116 @@ static void dumpRegPool(RegisterInfo *p, int numRegs)
     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)
 {
@@ -159,7 +249,7 @@ static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
 }
 
 //REDO: too many assumptions.
-static int allocTempDouble(CompilationUnit *cUnit)
+extern int allocTempDouble(CompilationUnit *cUnit)
 {
     RegisterInfo *p = cUnit->regPool->FPTemps;
     int numTemps = cUnit->regPool->numFPTemps;
@@ -195,19 +285,19 @@ static int allocTempDouble(CompilationUnit *cUnit)
 }
 
 /* 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);
@@ -254,7 +344,7 @@ static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
     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;
@@ -280,7 +370,7 @@ static void freeTemp(CompilationUnit *cUnit, int reg)
 }
 
 //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;
@@ -300,7 +390,7 @@ static RegisterInfo *isLive(CompilationUnit *cUnit, int reg)
     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;
@@ -320,120 +410,12 @@ static RegisterInfo *isTemp(CompilationUnit *cUnit, int reg)
     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;
@@ -467,7 +449,7 @@ static void lockArgRegs(CompilationUnit *cUnit)
 }
 
 /* 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);
@@ -480,7 +462,7 @@ static void clobberCallRegs(CompilationUnit *cUnit)
 }
 
 /* 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);
@@ -488,7 +470,7 @@ static void clobberHandlerRegs(CompilationUnit *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;
@@ -514,7 +496,7 @@ static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
  * 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);
@@ -530,7 +512,7 @@ static void markDef(CompilationUnit *cUnit, RegLocation rl,
  * 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);
@@ -542,18 +524,20 @@ static void markDefWide(CompilationUnit *cUnit, RegLocation rl,
     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);
@@ -571,7 +555,7 @@ static RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl)
     return rl;
 }
 
-static void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
+extern void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
 {
     assert(!rl.wide);
     if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
@@ -583,7 +567,7 @@ static void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
     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))) {
@@ -596,7 +580,7 @@ static void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
     resetDef(cUnit, rl.highReg);
 }
 
-static void resetDefTracking(CompilationUnit *cUnit)
+extern void resetDefTracking(CompilationUnit *cUnit)
 {
     int i;
     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
@@ -607,7 +591,7 @@ static void resetDefTracking(CompilationUnit *cUnit)
     }
 }
 
-static void clobberAllRegs(CompilationUnit *cUnit)
+extern void clobberAllRegs(CompilationUnit *cUnit)
 {
     int i;
     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
@@ -619,7 +603,7 @@ static void clobberAllRegs(CompilationUnit *cUnit)
 }
 
 /* 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++) {
@@ -643,7 +627,7 @@ static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
     }
 }
 
-static void flushAllRegs(CompilationUnit *cUnit)
+extern void flushAllRegs(CompilationUnit *cUnit)
 {
     flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
                      cUnit->regPool->numCoreTemps);
@@ -665,7 +649,7 @@ static bool regClassMatches(int regClass, int reg)
     }
 }
 
-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) {
@@ -680,7 +664,7 @@ static void markRegLive(CompilationUnit *cUnit, int reg, int sReg)
     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);
@@ -695,22 +679,22 @@ static void markRegSingle(CompilationUnit *cUnit, int reg)
     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 */
@@ -737,7 +721,7 @@ void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
  * 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) {
@@ -757,7 +741,7 @@ static RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc)
 }
 
 /* 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) {
@@ -811,11 +795,11 @@ static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
         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);
@@ -829,9 +813,10 @@ static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
     }
 
     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;
 
@@ -845,7 +830,7 @@ static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
     return loc;
 }
 
-static RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
+extern RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
                                int regClass, bool update)
 {
     RegisterInfo *infoLo = NULL;
@@ -857,8 +842,8 @@ static RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
     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;
@@ -868,7 +853,7 @@ static RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
 
     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) {
@@ -878,12 +863,6 @@ static RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
     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);
@@ -891,7 +870,7 @@ static inline int getDestSSAName(MIR *mir, int 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;
@@ -900,7 +879,7 @@ static inline RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num)
 }
 
 // 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;
@@ -931,25 +910,20 @@ static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
     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);
@@ -960,7 +934,7 @@ static RegLocation getReturnLocWide(CompilationUnit *cUnit)
     return res;
 }
 
-static RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
+extern RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
 {
     RegLocation res = LOC_C_RETURN_WIDE;
     res.lowReg = r2;
@@ -973,7 +947,7 @@ static RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
     return res;
 }
 
-static RegLocation getReturnLoc(CompilationUnit *cUnit)
+extern RegLocation getReturnLoc(CompilationUnit *cUnit)
 {
     RegLocation res = LOC_C_RETURN;
     clobberReg(cUnit, r0);
@@ -981,7 +955,7 @@ static RegLocation getReturnLoc(CompilationUnit *cUnit)
     return res;
 }
 
-static RegLocation getReturnLocAlt(CompilationUnit *cUnit)
+extern RegLocation getReturnLocAlt(CompilationUnit *cUnit)
 {
     RegLocation res = LOC_C_RETURN;
     res.lowReg = r1;
@@ -991,7 +965,7 @@ static RegLocation getReturnLocAlt(CompilationUnit *cUnit)
 }
 
 /* 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) {
@@ -1003,3 +977,14 @@ static inline void killNullCheckedLocation(CompilationUnit *cUnit,
         }
     }
 }
+
+extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
+                                              int reg1, int reg2)
+{
+    flushRegWide(cUnit, reg1, reg2);
+}
+
+extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
+{
+    flushReg(cUnit, reg);
+}
similarity index 68%
rename from vm/compiler/codegen/arm/ThumbUtil.c
rename to vm/compiler/codegen/arm/Thumb/Factory.c
index a626fc7..2348b3a 100644 (file)
  *
  */
 
-#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)
@@ -223,9 +208,6 @@ static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
     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)
 {
@@ -254,46 +236,6 @@ static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
     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)
 {
@@ -473,55 +415,13 @@ static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
     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. */
@@ -613,20 +513,9 @@ static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
     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
@@ -636,7 +525,6 @@ static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
  * rlp and then restore.
  */
 {
-    ArmLIR *first = NULL;
     ArmLIR *res;
     ArmLIR *load = NULL;
     ArmLIR *load2 = NULL;
@@ -706,8 +594,6 @@ static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
         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) {
@@ -740,36 +626,25 @@ static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
         }
     }
 
-    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)
@@ -866,226 +741,85 @@ static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
     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);
 }
diff --git a/vm/compiler/codegen/arm/Thumb/Gen.c b/vm/compiler/codegen/arm/Thumb/Gen.c
new file mode 100644 (file)
index 0000000..2e03fe1
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * 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;
+}
diff --git a/vm/compiler/codegen/arm/Thumb/Ralloc.c b/vm/compiler/codegen/arm/Thumb/Ralloc.c
new file mode 100644 (file)
index 0000000..e9dd9a5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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);
+}
similarity index 68%
rename from vm/compiler/codegen/arm/Thumb2Util.c
rename to vm/compiler/codegen/arm/Thumb2/Factory.c
index d553aae..dfa60fe 100644 (file)
  *
  */
 
-#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)
 {
@@ -78,256 +126,72 @@ static int modifiedImmediate(u4 value)
 }
 
 /*
- * 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)
@@ -569,20 +433,6 @@ static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
     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)
 {
@@ -753,175 +603,57 @@ static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
     }
 }
 
-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,
@@ -1024,22 +756,6 @@ static ArmLIR *storeBaseIndexed(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
@@ -1047,9 +763,8 @@ static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
  */
 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;
@@ -1074,9 +789,9 @@ static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
                 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:
@@ -1144,8 +859,7 @@ static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
         default:
             assert(0);
     }
-    if (nullCheck)
-        first = genNullCheck(cUnit, sReg, rBase, mir->offset, NULL);
+
     if (shortForm) {
         load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
     } else {
@@ -1158,23 +872,23 @@ static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
     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);
 }
 
 
@@ -1309,28 +1023,6 @@ static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
     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);
@@ -1338,83 +1030,11 @@ static void storePair(CompilationUnit *cUnit, int base, int lowReg, int 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.
  */
@@ -1454,123 +1074,90 @@ static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
     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);
+            }
+        }
+    }
 }
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c
new file mode 100644 (file)
index 0000000..579b0ea
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * 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;
+}
diff --git a/vm/compiler/codegen/arm/Thumb2/Ralloc.c b/vm/compiler/codegen/arm/Thumb2/Ralloc.c
new file mode 100644 (file)
index 0000000..0e089a7
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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);
+}
index 3a46cac..a763720 100644 (file)
  * 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();
@@ -97,239 +66,3 @@ static bool compilerArchVariantInit(void)
     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;
-}
diff --git a/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c
new file mode 100644 (file)
index 0000000..04bb3a2
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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"
index 4178c23..1067037 100644 (file)
  * 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();
@@ -89,72 +66,3 @@ static bool compilerArchVariantInit(void)
     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;
-}
diff --git a/vm/compiler/codegen/arm/armv5te/Codegen.c b/vm/compiler/codegen/arm/armv5te/Codegen.c
new file mode 100644 (file)
index 0000000..5e53ae4
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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"
index a2e4175..645af56 100644 (file)
  * 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();
@@ -98,251 +62,3 @@ static bool compilerArchVariantInit(void)
     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;
-}
diff --git a/vm/compiler/codegen/arm/armv7-a/Codegen.c b/vm/compiler/codegen/arm/armv7-a/Codegen.c
new file mode 100644 (file)
index 0000000..baa9632
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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"
index 4c09979..018a77f 100644 (file)
@@ -350,7 +350,11 @@ int dvmJitStartup(void)
 
 #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