blob: 673aaba61f8c02b34d15f5a35606465d5b069927 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
buzbee67bf8852011-08-17 17:51:35 -070017static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
18 INVALID_REG, INVALID_SREG, 0,
19 kLocDalvikFrame, INVALID_REG, INVALID_REG,
20 INVALID_OFFSET};
21static const RegLocation retLoc = LOC_DALVIK_RETURN_VAL;
22static const RegLocation retLocWide = LOC_DALVIK_RETURN_VAL_WIDE;
23
24static void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
25 RegLocation rlSrc)
26{
27 oatFlushAllRegs(cUnit); /* All temps to home location */
buzbeec143c552011-08-20 17:38:58 -070028 Class* classPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
Brian Carlstrom9ea1cb12011-08-24 23:18:18 -070029 GetResolvedType(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -070030 if (classPtr == NULL) {
buzbee3ea4ec52011-08-22 17:37:19 -070031 LOG(FATAL) << "Unexpected null classPtr";
buzbee67bf8852011-08-17 17:51:35 -070032 } else {
33 loadValueDirectFixed(cUnit, rlSrc, r1); /* get Len */
34 loadConstant(cUnit, r0, (int)classPtr);
35 }
buzbee3ea4ec52011-08-22 17:37:19 -070036 UNIMPLEMENTED(WARNING) << "Support for throwing errNegativeArraySize";
buzbee67bf8852011-08-17 17:51:35 -070037 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
buzbee67bf8852011-08-17 17:51:35 -070038 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pArtAllocArrayByClass),
39 rLR);
buzbee3ea4ec52011-08-22 17:37:19 -070040 UNIMPLEMENTED(WARNING) << "Need NoThrow wrapper";
buzbee67bf8852011-08-17 17:51:35 -070041 newLIR1(cUnit, kThumbBlxR, rLR); // (arrayClass, length, allocFlags)
42 storeValue(cUnit, rlDest, retLoc);
43}
44
45/*
46 * Similar to genNewArray, but with post-allocation initialization.
47 * Verifier guarantees we're dealing with an array class. Current
48 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
49 * Current code also throws internal unimp if not 'L', '[' or 'I'.
50 */
51static void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
52{
53 DecodedInstruction* dInsn = &mir->dalvikInsn;
54 int elems;
55 int typeIndex;
56 if (isRange) {
57 elems = dInsn->vA;
58 typeIndex = dInsn->vB;
59 } else {
60 elems = dInsn->vB;
61 typeIndex = dInsn->vC;
62 }
63 oatFlushAllRegs(cUnit); /* All temps to home location */
buzbeec143c552011-08-20 17:38:58 -070064 Class* classPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
Brian Carlstrom9ea1cb12011-08-24 23:18:18 -070065 GetResolvedType(typeIndex);
buzbee67bf8852011-08-17 17:51:35 -070066 if (classPtr == NULL) {
buzbee3ea4ec52011-08-22 17:37:19 -070067 LOG(FATAL) << "Unexpected null classPtr";
buzbee67bf8852011-08-17 17:51:35 -070068 } else {
69 loadConstant(cUnit, r0, (int)classPtr);
70 loadConstant(cUnit, r1, elems);
71 }
72 if (elems < 0) {
73 LOG(FATAL) << "Unexpected empty array";
74 }
75 /*
76 * FIXME: Need a new NoThrow allocator that checks for and handles
77 * the above mentioned bad cases of 'D', 'J' or !('L' | '[' | 'I').
78 * That will keep us from wasting space generating an inline check here.
79 */
buzbee67bf8852011-08-17 17:51:35 -070080 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pArtAllocArrayByClass),
81 rLR);
buzbee67bf8852011-08-17 17:51:35 -070082 newLIR1(cUnit, kThumbBlxR, rLR); // (arrayClass, length, allocFlags)
83 // Reserve ret0 (r0) - we'll use it in place.
84 oatLockTemp(cUnit, r0);
85 // Having a range of 0 is legal
86 if (isRange && (dInsn->vA > 0)) {
87 /*
88 * Bit of ugliness here. We're going generate a mem copy loop
89 * on the register range, but it is possible that some regs
90 * in the range have been promoted. This is unlikely, but
91 * before generating the copy, we'll just force a flush
92 * of any regs in the source range that have been promoted to
93 * home location.
94 */
95 for (unsigned int i = 0; i < dInsn->vA; i++) {
96 RegLocation loc = oatUpdateLoc(cUnit,
97 oatGetSrc(cUnit, mir, i));
98 if (loc.location == kLocPhysReg) {
99 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
100 }
101 }
102 /*
103 * TUNING note: generated code here could be much improved, but
104 * this is an uncommon operation and isn't especially performance
105 * critical.
106 */
107 int rSrc = oatAllocTemp(cUnit);
108 int rDst = oatAllocTemp(cUnit);
109 int rIdx = oatAllocTemp(cUnit);
110 int rVal = rLR; // Using a lot of temps, rLR is known free here
111 // Set up source pointer
112 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
113 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
114 // Set up the target pointer
115 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700116 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700117 // Set up the loop counter (known to be > 0)
118 loadConstant(cUnit, rIdx, dInsn->vA);
119 // Generate the copy loop. Going backwards for convenience
120 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
121 target->defMask = ENCODE_ALL;
122 // Copy next element
123 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
124 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
125 // Use setflags encoding here
126 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
127 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
128 branch->generic.target = (LIR*)target;
129 } else if (!isRange) {
130 // TUNING: interleave
131 for (unsigned int i = 0; i < dInsn->vA; i++) {
132 RegLocation rlArg = loadValue(cUnit,
133 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700134 storeBaseDisp(cUnit, r0,
135 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700136 i * 4, rlArg.lowReg, kWord);
137 // If the loadValue caused a temp to be allocated, free it
138 if (oatIsTemp(cUnit, rlArg.lowReg)) {
139 oatFreeTemp(cUnit, rlArg.lowReg);
140 }
141 }
142 }
143}
144
145static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
146{
buzbeec143c552011-08-20 17:38:58 -0700147 UNIMPLEMENTED(FATAL) << "Must update for new world";
148#if 0
buzbee67bf8852011-08-17 17:51:35 -0700149 int valOffset = OFFSETOF_MEMBER(StaticField, value);
150 int tReg = oatAllocTemp(cUnit);
151 int objHead;
152 bool isVolatile;
153 bool isSputObject;
154 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
155 mir->meta.calleeMethod : cUnit->method;
156 void* fieldPtr = (void*)
157 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
158 Opcode opcode = mir->dalvikInsn.opcode;
159
160 if (fieldPtr == NULL) {
161 // FIXME: need to handle this case for oat();
162 UNIMPLEMENTED(FATAL);
163 }
164
165#if ANDROID_SMP != 0
166 isVolatile = (opcode == OP_SPUT_VOLATILE) ||
167 (opcode == OP_SPUT_VOLATILE_JUMBO) ||
168 (opcode == OP_SPUT_OBJECT_VOLATILE) ||
169 (opcode == OP_SPUT_OBJECT_VOLATILE_JUMBO);
buzbeec143c552011-08-20 17:38:58 -0700170 assert(isVolatile == artIsVolatileField((Field *) fieldPtr));
buzbee67bf8852011-08-17 17:51:35 -0700171#else
buzbeec143c552011-08-20 17:38:58 -0700172 isVolatile = artIsVolatileField((Field *) fieldPtr);
buzbee67bf8852011-08-17 17:51:35 -0700173#endif
174
175 isSputObject = (opcode == OP_SPUT_OBJECT) ||
176 (opcode == OP_SPUT_OBJECT_VOLATILE);
177
178 rlSrc = oatGetSrc(cUnit, mir, 0);
179 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
180 loadConstant(cUnit, tReg, (int) fieldPtr);
181 if (isSputObject) {
182 objHead = oatAllocTemp(cUnit);
183 loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead);
184 }
185 storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg);
186 oatFreeTemp(cUnit, tReg);
187 if (isVolatile) {
188 oatGenMemBarrier(cUnit, kSY);
189 }
190 if (isSputObject) {
191 /* NOTE: marking card based sfield->clazz */
192 markGCCard(cUnit, rlSrc.lowReg, objHead);
193 oatFreeTemp(cUnit, objHead);
194 }
buzbeec143c552011-08-20 17:38:58 -0700195#endif
buzbee67bf8852011-08-17 17:51:35 -0700196}
197
198static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
199{
buzbeec143c552011-08-20 17:38:58 -0700200 UNIMPLEMENTED(FATAL) << "Must update for new world";
201#if 0
buzbee67bf8852011-08-17 17:51:35 -0700202 int tReg = oatAllocTemp(cUnit);
203 int valOffset = OFFSETOF_MEMBER(StaticField, value);
204 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
205 mir->meta.calleeMethod : cUnit->method;
206 void* fieldPtr = (void*)
207 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
208
209 if (fieldPtr == NULL) {
210 // FIXME: need to handle this case for oat();
211 UNIMPLEMENTED(FATAL);
212 }
213
214 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
215 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
216 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
217
218 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
buzbeec143c552011-08-20 17:38:58 -0700219#endif
buzbee67bf8852011-08-17 17:51:35 -0700220}
221
222
223
224static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
225 RegLocation rlResult, RegLocation rlDest)
226{
buzbeec143c552011-08-20 17:38:58 -0700227 UNIMPLEMENTED(FATAL) << "Must update for new world";
228#if 0
buzbee67bf8852011-08-17 17:51:35 -0700229 int valOffset = OFFSETOF_MEMBER(StaticField, value);
230 const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
231 mir->meta.calleeMethod : cUnit->method;
232 void* fieldPtr = (void*)
233 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
234
235 if (fieldPtr == NULL) {
236 // FIXME: need to handle this case for oat();
237 UNIMPLEMENTED(FATAL);
238 }
239
240 int tReg = oatAllocTemp(cUnit);
241 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
242 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
243 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
244
245 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
246
247 storeValueWide(cUnit, rlDest, rlResult);
buzbeec143c552011-08-20 17:38:58 -0700248#endif
buzbee67bf8852011-08-17 17:51:35 -0700249}
250
251static void genSget(CompilationUnit* cUnit, MIR* mir,
252 RegLocation rlResult, RegLocation rlDest)
253{
buzbeec143c552011-08-20 17:38:58 -0700254 UNIMPLEMENTED(FATAL) << "Must update for new world";
255#if 0
buzbee67bf8852011-08-17 17:51:35 -0700256 int valOffset = OFFSETOF_MEMBER(StaticField, value);
257 int tReg = oatAllocTemp(cUnit);
258 bool isVolatile;
259 const Method *method = cUnit->method;
260 void* fieldPtr = (void*)
261 (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
262
263 if (fieldPtr == NULL) {
264 // FIXME: need to handle this case for oat();
265 UNIMPLEMENTED(FATAL);
266 }
267
268 /*
269 * On SMP systems, Dalvik opcodes found to be referencing
270 * volatile fields are rewritten to their _VOLATILE variant.
271 * However, this does not happen on non-SMP systems. The compiler
272 * still needs to know about volatility to avoid unsafe
273 * optimizations so we determine volatility based on either
274 * the opcode or the field access flags.
275 */
276#if ANDROID_SMP != 0
277 Opcode opcode = mir->dalvikInsn.opcode;
278 isVolatile = (opcode == OP_SGET_VOLATILE) ||
279 (opcode == OP_SGET_OBJECT_VOLATILE);
buzbeec143c552011-08-20 17:38:58 -0700280 assert(isVolatile == artIsVolatileField((Field *) fieldPtr));
buzbee67bf8852011-08-17 17:51:35 -0700281#else
buzbeec143c552011-08-20 17:38:58 -0700282 isVolatile = artIsVolatileField((Field *) fieldPtr);
buzbee67bf8852011-08-17 17:51:35 -0700283#endif
284
285 rlDest = oatGetDest(cUnit, mir, 0);
286 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
287 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
288
289 if (isVolatile) {
290 oatGenMemBarrier(cUnit, kSY);
291 }
292 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
293
294 storeValue(cUnit, rlDest, rlResult);
buzbeec143c552011-08-20 17:38:58 -0700295#endif
buzbee67bf8852011-08-17 17:51:35 -0700296}
297
298typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int);
299
300/*
301 * Bit of a hack here - in leiu of a real scheduling pass,
302 * emit the next instruction in static & direct invoke sequences.
303 */
304static int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
305 DecodedInstruction* dInsn, int state)
306{
buzbeec143c552011-08-20 17:38:58 -0700307 UNIMPLEMENTED(FATAL) << "Update with new cache model";
308#if 0
buzbee67bf8852011-08-17 17:51:35 -0700309 switch(state) {
310 case 0: // Get the current Method* [sets r0]
311 loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
312 break;
313 case 1: // Get the pResMethods pointer [uses r0, sets r0]
buzbeec143c552011-08-20 17:38:58 -0700314 UNIMPLEMENTED(FATAL) << "Update with new cache";
buzbee67bf8852011-08-17 17:51:35 -0700315 loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, pResMethods),
316 r0, kWord, INVALID_SREG);
317 break;
318 case 2: // Get the target Method* [uses r0, sets r0]
319 loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
320 kWord, INVALID_SREG);
321 break;
322 case 3: // Get the target compiled code address [uses r0, sets rLR]
323 loadBaseDisp(cUnit, mir, r0,
324 OFFSETOF_MEMBER(Method, compiledInsns), rLR,
325 kWord, INVALID_SREG);
326 break;
327 default:
328 return -1;
329 }
buzbeec143c552011-08-20 17:38:58 -0700330#endif
buzbee67bf8852011-08-17 17:51:35 -0700331 return state + 1;
332}
333
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,
buzbee54330722011-08-23 16:46:55 -0700900 mir->dalvikInsn.vB_wide & 0xffffffff,
901 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -0700902 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700903 break;
904
905 case OP_CONST_WIDE_HIGH16:
906 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
907 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
908 0, mir->dalvikInsn.vB << 16);
909 storeValue(cUnit, rlDest, rlResult);
910 break;
911
912 case OP_MONITOR_ENTER:
913 genMonitorEnter(cUnit, mir, rlSrc[0]);
914 break;
915
916 case OP_MONITOR_EXIT:
917 genMonitorExit(cUnit, mir, rlSrc[0]);
918 break;
919
920 case OP_CHECK_CAST:
921 genCheckCast(cUnit, mir, rlSrc[0]);
922 break;
923
924 case OP_INSTANCE_OF:
925 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
926 break;
927
928 case OP_NEW_INSTANCE:
929 genNewInstance(cUnit, mir, rlDest);
930 break;
931
932 case OP_THROW:
933 genThrow(cUnit, mir, rlSrc[0]);
934 break;
935
936 case OP_ARRAY_LENGTH:
937 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -0700938 lenOffset = Array::LengthOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700939 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
940 mir->offset, NULL);
941 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
942 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
943 rlResult.lowReg);
944 storeValue(cUnit, rlDest, rlResult);
945 break;
946
947 case OP_CONST_STRING:
948 case OP_CONST_STRING_JUMBO:
949 genConstString(cUnit, mir, rlDest, rlSrc[0]);
950 break;
951
952 case OP_CONST_CLASS:
953 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
954 break;
955
956 case OP_FILL_ARRAY_DATA:
957 genFillArrayData(cUnit, mir, rlSrc[0]);
958 break;
959
960 case OP_FILLED_NEW_ARRAY:
961 genFilledNewArray(cUnit, mir, false /* not range */);
962 break;
963
964 case OP_FILLED_NEW_ARRAY_RANGE:
965 genFilledNewArray(cUnit, mir, true /* range */);
966 break;
967
968 case OP_NEW_ARRAY:
969 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
970 break;
971
972 case OP_GOTO:
973 case OP_GOTO_16:
974 case OP_GOTO_32:
975 // TUNING: add MIR flag to disable when unnecessary
976 bool backwardBranch;
977 backwardBranch = (bb->taken->startOffset <= mir->offset);
978 if (backwardBranch) {
979 genSuspendPoll(cUnit, mir);
980 }
981 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
982 break;
983
984 case OP_PACKED_SWITCH:
985 genPackedSwitch(cUnit, mir, rlSrc[0]);
986 break;
987
988 case OP_SPARSE_SWITCH:
989 genSparseSwitch(cUnit, mir, rlSrc[0]);
990 break;
991
992 case OP_CMPL_FLOAT:
993 case OP_CMPG_FLOAT:
994 case OP_CMPL_DOUBLE:
995 case OP_CMPG_DOUBLE:
996 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
997 break;
998
999 case OP_CMP_LONG:
1000 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1001 break;
1002
1003 case OP_IF_EQ:
1004 case OP_IF_NE:
1005 case OP_IF_LT:
1006 case OP_IF_GE:
1007 case OP_IF_GT:
1008 case OP_IF_LE: {
1009 bool backwardBranch;
1010 ArmConditionCode cond;
1011 backwardBranch = (bb->taken->startOffset <= mir->offset);
1012 if (backwardBranch) {
1013 genSuspendPoll(cUnit, mir);
1014 }
1015 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1016 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1017 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1018 switch(opcode) {
1019 case OP_IF_EQ:
1020 cond = kArmCondEq;
1021 break;
1022 case OP_IF_NE:
1023 cond = kArmCondNe;
1024 break;
1025 case OP_IF_LT:
1026 cond = kArmCondLt;
1027 break;
1028 case OP_IF_GE:
1029 cond = kArmCondGe;
1030 break;
1031 case OP_IF_GT:
1032 cond = kArmCondGt;
1033 break;
1034 case OP_IF_LE:
1035 cond = kArmCondLe;
1036 break;
1037 default:
1038 cond = (ArmConditionCode)0;
1039 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1040 }
1041 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1042 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1043 break;
1044 }
1045
1046 case OP_IF_EQZ:
1047 case OP_IF_NEZ:
1048 case OP_IF_LTZ:
1049 case OP_IF_GEZ:
1050 case OP_IF_GTZ:
1051 case OP_IF_LEZ: {
1052 bool backwardBranch;
1053 ArmConditionCode cond;
1054 backwardBranch = (bb->taken->startOffset <= mir->offset);
1055 if (backwardBranch) {
1056 genSuspendPoll(cUnit, mir);
1057 }
1058 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1059 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1060 switch(opcode) {
1061 case OP_IF_EQZ:
1062 cond = kArmCondEq;
1063 break;
1064 case OP_IF_NEZ:
1065 cond = kArmCondNe;
1066 break;
1067 case OP_IF_LTZ:
1068 cond = kArmCondLt;
1069 break;
1070 case OP_IF_GEZ:
1071 cond = kArmCondGe;
1072 break;
1073 case OP_IF_GTZ:
1074 cond = kArmCondGt;
1075 break;
1076 case OP_IF_LEZ:
1077 cond = kArmCondLe;
1078 break;
1079 default:
1080 cond = (ArmConditionCode)0;
1081 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1082 }
1083 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1084 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1085 break;
1086 }
1087
1088 case OP_AGET_WIDE:
1089 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1090 break;
1091 case OP_AGET:
1092 case OP_AGET_OBJECT:
1093 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1094 break;
1095 case OP_AGET_BOOLEAN:
1096 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1097 rlDest, 0);
1098 break;
1099 case OP_AGET_BYTE:
1100 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1101 break;
1102 case OP_AGET_CHAR:
1103 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1104 rlDest, 1);
1105 break;
1106 case OP_AGET_SHORT:
1107 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1108 break;
1109 case OP_APUT_WIDE:
1110 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1111 break;
1112 case OP_APUT:
1113 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1114 break;
1115 case OP_APUT_OBJECT:
buzbeec143c552011-08-20 17:38:58 -07001116 genArrayPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001117 break;
1118 case OP_APUT_SHORT:
1119 case OP_APUT_CHAR:
1120 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1121 rlSrc[0], 1);
1122 break;
1123 case OP_APUT_BYTE:
1124 case OP_APUT_BOOLEAN:
1125 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1126 rlSrc[0], 0);
1127 break;
1128
1129 case OP_IGET_WIDE:
1130 case OP_IGET_WIDE_VOLATILE:
1131 genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
1132 break;
1133
1134 case OP_IGET:
1135 case OP_IGET_VOLATILE:
1136 case OP_IGET_OBJECT:
1137 case OP_IGET_OBJECT_VOLATILE:
1138 genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
1139 break;
1140
1141 case OP_IGET_BOOLEAN:
1142 case OP_IGET_BYTE:
1143 genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
1144 break;
1145
1146 case OP_IGET_CHAR:
1147 genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
1148 break;
1149
1150 case OP_IGET_SHORT:
1151 genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
1152 break;
1153
1154 case OP_IPUT_WIDE:
1155 case OP_IPUT_WIDE_VOLATILE:
1156 genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
1157 break;
1158
1159 case OP_IPUT_OBJECT:
1160 case OP_IPUT_OBJECT_VOLATILE:
1161 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
1162 break;
1163
1164 case OP_IPUT:
1165 case OP_IPUT_VOLATILE:
1166 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
1167 break;
1168
1169 case OP_IPUT_BOOLEAN:
1170 case OP_IPUT_BYTE:
1171 genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
1172 break;
1173
1174 case OP_IPUT_CHAR:
1175 genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
1176 break;
1177
1178 case OP_IPUT_SHORT:
1179 genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
1180 break;
1181
1182 case OP_SGET:
1183 case OP_SGET_OBJECT:
1184 case OP_SGET_BOOLEAN:
1185 case OP_SGET_BYTE:
1186 case OP_SGET_CHAR:
1187 case OP_SGET_SHORT:
1188 genSget(cUnit, mir, rlResult, rlDest);
1189 break;
1190
1191 case OP_SGET_WIDE:
1192 genSgetWide(cUnit, mir, rlResult, rlDest);
1193 break;
1194
1195 case OP_SPUT:
1196 case OP_SPUT_OBJECT:
1197 case OP_SPUT_BOOLEAN:
1198 case OP_SPUT_BYTE:
1199 case OP_SPUT_CHAR:
1200 case OP_SPUT_SHORT:
1201 genSput(cUnit, mir, rlSrc[0]);
1202 break;
1203
1204 case OP_SPUT_WIDE:
1205 genSputWide(cUnit, mir, rlSrc[0]);
1206 break;
1207
1208 case OP_INVOKE_STATIC_RANGE:
1209 case OP_INVOKE_STATIC:
1210 genInvokeStatic(cUnit, mir);
1211 break;
1212
1213 case OP_INVOKE_DIRECT:
1214 case OP_INVOKE_DIRECT_RANGE:
1215 genInvokeDirect(cUnit, mir);
1216 break;
1217
1218 case OP_INVOKE_VIRTUAL:
1219 case OP_INVOKE_VIRTUAL_RANGE:
1220 genInvokeVirtual(cUnit, mir);
1221 break;
1222
1223 case OP_INVOKE_SUPER:
1224 case OP_INVOKE_SUPER_RANGE:
1225 genInvokeSuper(cUnit, mir);
1226 break;
1227
1228 case OP_INVOKE_INTERFACE:
1229 case OP_INVOKE_INTERFACE_RANGE:
1230 genInvokeInterface(cUnit, mir);
1231 break;
1232
1233 case OP_NEG_INT:
1234 case OP_NOT_INT:
1235 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1236 break;
1237
1238 case OP_NEG_LONG:
1239 case OP_NOT_LONG:
1240 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1241 break;
1242
1243 case OP_NEG_FLOAT:
1244 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1245 break;
1246
1247 case OP_NEG_DOUBLE:
1248 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1249 break;
1250
1251 case OP_INT_TO_LONG:
1252 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1253 if (rlSrc[0].location == kLocPhysReg) {
1254 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1255 } else {
1256 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1257 }
1258 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1259 rlResult.lowReg, 31);
1260 storeValueWide(cUnit, rlDest, rlResult);
1261 break;
1262
1263 case OP_LONG_TO_INT:
1264 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1265 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1266 storeValue(cUnit, rlDest, rlSrc[0]);
1267 break;
1268
1269 case OP_INT_TO_BYTE:
1270 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1271 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1272 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1273 storeValue(cUnit, rlDest, rlResult);
1274 break;
1275
1276 case OP_INT_TO_SHORT:
1277 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1278 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1279 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1280 storeValue(cUnit, rlDest, rlResult);
1281 break;
1282
1283 case OP_INT_TO_CHAR:
1284 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1285 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1286 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1287 storeValue(cUnit, rlDest, rlResult);
1288 break;
1289
1290 case OP_INT_TO_FLOAT:
1291 case OP_INT_TO_DOUBLE:
1292 case OP_LONG_TO_FLOAT:
1293 case OP_LONG_TO_DOUBLE:
1294 case OP_FLOAT_TO_INT:
1295 case OP_FLOAT_TO_LONG:
1296 case OP_FLOAT_TO_DOUBLE:
1297 case OP_DOUBLE_TO_INT:
1298 case OP_DOUBLE_TO_LONG:
1299 case OP_DOUBLE_TO_FLOAT:
1300 genConversion(cUnit, mir);
1301 break;
1302
1303 case OP_ADD_INT:
1304 case OP_SUB_INT:
1305 case OP_MUL_INT:
1306 case OP_DIV_INT:
1307 case OP_REM_INT:
1308 case OP_AND_INT:
1309 case OP_OR_INT:
1310 case OP_XOR_INT:
1311 case OP_SHL_INT:
1312 case OP_SHR_INT:
1313 case OP_USHR_INT:
1314 case OP_ADD_INT_2ADDR:
1315 case OP_SUB_INT_2ADDR:
1316 case OP_MUL_INT_2ADDR:
1317 case OP_DIV_INT_2ADDR:
1318 case OP_REM_INT_2ADDR:
1319 case OP_AND_INT_2ADDR:
1320 case OP_OR_INT_2ADDR:
1321 case OP_XOR_INT_2ADDR:
1322 case OP_SHL_INT_2ADDR:
1323 case OP_SHR_INT_2ADDR:
1324 case OP_USHR_INT_2ADDR:
1325 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1326 break;
1327
1328 case OP_ADD_LONG:
1329 case OP_SUB_LONG:
1330 case OP_MUL_LONG:
1331 case OP_DIV_LONG:
1332 case OP_REM_LONG:
1333 case OP_AND_LONG:
1334 case OP_OR_LONG:
1335 case OP_XOR_LONG:
1336 case OP_ADD_LONG_2ADDR:
1337 case OP_SUB_LONG_2ADDR:
1338 case OP_MUL_LONG_2ADDR:
1339 case OP_DIV_LONG_2ADDR:
1340 case OP_REM_LONG_2ADDR:
1341 case OP_AND_LONG_2ADDR:
1342 case OP_OR_LONG_2ADDR:
1343 case OP_XOR_LONG_2ADDR:
1344 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1345 break;
1346
1347 case OP_SHL_LONG_2ADDR:
1348 case OP_SHR_LONG_2ADDR:
1349 case OP_USHR_LONG_2ADDR:
1350 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[0]);
1351 break;
1352
1353 case OP_SHL_LONG:
1354 case OP_SHR_LONG:
1355 case OP_USHR_LONG:
1356 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1357 break;
1358
1359 case OP_ADD_FLOAT:
1360 case OP_SUB_FLOAT:
1361 case OP_MUL_FLOAT:
1362 case OP_DIV_FLOAT:
1363 case OP_REM_FLOAT:
1364 case OP_ADD_FLOAT_2ADDR:
1365 case OP_SUB_FLOAT_2ADDR:
1366 case OP_MUL_FLOAT_2ADDR:
1367 case OP_DIV_FLOAT_2ADDR:
1368 case OP_REM_FLOAT_2ADDR:
1369 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1370 break;
1371
1372 case OP_ADD_DOUBLE:
1373 case OP_SUB_DOUBLE:
1374 case OP_MUL_DOUBLE:
1375 case OP_DIV_DOUBLE:
1376 case OP_REM_DOUBLE:
1377 case OP_ADD_DOUBLE_2ADDR:
1378 case OP_SUB_DOUBLE_2ADDR:
1379 case OP_MUL_DOUBLE_2ADDR:
1380 case OP_DIV_DOUBLE_2ADDR:
1381 case OP_REM_DOUBLE_2ADDR:
1382 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1383 break;
1384
1385 case OP_RSUB_INT:
1386 case OP_ADD_INT_LIT16:
1387 case OP_MUL_INT_LIT16:
1388 case OP_DIV_INT_LIT16:
1389 case OP_REM_INT_LIT16:
1390 case OP_AND_INT_LIT16:
1391 case OP_OR_INT_LIT16:
1392 case OP_XOR_INT_LIT16:
1393 case OP_ADD_INT_LIT8:
1394 case OP_RSUB_INT_LIT8:
1395 case OP_MUL_INT_LIT8:
1396 case OP_DIV_INT_LIT8:
1397 case OP_REM_INT_LIT8:
1398 case OP_AND_INT_LIT8:
1399 case OP_OR_INT_LIT8:
1400 case OP_XOR_INT_LIT8:
1401 case OP_SHL_INT_LIT8:
1402 case OP_SHR_INT_LIT8:
1403 case OP_USHR_INT_LIT8:
1404 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1405 break;
1406
1407 default:
1408 res = true;
1409 }
1410 return res;
1411}
1412
1413static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1414 "kMirOpPhi",
1415 "kMirOpNullNRangeUpCheck",
1416 "kMirOpNullNRangeDownCheck",
1417 "kMirOpLowerBound",
1418 "kMirOpPunt",
1419 "kMirOpCheckInlinePrediction",
1420};
1421
1422/* Extended MIR instructions like PHI */
1423static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1424{
1425 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1426 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1427 strcpy(msg, extendedMIROpNames[opOffset]);
1428 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1429
1430 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1431 case kMirOpPhi: {
1432 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1433 op->flags.isNop = true;
1434 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1435 break;
1436 }
1437 default:
1438 break;
1439 }
1440}
1441
1442/* If there are any ins passed in registers that have not been promoted
1443 * to a callee-save register, flush them to the frame.
1444 * Note: at this pointCopy any ins that are passed in register to their home location */
1445static void flushIns(CompilationUnit* cUnit)
1446{
buzbeec143c552011-08-20 17:38:58 -07001447 if (cUnit->method->num_ins_ == 0)
buzbee67bf8852011-08-17 17:51:35 -07001448 return;
buzbeec143c552011-08-20 17:38:58 -07001449 int inRegs = (cUnit->method->num_ins_ > 2) ? 3 : cUnit->method->num_ins_;
buzbee67bf8852011-08-17 17:51:35 -07001450 int startReg = r1;
buzbeec143c552011-08-20 17:38:58 -07001451 int startLoc = cUnit->method->num_registers_ - cUnit->method->num_ins_;
buzbee67bf8852011-08-17 17:51:35 -07001452 for (int i = 0; i < inRegs; i++) {
1453 RegLocation loc = cUnit->regLocation[startLoc + i];
1454 if (loc.location == kLocPhysReg) {
1455 genRegCopy(cUnit, loc.lowReg, startReg + i);
1456 } else {
1457 assert(loc.location == kLocDalvikFrame);
1458 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
1459 }
1460 }
1461
1462 // Handle special case of wide argument half in regs, half in frame
1463 if (inRegs == 3) {
1464 RegLocation loc = cUnit->regLocation[startLoc + 2];
1465 if (loc.wide && loc.location == kLocPhysReg) {
1466 // Load the other half of the arg into the promoted pair
1467 loadBaseDisp(cUnit, NULL, rSP, loc.spOffset+4,
1468 loc.highReg, kWord, INVALID_SREG);
1469 inRegs++;
1470 }
1471 }
1472
1473 // Now, do initial assignment of all promoted arguments passed in frame
buzbeec143c552011-08-20 17:38:58 -07001474 for (int i = inRegs; i < cUnit->method->num_ins_;) {
buzbee67bf8852011-08-17 17:51:35 -07001475 RegLocation loc = cUnit->regLocation[startLoc + i];
1476 if (loc.fpLocation == kLocPhysReg) {
1477 loc.location = kLocPhysReg;
1478 loc.fp = true;
1479 loc.lowReg = loc.fpLowReg;
1480 loc.highReg = loc.fpHighReg;
1481 }
1482 if (loc.location == kLocPhysReg) {
1483 if (loc.wide) {
1484 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1485 loc.lowReg, loc.highReg, INVALID_SREG);
1486 i++;
1487 } else {
1488 loadBaseDisp(cUnit, NULL, rSP, loc.spOffset,
1489 loc.lowReg, kWord, INVALID_SREG);
1490 }
1491 }
1492 i++;
1493 }
1494}
1495
1496/* Handle the content in each basic block */
1497static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1498{
1499 MIR* mir;
1500 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1501 int blockId = bb->id;
1502
1503 cUnit->curBlock = bb;
1504 labelList[blockId].operands[0] = bb->startOffset;
1505
1506 /* Insert the block label */
1507 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1508 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1509
1510 oatClobberAllRegs(cUnit);
1511 oatResetNullCheck(cUnit);
1512
1513 ArmLIR* headLIR = NULL;
1514
1515 if (bb->blockType == kEntryBlock) {
1516 /*
1517 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1518 * mechanism know so it doesn't try to use any of them when
1519 * expanding the frame or flushing. This leaves the utility
1520 * code with a single temp: r12. This should be enough.
1521 */
1522 oatLockTemp(cUnit, r0);
1523 oatLockTemp(cUnit, r1);
1524 oatLockTemp(cUnit, r2);
1525 oatLockTemp(cUnit, r3);
1526 newLIR0(cUnit, kArmPseudoMethodEntry);
1527 /* Spill core callee saves */
1528 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1529 /* Need to spill any FP regs? */
1530 if (cUnit->numFPSpills) {
1531 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1532 }
1533 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1534 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1535 flushIns(cUnit);
1536 oatFreeTemp(cUnit, r0);
1537 oatFreeTemp(cUnit, r1);
1538 oatFreeTemp(cUnit, r2);
1539 oatFreeTemp(cUnit, r3);
1540 } else if (bb->blockType == kExitBlock) {
1541 newLIR0(cUnit, kArmPseudoMethodExit);
1542 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1543 /* Need to restore any FP callee saves? */
1544 if (cUnit->numFPSpills) {
1545 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1546 }
1547 if (cUnit->coreSpillMask & (1 << rLR)) {
1548 /* Unspill rLR to rPC */
1549 cUnit->coreSpillMask &= ~(1 << rLR);
1550 cUnit->coreSpillMask |= (1 << rPC);
1551 }
1552 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1553 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1554 /* We didn't pop to rPC, so must do a bv rLR */
1555 newLIR1(cUnit, kThumbBx, rLR);
1556 }
1557 }
1558
1559 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1560
1561 oatResetRegPool(cUnit);
1562 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1563 oatClobberAllRegs(cUnit);
1564 }
1565
1566 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1567 oatResetDefTracking(cUnit);
1568 }
1569
1570 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1571 handleExtendedMethodMIR(cUnit, mir);
1572 continue;
1573 }
1574
1575 cUnit->currentDalvikOffset = mir->offset;
1576
1577 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1578 InstructionFormat dalvikFormat =
1579 dexGetFormatFromOpcode(dalvikOpcode);
1580
1581 ArmLIR* boundaryLIR;
1582
1583 /* Mark the beginning of a Dalvik instruction for line tracking */
1584 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1585 (int) oatGetDalvikDisassembly(
1586 &mir->dalvikInsn, ""));
1587 /* Remember the first LIR for this block */
1588 if (headLIR == NULL) {
1589 headLIR = boundaryLIR;
1590 /* Set the first boundaryLIR as a scheduling barrier */
1591 headLIR->defMask = ENCODE_ALL;
1592 }
1593
1594 /* Don't generate the SSA annotation unless verbose mode is on */
1595 if (cUnit->printMe && mir->ssaRep) {
1596 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1597 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1598 }
1599
1600 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1601
1602 if (notHandled) {
1603 char buf[100];
1604 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1605 mir->offset,
1606 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1607 dalvikFormat);
1608 LOG(FATAL) << buf;
1609 }
1610 }
1611
1612 if (headLIR) {
1613 /*
1614 * Eliminate redundant loads/stores and delay stores into later
1615 * slots
1616 */
1617 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1618 cUnit->lastLIRInsn);
1619
1620 /*
1621 * Generate an unconditional branch to the fallthrough block.
1622 */
1623 if (bb->fallThrough) {
1624 genUnconditionalBranch(cUnit,
1625 &labelList[bb->fallThrough->id]);
1626 }
1627 }
1628 return false;
1629}
1630
1631/*
1632 * Nop any unconditional branches that go to the next instruction.
1633 * Note: new redundant branches may be inserted later, and we'll
1634 * use a check in final instruction assembly to nop those out.
1635 */
1636void removeRedundantBranches(CompilationUnit* cUnit)
1637{
1638 ArmLIR* thisLIR;
1639
1640 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1641 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1642 thisLIR = NEXT_LIR(thisLIR)) {
1643
1644 /* Branch to the next instruction */
1645 if ((thisLIR->opcode == kThumbBUncond) ||
1646 (thisLIR->opcode == kThumb2BUncond)) {
1647 ArmLIR* nextLIR = thisLIR;
1648
1649 while (true) {
1650 nextLIR = NEXT_LIR(nextLIR);
1651
1652 /*
1653 * Is the branch target the next instruction?
1654 */
1655 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1656 thisLIR->flags.isNop = true;
1657 break;
1658 }
1659
1660 /*
1661 * Found real useful stuff between the branch and the target.
1662 * Need to explicitly check the lastLIRInsn here because it
1663 * might be the last real instruction.
1664 */
1665 if (!isPseudoOpcode(nextLIR->opcode) ||
1666 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1667 break;
1668 }
1669 }
1670 }
1671}
1672
1673void oatMethodMIR2LIR(CompilationUnit* cUnit)
1674{
1675 /* Used to hold the labels of each block */
1676 cUnit->blockLabelList =
1677 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
1678
1679 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
1680 kPreOrderDFSTraversal, false /* Iterative */);
1681 removeRedundantBranches(cUnit);
1682}
1683
1684/* Common initialization routine for an architecture family */
1685bool oatArchInit()
1686{
1687 int i;
1688
1689 for (i = 0; i < kArmLast; i++) {
1690 if (EncodingMap[i].opcode != i) {
1691 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
1692 " is wrong: expecting " << i << ", seeing " <<
1693 (int)EncodingMap[i].opcode;
1694 }
1695 }
1696
1697 return oatArchVariantInit();
1698}
1699
1700/* Needed by the Assembler */
1701void oatSetupResourceMasks(ArmLIR* lir)
1702{
1703 setupResourceMasks(lir);
1704}
1705
1706/* Needed by the ld/st optmizatons */
1707ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
1708{
1709 return genRegCopyNoInsert(cUnit, rDest, rSrc);
1710}
1711
1712/* Needed by the register allocator */
1713ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1714{
1715 return genRegCopy(cUnit, rDest, rSrc);
1716}
1717
1718/* Needed by the register allocator */
1719void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
1720 int srcLo, int srcHi)
1721{
1722 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
1723}
1724
1725void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
1726 int displacement, int rSrc, OpSize size)
1727{
1728 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
1729}
1730
1731void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
1732 int displacement, int rSrcLo, int rSrcHi)
1733{
1734 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
1735}