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