blob: bfc56398176a92041051d90907057033ae18c443 [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
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070029LIR* callRuntimeHelper(CompilationUnit* cUnit, int reg_or_offset)
buzbee31a4a6f2012-02-28 15:36:15 -080030{
31 oatClobberCalleeSave(cUnit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070032#if !defined(TARGET_X86)
33 return opReg(cUnit, kOpBlx, reg_or_offset);
34#else
35 return opThreadMem(cUnit, kOpBlx, reg_or_offset);
36#endif
buzbee31a4a6f2012-02-28 15:36:15 -080037}
38
39/*
40 * Generate an kPseudoBarrier marker to indicate the boundary of special
41 * blocks.
42 */
43void genBarrier(CompilationUnit* cUnit)
44{
45 LIR* barrier = newLIR0(cUnit, kPseudoBarrier);
46 /* Mark all resources as being clobbered */
47 barrier->defMask = -1;
48}
49
buzbee31a4a6f2012-02-28 15:36:15 -080050
51/* Generate unconditional branch instructions */
buzbee82488f52012-03-02 08:20:26 -080052LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -080053{
Ian Rogers680b1bd2012-03-07 20:18:49 -080054 LIR* branch = opBranchUnconditional(cUnit, kOpUncondBr);
buzbee31a4a6f2012-02-28 15:36:15 -080055 branch->target = (LIR*) target;
56 return branch;
57}
58
buzbee5de34942012-03-01 14:51:57 -080059// FIXME: need to do some work to split out targets with
60// condition codes and those without
61#if defined(TARGET_ARM) || defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -080062LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, MIR* mir,
63 ThrowKind kind)
64{
buzbeea2ebdd72012-03-04 14:57:06 -080065 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
66 mir ? mir->offset : 0);
buzbee82488f52012-03-02 08:20:26 -080067 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080068 // Remember branch target - will process later
69 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
70 return branch;
71}
buzbee5de34942012-03-01 14:51:57 -080072#endif
buzbee31a4a6f2012-02-28 15:36:15 -080073
74LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
75 int reg, int immVal, MIR* mir, ThrowKind kind)
76{
buzbeea2ebdd72012-03-04 14:57:06 -080077 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, mir->offset);
buzbee31a4a6f2012-02-28 15:36:15 -080078 LIR* branch;
79 if (cCode == kCondAl) {
buzbee82488f52012-03-02 08:20:26 -080080 branch = opUnconditionalBranch(cUnit, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080081 } else {
buzbee82488f52012-03-02 08:20:26 -080082 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080083 }
84 // Remember branch target - will process later
85 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
86 return branch;
87}
88
89/* Perform null-check on a register. */
90LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir)
91{
92 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
93 mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
94 return NULL;
95 }
96 return genImmedCheck(cUnit, kCondEq, mReg, 0, mir, kThrowNullPointer);
97}
98
99/* Perform check on two registers */
100LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
Ian Rogersb5d09b22012-03-06 22:14:17 -0800101 int reg1, int reg2, MIR* mir, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800102{
buzbeea2ebdd72012-03-04 14:57:06 -0800103 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
104 mir ? mir->offset : 0, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800105#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800106 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800107#else
buzbee31a4a6f2012-02-28 15:36:15 -0800108 opRegReg(cUnit, kOpCmp, reg1, reg2);
buzbee82488f52012-03-02 08:20:26 -0800109 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800110#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800111 // Remember branch target - will process later
112 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
113 return branch;
114}
115
116void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
117 RegLocation rlSrc1, RegLocation rlSrc2, LIR* labelList)
118{
119 ConditionCode cond;
120 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
121 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800122 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -0800123 switch(opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800124 case Instruction::IF_EQ:
buzbee31a4a6f2012-02-28 15:36:15 -0800125 cond = kCondEq;
126 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800127 case Instruction::IF_NE:
buzbee31a4a6f2012-02-28 15:36:15 -0800128 cond = kCondNe;
129 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800130 case Instruction::IF_LT:
buzbee31a4a6f2012-02-28 15:36:15 -0800131 cond = kCondLt;
132 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800133 case Instruction::IF_GE:
buzbee31a4a6f2012-02-28 15:36:15 -0800134 cond = kCondGe;
135 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800136 case Instruction::IF_GT:
buzbee31a4a6f2012-02-28 15:36:15 -0800137 cond = kCondGt;
138 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800139 case Instruction::IF_LE:
buzbee31a4a6f2012-02-28 15:36:15 -0800140 cond = kCondLe;
141 break;
142 default:
143 cond = (ConditionCode)0;
144 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
145 }
buzbee5de34942012-03-01 14:51:57 -0800146#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800147 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg,
148 &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800149#else
150 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800151 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800152#endif
buzbee82488f52012-03-02 08:20:26 -0800153 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800154}
155
156void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
157 RegLocation rlSrc, LIR* labelList)
158{
159 ConditionCode cond;
160 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800161 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -0800162 switch(opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800163 case Instruction::IF_EQZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800164 cond = kCondEq;
165 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800166 case Instruction::IF_NEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800167 cond = kCondNe;
168 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800169 case Instruction::IF_LTZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800170 cond = kCondLt;
171 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800172 case Instruction::IF_GEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800173 cond = kCondGe;
174 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800175 case Instruction::IF_GTZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800176 cond = kCondGt;
177 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800178 case Instruction::IF_LEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800179 cond = kCondLe;
180 break;
181 default:
182 cond = (ConditionCode)0;
183 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
184 }
buzbee5de34942012-03-01 14:51:57 -0800185#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800186 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800187#else
188 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
buzbee82488f52012-03-02 08:20:26 -0800189 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800190#endif
buzbee82488f52012-03-02 08:20:26 -0800191 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800192}
193
194void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
195 RegLocation rlSrc)
196{
197 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
198 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -0800199 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800200 } else {
201 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
202 }
203 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
204 rlResult.lowReg, 31);
205 storeValueWide(cUnit, rlDest, rlResult);
206}
207
208void genIntNarrowing(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
209 RegLocation rlSrc)
210{
211 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
212 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
213 OpKind op = kOpInvalid;
214 switch(mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800215 case Instruction::INT_TO_BYTE:
buzbee31a4a6f2012-02-28 15:36:15 -0800216 op = kOp2Byte;
217 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800218 case Instruction::INT_TO_SHORT:
buzbee31a4a6f2012-02-28 15:36:15 -0800219 op = kOp2Short;
220 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800221 case Instruction::INT_TO_CHAR:
buzbee31a4a6f2012-02-28 15:36:15 -0800222 op = kOp2Char;
223 break;
224 default:
225 LOG(ERROR) << "Bad int conversion type";
226 }
227 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
228 storeValue(cUnit, rlDest, rlResult);
229}
230
231/*
232 * Let helper function take care of everything. Will call
233 * Array::AllocFromCode(type_idx, method, count);
234 * Note: AllocFromCode will handle checks for errNegativeArraySize.
235 */
236void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
237 RegLocation rlSrc)
238{
239 oatFlushAllRegs(cUnit); /* Everything to home location */
240 uint32_t type_idx = mir->dalvikInsn.vC;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700241 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -0800242 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
243 cUnit->dex_cache,
244 *cUnit->dex_file,
245 type_idx)) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700246 funcOffset = OFFSETOF_MEMBER(Thread, pAllocArrayFromCode);
buzbee31a4a6f2012-02-28 15:36:15 -0800247 } else {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700248 funcOffset= OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck);
buzbee31a4a6f2012-02-28 15:36:15 -0800249 }
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700250#if !defined(TARGET_X86)
251 int rTgt = loadHelper(cUnit, funcOffset);
252#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800253 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
254 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_id
255 loadValueDirectFixed(cUnit, rlSrc, rARG2); // arg2 <- count
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700256#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800257 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700258 oatFreeTemp(cUnit, rTgt);
259#else
260 callRuntimeHelper(cUnit, funcOffset);
261#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700262 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800263 storeValue(cUnit, rlDest, rlResult);
264}
265
266/*
267 * Similar to genNewArray, but with post-allocation initialization.
268 * Verifier guarantees we're dealing with an array class. Current
269 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
270 * Current code also throws internal unimp if not 'L', '[' or 'I'.
271 */
272void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
273{
274 DecodedInstruction* dInsn = &mir->dalvikInsn;
275 int elems = dInsn->vA;
276 int typeId = dInsn->vB;
277 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700278 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -0800279 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
280 cUnit->dex_cache,
281 *cUnit->dex_file,
282 typeId)) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700283 funcOffset = OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode);
buzbee31a4a6f2012-02-28 15:36:15 -0800284 } else {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700285 funcOffset = OFFSETOF_MEMBER(Thread,
286 pCheckAndAllocArrayFromCodeWithAccessCheck);
buzbee31a4a6f2012-02-28 15:36:15 -0800287 }
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700288#if !defined(TARGET_X86)
289 int rTgt = loadHelper(cUnit, funcOffset);
290#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800291 loadConstant(cUnit, rARG0, typeId); // arg0 <- type_id
292 loadConstant(cUnit, rARG2, elems); // arg2 <- count
buzbeee1965672012-03-11 18:39:19 -0700293 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700294#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800295 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700296 oatFreeTemp(cUnit, rTgt);
297#else
298 callRuntimeHelper(cUnit, funcOffset);
299#endif
buzbeee1965672012-03-11 18:39:19 -0700300 oatFreeTemp(cUnit, rARG2);
301 oatFreeTemp(cUnit, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -0800302 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -0800303 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
buzbee31a4a6f2012-02-28 15:36:15 -0800304 * return region. Because AllocFromCode placed the new array
305 * in rRET0, we'll just lock it into place. When debugger support is
306 * added, it may be necessary to additionally copy all return
307 * values to a home location in thread-local storage
308 */
309 oatLockTemp(cUnit, rRET0);
310
311 // TODO: use the correct component size, currently all supported types
312 // share array alignment with ints (see comment at head of function)
313 size_t component_size = sizeof(int32_t);
314
315 // Having a range of 0 is legal
316 if (isRange && (dInsn->vA > 0)) {
317 /*
318 * Bit of ugliness here. We're going generate a mem copy loop
319 * on the register range, but it is possible that some regs
320 * in the range have been promoted. This is unlikely, but
321 * before generating the copy, we'll just force a flush
322 * of any regs in the source range that have been promoted to
323 * home location.
324 */
325 for (unsigned int i = 0; i < dInsn->vA; i++) {
326 RegLocation loc = oatUpdateLoc(cUnit,
327 oatGetSrc(cUnit, mir, i));
328 if (loc.location == kLocPhysReg) {
329 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
330 loc.lowReg, kWord);
331 }
332 }
333 /*
334 * TUNING note: generated code here could be much improved, but
335 * this is an uncommon operation and isn't especially performance
336 * critical.
337 */
338 int rSrc = oatAllocTemp(cUnit);
339 int rDst = oatAllocTemp(cUnit);
340 int rIdx = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800341#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800342 int rVal = rLR; // Using a lot of temps, rLR is known free here
buzbee5de34942012-03-01 14:51:57 -0800343#else
344 int rVal = oatAllocTemp(cUnit);
345#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800346 // Set up source pointer
347 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800348#if defined(TARGET_X86)
349 UNIMPLEMENTED(FATAL);
350#else
buzbee31a4a6f2012-02-28 15:36:15 -0800351 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
352 oatSRegOffset(cUnit, rlFirst.sRegLow));
353 // Set up the target pointer
354 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
355 Array::DataOffset(component_size).Int32Value());
Ian Rogersb5d09b22012-03-06 22:14:17 -0800356#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800357 // Set up the loop counter (known to be > 0)
358 loadConstant(cUnit, rIdx, dInsn->vA - 1);
359 // Generate the copy loop. Going backwards for convenience
360 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800361 // Copy next element
362 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
363 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
364#if defined(TARGET_ARM)
365 // Combine sub & test using sub setflags encoding here
366 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800367 opCondBranch(cUnit, kCondGe, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800368#else
buzbee5de34942012-03-01 14:51:57 -0800369 oatFreeTemp(cUnit, rVal);
buzbee31a4a6f2012-02-28 15:36:15 -0800370 opRegImm(cUnit, kOpSub, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800371 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800372#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800373 } else if (!isRange) {
374 // TUNING: interleave
375 for (unsigned int i = 0; i < dInsn->vA; i++) {
376 RegLocation rlArg = loadValue(cUnit,
377 oatGetSrc(cUnit, mir, i), kCoreReg);
378 storeBaseDisp(cUnit, rRET0,
379 Array::DataOffset(component_size).Int32Value() +
380 i * 4, rlArg.lowReg, kWord);
381 // If the loadValue caused a temp to be allocated, free it
382 if (oatIsTemp(cUnit, rlArg.lowReg)) {
383 oatFreeTemp(cUnit, rlArg.lowReg);
384 }
385 }
386 }
387}
388
389void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
390 bool isLongOrDouble, bool isObject)
391{
392 int fieldOffset;
393 int ssbIndex;
394 bool isVolatile;
395 bool isReferrersClass;
396 uint32_t fieldIdx = mir->dalvikInsn.vB;
397
398 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
399 *cUnit->dex_file, *cUnit->dex_cache,
400 cUnit->code_item, cUnit->method_idx,
401 cUnit->access_flags);
402
403 bool fastPath =
404 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
405 fieldOffset, ssbIndex,
406 isReferrersClass, isVolatile, true);
407 if (fastPath && !SLOW_FIELD_PATH) {
408 DCHECK_GE(fieldOffset, 0);
409 int rBase;
buzbee31a4a6f2012-02-28 15:36:15 -0800410 if (isReferrersClass) {
411 // Fast path, static storage base is this method's class
buzbeee1965672012-03-11 18:39:19 -0700412 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800413 rBase = oatAllocTemp(cUnit);
buzbeee1965672012-03-11 18:39:19 -0700414 loadWordDisp(cUnit, rlMethod.lowReg,
buzbee31a4a6f2012-02-28 15:36:15 -0800415 Method::DeclaringClassOffset().Int32Value(), rBase);
416 } else {
417 // Medium path, static storage base in a different class which
418 // requires checks that the other class is initialized.
419 DCHECK_GE(ssbIndex, 0);
420 // May do runtime call so everything to home locations.
421 oatFlushAllRegs(cUnit);
422 // Using fixed register to sync with possible call to runtime
423 // support.
buzbeee1965672012-03-11 18:39:19 -0700424 int rMethod = rARG1;
buzbee31a4a6f2012-02-28 15:36:15 -0800425 oatLockTemp(cUnit, rMethod);
426 loadCurrMethodDirect(cUnit, rMethod);
427 rBase = rARG0;
428 oatLockTemp(cUnit, rBase);
429 loadWordDisp(cUnit, rMethod,
430 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
431 rBase);
432 loadWordDisp(cUnit, rBase,
433 Array::DataOffset(sizeof(Object*)).Int32Value() + sizeof(int32_t*) *
434 ssbIndex, rBase);
435 // rBase now points at appropriate static storage base (Class*)
436 // or NULL if not initialized. Check for NULL and call helper if NULL.
437 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800438 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700439#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800440 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
441 pInitializeStaticStorage));
442 loadConstant(cUnit, rARG0, ssbIndex);
443 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700444 oatFreeTemp(cUnit, rTgt);
445#else
446 loadConstant(cUnit, rARG0, ssbIndex);
447 callRuntimeHelper(cUnit,
448 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage));
449#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800450#if defined(TARGET_MIPS)
451 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800452 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800453#endif
454 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800455 branchOver->target = (LIR*)skipTarget;
buzbeee1965672012-03-11 18:39:19 -0700456 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800457 }
458 // rBase now holds static storage base
buzbee31a4a6f2012-02-28 15:36:15 -0800459 if (isLongOrDouble) {
460 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
461 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
462 } else {
463 rlSrc = oatGetSrc(cUnit, mir, 0);
464 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
465 }
466//FIXME: need to generalize the barrier call
467 if (isVolatile) {
468 oatGenMemBarrier(cUnit, kST);
469 }
470 if (isLongOrDouble) {
471 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
472 rlSrc.highReg);
473 } else {
474 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
475 }
476 if (isVolatile) {
477 oatGenMemBarrier(cUnit, kSY);
478 }
479 if (isObject) {
480 markGCCard(cUnit, rlSrc.lowReg, rBase);
481 }
482 oatFreeTemp(cUnit, rBase);
483 } else {
484 oatFlushAllRegs(cUnit); // Everything to home locations
485 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
486 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
487 : OFFSETOF_MEMBER(Thread, pSet32Static));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700488#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800489 int rTgt = loadHelper(cUnit, setterOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700490#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800491 loadConstant(cUnit, rARG0, fieldIdx);
492 if (isLongOrDouble) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800493#if defined(TARGET_X86)
494 UNIMPLEMENTED(FATAL);
495#else
buzbee31a4a6f2012-02-28 15:36:15 -0800496 loadValueDirectWideFixed(cUnit, rlSrc, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800497#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800498 } else {
499 loadValueDirect(cUnit, rlSrc, rARG1);
500 }
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700501#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800502 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700503 oatFreeTemp(cUnit, rTgt);
504#else
505 callRuntimeHelper(cUnit, setterOffset);
506#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800507 }
508}
509
510void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
511 bool isLongOrDouble, bool isObject)
512{
513 int fieldOffset;
514 int ssbIndex;
515 bool isVolatile;
516 bool isReferrersClass;
517 uint32_t fieldIdx = mir->dalvikInsn.vB;
518
519 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
520 *cUnit->dex_file, *cUnit->dex_cache,
521 cUnit->code_item, cUnit->method_idx,
522 cUnit->access_flags);
523
524 bool fastPath =
525 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
526 fieldOffset, ssbIndex,
527 isReferrersClass, isVolatile,
528 false);
529 if (fastPath && !SLOW_FIELD_PATH) {
530 DCHECK_GE(fieldOffset, 0);
531 int rBase;
buzbee31a4a6f2012-02-28 15:36:15 -0800532 if (isReferrersClass) {
533 // Fast path, static storage base is this method's class
buzbeee1965672012-03-11 18:39:19 -0700534 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800535 rBase = oatAllocTemp(cUnit);
buzbeee1965672012-03-11 18:39:19 -0700536 loadWordDisp(cUnit, rlMethod.lowReg,
buzbee31a4a6f2012-02-28 15:36:15 -0800537 Method::DeclaringClassOffset().Int32Value(), rBase);
538 } else {
539 // Medium path, static storage base in a different class which
540 // requires checks that the other class is initialized
541 DCHECK_GE(ssbIndex, 0);
542 // May do runtime call so everything to home locations.
543 oatFlushAllRegs(cUnit);
544 // Using fixed register to sync with possible call to runtime
545 // support
buzbeee1965672012-03-11 18:39:19 -0700546 int rMethod = rARG1;
buzbee31a4a6f2012-02-28 15:36:15 -0800547 oatLockTemp(cUnit, rMethod);
548 loadCurrMethodDirect(cUnit, rMethod);
549 rBase = rARG0;
550 oatLockTemp(cUnit, rBase);
551 loadWordDisp(cUnit, rMethod,
552 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
553 rBase);
554 loadWordDisp(cUnit, rBase,
555 Array::DataOffset(sizeof(Object*)).Int32Value() +
556 sizeof(int32_t*) * ssbIndex,
557 rBase);
558 // rBase now points at appropriate static storage base (Class*)
559 // or NULL if not initialized. Check for NULL and call helper if NULL.
560 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800561 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700562#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800563 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
564 pInitializeStaticStorage));
565 loadConstant(cUnit, rARG0, ssbIndex);
566 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700567 oatFreeTemp(cUnit, rTgt);
568#else
569 loadConstant(cUnit, rARG0, ssbIndex);
570 callRuntimeHelper(cUnit,
571 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage));
572#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800573#if defined(TARGET_MIPS)
574 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800575 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800576#endif
577 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800578 branchOver->target = (LIR*)skipTarget;
buzbeee1965672012-03-11 18:39:19 -0700579 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800580 }
581 // rBase now holds static storage base
buzbee31a4a6f2012-02-28 15:36:15 -0800582 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
583 : oatGetDest(cUnit, mir, 0);
584 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
585 if (isVolatile) {
586 oatGenMemBarrier(cUnit, kSY);
587 }
588 if (isLongOrDouble) {
589 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
590 rlResult.highReg, INVALID_SREG);
591 } else {
592 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
593 }
594 oatFreeTemp(cUnit, rBase);
595 if (isLongOrDouble) {
596 storeValueWide(cUnit, rlDest, rlResult);
597 } else {
598 storeValue(cUnit, rlDest, rlResult);
599 }
600 } else {
601 oatFlushAllRegs(cUnit); // Everything to home locations
602 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
603 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
604 : OFFSETOF_MEMBER(Thread, pGet32Static));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700605#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800606 int rTgt = loadHelper(cUnit, getterOffset);
607 loadConstant(cUnit, rARG0, fieldIdx);
608 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700609 oatFreeTemp(cUnit, rTgt);
610#else
611 loadConstant(cUnit, rARG0, fieldIdx);
612 callRuntimeHelper(cUnit, getterOffset);
613#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800614 if (isLongOrDouble) {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700615 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -0800616 storeValueWide(cUnit, rlDest, rlResult);
617 } else {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700618 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -0800619 storeValue(cUnit, rlDest, rlResult);
620 }
621 }
622}
623
624
625// Debugging routine - if null target, branch to DebugMe
626void genShowTarget(CompilationUnit* cUnit)
627{
buzbeea7678db2012-03-05 15:35:46 -0800628#if defined(TARGET_X86)
629 UNIMPLEMENTED(WARNING) << "genShowTarget";
630#else
buzbee0398c422012-03-02 15:22:47 -0800631 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800632 loadWordDisp(cUnit, rSELF,
buzbee0398c422012-03-02 15:22:47 -0800633 OFFSETOF_MEMBER(Thread, pDebugMe), rINVOKE_TGT);
buzbee31a4a6f2012-02-28 15:36:15 -0800634 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800635 branchOver->target = (LIR*)target;
buzbeea7678db2012-03-05 15:35:46 -0800636#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800637}
638
639void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
640{
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700641#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800642 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
643 pThrowVerificationErrorFromCode));
644 loadConstant(cUnit, rARG0, mir->dalvikInsn.vA);
645 loadConstant(cUnit, rARG1, mir->dalvikInsn.vB);
646 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700647 oatFreeTemp(cUnit, rTgt);
648#else
649 loadConstant(cUnit, rARG0, mir->dalvikInsn.vA);
650 loadConstant(cUnit, rARG1, mir->dalvikInsn.vB);
651 callRuntimeHelper(cUnit,
652 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode));
653#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800654}
655
656void handleSuspendLaunchpads(CompilationUnit *cUnit)
657{
658 LIR** suspendLabel =
659 (LIR **) cUnit->suspendLaunchpads.elemList;
660 int numElems = cUnit->suspendLaunchpads.numUsed;
661
662 for (int i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800663 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800664 LIR* lab = suspendLabel[i];
665 LIR* resumeLab = (LIR*)lab->operands[0];
666 cUnit->currentDalvikOffset = lab->operands[1];
667 oatAppendLIR(cUnit, (LIR *)lab);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700668#if defined(TARGET_X86)
669 opThreadMem(cUnit, kOpBlx,
670 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode));
671#else
buzbee31a4a6f2012-02-28 15:36:15 -0800672 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
673 pTestSuspendFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -0800674 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700675#endif
buzbee82488f52012-03-02 08:20:26 -0800676 opUnconditionalBranch(cUnit, resumeLab);
buzbee31a4a6f2012-02-28 15:36:15 -0800677 }
678}
679
680void handleThrowLaunchpads(CompilationUnit *cUnit)
681{
682 LIR** throwLabel = (LIR **) cUnit->throwLaunchpads.elemList;
683 int numElems = cUnit->throwLaunchpads.numUsed;
684 int i;
685
686 for (i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800687 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800688 LIR* lab = throwLabel[i];
689 cUnit->currentDalvikOffset = lab->operands[1];
690 oatAppendLIR(cUnit, (LIR *)lab);
691 int funcOffset = 0;
692 int v1 = lab->operands[2];
693 int v2 = lab->operands[3];
694 switch(lab->operands[0]) {
695 case kThrowNullPointer:
696 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
697 break;
698 case kThrowArrayBounds:
buzbee5de34942012-03-01 14:51:57 -0800699 if (v2 != rARG0) {
buzbee82488f52012-03-02 08:20:26 -0800700 opRegCopy(cUnit, rARG0, v1);
701 opRegCopy(cUnit, rARG1, v2);
buzbee31a4a6f2012-02-28 15:36:15 -0800702 } else {
buzbee5de34942012-03-01 14:51:57 -0800703 if (v1 == rARG1) {
buzbee31a4a6f2012-02-28 15:36:15 -0800704#if defined(TARGET_ARM)
705 int rTmp = r12;
706#else
707 int rTmp = oatAllocTemp(cUnit);
708#endif
buzbee82488f52012-03-02 08:20:26 -0800709 opRegCopy(cUnit, rTmp, v1);
710 opRegCopy(cUnit, rARG1, v2);
711 opRegCopy(cUnit, rARG0, rTmp);
buzbee31a4a6f2012-02-28 15:36:15 -0800712 } else {
buzbee82488f52012-03-02 08:20:26 -0800713 opRegCopy(cUnit, rARG1, v2);
714 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800715 }
716 }
717 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
718 break;
719 case kThrowDivZero:
720 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
721 break;
722 case kThrowVerificationError:
723 loadConstant(cUnit, rARG0, v1);
724 loadConstant(cUnit, rARG1, v2);
725 funcOffset =
726 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
727 break;
728 case kThrowNegArraySize:
buzbee82488f52012-03-02 08:20:26 -0800729 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800730 funcOffset =
731 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
732 break;
733 case kThrowNoSuchMethod:
buzbee82488f52012-03-02 08:20:26 -0800734 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800735 funcOffset =
736 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
737 break;
738 case kThrowStackOverflow:
739 funcOffset =
740 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
741 // Restore stack alignment
742 opRegImm(cUnit, kOpAdd, rSP,
743 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
744 break;
745 default:
746 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
747 }
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700748#if defined(TARGET_X86)
749 callRuntimeHelper(cUnit, funcOffset);
750#else
buzbee31a4a6f2012-02-28 15:36:15 -0800751 int rTgt = loadHelper(cUnit, funcOffset);
752 callRuntimeHelper(cUnit, rTgt);
buzbee0398c422012-03-02 15:22:47 -0800753 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700754#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800755 }
756}
757
758/* Needed by the Assembler */
759void oatSetupResourceMasks(LIR* lir)
760{
761 setupResourceMasks(lir);
762}
763
764void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
765 RegLocation rlDest, RegLocation rlObj,
766 bool isLongOrDouble, bool isObject)
767{
768 int fieldOffset;
769 bool isVolatile;
770 uint32_t fieldIdx = mir->dalvikInsn.vC;
771
772 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
773 *cUnit->dex_file, *cUnit->dex_cache,
774 cUnit->code_item, cUnit->method_idx,
775 cUnit->access_flags);
776
777 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
778 fieldOffset, isVolatile, false);
779
780 if (fastPath && !SLOW_FIELD_PATH) {
781 RegLocation rlResult;
782 RegisterClass regClass = oatRegClassBySize(size);
783 DCHECK_GE(fieldOffset, 0);
784 rlObj = loadValue(cUnit, rlObj, kCoreReg);
785 if (isLongOrDouble) {
786 DCHECK(rlDest.wide);
787 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800788#if defined(TARGET_X86)
789 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
790 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
791 loadBaseDispWide(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
792 rlResult.highReg, rlObj.sRegLow);
793 if (isVolatile) {
794 oatGenMemBarrier(cUnit, kSY);
795 }
796#else
buzbee31a4a6f2012-02-28 15:36:15 -0800797 int regPtr = oatAllocTemp(cUnit);
798 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
799 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
800 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
801 if (isVolatile) {
802 oatGenMemBarrier(cUnit, kSY);
803 }
804 oatFreeTemp(cUnit, regPtr);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800805#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800806 storeValueWide(cUnit, rlDest, rlResult);
807 } else {
808 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
809 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
810 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
811 kWord, rlObj.sRegLow);
812 if (isVolatile) {
813 oatGenMemBarrier(cUnit, kSY);
814 }
815 storeValue(cUnit, rlDest, rlResult);
816 }
817 } else {
818 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
819 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
820 : OFFSETOF_MEMBER(Thread, pGet32Instance));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700821#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800822 int rTgt = loadHelper(cUnit, getterOffset);
823 loadValueDirect(cUnit, rlObj, rARG1);
824 loadConstant(cUnit, rARG0, fieldIdx);
825 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700826#else
827 loadValueDirect(cUnit, rlObj, rARG1);
828 loadConstant(cUnit, rARG0, fieldIdx);
829 callRuntimeHelper(cUnit, getterOffset);
830#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800831 if (isLongOrDouble) {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700832 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -0800833 storeValueWide(cUnit, rlDest, rlResult);
834 } else {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700835 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -0800836 storeValue(cUnit, rlDest, rlResult);
837 }
838 }
839}
840
841void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, RegLocation rlSrc,
842 RegLocation rlObj, bool isLongOrDouble, bool isObject)
843{
844 int fieldOffset;
845 bool isVolatile;
846 uint32_t fieldIdx = mir->dalvikInsn.vC;
847
848 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
849 *cUnit->dex_file, *cUnit->dex_cache,
850 cUnit->code_item, cUnit->method_idx,
851 cUnit->access_flags);
852
853 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
854 fieldOffset, isVolatile, true);
855 if (fastPath && !SLOW_FIELD_PATH) {
856 RegisterClass regClass = oatRegClassBySize(size);
857 DCHECK_GE(fieldOffset, 0);
858 rlObj = loadValue(cUnit, rlObj, kCoreReg);
859 if (isLongOrDouble) {
860 int regPtr;
861 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
862 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
863 regPtr = oatAllocTemp(cUnit);
864 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
865 if (isVolatile) {
866 oatGenMemBarrier(cUnit, kST);
867 }
868 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
869 if (isVolatile) {
870 oatGenMemBarrier(cUnit, kSY);
871 }
872 oatFreeTemp(cUnit, regPtr);
873 } else {
874 rlSrc = loadValue(cUnit, rlSrc, regClass);
875 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
876 if (isVolatile) {
877 oatGenMemBarrier(cUnit, kST);
878 }
879 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
880 if (isVolatile) {
881 oatGenMemBarrier(cUnit, kSY);
882 }
883 }
884 } else {
885 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
886 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
887 : OFFSETOF_MEMBER(Thread, pSet32Instance));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700888#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800889 int rTgt = loadHelper(cUnit, setterOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700890#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800891 loadValueDirect(cUnit, rlObj, rARG1);
892 if (isLongOrDouble) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800893#if defined(TARGET_X86)
894 UNIMPLEMENTED(FATAL);
895#else
buzbee31a4a6f2012-02-28 15:36:15 -0800896 loadValueDirectWide(cUnit, rlSrc, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800897#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800898 } else {
899 loadValueDirect(cUnit, rlSrc, rARG2);
900 }
901 loadConstant(cUnit, rARG0, fieldIdx);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700902#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800903 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700904 oatFreeTemp(cUnit, rTgt);
905#else
906 callRuntimeHelper(cUnit, setterOffset);
907#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800908 }
909}
910
911void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
912 RegLocation rlSrc)
913{
914 uint32_t type_idx = mir->dalvikInsn.vB;
buzbeee1965672012-03-11 18:39:19 -0700915 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800916 int resReg = oatAllocTemp(cUnit);
917 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
918 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
919 cUnit->dex_cache,
920 *cUnit->dex_file,
921 type_idx)) {
922 // Call out to helper which resolves type and verifies access.
923 // Resolved type returned in rRET0.
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700924#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800925 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
926 pInitializeTypeAndVerifyAccessFromCode));
buzbeee1965672012-03-11 18:39:19 -0700927 opRegCopy(cUnit, rARG1, rlMethod.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800928 loadConstant(cUnit, rARG0, type_idx);
929 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700930 oatFreeTemp(cUnit, rTgt);
931#else
932 opRegCopy(cUnit, rARG1, rlMethod.lowReg);
933 loadConstant(cUnit, rARG0, type_idx);
934 callRuntimeHelper(cUnit, OFFSETOF_MEMBER(Thread,
935 pInitializeTypeAndVerifyAccessFromCode));
936#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700937 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800938 storeValue(cUnit, rlDest, rlResult);
939 } else {
940 // We're don't need access checks, load type from dex cache
941 int32_t dex_cache_offset =
942 Method::DexCacheResolvedTypesOffset().Int32Value();
buzbeee1965672012-03-11 18:39:19 -0700943 loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800944 int32_t offset_of_type =
945 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
946 * type_idx);
947 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
948 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
949 type_idx) || SLOW_TYPE_PATH) {
950 // Slow path, at runtime test if type is null and if so initialize
951 oatFlushAllRegs(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800952 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0,
953 NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800954 // Resolved, store and hop over following code
955 storeValue(cUnit, rlDest, rlResult);
buzbee3d661942012-03-14 17:37:27 -0700956 /*
957 * Because we have stores of the target value on two paths,
958 * clobber temp tracking for the destination using the ssa name
959 */
960 oatClobberSReg(cUnit, rlDest.sRegLow);
buzbee82488f52012-03-02 08:20:26 -0800961 LIR* branch2 = opUnconditionalBranch(cUnit,0);
buzbee31a4a6f2012-02-28 15:36:15 -0800962 // TUNING: move slow path to end & remove unconditional branch
963 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800964 // Call out to helper, which will return resolved type in rARG0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700965#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800966 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
967 pInitializeTypeFromCode));
buzbeee1965672012-03-11 18:39:19 -0700968 opRegCopy(cUnit, rARG1, rlMethod.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800969 loadConstant(cUnit, rARG0, type_idx);
970 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700971 oatFreeTemp(cUnit, rTgt);
972#else
973 opRegCopy(cUnit, rARG1, rlMethod.lowReg);
974 loadConstant(cUnit, rARG0, type_idx);
975 callRuntimeHelper(cUnit, OFFSETOF_MEMBER(Thread,
976 pInitializeTypeFromCode));
977#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700978 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800979 storeValue(cUnit, rlDest, rlResult);
buzbee3d661942012-03-14 17:37:27 -0700980 /*
981 * Because we have stores of the target value on two paths,
982 * clobber temp tracking for the destination using the ssa name
983 */
984 oatClobberSReg(cUnit, rlDest.sRegLow);
buzbee31a4a6f2012-02-28 15:36:15 -0800985 // Rejoin code paths
986 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800987 branch1->target = (LIR*)target1;
988 branch2->target = (LIR*)target2;
989 } else {
990 // Fast path, we're done - just store result
991 storeValue(cUnit, rlDest, rlResult);
992 }
993 }
994}
995void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
996 RegLocation rlSrc)
997{
998 /* NOTE: Most strings should be available at compile time */
999 uint32_t string_idx = mir->dalvikInsn.vB;
1000 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1001 (sizeof(String*) * string_idx);
1002 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
1003 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
1004 // slow path, resolve string if not in dex cache
1005 oatFlushAllRegs(cUnit);
1006 oatLockCallTemps(cUnit); // Using explicit registers
1007 loadCurrMethodDirect(cUnit, rARG2);
1008 loadWordDisp(cUnit, rARG2,
1009 Method::DexCacheStringsOffset().Int32Value(), rARG0);
1010 // Might call out to helper, which will return resolved string in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001011#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001012 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1013 pResolveStringFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001014#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001015 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
1016 loadConstant(cUnit, rARG1, string_idx);
1017#if defined(TARGET_ARM)
1018 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
1019 genBarrier(cUnit);
1020 // For testing, always force through helper
1021 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee82488f52012-03-02 08:20:26 -08001022 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08001023 }
buzbee82488f52012-03-02 08:20:26 -08001024 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -08001025 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001026 oatFreeTemp(cUnit, rTgt);
1027#elif defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -08001028 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
1029 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -08001030 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001031 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001032 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001033 branch->target = target;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001034#else
1035 opRegCopy(cUnit, rARG0, rARG2);
1036 callRuntimeHelper(cUnit, OFFSETOF_MEMBER(Thread,
1037 pResolveStringFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001038#endif
1039 genBarrier(cUnit);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001040 storeValue(cUnit, rlDest, oatGetReturn(cUnit, false));
buzbee31a4a6f2012-02-28 15:36:15 -08001041 } else {
buzbeee1965672012-03-11 18:39:19 -07001042 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001043 int resReg = oatAllocTemp(cUnit);
1044 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeee1965672012-03-11 18:39:19 -07001045 loadWordDisp(cUnit, rlMethod.lowReg,
buzbee31a4a6f2012-02-28 15:36:15 -08001046 Method::DexCacheStringsOffset().Int32Value(), resReg);
1047 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1048 storeValue(cUnit, rlDest, rlResult);
1049 }
1050}
1051
1052/*
1053 * Let helper function take care of everything. Will
1054 * call Class::NewInstanceFromCode(type_idx, method);
1055 */
1056void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
1057{
1058 oatFlushAllRegs(cUnit); /* Everything to home location */
1059 uint32_t type_idx = mir->dalvikInsn.vB;
1060 // alloc will always check for resolution, do we also need to verify
1061 // access because the verifier was unable to?
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001062 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001063 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
1064 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001065 funcOffset = OFFSETOF_MEMBER(Thread, pAllocObjectFromCode);
buzbee31a4a6f2012-02-28 15:36:15 -08001066 } else {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001067 funcOffset =
1068 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck);
buzbee31a4a6f2012-02-28 15:36:15 -08001069 }
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001070#if !defined(TARGET_X86)
1071 int rTgt = loadHelper(cUnit, funcOffset);
buzbee31a4a6f2012-02-28 15:36:15 -08001072 loadCurrMethodDirect(cUnit, rARG1); // arg1 <= Method*
1073 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_idx
1074 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001075 oatFreeTemp(cUnit, rTgt);
1076#else
1077 loadCurrMethodDirect(cUnit, rARG1); // arg1 <= Method*
1078 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_idx
1079 callRuntimeHelper(cUnit, funcOffset);
1080#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001081 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001082 storeValue(cUnit, rlDest, rlResult);
1083}
1084
1085void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1086 RegLocation rlSrc)
1087{
1088 oatFlushAllRegs(cUnit);
1089 // May generate a call - use explicit registers
1090 oatLockCallTemps(cUnit);
1091 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee5de34942012-03-01 14:51:57 -08001092 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
buzbee31a4a6f2012-02-28 15:36:15 -08001093 int classReg = rARG2; // rARG2 will hold the Class*
1094 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1095 cUnit->dex_cache,
1096 *cUnit->dex_file,
1097 type_idx)) {
1098 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbee5de34942012-03-01 14:51:57 -08001099 // returns Class* in rARG0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001100#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001101 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1102 pInitializeTypeAndVerifyAccessFromCode));
1103 loadConstant(cUnit, rARG0, type_idx);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001104 callRuntimeHelper(cUnit, rTgt);
1105 oatFreeTemp(cUnit, rTgt);
1106#else
1107 loadConstant(cUnit, rARG0, type_idx);
1108 callRuntimeHelper(cUnit,
1109 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode));
1110#endif
buzbee82488f52012-03-02 08:20:26 -08001111 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee5de34942012-03-01 14:51:57 -08001112 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
buzbee31a4a6f2012-02-28 15:36:15 -08001113 } else {
buzbee5de34942012-03-01 14:51:57 -08001114 // Load dex cache entry into classReg (rARG2)
buzbee31a4a6f2012-02-28 15:36:15 -08001115 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1116 loadWordDisp(cUnit, rARG1,
1117 Method::DexCacheResolvedTypesOffset().Int32Value(),
1118 classReg);
1119 int32_t offset_of_type =
1120 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1121 * type_idx);
1122 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1123 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1124 cUnit->dex_cache, type_idx)) {
1125 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001126 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001127 // Not resolved
1128 // Call out to helper, which will return resolved type in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001129#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001130 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1131 pInitializeTypeFromCode));
1132 loadConstant(cUnit, rARG0, type_idx);
1133 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001134 oatFreeTemp(cUnit, rTgt);
1135#else
1136 loadConstant(cUnit, rARG0, type_idx);
1137 callRuntimeHelper(cUnit, OFFSETOF_MEMBER(Thread,
1138 pInitializeTypeFromCode));
1139#endif
buzbee82488f52012-03-02 08:20:26 -08001140 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001141 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1142 // Rejoin code paths
1143 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001144 hopBranch->target = (LIR*)hopTarget;
1145 }
1146 }
1147 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
buzbee82488f52012-03-02 08:20:26 -08001148 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001149 /* load object->clazz */
1150 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1151 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1152 /* rARG0 is ref, rARG1 is ref->clazz, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001153#if defined(TARGET_ARM)
1154 /* Uses conditional nullification */
buzbee31a4a6f2012-02-28 15:36:15 -08001155 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1156 pInstanceofNonTrivialFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001157 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
buzbee82488f52012-03-02 08:20:26 -08001158 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
buzbee31a4a6f2012-02-28 15:36:15 -08001159 loadConstant(cUnit, rARG0, 1); // .eq case - load true
buzbee82488f52012-03-02 08:20:26 -08001160 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee31a4a6f2012-02-28 15:36:15 -08001161 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001162#else
buzbee0398c422012-03-02 15:22:47 -08001163 /* Uses branchovers */
1164 loadConstant(cUnit, rARG0, 1); // assume true
1165 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001166#if !defined(TARGET_X86)
buzbee0398c422012-03-02 15:22:47 -08001167 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1168 pInstanceofNonTrivialFromCode));
1169 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1170 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001171#else
1172 opRegCopy(cUnit, rARG0, rARG2);
1173 opReg(cUnit, kOpBlx,
1174 OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode));
1175#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001176#endif
buzbee0398c422012-03-02 15:22:47 -08001177 oatClobberCalleeSave(cUnit);
1178 /* branch targets here */
buzbee31a4a6f2012-02-28 15:36:15 -08001179 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001180 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001181 storeValue(cUnit, rlDest, rlResult);
buzbee0398c422012-03-02 15:22:47 -08001182 branch1->target = target;
1183#if !defined(TARGET_ARM)
1184 branchover->target = target;
1185#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001186}
1187
1188void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1189{
1190 oatFlushAllRegs(cUnit);
1191 // May generate a call - use explicit registers
1192 oatLockCallTemps(cUnit);
1193 uint32_t type_idx = mir->dalvikInsn.vB;
1194 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1195 int classReg = rARG2; // rARG2 will hold the Class*
1196 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1197 cUnit->dex_cache,
1198 *cUnit->dex_file,
1199 type_idx)) {
1200 // Check we have access to type_idx and if not throw IllegalAccessError,
1201 // returns Class* in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001202#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001203 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1204 pInitializeTypeAndVerifyAccessFromCode));
1205 loadConstant(cUnit, rARG0, type_idx);
1206 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001207 oatFreeTemp(cUnit, rTgt);
1208#else
1209 loadConstant(cUnit, rARG0, type_idx);
1210 callRuntimeHelper(cUnit,
1211 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode));
1212#endif
buzbee82488f52012-03-02 08:20:26 -08001213 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001214 } else {
1215 // Load dex cache entry into classReg (rARG2)
1216 loadWordDisp(cUnit, rARG1,
1217 Method::DexCacheResolvedTypesOffset().Int32Value(),
1218 classReg);
1219 int32_t offset_of_type =
1220 Array::DataOffset(sizeof(Class*)).Int32Value() +
1221 (sizeof(Class*) * type_idx);
1222 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1223 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1224 cUnit->dex_cache, type_idx)) {
1225 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001226 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001227 // Not resolved
buzbee5de34942012-03-01 14:51:57 -08001228 // Call out to helper, which will return resolved type in rARG0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001229#if !defined(TARGET_X86)
buzbee5de34942012-03-01 14:51:57 -08001230 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode));
1231 loadConstant(cUnit, rARG0, type_idx);
1232 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001233 oatFreeTemp(cUnit, rTgt);
1234#else
1235 loadConstant(cUnit, rARG0, type_idx);
1236 callRuntimeHelper(cUnit,
1237 OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode));
1238#endif
buzbee82488f52012-03-02 08:20:26 -08001239 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001240 // Rejoin code paths
1241 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001242 hopBranch->target = (LIR*)hopTarget;
1243 }
1244 }
buzbee5de34942012-03-01 14:51:57 -08001245 // At this point, classReg (rARG2) has class
buzbee31a4a6f2012-02-28 15:36:15 -08001246 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1247 /* Null is OK - continue */
buzbee82488f52012-03-02 08:20:26 -08001248 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001249 /* load object->clazz */
1250 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1251 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1252 /* rARG1 now contains object->clazz */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001253#if defined(TARGET_MIPS)
buzbee31a4a6f2012-02-28 15:36:15 -08001254 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1255 pCheckCastFromCode));
buzbee82488f52012-03-02 08:20:26 -08001256 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
buzbee82488f52012-03-02 08:20:26 -08001257 opRegCopy(cUnit, rARG0, rARG1);
1258 opRegCopy(cUnit, rARG1, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08001259 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001260 oatFreeTemp(cUnit, rTgt);
1261#elif defined(TARGET_ARM)
1262 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1263 pCheckCastFromCode));
1264 opRegReg(cUnit, kOpCmp, rARG1, classReg);
1265 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1266 opRegCopy(cUnit, rARG0, rARG1);
1267 opRegCopy(cUnit, rARG1, rARG2);
1268 callRuntimeHelper(cUnit, rTgt);
1269 oatFreeTemp(cUnit, rTgt);
1270#else
1271 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
1272 opRegCopy(cUnit, rARG0, rARG1);
1273 opRegCopy(cUnit, rARG1, rARG2);
1274 callRuntimeHelper(cUnit, OFFSETOF_MEMBER(Thread, pCheckCastFromCode));
1275#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001276 /* branch target here */
1277 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001278 branch1->target = (LIR*)target;
1279 branch2->target = (LIR*)target;
1280}
1281
1282
1283void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1284{
1285 oatFlushAllRegs(cUnit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001286#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001287 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException));
1288 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get exception object
1289 callRuntimeHelper(cUnit, rTgt); // art_deliver_exception(exception);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001290#else
1291 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get exception object
1292 callRuntimeHelper(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException));
1293#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001294}
1295
1296/*
1297 * Generate array store
1298 *
1299 */
1300void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
1301 RegLocation rlIndex, RegLocation rlSrc, int scale)
1302{
1303 RegisterClass regClass = oatRegClassBySize(kWord);
1304 int lenOffset = Array::LengthOffset().Int32Value();
1305 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
1306
1307 oatFlushAllRegs(cUnit);
1308 /* Make sure it's a legal object Put. Use direct regs at first */
1309 loadValueDirectFixed(cUnit, rlArray, rARG1);
1310 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1311
1312 /* null array object? */
1313 genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001314#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001315 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1316 pCanPutArrayElementFromCode));
1317 /* Get the array's clazz */
1318 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
1319 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001320 oatFreeTemp(cUnit, rTgt);
1321#else
1322 /* Get the array's clazz */
1323 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
1324 callRuntimeHelper(cUnit,
1325 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode));
1326#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001327 oatFreeTemp(cUnit, rARG0);
1328 oatFreeTemp(cUnit, rARG1);
1329
1330 // Now, redo loadValues in case they didn't survive the call
1331
1332 int regPtr;
1333 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1334 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1335
1336 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1337 oatClobber(cUnit, rlArray.lowReg);
1338 regPtr = rlArray.lowReg;
1339 } else {
1340 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001341 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001342 }
1343
1344 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1345 int regLen = oatAllocTemp(cUnit);
1346 //NOTE: max live temps(4) here.
1347 /* Get len */
1348 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1349 /* regPtr -> array data */
1350 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1351 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1352 kThrowArrayBounds);
1353 oatFreeTemp(cUnit, regLen);
1354 } else {
1355 /* regPtr -> array data */
1356 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1357 }
1358 /* at this point, regPtr points to array, 2 live temps */
1359 rlSrc = loadValue(cUnit, rlSrc, regClass);
1360 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1361 scale, kWord);
1362}
1363
1364/*
1365 * Generate array load
1366 */
1367void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1368 RegLocation rlArray, RegLocation rlIndex,
1369 RegLocation rlDest, int scale)
1370{
1371 RegisterClass regClass = oatRegClassBySize(size);
1372 int lenOffset = Array::LengthOffset().Int32Value();
1373 int dataOffset;
1374 RegLocation rlResult;
1375 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1376 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001377
1378 if (size == kLong || size == kDouble) {
1379 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1380 } else {
1381 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1382 }
1383
1384 /* null object? */
1385 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1386
Ian Rogersb5d09b22012-03-06 22:14:17 -08001387#if defined(TARGET_X86)
1388 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1389 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1390 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
1391 lenOffset, mir, kThrowArrayBounds);
1392 }
1393 if ((size == kLong) || (size == kDouble)) {
1394 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1395 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1396 rlResult.lowReg, rlResult.highReg, size, INVALID_SREG);
buzbee31a4a6f2012-02-28 15:36:15 -08001397
Ian Rogersb5d09b22012-03-06 22:14:17 -08001398 storeValueWide(cUnit, rlDest, rlResult);
1399 } else {
1400 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1401
1402 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1403 rlResult.lowReg, INVALID_REG, size, INVALID_SREG);
1404
1405 storeValue(cUnit, rlDest, rlResult);
1406 }
1407#else
1408 int regPtr = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001409 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1410 int regLen = oatAllocTemp(cUnit);
1411 /* Get len */
1412 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1413 /* regPtr -> array data */
1414 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001415 // TODO: change kCondCS to a more meaningful name, is the sense of
1416 // carry-set/clear flipped?
buzbee31a4a6f2012-02-28 15:36:15 -08001417 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1418 kThrowArrayBounds);
1419 oatFreeTemp(cUnit, regLen);
1420 } else {
1421 /* regPtr -> array data */
1422 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1423 }
1424 oatFreeTemp(cUnit, rlArray.lowReg);
1425 if ((size == kLong) || (size == kDouble)) {
1426 if (scale) {
1427 int rNewIndex = oatAllocTemp(cUnit);
1428 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1429 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1430 oatFreeTemp(cUnit, rNewIndex);
1431 } else {
1432 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1433 }
1434 oatFreeTemp(cUnit, rlIndex.lowReg);
1435 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1436
1437 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1438
1439 oatFreeTemp(cUnit, regPtr);
1440 storeValueWide(cUnit, rlDest, rlResult);
1441 } else {
1442 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1443
1444 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1445 scale, size);
1446
1447 oatFreeTemp(cUnit, regPtr);
1448 storeValue(cUnit, rlDest, rlResult);
1449 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001450#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001451}
1452
1453/*
1454 * Generate array store
1455 *
1456 */
1457void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1458 RegLocation rlArray, RegLocation rlIndex,
1459 RegLocation rlSrc, int scale)
1460{
1461 RegisterClass regClass = oatRegClassBySize(size);
1462 int lenOffset = Array::LengthOffset().Int32Value();
1463 int dataOffset;
1464
1465 if (size == kLong || size == kDouble) {
1466 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1467 } else {
1468 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1469 }
1470
1471 int regPtr;
1472 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1473 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1474
1475 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1476 oatClobber(cUnit, rlArray.lowReg);
1477 regPtr = rlArray.lowReg;
1478 } else {
1479 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001480 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001481 }
1482
1483 /* null object? */
1484 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1485
1486 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1487 int regLen = oatAllocTemp(cUnit);
1488 //NOTE: max live temps(4) here.
1489 /* Get len */
1490 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1491 /* regPtr -> array data */
1492 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1493 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1494 kThrowArrayBounds);
1495 oatFreeTemp(cUnit, regLen);
1496 } else {
1497 /* regPtr -> array data */
1498 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1499 }
1500 /* at this point, regPtr points to array, 2 live temps */
1501 if ((size == kLong) || (size == kDouble)) {
1502 //TUNING: specific wide routine that can handle fp regs
1503 if (scale) {
1504 int rNewIndex = oatAllocTemp(cUnit);
1505 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1506 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1507 oatFreeTemp(cUnit, rNewIndex);
1508 } else {
1509 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1510 }
1511 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1512
1513 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1514
1515 oatFreeTemp(cUnit, regPtr);
1516 } else {
1517 rlSrc = loadValue(cUnit, rlSrc, regClass);
1518
1519 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1520 scale, size);
1521 }
1522}
1523
1524void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1525 OpKind secondOp, RegLocation rlDest,
1526 RegLocation rlSrc1, RegLocation rlSrc2)
1527{
1528 RegLocation rlResult;
1529#if defined(TARGET_ARM)
1530 /*
1531 * NOTE: This is the one place in the code in which we might have
1532 * as many as six live temporary registers. There are 5 in the normal
1533 * set for Arm. Until we have spill capabilities, temporarily add
1534 * lr to the temp set. It is safe to do this locally, but note that
1535 * lr is used explicitly elsewhere in the code generator and cannot
1536 * normally be used as a general temp register.
1537 */
1538 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1539 oatFreeTemp(cUnit, rLR); // and make it available
1540#endif
1541 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1542 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1543 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1544 // The longs may overlap - use intermediate temp if so
1545 if (rlResult.lowReg == rlSrc1.highReg) {
1546 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001547 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001548 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1549 rlSrc2.lowReg);
1550 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1551 rlSrc2.highReg);
1552 oatFreeTemp(cUnit, tReg);
1553 } else {
1554 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1555 rlSrc2.lowReg);
1556 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1557 rlSrc2.highReg);
1558 }
1559 /*
1560 * NOTE: If rlDest refers to a frame variable in a large frame, the
1561 * following storeValueWide might need to allocate a temp register.
1562 * To further work around the lack of a spill capability, explicitly
1563 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1564 * Remove when spill is functional.
1565 */
1566 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1567 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1568 storeValueWide(cUnit, rlDest, rlResult);
1569#if defined(TARGET_ARM)
1570 oatClobber(cUnit, rLR);
1571 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1572#endif
1573}
1574
1575
1576bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1577 RegLocation rlSrc1, RegLocation rlShift)
1578{
1579 int funcOffset;
1580
1581 switch( mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001582 case Instruction::SHL_LONG:
1583 case Instruction::SHL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001584 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1585 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001586 case Instruction::SHR_LONG:
1587 case Instruction::SHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001588 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1589 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001590 case Instruction::USHR_LONG:
1591 case Instruction::USHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001592 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1593 break;
1594 default:
1595 LOG(FATAL) << "Unexpected case";
1596 return true;
1597 }
1598 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001599#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001600 int rTgt = loadHelper(cUnit, funcOffset);
1601 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1602 loadValueDirect(cUnit, rlShift, rARG2);
1603 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001604 oatFreeTemp(cUnit, rTgt);
1605#else
1606 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1607 loadValueDirect(cUnit, rlShift, rARG2);
1608 callRuntimeHelper(cUnit, funcOffset);
1609#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001610 RegLocation rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001611 storeValueWide(cUnit, rlDest, rlResult);
1612 return false;
1613}
1614
1615
1616bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1617 RegLocation rlSrc1, RegLocation rlSrc2)
1618{
1619 OpKind op = kOpBkpt;
1620 bool callOut = false;
1621 bool checkZero = false;
1622 bool unary = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001623 RegLocation rlResult;
1624 bool shiftOp = false;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001625 int funcOffset;
1626 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08001627 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001628 case Instruction::NEG_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001629 op = kOpNeg;
1630 unary = true;
1631 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001632 case Instruction::NOT_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001633 op = kOpMvn;
1634 unary = true;
1635 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001636 case Instruction::ADD_INT:
1637 case Instruction::ADD_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001638 op = kOpAdd;
1639 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001640 case Instruction::SUB_INT:
1641 case Instruction::SUB_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001642 op = kOpSub;
1643 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001644 case Instruction::MUL_INT:
1645 case Instruction::MUL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001646 op = kOpMul;
1647 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001648 case Instruction::DIV_INT:
1649 case Instruction::DIV_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001650 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001651 op = kOpDiv;
1652 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001653 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1654 retReg = rRET0;
1655 break;
buzbee5de34942012-03-01 14:51:57 -08001656 /* NOTE: returns in rARG1 */
Elliott Hughesadb8c672012-03-06 16:49:32 -08001657 case Instruction::REM_INT:
1658 case Instruction::REM_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001659 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001660 op = kOpRem;
1661 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001662 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1663 retReg = rRET1;
1664 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001665 case Instruction::AND_INT:
1666 case Instruction::AND_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001667 op = kOpAnd;
1668 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001669 case Instruction::OR_INT:
1670 case Instruction::OR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001671 op = kOpOr;
1672 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001673 case Instruction::XOR_INT:
1674 case Instruction::XOR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001675 op = kOpXor;
1676 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001677 case Instruction::SHL_INT:
1678 case Instruction::SHL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001679 shiftOp = true;
1680 op = kOpLsl;
1681 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001682 case Instruction::SHR_INT:
1683 case Instruction::SHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001684 shiftOp = true;
1685 op = kOpAsr;
1686 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001687 case Instruction::USHR_INT:
1688 case Instruction::USHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001689 shiftOp = true;
1690 op = kOpLsr;
1691 break;
1692 default:
1693 LOG(FATAL) << "Invalid word arith op: " <<
1694 (int)mir->dalvikInsn.opcode;
1695 }
1696 if (!callOut) {
1697 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1698 if (unary) {
1699 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1700 opRegReg(cUnit, op, rlResult.lowReg,
1701 rlSrc1.lowReg);
1702 } else {
1703 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001704#if defined(TARGET_X86)
1705 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1706 opRegRegReg(cUnit, op, rlResult.lowReg,
1707 rlSrc1.lowReg, rlSrc2.lowReg);
1708#else
buzbee31a4a6f2012-02-28 15:36:15 -08001709 if (shiftOp) {
1710 int tReg = oatAllocTemp(cUnit);
1711 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1712 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1713 opRegRegReg(cUnit, op, rlResult.lowReg,
1714 rlSrc1.lowReg, tReg);
1715 oatFreeTemp(cUnit, tReg);
1716 } else {
1717 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1718 opRegRegReg(cUnit, op, rlResult.lowReg,
1719 rlSrc1.lowReg, rlSrc2.lowReg);
1720 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001721#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001722 }
1723 storeValue(cUnit, rlDest, rlResult);
1724 } else {
1725 RegLocation rlResult;
1726 oatFlushAllRegs(cUnit); /* Send everything to home location */
1727 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001728#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001729 int rTgt = loadHelper(cUnit, funcOffset);
1730 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1731 if (checkZero) {
1732 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1733 }
1734 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001735 oatFreeTemp(cUnit, rTgt);
1736#else
1737 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1738 if (checkZero) {
1739 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1740 }
1741 callRuntimeHelper(cUnit, funcOffset);
1742#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001743 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001744 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001745 else
1746 rlResult = oatGetReturnAlt(cUnit);
1747 storeValue(cUnit, rlDest, rlResult);
1748 }
1749 return false;
1750}
1751
1752/*
1753 * The following are the first-level codegen routines that analyze the format
1754 * of each bytecode then either dispatch special purpose codegen routines
1755 * or produce corresponding Thumb instructions directly.
1756 */
1757
1758bool isPowerOfTwo(int x)
1759{
1760 return (x & (x - 1)) == 0;
1761}
1762
1763// Returns true if no more than two bits are set in 'x'.
1764bool isPopCountLE2(unsigned int x)
1765{
1766 x &= x - 1;
1767 return (x & (x - 1)) == 0;
1768}
1769
1770// Returns the index of the lowest set bit in 'x'.
1771int lowestSetBit(unsigned int x) {
1772 int bit_posn = 0;
1773 while ((x & 0xf) == 0) {
1774 bit_posn += 4;
1775 x >>= 4;
1776 }
1777 while ((x & 1) == 0) {
1778 bit_posn++;
1779 x >>= 1;
1780 }
1781 return bit_posn;
1782}
1783
1784// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1785// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001786bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
buzbee31a4a6f2012-02-28 15:36:15 -08001787 RegLocation rlSrc, RegLocation rlDest, int lit)
1788{
1789 if (lit < 2 || !isPowerOfTwo(lit)) {
1790 return false;
1791 }
1792 int k = lowestSetBit(lit);
1793 if (k >= 30) {
1794 // Avoid special cases.
1795 return false;
1796 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001797 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1798 dalvikOpcode == Instruction::DIV_INT_LIT16);
buzbee31a4a6f2012-02-28 15:36:15 -08001799 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1800 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1801 if (div) {
1802 int tReg = oatAllocTemp(cUnit);
1803 if (lit == 2) {
1804 // Division by 2 is by far the most common division by constant.
1805 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1806 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1807 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1808 } else {
1809 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1810 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1811 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1812 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1813 }
1814 } else {
1815 int cReg = oatAllocTemp(cUnit);
1816 loadConstant(cUnit, cReg, lit - 1);
1817 int tReg1 = oatAllocTemp(cUnit);
1818 int tReg2 = oatAllocTemp(cUnit);
1819 if (lit == 2) {
1820 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1821 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1822 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1823 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1824 } else {
1825 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1826 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1827 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1828 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1829 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1830 }
1831 }
1832 storeValue(cUnit, rlDest, rlResult);
1833 return true;
1834}
1835
1836void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1837 RegLocation rlResult, int lit,
1838 int firstBit, int secondBit)
1839{
buzbee0398c422012-03-02 15:22:47 -08001840#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001841 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1842 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001843#else
1844 int tReg = oatAllocTemp(cUnit);
1845 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1846 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1847 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001848#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001849 if (firstBit != 0) {
1850 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1851 }
1852}
1853
1854// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1855// and store the result in 'rlDest'.
1856bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1857 RegLocation rlDest, int lit)
1858{
1859 // Can we simplify this multiplication?
1860 bool powerOfTwo = false;
1861 bool popCountLE2 = false;
1862 bool powerOfTwoMinusOne = false;
1863 if (lit < 2) {
1864 // Avoid special cases.
1865 return false;
1866 } else if (isPowerOfTwo(lit)) {
1867 powerOfTwo = true;
1868 } else if (isPopCountLE2(lit)) {
1869 popCountLE2 = true;
1870 } else if (isPowerOfTwo(lit + 1)) {
1871 powerOfTwoMinusOne = true;
1872 } else {
1873 return false;
1874 }
1875 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1876 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1877 if (powerOfTwo) {
1878 // Shift.
1879 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1880 lowestSetBit(lit));
1881 } else if (popCountLE2) {
1882 // Shift and add and shift.
1883 int firstBit = lowestSetBit(lit);
1884 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1885 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1886 firstBit, secondBit);
1887 } else {
1888 // Reverse subtract: (src << (shift + 1)) - src.
1889 DCHECK(powerOfTwoMinusOne);
1890 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1891 int tReg = oatAllocTemp(cUnit);
1892 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1893 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1894 }
1895 storeValue(cUnit, rlDest, rlResult);
1896 return true;
1897}
1898
1899bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1900 RegLocation rlSrc, int lit)
1901{
Elliott Hughesadb8c672012-03-06 16:49:32 -08001902 Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08001903 RegLocation rlResult;
1904 OpKind op = (OpKind)0; /* Make gcc happy */
1905 int shiftOp = false;
1906 bool isDiv = false;
1907 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001908
1909 switch (dalvikOpcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001910 case Instruction::RSUB_INT_LIT8:
1911 case Instruction::RSUB_INT: {
buzbee31a4a6f2012-02-28 15:36:15 -08001912 int tReg;
1913 //TUNING: add support for use of Arm rsub op
1914 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1915 tReg = oatAllocTemp(cUnit);
1916 loadConstant(cUnit, tReg, lit);
1917 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1918 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1919 tReg, rlSrc.lowReg);
1920 storeValue(cUnit, rlDest, rlResult);
1921 return false;
1922 break;
1923 }
1924
Elliott Hughesadb8c672012-03-06 16:49:32 -08001925 case Instruction::ADD_INT_LIT8:
1926 case Instruction::ADD_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001927 op = kOpAdd;
1928 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001929 case Instruction::MUL_INT_LIT8:
1930 case Instruction::MUL_INT_LIT16: {
buzbee31a4a6f2012-02-28 15:36:15 -08001931 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1932 return false;
1933 }
1934 op = kOpMul;
1935 break;
1936 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001937 case Instruction::AND_INT_LIT8:
1938 case Instruction::AND_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001939 op = kOpAnd;
1940 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001941 case Instruction::OR_INT_LIT8:
1942 case Instruction::OR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001943 op = kOpOr;
1944 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001945 case Instruction::XOR_INT_LIT8:
1946 case Instruction::XOR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001947 op = kOpXor;
1948 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001949 case Instruction::SHL_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001950 lit &= 31;
1951 shiftOp = true;
1952 op = kOpLsl;
1953 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001954 case Instruction::SHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001955 lit &= 31;
1956 shiftOp = true;
1957 op = kOpAsr;
1958 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001959 case Instruction::USHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001960 lit &= 31;
1961 shiftOp = true;
1962 op = kOpLsr;
1963 break;
1964
Elliott Hughesadb8c672012-03-06 16:49:32 -08001965 case Instruction::DIV_INT_LIT8:
1966 case Instruction::DIV_INT_LIT16:
1967 case Instruction::REM_INT_LIT8:
1968 case Instruction::REM_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001969 if (lit == 0) {
1970 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
1971 return false;
1972 }
1973 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
1974 return false;
1975 }
1976 oatFlushAllRegs(cUnit); /* Everything to home location */
1977 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1978 oatClobber(cUnit, rARG0);
Elliott Hughesadb8c672012-03-06 16:49:32 -08001979 if ((dalvikOpcode == Instruction::DIV_INT_LIT8) ||
1980 (dalvikOpcode == Instruction::DIV_INT_LIT16)) {
buzbee31a4a6f2012-02-28 15:36:15 -08001981 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1982 isDiv = true;
1983 } else {
1984 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1985 isDiv = false;
1986 }
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001987#if !defined(TARGET_X86)
1988 {
1989 int rTgt = loadHelper(cUnit, funcOffset);
1990 loadConstant(cUnit, rARG1, lit);
1991 callRuntimeHelper(cUnit, rTgt);
1992 oatFreeTemp(cUnit, rTgt);
1993 }
1994#else
buzbee31a4a6f2012-02-28 15:36:15 -08001995 loadConstant(cUnit, rARG1, lit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001996 callRuntimeHelper(cUnit, funcOffset);
1997#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001998 if (isDiv)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001999 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002000 else
2001 rlResult = oatGetReturnAlt(cUnit);
2002 storeValue(cUnit, rlDest, rlResult);
2003 return false;
2004 break;
2005 default:
2006 return true;
2007 }
2008 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2009 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2010 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2011 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08002012 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002013 } else {
2014 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2015 }
2016 storeValue(cUnit, rlDest, rlResult);
2017 return false;
2018}
2019
2020bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
2021 RegLocation rlSrc1, RegLocation rlSrc2)
2022{
2023 RegLocation rlResult;
2024 OpKind firstOp = kOpBkpt;
2025 OpKind secondOp = kOpBkpt;
2026 bool callOut = false;
2027 bool checkZero = false;
2028 int funcOffset;
2029 int retReg = rRET0;
2030
2031 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002032 case Instruction::NOT_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002033 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2034 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2035 // Check for destructive overlap
2036 if (rlResult.lowReg == rlSrc2.highReg) {
2037 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08002038 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002039 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2040 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2041 oatFreeTemp(cUnit, tReg);
2042 } else {
2043 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2044 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2045 }
2046 storeValueWide(cUnit, rlDest, rlResult);
2047 return false;
2048 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002049 case Instruction::ADD_LONG:
2050 case Instruction::ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002051#if defined(TARGET_MIPS)
2052 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2053#else
buzbee31a4a6f2012-02-28 15:36:15 -08002054 firstOp = kOpAdd;
2055 secondOp = kOpAdc;
2056 break;
buzbeec5159d52012-03-03 11:48:39 -08002057#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002058 case Instruction::SUB_LONG:
2059 case Instruction::SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002060#if defined(TARGET_MIPS)
2061 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2062#else
buzbee31a4a6f2012-02-28 15:36:15 -08002063 firstOp = kOpSub;
2064 secondOp = kOpSbc;
2065 break;
buzbeec5159d52012-03-03 11:48:39 -08002066#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002067 case Instruction::MUL_LONG:
2068 case Instruction::MUL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002069 callOut = true;
2070 retReg = rRET0;
2071 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
2072 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002073 case Instruction::DIV_LONG:
2074 case Instruction::DIV_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002075 callOut = true;
2076 checkZero = true;
2077 retReg = rRET0;
2078 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2079 break;
2080 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2081 // FIXME: is true, or could be made true, or other targets?
Elliott Hughesadb8c672012-03-06 16:49:32 -08002082 case Instruction::REM_LONG:
2083 case Instruction::REM_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002084 callOut = true;
2085 checkZero = true;
2086 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2087 retReg = rARG2;
2088 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002089 case Instruction::AND_LONG_2ADDR:
2090 case Instruction::AND_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002091 firstOp = kOpAnd;
2092 secondOp = kOpAnd;
2093 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002094 case Instruction::OR_LONG:
2095 case Instruction::OR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002096 firstOp = kOpOr;
2097 secondOp = kOpOr;
2098 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002099 case Instruction::XOR_LONG:
2100 case Instruction::XOR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002101 firstOp = kOpXor;
2102 secondOp = kOpXor;
2103 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002104 case Instruction::NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08002105 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002106 }
2107 default:
2108 LOG(FATAL) << "Invalid long arith op";
2109 }
2110 if (!callOut) {
2111 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
2112 } else {
2113 int rTgt;
2114 oatFlushAllRegs(cUnit); /* Send everything to home location */
2115 if (checkZero) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002116#if defined(TARGET_X86)
2117 UNIMPLEMENTED(FATAL);
2118#else
buzbee31a4a6f2012-02-28 15:36:15 -08002119 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2120 rTgt = loadHelper(cUnit, funcOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002121#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002122 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2123 int tReg = oatAllocTemp(cUnit);
2124#if defined(TARGET_ARM)
2125 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2126 oatFreeTemp(cUnit, tReg);
2127 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
2128#else
Ian Rogersb5d09b22012-03-06 22:14:17 -08002129#if defined(TARGET_X86)
2130 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002131 rTgt = -1;
Ian Rogersb5d09b22012-03-06 22:14:17 -08002132#else
buzbee31a4a6f2012-02-28 15:36:15 -08002133 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002134#endif
buzbee5de34942012-03-01 14:51:57 -08002135 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08002136 oatFreeTemp(cUnit, tReg);
2137#endif
2138 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002139#if defined(TARGET_X86)
2140 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002141 rTgt = -1;
Ian Rogersb5d09b22012-03-06 22:14:17 -08002142#else
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002143 rTgt = loadHelper(cUnit, funcOffset);
2144 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -08002145 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002146#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002147 }
2148 callRuntimeHelper(cUnit, rTgt);
2149 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2150 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002151 rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002152 else
2153 rlResult = oatGetReturnWideAlt(cUnit);
2154 storeValueWide(cUnit, rlDest, rlResult);
2155 }
2156 return false;
2157}
2158
2159bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
2160 int srcSize, int tgtSize)
2161{
2162 /*
2163 * Don't optimize the register usage since it calls out to support
2164 * functions
2165 */
2166 RegLocation rlSrc;
2167 RegLocation rlDest;
2168 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002169#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08002170 int rTgt = loadHelper(cUnit, funcOffset);
2171 if (srcSize == 1) {
2172 rlSrc = oatGetSrc(cUnit, mir, 0);
2173 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2174 } else {
2175 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
2176 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
2177 }
2178 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002179#else
2180 if (srcSize == 1) {
2181 rlSrc = oatGetSrc(cUnit, mir, 0);
2182 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2183 } else {
2184 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
2185 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
2186 }
2187 callRuntimeHelper(cUnit, funcOffset);
2188#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002189 if (tgtSize == 1) {
2190 RegLocation rlResult;
2191 rlDest = oatGetDest(cUnit, mir, 0);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002192 rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002193 storeValue(cUnit, rlDest, rlResult);
2194 } else {
2195 RegLocation rlResult;
2196 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002197 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002198 storeValueWide(cUnit, rlDest, rlResult);
2199 }
2200 return false;
2201}
2202
2203void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
2204bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
2205 RegLocation rlDest, RegLocation rlSrc1,
2206 RegLocation rlSrc2)
2207{
2208 RegLocation rlResult;
2209 int funcOffset;
2210
2211 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002212 case Instruction::ADD_FLOAT_2ADDR:
2213 case Instruction::ADD_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002214 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
2215 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002216 case Instruction::SUB_FLOAT_2ADDR:
2217 case Instruction::SUB_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002218 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
2219 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002220 case Instruction::DIV_FLOAT_2ADDR:
2221 case Instruction::DIV_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002222 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
2223 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002224 case Instruction::MUL_FLOAT_2ADDR:
2225 case Instruction::MUL_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002226 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
2227 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002228 case Instruction::REM_FLOAT_2ADDR:
2229 case Instruction::REM_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002230 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
2231 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002232 case Instruction::NEG_FLOAT: {
buzbee31a4a6f2012-02-28 15:36:15 -08002233 genNegFloat(cUnit, rlDest, rlSrc1);
2234 return false;
2235 }
2236 default:
2237 return true;
2238 }
2239 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002240#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08002241 int rTgt = loadHelper(cUnit, funcOffset);
2242 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
2243 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
2244 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002245 oatFreeTemp(cUnit, rTgt);
2246#else
2247 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
2248 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
2249 callRuntimeHelper(cUnit, funcOffset);
2250#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002251 rlResult = oatGetReturn(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002252 storeValue(cUnit, rlDest, rlResult);
2253 return false;
2254}
2255
2256void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
2257bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
2258 RegLocation rlDest, RegLocation rlSrc1,
2259 RegLocation rlSrc2)
2260{
2261 RegLocation rlResult;
2262 int funcOffset;
2263
2264 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002265 case Instruction::ADD_DOUBLE_2ADDR:
2266 case Instruction::ADD_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002267 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
2268 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002269 case Instruction::SUB_DOUBLE_2ADDR:
2270 case Instruction::SUB_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002271 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
2272 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002273 case Instruction::DIV_DOUBLE_2ADDR:
2274 case Instruction::DIV_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002275 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2276 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002277 case Instruction::MUL_DOUBLE_2ADDR:
2278 case Instruction::MUL_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002279 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2280 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002281 case Instruction::REM_DOUBLE_2ADDR:
2282 case Instruction::REM_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002283 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2284 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002285 case Instruction::NEG_DOUBLE: {
buzbee31a4a6f2012-02-28 15:36:15 -08002286 genNegDouble(cUnit, rlDest, rlSrc1);
2287 return false;
2288 }
2289 default:
2290 return true;
2291 }
2292 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002293#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08002294 int rTgt = loadHelper(cUnit, funcOffset);
2295 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2296 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2297 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002298#else
2299 UNIMPLEMENTED(FATAL);
2300 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2301 //loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2302 callRuntimeHelper(cUnit, funcOffset);
2303#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002304 rlResult = oatGetReturnWide(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002305 storeValueWide(cUnit, rlDest, rlResult);
2306 return false;
2307}
2308
2309bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2310{
Elliott Hughesadb8c672012-03-06 16:49:32 -08002311 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08002312
2313 switch (opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002314 case Instruction::INT_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002315 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2316 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002317 case Instruction::FLOAT_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002318 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2319 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002320 case Instruction::DOUBLE_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002321 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2322 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002323 case Instruction::FLOAT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002324 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2325 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002326 case Instruction::INT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002327 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2328 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002329 case Instruction::DOUBLE_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002330 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2331 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002332 case Instruction::FLOAT_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002333 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2334 pF2l), 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002335 case Instruction::LONG_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002336 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2337 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002338 case Instruction::DOUBLE_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002339 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2340 pD2l), 2, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002341 case Instruction::LONG_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002342 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2343 2, 2);
2344 default:
2345 return true;
2346 }
2347 return false;
2348}
2349
2350/*
2351 * Generate callout to updateDebugger. Note that we're overloading
2352 * the use of rSUSPEND here. When the debugger is active, this
2353 * register holds the address of the update function. So, if it's
2354 * non-null, we call out to it.
2355 *
2356 * Note also that rRET0 and rRET1 must be preserved across this
2357 * code. This must be handled by the stub.
2358 */
2359void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2360{
2361 // Following DCHECK verifies that dPC is in range of single load immediate
2362 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2363 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2364 oatClobberCalleeSave(cUnit);
2365#if defined(TARGET_ARM)
2366 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002367 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002368 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2369 opReg(cUnit, kOpBlx, rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002370#elif defined(TARGET_X86)
2371 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002372#else
buzbee82488f52012-03-02 08:20:26 -08002373 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002374 loadConstant(cUnit, rARG2, offset);
2375 opReg(cUnit, kOpBlx, rSUSPEND);
2376 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002377 branch->target = (LIR*)target;
2378#endif
2379 oatFreeTemp(cUnit, rARG2);
2380}
2381
2382/* Check if we need to check for pending suspend request */
2383void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2384{
2385 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2386 return;
2387 }
2388 oatFlushAllRegs(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002389 if (cUnit->genDebugger) {
2390 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002391#if defined(TARGET_X86)
2392 UNIMPLEMENTED(FATAL);
2393#else
buzbee86a4bce2012-03-06 18:15:00 -08002394 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
2395 pTestSuspendFromCode));
2396 opReg(cUnit, kOpBlx, rTgt);
2397 // Refresh rSUSPEND
2398 loadWordDisp(cUnit, rSELF,
2399 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
2400 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002401#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002402 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002403 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002404#if defined(TARGET_ARM)
2405 // In non-debug case, only check periodically
2406 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002407 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002408#elif defined(TARGET_X86)
2409 newLIR2(cUnit, kX86Cmp32TI, Thread::SuspendCountOffset().Int32Value(), 0);
2410 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002411#else
2412 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002413 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002414#endif
buzbee86a4bce2012-03-06 18:15:00 -08002415 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2416 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2417 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
2418 branch->target = (LIR*)target;
2419 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
buzbee31a4a6f2012-02-28 15:36:15 -08002420 }
buzbee31a4a6f2012-02-28 15:36:15 -08002421}
2422
2423} // namespace art