blob: 4106e1ddeb00ffc69a6353c53bcb35401b5ce4a4 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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
buzbee67bf8852011-08-17 17:51:35 -070017static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
18 INVALID_REG, INVALID_SREG, 0,
19 kLocDalvikFrame, INVALID_REG, INVALID_REG,
20 INVALID_OFFSET};
21static const RegLocation retLoc = LOC_DALVIK_RETURN_VAL;
22static const RegLocation retLocWide = LOC_DALVIK_RETURN_VAL_WIDE;
23
24static void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
25 RegLocation rlSrc)
26{
27 oatFlushAllRegs(cUnit); /* All temps to home location */
buzbee439c4fa2011-08-27 15:59:07 -070028 UNIMPLEMENTED(WARNING) << "Need to handle unresolved";
29 /*
30 * Need new routine that passes Method*, type index, length.
31 * This is unconditional - always go this way.
32 */
buzbeec143c552011-08-20 17:38:58 -070033 Class* classPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
Brian Carlstrom9ea1cb12011-08-24 23:18:18 -070034 GetResolvedType(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -070035 if (classPtr == NULL) {
buzbee3ea4ec52011-08-22 17:37:19 -070036 LOG(FATAL) << "Unexpected null classPtr";
buzbee67bf8852011-08-17 17:51:35 -070037 } else {
38 loadValueDirectFixed(cUnit, rlSrc, r1); /* get Len */
39 loadConstant(cUnit, r0, (int)classPtr);
40 }
buzbee3ea4ec52011-08-22 17:37:19 -070041 UNIMPLEMENTED(WARNING) << "Support for throwing errNegativeArraySize";
buzbee67bf8852011-08-17 17:51:35 -070042 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
buzbee67bf8852011-08-17 17:51:35 -070043 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pArtAllocArrayByClass),
44 rLR);
buzbee3ea4ec52011-08-22 17:37:19 -070045 UNIMPLEMENTED(WARNING) << "Need NoThrow wrapper";
buzbee67bf8852011-08-17 17:51:35 -070046 newLIR1(cUnit, kThumbBlxR, rLR); // (arrayClass, length, allocFlags)
47 storeValue(cUnit, rlDest, retLoc);
48}
49
50/*
51 * Similar to genNewArray, but with post-allocation initialization.
52 * Verifier guarantees we're dealing with an array class. Current
53 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
54 * Current code also throws internal unimp if not 'L', '[' or 'I'.
55 */
56static void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
57{
58 DecodedInstruction* dInsn = &mir->dalvikInsn;
59 int elems;
60 int typeIndex;
61 if (isRange) {
62 elems = dInsn->vA;
63 typeIndex = dInsn->vB;
64 } else {
65 elems = dInsn->vB;
66 typeIndex = dInsn->vC;
67 }
68 oatFlushAllRegs(cUnit); /* All temps to home location */
buzbeec143c552011-08-20 17:38:58 -070069 Class* classPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
Brian Carlstrom9ea1cb12011-08-24 23:18:18 -070070 GetResolvedType(typeIndex);
buzbee67bf8852011-08-17 17:51:35 -070071 if (classPtr == NULL) {
buzbee3ea4ec52011-08-22 17:37:19 -070072 LOG(FATAL) << "Unexpected null classPtr";
buzbee67bf8852011-08-17 17:51:35 -070073 } else {
74 loadConstant(cUnit, r0, (int)classPtr);
75 loadConstant(cUnit, r1, elems);
76 }
77 if (elems < 0) {
78 LOG(FATAL) << "Unexpected empty array";
79 }
80 /*
81 * FIXME: Need a new NoThrow allocator that checks for and handles
82 * the above mentioned bad cases of 'D', 'J' or !('L' | '[' | 'I').
83 * That will keep us from wasting space generating an inline check here.
84 */
buzbee67bf8852011-08-17 17:51:35 -070085 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pArtAllocArrayByClass),
86 rLR);
buzbee67bf8852011-08-17 17:51:35 -070087 newLIR1(cUnit, kThumbBlxR, rLR); // (arrayClass, length, allocFlags)
88 // Reserve ret0 (r0) - we'll use it in place.
89 oatLockTemp(cUnit, r0);
90 // Having a range of 0 is legal
91 if (isRange && (dInsn->vA > 0)) {
92 /*
93 * Bit of ugliness here. We're going generate a mem copy loop
94 * on the register range, but it is possible that some regs
95 * in the range have been promoted. This is unlikely, but
96 * before generating the copy, we'll just force a flush
97 * of any regs in the source range that have been promoted to
98 * home location.
99 */
100 for (unsigned int i = 0; i < dInsn->vA; i++) {
101 RegLocation loc = oatUpdateLoc(cUnit,
102 oatGetSrc(cUnit, mir, i));
103 if (loc.location == kLocPhysReg) {
104 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
105 }
106 }
107 /*
108 * TUNING note: generated code here could be much improved, but
109 * this is an uncommon operation and isn't especially performance
110 * critical.
111 */
112 int rSrc = oatAllocTemp(cUnit);
113 int rDst = oatAllocTemp(cUnit);
114 int rIdx = oatAllocTemp(cUnit);
115 int rVal = rLR; // Using a lot of temps, rLR is known free here
116 // Set up source pointer
117 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
118 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
119 // Set up the target pointer
120 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700121 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700122 // Set up the loop counter (known to be > 0)
123 loadConstant(cUnit, rIdx, dInsn->vA);
124 // Generate the copy loop. Going backwards for convenience
125 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
126 target->defMask = ENCODE_ALL;
127 // Copy next element
128 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
129 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
130 // Use setflags encoding here
131 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
132 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
133 branch->generic.target = (LIR*)target;
134 } else if (!isRange) {
135 // TUNING: interleave
136 for (unsigned int i = 0; i < dInsn->vA; i++) {
137 RegLocation rlArg = loadValue(cUnit,
138 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700139 storeBaseDisp(cUnit, r0,
140 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700141 i * 4, rlArg.lowReg, kWord);
142 // If the loadValue caused a temp to be allocated, free it
143 if (oatIsTemp(cUnit, rlArg.lowReg)) {
144 oatFreeTemp(cUnit, rlArg.lowReg);
145 }
146 }
147 }
148}
149
150static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
151{
buzbeec143c552011-08-20 17:38:58 -0700152 UNIMPLEMENTED(FATAL) << "Must update for new world";
153#if 0
buzbee67bf8852011-08-17 17:51:35 -0700154 int valOffset = OFFSETOF_MEMBER(StaticField, value);
155 int tReg = oatAllocTemp(cUnit);
156 int objHead;
157 bool isVolatile;
158 bool isSputObject;
159 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
160 mir->meta.calleeMethod : cUnit->method;
161 void* fieldPtr = (void*)
162 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
163 Opcode opcode = mir->dalvikInsn.opcode;
164
165 if (fieldPtr == NULL) {
166 // FIXME: need to handle this case for oat();
167 UNIMPLEMENTED(FATAL);
168 }
169
170#if ANDROID_SMP != 0
171 isVolatile = (opcode == OP_SPUT_VOLATILE) ||
172 (opcode == OP_SPUT_VOLATILE_JUMBO) ||
173 (opcode == OP_SPUT_OBJECT_VOLATILE) ||
174 (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO);
buzbeec143c552011-08-20 17:38:58 -0700175 assert(isVolatile == artIsVolatileField((Field *) fieldPtr));
buzbee67bf8852011-08-17 17:51:35 -0700176#else
buzbeec143c552011-08-20 17:38:58 -0700177 isVolatile = artIsVolatileField((Field *) fieldPtr);
buzbee67bf8852011-08-17 17:51:35 -0700178#endif
179
180 isSputObject = (opcode == OP_SPUT_OBJECT) ||
181 (opcode == OP_SPUT_OBJECT_VOLATILE);
182
183 rlSrc = oatGetSrc(cUnit, mir, 0);
184 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
185 loadConstant(cUnit, tReg, (int) fieldPtr);
186 if (isSputObject) {
187 objHead = oatAllocTemp(cUnit);
188 loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead);
189 }
190 storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg);
191 oatFreeTemp(cUnit, tReg);
192 if (isVolatile) {
193 oatGenMemBarrier(cUnit, kSY);
194 }
195 if (isSputObject) {
196 /* NOTE: marking card based sfield->clazz */
197 markGCCard(cUnit, rlSrc.lowReg, objHead);
198 oatFreeTemp(cUnit, objHead);
199 }
buzbeec143c552011-08-20 17:38:58 -0700200#endif
buzbee67bf8852011-08-17 17:51:35 -0700201}
202
203static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
204{
buzbeec143c552011-08-20 17:38:58 -0700205 UNIMPLEMENTED(FATAL) << "Must update for new world";
206#if 0
buzbee67bf8852011-08-17 17:51:35 -0700207 int tReg = oatAllocTemp(cUnit);
208 int valOffset = OFFSETOF_MEMBER(StaticField, value);
209 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
210 mir->meta.calleeMethod : cUnit->method;
211 void* fieldPtr = (void*)
212 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
213
214 if (fieldPtr == NULL) {
215 // FIXME: need to handle this case for oat();
216 UNIMPLEMENTED(FATAL);
217 }
218
219 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
220 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
221 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
222
223 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
buzbeec143c552011-08-20 17:38:58 -0700224#endif
buzbee67bf8852011-08-17 17:51:35 -0700225}
226
227
228
229static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
230 RegLocation rlResult, RegLocation rlDest)
231{
buzbeec143c552011-08-20 17:38:58 -0700232 UNIMPLEMENTED(FATAL) << "Must update for new world";
233#if 0
buzbee67bf8852011-08-17 17:51:35 -0700234 int valOffset = OFFSETOF_MEMBER(StaticField, value);
235 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
236 mir->meta.calleeMethod : cUnit->method;
237 void* fieldPtr = (void*)
238 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
239
240 if (fieldPtr == NULL) {
241 // FIXME: need to handle this case for oat();
242 UNIMPLEMENTED(FATAL);
243 }
244
245 int tReg = oatAllocTemp(cUnit);
246 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
247 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
248 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
249
250 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
251
252 storeValueWide(cUnit, rlDest, rlResult);
buzbeec143c552011-08-20 17:38:58 -0700253#endif
buzbee67bf8852011-08-17 17:51:35 -0700254}
255
256static void genSget(CompilationUnit* cUnit, MIR* mir,
257 RegLocation rlResult, RegLocation rlDest)
258{
buzbeec143c552011-08-20 17:38:58 -0700259 UNIMPLEMENTED(FATAL) << "Must update for new world";
260#if 0
buzbee67bf8852011-08-17 17:51:35 -0700261 int valOffset = OFFSETOF_MEMBER(StaticField, value);
262 int tReg = oatAllocTemp(cUnit);
263 bool isVolatile;
264 const Method *method = cUnit->method;
265 void* fieldPtr = (void*)
266 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
267
268 if (fieldPtr == NULL) {
269 // FIXME: need to handle this case for oat();
270 UNIMPLEMENTED(FATAL);
271 }
272
273 /*
274 * On SMP systems, Dalvik opcodes found to be referencing
275 * volatile fields are rewritten to their _VOLATILE variant.
276 * However, this does not happen on non-SMP systems. The compiler
277 * still needs to know about volatility to avoid unsafe
278 * optimizations so we determine volatility based on either
279 * the opcode or the field access flags.
280 */
281#if ANDROID_SMP != 0
282 Opcode opcode = mir->dalvikInsn.opcode;
283 isVolatile = (opcode == OP_SGET_VOLATILE) ||
284 (opcode == OP_SGET_OBJECT_VOLATILE);
buzbeec143c552011-08-20 17:38:58 -0700285 assert(isVolatile == artIsVolatileField((Field *) fieldPtr));
buzbee67bf8852011-08-17 17:51:35 -0700286#else
buzbeec143c552011-08-20 17:38:58 -0700287 isVolatile = artIsVolatileField((Field *) fieldPtr);
buzbee67bf8852011-08-17 17:51:35 -0700288#endif
289
290 rlDest = oatGetDest(cUnit, mir, 0);
291 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
292 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
293
294 if (isVolatile) {
295 oatGenMemBarrier(cUnit, kSY);
296 }
297 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
298
299 storeValue(cUnit, rlDest, rlResult);
buzbeec143c552011-08-20 17:38:58 -0700300#endif
buzbee67bf8852011-08-17 17:51:35 -0700301}
302
303typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int);
304
305/*
306 * Bit of a hack here - in leiu of a real scheduling pass,
307 * emit the next instruction in static & direct invoke sequences.
308 */
309static int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
310 DecodedInstruction* dInsn, int state)
311{
buzbeec143c552011-08-20 17:38:58 -0700312 UNIMPLEMENTED(FATAL) << "Update with new cache model";
313#if 0
buzbee67bf8852011-08-17 17:51:35 -0700314 switch(state) {
315 case 0: // Get the current Method* [sets r0]
316 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
317 break;
318 case 1: // Get the pResMethods pointer [uses r0, sets r0]
buzbeec143c552011-08-20 17:38:58 -0700319 UNIMPLEMENTED(FATAL) << "Update with new cache";
buzbee67bf8852011-08-17 17:51:35 -0700320 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, pResMethods),
321 r0, kWord, INVALID_SREG);
322 break;
323 case 2: // Get the target Method* [uses r0, sets r0]
324 loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
325 kWord, INVALID_SREG);
326 break;
327 case 3: // Get the target compiled code address [uses r0, sets rLR]
328 loadBaseDisp(cUnit, mir, r0,
329 OFFSETOF_MEMBER(Method, compiledInsns), rLR,
330 kWord, INVALID_SREG);
331 break;
332 default:
333 return -1;
334 }
buzbeec143c552011-08-20 17:38:58 -0700335#endif
buzbee67bf8852011-08-17 17:51:35 -0700336 return state + 1;
337}
338
buzbeec5ef0462011-08-25 18:44:49 -0700339// Slow path static & direct invoke launch sequence
340static int nextSDCallInsnSP(CompilationUnit* cUnit, MIR* mir,
341 DecodedInstruction* dInsn, int state)
342{
343 switch(state) {
344 case 0: // Get the current Method* [sets r0]
345 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
346 break;
347 case 1: // Get the current Method->DeclaringClass() [sets r0]
348 loadBaseDisp(cUnit, mir, r0,
349 OFFSETOF_MEMBER(art::Method, declaring_class_),
350 r0, kWord, INVALID_SREG);
351 break;
352 case 2: // Method->DeclaringClass()->GetDexCache() [sets r0]
353 loadBaseDisp(cUnit, mir, r0,
354 OFFSETOF_MEMBER(art::Class, dex_cache_), r0, kWord,
355 INVALID_SREG);
356 break;
357 case 3: // Method->DeclaringClass()->GetDexCache()->methodsObjectArr
buzbee5cd21802011-08-26 10:40:14 -0700358 loadBaseDisp(cUnit, mir, r0,
359 art::DexCache::MethodsOffset().Int32Value(), r0,
360 kWord, INVALID_SREG);
buzbeec5ef0462011-08-25 18:44:49 -0700361 break;
362 case 4: // Skip past the object header
363 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
364 break;
365 case 5: // Get the target Method* [uses r0, sets r0]
366 loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
367 kWord, INVALID_SREG);
368 break;
369 case 6: // Get the target compiled code address [uses r0, sets rLR]
370 loadBaseDisp(cUnit, mir, r0, art::Method::GetCodeOffset(), rLR,
371 kWord, INVALID_SREG);
372 break;
373 default:
374 return -1;
375 }
376 return state + 1;
377}
378
buzbee67bf8852011-08-17 17:51:35 -0700379/*
380 * Bit of a hack here - in leiu of a real scheduling pass,
381 * emit the next instruction in a virtual invoke sequence.
382 * We can use rLR as a temp prior to target address loading
383 * Note also that we'll load the first argument ("this") into
384 * r1 here rather than the standard loadArgRegs.
385 */
386static int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
387 DecodedInstruction* dInsn, int state)
388{
buzbeec143c552011-08-20 17:38:58 -0700389 UNIMPLEMENTED(FATAL) << "Update with new cache model";
390#if 0
buzbee67bf8852011-08-17 17:51:35 -0700391 RegLocation rlArg;
392 switch(state) {
393 case 0: // Get the current Method* [set r0]
394 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
395 // Load "this" [set r1]
396 rlArg = oatGetSrc(cUnit, mir, 0);
397 loadValueDirectFixed(cUnit, rlArg, r1);
398 break;
399 case 1: // Get the pResMethods pointer [use r0, set r12]
400 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, pResMethods),
401 r12, kWord, INVALID_SREG);
402 // Is "this" null? [use r1]
403 genNullCheck(cUnit, oatSSASrc(mir,0), r1,
404 mir->offset, NULL);
405 break;
406 case 2: // Get the base Method* [use r12, set r0]
407 loadBaseDisp(cUnit, mir, r12, dInsn->vB * 4, r0,
408 kWord, INVALID_SREG);
409 // get this->clazz [use r1, set rLR]
410 loadBaseDisp(cUnit, mir, r1, OFFSETOF_MEMBER(Object, clazz), rLR,
411 kWord, INVALID_SREG);
412 break;
413 case 3: // Get the method index [use r0, set r12]
414 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, methodIndex),
415 r12, kUnsignedHalf, INVALID_SREG);
416 // get this->clazz->vtable [use rLR, set rLR]
417 loadBaseDisp(cUnit, mir, rLR,
buzbeec143c552011-08-20 17:38:58 -0700418 OFFSETOF_MEMBER(Class, vtable), rLR, kWord,
buzbee67bf8852011-08-17 17:51:35 -0700419 INVALID_SREG);
420 break;
421 case 4: // get target Method* [use rLR, use r12, set r0]
422 loadBaseIndexed(cUnit, rLR, r12, r0, 2, kWord);
423 break;
424 case 5: // Get the target compiled code address [use r0, set rLR]
buzbeec143c552011-08-20 17:38:58 -0700425 UNIMPLEMENTED(FATAL) << "Update with new cache";
buzbee67bf8852011-08-17 17:51:35 -0700426 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
427 rLR, kWord, INVALID_SREG);
428 break;
429 default:
430 return -1;
431 }
buzbeec143c552011-08-20 17:38:58 -0700432#endif
buzbee67bf8852011-08-17 17:51:35 -0700433 return state + 1;
434}
435
buzbee7b1b86d2011-08-26 18:59:10 -0700436// Slow path sequence for virtual calls
437static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
438 DecodedInstruction* dInsn, int state)
439{
440 RegLocation rlArg;
441 switch(state) {
442 case 0: // Get the current Method* [sets r0]
443 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
444 break;
445 case 1: // Get the current Method->DeclaringClass() [uses/sets r0]
446 loadBaseDisp(cUnit, mir, r0,
447 OFFSETOF_MEMBER(art::Method, declaring_class_),
448 r0, kWord, INVALID_SREG);
449 break;
450 case 2: // Method->DeclaringClass()->GetDexCache() [uses/sets r0]
451 loadBaseDisp(cUnit, mir, r0,
452 OFFSETOF_MEMBER(art::Class, dex_cache_), r0, kWord,
453 INVALID_SREG);
454 break;
455 case 3: // ...()->GetDexCache()->methodsObjectArr [uses/sets r0]
456 loadBaseDisp(cUnit, mir, r0,
457 art::DexCache::MethodsOffset().Int32Value(), r0,
458 kWord, INVALID_SREG);
459 // Load "this" [set r1]
460 rlArg = oatGetSrc(cUnit, mir, 0);
461 loadValueDirectFixed(cUnit, rlArg, r1);
462 // Skip past the object header
463 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
464 break;
465 case 4:
466 // Is "this" null? [use r1]
467 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
468 // get this->clazz [use r1, set rLR]
469 loadBaseDisp(cUnit, mir, r1, OFFSETOF_MEMBER(Object, klass_), rLR,
470 kWord, INVALID_SREG);
471 // Get the base Method* [uses r0, sets r0]
472 loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
473 kWord, INVALID_SREG);
474 // get this->clazz->vtable [use rLR, set rLR]
475 loadBaseDisp(cUnit, mir, rLR,
476 OFFSETOF_MEMBER(Class, vtable_), rLR, kWord,
477 INVALID_SREG);
478 // Get the method index [use r0, set r12]
479 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, method_index_),
480 r12, kUnsignedHalf, INVALID_SREG);
481 // Skip past the object header
482 opRegImm(cUnit, kOpAdd, rLR, art::Array::DataOffset().Int32Value());
483 // Get target Method*
484 loadBaseIndexed(cUnit, rLR, r12, r0, 2, kWord);
485 break;
486 case 5: // Get the target compiled code address [uses r0, sets rLR]
487 loadBaseDisp(cUnit, mir, r0, art::Method::GetCodeOffset(), rLR,
488 kWord, INVALID_SREG);
489 break;
490 default:
491 return -1;
492 }
493 return state + 1;
494}
495
buzbee67bf8852011-08-17 17:51:35 -0700496/* Load up to 3 arguments in r1..r3 */
497static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
498 DecodedInstruction* dInsn, int callState,
499 int *args, NextCallInsn nextCallInsn)
500{
501 for (int i = 0; i < 3; i++) {
502 if (args[i] != INVALID_REG) {
503 RegLocation rlArg = oatGetSrc(cUnit, mir, i);
504 loadValueDirectFixed(cUnit, rlArg, r1 + i);
505 callState = nextCallInsn(cUnit, mir, dInsn, callState);
506 }
507 }
508 return callState;
509}
510
511/*
512 * Interleave launch code for INVOKE_INTERFACE. The target is
513 * identified using artFindInterfaceMethodInCache(class, ref, method, dex)
514 * Note that we'll have to reload "this" following the helper call.
515 *
516 * FIXME: do we need to have artFindInterfaceMethodInCache return
517 * a NULL if not found so we can throw exception here? Otherwise,
518 * may need to pass some additional info to allow the helper function
519 * to throw on its own.
520 */
521static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
522 DecodedInstruction* dInsn, int state)
523{
buzbeec143c552011-08-20 17:38:58 -0700524 UNIMPLEMENTED(FATAL) << "Update with new cache model";
525#if 0
buzbee67bf8852011-08-17 17:51:35 -0700526 RegLocation rlArg;
527 switch(state) {
528 case 0:
529 // Load "this" [set r12]
530 rlArg = oatGetSrc(cUnit, mir, 0);
531 loadValueDirectFixed(cUnit, rlArg, r12);
532 // Get the current Method* [set arg2]
533 loadBaseDisp(cUnit, mir, rSP, 0, r2, kWord, INVALID_SREG);
534 // Is "this" null? [use r12]
535 genNullCheck(cUnit, oatSSASrc(mir,0), r12,
536 mir->offset, NULL);
537 // Get curMethod->clazz [set arg3]
538 loadBaseDisp(cUnit, mir, r2, OFFSETOF_MEMBER(Method, clazz),
539 r3, kWord, INVALID_SREG);
540 // Load this->class [usr r12, set arg0]
buzbeec143c552011-08-20 17:38:58 -0700541 loadBaseDisp(cUnit, mir, r12, OFFSETOF_MEMBER(Class, clazz),
buzbee67bf8852011-08-17 17:51:35 -0700542 r3, kWord, INVALID_SREG);
543 // Load address of helper function
544 loadBaseDisp(cUnit, mir, rSELF,
545 OFFSETOF_MEMBER(Thread, pArtFindInterfaceMethodInCache),
546 rLR, kWord, INVALID_SREG);
547 // Get dvmDex
buzbeec143c552011-08-20 17:38:58 -0700548 loadBaseDisp(cUnit, mir, r3, OFFSETOF_MEMBER(Class, pDvmDex),
buzbee67bf8852011-08-17 17:51:35 -0700549 r3, kWord, INVALID_SREG);
550 // Load ref [set arg1]
551 loadConstant(cUnit, r1, dInsn->vB);
552 // Call out to helper, target Method returned in ret0
553 newLIR1(cUnit, kThumbBlxR, rLR);
554 break;
555 case 1: // Get the target compiled code address [use r0, set rLR]
556 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
557 rLR, kWord, INVALID_SREG);
558 default:
559 return -1;
560 }
buzbeec143c552011-08-20 17:38:58 -0700561#endif
buzbee67bf8852011-08-17 17:51:35 -0700562 return state + 1;
563}
564
565
566/*
567 * Interleave launch code for INVOKE_SUPER. See comments
568 * for nextVCallIns.
569 */
570static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
571 DecodedInstruction* dInsn, int state)
572{
buzbeec143c552011-08-20 17:38:58 -0700573 UNIMPLEMENTED(FATAL) << "Update with new cache model";
574#if 0
buzbee67bf8852011-08-17 17:51:35 -0700575 RegLocation rlArg;
576 switch(state) {
577 case 0:
578 // Get the current Method* [set r0]
579 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
580 // Load "this" [set r1]
581 rlArg = oatGetSrc(cUnit, mir, 0);
582 loadValueDirectFixed(cUnit, rlArg, r1);
583 // Get method->clazz [use r0, set r12]
584 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, clazz),
585 r12, kWord, INVALID_SREG);
586 // Get pResmethods [use r0, set rLR]
587 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, pResMethods),
588 rLR, kWord, INVALID_SREG);
589 // Get clazz->super [use r12, set r12]
buzbeec143c552011-08-20 17:38:58 -0700590 loadBaseDisp(cUnit, mir, r12, OFFSETOF_MEMBER(Class, super),
buzbee67bf8852011-08-17 17:51:35 -0700591 r12, kWord, INVALID_SREG);
592 // Get base method [use rLR, set r0]
593 loadBaseDisp(cUnit, mir, rLR, dInsn->vB * 4, r0,
594 kWord, INVALID_SREG);
595 // Is "this" null? [use r1]
596 genNullCheck(cUnit, oatSSASrc(mir,0), r1,
597 mir->offset, NULL);
598 // Get methodIndex [use r0, set rLR]
599 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, methodIndex),
600 rLR, kUnsignedHalf, INVALID_SREG);
601 // Get vtableCount [use r12, set r0]
602 loadBaseDisp(cUnit, mir, r12,
buzbeec143c552011-08-20 17:38:58 -0700603 OFFSETOF_MEMBER(Class, vtableCount),
buzbee67bf8852011-08-17 17:51:35 -0700604 r0, kWord, INVALID_SREG);
605 // Compare method index w/ vtable count [use r12, use rLR]
606 genRegRegCheck(cUnit, kArmCondGe, rLR, r0, mir->offset, NULL);
607 // get target Method* [use rLR, use r12, set r0]
608 loadBaseIndexed(cUnit, r0, r12, rLR, 2, kWord);
609 case 1: // Get the target compiled code address [use r0, set rLR]
610 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
611 rLR, kWord, INVALID_SREG);
612 default:
613 return -1;
614 }
buzbeec143c552011-08-20 17:38:58 -0700615#endif
buzbee67bf8852011-08-17 17:51:35 -0700616 return state + 1;
617}
618
619/*
620 * Load up to 5 arguments, the first three of which will be in
621 * r1 .. r3. On entry r0 contains the current method pointer,
622 * and as part of the load sequence, it must be replaced with
623 * the target method pointer. Note, this may also be called
624 * for "range" variants if the number of arguments is 5 or fewer.
625 */
626static int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
627 DecodedInstruction* dInsn, int callState,
628 ArmLIR** pcrLabel, bool isRange,
629 NextCallInsn nextCallInsn)
630{
631 RegLocation rlArg;
632 int registerArgs[3];
633
634 /* If no arguments, just return */
635 if (dInsn->vA == 0)
636 return callState;
637
638 oatLockAllTemps(cUnit);
639 callState = nextCallInsn(cUnit, mir, dInsn, callState);
640
641 /*
642 * Load frame arguments arg4 & arg5 first. Coded a little odd to
643 * pre-schedule the method pointer target.
644 */
645 for (unsigned int i=3; i < dInsn->vA; i++) {
646 int reg;
647 int arg = (isRange) ? dInsn->vC + i : i;
648 rlArg = oatUpdateLoc(cUnit, oatGetSrc(cUnit, mir, arg));
649 if (rlArg.location == kLocPhysReg) {
650 reg = rlArg.lowReg;
651 } else {
652 reg = r1;
653 loadValueDirectFixed(cUnit, rlArg, r1);
654 callState = nextCallInsn(cUnit, mir, dInsn, callState);
655 }
656 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
657 callState = nextCallInsn(cUnit, mir, dInsn, callState);
658 }
659
660 /* Load register arguments r1..r3 */
661 for (unsigned int i = 0; i < 3; i++) {
662 if (i < dInsn->vA)
663 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
664 else
665 registerArgs[i] = INVALID_REG;
666 }
667 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
668 nextCallInsn);
669
670 // Load direct & need a "this" null check?
671 if (pcrLabel) {
672 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1,
673 mir->offset, NULL);
674 }
675 return callState;
676}
677
678/*
679 * May have 0+ arguments (also used for jumbo). Note that
680 * source virtual registers may be in physical registers, so may
681 * need to be flushed to home location before copying. This
682 * applies to arg3 and above (see below).
683 *
684 * Two general strategies:
685 * If < 20 arguments
686 * Pass args 3-18 using vldm/vstm block copy
687 * Pass arg0, arg1 & arg2 in r1-r3
688 * If 20+ arguments
689 * Pass args arg19+ using memcpy block copy
690 * Pass arg0, arg1 & arg2 in r1-r3
691 *
692 */
693static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
694 DecodedInstruction* dInsn, int callState,
695 ArmLIR** pcrLabel, NextCallInsn nextCallInsn)
696{
697 int firstArg = dInsn->vC;
698 int numArgs = dInsn->vA;
699
700 // If we can treat it as non-range (Jumbo ops will use range form)
701 if (numArgs <= 5)
702 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
703 true, nextCallInsn);
704 /*
705 * Make sure range list doesn't span the break between in normal
706 * Dalvik vRegs and the ins.
707 */
708 int highestVreg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
buzbeec143c552011-08-20 17:38:58 -0700709 if (highestVreg >= cUnit->method->num_registers_ -
710 cUnit->method->num_ins_) {
buzbee67bf8852011-08-17 17:51:35 -0700711 LOG(FATAL) << "Wide argument spanned locals & args";
712 }
713
714 /*
715 * First load the non-register arguments. Both forms expect all
716 * of the source arguments to be in their home frame location, so
717 * scan the sReg names and flush any that have been promoted to
718 * frame backing storage.
719 */
720 // Scan the rest of the args - if in physReg flush to memory
721 for (int i = 4; i < numArgs; i++) {
722 RegLocation loc = oatUpdateLoc(cUnit,
723 oatGetSrc(cUnit, mir, i));
724 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
725 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
726 callState = nextCallInsn(cUnit, mir, dInsn, callState);
727 }
728 }
729
730 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
731 int outsOffset = 4 /* Method* */ + (3 * 4);
732 if (numArgs >= 20) {
733 // Generate memcpy, but first make sure all of
734 opRegRegImm(cUnit, kOpAdd, r0, rSP, startOffset);
735 opRegRegImm(cUnit, kOpAdd, r1, rSP, outsOffset);
736 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
737 loadConstant(cUnit, r2, (numArgs - 3) * 4);
738 newLIR1(cUnit, kThumbBlxR, rLR);
739 } else {
740 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700741 int regsLeft = std::min(numArgs - 3, 16);
buzbee67bf8852011-08-17 17:51:35 -0700742 callState = nextCallInsn(cUnit, mir, dInsn, callState);
743 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
744 newLIR3(cUnit, kThumb2Vldms, r3, fr0 & FP_REG_MASK, regsLeft);
745 callState = nextCallInsn(cUnit, mir, dInsn, callState);
746 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
747 callState = nextCallInsn(cUnit, mir, dInsn, callState);
748 newLIR3(cUnit, kThumb2Vstms, r3, fr0 & FP_REG_MASK, regsLeft);
749 callState = nextCallInsn(cUnit, mir, dInsn, callState);
750 }
751
752 // Handle the 1st 3 in r1, r2 & r3
753 for (unsigned int i = 0; i < dInsn->vA && i < 3; i++) {
754 RegLocation loc = oatGetSrc(cUnit, mir, firstArg + i);
755 loadValueDirectFixed(cUnit, loc, r1 + i);
756 callState = nextCallInsn(cUnit, mir, dInsn, callState);
757 }
758
759 // Finally, deal with the register arguments
760 // We'll be using fixed registers here
761 oatLockAllTemps(cUnit);
762 callState = nextCallInsn(cUnit, mir, dInsn, callState);
763 return callState;
764}
765
766static void genInvokeStatic(CompilationUnit* cUnit, MIR* mir)
767{
768 DecodedInstruction* dInsn = &mir->dalvikInsn;
769 int callState = 0;
buzbeec5ef0462011-08-25 18:44:49 -0700770 int fastPath = false; // TODO: set based on resolution results
771
772 NextCallInsn nextCallInsn = fastPath ? nextSDCallInsn : nextSDCallInsnSP;
773
buzbee67bf8852011-08-17 17:51:35 -0700774 if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC) {
775 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbeec5ef0462011-08-25 18:44:49 -0700776 false, nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700777 } else {
778 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbeec5ef0462011-08-25 18:44:49 -0700779 nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700780 }
781 // Finish up any of the call sequence not interleaved in arg loading
782 while (callState >= 0) {
buzbeec5ef0462011-08-25 18:44:49 -0700783 callState = nextCallInsn(cUnit, mir, dInsn, callState);
buzbee67bf8852011-08-17 17:51:35 -0700784 }
785 newLIR1(cUnit, kThumbBlxR, rLR);
786}
787
788static void genInvokeDirect(CompilationUnit* cUnit, MIR* mir)
789{
790 DecodedInstruction* dInsn = &mir->dalvikInsn;
791 int callState = 0;
792 ArmLIR* nullCk;
buzbee7b1b86d2011-08-26 18:59:10 -0700793 int fastPath = false; // TODO: set based on resolution results
794
795 NextCallInsn nextCallInsn = fastPath ? nextSDCallInsn : nextSDCallInsnSP;
buzbee67bf8852011-08-17 17:51:35 -0700796 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
797 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee7b1b86d2011-08-26 18:59:10 -0700798 false, nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700799 else
800 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee7b1b86d2011-08-26 18:59:10 -0700801 nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700802 // Finish up any of the call sequence not interleaved in arg loading
803 while (callState >= 0) {
buzbee7b1b86d2011-08-26 18:59:10 -0700804 callState = nextCallInsn(cUnit, mir, dInsn, callState);
buzbee67bf8852011-08-17 17:51:35 -0700805 }
806 newLIR1(cUnit, kThumbBlxR, rLR);
807}
808
809static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
810{
811 DecodedInstruction* dInsn = &mir->dalvikInsn;
812 int callState = 0;
813 ArmLIR* nullCk;
814 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
815 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState);
816 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
817 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
818 false, nextInterfaceCallInsn);
819 else
820 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
821 nextInterfaceCallInsn);
822 // Finish up any of the call sequence not interleaved in arg loading
823 while (callState >= 0) {
824 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState);
825 }
826 newLIR1(cUnit, kThumbBlxR, rLR);
827}
828
829static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
830{
831 DecodedInstruction* dInsn = &mir->dalvikInsn;
832 int callState = 0;
833 ArmLIR* nullCk;
834// FIXME - redundantly loading arg0/r1 ("this")
835 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
836 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
837 false, nextSuperCallInsn);
838 else
839 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
840 nextSuperCallInsn);
841 // Finish up any of the call sequence not interleaved in arg loading
842 while (callState >= 0) {
843 callState = nextSuperCallInsn(cUnit, mir, dInsn, callState);
844 }
845 newLIR1(cUnit, kThumbBlxR, rLR);
846}
847
848static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
849{
850 DecodedInstruction* dInsn = &mir->dalvikInsn;
851 int callState = 0;
852 ArmLIR* nullCk;
buzbee7b1b86d2011-08-26 18:59:10 -0700853 int fastPath = false; // TODO: set based on resolution results
854
855 NextCallInsn nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
856 // TODO - redundantly loading arg0/r1 ("this")
buzbee67bf8852011-08-17 17:51:35 -0700857 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
858 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee7b1b86d2011-08-26 18:59:10 -0700859 false, nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700860 else
861 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee7b1b86d2011-08-26 18:59:10 -0700862 nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700863 // Finish up any of the call sequence not interleaved in arg loading
864 while (callState >= 0) {
buzbee7b1b86d2011-08-26 18:59:10 -0700865 callState = nextCallInsn(cUnit, mir, dInsn, callState);
buzbee67bf8852011-08-17 17:51:35 -0700866 }
867 newLIR1(cUnit, kThumbBlxR, rLR);
868}
869
870// TODO: break out the case handlers. Might make it easier to support x86
871static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
872 BasicBlock* bb, ArmLIR* labelList)
873{
874 bool res = false; // Assume success
875 RegLocation rlSrc[3];
876 RegLocation rlDest = badLoc;
877 RegLocation rlResult = badLoc;
878 Opcode opcode = mir->dalvikInsn.opcode;
879
880 /* Prep Src and Dest locations */
881 int nextSreg = 0;
882 int nextLoc = 0;
883 int attrs = oatDataFlowAttributes[opcode];
884 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
885 if (attrs & DF_UA) {
886 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
887 nextSreg++;
888 } else if (attrs & DF_UA_WIDE) {
889 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
890 nextSreg + 1);
891 nextSreg+= 2;
892 }
893 if (attrs & DF_UB) {
894 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
895 nextSreg++;
896 } else if (attrs & DF_UB_WIDE) {
897 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
898 nextSreg + 1);
899 nextSreg+= 2;
900 }
901 if (attrs & DF_UC) {
902 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
903 } else if (attrs & DF_UC_WIDE) {
904 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
905 nextSreg + 1);
906 }
907 if (attrs & DF_DA) {
908 rlDest = oatGetDest(cUnit, mir, 0);
909 } else if (attrs & DF_DA_WIDE) {
910 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
911 }
912
913 switch(opcode) {
914 case OP_NOP:
915 break;
916
917 case OP_MOVE_EXCEPTION:
918 int exOffset;
919 int resetReg;
buzbeec143c552011-08-20 17:38:58 -0700920 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700921 resetReg = oatAllocTemp(cUnit);
922 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
923 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
924 loadConstant(cUnit, resetReg, 0);
925 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
926 storeValue(cUnit, rlDest, rlResult);
927 break;
928
929 case OP_RETURN_VOID:
930 break;
931
932 case OP_RETURN:
933 case OP_RETURN_OBJECT:
934 storeValue(cUnit, retLoc, rlSrc[0]);
935 break;
936
937 case OP_RETURN_WIDE:
938 rlDest = retLocWide;
939 rlDest.fp = rlSrc[0].fp;
940 storeValueWide(cUnit, rlDest, rlSrc[0]);
941 break;
942
943 case OP_MOVE_RESULT_WIDE:
944 if (mir->OptimizationFlags & MIR_INLINED)
945 break; // Nop - combined w/ previous invoke
946 /*
947 * Somewhat hacky here. Because we're now passing
948 * return values in registers, we have to let the
949 * register allocation utilities know that the return
950 * registers are live and may not be used for address
951 * formation in storeValueWide.
952 */
953 assert(retLocWide.lowReg == r0);
954 assert(retLocWide.lowReg == r1);
955 oatLockTemp(cUnit, retLocWide.lowReg);
956 oatLockTemp(cUnit, retLocWide.highReg);
957 storeValueWide(cUnit, rlDest, retLocWide);
958 oatFreeTemp(cUnit, retLocWide.lowReg);
959 oatFreeTemp(cUnit, retLocWide.highReg);
960 break;
961
962 case OP_MOVE_RESULT:
963 case OP_MOVE_RESULT_OBJECT:
964 if (mir->OptimizationFlags & MIR_INLINED)
965 break; // Nop - combined w/ previous invoke
966 /* See comment for OP_MOVE_RESULT_WIDE */
967 assert(retLoc.lowReg == r0);
968 oatLockTemp(cUnit, retLoc.lowReg);
969 storeValue(cUnit, rlDest, retLoc);
970 oatFreeTemp(cUnit, retLoc.lowReg);
971 break;
972
973 case OP_MOVE:
974 case OP_MOVE_OBJECT:
975 case OP_MOVE_16:
976 case OP_MOVE_OBJECT_16:
977 case OP_MOVE_FROM16:
978 case OP_MOVE_OBJECT_FROM16:
979 storeValue(cUnit, rlDest, rlSrc[0]);
980 break;
981
982 case OP_MOVE_WIDE:
983 case OP_MOVE_WIDE_16:
984 case OP_MOVE_WIDE_FROM16:
985 storeValueWide(cUnit, rlDest, rlSrc[0]);
986 break;
987
988 case OP_CONST:
989 case OP_CONST_4:
990 case OP_CONST_16:
991 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
992 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
993 storeValue(cUnit, rlDest, rlResult);
994 break;
995
996 case OP_CONST_HIGH16:
997 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
998 loadConstantNoClobber(cUnit, rlResult.lowReg,
999 mir->dalvikInsn.vB << 16);
1000 storeValue(cUnit, rlDest, rlResult);
1001 break;
1002
1003 case OP_CONST_WIDE_16:
1004 case OP_CONST_WIDE_32:
1005 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1006 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1007 //TUNING: do high separately to avoid load dependency
1008 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1009 storeValueWide(cUnit, rlDest, rlResult);
1010 break;
1011
1012 case OP_CONST_WIDE:
1013 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1014 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001015 mir->dalvikInsn.vB_wide & 0xffffffff,
1016 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001017 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001018 break;
1019
1020 case OP_CONST_WIDE_HIGH16:
1021 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1022 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1023 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001024 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001025 break;
1026
1027 case OP_MONITOR_ENTER:
1028 genMonitorEnter(cUnit, mir, rlSrc[0]);
1029 break;
1030
1031 case OP_MONITOR_EXIT:
1032 genMonitorExit(cUnit, mir, rlSrc[0]);
1033 break;
1034
1035 case OP_CHECK_CAST:
1036 genCheckCast(cUnit, mir, rlSrc[0]);
1037 break;
1038
1039 case OP_INSTANCE_OF:
1040 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1041 break;
1042
1043 case OP_NEW_INSTANCE:
1044 genNewInstance(cUnit, mir, rlDest);
1045 break;
1046
1047 case OP_THROW:
1048 genThrow(cUnit, mir, rlSrc[0]);
1049 break;
1050
1051 case OP_ARRAY_LENGTH:
1052 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001053 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001054 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee67bf8852011-08-17 17:51:35 -07001055 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
1056 mir->offset, NULL);
1057 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1058 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1059 rlResult.lowReg);
1060 storeValue(cUnit, rlDest, rlResult);
1061 break;
1062
1063 case OP_CONST_STRING:
1064 case OP_CONST_STRING_JUMBO:
1065 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1066 break;
1067
1068 case OP_CONST_CLASS:
1069 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1070 break;
1071
1072 case OP_FILL_ARRAY_DATA:
1073 genFillArrayData(cUnit, mir, rlSrc[0]);
1074 break;
1075
1076 case OP_FILLED_NEW_ARRAY:
1077 genFilledNewArray(cUnit, mir, false /* not range */);
1078 break;
1079
1080 case OP_FILLED_NEW_ARRAY_RANGE:
1081 genFilledNewArray(cUnit, mir, true /* range */);
1082 break;
1083
1084 case OP_NEW_ARRAY:
1085 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1086 break;
1087
1088 case OP_GOTO:
1089 case OP_GOTO_16:
1090 case OP_GOTO_32:
1091 // TUNING: add MIR flag to disable when unnecessary
1092 bool backwardBranch;
1093 backwardBranch = (bb->taken->startOffset <= mir->offset);
1094 if (backwardBranch) {
1095 genSuspendPoll(cUnit, mir);
1096 }
1097 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1098 break;
1099
1100 case OP_PACKED_SWITCH:
1101 genPackedSwitch(cUnit, mir, rlSrc[0]);
1102 break;
1103
1104 case OP_SPARSE_SWITCH:
1105 genSparseSwitch(cUnit, mir, rlSrc[0]);
1106 break;
1107
1108 case OP_CMPL_FLOAT:
1109 case OP_CMPG_FLOAT:
1110 case OP_CMPL_DOUBLE:
1111 case OP_CMPG_DOUBLE:
1112 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1113 break;
1114
1115 case OP_CMP_LONG:
1116 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1117 break;
1118
1119 case OP_IF_EQ:
1120 case OP_IF_NE:
1121 case OP_IF_LT:
1122 case OP_IF_GE:
1123 case OP_IF_GT:
1124 case OP_IF_LE: {
1125 bool backwardBranch;
1126 ArmConditionCode cond;
1127 backwardBranch = (bb->taken->startOffset <= mir->offset);
1128 if (backwardBranch) {
1129 genSuspendPoll(cUnit, mir);
1130 }
1131 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1132 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1133 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1134 switch(opcode) {
1135 case OP_IF_EQ:
1136 cond = kArmCondEq;
1137 break;
1138 case OP_IF_NE:
1139 cond = kArmCondNe;
1140 break;
1141 case OP_IF_LT:
1142 cond = kArmCondLt;
1143 break;
1144 case OP_IF_GE:
1145 cond = kArmCondGe;
1146 break;
1147 case OP_IF_GT:
1148 cond = kArmCondGt;
1149 break;
1150 case OP_IF_LE:
1151 cond = kArmCondLe;
1152 break;
1153 default:
1154 cond = (ArmConditionCode)0;
1155 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1156 }
1157 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1158 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1159 break;
1160 }
1161
1162 case OP_IF_EQZ:
1163 case OP_IF_NEZ:
1164 case OP_IF_LTZ:
1165 case OP_IF_GEZ:
1166 case OP_IF_GTZ:
1167 case OP_IF_LEZ: {
1168 bool backwardBranch;
1169 ArmConditionCode cond;
1170 backwardBranch = (bb->taken->startOffset <= mir->offset);
1171 if (backwardBranch) {
1172 genSuspendPoll(cUnit, mir);
1173 }
1174 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1175 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1176 switch(opcode) {
1177 case OP_IF_EQZ:
1178 cond = kArmCondEq;
1179 break;
1180 case OP_IF_NEZ:
1181 cond = kArmCondNe;
1182 break;
1183 case OP_IF_LTZ:
1184 cond = kArmCondLt;
1185 break;
1186 case OP_IF_GEZ:
1187 cond = kArmCondGe;
1188 break;
1189 case OP_IF_GTZ:
1190 cond = kArmCondGt;
1191 break;
1192 case OP_IF_LEZ:
1193 cond = kArmCondLe;
1194 break;
1195 default:
1196 cond = (ArmConditionCode)0;
1197 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1198 }
1199 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1200 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1201 break;
1202 }
1203
1204 case OP_AGET_WIDE:
1205 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1206 break;
1207 case OP_AGET:
1208 case OP_AGET_OBJECT:
1209 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1210 break;
1211 case OP_AGET_BOOLEAN:
1212 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1213 rlDest, 0);
1214 break;
1215 case OP_AGET_BYTE:
1216 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1217 break;
1218 case OP_AGET_CHAR:
1219 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1220 rlDest, 1);
1221 break;
1222 case OP_AGET_SHORT:
1223 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1224 break;
1225 case OP_APUT_WIDE:
1226 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1227 break;
1228 case OP_APUT:
1229 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1230 break;
1231 case OP_APUT_OBJECT:
buzbeec143c552011-08-20 17:38:58 -07001232 genArrayPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001233 break;
1234 case OP_APUT_SHORT:
1235 case OP_APUT_CHAR:
1236 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1237 rlSrc[0], 1);
1238 break;
1239 case OP_APUT_BYTE:
1240 case OP_APUT_BOOLEAN:
1241 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1242 rlSrc[0], 0);
1243 break;
1244
1245 case OP_IGET_WIDE:
1246 case OP_IGET_WIDE_VOLATILE:
1247 genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
1248 break;
1249
1250 case OP_IGET:
1251 case OP_IGET_VOLATILE:
1252 case OP_IGET_OBJECT:
1253 case OP_IGET_OBJECT_VOLATILE:
1254 genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
1255 break;
1256
1257 case OP_IGET_BOOLEAN:
1258 case OP_IGET_BYTE:
1259 genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
1260 break;
1261
1262 case OP_IGET_CHAR:
1263 genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
1264 break;
1265
1266 case OP_IGET_SHORT:
1267 genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
1268 break;
1269
1270 case OP_IPUT_WIDE:
1271 case OP_IPUT_WIDE_VOLATILE:
1272 genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
1273 break;
1274
1275 case OP_IPUT_OBJECT:
1276 case OP_IPUT_OBJECT_VOLATILE:
1277 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
1278 break;
1279
1280 case OP_IPUT:
1281 case OP_IPUT_VOLATILE:
1282 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
1283 break;
1284
1285 case OP_IPUT_BOOLEAN:
1286 case OP_IPUT_BYTE:
1287 genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
1288 break;
1289
1290 case OP_IPUT_CHAR:
1291 genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
1292 break;
1293
1294 case OP_IPUT_SHORT:
1295 genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
1296 break;
1297
1298 case OP_SGET:
1299 case OP_SGET_OBJECT:
1300 case OP_SGET_BOOLEAN:
1301 case OP_SGET_BYTE:
1302 case OP_SGET_CHAR:
1303 case OP_SGET_SHORT:
1304 genSget(cUnit, mir, rlResult, rlDest);
1305 break;
1306
1307 case OP_SGET_WIDE:
1308 genSgetWide(cUnit, mir, rlResult, rlDest);
1309 break;
1310
1311 case OP_SPUT:
1312 case OP_SPUT_OBJECT:
1313 case OP_SPUT_BOOLEAN:
1314 case OP_SPUT_BYTE:
1315 case OP_SPUT_CHAR:
1316 case OP_SPUT_SHORT:
1317 genSput(cUnit, mir, rlSrc[0]);
1318 break;
1319
1320 case OP_SPUT_WIDE:
1321 genSputWide(cUnit, mir, rlSrc[0]);
1322 break;
1323
1324 case OP_INVOKE_STATIC_RANGE:
1325 case OP_INVOKE_STATIC:
1326 genInvokeStatic(cUnit, mir);
1327 break;
1328
1329 case OP_INVOKE_DIRECT:
1330 case OP_INVOKE_DIRECT_RANGE:
1331 genInvokeDirect(cUnit, mir);
1332 break;
1333
1334 case OP_INVOKE_VIRTUAL:
1335 case OP_INVOKE_VIRTUAL_RANGE:
1336 genInvokeVirtual(cUnit, mir);
1337 break;
1338
1339 case OP_INVOKE_SUPER:
1340 case OP_INVOKE_SUPER_RANGE:
1341 genInvokeSuper(cUnit, mir);
1342 break;
1343
1344 case OP_INVOKE_INTERFACE:
1345 case OP_INVOKE_INTERFACE_RANGE:
1346 genInvokeInterface(cUnit, mir);
1347 break;
1348
1349 case OP_NEG_INT:
1350 case OP_NOT_INT:
1351 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1352 break;
1353
1354 case OP_NEG_LONG:
1355 case OP_NOT_LONG:
1356 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1357 break;
1358
1359 case OP_NEG_FLOAT:
1360 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1361 break;
1362
1363 case OP_NEG_DOUBLE:
1364 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1365 break;
1366
1367 case OP_INT_TO_LONG:
1368 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1369 if (rlSrc[0].location == kLocPhysReg) {
1370 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1371 } else {
1372 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1373 }
1374 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1375 rlResult.lowReg, 31);
1376 storeValueWide(cUnit, rlDest, rlResult);
1377 break;
1378
1379 case OP_LONG_TO_INT:
1380 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1381 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1382 storeValue(cUnit, rlDest, rlSrc[0]);
1383 break;
1384
1385 case OP_INT_TO_BYTE:
1386 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1387 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1388 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1389 storeValue(cUnit, rlDest, rlResult);
1390 break;
1391
1392 case OP_INT_TO_SHORT:
1393 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1394 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1395 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1396 storeValue(cUnit, rlDest, rlResult);
1397 break;
1398
1399 case OP_INT_TO_CHAR:
1400 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1401 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1402 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1403 storeValue(cUnit, rlDest, rlResult);
1404 break;
1405
1406 case OP_INT_TO_FLOAT:
1407 case OP_INT_TO_DOUBLE:
1408 case OP_LONG_TO_FLOAT:
1409 case OP_LONG_TO_DOUBLE:
1410 case OP_FLOAT_TO_INT:
1411 case OP_FLOAT_TO_LONG:
1412 case OP_FLOAT_TO_DOUBLE:
1413 case OP_DOUBLE_TO_INT:
1414 case OP_DOUBLE_TO_LONG:
1415 case OP_DOUBLE_TO_FLOAT:
1416 genConversion(cUnit, mir);
1417 break;
1418
1419 case OP_ADD_INT:
1420 case OP_SUB_INT:
1421 case OP_MUL_INT:
1422 case OP_DIV_INT:
1423 case OP_REM_INT:
1424 case OP_AND_INT:
1425 case OP_OR_INT:
1426 case OP_XOR_INT:
1427 case OP_SHL_INT:
1428 case OP_SHR_INT:
1429 case OP_USHR_INT:
1430 case OP_ADD_INT_2ADDR:
1431 case OP_SUB_INT_2ADDR:
1432 case OP_MUL_INT_2ADDR:
1433 case OP_DIV_INT_2ADDR:
1434 case OP_REM_INT_2ADDR:
1435 case OP_AND_INT_2ADDR:
1436 case OP_OR_INT_2ADDR:
1437 case OP_XOR_INT_2ADDR:
1438 case OP_SHL_INT_2ADDR:
1439 case OP_SHR_INT_2ADDR:
1440 case OP_USHR_INT_2ADDR:
1441 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1442 break;
1443
1444 case OP_ADD_LONG:
1445 case OP_SUB_LONG:
1446 case OP_MUL_LONG:
1447 case OP_DIV_LONG:
1448 case OP_REM_LONG:
1449 case OP_AND_LONG:
1450 case OP_OR_LONG:
1451 case OP_XOR_LONG:
1452 case OP_ADD_LONG_2ADDR:
1453 case OP_SUB_LONG_2ADDR:
1454 case OP_MUL_LONG_2ADDR:
1455 case OP_DIV_LONG_2ADDR:
1456 case OP_REM_LONG_2ADDR:
1457 case OP_AND_LONG_2ADDR:
1458 case OP_OR_LONG_2ADDR:
1459 case OP_XOR_LONG_2ADDR:
1460 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1461 break;
1462
buzbee67bf8852011-08-17 17:51:35 -07001463 case OP_SHL_LONG:
1464 case OP_SHR_LONG:
1465 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001466 case OP_SHL_LONG_2ADDR:
1467 case OP_SHR_LONG_2ADDR:
1468 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001469 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1470 break;
1471
1472 case OP_ADD_FLOAT:
1473 case OP_SUB_FLOAT:
1474 case OP_MUL_FLOAT:
1475 case OP_DIV_FLOAT:
1476 case OP_REM_FLOAT:
1477 case OP_ADD_FLOAT_2ADDR:
1478 case OP_SUB_FLOAT_2ADDR:
1479 case OP_MUL_FLOAT_2ADDR:
1480 case OP_DIV_FLOAT_2ADDR:
1481 case OP_REM_FLOAT_2ADDR:
1482 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1483 break;
1484
1485 case OP_ADD_DOUBLE:
1486 case OP_SUB_DOUBLE:
1487 case OP_MUL_DOUBLE:
1488 case OP_DIV_DOUBLE:
1489 case OP_REM_DOUBLE:
1490 case OP_ADD_DOUBLE_2ADDR:
1491 case OP_SUB_DOUBLE_2ADDR:
1492 case OP_MUL_DOUBLE_2ADDR:
1493 case OP_DIV_DOUBLE_2ADDR:
1494 case OP_REM_DOUBLE_2ADDR:
1495 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1496 break;
1497
1498 case OP_RSUB_INT:
1499 case OP_ADD_INT_LIT16:
1500 case OP_MUL_INT_LIT16:
1501 case OP_DIV_INT_LIT16:
1502 case OP_REM_INT_LIT16:
1503 case OP_AND_INT_LIT16:
1504 case OP_OR_INT_LIT16:
1505 case OP_XOR_INT_LIT16:
1506 case OP_ADD_INT_LIT8:
1507 case OP_RSUB_INT_LIT8:
1508 case OP_MUL_INT_LIT8:
1509 case OP_DIV_INT_LIT8:
1510 case OP_REM_INT_LIT8:
1511 case OP_AND_INT_LIT8:
1512 case OP_OR_INT_LIT8:
1513 case OP_XOR_INT_LIT8:
1514 case OP_SHL_INT_LIT8:
1515 case OP_SHR_INT_LIT8:
1516 case OP_USHR_INT_LIT8:
1517 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1518 break;
1519
1520 default:
1521 res = true;
1522 }
1523 return res;
1524}
1525
1526static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1527 "kMirOpPhi",
1528 "kMirOpNullNRangeUpCheck",
1529 "kMirOpNullNRangeDownCheck",
1530 "kMirOpLowerBound",
1531 "kMirOpPunt",
1532 "kMirOpCheckInlinePrediction",
1533};
1534
1535/* Extended MIR instructions like PHI */
1536static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1537{
1538 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1539 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1540 strcpy(msg, extendedMIROpNames[opOffset]);
1541 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1542
1543 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1544 case kMirOpPhi: {
1545 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1546 op->flags.isNop = true;
1547 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1548 break;
1549 }
1550 default:
1551 break;
1552 }
1553}
1554
1555/* If there are any ins passed in registers that have not been promoted
1556 * to a callee-save register, flush them to the frame.
1557 * Note: at this pointCopy any ins that are passed in register to their home location */
1558static void flushIns(CompilationUnit* cUnit)
1559{
buzbeec143c552011-08-20 17:38:58 -07001560 if (cUnit->method->num_ins_ == 0)
buzbee67bf8852011-08-17 17:51:35 -07001561 return;
buzbeec143c552011-08-20 17:38:58 -07001562 int inRegs = (cUnit->method->num_ins_ > 2) ? 3 : cUnit->method->num_ins_;
buzbee67bf8852011-08-17 17:51:35 -07001563 int startReg = r1;
buzbeec143c552011-08-20 17:38:58 -07001564 int startLoc = cUnit->method->num_registers_ - cUnit->method->num_ins_;
buzbee67bf8852011-08-17 17:51:35 -07001565 for (int i = 0; i < inRegs; i++) {
1566 RegLocation loc = cUnit->regLocation[startLoc + i];
1567 if (loc.location == kLocPhysReg) {
1568 genRegCopy(cUnit, loc.lowReg, startReg + i);
1569 } else {
1570 assert(loc.location == kLocDalvikFrame);
1571 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
1572 }
1573 }
1574
1575 // Handle special case of wide argument half in regs, half in frame
1576 if (inRegs == 3) {
1577 RegLocation loc = cUnit->regLocation[startLoc + 2];
1578 if (loc.wide && loc.location == kLocPhysReg) {
1579 // Load the other half of the arg into the promoted pair
1580 loadBaseDisp(cUnit, NULL, rSP, loc.spOffset+4,
1581 loc.highReg, kWord, INVALID_SREG);
1582 inRegs++;
1583 }
1584 }
1585
1586 // Now, do initial assignment of all promoted arguments passed in frame
buzbeec143c552011-08-20 17:38:58 -07001587 for (int i = inRegs; i < cUnit->method->num_ins_;) {
buzbee67bf8852011-08-17 17:51:35 -07001588 RegLocation loc = cUnit->regLocation[startLoc + i];
1589 if (loc.fpLocation == kLocPhysReg) {
1590 loc.location = kLocPhysReg;
1591 loc.fp = true;
1592 loc.lowReg = loc.fpLowReg;
1593 loc.highReg = loc.fpHighReg;
1594 }
1595 if (loc.location == kLocPhysReg) {
1596 if (loc.wide) {
1597 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1598 loc.lowReg, loc.highReg, INVALID_SREG);
1599 i++;
1600 } else {
1601 loadBaseDisp(cUnit, NULL, rSP, loc.spOffset,
1602 loc.lowReg, kWord, INVALID_SREG);
1603 }
1604 }
1605 i++;
1606 }
1607}
1608
1609/* Handle the content in each basic block */
1610static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1611{
1612 MIR* mir;
1613 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1614 int blockId = bb->id;
1615
1616 cUnit->curBlock = bb;
1617 labelList[blockId].operands[0] = bb->startOffset;
1618
1619 /* Insert the block label */
1620 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1621 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1622
1623 oatClobberAllRegs(cUnit);
1624 oatResetNullCheck(cUnit);
1625
1626 ArmLIR* headLIR = NULL;
1627
1628 if (bb->blockType == kEntryBlock) {
1629 /*
1630 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1631 * mechanism know so it doesn't try to use any of them when
1632 * expanding the frame or flushing. This leaves the utility
1633 * code with a single temp: r12. This should be enough.
1634 */
1635 oatLockTemp(cUnit, r0);
1636 oatLockTemp(cUnit, r1);
1637 oatLockTemp(cUnit, r2);
1638 oatLockTemp(cUnit, r3);
1639 newLIR0(cUnit, kArmPseudoMethodEntry);
1640 /* Spill core callee saves */
1641 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1642 /* Need to spill any FP regs? */
1643 if (cUnit->numFPSpills) {
1644 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1645 }
1646 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1647 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1648 flushIns(cUnit);
1649 oatFreeTemp(cUnit, r0);
1650 oatFreeTemp(cUnit, r1);
1651 oatFreeTemp(cUnit, r2);
1652 oatFreeTemp(cUnit, r3);
1653 } else if (bb->blockType == kExitBlock) {
1654 newLIR0(cUnit, kArmPseudoMethodExit);
1655 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1656 /* Need to restore any FP callee saves? */
1657 if (cUnit->numFPSpills) {
1658 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1659 }
1660 if (cUnit->coreSpillMask & (1 << rLR)) {
1661 /* Unspill rLR to rPC */
1662 cUnit->coreSpillMask &= ~(1 << rLR);
1663 cUnit->coreSpillMask |= (1 << rPC);
1664 }
1665 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1666 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1667 /* We didn't pop to rPC, so must do a bv rLR */
1668 newLIR1(cUnit, kThumbBx, rLR);
1669 }
1670 }
1671
1672 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1673
1674 oatResetRegPool(cUnit);
1675 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1676 oatClobberAllRegs(cUnit);
1677 }
1678
1679 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1680 oatResetDefTracking(cUnit);
1681 }
1682
1683 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1684 handleExtendedMethodMIR(cUnit, mir);
1685 continue;
1686 }
1687
1688 cUnit->currentDalvikOffset = mir->offset;
1689
1690 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1691 InstructionFormat dalvikFormat =
1692 dexGetFormatFromOpcode(dalvikOpcode);
1693
1694 ArmLIR* boundaryLIR;
1695
1696 /* Mark the beginning of a Dalvik instruction for line tracking */
1697 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1698 (int) oatGetDalvikDisassembly(
1699 &mir->dalvikInsn, ""));
1700 /* Remember the first LIR for this block */
1701 if (headLIR == NULL) {
1702 headLIR = boundaryLIR;
1703 /* Set the first boundaryLIR as a scheduling barrier */
1704 headLIR->defMask = ENCODE_ALL;
1705 }
1706
1707 /* Don't generate the SSA annotation unless verbose mode is on */
1708 if (cUnit->printMe && mir->ssaRep) {
1709 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1710 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1711 }
1712
1713 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1714
1715 if (notHandled) {
1716 char buf[100];
1717 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1718 mir->offset,
1719 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1720 dalvikFormat);
1721 LOG(FATAL) << buf;
1722 }
1723 }
1724
1725 if (headLIR) {
1726 /*
1727 * Eliminate redundant loads/stores and delay stores into later
1728 * slots
1729 */
1730 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1731 cUnit->lastLIRInsn);
1732
1733 /*
1734 * Generate an unconditional branch to the fallthrough block.
1735 */
1736 if (bb->fallThrough) {
1737 genUnconditionalBranch(cUnit,
1738 &labelList[bb->fallThrough->id]);
1739 }
1740 }
1741 return false;
1742}
1743
1744/*
1745 * Nop any unconditional branches that go to the next instruction.
1746 * Note: new redundant branches may be inserted later, and we'll
1747 * use a check in final instruction assembly to nop those out.
1748 */
1749void removeRedundantBranches(CompilationUnit* cUnit)
1750{
1751 ArmLIR* thisLIR;
1752
1753 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1754 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1755 thisLIR = NEXT_LIR(thisLIR)) {
1756
1757 /* Branch to the next instruction */
1758 if ((thisLIR->opcode == kThumbBUncond) ||
1759 (thisLIR->opcode == kThumb2BUncond)) {
1760 ArmLIR* nextLIR = thisLIR;
1761
1762 while (true) {
1763 nextLIR = NEXT_LIR(nextLIR);
1764
1765 /*
1766 * Is the branch target the next instruction?
1767 */
1768 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1769 thisLIR->flags.isNop = true;
1770 break;
1771 }
1772
1773 /*
1774 * Found real useful stuff between the branch and the target.
1775 * Need to explicitly check the lastLIRInsn here because it
1776 * might be the last real instruction.
1777 */
1778 if (!isPseudoOpcode(nextLIR->opcode) ||
1779 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1780 break;
1781 }
1782 }
1783 }
1784}
1785
1786void oatMethodMIR2LIR(CompilationUnit* cUnit)
1787{
1788 /* Used to hold the labels of each block */
1789 cUnit->blockLabelList =
1790 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
1791
1792 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
1793 kPreOrderDFSTraversal, false /* Iterative */);
1794 removeRedundantBranches(cUnit);
1795}
1796
1797/* Common initialization routine for an architecture family */
1798bool oatArchInit()
1799{
1800 int i;
1801
1802 for (i = 0; i < kArmLast; i++) {
1803 if (EncodingMap[i].opcode != i) {
1804 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
1805 " is wrong: expecting " << i << ", seeing " <<
1806 (int)EncodingMap[i].opcode;
1807 }
1808 }
1809
1810 return oatArchVariantInit();
1811}
1812
1813/* Needed by the Assembler */
1814void oatSetupResourceMasks(ArmLIR* lir)
1815{
1816 setupResourceMasks(lir);
1817}
1818
1819/* Needed by the ld/st optmizatons */
1820ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
1821{
1822 return genRegCopyNoInsert(cUnit, rDest, rSrc);
1823}
1824
1825/* Needed by the register allocator */
1826ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1827{
1828 return genRegCopy(cUnit, rDest, rSrc);
1829}
1830
1831/* Needed by the register allocator */
1832void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
1833 int srcLo, int srcHi)
1834{
1835 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
1836}
1837
1838void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
1839 int displacement, int rSrc, OpSize size)
1840{
1841 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
1842}
1843
1844void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
1845 int displacement, int rSrcLo, int rSrcHi)
1846{
1847 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
1848}