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