blob: 52ff3d79a1eddb73ced504083b6dfcd5144ce8dd [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 }
1052 }
1053 } else {
1054 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
1055 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
1056 : OFFSETOF_MEMBER(Thread, pSet32Instance));
Ian Rogersab2b55d2012-03-18 00:06:11 -07001057 callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset,
1058 fieldIdx, rlObj, rlSrc);
buzbee31a4a6f2012-02-28 15:36:15 -08001059 }
1060}
1061
1062void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1063 RegLocation rlSrc)
1064{
1065 uint32_t type_idx = mir->dalvikInsn.vB;
buzbeee1965672012-03-11 18:39:19 -07001066 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001067 int resReg = oatAllocTemp(cUnit);
1068 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1069 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1070 cUnit->dex_cache,
1071 *cUnit->dex_file,
1072 type_idx)) {
1073 // Call out to helper which resolves type and verifies access.
1074 // Resolved type returned in rRET0.
Ian Rogersab2b55d2012-03-18 00:06:11 -07001075 callRuntimeHelperImmReg(cUnit,
1076 OFFSETOF_MEMBER(Thread,
1077 pInitializeTypeAndVerifyAccessFromCode),
1078 type_idx, rlMethod.lowReg);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001079 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001080 storeValue(cUnit, rlDest, rlResult);
1081 } else {
1082 // We're don't need access checks, load type from dex cache
1083 int32_t dex_cache_offset =
1084 Method::DexCacheResolvedTypesOffset().Int32Value();
buzbeee1965672012-03-11 18:39:19 -07001085 loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001086 int32_t offset_of_type =
1087 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1088 * type_idx);
1089 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
1090 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
1091 type_idx) || SLOW_TYPE_PATH) {
1092 // Slow path, at runtime test if type is null and if so initialize
1093 oatFlushAllRegs(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001094 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0,
1095 NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001096 // Resolved, store and hop over following code
1097 storeValue(cUnit, rlDest, rlResult);
buzbee3d661942012-03-14 17:37:27 -07001098 /*
1099 * Because we have stores of the target value on two paths,
1100 * clobber temp tracking for the destination using the ssa name
1101 */
1102 oatClobberSReg(cUnit, rlDest.sRegLow);
buzbee82488f52012-03-02 08:20:26 -08001103 LIR* branch2 = opUnconditionalBranch(cUnit,0);
buzbee31a4a6f2012-02-28 15:36:15 -08001104 // TUNING: move slow path to end & remove unconditional branch
1105 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -08001106 // Call out to helper, which will return resolved type in rARG0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001107 callRuntimeHelperImmReg(cUnit, OFFSETOF_MEMBER(Thread,
1108 pInitializeTypeFromCode),
1109 type_idx, rlMethod.lowReg);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001110 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001111 storeValue(cUnit, rlDest, rlResult);
buzbee3d661942012-03-14 17:37:27 -07001112 /*
1113 * Because we have stores of the target value on two paths,
1114 * clobber temp tracking for the destination using the ssa name
1115 */
1116 oatClobberSReg(cUnit, rlDest.sRegLow);
buzbee31a4a6f2012-02-28 15:36:15 -08001117 // Rejoin code paths
1118 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001119 branch1->target = (LIR*)target1;
1120 branch2->target = (LIR*)target2;
1121 } else {
1122 // Fast path, we're done - just store result
1123 storeValue(cUnit, rlDest, rlResult);
1124 }
1125 }
1126}
Ian Rogersab2b55d2012-03-18 00:06:11 -07001127
buzbee31a4a6f2012-02-28 15:36:15 -08001128void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1129 RegLocation rlSrc)
1130{
1131 /* NOTE: Most strings should be available at compile time */
1132 uint32_t string_idx = mir->dalvikInsn.vB;
1133 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1134 (sizeof(String*) * string_idx);
1135 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
1136 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
1137 // slow path, resolve string if not in dex cache
1138 oatFlushAllRegs(cUnit);
1139 oatLockCallTemps(cUnit); // Using explicit registers
1140 loadCurrMethodDirect(cUnit, rARG2);
1141 loadWordDisp(cUnit, rARG2,
1142 Method::DexCacheStringsOffset().Int32Value(), rARG0);
1143 // Might call out to helper, which will return resolved string in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001144#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001145 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1146 pResolveStringFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001147#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001148 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
1149 loadConstant(cUnit, rARG1, string_idx);
1150#if defined(TARGET_ARM)
1151 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
1152 genBarrier(cUnit);
1153 // For testing, always force through helper
1154 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee82488f52012-03-02 08:20:26 -08001155 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08001156 }
buzbee82488f52012-03-02 08:20:26 -08001157 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -08001158 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001159 oatFreeTemp(cUnit, rTgt);
1160#elif defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -08001161 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
1162 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -08001163 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001164 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001165 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001166 branch->target = target;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001167#else
Ian Rogersab2b55d2012-03-18 00:06:11 -07001168 callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
1169 pResolveStringFromCode),
1170 rARG2, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -08001171#endif
1172 genBarrier(cUnit);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001173 storeValue(cUnit, rlDest, oatGetReturn(cUnit, false));
buzbee31a4a6f2012-02-28 15:36:15 -08001174 } else {
buzbeee1965672012-03-11 18:39:19 -07001175 RegLocation rlMethod = loadCurrMethod(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001176 int resReg = oatAllocTemp(cUnit);
1177 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeee1965672012-03-11 18:39:19 -07001178 loadWordDisp(cUnit, rlMethod.lowReg,
buzbee31a4a6f2012-02-28 15:36:15 -08001179 Method::DexCacheStringsOffset().Int32Value(), resReg);
1180 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1181 storeValue(cUnit, rlDest, rlResult);
1182 }
1183}
1184
1185/*
1186 * Let helper function take care of everything. Will
1187 * call Class::NewInstanceFromCode(type_idx, method);
1188 */
1189void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
1190{
1191 oatFlushAllRegs(cUnit); /* Everything to home location */
1192 uint32_t type_idx = mir->dalvikInsn.vB;
1193 // alloc will always check for resolution, do we also need to verify
1194 // access because the verifier was unable to?
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001195 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001196 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
1197 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001198 funcOffset = OFFSETOF_MEMBER(Thread, pAllocObjectFromCode);
buzbee31a4a6f2012-02-28 15:36:15 -08001199 } else {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001200 funcOffset =
1201 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck);
buzbee31a4a6f2012-02-28 15:36:15 -08001202 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07001203 callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001204 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001205 storeValue(cUnit, rlDest, rlResult);
1206}
1207
Ian Rogersab2b55d2012-03-18 00:06:11 -07001208void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1209{
1210 oatFlushAllRegs(cUnit);
1211 callRuntimeHelperRegLocation(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException), rlSrc);
1212}
1213
buzbee31a4a6f2012-02-28 15:36:15 -08001214void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1215 RegLocation rlSrc)
1216{
1217 oatFlushAllRegs(cUnit);
1218 // May generate a call - use explicit registers
1219 oatLockCallTemps(cUnit);
1220 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee5de34942012-03-01 14:51:57 -08001221 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
buzbee31a4a6f2012-02-28 15:36:15 -08001222 int classReg = rARG2; // rARG2 will hold the Class*
1223 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1224 cUnit->dex_cache,
1225 *cUnit->dex_file,
1226 type_idx)) {
1227 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbee5de34942012-03-01 14:51:57 -08001228 // returns Class* in rARG0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001229 callRuntimeHelperImm(cUnit,
1230 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
1231 type_idx);
buzbee82488f52012-03-02 08:20:26 -08001232 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee5de34942012-03-01 14:51:57 -08001233 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
buzbee31a4a6f2012-02-28 15:36:15 -08001234 } else {
buzbee5de34942012-03-01 14:51:57 -08001235 // Load dex cache entry into classReg (rARG2)
buzbee31a4a6f2012-02-28 15:36:15 -08001236 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1237 loadWordDisp(cUnit, rARG1,
1238 Method::DexCacheResolvedTypesOffset().Int32Value(),
1239 classReg);
1240 int32_t offset_of_type =
1241 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1242 * type_idx);
1243 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1244 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1245 cUnit->dex_cache, type_idx)) {
1246 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001247 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001248 // Not resolved
1249 // Call out to helper, which will return resolved type in rRET0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001250 callRuntimeHelperImm(cUnit, OFFSETOF_MEMBER(Thread,
1251 pInitializeTypeFromCode),
1252 type_idx);
buzbee82488f52012-03-02 08:20:26 -08001253 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001254 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1255 // Rejoin code paths
1256 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001257 hopBranch->target = (LIR*)hopTarget;
1258 }
1259 }
1260 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
buzbee82488f52012-03-02 08:20:26 -08001261 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001262 /* load object->clazz */
1263 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1264 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1265 /* rARG0 is ref, rARG1 is ref->clazz, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001266#if defined(TARGET_ARM)
1267 /* Uses conditional nullification */
buzbee31a4a6f2012-02-28 15:36:15 -08001268 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1269 pInstanceofNonTrivialFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001270 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
buzbee82488f52012-03-02 08:20:26 -08001271 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
buzbee31a4a6f2012-02-28 15:36:15 -08001272 loadConstant(cUnit, rARG0, 1); // .eq case - load true
buzbee82488f52012-03-02 08:20:26 -08001273 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee31a4a6f2012-02-28 15:36:15 -08001274 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001275 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001276#else
buzbee0398c422012-03-02 15:22:47 -08001277 /* Uses branchovers */
1278 loadConstant(cUnit, rARG0, 1); // assume true
1279 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001280#if !defined(TARGET_X86)
buzbee0398c422012-03-02 15:22:47 -08001281 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1282 pInstanceofNonTrivialFromCode));
1283 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1284 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001285 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001286#else
1287 opRegCopy(cUnit, rARG0, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001288 opThreadMem(cUnit, kOpBlx,
1289 OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001290#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001291#endif
buzbee0398c422012-03-02 15:22:47 -08001292 oatClobberCalleeSave(cUnit);
1293 /* branch targets here */
buzbee31a4a6f2012-02-28 15:36:15 -08001294 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001295 RegLocation rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001296 storeValue(cUnit, rlDest, rlResult);
buzbee0398c422012-03-02 15:22:47 -08001297 branch1->target = target;
1298#if !defined(TARGET_ARM)
1299 branchover->target = target;
1300#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001301}
1302
1303void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1304{
1305 oatFlushAllRegs(cUnit);
1306 // May generate a call - use explicit registers
1307 oatLockCallTemps(cUnit);
1308 uint32_t type_idx = mir->dalvikInsn.vB;
1309 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1310 int classReg = rARG2; // rARG2 will hold the Class*
1311 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1312 cUnit->dex_cache,
1313 *cUnit->dex_file,
1314 type_idx)) {
1315 // Check we have access to type_idx and if not throw IllegalAccessError,
1316 // returns Class* in rRET0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001317 // InitializeTypeAndVerifyAccess(idx, method)
1318 callRuntimeHelperImmReg(cUnit,
1319 OFFSETOF_MEMBER(Thread,
1320 pInitializeTypeAndVerifyAccessFromCode),
1321 type_idx, rARG1);
buzbee82488f52012-03-02 08:20:26 -08001322 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001323 } else {
1324 // Load dex cache entry into classReg (rARG2)
1325 loadWordDisp(cUnit, rARG1,
1326 Method::DexCacheResolvedTypesOffset().Int32Value(),
1327 classReg);
1328 int32_t offset_of_type =
1329 Array::DataOffset(sizeof(Class*)).Int32Value() +
1330 (sizeof(Class*) * type_idx);
1331 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1332 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1333 cUnit->dex_cache, type_idx)) {
1334 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001335 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001336 // Not resolved
buzbee5de34942012-03-01 14:51:57 -08001337 // Call out to helper, which will return resolved type in rARG0
Ian Rogersab2b55d2012-03-18 00:06:11 -07001338 // InitializeTypeFromCode(idx, method)
1339 callRuntimeHelperImmReg(cUnit,
1340 OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode),
1341 type_idx, rARG1);
buzbee82488f52012-03-02 08:20:26 -08001342 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001343 // Rejoin code paths
1344 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001345 hopBranch->target = (LIR*)hopTarget;
1346 }
1347 }
buzbee5de34942012-03-01 14:51:57 -08001348 // At this point, classReg (rARG2) has class
buzbee31a4a6f2012-02-28 15:36:15 -08001349 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1350 /* Null is OK - continue */
buzbee82488f52012-03-02 08:20:26 -08001351 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001352 /* load object->clazz */
1353 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1354 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1355 /* rARG1 now contains object->clazz */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001356#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee82488f52012-03-02 08:20:26 -08001357 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001358 callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
1359 pCheckCastFromCode),
1360 rARG1, rARG2);
1361#else // defined(TARGET_ARM)
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001362 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1363 pCheckCastFromCode));
1364 opRegReg(cUnit, kOpCmp, rARG1, classReg);
1365 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1366 opRegCopy(cUnit, rARG0, rARG1);
1367 opRegCopy(cUnit, rARG1, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001368 oatClobberCalleeSave(cUnit);
1369 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001370 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001371#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001372 /* branch target here */
1373 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001374 branch1->target = (LIR*)target;
1375 branch2->target = (LIR*)target;
1376}
1377
buzbee31a4a6f2012-02-28 15:36:15 -08001378/*
1379 * Generate array store
1380 *
1381 */
1382void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
1383 RegLocation rlIndex, RegLocation rlSrc, int scale)
1384{
1385 RegisterClass regClass = oatRegClassBySize(kWord);
1386 int lenOffset = Array::LengthOffset().Int32Value();
1387 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
1388
1389 oatFlushAllRegs(cUnit);
1390 /* Make sure it's a legal object Put. Use direct regs at first */
1391 loadValueDirectFixed(cUnit, rlArray, rARG1);
1392 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1393
1394 /* null array object? */
1395 genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
buzbee31a4a6f2012-02-28 15:36:15 -08001396 /* Get the array's clazz */
1397 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001398 callRuntimeHelperRegReg(cUnit, OFFSETOF_MEMBER(Thread,
1399 pCanPutArrayElementFromCode),
1400 rARG0, rARG1);
buzbee31a4a6f2012-02-28 15:36:15 -08001401 oatFreeTemp(cUnit, rARG0);
1402 oatFreeTemp(cUnit, rARG1);
1403
1404 // Now, redo loadValues in case they didn't survive the call
1405
1406 int regPtr;
1407 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1408 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1409
1410 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1411 oatClobber(cUnit, rlArray.lowReg);
1412 regPtr = rlArray.lowReg;
1413 } else {
1414 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001415 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001416 }
1417
buzbee239c4e72012-03-16 08:42:29 -07001418 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1419 int regLen = INVALID_REG;
1420 if (needsRangeCheck) {
1421 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001422 //NOTE: max live temps(4) here.
1423 /* Get len */
1424 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee239c4e72012-03-16 08:42:29 -07001425 }
1426 /* regPtr -> array data */
1427 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1428 /* at this point, regPtr points to array, 2 live temps */
1429 rlSrc = loadValue(cUnit, rlSrc, regClass);
1430 if (needsRangeCheck) {
buzbee31a4a6f2012-02-28 15:36:15 -08001431 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1432 kThrowArrayBounds);
1433 oatFreeTemp(cUnit, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001434 }
buzbee31a4a6f2012-02-28 15:36:15 -08001435 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1436 scale, kWord);
1437}
1438
1439/*
1440 * Generate array load
1441 */
1442void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1443 RegLocation rlArray, RegLocation rlIndex,
1444 RegLocation rlDest, int scale)
1445{
1446 RegisterClass regClass = oatRegClassBySize(size);
1447 int lenOffset = Array::LengthOffset().Int32Value();
1448 int dataOffset;
1449 RegLocation rlResult;
1450 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1451 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001452
1453 if (size == kLong || size == kDouble) {
1454 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1455 } else {
1456 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1457 }
1458
1459 /* null object? */
1460 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1461
Ian Rogersb5d09b22012-03-06 22:14:17 -08001462#if defined(TARGET_X86)
1463 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1464 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1465 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
1466 lenOffset, mir, kThrowArrayBounds);
1467 }
1468 if ((size == kLong) || (size == kDouble)) {
1469 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1470 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1471 rlResult.lowReg, rlResult.highReg, size, INVALID_SREG);
buzbee31a4a6f2012-02-28 15:36:15 -08001472
Ian Rogersb5d09b22012-03-06 22:14:17 -08001473 storeValueWide(cUnit, rlDest, rlResult);
1474 } else {
1475 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1476
1477 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset,
1478 rlResult.lowReg, INVALID_REG, size, INVALID_SREG);
1479
1480 storeValue(cUnit, rlDest, rlResult);
1481 }
1482#else
1483 int regPtr = oatAllocTemp(cUnit);
buzbee239c4e72012-03-16 08:42:29 -07001484 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1485 int regLen = INVALID_REG;
1486 if (needsRangeCheck) {
1487 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001488 /* Get len */
1489 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001490 }
buzbee239c4e72012-03-16 08:42:29 -07001491 /* regPtr -> array data */
1492 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -08001493 oatFreeTemp(cUnit, rlArray.lowReg);
1494 if ((size == kLong) || (size == kDouble)) {
1495 if (scale) {
1496 int rNewIndex = oatAllocTemp(cUnit);
1497 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1498 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1499 oatFreeTemp(cUnit, rNewIndex);
1500 } else {
1501 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1502 }
1503 oatFreeTemp(cUnit, rlIndex.lowReg);
1504 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1505
buzbee239c4e72012-03-16 08:42:29 -07001506 if (needsRangeCheck) {
1507 // TODO: change kCondCS to a more meaningful name, is the sense of
1508 // carry-set/clear flipped?
1509 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1510 kThrowArrayBounds);
1511 oatFreeTemp(cUnit, regLen);
1512 }
buzbee31a4a6f2012-02-28 15:36:15 -08001513 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1514
1515 oatFreeTemp(cUnit, regPtr);
1516 storeValueWide(cUnit, rlDest, rlResult);
1517 } else {
1518 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1519
buzbee239c4e72012-03-16 08:42:29 -07001520 if (needsRangeCheck) {
1521 // TODO: change kCondCS to a more meaningful name, is the sense of
1522 // carry-set/clear flipped?
1523 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1524 kThrowArrayBounds);
1525 oatFreeTemp(cUnit, regLen);
1526 }
buzbee31a4a6f2012-02-28 15:36:15 -08001527 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1528 scale, size);
1529
1530 oatFreeTemp(cUnit, regPtr);
1531 storeValue(cUnit, rlDest, rlResult);
1532 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001533#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001534}
1535
1536/*
1537 * Generate array store
1538 *
1539 */
1540void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1541 RegLocation rlArray, RegLocation rlIndex,
1542 RegLocation rlSrc, int scale)
1543{
1544 RegisterClass regClass = oatRegClassBySize(size);
1545 int lenOffset = Array::LengthOffset().Int32Value();
1546 int dataOffset;
1547
1548 if (size == kLong || size == kDouble) {
1549 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1550 } else {
1551 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1552 }
1553
1554 int regPtr;
1555 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1556 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1557
1558 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1559 oatClobber(cUnit, rlArray.lowReg);
1560 regPtr = rlArray.lowReg;
1561 } else {
1562 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001563 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001564 }
1565
1566 /* null object? */
1567 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1568
buzbee239c4e72012-03-16 08:42:29 -07001569 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1570 int regLen = INVALID_REG;
1571 if (needsRangeCheck) {
1572 regLen = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001573 //NOTE: max live temps(4) here.
1574 /* Get len */
1575 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
buzbee31a4a6f2012-02-28 15:36:15 -08001576 }
buzbee239c4e72012-03-16 08:42:29 -07001577 /* regPtr -> array data */
1578 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbee31a4a6f2012-02-28 15:36:15 -08001579 /* at this point, regPtr points to array, 2 live temps */
1580 if ((size == kLong) || (size == kDouble)) {
1581 //TUNING: specific wide routine that can handle fp regs
1582 if (scale) {
1583 int rNewIndex = oatAllocTemp(cUnit);
1584 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1585 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1586 oatFreeTemp(cUnit, rNewIndex);
1587 } else {
1588 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1589 }
1590 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1591
buzbee239c4e72012-03-16 08:42:29 -07001592 if (needsRangeCheck) {
1593 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1594 kThrowArrayBounds);
1595 oatFreeTemp(cUnit, regLen);
1596 }
1597
buzbee31a4a6f2012-02-28 15:36:15 -08001598 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1599
1600 oatFreeTemp(cUnit, regPtr);
1601 } else {
1602 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee239c4e72012-03-16 08:42:29 -07001603 if (needsRangeCheck) {
1604 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1605 kThrowArrayBounds);
1606 oatFreeTemp(cUnit, regLen);
1607 }
buzbee31a4a6f2012-02-28 15:36:15 -08001608 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1609 scale, size);
1610 }
1611}
1612
1613void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1614 OpKind secondOp, RegLocation rlDest,
1615 RegLocation rlSrc1, RegLocation rlSrc2)
1616{
1617 RegLocation rlResult;
1618#if defined(TARGET_ARM)
1619 /*
1620 * NOTE: This is the one place in the code in which we might have
1621 * as many as six live temporary registers. There are 5 in the normal
1622 * set for Arm. Until we have spill capabilities, temporarily add
1623 * lr to the temp set. It is safe to do this locally, but note that
1624 * lr is used explicitly elsewhere in the code generator and cannot
1625 * normally be used as a general temp register.
1626 */
1627 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1628 oatFreeTemp(cUnit, rLR); // and make it available
1629#endif
1630 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1631 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1632 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1633 // The longs may overlap - use intermediate temp if so
1634 if (rlResult.lowReg == rlSrc1.highReg) {
1635 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001636 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001637 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1638 rlSrc2.lowReg);
1639 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1640 rlSrc2.highReg);
1641 oatFreeTemp(cUnit, tReg);
1642 } else {
1643 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1644 rlSrc2.lowReg);
1645 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1646 rlSrc2.highReg);
1647 }
1648 /*
1649 * NOTE: If rlDest refers to a frame variable in a large frame, the
1650 * following storeValueWide might need to allocate a temp register.
1651 * To further work around the lack of a spill capability, explicitly
1652 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1653 * Remove when spill is functional.
1654 */
1655 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1656 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1657 storeValueWide(cUnit, rlDest, rlResult);
1658#if defined(TARGET_ARM)
1659 oatClobber(cUnit, rLR);
1660 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1661#endif
1662}
1663
1664
1665bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1666 RegLocation rlSrc1, RegLocation rlShift)
1667{
1668 int funcOffset;
1669
1670 switch( mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001671 case Instruction::SHL_LONG:
1672 case Instruction::SHL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001673 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1674 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001675 case Instruction::SHR_LONG:
1676 case Instruction::SHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001677 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1678 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001679 case Instruction::USHR_LONG:
1680 case Instruction::USHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001681 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1682 break;
1683 default:
1684 LOG(FATAL) << "Unexpected case";
1685 return true;
1686 }
1687 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001688 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001689 RegLocation rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001690 storeValueWide(cUnit, rlDest, rlResult);
1691 return false;
1692}
1693
1694
1695bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1696 RegLocation rlSrc1, RegLocation rlSrc2)
1697{
1698 OpKind op = kOpBkpt;
1699 bool callOut = false;
1700 bool checkZero = false;
1701 bool unary = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001702 RegLocation rlResult;
1703 bool shiftOp = false;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001704 int funcOffset;
1705 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08001706 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001707 case Instruction::NEG_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001708 op = kOpNeg;
1709 unary = true;
1710 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001711 case Instruction::NOT_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001712 op = kOpMvn;
1713 unary = true;
1714 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001715 case Instruction::ADD_INT:
1716 case Instruction::ADD_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001717 op = kOpAdd;
1718 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001719 case Instruction::SUB_INT:
1720 case Instruction::SUB_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001721 op = kOpSub;
1722 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001723 case Instruction::MUL_INT:
1724 case Instruction::MUL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001725 op = kOpMul;
1726 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001727 case Instruction::DIV_INT:
1728 case Instruction::DIV_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001729 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001730 op = kOpDiv;
1731 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001732 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1733 retReg = rRET0;
1734 break;
buzbee5de34942012-03-01 14:51:57 -08001735 /* NOTE: returns in rARG1 */
Elliott Hughesadb8c672012-03-06 16:49:32 -08001736 case Instruction::REM_INT:
1737 case Instruction::REM_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001738 checkZero = true;
Ian Rogersb5d09b22012-03-06 22:14:17 -08001739 op = kOpRem;
1740 callOut = true;
buzbee31a4a6f2012-02-28 15:36:15 -08001741 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1742 retReg = rRET1;
1743 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001744 case Instruction::AND_INT:
1745 case Instruction::AND_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001746 op = kOpAnd;
1747 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001748 case Instruction::OR_INT:
1749 case Instruction::OR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001750 op = kOpOr;
1751 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001752 case Instruction::XOR_INT:
1753 case Instruction::XOR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001754 op = kOpXor;
1755 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001756 case Instruction::SHL_INT:
1757 case Instruction::SHL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001758 shiftOp = true;
1759 op = kOpLsl;
1760 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001761 case Instruction::SHR_INT:
1762 case Instruction::SHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001763 shiftOp = true;
1764 op = kOpAsr;
1765 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001766 case Instruction::USHR_INT:
1767 case Instruction::USHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001768 shiftOp = true;
1769 op = kOpLsr;
1770 break;
1771 default:
1772 LOG(FATAL) << "Invalid word arith op: " <<
1773 (int)mir->dalvikInsn.opcode;
1774 }
1775 if (!callOut) {
1776 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1777 if (unary) {
1778 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1779 opRegReg(cUnit, op, rlResult.lowReg,
1780 rlSrc1.lowReg);
1781 } else {
1782 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001783#if defined(TARGET_X86)
1784 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1785 opRegRegReg(cUnit, op, rlResult.lowReg,
1786 rlSrc1.lowReg, rlSrc2.lowReg);
1787#else
buzbee31a4a6f2012-02-28 15:36:15 -08001788 if (shiftOp) {
1789 int tReg = oatAllocTemp(cUnit);
1790 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1791 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1792 opRegRegReg(cUnit, op, rlResult.lowReg,
1793 rlSrc1.lowReg, tReg);
1794 oatFreeTemp(cUnit, tReg);
1795 } else {
1796 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1797 opRegRegReg(cUnit, op, rlResult.lowReg,
1798 rlSrc1.lowReg, rlSrc2.lowReg);
1799 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001800#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001801 }
1802 storeValue(cUnit, rlDest, rlResult);
1803 } else {
1804 RegLocation rlResult;
1805 oatFlushAllRegs(cUnit); /* Send everything to home location */
1806 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001807#if !defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -08001808 int rTgt = loadHelper(cUnit, funcOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001809#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001810 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1811 if (checkZero) {
1812 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1813 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07001814#if !defined(TARGET_X86)
1815 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001816 oatFreeTemp(cUnit, rTgt);
1817#else
Ian Rogersab2b55d2012-03-18 00:06:11 -07001818 opThreadMem(cUnit, kOpBlx, funcOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001819#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001820 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001821 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001822 else
1823 rlResult = oatGetReturnAlt(cUnit);
1824 storeValue(cUnit, rlDest, rlResult);
1825 }
1826 return false;
1827}
1828
1829/*
1830 * The following are the first-level codegen routines that analyze the format
1831 * of each bytecode then either dispatch special purpose codegen routines
1832 * or produce corresponding Thumb instructions directly.
1833 */
1834
1835bool isPowerOfTwo(int x)
1836{
1837 return (x & (x - 1)) == 0;
1838}
1839
1840// Returns true if no more than two bits are set in 'x'.
1841bool isPopCountLE2(unsigned int x)
1842{
1843 x &= x - 1;
1844 return (x & (x - 1)) == 0;
1845}
1846
1847// Returns the index of the lowest set bit in 'x'.
1848int lowestSetBit(unsigned int x) {
1849 int bit_posn = 0;
1850 while ((x & 0xf) == 0) {
1851 bit_posn += 4;
1852 x >>= 4;
1853 }
1854 while ((x & 1) == 0) {
1855 bit_posn++;
1856 x >>= 1;
1857 }
1858 return bit_posn;
1859}
1860
1861// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1862// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001863bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
buzbee31a4a6f2012-02-28 15:36:15 -08001864 RegLocation rlSrc, RegLocation rlDest, int lit)
1865{
1866 if (lit < 2 || !isPowerOfTwo(lit)) {
1867 return false;
1868 }
1869 int k = lowestSetBit(lit);
1870 if (k >= 30) {
1871 // Avoid special cases.
1872 return false;
1873 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001874 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1875 dalvikOpcode == Instruction::DIV_INT_LIT16);
buzbee31a4a6f2012-02-28 15:36:15 -08001876 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1877 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1878 if (div) {
1879 int tReg = oatAllocTemp(cUnit);
1880 if (lit == 2) {
1881 // Division by 2 is by far the most common division by constant.
1882 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1883 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1884 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1885 } else {
1886 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1887 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1888 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1889 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1890 }
1891 } else {
1892 int cReg = oatAllocTemp(cUnit);
1893 loadConstant(cUnit, cReg, lit - 1);
1894 int tReg1 = oatAllocTemp(cUnit);
1895 int tReg2 = oatAllocTemp(cUnit);
1896 if (lit == 2) {
1897 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1898 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1899 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1900 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1901 } else {
1902 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1903 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1904 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1905 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1906 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1907 }
1908 }
1909 storeValue(cUnit, rlDest, rlResult);
1910 return true;
1911}
1912
1913void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1914 RegLocation rlResult, int lit,
1915 int firstBit, int secondBit)
1916{
buzbee0398c422012-03-02 15:22:47 -08001917#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001918 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1919 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001920#else
1921 int tReg = oatAllocTemp(cUnit);
1922 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1923 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1924 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001925#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001926 if (firstBit != 0) {
1927 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1928 }
1929}
1930
1931// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1932// and store the result in 'rlDest'.
1933bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1934 RegLocation rlDest, int lit)
1935{
1936 // Can we simplify this multiplication?
1937 bool powerOfTwo = false;
1938 bool popCountLE2 = false;
1939 bool powerOfTwoMinusOne = false;
1940 if (lit < 2) {
1941 // Avoid special cases.
1942 return false;
1943 } else if (isPowerOfTwo(lit)) {
1944 powerOfTwo = true;
1945 } else if (isPopCountLE2(lit)) {
1946 popCountLE2 = true;
1947 } else if (isPowerOfTwo(lit + 1)) {
1948 powerOfTwoMinusOne = true;
1949 } else {
1950 return false;
1951 }
1952 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1953 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1954 if (powerOfTwo) {
1955 // Shift.
1956 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1957 lowestSetBit(lit));
1958 } else if (popCountLE2) {
1959 // Shift and add and shift.
1960 int firstBit = lowestSetBit(lit);
1961 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1962 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1963 firstBit, secondBit);
1964 } else {
1965 // Reverse subtract: (src << (shift + 1)) - src.
1966 DCHECK(powerOfTwoMinusOne);
1967 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1968 int tReg = oatAllocTemp(cUnit);
1969 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1970 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1971 }
1972 storeValue(cUnit, rlDest, rlResult);
1973 return true;
1974}
1975
1976bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1977 RegLocation rlSrc, int lit)
1978{
Elliott Hughesadb8c672012-03-06 16:49:32 -08001979 Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08001980 RegLocation rlResult;
1981 OpKind op = (OpKind)0; /* Make gcc happy */
1982 int shiftOp = false;
1983 bool isDiv = false;
1984 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001985
1986 switch (dalvikOpcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001987 case Instruction::RSUB_INT_LIT8:
1988 case Instruction::RSUB_INT: {
buzbee31a4a6f2012-02-28 15:36:15 -08001989 int tReg;
1990 //TUNING: add support for use of Arm rsub op
1991 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1992 tReg = oatAllocTemp(cUnit);
1993 loadConstant(cUnit, tReg, lit);
1994 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1995 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1996 tReg, rlSrc.lowReg);
1997 storeValue(cUnit, rlDest, rlResult);
1998 return false;
1999 break;
2000 }
2001
Elliott Hughesadb8c672012-03-06 16:49:32 -08002002 case Instruction::ADD_INT_LIT8:
2003 case Instruction::ADD_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002004 op = kOpAdd;
2005 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002006 case Instruction::MUL_INT_LIT8:
2007 case Instruction::MUL_INT_LIT16: {
buzbee31a4a6f2012-02-28 15:36:15 -08002008 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2009 return false;
2010 }
2011 op = kOpMul;
2012 break;
2013 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08002014 case Instruction::AND_INT_LIT8:
2015 case Instruction::AND_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002016 op = kOpAnd;
2017 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002018 case Instruction::OR_INT_LIT8:
2019 case Instruction::OR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002020 op = kOpOr;
2021 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002022 case Instruction::XOR_INT_LIT8:
2023 case Instruction::XOR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002024 op = kOpXor;
2025 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002026 case Instruction::SHL_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08002027 lit &= 31;
2028 shiftOp = true;
2029 op = kOpLsl;
2030 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002031 case Instruction::SHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08002032 lit &= 31;
2033 shiftOp = true;
2034 op = kOpAsr;
2035 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002036 case Instruction::USHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08002037 lit &= 31;
2038 shiftOp = true;
2039 op = kOpLsr;
2040 break;
2041
Elliott Hughesadb8c672012-03-06 16:49:32 -08002042 case Instruction::DIV_INT_LIT8:
2043 case Instruction::DIV_INT_LIT16:
2044 case Instruction::REM_INT_LIT8:
2045 case Instruction::REM_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08002046 if (lit == 0) {
2047 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
2048 return false;
2049 }
2050 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2051 return false;
2052 }
2053 oatFlushAllRegs(cUnit); /* Everything to home location */
2054 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2055 oatClobber(cUnit, rARG0);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002056 if ((dalvikOpcode == Instruction::DIV_INT_LIT8) ||
2057 (dalvikOpcode == Instruction::DIV_INT_LIT16)) {
buzbee31a4a6f2012-02-28 15:36:15 -08002058 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2059 isDiv = true;
2060 } else {
2061 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2062 isDiv = false;
2063 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07002064 callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit);
buzbee31a4a6f2012-02-28 15:36:15 -08002065 if (isDiv)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002066 rlResult = oatGetReturn(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002067 else
2068 rlResult = oatGetReturnAlt(cUnit);
2069 storeValue(cUnit, rlDest, rlResult);
2070 return false;
2071 break;
2072 default:
2073 return true;
2074 }
2075 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2076 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2077 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2078 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08002079 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002080 } else {
2081 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2082 }
2083 storeValue(cUnit, rlDest, rlResult);
2084 return false;
2085}
2086
2087bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
2088 RegLocation rlSrc1, RegLocation rlSrc2)
2089{
2090 RegLocation rlResult;
2091 OpKind firstOp = kOpBkpt;
2092 OpKind secondOp = kOpBkpt;
2093 bool callOut = false;
2094 bool checkZero = false;
2095 int funcOffset;
2096 int retReg = rRET0;
2097
2098 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002099 case Instruction::NOT_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002100 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2101 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2102 // Check for destructive overlap
2103 if (rlResult.lowReg == rlSrc2.highReg) {
2104 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08002105 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08002106 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2107 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2108 oatFreeTemp(cUnit, tReg);
2109 } else {
2110 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2111 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2112 }
2113 storeValueWide(cUnit, rlDest, rlResult);
2114 return false;
2115 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002116 case Instruction::ADD_LONG:
2117 case Instruction::ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002118#if defined(TARGET_MIPS)
2119 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2120#else
buzbee31a4a6f2012-02-28 15:36:15 -08002121 firstOp = kOpAdd;
2122 secondOp = kOpAdc;
2123 break;
buzbeec5159d52012-03-03 11:48:39 -08002124#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002125 case Instruction::SUB_LONG:
2126 case Instruction::SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08002127#if defined(TARGET_MIPS)
2128 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
2129#else
buzbee31a4a6f2012-02-28 15:36:15 -08002130 firstOp = kOpSub;
2131 secondOp = kOpSbc;
2132 break;
buzbeec5159d52012-03-03 11:48:39 -08002133#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08002134 case Instruction::MUL_LONG:
2135 case Instruction::MUL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002136 callOut = true;
2137 retReg = rRET0;
2138 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
2139 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002140 case Instruction::DIV_LONG:
2141 case Instruction::DIV_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002142 callOut = true;
2143 checkZero = true;
2144 retReg = rRET0;
2145 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2146 break;
2147 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2148 // FIXME: is true, or could be made true, or other targets?
Elliott Hughesadb8c672012-03-06 16:49:32 -08002149 case Instruction::REM_LONG:
2150 case Instruction::REM_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002151 callOut = true;
2152 checkZero = true;
2153 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
2154 retReg = rARG2;
2155 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002156 case Instruction::AND_LONG_2ADDR:
2157 case Instruction::AND_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002158 firstOp = kOpAnd;
2159 secondOp = kOpAnd;
2160 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002161 case Instruction::OR_LONG:
2162 case Instruction::OR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002163 firstOp = kOpOr;
2164 secondOp = kOpOr;
2165 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002166 case Instruction::XOR_LONG:
2167 case Instruction::XOR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08002168 firstOp = kOpXor;
2169 secondOp = kOpXor;
2170 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002171 case Instruction::NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08002172 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002173 }
2174 default:
2175 LOG(FATAL) << "Invalid long arith op";
2176 }
2177 if (!callOut) {
2178 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
2179 } else {
buzbee31a4a6f2012-02-28 15:36:15 -08002180 oatFlushAllRegs(cUnit); /* Send everything to home location */
2181 if (checkZero) {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002182#if defined(TARGET_X86)
2183 UNIMPLEMENTED(FATAL);
2184#else
buzbee31a4a6f2012-02-28 15:36:15 -08002185 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
Ian Rogersab2b55d2012-03-18 00:06:11 -07002186 int rTgt = loadHelper(cUnit, funcOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002187#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002188 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2189 int tReg = oatAllocTemp(cUnit);
2190#if defined(TARGET_ARM)
2191 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2192 oatFreeTemp(cUnit, tReg);
2193 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
2194#else
Ian Rogersb5d09b22012-03-06 22:14:17 -08002195#if defined(TARGET_X86)
2196 UNIMPLEMENTED(FATAL);
2197#else
buzbee31a4a6f2012-02-28 15:36:15 -08002198 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002199#endif
buzbee5de34942012-03-01 14:51:57 -08002200 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08002201 oatFreeTemp(cUnit, tReg);
2202#endif
Ian Rogersab2b55d2012-03-18 00:06:11 -07002203#if !defined(TARGET_X86)
2204 opReg(cUnit, kOpBlx, rTgt);
2205 oatFreeTemp(cUnit, rTgt);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002206#endif
Ian Rogersab2b55d2012-03-18 00:06:11 -07002207 } else {
2208 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset,
2209 rlSrc1, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002210 }
buzbee31a4a6f2012-02-28 15:36:15 -08002211 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2212 if (retReg == rRET0)
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002213 rlResult = oatGetReturnWide(cUnit, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002214 else
2215 rlResult = oatGetReturnWideAlt(cUnit);
2216 storeValueWide(cUnit, rlDest, rlResult);
2217 }
2218 return false;
2219}
2220
2221bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
2222 int srcSize, int tgtSize)
2223{
2224 /*
2225 * Don't optimize the register usage since it calls out to support
2226 * functions
2227 */
2228 RegLocation rlSrc;
2229 RegLocation rlDest;
2230 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee31a4a6f2012-02-28 15:36:15 -08002231 if (srcSize == 1) {
2232 rlSrc = oatGetSrc(cUnit, mir, 0);
2233 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2234 } else {
2235 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
2236 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
2237 }
Ian Rogersab2b55d2012-03-18 00:06:11 -07002238 callRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc);
buzbee31a4a6f2012-02-28 15:36:15 -08002239 if (tgtSize == 1) {
2240 RegLocation rlResult;
2241 rlDest = oatGetDest(cUnit, mir, 0);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002242 rlResult = oatGetReturn(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002243 storeValue(cUnit, rlDest, rlResult);
2244 } else {
2245 RegLocation rlResult;
2246 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002247 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
buzbee31a4a6f2012-02-28 15:36:15 -08002248 storeValueWide(cUnit, rlDest, rlResult);
2249 }
2250 return false;
2251}
2252
2253void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
2254bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
2255 RegLocation rlDest, RegLocation rlSrc1,
2256 RegLocation rlSrc2)
2257{
2258 RegLocation rlResult;
2259 int funcOffset;
2260
2261 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002262 case Instruction::ADD_FLOAT_2ADDR:
2263 case Instruction::ADD_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002264 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
2265 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002266 case Instruction::SUB_FLOAT_2ADDR:
2267 case Instruction::SUB_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002268 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
2269 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002270 case Instruction::DIV_FLOAT_2ADDR:
2271 case Instruction::DIV_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002272 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
2273 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002274 case Instruction::MUL_FLOAT_2ADDR:
2275 case Instruction::MUL_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002276 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
2277 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002278 case Instruction::REM_FLOAT_2ADDR:
2279 case Instruction::REM_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002280 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
2281 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002282 case Instruction::NEG_FLOAT: {
buzbee31a4a6f2012-02-28 15:36:15 -08002283 genNegFloat(cUnit, rlDest, rlSrc1);
2284 return false;
2285 }
2286 default:
2287 return true;
2288 }
2289 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogersab2b55d2012-03-18 00:06:11 -07002290 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002291 rlResult = oatGetReturn(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002292 storeValue(cUnit, rlDest, rlResult);
2293 return false;
2294}
2295
2296void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
2297bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
2298 RegLocation rlDest, RegLocation rlSrc1,
2299 RegLocation rlSrc2)
2300{
2301 RegLocation rlResult;
2302 int funcOffset;
2303
2304 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002305 case Instruction::ADD_DOUBLE_2ADDR:
2306 case Instruction::ADD_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002307 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
2308 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002309 case Instruction::SUB_DOUBLE_2ADDR:
2310 case Instruction::SUB_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002311 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
2312 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002313 case Instruction::DIV_DOUBLE_2ADDR:
2314 case Instruction::DIV_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002315 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2316 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002317 case Instruction::MUL_DOUBLE_2ADDR:
2318 case Instruction::MUL_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002319 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2320 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002321 case Instruction::REM_DOUBLE_2ADDR:
2322 case Instruction::REM_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002323 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2324 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002325 case Instruction::NEG_DOUBLE: {
buzbee31a4a6f2012-02-28 15:36:15 -08002326 genNegDouble(cUnit, rlDest, rlSrc1);
2327 return false;
2328 }
2329 default:
2330 return true;
2331 }
2332 oatFlushAllRegs(cUnit); /* Send everything to home location */
Ian Rogersab2b55d2012-03-18 00:06:11 -07002333 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
Ian Rogersf7d9ad32012-03-13 18:45:39 -07002334 rlResult = oatGetReturnWide(cUnit, true);
buzbee31a4a6f2012-02-28 15:36:15 -08002335 storeValueWide(cUnit, rlDest, rlResult);
2336 return false;
2337}
2338
2339bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2340{
Elliott Hughesadb8c672012-03-06 16:49:32 -08002341 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08002342
2343 switch (opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002344 case Instruction::INT_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002345 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2346 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002347 case Instruction::FLOAT_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002348 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2349 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002350 case Instruction::DOUBLE_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002351 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2352 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002353 case Instruction::FLOAT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002354 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2355 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002356 case Instruction::INT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002357 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2358 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002359 case Instruction::DOUBLE_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002360 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2361 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002362 case Instruction::FLOAT_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002363 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2364 pF2l), 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002365 case Instruction::LONG_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002366 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2367 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002368 case Instruction::DOUBLE_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002369 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2370 pD2l), 2, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002371 case Instruction::LONG_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002372 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2373 2, 2);
2374 default:
2375 return true;
2376 }
2377 return false;
2378}
2379
2380/*
2381 * Generate callout to updateDebugger. Note that we're overloading
2382 * the use of rSUSPEND here. When the debugger is active, this
2383 * register holds the address of the update function. So, if it's
2384 * non-null, we call out to it.
2385 *
2386 * Note also that rRET0 and rRET1 must be preserved across this
2387 * code. This must be handled by the stub.
2388 */
2389void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2390{
2391 // Following DCHECK verifies that dPC is in range of single load immediate
2392 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2393 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2394 oatClobberCalleeSave(cUnit);
2395#if defined(TARGET_ARM)
2396 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002397 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002398 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2399 opReg(cUnit, kOpBlx, rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002400#elif defined(TARGET_X86)
2401 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002402#else
buzbee82488f52012-03-02 08:20:26 -08002403 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002404 loadConstant(cUnit, rARG2, offset);
2405 opReg(cUnit, kOpBlx, rSUSPEND);
2406 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002407 branch->target = (LIR*)target;
2408#endif
2409 oatFreeTemp(cUnit, rARG2);
2410}
2411
2412/* Check if we need to check for pending suspend request */
2413void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2414{
2415 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2416 return;
2417 }
2418 oatFlushAllRegs(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002419 if (cUnit->genDebugger) {
2420 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002421#if defined(TARGET_X86)
2422 UNIMPLEMENTED(FATAL);
2423#else
buzbee86a4bce2012-03-06 18:15:00 -08002424 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
2425 pTestSuspendFromCode));
2426 opReg(cUnit, kOpBlx, rTgt);
2427 // Refresh rSUSPEND
2428 loadWordDisp(cUnit, rSELF,
2429 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
2430 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002431#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002432 } else {
Ian Rogersb5d09b22012-03-06 22:14:17 -08002433 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002434#if defined(TARGET_ARM)
2435 // In non-debug case, only check periodically
2436 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002437 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002438#elif defined(TARGET_X86)
2439 newLIR2(cUnit, kX86Cmp32TI, Thread::SuspendCountOffset().Int32Value(), 0);
2440 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002441#else
2442 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002443 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002444#endif
buzbee86a4bce2012-03-06 18:15:00 -08002445 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2446 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2447 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
2448 branch->target = (LIR*)target;
2449 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
buzbee31a4a6f2012-02-28 15:36:15 -08002450 }
buzbee31a4a6f2012-02-28 15:36:15 -08002451}
2452
2453} // namespace art