OSDN Git Service

Inline Sqrt bug fix; add support for fp/gen register copies
[android-x86/dalvik.git] / vm / compiler / codegen / arm / armv7-a / ArchVariant.c
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <math.h>  // for double sqrt(double)
18
19
20 /*
21  * This file is included by Codegen-armv5te-vfp.c, and implements architecture
22  * variant-specific code.
23  */
24
25 #define USE_IN_CACHE_HANDLER 1
26
27 /*
28  * Determine the initial instruction set to be used for this trace.
29  * Later components may decide to change this.
30  */
31 JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
32 {
33     return DALVIK_JIT_THUMB2;
34 }
35
36 /*
37  * Jump to the out-of-line handler in ARM mode to finish executing the
38  * remaining of more complex instructions.
39  */
40 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
41 {
42 #if USE_IN_CACHE_HANDLER
43     /*
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].
50      */
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]);
57 #else
58     /*
59      * In case we want to access the statically compiled handlers for
60      * debugging purposes, define USE_IN_CACHE_HANDLER to 0
61      */
62     void *templatePtr;
63
64 #define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
65 #include "../../../template/armv5te-vfp/TemplateOpList.h"
66 #undef JIT_TEMPLATE
67     switch (opCode) {
68 #define JIT_TEMPLATE(X) \
69         case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
70 #include "../../../template/armv5te-vfp/TemplateOpList.h"
71 #undef JIT_TEMPLATE
72         default: templatePtr = NULL;
73     }
74     loadConstant(cUnit, r7, (int) templatePtr);
75     newLIR1(cUnit, THUMB_BLX_R, r7);
76 #endif
77 }
78
79 /* Architecture-specific initializations and checks go here */
80 bool dvmCompilerArchInit(void)
81 {
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"
85 #undef JIT_TEMPLATE
86
87     int i = 0;
88     extern void dvmCompilerTemplateStart(void);
89
90     /*
91      * Then, populate the templateEntryOffsets array with the offsets from the
92      * the dvmCompilerTemplateStart symbol for each template.
93      */
94 #define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
95     (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
96 #include "../../../template/armv5te-vfp/TemplateOpList.h"
97 #undef JIT_TEMPLATE
98
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);
105
106     /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
107     assert(sizeof(StackSaveArea) < 236);
108
109     /*
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.
113      */
114     assert(offsetof(InterpState, jitToInterpEntries) < 108);
115     return true;
116 }
117
118 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
119 {
120     int offset = offsetof(InterpState, retval);
121     int vSrc = mir->dalvikInsn.arg[0];
122     int vDest = inlinedTarget(mir);
123     ArmLIR *branch;
124     ArmLIR *target;
125
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);
135     if (vDest >= 0)
136         target = storeDouble(cUnit, dr0, vDest, rNone);
137     else
138         target = newLIR3(cUnit, THUMB2_VSTRD, dr0, rGLUE, offset >> 2);
139     branch->generic.target = (LIR *)target;
140     resetRegisterScoreboard(cUnit);
141     return true;
142 }
143
144 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
145                                 int vSrc1, int vSrc2)
146 {
147     int op = THUMB_BKPT;
148
149     /*
150      * Don't attempt to optimize register usage since these opcodes call out to
151      * the handlers.
152      */
153     switch (mir->dalvikInsn.opCode) {
154         case OP_ADD_FLOAT_2ADDR:
155         case OP_ADD_FLOAT:
156             op = THUMB2_VADDS;
157             break;
158         case OP_SUB_FLOAT_2ADDR:
159         case OP_SUB_FLOAT:
160             op = THUMB2_VSUBS;
161             break;
162         case OP_DIV_FLOAT_2ADDR:
163         case OP_DIV_FLOAT:
164             op = THUMB2_VDIVS;
165             break;
166         case OP_MUL_FLOAT_2ADDR:
167         case OP_MUL_FLOAT:
168             op = THUMB2_VMULS;
169             break;
170         case OP_REM_FLOAT_2ADDR:
171         case OP_REM_FLOAT:
172         case OP_NEG_FLOAT: {
173             return genArithOpFloatPortable(cUnit, mir, vDest, vSrc1, vSrc2);
174         }
175         default:
176             return true;
177     }
178     loadFloat(cUnit, vSrc1, fr2);
179     loadFloat(cUnit, vSrc2, fr4);
180     newLIR3(cUnit, op, fr0, fr2, fr4);
181     storeFloat(cUnit, fr0, vDest, 0);
182     return false;
183 }
184
185 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
186                              int vSrc1, int vSrc2)
187 {
188     int op = THUMB_BKPT;
189
190     switch (mir->dalvikInsn.opCode) {
191         case OP_ADD_DOUBLE_2ADDR:
192         case OP_ADD_DOUBLE:
193             op = THUMB2_VADDD;
194             break;
195         case OP_SUB_DOUBLE_2ADDR:
196         case OP_SUB_DOUBLE:
197             op = THUMB2_VSUBD;
198             break;
199         case OP_DIV_DOUBLE_2ADDR:
200         case OP_DIV_DOUBLE:
201             op = THUMB2_VDIVD;
202             break;
203         case OP_MUL_DOUBLE_2ADDR:
204         case OP_MUL_DOUBLE:
205             op = THUMB2_VMULD;
206             break;
207         case OP_REM_DOUBLE_2ADDR:
208         case OP_REM_DOUBLE:
209         case OP_NEG_DOUBLE: {
210             return genArithOpDoublePortable(cUnit, mir, vDest, vSrc1, vSrc2);
211         }
212         default:
213             return true;
214     }
215     loadDouble(cUnit, vSrc1, dr1);
216     loadDouble(cUnit, vSrc2, dr2);
217     newLIR3(cUnit, op, dr0, dr1, dr2);
218     storeDouble(cUnit, dr0, vDest, rNone);
219     return false;
220 }
221
222 static bool genConversion(CompilationUnit *cUnit, MIR *mir)
223 {
224     OpCode opCode = mir->dalvikInsn.opCode;
225     int vSrc1Dest = mir->dalvikInsn.vA;
226     int vSrc2 = mir->dalvikInsn.vB;
227     int op = THUMB_BKPT;
228     bool longSrc = false;
229     bool longDest = false;
230     int srcReg;
231     int tgtReg;
232
233     switch (opCode) {
234         case OP_INT_TO_FLOAT:
235             longSrc = false;
236             longDest = false;
237             op = THUMB2_VCVTIF;
238             break;
239         case OP_FLOAT_TO_INT:
240             longSrc = false;
241             longDest = false;
242             op = THUMB2_VCVTFI;
243             break;
244         case OP_DOUBLE_TO_FLOAT:
245             longSrc = true;
246             longDest = false;
247             op = THUMB2_VCVTDF;
248             break;
249         case OP_FLOAT_TO_DOUBLE:
250             longSrc = false;
251             longDest = true;
252             op = THUMB2_VCVTFD;
253             break;
254         case OP_INT_TO_DOUBLE:
255             longSrc = false;
256             longDest = true;
257             op = THUMB2_VCVTID;
258             break;
259         case OP_DOUBLE_TO_INT:
260             longSrc = true;
261             longDest = false;
262             op = THUMB2_VCVTDI;
263             break;
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);
269         default:
270             return true;
271     }
272     if (longSrc) {
273         srcReg = dr1;
274         loadDouble(cUnit, vSrc2, srcReg);
275     } else {
276         srcReg = fr2;
277         loadFloat(cUnit, vSrc2, srcReg);
278     }
279     if (longDest) {
280         newLIR2(cUnit, op, dr0, srcReg);
281         storeDouble(cUnit, dr0, vSrc1Dest, rNone);
282     } else {
283         newLIR2(cUnit, op, fr0, srcReg);
284         storeFloat(cUnit, fr0, vSrc1Dest, 0);
285     }
286     return false;
287 }
288
289 static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
290                     int vSrc2)
291 {
292     bool isDouble;
293     int defaultResult;
294     bool ltNaNBias;
295
296     switch(mir->dalvikInsn.opCode) {
297         case OP_CMPL_FLOAT:
298             isDouble = false;
299             defaultResult = -1;
300             break;
301         case OP_CMPG_FLOAT:
302             isDouble = false;
303             defaultResult = 1;
304             break;
305         case OP_CMPL_DOUBLE:
306             isDouble = true;
307             defaultResult = -1;
308             break;
309         case OP_CMPG_DOUBLE:
310             isDouble = true;
311             defaultResult = 1;
312             break;
313         default:
314             return true;
315     }
316     if (isDouble) {
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);
322     } else {
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);
328     }
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);
337     return false;
338 }