blob: 49529e117409085bc35ebe487ec19f3fe28eeef8 [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
353 loadBaseDisp(cUnit, mir, r0, art::DexCache::MethodsOffset(),
354 r0, kWord, INVALID_SREG);
355 break;
356 case 4: // Skip past the object header
357 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
358 break;
359 case 5: // Get the target Method* [uses r0, sets r0]
360 loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
361 kWord, INVALID_SREG);
362 break;
363 case 6: // Get the target compiled code address [uses r0, sets rLR]
364 loadBaseDisp(cUnit, mir, r0, art::Method::GetCodeOffset(), rLR,
365 kWord, INVALID_SREG);
366 break;
367 default:
368 return -1;
369 }
370 return state + 1;
371}
372
buzbee67bf8852011-08-17 17:51:35 -0700373/*
374 * Bit of a hack here - in leiu of a real scheduling pass,
375 * emit the next instruction in a virtual invoke sequence.
376 * We can use rLR as a temp prior to target address loading
377 * Note also that we'll load the first argument ("this") into
378 * r1 here rather than the standard loadArgRegs.
379 */
380static int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
381 DecodedInstruction* dInsn, int state)
382{
buzbeec143c552011-08-20 17:38:58 -0700383 UNIMPLEMENTED(FATAL) << "Update with new cache model";
384#if 0
buzbee67bf8852011-08-17 17:51:35 -0700385 RegLocation rlArg;
386 switch(state) {
387 case 0: // Get the current Method* [set r0]
388 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
389 // Load "this" [set r1]
390 rlArg = oatGetSrc(cUnit, mir, 0);
391 loadValueDirectFixed(cUnit, rlArg, r1);
392 break;
393 case 1: // Get the pResMethods pointer [use r0, set r12]
394 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, pResMethods),
395 r12, kWord, INVALID_SREG);
396 // Is "this" null? [use r1]
397 genNullCheck(cUnit, oatSSASrc(mir,0), r1,
398 mir->offset, NULL);
399 break;
400 case 2: // Get the base Method* [use r12, set r0]
401 loadBaseDisp(cUnit, mir, r12, dInsn->vB * 4, r0,
402 kWord, INVALID_SREG);
403 // get this->clazz [use r1, set rLR]
404 loadBaseDisp(cUnit, mir, r1, OFFSETOF_MEMBER(Object, clazz), rLR,
405 kWord, INVALID_SREG);
406 break;
407 case 3: // Get the method index [use r0, set r12]
408 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, methodIndex),
409 r12, kUnsignedHalf, INVALID_SREG);
410 // get this->clazz->vtable [use rLR, set rLR]
411 loadBaseDisp(cUnit, mir, rLR,
buzbeec143c552011-08-20 17:38:58 -0700412 OFFSETOF_MEMBER(Class, vtable), rLR, kWord,
buzbee67bf8852011-08-17 17:51:35 -0700413 INVALID_SREG);
414 break;
415 case 4: // get target Method* [use rLR, use r12, set r0]
416 loadBaseIndexed(cUnit, rLR, r12, r0, 2, kWord);
417 break;
418 case 5: // Get the target compiled code address [use r0, set rLR]
buzbeec143c552011-08-20 17:38:58 -0700419 UNIMPLEMENTED(FATAL) << "Update with new cache";
buzbee67bf8852011-08-17 17:51:35 -0700420 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
421 rLR, kWord, INVALID_SREG);
422 break;
423 default:
424 return -1;
425 }
buzbeec143c552011-08-20 17:38:58 -0700426#endif
buzbee67bf8852011-08-17 17:51:35 -0700427 return state + 1;
428}
429
430/* Load up to 3 arguments in r1..r3 */
431static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
432 DecodedInstruction* dInsn, int callState,
433 int *args, NextCallInsn nextCallInsn)
434{
435 for (int i = 0; i < 3; i++) {
436 if (args[i] != INVALID_REG) {
437 RegLocation rlArg = oatGetSrc(cUnit, mir, i);
438 loadValueDirectFixed(cUnit, rlArg, r1 + i);
439 callState = nextCallInsn(cUnit, mir, dInsn, callState);
440 }
441 }
442 return callState;
443}
444
445/*
446 * Interleave launch code for INVOKE_INTERFACE. The target is
447 * identified using artFindInterfaceMethodInCache(class, ref, method, dex)
448 * Note that we'll have to reload "this" following the helper call.
449 *
450 * FIXME: do we need to have artFindInterfaceMethodInCache return
451 * a NULL if not found so we can throw exception here? Otherwise,
452 * may need to pass some additional info to allow the helper function
453 * to throw on its own.
454 */
455static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
456 DecodedInstruction* dInsn, int state)
457{
buzbeec143c552011-08-20 17:38:58 -0700458 UNIMPLEMENTED(FATAL) << "Update with new cache model";
459#if 0
buzbee67bf8852011-08-17 17:51:35 -0700460 RegLocation rlArg;
461 switch(state) {
462 case 0:
463 // Load "this" [set r12]
464 rlArg = oatGetSrc(cUnit, mir, 0);
465 loadValueDirectFixed(cUnit, rlArg, r12);
466 // Get the current Method* [set arg2]
467 loadBaseDisp(cUnit, mir, rSP, 0, r2, kWord, INVALID_SREG);
468 // Is "this" null? [use r12]
469 genNullCheck(cUnit, oatSSASrc(mir,0), r12,
470 mir->offset, NULL);
471 // Get curMethod->clazz [set arg3]
472 loadBaseDisp(cUnit, mir, r2, OFFSETOF_MEMBER(Method, clazz),
473 r3, kWord, INVALID_SREG);
474 // Load this->class [usr r12, set arg0]
buzbeec143c552011-08-20 17:38:58 -0700475 loadBaseDisp(cUnit, mir, r12, OFFSETOF_MEMBER(Class, clazz),
buzbee67bf8852011-08-17 17:51:35 -0700476 r3, kWord, INVALID_SREG);
477 // Load address of helper function
478 loadBaseDisp(cUnit, mir, rSELF,
479 OFFSETOF_MEMBER(Thread, pArtFindInterfaceMethodInCache),
480 rLR, kWord, INVALID_SREG);
481 // Get dvmDex
buzbeec143c552011-08-20 17:38:58 -0700482 loadBaseDisp(cUnit, mir, r3, OFFSETOF_MEMBER(Class, pDvmDex),
buzbee67bf8852011-08-17 17:51:35 -0700483 r3, kWord, INVALID_SREG);
484 // Load ref [set arg1]
485 loadConstant(cUnit, r1, dInsn->vB);
486 // Call out to helper, target Method returned in ret0
487 newLIR1(cUnit, kThumbBlxR, rLR);
488 break;
489 case 1: // Get the target compiled code address [use r0, set rLR]
490 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
491 rLR, kWord, INVALID_SREG);
492 default:
493 return -1;
494 }
buzbeec143c552011-08-20 17:38:58 -0700495#endif
buzbee67bf8852011-08-17 17:51:35 -0700496 return state + 1;
497}
498
499
500/*
501 * Interleave launch code for INVOKE_SUPER. See comments
502 * for nextVCallIns.
503 */
504static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
505 DecodedInstruction* dInsn, int state)
506{
buzbeec143c552011-08-20 17:38:58 -0700507 UNIMPLEMENTED(FATAL) << "Update with new cache model";
508#if 0
buzbee67bf8852011-08-17 17:51:35 -0700509 RegLocation rlArg;
510 switch(state) {
511 case 0:
512 // Get the current Method* [set r0]
513 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
514 // Load "this" [set r1]
515 rlArg = oatGetSrc(cUnit, mir, 0);
516 loadValueDirectFixed(cUnit, rlArg, r1);
517 // Get method->clazz [use r0, set r12]
518 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, clazz),
519 r12, kWord, INVALID_SREG);
520 // Get pResmethods [use r0, set rLR]
521 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, pResMethods),
522 rLR, kWord, INVALID_SREG);
523 // Get clazz->super [use r12, set r12]
buzbeec143c552011-08-20 17:38:58 -0700524 loadBaseDisp(cUnit, mir, r12, OFFSETOF_MEMBER(Class, super),
buzbee67bf8852011-08-17 17:51:35 -0700525 r12, kWord, INVALID_SREG);
526 // Get base method [use rLR, set r0]
527 loadBaseDisp(cUnit, mir, rLR, dInsn->vB * 4, r0,
528 kWord, INVALID_SREG);
529 // Is "this" null? [use r1]
530 genNullCheck(cUnit, oatSSASrc(mir,0), r1,
531 mir->offset, NULL);
532 // Get methodIndex [use r0, set rLR]
533 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, methodIndex),
534 rLR, kUnsignedHalf, INVALID_SREG);
535 // Get vtableCount [use r12, set r0]
536 loadBaseDisp(cUnit, mir, r12,
buzbeec143c552011-08-20 17:38:58 -0700537 OFFSETOF_MEMBER(Class, vtableCount),
buzbee67bf8852011-08-17 17:51:35 -0700538 r0, kWord, INVALID_SREG);
539 // Compare method index w/ vtable count [use r12, use rLR]
540 genRegRegCheck(cUnit, kArmCondGe, rLR, r0, mir->offset, NULL);
541 // get target Method* [use rLR, use r12, set r0]
542 loadBaseIndexed(cUnit, r0, r12, rLR, 2, kWord);
543 case 1: // Get the target compiled code address [use r0, set rLR]
544 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, compiledInsns),
545 rLR, kWord, INVALID_SREG);
546 default:
547 return -1;
548 }
buzbeec143c552011-08-20 17:38:58 -0700549#endif
buzbee67bf8852011-08-17 17:51:35 -0700550 return state + 1;
551}
552
553/*
554 * Load up to 5 arguments, the first three of which will be in
555 * r1 .. r3. On entry r0 contains the current method pointer,
556 * and as part of the load sequence, it must be replaced with
557 * the target method pointer. Note, this may also be called
558 * for "range" variants if the number of arguments is 5 or fewer.
559 */
560static int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
561 DecodedInstruction* dInsn, int callState,
562 ArmLIR** pcrLabel, bool isRange,
563 NextCallInsn nextCallInsn)
564{
565 RegLocation rlArg;
566 int registerArgs[3];
567
568 /* If no arguments, just return */
569 if (dInsn->vA == 0)
570 return callState;
571
572 oatLockAllTemps(cUnit);
573 callState = nextCallInsn(cUnit, mir, dInsn, callState);
574
575 /*
576 * Load frame arguments arg4 & arg5 first. Coded a little odd to
577 * pre-schedule the method pointer target.
578 */
579 for (unsigned int i=3; i < dInsn->vA; i++) {
580 int reg;
581 int arg = (isRange) ? dInsn->vC + i : i;
582 rlArg = oatUpdateLoc(cUnit, oatGetSrc(cUnit, mir, arg));
583 if (rlArg.location == kLocPhysReg) {
584 reg = rlArg.lowReg;
585 } else {
586 reg = r1;
587 loadValueDirectFixed(cUnit, rlArg, r1);
588 callState = nextCallInsn(cUnit, mir, dInsn, callState);
589 }
590 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
591 callState = nextCallInsn(cUnit, mir, dInsn, callState);
592 }
593
594 /* Load register arguments r1..r3 */
595 for (unsigned int i = 0; i < 3; i++) {
596 if (i < dInsn->vA)
597 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
598 else
599 registerArgs[i] = INVALID_REG;
600 }
601 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
602 nextCallInsn);
603
604 // Load direct & need a "this" null check?
605 if (pcrLabel) {
606 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1,
607 mir->offset, NULL);
608 }
609 return callState;
610}
611
612/*
613 * May have 0+ arguments (also used for jumbo). Note that
614 * source virtual registers may be in physical registers, so may
615 * need to be flushed to home location before copying. This
616 * applies to arg3 and above (see below).
617 *
618 * Two general strategies:
619 * If < 20 arguments
620 * Pass args 3-18 using vldm/vstm block copy
621 * Pass arg0, arg1 & arg2 in r1-r3
622 * If 20+ arguments
623 * Pass args arg19+ using memcpy block copy
624 * Pass arg0, arg1 & arg2 in r1-r3
625 *
626 */
627static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
628 DecodedInstruction* dInsn, int callState,
629 ArmLIR** pcrLabel, NextCallInsn nextCallInsn)
630{
631 int firstArg = dInsn->vC;
632 int numArgs = dInsn->vA;
633
634 // If we can treat it as non-range (Jumbo ops will use range form)
635 if (numArgs <= 5)
636 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
637 true, nextCallInsn);
638 /*
639 * Make sure range list doesn't span the break between in normal
640 * Dalvik vRegs and the ins.
641 */
642 int highestVreg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
buzbeec143c552011-08-20 17:38:58 -0700643 if (highestVreg >= cUnit->method->num_registers_ -
644 cUnit->method->num_ins_) {
buzbee67bf8852011-08-17 17:51:35 -0700645 LOG(FATAL) << "Wide argument spanned locals & args";
646 }
647
648 /*
649 * First load the non-register arguments. Both forms expect all
650 * of the source arguments to be in their home frame location, so
651 * scan the sReg names and flush any that have been promoted to
652 * frame backing storage.
653 */
654 // Scan the rest of the args - if in physReg flush to memory
655 for (int i = 4; i < numArgs; i++) {
656 RegLocation loc = oatUpdateLoc(cUnit,
657 oatGetSrc(cUnit, mir, i));
658 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
659 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
660 callState = nextCallInsn(cUnit, mir, dInsn, callState);
661 }
662 }
663
664 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
665 int outsOffset = 4 /* Method* */ + (3 * 4);
666 if (numArgs >= 20) {
667 // Generate memcpy, but first make sure all of
668 opRegRegImm(cUnit, kOpAdd, r0, rSP, startOffset);
669 opRegRegImm(cUnit, kOpAdd, r1, rSP, outsOffset);
670 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
671 loadConstant(cUnit, r2, (numArgs - 3) * 4);
672 newLIR1(cUnit, kThumbBlxR, rLR);
673 } else {
674 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700675 int regsLeft = std::min(numArgs - 3, 16);
buzbee67bf8852011-08-17 17:51:35 -0700676 callState = nextCallInsn(cUnit, mir, dInsn, callState);
677 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
678 newLIR3(cUnit, kThumb2Vldms, r3, fr0 & FP_REG_MASK, regsLeft);
679 callState = nextCallInsn(cUnit, mir, dInsn, callState);
680 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
681 callState = nextCallInsn(cUnit, mir, dInsn, callState);
682 newLIR3(cUnit, kThumb2Vstms, r3, fr0 & FP_REG_MASK, regsLeft);
683 callState = nextCallInsn(cUnit, mir, dInsn, callState);
684 }
685
686 // Handle the 1st 3 in r1, r2 & r3
687 for (unsigned int i = 0; i < dInsn->vA && i < 3; i++) {
688 RegLocation loc = oatGetSrc(cUnit, mir, firstArg + i);
689 loadValueDirectFixed(cUnit, loc, r1 + i);
690 callState = nextCallInsn(cUnit, mir, dInsn, callState);
691 }
692
693 // Finally, deal with the register arguments
694 // We'll be using fixed registers here
695 oatLockAllTemps(cUnit);
696 callState = nextCallInsn(cUnit, mir, dInsn, callState);
697 return callState;
698}
699
700static void genInvokeStatic(CompilationUnit* cUnit, MIR* mir)
701{
702 DecodedInstruction* dInsn = &mir->dalvikInsn;
703 int callState = 0;
buzbeec5ef0462011-08-25 18:44:49 -0700704 /*
705 * TODO: check for/force resolution of target method
706 * note to bdc: you can find the method index in
707 * dInsn->vB. If you need it, the calling method's
708 * Method* is cUnit->method.
709 */
710 int fastPath = false; // TODO: set based on resolution results
711
712 NextCallInsn nextCallInsn = fastPath ? nextSDCallInsn : nextSDCallInsnSP;
713
buzbee67bf8852011-08-17 17:51:35 -0700714 if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC) {
715 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbeec5ef0462011-08-25 18:44:49 -0700716 false, nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700717 } else {
718 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbeec5ef0462011-08-25 18:44:49 -0700719 nextCallInsn);
buzbee67bf8852011-08-17 17:51:35 -0700720 }
721 // Finish up any of the call sequence not interleaved in arg loading
722 while (callState >= 0) {
buzbeec5ef0462011-08-25 18:44:49 -0700723 callState = nextCallInsn(cUnit, mir, dInsn, callState);
buzbee67bf8852011-08-17 17:51:35 -0700724 }
725 newLIR1(cUnit, kThumbBlxR, rLR);
726}
727
728static void genInvokeDirect(CompilationUnit* cUnit, MIR* mir)
729{
730 DecodedInstruction* dInsn = &mir->dalvikInsn;
731 int callState = 0;
732 ArmLIR* nullCk;
733 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
734 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
735 false, nextSDCallInsn);
736 else
737 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
738 nextSDCallInsn);
739 // Finish up any of the call sequence not interleaved in arg loading
740 while (callState >= 0) {
741 callState = nextSDCallInsn(cUnit, mir, dInsn, callState);
742 }
743 newLIR1(cUnit, kThumbBlxR, rLR);
744}
745
746static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
747{
748 DecodedInstruction* dInsn = &mir->dalvikInsn;
749 int callState = 0;
750 ArmLIR* nullCk;
751 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
752 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState);
753 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
754 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
755 false, nextInterfaceCallInsn);
756 else
757 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
758 nextInterfaceCallInsn);
759 // Finish up any of the call sequence not interleaved in arg loading
760 while (callState >= 0) {
761 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState);
762 }
763 newLIR1(cUnit, kThumbBlxR, rLR);
764}
765
766static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
767{
768 DecodedInstruction* dInsn = &mir->dalvikInsn;
769 int callState = 0;
770 ArmLIR* nullCk;
771// FIXME - redundantly loading arg0/r1 ("this")
772 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
773 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
774 false, nextSuperCallInsn);
775 else
776 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
777 nextSuperCallInsn);
778 // Finish up any of the call sequence not interleaved in arg loading
779 while (callState >= 0) {
780 callState = nextSuperCallInsn(cUnit, mir, dInsn, callState);
781 }
782 newLIR1(cUnit, kThumbBlxR, rLR);
783}
784
785static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
786{
787 DecodedInstruction* dInsn = &mir->dalvikInsn;
788 int callState = 0;
789 ArmLIR* nullCk;
790// FIXME - redundantly loading arg0/r1 ("this")
791 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
792 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
793 false, nextVCallInsn);
794 else
795 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
796 nextVCallInsn);
797 // Finish up any of the call sequence not interleaved in arg loading
798 while (callState >= 0) {
799 callState = nextVCallInsn(cUnit, mir, dInsn, callState);
800 }
801 newLIR1(cUnit, kThumbBlxR, rLR);
802}
803
804// TODO: break out the case handlers. Might make it easier to support x86
805static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
806 BasicBlock* bb, ArmLIR* labelList)
807{
808 bool res = false; // Assume success
809 RegLocation rlSrc[3];
810 RegLocation rlDest = badLoc;
811 RegLocation rlResult = badLoc;
812 Opcode opcode = mir->dalvikInsn.opcode;
813
814 /* Prep Src and Dest locations */
815 int nextSreg = 0;
816 int nextLoc = 0;
817 int attrs = oatDataFlowAttributes[opcode];
818 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
819 if (attrs & DF_UA) {
820 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
821 nextSreg++;
822 } else if (attrs & DF_UA_WIDE) {
823 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
824 nextSreg + 1);
825 nextSreg+= 2;
826 }
827 if (attrs & DF_UB) {
828 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
829 nextSreg++;
830 } else if (attrs & DF_UB_WIDE) {
831 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
832 nextSreg + 1);
833 nextSreg+= 2;
834 }
835 if (attrs & DF_UC) {
836 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
837 } else if (attrs & DF_UC_WIDE) {
838 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
839 nextSreg + 1);
840 }
841 if (attrs & DF_DA) {
842 rlDest = oatGetDest(cUnit, mir, 0);
843 } else if (attrs & DF_DA_WIDE) {
844 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
845 }
846
847 switch(opcode) {
848 case OP_NOP:
849 break;
850
851 case OP_MOVE_EXCEPTION:
852 int exOffset;
853 int resetReg;
buzbeec143c552011-08-20 17:38:58 -0700854 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700855 resetReg = oatAllocTemp(cUnit);
856 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
857 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
858 loadConstant(cUnit, resetReg, 0);
859 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
860 storeValue(cUnit, rlDest, rlResult);
861 break;
862
863 case OP_RETURN_VOID:
864 break;
865
866 case OP_RETURN:
867 case OP_RETURN_OBJECT:
868 storeValue(cUnit, retLoc, rlSrc[0]);
869 break;
870
871 case OP_RETURN_WIDE:
872 rlDest = retLocWide;
873 rlDest.fp = rlSrc[0].fp;
874 storeValueWide(cUnit, rlDest, rlSrc[0]);
875 break;
876
877 case OP_MOVE_RESULT_WIDE:
878 if (mir->OptimizationFlags & MIR_INLINED)
879 break; // Nop - combined w/ previous invoke
880 /*
881 * Somewhat hacky here. Because we're now passing
882 * return values in registers, we have to let the
883 * register allocation utilities know that the return
884 * registers are live and may not be used for address
885 * formation in storeValueWide.
886 */
887 assert(retLocWide.lowReg == r0);
888 assert(retLocWide.lowReg == r1);
889 oatLockTemp(cUnit, retLocWide.lowReg);
890 oatLockTemp(cUnit, retLocWide.highReg);
891 storeValueWide(cUnit, rlDest, retLocWide);
892 oatFreeTemp(cUnit, retLocWide.lowReg);
893 oatFreeTemp(cUnit, retLocWide.highReg);
894 break;
895
896 case OP_MOVE_RESULT:
897 case OP_MOVE_RESULT_OBJECT:
898 if (mir->OptimizationFlags & MIR_INLINED)
899 break; // Nop - combined w/ previous invoke
900 /* See comment for OP_MOVE_RESULT_WIDE */
901 assert(retLoc.lowReg == r0);
902 oatLockTemp(cUnit, retLoc.lowReg);
903 storeValue(cUnit, rlDest, retLoc);
904 oatFreeTemp(cUnit, retLoc.lowReg);
905 break;
906
907 case OP_MOVE:
908 case OP_MOVE_OBJECT:
909 case OP_MOVE_16:
910 case OP_MOVE_OBJECT_16:
911 case OP_MOVE_FROM16:
912 case OP_MOVE_OBJECT_FROM16:
913 storeValue(cUnit, rlDest, rlSrc[0]);
914 break;
915
916 case OP_MOVE_WIDE:
917 case OP_MOVE_WIDE_16:
918 case OP_MOVE_WIDE_FROM16:
919 storeValueWide(cUnit, rlDest, rlSrc[0]);
920 break;
921
922 case OP_CONST:
923 case OP_CONST_4:
924 case OP_CONST_16:
925 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
926 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
927 storeValue(cUnit, rlDest, rlResult);
928 break;
929
930 case OP_CONST_HIGH16:
931 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
932 loadConstantNoClobber(cUnit, rlResult.lowReg,
933 mir->dalvikInsn.vB << 16);
934 storeValue(cUnit, rlDest, rlResult);
935 break;
936
937 case OP_CONST_WIDE_16:
938 case OP_CONST_WIDE_32:
939 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
940 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
941 //TUNING: do high separately to avoid load dependency
942 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
943 storeValueWide(cUnit, rlDest, rlResult);
944 break;
945
946 case OP_CONST_WIDE:
947 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
948 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -0700949 mir->dalvikInsn.vB_wide & 0xffffffff,
950 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -0700951 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700952 break;
953
954 case OP_CONST_WIDE_HIGH16:
955 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
956 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
957 0, mir->dalvikInsn.vB << 16);
958 storeValue(cUnit, rlDest, rlResult);
959 break;
960
961 case OP_MONITOR_ENTER:
962 genMonitorEnter(cUnit, mir, rlSrc[0]);
963 break;
964
965 case OP_MONITOR_EXIT:
966 genMonitorExit(cUnit, mir, rlSrc[0]);
967 break;
968
969 case OP_CHECK_CAST:
970 genCheckCast(cUnit, mir, rlSrc[0]);
971 break;
972
973 case OP_INSTANCE_OF:
974 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
975 break;
976
977 case OP_NEW_INSTANCE:
978 genNewInstance(cUnit, mir, rlDest);
979 break;
980
981 case OP_THROW:
982 genThrow(cUnit, mir, rlSrc[0]);
983 break;
984
985 case OP_ARRAY_LENGTH:
986 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -0700987 lenOffset = Array::LengthOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700988 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
989 mir->offset, NULL);
990 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
991 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
992 rlResult.lowReg);
993 storeValue(cUnit, rlDest, rlResult);
994 break;
995
996 case OP_CONST_STRING:
997 case OP_CONST_STRING_JUMBO:
998 genConstString(cUnit, mir, rlDest, rlSrc[0]);
999 break;
1000
1001 case OP_CONST_CLASS:
1002 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1003 break;
1004
1005 case OP_FILL_ARRAY_DATA:
1006 genFillArrayData(cUnit, mir, rlSrc[0]);
1007 break;
1008
1009 case OP_FILLED_NEW_ARRAY:
1010 genFilledNewArray(cUnit, mir, false /* not range */);
1011 break;
1012
1013 case OP_FILLED_NEW_ARRAY_RANGE:
1014 genFilledNewArray(cUnit, mir, true /* range */);
1015 break;
1016
1017 case OP_NEW_ARRAY:
1018 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1019 break;
1020
1021 case OP_GOTO:
1022 case OP_GOTO_16:
1023 case OP_GOTO_32:
1024 // TUNING: add MIR flag to disable when unnecessary
1025 bool backwardBranch;
1026 backwardBranch = (bb->taken->startOffset <= mir->offset);
1027 if (backwardBranch) {
1028 genSuspendPoll(cUnit, mir);
1029 }
1030 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1031 break;
1032
1033 case OP_PACKED_SWITCH:
1034 genPackedSwitch(cUnit, mir, rlSrc[0]);
1035 break;
1036
1037 case OP_SPARSE_SWITCH:
1038 genSparseSwitch(cUnit, mir, rlSrc[0]);
1039 break;
1040
1041 case OP_CMPL_FLOAT:
1042 case OP_CMPG_FLOAT:
1043 case OP_CMPL_DOUBLE:
1044 case OP_CMPG_DOUBLE:
1045 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1046 break;
1047
1048 case OP_CMP_LONG:
1049 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1050 break;
1051
1052 case OP_IF_EQ:
1053 case OP_IF_NE:
1054 case OP_IF_LT:
1055 case OP_IF_GE:
1056 case OP_IF_GT:
1057 case OP_IF_LE: {
1058 bool backwardBranch;
1059 ArmConditionCode cond;
1060 backwardBranch = (bb->taken->startOffset <= mir->offset);
1061 if (backwardBranch) {
1062 genSuspendPoll(cUnit, mir);
1063 }
1064 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1065 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1066 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1067 switch(opcode) {
1068 case OP_IF_EQ:
1069 cond = kArmCondEq;
1070 break;
1071 case OP_IF_NE:
1072 cond = kArmCondNe;
1073 break;
1074 case OP_IF_LT:
1075 cond = kArmCondLt;
1076 break;
1077 case OP_IF_GE:
1078 cond = kArmCondGe;
1079 break;
1080 case OP_IF_GT:
1081 cond = kArmCondGt;
1082 break;
1083 case OP_IF_LE:
1084 cond = kArmCondLe;
1085 break;
1086 default:
1087 cond = (ArmConditionCode)0;
1088 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1089 }
1090 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1091 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1092 break;
1093 }
1094
1095 case OP_IF_EQZ:
1096 case OP_IF_NEZ:
1097 case OP_IF_LTZ:
1098 case OP_IF_GEZ:
1099 case OP_IF_GTZ:
1100 case OP_IF_LEZ: {
1101 bool backwardBranch;
1102 ArmConditionCode cond;
1103 backwardBranch = (bb->taken->startOffset <= mir->offset);
1104 if (backwardBranch) {
1105 genSuspendPoll(cUnit, mir);
1106 }
1107 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1108 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1109 switch(opcode) {
1110 case OP_IF_EQZ:
1111 cond = kArmCondEq;
1112 break;
1113 case OP_IF_NEZ:
1114 cond = kArmCondNe;
1115 break;
1116 case OP_IF_LTZ:
1117 cond = kArmCondLt;
1118 break;
1119 case OP_IF_GEZ:
1120 cond = kArmCondGe;
1121 break;
1122 case OP_IF_GTZ:
1123 cond = kArmCondGt;
1124 break;
1125 case OP_IF_LEZ:
1126 cond = kArmCondLe;
1127 break;
1128 default:
1129 cond = (ArmConditionCode)0;
1130 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1131 }
1132 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1133 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1134 break;
1135 }
1136
1137 case OP_AGET_WIDE:
1138 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1139 break;
1140 case OP_AGET:
1141 case OP_AGET_OBJECT:
1142 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1143 break;
1144 case OP_AGET_BOOLEAN:
1145 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1146 rlDest, 0);
1147 break;
1148 case OP_AGET_BYTE:
1149 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1150 break;
1151 case OP_AGET_CHAR:
1152 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1153 rlDest, 1);
1154 break;
1155 case OP_AGET_SHORT:
1156 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1157 break;
1158 case OP_APUT_WIDE:
1159 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1160 break;
1161 case OP_APUT:
1162 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1163 break;
1164 case OP_APUT_OBJECT:
buzbeec143c552011-08-20 17:38:58 -07001165 genArrayPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001166 break;
1167 case OP_APUT_SHORT:
1168 case OP_APUT_CHAR:
1169 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1170 rlSrc[0], 1);
1171 break;
1172 case OP_APUT_BYTE:
1173 case OP_APUT_BOOLEAN:
1174 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1175 rlSrc[0], 0);
1176 break;
1177
1178 case OP_IGET_WIDE:
1179 case OP_IGET_WIDE_VOLATILE:
1180 genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
1181 break;
1182
1183 case OP_IGET:
1184 case OP_IGET_VOLATILE:
1185 case OP_IGET_OBJECT:
1186 case OP_IGET_OBJECT_VOLATILE:
1187 genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
1188 break;
1189
1190 case OP_IGET_BOOLEAN:
1191 case OP_IGET_BYTE:
1192 genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
1193 break;
1194
1195 case OP_IGET_CHAR:
1196 genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
1197 break;
1198
1199 case OP_IGET_SHORT:
1200 genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
1201 break;
1202
1203 case OP_IPUT_WIDE:
1204 case OP_IPUT_WIDE_VOLATILE:
1205 genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
1206 break;
1207
1208 case OP_IPUT_OBJECT:
1209 case OP_IPUT_OBJECT_VOLATILE:
1210 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
1211 break;
1212
1213 case OP_IPUT:
1214 case OP_IPUT_VOLATILE:
1215 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
1216 break;
1217
1218 case OP_IPUT_BOOLEAN:
1219 case OP_IPUT_BYTE:
1220 genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
1221 break;
1222
1223 case OP_IPUT_CHAR:
1224 genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
1225 break;
1226
1227 case OP_IPUT_SHORT:
1228 genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
1229 break;
1230
1231 case OP_SGET:
1232 case OP_SGET_OBJECT:
1233 case OP_SGET_BOOLEAN:
1234 case OP_SGET_BYTE:
1235 case OP_SGET_CHAR:
1236 case OP_SGET_SHORT:
1237 genSget(cUnit, mir, rlResult, rlDest);
1238 break;
1239
1240 case OP_SGET_WIDE:
1241 genSgetWide(cUnit, mir, rlResult, rlDest);
1242 break;
1243
1244 case OP_SPUT:
1245 case OP_SPUT_OBJECT:
1246 case OP_SPUT_BOOLEAN:
1247 case OP_SPUT_BYTE:
1248 case OP_SPUT_CHAR:
1249 case OP_SPUT_SHORT:
1250 genSput(cUnit, mir, rlSrc[0]);
1251 break;
1252
1253 case OP_SPUT_WIDE:
1254 genSputWide(cUnit, mir, rlSrc[0]);
1255 break;
1256
1257 case OP_INVOKE_STATIC_RANGE:
1258 case OP_INVOKE_STATIC:
1259 genInvokeStatic(cUnit, mir);
1260 break;
1261
1262 case OP_INVOKE_DIRECT:
1263 case OP_INVOKE_DIRECT_RANGE:
1264 genInvokeDirect(cUnit, mir);
1265 break;
1266
1267 case OP_INVOKE_VIRTUAL:
1268 case OP_INVOKE_VIRTUAL_RANGE:
1269 genInvokeVirtual(cUnit, mir);
1270 break;
1271
1272 case OP_INVOKE_SUPER:
1273 case OP_INVOKE_SUPER_RANGE:
1274 genInvokeSuper(cUnit, mir);
1275 break;
1276
1277 case OP_INVOKE_INTERFACE:
1278 case OP_INVOKE_INTERFACE_RANGE:
1279 genInvokeInterface(cUnit, mir);
1280 break;
1281
1282 case OP_NEG_INT:
1283 case OP_NOT_INT:
1284 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1285 break;
1286
1287 case OP_NEG_LONG:
1288 case OP_NOT_LONG:
1289 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1290 break;
1291
1292 case OP_NEG_FLOAT:
1293 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1294 break;
1295
1296 case OP_NEG_DOUBLE:
1297 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1298 break;
1299
1300 case OP_INT_TO_LONG:
1301 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1302 if (rlSrc[0].location == kLocPhysReg) {
1303 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1304 } else {
1305 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1306 }
1307 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1308 rlResult.lowReg, 31);
1309 storeValueWide(cUnit, rlDest, rlResult);
1310 break;
1311
1312 case OP_LONG_TO_INT:
1313 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1314 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1315 storeValue(cUnit, rlDest, rlSrc[0]);
1316 break;
1317
1318 case OP_INT_TO_BYTE:
1319 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1320 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1321 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1322 storeValue(cUnit, rlDest, rlResult);
1323 break;
1324
1325 case OP_INT_TO_SHORT:
1326 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1327 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1328 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1329 storeValue(cUnit, rlDest, rlResult);
1330 break;
1331
1332 case OP_INT_TO_CHAR:
1333 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1334 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1335 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1336 storeValue(cUnit, rlDest, rlResult);
1337 break;
1338
1339 case OP_INT_TO_FLOAT:
1340 case OP_INT_TO_DOUBLE:
1341 case OP_LONG_TO_FLOAT:
1342 case OP_LONG_TO_DOUBLE:
1343 case OP_FLOAT_TO_INT:
1344 case OP_FLOAT_TO_LONG:
1345 case OP_FLOAT_TO_DOUBLE:
1346 case OP_DOUBLE_TO_INT:
1347 case OP_DOUBLE_TO_LONG:
1348 case OP_DOUBLE_TO_FLOAT:
1349 genConversion(cUnit, mir);
1350 break;
1351
1352 case OP_ADD_INT:
1353 case OP_SUB_INT:
1354 case OP_MUL_INT:
1355 case OP_DIV_INT:
1356 case OP_REM_INT:
1357 case OP_AND_INT:
1358 case OP_OR_INT:
1359 case OP_XOR_INT:
1360 case OP_SHL_INT:
1361 case OP_SHR_INT:
1362 case OP_USHR_INT:
1363 case OP_ADD_INT_2ADDR:
1364 case OP_SUB_INT_2ADDR:
1365 case OP_MUL_INT_2ADDR:
1366 case OP_DIV_INT_2ADDR:
1367 case OP_REM_INT_2ADDR:
1368 case OP_AND_INT_2ADDR:
1369 case OP_OR_INT_2ADDR:
1370 case OP_XOR_INT_2ADDR:
1371 case OP_SHL_INT_2ADDR:
1372 case OP_SHR_INT_2ADDR:
1373 case OP_USHR_INT_2ADDR:
1374 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1375 break;
1376
1377 case OP_ADD_LONG:
1378 case OP_SUB_LONG:
1379 case OP_MUL_LONG:
1380 case OP_DIV_LONG:
1381 case OP_REM_LONG:
1382 case OP_AND_LONG:
1383 case OP_OR_LONG:
1384 case OP_XOR_LONG:
1385 case OP_ADD_LONG_2ADDR:
1386 case OP_SUB_LONG_2ADDR:
1387 case OP_MUL_LONG_2ADDR:
1388 case OP_DIV_LONG_2ADDR:
1389 case OP_REM_LONG_2ADDR:
1390 case OP_AND_LONG_2ADDR:
1391 case OP_OR_LONG_2ADDR:
1392 case OP_XOR_LONG_2ADDR:
1393 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1394 break;
1395
1396 case OP_SHL_LONG_2ADDR:
1397 case OP_SHR_LONG_2ADDR:
1398 case OP_USHR_LONG_2ADDR:
1399 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[0]);
1400 break;
1401
1402 case OP_SHL_LONG:
1403 case OP_SHR_LONG:
1404 case OP_USHR_LONG:
1405 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1406 break;
1407
1408 case OP_ADD_FLOAT:
1409 case OP_SUB_FLOAT:
1410 case OP_MUL_FLOAT:
1411 case OP_DIV_FLOAT:
1412 case OP_REM_FLOAT:
1413 case OP_ADD_FLOAT_2ADDR:
1414 case OP_SUB_FLOAT_2ADDR:
1415 case OP_MUL_FLOAT_2ADDR:
1416 case OP_DIV_FLOAT_2ADDR:
1417 case OP_REM_FLOAT_2ADDR:
1418 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1419 break;
1420
1421 case OP_ADD_DOUBLE:
1422 case OP_SUB_DOUBLE:
1423 case OP_MUL_DOUBLE:
1424 case OP_DIV_DOUBLE:
1425 case OP_REM_DOUBLE:
1426 case OP_ADD_DOUBLE_2ADDR:
1427 case OP_SUB_DOUBLE_2ADDR:
1428 case OP_MUL_DOUBLE_2ADDR:
1429 case OP_DIV_DOUBLE_2ADDR:
1430 case OP_REM_DOUBLE_2ADDR:
1431 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1432 break;
1433
1434 case OP_RSUB_INT:
1435 case OP_ADD_INT_LIT16:
1436 case OP_MUL_INT_LIT16:
1437 case OP_DIV_INT_LIT16:
1438 case OP_REM_INT_LIT16:
1439 case OP_AND_INT_LIT16:
1440 case OP_OR_INT_LIT16:
1441 case OP_XOR_INT_LIT16:
1442 case OP_ADD_INT_LIT8:
1443 case OP_RSUB_INT_LIT8:
1444 case OP_MUL_INT_LIT8:
1445 case OP_DIV_INT_LIT8:
1446 case OP_REM_INT_LIT8:
1447 case OP_AND_INT_LIT8:
1448 case OP_OR_INT_LIT8:
1449 case OP_XOR_INT_LIT8:
1450 case OP_SHL_INT_LIT8:
1451 case OP_SHR_INT_LIT8:
1452 case OP_USHR_INT_LIT8:
1453 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1454 break;
1455
1456 default:
1457 res = true;
1458 }
1459 return res;
1460}
1461
1462static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1463 "kMirOpPhi",
1464 "kMirOpNullNRangeUpCheck",
1465 "kMirOpNullNRangeDownCheck",
1466 "kMirOpLowerBound",
1467 "kMirOpPunt",
1468 "kMirOpCheckInlinePrediction",
1469};
1470
1471/* Extended MIR instructions like PHI */
1472static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1473{
1474 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1475 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1476 strcpy(msg, extendedMIROpNames[opOffset]);
1477 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1478
1479 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1480 case kMirOpPhi: {
1481 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1482 op->flags.isNop = true;
1483 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1484 break;
1485 }
1486 default:
1487 break;
1488 }
1489}
1490
1491/* If there are any ins passed in registers that have not been promoted
1492 * to a callee-save register, flush them to the frame.
1493 * Note: at this pointCopy any ins that are passed in register to their home location */
1494static void flushIns(CompilationUnit* cUnit)
1495{
buzbeec143c552011-08-20 17:38:58 -07001496 if (cUnit->method->num_ins_ == 0)
buzbee67bf8852011-08-17 17:51:35 -07001497 return;
buzbeec143c552011-08-20 17:38:58 -07001498 int inRegs = (cUnit->method->num_ins_ > 2) ? 3 : cUnit->method->num_ins_;
buzbee67bf8852011-08-17 17:51:35 -07001499 int startReg = r1;
buzbeec143c552011-08-20 17:38:58 -07001500 int startLoc = cUnit->method->num_registers_ - cUnit->method->num_ins_;
buzbee67bf8852011-08-17 17:51:35 -07001501 for (int i = 0; i < inRegs; i++) {
1502 RegLocation loc = cUnit->regLocation[startLoc + i];
1503 if (loc.location == kLocPhysReg) {
1504 genRegCopy(cUnit, loc.lowReg, startReg + i);
1505 } else {
1506 assert(loc.location == kLocDalvikFrame);
1507 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
1508 }
1509 }
1510
1511 // Handle special case of wide argument half in regs, half in frame
1512 if (inRegs == 3) {
1513 RegLocation loc = cUnit->regLocation[startLoc + 2];
1514 if (loc.wide && loc.location == kLocPhysReg) {
1515 // Load the other half of the arg into the promoted pair
1516 loadBaseDisp(cUnit, NULL, rSP, loc.spOffset+4,
1517 loc.highReg, kWord, INVALID_SREG);
1518 inRegs++;
1519 }
1520 }
1521
1522 // Now, do initial assignment of all promoted arguments passed in frame
buzbeec143c552011-08-20 17:38:58 -07001523 for (int i = inRegs; i < cUnit->method->num_ins_;) {
buzbee67bf8852011-08-17 17:51:35 -07001524 RegLocation loc = cUnit->regLocation[startLoc + i];
1525 if (loc.fpLocation == kLocPhysReg) {
1526 loc.location = kLocPhysReg;
1527 loc.fp = true;
1528 loc.lowReg = loc.fpLowReg;
1529 loc.highReg = loc.fpHighReg;
1530 }
1531 if (loc.location == kLocPhysReg) {
1532 if (loc.wide) {
1533 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1534 loc.lowReg, loc.highReg, INVALID_SREG);
1535 i++;
1536 } else {
1537 loadBaseDisp(cUnit, NULL, rSP, loc.spOffset,
1538 loc.lowReg, kWord, INVALID_SREG);
1539 }
1540 }
1541 i++;
1542 }
1543}
1544
1545/* Handle the content in each basic block */
1546static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1547{
1548 MIR* mir;
1549 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1550 int blockId = bb->id;
1551
1552 cUnit->curBlock = bb;
1553 labelList[blockId].operands[0] = bb->startOffset;
1554
1555 /* Insert the block label */
1556 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1557 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1558
1559 oatClobberAllRegs(cUnit);
1560 oatResetNullCheck(cUnit);
1561
1562 ArmLIR* headLIR = NULL;
1563
1564 if (bb->blockType == kEntryBlock) {
1565 /*
1566 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1567 * mechanism know so it doesn't try to use any of them when
1568 * expanding the frame or flushing. This leaves the utility
1569 * code with a single temp: r12. This should be enough.
1570 */
1571 oatLockTemp(cUnit, r0);
1572 oatLockTemp(cUnit, r1);
1573 oatLockTemp(cUnit, r2);
1574 oatLockTemp(cUnit, r3);
1575 newLIR0(cUnit, kArmPseudoMethodEntry);
1576 /* Spill core callee saves */
1577 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1578 /* Need to spill any FP regs? */
1579 if (cUnit->numFPSpills) {
1580 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1581 }
1582 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1583 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1584 flushIns(cUnit);
1585 oatFreeTemp(cUnit, r0);
1586 oatFreeTemp(cUnit, r1);
1587 oatFreeTemp(cUnit, r2);
1588 oatFreeTemp(cUnit, r3);
1589 } else if (bb->blockType == kExitBlock) {
1590 newLIR0(cUnit, kArmPseudoMethodExit);
1591 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1592 /* Need to restore any FP callee saves? */
1593 if (cUnit->numFPSpills) {
1594 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1595 }
1596 if (cUnit->coreSpillMask & (1 << rLR)) {
1597 /* Unspill rLR to rPC */
1598 cUnit->coreSpillMask &= ~(1 << rLR);
1599 cUnit->coreSpillMask |= (1 << rPC);
1600 }
1601 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1602 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1603 /* We didn't pop to rPC, so must do a bv rLR */
1604 newLIR1(cUnit, kThumbBx, rLR);
1605 }
1606 }
1607
1608 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1609
1610 oatResetRegPool(cUnit);
1611 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1612 oatClobberAllRegs(cUnit);
1613 }
1614
1615 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1616 oatResetDefTracking(cUnit);
1617 }
1618
1619 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1620 handleExtendedMethodMIR(cUnit, mir);
1621 continue;
1622 }
1623
1624 cUnit->currentDalvikOffset = mir->offset;
1625
1626 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1627 InstructionFormat dalvikFormat =
1628 dexGetFormatFromOpcode(dalvikOpcode);
1629
1630 ArmLIR* boundaryLIR;
1631
1632 /* Mark the beginning of a Dalvik instruction for line tracking */
1633 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1634 (int) oatGetDalvikDisassembly(
1635 &mir->dalvikInsn, ""));
1636 /* Remember the first LIR for this block */
1637 if (headLIR == NULL) {
1638 headLIR = boundaryLIR;
1639 /* Set the first boundaryLIR as a scheduling barrier */
1640 headLIR->defMask = ENCODE_ALL;
1641 }
1642
1643 /* Don't generate the SSA annotation unless verbose mode is on */
1644 if (cUnit->printMe && mir->ssaRep) {
1645 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1646 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1647 }
1648
1649 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1650
1651 if (notHandled) {
1652 char buf[100];
1653 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1654 mir->offset,
1655 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1656 dalvikFormat);
1657 LOG(FATAL) << buf;
1658 }
1659 }
1660
1661 if (headLIR) {
1662 /*
1663 * Eliminate redundant loads/stores and delay stores into later
1664 * slots
1665 */
1666 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1667 cUnit->lastLIRInsn);
1668
1669 /*
1670 * Generate an unconditional branch to the fallthrough block.
1671 */
1672 if (bb->fallThrough) {
1673 genUnconditionalBranch(cUnit,
1674 &labelList[bb->fallThrough->id]);
1675 }
1676 }
1677 return false;
1678}
1679
1680/*
1681 * Nop any unconditional branches that go to the next instruction.
1682 * Note: new redundant branches may be inserted later, and we'll
1683 * use a check in final instruction assembly to nop those out.
1684 */
1685void removeRedundantBranches(CompilationUnit* cUnit)
1686{
1687 ArmLIR* thisLIR;
1688
1689 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1690 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1691 thisLIR = NEXT_LIR(thisLIR)) {
1692
1693 /* Branch to the next instruction */
1694 if ((thisLIR->opcode == kThumbBUncond) ||
1695 (thisLIR->opcode == kThumb2BUncond)) {
1696 ArmLIR* nextLIR = thisLIR;
1697
1698 while (true) {
1699 nextLIR = NEXT_LIR(nextLIR);
1700
1701 /*
1702 * Is the branch target the next instruction?
1703 */
1704 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1705 thisLIR->flags.isNop = true;
1706 break;
1707 }
1708
1709 /*
1710 * Found real useful stuff between the branch and the target.
1711 * Need to explicitly check the lastLIRInsn here because it
1712 * might be the last real instruction.
1713 */
1714 if (!isPseudoOpcode(nextLIR->opcode) ||
1715 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1716 break;
1717 }
1718 }
1719 }
1720}
1721
1722void oatMethodMIR2LIR(CompilationUnit* cUnit)
1723{
1724 /* Used to hold the labels of each block */
1725 cUnit->blockLabelList =
1726 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
1727
1728 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
1729 kPreOrderDFSTraversal, false /* Iterative */);
1730 removeRedundantBranches(cUnit);
1731}
1732
1733/* Common initialization routine for an architecture family */
1734bool oatArchInit()
1735{
1736 int i;
1737
1738 for (i = 0; i < kArmLast; i++) {
1739 if (EncodingMap[i].opcode != i) {
1740 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
1741 " is wrong: expecting " << i << ", seeing " <<
1742 (int)EncodingMap[i].opcode;
1743 }
1744 }
1745
1746 return oatArchVariantInit();
1747}
1748
1749/* Needed by the Assembler */
1750void oatSetupResourceMasks(ArmLIR* lir)
1751{
1752 setupResourceMasks(lir);
1753}
1754
1755/* Needed by the ld/st optmizatons */
1756ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
1757{
1758 return genRegCopyNoInsert(cUnit, rDest, rSrc);
1759}
1760
1761/* Needed by the register allocator */
1762ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1763{
1764 return genRegCopy(cUnit, rDest, rSrc);
1765}
1766
1767/* Needed by the register allocator */
1768void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
1769 int srcLo, int srcHi)
1770{
1771 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
1772}
1773
1774void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
1775 int displacement, int rSrc, OpSize size)
1776{
1777 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
1778}
1779
1780void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
1781 int displacement, int rSrcLo, int rSrcHi)
1782{
1783 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
1784}