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