blob: 34d9fb9e65cb411c7be97b3a7db3bbcb269e20d2 [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
buzbee239c4e72012-03-16 08:42:29 -07001344 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1345 int regLen = INVALID_REG;
1346 if (needsRangeCheck) {
1347 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001348 //NOTE: max live temps(4) here.
1349 /* Get len */
1350 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee239c4e72012-03-16 08:42:29 -07001351 }
1352 /* regPtr -> array data */
1353 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1354 /* at this point, regPtr points to array, 2 live temps */
1355 rlSrc = loadValue(cUnit, rlSrc, regClass);
1356 if (needsRangeCheck) {
buzbee31a4a6f2012-02-28 15:36:15 -08001357 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1358 kThrowArrayBounds);
1359 oatFreeTemp(cUnit, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001360 }
buzbee31a4a6f2012-02-28 15:36:15 -08001361 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1362 scale, kWord);
1363}
1364
1365/*
1366 * Generate array load
1367 */
1368void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1369 RegLocation rlArray, RegLocation rlIndex,
1370 RegLocation rlDest, int scale)
1371{
1372 RegisterClass regClass = oatRegClassBySize(size);
1373 int lenOffset = Array::LengthOffset().Int32Value();
1374 int dataOffset;
1375 RegLocation rlResult;
1376 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1377 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001378
1379 if (size == kLong || size == kDouble) {
1380 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1381 } else {
1382 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1383 }
1384
1385 /* null object? */
1386 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1387
Ian Rogersb5d09b22012-03-06 22:14:17 -08001388#if defined(TARGET_X86)
1389 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1390 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1391 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
1392 lenOffset, mir, kThrowArrayBounds);
1393 }
1394 if ((size == kLong) || (size == kDouble)) {
1395 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1396 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1397 rlResult.lowReg, rlResult.highReg, size, INVALID_SREG);
buzbee31a4a6f2012-02-28 15:36:15 -08001398
Ian Rogersb5d09b22012-03-06 22:14:17 -08001399 storeValueWide(cUnit, rlDest, rlResult);
1400 } else {
1401 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1402
1403 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1404 rlResult.lowReg, INVALID_REG, size, INVALID_SREG);
1405
1406 storeValue(cUnit, rlDest, rlResult);
1407 }
1408#else
1409 int regPtr = oatAllocTemp(cUnit);
buzbee239c4e72012-03-16 08:42:29 -07001410 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1411 int regLen = INVALID_REG;
1412 if (needsRangeCheck) {
1413 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001414 /* Get len */
1415 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001416 }
buzbee239c4e72012-03-16 08:42:29 -07001417 /* regPtr -> array data */
1418 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -08001419 oatFreeTemp(cUnit, rlArray.lowReg);
1420 if ((size == kLong) || (size == kDouble)) {
1421 if (scale) {
1422 int rNewIndex = oatAllocTemp(cUnit);
1423 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1424 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1425 oatFreeTemp(cUnit, rNewIndex);
1426 } else {
1427 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1428 }
1429 oatFreeTemp(cUnit, rlIndex.lowReg);
1430 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1431
buzbee239c4e72012-03-16 08:42:29 -07001432 if (needsRangeCheck) {
1433 // TODO: change kCondCS to a more meaningful name, is the sense of
1434 // carry-set/clear flipped?
1435 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1436 kThrowArrayBounds);
1437 oatFreeTemp(cUnit, regLen);
1438 }
buzbee31a4a6f2012-02-28 15:36:15 -08001439 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1440
1441 oatFreeTemp(cUnit, regPtr);
1442 storeValueWide(cUnit, rlDest, rlResult);
1443 } else {
1444 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1445
buzbee239c4e72012-03-16 08:42:29 -07001446 if (needsRangeCheck) {
1447 // TODO: change kCondCS to a more meaningful name, is the sense of
1448 // carry-set/clear flipped?
1449 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1450 kThrowArrayBounds);
1451 oatFreeTemp(cUnit, regLen);
1452 }
buzbee31a4a6f2012-02-28 15:36:15 -08001453 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1454 scale, size);
1455
1456 oatFreeTemp(cUnit, regPtr);
1457 storeValue(cUnit, rlDest, rlResult);
1458 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001459#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001460}
1461
1462/*
1463 * Generate array store
1464 *
1465 */
1466void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1467 RegLocation rlArray, RegLocation rlIndex,
1468 RegLocation rlSrc, int scale)
1469{
1470 RegisterClass regClass = oatRegClassBySize(size);
1471 int lenOffset = Array::LengthOffset().Int32Value();
1472 int dataOffset;
1473
1474 if (size == kLong || size == kDouble) {
1475 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1476 } else {
1477 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1478 }
1479
1480 int regPtr;
1481 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1482 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1483
1484 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1485 oatClobber(cUnit, rlArray.lowReg);
1486 regPtr = rlArray.lowReg;
1487 } else {
1488 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001489 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001490 }
1491
1492 /* null object? */
1493 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1494
buzbee239c4e72012-03-16 08:42:29 -07001495 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1496 int regLen = INVALID_REG;
1497 if (needsRangeCheck) {
1498 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001499 //NOTE: max live temps(4) here.
1500 /* Get len */
1501 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001502 }
buzbee239c4e72012-03-16 08:42:29 -07001503 /* regPtr -> array data */
1504 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -08001505 /* at this point, regPtr points to array, 2 live temps */
1506 if ((size == kLong) || (size == kDouble)) {
1507 //TUNING: specific wide routine that can handle fp regs
1508 if (scale) {
1509 int rNewIndex = oatAllocTemp(cUnit);
1510 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1511 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1512 oatFreeTemp(cUnit, rNewIndex);
1513 } else {
1514 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1515 }
1516 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1517
buzbee239c4e72012-03-16 08:42:29 -07001518 if (needsRangeCheck) {
1519 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1520 kThrowArrayBounds);
1521 oatFreeTemp(cUnit, regLen);
1522 }
1523
buzbee31a4a6f2012-02-28 15:36:15 -08001524 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1525
1526 oatFreeTemp(cUnit, regPtr);
1527 } else {
1528 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee239c4e72012-03-16 08:42:29 -07001529 if (needsRangeCheck) {
1530 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1531 kThrowArrayBounds);
1532 oatFreeTemp(cUnit, regLen);
1533 }
buzbee31a4a6f2012-02-28 15:36:15 -08001534 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1535 scale, size);
1536 }
1537}
1538
1539void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1540 OpKind secondOp, RegLocation rlDest,
1541 RegLocation rlSrc1, RegLocation rlSrc2)
1542{
1543 RegLocation rlResult;
1544#if defined(TARGET_ARM)
1545 /*
1546 * NOTE: This is the one place in the code in which we might have
1547 * as many as six live temporary registers. There are 5 in the normal
1548 * set for Arm. Until we have spill capabilities, temporarily add
1549 * lr to the temp set. It is safe to do this locally, but note that
1550 * lr is used explicitly elsewhere in the code generator and cannot
1551 * normally be used as a general temp register.
1552 */
1553 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1554 oatFreeTemp(cUnit, rLR); // and make it available
1555#endif
1556 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1557 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1558 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1559 // The longs may overlap - use intermediate temp if so
1560 if (rlResult.lowReg == rlSrc1.highReg) {
1561 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001562 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001563 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1564 rlSrc2.lowReg);
1565 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1566 rlSrc2.highReg);
1567 oatFreeTemp(cUnit, tReg);
1568 } else {
1569 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1570 rlSrc2.lowReg);
1571 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1572 rlSrc2.highReg);
1573 }
1574 /*
1575 * NOTE: If rlDest refers to a frame variable in a large frame, the
1576 * following storeValueWide might need to allocate a temp register.
1577 * To further work around the lack of a spill capability, explicitly
1578 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1579 * Remove when spill is functional.
1580 */
1581 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1582 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1583 storeValueWide(cUnit, rlDest, rlResult);
1584#if defined(TARGET_ARM)
1585 oatClobber(cUnit, rLR);
1586 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1587#endif
1588}
1589
1590
1591bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1592 RegLocation rlSrc1, RegLocation rlShift)
1593{
1594 int funcOffset;
1595
1596 switch( mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001597 case Instruction::SHL_LONG:
1598 case Instruction::SHL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001599 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1600 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001601 case Instruction::SHR_LONG:
1602 case Instruction::SHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001603 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1604 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001605 case Instruction::USHR_LONG:
1606 case Instruction::USHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001607 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1608 break;
1609 default:
1610 LOG(FATAL) << "Unexpected case";
1611 return true;
1612 }
1613 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001614#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001615 int rTgt = loadHelper(cUnit, funcOffset);
1616 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1617 loadValueDirect(cUnit, rlShift, rARG2);
1618 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001619 oatFreeTemp(cUnit, rTgt);
1620#else
1621 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1622 loadValueDirect(cUnit, rlShift, rARG2);
1623 callRuntimeHelper(cUnit, funcOffset);
1624#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001625 RegLocation rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001626 storeValueWide(cUnit, rlDest, rlResult);
1627 return false;
1628}
1629
1630
1631bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1632 RegLocation rlSrc1, RegLocation rlSrc2)
1633{
1634 OpKind op = kOpBkpt;
1635 bool callOut = false;
1636 bool checkZero = false;
1637 bool unary = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001638 RegLocation rlResult;
1639 bool shiftOp = false;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001640 int funcOffset;
1641 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08001642 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001643 case Instruction::NEG_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001644 op = kOpNeg;
1645 unary = true;
1646 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001647 case Instruction::NOT_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001648 op = kOpMvn;
1649 unary = true;
1650 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001651 case Instruction::ADD_INT:
1652 case Instruction::ADD_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001653 op = kOpAdd;
1654 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001655 case Instruction::SUB_INT:
1656 case Instruction::SUB_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001657 op = kOpSub;
1658 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001659 case Instruction::MUL_INT:
1660 case Instruction::MUL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001661 op = kOpMul;
1662 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001663 case Instruction::DIV_INT:
1664 case Instruction::DIV_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001665 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001666 op = kOpDiv;
1667 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001668 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1669 retReg = rRET0;
1670 break;
buzbee5de34942012-03-01 14:51:57 -08001671 /* NOTE: returns in rARG1 */
Elliott Hughesadb8c672012-03-06 16:49:32 -08001672 case Instruction::REM_INT:
1673 case Instruction::REM_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001674 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001675 op = kOpRem;
1676 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001677 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1678 retReg = rRET1;
1679 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001680 case Instruction::AND_INT:
1681 case Instruction::AND_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001682 op = kOpAnd;
1683 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001684 case Instruction::OR_INT:
1685 case Instruction::OR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001686 op = kOpOr;
1687 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001688 case Instruction::XOR_INT:
1689 case Instruction::XOR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001690 op = kOpXor;
1691 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001692 case Instruction::SHL_INT:
1693 case Instruction::SHL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001694 shiftOp = true;
1695 op = kOpLsl;
1696 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001697 case Instruction::SHR_INT:
1698 case Instruction::SHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001699 shiftOp = true;
1700 op = kOpAsr;
1701 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001702 case Instruction::USHR_INT:
1703 case Instruction::USHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001704 shiftOp = true;
1705 op = kOpLsr;
1706 break;
1707 default:
1708 LOG(FATAL) << "Invalid word arith op: " <<
1709 (int)mir->dalvikInsn.opcode;
1710 }
1711 if (!callOut) {
1712 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1713 if (unary) {
1714 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1715 opRegReg(cUnit, op, rlResult.lowReg,
1716 rlSrc1.lowReg);
1717 } else {
1718 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001719#if defined(TARGET_X86)
1720 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1721 opRegRegReg(cUnit, op, rlResult.lowReg,
1722 rlSrc1.lowReg, rlSrc2.lowReg);
1723#else
buzbee31a4a6f2012-02-28 15:36:15 -08001724 if (shiftOp) {
1725 int tReg = oatAllocTemp(cUnit);
1726 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1727 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1728 opRegRegReg(cUnit, op, rlResult.lowReg,
1729 rlSrc1.lowReg, tReg);
1730 oatFreeTemp(cUnit, tReg);
1731 } else {
1732 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1733 opRegRegReg(cUnit, op, rlResult.lowReg,
1734 rlSrc1.lowReg, rlSrc2.lowReg);
1735 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001736#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001737 }
1738 storeValue(cUnit, rlDest, rlResult);
1739 } else {
1740 RegLocation rlResult;
1741 oatFlushAllRegs(cUnit); /* Send everything to home location */
1742 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001743#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001744 int rTgt = loadHelper(cUnit, funcOffset);
1745 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1746 if (checkZero) {
1747 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1748 }
1749 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001750 oatFreeTemp(cUnit, rTgt);
1751#else
1752 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1753 if (checkZero) {
1754 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1755 }
1756 callRuntimeHelper(cUnit, funcOffset);
1757#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001758 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001759 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001760 else
1761 rlResult = oatGetReturnAlt(cUnit);
1762 storeValue(cUnit, rlDest, rlResult);
1763 }
1764 return false;
1765}
1766
1767/*
1768 * The following are the first-level codegen routines that analyze the format
1769 * of each bytecode then either dispatch special purpose codegen routines
1770 * or produce corresponding Thumb instructions directly.
1771 */
1772
1773bool isPowerOfTwo(int x)
1774{
1775 return (x & (x - 1)) == 0;
1776}
1777
1778// Returns true if no more than two bits are set in 'x'.
1779bool isPopCountLE2(unsigned int x)
1780{
1781 x &= x - 1;
1782 return (x & (x - 1)) == 0;
1783}
1784
1785// Returns the index of the lowest set bit in 'x'.
1786int lowestSetBit(unsigned int x) {
1787 int bit_posn = 0;
1788 while ((x & 0xf) == 0) {
1789 bit_posn += 4;
1790 x >>= 4;
1791 }
1792 while ((x & 1) == 0) {
1793 bit_posn++;
1794 x >>= 1;
1795 }
1796 return bit_posn;
1797}
1798
1799// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1800// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001801bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
buzbee31a4a6f2012-02-28 15:36:15 -08001802 RegLocation rlSrc, RegLocation rlDest, int lit)
1803{
1804 if (lit < 2 || !isPowerOfTwo(lit)) {
1805 return false;
1806 }
1807 int k = lowestSetBit(lit);
1808 if (k >= 30) {
1809 // Avoid special cases.
1810 return false;
1811 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001812 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1813 dalvikOpcode == Instruction::DIV_INT_LIT16);
buzbee31a4a6f2012-02-28 15:36:15 -08001814 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1815 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1816 if (div) {
1817 int tReg = oatAllocTemp(cUnit);
1818 if (lit == 2) {
1819 // Division by 2 is by far the most common division by constant.
1820 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1821 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1822 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1823 } else {
1824 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1825 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1826 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1827 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1828 }
1829 } else {
1830 int cReg = oatAllocTemp(cUnit);
1831 loadConstant(cUnit, cReg, lit - 1);
1832 int tReg1 = oatAllocTemp(cUnit);
1833 int tReg2 = oatAllocTemp(cUnit);
1834 if (lit == 2) {
1835 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1836 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1837 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1838 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1839 } else {
1840 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1841 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1842 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1843 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1844 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1845 }
1846 }
1847 storeValue(cUnit, rlDest, rlResult);
1848 return true;
1849}
1850
1851void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1852 RegLocation rlResult, int lit,
1853 int firstBit, int secondBit)
1854{
buzbee0398c422012-03-02 15:22:47 -08001855#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001856 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1857 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001858#else
1859 int tReg = oatAllocTemp(cUnit);
1860 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1861 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1862 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001863#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001864 if (firstBit != 0) {
1865 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1866 }
1867}
1868
1869// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1870// and store the result in 'rlDest'.
1871bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1872 RegLocation rlDest, int lit)
1873{
1874 // Can we simplify this multiplication?
1875 bool powerOfTwo = false;
1876 bool popCountLE2 = false;
1877 bool powerOfTwoMinusOne = false;
1878 if (lit < 2) {
1879 // Avoid special cases.
1880 return false;
1881 } else if (isPowerOfTwo(lit)) {
1882 powerOfTwo = true;
1883 } else if (isPopCountLE2(lit)) {
1884 popCountLE2 = true;
1885 } else if (isPowerOfTwo(lit + 1)) {
1886 powerOfTwoMinusOne = true;
1887 } else {
1888 return false;
1889 }
1890 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1891 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1892 if (powerOfTwo) {
1893 // Shift.
1894 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1895 lowestSetBit(lit));
1896 } else if (popCountLE2) {
1897 // Shift and add and shift.
1898 int firstBit = lowestSetBit(lit);
1899 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1900 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1901 firstBit, secondBit);
1902 } else {
1903 // Reverse subtract: (src << (shift + 1)) - src.
1904 DCHECK(powerOfTwoMinusOne);
1905 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1906 int tReg = oatAllocTemp(cUnit);
1907 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1908 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1909 }
1910 storeValue(cUnit, rlDest, rlResult);
1911 return true;
1912}
1913
1914bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1915 RegLocation rlSrc, int lit)
1916{
Elliott Hughesadb8c672012-03-06 16:49:32 -08001917 Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08001918 RegLocation rlResult;
1919 OpKind op = (OpKind)0; /* Make gcc happy */
1920 int shiftOp = false;
1921 bool isDiv = false;
1922 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001923
1924 switch (dalvikOpcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001925 case Instruction::RSUB_INT_LIT8:
1926 case Instruction::RSUB_INT: {
buzbee31a4a6f2012-02-28 15:36:15 -08001927 int tReg;
1928 //TUNING: add support for use of Arm rsub op
1929 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1930 tReg = oatAllocTemp(cUnit);
1931 loadConstant(cUnit, tReg, lit);
1932 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1933 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1934 tReg, rlSrc.lowReg);
1935 storeValue(cUnit, rlDest, rlResult);
1936 return false;
1937 break;
1938 }
1939
Elliott Hughesadb8c672012-03-06 16:49:32 -08001940 case Instruction::ADD_INT_LIT8:
1941 case Instruction::ADD_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001942 op = kOpAdd;
1943 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001944 case Instruction::MUL_INT_LIT8:
1945 case Instruction::MUL_INT_LIT16: {
buzbee31a4a6f2012-02-28 15:36:15 -08001946 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1947 return false;
1948 }
1949 op = kOpMul;
1950 break;
1951 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001952 case Instruction::AND_INT_LIT8:
1953 case Instruction::AND_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001954 op = kOpAnd;
1955 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001956 case Instruction::OR_INT_LIT8:
1957 case Instruction::OR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001958 op = kOpOr;
1959 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001960 case Instruction::XOR_INT_LIT8:
1961 case Instruction::XOR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001962 op = kOpXor;
1963 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001964 case Instruction::SHL_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001965 lit &= 31;
1966 shiftOp = true;
1967 op = kOpLsl;
1968 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001969 case Instruction::SHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001970 lit &= 31;
1971 shiftOp = true;
1972 op = kOpAsr;
1973 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001974 case Instruction::USHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001975 lit &= 31;
1976 shiftOp = true;
1977 op = kOpLsr;
1978 break;
1979
Elliott Hughesadb8c672012-03-06 16:49:32 -08001980 case Instruction::DIV_INT_LIT8:
1981 case Instruction::DIV_INT_LIT16:
1982 case Instruction::REM_INT_LIT8:
1983 case Instruction::REM_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001984 if (lit == 0) {
1985 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
1986 return false;
1987 }
1988 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
1989 return false;
1990 }
1991 oatFlushAllRegs(cUnit); /* Everything to home location */
1992 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1993 oatClobber(cUnit, rARG0);
Elliott Hughesadb8c672012-03-06 16:49:32 -08001994 if ((dalvikOpcode == Instruction::DIV_INT_LIT8) ||
1995 (dalvikOpcode == Instruction::DIV_INT_LIT16)) {
buzbee31a4a6f2012-02-28 15:36:15 -08001996 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1997 isDiv = true;
1998 } else {
1999 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2000 isDiv = false;
2001 }
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002002#if !defined(TARGET_X86)
2003 {
2004 int rTgt = loadHelper(cUnit, funcOffset);
2005 loadConstant(cUnit, rARG1, lit);
2006 callRuntimeHelper(cUnit, rTgt);
2007 oatFreeTemp(cUnit, rTgt);
2008 }
2009#else
buzbee31a4a6f2012-02-28 15:36:15 -08002010 loadConstant(cUnit, rARG1, lit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002011 callRuntimeHelper(cUnit, funcOffset);
2012#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002013 if (isDiv)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002014 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002015 else
2016 rlResult = oatGetReturnAlt(cUnit);
2017 storeValue(cUnit, rlDest, rlResult);
2018 return false;
2019 break;
2020 default:
2021 return true;
2022 }
2023 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2024 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2025 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2026 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08002027 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002028 } else {
2029 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2030 }
2031 storeValue(cUnit, rlDest, rlResult);
2032 return false;
2033}
2034
2035bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
2036 RegLocation rlSrc1, RegLocation rlSrc2)
2037{
2038 RegLocation rlResult;
2039 OpKind firstOp = kOpBkpt;
2040 OpKind secondOp = kOpBkpt;
2041 bool callOut = false;
2042 bool checkZero = false;
2043 int funcOffset;
2044 int retReg = rRET0;
2045
2046 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002047 case Instruction::NOT_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002048 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2049 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2050 // Check for destructive overlap
2051 if (rlResult.lowReg == rlSrc2.highReg) {
2052 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08002053 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002054 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2055 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2056 oatFreeTemp(cUnit, tReg);
2057 } else {
2058 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2059 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2060 }
2061 storeValueWide(cUnit, rlDest, rlResult);
2062 return false;
2063 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002064 case Instruction::ADD_LONG:
2065 case Instruction::ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002066#if defined(TARGET_MIPS)
2067 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2068#else
buzbee31a4a6f2012-02-28 15:36:15 -08002069 firstOp = kOpAdd;
2070 secondOp = kOpAdc;
2071 break;
buzbeec5159d52012-03-03 11:48:39 -08002072#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002073 case Instruction::SUB_LONG:
2074 case Instruction::SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002075#if defined(TARGET_MIPS)
2076 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2077#else
buzbee31a4a6f2012-02-28 15:36:15 -08002078 firstOp = kOpSub;
2079 secondOp = kOpSbc;
2080 break;
buzbeec5159d52012-03-03 11:48:39 -08002081#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002082 case Instruction::MUL_LONG:
2083 case Instruction::MUL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002084 callOut = true;
2085 retReg = rRET0;
2086 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
2087 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002088 case Instruction::DIV_LONG:
2089 case Instruction::DIV_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002090 callOut = true;
2091 checkZero = true;
2092 retReg = rRET0;
2093 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2094 break;
2095 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2096 // FIXME: is true, or could be made true, or other targets?
Elliott Hughesadb8c672012-03-06 16:49:32 -08002097 case Instruction::REM_LONG:
2098 case Instruction::REM_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002099 callOut = true;
2100 checkZero = true;
2101 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2102 retReg = rARG2;
2103 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002104 case Instruction::AND_LONG_2ADDR:
2105 case Instruction::AND_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002106 firstOp = kOpAnd;
2107 secondOp = kOpAnd;
2108 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002109 case Instruction::OR_LONG:
2110 case Instruction::OR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002111 firstOp = kOpOr;
2112 secondOp = kOpOr;
2113 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002114 case Instruction::XOR_LONG:
2115 case Instruction::XOR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002116 firstOp = kOpXor;
2117 secondOp = kOpXor;
2118 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002119 case Instruction::NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08002120 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002121 }
2122 default:
2123 LOG(FATAL) << "Invalid long arith op";
2124 }
2125 if (!callOut) {
2126 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
2127 } else {
2128 int rTgt;
2129 oatFlushAllRegs(cUnit); /* Send everything to home location */
2130 if (checkZero) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002131#if defined(TARGET_X86)
2132 UNIMPLEMENTED(FATAL);
2133#else
buzbee31a4a6f2012-02-28 15:36:15 -08002134 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2135 rTgt = loadHelper(cUnit, funcOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002136#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002137 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2138 int tReg = oatAllocTemp(cUnit);
2139#if defined(TARGET_ARM)
2140 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2141 oatFreeTemp(cUnit, tReg);
2142 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
2143#else
Ian Rogersb5d09b22012-03-06 22:14:17 -08002144#if defined(TARGET_X86)
2145 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002146 rTgt = -1;
Ian Rogersb5d09b22012-03-06 22:14:17 -08002147#else
buzbee31a4a6f2012-02-28 15:36:15 -08002148 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002149#endif
buzbee5de34942012-03-01 14:51:57 -08002150 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08002151 oatFreeTemp(cUnit, tReg);
2152#endif
2153 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002154#if defined(TARGET_X86)
2155 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002156 rTgt = -1;
Ian Rogersb5d09b22012-03-06 22:14:17 -08002157#else
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002158 rTgt = loadHelper(cUnit, funcOffset);
2159 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -08002160 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002161#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002162 }
2163 callRuntimeHelper(cUnit, rTgt);
2164 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2165 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002166 rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002167 else
2168 rlResult = oatGetReturnWideAlt(cUnit);
2169 storeValueWide(cUnit, rlDest, rlResult);
2170 }
2171 return false;
2172}
2173
2174bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
2175 int srcSize, int tgtSize)
2176{
2177 /*
2178 * Don't optimize the register usage since it calls out to support
2179 * functions
2180 */
2181 RegLocation rlSrc;
2182 RegLocation rlDest;
2183 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002184#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08002185 int rTgt = loadHelper(cUnit, funcOffset);
2186 if (srcSize == 1) {
2187 rlSrc = oatGetSrc(cUnit, mir, 0);
2188 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2189 } else {
2190 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
2191 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
2192 }
2193 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002194#else
2195 if (srcSize == 1) {
2196 rlSrc = oatGetSrc(cUnit, mir, 0);
2197 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2198 } else {
2199 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
2200 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
2201 }
2202 callRuntimeHelper(cUnit, funcOffset);
2203#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002204 if (tgtSize == 1) {
2205 RegLocation rlResult;
2206 rlDest = oatGetDest(cUnit, mir, 0);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002207 rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002208 storeValue(cUnit, rlDest, rlResult);
2209 } else {
2210 RegLocation rlResult;
2211 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002212 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002213 storeValueWide(cUnit, rlDest, rlResult);
2214 }
2215 return false;
2216}
2217
2218void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
2219bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
2220 RegLocation rlDest, RegLocation rlSrc1,
2221 RegLocation rlSrc2)
2222{
2223 RegLocation rlResult;
2224 int funcOffset;
2225
2226 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002227 case Instruction::ADD_FLOAT_2ADDR:
2228 case Instruction::ADD_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002229 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
2230 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002231 case Instruction::SUB_FLOAT_2ADDR:
2232 case Instruction::SUB_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002233 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
2234 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002235 case Instruction::DIV_FLOAT_2ADDR:
2236 case Instruction::DIV_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002237 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
2238 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002239 case Instruction::MUL_FLOAT_2ADDR:
2240 case Instruction::MUL_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002241 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
2242 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002243 case Instruction::REM_FLOAT_2ADDR:
2244 case Instruction::REM_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002245 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
2246 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002247 case Instruction::NEG_FLOAT: {
buzbee31a4a6f2012-02-28 15:36:15 -08002248 genNegFloat(cUnit, rlDest, rlSrc1);
2249 return false;
2250 }
2251 default:
2252 return true;
2253 }
2254 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002255#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08002256 int rTgt = loadHelper(cUnit, funcOffset);
2257 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
2258 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
2259 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002260 oatFreeTemp(cUnit, rTgt);
2261#else
2262 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
2263 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
2264 callRuntimeHelper(cUnit, funcOffset);
2265#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002266 rlResult = oatGetReturn(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002267 storeValue(cUnit, rlDest, rlResult);
2268 return false;
2269}
2270
2271void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
2272bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
2273 RegLocation rlDest, RegLocation rlSrc1,
2274 RegLocation rlSrc2)
2275{
2276 RegLocation rlResult;
2277 int funcOffset;
2278
2279 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002280 case Instruction::ADD_DOUBLE_2ADDR:
2281 case Instruction::ADD_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002282 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
2283 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002284 case Instruction::SUB_DOUBLE_2ADDR:
2285 case Instruction::SUB_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002286 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
2287 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002288 case Instruction::DIV_DOUBLE_2ADDR:
2289 case Instruction::DIV_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002290 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2291 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002292 case Instruction::MUL_DOUBLE_2ADDR:
2293 case Instruction::MUL_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002294 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2295 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002296 case Instruction::REM_DOUBLE_2ADDR:
2297 case Instruction::REM_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002298 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2299 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002300 case Instruction::NEG_DOUBLE: {
buzbee31a4a6f2012-02-28 15:36:15 -08002301 genNegDouble(cUnit, rlDest, rlSrc1);
2302 return false;
2303 }
2304 default:
2305 return true;
2306 }
2307 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002308#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08002309 int rTgt = loadHelper(cUnit, funcOffset);
2310 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2311 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2312 callRuntimeHelper(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002313#else
2314 UNIMPLEMENTED(FATAL);
2315 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2316 //loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2317 callRuntimeHelper(cUnit, funcOffset);
2318#endif
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002319 rlResult = oatGetReturnWide(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002320 storeValueWide(cUnit, rlDest, rlResult);
2321 return false;
2322}
2323
2324bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2325{
Elliott Hughesadb8c672012-03-06 16:49:32 -08002326 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08002327
2328 switch (opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002329 case Instruction::INT_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002330 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2331 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002332 case Instruction::FLOAT_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002333 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2334 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002335 case Instruction::DOUBLE_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002336 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2337 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002338 case Instruction::FLOAT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002339 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2340 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002341 case Instruction::INT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002342 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2343 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002344 case Instruction::DOUBLE_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002345 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2346 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002347 case Instruction::FLOAT_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002348 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2349 pF2l), 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002350 case Instruction::LONG_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002351 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2352 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002353 case Instruction::DOUBLE_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002354 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2355 pD2l), 2, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002356 case Instruction::LONG_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002357 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2358 2, 2);
2359 default:
2360 return true;
2361 }
2362 return false;
2363}
2364
2365/*
2366 * Generate callout to updateDebugger. Note that we're overloading
2367 * the use of rSUSPEND here. When the debugger is active, this
2368 * register holds the address of the update function. So, if it's
2369 * non-null, we call out to it.
2370 *
2371 * Note also that rRET0 and rRET1 must be preserved across this
2372 * code. This must be handled by the stub.
2373 */
2374void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2375{
2376 // Following DCHECK verifies that dPC is in range of single load immediate
2377 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2378 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2379 oatClobberCalleeSave(cUnit);
2380#if defined(TARGET_ARM)
2381 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002382 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002383 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2384 opReg(cUnit, kOpBlx, rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002385#elif defined(TARGET_X86)
2386 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002387#else
buzbee82488f52012-03-02 08:20:26 -08002388 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002389 loadConstant(cUnit, rARG2, offset);
2390 opReg(cUnit, kOpBlx, rSUSPEND);
2391 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002392 branch->target = (LIR*)target;
2393#endif
2394 oatFreeTemp(cUnit, rARG2);
2395}
2396
2397/* Check if we need to check for pending suspend request */
2398void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2399{
2400 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2401 return;
2402 }
2403 oatFlushAllRegs(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002404 if (cUnit->genDebugger) {
2405 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002406#if defined(TARGET_X86)
2407 UNIMPLEMENTED(FATAL);
2408#else
buzbee86a4bce2012-03-06 18:15:00 -08002409 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
2410 pTestSuspendFromCode));
2411 opReg(cUnit, kOpBlx, rTgt);
2412 // Refresh rSUSPEND
2413 loadWordDisp(cUnit, rSELF,
2414 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
2415 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002416#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002417 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002418 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002419#if defined(TARGET_ARM)
2420 // In non-debug case, only check periodically
2421 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002422 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002423#elif defined(TARGET_X86)
2424 newLIR2(cUnit, kX86Cmp32TI, Thread::SuspendCountOffset().Int32Value(), 0);
2425 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002426#else
2427 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002428 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002429#endif
buzbee86a4bce2012-03-06 18:15:00 -08002430 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2431 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2432 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
2433 branch->target = (LIR*)target;
2434 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
buzbee31a4a6f2012-02-28 15:36:15 -08002435 }
buzbee31a4a6f2012-02-28 15:36:15 -08002436}
2437
2438} // namespace art