blob: d0063faf9de5673c154be12e296d00595d988b1f [file] [log] [blame]
buzbee31a4a6f2012-02-28 15:36:15 -08001/*
2 * Copyright (C) 2012 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
17namespace art {
18
19/*
20 * This source files contains "gen" codegen routines that should
21 * be applicable to most targets. Only mid-level support utilities
22 * and "op" calls may be used here.
23 */
24
25#if defined(TARGET_ARM)
buzbee82488f52012-03-02 08:20:26 -080026LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide);
buzbee31a4a6f2012-02-28 15:36:15 -080027#endif
28
29LIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
30{
31 oatClobberCalleeSave(cUnit);
32 return opReg(cUnit, kOpBlx, reg);
33}
34
35/*
36 * Generate an kPseudoBarrier marker to indicate the boundary of special
37 * blocks.
38 */
39void genBarrier(CompilationUnit* cUnit)
40{
41 LIR* barrier = newLIR0(cUnit, kPseudoBarrier);
42 /* Mark all resources as being clobbered */
43 barrier->defMask = -1;
44}
45
buzbee31a4a6f2012-02-28 15:36:15 -080046
47/* Generate unconditional branch instructions */
buzbee82488f52012-03-02 08:20:26 -080048LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -080049{
50 LIR* branch = opNone(cUnit, kOpUncondBr);
51 branch->target = (LIR*) target;
52 return branch;
53}
54
buzbee5de34942012-03-01 14:51:57 -080055// FIXME: need to do some work to split out targets with
56// condition codes and those without
57#if defined(TARGET_ARM) || defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -080058LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, MIR* mir,
59 ThrowKind kind)
60{
61 LIR* tgt = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
62 tgt->opcode = kPseudoThrowTarget;
63 tgt->operands[0] = kind;
64 tgt->operands[1] = mir ? mir->offset : 0;
buzbee82488f52012-03-02 08:20:26 -080065 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080066 // Remember branch target - will process later
67 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
68 return branch;
69}
buzbee5de34942012-03-01 14:51:57 -080070#endif
buzbee31a4a6f2012-02-28 15:36:15 -080071
72LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
73 int reg, int immVal, MIR* mir, ThrowKind kind)
74{
75 LIR* tgt = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
76 tgt->opcode = kPseudoThrowTarget;
77 tgt->operands[0] = kind;
78 tgt->operands[1] = mir->offset;
79 LIR* branch;
80 if (cCode == kCondAl) {
buzbee82488f52012-03-02 08:20:26 -080081 branch = opUnconditionalBranch(cUnit, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080082 } else {
buzbee82488f52012-03-02 08:20:26 -080083 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080084 }
85 // Remember branch target - will process later
86 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
87 return branch;
88}
89
90/* Perform null-check on a register. */
91LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir)
92{
93 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
94 mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
95 return NULL;
96 }
97 return genImmedCheck(cUnit, kCondEq, mReg, 0, mir, kThrowNullPointer);
98}
99
100/* Perform check on two registers */
101LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
102 int reg1, int reg2, MIR* mir, ThrowKind kind)
103{
104 LIR* tgt = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
105 tgt->opcode = kPseudoThrowTarget;
106 tgt->operands[0] = kind;
107 tgt->operands[1] = mir ? mir->offset : 0;
108 tgt->operands[2] = reg1;
109 tgt->operands[3] = reg2;
buzbee5de34942012-03-01 14:51:57 -0800110#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800111 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800112#else
buzbee31a4a6f2012-02-28 15:36:15 -0800113 opRegReg(cUnit, kOpCmp, reg1, reg2);
buzbee82488f52012-03-02 08:20:26 -0800114 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800115#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800116 // Remember branch target - will process later
117 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
118 return branch;
119}
120
121void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
122 RegLocation rlSrc1, RegLocation rlSrc2, LIR* labelList)
123{
124 ConditionCode cond;
125 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
126 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800127 Opcode opcode = mir->dalvikInsn.opcode;
128 switch(opcode) {
129 case OP_IF_EQ:
130 cond = kCondEq;
131 break;
132 case OP_IF_NE:
133 cond = kCondNe;
134 break;
135 case OP_IF_LT:
136 cond = kCondLt;
137 break;
138 case OP_IF_GE:
139 cond = kCondGe;
140 break;
141 case OP_IF_GT:
142 cond = kCondGt;
143 break;
144 case OP_IF_LE:
145 cond = kCondLe;
146 break;
147 default:
148 cond = (ConditionCode)0;
149 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
150 }
buzbee5de34942012-03-01 14:51:57 -0800151#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800152 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg,
153 &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800154#else
155 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800156 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800157#endif
buzbee82488f52012-03-02 08:20:26 -0800158 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800159}
160
161void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
162 RegLocation rlSrc, LIR* labelList)
163{
164 ConditionCode cond;
165 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800166 Opcode opcode = mir->dalvikInsn.opcode;
167 switch(opcode) {
168 case OP_IF_EQZ:
169 cond = kCondEq;
170 break;
171 case OP_IF_NEZ:
172 cond = kCondNe;
173 break;
174 case OP_IF_LTZ:
175 cond = kCondLt;
176 break;
177 case OP_IF_GEZ:
178 cond = kCondGe;
179 break;
180 case OP_IF_GTZ:
181 cond = kCondGt;
182 break;
183 case OP_IF_LEZ:
184 cond = kCondLe;
185 break;
186 default:
187 cond = (ConditionCode)0;
188 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
189 }
buzbee5de34942012-03-01 14:51:57 -0800190#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800191 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800192#else
193 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
buzbee82488f52012-03-02 08:20:26 -0800194 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800195#endif
buzbee82488f52012-03-02 08:20:26 -0800196 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800197}
198
199void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
200 RegLocation rlSrc)
201{
202 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
203 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -0800204 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800205 } else {
206 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
207 }
208 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
209 rlResult.lowReg, 31);
210 storeValueWide(cUnit, rlDest, rlResult);
211}
212
213void genIntNarrowing(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
214 RegLocation rlSrc)
215{
216 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
217 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
218 OpKind op = kOpInvalid;
219 switch(mir->dalvikInsn.opcode) {
220 case OP_INT_TO_BYTE:
221 op = kOp2Byte;
222 break;
223 case OP_INT_TO_SHORT:
224 op = kOp2Short;
225 break;
226 case OP_INT_TO_CHAR:
227 op = kOp2Char;
228 break;
229 default:
230 LOG(ERROR) << "Bad int conversion type";
231 }
232 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
233 storeValue(cUnit, rlDest, rlResult);
234}
235
236/*
237 * Let helper function take care of everything. Will call
238 * Array::AllocFromCode(type_idx, method, count);
239 * Note: AllocFromCode will handle checks for errNegativeArraySize.
240 */
241void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
242 RegLocation rlSrc)
243{
244 oatFlushAllRegs(cUnit); /* Everything to home location */
245 uint32_t type_idx = mir->dalvikInsn.vC;
246 int rTgt;
247 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
248 cUnit->dex_cache,
249 *cUnit->dex_file,
250 type_idx)) {
251 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pAllocArrayFromCode));
252 } else {
253 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
254 pAllocArrayFromCodeWithAccessCheck));
255 }
256 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
257 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_id
258 loadValueDirectFixed(cUnit, rlSrc, rARG2); // arg2 <- count
259 callRuntimeHelper(cUnit, rTgt);
260 RegLocation rlResult = oatGetReturn(cUnit);
261 storeValue(cUnit, rlDest, rlResult);
262}
263
264/*
265 * Similar to genNewArray, but with post-allocation initialization.
266 * Verifier guarantees we're dealing with an array class. Current
267 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
268 * Current code also throws internal unimp if not 'L', '[' or 'I'.
269 */
270void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
271{
272 DecodedInstruction* dInsn = &mir->dalvikInsn;
273 int elems = dInsn->vA;
274 int typeId = dInsn->vB;
275 oatFlushAllRegs(cUnit); /* Everything to home location */
276 int rTgt;
277 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
278 cUnit->dex_cache,
279 *cUnit->dex_file,
280 typeId)) {
281 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
282 pCheckAndAllocArrayFromCode));
283 } else {
284 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
285 pCheckAndAllocArrayFromCodeWithAccessCheck));
286 }
287 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
288 loadConstant(cUnit, rARG0, typeId); // arg0 <- type_id
289 loadConstant(cUnit, rARG2, elems); // arg2 <- count
290 callRuntimeHelper(cUnit, rTgt);
291 /*
292 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
293 * return region. Because AllocFromCode placed the new array
294 * in rRET0, we'll just lock it into place. When debugger support is
295 * added, it may be necessary to additionally copy all return
296 * values to a home location in thread-local storage
297 */
298 oatLockTemp(cUnit, rRET0);
299
300 // TODO: use the correct component size, currently all supported types
301 // share array alignment with ints (see comment at head of function)
302 size_t component_size = sizeof(int32_t);
303
304 // Having a range of 0 is legal
305 if (isRange && (dInsn->vA > 0)) {
306 /*
307 * Bit of ugliness here. We're going generate a mem copy loop
308 * on the register range, but it is possible that some regs
309 * in the range have been promoted. This is unlikely, but
310 * before generating the copy, we'll just force a flush
311 * of any regs in the source range that have been promoted to
312 * home location.
313 */
314 for (unsigned int i = 0; i < dInsn->vA; i++) {
315 RegLocation loc = oatUpdateLoc(cUnit,
316 oatGetSrc(cUnit, mir, i));
317 if (loc.location == kLocPhysReg) {
318 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
319 loc.lowReg, kWord);
320 }
321 }
322 /*
323 * TUNING note: generated code here could be much improved, but
324 * this is an uncommon operation and isn't especially performance
325 * critical.
326 */
327 int rSrc = oatAllocTemp(cUnit);
328 int rDst = oatAllocTemp(cUnit);
329 int rIdx = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800330#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800331 int rVal = rLR; // Using a lot of temps, rLR is known free here
buzbee5de34942012-03-01 14:51:57 -0800332#else
333 int rVal = oatAllocTemp(cUnit);
334#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800335 // Set up source pointer
336 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
337 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
338 oatSRegOffset(cUnit, rlFirst.sRegLow));
339 // Set up the target pointer
340 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
341 Array::DataOffset(component_size).Int32Value());
342 // Set up the loop counter (known to be > 0)
343 loadConstant(cUnit, rIdx, dInsn->vA - 1);
344 // Generate the copy loop. Going backwards for convenience
345 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800346 // Copy next element
347 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
348 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
349#if defined(TARGET_ARM)
350 // Combine sub & test using sub setflags encoding here
351 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800352 opCondBranch(cUnit, kCondGe, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800353#else
buzbee5de34942012-03-01 14:51:57 -0800354 oatFreeTemp(cUnit, rVal);
buzbee31a4a6f2012-02-28 15:36:15 -0800355 opRegImm(cUnit, kOpSub, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800356 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800357#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800358 } else if (!isRange) {
359 // TUNING: interleave
360 for (unsigned int i = 0; i < dInsn->vA; i++) {
361 RegLocation rlArg = loadValue(cUnit,
362 oatGetSrc(cUnit, mir, i), kCoreReg);
363 storeBaseDisp(cUnit, rRET0,
364 Array::DataOffset(component_size).Int32Value() +
365 i * 4, rlArg.lowReg, kWord);
366 // If the loadValue caused a temp to be allocated, free it
367 if (oatIsTemp(cUnit, rlArg.lowReg)) {
368 oatFreeTemp(cUnit, rlArg.lowReg);
369 }
370 }
371 }
372}
373
374void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
375 bool isLongOrDouble, bool isObject)
376{
377 int fieldOffset;
378 int ssbIndex;
379 bool isVolatile;
380 bool isReferrersClass;
381 uint32_t fieldIdx = mir->dalvikInsn.vB;
382
383 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
384 *cUnit->dex_file, *cUnit->dex_cache,
385 cUnit->code_item, cUnit->method_idx,
386 cUnit->access_flags);
387
388 bool fastPath =
389 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
390 fieldOffset, ssbIndex,
391 isReferrersClass, isVolatile, true);
392 if (fastPath && !SLOW_FIELD_PATH) {
393 DCHECK_GE(fieldOffset, 0);
394 int rBase;
395 int rMethod;
396 if (isReferrersClass) {
397 // Fast path, static storage base is this method's class
398 rMethod = loadCurrMethod(cUnit);
399 rBase = oatAllocTemp(cUnit);
400 loadWordDisp(cUnit, rMethod,
401 Method::DeclaringClassOffset().Int32Value(), rBase);
402 } else {
403 // Medium path, static storage base in a different class which
404 // requires checks that the other class is initialized.
405 DCHECK_GE(ssbIndex, 0);
406 // May do runtime call so everything to home locations.
407 oatFlushAllRegs(cUnit);
408 // Using fixed register to sync with possible call to runtime
409 // support.
410 rMethod = rARG1;
411 oatLockTemp(cUnit, rMethod);
412 loadCurrMethodDirect(cUnit, rMethod);
413 rBase = rARG0;
414 oatLockTemp(cUnit, rBase);
415 loadWordDisp(cUnit, rMethod,
416 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
417 rBase);
418 loadWordDisp(cUnit, rBase,
419 Array::DataOffset(sizeof(Object*)).Int32Value() + sizeof(int32_t*) *
420 ssbIndex, rBase);
421 // rBase now points at appropriate static storage base (Class*)
422 // or NULL if not initialized. Check for NULL and call helper if NULL.
423 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800424 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800425 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
426 pInitializeStaticStorage));
427 loadConstant(cUnit, rARG0, ssbIndex);
428 callRuntimeHelper(cUnit, rTgt);
429#if defined(TARGET_MIPS)
430 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800431 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800432#endif
433 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800434 branchOver->target = (LIR*)skipTarget;
435 }
436 // rBase now holds static storage base
437 oatFreeTemp(cUnit, rMethod);
438 if (isLongOrDouble) {
439 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
440 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
441 } else {
442 rlSrc = oatGetSrc(cUnit, mir, 0);
443 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
444 }
445//FIXME: need to generalize the barrier call
446 if (isVolatile) {
447 oatGenMemBarrier(cUnit, kST);
448 }
449 if (isLongOrDouble) {
450 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
451 rlSrc.highReg);
452 } else {
453 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
454 }
455 if (isVolatile) {
456 oatGenMemBarrier(cUnit, kSY);
457 }
458 if (isObject) {
459 markGCCard(cUnit, rlSrc.lowReg, rBase);
460 }
461 oatFreeTemp(cUnit, rBase);
462 } else {
463 oatFlushAllRegs(cUnit); // Everything to home locations
464 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
465 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
466 : OFFSETOF_MEMBER(Thread, pSet32Static));
467 int rTgt = loadHelper(cUnit, setterOffset);
468 loadConstant(cUnit, rARG0, fieldIdx);
469 if (isLongOrDouble) {
470 loadValueDirectWideFixed(cUnit, rlSrc, rARG2, rARG3);
471 } else {
472 loadValueDirect(cUnit, rlSrc, rARG1);
473 }
474 callRuntimeHelper(cUnit, rTgt);
475 }
476}
477
478void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
479 bool isLongOrDouble, bool isObject)
480{
481 int fieldOffset;
482 int ssbIndex;
483 bool isVolatile;
484 bool isReferrersClass;
485 uint32_t fieldIdx = mir->dalvikInsn.vB;
486
487 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
488 *cUnit->dex_file, *cUnit->dex_cache,
489 cUnit->code_item, cUnit->method_idx,
490 cUnit->access_flags);
491
492 bool fastPath =
493 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
494 fieldOffset, ssbIndex,
495 isReferrersClass, isVolatile,
496 false);
497 if (fastPath && !SLOW_FIELD_PATH) {
498 DCHECK_GE(fieldOffset, 0);
499 int rBase;
500 int rMethod;
501 if (isReferrersClass) {
502 // Fast path, static storage base is this method's class
503 rMethod = loadCurrMethod(cUnit);
504 rBase = oatAllocTemp(cUnit);
505 loadWordDisp(cUnit, rMethod,
506 Method::DeclaringClassOffset().Int32Value(), rBase);
507 } else {
508 // Medium path, static storage base in a different class which
509 // requires checks that the other class is initialized
510 DCHECK_GE(ssbIndex, 0);
511 // May do runtime call so everything to home locations.
512 oatFlushAllRegs(cUnit);
513 // Using fixed register to sync with possible call to runtime
514 // support
515 rMethod = rARG1;
516 oatLockTemp(cUnit, rMethod);
517 loadCurrMethodDirect(cUnit, rMethod);
518 rBase = rARG0;
519 oatLockTemp(cUnit, rBase);
520 loadWordDisp(cUnit, rMethod,
521 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
522 rBase);
523 loadWordDisp(cUnit, rBase,
524 Array::DataOffset(sizeof(Object*)).Int32Value() +
525 sizeof(int32_t*) * ssbIndex,
526 rBase);
527 // rBase now points at appropriate static storage base (Class*)
528 // or NULL if not initialized. Check for NULL and call helper if NULL.
529 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800530 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800531 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
532 pInitializeStaticStorage));
533 loadConstant(cUnit, rARG0, ssbIndex);
534 callRuntimeHelper(cUnit, rTgt);
535#if defined(TARGET_MIPS)
536 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800537 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800538#endif
539 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800540 branchOver->target = (LIR*)skipTarget;
541 }
542 // rBase now holds static storage base
543 oatFreeTemp(cUnit, rMethod);
544 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
545 : oatGetDest(cUnit, mir, 0);
546 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
547 if (isVolatile) {
548 oatGenMemBarrier(cUnit, kSY);
549 }
550 if (isLongOrDouble) {
551 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
552 rlResult.highReg, INVALID_SREG);
553 } else {
554 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
555 }
556 oatFreeTemp(cUnit, rBase);
557 if (isLongOrDouble) {
558 storeValueWide(cUnit, rlDest, rlResult);
559 } else {
560 storeValue(cUnit, rlDest, rlResult);
561 }
562 } else {
563 oatFlushAllRegs(cUnit); // Everything to home locations
564 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
565 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
566 : OFFSETOF_MEMBER(Thread, pGet32Static));
567 int rTgt = loadHelper(cUnit, getterOffset);
568 loadConstant(cUnit, rARG0, fieldIdx);
569 callRuntimeHelper(cUnit, rTgt);
570 if (isLongOrDouble) {
571 RegLocation rlResult = oatGetReturnWide(cUnit);
572 storeValueWide(cUnit, rlDest, rlResult);
573 } else {
574 RegLocation rlResult = oatGetReturn(cUnit);
575 storeValue(cUnit, rlDest, rlResult);
576 }
577 }
578}
579
580
581// Debugging routine - if null target, branch to DebugMe
582void genShowTarget(CompilationUnit* cUnit)
583{
buzbee0398c422012-03-02 15:22:47 -0800584 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800585 loadWordDisp(cUnit, rSELF,
buzbee0398c422012-03-02 15:22:47 -0800586 OFFSETOF_MEMBER(Thread, pDebugMe), rINVOKE_TGT);
buzbee31a4a6f2012-02-28 15:36:15 -0800587 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800588 branchOver->target = (LIR*)target;
589}
590
591void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
592{
593 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
594 pThrowVerificationErrorFromCode));
595 loadConstant(cUnit, rARG0, mir->dalvikInsn.vA);
596 loadConstant(cUnit, rARG1, mir->dalvikInsn.vB);
597 callRuntimeHelper(cUnit, rTgt);
598}
599
600void handleSuspendLaunchpads(CompilationUnit *cUnit)
601{
602 LIR** suspendLabel =
603 (LIR **) cUnit->suspendLaunchpads.elemList;
604 int numElems = cUnit->suspendLaunchpads.numUsed;
605
606 for (int i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800607 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800608 /* TUNING: move suspend count load into helper */
609 LIR* lab = suspendLabel[i];
610 LIR* resumeLab = (LIR*)lab->operands[0];
611 cUnit->currentDalvikOffset = lab->operands[1];
612 oatAppendLIR(cUnit, (LIR *)lab);
613 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
614 pTestSuspendFromCode));
615 if (!cUnit->genDebugger) {
616 // use rSUSPEND for suspend count
617 loadWordDisp(cUnit, rSELF,
618 Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
619 }
620 opReg(cUnit, kOpBlx, rTgt);
621 if ( cUnit->genDebugger) {
622 // use rSUSPEND for update debugger
623 loadWordDisp(cUnit, rSELF,
624 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
625 rSUSPEND);
626 }
buzbee82488f52012-03-02 08:20:26 -0800627 opUnconditionalBranch(cUnit, resumeLab);
buzbee31a4a6f2012-02-28 15:36:15 -0800628 }
629}
630
631void handleThrowLaunchpads(CompilationUnit *cUnit)
632{
633 LIR** throwLabel = (LIR **) cUnit->throwLaunchpads.elemList;
634 int numElems = cUnit->throwLaunchpads.numUsed;
635 int i;
636
637 for (i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800638 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800639 LIR* lab = throwLabel[i];
640 cUnit->currentDalvikOffset = lab->operands[1];
641 oatAppendLIR(cUnit, (LIR *)lab);
642 int funcOffset = 0;
643 int v1 = lab->operands[2];
644 int v2 = lab->operands[3];
645 switch(lab->operands[0]) {
646 case kThrowNullPointer:
647 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
648 break;
649 case kThrowArrayBounds:
buzbee5de34942012-03-01 14:51:57 -0800650 if (v2 != rARG0) {
buzbee82488f52012-03-02 08:20:26 -0800651 opRegCopy(cUnit, rARG0, v1);
652 opRegCopy(cUnit, rARG1, v2);
buzbee31a4a6f2012-02-28 15:36:15 -0800653 } else {
buzbee5de34942012-03-01 14:51:57 -0800654 if (v1 == rARG1) {
buzbee31a4a6f2012-02-28 15:36:15 -0800655#if defined(TARGET_ARM)
656 int rTmp = r12;
657#else
658 int rTmp = oatAllocTemp(cUnit);
659#endif
buzbee82488f52012-03-02 08:20:26 -0800660 opRegCopy(cUnit, rTmp, v1);
661 opRegCopy(cUnit, rARG1, v2);
662 opRegCopy(cUnit, rARG0, rTmp);
buzbee31a4a6f2012-02-28 15:36:15 -0800663 } else {
buzbee82488f52012-03-02 08:20:26 -0800664 opRegCopy(cUnit, rARG1, v2);
665 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800666 }
667 }
668 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
669 break;
670 case kThrowDivZero:
671 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
672 break;
673 case kThrowVerificationError:
674 loadConstant(cUnit, rARG0, v1);
675 loadConstant(cUnit, rARG1, v2);
676 funcOffset =
677 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
678 break;
679 case kThrowNegArraySize:
buzbee82488f52012-03-02 08:20:26 -0800680 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800681 funcOffset =
682 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
683 break;
684 case kThrowNoSuchMethod:
buzbee82488f52012-03-02 08:20:26 -0800685 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800686 funcOffset =
687 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
688 break;
689 case kThrowStackOverflow:
690 funcOffset =
691 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
692 // Restore stack alignment
693 opRegImm(cUnit, kOpAdd, rSP,
694 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
695 break;
696 default:
697 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
698 }
699 int rTgt = loadHelper(cUnit, funcOffset);
700 callRuntimeHelper(cUnit, rTgt);
buzbee0398c422012-03-02 15:22:47 -0800701 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800702 }
703}
704
705/* Needed by the Assembler */
706void oatSetupResourceMasks(LIR* lir)
707{
708 setupResourceMasks(lir);
709}
710
711void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
712 RegLocation rlDest, RegLocation rlObj,
713 bool isLongOrDouble, bool isObject)
714{
715 int fieldOffset;
716 bool isVolatile;
717 uint32_t fieldIdx = mir->dalvikInsn.vC;
718
719 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
720 *cUnit->dex_file, *cUnit->dex_cache,
721 cUnit->code_item, cUnit->method_idx,
722 cUnit->access_flags);
723
724 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
725 fieldOffset, isVolatile, false);
726
727 if (fastPath && !SLOW_FIELD_PATH) {
728 RegLocation rlResult;
729 RegisterClass regClass = oatRegClassBySize(size);
730 DCHECK_GE(fieldOffset, 0);
731 rlObj = loadValue(cUnit, rlObj, kCoreReg);
732 if (isLongOrDouble) {
733 DCHECK(rlDest.wide);
734 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
735 int regPtr = oatAllocTemp(cUnit);
736 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
737 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
738 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
739 if (isVolatile) {
740 oatGenMemBarrier(cUnit, kSY);
741 }
742 oatFreeTemp(cUnit, regPtr);
743 storeValueWide(cUnit, rlDest, rlResult);
744 } else {
745 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
746 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
747 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
748 kWord, rlObj.sRegLow);
749 if (isVolatile) {
750 oatGenMemBarrier(cUnit, kSY);
751 }
752 storeValue(cUnit, rlDest, rlResult);
753 }
754 } else {
755 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
756 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
757 : OFFSETOF_MEMBER(Thread, pGet32Instance));
758 int rTgt = loadHelper(cUnit, getterOffset);
759 loadValueDirect(cUnit, rlObj, rARG1);
760 loadConstant(cUnit, rARG0, fieldIdx);
761 callRuntimeHelper(cUnit, rTgt);
762 if (isLongOrDouble) {
763 RegLocation rlResult = oatGetReturnWide(cUnit);
764 storeValueWide(cUnit, rlDest, rlResult);
765 } else {
766 RegLocation rlResult = oatGetReturn(cUnit);
767 storeValue(cUnit, rlDest, rlResult);
768 }
769 }
770}
771
772void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, RegLocation rlSrc,
773 RegLocation rlObj, bool isLongOrDouble, bool isObject)
774{
775 int fieldOffset;
776 bool isVolatile;
777 uint32_t fieldIdx = mir->dalvikInsn.vC;
778
779 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
780 *cUnit->dex_file, *cUnit->dex_cache,
781 cUnit->code_item, cUnit->method_idx,
782 cUnit->access_flags);
783
784 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
785 fieldOffset, isVolatile, true);
786 if (fastPath && !SLOW_FIELD_PATH) {
787 RegisterClass regClass = oatRegClassBySize(size);
788 DCHECK_GE(fieldOffset, 0);
789 rlObj = loadValue(cUnit, rlObj, kCoreReg);
790 if (isLongOrDouble) {
791 int regPtr;
792 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
793 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
794 regPtr = oatAllocTemp(cUnit);
795 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
796 if (isVolatile) {
797 oatGenMemBarrier(cUnit, kST);
798 }
799 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
800 if (isVolatile) {
801 oatGenMemBarrier(cUnit, kSY);
802 }
803 oatFreeTemp(cUnit, regPtr);
804 } else {
805 rlSrc = loadValue(cUnit, rlSrc, regClass);
806 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
807 if (isVolatile) {
808 oatGenMemBarrier(cUnit, kST);
809 }
810 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
811 if (isVolatile) {
812 oatGenMemBarrier(cUnit, kSY);
813 }
814 }
815 } else {
816 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
817 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
818 : OFFSETOF_MEMBER(Thread, pSet32Instance));
819 int rTgt = loadHelper(cUnit, setterOffset);
820 loadValueDirect(cUnit, rlObj, rARG1);
821 if (isLongOrDouble) {
822 loadValueDirectWide(cUnit, rlSrc, rARG2, rARG3);
823 } else {
824 loadValueDirect(cUnit, rlSrc, rARG2);
825 }
826 loadConstant(cUnit, rARG0, fieldIdx);
827 callRuntimeHelper(cUnit, rTgt);
828 }
829}
830
831void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
832 RegLocation rlSrc)
833{
834 uint32_t type_idx = mir->dalvikInsn.vB;
835 int mReg = loadCurrMethod(cUnit);
836 int resReg = oatAllocTemp(cUnit);
837 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
838 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
839 cUnit->dex_cache,
840 *cUnit->dex_file,
841 type_idx)) {
842 // Call out to helper which resolves type and verifies access.
843 // Resolved type returned in rRET0.
844 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
845 pInitializeTypeAndVerifyAccessFromCode));
buzbee82488f52012-03-02 08:20:26 -0800846 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800847 loadConstant(cUnit, rARG0, type_idx);
848 callRuntimeHelper(cUnit, rTgt);
849 RegLocation rlResult = oatGetReturn(cUnit);
850 storeValue(cUnit, rlDest, rlResult);
851 } else {
852 // We're don't need access checks, load type from dex cache
853 int32_t dex_cache_offset =
854 Method::DexCacheResolvedTypesOffset().Int32Value();
855 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
856 int32_t offset_of_type =
857 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
858 * type_idx);
859 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
860 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
861 type_idx) || SLOW_TYPE_PATH) {
862 // Slow path, at runtime test if type is null and if so initialize
863 oatFlushAllRegs(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800864 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0,
865 NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800866 // Resolved, store and hop over following code
867 storeValue(cUnit, rlDest, rlResult);
buzbee82488f52012-03-02 08:20:26 -0800868 LIR* branch2 = opUnconditionalBranch(cUnit,0);
buzbee31a4a6f2012-02-28 15:36:15 -0800869 // TUNING: move slow path to end & remove unconditional branch
870 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800871 // Call out to helper, which will return resolved type in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800872 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
873 pInitializeTypeFromCode));
buzbee82488f52012-03-02 08:20:26 -0800874 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800875 loadConstant(cUnit, rARG0, type_idx);
876 callRuntimeHelper(cUnit, rTgt);
877 RegLocation rlResult = oatGetReturn(cUnit);
878 storeValue(cUnit, rlDest, rlResult);
879 // Rejoin code paths
880 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800881 branch1->target = (LIR*)target1;
882 branch2->target = (LIR*)target2;
883 } else {
884 // Fast path, we're done - just store result
885 storeValue(cUnit, rlDest, rlResult);
886 }
887 }
888}
889void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
890 RegLocation rlSrc)
891{
892 /* NOTE: Most strings should be available at compile time */
893 uint32_t string_idx = mir->dalvikInsn.vB;
894 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
895 (sizeof(String*) * string_idx);
896 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
897 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
898 // slow path, resolve string if not in dex cache
899 oatFlushAllRegs(cUnit);
900 oatLockCallTemps(cUnit); // Using explicit registers
901 loadCurrMethodDirect(cUnit, rARG2);
902 loadWordDisp(cUnit, rARG2,
903 Method::DexCacheStringsOffset().Int32Value(), rARG0);
904 // Might call out to helper, which will return resolved string in rRET0
905 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
906 pResolveStringFromCode));
907 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
908 loadConstant(cUnit, rARG1, string_idx);
909#if defined(TARGET_ARM)
910 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
911 genBarrier(cUnit);
912 // For testing, always force through helper
913 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee82488f52012-03-02 08:20:26 -0800914 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -0800915 }
buzbee82488f52012-03-02 08:20:26 -0800916 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800917 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
918#else
buzbee82488f52012-03-02 08:20:26 -0800919 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
920 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800921 opReg(cUnit, kOpBlx, rTgt);
922 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800923 branch->target = target;
924#endif
925 genBarrier(cUnit);
926 storeValue(cUnit, rlDest, getRetLoc(cUnit));
927 } else {
928 int mReg = loadCurrMethod(cUnit);
929 int resReg = oatAllocTemp(cUnit);
930 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
931 loadWordDisp(cUnit, mReg,
932 Method::DexCacheStringsOffset().Int32Value(), resReg);
933 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
934 storeValue(cUnit, rlDest, rlResult);
935 }
936}
937
938/*
939 * Let helper function take care of everything. Will
940 * call Class::NewInstanceFromCode(type_idx, method);
941 */
942void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
943{
944 oatFlushAllRegs(cUnit); /* Everything to home location */
945 uint32_t type_idx = mir->dalvikInsn.vB;
946 // alloc will always check for resolution, do we also need to verify
947 // access because the verifier was unable to?
948 int rTgt;
949 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
950 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
951 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode));
952 } else {
953 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
954 pAllocObjectFromCodeWithAccessCheck));
955 }
956 loadCurrMethodDirect(cUnit, rARG1); // arg1 <= Method*
957 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_idx
958 callRuntimeHelper(cUnit, rTgt);
959 RegLocation rlResult = oatGetReturn(cUnit);
960 storeValue(cUnit, rlDest, rlResult);
961}
962
963void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
964 RegLocation rlSrc)
965{
966 oatFlushAllRegs(cUnit);
967 // May generate a call - use explicit registers
968 oatLockCallTemps(cUnit);
969 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee5de34942012-03-01 14:51:57 -0800970 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
buzbee31a4a6f2012-02-28 15:36:15 -0800971 int classReg = rARG2; // rARG2 will hold the Class*
972 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
973 cUnit->dex_cache,
974 *cUnit->dex_file,
975 type_idx)) {
976 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbee5de34942012-03-01 14:51:57 -0800977 // returns Class* in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800978 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
979 pInitializeTypeAndVerifyAccessFromCode));
980 loadConstant(cUnit, rARG0, type_idx);
981 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -0800982 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee5de34942012-03-01 14:51:57 -0800983 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
buzbee31a4a6f2012-02-28 15:36:15 -0800984 } else {
buzbee5de34942012-03-01 14:51:57 -0800985 // Load dex cache entry into classReg (rARG2)
buzbee31a4a6f2012-02-28 15:36:15 -0800986 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
987 loadWordDisp(cUnit, rARG1,
988 Method::DexCacheResolvedTypesOffset().Int32Value(),
989 classReg);
990 int32_t offset_of_type =
991 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
992 * type_idx);
993 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
994 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
995 cUnit->dex_cache, type_idx)) {
996 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -0800997 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800998 // Not resolved
999 // Call out to helper, which will return resolved type in rRET0
1000 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1001 pInitializeTypeFromCode));
1002 loadConstant(cUnit, rARG0, type_idx);
1003 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001004 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001005 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1006 // Rejoin code paths
1007 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001008 hopBranch->target = (LIR*)hopTarget;
1009 }
1010 }
1011 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
buzbee82488f52012-03-02 08:20:26 -08001012 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001013 /* load object->clazz */
1014 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1015 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1016 /* rARG0 is ref, rARG1 is ref->clazz, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001017#if defined(TARGET_ARM)
1018 /* Uses conditional nullification */
buzbee31a4a6f2012-02-28 15:36:15 -08001019 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1020 pInstanceofNonTrivialFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001021 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
buzbee82488f52012-03-02 08:20:26 -08001022 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
buzbee31a4a6f2012-02-28 15:36:15 -08001023 loadConstant(cUnit, rARG0, 1); // .eq case - load true
buzbee82488f52012-03-02 08:20:26 -08001024 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee31a4a6f2012-02-28 15:36:15 -08001025 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001026#else
buzbee0398c422012-03-02 15:22:47 -08001027 /* Uses branchovers */
1028 loadConstant(cUnit, rARG0, 1); // assume true
1029 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
1030 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1031 pInstanceofNonTrivialFromCode));
1032 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1033 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001034#endif
buzbee0398c422012-03-02 15:22:47 -08001035 oatClobberCalleeSave(cUnit);
1036 /* branch targets here */
buzbee31a4a6f2012-02-28 15:36:15 -08001037 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001038 RegLocation rlResult = oatGetReturn(cUnit);
1039 storeValue(cUnit, rlDest, rlResult);
buzbee0398c422012-03-02 15:22:47 -08001040 branch1->target = target;
1041#if !defined(TARGET_ARM)
1042 branchover->target = target;
1043#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001044}
1045
1046void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1047{
1048 oatFlushAllRegs(cUnit);
1049 // May generate a call - use explicit registers
1050 oatLockCallTemps(cUnit);
1051 uint32_t type_idx = mir->dalvikInsn.vB;
1052 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1053 int classReg = rARG2; // rARG2 will hold the Class*
1054 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1055 cUnit->dex_cache,
1056 *cUnit->dex_file,
1057 type_idx)) {
1058 // Check we have access to type_idx and if not throw IllegalAccessError,
1059 // returns Class* in rRET0
1060 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1061 pInitializeTypeAndVerifyAccessFromCode));
1062 loadConstant(cUnit, rARG0, type_idx);
1063 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001064 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001065 } else {
1066 // Load dex cache entry into classReg (rARG2)
1067 loadWordDisp(cUnit, rARG1,
1068 Method::DexCacheResolvedTypesOffset().Int32Value(),
1069 classReg);
1070 int32_t offset_of_type =
1071 Array::DataOffset(sizeof(Class*)).Int32Value() +
1072 (sizeof(Class*) * type_idx);
1073 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1074 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1075 cUnit->dex_cache, type_idx)) {
1076 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001077 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001078 // Not resolved
buzbee5de34942012-03-01 14:51:57 -08001079 // Call out to helper, which will return resolved type in rARG0
1080 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode));
1081 loadConstant(cUnit, rARG0, type_idx);
1082 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001083 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001084 // Rejoin code paths
1085 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001086 hopBranch->target = (LIR*)hopTarget;
1087 }
1088 }
buzbee5de34942012-03-01 14:51:57 -08001089 // At this point, classReg (rARG2) has class
buzbee31a4a6f2012-02-28 15:36:15 -08001090 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1091 /* Null is OK - continue */
buzbee82488f52012-03-02 08:20:26 -08001092 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001093 /* load object->clazz */
1094 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1095 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1096 /* rARG1 now contains object->clazz */
1097 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1098 pCheckCastFromCode));
buzbee5de34942012-03-01 14:51:57 -08001099#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -08001100 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
buzbee5de34942012-03-01 14:51:57 -08001101#else
buzbee31a4a6f2012-02-28 15:36:15 -08001102 opRegReg(cUnit, kOpCmp, rARG1, classReg);
buzbee82488f52012-03-02 08:20:26 -08001103 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
buzbee5de34942012-03-01 14:51:57 -08001104#endif
buzbee82488f52012-03-02 08:20:26 -08001105 opRegCopy(cUnit, rARG0, rARG1);
1106 opRegCopy(cUnit, rARG1, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08001107 callRuntimeHelper(cUnit, rTgt);
1108 /* branch target here */
1109 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001110 branch1->target = (LIR*)target;
1111 branch2->target = (LIR*)target;
1112}
1113
1114
1115void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1116{
1117 oatFlushAllRegs(cUnit);
1118 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException));
1119 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get exception object
1120 callRuntimeHelper(cUnit, rTgt); // art_deliver_exception(exception);
1121}
1122
1123/*
1124 * Generate array store
1125 *
1126 */
1127void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
1128 RegLocation rlIndex, RegLocation rlSrc, int scale)
1129{
1130 RegisterClass regClass = oatRegClassBySize(kWord);
1131 int lenOffset = Array::LengthOffset().Int32Value();
1132 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
1133
1134 oatFlushAllRegs(cUnit);
1135 /* Make sure it's a legal object Put. Use direct regs at first */
1136 loadValueDirectFixed(cUnit, rlArray, rARG1);
1137 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1138
1139 /* null array object? */
1140 genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
1141 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1142 pCanPutArrayElementFromCode));
1143 /* Get the array's clazz */
1144 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
1145 callRuntimeHelper(cUnit, rTgt);
1146 oatFreeTemp(cUnit, rARG0);
1147 oatFreeTemp(cUnit, rARG1);
1148
1149 // Now, redo loadValues in case they didn't survive the call
1150
1151 int regPtr;
1152 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1153 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1154
1155 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1156 oatClobber(cUnit, rlArray.lowReg);
1157 regPtr = rlArray.lowReg;
1158 } else {
1159 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001160 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001161 }
1162
1163 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1164 int regLen = oatAllocTemp(cUnit);
1165 //NOTE: max live temps(4) here.
1166 /* Get len */
1167 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1168 /* regPtr -> array data */
1169 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1170 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1171 kThrowArrayBounds);
1172 oatFreeTemp(cUnit, regLen);
1173 } else {
1174 /* regPtr -> array data */
1175 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1176 }
1177 /* at this point, regPtr points to array, 2 live temps */
1178 rlSrc = loadValue(cUnit, rlSrc, regClass);
1179 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1180 scale, kWord);
1181}
1182
1183/*
1184 * Generate array load
1185 */
1186void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1187 RegLocation rlArray, RegLocation rlIndex,
1188 RegLocation rlDest, int scale)
1189{
1190 RegisterClass regClass = oatRegClassBySize(size);
1191 int lenOffset = Array::LengthOffset().Int32Value();
1192 int dataOffset;
1193 RegLocation rlResult;
1194 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1195 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1196 int regPtr;
1197
1198 if (size == kLong || size == kDouble) {
1199 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1200 } else {
1201 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1202 }
1203
1204 /* null object? */
1205 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1206
1207 regPtr = oatAllocTemp(cUnit);
1208
1209 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1210 int regLen = oatAllocTemp(cUnit);
1211 /* Get len */
1212 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1213 /* regPtr -> array data */
1214 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1215 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1216 kThrowArrayBounds);
1217 oatFreeTemp(cUnit, regLen);
1218 } else {
1219 /* regPtr -> array data */
1220 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1221 }
1222 oatFreeTemp(cUnit, rlArray.lowReg);
1223 if ((size == kLong) || (size == kDouble)) {
1224 if (scale) {
1225 int rNewIndex = oatAllocTemp(cUnit);
1226 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1227 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1228 oatFreeTemp(cUnit, rNewIndex);
1229 } else {
1230 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1231 }
1232 oatFreeTemp(cUnit, rlIndex.lowReg);
1233 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1234
1235 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1236
1237 oatFreeTemp(cUnit, regPtr);
1238 storeValueWide(cUnit, rlDest, rlResult);
1239 } else {
1240 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1241
1242 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1243 scale, size);
1244
1245 oatFreeTemp(cUnit, regPtr);
1246 storeValue(cUnit, rlDest, rlResult);
1247 }
1248}
1249
1250/*
1251 * Generate array store
1252 *
1253 */
1254void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1255 RegLocation rlArray, RegLocation rlIndex,
1256 RegLocation rlSrc, int scale)
1257{
1258 RegisterClass regClass = oatRegClassBySize(size);
1259 int lenOffset = Array::LengthOffset().Int32Value();
1260 int dataOffset;
1261
1262 if (size == kLong || size == kDouble) {
1263 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1264 } else {
1265 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1266 }
1267
1268 int regPtr;
1269 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1270 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1271
1272 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1273 oatClobber(cUnit, rlArray.lowReg);
1274 regPtr = rlArray.lowReg;
1275 } else {
1276 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001277 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001278 }
1279
1280 /* null object? */
1281 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1282
1283 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1284 int regLen = oatAllocTemp(cUnit);
1285 //NOTE: max live temps(4) here.
1286 /* Get len */
1287 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1288 /* regPtr -> array data */
1289 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1290 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1291 kThrowArrayBounds);
1292 oatFreeTemp(cUnit, regLen);
1293 } else {
1294 /* regPtr -> array data */
1295 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1296 }
1297 /* at this point, regPtr points to array, 2 live temps */
1298 if ((size == kLong) || (size == kDouble)) {
1299 //TUNING: specific wide routine that can handle fp regs
1300 if (scale) {
1301 int rNewIndex = oatAllocTemp(cUnit);
1302 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1303 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1304 oatFreeTemp(cUnit, rNewIndex);
1305 } else {
1306 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1307 }
1308 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1309
1310 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1311
1312 oatFreeTemp(cUnit, regPtr);
1313 } else {
1314 rlSrc = loadValue(cUnit, rlSrc, regClass);
1315
1316 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1317 scale, size);
1318 }
1319}
1320
1321void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1322 OpKind secondOp, RegLocation rlDest,
1323 RegLocation rlSrc1, RegLocation rlSrc2)
1324{
1325 RegLocation rlResult;
1326#if defined(TARGET_ARM)
1327 /*
1328 * NOTE: This is the one place in the code in which we might have
1329 * as many as six live temporary registers. There are 5 in the normal
1330 * set for Arm. Until we have spill capabilities, temporarily add
1331 * lr to the temp set. It is safe to do this locally, but note that
1332 * lr is used explicitly elsewhere in the code generator and cannot
1333 * normally be used as a general temp register.
1334 */
1335 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1336 oatFreeTemp(cUnit, rLR); // and make it available
1337#endif
1338 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1339 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1340 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1341 // The longs may overlap - use intermediate temp if so
1342 if (rlResult.lowReg == rlSrc1.highReg) {
1343 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001344 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001345 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1346 rlSrc2.lowReg);
1347 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1348 rlSrc2.highReg);
1349 oatFreeTemp(cUnit, tReg);
1350 } else {
1351 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1352 rlSrc2.lowReg);
1353 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1354 rlSrc2.highReg);
1355 }
1356 /*
1357 * NOTE: If rlDest refers to a frame variable in a large frame, the
1358 * following storeValueWide might need to allocate a temp register.
1359 * To further work around the lack of a spill capability, explicitly
1360 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1361 * Remove when spill is functional.
1362 */
1363 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1364 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1365 storeValueWide(cUnit, rlDest, rlResult);
1366#if defined(TARGET_ARM)
1367 oatClobber(cUnit, rLR);
1368 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1369#endif
1370}
1371
1372
1373bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1374 RegLocation rlSrc1, RegLocation rlShift)
1375{
1376 int funcOffset;
1377
1378 switch( mir->dalvikInsn.opcode) {
1379 case OP_SHL_LONG:
1380 case OP_SHL_LONG_2ADDR:
1381 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1382 break;
1383 case OP_SHR_LONG:
1384 case OP_SHR_LONG_2ADDR:
1385 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1386 break;
1387 case OP_USHR_LONG:
1388 case OP_USHR_LONG_2ADDR:
1389 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1390 break;
1391 default:
1392 LOG(FATAL) << "Unexpected case";
1393 return true;
1394 }
1395 oatFlushAllRegs(cUnit); /* Send everything to home location */
1396 int rTgt = loadHelper(cUnit, funcOffset);
1397 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1398 loadValueDirect(cUnit, rlShift, rARG2);
1399 callRuntimeHelper(cUnit, rTgt);
1400 RegLocation rlResult = oatGetReturnWide(cUnit);
1401 storeValueWide(cUnit, rlDest, rlResult);
1402 return false;
1403}
1404
1405
1406bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1407 RegLocation rlSrc1, RegLocation rlSrc2)
1408{
1409 OpKind op = kOpBkpt;
1410 bool callOut = false;
1411 bool checkZero = false;
1412 bool unary = false;
1413 int retReg = rRET0;
1414 int funcOffset;
1415 RegLocation rlResult;
1416 bool shiftOp = false;
1417
1418 switch (mir->dalvikInsn.opcode) {
1419 case OP_NEG_INT:
1420 op = kOpNeg;
1421 unary = true;
1422 break;
1423 case OP_NOT_INT:
1424 op = kOpMvn;
1425 unary = true;
1426 break;
1427 case OP_ADD_INT:
1428 case OP_ADD_INT_2ADDR:
1429 op = kOpAdd;
1430 break;
1431 case OP_SUB_INT:
1432 case OP_SUB_INT_2ADDR:
1433 op = kOpSub;
1434 break;
1435 case OP_MUL_INT:
1436 case OP_MUL_INT_2ADDR:
1437 op = kOpMul;
1438 break;
1439 case OP_DIV_INT:
1440 case OP_DIV_INT_2ADDR:
1441 callOut = true;
1442 checkZero = true;
1443 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1444 retReg = rRET0;
1445 break;
buzbee5de34942012-03-01 14:51:57 -08001446 /* NOTE: returns in rARG1 */
buzbee31a4a6f2012-02-28 15:36:15 -08001447 case OP_REM_INT:
1448 case OP_REM_INT_2ADDR:
1449 callOut = true;
1450 checkZero = true;
1451 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1452 retReg = rRET1;
1453 break;
1454 case OP_AND_INT:
1455 case OP_AND_INT_2ADDR:
1456 op = kOpAnd;
1457 break;
1458 case OP_OR_INT:
1459 case OP_OR_INT_2ADDR:
1460 op = kOpOr;
1461 break;
1462 case OP_XOR_INT:
1463 case OP_XOR_INT_2ADDR:
1464 op = kOpXor;
1465 break;
1466 case OP_SHL_INT:
1467 case OP_SHL_INT_2ADDR:
1468 shiftOp = true;
1469 op = kOpLsl;
1470 break;
1471 case OP_SHR_INT:
1472 case OP_SHR_INT_2ADDR:
1473 shiftOp = true;
1474 op = kOpAsr;
1475 break;
1476 case OP_USHR_INT:
1477 case OP_USHR_INT_2ADDR:
1478 shiftOp = true;
1479 op = kOpLsr;
1480 break;
1481 default:
1482 LOG(FATAL) << "Invalid word arith op: " <<
1483 (int)mir->dalvikInsn.opcode;
1484 }
1485 if (!callOut) {
1486 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1487 if (unary) {
1488 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1489 opRegReg(cUnit, op, rlResult.lowReg,
1490 rlSrc1.lowReg);
1491 } else {
1492 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1493 if (shiftOp) {
1494 int tReg = oatAllocTemp(cUnit);
1495 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1496 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1497 opRegRegReg(cUnit, op, rlResult.lowReg,
1498 rlSrc1.lowReg, tReg);
1499 oatFreeTemp(cUnit, tReg);
1500 } else {
1501 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1502 opRegRegReg(cUnit, op, rlResult.lowReg,
1503 rlSrc1.lowReg, rlSrc2.lowReg);
1504 }
1505 }
1506 storeValue(cUnit, rlDest, rlResult);
1507 } else {
1508 RegLocation rlResult;
1509 oatFlushAllRegs(cUnit); /* Send everything to home location */
1510 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
1511 int rTgt = loadHelper(cUnit, funcOffset);
1512 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1513 if (checkZero) {
1514 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1515 }
1516 callRuntimeHelper(cUnit, rTgt);
1517 if (retReg == rRET0)
1518 rlResult = oatGetReturn(cUnit);
1519 else
1520 rlResult = oatGetReturnAlt(cUnit);
1521 storeValue(cUnit, rlDest, rlResult);
1522 }
1523 return false;
1524}
1525
1526/*
1527 * The following are the first-level codegen routines that analyze the format
1528 * of each bytecode then either dispatch special purpose codegen routines
1529 * or produce corresponding Thumb instructions directly.
1530 */
1531
1532bool isPowerOfTwo(int x)
1533{
1534 return (x & (x - 1)) == 0;
1535}
1536
1537// Returns true if no more than two bits are set in 'x'.
1538bool isPopCountLE2(unsigned int x)
1539{
1540 x &= x - 1;
1541 return (x & (x - 1)) == 0;
1542}
1543
1544// Returns the index of the lowest set bit in 'x'.
1545int lowestSetBit(unsigned int x) {
1546 int bit_posn = 0;
1547 while ((x & 0xf) == 0) {
1548 bit_posn += 4;
1549 x >>= 4;
1550 }
1551 while ((x & 1) == 0) {
1552 bit_posn++;
1553 x >>= 1;
1554 }
1555 return bit_posn;
1556}
1557
1558// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1559// and store the result in 'rlDest'.
1560bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
1561 RegLocation rlSrc, RegLocation rlDest, int lit)
1562{
1563 if (lit < 2 || !isPowerOfTwo(lit)) {
1564 return false;
1565 }
1566 int k = lowestSetBit(lit);
1567 if (k >= 30) {
1568 // Avoid special cases.
1569 return false;
1570 }
1571 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1572 dalvikOpcode == OP_DIV_INT_LIT16);
1573 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1574 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1575 if (div) {
1576 int tReg = oatAllocTemp(cUnit);
1577 if (lit == 2) {
1578 // Division by 2 is by far the most common division by constant.
1579 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1580 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1581 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1582 } else {
1583 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1584 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1585 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1586 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1587 }
1588 } else {
1589 int cReg = oatAllocTemp(cUnit);
1590 loadConstant(cUnit, cReg, lit - 1);
1591 int tReg1 = oatAllocTemp(cUnit);
1592 int tReg2 = oatAllocTemp(cUnit);
1593 if (lit == 2) {
1594 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1595 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1596 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1597 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1598 } else {
1599 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1600 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1601 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1602 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1603 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1604 }
1605 }
1606 storeValue(cUnit, rlDest, rlResult);
1607 return true;
1608}
1609
1610void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1611 RegLocation rlResult, int lit,
1612 int firstBit, int secondBit)
1613{
buzbee0398c422012-03-02 15:22:47 -08001614#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001615 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1616 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001617#else
1618 int tReg = oatAllocTemp(cUnit);
1619 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1620 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1621 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001622#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001623 if (firstBit != 0) {
1624 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1625 }
1626}
1627
1628// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1629// and store the result in 'rlDest'.
1630bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1631 RegLocation rlDest, int lit)
1632{
1633 // Can we simplify this multiplication?
1634 bool powerOfTwo = false;
1635 bool popCountLE2 = false;
1636 bool powerOfTwoMinusOne = false;
1637 if (lit < 2) {
1638 // Avoid special cases.
1639 return false;
1640 } else if (isPowerOfTwo(lit)) {
1641 powerOfTwo = true;
1642 } else if (isPopCountLE2(lit)) {
1643 popCountLE2 = true;
1644 } else if (isPowerOfTwo(lit + 1)) {
1645 powerOfTwoMinusOne = true;
1646 } else {
1647 return false;
1648 }
1649 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1650 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1651 if (powerOfTwo) {
1652 // Shift.
1653 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1654 lowestSetBit(lit));
1655 } else if (popCountLE2) {
1656 // Shift and add and shift.
1657 int firstBit = lowestSetBit(lit);
1658 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1659 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1660 firstBit, secondBit);
1661 } else {
1662 // Reverse subtract: (src << (shift + 1)) - src.
1663 DCHECK(powerOfTwoMinusOne);
1664 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1665 int tReg = oatAllocTemp(cUnit);
1666 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1667 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1668 }
1669 storeValue(cUnit, rlDest, rlResult);
1670 return true;
1671}
1672
1673bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1674 RegLocation rlSrc, int lit)
1675{
1676 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1677 RegLocation rlResult;
1678 OpKind op = (OpKind)0; /* Make gcc happy */
1679 int shiftOp = false;
1680 bool isDiv = false;
1681 int funcOffset;
1682 int rTgt;
1683
1684 switch (dalvikOpcode) {
1685 case OP_RSUB_INT_LIT8:
1686 case OP_RSUB_INT: {
1687 int tReg;
1688 //TUNING: add support for use of Arm rsub op
1689 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1690 tReg = oatAllocTemp(cUnit);
1691 loadConstant(cUnit, tReg, lit);
1692 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1693 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1694 tReg, rlSrc.lowReg);
1695 storeValue(cUnit, rlDest, rlResult);
1696 return false;
1697 break;
1698 }
1699
1700 case OP_ADD_INT_LIT8:
1701 case OP_ADD_INT_LIT16:
1702 op = kOpAdd;
1703 break;
1704 case OP_MUL_INT_LIT8:
1705 case OP_MUL_INT_LIT16: {
1706 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1707 return false;
1708 }
1709 op = kOpMul;
1710 break;
1711 }
1712 case OP_AND_INT_LIT8:
1713 case OP_AND_INT_LIT16:
1714 op = kOpAnd;
1715 break;
1716 case OP_OR_INT_LIT8:
1717 case OP_OR_INT_LIT16:
1718 op = kOpOr;
1719 break;
1720 case OP_XOR_INT_LIT8:
1721 case OP_XOR_INT_LIT16:
1722 op = kOpXor;
1723 break;
1724 case OP_SHL_INT_LIT8:
1725 lit &= 31;
1726 shiftOp = true;
1727 op = kOpLsl;
1728 break;
1729 case OP_SHR_INT_LIT8:
1730 lit &= 31;
1731 shiftOp = true;
1732 op = kOpAsr;
1733 break;
1734 case OP_USHR_INT_LIT8:
1735 lit &= 31;
1736 shiftOp = true;
1737 op = kOpLsr;
1738 break;
1739
1740 case OP_DIV_INT_LIT8:
1741 case OP_DIV_INT_LIT16:
1742 case OP_REM_INT_LIT8:
1743 case OP_REM_INT_LIT16:
1744 if (lit == 0) {
1745 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
1746 return false;
1747 }
1748 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
1749 return false;
1750 }
1751 oatFlushAllRegs(cUnit); /* Everything to home location */
1752 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1753 oatClobber(cUnit, rARG0);
1754 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
1755 (dalvikOpcode == OP_DIV_INT_LIT16)) {
1756 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1757 isDiv = true;
1758 } else {
1759 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1760 isDiv = false;
1761 }
1762 rTgt = loadHelper(cUnit, funcOffset);
1763 loadConstant(cUnit, rARG1, lit);
1764 callRuntimeHelper(cUnit, rTgt);
1765 if (isDiv)
1766 rlResult = oatGetReturn(cUnit);
1767 else
1768 rlResult = oatGetReturnAlt(cUnit);
1769 storeValue(cUnit, rlDest, rlResult);
1770 return false;
1771 break;
1772 default:
1773 return true;
1774 }
1775 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1776 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1777 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
1778 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08001779 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001780 } else {
1781 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
1782 }
1783 storeValue(cUnit, rlDest, rlResult);
1784 return false;
1785}
1786
1787bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1788 RegLocation rlSrc1, RegLocation rlSrc2)
1789{
1790 RegLocation rlResult;
1791 OpKind firstOp = kOpBkpt;
1792 OpKind secondOp = kOpBkpt;
1793 bool callOut = false;
1794 bool checkZero = false;
1795 int funcOffset;
1796 int retReg = rRET0;
1797
1798 switch (mir->dalvikInsn.opcode) {
1799 case OP_NOT_LONG:
1800 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1801 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1802 // Check for destructive overlap
1803 if (rlResult.lowReg == rlSrc2.highReg) {
1804 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001805 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001806 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1807 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1808 oatFreeTemp(cUnit, tReg);
1809 } else {
1810 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1811 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1812 }
1813 storeValueWide(cUnit, rlDest, rlResult);
1814 return false;
1815 break;
1816 case OP_ADD_LONG:
1817 case OP_ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001818#if defined(TARGET_MIPS)
1819 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1820#else
buzbee31a4a6f2012-02-28 15:36:15 -08001821 firstOp = kOpAdd;
1822 secondOp = kOpAdc;
1823 break;
buzbeec5159d52012-03-03 11:48:39 -08001824#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001825 case OP_SUB_LONG:
1826 case OP_SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001827#if defined(TARGET_MIPS)
1828 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1829#else
buzbee31a4a6f2012-02-28 15:36:15 -08001830 firstOp = kOpSub;
1831 secondOp = kOpSbc;
1832 break;
buzbeec5159d52012-03-03 11:48:39 -08001833#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001834 case OP_MUL_LONG:
1835 case OP_MUL_LONG_2ADDR:
1836 callOut = true;
1837 retReg = rRET0;
1838 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1839 break;
1840 case OP_DIV_LONG:
1841 case OP_DIV_LONG_2ADDR:
1842 callOut = true;
1843 checkZero = true;
1844 retReg = rRET0;
1845 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1846 break;
1847 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
1848 // FIXME: is true, or could be made true, or other targets?
1849 case OP_REM_LONG:
1850 case OP_REM_LONG_2ADDR:
1851 callOut = true;
1852 checkZero = true;
1853 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1854 retReg = rARG2;
1855 break;
1856 case OP_AND_LONG_2ADDR:
1857 case OP_AND_LONG:
1858 firstOp = kOpAnd;
1859 secondOp = kOpAnd;
1860 break;
1861 case OP_OR_LONG:
1862 case OP_OR_LONG_2ADDR:
1863 firstOp = kOpOr;
1864 secondOp = kOpOr;
1865 break;
1866 case OP_XOR_LONG:
1867 case OP_XOR_LONG_2ADDR:
1868 firstOp = kOpXor;
1869 secondOp = kOpXor;
1870 break;
1871 case OP_NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08001872 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08001873 }
1874 default:
1875 LOG(FATAL) << "Invalid long arith op";
1876 }
1877 if (!callOut) {
1878 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1879 } else {
1880 int rTgt;
1881 oatFlushAllRegs(cUnit); /* Send everything to home location */
1882 if (checkZero) {
1883 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1884 rTgt = loadHelper(cUnit, funcOffset);
1885 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1886 int tReg = oatAllocTemp(cUnit);
1887#if defined(TARGET_ARM)
1888 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
1889 oatFreeTemp(cUnit, tReg);
1890 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
1891#else
1892 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
buzbee5de34942012-03-01 14:51:57 -08001893 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08001894 oatFreeTemp(cUnit, tReg);
1895#endif
1896 } else {
1897 rTgt = loadHelper(cUnit, funcOffset);
1898 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1899 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1900 }
1901 callRuntimeHelper(cUnit, rTgt);
1902 // Adjust return regs in to handle case of rem returning rARG2/rARG3
1903 if (retReg == rRET0)
1904 rlResult = oatGetReturnWide(cUnit);
1905 else
1906 rlResult = oatGetReturnWideAlt(cUnit);
1907 storeValueWide(cUnit, rlDest, rlResult);
1908 }
1909 return false;
1910}
1911
1912bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
1913 int srcSize, int tgtSize)
1914{
1915 /*
1916 * Don't optimize the register usage since it calls out to support
1917 * functions
1918 */
1919 RegLocation rlSrc;
1920 RegLocation rlDest;
1921 oatFlushAllRegs(cUnit); /* Send everything to home location */
1922 int rTgt = loadHelper(cUnit, funcOffset);
1923 if (srcSize == 1) {
1924 rlSrc = oatGetSrc(cUnit, mir, 0);
1925 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1926 } else {
1927 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1928 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
1929 }
1930 callRuntimeHelper(cUnit, rTgt);
1931 if (tgtSize == 1) {
1932 RegLocation rlResult;
1933 rlDest = oatGetDest(cUnit, mir, 0);
1934 rlResult = oatGetReturn(cUnit);
1935 storeValue(cUnit, rlDest, rlResult);
1936 } else {
1937 RegLocation rlResult;
1938 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1939 rlResult = oatGetReturnWide(cUnit);
1940 storeValueWide(cUnit, rlDest, rlResult);
1941 }
1942 return false;
1943}
1944
1945void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
1946bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
1947 RegLocation rlDest, RegLocation rlSrc1,
1948 RegLocation rlSrc2)
1949{
1950 RegLocation rlResult;
1951 int funcOffset;
1952
1953 switch (mir->dalvikInsn.opcode) {
1954 case OP_ADD_FLOAT_2ADDR:
1955 case OP_ADD_FLOAT:
1956 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1957 break;
1958 case OP_SUB_FLOAT_2ADDR:
1959 case OP_SUB_FLOAT:
1960 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1961 break;
1962 case OP_DIV_FLOAT_2ADDR:
1963 case OP_DIV_FLOAT:
1964 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1965 break;
1966 case OP_MUL_FLOAT_2ADDR:
1967 case OP_MUL_FLOAT:
1968 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1969 break;
1970 case OP_REM_FLOAT_2ADDR:
1971 case OP_REM_FLOAT:
1972 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1973 break;
1974 case OP_NEG_FLOAT: {
1975 genNegFloat(cUnit, rlDest, rlSrc1);
1976 return false;
1977 }
1978 default:
1979 return true;
1980 }
1981 oatFlushAllRegs(cUnit); /* Send everything to home location */
1982 int rTgt = loadHelper(cUnit, funcOffset);
1983 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1984 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
1985 callRuntimeHelper(cUnit, rTgt);
1986 rlResult = oatGetReturn(cUnit);
1987 storeValue(cUnit, rlDest, rlResult);
1988 return false;
1989}
1990
1991void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
1992bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
1993 RegLocation rlDest, RegLocation rlSrc1,
1994 RegLocation rlSrc2)
1995{
1996 RegLocation rlResult;
1997 int funcOffset;
1998
1999 switch (mir->dalvikInsn.opcode) {
2000 case OP_ADD_DOUBLE_2ADDR:
2001 case OP_ADD_DOUBLE:
2002 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
2003 break;
2004 case OP_SUB_DOUBLE_2ADDR:
2005 case OP_SUB_DOUBLE:
2006 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
2007 break;
2008 case OP_DIV_DOUBLE_2ADDR:
2009 case OP_DIV_DOUBLE:
2010 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2011 break;
2012 case OP_MUL_DOUBLE_2ADDR:
2013 case OP_MUL_DOUBLE:
2014 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2015 break;
2016 case OP_REM_DOUBLE_2ADDR:
2017 case OP_REM_DOUBLE:
2018 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2019 break;
2020 case OP_NEG_DOUBLE: {
2021 genNegDouble(cUnit, rlDest, rlSrc1);
2022 return false;
2023 }
2024 default:
2025 return true;
2026 }
2027 oatFlushAllRegs(cUnit); /* Send everything to home location */
2028 int rTgt = loadHelper(cUnit, funcOffset);
2029 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2030 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2031 callRuntimeHelper(cUnit, rTgt);
2032 rlResult = oatGetReturnWide(cUnit);
2033 storeValueWide(cUnit, rlDest, rlResult);
2034 return false;
2035}
2036
2037bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2038{
2039 Opcode opcode = mir->dalvikInsn.opcode;
2040
2041 switch (opcode) {
2042 case OP_INT_TO_FLOAT:
2043 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2044 1, 1);
2045 case OP_FLOAT_TO_INT:
2046 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2047 1, 1);
2048 case OP_DOUBLE_TO_FLOAT:
2049 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2050 2, 1);
2051 case OP_FLOAT_TO_DOUBLE:
2052 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2053 1, 2);
2054 case OP_INT_TO_DOUBLE:
2055 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2056 1, 2);
2057 case OP_DOUBLE_TO_INT:
2058 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2059 2, 1);
2060 case OP_FLOAT_TO_LONG:
2061 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2062 pF2l), 1, 2);
2063 case OP_LONG_TO_FLOAT:
2064 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2065 2, 1);
2066 case OP_DOUBLE_TO_LONG:
2067 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2068 pD2l), 2, 2);
2069 case OP_LONG_TO_DOUBLE:
2070 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2071 2, 2);
2072 default:
2073 return true;
2074 }
2075 return false;
2076}
2077
2078/*
2079 * Generate callout to updateDebugger. Note that we're overloading
2080 * the use of rSUSPEND here. When the debugger is active, this
2081 * register holds the address of the update function. So, if it's
2082 * non-null, we call out to it.
2083 *
2084 * Note also that rRET0 and rRET1 must be preserved across this
2085 * code. This must be handled by the stub.
2086 */
2087void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2088{
2089 // Following DCHECK verifies that dPC is in range of single load immediate
2090 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2091 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2092 oatClobberCalleeSave(cUnit);
2093#if defined(TARGET_ARM)
2094 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002095 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002096 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2097 opReg(cUnit, kOpBlx, rSUSPEND);
2098#else
buzbee82488f52012-03-02 08:20:26 -08002099 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002100 loadConstant(cUnit, rARG2, offset);
2101 opReg(cUnit, kOpBlx, rSUSPEND);
2102 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002103 branch->target = (LIR*)target;
2104#endif
2105 oatFreeTemp(cUnit, rARG2);
2106}
2107
2108/* Check if we need to check for pending suspend request */
2109void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2110{
2111 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2112 return;
2113 }
2114 oatFlushAllRegs(cUnit);
2115 LIR* branch;
2116 if (cUnit->genDebugger) {
2117 // If generating code for the debugger, always check for suspension
buzbee82488f52012-03-02 08:20:26 -08002118 branch = opUnconditionalBranch(cUnit, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002119 } else {
2120#if defined(TARGET_ARM)
2121 // In non-debug case, only check periodically
2122 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002123 branch = opCondBranch(cUnit, kCondEq, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002124#else
2125 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002126 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002127#endif
2128 }
2129 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002130 LIR* target = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
2131 target->dalvikOffset = cUnit->currentDalvikOffset;
2132 target->opcode = kPseudoSuspendTarget;
2133 target->operands[0] = (intptr_t)retLab;
2134 target->operands[1] = mir->offset;
2135 branch->target = (LIR*)target;
2136 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
2137}
2138
2139} // namespace art