blob: cc0d624099231bb8f18dd0a24f686a8e87c80bd5 [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 Rogersab2b55d2012-03-18 00:06:11 -070029void callRuntimeHelperImm(CompilationUnit* cUnit, int helperOffset, int arg0) {
30#if !defined(TARGET_X86)
31 int rTgt = loadHelper(cUnit, helperOffset);
32#endif
33 loadConstant(cUnit, rARG0, arg0);
buzbee31a4a6f2012-02-28 15:36:15 -080034 oatClobberCalleeSave(cUnit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070035#if !defined(TARGET_X86)
Ian Rogersab2b55d2012-03-18 00:06:11 -070036 opReg(cUnit, kOpBlx, rTgt);
37 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070038#else
Ian Rogersab2b55d2012-03-18 00:06:11 -070039 opThreadMem(cUnit, kOpBlx, helperOffset);
40#endif
41}
42
43void callRuntimeHelperRegLocation(CompilationUnit* cUnit, int helperOffset,
44 RegLocation arg0) {
45#if !defined(TARGET_X86)
46 int rTgt = loadHelper(cUnit, helperOffset);
47#endif
48 if (arg0.wide == 0) {
49 loadValueDirectFixed(cUnit, arg0, rARG0);
50 } else {
51 loadValueDirectWideFixed(cUnit, arg0, rARG0, rARG1);
52 }
53 oatClobberCalleeSave(cUnit);
54#if !defined(TARGET_X86)
55 opReg(cUnit, kOpBlx, rTgt);
56 oatFreeTemp(cUnit, rTgt);
57#else
58 opThreadMem(cUnit, kOpBlx, helperOffset);
59#endif
60}
61
62void callRuntimeHelperImmImm(CompilationUnit* cUnit, int helperOffset,
63 int arg0, int arg1) {
64#if !defined(TARGET_X86)
65 int rTgt = loadHelper(cUnit, helperOffset);
66#endif
67 loadConstant(cUnit, rARG0, arg0);
68 loadConstant(cUnit, rARG1, arg1);
69 oatClobberCalleeSave(cUnit);
70#if !defined(TARGET_X86)
71 opReg(cUnit, kOpBlx, rTgt);
72 oatFreeTemp(cUnit, rTgt);
73#else
74 opThreadMem(cUnit, kOpBlx, helperOffset);
75#endif
76}
77
78void callRuntimeHelperImmRegLocation(CompilationUnit* cUnit, int helperOffset,
79 int arg0, RegLocation arg1) {
80#if !defined(TARGET_X86)
81 int rTgt = loadHelper(cUnit, helperOffset);
82#endif
83 if (arg1.wide == 0) {
84 loadValueDirectFixed(cUnit, arg1, rARG1);
85 } else {
86 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
87 }
88 loadConstant(cUnit, rARG0, arg0);
89 oatClobberCalleeSave(cUnit);
90#if !defined(TARGET_X86)
91 opReg(cUnit, kOpBlx, rTgt);
92 oatFreeTemp(cUnit, rTgt);
93#else
94 opThreadMem(cUnit, kOpBlx, helperOffset);
95#endif
96}
97
98void callRuntimeHelperRegLocationImm(CompilationUnit* cUnit, int helperOffset,
99 RegLocation arg0, int arg1) {
100#if !defined(TARGET_X86)
101 int rTgt = loadHelper(cUnit, helperOffset);
102#endif
103 loadValueDirectFixed(cUnit, arg0, rARG0);
104 loadConstant(cUnit, rARG1, arg1);
105 oatClobberCalleeSave(cUnit);
106#if !defined(TARGET_X86)
107 opReg(cUnit, kOpBlx, rTgt);
108 oatFreeTemp(cUnit, rTgt);
109#else
110 opThreadMem(cUnit, kOpBlx, helperOffset);
111#endif
112}
113
114void callRuntimeHelperImmReg(CompilationUnit* cUnit, int helperOffset,
115 int arg0, int arg1) {
116#if !defined(TARGET_X86)
117 int rTgt = loadHelper(cUnit, helperOffset);
118#endif
119 opRegCopy(cUnit, rARG1, arg1);
120 loadConstant(cUnit, rARG0, arg0);
121 oatClobberCalleeSave(cUnit);
122#if !defined(TARGET_X86)
123 opReg(cUnit, kOpBlx, rTgt);
124 oatFreeTemp(cUnit, rTgt);
125#else
126 opThreadMem(cUnit, kOpBlx, helperOffset);
127#endif
128}
129
130void callRuntimeHelperRegImm(CompilationUnit* cUnit, int helperOffset,
131 int arg0, int arg1) {
132#if !defined(TARGET_X86)
133 int rTgt = loadHelper(cUnit, helperOffset);
134#endif
135 opRegCopy(cUnit, rARG0, arg0);
136 loadConstant(cUnit, rARG1, arg1);
137 oatClobberCalleeSave(cUnit);
138#if !defined(TARGET_X86)
139 opReg(cUnit, kOpBlx, rTgt);
140 oatFreeTemp(cUnit, rTgt);
141#else
142 opThreadMem(cUnit, kOpBlx, helperOffset);
143#endif
144}
145
146void callRuntimeHelperImmMethod(CompilationUnit* cUnit, int helperOffset,
147 int arg0) {
148#if !defined(TARGET_X86)
149 int rTgt = loadHelper(cUnit, helperOffset);
150#endif
151 loadCurrMethodDirect(cUnit, rARG1);
152 loadConstant(cUnit, rARG0, arg0);
153 oatClobberCalleeSave(cUnit);
154#if !defined(TARGET_X86)
155 opReg(cUnit, kOpBlx, rTgt);
156 oatFreeTemp(cUnit, rTgt);
157#else
158 opThreadMem(cUnit, kOpBlx, helperOffset);
159#endif
160}
161
162void callRuntimeHelperRegLocationRegLocation(CompilationUnit* cUnit,
163 int helperOffset,
164 RegLocation arg0,
165 RegLocation arg1) {
166#if !defined(TARGET_X86)
167 int rTgt = loadHelper(cUnit, helperOffset);
168#endif
169 if (arg0.wide == 0) {
170 loadValueDirectFixed(cUnit, arg0, rARG0);
171 if (arg1.wide == 0) {
172 loadValueDirectFixed(cUnit, arg1, rARG1);
173 } else {
174 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
175 }
176 } else {
177 loadValueDirectWideFixed(cUnit, arg0, rARG0, rARG1);
178 if (arg1.wide == 0) {
179 loadValueDirectFixed(cUnit, arg1, rARG2);
180 } else {
181#if defined(TARGET_X86)
182 UNIMPLEMENTED(FATAL);
183#else
184 loadValueDirectWideFixed(cUnit, arg1, rARG2, rARG3);
185#endif
186 }
187 }
188 oatClobberCalleeSave(cUnit);
189#if !defined(TARGET_X86)
190 opReg(cUnit, kOpBlx, rTgt);
191 oatFreeTemp(cUnit, rTgt);
192#else
193 opThreadMem(cUnit, kOpBlx, helperOffset);
194#endif
195}
196
197void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset,
198 int arg0, int arg1) {
199#if !defined(TARGET_X86)
200 int rTgt = loadHelper(cUnit, helperOffset);
201#endif
202 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
203 opRegCopy(cUnit, rARG0, arg0);
204 opRegCopy(cUnit, rARG1, arg1);
205 oatClobberCalleeSave(cUnit);
206#if !defined(TARGET_X86)
207 opReg(cUnit, kOpBlx, rTgt);
208 oatFreeTemp(cUnit, rTgt);
209#else
210 opThreadMem(cUnit, kOpBlx, helperOffset);
211#endif
212}
213
214void callRuntimeHelperRegRegImm(CompilationUnit* cUnit, int helperOffset,
215 int arg0, int arg1, int arg2) {
216#if !defined(TARGET_X86)
217 int rTgt = loadHelper(cUnit, helperOffset);
218#endif
219 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
220 opRegCopy(cUnit, rARG0, arg0);
221 opRegCopy(cUnit, rARG1, arg1);
222 loadConstant(cUnit, rARG2, arg2);
223 oatClobberCalleeSave(cUnit);
224#if !defined(TARGET_X86)
225 opReg(cUnit, kOpBlx, rTgt);
226 oatFreeTemp(cUnit, rTgt);
227#else
228 opThreadMem(cUnit, kOpBlx, helperOffset);
229#endif
230}
231
232void callRuntimeHelperImmMethodRegLocation(CompilationUnit* cUnit, int helperOffset,
233 int arg0, RegLocation arg2) {
234#if !defined(TARGET_X86)
235 int rTgt = loadHelper(cUnit, helperOffset);
236#endif
237 loadValueDirectFixed(cUnit, arg2, rARG2);
238 loadCurrMethodDirect(cUnit, rARG1);
239 loadConstant(cUnit, rARG0, arg0);
240 oatClobberCalleeSave(cUnit);
241#if !defined(TARGET_X86)
242 opReg(cUnit, kOpBlx, rTgt);
243 oatFreeTemp(cUnit, rTgt);
244#else
245 opThreadMem(cUnit, kOpBlx, helperOffset);
246#endif
247}
248
249void callRuntimeHelperImmMethodImm(CompilationUnit* cUnit, int helperOffset,
250 int arg0, int arg2) {
251#if !defined(TARGET_X86)
252 int rTgt = loadHelper(cUnit, helperOffset);
253#endif
254 loadCurrMethodDirect(cUnit, rARG1);
255 loadConstant(cUnit, rARG2, arg2);
256 loadConstant(cUnit, rARG0, arg0);
257 oatClobberCalleeSave(cUnit);
258#if !defined(TARGET_X86)
259 opReg(cUnit, kOpBlx, rTgt);
260 oatFreeTemp(cUnit, rTgt);
261#else
262 opThreadMem(cUnit, kOpBlx, helperOffset);
263#endif
264}
265
266void callRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cUnit,
267 int helperOffset,
268 int arg0, RegLocation arg1,
269 RegLocation arg2) {
270#if !defined(TARGET_X86)
271 int rTgt = loadHelper(cUnit, helperOffset);
272#endif
273 loadValueDirectFixed(cUnit, arg1, rARG1);
274 if (arg2.wide == 0) {
275 loadValueDirectFixed(cUnit, arg2, rARG2);
276 } else {
277#if defined(TARGET_X86)
278 UNIMPLEMENTED(FATAL);
279#else
280 loadValueDirectWideFixed(cUnit, arg2, rARG2, rARG3);
281#endif
282 }
283 loadConstant(cUnit, rARG0, arg0);
284 oatClobberCalleeSave(cUnit);
285#if !defined(TARGET_X86)
286 opReg(cUnit, kOpBlx, rTgt);
287 oatFreeTemp(cUnit, rTgt);
288#else
289 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700290#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800291}
292
293/*
294 * Generate an kPseudoBarrier marker to indicate the boundary of special
295 * blocks.
296 */
297void genBarrier(CompilationUnit* cUnit)
298{
299 LIR* barrier = newLIR0(cUnit, kPseudoBarrier);
300 /* Mark all resources as being clobbered */
301 barrier->defMask = -1;
302}
303
buzbee31a4a6f2012-02-28 15:36:15 -0800304
305/* Generate unconditional branch instructions */
buzbee82488f52012-03-02 08:20:26 -0800306LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -0800307{
Ian Rogers680b1bd2012-03-07 20:18:49 -0800308 LIR* branch = opBranchUnconditional(cUnit, kOpUncondBr);
buzbee31a4a6f2012-02-28 15:36:15 -0800309 branch->target = (LIR*) target;
310 return branch;
311}
312
buzbee5de34942012-03-01 14:51:57 -0800313// FIXME: need to do some work to split out targets with
314// condition codes and those without
315#if defined(TARGET_ARM) || defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800316LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, MIR* mir,
317 ThrowKind kind)
318{
buzbeea2ebdd72012-03-04 14:57:06 -0800319 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
320 mir ? mir->offset : 0);
buzbee82488f52012-03-02 08:20:26 -0800321 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800322 // Remember branch target - will process later
323 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
324 return branch;
325}
buzbee5de34942012-03-01 14:51:57 -0800326#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800327
328LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
329 int reg, int immVal, MIR* mir, ThrowKind kind)
330{
buzbeea2ebdd72012-03-04 14:57:06 -0800331 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, mir->offset);
buzbee31a4a6f2012-02-28 15:36:15 -0800332 LIR* branch;
333 if (cCode == kCondAl) {
buzbee82488f52012-03-02 08:20:26 -0800334 branch = opUnconditionalBranch(cUnit, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800335 } else {
buzbee82488f52012-03-02 08:20:26 -0800336 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800337 }
338 // Remember branch target - will process later
339 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
340 return branch;
341}
342
343/* Perform null-check on a register. */
344LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir)
345{
346 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
347 mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
348 return NULL;
349 }
350 return genImmedCheck(cUnit, kCondEq, mReg, 0, mir, kThrowNullPointer);
351}
352
353/* Perform check on two registers */
354LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
Ian Rogersb5d09b22012-03-06 22:14:17 -0800355 int reg1, int reg2, MIR* mir, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800356{
buzbeea2ebdd72012-03-04 14:57:06 -0800357 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
358 mir ? mir->offset : 0, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800359#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800360 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800361#else
buzbee31a4a6f2012-02-28 15:36:15 -0800362 opRegReg(cUnit, kOpCmp, reg1, reg2);
buzbee82488f52012-03-02 08:20:26 -0800363 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800364#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800365 // Remember branch target - will process later
366 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
367 return branch;
368}
369
370void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
371 RegLocation rlSrc1, RegLocation rlSrc2, LIR* labelList)
372{
373 ConditionCode cond;
374 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
375 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800376 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -0800377 switch(opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800378 case Instruction::IF_EQ:
buzbee31a4a6f2012-02-28 15:36:15 -0800379 cond = kCondEq;
380 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800381 case Instruction::IF_NE:
buzbee31a4a6f2012-02-28 15:36:15 -0800382 cond = kCondNe;
383 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800384 case Instruction::IF_LT:
buzbee31a4a6f2012-02-28 15:36:15 -0800385 cond = kCondLt;
386 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800387 case Instruction::IF_GE:
buzbee31a4a6f2012-02-28 15:36:15 -0800388 cond = kCondGe;
389 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800390 case Instruction::IF_GT:
buzbee31a4a6f2012-02-28 15:36:15 -0800391 cond = kCondGt;
392 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800393 case Instruction::IF_LE:
buzbee31a4a6f2012-02-28 15:36:15 -0800394 cond = kCondLe;
395 break;
396 default:
397 cond = (ConditionCode)0;
398 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
399 }
buzbee5de34942012-03-01 14:51:57 -0800400#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800401 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg,
402 &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800403#else
404 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800405 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800406#endif
buzbee82488f52012-03-02 08:20:26 -0800407 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800408}
409
410void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
411 RegLocation rlSrc, LIR* labelList)
412{
413 ConditionCode cond;
414 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800415 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -0800416 switch(opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800417 case Instruction::IF_EQZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800418 cond = kCondEq;
419 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800420 case Instruction::IF_NEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800421 cond = kCondNe;
422 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800423 case Instruction::IF_LTZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800424 cond = kCondLt;
425 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800426 case Instruction::IF_GEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800427 cond = kCondGe;
428 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800429 case Instruction::IF_GTZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800430 cond = kCondGt;
431 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800432 case Instruction::IF_LEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800433 cond = kCondLe;
434 break;
435 default:
436 cond = (ConditionCode)0;
437 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
438 }
buzbee5de34942012-03-01 14:51:57 -0800439#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800440 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800441#else
442 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
buzbee82488f52012-03-02 08:20:26 -0800443 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800444#endif
buzbee82488f52012-03-02 08:20:26 -0800445 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800446}
447
448void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
449 RegLocation rlSrc)
450{
451 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
452 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -0800453 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800454 } else {
455 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
456 }
457 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
458 rlResult.lowReg, 31);
459 storeValueWide(cUnit, rlDest, rlResult);
460}
461
462void genIntNarrowing(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
463 RegLocation rlSrc)
464{
465 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
466 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
467 OpKind op = kOpInvalid;
468 switch(mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800469 case Instruction::INT_TO_BYTE:
buzbee31a4a6f2012-02-28 15:36:15 -0800470 op = kOp2Byte;
471 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800472 case Instruction::INT_TO_SHORT:
buzbee31a4a6f2012-02-28 15:36:15 -0800473 op = kOp2Short;
474 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800475 case Instruction::INT_TO_CHAR:
buzbee31a4a6f2012-02-28 15:36:15 -0800476 op = kOp2Char;
477 break;
478 default:
479 LOG(ERROR) << "Bad int conversion type";
480 }
481 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
482 storeValue(cUnit, rlDest, rlResult);
483}
484
485/*
486 * Let helper function take care of everything. Will call
487 * Array::AllocFromCode(type_idx, method, count);
488 * Note: AllocFromCode will handle checks for errNegativeArraySize.
489 */
490void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
491 RegLocation rlSrc)
492{
493 oatFlushAllRegs(cUnit); /* Everything to home location */
494 uint32_t type_idx = mir->dalvikInsn.vC;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700495 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -0800496 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
497 cUnit->dex_cache,
498 *cUnit->dex_file,
499 type_idx)) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700500 funcOffset = OFFSETOF_MEMBER(Thread, pAllocArrayFromCode);
buzbee31a4a6f2012-02-28 15:36:15 -0800501 } else {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700502 funcOffset= OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck);
buzbee31a4a6f2012-02-28 15:36:15 -0800503 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700504 callRuntimeHelperImmMethodRegLocation(cUnit, funcOffset, type_idx, rlSrc);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700505 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800506 storeValue(cUnit, rlDest, rlResult);
507}
508
509/*
510 * Similar to genNewArray, but with post-allocation initialization.
511 * Verifier guarantees we're dealing with an array class. Current
512 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
513 * Current code also throws internal unimp if not 'L', '[' or 'I'.
514 */
515void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
516{
517 DecodedInstruction* dInsn = &mir->dalvikInsn;
518 int elems = dInsn->vA;
Ian Rogersab2b55d2012-03-18 00:06:11 -0700519 int typeIdx = dInsn->vB;
buzbee31a4a6f2012-02-28 15:36:15 -0800520 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700521 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -0800522 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
523 cUnit->dex_cache,
524 *cUnit->dex_file,
Ian Rogersab2b55d2012-03-18 00:06:11 -0700525 typeIdx)) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700526 funcOffset = OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode);
buzbee31a4a6f2012-02-28 15:36:15 -0800527 } else {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700528 funcOffset = OFFSETOF_MEMBER(Thread,
529 pCheckAndAllocArrayFromCodeWithAccessCheck);
buzbee31a4a6f2012-02-28 15:36:15 -0800530 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700531 callRuntimeHelperImmMethodImm(cUnit, funcOffset, typeIdx, elems);
buzbeee1965672012-03-11 18:39:19 -0700532 oatFreeTemp(cUnit, rARG2);
533 oatFreeTemp(cUnit, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -0800534 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -0800535 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
buzbee31a4a6f2012-02-28 15:36:15 -0800536 * return region. Because AllocFromCode placed the new array
537 * in rRET0, we'll just lock it into place. When debugger support is
538 * added, it may be necessary to additionally copy all return
539 * values to a home location in thread-local storage
540 */
541 oatLockTemp(cUnit, rRET0);
542
543 // TODO: use the correct component size, currently all supported types
544 // share array alignment with ints (see comment at head of function)
545 size_t component_size = sizeof(int32_t);
546
547 // Having a range of 0 is legal
548 if (isRange && (dInsn->vA > 0)) {
549 /*
550 * Bit of ugliness here. We're going generate a mem copy loop
551 * on the register range, but it is possible that some regs
552 * in the range have been promoted. This is unlikely, but
553 * before generating the copy, we'll just force a flush
554 * of any regs in the source range that have been promoted to
555 * home location.
556 */
557 for (unsigned int i = 0; i < dInsn->vA; i++) {
558 RegLocation loc = oatUpdateLoc(cUnit,
559 oatGetSrc(cUnit, mir, i));
560 if (loc.location == kLocPhysReg) {
561 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
562 loc.lowReg, kWord);
563 }
564 }
565 /*
566 * TUNING note: generated code here could be much improved, but
567 * this is an uncommon operation and isn't especially performance
568 * critical.
569 */
570 int rSrc = oatAllocTemp(cUnit);
571 int rDst = oatAllocTemp(cUnit);
572 int rIdx = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800573#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800574 int rVal = rLR; // Using a lot of temps, rLR is known free here
buzbee5de34942012-03-01 14:51:57 -0800575#else
576 int rVal = oatAllocTemp(cUnit);
577#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800578 // Set up source pointer
579 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800580#if defined(TARGET_X86)
581 UNIMPLEMENTED(FATAL);
582#else
buzbee31a4a6f2012-02-28 15:36:15 -0800583 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
584 oatSRegOffset(cUnit, rlFirst.sRegLow));
585 // Set up the target pointer
586 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
587 Array::DataOffset(component_size).Int32Value());
Ian Rogersb5d09b22012-03-06 22:14:17 -0800588#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800589 // Set up the loop counter (known to be > 0)
590 loadConstant(cUnit, rIdx, dInsn->vA - 1);
591 // Generate the copy loop. Going backwards for convenience
592 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800593 // Copy next element
594 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
595 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
596#if defined(TARGET_ARM)
597 // Combine sub & test using sub setflags encoding here
598 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800599 opCondBranch(cUnit, kCondGe, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800600#else
buzbee5de34942012-03-01 14:51:57 -0800601 oatFreeTemp(cUnit, rVal);
buzbee31a4a6f2012-02-28 15:36:15 -0800602 opRegImm(cUnit, kOpSub, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800603 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800604#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800605 } else if (!isRange) {
606 // TUNING: interleave
607 for (unsigned int i = 0; i < dInsn->vA; i++) {
608 RegLocation rlArg = loadValue(cUnit,
609 oatGetSrc(cUnit, mir, i), kCoreReg);
610 storeBaseDisp(cUnit, rRET0,
611 Array::DataOffset(component_size).Int32Value() +
612 i * 4, rlArg.lowReg, kWord);
613 // If the loadValue caused a temp to be allocated, free it
614 if (oatIsTemp(cUnit, rlArg.lowReg)) {
615 oatFreeTemp(cUnit, rlArg.lowReg);
616 }
617 }
618 }
619}
620
621void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
622 bool isLongOrDouble, bool isObject)
623{
624 int fieldOffset;
625 int ssbIndex;
626 bool isVolatile;
627 bool isReferrersClass;
628 uint32_t fieldIdx = mir->dalvikInsn.vB;
629
630 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
631 *cUnit->dex_file, *cUnit->dex_cache,
632 cUnit->code_item, cUnit->method_idx,
633 cUnit->access_flags);
634
635 bool fastPath =
636 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
637 fieldOffset, ssbIndex,
638 isReferrersClass, isVolatile, true);
639 if (fastPath && !SLOW_FIELD_PATH) {
640 DCHECK_GE(fieldOffset, 0);
641 int rBase;
buzbee31a4a6f2012-02-28 15:36:15 -0800642 if (isReferrersClass) {
643 // Fast path, static storage base is this method's class
buzbeee1965672012-03-11 18:39:19 -0700644 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800645 rBase = oatAllocTemp(cUnit);
buzbeee1965672012-03-11 18:39:19 -0700646 loadWordDisp(cUnit, rlMethod.lowReg,
buzbee31a4a6f2012-02-28 15:36:15 -0800647 Method::DeclaringClassOffset().Int32Value(), rBase);
648 } else {
649 // Medium path, static storage base in a different class which
650 // requires checks that the other class is initialized.
651 DCHECK_GE(ssbIndex, 0);
652 // May do runtime call so everything to home locations.
653 oatFlushAllRegs(cUnit);
654 // Using fixed register to sync with possible call to runtime
655 // support.
buzbeee1965672012-03-11 18:39:19 -0700656 int rMethod = rARG1;
buzbee31a4a6f2012-02-28 15:36:15 -0800657 oatLockTemp(cUnit, rMethod);
658 loadCurrMethodDirect(cUnit, rMethod);
659 rBase = rARG0;
660 oatLockTemp(cUnit, rBase);
661 loadWordDisp(cUnit, rMethod,
662 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
663 rBase);
664 loadWordDisp(cUnit, rBase,
665 Array::DataOffset(sizeof(Object*)).Int32Value() + sizeof(int32_t*) *
666 ssbIndex, rBase);
667 // rBase now points at appropriate static storage base (Class*)
668 // or NULL if not initialized. Check for NULL and call helper if NULL.
669 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800670 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800671 loadConstant(cUnit, rARG0, ssbIndex);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700672 callRuntimeHelperImm(cUnit,
673 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage),
674 ssbIndex);
buzbee31a4a6f2012-02-28 15:36:15 -0800675#if defined(TARGET_MIPS)
676 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800677 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800678#endif
679 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800680 branchOver->target = (LIR*)skipTarget;
buzbeee1965672012-03-11 18:39:19 -0700681 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800682 }
683 // rBase now holds static storage base
buzbee31a4a6f2012-02-28 15:36:15 -0800684 if (isLongOrDouble) {
685 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
686 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
687 } else {
688 rlSrc = oatGetSrc(cUnit, mir, 0);
689 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
690 }
691//FIXME: need to generalize the barrier call
692 if (isVolatile) {
693 oatGenMemBarrier(cUnit, kST);
694 }
695 if (isLongOrDouble) {
696 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
697 rlSrc.highReg);
698 } else {
699 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
700 }
701 if (isVolatile) {
702 oatGenMemBarrier(cUnit, kSY);
703 }
704 if (isObject) {
705 markGCCard(cUnit, rlSrc.lowReg, rBase);
706 }
707 oatFreeTemp(cUnit, rBase);
708 } else {
709 oatFlushAllRegs(cUnit); // Everything to home locations
710 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
711 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
712 : OFFSETOF_MEMBER(Thread, pSet32Static));
Ian Rogersab2b55d2012-03-18 00:06:11 -0700713 callRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc);
buzbee31a4a6f2012-02-28 15:36:15 -0800714 }
715}
716
717void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
718 bool isLongOrDouble, bool isObject)
719{
720 int fieldOffset;
721 int ssbIndex;
722 bool isVolatile;
723 bool isReferrersClass;
724 uint32_t fieldIdx = mir->dalvikInsn.vB;
725
726 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
727 *cUnit->dex_file, *cUnit->dex_cache,
728 cUnit->code_item, cUnit->method_idx,
729 cUnit->access_flags);
730
731 bool fastPath =
732 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
733 fieldOffset, ssbIndex,
734 isReferrersClass, isVolatile,
735 false);
736 if (fastPath && !SLOW_FIELD_PATH) {
737 DCHECK_GE(fieldOffset, 0);
738 int rBase;
buzbee31a4a6f2012-02-28 15:36:15 -0800739 if (isReferrersClass) {
740 // Fast path, static storage base is this method's class
buzbeee1965672012-03-11 18:39:19 -0700741 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800742 rBase = oatAllocTemp(cUnit);
buzbeee1965672012-03-11 18:39:19 -0700743 loadWordDisp(cUnit, rlMethod.lowReg,
buzbee31a4a6f2012-02-28 15:36:15 -0800744 Method::DeclaringClassOffset().Int32Value(), rBase);
745 } else {
746 // Medium path, static storage base in a different class which
747 // requires checks that the other class is initialized
748 DCHECK_GE(ssbIndex, 0);
749 // May do runtime call so everything to home locations.
750 oatFlushAllRegs(cUnit);
751 // Using fixed register to sync with possible call to runtime
752 // support
buzbeee1965672012-03-11 18:39:19 -0700753 int rMethod = rARG1;
buzbee31a4a6f2012-02-28 15:36:15 -0800754 oatLockTemp(cUnit, rMethod);
755 loadCurrMethodDirect(cUnit, rMethod);
756 rBase = rARG0;
757 oatLockTemp(cUnit, rBase);
758 loadWordDisp(cUnit, rMethod,
759 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
760 rBase);
761 loadWordDisp(cUnit, rBase,
762 Array::DataOffset(sizeof(Object*)).Int32Value() +
763 sizeof(int32_t*) * ssbIndex,
764 rBase);
765 // rBase now points at appropriate static storage base (Class*)
766 // or NULL if not initialized. Check for NULL and call helper if NULL.
767 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800768 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700769 callRuntimeHelperImm(cUnit,
770 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage),
771 ssbIndex);
buzbee31a4a6f2012-02-28 15:36:15 -0800772#if defined(TARGET_MIPS)
773 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800774 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800775#endif
776 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800777 branchOver->target = (LIR*)skipTarget;
buzbeee1965672012-03-11 18:39:19 -0700778 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800779 }
780 // rBase now holds static storage base
buzbee31a4a6f2012-02-28 15:36:15 -0800781 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
782 : oatGetDest(cUnit, mir, 0);
783 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
784 if (isVolatile) {
785 oatGenMemBarrier(cUnit, kSY);
786 }
787 if (isLongOrDouble) {
788 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
789 rlResult.highReg, INVALID_SREG);
790 } else {
791 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
792 }
793 oatFreeTemp(cUnit, rBase);
794 if (isLongOrDouble) {
795 storeValueWide(cUnit, rlDest, rlResult);
796 } else {
797 storeValue(cUnit, rlDest, rlResult);
798 }
799 } else {
800 oatFlushAllRegs(cUnit); // Everything to home locations
801 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
802 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
803 : OFFSETOF_MEMBER(Thread, pGet32Static));
Ian Rogersab2b55d2012-03-18 00:06:11 -0700804 callRuntimeHelperImm(cUnit, getterOffset, fieldIdx);
buzbee31a4a6f2012-02-28 15:36:15 -0800805 if (isLongOrDouble) {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700806 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -0800807 storeValueWide(cUnit, rlDest, rlResult);
808 } else {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700809 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -0800810 storeValue(cUnit, rlDest, rlResult);
811 }
812 }
813}
814
815
816// Debugging routine - if null target, branch to DebugMe
817void genShowTarget(CompilationUnit* cUnit)
818{
buzbeea7678db2012-03-05 15:35:46 -0800819#if defined(TARGET_X86)
820 UNIMPLEMENTED(WARNING) << "genShowTarget";
821#else
buzbee0398c422012-03-02 15:22:47 -0800822 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800823 loadWordDisp(cUnit, rSELF,
buzbee0398c422012-03-02 15:22:47 -0800824 OFFSETOF_MEMBER(Thread, pDebugMe), rINVOKE_TGT);
buzbee31a4a6f2012-02-28 15:36:15 -0800825 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800826 branchOver->target = (LIR*)target;
buzbeea7678db2012-03-05 15:35:46 -0800827#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800828}
829
830void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
831{
Ian Rogersab2b55d2012-03-18 00:06:11 -0700832 callRuntimeHelperImmImm(cUnit, OFFSETOF_MEMBER(Thread,
833 pThrowVerificationErrorFromCode),
834 mir->dalvikInsn.vA, mir->dalvikInsn.vB);
buzbee31a4a6f2012-02-28 15:36:15 -0800835}
836
837void handleSuspendLaunchpads(CompilationUnit *cUnit)
838{
Ian Rogersab2b55d2012-03-18 00:06:11 -0700839 LIR** suspendLabel = (LIR **)cUnit->suspendLaunchpads.elemList;
buzbee31a4a6f2012-02-28 15:36:15 -0800840 int numElems = cUnit->suspendLaunchpads.numUsed;
buzbee31a4a6f2012-02-28 15:36:15 -0800841 for (int i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800842 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800843 LIR* lab = suspendLabel[i];
844 LIR* resumeLab = (LIR*)lab->operands[0];
845 cUnit->currentDalvikOffset = lab->operands[1];
Ian Rogersab2b55d2012-03-18 00:06:11 -0700846 oatAppendLIR(cUnit, lab);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700847#if defined(TARGET_X86)
848 opThreadMem(cUnit, kOpBlx,
849 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode));
850#else
buzbee31a4a6f2012-02-28 15:36:15 -0800851 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
852 pTestSuspendFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -0800853 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700854#endif
buzbee82488f52012-03-02 08:20:26 -0800855 opUnconditionalBranch(cUnit, resumeLab);
buzbee31a4a6f2012-02-28 15:36:15 -0800856 }
857}
858
859void handleThrowLaunchpads(CompilationUnit *cUnit)
860{
Ian Rogersab2b55d2012-03-18 00:06:11 -0700861 LIR** throwLabel = (LIR **)cUnit->throwLaunchpads.elemList;
buzbee31a4a6f2012-02-28 15:36:15 -0800862 int numElems = cUnit->throwLaunchpads.numUsed;
Ian Rogersab2b55d2012-03-18 00:06:11 -0700863 for (int i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800864 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800865 LIR* lab = throwLabel[i];
866 cUnit->currentDalvikOffset = lab->operands[1];
Ian Rogersab2b55d2012-03-18 00:06:11 -0700867 oatAppendLIR(cUnit, lab);
buzbee31a4a6f2012-02-28 15:36:15 -0800868 int funcOffset = 0;
869 int v1 = lab->operands[2];
870 int v2 = lab->operands[3];
871 switch(lab->operands[0]) {
872 case kThrowNullPointer:
873 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
874 break;
875 case kThrowArrayBounds:
buzbee5de34942012-03-01 14:51:57 -0800876 if (v2 != rARG0) {
buzbee82488f52012-03-02 08:20:26 -0800877 opRegCopy(cUnit, rARG0, v1);
878 opRegCopy(cUnit, rARG1, v2);
buzbee31a4a6f2012-02-28 15:36:15 -0800879 } else {
buzbee5de34942012-03-01 14:51:57 -0800880 if (v1 == rARG1) {
buzbee31a4a6f2012-02-28 15:36:15 -0800881#if defined(TARGET_ARM)
882 int rTmp = r12;
883#else
884 int rTmp = oatAllocTemp(cUnit);
885#endif
buzbee82488f52012-03-02 08:20:26 -0800886 opRegCopy(cUnit, rTmp, v1);
887 opRegCopy(cUnit, rARG1, v2);
888 opRegCopy(cUnit, rARG0, rTmp);
buzbee31a4a6f2012-02-28 15:36:15 -0800889 } else {
buzbee82488f52012-03-02 08:20:26 -0800890 opRegCopy(cUnit, rARG1, v2);
891 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800892 }
893 }
894 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
895 break;
896 case kThrowDivZero:
897 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
898 break;
899 case kThrowVerificationError:
900 loadConstant(cUnit, rARG0, v1);
901 loadConstant(cUnit, rARG1, v2);
902 funcOffset =
903 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
904 break;
905 case kThrowNegArraySize:
buzbee82488f52012-03-02 08:20:26 -0800906 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800907 funcOffset =
908 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
909 break;
910 case kThrowNoSuchMethod:
buzbee82488f52012-03-02 08:20:26 -0800911 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800912 funcOffset =
913 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
914 break;
915 case kThrowStackOverflow:
916 funcOffset =
917 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
918 // Restore stack alignment
919 opRegImm(cUnit, kOpAdd, rSP,
920 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
921 break;
922 default:
923 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
924 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700925 oatClobberCalleeSave(cUnit);
926#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800927 int rTgt = loadHelper(cUnit, funcOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700928 opReg(cUnit, kOpBlx, rTgt);
buzbee0398c422012-03-02 15:22:47 -0800929 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700930#else
931 opThreadMem(cUnit, kOpBlx, funcOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700932#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800933 }
934}
935
936/* Needed by the Assembler */
937void oatSetupResourceMasks(LIR* lir)
938{
939 setupResourceMasks(lir);
940}
941
942void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
943 RegLocation rlDest, RegLocation rlObj,
944 bool isLongOrDouble, bool isObject)
945{
946 int fieldOffset;
947 bool isVolatile;
948 uint32_t fieldIdx = mir->dalvikInsn.vC;
949
950 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
951 *cUnit->dex_file, *cUnit->dex_cache,
952 cUnit->code_item, cUnit->method_idx,
953 cUnit->access_flags);
954
955 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
956 fieldOffset, isVolatile, false);
957
958 if (fastPath && !SLOW_FIELD_PATH) {
959 RegLocation rlResult;
960 RegisterClass regClass = oatRegClassBySize(size);
961 DCHECK_GE(fieldOffset, 0);
962 rlObj = loadValue(cUnit, rlObj, kCoreReg);
963 if (isLongOrDouble) {
964 DCHECK(rlDest.wide);
965 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800966#if defined(TARGET_X86)
967 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
968 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
969 loadBaseDispWide(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
970 rlResult.highReg, rlObj.sRegLow);
971 if (isVolatile) {
972 oatGenMemBarrier(cUnit, kSY);
973 }
974#else
buzbee31a4a6f2012-02-28 15:36:15 -0800975 int regPtr = oatAllocTemp(cUnit);
976 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
977 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
978 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
979 if (isVolatile) {
980 oatGenMemBarrier(cUnit, kSY);
981 }
982 oatFreeTemp(cUnit, regPtr);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800983#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800984 storeValueWide(cUnit, rlDest, rlResult);
985 } else {
986 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
987 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
988 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
989 kWord, rlObj.sRegLow);
990 if (isVolatile) {
991 oatGenMemBarrier(cUnit, kSY);
992 }
993 storeValue(cUnit, rlDest, rlResult);
994 }
995 } else {
996 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
997 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
998 : OFFSETOF_MEMBER(Thread, pGet32Instance));
Ian Rogersab2b55d2012-03-18 00:06:11 -0700999 callRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj);
buzbee31a4a6f2012-02-28 15:36:15 -08001000 if (isLongOrDouble) {
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001001 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08001002 storeValueWide(cUnit, rlDest, rlResult);
1003 } else {
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001004 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08001005 storeValue(cUnit, rlDest, rlResult);
1006 }
1007 }
1008}
1009
1010void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, RegLocation rlSrc,
1011 RegLocation rlObj, bool isLongOrDouble, bool isObject)
1012{
1013 int fieldOffset;
1014 bool isVolatile;
1015 uint32_t fieldIdx = mir->dalvikInsn.vC;
1016
1017 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
1018 *cUnit->dex_file, *cUnit->dex_cache,
1019 cUnit->code_item, cUnit->method_idx,
1020 cUnit->access_flags);
1021
1022 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
1023 fieldOffset, isVolatile, true);
1024 if (fastPath && !SLOW_FIELD_PATH) {
1025 RegisterClass regClass = oatRegClassBySize(size);
1026 DCHECK_GE(fieldOffset, 0);
1027 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1028 if (isLongOrDouble) {
1029 int regPtr;
1030 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1031 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
1032 regPtr = oatAllocTemp(cUnit);
1033 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1034 if (isVolatile) {
1035 oatGenMemBarrier(cUnit, kST);
1036 }
1037 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1038 if (isVolatile) {
1039 oatGenMemBarrier(cUnit, kSY);
1040 }
1041 oatFreeTemp(cUnit, regPtr);
1042 } else {
1043 rlSrc = loadValue(cUnit, rlSrc, regClass);
1044 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
1045 if (isVolatile) {
1046 oatGenMemBarrier(cUnit, kST);
1047 }
1048 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
1049 if (isVolatile) {
1050 oatGenMemBarrier(cUnit, kSY);
1051 }
buzbeea7c12682012-03-19 13:13:53 -07001052 if (isObject) {
1053 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
1054 }
buzbee31a4a6f2012-02-28 15:36:15 -08001055 }
1056 } else {
1057 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
1058 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
1059 : OFFSETOF_MEMBER(Thread, pSet32Instance));
Ian Rogersab2b55d2012-03-18 00:06:11 -07001060 callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset,
1061 fieldIdx, rlObj, rlSrc);
buzbee31a4a6f2012-02-28 15:36:15 -08001062 }
1063}
1064
1065void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1066 RegLocation rlSrc)
1067{
1068 uint32_t type_idx = mir->dalvikInsn.vB;
buzbeee1965672012-03-11 18:39:19 -07001069 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001070 int resReg = oatAllocTemp(cUnit);
1071 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1072 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1073 cUnit->dex_cache,
1074 *cUnit->dex_file,
1075 type_idx)) {
1076 // Call out to helper which resolves type and verifies access.
1077 // Resolved type returned in rRET0.
Ian Rogersab2b55d2012-03-18 00:06:11 -07001078 callRuntimeHelperImmReg(cUnit,
1079 OFFSETOF_MEMBER(Thread,
1080 pInitializeTypeAndVerifyAccessFromCode),
1081 type_idx, rlMethod.lowReg);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001082 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001083 storeValue(cUnit, rlDest, rlResult);
1084 } else {
1085 // We're don't need access checks, load type from dex cache
1086 int32_t dex_cache_offset =
1087 Method::DexCacheResolvedTypesOffset().Int32Value();
buzbeee1965672012-03-11 18:39:19 -07001088 loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001089 int32_t offset_of_type =
1090 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1091 * type_idx);
1092 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
1093 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
1094 type_idx) || SLOW_TYPE_PATH) {
1095 // Slow path, at runtime test if type is null and if so initialize
1096 oatFlushAllRegs(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001097 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0,
1098 NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001099 // Resolved, store and hop over following code
1100 storeValue(cUnit, rlDest, rlResult);
buzbee3d661942012-03-14 17:37:27 -07001101 /*
1102 * Because we have stores of the target value on two paths,
1103 * clobber temp tracking for the destination using the ssa name
1104 */
1105 oatClobberSReg(cUnit, rlDest.sRegLow);
buzbee82488f52012-03-02 08:20:26 -08001106 LIR* branch2 = opUnconditionalBranch(cUnit,0);
buzbee31a4a6f2012-02-28 15:36:15 -08001107 // TUNING: move slow path to end & remove unconditional branch
1108 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -08001109 // Call out to helper, which will return resolved type in rARG0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001110 callRuntimeHelperImmReg(cUnit, OFFSETOF_MEMBER(Thread,
1111 pInitializeTypeFromCode),
1112 type_idx, rlMethod.lowReg);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001113 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001114 storeValue(cUnit, rlDest, rlResult);
buzbee3d661942012-03-14 17:37:27 -07001115 /*
1116 * Because we have stores of the target value on two paths,
1117 * clobber temp tracking for the destination using the ssa name
1118 */
1119 oatClobberSReg(cUnit, rlDest.sRegLow);
buzbee31a4a6f2012-02-28 15:36:15 -08001120 // Rejoin code paths
1121 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001122 branch1->target = (LIR*)target1;
1123 branch2->target = (LIR*)target2;
1124 } else {
1125 // Fast path, we're done - just store result
1126 storeValue(cUnit, rlDest, rlResult);
1127 }
1128 }
1129}
Ian Rogersab2b55d2012-03-18 00:06:11 -07001130
buzbee31a4a6f2012-02-28 15:36:15 -08001131void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1132 RegLocation rlSrc)
1133{
1134 /* NOTE: Most strings should be available at compile time */
1135 uint32_t string_idx = mir->dalvikInsn.vB;
1136 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1137 (sizeof(String*) * string_idx);
1138 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
1139 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
1140 // slow path, resolve string if not in dex cache
1141 oatFlushAllRegs(cUnit);
1142 oatLockCallTemps(cUnit); // Using explicit registers
1143 loadCurrMethodDirect(cUnit, rARG2);
1144 loadWordDisp(cUnit, rARG2,
1145 Method::DexCacheStringsOffset().Int32Value(), rARG0);
1146 // Might call out to helper, which will return resolved string in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001147#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001148 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1149 pResolveStringFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001150#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001151 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
1152 loadConstant(cUnit, rARG1, string_idx);
1153#if defined(TARGET_ARM)
1154 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
1155 genBarrier(cUnit);
1156 // For testing, always force through helper
1157 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee82488f52012-03-02 08:20:26 -08001158 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08001159 }
buzbee82488f52012-03-02 08:20:26 -08001160 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -08001161 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001162 oatFreeTemp(cUnit, rTgt);
1163#elif defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -08001164 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
1165 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -08001166 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001167 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001168 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001169 branch->target = target;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001170#else
Ian Rogersab2b55d2012-03-18 00:06:11 -07001171 callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
1172 pResolveStringFromCode),
1173 rARG2, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -08001174#endif
1175 genBarrier(cUnit);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001176 storeValue(cUnit, rlDest, oatGetReturn(cUnit, false));
buzbee31a4a6f2012-02-28 15:36:15 -08001177 } else {
buzbeee1965672012-03-11 18:39:19 -07001178 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001179 int resReg = oatAllocTemp(cUnit);
1180 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeee1965672012-03-11 18:39:19 -07001181 loadWordDisp(cUnit, rlMethod.lowReg,
buzbee31a4a6f2012-02-28 15:36:15 -08001182 Method::DexCacheStringsOffset().Int32Value(), resReg);
1183 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1184 storeValue(cUnit, rlDest, rlResult);
1185 }
1186}
1187
1188/*
1189 * Let helper function take care of everything. Will
1190 * call Class::NewInstanceFromCode(type_idx, method);
1191 */
1192void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
1193{
1194 oatFlushAllRegs(cUnit); /* Everything to home location */
1195 uint32_t type_idx = mir->dalvikInsn.vB;
1196 // alloc will always check for resolution, do we also need to verify
1197 // access because the verifier was unable to?
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001198 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001199 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
1200 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001201 funcOffset = OFFSETOF_MEMBER(Thread, pAllocObjectFromCode);
buzbee31a4a6f2012-02-28 15:36:15 -08001202 } else {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001203 funcOffset =
1204 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck);
buzbee31a4a6f2012-02-28 15:36:15 -08001205 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07001206 callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001207 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001208 storeValue(cUnit, rlDest, rlResult);
1209}
1210
Ian Rogersab2b55d2012-03-18 00:06:11 -07001211void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1212{
1213 oatFlushAllRegs(cUnit);
1214 callRuntimeHelperRegLocation(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException), rlSrc);
1215}
1216
buzbee31a4a6f2012-02-28 15:36:15 -08001217void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1218 RegLocation rlSrc)
1219{
1220 oatFlushAllRegs(cUnit);
1221 // May generate a call - use explicit registers
1222 oatLockCallTemps(cUnit);
1223 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee5de34942012-03-01 14:51:57 -08001224 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
buzbee31a4a6f2012-02-28 15:36:15 -08001225 int classReg = rARG2; // rARG2 will hold the Class*
1226 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1227 cUnit->dex_cache,
1228 *cUnit->dex_file,
1229 type_idx)) {
1230 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbee5de34942012-03-01 14:51:57 -08001231 // returns Class* in rARG0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001232 callRuntimeHelperImm(cUnit,
1233 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
1234 type_idx);
buzbee82488f52012-03-02 08:20:26 -08001235 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee5de34942012-03-01 14:51:57 -08001236 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
buzbee31a4a6f2012-02-28 15:36:15 -08001237 } else {
buzbee5de34942012-03-01 14:51:57 -08001238 // Load dex cache entry into classReg (rARG2)
buzbee31a4a6f2012-02-28 15:36:15 -08001239 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1240 loadWordDisp(cUnit, rARG1,
1241 Method::DexCacheResolvedTypesOffset().Int32Value(),
1242 classReg);
1243 int32_t offset_of_type =
1244 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1245 * type_idx);
1246 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1247 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1248 cUnit->dex_cache, type_idx)) {
1249 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001250 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001251 // Not resolved
1252 // Call out to helper, which will return resolved type in rRET0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001253 callRuntimeHelperImm(cUnit, OFFSETOF_MEMBER(Thread,
1254 pInitializeTypeFromCode),
1255 type_idx);
buzbee82488f52012-03-02 08:20:26 -08001256 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001257 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1258 // Rejoin code paths
1259 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001260 hopBranch->target = (LIR*)hopTarget;
1261 }
1262 }
1263 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
buzbee82488f52012-03-02 08:20:26 -08001264 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001265 /* load object->clazz */
1266 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1267 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1268 /* rARG0 is ref, rARG1 is ref->clazz, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001269#if defined(TARGET_ARM)
1270 /* Uses conditional nullification */
buzbee31a4a6f2012-02-28 15:36:15 -08001271 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1272 pInstanceofNonTrivialFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001273 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
buzbee82488f52012-03-02 08:20:26 -08001274 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
buzbee31a4a6f2012-02-28 15:36:15 -08001275 loadConstant(cUnit, rARG0, 1); // .eq case - load true
buzbee82488f52012-03-02 08:20:26 -08001276 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee31a4a6f2012-02-28 15:36:15 -08001277 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001278 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001279#else
buzbee0398c422012-03-02 15:22:47 -08001280 /* Uses branchovers */
1281 loadConstant(cUnit, rARG0, 1); // assume true
1282 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001283#if !defined(TARGET_X86)
buzbee0398c422012-03-02 15:22:47 -08001284 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1285 pInstanceofNonTrivialFromCode));
1286 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1287 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001288 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001289#else
1290 opRegCopy(cUnit, rARG0, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001291 opThreadMem(cUnit, kOpBlx,
1292 OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001293#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001294#endif
buzbee0398c422012-03-02 15:22:47 -08001295 oatClobberCalleeSave(cUnit);
1296 /* branch targets here */
buzbee31a4a6f2012-02-28 15:36:15 -08001297 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001298 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001299 storeValue(cUnit, rlDest, rlResult);
buzbee0398c422012-03-02 15:22:47 -08001300 branch1->target = target;
1301#if !defined(TARGET_ARM)
1302 branchover->target = target;
1303#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001304}
1305
1306void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1307{
1308 oatFlushAllRegs(cUnit);
1309 // May generate a call - use explicit registers
1310 oatLockCallTemps(cUnit);
1311 uint32_t type_idx = mir->dalvikInsn.vB;
1312 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1313 int classReg = rARG2; // rARG2 will hold the Class*
1314 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1315 cUnit->dex_cache,
1316 *cUnit->dex_file,
1317 type_idx)) {
1318 // Check we have access to type_idx and if not throw IllegalAccessError,
1319 // returns Class* in rRET0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001320 // InitializeTypeAndVerifyAccess(idx, method)
1321 callRuntimeHelperImmReg(cUnit,
1322 OFFSETOF_MEMBER(Thread,
1323 pInitializeTypeAndVerifyAccessFromCode),
1324 type_idx, rARG1);
buzbee82488f52012-03-02 08:20:26 -08001325 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001326 } else {
1327 // Load dex cache entry into classReg (rARG2)
1328 loadWordDisp(cUnit, rARG1,
1329 Method::DexCacheResolvedTypesOffset().Int32Value(),
1330 classReg);
1331 int32_t offset_of_type =
1332 Array::DataOffset(sizeof(Class*)).Int32Value() +
1333 (sizeof(Class*) * type_idx);
1334 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1335 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1336 cUnit->dex_cache, type_idx)) {
1337 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001338 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001339 // Not resolved
buzbee5de34942012-03-01 14:51:57 -08001340 // Call out to helper, which will return resolved type in rARG0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001341 // InitializeTypeFromCode(idx, method)
1342 callRuntimeHelperImmReg(cUnit,
1343 OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode),
1344 type_idx, rARG1);
buzbee82488f52012-03-02 08:20:26 -08001345 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001346 // Rejoin code paths
1347 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001348 hopBranch->target = (LIR*)hopTarget;
1349 }
1350 }
buzbee5de34942012-03-01 14:51:57 -08001351 // At this point, classReg (rARG2) has class
buzbee31a4a6f2012-02-28 15:36:15 -08001352 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1353 /* Null is OK - continue */
buzbee82488f52012-03-02 08:20:26 -08001354 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001355 /* load object->clazz */
1356 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1357 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1358 /* rARG1 now contains object->clazz */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001359#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee82488f52012-03-02 08:20:26 -08001360 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001361 callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
1362 pCheckCastFromCode),
1363 rARG1, rARG2);
1364#else // defined(TARGET_ARM)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001365 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1366 pCheckCastFromCode));
1367 opRegReg(cUnit, kOpCmp, rARG1, classReg);
1368 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1369 opRegCopy(cUnit, rARG0, rARG1);
1370 opRegCopy(cUnit, rARG1, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001371 oatClobberCalleeSave(cUnit);
1372 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001373 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001374#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001375 /* branch target here */
1376 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001377 branch1->target = (LIR*)target;
1378 branch2->target = (LIR*)target;
1379}
1380
buzbee31a4a6f2012-02-28 15:36:15 -08001381/*
1382 * Generate array store
1383 *
1384 */
1385void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
1386 RegLocation rlIndex, RegLocation rlSrc, int scale)
1387{
1388 RegisterClass regClass = oatRegClassBySize(kWord);
1389 int lenOffset = Array::LengthOffset().Int32Value();
1390 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
1391
1392 oatFlushAllRegs(cUnit);
1393 /* Make sure it's a legal object Put. Use direct regs at first */
1394 loadValueDirectFixed(cUnit, rlArray, rARG1);
1395 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1396
1397 /* null array object? */
1398 genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
buzbee31a4a6f2012-02-28 15:36:15 -08001399 /* Get the array's clazz */
1400 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001401 callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
1402 pCanPutArrayElementFromCode),
1403 rARG0, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -08001404 oatFreeTemp(cUnit, rARG0);
1405 oatFreeTemp(cUnit, rARG1);
1406
1407 // Now, redo loadValues in case they didn't survive the call
1408
1409 int regPtr;
1410 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1411 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1412
1413 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1414 oatClobber(cUnit, rlArray.lowReg);
1415 regPtr = rlArray.lowReg;
1416 } else {
1417 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001418 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001419 }
1420
buzbee239c4e72012-03-16 08:42:29 -07001421 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1422 int regLen = INVALID_REG;
1423 if (needsRangeCheck) {
1424 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001425 //NOTE: max live temps(4) here.
1426 /* Get len */
1427 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee239c4e72012-03-16 08:42:29 -07001428 }
1429 /* regPtr -> array data */
1430 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1431 /* at this point, regPtr points to array, 2 live temps */
1432 rlSrc = loadValue(cUnit, rlSrc, regClass);
1433 if (needsRangeCheck) {
buzbee31a4a6f2012-02-28 15:36:15 -08001434 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1435 kThrowArrayBounds);
1436 oatFreeTemp(cUnit, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001437 }
buzbee31a4a6f2012-02-28 15:36:15 -08001438 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1439 scale, kWord);
buzbeea7c12682012-03-19 13:13:53 -07001440 markGCCard(cUnit, rlSrc.lowReg, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001441}
1442
1443/*
1444 * Generate array load
1445 */
1446void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1447 RegLocation rlArray, RegLocation rlIndex,
1448 RegLocation rlDest, int scale)
1449{
1450 RegisterClass regClass = oatRegClassBySize(size);
1451 int lenOffset = Array::LengthOffset().Int32Value();
1452 int dataOffset;
1453 RegLocation rlResult;
1454 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1455 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001456
1457 if (size == kLong || size == kDouble) {
1458 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1459 } else {
1460 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1461 }
1462
1463 /* null object? */
1464 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1465
Ian Rogersb5d09b22012-03-06 22:14:17 -08001466#if defined(TARGET_X86)
1467 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1468 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1469 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
1470 lenOffset, mir, kThrowArrayBounds);
1471 }
1472 if ((size == kLong) || (size == kDouble)) {
1473 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1474 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1475 rlResult.lowReg, rlResult.highReg, size, INVALID_SREG);
buzbee31a4a6f2012-02-28 15:36:15 -08001476
Ian Rogersb5d09b22012-03-06 22:14:17 -08001477 storeValueWide(cUnit, rlDest, rlResult);
1478 } else {
1479 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1480
1481 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1482 rlResult.lowReg, INVALID_REG, size, INVALID_SREG);
1483
1484 storeValue(cUnit, rlDest, rlResult);
1485 }
1486#else
1487 int regPtr = oatAllocTemp(cUnit);
buzbee239c4e72012-03-16 08:42:29 -07001488 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1489 int regLen = INVALID_REG;
1490 if (needsRangeCheck) {
1491 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001492 /* Get len */
1493 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001494 }
buzbee239c4e72012-03-16 08:42:29 -07001495 /* regPtr -> array data */
1496 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -08001497 oatFreeTemp(cUnit, rlArray.lowReg);
1498 if ((size == kLong) || (size == kDouble)) {
1499 if (scale) {
1500 int rNewIndex = oatAllocTemp(cUnit);
1501 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1502 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1503 oatFreeTemp(cUnit, rNewIndex);
1504 } else {
1505 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1506 }
1507 oatFreeTemp(cUnit, rlIndex.lowReg);
1508 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1509
buzbee239c4e72012-03-16 08:42:29 -07001510 if (needsRangeCheck) {
1511 // TODO: change kCondCS to a more meaningful name, is the sense of
1512 // carry-set/clear flipped?
1513 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1514 kThrowArrayBounds);
1515 oatFreeTemp(cUnit, regLen);
1516 }
buzbee31a4a6f2012-02-28 15:36:15 -08001517 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1518
1519 oatFreeTemp(cUnit, regPtr);
1520 storeValueWide(cUnit, rlDest, rlResult);
1521 } else {
1522 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1523
buzbee239c4e72012-03-16 08:42:29 -07001524 if (needsRangeCheck) {
1525 // TODO: change kCondCS to a more meaningful name, is the sense of
1526 // carry-set/clear flipped?
1527 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1528 kThrowArrayBounds);
1529 oatFreeTemp(cUnit, regLen);
1530 }
buzbee31a4a6f2012-02-28 15:36:15 -08001531 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1532 scale, size);
1533
1534 oatFreeTemp(cUnit, regPtr);
1535 storeValue(cUnit, rlDest, rlResult);
1536 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001537#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001538}
1539
1540/*
1541 * Generate array store
1542 *
1543 */
1544void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1545 RegLocation rlArray, RegLocation rlIndex,
1546 RegLocation rlSrc, int scale)
1547{
1548 RegisterClass regClass = oatRegClassBySize(size);
1549 int lenOffset = Array::LengthOffset().Int32Value();
1550 int dataOffset;
1551
1552 if (size == kLong || size == kDouble) {
1553 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1554 } else {
1555 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1556 }
1557
1558 int regPtr;
1559 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1560 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1561
1562 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1563 oatClobber(cUnit, rlArray.lowReg);
1564 regPtr = rlArray.lowReg;
1565 } else {
1566 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001567 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001568 }
1569
1570 /* null object? */
1571 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1572
buzbee239c4e72012-03-16 08:42:29 -07001573 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1574 int regLen = INVALID_REG;
1575 if (needsRangeCheck) {
1576 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001577 //NOTE: max live temps(4) here.
1578 /* Get len */
1579 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001580 }
buzbee239c4e72012-03-16 08:42:29 -07001581 /* regPtr -> array data */
1582 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -08001583 /* at this point, regPtr points to array, 2 live temps */
1584 if ((size == kLong) || (size == kDouble)) {
1585 //TUNING: specific wide routine that can handle fp regs
1586 if (scale) {
1587 int rNewIndex = oatAllocTemp(cUnit);
1588 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1589 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1590 oatFreeTemp(cUnit, rNewIndex);
1591 } else {
1592 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1593 }
1594 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1595
buzbee239c4e72012-03-16 08:42:29 -07001596 if (needsRangeCheck) {
1597 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1598 kThrowArrayBounds);
1599 oatFreeTemp(cUnit, regLen);
1600 }
1601
buzbee31a4a6f2012-02-28 15:36:15 -08001602 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1603
1604 oatFreeTemp(cUnit, regPtr);
1605 } else {
1606 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee239c4e72012-03-16 08:42:29 -07001607 if (needsRangeCheck) {
1608 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1609 kThrowArrayBounds);
1610 oatFreeTemp(cUnit, regLen);
1611 }
buzbee31a4a6f2012-02-28 15:36:15 -08001612 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1613 scale, size);
1614 }
1615}
1616
1617void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1618 OpKind secondOp, RegLocation rlDest,
1619 RegLocation rlSrc1, RegLocation rlSrc2)
1620{
1621 RegLocation rlResult;
1622#if defined(TARGET_ARM)
1623 /*
1624 * NOTE: This is the one place in the code in which we might have
1625 * as many as six live temporary registers. There are 5 in the normal
1626 * set for Arm. Until we have spill capabilities, temporarily add
1627 * lr to the temp set. It is safe to do this locally, but note that
1628 * lr is used explicitly elsewhere in the code generator and cannot
1629 * normally be used as a general temp register.
1630 */
1631 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1632 oatFreeTemp(cUnit, rLR); // and make it available
1633#endif
1634 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1635 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1636 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1637 // The longs may overlap - use intermediate temp if so
1638 if (rlResult.lowReg == rlSrc1.highReg) {
1639 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001640 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001641 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1642 rlSrc2.lowReg);
1643 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1644 rlSrc2.highReg);
1645 oatFreeTemp(cUnit, tReg);
1646 } else {
1647 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1648 rlSrc2.lowReg);
1649 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1650 rlSrc2.highReg);
1651 }
1652 /*
1653 * NOTE: If rlDest refers to a frame variable in a large frame, the
1654 * following storeValueWide might need to allocate a temp register.
1655 * To further work around the lack of a spill capability, explicitly
1656 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1657 * Remove when spill is functional.
1658 */
1659 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1660 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1661 storeValueWide(cUnit, rlDest, rlResult);
1662#if defined(TARGET_ARM)
1663 oatClobber(cUnit, rLR);
1664 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1665#endif
1666}
1667
1668
1669bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1670 RegLocation rlSrc1, RegLocation rlShift)
1671{
1672 int funcOffset;
1673
1674 switch( mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001675 case Instruction::SHL_LONG:
1676 case Instruction::SHL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001677 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1678 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001679 case Instruction::SHR_LONG:
1680 case Instruction::SHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001681 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1682 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001683 case Instruction::USHR_LONG:
1684 case Instruction::USHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001685 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1686 break;
1687 default:
1688 LOG(FATAL) << "Unexpected case";
1689 return true;
1690 }
1691 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001692 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001693 RegLocation rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001694 storeValueWide(cUnit, rlDest, rlResult);
1695 return false;
1696}
1697
1698
1699bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1700 RegLocation rlSrc1, RegLocation rlSrc2)
1701{
1702 OpKind op = kOpBkpt;
1703 bool callOut = false;
1704 bool checkZero = false;
1705 bool unary = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001706 RegLocation rlResult;
1707 bool shiftOp = false;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001708 int funcOffset;
1709 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08001710 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001711 case Instruction::NEG_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001712 op = kOpNeg;
1713 unary = true;
1714 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001715 case Instruction::NOT_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001716 op = kOpMvn;
1717 unary = true;
1718 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001719 case Instruction::ADD_INT:
1720 case Instruction::ADD_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001721 op = kOpAdd;
1722 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001723 case Instruction::SUB_INT:
1724 case Instruction::SUB_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001725 op = kOpSub;
1726 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001727 case Instruction::MUL_INT:
1728 case Instruction::MUL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001729 op = kOpMul;
1730 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001731 case Instruction::DIV_INT:
1732 case Instruction::DIV_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001733 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001734 op = kOpDiv;
1735 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001736 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1737 retReg = rRET0;
1738 break;
buzbee5de34942012-03-01 14:51:57 -08001739 /* NOTE: returns in rARG1 */
Elliott Hughesadb8c672012-03-06 16:49:32 -08001740 case Instruction::REM_INT:
1741 case Instruction::REM_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001742 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001743 op = kOpRem;
1744 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001745 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1746 retReg = rRET1;
1747 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001748 case Instruction::AND_INT:
1749 case Instruction::AND_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001750 op = kOpAnd;
1751 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001752 case Instruction::OR_INT:
1753 case Instruction::OR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001754 op = kOpOr;
1755 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001756 case Instruction::XOR_INT:
1757 case Instruction::XOR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001758 op = kOpXor;
1759 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001760 case Instruction::SHL_INT:
1761 case Instruction::SHL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001762 shiftOp = true;
1763 op = kOpLsl;
1764 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001765 case Instruction::SHR_INT:
1766 case Instruction::SHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001767 shiftOp = true;
1768 op = kOpAsr;
1769 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001770 case Instruction::USHR_INT:
1771 case Instruction::USHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001772 shiftOp = true;
1773 op = kOpLsr;
1774 break;
1775 default:
1776 LOG(FATAL) << "Invalid word arith op: " <<
1777 (int)mir->dalvikInsn.opcode;
1778 }
1779 if (!callOut) {
1780 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1781 if (unary) {
1782 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1783 opRegReg(cUnit, op, rlResult.lowReg,
1784 rlSrc1.lowReg);
1785 } else {
1786 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001787#if defined(TARGET_X86)
1788 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1789 opRegRegReg(cUnit, op, rlResult.lowReg,
1790 rlSrc1.lowReg, rlSrc2.lowReg);
1791#else
buzbee31a4a6f2012-02-28 15:36:15 -08001792 if (shiftOp) {
1793 int tReg = oatAllocTemp(cUnit);
1794 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1795 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1796 opRegRegReg(cUnit, op, rlResult.lowReg,
1797 rlSrc1.lowReg, tReg);
1798 oatFreeTemp(cUnit, tReg);
1799 } else {
1800 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1801 opRegRegReg(cUnit, op, rlResult.lowReg,
1802 rlSrc1.lowReg, rlSrc2.lowReg);
1803 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001804#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001805 }
1806 storeValue(cUnit, rlDest, rlResult);
1807 } else {
1808 RegLocation rlResult;
1809 oatFlushAllRegs(cUnit); /* Send everything to home location */
1810 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001811#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001812 int rTgt = loadHelper(cUnit, funcOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001813#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001814 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1815 if (checkZero) {
1816 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1817 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07001818#if !defined(TARGET_X86)
1819 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001820 oatFreeTemp(cUnit, rTgt);
1821#else
Ian Rogersab2b55d2012-03-18 00:06:11 -07001822 opThreadMem(cUnit, kOpBlx, funcOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001823#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001824 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001825 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001826 else
1827 rlResult = oatGetReturnAlt(cUnit);
1828 storeValue(cUnit, rlDest, rlResult);
1829 }
1830 return false;
1831}
1832
1833/*
1834 * The following are the first-level codegen routines that analyze the format
1835 * of each bytecode then either dispatch special purpose codegen routines
1836 * or produce corresponding Thumb instructions directly.
1837 */
1838
1839bool isPowerOfTwo(int x)
1840{
1841 return (x & (x - 1)) == 0;
1842}
1843
1844// Returns true if no more than two bits are set in 'x'.
1845bool isPopCountLE2(unsigned int x)
1846{
1847 x &= x - 1;
1848 return (x & (x - 1)) == 0;
1849}
1850
1851// Returns the index of the lowest set bit in 'x'.
1852int lowestSetBit(unsigned int x) {
1853 int bit_posn = 0;
1854 while ((x & 0xf) == 0) {
1855 bit_posn += 4;
1856 x >>= 4;
1857 }
1858 while ((x & 1) == 0) {
1859 bit_posn++;
1860 x >>= 1;
1861 }
1862 return bit_posn;
1863}
1864
1865// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1866// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001867bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
buzbee31a4a6f2012-02-28 15:36:15 -08001868 RegLocation rlSrc, RegLocation rlDest, int lit)
1869{
1870 if (lit < 2 || !isPowerOfTwo(lit)) {
1871 return false;
1872 }
1873 int k = lowestSetBit(lit);
1874 if (k >= 30) {
1875 // Avoid special cases.
1876 return false;
1877 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001878 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1879 dalvikOpcode == Instruction::DIV_INT_LIT16);
buzbee31a4a6f2012-02-28 15:36:15 -08001880 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1881 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1882 if (div) {
1883 int tReg = oatAllocTemp(cUnit);
1884 if (lit == 2) {
1885 // Division by 2 is by far the most common division by constant.
1886 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1887 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1888 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1889 } else {
1890 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1891 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1892 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1893 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1894 }
1895 } else {
1896 int cReg = oatAllocTemp(cUnit);
1897 loadConstant(cUnit, cReg, lit - 1);
1898 int tReg1 = oatAllocTemp(cUnit);
1899 int tReg2 = oatAllocTemp(cUnit);
1900 if (lit == 2) {
1901 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1902 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1903 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1904 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1905 } else {
1906 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1907 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1908 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1909 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1910 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1911 }
1912 }
1913 storeValue(cUnit, rlDest, rlResult);
1914 return true;
1915}
1916
1917void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1918 RegLocation rlResult, int lit,
1919 int firstBit, int secondBit)
1920{
buzbee0398c422012-03-02 15:22:47 -08001921#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001922 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1923 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001924#else
1925 int tReg = oatAllocTemp(cUnit);
1926 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1927 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1928 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001929#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001930 if (firstBit != 0) {
1931 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1932 }
1933}
1934
1935// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1936// and store the result in 'rlDest'.
1937bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1938 RegLocation rlDest, int lit)
1939{
1940 // Can we simplify this multiplication?
1941 bool powerOfTwo = false;
1942 bool popCountLE2 = false;
1943 bool powerOfTwoMinusOne = false;
1944 if (lit < 2) {
1945 // Avoid special cases.
1946 return false;
1947 } else if (isPowerOfTwo(lit)) {
1948 powerOfTwo = true;
1949 } else if (isPopCountLE2(lit)) {
1950 popCountLE2 = true;
1951 } else if (isPowerOfTwo(lit + 1)) {
1952 powerOfTwoMinusOne = true;
1953 } else {
1954 return false;
1955 }
1956 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1957 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1958 if (powerOfTwo) {
1959 // Shift.
1960 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1961 lowestSetBit(lit));
1962 } else if (popCountLE2) {
1963 // Shift and add and shift.
1964 int firstBit = lowestSetBit(lit);
1965 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1966 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1967 firstBit, secondBit);
1968 } else {
1969 // Reverse subtract: (src << (shift + 1)) - src.
1970 DCHECK(powerOfTwoMinusOne);
1971 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1972 int tReg = oatAllocTemp(cUnit);
1973 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1974 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1975 }
1976 storeValue(cUnit, rlDest, rlResult);
1977 return true;
1978}
1979
1980bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1981 RegLocation rlSrc, int lit)
1982{
Elliott Hughesadb8c672012-03-06 16:49:32 -08001983 Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08001984 RegLocation rlResult;
1985 OpKind op = (OpKind)0; /* Make gcc happy */
1986 int shiftOp = false;
1987 bool isDiv = false;
1988 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001989
1990 switch (dalvikOpcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001991 case Instruction::RSUB_INT_LIT8:
1992 case Instruction::RSUB_INT: {
buzbee31a4a6f2012-02-28 15:36:15 -08001993 int tReg;
1994 //TUNING: add support for use of Arm rsub op
1995 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1996 tReg = oatAllocTemp(cUnit);
1997 loadConstant(cUnit, tReg, lit);
1998 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1999 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
2000 tReg, rlSrc.lowReg);
2001 storeValue(cUnit, rlDest, rlResult);
2002 return false;
2003 break;
2004 }
2005
Elliott Hughesadb8c672012-03-06 16:49:32 -08002006 case Instruction::ADD_INT_LIT8:
2007 case Instruction::ADD_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002008 op = kOpAdd;
2009 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002010 case Instruction::MUL_INT_LIT8:
2011 case Instruction::MUL_INT_LIT16: {
buzbee31a4a6f2012-02-28 15:36:15 -08002012 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2013 return false;
2014 }
2015 op = kOpMul;
2016 break;
2017 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08002018 case Instruction::AND_INT_LIT8:
2019 case Instruction::AND_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002020 op = kOpAnd;
2021 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002022 case Instruction::OR_INT_LIT8:
2023 case Instruction::OR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002024 op = kOpOr;
2025 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002026 case Instruction::XOR_INT_LIT8:
2027 case Instruction::XOR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002028 op = kOpXor;
2029 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002030 case Instruction::SHL_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08002031 lit &= 31;
2032 shiftOp = true;
2033 op = kOpLsl;
2034 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002035 case Instruction::SHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08002036 lit &= 31;
2037 shiftOp = true;
2038 op = kOpAsr;
2039 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002040 case Instruction::USHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08002041 lit &= 31;
2042 shiftOp = true;
2043 op = kOpLsr;
2044 break;
2045
Elliott Hughesadb8c672012-03-06 16:49:32 -08002046 case Instruction::DIV_INT_LIT8:
2047 case Instruction::DIV_INT_LIT16:
2048 case Instruction::REM_INT_LIT8:
2049 case Instruction::REM_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002050 if (lit == 0) {
2051 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
2052 return false;
2053 }
2054 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2055 return false;
2056 }
2057 oatFlushAllRegs(cUnit); /* Everything to home location */
2058 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2059 oatClobber(cUnit, rARG0);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002060 if ((dalvikOpcode == Instruction::DIV_INT_LIT8) ||
2061 (dalvikOpcode == Instruction::DIV_INT_LIT16)) {
buzbee31a4a6f2012-02-28 15:36:15 -08002062 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2063 isDiv = true;
2064 } else {
2065 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2066 isDiv = false;
2067 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07002068 callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit);
buzbee31a4a6f2012-02-28 15:36:15 -08002069 if (isDiv)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002070 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002071 else
2072 rlResult = oatGetReturnAlt(cUnit);
2073 storeValue(cUnit, rlDest, rlResult);
2074 return false;
2075 break;
2076 default:
2077 return true;
2078 }
2079 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2080 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2081 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2082 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08002083 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002084 } else {
2085 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2086 }
2087 storeValue(cUnit, rlDest, rlResult);
2088 return false;
2089}
2090
2091bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
2092 RegLocation rlSrc1, RegLocation rlSrc2)
2093{
2094 RegLocation rlResult;
2095 OpKind firstOp = kOpBkpt;
2096 OpKind secondOp = kOpBkpt;
2097 bool callOut = false;
2098 bool checkZero = false;
2099 int funcOffset;
2100 int retReg = rRET0;
2101
2102 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002103 case Instruction::NOT_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002104 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2105 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2106 // Check for destructive overlap
2107 if (rlResult.lowReg == rlSrc2.highReg) {
2108 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08002109 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002110 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2111 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2112 oatFreeTemp(cUnit, tReg);
2113 } else {
2114 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2115 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2116 }
2117 storeValueWide(cUnit, rlDest, rlResult);
2118 return false;
2119 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002120 case Instruction::ADD_LONG:
2121 case Instruction::ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002122#if defined(TARGET_MIPS)
2123 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2124#else
buzbee31a4a6f2012-02-28 15:36:15 -08002125 firstOp = kOpAdd;
2126 secondOp = kOpAdc;
2127 break;
buzbeec5159d52012-03-03 11:48:39 -08002128#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002129 case Instruction::SUB_LONG:
2130 case Instruction::SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002131#if defined(TARGET_MIPS)
2132 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2133#else
buzbee31a4a6f2012-02-28 15:36:15 -08002134 firstOp = kOpSub;
2135 secondOp = kOpSbc;
2136 break;
buzbeec5159d52012-03-03 11:48:39 -08002137#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002138 case Instruction::MUL_LONG:
2139 case Instruction::MUL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002140 callOut = true;
2141 retReg = rRET0;
2142 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
2143 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002144 case Instruction::DIV_LONG:
2145 case Instruction::DIV_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002146 callOut = true;
2147 checkZero = true;
2148 retReg = rRET0;
2149 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2150 break;
2151 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2152 // FIXME: is true, or could be made true, or other targets?
Elliott Hughesadb8c672012-03-06 16:49:32 -08002153 case Instruction::REM_LONG:
2154 case Instruction::REM_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002155 callOut = true;
2156 checkZero = true;
2157 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2158 retReg = rARG2;
2159 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002160 case Instruction::AND_LONG_2ADDR:
2161 case Instruction::AND_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002162 firstOp = kOpAnd;
2163 secondOp = kOpAnd;
2164 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002165 case Instruction::OR_LONG:
2166 case Instruction::OR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002167 firstOp = kOpOr;
2168 secondOp = kOpOr;
2169 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002170 case Instruction::XOR_LONG:
2171 case Instruction::XOR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002172 firstOp = kOpXor;
2173 secondOp = kOpXor;
2174 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002175 case Instruction::NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08002176 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002177 }
2178 default:
2179 LOG(FATAL) << "Invalid long arith op";
2180 }
2181 if (!callOut) {
2182 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
2183 } else {
buzbee31a4a6f2012-02-28 15:36:15 -08002184 oatFlushAllRegs(cUnit); /* Send everything to home location */
2185 if (checkZero) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002186#if defined(TARGET_X86)
2187 UNIMPLEMENTED(FATAL);
2188#else
buzbee31a4a6f2012-02-28 15:36:15 -08002189 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
Ian Rogersab2b55d2012-03-18 00:06:11 -07002190 int rTgt = loadHelper(cUnit, funcOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002191#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002192 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2193 int tReg = oatAllocTemp(cUnit);
2194#if defined(TARGET_ARM)
2195 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2196 oatFreeTemp(cUnit, tReg);
2197 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
2198#else
Ian Rogersb5d09b22012-03-06 22:14:17 -08002199#if defined(TARGET_X86)
2200 UNIMPLEMENTED(FATAL);
2201#else
buzbee31a4a6f2012-02-28 15:36:15 -08002202 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002203#endif
buzbee5de34942012-03-01 14:51:57 -08002204 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08002205 oatFreeTemp(cUnit, tReg);
2206#endif
Ian Rogersab2b55d2012-03-18 00:06:11 -07002207#if !defined(TARGET_X86)
2208 opReg(cUnit, kOpBlx, rTgt);
2209 oatFreeTemp(cUnit, rTgt);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002210#endif
Ian Rogersab2b55d2012-03-18 00:06:11 -07002211 } else {
2212 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset,
2213 rlSrc1, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002214 }
buzbee31a4a6f2012-02-28 15:36:15 -08002215 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2216 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002217 rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002218 else
2219 rlResult = oatGetReturnWideAlt(cUnit);
2220 storeValueWide(cUnit, rlDest, rlResult);
2221 }
2222 return false;
2223}
2224
2225bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
2226 int srcSize, int tgtSize)
2227{
2228 /*
2229 * Don't optimize the register usage since it calls out to support
2230 * functions
2231 */
2232 RegLocation rlSrc;
2233 RegLocation rlDest;
2234 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee31a4a6f2012-02-28 15:36:15 -08002235 if (srcSize == 1) {
2236 rlSrc = oatGetSrc(cUnit, mir, 0);
2237 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2238 } else {
2239 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
2240 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
2241 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07002242 callRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc);
buzbee31a4a6f2012-02-28 15:36:15 -08002243 if (tgtSize == 1) {
2244 RegLocation rlResult;
2245 rlDest = oatGetDest(cUnit, mir, 0);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002246 rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002247 storeValue(cUnit, rlDest, rlResult);
2248 } else {
2249 RegLocation rlResult;
2250 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002251 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002252 storeValueWide(cUnit, rlDest, rlResult);
2253 }
2254 return false;
2255}
2256
2257void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
2258bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
2259 RegLocation rlDest, RegLocation rlSrc1,
2260 RegLocation rlSrc2)
2261{
2262 RegLocation rlResult;
2263 int funcOffset;
2264
2265 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002266 case Instruction::ADD_FLOAT_2ADDR:
2267 case Instruction::ADD_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002268 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
2269 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002270 case Instruction::SUB_FLOAT_2ADDR:
2271 case Instruction::SUB_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002272 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
2273 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002274 case Instruction::DIV_FLOAT_2ADDR:
2275 case Instruction::DIV_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002276 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
2277 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002278 case Instruction::MUL_FLOAT_2ADDR:
2279 case Instruction::MUL_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002280 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
2281 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002282 case Instruction::REM_FLOAT_2ADDR:
2283 case Instruction::REM_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002284 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
2285 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002286 case Instruction::NEG_FLOAT: {
buzbee31a4a6f2012-02-28 15:36:15 -08002287 genNegFloat(cUnit, rlDest, rlSrc1);
2288 return false;
2289 }
2290 default:
2291 return true;
2292 }
2293 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogersab2b55d2012-03-18 00:06:11 -07002294 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002295 rlResult = oatGetReturn(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002296 storeValue(cUnit, rlDest, rlResult);
2297 return false;
2298}
2299
2300void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
2301bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
2302 RegLocation rlDest, RegLocation rlSrc1,
2303 RegLocation rlSrc2)
2304{
2305 RegLocation rlResult;
2306 int funcOffset;
2307
2308 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002309 case Instruction::ADD_DOUBLE_2ADDR:
2310 case Instruction::ADD_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002311 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
2312 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002313 case Instruction::SUB_DOUBLE_2ADDR:
2314 case Instruction::SUB_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002315 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
2316 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002317 case Instruction::DIV_DOUBLE_2ADDR:
2318 case Instruction::DIV_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002319 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2320 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002321 case Instruction::MUL_DOUBLE_2ADDR:
2322 case Instruction::MUL_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002323 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2324 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002325 case Instruction::REM_DOUBLE_2ADDR:
2326 case Instruction::REM_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002327 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2328 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002329 case Instruction::NEG_DOUBLE: {
buzbee31a4a6f2012-02-28 15:36:15 -08002330 genNegDouble(cUnit, rlDest, rlSrc1);
2331 return false;
2332 }
2333 default:
2334 return true;
2335 }
2336 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogersab2b55d2012-03-18 00:06:11 -07002337 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002338 rlResult = oatGetReturnWide(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002339 storeValueWide(cUnit, rlDest, rlResult);
2340 return false;
2341}
2342
2343bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2344{
Elliott Hughesadb8c672012-03-06 16:49:32 -08002345 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08002346
2347 switch (opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002348 case Instruction::INT_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002349 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2350 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002351 case Instruction::FLOAT_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002352 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2353 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002354 case Instruction::DOUBLE_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002355 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2356 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002357 case Instruction::FLOAT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002358 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2359 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002360 case Instruction::INT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002361 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2362 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002363 case Instruction::DOUBLE_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002364 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2365 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002366 case Instruction::FLOAT_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002367 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2368 pF2l), 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002369 case Instruction::LONG_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002370 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2371 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002372 case Instruction::DOUBLE_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002373 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2374 pD2l), 2, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002375 case Instruction::LONG_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002376 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2377 2, 2);
2378 default:
2379 return true;
2380 }
2381 return false;
2382}
2383
2384/*
2385 * Generate callout to updateDebugger. Note that we're overloading
2386 * the use of rSUSPEND here. When the debugger is active, this
2387 * register holds the address of the update function. So, if it's
2388 * non-null, we call out to it.
2389 *
2390 * Note also that rRET0 and rRET1 must be preserved across this
2391 * code. This must be handled by the stub.
2392 */
2393void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2394{
2395 // Following DCHECK verifies that dPC is in range of single load immediate
2396 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2397 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2398 oatClobberCalleeSave(cUnit);
2399#if defined(TARGET_ARM)
2400 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002401 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002402 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2403 opReg(cUnit, kOpBlx, rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002404#elif defined(TARGET_X86)
2405 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002406#else
buzbee82488f52012-03-02 08:20:26 -08002407 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002408 loadConstant(cUnit, rARG2, offset);
2409 opReg(cUnit, kOpBlx, rSUSPEND);
2410 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002411 branch->target = (LIR*)target;
2412#endif
2413 oatFreeTemp(cUnit, rARG2);
2414}
2415
2416/* Check if we need to check for pending suspend request */
2417void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2418{
2419 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2420 return;
2421 }
2422 oatFlushAllRegs(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002423 if (cUnit->genDebugger) {
2424 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002425#if defined(TARGET_X86)
2426 UNIMPLEMENTED(FATAL);
2427#else
buzbee86a4bce2012-03-06 18:15:00 -08002428 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
2429 pTestSuspendFromCode));
2430 opReg(cUnit, kOpBlx, rTgt);
2431 // Refresh rSUSPEND
2432 loadWordDisp(cUnit, rSELF,
2433 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
2434 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002435#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002436 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002437 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002438#if defined(TARGET_ARM)
2439 // In non-debug case, only check periodically
2440 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002441 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002442#elif defined(TARGET_X86)
2443 newLIR2(cUnit, kX86Cmp32TI, Thread::SuspendCountOffset().Int32Value(), 0);
2444 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002445#else
2446 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002447 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002448#endif
buzbee86a4bce2012-03-06 18:15:00 -08002449 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2450 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2451 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
2452 branch->target = (LIR*)target;
2453 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
buzbee31a4a6f2012-02-28 15:36:15 -08002454 }
buzbee31a4a6f2012-02-28 15:36:15 -08002455}
2456
2457} // namespace art