blob: 1c4e6c805e3cf42efa0fd3957582ed483c626d9a [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{
buzbeea7678db2012-03-05 15:35:46 -0800368#if defined(TARGET_X86)
369 UNIMPLEMENTED(WARNING) << "genSput";
370#else
buzbee31a4a6f2012-02-28 15:36:15 -0800371 int fieldOffset;
372 int ssbIndex;
373 bool isVolatile;
374 bool isReferrersClass;
375 uint32_t fieldIdx = mir->dalvikInsn.vB;
376
377 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
378 *cUnit->dex_file, *cUnit->dex_cache,
379 cUnit->code_item, cUnit->method_idx,
380 cUnit->access_flags);
381
382 bool fastPath =
383 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
384 fieldOffset, ssbIndex,
385 isReferrersClass, isVolatile, true);
386 if (fastPath && !SLOW_FIELD_PATH) {
387 DCHECK_GE(fieldOffset, 0);
388 int rBase;
389 int rMethod;
390 if (isReferrersClass) {
391 // Fast path, static storage base is this method's class
392 rMethod = loadCurrMethod(cUnit);
393 rBase = oatAllocTemp(cUnit);
394 loadWordDisp(cUnit, rMethod,
395 Method::DeclaringClassOffset().Int32Value(), rBase);
396 } else {
397 // Medium path, static storage base in a different class which
398 // requires checks that the other class is initialized.
399 DCHECK_GE(ssbIndex, 0);
400 // May do runtime call so everything to home locations.
401 oatFlushAllRegs(cUnit);
402 // Using fixed register to sync with possible call to runtime
403 // support.
404 rMethod = rARG1;
405 oatLockTemp(cUnit, rMethod);
406 loadCurrMethodDirect(cUnit, rMethod);
407 rBase = rARG0;
408 oatLockTemp(cUnit, rBase);
409 loadWordDisp(cUnit, rMethod,
410 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
411 rBase);
412 loadWordDisp(cUnit, rBase,
413 Array::DataOffset(sizeof(Object*)).Int32Value() + sizeof(int32_t*) *
414 ssbIndex, rBase);
415 // rBase now points at appropriate static storage base (Class*)
416 // or NULL if not initialized. Check for NULL and call helper if NULL.
417 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800418 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800419 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
420 pInitializeStaticStorage));
421 loadConstant(cUnit, rARG0, ssbIndex);
422 callRuntimeHelper(cUnit, rTgt);
423#if defined(TARGET_MIPS)
424 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800425 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800426#endif
427 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800428 branchOver->target = (LIR*)skipTarget;
429 }
430 // rBase now holds static storage base
431 oatFreeTemp(cUnit, rMethod);
432 if (isLongOrDouble) {
433 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
434 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
435 } else {
436 rlSrc = oatGetSrc(cUnit, mir, 0);
437 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
438 }
439//FIXME: need to generalize the barrier call
440 if (isVolatile) {
441 oatGenMemBarrier(cUnit, kST);
442 }
443 if (isLongOrDouble) {
444 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
445 rlSrc.highReg);
446 } else {
447 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
448 }
449 if (isVolatile) {
450 oatGenMemBarrier(cUnit, kSY);
451 }
452 if (isObject) {
453 markGCCard(cUnit, rlSrc.lowReg, rBase);
454 }
455 oatFreeTemp(cUnit, rBase);
456 } else {
457 oatFlushAllRegs(cUnit); // Everything to home locations
458 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
459 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
460 : OFFSETOF_MEMBER(Thread, pSet32Static));
461 int rTgt = loadHelper(cUnit, setterOffset);
462 loadConstant(cUnit, rARG0, fieldIdx);
463 if (isLongOrDouble) {
464 loadValueDirectWideFixed(cUnit, rlSrc, rARG2, rARG3);
465 } else {
466 loadValueDirect(cUnit, rlSrc, rARG1);
467 }
468 callRuntimeHelper(cUnit, rTgt);
469 }
buzbeea7678db2012-03-05 15:35:46 -0800470#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800471}
472
473void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
474 bool isLongOrDouble, bool isObject)
475{
476 int fieldOffset;
477 int ssbIndex;
478 bool isVolatile;
479 bool isReferrersClass;
480 uint32_t fieldIdx = mir->dalvikInsn.vB;
481
482 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
483 *cUnit->dex_file, *cUnit->dex_cache,
484 cUnit->code_item, cUnit->method_idx,
485 cUnit->access_flags);
486
487 bool fastPath =
488 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
489 fieldOffset, ssbIndex,
490 isReferrersClass, isVolatile,
491 false);
492 if (fastPath && !SLOW_FIELD_PATH) {
493 DCHECK_GE(fieldOffset, 0);
494 int rBase;
495 int rMethod;
496 if (isReferrersClass) {
497 // Fast path, static storage base is this method's class
498 rMethod = loadCurrMethod(cUnit);
499 rBase = oatAllocTemp(cUnit);
500 loadWordDisp(cUnit, rMethod,
501 Method::DeclaringClassOffset().Int32Value(), rBase);
502 } else {
503 // Medium path, static storage base in a different class which
504 // requires checks that the other class is initialized
505 DCHECK_GE(ssbIndex, 0);
506 // May do runtime call so everything to home locations.
507 oatFlushAllRegs(cUnit);
508 // Using fixed register to sync with possible call to runtime
509 // support
510 rMethod = rARG1;
511 oatLockTemp(cUnit, rMethod);
512 loadCurrMethodDirect(cUnit, rMethod);
513 rBase = rARG0;
514 oatLockTemp(cUnit, rBase);
515 loadWordDisp(cUnit, rMethod,
516 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
517 rBase);
518 loadWordDisp(cUnit, rBase,
519 Array::DataOffset(sizeof(Object*)).Int32Value() +
520 sizeof(int32_t*) * ssbIndex,
521 rBase);
522 // rBase now points at appropriate static storage base (Class*)
523 // or NULL if not initialized. Check for NULL and call helper if NULL.
524 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800525 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800526 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
527 pInitializeStaticStorage));
528 loadConstant(cUnit, rARG0, ssbIndex);
529 callRuntimeHelper(cUnit, rTgt);
530#if defined(TARGET_MIPS)
531 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800532 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800533#endif
534 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800535 branchOver->target = (LIR*)skipTarget;
536 }
537 // rBase now holds static storage base
538 oatFreeTemp(cUnit, rMethod);
539 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
540 : oatGetDest(cUnit, mir, 0);
541 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
542 if (isVolatile) {
543 oatGenMemBarrier(cUnit, kSY);
544 }
545 if (isLongOrDouble) {
546 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
547 rlResult.highReg, INVALID_SREG);
548 } else {
549 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
550 }
551 oatFreeTemp(cUnit, rBase);
552 if (isLongOrDouble) {
553 storeValueWide(cUnit, rlDest, rlResult);
554 } else {
555 storeValue(cUnit, rlDest, rlResult);
556 }
557 } else {
558 oatFlushAllRegs(cUnit); // Everything to home locations
559 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
560 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
561 : OFFSETOF_MEMBER(Thread, pGet32Static));
562 int rTgt = loadHelper(cUnit, getterOffset);
563 loadConstant(cUnit, rARG0, fieldIdx);
564 callRuntimeHelper(cUnit, rTgt);
565 if (isLongOrDouble) {
566 RegLocation rlResult = oatGetReturnWide(cUnit);
567 storeValueWide(cUnit, rlDest, rlResult);
568 } else {
569 RegLocation rlResult = oatGetReturn(cUnit);
570 storeValue(cUnit, rlDest, rlResult);
571 }
572 }
573}
574
575
576// Debugging routine - if null target, branch to DebugMe
577void genShowTarget(CompilationUnit* cUnit)
578{
buzbeea7678db2012-03-05 15:35:46 -0800579#if defined(TARGET_X86)
580 UNIMPLEMENTED(WARNING) << "genShowTarget";
581#else
buzbee0398c422012-03-02 15:22:47 -0800582 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800583 loadWordDisp(cUnit, rSELF,
buzbee0398c422012-03-02 15:22:47 -0800584 OFFSETOF_MEMBER(Thread, pDebugMe), rINVOKE_TGT);
buzbee31a4a6f2012-02-28 15:36:15 -0800585 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800586 branchOver->target = (LIR*)target;
buzbeea7678db2012-03-05 15:35:46 -0800587#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800588}
589
590void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
591{
592 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
593 pThrowVerificationErrorFromCode));
594 loadConstant(cUnit, rARG0, mir->dalvikInsn.vA);
595 loadConstant(cUnit, rARG1, mir->dalvikInsn.vB);
596 callRuntimeHelper(cUnit, rTgt);
597}
598
599void handleSuspendLaunchpads(CompilationUnit *cUnit)
600{
buzbeea7678db2012-03-05 15:35:46 -0800601#if defined(TARGET_X86)
602 UNIMPLEMENTED(WARNING);
603#else
buzbee31a4a6f2012-02-28 15:36:15 -0800604 LIR** suspendLabel =
605 (LIR **) cUnit->suspendLaunchpads.elemList;
606 int numElems = cUnit->suspendLaunchpads.numUsed;
607
608 for (int i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800609 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800610 /* TUNING: move suspend count load into helper */
611 LIR* lab = suspendLabel[i];
612 LIR* resumeLab = (LIR*)lab->operands[0];
613 cUnit->currentDalvikOffset = lab->operands[1];
614 oatAppendLIR(cUnit, (LIR *)lab);
615 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
616 pTestSuspendFromCode));
617 if (!cUnit->genDebugger) {
618 // use rSUSPEND for suspend count
619 loadWordDisp(cUnit, rSELF,
620 Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
621 }
622 opReg(cUnit, kOpBlx, rTgt);
623 if ( cUnit->genDebugger) {
624 // use rSUSPEND for update debugger
625 loadWordDisp(cUnit, rSELF,
626 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
627 rSUSPEND);
628 }
buzbee82488f52012-03-02 08:20:26 -0800629 opUnconditionalBranch(cUnit, resumeLab);
buzbee31a4a6f2012-02-28 15:36:15 -0800630 }
buzbeea7678db2012-03-05 15:35:46 -0800631#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800632}
633
634void handleThrowLaunchpads(CompilationUnit *cUnit)
635{
636 LIR** throwLabel = (LIR **) cUnit->throwLaunchpads.elemList;
637 int numElems = cUnit->throwLaunchpads.numUsed;
638 int i;
639
640 for (i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800641 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800642 LIR* lab = throwLabel[i];
643 cUnit->currentDalvikOffset = lab->operands[1];
644 oatAppendLIR(cUnit, (LIR *)lab);
645 int funcOffset = 0;
646 int v1 = lab->operands[2];
647 int v2 = lab->operands[3];
648 switch(lab->operands[0]) {
649 case kThrowNullPointer:
650 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
651 break;
652 case kThrowArrayBounds:
buzbee5de34942012-03-01 14:51:57 -0800653 if (v2 != rARG0) {
buzbee82488f52012-03-02 08:20:26 -0800654 opRegCopy(cUnit, rARG0, v1);
655 opRegCopy(cUnit, rARG1, v2);
buzbee31a4a6f2012-02-28 15:36:15 -0800656 } else {
buzbee5de34942012-03-01 14:51:57 -0800657 if (v1 == rARG1) {
buzbee31a4a6f2012-02-28 15:36:15 -0800658#if defined(TARGET_ARM)
659 int rTmp = r12;
660#else
661 int rTmp = oatAllocTemp(cUnit);
662#endif
buzbee82488f52012-03-02 08:20:26 -0800663 opRegCopy(cUnit, rTmp, v1);
664 opRegCopy(cUnit, rARG1, v2);
665 opRegCopy(cUnit, rARG0, rTmp);
buzbee31a4a6f2012-02-28 15:36:15 -0800666 } else {
buzbee82488f52012-03-02 08:20:26 -0800667 opRegCopy(cUnit, rARG1, v2);
668 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800669 }
670 }
671 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
672 break;
673 case kThrowDivZero:
674 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
675 break;
676 case kThrowVerificationError:
677 loadConstant(cUnit, rARG0, v1);
678 loadConstant(cUnit, rARG1, v2);
679 funcOffset =
680 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
681 break;
682 case kThrowNegArraySize:
buzbee82488f52012-03-02 08:20:26 -0800683 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800684 funcOffset =
685 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
686 break;
687 case kThrowNoSuchMethod:
buzbee82488f52012-03-02 08:20:26 -0800688 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800689 funcOffset =
690 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
691 break;
692 case kThrowStackOverflow:
693 funcOffset =
694 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
695 // Restore stack alignment
696 opRegImm(cUnit, kOpAdd, rSP,
697 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
698 break;
699 default:
700 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
701 }
702 int rTgt = loadHelper(cUnit, funcOffset);
703 callRuntimeHelper(cUnit, rTgt);
buzbee0398c422012-03-02 15:22:47 -0800704 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800705 }
706}
707
708/* Needed by the Assembler */
709void oatSetupResourceMasks(LIR* lir)
710{
711 setupResourceMasks(lir);
712}
713
714void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
715 RegLocation rlDest, RegLocation rlObj,
716 bool isLongOrDouble, bool isObject)
717{
718 int fieldOffset;
719 bool isVolatile;
720 uint32_t fieldIdx = mir->dalvikInsn.vC;
721
722 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
723 *cUnit->dex_file, *cUnit->dex_cache,
724 cUnit->code_item, cUnit->method_idx,
725 cUnit->access_flags);
726
727 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
728 fieldOffset, isVolatile, false);
729
730 if (fastPath && !SLOW_FIELD_PATH) {
731 RegLocation rlResult;
732 RegisterClass regClass = oatRegClassBySize(size);
733 DCHECK_GE(fieldOffset, 0);
734 rlObj = loadValue(cUnit, rlObj, kCoreReg);
735 if (isLongOrDouble) {
736 DCHECK(rlDest.wide);
737 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
738 int regPtr = oatAllocTemp(cUnit);
739 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
740 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
741 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
742 if (isVolatile) {
743 oatGenMemBarrier(cUnit, kSY);
744 }
745 oatFreeTemp(cUnit, regPtr);
746 storeValueWide(cUnit, rlDest, rlResult);
747 } else {
748 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
749 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
750 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
751 kWord, rlObj.sRegLow);
752 if (isVolatile) {
753 oatGenMemBarrier(cUnit, kSY);
754 }
755 storeValue(cUnit, rlDest, rlResult);
756 }
757 } else {
758 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
759 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
760 : OFFSETOF_MEMBER(Thread, pGet32Instance));
761 int rTgt = loadHelper(cUnit, getterOffset);
762 loadValueDirect(cUnit, rlObj, rARG1);
763 loadConstant(cUnit, rARG0, fieldIdx);
764 callRuntimeHelper(cUnit, rTgt);
765 if (isLongOrDouble) {
766 RegLocation rlResult = oatGetReturnWide(cUnit);
767 storeValueWide(cUnit, rlDest, rlResult);
768 } else {
769 RegLocation rlResult = oatGetReturn(cUnit);
770 storeValue(cUnit, rlDest, rlResult);
771 }
772 }
773}
774
775void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, RegLocation rlSrc,
776 RegLocation rlObj, bool isLongOrDouble, bool isObject)
777{
buzbeea7678db2012-03-05 15:35:46 -0800778#if defined(TARGET_X86)
779 UNIMPLEMENTED(WARNING);
780#else
buzbee31a4a6f2012-02-28 15:36:15 -0800781 int fieldOffset;
782 bool isVolatile;
783 uint32_t fieldIdx = mir->dalvikInsn.vC;
784
785 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
786 *cUnit->dex_file, *cUnit->dex_cache,
787 cUnit->code_item, cUnit->method_idx,
788 cUnit->access_flags);
789
790 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
791 fieldOffset, isVolatile, true);
792 if (fastPath && !SLOW_FIELD_PATH) {
793 RegisterClass regClass = oatRegClassBySize(size);
794 DCHECK_GE(fieldOffset, 0);
795 rlObj = loadValue(cUnit, rlObj, kCoreReg);
796 if (isLongOrDouble) {
797 int regPtr;
798 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
799 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
800 regPtr = oatAllocTemp(cUnit);
801 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
802 if (isVolatile) {
803 oatGenMemBarrier(cUnit, kST);
804 }
805 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
806 if (isVolatile) {
807 oatGenMemBarrier(cUnit, kSY);
808 }
809 oatFreeTemp(cUnit, regPtr);
810 } else {
811 rlSrc = loadValue(cUnit, rlSrc, regClass);
812 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
813 if (isVolatile) {
814 oatGenMemBarrier(cUnit, kST);
815 }
816 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
817 if (isVolatile) {
818 oatGenMemBarrier(cUnit, kSY);
819 }
820 }
821 } else {
822 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
823 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
824 : OFFSETOF_MEMBER(Thread, pSet32Instance));
825 int rTgt = loadHelper(cUnit, setterOffset);
826 loadValueDirect(cUnit, rlObj, rARG1);
827 if (isLongOrDouble) {
828 loadValueDirectWide(cUnit, rlSrc, rARG2, rARG3);
829 } else {
830 loadValueDirect(cUnit, rlSrc, rARG2);
831 }
832 loadConstant(cUnit, rARG0, fieldIdx);
833 callRuntimeHelper(cUnit, rTgt);
834 }
buzbeea7678db2012-03-05 15:35:46 -0800835#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800836}
837
838void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
839 RegLocation rlSrc)
840{
841 uint32_t type_idx = mir->dalvikInsn.vB;
842 int mReg = loadCurrMethod(cUnit);
843 int resReg = oatAllocTemp(cUnit);
844 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
845 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
846 cUnit->dex_cache,
847 *cUnit->dex_file,
848 type_idx)) {
849 // Call out to helper which resolves type and verifies access.
850 // Resolved type returned in rRET0.
851 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
852 pInitializeTypeAndVerifyAccessFromCode));
buzbee82488f52012-03-02 08:20:26 -0800853 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800854 loadConstant(cUnit, rARG0, type_idx);
855 callRuntimeHelper(cUnit, rTgt);
856 RegLocation rlResult = oatGetReturn(cUnit);
857 storeValue(cUnit, rlDest, rlResult);
858 } else {
859 // We're don't need access checks, load type from dex cache
860 int32_t dex_cache_offset =
861 Method::DexCacheResolvedTypesOffset().Int32Value();
862 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
863 int32_t offset_of_type =
864 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
865 * type_idx);
866 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
867 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
868 type_idx) || SLOW_TYPE_PATH) {
869 // Slow path, at runtime test if type is null and if so initialize
870 oatFlushAllRegs(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800871 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0,
872 NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800873 // Resolved, store and hop over following code
874 storeValue(cUnit, rlDest, rlResult);
buzbee82488f52012-03-02 08:20:26 -0800875 LIR* branch2 = opUnconditionalBranch(cUnit,0);
buzbee31a4a6f2012-02-28 15:36:15 -0800876 // TUNING: move slow path to end & remove unconditional branch
877 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800878 // Call out to helper, which will return resolved type in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800879 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
880 pInitializeTypeFromCode));
buzbee82488f52012-03-02 08:20:26 -0800881 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800882 loadConstant(cUnit, rARG0, type_idx);
883 callRuntimeHelper(cUnit, rTgt);
884 RegLocation rlResult = oatGetReturn(cUnit);
885 storeValue(cUnit, rlDest, rlResult);
886 // Rejoin code paths
887 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800888 branch1->target = (LIR*)target1;
889 branch2->target = (LIR*)target2;
890 } else {
891 // Fast path, we're done - just store result
892 storeValue(cUnit, rlDest, rlResult);
893 }
894 }
895}
896void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
897 RegLocation rlSrc)
898{
899 /* NOTE: Most strings should be available at compile time */
900 uint32_t string_idx = mir->dalvikInsn.vB;
901 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
902 (sizeof(String*) * string_idx);
903 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
904 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
905 // slow path, resolve string if not in dex cache
906 oatFlushAllRegs(cUnit);
907 oatLockCallTemps(cUnit); // Using explicit registers
908 loadCurrMethodDirect(cUnit, rARG2);
909 loadWordDisp(cUnit, rARG2,
910 Method::DexCacheStringsOffset().Int32Value(), rARG0);
911 // Might call out to helper, which will return resolved string in rRET0
912 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
913 pResolveStringFromCode));
914 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
915 loadConstant(cUnit, rARG1, string_idx);
916#if defined(TARGET_ARM)
917 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
918 genBarrier(cUnit);
919 // For testing, always force through helper
920 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee82488f52012-03-02 08:20:26 -0800921 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -0800922 }
buzbee82488f52012-03-02 08:20:26 -0800923 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800924 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
925#else
buzbee82488f52012-03-02 08:20:26 -0800926 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
927 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800928 opReg(cUnit, kOpBlx, rTgt);
929 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800930 branch->target = target;
931#endif
932 genBarrier(cUnit);
933 storeValue(cUnit, rlDest, getRetLoc(cUnit));
934 } else {
935 int mReg = loadCurrMethod(cUnit);
936 int resReg = oatAllocTemp(cUnit);
937 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
938 loadWordDisp(cUnit, mReg,
939 Method::DexCacheStringsOffset().Int32Value(), resReg);
940 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
941 storeValue(cUnit, rlDest, rlResult);
942 }
943}
944
945/*
946 * Let helper function take care of everything. Will
947 * call Class::NewInstanceFromCode(type_idx, method);
948 */
949void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
950{
951 oatFlushAllRegs(cUnit); /* Everything to home location */
952 uint32_t type_idx = mir->dalvikInsn.vB;
953 // alloc will always check for resolution, do we also need to verify
954 // access because the verifier was unable to?
955 int rTgt;
956 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
957 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
958 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode));
959 } else {
960 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
961 pAllocObjectFromCodeWithAccessCheck));
962 }
963 loadCurrMethodDirect(cUnit, rARG1); // arg1 <= Method*
964 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_idx
965 callRuntimeHelper(cUnit, rTgt);
966 RegLocation rlResult = oatGetReturn(cUnit);
967 storeValue(cUnit, rlDest, rlResult);
968}
969
970void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
971 RegLocation rlSrc)
972{
973 oatFlushAllRegs(cUnit);
974 // May generate a call - use explicit registers
975 oatLockCallTemps(cUnit);
976 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee5de34942012-03-01 14:51:57 -0800977 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
buzbee31a4a6f2012-02-28 15:36:15 -0800978 int classReg = rARG2; // rARG2 will hold the Class*
979 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
980 cUnit->dex_cache,
981 *cUnit->dex_file,
982 type_idx)) {
983 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbee5de34942012-03-01 14:51:57 -0800984 // returns Class* in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800985 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
986 pInitializeTypeAndVerifyAccessFromCode));
987 loadConstant(cUnit, rARG0, type_idx);
988 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -0800989 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee5de34942012-03-01 14:51:57 -0800990 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
buzbee31a4a6f2012-02-28 15:36:15 -0800991 } else {
buzbee5de34942012-03-01 14:51:57 -0800992 // Load dex cache entry into classReg (rARG2)
buzbee31a4a6f2012-02-28 15:36:15 -0800993 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
994 loadWordDisp(cUnit, rARG1,
995 Method::DexCacheResolvedTypesOffset().Int32Value(),
996 classReg);
997 int32_t offset_of_type =
998 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
999 * type_idx);
1000 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1001 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1002 cUnit->dex_cache, type_idx)) {
1003 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001004 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001005 // Not resolved
1006 // Call out to helper, which will return resolved type in rRET0
1007 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1008 pInitializeTypeFromCode));
1009 loadConstant(cUnit, rARG0, type_idx);
1010 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001011 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001012 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1013 // Rejoin code paths
1014 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001015 hopBranch->target = (LIR*)hopTarget;
1016 }
1017 }
1018 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
buzbee82488f52012-03-02 08:20:26 -08001019 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001020 /* load object->clazz */
1021 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1022 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1023 /* rARG0 is ref, rARG1 is ref->clazz, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001024#if defined(TARGET_ARM)
1025 /* Uses conditional nullification */
buzbee31a4a6f2012-02-28 15:36:15 -08001026 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1027 pInstanceofNonTrivialFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001028 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
buzbee82488f52012-03-02 08:20:26 -08001029 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
buzbee31a4a6f2012-02-28 15:36:15 -08001030 loadConstant(cUnit, rARG0, 1); // .eq case - load true
buzbee82488f52012-03-02 08:20:26 -08001031 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee31a4a6f2012-02-28 15:36:15 -08001032 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001033#else
buzbee0398c422012-03-02 15:22:47 -08001034 /* Uses branchovers */
1035 loadConstant(cUnit, rARG0, 1); // assume true
1036 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
1037 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1038 pInstanceofNonTrivialFromCode));
1039 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1040 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001041#endif
buzbee0398c422012-03-02 15:22:47 -08001042 oatClobberCalleeSave(cUnit);
1043 /* branch targets here */
buzbee31a4a6f2012-02-28 15:36:15 -08001044 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001045 RegLocation rlResult = oatGetReturn(cUnit);
1046 storeValue(cUnit, rlDest, rlResult);
buzbee0398c422012-03-02 15:22:47 -08001047 branch1->target = target;
1048#if !defined(TARGET_ARM)
1049 branchover->target = target;
1050#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001051}
1052
1053void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1054{
1055 oatFlushAllRegs(cUnit);
1056 // May generate a call - use explicit registers
1057 oatLockCallTemps(cUnit);
1058 uint32_t type_idx = mir->dalvikInsn.vB;
1059 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1060 int classReg = rARG2; // rARG2 will hold the Class*
1061 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1062 cUnit->dex_cache,
1063 *cUnit->dex_file,
1064 type_idx)) {
1065 // Check we have access to type_idx and if not throw IllegalAccessError,
1066 // returns Class* in rRET0
1067 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1068 pInitializeTypeAndVerifyAccessFromCode));
1069 loadConstant(cUnit, rARG0, type_idx);
1070 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001071 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001072 } else {
1073 // Load dex cache entry into classReg (rARG2)
1074 loadWordDisp(cUnit, rARG1,
1075 Method::DexCacheResolvedTypesOffset().Int32Value(),
1076 classReg);
1077 int32_t offset_of_type =
1078 Array::DataOffset(sizeof(Class*)).Int32Value() +
1079 (sizeof(Class*) * type_idx);
1080 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1081 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1082 cUnit->dex_cache, type_idx)) {
1083 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001084 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001085 // Not resolved
buzbee5de34942012-03-01 14:51:57 -08001086 // Call out to helper, which will return resolved type in rARG0
1087 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode));
1088 loadConstant(cUnit, rARG0, type_idx);
1089 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001090 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001091 // Rejoin code paths
1092 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001093 hopBranch->target = (LIR*)hopTarget;
1094 }
1095 }
buzbee5de34942012-03-01 14:51:57 -08001096 // At this point, classReg (rARG2) has class
buzbee31a4a6f2012-02-28 15:36:15 -08001097 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1098 /* Null is OK - continue */
buzbee82488f52012-03-02 08:20:26 -08001099 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001100 /* load object->clazz */
1101 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1102 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1103 /* rARG1 now contains object->clazz */
1104 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1105 pCheckCastFromCode));
buzbee5de34942012-03-01 14:51:57 -08001106#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -08001107 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
buzbee5de34942012-03-01 14:51:57 -08001108#else
buzbee31a4a6f2012-02-28 15:36:15 -08001109 opRegReg(cUnit, kOpCmp, rARG1, classReg);
buzbee82488f52012-03-02 08:20:26 -08001110 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
buzbee5de34942012-03-01 14:51:57 -08001111#endif
buzbee82488f52012-03-02 08:20:26 -08001112 opRegCopy(cUnit, rARG0, rARG1);
1113 opRegCopy(cUnit, rARG1, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08001114 callRuntimeHelper(cUnit, rTgt);
1115 /* branch target here */
1116 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001117 branch1->target = (LIR*)target;
1118 branch2->target = (LIR*)target;
1119}
1120
1121
1122void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1123{
1124 oatFlushAllRegs(cUnit);
1125 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException));
1126 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get exception object
1127 callRuntimeHelper(cUnit, rTgt); // art_deliver_exception(exception);
1128}
1129
1130/*
1131 * Generate array store
1132 *
1133 */
1134void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
1135 RegLocation rlIndex, RegLocation rlSrc, int scale)
1136{
1137 RegisterClass regClass = oatRegClassBySize(kWord);
1138 int lenOffset = Array::LengthOffset().Int32Value();
1139 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
1140
1141 oatFlushAllRegs(cUnit);
1142 /* Make sure it's a legal object Put. Use direct regs at first */
1143 loadValueDirectFixed(cUnit, rlArray, rARG1);
1144 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1145
1146 /* null array object? */
1147 genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
1148 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1149 pCanPutArrayElementFromCode));
1150 /* Get the array's clazz */
1151 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
1152 callRuntimeHelper(cUnit, rTgt);
1153 oatFreeTemp(cUnit, rARG0);
1154 oatFreeTemp(cUnit, rARG1);
1155
1156 // Now, redo loadValues in case they didn't survive the call
1157
1158 int regPtr;
1159 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1160 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1161
1162 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1163 oatClobber(cUnit, rlArray.lowReg);
1164 regPtr = rlArray.lowReg;
1165 } else {
1166 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001167 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001168 }
1169
1170 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1171 int regLen = oatAllocTemp(cUnit);
1172 //NOTE: max live temps(4) here.
1173 /* Get len */
1174 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1175 /* regPtr -> array data */
1176 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1177 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1178 kThrowArrayBounds);
1179 oatFreeTemp(cUnit, regLen);
1180 } else {
1181 /* regPtr -> array data */
1182 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1183 }
1184 /* at this point, regPtr points to array, 2 live temps */
1185 rlSrc = loadValue(cUnit, rlSrc, regClass);
1186 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1187 scale, kWord);
1188}
1189
1190/*
1191 * Generate array load
1192 */
1193void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1194 RegLocation rlArray, RegLocation rlIndex,
1195 RegLocation rlDest, int scale)
1196{
1197 RegisterClass regClass = oatRegClassBySize(size);
1198 int lenOffset = Array::LengthOffset().Int32Value();
1199 int dataOffset;
1200 RegLocation rlResult;
1201 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1202 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1203 int regPtr;
1204
1205 if (size == kLong || size == kDouble) {
1206 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1207 } else {
1208 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1209 }
1210
1211 /* null object? */
1212 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1213
1214 regPtr = oatAllocTemp(cUnit);
1215
1216 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1217 int regLen = oatAllocTemp(cUnit);
1218 /* Get len */
1219 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1220 /* regPtr -> array data */
1221 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1222 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1223 kThrowArrayBounds);
1224 oatFreeTemp(cUnit, regLen);
1225 } else {
1226 /* regPtr -> array data */
1227 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1228 }
1229 oatFreeTemp(cUnit, rlArray.lowReg);
1230 if ((size == kLong) || (size == kDouble)) {
1231 if (scale) {
1232 int rNewIndex = oatAllocTemp(cUnit);
1233 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1234 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1235 oatFreeTemp(cUnit, rNewIndex);
1236 } else {
1237 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1238 }
1239 oatFreeTemp(cUnit, rlIndex.lowReg);
1240 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1241
1242 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1243
1244 oatFreeTemp(cUnit, regPtr);
1245 storeValueWide(cUnit, rlDest, rlResult);
1246 } else {
1247 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1248
1249 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1250 scale, size);
1251
1252 oatFreeTemp(cUnit, regPtr);
1253 storeValue(cUnit, rlDest, rlResult);
1254 }
1255}
1256
1257/*
1258 * Generate array store
1259 *
1260 */
1261void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1262 RegLocation rlArray, RegLocation rlIndex,
1263 RegLocation rlSrc, int scale)
1264{
1265 RegisterClass regClass = oatRegClassBySize(size);
1266 int lenOffset = Array::LengthOffset().Int32Value();
1267 int dataOffset;
1268
1269 if (size == kLong || size == kDouble) {
1270 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1271 } else {
1272 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1273 }
1274
1275 int regPtr;
1276 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1277 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1278
1279 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1280 oatClobber(cUnit, rlArray.lowReg);
1281 regPtr = rlArray.lowReg;
1282 } else {
1283 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001284 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001285 }
1286
1287 /* null object? */
1288 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1289
1290 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1291 int regLen = oatAllocTemp(cUnit);
1292 //NOTE: max live temps(4) here.
1293 /* Get len */
1294 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1295 /* regPtr -> array data */
1296 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1297 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1298 kThrowArrayBounds);
1299 oatFreeTemp(cUnit, regLen);
1300 } else {
1301 /* regPtr -> array data */
1302 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1303 }
1304 /* at this point, regPtr points to array, 2 live temps */
1305 if ((size == kLong) || (size == kDouble)) {
1306 //TUNING: specific wide routine that can handle fp regs
1307 if (scale) {
1308 int rNewIndex = oatAllocTemp(cUnit);
1309 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1310 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1311 oatFreeTemp(cUnit, rNewIndex);
1312 } else {
1313 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1314 }
1315 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1316
1317 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1318
1319 oatFreeTemp(cUnit, regPtr);
1320 } else {
1321 rlSrc = loadValue(cUnit, rlSrc, regClass);
1322
1323 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1324 scale, size);
1325 }
1326}
1327
1328void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1329 OpKind secondOp, RegLocation rlDest,
1330 RegLocation rlSrc1, RegLocation rlSrc2)
1331{
1332 RegLocation rlResult;
1333#if defined(TARGET_ARM)
1334 /*
1335 * NOTE: This is the one place in the code in which we might have
1336 * as many as six live temporary registers. There are 5 in the normal
1337 * set for Arm. Until we have spill capabilities, temporarily add
1338 * lr to the temp set. It is safe to do this locally, but note that
1339 * lr is used explicitly elsewhere in the code generator and cannot
1340 * normally be used as a general temp register.
1341 */
1342 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1343 oatFreeTemp(cUnit, rLR); // and make it available
1344#endif
1345 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1346 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1347 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1348 // The longs may overlap - use intermediate temp if so
1349 if (rlResult.lowReg == rlSrc1.highReg) {
1350 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001351 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001352 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1353 rlSrc2.lowReg);
1354 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1355 rlSrc2.highReg);
1356 oatFreeTemp(cUnit, tReg);
1357 } else {
1358 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1359 rlSrc2.lowReg);
1360 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1361 rlSrc2.highReg);
1362 }
1363 /*
1364 * NOTE: If rlDest refers to a frame variable in a large frame, the
1365 * following storeValueWide might need to allocate a temp register.
1366 * To further work around the lack of a spill capability, explicitly
1367 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1368 * Remove when spill is functional.
1369 */
1370 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1371 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1372 storeValueWide(cUnit, rlDest, rlResult);
1373#if defined(TARGET_ARM)
1374 oatClobber(cUnit, rLR);
1375 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1376#endif
1377}
1378
1379
1380bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1381 RegLocation rlSrc1, RegLocation rlShift)
1382{
1383 int funcOffset;
1384
1385 switch( mir->dalvikInsn.opcode) {
1386 case OP_SHL_LONG:
1387 case OP_SHL_LONG_2ADDR:
1388 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1389 break;
1390 case OP_SHR_LONG:
1391 case OP_SHR_LONG_2ADDR:
1392 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1393 break;
1394 case OP_USHR_LONG:
1395 case OP_USHR_LONG_2ADDR:
1396 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1397 break;
1398 default:
1399 LOG(FATAL) << "Unexpected case";
1400 return true;
1401 }
1402 oatFlushAllRegs(cUnit); /* Send everything to home location */
1403 int rTgt = loadHelper(cUnit, funcOffset);
1404 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1405 loadValueDirect(cUnit, rlShift, rARG2);
1406 callRuntimeHelper(cUnit, rTgt);
1407 RegLocation rlResult = oatGetReturnWide(cUnit);
1408 storeValueWide(cUnit, rlDest, rlResult);
1409 return false;
1410}
1411
1412
1413bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1414 RegLocation rlSrc1, RegLocation rlSrc2)
1415{
1416 OpKind op = kOpBkpt;
1417 bool callOut = false;
1418 bool checkZero = false;
1419 bool unary = false;
1420 int retReg = rRET0;
1421 int funcOffset;
1422 RegLocation rlResult;
1423 bool shiftOp = false;
1424
1425 switch (mir->dalvikInsn.opcode) {
1426 case OP_NEG_INT:
1427 op = kOpNeg;
1428 unary = true;
1429 break;
1430 case OP_NOT_INT:
1431 op = kOpMvn;
1432 unary = true;
1433 break;
1434 case OP_ADD_INT:
1435 case OP_ADD_INT_2ADDR:
1436 op = kOpAdd;
1437 break;
1438 case OP_SUB_INT:
1439 case OP_SUB_INT_2ADDR:
1440 op = kOpSub;
1441 break;
1442 case OP_MUL_INT:
1443 case OP_MUL_INT_2ADDR:
1444 op = kOpMul;
1445 break;
1446 case OP_DIV_INT:
1447 case OP_DIV_INT_2ADDR:
1448 callOut = true;
1449 checkZero = true;
1450 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1451 retReg = rRET0;
1452 break;
buzbee5de34942012-03-01 14:51:57 -08001453 /* NOTE: returns in rARG1 */
buzbee31a4a6f2012-02-28 15:36:15 -08001454 case OP_REM_INT:
1455 case OP_REM_INT_2ADDR:
1456 callOut = true;
1457 checkZero = true;
1458 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1459 retReg = rRET1;
1460 break;
1461 case OP_AND_INT:
1462 case OP_AND_INT_2ADDR:
1463 op = kOpAnd;
1464 break;
1465 case OP_OR_INT:
1466 case OP_OR_INT_2ADDR:
1467 op = kOpOr;
1468 break;
1469 case OP_XOR_INT:
1470 case OP_XOR_INT_2ADDR:
1471 op = kOpXor;
1472 break;
1473 case OP_SHL_INT:
1474 case OP_SHL_INT_2ADDR:
1475 shiftOp = true;
1476 op = kOpLsl;
1477 break;
1478 case OP_SHR_INT:
1479 case OP_SHR_INT_2ADDR:
1480 shiftOp = true;
1481 op = kOpAsr;
1482 break;
1483 case OP_USHR_INT:
1484 case OP_USHR_INT_2ADDR:
1485 shiftOp = true;
1486 op = kOpLsr;
1487 break;
1488 default:
1489 LOG(FATAL) << "Invalid word arith op: " <<
1490 (int)mir->dalvikInsn.opcode;
1491 }
1492 if (!callOut) {
1493 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1494 if (unary) {
1495 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1496 opRegReg(cUnit, op, rlResult.lowReg,
1497 rlSrc1.lowReg);
1498 } else {
1499 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1500 if (shiftOp) {
1501 int tReg = oatAllocTemp(cUnit);
1502 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1503 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1504 opRegRegReg(cUnit, op, rlResult.lowReg,
1505 rlSrc1.lowReg, tReg);
1506 oatFreeTemp(cUnit, tReg);
1507 } else {
1508 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1509 opRegRegReg(cUnit, op, rlResult.lowReg,
1510 rlSrc1.lowReg, rlSrc2.lowReg);
1511 }
1512 }
1513 storeValue(cUnit, rlDest, rlResult);
1514 } else {
1515 RegLocation rlResult;
1516 oatFlushAllRegs(cUnit); /* Send everything to home location */
1517 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
1518 int rTgt = loadHelper(cUnit, funcOffset);
1519 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1520 if (checkZero) {
1521 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1522 }
1523 callRuntimeHelper(cUnit, rTgt);
1524 if (retReg == rRET0)
1525 rlResult = oatGetReturn(cUnit);
1526 else
1527 rlResult = oatGetReturnAlt(cUnit);
1528 storeValue(cUnit, rlDest, rlResult);
1529 }
1530 return false;
1531}
1532
1533/*
1534 * The following are the first-level codegen routines that analyze the format
1535 * of each bytecode then either dispatch special purpose codegen routines
1536 * or produce corresponding Thumb instructions directly.
1537 */
1538
1539bool isPowerOfTwo(int x)
1540{
1541 return (x & (x - 1)) == 0;
1542}
1543
1544// Returns true if no more than two bits are set in 'x'.
1545bool isPopCountLE2(unsigned int x)
1546{
1547 x &= x - 1;
1548 return (x & (x - 1)) == 0;
1549}
1550
1551// Returns the index of the lowest set bit in 'x'.
1552int lowestSetBit(unsigned int x) {
1553 int bit_posn = 0;
1554 while ((x & 0xf) == 0) {
1555 bit_posn += 4;
1556 x >>= 4;
1557 }
1558 while ((x & 1) == 0) {
1559 bit_posn++;
1560 x >>= 1;
1561 }
1562 return bit_posn;
1563}
1564
1565// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1566// and store the result in 'rlDest'.
1567bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
1568 RegLocation rlSrc, RegLocation rlDest, int lit)
1569{
1570 if (lit < 2 || !isPowerOfTwo(lit)) {
1571 return false;
1572 }
1573 int k = lowestSetBit(lit);
1574 if (k >= 30) {
1575 // Avoid special cases.
1576 return false;
1577 }
1578 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1579 dalvikOpcode == OP_DIV_INT_LIT16);
1580 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1581 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1582 if (div) {
1583 int tReg = oatAllocTemp(cUnit);
1584 if (lit == 2) {
1585 // Division by 2 is by far the most common division by constant.
1586 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1587 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1588 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1589 } else {
1590 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1591 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1592 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1593 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1594 }
1595 } else {
1596 int cReg = oatAllocTemp(cUnit);
1597 loadConstant(cUnit, cReg, lit - 1);
1598 int tReg1 = oatAllocTemp(cUnit);
1599 int tReg2 = oatAllocTemp(cUnit);
1600 if (lit == 2) {
1601 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1602 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1603 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1604 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1605 } else {
1606 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1607 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1608 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1609 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1610 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1611 }
1612 }
1613 storeValue(cUnit, rlDest, rlResult);
1614 return true;
1615}
1616
1617void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1618 RegLocation rlResult, int lit,
1619 int firstBit, int secondBit)
1620{
buzbee0398c422012-03-02 15:22:47 -08001621#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001622 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1623 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001624#else
1625 int tReg = oatAllocTemp(cUnit);
1626 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1627 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1628 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001629#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001630 if (firstBit != 0) {
1631 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1632 }
1633}
1634
1635// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1636// and store the result in 'rlDest'.
1637bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1638 RegLocation rlDest, int lit)
1639{
1640 // Can we simplify this multiplication?
1641 bool powerOfTwo = false;
1642 bool popCountLE2 = false;
1643 bool powerOfTwoMinusOne = false;
1644 if (lit < 2) {
1645 // Avoid special cases.
1646 return false;
1647 } else if (isPowerOfTwo(lit)) {
1648 powerOfTwo = true;
1649 } else if (isPopCountLE2(lit)) {
1650 popCountLE2 = true;
1651 } else if (isPowerOfTwo(lit + 1)) {
1652 powerOfTwoMinusOne = true;
1653 } else {
1654 return false;
1655 }
1656 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1657 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1658 if (powerOfTwo) {
1659 // Shift.
1660 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1661 lowestSetBit(lit));
1662 } else if (popCountLE2) {
1663 // Shift and add and shift.
1664 int firstBit = lowestSetBit(lit);
1665 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1666 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1667 firstBit, secondBit);
1668 } else {
1669 // Reverse subtract: (src << (shift + 1)) - src.
1670 DCHECK(powerOfTwoMinusOne);
1671 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1672 int tReg = oatAllocTemp(cUnit);
1673 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1674 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1675 }
1676 storeValue(cUnit, rlDest, rlResult);
1677 return true;
1678}
1679
1680bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1681 RegLocation rlSrc, int lit)
1682{
1683 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1684 RegLocation rlResult;
1685 OpKind op = (OpKind)0; /* Make gcc happy */
1686 int shiftOp = false;
1687 bool isDiv = false;
1688 int funcOffset;
1689 int rTgt;
1690
1691 switch (dalvikOpcode) {
1692 case OP_RSUB_INT_LIT8:
1693 case OP_RSUB_INT: {
1694 int tReg;
1695 //TUNING: add support for use of Arm rsub op
1696 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1697 tReg = oatAllocTemp(cUnit);
1698 loadConstant(cUnit, tReg, lit);
1699 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1700 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1701 tReg, rlSrc.lowReg);
1702 storeValue(cUnit, rlDest, rlResult);
1703 return false;
1704 break;
1705 }
1706
1707 case OP_ADD_INT_LIT8:
1708 case OP_ADD_INT_LIT16:
1709 op = kOpAdd;
1710 break;
1711 case OP_MUL_INT_LIT8:
1712 case OP_MUL_INT_LIT16: {
1713 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1714 return false;
1715 }
1716 op = kOpMul;
1717 break;
1718 }
1719 case OP_AND_INT_LIT8:
1720 case OP_AND_INT_LIT16:
1721 op = kOpAnd;
1722 break;
1723 case OP_OR_INT_LIT8:
1724 case OP_OR_INT_LIT16:
1725 op = kOpOr;
1726 break;
1727 case OP_XOR_INT_LIT8:
1728 case OP_XOR_INT_LIT16:
1729 op = kOpXor;
1730 break;
1731 case OP_SHL_INT_LIT8:
1732 lit &= 31;
1733 shiftOp = true;
1734 op = kOpLsl;
1735 break;
1736 case OP_SHR_INT_LIT8:
1737 lit &= 31;
1738 shiftOp = true;
1739 op = kOpAsr;
1740 break;
1741 case OP_USHR_INT_LIT8:
1742 lit &= 31;
1743 shiftOp = true;
1744 op = kOpLsr;
1745 break;
1746
1747 case OP_DIV_INT_LIT8:
1748 case OP_DIV_INT_LIT16:
1749 case OP_REM_INT_LIT8:
1750 case OP_REM_INT_LIT16:
1751 if (lit == 0) {
1752 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
1753 return false;
1754 }
1755 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
1756 return false;
1757 }
1758 oatFlushAllRegs(cUnit); /* Everything to home location */
1759 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1760 oatClobber(cUnit, rARG0);
1761 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
1762 (dalvikOpcode == OP_DIV_INT_LIT16)) {
1763 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1764 isDiv = true;
1765 } else {
1766 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1767 isDiv = false;
1768 }
1769 rTgt = loadHelper(cUnit, funcOffset);
1770 loadConstant(cUnit, rARG1, lit);
1771 callRuntimeHelper(cUnit, rTgt);
1772 if (isDiv)
1773 rlResult = oatGetReturn(cUnit);
1774 else
1775 rlResult = oatGetReturnAlt(cUnit);
1776 storeValue(cUnit, rlDest, rlResult);
1777 return false;
1778 break;
1779 default:
1780 return true;
1781 }
1782 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1783 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1784 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
1785 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08001786 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001787 } else {
1788 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
1789 }
1790 storeValue(cUnit, rlDest, rlResult);
1791 return false;
1792}
1793
1794bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1795 RegLocation rlSrc1, RegLocation rlSrc2)
1796{
buzbeea7678db2012-03-05 15:35:46 -08001797#if defined(TARGET_X86)
1798 UNIMPLEMENTED(WARNING) << "genArithOpLong";
1799 return false;
1800#else
buzbee31a4a6f2012-02-28 15:36:15 -08001801 RegLocation rlResult;
1802 OpKind firstOp = kOpBkpt;
1803 OpKind secondOp = kOpBkpt;
1804 bool callOut = false;
1805 bool checkZero = false;
1806 int funcOffset;
1807 int retReg = rRET0;
1808
1809 switch (mir->dalvikInsn.opcode) {
1810 case OP_NOT_LONG:
1811 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1812 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1813 // Check for destructive overlap
1814 if (rlResult.lowReg == rlSrc2.highReg) {
1815 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001816 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001817 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1818 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1819 oatFreeTemp(cUnit, tReg);
1820 } else {
1821 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1822 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1823 }
1824 storeValueWide(cUnit, rlDest, rlResult);
1825 return false;
1826 break;
1827 case OP_ADD_LONG:
1828 case OP_ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001829#if defined(TARGET_MIPS)
1830 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1831#else
buzbee31a4a6f2012-02-28 15:36:15 -08001832 firstOp = kOpAdd;
1833 secondOp = kOpAdc;
1834 break;
buzbeec5159d52012-03-03 11:48:39 -08001835#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001836 case OP_SUB_LONG:
1837 case OP_SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001838#if defined(TARGET_MIPS)
1839 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1840#else
buzbee31a4a6f2012-02-28 15:36:15 -08001841 firstOp = kOpSub;
1842 secondOp = kOpSbc;
1843 break;
buzbeec5159d52012-03-03 11:48:39 -08001844#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001845 case OP_MUL_LONG:
1846 case OP_MUL_LONG_2ADDR:
1847 callOut = true;
1848 retReg = rRET0;
1849 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1850 break;
1851 case OP_DIV_LONG:
1852 case OP_DIV_LONG_2ADDR:
1853 callOut = true;
1854 checkZero = true;
1855 retReg = rRET0;
1856 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1857 break;
1858 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
1859 // FIXME: is true, or could be made true, or other targets?
1860 case OP_REM_LONG:
1861 case OP_REM_LONG_2ADDR:
1862 callOut = true;
1863 checkZero = true;
1864 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1865 retReg = rARG2;
1866 break;
1867 case OP_AND_LONG_2ADDR:
1868 case OP_AND_LONG:
1869 firstOp = kOpAnd;
1870 secondOp = kOpAnd;
1871 break;
1872 case OP_OR_LONG:
1873 case OP_OR_LONG_2ADDR:
1874 firstOp = kOpOr;
1875 secondOp = kOpOr;
1876 break;
1877 case OP_XOR_LONG:
1878 case OP_XOR_LONG_2ADDR:
1879 firstOp = kOpXor;
1880 secondOp = kOpXor;
1881 break;
1882 case OP_NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08001883 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08001884 }
1885 default:
1886 LOG(FATAL) << "Invalid long arith op";
1887 }
1888 if (!callOut) {
1889 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1890 } else {
1891 int rTgt;
1892 oatFlushAllRegs(cUnit); /* Send everything to home location */
1893 if (checkZero) {
1894 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1895 rTgt = loadHelper(cUnit, funcOffset);
1896 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1897 int tReg = oatAllocTemp(cUnit);
1898#if defined(TARGET_ARM)
1899 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
1900 oatFreeTemp(cUnit, tReg);
1901 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
1902#else
1903 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
buzbee5de34942012-03-01 14:51:57 -08001904 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08001905 oatFreeTemp(cUnit, tReg);
1906#endif
1907 } else {
1908 rTgt = loadHelper(cUnit, funcOffset);
1909 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1910 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1911 }
1912 callRuntimeHelper(cUnit, rTgt);
1913 // Adjust return regs in to handle case of rem returning rARG2/rARG3
1914 if (retReg == rRET0)
1915 rlResult = oatGetReturnWide(cUnit);
1916 else
1917 rlResult = oatGetReturnWideAlt(cUnit);
1918 storeValueWide(cUnit, rlDest, rlResult);
1919 }
1920 return false;
buzbeea7678db2012-03-05 15:35:46 -08001921#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001922}
1923
1924bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
1925 int srcSize, int tgtSize)
1926{
1927 /*
1928 * Don't optimize the register usage since it calls out to support
1929 * functions
1930 */
1931 RegLocation rlSrc;
1932 RegLocation rlDest;
1933 oatFlushAllRegs(cUnit); /* Send everything to home location */
1934 int rTgt = loadHelper(cUnit, funcOffset);
1935 if (srcSize == 1) {
1936 rlSrc = oatGetSrc(cUnit, mir, 0);
1937 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1938 } else {
1939 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1940 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
1941 }
1942 callRuntimeHelper(cUnit, rTgt);
1943 if (tgtSize == 1) {
1944 RegLocation rlResult;
1945 rlDest = oatGetDest(cUnit, mir, 0);
1946 rlResult = oatGetReturn(cUnit);
1947 storeValue(cUnit, rlDest, rlResult);
1948 } else {
1949 RegLocation rlResult;
1950 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1951 rlResult = oatGetReturnWide(cUnit);
1952 storeValueWide(cUnit, rlDest, rlResult);
1953 }
1954 return false;
1955}
1956
1957void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
1958bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
1959 RegLocation rlDest, RegLocation rlSrc1,
1960 RegLocation rlSrc2)
1961{
1962 RegLocation rlResult;
1963 int funcOffset;
1964
1965 switch (mir->dalvikInsn.opcode) {
1966 case OP_ADD_FLOAT_2ADDR:
1967 case OP_ADD_FLOAT:
1968 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1969 break;
1970 case OP_SUB_FLOAT_2ADDR:
1971 case OP_SUB_FLOAT:
1972 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1973 break;
1974 case OP_DIV_FLOAT_2ADDR:
1975 case OP_DIV_FLOAT:
1976 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1977 break;
1978 case OP_MUL_FLOAT_2ADDR:
1979 case OP_MUL_FLOAT:
1980 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1981 break;
1982 case OP_REM_FLOAT_2ADDR:
1983 case OP_REM_FLOAT:
1984 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1985 break;
1986 case OP_NEG_FLOAT: {
1987 genNegFloat(cUnit, rlDest, rlSrc1);
1988 return false;
1989 }
1990 default:
1991 return true;
1992 }
1993 oatFlushAllRegs(cUnit); /* Send everything to home location */
1994 int rTgt = loadHelper(cUnit, funcOffset);
1995 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1996 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
1997 callRuntimeHelper(cUnit, rTgt);
1998 rlResult = oatGetReturn(cUnit);
1999 storeValue(cUnit, rlDest, rlResult);
2000 return false;
2001}
2002
2003void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
2004bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
2005 RegLocation rlDest, RegLocation rlSrc1,
2006 RegLocation rlSrc2)
2007{
buzbeea7678db2012-03-05 15:35:46 -08002008#if defined(TARGET_X86)
2009//NOTE: probably don't need the portable versions for x86
2010 UNIMPLEMENTED(WARNING) << "genArithOpDoublePortable";
2011 return false;
2012#else
buzbee31a4a6f2012-02-28 15:36:15 -08002013 RegLocation rlResult;
2014 int funcOffset;
2015
2016 switch (mir->dalvikInsn.opcode) {
2017 case OP_ADD_DOUBLE_2ADDR:
2018 case OP_ADD_DOUBLE:
2019 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
2020 break;
2021 case OP_SUB_DOUBLE_2ADDR:
2022 case OP_SUB_DOUBLE:
2023 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
2024 break;
2025 case OP_DIV_DOUBLE_2ADDR:
2026 case OP_DIV_DOUBLE:
2027 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2028 break;
2029 case OP_MUL_DOUBLE_2ADDR:
2030 case OP_MUL_DOUBLE:
2031 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2032 break;
2033 case OP_REM_DOUBLE_2ADDR:
2034 case OP_REM_DOUBLE:
2035 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2036 break;
2037 case OP_NEG_DOUBLE: {
2038 genNegDouble(cUnit, rlDest, rlSrc1);
2039 return false;
2040 }
2041 default:
2042 return true;
2043 }
2044 oatFlushAllRegs(cUnit); /* Send everything to home location */
2045 int rTgt = loadHelper(cUnit, funcOffset);
2046 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2047 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2048 callRuntimeHelper(cUnit, rTgt);
2049 rlResult = oatGetReturnWide(cUnit);
2050 storeValueWide(cUnit, rlDest, rlResult);
2051 return false;
buzbeea7678db2012-03-05 15:35:46 -08002052#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002053}
2054
2055bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2056{
2057 Opcode opcode = mir->dalvikInsn.opcode;
2058
2059 switch (opcode) {
2060 case OP_INT_TO_FLOAT:
2061 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2062 1, 1);
2063 case OP_FLOAT_TO_INT:
2064 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2065 1, 1);
2066 case OP_DOUBLE_TO_FLOAT:
2067 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2068 2, 1);
2069 case OP_FLOAT_TO_DOUBLE:
2070 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2071 1, 2);
2072 case OP_INT_TO_DOUBLE:
2073 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2074 1, 2);
2075 case OP_DOUBLE_TO_INT:
2076 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2077 2, 1);
2078 case OP_FLOAT_TO_LONG:
2079 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2080 pF2l), 1, 2);
2081 case OP_LONG_TO_FLOAT:
2082 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2083 2, 1);
2084 case OP_DOUBLE_TO_LONG:
2085 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2086 pD2l), 2, 2);
2087 case OP_LONG_TO_DOUBLE:
2088 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2089 2, 2);
2090 default:
2091 return true;
2092 }
2093 return false;
2094}
2095
2096/*
2097 * Generate callout to updateDebugger. Note that we're overloading
2098 * the use of rSUSPEND here. When the debugger is active, this
2099 * register holds the address of the update function. So, if it's
2100 * non-null, we call out to it.
2101 *
2102 * Note also that rRET0 and rRET1 must be preserved across this
2103 * code. This must be handled by the stub.
2104 */
2105void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2106{
buzbeea7678db2012-03-05 15:35:46 -08002107#if defined(TARGET_X86)
2108 UNIMPLEMENTED(WARNING);
2109#else
buzbee31a4a6f2012-02-28 15:36:15 -08002110 // Following DCHECK verifies that dPC is in range of single load immediate
2111 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2112 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2113 oatClobberCalleeSave(cUnit);
2114#if defined(TARGET_ARM)
2115 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002116 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002117 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2118 opReg(cUnit, kOpBlx, rSUSPEND);
2119#else
buzbee82488f52012-03-02 08:20:26 -08002120 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002121 loadConstant(cUnit, rARG2, offset);
2122 opReg(cUnit, kOpBlx, rSUSPEND);
2123 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002124 branch->target = (LIR*)target;
2125#endif
2126 oatFreeTemp(cUnit, rARG2);
buzbeea7678db2012-03-05 15:35:46 -08002127#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002128}
2129
2130/* Check if we need to check for pending suspend request */
2131void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2132{
buzbeea7678db2012-03-05 15:35:46 -08002133#if defined(TARGET_X86)
2134 UNIMPLEMENTED(WARNING) << "genSuspendTest";
2135#else
buzbee31a4a6f2012-02-28 15:36:15 -08002136 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2137 return;
2138 }
2139 oatFlushAllRegs(cUnit);
2140 LIR* branch;
2141 if (cUnit->genDebugger) {
2142 // If generating code for the debugger, always check for suspension
buzbee82488f52012-03-02 08:20:26 -08002143 branch = opUnconditionalBranch(cUnit, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002144 } else {
2145#if defined(TARGET_ARM)
2146 // In non-debug case, only check periodically
2147 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002148 branch = opCondBranch(cUnit, kCondEq, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002149#else
2150 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002151 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002152#endif
2153 }
2154 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
buzbeea2ebdd72012-03-04 14:57:06 -08002155 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2156 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
buzbee31a4a6f2012-02-28 15:36:15 -08002157 branch->target = (LIR*)target;
2158 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
buzbeea7678db2012-03-05 15:35:46 -08002159#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002160}
2161
2162} // namespace art