diff options
author | Ben Cheng <bccheng@google.com> | 2009-11-22 23:31:11 -0800 |
---|---|---|
committer | Ben Cheng <bccheng@google.com> | 2009-11-22 23:31:11 -0800 |
commit | 5d90c20bd7903d7bba966b224e576bf137bf8b4b (patch) | |
tree | 0e83785f8132c4397aa9438325c1503e37a54b0e /vm/compiler | |
parent | ec6029afbfb9aafec2b54b447dff7ddef81e49f5 (diff) | |
download | android_dalvik-5d90c20bd7903d7bba966b224e576bf137bf8b4b.tar.gz android_dalvik-5d90c20bd7903d7bba966b224e576bf137bf8b4b.tar.bz2 android_dalvik-5d90c20bd7903d7bba966b224e576bf137bf8b4b.zip |
Restructure the codegen to make architectural depedency explicit.
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
Diffstat (limited to 'vm/compiler')
30 files changed, 3353 insertions, 2902 deletions
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h index 1cfc56b31..4ab650d72 100644 --- a/vm/compiler/CompilerUtility.h +++ b/vm/compiler/CompilerUtility.h @@ -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 diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c index 1cd821f3c..0683ba26c 100644 --- a/vm/compiler/Frontend.c +++ b/vm/compiler/Frontend.c @@ -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); diff --git a/vm/compiler/codegen/CompilerCodegen.h b/vm/compiler/codegen/CompilerCodegen.h index 75307a766..3e9718c6d 100644 --- a/vm/compiler/codegen/CompilerCodegen.h +++ b/vm/compiler/codegen/CompilerCodegen.h @@ -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_ */ diff --git a/vm/compiler/codegen/arm/ArmLIR.h b/vm/compiler/codegen/arm/ArmLIR.h index 6c3a4864b..15000555a 100644 --- a/vm/compiler/codegen/arm/ArmLIR.h +++ b/vm/compiler/codegen/arm/ArmLIR.h @@ -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 index 506ac9e2b..000000000 --- a/vm/compiler/codegen/arm/Codegen-armv5te-vfp.c +++ /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 index aec19f2c3..000000000 --- a/vm/compiler/codegen/arm/Codegen-armv5te.c +++ /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 index eb18b1a75..000000000 --- a/vm/compiler/codegen/arm/Codegen-armv7-a.c +++ /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" diff --git a/vm/compiler/codegen/arm/Codegen.h b/vm/compiler/codegen/arm/Codegen.h index 414c34330..b148bda9b 100644 --- a/vm/compiler/codegen/arm/Codegen.h +++ b/vm/compiler/codegen/arm/Codegen.h @@ -14,78 +14,59 @@ * 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 index 000000000..9d2f78ab2 --- /dev/null +++ b/vm/compiler/codegen/arm/CodegenCommon.c @@ -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; +} diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/CodegenDriver.c index 370c85781..857536f48 100644 --- a/vm/compiler/codegen/arm/Codegen.c +++ b/vm/compiler/codegen/arm/CodegenDriver.c @@ -24,13 +24,188 @@ * 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; + + 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 ); -/* Track exercised opcodes */ -static int opcodeCoverage[256]; + 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 */ @@ -444,592 +619,8 @@ static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap, 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); - } - /* 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) -{ - ArmLIR *res; - res = opRegReg(cUnit, kOpCmp, reg1, reg2); - ArmLIR *branch = opCondBranch(cUnit, cond); - genCheckCommon(cUnit, dOffset, branch, pcrLabel); - return res; -} - -/* - * 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 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); -} +#endif /* Generate a unconditional branch to go to the interpreter */ static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset, @@ -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 index 000000000..e5a56cc45 --- /dev/null +++ b/vm/compiler/codegen/arm/CodegenFactory.c @@ -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 index 000000000..c0d5d6bba --- /dev/null +++ b/vm/compiler/codegen/arm/FP/Thumb2VFP.c @@ -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 index 000000000..957b4d41f --- /dev/null +++ b/vm/compiler/codegen/arm/FP/ThumbPortableFP.c @@ -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 index 000000000..099f3c6c3 --- /dev/null +++ b/vm/compiler/codegen/arm/FP/ThumbVFP.c @@ -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; +} diff --git a/vm/compiler/codegen/arm/LocalOptimizations.c b/vm/compiler/codegen/arm/LocalOptimizations.c index 86f692f75..159c2aae5 100644 --- a/vm/compiler/codegen/arm/LocalOptimizations.c +++ b/vm/compiler/codegen/arm/LocalOptimizations.c @@ -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 index 000000000..6698ac3fd --- /dev/null +++ b/vm/compiler/codegen/arm/README.txt @@ -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 index 000000000..dce19392c --- /dev/null +++ b/vm/compiler/codegen/arm/Ralloc.h @@ -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); diff --git a/vm/compiler/codegen/arm/RallocUtil.c b/vm/compiler/codegen/arm/RallocUtil.c index 8aa5fc71f..ff7700260 100644 --- a/vm/compiler/codegen/arm/RallocUtil.c +++ b/vm/compiler/codegen/arm/RallocUtil.c @@ -22,8 +22,17 @@ * */ +#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: @@ -48,19 +57,6 @@ * */ -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); +} diff --git a/vm/compiler/codegen/arm/ThumbUtil.c b/vm/compiler/codegen/arm/Thumb/Factory.c index a626fc7f6..2348b3a84 100644 --- a/vm/compiler/codegen/arm/ThumbUtil.c +++ b/vm/compiler/codegen/arm/Thumb/Factory.c @@ -22,102 +22,87 @@ * */ -#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 index 000000000..2e03fe16e --- /dev/null +++ b/vm/compiler/codegen/arm/Thumb/Gen.c @@ -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 index 000000000..e9dd9a57a --- /dev/null +++ b/vm/compiler/codegen/arm/Thumb/Ralloc.c @@ -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); +} diff --git a/vm/compiler/codegen/arm/Thumb2Util.c b/vm/compiler/codegen/arm/Thumb2/Factory.c index d553aaec4..dfa60fe93 100644 --- a/vm/compiler/codegen/arm/Thumb2Util.c +++ b/vm/compiler/codegen/arm/Thumb2/Factory.c @@ -22,7 +22,55 @@ * */ -#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 index 000000000..579b0eadd --- /dev/null +++ b/vm/compiler/codegen/arm/Thumb2/Gen.c @@ -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 index 000000000..0e089a724 --- /dev/null +++ b/vm/compiler/codegen/arm/Thumb2/Ralloc.c @@ -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); +} diff --git a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c index 3a46cace9..a76372074 100644 --- a/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c +++ b/vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c @@ -19,48 +19,17 @@ * 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 index 000000000..04bb3a2b7 --- /dev/null +++ b/vm/compiler/codegen/arm/armv5te-vfp/Codegen.c @@ -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" diff --git a/vm/compiler/codegen/arm/armv5te/ArchVariant.c b/vm/compiler/codegen/arm/armv5te/ArchVariant.c index 4178c2386..106703721 100644 --- a/vm/compiler/codegen/arm/armv5te/ArchVariant.c +++ b/vm/compiler/codegen/arm/armv5te/ArchVariant.c @@ -23,36 +23,13 @@ * 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 index 000000000..5e53ae4e4 --- /dev/null +++ b/vm/compiler/codegen/arm/armv5te/Codegen.c @@ -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" diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c index a2e417502..645af567b 100644 --- a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c +++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c @@ -14,54 +14,18 @@ * 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 index 000000000..baa96323a --- /dev/null +++ b/vm/compiler/codegen/arm/armv7-a/Codegen.c @@ -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" |