blob: f33b3742a3663a5fc3c6972aa904827148b78988 [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{
buzbeea2ebdd72012-03-04 14:57:06 -080061 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
62 mir ? mir->offset : 0);
buzbee82488f52012-03-02 08:20:26 -080063 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080064 // Remember branch target - will process later
65 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
66 return branch;
67}
buzbee5de34942012-03-01 14:51:57 -080068#endif
buzbee31a4a6f2012-02-28 15:36:15 -080069
70LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
71 int reg, int immVal, MIR* mir, ThrowKind kind)
72{
buzbeea2ebdd72012-03-04 14:57:06 -080073 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, mir->offset);
buzbee31a4a6f2012-02-28 15:36:15 -080074 LIR* branch;
75 if (cCode == kCondAl) {
buzbee82488f52012-03-02 08:20:26 -080076 branch = opUnconditionalBranch(cUnit, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080077 } else {
buzbee82488f52012-03-02 08:20:26 -080078 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080079 }
80 // Remember branch target - will process later
81 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
82 return branch;
83}
84
85/* Perform null-check on a register. */
86LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir)
87{
88 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
89 mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
90 return NULL;
91 }
92 return genImmedCheck(cUnit, kCondEq, mReg, 0, mir, kThrowNullPointer);
93}
94
95/* Perform check on two registers */
96LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
97 int reg1, int reg2, MIR* mir, ThrowKind kind)
98{
buzbeea2ebdd72012-03-04 14:57:06 -080099 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
100 mir ? mir->offset : 0, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800101#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800102 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800103#else
buzbee31a4a6f2012-02-28 15:36:15 -0800104 opRegReg(cUnit, kOpCmp, reg1, reg2);
buzbee82488f52012-03-02 08:20:26 -0800105 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800106#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800107 // Remember branch target - will process later
108 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
109 return branch;
110}
111
112void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
113 RegLocation rlSrc1, RegLocation rlSrc2, LIR* labelList)
114{
115 ConditionCode cond;
116 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
117 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800118 Opcode opcode = mir->dalvikInsn.opcode;
119 switch(opcode) {
120 case OP_IF_EQ:
121 cond = kCondEq;
122 break;
123 case OP_IF_NE:
124 cond = kCondNe;
125 break;
126 case OP_IF_LT:
127 cond = kCondLt;
128 break;
129 case OP_IF_GE:
130 cond = kCondGe;
131 break;
132 case OP_IF_GT:
133 cond = kCondGt;
134 break;
135 case OP_IF_LE:
136 cond = kCondLe;
137 break;
138 default:
139 cond = (ConditionCode)0;
140 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
141 }
buzbee5de34942012-03-01 14:51:57 -0800142#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800143 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg,
144 &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800145#else
146 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800147 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800148#endif
buzbee82488f52012-03-02 08:20:26 -0800149 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800150}
151
152void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
153 RegLocation rlSrc, LIR* labelList)
154{
155 ConditionCode cond;
156 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800157 Opcode opcode = mir->dalvikInsn.opcode;
158 switch(opcode) {
159 case OP_IF_EQZ:
160 cond = kCondEq;
161 break;
162 case OP_IF_NEZ:
163 cond = kCondNe;
164 break;
165 case OP_IF_LTZ:
166 cond = kCondLt;
167 break;
168 case OP_IF_GEZ:
169 cond = kCondGe;
170 break;
171 case OP_IF_GTZ:
172 cond = kCondGt;
173 break;
174 case OP_IF_LEZ:
175 cond = kCondLe;
176 break;
177 default:
178 cond = (ConditionCode)0;
179 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
180 }
buzbee5de34942012-03-01 14:51:57 -0800181#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800182 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800183#else
184 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
buzbee82488f52012-03-02 08:20:26 -0800185 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800186#endif
buzbee82488f52012-03-02 08:20:26 -0800187 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800188}
189
190void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
191 RegLocation rlSrc)
192{
193 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
194 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -0800195 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800196 } else {
197 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
198 }
199 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
200 rlResult.lowReg, 31);
201 storeValueWide(cUnit, rlDest, rlResult);
202}
203
204void genIntNarrowing(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
205 RegLocation rlSrc)
206{
207 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
208 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
209 OpKind op = kOpInvalid;
210 switch(mir->dalvikInsn.opcode) {
211 case OP_INT_TO_BYTE:
212 op = kOp2Byte;
213 break;
214 case OP_INT_TO_SHORT:
215 op = kOp2Short;
216 break;
217 case OP_INT_TO_CHAR:
218 op = kOp2Char;
219 break;
220 default:
221 LOG(ERROR) << "Bad int conversion type";
222 }
223 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
224 storeValue(cUnit, rlDest, rlResult);
225}
226
227/*
228 * Let helper function take care of everything. Will call
229 * Array::AllocFromCode(type_idx, method, count);
230 * Note: AllocFromCode will handle checks for errNegativeArraySize.
231 */
232void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
233 RegLocation rlSrc)
234{
235 oatFlushAllRegs(cUnit); /* Everything to home location */
236 uint32_t type_idx = mir->dalvikInsn.vC;
237 int rTgt;
238 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
239 cUnit->dex_cache,
240 *cUnit->dex_file,
241 type_idx)) {
242 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pAllocArrayFromCode));
243 } else {
244 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
245 pAllocArrayFromCodeWithAccessCheck));
246 }
247 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
248 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_id
249 loadValueDirectFixed(cUnit, rlSrc, rARG2); // arg2 <- count
250 callRuntimeHelper(cUnit, rTgt);
251 RegLocation rlResult = oatGetReturn(cUnit);
252 storeValue(cUnit, rlDest, rlResult);
253}
254
255/*
256 * Similar to genNewArray, but with post-allocation initialization.
257 * Verifier guarantees we're dealing with an array class. Current
258 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
259 * Current code also throws internal unimp if not 'L', '[' or 'I'.
260 */
261void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
262{
263 DecodedInstruction* dInsn = &mir->dalvikInsn;
264 int elems = dInsn->vA;
265 int typeId = dInsn->vB;
266 oatFlushAllRegs(cUnit); /* Everything to home location */
267 int rTgt;
268 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
269 cUnit->dex_cache,
270 *cUnit->dex_file,
271 typeId)) {
272 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
273 pCheckAndAllocArrayFromCode));
274 } else {
275 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
276 pCheckAndAllocArrayFromCodeWithAccessCheck));
277 }
278 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
279 loadConstant(cUnit, rARG0, typeId); // arg0 <- type_id
280 loadConstant(cUnit, rARG2, elems); // arg2 <- count
281 callRuntimeHelper(cUnit, rTgt);
282 /*
283 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
284 * return region. Because AllocFromCode placed the new array
285 * in rRET0, we'll just lock it into place. When debugger support is
286 * added, it may be necessary to additionally copy all return
287 * values to a home location in thread-local storage
288 */
289 oatLockTemp(cUnit, rRET0);
290
291 // TODO: use the correct component size, currently all supported types
292 // share array alignment with ints (see comment at head of function)
293 size_t component_size = sizeof(int32_t);
294
295 // Having a range of 0 is legal
296 if (isRange && (dInsn->vA > 0)) {
297 /*
298 * Bit of ugliness here. We're going generate a mem copy loop
299 * on the register range, but it is possible that some regs
300 * in the range have been promoted. This is unlikely, but
301 * before generating the copy, we'll just force a flush
302 * of any regs in the source range that have been promoted to
303 * home location.
304 */
305 for (unsigned int i = 0; i < dInsn->vA; i++) {
306 RegLocation loc = oatUpdateLoc(cUnit,
307 oatGetSrc(cUnit, mir, i));
308 if (loc.location == kLocPhysReg) {
309 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
310 loc.lowReg, kWord);
311 }
312 }
313 /*
314 * TUNING note: generated code here could be much improved, but
315 * this is an uncommon operation and isn't especially performance
316 * critical.
317 */
318 int rSrc = oatAllocTemp(cUnit);
319 int rDst = oatAllocTemp(cUnit);
320 int rIdx = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800321#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800322 int rVal = rLR; // Using a lot of temps, rLR is known free here
buzbee5de34942012-03-01 14:51:57 -0800323#else
324 int rVal = oatAllocTemp(cUnit);
325#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800326 // Set up source pointer
327 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
328 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
329 oatSRegOffset(cUnit, rlFirst.sRegLow));
330 // Set up the target pointer
331 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
332 Array::DataOffset(component_size).Int32Value());
333 // Set up the loop counter (known to be > 0)
334 loadConstant(cUnit, rIdx, dInsn->vA - 1);
335 // Generate the copy loop. Going backwards for convenience
336 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800337 // Copy next element
338 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
339 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
340#if defined(TARGET_ARM)
341 // Combine sub & test using sub setflags encoding here
342 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800343 opCondBranch(cUnit, kCondGe, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800344#else
buzbee5de34942012-03-01 14:51:57 -0800345 oatFreeTemp(cUnit, rVal);
buzbee31a4a6f2012-02-28 15:36:15 -0800346 opRegImm(cUnit, kOpSub, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800347 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800348#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800349 } else if (!isRange) {
350 // TUNING: interleave
351 for (unsigned int i = 0; i < dInsn->vA; i++) {
352 RegLocation rlArg = loadValue(cUnit,
353 oatGetSrc(cUnit, mir, i), kCoreReg);
354 storeBaseDisp(cUnit, rRET0,
355 Array::DataOffset(component_size).Int32Value() +
356 i * 4, rlArg.lowReg, kWord);
357 // If the loadValue caused a temp to be allocated, free it
358 if (oatIsTemp(cUnit, rlArg.lowReg)) {
359 oatFreeTemp(cUnit, rlArg.lowReg);
360 }
361 }
362 }
363}
364
365void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
366 bool isLongOrDouble, bool isObject)
367{
368 int fieldOffset;
369 int ssbIndex;
370 bool isVolatile;
371 bool isReferrersClass;
372 uint32_t fieldIdx = mir->dalvikInsn.vB;
373
374 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
375 *cUnit->dex_file, *cUnit->dex_cache,
376 cUnit->code_item, cUnit->method_idx,
377 cUnit->access_flags);
378
379 bool fastPath =
380 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
381 fieldOffset, ssbIndex,
382 isReferrersClass, isVolatile, true);
383 if (fastPath && !SLOW_FIELD_PATH) {
384 DCHECK_GE(fieldOffset, 0);
385 int rBase;
386 int rMethod;
387 if (isReferrersClass) {
388 // Fast path, static storage base is this method's class
389 rMethod = loadCurrMethod(cUnit);
390 rBase = oatAllocTemp(cUnit);
391 loadWordDisp(cUnit, rMethod,
392 Method::DeclaringClassOffset().Int32Value(), rBase);
393 } else {
394 // Medium path, static storage base in a different class which
395 // requires checks that the other class is initialized.
396 DCHECK_GE(ssbIndex, 0);
397 // May do runtime call so everything to home locations.
398 oatFlushAllRegs(cUnit);
399 // Using fixed register to sync with possible call to runtime
400 // support.
401 rMethod = rARG1;
402 oatLockTemp(cUnit, rMethod);
403 loadCurrMethodDirect(cUnit, rMethod);
404 rBase = rARG0;
405 oatLockTemp(cUnit, rBase);
406 loadWordDisp(cUnit, rMethod,
407 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
408 rBase);
409 loadWordDisp(cUnit, rBase,
410 Array::DataOffset(sizeof(Object*)).Int32Value() + sizeof(int32_t*) *
411 ssbIndex, rBase);
412 // rBase now points at appropriate static storage base (Class*)
413 // or NULL if not initialized. Check for NULL and call helper if NULL.
414 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800415 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800416 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
417 pInitializeStaticStorage));
418 loadConstant(cUnit, rARG0, ssbIndex);
419 callRuntimeHelper(cUnit, rTgt);
420#if defined(TARGET_MIPS)
421 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800422 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800423#endif
424 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800425 branchOver->target = (LIR*)skipTarget;
426 }
427 // rBase now holds static storage base
428 oatFreeTemp(cUnit, rMethod);
429 if (isLongOrDouble) {
430 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
431 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
432 } else {
433 rlSrc = oatGetSrc(cUnit, mir, 0);
434 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
435 }
436//FIXME: need to generalize the barrier call
437 if (isVolatile) {
438 oatGenMemBarrier(cUnit, kST);
439 }
440 if (isLongOrDouble) {
441 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
442 rlSrc.highReg);
443 } else {
444 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
445 }
446 if (isVolatile) {
447 oatGenMemBarrier(cUnit, kSY);
448 }
449 if (isObject) {
450 markGCCard(cUnit, rlSrc.lowReg, rBase);
451 }
452 oatFreeTemp(cUnit, rBase);
453 } else {
454 oatFlushAllRegs(cUnit); // Everything to home locations
455 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
456 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
457 : OFFSETOF_MEMBER(Thread, pSet32Static));
458 int rTgt = loadHelper(cUnit, setterOffset);
459 loadConstant(cUnit, rARG0, fieldIdx);
460 if (isLongOrDouble) {
461 loadValueDirectWideFixed(cUnit, rlSrc, rARG2, rARG3);
462 } else {
463 loadValueDirect(cUnit, rlSrc, rARG1);
464 }
465 callRuntimeHelper(cUnit, rTgt);
466 }
467}
468
469void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
470 bool isLongOrDouble, bool isObject)
471{
472 int fieldOffset;
473 int ssbIndex;
474 bool isVolatile;
475 bool isReferrersClass;
476 uint32_t fieldIdx = mir->dalvikInsn.vB;
477
478 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
479 *cUnit->dex_file, *cUnit->dex_cache,
480 cUnit->code_item, cUnit->method_idx,
481 cUnit->access_flags);
482
483 bool fastPath =
484 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
485 fieldOffset, ssbIndex,
486 isReferrersClass, isVolatile,
487 false);
488 if (fastPath && !SLOW_FIELD_PATH) {
489 DCHECK_GE(fieldOffset, 0);
490 int rBase;
491 int rMethod;
492 if (isReferrersClass) {
493 // Fast path, static storage base is this method's class
494 rMethod = loadCurrMethod(cUnit);
495 rBase = oatAllocTemp(cUnit);
496 loadWordDisp(cUnit, rMethod,
497 Method::DeclaringClassOffset().Int32Value(), rBase);
498 } else {
499 // Medium path, static storage base in a different class which
500 // requires checks that the other class is initialized
501 DCHECK_GE(ssbIndex, 0);
502 // May do runtime call so everything to home locations.
503 oatFlushAllRegs(cUnit);
504 // Using fixed register to sync with possible call to runtime
505 // support
506 rMethod = rARG1;
507 oatLockTemp(cUnit, rMethod);
508 loadCurrMethodDirect(cUnit, rMethod);
509 rBase = rARG0;
510 oatLockTemp(cUnit, rBase);
511 loadWordDisp(cUnit, rMethod,
512 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
513 rBase);
514 loadWordDisp(cUnit, rBase,
515 Array::DataOffset(sizeof(Object*)).Int32Value() +
516 sizeof(int32_t*) * ssbIndex,
517 rBase);
518 // rBase now points at appropriate static storage base (Class*)
519 // or NULL if not initialized. Check for NULL and call helper if NULL.
520 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800521 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800522 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
523 pInitializeStaticStorage));
524 loadConstant(cUnit, rARG0, ssbIndex);
525 callRuntimeHelper(cUnit, rTgt);
526#if defined(TARGET_MIPS)
527 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800528 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800529#endif
530 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800531 branchOver->target = (LIR*)skipTarget;
532 }
533 // rBase now holds static storage base
534 oatFreeTemp(cUnit, rMethod);
535 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
536 : oatGetDest(cUnit, mir, 0);
537 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
538 if (isVolatile) {
539 oatGenMemBarrier(cUnit, kSY);
540 }
541 if (isLongOrDouble) {
542 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
543 rlResult.highReg, INVALID_SREG);
544 } else {
545 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
546 }
547 oatFreeTemp(cUnit, rBase);
548 if (isLongOrDouble) {
549 storeValueWide(cUnit, rlDest, rlResult);
550 } else {
551 storeValue(cUnit, rlDest, rlResult);
552 }
553 } else {
554 oatFlushAllRegs(cUnit); // Everything to home locations
555 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
556 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
557 : OFFSETOF_MEMBER(Thread, pGet32Static));
558 int rTgt = loadHelper(cUnit, getterOffset);
559 loadConstant(cUnit, rARG0, fieldIdx);
560 callRuntimeHelper(cUnit, rTgt);
561 if (isLongOrDouble) {
562 RegLocation rlResult = oatGetReturnWide(cUnit);
563 storeValueWide(cUnit, rlDest, rlResult);
564 } else {
565 RegLocation rlResult = oatGetReturn(cUnit);
566 storeValue(cUnit, rlDest, rlResult);
567 }
568 }
569}
570
571
572// Debugging routine - if null target, branch to DebugMe
573void genShowTarget(CompilationUnit* cUnit)
574{
buzbee0398c422012-03-02 15:22:47 -0800575 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800576 loadWordDisp(cUnit, rSELF,
buzbee0398c422012-03-02 15:22:47 -0800577 OFFSETOF_MEMBER(Thread, pDebugMe), rINVOKE_TGT);
buzbee31a4a6f2012-02-28 15:36:15 -0800578 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800579 branchOver->target = (LIR*)target;
580}
581
582void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
583{
584 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
585 pThrowVerificationErrorFromCode));
586 loadConstant(cUnit, rARG0, mir->dalvikInsn.vA);
587 loadConstant(cUnit, rARG1, mir->dalvikInsn.vB);
588 callRuntimeHelper(cUnit, rTgt);
589}
590
591void handleSuspendLaunchpads(CompilationUnit *cUnit)
592{
593 LIR** suspendLabel =
594 (LIR **) cUnit->suspendLaunchpads.elemList;
595 int numElems = cUnit->suspendLaunchpads.numUsed;
596
597 for (int i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800598 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800599 /* TUNING: move suspend count load into helper */
600 LIR* lab = suspendLabel[i];
601 LIR* resumeLab = (LIR*)lab->operands[0];
602 cUnit->currentDalvikOffset = lab->operands[1];
603 oatAppendLIR(cUnit, (LIR *)lab);
604 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
605 pTestSuspendFromCode));
606 if (!cUnit->genDebugger) {
607 // use rSUSPEND for suspend count
608 loadWordDisp(cUnit, rSELF,
609 Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
610 }
611 opReg(cUnit, kOpBlx, rTgt);
612 if ( cUnit->genDebugger) {
613 // use rSUSPEND for update debugger
614 loadWordDisp(cUnit, rSELF,
615 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
616 rSUSPEND);
617 }
buzbee82488f52012-03-02 08:20:26 -0800618 opUnconditionalBranch(cUnit, resumeLab);
buzbee31a4a6f2012-02-28 15:36:15 -0800619 }
620}
621
622void handleThrowLaunchpads(CompilationUnit *cUnit)
623{
624 LIR** throwLabel = (LIR **) cUnit->throwLaunchpads.elemList;
625 int numElems = cUnit->throwLaunchpads.numUsed;
626 int i;
627
628 for (i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800629 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800630 LIR* lab = throwLabel[i];
631 cUnit->currentDalvikOffset = lab->operands[1];
632 oatAppendLIR(cUnit, (LIR *)lab);
633 int funcOffset = 0;
634 int v1 = lab->operands[2];
635 int v2 = lab->operands[3];
636 switch(lab->operands[0]) {
637 case kThrowNullPointer:
638 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
639 break;
640 case kThrowArrayBounds:
buzbee5de34942012-03-01 14:51:57 -0800641 if (v2 != rARG0) {
buzbee82488f52012-03-02 08:20:26 -0800642 opRegCopy(cUnit, rARG0, v1);
643 opRegCopy(cUnit, rARG1, v2);
buzbee31a4a6f2012-02-28 15:36:15 -0800644 } else {
buzbee5de34942012-03-01 14:51:57 -0800645 if (v1 == rARG1) {
buzbee31a4a6f2012-02-28 15:36:15 -0800646#if defined(TARGET_ARM)
647 int rTmp = r12;
648#else
649 int rTmp = oatAllocTemp(cUnit);
650#endif
buzbee82488f52012-03-02 08:20:26 -0800651 opRegCopy(cUnit, rTmp, v1);
652 opRegCopy(cUnit, rARG1, v2);
653 opRegCopy(cUnit, rARG0, rTmp);
buzbee31a4a6f2012-02-28 15:36:15 -0800654 } else {
buzbee82488f52012-03-02 08:20:26 -0800655 opRegCopy(cUnit, rARG1, v2);
656 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800657 }
658 }
659 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
660 break;
661 case kThrowDivZero:
662 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
663 break;
664 case kThrowVerificationError:
665 loadConstant(cUnit, rARG0, v1);
666 loadConstant(cUnit, rARG1, v2);
667 funcOffset =
668 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
669 break;
670 case kThrowNegArraySize:
buzbee82488f52012-03-02 08:20:26 -0800671 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800672 funcOffset =
673 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
674 break;
675 case kThrowNoSuchMethod:
buzbee82488f52012-03-02 08:20:26 -0800676 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800677 funcOffset =
678 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
679 break;
680 case kThrowStackOverflow:
681 funcOffset =
682 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
683 // Restore stack alignment
684 opRegImm(cUnit, kOpAdd, rSP,
685 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
686 break;
687 default:
688 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
689 }
690 int rTgt = loadHelper(cUnit, funcOffset);
691 callRuntimeHelper(cUnit, rTgt);
buzbee0398c422012-03-02 15:22:47 -0800692 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800693 }
694}
695
696/* Needed by the Assembler */
697void oatSetupResourceMasks(LIR* lir)
698{
699 setupResourceMasks(lir);
700}
701
702void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
703 RegLocation rlDest, RegLocation rlObj,
704 bool isLongOrDouble, bool isObject)
705{
706 int fieldOffset;
707 bool isVolatile;
708 uint32_t fieldIdx = mir->dalvikInsn.vC;
709
710 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
711 *cUnit->dex_file, *cUnit->dex_cache,
712 cUnit->code_item, cUnit->method_idx,
713 cUnit->access_flags);
714
715 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
716 fieldOffset, isVolatile, false);
717
718 if (fastPath && !SLOW_FIELD_PATH) {
719 RegLocation rlResult;
720 RegisterClass regClass = oatRegClassBySize(size);
721 DCHECK_GE(fieldOffset, 0);
722 rlObj = loadValue(cUnit, rlObj, kCoreReg);
723 if (isLongOrDouble) {
724 DCHECK(rlDest.wide);
725 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
726 int regPtr = oatAllocTemp(cUnit);
727 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
728 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
729 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
730 if (isVolatile) {
731 oatGenMemBarrier(cUnit, kSY);
732 }
733 oatFreeTemp(cUnit, regPtr);
734 storeValueWide(cUnit, rlDest, rlResult);
735 } else {
736 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
737 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
738 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
739 kWord, rlObj.sRegLow);
740 if (isVolatile) {
741 oatGenMemBarrier(cUnit, kSY);
742 }
743 storeValue(cUnit, rlDest, rlResult);
744 }
745 } else {
746 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
747 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
748 : OFFSETOF_MEMBER(Thread, pGet32Instance));
749 int rTgt = loadHelper(cUnit, getterOffset);
750 loadValueDirect(cUnit, rlObj, rARG1);
751 loadConstant(cUnit, rARG0, fieldIdx);
752 callRuntimeHelper(cUnit, rTgt);
753 if (isLongOrDouble) {
754 RegLocation rlResult = oatGetReturnWide(cUnit);
755 storeValueWide(cUnit, rlDest, rlResult);
756 } else {
757 RegLocation rlResult = oatGetReturn(cUnit);
758 storeValue(cUnit, rlDest, rlResult);
759 }
760 }
761}
762
763void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, RegLocation rlSrc,
764 RegLocation rlObj, bool isLongOrDouble, bool isObject)
765{
766 int fieldOffset;
767 bool isVolatile;
768 uint32_t fieldIdx = mir->dalvikInsn.vC;
769
770 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
771 *cUnit->dex_file, *cUnit->dex_cache,
772 cUnit->code_item, cUnit->method_idx,
773 cUnit->access_flags);
774
775 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
776 fieldOffset, isVolatile, true);
777 if (fastPath && !SLOW_FIELD_PATH) {
778 RegisterClass regClass = oatRegClassBySize(size);
779 DCHECK_GE(fieldOffset, 0);
780 rlObj = loadValue(cUnit, rlObj, kCoreReg);
781 if (isLongOrDouble) {
782 int regPtr;
783 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
784 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
785 regPtr = oatAllocTemp(cUnit);
786 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
787 if (isVolatile) {
788 oatGenMemBarrier(cUnit, kST);
789 }
790 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
791 if (isVolatile) {
792 oatGenMemBarrier(cUnit, kSY);
793 }
794 oatFreeTemp(cUnit, regPtr);
795 } else {
796 rlSrc = loadValue(cUnit, rlSrc, regClass);
797 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
798 if (isVolatile) {
799 oatGenMemBarrier(cUnit, kST);
800 }
801 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
802 if (isVolatile) {
803 oatGenMemBarrier(cUnit, kSY);
804 }
805 }
806 } else {
807 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
808 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
809 : OFFSETOF_MEMBER(Thread, pSet32Instance));
810 int rTgt = loadHelper(cUnit, setterOffset);
811 loadValueDirect(cUnit, rlObj, rARG1);
812 if (isLongOrDouble) {
813 loadValueDirectWide(cUnit, rlSrc, rARG2, rARG3);
814 } else {
815 loadValueDirect(cUnit, rlSrc, rARG2);
816 }
817 loadConstant(cUnit, rARG0, fieldIdx);
818 callRuntimeHelper(cUnit, rTgt);
819 }
820}
821
822void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
823 RegLocation rlSrc)
824{
825 uint32_t type_idx = mir->dalvikInsn.vB;
826 int mReg = loadCurrMethod(cUnit);
827 int resReg = oatAllocTemp(cUnit);
828 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
829 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
830 cUnit->dex_cache,
831 *cUnit->dex_file,
832 type_idx)) {
833 // Call out to helper which resolves type and verifies access.
834 // Resolved type returned in rRET0.
835 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
836 pInitializeTypeAndVerifyAccessFromCode));
buzbee82488f52012-03-02 08:20:26 -0800837 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800838 loadConstant(cUnit, rARG0, type_idx);
839 callRuntimeHelper(cUnit, rTgt);
840 RegLocation rlResult = oatGetReturn(cUnit);
841 storeValue(cUnit, rlDest, rlResult);
842 } else {
843 // We're don't need access checks, load type from dex cache
844 int32_t dex_cache_offset =
845 Method::DexCacheResolvedTypesOffset().Int32Value();
846 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
847 int32_t offset_of_type =
848 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
849 * type_idx);
850 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
851 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
852 type_idx) || SLOW_TYPE_PATH) {
853 // Slow path, at runtime test if type is null and if so initialize
854 oatFlushAllRegs(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800855 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0,
856 NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800857 // Resolved, store and hop over following code
858 storeValue(cUnit, rlDest, rlResult);
buzbee82488f52012-03-02 08:20:26 -0800859 LIR* branch2 = opUnconditionalBranch(cUnit,0);
buzbee31a4a6f2012-02-28 15:36:15 -0800860 // TUNING: move slow path to end & remove unconditional branch
861 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800862 // Call out to helper, which will return resolved type in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800863 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
864 pInitializeTypeFromCode));
buzbee82488f52012-03-02 08:20:26 -0800865 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800866 loadConstant(cUnit, rARG0, type_idx);
867 callRuntimeHelper(cUnit, rTgt);
868 RegLocation rlResult = oatGetReturn(cUnit);
869 storeValue(cUnit, rlDest, rlResult);
870 // Rejoin code paths
871 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800872 branch1->target = (LIR*)target1;
873 branch2->target = (LIR*)target2;
874 } else {
875 // Fast path, we're done - just store result
876 storeValue(cUnit, rlDest, rlResult);
877 }
878 }
879}
880void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
881 RegLocation rlSrc)
882{
883 /* NOTE: Most strings should be available at compile time */
884 uint32_t string_idx = mir->dalvikInsn.vB;
885 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
886 (sizeof(String*) * string_idx);
887 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
888 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
889 // slow path, resolve string if not in dex cache
890 oatFlushAllRegs(cUnit);
891 oatLockCallTemps(cUnit); // Using explicit registers
892 loadCurrMethodDirect(cUnit, rARG2);
893 loadWordDisp(cUnit, rARG2,
894 Method::DexCacheStringsOffset().Int32Value(), rARG0);
895 // Might call out to helper, which will return resolved string in rRET0
896 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
897 pResolveStringFromCode));
898 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
899 loadConstant(cUnit, rARG1, string_idx);
900#if defined(TARGET_ARM)
901 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
902 genBarrier(cUnit);
903 // For testing, always force through helper
904 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee82488f52012-03-02 08:20:26 -0800905 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -0800906 }
buzbee82488f52012-03-02 08:20:26 -0800907 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800908 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
909#else
buzbee82488f52012-03-02 08:20:26 -0800910 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
911 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800912 opReg(cUnit, kOpBlx, rTgt);
913 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800914 branch->target = target;
915#endif
916 genBarrier(cUnit);
917 storeValue(cUnit, rlDest, getRetLoc(cUnit));
918 } else {
919 int mReg = loadCurrMethod(cUnit);
920 int resReg = oatAllocTemp(cUnit);
921 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
922 loadWordDisp(cUnit, mReg,
923 Method::DexCacheStringsOffset().Int32Value(), resReg);
924 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
925 storeValue(cUnit, rlDest, rlResult);
926 }
927}
928
929/*
930 * Let helper function take care of everything. Will
931 * call Class::NewInstanceFromCode(type_idx, method);
932 */
933void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
934{
935 oatFlushAllRegs(cUnit); /* Everything to home location */
936 uint32_t type_idx = mir->dalvikInsn.vB;
937 // alloc will always check for resolution, do we also need to verify
938 // access because the verifier was unable to?
939 int rTgt;
940 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
941 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
942 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode));
943 } else {
944 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
945 pAllocObjectFromCodeWithAccessCheck));
946 }
947 loadCurrMethodDirect(cUnit, rARG1); // arg1 <= Method*
948 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_idx
949 callRuntimeHelper(cUnit, rTgt);
950 RegLocation rlResult = oatGetReturn(cUnit);
951 storeValue(cUnit, rlDest, rlResult);
952}
953
954void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
955 RegLocation rlSrc)
956{
957 oatFlushAllRegs(cUnit);
958 // May generate a call - use explicit registers
959 oatLockCallTemps(cUnit);
960 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee5de34942012-03-01 14:51:57 -0800961 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
buzbee31a4a6f2012-02-28 15:36:15 -0800962 int classReg = rARG2; // rARG2 will hold the Class*
963 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
964 cUnit->dex_cache,
965 *cUnit->dex_file,
966 type_idx)) {
967 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbee5de34942012-03-01 14:51:57 -0800968 // returns Class* in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800969 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
970 pInitializeTypeAndVerifyAccessFromCode));
971 loadConstant(cUnit, rARG0, type_idx);
972 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -0800973 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee5de34942012-03-01 14:51:57 -0800974 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
buzbee31a4a6f2012-02-28 15:36:15 -0800975 } else {
buzbee5de34942012-03-01 14:51:57 -0800976 // Load dex cache entry into classReg (rARG2)
buzbee31a4a6f2012-02-28 15:36:15 -0800977 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
978 loadWordDisp(cUnit, rARG1,
979 Method::DexCacheResolvedTypesOffset().Int32Value(),
980 classReg);
981 int32_t offset_of_type =
982 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
983 * type_idx);
984 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
985 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
986 cUnit->dex_cache, type_idx)) {
987 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -0800988 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800989 // Not resolved
990 // Call out to helper, which will return resolved type in rRET0
991 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
992 pInitializeTypeFromCode));
993 loadConstant(cUnit, rARG0, type_idx);
994 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -0800995 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -0800996 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
997 // Rejoin code paths
998 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800999 hopBranch->target = (LIR*)hopTarget;
1000 }
1001 }
1002 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
buzbee82488f52012-03-02 08:20:26 -08001003 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001004 /* load object->clazz */
1005 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1006 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1007 /* rARG0 is ref, rARG1 is ref->clazz, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001008#if defined(TARGET_ARM)
1009 /* Uses conditional nullification */
buzbee31a4a6f2012-02-28 15:36:15 -08001010 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1011 pInstanceofNonTrivialFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001012 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
buzbee82488f52012-03-02 08:20:26 -08001013 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
buzbee31a4a6f2012-02-28 15:36:15 -08001014 loadConstant(cUnit, rARG0, 1); // .eq case - load true
buzbee82488f52012-03-02 08:20:26 -08001015 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee31a4a6f2012-02-28 15:36:15 -08001016 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001017#else
buzbee0398c422012-03-02 15:22:47 -08001018 /* Uses branchovers */
1019 loadConstant(cUnit, rARG0, 1); // assume true
1020 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
1021 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1022 pInstanceofNonTrivialFromCode));
1023 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1024 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001025#endif
buzbee0398c422012-03-02 15:22:47 -08001026 oatClobberCalleeSave(cUnit);
1027 /* branch targets here */
buzbee31a4a6f2012-02-28 15:36:15 -08001028 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001029 RegLocation rlResult = oatGetReturn(cUnit);
1030 storeValue(cUnit, rlDest, rlResult);
buzbee0398c422012-03-02 15:22:47 -08001031 branch1->target = target;
1032#if !defined(TARGET_ARM)
1033 branchover->target = target;
1034#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001035}
1036
1037void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1038{
1039 oatFlushAllRegs(cUnit);
1040 // May generate a call - use explicit registers
1041 oatLockCallTemps(cUnit);
1042 uint32_t type_idx = mir->dalvikInsn.vB;
1043 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1044 int classReg = rARG2; // rARG2 will hold the Class*
1045 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1046 cUnit->dex_cache,
1047 *cUnit->dex_file,
1048 type_idx)) {
1049 // Check we have access to type_idx and if not throw IllegalAccessError,
1050 // returns Class* in rRET0
1051 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1052 pInitializeTypeAndVerifyAccessFromCode));
1053 loadConstant(cUnit, rARG0, type_idx);
1054 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001055 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001056 } else {
1057 // Load dex cache entry into classReg (rARG2)
1058 loadWordDisp(cUnit, rARG1,
1059 Method::DexCacheResolvedTypesOffset().Int32Value(),
1060 classReg);
1061 int32_t offset_of_type =
1062 Array::DataOffset(sizeof(Class*)).Int32Value() +
1063 (sizeof(Class*) * type_idx);
1064 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1065 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1066 cUnit->dex_cache, type_idx)) {
1067 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001068 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001069 // Not resolved
buzbee5de34942012-03-01 14:51:57 -08001070 // Call out to helper, which will return resolved type in rARG0
1071 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode));
1072 loadConstant(cUnit, rARG0, type_idx);
1073 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001074 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001075 // Rejoin code paths
1076 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001077 hopBranch->target = (LIR*)hopTarget;
1078 }
1079 }
buzbee5de34942012-03-01 14:51:57 -08001080 // At this point, classReg (rARG2) has class
buzbee31a4a6f2012-02-28 15:36:15 -08001081 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1082 /* Null is OK - continue */
buzbee82488f52012-03-02 08:20:26 -08001083 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001084 /* load object->clazz */
1085 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1086 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1087 /* rARG1 now contains object->clazz */
1088 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1089 pCheckCastFromCode));
buzbee5de34942012-03-01 14:51:57 -08001090#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -08001091 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
buzbee5de34942012-03-01 14:51:57 -08001092#else
buzbee31a4a6f2012-02-28 15:36:15 -08001093 opRegReg(cUnit, kOpCmp, rARG1, classReg);
buzbee82488f52012-03-02 08:20:26 -08001094 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
buzbee5de34942012-03-01 14:51:57 -08001095#endif
buzbee82488f52012-03-02 08:20:26 -08001096 opRegCopy(cUnit, rARG0, rARG1);
1097 opRegCopy(cUnit, rARG1, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08001098 callRuntimeHelper(cUnit, rTgt);
1099 /* branch target here */
1100 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001101 branch1->target = (LIR*)target;
1102 branch2->target = (LIR*)target;
1103}
1104
1105
1106void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1107{
1108 oatFlushAllRegs(cUnit);
1109 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException));
1110 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get exception object
1111 callRuntimeHelper(cUnit, rTgt); // art_deliver_exception(exception);
1112}
1113
1114/*
1115 * Generate array store
1116 *
1117 */
1118void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
1119 RegLocation rlIndex, RegLocation rlSrc, int scale)
1120{
1121 RegisterClass regClass = oatRegClassBySize(kWord);
1122 int lenOffset = Array::LengthOffset().Int32Value();
1123 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
1124
1125 oatFlushAllRegs(cUnit);
1126 /* Make sure it's a legal object Put. Use direct regs at first */
1127 loadValueDirectFixed(cUnit, rlArray, rARG1);
1128 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1129
1130 /* null array object? */
1131 genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
1132 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1133 pCanPutArrayElementFromCode));
1134 /* Get the array's clazz */
1135 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
1136 callRuntimeHelper(cUnit, rTgt);
1137 oatFreeTemp(cUnit, rARG0);
1138 oatFreeTemp(cUnit, rARG1);
1139
1140 // Now, redo loadValues in case they didn't survive the call
1141
1142 int regPtr;
1143 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1144 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1145
1146 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1147 oatClobber(cUnit, rlArray.lowReg);
1148 regPtr = rlArray.lowReg;
1149 } else {
1150 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001151 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001152 }
1153
1154 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1155 int regLen = oatAllocTemp(cUnit);
1156 //NOTE: max live temps(4) here.
1157 /* Get len */
1158 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1159 /* regPtr -> array data */
1160 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1161 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1162 kThrowArrayBounds);
1163 oatFreeTemp(cUnit, regLen);
1164 } else {
1165 /* regPtr -> array data */
1166 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1167 }
1168 /* at this point, regPtr points to array, 2 live temps */
1169 rlSrc = loadValue(cUnit, rlSrc, regClass);
1170 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1171 scale, kWord);
1172}
1173
1174/*
1175 * Generate array load
1176 */
1177void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1178 RegLocation rlArray, RegLocation rlIndex,
1179 RegLocation rlDest, int scale)
1180{
1181 RegisterClass regClass = oatRegClassBySize(size);
1182 int lenOffset = Array::LengthOffset().Int32Value();
1183 int dataOffset;
1184 RegLocation rlResult;
1185 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1186 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1187 int regPtr;
1188
1189 if (size == kLong || size == kDouble) {
1190 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1191 } else {
1192 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1193 }
1194
1195 /* null object? */
1196 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1197
1198 regPtr = oatAllocTemp(cUnit);
1199
1200 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1201 int regLen = oatAllocTemp(cUnit);
1202 /* Get len */
1203 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1204 /* regPtr -> array data */
1205 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1206 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1207 kThrowArrayBounds);
1208 oatFreeTemp(cUnit, regLen);
1209 } else {
1210 /* regPtr -> array data */
1211 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1212 }
1213 oatFreeTemp(cUnit, rlArray.lowReg);
1214 if ((size == kLong) || (size == kDouble)) {
1215 if (scale) {
1216 int rNewIndex = oatAllocTemp(cUnit);
1217 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1218 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1219 oatFreeTemp(cUnit, rNewIndex);
1220 } else {
1221 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1222 }
1223 oatFreeTemp(cUnit, rlIndex.lowReg);
1224 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1225
1226 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1227
1228 oatFreeTemp(cUnit, regPtr);
1229 storeValueWide(cUnit, rlDest, rlResult);
1230 } else {
1231 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1232
1233 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1234 scale, size);
1235
1236 oatFreeTemp(cUnit, regPtr);
1237 storeValue(cUnit, rlDest, rlResult);
1238 }
1239}
1240
1241/*
1242 * Generate array store
1243 *
1244 */
1245void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1246 RegLocation rlArray, RegLocation rlIndex,
1247 RegLocation rlSrc, int scale)
1248{
1249 RegisterClass regClass = oatRegClassBySize(size);
1250 int lenOffset = Array::LengthOffset().Int32Value();
1251 int dataOffset;
1252
1253 if (size == kLong || size == kDouble) {
1254 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1255 } else {
1256 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1257 }
1258
1259 int regPtr;
1260 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1261 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1262
1263 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1264 oatClobber(cUnit, rlArray.lowReg);
1265 regPtr = rlArray.lowReg;
1266 } else {
1267 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001268 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001269 }
1270
1271 /* null object? */
1272 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1273
1274 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1275 int regLen = oatAllocTemp(cUnit);
1276 //NOTE: max live temps(4) here.
1277 /* Get len */
1278 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1279 /* regPtr -> array data */
1280 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1281 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1282 kThrowArrayBounds);
1283 oatFreeTemp(cUnit, regLen);
1284 } else {
1285 /* regPtr -> array data */
1286 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1287 }
1288 /* at this point, regPtr points to array, 2 live temps */
1289 if ((size == kLong) || (size == kDouble)) {
1290 //TUNING: specific wide routine that can handle fp regs
1291 if (scale) {
1292 int rNewIndex = oatAllocTemp(cUnit);
1293 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1294 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1295 oatFreeTemp(cUnit, rNewIndex);
1296 } else {
1297 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1298 }
1299 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1300
1301 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1302
1303 oatFreeTemp(cUnit, regPtr);
1304 } else {
1305 rlSrc = loadValue(cUnit, rlSrc, regClass);
1306
1307 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1308 scale, size);
1309 }
1310}
1311
1312void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1313 OpKind secondOp, RegLocation rlDest,
1314 RegLocation rlSrc1, RegLocation rlSrc2)
1315{
1316 RegLocation rlResult;
1317#if defined(TARGET_ARM)
1318 /*
1319 * NOTE: This is the one place in the code in which we might have
1320 * as many as six live temporary registers. There are 5 in the normal
1321 * set for Arm. Until we have spill capabilities, temporarily add
1322 * lr to the temp set. It is safe to do this locally, but note that
1323 * lr is used explicitly elsewhere in the code generator and cannot
1324 * normally be used as a general temp register.
1325 */
1326 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1327 oatFreeTemp(cUnit, rLR); // and make it available
1328#endif
1329 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1330 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1331 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1332 // The longs may overlap - use intermediate temp if so
1333 if (rlResult.lowReg == rlSrc1.highReg) {
1334 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001335 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001336 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1337 rlSrc2.lowReg);
1338 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1339 rlSrc2.highReg);
1340 oatFreeTemp(cUnit, tReg);
1341 } else {
1342 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1343 rlSrc2.lowReg);
1344 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1345 rlSrc2.highReg);
1346 }
1347 /*
1348 * NOTE: If rlDest refers to a frame variable in a large frame, the
1349 * following storeValueWide might need to allocate a temp register.
1350 * To further work around the lack of a spill capability, explicitly
1351 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1352 * Remove when spill is functional.
1353 */
1354 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1355 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1356 storeValueWide(cUnit, rlDest, rlResult);
1357#if defined(TARGET_ARM)
1358 oatClobber(cUnit, rLR);
1359 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1360#endif
1361}
1362
1363
1364bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1365 RegLocation rlSrc1, RegLocation rlShift)
1366{
1367 int funcOffset;
1368
1369 switch( mir->dalvikInsn.opcode) {
1370 case OP_SHL_LONG:
1371 case OP_SHL_LONG_2ADDR:
1372 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1373 break;
1374 case OP_SHR_LONG:
1375 case OP_SHR_LONG_2ADDR:
1376 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1377 break;
1378 case OP_USHR_LONG:
1379 case OP_USHR_LONG_2ADDR:
1380 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1381 break;
1382 default:
1383 LOG(FATAL) << "Unexpected case";
1384 return true;
1385 }
1386 oatFlushAllRegs(cUnit); /* Send everything to home location */
1387 int rTgt = loadHelper(cUnit, funcOffset);
1388 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1389 loadValueDirect(cUnit, rlShift, rARG2);
1390 callRuntimeHelper(cUnit, rTgt);
1391 RegLocation rlResult = oatGetReturnWide(cUnit);
1392 storeValueWide(cUnit, rlDest, rlResult);
1393 return false;
1394}
1395
1396
1397bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1398 RegLocation rlSrc1, RegLocation rlSrc2)
1399{
1400 OpKind op = kOpBkpt;
1401 bool callOut = false;
1402 bool checkZero = false;
1403 bool unary = false;
1404 int retReg = rRET0;
1405 int funcOffset;
1406 RegLocation rlResult;
1407 bool shiftOp = false;
1408
1409 switch (mir->dalvikInsn.opcode) {
1410 case OP_NEG_INT:
1411 op = kOpNeg;
1412 unary = true;
1413 break;
1414 case OP_NOT_INT:
1415 op = kOpMvn;
1416 unary = true;
1417 break;
1418 case OP_ADD_INT:
1419 case OP_ADD_INT_2ADDR:
1420 op = kOpAdd;
1421 break;
1422 case OP_SUB_INT:
1423 case OP_SUB_INT_2ADDR:
1424 op = kOpSub;
1425 break;
1426 case OP_MUL_INT:
1427 case OP_MUL_INT_2ADDR:
1428 op = kOpMul;
1429 break;
1430 case OP_DIV_INT:
1431 case OP_DIV_INT_2ADDR:
1432 callOut = true;
1433 checkZero = true;
1434 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1435 retReg = rRET0;
1436 break;
buzbee5de34942012-03-01 14:51:57 -08001437 /* NOTE: returns in rARG1 */
buzbee31a4a6f2012-02-28 15:36:15 -08001438 case OP_REM_INT:
1439 case OP_REM_INT_2ADDR:
1440 callOut = true;
1441 checkZero = true;
1442 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1443 retReg = rRET1;
1444 break;
1445 case OP_AND_INT:
1446 case OP_AND_INT_2ADDR:
1447 op = kOpAnd;
1448 break;
1449 case OP_OR_INT:
1450 case OP_OR_INT_2ADDR:
1451 op = kOpOr;
1452 break;
1453 case OP_XOR_INT:
1454 case OP_XOR_INT_2ADDR:
1455 op = kOpXor;
1456 break;
1457 case OP_SHL_INT:
1458 case OP_SHL_INT_2ADDR:
1459 shiftOp = true;
1460 op = kOpLsl;
1461 break;
1462 case OP_SHR_INT:
1463 case OP_SHR_INT_2ADDR:
1464 shiftOp = true;
1465 op = kOpAsr;
1466 break;
1467 case OP_USHR_INT:
1468 case OP_USHR_INT_2ADDR:
1469 shiftOp = true;
1470 op = kOpLsr;
1471 break;
1472 default:
1473 LOG(FATAL) << "Invalid word arith op: " <<
1474 (int)mir->dalvikInsn.opcode;
1475 }
1476 if (!callOut) {
1477 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1478 if (unary) {
1479 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1480 opRegReg(cUnit, op, rlResult.lowReg,
1481 rlSrc1.lowReg);
1482 } else {
1483 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1484 if (shiftOp) {
1485 int tReg = oatAllocTemp(cUnit);
1486 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1487 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1488 opRegRegReg(cUnit, op, rlResult.lowReg,
1489 rlSrc1.lowReg, tReg);
1490 oatFreeTemp(cUnit, tReg);
1491 } else {
1492 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1493 opRegRegReg(cUnit, op, rlResult.lowReg,
1494 rlSrc1.lowReg, rlSrc2.lowReg);
1495 }
1496 }
1497 storeValue(cUnit, rlDest, rlResult);
1498 } else {
1499 RegLocation rlResult;
1500 oatFlushAllRegs(cUnit); /* Send everything to home location */
1501 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
1502 int rTgt = loadHelper(cUnit, funcOffset);
1503 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1504 if (checkZero) {
1505 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1506 }
1507 callRuntimeHelper(cUnit, rTgt);
1508 if (retReg == rRET0)
1509 rlResult = oatGetReturn(cUnit);
1510 else
1511 rlResult = oatGetReturnAlt(cUnit);
1512 storeValue(cUnit, rlDest, rlResult);
1513 }
1514 return false;
1515}
1516
1517/*
1518 * The following are the first-level codegen routines that analyze the format
1519 * of each bytecode then either dispatch special purpose codegen routines
1520 * or produce corresponding Thumb instructions directly.
1521 */
1522
1523bool isPowerOfTwo(int x)
1524{
1525 return (x & (x - 1)) == 0;
1526}
1527
1528// Returns true if no more than two bits are set in 'x'.
1529bool isPopCountLE2(unsigned int x)
1530{
1531 x &= x - 1;
1532 return (x & (x - 1)) == 0;
1533}
1534
1535// Returns the index of the lowest set bit in 'x'.
1536int lowestSetBit(unsigned int x) {
1537 int bit_posn = 0;
1538 while ((x & 0xf) == 0) {
1539 bit_posn += 4;
1540 x >>= 4;
1541 }
1542 while ((x & 1) == 0) {
1543 bit_posn++;
1544 x >>= 1;
1545 }
1546 return bit_posn;
1547}
1548
1549// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1550// and store the result in 'rlDest'.
1551bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
1552 RegLocation rlSrc, RegLocation rlDest, int lit)
1553{
1554 if (lit < 2 || !isPowerOfTwo(lit)) {
1555 return false;
1556 }
1557 int k = lowestSetBit(lit);
1558 if (k >= 30) {
1559 // Avoid special cases.
1560 return false;
1561 }
1562 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1563 dalvikOpcode == OP_DIV_INT_LIT16);
1564 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1565 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1566 if (div) {
1567 int tReg = oatAllocTemp(cUnit);
1568 if (lit == 2) {
1569 // Division by 2 is by far the most common division by constant.
1570 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1571 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1572 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1573 } else {
1574 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1575 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1576 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1577 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1578 }
1579 } else {
1580 int cReg = oatAllocTemp(cUnit);
1581 loadConstant(cUnit, cReg, lit - 1);
1582 int tReg1 = oatAllocTemp(cUnit);
1583 int tReg2 = oatAllocTemp(cUnit);
1584 if (lit == 2) {
1585 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1586 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1587 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1588 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1589 } else {
1590 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1591 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1592 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1593 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1594 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1595 }
1596 }
1597 storeValue(cUnit, rlDest, rlResult);
1598 return true;
1599}
1600
1601void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1602 RegLocation rlResult, int lit,
1603 int firstBit, int secondBit)
1604{
buzbee0398c422012-03-02 15:22:47 -08001605#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001606 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1607 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001608#else
1609 int tReg = oatAllocTemp(cUnit);
1610 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1611 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1612 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001613#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001614 if (firstBit != 0) {
1615 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1616 }
1617}
1618
1619// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1620// and store the result in 'rlDest'.
1621bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1622 RegLocation rlDest, int lit)
1623{
1624 // Can we simplify this multiplication?
1625 bool powerOfTwo = false;
1626 bool popCountLE2 = false;
1627 bool powerOfTwoMinusOne = false;
1628 if (lit < 2) {
1629 // Avoid special cases.
1630 return false;
1631 } else if (isPowerOfTwo(lit)) {
1632 powerOfTwo = true;
1633 } else if (isPopCountLE2(lit)) {
1634 popCountLE2 = true;
1635 } else if (isPowerOfTwo(lit + 1)) {
1636 powerOfTwoMinusOne = true;
1637 } else {
1638 return false;
1639 }
1640 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1641 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1642 if (powerOfTwo) {
1643 // Shift.
1644 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1645 lowestSetBit(lit));
1646 } else if (popCountLE2) {
1647 // Shift and add and shift.
1648 int firstBit = lowestSetBit(lit);
1649 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1650 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1651 firstBit, secondBit);
1652 } else {
1653 // Reverse subtract: (src << (shift + 1)) - src.
1654 DCHECK(powerOfTwoMinusOne);
1655 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1656 int tReg = oatAllocTemp(cUnit);
1657 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1658 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1659 }
1660 storeValue(cUnit, rlDest, rlResult);
1661 return true;
1662}
1663
1664bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1665 RegLocation rlSrc, int lit)
1666{
1667 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1668 RegLocation rlResult;
1669 OpKind op = (OpKind)0; /* Make gcc happy */
1670 int shiftOp = false;
1671 bool isDiv = false;
1672 int funcOffset;
1673 int rTgt;
1674
1675 switch (dalvikOpcode) {
1676 case OP_RSUB_INT_LIT8:
1677 case OP_RSUB_INT: {
1678 int tReg;
1679 //TUNING: add support for use of Arm rsub op
1680 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1681 tReg = oatAllocTemp(cUnit);
1682 loadConstant(cUnit, tReg, lit);
1683 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1684 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1685 tReg, rlSrc.lowReg);
1686 storeValue(cUnit, rlDest, rlResult);
1687 return false;
1688 break;
1689 }
1690
1691 case OP_ADD_INT_LIT8:
1692 case OP_ADD_INT_LIT16:
1693 op = kOpAdd;
1694 break;
1695 case OP_MUL_INT_LIT8:
1696 case OP_MUL_INT_LIT16: {
1697 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1698 return false;
1699 }
1700 op = kOpMul;
1701 break;
1702 }
1703 case OP_AND_INT_LIT8:
1704 case OP_AND_INT_LIT16:
1705 op = kOpAnd;
1706 break;
1707 case OP_OR_INT_LIT8:
1708 case OP_OR_INT_LIT16:
1709 op = kOpOr;
1710 break;
1711 case OP_XOR_INT_LIT8:
1712 case OP_XOR_INT_LIT16:
1713 op = kOpXor;
1714 break;
1715 case OP_SHL_INT_LIT8:
1716 lit &= 31;
1717 shiftOp = true;
1718 op = kOpLsl;
1719 break;
1720 case OP_SHR_INT_LIT8:
1721 lit &= 31;
1722 shiftOp = true;
1723 op = kOpAsr;
1724 break;
1725 case OP_USHR_INT_LIT8:
1726 lit &= 31;
1727 shiftOp = true;
1728 op = kOpLsr;
1729 break;
1730
1731 case OP_DIV_INT_LIT8:
1732 case OP_DIV_INT_LIT16:
1733 case OP_REM_INT_LIT8:
1734 case OP_REM_INT_LIT16:
1735 if (lit == 0) {
1736 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
1737 return false;
1738 }
1739 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
1740 return false;
1741 }
1742 oatFlushAllRegs(cUnit); /* Everything to home location */
1743 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1744 oatClobber(cUnit, rARG0);
1745 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
1746 (dalvikOpcode == OP_DIV_INT_LIT16)) {
1747 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1748 isDiv = true;
1749 } else {
1750 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1751 isDiv = false;
1752 }
1753 rTgt = loadHelper(cUnit, funcOffset);
1754 loadConstant(cUnit, rARG1, lit);
1755 callRuntimeHelper(cUnit, rTgt);
1756 if (isDiv)
1757 rlResult = oatGetReturn(cUnit);
1758 else
1759 rlResult = oatGetReturnAlt(cUnit);
1760 storeValue(cUnit, rlDest, rlResult);
1761 return false;
1762 break;
1763 default:
1764 return true;
1765 }
1766 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1767 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1768 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
1769 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08001770 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001771 } else {
1772 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
1773 }
1774 storeValue(cUnit, rlDest, rlResult);
1775 return false;
1776}
1777
1778bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1779 RegLocation rlSrc1, RegLocation rlSrc2)
1780{
1781 RegLocation rlResult;
1782 OpKind firstOp = kOpBkpt;
1783 OpKind secondOp = kOpBkpt;
1784 bool callOut = false;
1785 bool checkZero = false;
1786 int funcOffset;
1787 int retReg = rRET0;
1788
1789 switch (mir->dalvikInsn.opcode) {
1790 case OP_NOT_LONG:
1791 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1792 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1793 // Check for destructive overlap
1794 if (rlResult.lowReg == rlSrc2.highReg) {
1795 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001796 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001797 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1798 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1799 oatFreeTemp(cUnit, tReg);
1800 } else {
1801 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1802 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1803 }
1804 storeValueWide(cUnit, rlDest, rlResult);
1805 return false;
1806 break;
1807 case OP_ADD_LONG:
1808 case OP_ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001809#if defined(TARGET_MIPS)
1810 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1811#else
buzbee31a4a6f2012-02-28 15:36:15 -08001812 firstOp = kOpAdd;
1813 secondOp = kOpAdc;
1814 break;
buzbeec5159d52012-03-03 11:48:39 -08001815#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001816 case OP_SUB_LONG:
1817 case OP_SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001818#if defined(TARGET_MIPS)
1819 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1820#else
buzbee31a4a6f2012-02-28 15:36:15 -08001821 firstOp = kOpSub;
1822 secondOp = kOpSbc;
1823 break;
buzbeec5159d52012-03-03 11:48:39 -08001824#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001825 case OP_MUL_LONG:
1826 case OP_MUL_LONG_2ADDR:
1827 callOut = true;
1828 retReg = rRET0;
1829 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1830 break;
1831 case OP_DIV_LONG:
1832 case OP_DIV_LONG_2ADDR:
1833 callOut = true;
1834 checkZero = true;
1835 retReg = rRET0;
1836 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1837 break;
1838 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
1839 // FIXME: is true, or could be made true, or other targets?
1840 case OP_REM_LONG:
1841 case OP_REM_LONG_2ADDR:
1842 callOut = true;
1843 checkZero = true;
1844 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1845 retReg = rARG2;
1846 break;
1847 case OP_AND_LONG_2ADDR:
1848 case OP_AND_LONG:
1849 firstOp = kOpAnd;
1850 secondOp = kOpAnd;
1851 break;
1852 case OP_OR_LONG:
1853 case OP_OR_LONG_2ADDR:
1854 firstOp = kOpOr;
1855 secondOp = kOpOr;
1856 break;
1857 case OP_XOR_LONG:
1858 case OP_XOR_LONG_2ADDR:
1859 firstOp = kOpXor;
1860 secondOp = kOpXor;
1861 break;
1862 case OP_NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08001863 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08001864 }
1865 default:
1866 LOG(FATAL) << "Invalid long arith op";
1867 }
1868 if (!callOut) {
1869 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1870 } else {
1871 int rTgt;
1872 oatFlushAllRegs(cUnit); /* Send everything to home location */
1873 if (checkZero) {
1874 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1875 rTgt = loadHelper(cUnit, funcOffset);
1876 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1877 int tReg = oatAllocTemp(cUnit);
1878#if defined(TARGET_ARM)
1879 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
1880 oatFreeTemp(cUnit, tReg);
1881 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
1882#else
1883 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
buzbee5de34942012-03-01 14:51:57 -08001884 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08001885 oatFreeTemp(cUnit, tReg);
1886#endif
1887 } else {
1888 rTgt = loadHelper(cUnit, funcOffset);
1889 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1890 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1891 }
1892 callRuntimeHelper(cUnit, rTgt);
1893 // Adjust return regs in to handle case of rem returning rARG2/rARG3
1894 if (retReg == rRET0)
1895 rlResult = oatGetReturnWide(cUnit);
1896 else
1897 rlResult = oatGetReturnWideAlt(cUnit);
1898 storeValueWide(cUnit, rlDest, rlResult);
1899 }
1900 return false;
1901}
1902
1903bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
1904 int srcSize, int tgtSize)
1905{
1906 /*
1907 * Don't optimize the register usage since it calls out to support
1908 * functions
1909 */
1910 RegLocation rlSrc;
1911 RegLocation rlDest;
1912 oatFlushAllRegs(cUnit); /* Send everything to home location */
1913 int rTgt = loadHelper(cUnit, funcOffset);
1914 if (srcSize == 1) {
1915 rlSrc = oatGetSrc(cUnit, mir, 0);
1916 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1917 } else {
1918 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1919 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
1920 }
1921 callRuntimeHelper(cUnit, rTgt);
1922 if (tgtSize == 1) {
1923 RegLocation rlResult;
1924 rlDest = oatGetDest(cUnit, mir, 0);
1925 rlResult = oatGetReturn(cUnit);
1926 storeValue(cUnit, rlDest, rlResult);
1927 } else {
1928 RegLocation rlResult;
1929 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1930 rlResult = oatGetReturnWide(cUnit);
1931 storeValueWide(cUnit, rlDest, rlResult);
1932 }
1933 return false;
1934}
1935
1936void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
1937bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
1938 RegLocation rlDest, RegLocation rlSrc1,
1939 RegLocation rlSrc2)
1940{
1941 RegLocation rlResult;
1942 int funcOffset;
1943
1944 switch (mir->dalvikInsn.opcode) {
1945 case OP_ADD_FLOAT_2ADDR:
1946 case OP_ADD_FLOAT:
1947 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1948 break;
1949 case OP_SUB_FLOAT_2ADDR:
1950 case OP_SUB_FLOAT:
1951 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1952 break;
1953 case OP_DIV_FLOAT_2ADDR:
1954 case OP_DIV_FLOAT:
1955 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1956 break;
1957 case OP_MUL_FLOAT_2ADDR:
1958 case OP_MUL_FLOAT:
1959 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1960 break;
1961 case OP_REM_FLOAT_2ADDR:
1962 case OP_REM_FLOAT:
1963 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1964 break;
1965 case OP_NEG_FLOAT: {
1966 genNegFloat(cUnit, rlDest, rlSrc1);
1967 return false;
1968 }
1969 default:
1970 return true;
1971 }
1972 oatFlushAllRegs(cUnit); /* Send everything to home location */
1973 int rTgt = loadHelper(cUnit, funcOffset);
1974 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1975 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
1976 callRuntimeHelper(cUnit, rTgt);
1977 rlResult = oatGetReturn(cUnit);
1978 storeValue(cUnit, rlDest, rlResult);
1979 return false;
1980}
1981
1982void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
1983bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
1984 RegLocation rlDest, RegLocation rlSrc1,
1985 RegLocation rlSrc2)
1986{
1987 RegLocation rlResult;
1988 int funcOffset;
1989
1990 switch (mir->dalvikInsn.opcode) {
1991 case OP_ADD_DOUBLE_2ADDR:
1992 case OP_ADD_DOUBLE:
1993 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
1994 break;
1995 case OP_SUB_DOUBLE_2ADDR:
1996 case OP_SUB_DOUBLE:
1997 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
1998 break;
1999 case OP_DIV_DOUBLE_2ADDR:
2000 case OP_DIV_DOUBLE:
2001 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2002 break;
2003 case OP_MUL_DOUBLE_2ADDR:
2004 case OP_MUL_DOUBLE:
2005 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2006 break;
2007 case OP_REM_DOUBLE_2ADDR:
2008 case OP_REM_DOUBLE:
2009 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2010 break;
2011 case OP_NEG_DOUBLE: {
2012 genNegDouble(cUnit, rlDest, rlSrc1);
2013 return false;
2014 }
2015 default:
2016 return true;
2017 }
2018 oatFlushAllRegs(cUnit); /* Send everything to home location */
2019 int rTgt = loadHelper(cUnit, funcOffset);
2020 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2021 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2022 callRuntimeHelper(cUnit, rTgt);
2023 rlResult = oatGetReturnWide(cUnit);
2024 storeValueWide(cUnit, rlDest, rlResult);
2025 return false;
2026}
2027
2028bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2029{
2030 Opcode opcode = mir->dalvikInsn.opcode;
2031
2032 switch (opcode) {
2033 case OP_INT_TO_FLOAT:
2034 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2035 1, 1);
2036 case OP_FLOAT_TO_INT:
2037 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2038 1, 1);
2039 case OP_DOUBLE_TO_FLOAT:
2040 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2041 2, 1);
2042 case OP_FLOAT_TO_DOUBLE:
2043 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2044 1, 2);
2045 case OP_INT_TO_DOUBLE:
2046 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2047 1, 2);
2048 case OP_DOUBLE_TO_INT:
2049 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2050 2, 1);
2051 case OP_FLOAT_TO_LONG:
2052 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2053 pF2l), 1, 2);
2054 case OP_LONG_TO_FLOAT:
2055 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2056 2, 1);
2057 case OP_DOUBLE_TO_LONG:
2058 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2059 pD2l), 2, 2);
2060 case OP_LONG_TO_DOUBLE:
2061 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2062 2, 2);
2063 default:
2064 return true;
2065 }
2066 return false;
2067}
2068
2069/*
2070 * Generate callout to updateDebugger. Note that we're overloading
2071 * the use of rSUSPEND here. When the debugger is active, this
2072 * register holds the address of the update function. So, if it's
2073 * non-null, we call out to it.
2074 *
2075 * Note also that rRET0 and rRET1 must be preserved across this
2076 * code. This must be handled by the stub.
2077 */
2078void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2079{
2080 // Following DCHECK verifies that dPC is in range of single load immediate
2081 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2082 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2083 oatClobberCalleeSave(cUnit);
2084#if defined(TARGET_ARM)
2085 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002086 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002087 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2088 opReg(cUnit, kOpBlx, rSUSPEND);
2089#else
buzbee82488f52012-03-02 08:20:26 -08002090 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002091 loadConstant(cUnit, rARG2, offset);
2092 opReg(cUnit, kOpBlx, rSUSPEND);
2093 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002094 branch->target = (LIR*)target;
2095#endif
2096 oatFreeTemp(cUnit, rARG2);
2097}
2098
2099/* Check if we need to check for pending suspend request */
2100void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2101{
2102 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2103 return;
2104 }
2105 oatFlushAllRegs(cUnit);
2106 LIR* branch;
2107 if (cUnit->genDebugger) {
2108 // If generating code for the debugger, always check for suspension
buzbee82488f52012-03-02 08:20:26 -08002109 branch = opUnconditionalBranch(cUnit, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002110 } else {
2111#if defined(TARGET_ARM)
2112 // In non-debug case, only check periodically
2113 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002114 branch = opCondBranch(cUnit, kCondEq, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002115#else
2116 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002117 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002118#endif
2119 }
2120 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
buzbeea2ebdd72012-03-04 14:57:06 -08002121 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2122 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
buzbee31a4a6f2012-02-28 15:36:15 -08002123 branch->target = (LIR*)target;
2124 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
2125}
2126
2127} // namespace art