2 * Copyright (C) 2009 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <math.h> // for double sqrt(double)
21 * This file is included by Codegen-armv5te-vfp.c, and implements architecture
22 * variant-specific code.
25 #define USE_IN_CACHE_HANDLER 1
28 * Determine the initial instruction set to be used for this trace.
29 * Later components may decide to change this.
31 JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
33 return DALVIK_JIT_THUMB2;
37 * Jump to the out-of-line handler in ARM mode to finish executing the
38 * remaining of more complex instructions.
40 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
42 #if USE_IN_CACHE_HANDLER
44 * NOTE - In practice BLX only needs one operand, but since the assembler
45 * may abort itself and retry due to other out-of-range conditions we
46 * cannot really use operand[0] to store the absolute target address since
47 * it may get clobbered by the final relative offset. Therefore,
48 * we fake BLX_1 is a two operand instruction and the absolute target
49 * address is stored in operand[1].
51 newLIR2(cUnit, THUMB_BLX_1,
52 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
53 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
54 newLIR2(cUnit, THUMB_BLX_2,
55 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
56 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
59 * In case we want to access the statically compiled handlers for
60 * debugging purposes, define USE_IN_CACHE_HANDLER to 0
64 #define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
65 #include "../../../template/armv5te-vfp/TemplateOpList.h"
68 #define JIT_TEMPLATE(X) \
69 case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
70 #include "../../../template/armv5te-vfp/TemplateOpList.h"
72 default: templatePtr = NULL;
74 loadConstant(cUnit, r7, (int) templatePtr);
75 newLIR1(cUnit, THUMB_BLX_R, r7);
79 /* Architecture-specific initializations and checks go here */
80 bool dvmCompilerArchInit(void)
82 /* First, declare dvmCompiler_TEMPLATE_XXX for each template */
83 #define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
84 #include "../../../template/armv5te-vfp/TemplateOpList.h"
88 extern void dvmCompilerTemplateStart(void);
91 * Then, populate the templateEntryOffsets array with the offsets from the
92 * the dvmCompilerTemplateStart symbol for each template.
94 #define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
95 (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
96 #include "../../../template/armv5te-vfp/TemplateOpList.h"
99 /* Codegen-specific assumptions */
100 assert(offsetof(ClassObject, vtable) < 128 &&
101 (offsetof(ClassObject, vtable) & 0x3) == 0);
102 assert(offsetof(ArrayObject, length) < 128 &&
103 (offsetof(ArrayObject, length) & 0x3) == 0);
104 assert(offsetof(ArrayObject, contents) < 256);
106 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
107 assert(sizeof(StackSaveArea) < 236);
110 * EA is calculated by doing "Rn + imm5 << 2", and there are 5 entry points
111 * that codegen may access, make sure that the offset from the top of the
112 * struct is less than 108.
114 assert(offsetof(InterpState, jitToInterpEntries) < 108);
118 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
120 int offset = offsetof(InterpState, retval);
121 int vSrc = mir->dalvikInsn.arg[0];
122 int vDest = inlinedTarget(mir);
126 loadDouble(cUnit, vSrc, dr1);
127 newLIR2(cUnit, THUMB2_VSQRTD, dr0, dr1);
128 newLIR2(cUnit, THUMB2_VCMPD, dr0, dr0);
129 newLIR0(cUnit, THUMB2_FMSTAT);
130 branch = newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_EQ);
131 loadConstant(cUnit, r2, (int)sqrt);
132 newLIR3(cUnit, THUMB2_FMRRD, r0, r1, dr1);
133 newLIR1(cUnit, THUMB_BLX_R, r2);
134 newLIR3(cUnit, THUMB2_FMDRR, dr0, r0, r1);
136 target = storeDouble(cUnit, dr0, vDest, rNone);
138 target = newLIR3(cUnit, THUMB2_VSTRD, dr0, rGLUE, offset >> 2);
139 branch->generic.target = (LIR *)target;
140 resetRegisterScoreboard(cUnit);
144 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
145 int vSrc1, int vSrc2)
150 * Don't attempt to optimize register usage since these opcodes call out to
153 switch (mir->dalvikInsn.opCode) {
154 case OP_ADD_FLOAT_2ADDR:
158 case OP_SUB_FLOAT_2ADDR:
162 case OP_DIV_FLOAT_2ADDR:
166 case OP_MUL_FLOAT_2ADDR:
170 case OP_REM_FLOAT_2ADDR:
173 return genArithOpFloatPortable(cUnit, mir, vDest, vSrc1, vSrc2);
178 loadFloat(cUnit, vSrc1, fr2);
179 loadFloat(cUnit, vSrc2, fr4);
180 newLIR3(cUnit, op, fr0, fr2, fr4);
181 storeFloat(cUnit, fr0, vDest, 0);
185 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
186 int vSrc1, int vSrc2)
190 switch (mir->dalvikInsn.opCode) {
191 case OP_ADD_DOUBLE_2ADDR:
195 case OP_SUB_DOUBLE_2ADDR:
199 case OP_DIV_DOUBLE_2ADDR:
203 case OP_MUL_DOUBLE_2ADDR:
207 case OP_REM_DOUBLE_2ADDR:
209 case OP_NEG_DOUBLE: {
210 return genArithOpDoublePortable(cUnit, mir, vDest, vSrc1, vSrc2);
215 loadDouble(cUnit, vSrc1, dr1);
216 loadDouble(cUnit, vSrc2, dr2);
217 newLIR3(cUnit, op, dr0, dr1, dr2);
218 storeDouble(cUnit, dr0, vDest, rNone);
222 static bool genConversion(CompilationUnit *cUnit, MIR *mir)
224 OpCode opCode = mir->dalvikInsn.opCode;
225 int vSrc1Dest = mir->dalvikInsn.vA;
226 int vSrc2 = mir->dalvikInsn.vB;
228 bool longSrc = false;
229 bool longDest = false;
234 case OP_INT_TO_FLOAT:
239 case OP_FLOAT_TO_INT:
244 case OP_DOUBLE_TO_FLOAT:
249 case OP_FLOAT_TO_DOUBLE:
254 case OP_INT_TO_DOUBLE:
259 case OP_DOUBLE_TO_INT:
264 case OP_FLOAT_TO_LONG:
265 case OP_LONG_TO_FLOAT:
266 case OP_DOUBLE_TO_LONG:
267 case OP_LONG_TO_DOUBLE:
268 return genConversionPortable(cUnit, mir);
274 loadDouble(cUnit, vSrc2, srcReg);
277 loadFloat(cUnit, vSrc2, srcReg);
280 newLIR2(cUnit, op, dr0, srcReg);
281 storeDouble(cUnit, dr0, vSrc1Dest, rNone);
283 newLIR2(cUnit, op, fr0, srcReg);
284 storeFloat(cUnit, fr0, vSrc1Dest, 0);
289 static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
296 switch(mir->dalvikInsn.opCode) {
317 loadDouble(cUnit, vSrc1, dr0);
318 loadDouble(cUnit, vSrc2, dr1);
319 // Hard-coded use of r7 as temp. Revisit
320 loadConstant(cUnit,r7, defaultResult);
321 newLIR2(cUnit, THUMB2_VCMPD, dr0, dr1);
323 loadFloat(cUnit, vSrc1, fr0);
324 loadFloat(cUnit, vSrc2, fr2);
325 // Hard-coded use of r7 as temp. Revisit
326 loadConstant(cUnit,r7, defaultResult);
327 newLIR2(cUnit, THUMB2_VCMPS, fr0, fr2);
329 newLIR0(cUnit, THUMB2_FMSTAT);
330 genIT(cUnit, (defaultResult == -1) ? ARM_COND_GT : ARM_COND_MI, "");
331 newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7,
332 modifiedImmediate(-defaultResult)); // Must not alter ccodes
333 genIT(cUnit, ARM_COND_EQ, "");
334 loadConstant(cUnit, r7, 0);
335 // Hard-coded use of r4PC as temp. Revisit
336 storeValue(cUnit, r7, vDest, r4PC);