diff options
author | Bill Buzbee <buzbee@google.com> | 2009-07-30 10:52:29 -0700 |
---|---|---|
committer | Bill Buzbee <buzbee@google.com> | 2009-07-31 17:30:22 -0700 |
commit | 9bc3df373ae6f4f7e6e97d554884d4e0dbad5494 (patch) | |
tree | 4d3e4e99e62524beb247dd6c56838eb69a5057f9 /vm/compiler/codegen/arm/armv7-a/ArchVariant.c | |
parent | 51b9e5c27aa5d5c399f93f2df2b2ca1674b0858d (diff) | |
download | android_dalvik-9bc3df373ae6f4f7e6e97d554884d4e0dbad5494.tar.gz android_dalvik-9bc3df373ae6f4f7e6e97d554884d4e0dbad5494.tar.bz2 android_dalvik-9bc3df373ae6f4f7e6e97d554884d4e0dbad5494.zip |
Stage 3 of Thumb2 support. armv7-a now generates vfp code inline.
Diffstat (limited to 'vm/compiler/codegen/arm/armv7-a/ArchVariant.c')
-rw-r--r-- | vm/compiler/codegen/arm/armv7-a/ArchVariant.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/vm/compiler/codegen/arm/armv7-a/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c new file mode 100644 index 000000000..15ed0781f --- /dev/null +++ b/vm/compiler/codegen/arm/armv7-a/ArchVariant.c @@ -0,0 +1,312 @@ +/* + * 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. + */ + + +static void loadFloat(CompilationUnit *cUnit, int vSrc, int rDest); + +/* + * This file is included by Codegen-armv5te-vfp.c, and implements architecture + * variant-specific code. + */ + +#define USE_IN_CACHE_HANDLER 1 + +/* + * Determine the initial instruction set to be used for this trace. + * Later components may decide to change this. + */ +JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit) +{ + 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) +{ +#if USE_IN_CACHE_HANDLER + /* + * 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]. + */ + newLIR2(cUnit, THUMB_BLX_1, + (int) gDvmJit.codeCache + templateEntryOffsets[opCode], + (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); + newLIR2(cUnit, THUMB_BLX_2, + (int) gDvmJit.codeCache + templateEntryOffsets[opCode], + (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); +#else + /* + * In case we want to access the statically compiled handlers for + * debugging purposes, define USE_IN_CACHE_HANDLER to 0 + */ + void *templatePtr; + +#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X(); +#include "../../../template/armv5te-vfp/TemplateOpList.h" +#undef JIT_TEMPLATE + switch (opCode) { +#define JIT_TEMPLATE(X) \ + case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; } +#include "../../../template/armv5te-vfp/TemplateOpList.h" +#undef JIT_TEMPLATE + default: templatePtr = NULL; + } + loadConstant(cUnit, r7, (int) templatePtr); + newLIR1(cUnit, THUMB_BLX_R, r7); +#endif +} + +/* Architecture-specific initializations and checks go here */ +bool dvmCompilerArchInit(void) +{ + /* First, declare dvmCompiler_TEMPLATE_XXX for each template */ +#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X(); +#include "../../../template/armv5te-vfp/TemplateOpList.h" +#undef JIT_TEMPLATE + + int i = 0; + extern void dvmCompilerTemplateStart(void); + + /* + * Then, populate the templateEntryOffsets array with the offsets from the + * the dvmCompilerTemplateStart symbol for each template. + */ +#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \ + (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart; +#include "../../../template/armv5te-vfp/TemplateOpList.h" +#undef JIT_TEMPLATE + + /* Codegen-specific assumptions */ + assert(offsetof(ClassObject, vtable) < 128 && + (offsetof(ClassObject, vtable) & 0x3) == 0); + assert(offsetof(ArrayObject, length) < 128 && + (offsetof(ArrayObject, length) & 0x3) == 0); + assert(offsetof(ArrayObject, contents) < 256); + + /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */ + assert(sizeof(StackSaveArea) < 236); + + /* + * EA is calculated by doing "Rn + imm5 << 2", and there are 5 entry points + * that codegen may access, make sure that the offset from the top of the + * struct is less than 108. + */ + assert(offsetof(InterpState, jitToInterpEntries) < 108); + return true; +} + +static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir) +{ + int offset = offsetof(InterpState, retval); + OpCode opCode = mir->dalvikInsn.opCode; + int vSrc = mir->dalvikInsn.vA; + loadValueAddress(cUnit, vSrc, r2); + genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP); + newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2); + newLIR3(cUnit, THUMB_STR_RRI5, r1, rGLUE, (offset >> 2) + 1); + return false; +} + +static bool genInlineCos(CompilationUnit *cUnit, MIR *mir) +{ + return false; +} + +static bool genInlineSin(CompilationUnit *cUnit, MIR *mir) +{ + return false; +} + +static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest, + int vSrc1, int vSrc2) +{ + int op = THUMB_BKPT; + + /* + * 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 = THUMB2_VADDS; + break; + case OP_SUB_FLOAT_2ADDR: + case OP_SUB_FLOAT: + op = THUMB2_VSUBS; + break; + case OP_DIV_FLOAT_2ADDR: + case OP_DIV_FLOAT: + op = THUMB2_VDIVS; + break; + case OP_MUL_FLOAT_2ADDR: + case OP_MUL_FLOAT: + op = THUMB2_VMULS; + break; + case OP_REM_FLOAT_2ADDR: + case OP_REM_FLOAT: + case OP_NEG_FLOAT: { + return genArithOpFloatPortable(cUnit, mir, vDest, vSrc1, vSrc2); + } + default: + return true; + } + loadFloat(cUnit, vSrc1, fr2); + loadFloat(cUnit, vSrc2, fr4); + newLIR3(cUnit, op, fr0, fr2, fr4); + storeFloat(cUnit, fr0, vDest, 0); + return false; +} + +static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest, + int vSrc1, int vSrc2) +{ + int op = THUMB_BKPT; + + /* + * Don't attempt to optimize register usage since these opcodes call out to + * the handlers. + */ + switch (mir->dalvikInsn.opCode) { + case OP_ADD_DOUBLE_2ADDR: + case OP_ADD_DOUBLE: + op = THUMB2_VADDD; + break; + case OP_SUB_DOUBLE_2ADDR: + case OP_SUB_DOUBLE: + op = THUMB2_VSUBD; + break; + case OP_DIV_DOUBLE_2ADDR: + case OP_DIV_DOUBLE: + op = THUMB2_VDIVD; + break; + case OP_MUL_DOUBLE_2ADDR: + case OP_MUL_DOUBLE: + op = THUMB2_VMULD; + break; + case OP_REM_DOUBLE_2ADDR: + case OP_REM_DOUBLE: + case OP_NEG_DOUBLE: { + return genArithOpDoublePortable(cUnit, mir, vDest, vSrc1, vSrc2); + } + default: + return true; + } + loadDouble(cUnit, vSrc1, fr2); + loadDouble(cUnit, vSrc2, fr4); + newLIR3(cUnit, op, fr0, fr2, fr4); + storeDouble(cUnit, fr0, vDest, 0); + return false; +} + +static bool genConversion(CompilationUnit *cUnit, MIR *mir) +{ + OpCode opCode = mir->dalvikInsn.opCode; + int vSrc1Dest = mir->dalvikInsn.vA; + int vSrc2 = mir->dalvikInsn.vB; + int op = THUMB_BKPT; + bool longSrc = false; + bool longDest = false; + + switch (opCode) { + case OP_INT_TO_FLOAT: + longSrc = false; + longDest = false; + op = THUMB2_VCVTIF; + break; + case OP_FLOAT_TO_INT: + longSrc = false; + longDest = false; + op = THUMB2_VCVTFI; + break; + case OP_DOUBLE_TO_FLOAT: + longSrc = true; + longDest = false; + op = THUMB2_VCVTDF; + break; + case OP_FLOAT_TO_DOUBLE: + longSrc = false; + longDest = true; + op = THUMB2_VCVTFD; + break; + case OP_INT_TO_DOUBLE: + longSrc = false; + longDest = true; + op = THUMB2_VCVTID; + break; + case OP_DOUBLE_TO_INT: + longSrc = true; + longDest = false; + op = THUMB2_VCVTDI; + break; + case OP_FLOAT_TO_LONG: + case OP_LONG_TO_FLOAT: + case OP_DOUBLE_TO_LONG: + case OP_LONG_TO_DOUBLE: + return genConversionPortable(cUnit, mir); + default: + return true; + } + if (longSrc) + loadDouble(cUnit, vSrc2, fr2); + else + loadFloat(cUnit, vSrc2, fr2); + newLIR2(cUnit, op, fr0, fr2); + if (longSrc) + storeDouble(cUnit, fr0, vSrc1Dest, 0); + else + storeFloat(cUnit, fr0, vSrc1Dest, 0); + return false; +} + +static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1, + int vSrc2) +{ + TemplateOpCode template; + + /* + * Don't attempt to optimize register usage since these opcodes call out to + * the handlers. + */ + switch(mir->dalvikInsn.opCode) { + case OP_CMPL_FLOAT: + template = TEMPLATE_CMPL_FLOAT_VFP; + break; + case OP_CMPG_FLOAT: + template = TEMPLATE_CMPG_FLOAT_VFP; + 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, vSrc1, r0); + loadValueAddress(cUnit, vSrc2, r1); + genDispatchToHandler(cUnit, template); + storeValue(cUnit, r0, vDest, r1); + return false; +} |