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