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