• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 static void loadFloat(CompilationUnit *cUnit, int vSrc, int rDest);
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  */
dvmCompilerInstructionSet(CompilationUnit * cUnit)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  */
genDispatchToHandler(CompilationUnit * cUnit,TemplateOpCode opCode)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 */
dvmCompilerArchInit(void)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 
genInlineSqrt(CompilationUnit * cUnit,MIR * mir)118 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
119 {
120     int offset = offsetof(InterpState, retval);
121     int vSrc = mir->dalvikInsn.vA;
122     loadDouble(cUnit, vSrc, dr1);
123     newLIR2(cUnit, THUMB2_VSQRTD, dr0, dr1);
124     assert(offset & 0x3 == 0);  /* Must be word aligned */
125     assert(offset < 1024);
126     newLIR3(cUnit, THUMB2_VSTRD, dr0, rGLUE, offset >> 2);
127     return true;
128 }
129 
genInlineCos(CompilationUnit * cUnit,MIR * mir)130 static bool genInlineCos(CompilationUnit *cUnit, MIR *mir)
131 {
132     return false;
133 }
134 
genInlineSin(CompilationUnit * cUnit,MIR * mir)135 static bool genInlineSin(CompilationUnit *cUnit, MIR *mir)
136 {
137     return false;
138 }
139 
genArithOpFloat(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vSrc2)140 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
141                                 int vSrc1, int vSrc2)
142 {
143     int op = THUMB_BKPT;
144 
145     /*
146      * Don't attempt to optimize register usage since these opcodes call out to
147      * the handlers.
148      */
149     switch (mir->dalvikInsn.opCode) {
150         case OP_ADD_FLOAT_2ADDR:
151         case OP_ADD_FLOAT:
152             op = THUMB2_VADDS;
153             break;
154         case OP_SUB_FLOAT_2ADDR:
155         case OP_SUB_FLOAT:
156             op = THUMB2_VSUBS;
157             break;
158         case OP_DIV_FLOAT_2ADDR:
159         case OP_DIV_FLOAT:
160             op = THUMB2_VDIVS;
161             break;
162         case OP_MUL_FLOAT_2ADDR:
163         case OP_MUL_FLOAT:
164             op = THUMB2_VMULS;
165             break;
166         case OP_REM_FLOAT_2ADDR:
167         case OP_REM_FLOAT:
168         case OP_NEG_FLOAT: {
169             return genArithOpFloatPortable(cUnit, mir, vDest, vSrc1, vSrc2);
170         }
171         default:
172             return true;
173     }
174     loadFloat(cUnit, vSrc1, fr2);
175     loadFloat(cUnit, vSrc2, fr4);
176     newLIR3(cUnit, op, fr0, fr2, fr4);
177     storeFloat(cUnit, fr0, vDest, 0);
178     return false;
179 }
180 
genArithOpDouble(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vSrc2)181 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
182                              int vSrc1, int vSrc2)
183 {
184     int op = THUMB_BKPT;
185 
186     /*
187      * Don't attempt to optimize register usage since these opcodes call out to
188      * the handlers.
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, 0);
219     return false;
220 }
221 
genConversion(CompilationUnit * cUnit,MIR * mir)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, 0);
282     } else {
283         newLIR2(cUnit, op, fr0, srcReg);
284         storeFloat(cUnit, fr0, vSrc1Dest, 0);
285     }
286     return false;
287 }
288 
genCmpX(CompilationUnit * cUnit,MIR * mir,int vDest,int vSrc1,int vSrc2)289 static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
290                     int vSrc2)
291 {
292     TemplateOpCode template;
293 
294     /*
295      * Don't attempt to optimize register usage since these opcodes call out to
296      * the handlers.
297      */
298     switch(mir->dalvikInsn.opCode) {
299         case OP_CMPL_FLOAT:
300             template = TEMPLATE_CMPL_FLOAT_VFP;
301             break;
302         case OP_CMPG_FLOAT:
303             template = TEMPLATE_CMPG_FLOAT_VFP;
304             break;
305         case OP_CMPL_DOUBLE:
306             template = TEMPLATE_CMPL_DOUBLE_VFP;
307             break;
308         case OP_CMPG_DOUBLE:
309             template = TEMPLATE_CMPG_DOUBLE_VFP;
310             break;
311         default:
312             return true;
313     }
314     loadValueAddress(cUnit, vSrc1, r0);
315     loadValueAddress(cUnit, vSrc2, r1);
316     genDispatchToHandler(cUnit, template);
317     storeValue(cUnit, r0, vDest, r1);
318     return false;
319 }
320