blob: c9ba285c5f89dba9b998f5389e79c9d6d1cd2fdf [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
Ian Rogers57b86d42012-03-27 16:05:41 -070017#include "oat/runtime/oat_support_entrypoints.h"
18
buzbee31a4a6f2012-02-28 15:36:15 -080019namespace art {
20
21/*
22 * This source files contains "gen" codegen routines that should
23 * be applicable to most targets. Only mid-level support utilities
24 * and "op" calls may be used here.
25 */
buzbeefc9e6fa2012-03-23 15:14:29 -070026void genInvoke(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
Bill Buzbeea114add2012-05-03 15:00:40 -070027 InvokeType type, bool isRange);
buzbee31a4a6f2012-02-28 15:36:15 -080028#if defined(TARGET_ARM)
buzbee82488f52012-03-02 08:20:26 -080029LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide);
buzbeef3aac972012-04-11 16:33:36 -070030bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
31 RegLocation rlSrc, RegLocation rlDest, int lit);
buzbee31a4a6f2012-02-28 15:36:15 -080032#endif
33
Ian Rogersab2b55d2012-03-18 00:06:11 -070034void callRuntimeHelperImm(CompilationUnit* cUnit, int helperOffset, int arg0) {
35#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070036 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070037#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070038 loadConstant(cUnit, rARG0, arg0);
39 oatClobberCalleeSave(cUnit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070040#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070041 opReg(cUnit, kOpBlx, rTgt);
42 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070043#else
Bill Buzbeea114add2012-05-03 15:00:40 -070044 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070045#endif
46}
47
Ian Rogers7caad772012-03-30 01:07:54 -070048void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0) {
49#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070050 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogers7caad772012-03-30 01:07:54 -070051#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070052 opRegCopy(cUnit, rARG0, arg0);
53 oatClobberCalleeSave(cUnit);
Ian Rogers7caad772012-03-30 01:07:54 -070054#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070055 opReg(cUnit, kOpBlx, rTgt);
56 oatFreeTemp(cUnit, rTgt);
Ian Rogers7caad772012-03-30 01:07:54 -070057#else
Bill Buzbeea114add2012-05-03 15:00:40 -070058 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogers7caad772012-03-30 01:07:54 -070059#endif
60}
61
Ian Rogersab2b55d2012-03-18 00:06:11 -070062void callRuntimeHelperRegLocation(CompilationUnit* cUnit, int helperOffset,
63 RegLocation arg0) {
64#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070065 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070066#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070067 if (arg0.wide == 0) {
68 loadValueDirectFixed(cUnit, arg0, rARG0);
69 } else {
70 loadValueDirectWideFixed(cUnit, arg0, rARG0, rARG1);
71 }
72 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -070073#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070074 opReg(cUnit, kOpBlx, rTgt);
75 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -070076#else
Bill Buzbeea114add2012-05-03 15:00:40 -070077 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070078#endif
79}
80
81void callRuntimeHelperImmImm(CompilationUnit* cUnit, int helperOffset,
82 int arg0, int arg1) {
83#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070084 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070085#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070086 loadConstant(cUnit, rARG0, arg0);
87 loadConstant(cUnit, rARG1, arg1);
88 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -070089#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070090 opReg(cUnit, kOpBlx, rTgt);
91 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -070092#else
Bill Buzbeea114add2012-05-03 15:00:40 -070093 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070094#endif
95}
96
97void callRuntimeHelperImmRegLocation(CompilationUnit* cUnit, int helperOffset,
98 int arg0, RegLocation arg1) {
99#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700100 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700101#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700102 if (arg1.wide == 0) {
103 loadValueDirectFixed(cUnit, arg1, rARG1);
104 } else {
105 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
106 }
107 loadConstant(cUnit, rARG0, arg0);
108 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700109#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700110 opReg(cUnit, kOpBlx, rTgt);
111 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700112#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700113 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700114#endif
115}
116
117void callRuntimeHelperRegLocationImm(CompilationUnit* cUnit, int helperOffset,
118 RegLocation arg0, int arg1) {
119#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700120 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700121#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700122 loadValueDirectFixed(cUnit, arg0, rARG0);
123 loadConstant(cUnit, rARG1, arg1);
124 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700125#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700126 opReg(cUnit, kOpBlx, rTgt);
127 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700128#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700130#endif
131}
132
133void callRuntimeHelperImmReg(CompilationUnit* cUnit, int helperOffset,
134 int arg0, int arg1) {
135#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700136 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700137#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700138 opRegCopy(cUnit, rARG1, arg1);
139 loadConstant(cUnit, rARG0, arg0);
140 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700141#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700142 opReg(cUnit, kOpBlx, rTgt);
143 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700144#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700145 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700146#endif
147}
148
149void callRuntimeHelperRegImm(CompilationUnit* cUnit, int helperOffset,
150 int arg0, int arg1) {
151#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700153#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700154 opRegCopy(cUnit, rARG0, arg0);
155 loadConstant(cUnit, rARG1, arg1);
156 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700157#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700158 opReg(cUnit, kOpBlx, rTgt);
159 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700160#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700161 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700162#endif
163}
164
165void callRuntimeHelperImmMethod(CompilationUnit* cUnit, int helperOffset,
166 int arg0) {
167#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700168 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700169#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700170 loadCurrMethodDirect(cUnit, rARG1);
171 loadConstant(cUnit, rARG0, arg0);
172 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700173#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 opReg(cUnit, kOpBlx, rTgt);
175 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700176#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700177 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700178#endif
179}
180
181void callRuntimeHelperRegLocationRegLocation(CompilationUnit* cUnit,
182 int helperOffset,
183 RegLocation arg0,
184 RegLocation arg1) {
185#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700186 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700187#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700188 if (arg0.wide == 0) {
189 loadValueDirectFixed(cUnit, arg0, rARG0);
190 if (arg1.wide == 0) {
191 loadValueDirectFixed(cUnit, arg1, rARG1);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700192 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700193 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700194 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700195 } else {
196 loadValueDirectWideFixed(cUnit, arg0, rARG0, rARG1);
197 if (arg1.wide == 0) {
198 loadValueDirectFixed(cUnit, arg1, rARG2);
199 } else {
200 loadValueDirectWideFixed(cUnit, arg1, rARG2, rARG3);
201 }
202 }
203 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700204#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700205 opReg(cUnit, kOpBlx, rTgt);
206 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700207#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700208 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700209#endif
210}
211
212void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset,
213 int arg0, int arg1) {
214#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700215 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700216#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700217 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
218 opRegCopy(cUnit, rARG0, arg0);
219 opRegCopy(cUnit, rARG1, arg1);
220 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700221#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700222 opReg(cUnit, kOpBlx, rTgt);
223 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700224#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700225 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700226#endif
227}
228
229void callRuntimeHelperRegRegImm(CompilationUnit* cUnit, int helperOffset,
230 int arg0, int arg1, int arg2) {
231#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700232 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700233#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700234 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
235 opRegCopy(cUnit, rARG0, arg0);
236 opRegCopy(cUnit, rARG1, arg1);
237 loadConstant(cUnit, rARG2, arg2);
238 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700239#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700240 opReg(cUnit, kOpBlx, rTgt);
241 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700242#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700243 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700244#endif
245}
246
Bill Buzbeea114add2012-05-03 15:00:40 -0700247void callRuntimeHelperImmMethodRegLocation(CompilationUnit* cUnit,
248 int helperOffset,
249 int arg0, RegLocation arg2) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700250#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700252#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 loadValueDirectFixed(cUnit, arg2, rARG2);
254 loadCurrMethodDirect(cUnit, rARG1);
255 loadConstant(cUnit, rARG0, arg0);
256 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700257#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 opReg(cUnit, kOpBlx, rTgt);
259 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700260#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700261 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700262#endif
263}
264
265void callRuntimeHelperImmMethodImm(CompilationUnit* cUnit, int helperOffset,
266 int arg0, int arg2) {
267#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700268 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700269#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700270 loadCurrMethodDirect(cUnit, rARG1);
271 loadConstant(cUnit, rARG2, arg2);
272 loadConstant(cUnit, rARG0, arg0);
273 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700274#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 opReg(cUnit, kOpBlx, rTgt);
276 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700277#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700278 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700279#endif
280}
281
282void callRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cUnit,
283 int helperOffset,
284 int arg0, RegLocation arg1,
285 RegLocation arg2) {
286#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700287 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700288#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700289 loadValueDirectFixed(cUnit, arg1, rARG1);
290 if (arg2.wide == 0) {
291 loadValueDirectFixed(cUnit, arg2, rARG2);
292 } else {
293 loadValueDirectWideFixed(cUnit, arg2, rARG2, rARG3);
294 }
295 loadConstant(cUnit, rARG0, arg0);
296 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700297#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700298 opReg(cUnit, kOpBlx, rTgt);
299 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700300#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700301 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700302#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800303}
304
305/*
306 * Generate an kPseudoBarrier marker to indicate the boundary of special
307 * blocks.
308 */
309void genBarrier(CompilationUnit* cUnit)
310{
Bill Buzbeea114add2012-05-03 15:00:40 -0700311 LIR* barrier = newLIR0(cUnit, kPseudoBarrier);
312 /* Mark all resources as being clobbered */
313 barrier->defMask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800314}
315
buzbee31a4a6f2012-02-28 15:36:15 -0800316
317/* Generate unconditional branch instructions */
buzbee82488f52012-03-02 08:20:26 -0800318LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -0800319{
Bill Buzbeea114add2012-05-03 15:00:40 -0700320 LIR* branch = opBranchUnconditional(cUnit, kOpUncondBr);
321 branch->target = (LIR*) target;
322 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800323}
324
buzbee5de34942012-03-01 14:51:57 -0800325// FIXME: need to do some work to split out targets with
326// condition codes and those without
327#if defined(TARGET_ARM) || defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -0800328LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, MIR* mir,
329 ThrowKind kind)
330{
Bill Buzbeea114add2012-05-03 15:00:40 -0700331 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
332 mir ? mir->offset : 0);
333 LIR* branch = opCondBranch(cUnit, cCode, tgt);
334 // Remember branch target - will process later
335 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
336 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800337}
buzbee5de34942012-03-01 14:51:57 -0800338#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800339
340LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
341 int reg, int immVal, MIR* mir, ThrowKind kind)
342{
Bill Buzbeea114add2012-05-03 15:00:40 -0700343 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, mir->offset);
344 LIR* branch;
345 if (cCode == kCondAl) {
346 branch = opUnconditionalBranch(cUnit, tgt);
347 } else {
348 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
349 }
350 // Remember branch target - will process later
351 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
352 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800353}
354
355/* Perform null-check on a register. */
356LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir)
357{
Bill Buzbeea114add2012-05-03 15:00:40 -0700358 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
359 mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
360 return NULL;
361 }
362 return genImmedCheck(cUnit, kCondEq, mReg, 0, mir, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -0800363}
364
365/* Perform check on two registers */
366LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
Bill Buzbeea114add2012-05-03 15:00:40 -0700367 int reg1, int reg2, MIR* mir, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800368{
Bill Buzbeea114add2012-05-03 15:00:40 -0700369 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
370 mir ? mir->offset : 0, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800371#if defined(TARGET_MIPS)
Bill Buzbeea114add2012-05-03 15:00:40 -0700372 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800373#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700374 opRegReg(cUnit, kOpCmp, reg1, reg2);
375 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800376#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700377 // Remember branch target - will process later
378 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
379 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800380}
381
382void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
383 RegLocation rlSrc1, RegLocation rlSrc2, LIR* labelList)
384{
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 ConditionCode cond;
386 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
387 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
388 Instruction::Code opcode = mir->dalvikInsn.opcode;
389 switch (opcode) {
390 case Instruction::IF_EQ:
391 cond = kCondEq;
392 break;
393 case Instruction::IF_NE:
394 cond = kCondNe;
395 break;
396 case Instruction::IF_LT:
397 cond = kCondLt;
398 break;
399 case Instruction::IF_GE:
400 cond = kCondGe;
401 break;
402 case Instruction::IF_GT:
403 cond = kCondGt;
404 break;
405 case Instruction::IF_LE:
406 cond = kCondLe;
407 break;
408 default:
409 cond = (ConditionCode)0;
410 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
411 }
buzbee5de34942012-03-01 14:51:57 -0800412#if defined(TARGET_MIPS)
Bill Buzbeea114add2012-05-03 15:00:40 -0700413 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg,
414 &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800415#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700416 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
417 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800418#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700419 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800420}
421
422void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
423 RegLocation rlSrc, LIR* labelList)
424{
Bill Buzbeea114add2012-05-03 15:00:40 -0700425 ConditionCode cond;
426 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
427 Instruction::Code opcode = mir->dalvikInsn.opcode;
428 switch (opcode) {
429 case Instruction::IF_EQZ:
430 cond = kCondEq;
431 break;
432 case Instruction::IF_NEZ:
433 cond = kCondNe;
434 break;
435 case Instruction::IF_LTZ:
436 cond = kCondLt;
437 break;
438 case Instruction::IF_GEZ:
439 cond = kCondGe;
440 break;
441 case Instruction::IF_GTZ:
442 cond = kCondGt;
443 break;
444 case Instruction::IF_LEZ:
445 cond = kCondLe;
446 break;
447 default:
448 cond = (ConditionCode)0;
449 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
450 }
Ian Rogers7caad772012-03-30 01:07:54 -0700451#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700452 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800453#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700454 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
455 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800456#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700457 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800458}
459
460void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
461 RegLocation rlSrc)
462{
Bill Buzbeea114add2012-05-03 15:00:40 -0700463 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
464 if (rlSrc.location == kLocPhysReg) {
465 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
466 } else {
467 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
468 }
469 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
470 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800471}
472
473void genIntNarrowing(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
474 RegLocation rlSrc)
475{
Bill Buzbeea114add2012-05-03 15:00:40 -0700476 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
477 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
478 OpKind op = kOpInvalid;
479 switch (mir->dalvikInsn.opcode) {
480 case Instruction::INT_TO_BYTE:
481 op = kOp2Byte;
482 break;
483 case Instruction::INT_TO_SHORT:
484 op = kOp2Short;
485 break;
486 case Instruction::INT_TO_CHAR:
487 op = kOp2Char;
488 break;
489 default:
490 LOG(ERROR) << "Bad int conversion type";
491 }
492 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
493 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800494}
495
496/*
497 * Let helper function take care of everything. Will call
498 * Array::AllocFromCode(type_idx, method, count);
499 * Note: AllocFromCode will handle checks for errNegativeArraySize.
500 */
501void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
502 RegLocation rlSrc)
503{
Bill Buzbeea114add2012-05-03 15:00:40 -0700504 oatFlushAllRegs(cUnit); /* Everything to home location */
505 uint32_t type_idx = mir->dalvikInsn.vC;
506 int funcOffset;
507 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
508 cUnit->dex_cache,
509 *cUnit->dex_file,
510 type_idx)) {
511 funcOffset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
512 } else {
513 funcOffset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
514 }
515 callRuntimeHelperImmMethodRegLocation(cUnit, funcOffset, type_idx, rlSrc);
516 RegLocation rlResult = oatGetReturn(cUnit, false);
517 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800518}
519
520/*
521 * Similar to genNewArray, but with post-allocation initialization.
522 * Verifier guarantees we're dealing with an array class. Current
523 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
524 * Current code also throws internal unimp if not 'L', '[' or 'I'.
525 */
526void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
527{
Bill Buzbeea114add2012-05-03 15:00:40 -0700528 DecodedInstruction* dInsn = &mir->dalvikInsn;
529 int elems = dInsn->vA;
530 int typeIdx = dInsn->vB;
531 oatFlushAllRegs(cUnit); /* Everything to home location */
532 int funcOffset;
533 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
534 cUnit->dex_cache,
535 *cUnit->dex_file,
536 typeIdx)) {
537 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
538 } else {
539 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
540 }
541 callRuntimeHelperImmMethodImm(cUnit, funcOffset, typeIdx, elems);
542 oatFreeTemp(cUnit, rARG2);
543 oatFreeTemp(cUnit, rARG1);
544 /*
545 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
546 * return region. Because AllocFromCode placed the new array
547 * in rRET0, we'll just lock it into place. When debugger support is
548 * added, it may be necessary to additionally copy all return
549 * values to a home location in thread-local storage
550 */
551 oatLockTemp(cUnit, rRET0);
552
553 // TODO: use the correct component size, currently all supported types
554 // share array alignment with ints (see comment at head of function)
555 size_t component_size = sizeof(int32_t);
556
557 // Having a range of 0 is legal
558 if (isRange && (dInsn->vA > 0)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800559 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700560 * Bit of ugliness here. We're going generate a mem copy loop
561 * on the register range, but it is possible that some regs
562 * in the range have been promoted. This is unlikely, but
563 * before generating the copy, we'll just force a flush
564 * of any regs in the source range that have been promoted to
565 * home location.
buzbee31a4a6f2012-02-28 15:36:15 -0800566 */
Bill Buzbeea114add2012-05-03 15:00:40 -0700567 for (unsigned int i = 0; i < dInsn->vA; i++) {
568 RegLocation loc = oatUpdateLoc(cUnit, oatGetSrc(cUnit, mir, i));
569 if (loc.location == kLocPhysReg) {
570 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
571 loc.lowReg, kWord);
572 }
buzbee31a4a6f2012-02-28 15:36:15 -0800573 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700574 /*
575 * TUNING note: generated code here could be much improved, but
576 * this is an uncommon operation and isn't especially performance
577 * critical.
578 */
579 int rSrc = oatAllocTemp(cUnit);
580 int rDst = oatAllocTemp(cUnit);
581 int rIdx = oatAllocTemp(cUnit);
582#if defined(TARGET_ARM)
583 int rVal = rLR; // Using a lot of temps, rLR is known free here
584#elif defined(TARGET_X86)
585 int rVal = rSrc;
586#else
587 int rVal = oatAllocTemp(cUnit);
588#endif
589 // Set up source pointer
590 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
591 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
592 oatSRegOffset(cUnit, rlFirst.sRegLow));
593 // Set up the target pointer
594 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
595 Array::DataOffset(component_size).Int32Value());
596 // Set up the loop counter (known to be > 0)
597 loadConstant(cUnit, rIdx, dInsn->vA - 1);
598 // Generate the copy loop. Going backwards for convenience
599 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
600 // Copy next element
601 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
602 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
603#if defined(TARGET_ARM)
604 // Combine sub & test using sub setflags encoding here
605 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
606 opCondBranch(cUnit, kCondGe, target);
607#else
608 oatFreeTemp(cUnit, rVal);
609 opRegImm(cUnit, kOpSub, rIdx, 1);
610 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
611#endif
612 } else if (!isRange) {
613 // TUNING: interleave
614 for (unsigned int i = 0; i < dInsn->vA; i++) {
615 RegLocation rlArg = loadValue(cUnit, oatGetSrc(cUnit, mir, i), kCoreReg);
616 storeBaseDisp(cUnit, rRET0,
617 Array::DataOffset(component_size).Int32Value() +
618 i * 4, rlArg.lowReg, kWord);
619 // If the loadValue caused a temp to be allocated, free it
620 if (oatIsTemp(cUnit, rlArg.lowReg)) {
621 oatFreeTemp(cUnit, rlArg.lowReg);
622 }
623 }
624 }
buzbee31a4a6f2012-02-28 15:36:15 -0800625}
626
627void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
Bill Buzbeea114add2012-05-03 15:00:40 -0700628 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800629{
Bill Buzbeea114add2012-05-03 15:00:40 -0700630 int fieldOffset;
631 int ssbIndex;
632 bool isVolatile;
633 bool isReferrersClass;
634 uint32_t fieldIdx = mir->dalvikInsn.vB;
buzbee31a4a6f2012-02-28 15:36:15 -0800635
Bill Buzbeea114add2012-05-03 15:00:40 -0700636 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
637 *cUnit->dex_file, *cUnit->dex_cache,
638 cUnit->code_item, cUnit->method_idx,
639 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800640
Bill Buzbeea114add2012-05-03 15:00:40 -0700641 bool fastPath =
642 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
643 fieldOffset, ssbIndex,
644 isReferrersClass, isVolatile,
645 true);
646 if (fastPath && !SLOW_FIELD_PATH) {
647 DCHECK_GE(fieldOffset, 0);
648 int rBase;
649 if (isReferrersClass) {
650 // Fast path, static storage base is this method's class
651 RegLocation rlMethod = loadCurrMethod(cUnit);
652 rBase = oatAllocTemp(cUnit);
653 loadWordDisp(cUnit, rlMethod.lowReg,
654 Method::DeclaringClassOffset().Int32Value(), rBase);
655 if (oatIsTemp(cUnit, rlMethod.lowReg)) {
656 oatFreeTemp(cUnit, rlMethod.lowReg);
657 }
buzbee31a4a6f2012-02-28 15:36:15 -0800658 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700659 // Medium path, static storage base in a different class which
660 // requires checks that the other class is initialized.
661 DCHECK_GE(ssbIndex, 0);
662 // May do runtime call so everything to home locations.
663 oatFlushAllRegs(cUnit);
664 // Using fixed register to sync with possible call to runtime
665 // support.
666 int rMethod = rARG1;
667 oatLockTemp(cUnit, rMethod);
668 loadCurrMethodDirect(cUnit, rMethod);
669 rBase = rARG0;
670 oatLockTemp(cUnit, rBase);
671 loadWordDisp(cUnit, rMethod,
672 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
673 rBase);
674 loadWordDisp(cUnit, rBase,
675 Array::DataOffset(sizeof(Object*)).Int32Value() +
676 sizeof(int32_t*) * ssbIndex, rBase);
677 // rBase now points at appropriate static storage base (Class*)
678 // or NULL if not initialized. Check for NULL and call helper if NULL.
679 // TUNING: fast path should fall through
680 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
681 loadConstant(cUnit, rARG0, ssbIndex);
682 callRuntimeHelperImm(cUnit,
683 ENTRYPOINT_OFFSET(pInitializeStaticStorage),
684 ssbIndex);
685#if defined(TARGET_MIPS)
686 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
687 opRegCopy(cUnit, rBase, rRET0);
688#endif
689 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
690 branchOver->target = (LIR*)skipTarget;
691 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800692 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700693 // rBase now holds static storage base
694 if (isLongOrDouble) {
695 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
696 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
697 } else {
698 rlSrc = oatGetSrc(cUnit, mir, 0);
699 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
700 }
701//FIXME: need to generalize the barrier call
702 if (isVolatile) {
703 oatGenMemBarrier(cUnit, kST);
704 }
705 if (isLongOrDouble) {
706 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
707 rlSrc.highReg);
708 } else {
709 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
710 }
711 if (isVolatile) {
712 oatGenMemBarrier(cUnit, kSY);
713 }
714 if (isObject) {
715 markGCCard(cUnit, rlSrc.lowReg, rBase);
716 }
717 oatFreeTemp(cUnit, rBase);
718 } else {
719 oatFlushAllRegs(cUnit); // Everything to home locations
720 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Static) :
721 (isObject ? ENTRYPOINT_OFFSET(pSetObjStatic)
722 : ENTRYPOINT_OFFSET(pSet32Static));
723 callRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc);
724 }
buzbee31a4a6f2012-02-28 15:36:15 -0800725}
726
727void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700728 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800729{
Bill Buzbeea114add2012-05-03 15:00:40 -0700730 int fieldOffset;
731 int ssbIndex;
732 bool isVolatile;
733 bool isReferrersClass;
734 uint32_t fieldIdx = mir->dalvikInsn.vB;
buzbee31a4a6f2012-02-28 15:36:15 -0800735
Bill Buzbeea114add2012-05-03 15:00:40 -0700736 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
737 *cUnit->dex_file, *cUnit->dex_cache,
738 cUnit->code_item, cUnit->method_idx,
739 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800740
Bill Buzbeea114add2012-05-03 15:00:40 -0700741 bool fastPath =
742 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
743 fieldOffset, ssbIndex,
744 isReferrersClass, isVolatile,
745 false);
746 if (fastPath && !SLOW_FIELD_PATH) {
747 DCHECK_GE(fieldOffset, 0);
748 int rBase;
749 if (isReferrersClass) {
750 // Fast path, static storage base is this method's class
751 RegLocation rlMethod = loadCurrMethod(cUnit);
752 rBase = oatAllocTemp(cUnit);
753 loadWordDisp(cUnit, rlMethod.lowReg,
754 Method::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800755 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700756 // Medium path, static storage base in a different class which
757 // requires checks that the other class is initialized
758 DCHECK_GE(ssbIndex, 0);
759 // May do runtime call so everything to home locations.
760 oatFlushAllRegs(cUnit);
761 // Using fixed register to sync with possible call to runtime
762 // support
763 int rMethod = rARG1;
764 oatLockTemp(cUnit, rMethod);
765 loadCurrMethodDirect(cUnit, rMethod);
766 rBase = rARG0;
767 oatLockTemp(cUnit, rBase);
768 loadWordDisp(cUnit, rMethod,
769 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
770 rBase);
771 loadWordDisp(cUnit, rBase,
772 Array::DataOffset(sizeof(Object*)).Int32Value() +
773 sizeof(int32_t*) * ssbIndex, rBase);
774 // rBase now points at appropriate static storage base (Class*)
775 // or NULL if not initialized. Check for NULL and call helper if NULL.
776 // TUNING: fast path should fall through
777 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
778 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage),
779 ssbIndex);
780#if defined(TARGET_MIPS)
781 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
782 opRegCopy(cUnit, rBase, rRET0);
783#endif
784 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
785 branchOver->target = (LIR*)skipTarget;
786 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800787 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700788 // rBase now holds static storage base
789 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
790 : oatGetDest(cUnit, mir, 0);
791 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
792 if (isVolatile) {
793 oatGenMemBarrier(cUnit, kSY);
794 }
795 if (isLongOrDouble) {
796 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
797 rlResult.highReg, INVALID_SREG);
798 } else {
799 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
800 }
801 oatFreeTemp(cUnit, rBase);
802 if (isLongOrDouble) {
803 storeValueWide(cUnit, rlDest, rlResult);
804 } else {
805 storeValue(cUnit, rlDest, rlResult);
806 }
807 } else {
808 oatFlushAllRegs(cUnit); // Everything to home locations
809 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Static) :
810 (isObject ? ENTRYPOINT_OFFSET(pGetObjStatic)
811 : ENTRYPOINT_OFFSET(pGet32Static));
812 callRuntimeHelperImm(cUnit, getterOffset, fieldIdx);
813 if (isLongOrDouble) {
814 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
815 storeValueWide(cUnit, rlDest, rlResult);
816 } else {
817 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
818 storeValue(cUnit, rlDest, rlResult);
819 }
820 }
buzbee31a4a6f2012-02-28 15:36:15 -0800821}
822
823
824// Debugging routine - if null target, branch to DebugMe
825void genShowTarget(CompilationUnit* cUnit)
826{
buzbeea7678db2012-03-05 15:35:46 -0800827#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700828 UNIMPLEMENTED(WARNING) << "genShowTarget";
buzbeea7678db2012-03-05 15:35:46 -0800829#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700830 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
831 loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pDebugMe), rINVOKE_TGT);
832 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
833 branchOver->target = (LIR*)target;
buzbeea7678db2012-03-05 15:35:46 -0800834#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800835}
836
837void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
838{
Bill Buzbeea114add2012-05-03 15:00:40 -0700839 callRuntimeHelperImmImm(cUnit,
840 ENTRYPOINT_OFFSET(pThrowVerificationErrorFromCode),
841 mir->dalvikInsn.vA, mir->dalvikInsn.vB);
buzbee31a4a6f2012-02-28 15:36:15 -0800842}
843
844void handleSuspendLaunchpads(CompilationUnit *cUnit)
845{
Bill Buzbeea114add2012-05-03 15:00:40 -0700846 LIR** suspendLabel = (LIR **)cUnit->suspendLaunchpads.elemList;
847 int numElems = cUnit->suspendLaunchpads.numUsed;
848 for (int i = 0; i < numElems; i++) {
849 oatResetRegPool(cUnit);
850 oatResetDefTracking(cUnit);
851 LIR* lab = suspendLabel[i];
852 LIR* resumeLab = (LIR*)lab->operands[0];
853 cUnit->currentDalvikOffset = lab->operands[1];
854 oatAppendLIR(cUnit, lab);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700855#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700856 opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700857#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700858 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
859 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700860#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700861 opUnconditionalBranch(cUnit, resumeLab);
862 }
buzbee31a4a6f2012-02-28 15:36:15 -0800863}
864
buzbeefc9e6fa2012-03-23 15:14:29 -0700865void handleIntrinsicLaunchpads(CompilationUnit *cUnit)
866{
Bill Buzbeea114add2012-05-03 15:00:40 -0700867 LIR** intrinsicLabel = (LIR **)cUnit->intrinsicLaunchpads.elemList;
868 int numElems = cUnit->intrinsicLaunchpads.numUsed;
869 for (int i = 0; i < numElems; i++) {
870 oatResetRegPool(cUnit);
871 oatResetDefTracking(cUnit);
872 LIR* lab = intrinsicLabel[i];
873 MIR* mir = (MIR*)lab->operands[0];
874 InvokeType type = (InvokeType)lab->operands[1];
875 BasicBlock* bb = (BasicBlock*)lab->operands[3];
876 cUnit->currentDalvikOffset = mir->offset;
877 oatAppendLIR(cUnit, lab);
878 genInvoke(cUnit, bb, mir, type, false /* isRange */);
879 LIR* resumeLab = (LIR*)lab->operands[2];
880 if (resumeLab != NULL) {
881 opUnconditionalBranch(cUnit, resumeLab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700882 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700883 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700884}
885
buzbee31a4a6f2012-02-28 15:36:15 -0800886void handleThrowLaunchpads(CompilationUnit *cUnit)
887{
Bill Buzbeea114add2012-05-03 15:00:40 -0700888 LIR** throwLabel = (LIR **)cUnit->throwLaunchpads.elemList;
889 int numElems = cUnit->throwLaunchpads.numUsed;
890 for (int i = 0; i < numElems; i++) {
891 oatResetRegPool(cUnit);
892 oatResetDefTracking(cUnit);
893 LIR* lab = throwLabel[i];
894 cUnit->currentDalvikOffset = lab->operands[1];
895 oatAppendLIR(cUnit, lab);
896 int funcOffset = 0;
897 int v1 = lab->operands[2];
898 int v2 = lab->operands[3];
899 switch (lab->operands[0]) {
900 case kThrowNullPointer:
901 funcOffset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
902 break;
903 case kThrowArrayBounds:
904 if (v2 != rARG0) {
905 opRegCopy(cUnit, rARG0, v1);
906 opRegCopy(cUnit, rARG1, v2);
907 } else {
908 if (v1 == rARG1) {
buzbee31a4a6f2012-02-28 15:36:15 -0800909#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -0700910 int rTmp = r12;
buzbee31a4a6f2012-02-28 15:36:15 -0800911#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700912 int rTmp = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800913#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700914 opRegCopy(cUnit, rTmp, v1);
915 opRegCopy(cUnit, rARG1, v2);
916 opRegCopy(cUnit, rARG0, rTmp);
917 } else {
918 opRegCopy(cUnit, rARG1, v2);
919 opRegCopy(cUnit, rARG0, v1);
920 }
buzbee31a4a6f2012-02-28 15:36:15 -0800921 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700922 funcOffset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
923 break;
924 case kThrowDivZero:
925 funcOffset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
926 break;
927 case kThrowVerificationError:
928 loadConstant(cUnit, rARG0, v1);
929 loadConstant(cUnit, rARG1, v2);
930 funcOffset =
931 ENTRYPOINT_OFFSET(pThrowVerificationErrorFromCode);
932 break;
933 case kThrowNoSuchMethod:
934 opRegCopy(cUnit, rARG0, v1);
935 funcOffset =
936 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
937 break;
938 case kThrowStackOverflow:
939 funcOffset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
940 // Restore stack alignment
Ian Rogersab2b55d2012-03-18 00:06:11 -0700941#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700942 opRegImm(cUnit, kOpAdd, rSP,
943 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700944#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700945 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700946#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700947 break;
948 default:
949 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
buzbee31a4a6f2012-02-28 15:36:15 -0800950 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 oatClobberCalleeSave(cUnit);
952#if !defined(TARGET_X86)
953 int rTgt = loadHelper(cUnit, funcOffset);
954 opReg(cUnit, kOpBlx, rTgt);
955 oatFreeTemp(cUnit, rTgt);
956#else
957 opThreadMem(cUnit, kOpBlx, funcOffset);
958#endif
959 }
buzbee31a4a6f2012-02-28 15:36:15 -0800960}
961
962/* Needed by the Assembler */
963void oatSetupResourceMasks(LIR* lir)
964{
Bill Buzbeea114add2012-05-03 15:00:40 -0700965 setupResourceMasks(lir);
buzbee31a4a6f2012-02-28 15:36:15 -0800966}
967
buzbee16da88c2012-03-20 10:38:17 -0700968bool fastInstance(CompilationUnit* cUnit, uint32_t fieldIdx,
969 int& fieldOffset, bool& isVolatile, bool isPut)
970{
Bill Buzbeea114add2012-05-03 15:00:40 -0700971 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
972 *cUnit->dex_file, *cUnit->dex_cache,
973 cUnit->code_item, cUnit->method_idx,
974 cUnit->access_flags);
975 return cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
976 fieldOffset, isVolatile, isPut);
buzbee16da88c2012-03-20 10:38:17 -0700977}
978
buzbee31a4a6f2012-02-28 15:36:15 -0800979void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
980 RegLocation rlDest, RegLocation rlObj,
Bill Buzbeea114add2012-05-03 15:00:40 -0700981 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800982{
Bill Buzbeea114add2012-05-03 15:00:40 -0700983 int fieldOffset;
984 bool isVolatile;
985 uint32_t fieldIdx = mir->dalvikInsn.vC;
buzbee31a4a6f2012-02-28 15:36:15 -0800986
Bill Buzbeea114add2012-05-03 15:00:40 -0700987 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800988
Bill Buzbeea114add2012-05-03 15:00:40 -0700989 if (fastPath && !SLOW_FIELD_PATH) {
990 RegLocation rlResult;
991 RegisterClass regClass = oatRegClassBySize(size);
992 DCHECK_GE(fieldOffset, 0);
993 rlObj = loadValue(cUnit, rlObj, kCoreReg);
994 if (isLongOrDouble) {
995 DCHECK(rlDest.wide);
996 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
Ian Rogersb5d09b22012-03-06 22:14:17 -0800997#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700998 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
999 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
1000 loadBaseDispWide(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
1001 rlResult.highReg, rlObj.sRegLow);
1002 if (isVolatile) {
1003 oatGenMemBarrier(cUnit, kSY);
1004 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001005#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001006 int regPtr = oatAllocTemp(cUnit);
1007 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1008 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1009 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1010 if (isVolatile) {
1011 oatGenMemBarrier(cUnit, kSY);
1012 }
1013 oatFreeTemp(cUnit, regPtr);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001014#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001015 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001016 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001017 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1018 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
1019 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
1020 kWord, rlObj.sRegLow);
1021 if (isVolatile) {
1022 oatGenMemBarrier(cUnit, kSY);
1023 }
1024 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001025 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001026 } else {
1027 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Instance) :
1028 (isObject ? ENTRYPOINT_OFFSET(pGetObjInstance)
1029 : ENTRYPOINT_OFFSET(pGet32Instance));
1030 callRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj);
1031 if (isLongOrDouble) {
1032 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
1033 storeValueWide(cUnit, rlDest, rlResult);
1034 } else {
1035 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
1036 storeValue(cUnit, rlDest, rlResult);
1037 }
1038 }
buzbee31a4a6f2012-02-28 15:36:15 -08001039}
1040
1041void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, RegLocation rlSrc,
Bill Buzbeea114add2012-05-03 15:00:40 -07001042 RegLocation rlObj, bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -08001043{
Bill Buzbeea114add2012-05-03 15:00:40 -07001044 int fieldOffset;
1045 bool isVolatile;
1046 uint32_t fieldIdx = mir->dalvikInsn.vC;
buzbee31a4a6f2012-02-28 15:36:15 -08001047
Bill Buzbeea114add2012-05-03 15:00:40 -07001048 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
1049 true);
1050 if (fastPath && !SLOW_FIELD_PATH) {
1051 RegisterClass regClass = oatRegClassBySize(size);
1052 DCHECK_GE(fieldOffset, 0);
1053 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1054 if (isLongOrDouble) {
1055 int regPtr;
1056 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1057 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
1058 regPtr = oatAllocTemp(cUnit);
1059 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1060 if (isVolatile) {
1061 oatGenMemBarrier(cUnit, kST);
1062 }
jeffhao41005dd2012-05-09 17:58:52 -07001063 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001064 if (isVolatile) {
1065 oatGenMemBarrier(cUnit, kSY);
1066 }
1067 oatFreeTemp(cUnit, regPtr);
buzbee31a4a6f2012-02-28 15:36:15 -08001068 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001069 rlSrc = loadValue(cUnit, rlSrc, regClass);
1070 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
1071 if (isVolatile) {
1072 oatGenMemBarrier(cUnit, kST);
1073 }
1074 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
1075 if (isVolatile) {
1076 oatGenMemBarrier(cUnit, kSY);
1077 }
1078 if (isObject) {
1079 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
1080 }
buzbee31a4a6f2012-02-28 15:36:15 -08001081 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001082 } else {
1083 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Instance) :
1084 (isObject ? ENTRYPOINT_OFFSET(pSetObjInstance)
1085 : ENTRYPOINT_OFFSET(pSet32Instance));
1086 callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset,
1087 fieldIdx, rlObj, rlSrc);
1088 }
buzbee31a4a6f2012-02-28 15:36:15 -08001089}
1090
1091void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1092 RegLocation rlSrc)
1093{
Bill Buzbeea114add2012-05-03 15:00:40 -07001094 uint32_t type_idx = mir->dalvikInsn.vB;
1095 RegLocation rlMethod = loadCurrMethod(cUnit);
1096 int resReg = oatAllocTemp(cUnit);
1097 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1098 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1099 cUnit->dex_cache,
1100 *cUnit->dex_file,
1101 type_idx)) {
1102 // Call out to helper which resolves type and verifies access.
1103 // Resolved type returned in rRET0.
1104 callRuntimeHelperImmReg(cUnit,
1105 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1106 type_idx, rlMethod.lowReg);
1107 RegLocation rlResult = oatGetReturn(cUnit, false);
1108 storeValue(cUnit, rlDest, rlResult);
1109 } else {
1110 // We're don't need access checks, load type from dex cache
1111 int32_t dex_cache_offset =
1112 Method::DexCacheResolvedTypesOffset().Int32Value();
1113 loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
1114 int32_t offset_of_type =
1115 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1116 * type_idx);
1117 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
1118 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
1119 type_idx) || SLOW_TYPE_PATH) {
1120 // Slow path, at runtime test if type is null and if so initialize
1121 oatFlushAllRegs(cUnit);
1122 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0, NULL);
1123 // Resolved, store and hop over following code
1124 storeValue(cUnit, rlDest, rlResult);
1125 /*
1126 * Because we have stores of the target value on two paths,
1127 * clobber temp tracking for the destination using the ssa name
1128 */
1129 oatClobberSReg(cUnit, rlDest.sRegLow);
1130 LIR* branch2 = opUnconditionalBranch(cUnit,0);
1131 // TUNING: move slow path to end & remove unconditional branch
1132 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
1133 // Call out to helper, which will return resolved type in rARG0
1134 callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1135 type_idx, rlMethod.lowReg);
1136 RegLocation rlResult = oatGetReturn(cUnit, false);
1137 storeValue(cUnit, rlDest, rlResult);
1138 /*
1139 * Because we have stores of the target value on two paths,
1140 * clobber temp tracking for the destination using the ssa name
1141 */
1142 oatClobberSReg(cUnit, rlDest.sRegLow);
1143 // Rejoin code paths
1144 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
1145 branch1->target = (LIR*)target1;
1146 branch2->target = (LIR*)target2;
buzbee31a4a6f2012-02-28 15:36:15 -08001147 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001148 // Fast path, we're done - just store result
1149 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001150 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001151 }
buzbee31a4a6f2012-02-28 15:36:15 -08001152}
Ian Rogersab2b55d2012-03-18 00:06:11 -07001153
buzbee31a4a6f2012-02-28 15:36:15 -08001154void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001155 RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08001156{
Bill Buzbeea114add2012-05-03 15:00:40 -07001157 /* NOTE: Most strings should be available at compile time */
1158 uint32_t string_idx = mir->dalvikInsn.vB;
1159 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1160 (sizeof(String*) * string_idx);
1161 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
1162 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
1163 // slow path, resolve string if not in dex cache
1164 oatFlushAllRegs(cUnit);
1165 oatLockCallTemps(cUnit); // Using explicit registers
1166 loadCurrMethodDirect(cUnit, rARG2);
1167 loadWordDisp(cUnit, rARG2,
1168 Method::DexCacheStringsOffset().Int32Value(), rARG0);
1169 // Might call out to helper, which will return resolved string in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001170#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001171 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001172#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001173 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
1174 loadConstant(cUnit, rARG1, string_idx);
buzbee31a4a6f2012-02-28 15:36:15 -08001175#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001176 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
1177 genBarrier(cUnit);
1178 // For testing, always force through helper
1179 if (!EXERCISE_SLOWEST_STRING_PATH) {
1180 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08001181 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001182 opRegCopy(cUnit, rARG0, rARG2); // .eq
1183 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
1184 oatFreeTemp(cUnit, rTgt);
1185#elif defined(TARGET_MIPS)
1186 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
1187 opRegCopy(cUnit, rARG0, rARG2); // .eq
1188 opReg(cUnit, kOpBlx, rTgt);
1189 oatFreeTemp(cUnit, rTgt);
1190 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1191 branch->target = target;
1192#else
1193 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode),
1194 rARG2, rARG1);
1195#endif
1196 genBarrier(cUnit);
1197 storeValue(cUnit, rlDest, oatGetReturn(cUnit, false));
1198 } else {
1199 RegLocation rlMethod = loadCurrMethod(cUnit);
1200 int resReg = oatAllocTemp(cUnit);
1201 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1202 loadWordDisp(cUnit, rlMethod.lowReg,
1203 Method::DexCacheStringsOffset().Int32Value(), resReg);
1204 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1205 storeValue(cUnit, rlDest, rlResult);
1206 }
buzbee31a4a6f2012-02-28 15:36:15 -08001207}
1208
1209/*
1210 * Let helper function take care of everything. Will
1211 * call Class::NewInstanceFromCode(type_idx, method);
1212 */
1213void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
1214{
Bill Buzbeea114add2012-05-03 15:00:40 -07001215 oatFlushAllRegs(cUnit); /* Everything to home location */
1216 uint32_t type_idx = mir->dalvikInsn.vB;
1217 // alloc will always check for resolution, do we also need to verify
1218 // access because the verifier was unable to?
1219 int funcOffset;
1220 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
1221 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
1222 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
1223 } else {
1224 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
1225 }
1226 callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx);
1227 RegLocation rlResult = oatGetReturn(cUnit, false);
1228 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001229}
1230
Ian Rogersab2b55d2012-03-18 00:06:11 -07001231void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1232{
Bill Buzbeea114add2012-05-03 15:00:40 -07001233 oatFlushAllRegs(cUnit);
1234 callRuntimeHelperRegLocation(cUnit, ENTRYPOINT_OFFSET(pDeliverException),
1235 rlSrc);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001236}
1237
buzbee31a4a6f2012-02-28 15:36:15 -08001238void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1239 RegLocation rlSrc)
1240{
Bill Buzbeea114add2012-05-03 15:00:40 -07001241 oatFlushAllRegs(cUnit);
1242 // May generate a call - use explicit registers
1243 oatLockCallTemps(cUnit);
1244 uint32_t type_idx = mir->dalvikInsn.vC;
1245 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1246 int classReg = rARG2; // rARG2 will hold the Class*
1247 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1248 cUnit->dex_cache,
1249 *cUnit->dex_file,
1250 type_idx)) {
1251 // Check we have access to type_idx and if not throw IllegalAccessError,
1252 // returns Class* in rARG0
1253 callRuntimeHelperImm(cUnit,
1254 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1255 type_idx);
1256 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1257 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1258 } else {
1259 // Load dex cache entry into classReg (rARG2)
1260 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1261 loadWordDisp(cUnit, rARG1,
1262 Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
1263 int32_t offset_of_type =
1264 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1265 * type_idx);
1266 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1267 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1268 cUnit->dex_cache, type_idx)) {
1269 // Need to test presence of type in dex cache at runtime
1270 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1271 // Not resolved
1272 // Call out to helper, which will return resolved type in rRET0
1273 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1274 type_idx);
1275 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
1276 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1277 // Rejoin code paths
1278 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1279 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001280 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001281 }
1282 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
1283 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1284 /* load object->klass_ */
1285 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1286 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1287 /* rARG0 is ref, rARG1 is ref->klass_, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001288#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001289 /* Uses conditional nullification */
1290 int rTgt = loadHelper(cUnit,
1291 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1292 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
1293 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
1294 loadConstant(cUnit, rARG0, 1); // .eq case - load true
1295 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1296 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1297 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001298#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001299 /* Uses branchovers */
1300 loadConstant(cUnit, rARG0, 1); // assume true
1301 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001302#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001303 int rTgt = loadHelper(cUnit,
1304 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1305 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1306 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1307 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001308#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001309 opRegCopy(cUnit, rARG0, rARG2);
1310 opThreadMem(cUnit, kOpBlx,
1311 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001312#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001313#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001314 oatClobberCalleeSave(cUnit);
1315 /* branch targets here */
1316 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1317 RegLocation rlResult = oatGetReturn(cUnit, false);
1318 storeValue(cUnit, rlDest, rlResult);
1319 branch1->target = target;
buzbee0398c422012-03-02 15:22:47 -08001320#if !defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001321 branchover->target = target;
buzbee0398c422012-03-02 15:22:47 -08001322#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001323}
1324
1325void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1326{
Bill Buzbeea114add2012-05-03 15:00:40 -07001327 oatFlushAllRegs(cUnit);
1328 // May generate a call - use explicit registers
1329 oatLockCallTemps(cUnit);
1330 uint32_t type_idx = mir->dalvikInsn.vB;
1331 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1332 int classReg = rARG2; // rARG2 will hold the Class*
1333 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1334 cUnit->dex_cache,
1335 *cUnit->dex_file,
1336 type_idx)) {
1337 // Check we have access to type_idx and if not throw IllegalAccessError,
1338 // returns Class* in rRET0
1339 // InitializeTypeAndVerifyAccess(idx, method)
1340 callRuntimeHelperImmReg(cUnit,
1341 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1342 type_idx, rARG1);
1343 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1344 } else {
1345 // Load dex cache entry into classReg (rARG2)
1346 loadWordDisp(cUnit, rARG1,
1347 Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
1348 int32_t offset_of_type =
1349 Array::DataOffset(sizeof(Class*)).Int32Value() +
1350 (sizeof(Class*) * type_idx);
1351 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1352 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1353 cUnit->dex_cache, type_idx)) {
1354 // Need to test presence of type in dex cache at runtime
1355 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1356 // Not resolved
1357 // Call out to helper, which will return resolved type in rARG0
1358 // InitializeTypeFromCode(idx, method)
1359 callRuntimeHelperImmReg(cUnit,
1360 ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1361 type_idx, rARG1);
1362 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
1363 // Rejoin code paths
1364 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1365 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001366 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001367 }
1368 // At this point, classReg (rARG2) has class
1369 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1370 /* Null is OK - continue */
1371 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1372 /* load object->klass_ */
1373 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1374 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1375 /* rARG1 now contains object->klass_ */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001376#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001377 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
1378 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode),
1379 rARG1, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001380#else // defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001381 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1382 opRegReg(cUnit, kOpCmp, rARG1, classReg);
1383 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1384 opRegCopy(cUnit, rARG0, rARG1);
1385 opRegCopy(cUnit, rARG1, rARG2);
1386 oatClobberCalleeSave(cUnit);
1387 opReg(cUnit, kOpBlx, rTgt);
1388 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001389#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001390 /* branch target here */
1391 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1392 branch1->target = target;
1393 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001394}
1395
buzbee31a4a6f2012-02-28 15:36:15 -08001396/*
1397 * Generate array store
1398 *
1399 */
1400void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
Bill Buzbeea114add2012-05-03 15:00:40 -07001401 RegLocation rlIndex, RegLocation rlSrc, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001402{
Bill Buzbeea114add2012-05-03 15:00:40 -07001403 int lenOffset = Array::LengthOffset().Int32Value();
1404 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
buzbee31a4a6f2012-02-28 15:36:15 -08001405
Bill Buzbeea114add2012-05-03 15:00:40 -07001406 oatFlushAllRegs(cUnit); // Use explicit registers
1407 oatLockCallTemps(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001408
Bill Buzbeea114add2012-05-03 15:00:40 -07001409 int rValue = rARG0; // Register holding value
1410 int rArrayClass = rARG1; // Register holding array's Class
1411 int rArray = rARG2; // Register holding array
1412 int rIndex = rARG3; // Register holding index into array
Ian Rogersd36c52e2012-04-09 16:29:25 -07001413
Bill Buzbeea114add2012-05-03 15:00:40 -07001414 loadValueDirectFixed(cUnit, rlArray, rArray); // Grab array
1415 loadValueDirectFixed(cUnit, rlSrc, rValue); // Grab value
1416 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Grab index
Ian Rogersd36c52e2012-04-09 16:29:25 -07001417
Bill Buzbeea114add2012-05-03 15:00:40 -07001418 genNullCheck(cUnit, rlArray.sRegLow, rArray, mir); // NPE?
Ian Rogersd36c52e2012-04-09 16:29:25 -07001419
Bill Buzbeea114add2012-05-03 15:00:40 -07001420 // Store of null?
1421 LIR* null_value_check = opCmpImmBranch(cUnit, kCondEq, rValue, 0, NULL);
Ian Rogersd36c52e2012-04-09 16:29:25 -07001422
Bill Buzbeea114add2012-05-03 15:00:40 -07001423 // Get the array's class.
1424 loadWordDisp(cUnit, rArray, Object::ClassOffset().Int32Value(), rArrayClass);
1425 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode),
1426 rValue, rArrayClass);
1427 // Redo loadValues in case they didn't survive the call.
1428 loadValueDirectFixed(cUnit, rlArray, rArray); // Reload array
1429 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Reload index
1430 loadValueDirectFixed(cUnit, rlSrc, rValue); // Reload value
1431 rArrayClass = INVALID_REG;
buzbee31a4a6f2012-02-28 15:36:15 -08001432
Bill Buzbeea114add2012-05-03 15:00:40 -07001433 // Branch here if value to be stored == null
1434 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1435 null_value_check->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001436
Ian Rogersb41b33b2012-03-20 14:22:54 -07001437#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001438 // make an extra temp available for card mark below
1439 oatFreeTemp(cUnit, rARG1);
1440 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1441 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1442 genRegMemCheck(cUnit, kCondUge, rIndex, rArray,
1443 lenOffset, mir, kThrowArrayBounds);
1444 }
1445 storeBaseIndexedDisp(cUnit, NULL, rArray, rIndex, scale,
1446 dataOffset, rValue, INVALID_REG, kWord, INVALID_SREG);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001447#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001448 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1449 int regLen = INVALID_REG;
1450 if (needsRangeCheck) {
1451 regLen = rARG1;
1452 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); // Get len
1453 }
1454 /* rPtr -> array data */
1455 int rPtr = oatAllocTemp(cUnit);
1456 opRegRegImm(cUnit, kOpAdd, rPtr, rArray, dataOffset);
1457 if (needsRangeCheck) {
1458 genRegRegCheck(cUnit, kCondCs, rIndex, regLen, mir,
1459 kThrowArrayBounds);
1460 }
1461 storeBaseIndexed(cUnit, rPtr, rIndex, rValue, scale, kWord);
1462 oatFreeTemp(cUnit, rPtr);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001463#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001464 oatFreeTemp(cUnit, rIndex);
1465 markGCCard(cUnit, rValue, rArray);
buzbee31a4a6f2012-02-28 15:36:15 -08001466}
1467
1468/*
1469 * Generate array load
1470 */
1471void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1472 RegLocation rlArray, RegLocation rlIndex,
1473 RegLocation rlDest, int scale)
1474{
Bill Buzbeea114add2012-05-03 15:00:40 -07001475 RegisterClass regClass = oatRegClassBySize(size);
1476 int lenOffset = Array::LengthOffset().Int32Value();
1477 int dataOffset;
1478 RegLocation rlResult;
1479 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1480 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001481
Bill Buzbeea114add2012-05-03 15:00:40 -07001482 if (size == kLong || size == kDouble) {
1483 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1484 } else {
1485 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1486 }
buzbee31a4a6f2012-02-28 15:36:15 -08001487
Bill Buzbeea114add2012-05-03 15:00:40 -07001488 /* null object? */
1489 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee31a4a6f2012-02-28 15:36:15 -08001490
Ian Rogersb5d09b22012-03-06 22:14:17 -08001491#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001492 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1493 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1494 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
1495 lenOffset, mir, kThrowArrayBounds);
1496 }
1497 if ((size == kLong) || (size == kDouble)) {
1498 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1499 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale,
1500 dataOffset, rlResult.lowReg, rlResult.highReg, size,
1501 INVALID_SREG);
buzbee31a4a6f2012-02-28 15:36:15 -08001502
Bill Buzbeea114add2012-05-03 15:00:40 -07001503 storeValueWide(cUnit, rlDest, rlResult);
1504 } else {
1505 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001506
Bill Buzbeea114add2012-05-03 15:00:40 -07001507 loadBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale,
1508 dataOffset, rlResult.lowReg, INVALID_REG, size,
1509 INVALID_SREG);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001510
Bill Buzbeea114add2012-05-03 15:00:40 -07001511 storeValue(cUnit, rlDest, rlResult);
1512 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001513#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001514 int regPtr = oatAllocTemp(cUnit);
1515 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1516 int regLen = INVALID_REG;
1517 if (needsRangeCheck) {
1518 regLen = oatAllocTemp(cUnit);
1519 /* Get len */
1520 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1521 }
1522 /* regPtr -> array data */
1523 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1524 oatFreeTemp(cUnit, rlArray.lowReg);
1525 if ((size == kLong) || (size == kDouble)) {
1526 if (scale) {
1527 int rNewIndex = oatAllocTemp(cUnit);
1528 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1529 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1530 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001531 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001532 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001533 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001534 oatFreeTemp(cUnit, rlIndex.lowReg);
1535 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1536
1537 if (needsRangeCheck) {
1538 // TODO: change kCondCS to a more meaningful name, is the sense of
1539 // carry-set/clear flipped?
1540 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1541 kThrowArrayBounds);
1542 oatFreeTemp(cUnit, regLen);
1543 }
1544 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1545
1546 oatFreeTemp(cUnit, regPtr);
1547 storeValueWide(cUnit, rlDest, rlResult);
1548 } else {
1549 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1550
1551 if (needsRangeCheck) {
1552 // TODO: change kCondCS to a more meaningful name, is the sense of
1553 // carry-set/clear flipped?
1554 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1555 kThrowArrayBounds);
1556 oatFreeTemp(cUnit, regLen);
1557 }
1558 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1559 scale, size);
1560
1561 oatFreeTemp(cUnit, regPtr);
1562 storeValue(cUnit, rlDest, rlResult);
1563 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001564#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001565}
1566
1567/*
1568 * Generate array store
1569 *
1570 */
1571void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1572 RegLocation rlArray, RegLocation rlIndex,
1573 RegLocation rlSrc, int scale)
1574{
Bill Buzbeea114add2012-05-03 15:00:40 -07001575 RegisterClass regClass = oatRegClassBySize(size);
1576 int lenOffset = Array::LengthOffset().Int32Value();
1577 int dataOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001578
Bill Buzbeea114add2012-05-03 15:00:40 -07001579 if (size == kLong || size == kDouble) {
1580 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1581 } else {
1582 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1583 }
buzbee31a4a6f2012-02-28 15:36:15 -08001584
Bill Buzbeea114add2012-05-03 15:00:40 -07001585 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1586 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001587#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001588 int regPtr;
1589 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1590 oatClobber(cUnit, rlArray.lowReg);
1591 regPtr = rlArray.lowReg;
1592 } else {
1593 regPtr = oatAllocTemp(cUnit);
1594 opRegCopy(cUnit, regPtr, rlArray.lowReg);
1595 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001596#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001597
Bill Buzbeea114add2012-05-03 15:00:40 -07001598 /* null object? */
1599 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee31a4a6f2012-02-28 15:36:15 -08001600
Ian Rogersb41b33b2012-03-20 14:22:54 -07001601#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001602 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1603 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1604 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
1605 lenOffset, mir, kThrowArrayBounds);
1606 }
1607 if ((size == kLong) || (size == kDouble)) {
1608 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1609 } else {
1610 rlSrc = loadValue(cUnit, rlSrc, regClass);
1611 }
1612 storeBaseIndexedDisp(cUnit, NULL, rlArray.lowReg, rlIndex.lowReg, scale,
1613 dataOffset, rlSrc.lowReg, rlSrc.highReg, size,
1614 INVALID_SREG);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001615#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001616 bool needsRangeCheck = (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK));
1617 int regLen = INVALID_REG;
1618 if (needsRangeCheck) {
1619 regLen = oatAllocTemp(cUnit);
1620 //NOTE: max live temps(4) here.
1621 /* Get len */
1622 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1623 }
1624 /* regPtr -> array data */
1625 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1626 /* at this point, regPtr points to array, 2 live temps */
1627 if ((size == kLong) || (size == kDouble)) {
1628 //TUNING: specific wide routine that can handle fp regs
1629 if (scale) {
1630 int rNewIndex = oatAllocTemp(cUnit);
1631 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1632 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1633 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001634 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001635 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001636 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001637 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1638
1639 if (needsRangeCheck) {
1640 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1641 kThrowArrayBounds);
1642 oatFreeTemp(cUnit, regLen);
1643 }
1644
jeffhao41005dd2012-05-09 17:58:52 -07001645 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001646
1647 oatFreeTemp(cUnit, regPtr);
1648 } else {
1649 rlSrc = loadValue(cUnit, rlSrc, regClass);
1650 if (needsRangeCheck) {
1651 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1652 kThrowArrayBounds);
1653 oatFreeTemp(cUnit, regLen);
1654 }
1655 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1656 scale, size);
1657 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001658#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001659}
1660
1661void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1662 OpKind secondOp, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001663 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001664{
Bill Buzbeea114add2012-05-03 15:00:40 -07001665 RegLocation rlResult;
buzbee31a4a6f2012-02-28 15:36:15 -08001666#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001667 /*
1668 * NOTE: This is the one place in the code in which we might have
1669 * as many as six live temporary registers. There are 5 in the normal
1670 * set for Arm. Until we have spill capabilities, temporarily add
1671 * lr to the temp set. It is safe to do this locally, but note that
1672 * lr is used explicitly elsewhere in the code generator and cannot
1673 * normally be used as a general temp register.
1674 */
1675 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1676 oatFreeTemp(cUnit, rLR); // and make it available
buzbee31a4a6f2012-02-28 15:36:15 -08001677#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001678 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1679 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1680 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1681 // The longs may overlap - use intermediate temp if so
1682 if (rlResult.lowReg == rlSrc1.highReg) {
1683 int tReg = oatAllocTemp(cUnit);
1684 opRegCopy(cUnit, tReg, rlSrc1.highReg);
1685 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1686 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg, rlSrc2.highReg);
1687 oatFreeTemp(cUnit, tReg);
1688 } else {
1689 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1690 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1691 rlSrc2.highReg);
1692 }
1693 /*
1694 * NOTE: If rlDest refers to a frame variable in a large frame, the
1695 * following storeValueWide might need to allocate a temp register.
1696 * To further work around the lack of a spill capability, explicitly
1697 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1698 * Remove when spill is functional.
1699 */
1700 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1701 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1702 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001703#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001704 oatClobber(cUnit, rLR);
1705 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee31a4a6f2012-02-28 15:36:15 -08001706#endif
1707}
1708
1709
1710bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1711 RegLocation rlSrc1, RegLocation rlShift)
1712{
Bill Buzbeea114add2012-05-03 15:00:40 -07001713 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001714
Bill Buzbeea114add2012-05-03 15:00:40 -07001715 switch (mir->dalvikInsn.opcode) {
1716 case Instruction::SHL_LONG:
1717 case Instruction::SHL_LONG_2ADDR:
1718 funcOffset = ENTRYPOINT_OFFSET(pShlLong);
1719 break;
1720 case Instruction::SHR_LONG:
1721 case Instruction::SHR_LONG_2ADDR:
1722 funcOffset = ENTRYPOINT_OFFSET(pShrLong);
1723 break;
1724 case Instruction::USHR_LONG:
1725 case Instruction::USHR_LONG_2ADDR:
1726 funcOffset = ENTRYPOINT_OFFSET(pUshrLong);
1727 break;
1728 default:
1729 LOG(FATAL) << "Unexpected case";
1730 return true;
1731 }
1732 oatFlushAllRegs(cUnit); /* Send everything to home location */
1733 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift);
1734 RegLocation rlResult = oatGetReturnWide(cUnit, false);
1735 storeValueWide(cUnit, rlDest, rlResult);
1736 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001737}
1738
1739
1740bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001741 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001742{
Bill Buzbeea114add2012-05-03 15:00:40 -07001743 OpKind op = kOpBkpt;
1744 bool callOut = false;
1745 bool checkZero = false;
1746 bool unary = false;
1747 RegLocation rlResult;
1748 bool shiftOp = false;
1749 int funcOffset;
1750 int retReg = rRET0;
1751 switch (mir->dalvikInsn.opcode) {
1752 case Instruction::NEG_INT:
1753 op = kOpNeg;
1754 unary = true;
1755 break;
1756 case Instruction::NOT_INT:
1757 op = kOpMvn;
1758 unary = true;
1759 break;
1760 case Instruction::ADD_INT:
1761 case Instruction::ADD_INT_2ADDR:
1762 op = kOpAdd;
1763 break;
1764 case Instruction::SUB_INT:
1765 case Instruction::SUB_INT_2ADDR:
1766 op = kOpSub;
1767 break;
1768 case Instruction::MUL_INT:
1769 case Instruction::MUL_INT_2ADDR:
1770 op = kOpMul;
1771 break;
1772 case Instruction::DIV_INT:
1773 case Instruction::DIV_INT_2ADDR:
1774 checkZero = true;
1775 op = kOpDiv;
1776 callOut = true;
1777 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
1778 retReg = rRET0;
1779 break;
1780 /* NOTE: returns in rARG1 */
1781 case Instruction::REM_INT:
1782 case Instruction::REM_INT_2ADDR:
1783 checkZero = true;
1784 op = kOpRem;
1785 callOut = true;
1786 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
1787 retReg = rRET1;
1788 break;
1789 case Instruction::AND_INT:
1790 case Instruction::AND_INT_2ADDR:
1791 op = kOpAnd;
1792 break;
1793 case Instruction::OR_INT:
1794 case Instruction::OR_INT_2ADDR:
1795 op = kOpOr;
1796 break;
1797 case Instruction::XOR_INT:
1798 case Instruction::XOR_INT_2ADDR:
1799 op = kOpXor;
1800 break;
1801 case Instruction::SHL_INT:
1802 case Instruction::SHL_INT_2ADDR:
1803 shiftOp = true;
1804 op = kOpLsl;
1805 break;
1806 case Instruction::SHR_INT:
1807 case Instruction::SHR_INT_2ADDR:
1808 shiftOp = true;
1809 op = kOpAsr;
1810 break;
1811 case Instruction::USHR_INT:
1812 case Instruction::USHR_INT_2ADDR:
1813 shiftOp = true;
1814 op = kOpLsr;
1815 break;
1816 default:
1817 LOG(FATAL) << "Invalid word arith op: " <<
1818 (int)mir->dalvikInsn.opcode;
1819 }
1820 if (!callOut) {
1821 if (unary) {
1822 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1823 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1824 opRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001825 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001826 if (shiftOp) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001827#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001828 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1829 int tReg = oatAllocTemp(cUnit);
1830 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001831#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001832 // X86 doesn't require masking and must use ECX
1833 loadValueDirectFixed(cUnit, rlSrc2, rCX);
1834 int tReg = rCX;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001835#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001836 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1837 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1838 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, tReg);
1839 oatFreeTemp(cUnit, tReg);
1840 } else {
1841 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1842 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1843 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1844 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1845 }
buzbee31a4a6f2012-02-28 15:36:15 -08001846 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001847 storeValue(cUnit, rlDest, rlResult);
1848 } else {
1849 RegLocation rlResult;
1850 oatFlushAllRegs(cUnit); /* Send everything to home location */
1851 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
1852#if !defined(TARGET_X86)
1853 int rTgt = loadHelper(cUnit, funcOffset);
1854#endif
1855 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1856 if (checkZero) {
1857 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1858 }
1859#if !defined(TARGET_X86)
1860 opReg(cUnit, kOpBlx, rTgt);
1861 oatFreeTemp(cUnit, rTgt);
1862#else
1863 opThreadMem(cUnit, kOpBlx, funcOffset);
1864#endif
1865 if (retReg == rRET0)
1866 rlResult = oatGetReturn(cUnit, false);
1867 else
1868 rlResult = oatGetReturnAlt(cUnit);
1869 storeValue(cUnit, rlDest, rlResult);
1870 }
1871 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001872}
1873
1874/*
1875 * The following are the first-level codegen routines that analyze the format
1876 * of each bytecode then either dispatch special purpose codegen routines
1877 * or produce corresponding Thumb instructions directly.
1878 */
1879
1880bool isPowerOfTwo(int x)
1881{
Bill Buzbeea114add2012-05-03 15:00:40 -07001882 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001883}
1884
1885// Returns true if no more than two bits are set in 'x'.
1886bool isPopCountLE2(unsigned int x)
1887{
Bill Buzbeea114add2012-05-03 15:00:40 -07001888 x &= x - 1;
1889 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001890}
1891
1892// Returns the index of the lowest set bit in 'x'.
1893int lowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001894 int bit_posn = 0;
1895 while ((x & 0xf) == 0) {
1896 bit_posn += 4;
1897 x >>= 4;
1898 }
1899 while ((x & 1) == 0) {
1900 bit_posn++;
1901 x >>= 1;
1902 }
1903 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001904}
1905
1906// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1907// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001908bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
Bill Buzbeea114add2012-05-03 15:00:40 -07001909 RegLocation rlSrc, RegLocation rlDest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001910{
buzbeef3aac972012-04-11 16:33:36 -07001911#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001912 // No divide instruction for Arm, so check for more special cases
1913 if (lit < 2) {
1914 return false;
1915 }
1916 if (!isPowerOfTwo(lit)) {
1917 return smallLiteralDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit);
1918 }
buzbeef3aac972012-04-11 16:33:36 -07001919#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001920 if (lit < 2 || !isPowerOfTwo(lit)) {
1921 return false;
1922 }
buzbeef3aac972012-04-11 16:33:36 -07001923#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001924 int k = lowestSetBit(lit);
1925 if (k >= 30) {
1926 // Avoid special cases.
1927 return false;
1928 }
1929 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1930 dalvikOpcode == Instruction::DIV_INT_LIT16);
1931 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1932 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1933 if (div) {
1934 int tReg = oatAllocTemp(cUnit);
1935 if (lit == 2) {
1936 // Division by 2 is by far the most common division by constant.
1937 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1938 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1939 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001940 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001941 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1942 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1943 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1944 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001945 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001946 } else {
1947 int tReg1 = oatAllocTemp(cUnit);
1948 int tReg2 = oatAllocTemp(cUnit);
1949 if (lit == 2) {
1950 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1951 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1952 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit -1);
1953 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1954 } else {
1955 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1956 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1957 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1958 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit - 1);
1959 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1960 }
1961 }
1962 storeValue(cUnit, rlDest, rlResult);
1963 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001964}
1965
1966void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1967 RegLocation rlResult, int lit,
1968 int firstBit, int secondBit)
1969{
buzbee0398c422012-03-02 15:22:47 -08001970#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001971 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1972 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001973#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001974 int tReg = oatAllocTemp(cUnit);
1975 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1976 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1977 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001978#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001979 if (firstBit != 0) {
1980 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1981 }
buzbee31a4a6f2012-02-28 15:36:15 -08001982}
1983
1984// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1985// and store the result in 'rlDest'.
1986bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1987 RegLocation rlDest, int lit)
1988{
Bill Buzbeea114add2012-05-03 15:00:40 -07001989 // Can we simplify this multiplication?
1990 bool powerOfTwo = false;
1991 bool popCountLE2 = false;
1992 bool powerOfTwoMinusOne = false;
1993 if (lit < 2) {
1994 // Avoid special cases.
1995 return false;
1996 } else if (isPowerOfTwo(lit)) {
1997 powerOfTwo = true;
1998 } else if (isPopCountLE2(lit)) {
1999 popCountLE2 = true;
2000 } else if (isPowerOfTwo(lit + 1)) {
2001 powerOfTwoMinusOne = true;
2002 } else {
2003 return false;
2004 }
2005 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2006 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2007 if (powerOfTwo) {
2008 // Shift.
2009 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
2010 lowestSetBit(lit));
2011 } else if (popCountLE2) {
2012 // Shift and add and shift.
2013 int firstBit = lowestSetBit(lit);
2014 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
2015 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
2016 firstBit, secondBit);
2017 } else {
2018 // Reverse subtract: (src << (shift + 1)) - src.
2019 DCHECK(powerOfTwoMinusOne);
2020 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
2021 int tReg = oatAllocTemp(cUnit);
2022 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
2023 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2024 }
2025 storeValue(cUnit, rlDest, rlResult);
2026 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08002027}
2028
2029bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
2030 RegLocation rlSrc, int lit)
2031{
Bill Buzbeea114add2012-05-03 15:00:40 -07002032 Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
2033 RegLocation rlResult;
2034 OpKind op = (OpKind)0; /* Make gcc happy */
2035 int shiftOp = false;
2036 bool isDiv = false;
2037 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002038
Bill Buzbeea114add2012-05-03 15:00:40 -07002039 switch (dalvikOpcode) {
2040 case Instruction::RSUB_INT_LIT8:
2041 case Instruction::RSUB_INT: {
2042 int tReg;
2043 //TUNING: add support for use of Arm rsub op
2044 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2045 tReg = oatAllocTemp(cUnit);
2046 loadConstant(cUnit, tReg, lit);
2047 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2048 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2049 storeValue(cUnit, rlDest, rlResult);
2050 return false;
2051 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002052 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002053
2054 case Instruction::ADD_INT_LIT8:
2055 case Instruction::ADD_INT_LIT16:
2056 op = kOpAdd;
2057 break;
2058 case Instruction::MUL_INT_LIT8:
2059 case Instruction::MUL_INT_LIT16: {
2060 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2061 return false;
2062 }
2063 op = kOpMul;
2064 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002065 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002066 case Instruction::AND_INT_LIT8:
2067 case Instruction::AND_INT_LIT16:
2068 op = kOpAnd;
2069 break;
2070 case Instruction::OR_INT_LIT8:
2071 case Instruction::OR_INT_LIT16:
2072 op = kOpOr;
2073 break;
2074 case Instruction::XOR_INT_LIT8:
2075 case Instruction::XOR_INT_LIT16:
2076 op = kOpXor;
2077 break;
2078 case Instruction::SHL_INT_LIT8:
2079 lit &= 31;
2080 shiftOp = true;
2081 op = kOpLsl;
2082 break;
2083 case Instruction::SHR_INT_LIT8:
2084 lit &= 31;
2085 shiftOp = true;
2086 op = kOpAsr;
2087 break;
2088 case Instruction::USHR_INT_LIT8:
2089 lit &= 31;
2090 shiftOp = true;
2091 op = kOpLsr;
2092 break;
2093
2094 case Instruction::DIV_INT_LIT8:
2095 case Instruction::DIV_INT_LIT16:
2096 case Instruction::REM_INT_LIT8:
2097 case Instruction::REM_INT_LIT16:
2098 if (lit == 0) {
2099 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
2100 return false;
2101 }
2102 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2103 return false;
2104 }
2105 oatFlushAllRegs(cUnit); /* Everything to home location */
2106 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2107 oatClobber(cUnit, rARG0);
2108 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
2109 if ((dalvikOpcode == Instruction::DIV_INT_LIT8) ||
2110 (dalvikOpcode == Instruction::DIV_INT_LIT16)) {
2111 isDiv = true;
2112 } else {
2113 isDiv = false;
2114 }
2115 callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit);
2116 if (isDiv)
2117 rlResult = oatGetReturn(cUnit, false);
2118 else
2119 rlResult = oatGetReturnAlt(cUnit);
2120 storeValue(cUnit, rlDest, rlResult);
2121 return false;
2122 break;
2123 default:
2124 return true;
2125 }
2126 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2127 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2128 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2129 if (shiftOp && (lit == 0)) {
2130 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2131 } else {
2132 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2133 }
2134 storeValue(cUnit, rlDest, rlResult);
2135 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002136}
2137
2138bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07002139 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08002140{
Bill Buzbeea114add2012-05-03 15:00:40 -07002141 RegLocation rlResult;
2142 OpKind firstOp = kOpBkpt;
2143 OpKind secondOp = kOpBkpt;
2144 bool callOut = false;
2145 bool checkZero = false;
2146 int funcOffset;
2147 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08002148
Bill Buzbeea114add2012-05-03 15:00:40 -07002149 switch (mir->dalvikInsn.opcode) {
2150 case Instruction::NOT_LONG:
2151 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2152 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2153 // Check for destructive overlap
2154 if (rlResult.lowReg == rlSrc2.highReg) {
2155 int tReg = oatAllocTemp(cUnit);
2156 opRegCopy(cUnit, tReg, rlSrc2.highReg);
2157 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2158 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2159 oatFreeTemp(cUnit, tReg);
2160 } else {
2161 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2162 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2163 }
2164 storeValueWide(cUnit, rlDest, rlResult);
2165 return false;
2166 break;
2167 case Instruction::ADD_LONG:
2168 case Instruction::ADD_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002169#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002170 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
buzbeec5159d52012-03-03 11:48:39 -08002171#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002172 firstOp = kOpAdd;
2173 secondOp = kOpAdc;
2174 break;
buzbeec5159d52012-03-03 11:48:39 -08002175#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002176 case Instruction::SUB_LONG:
2177 case Instruction::SUB_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002178#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002179 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002180#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002181 firstOp = kOpSub;
2182 secondOp = kOpSbc;
2183 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002184#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002185 case Instruction::MUL_LONG:
2186 case Instruction::MUL_LONG_2ADDR:
2187 callOut = true;
2188 retReg = rRET0;
2189 funcOffset = ENTRYPOINT_OFFSET(pLmul);
2190 break;
2191 case Instruction::DIV_LONG:
2192 case Instruction::DIV_LONG_2ADDR:
2193 callOut = true;
2194 checkZero = true;
2195 retReg = rRET0;
jeffhao644d5312012-05-03 19:04:49 -07002196 funcOffset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002197 break;
2198 case Instruction::REM_LONG:
2199 case Instruction::REM_LONG_2ADDR:
2200 callOut = true;
2201 checkZero = true;
jeffhao644d5312012-05-03 19:04:49 -07002202 funcOffset = ENTRYPOINT_OFFSET(pLdivmod);
Ian Rogers55bd45f2012-04-04 17:31:20 -07002203#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002204 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2205 retReg = rARG2;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002206#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002207 retReg = rRET0;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002208#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002209 break;
2210 case Instruction::AND_LONG_2ADDR:
2211 case Instruction::AND_LONG:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002212#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002213 return genAndLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002214#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002215 firstOp = kOpAnd;
2216 secondOp = kOpAnd;
2217 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002218#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002219 case Instruction::OR_LONG:
2220 case Instruction::OR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002221#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002222 return genOrLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002223#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002224 firstOp = kOpOr;
2225 secondOp = kOpOr;
2226 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002227#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002228 case Instruction::XOR_LONG:
2229 case Instruction::XOR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002230#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002231 return genXorLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002232#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002233 firstOp = kOpXor;
2234 secondOp = kOpXor;
2235 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002236#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002237 case Instruction::NEG_LONG: {
2238 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002239 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002240 default:
2241 LOG(FATAL) << "Invalid long arith op";
2242 }
2243 if (!callOut) {
2244 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
2245 } else {
2246 oatFlushAllRegs(cUnit); /* Send everything to home location */
2247 if (checkZero) {
2248 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2249#if !defined(TARGET_X86)
2250 int rTgt = loadHelper(cUnit, funcOffset);
2251#endif
2252 int tReg = oatAllocTemp(cUnit);
2253#if defined(TARGET_ARM)
2254 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2255 oatFreeTemp(cUnit, tReg);
2256 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
2257#else
2258 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
2259#endif
2260 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
2261 oatFreeTemp(cUnit, tReg);
2262 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2263#if !defined(TARGET_X86)
2264 opReg(cUnit, kOpBlx, rTgt);
2265 oatFreeTemp(cUnit, rTgt);
2266#else
2267 opThreadMem(cUnit, kOpBlx, funcOffset);
2268#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002269 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07002270 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset,
2271 rlSrc1, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002272 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002273 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2274 if (retReg == rRET0)
2275 rlResult = oatGetReturnWide(cUnit, false);
2276 else
2277 rlResult = oatGetReturnWideAlt(cUnit);
2278 storeValueWide(cUnit, rlDest, rlResult);
2279 }
2280 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002281}
2282
2283bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
Bill Buzbeea114add2012-05-03 15:00:40 -07002284 int srcSize, int tgtSize)
buzbee31a4a6f2012-02-28 15:36:15 -08002285{
Bill Buzbeea114add2012-05-03 15:00:40 -07002286 /*
2287 * Don't optimize the register usage since it calls out to support
2288 * functions
2289 */
2290 RegLocation rlSrc;
2291 RegLocation rlDest;
2292 oatFlushAllRegs(cUnit); /* Send everything to home location */
2293 if (srcSize == 1) {
2294 rlSrc = oatGetSrc(cUnit, mir, 0);
2295 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2296 } else {
2297 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
2298 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
2299 }
2300 callRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc);
2301 if (tgtSize == 1) {
2302 RegLocation rlResult;
2303 rlDest = oatGetDest(cUnit, mir, 0);
2304 rlResult = oatGetReturn(cUnit, rlDest.fp);
2305 storeValue(cUnit, rlDest, rlResult);
2306 } else {
2307 RegLocation rlResult;
2308 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
2309 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
2310 storeValueWide(cUnit, rlDest, rlResult);
2311 }
2312 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002313}
2314
2315void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
2316bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
2317 RegLocation rlDest, RegLocation rlSrc1,
2318 RegLocation rlSrc2)
2319{
Bill Buzbeea114add2012-05-03 15:00:40 -07002320 RegLocation rlResult;
2321 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002322
Bill Buzbeea114add2012-05-03 15:00:40 -07002323 switch (mir->dalvikInsn.opcode) {
2324 case Instruction::ADD_FLOAT_2ADDR:
2325 case Instruction::ADD_FLOAT:
2326 funcOffset = ENTRYPOINT_OFFSET(pFadd);
2327 break;
2328 case Instruction::SUB_FLOAT_2ADDR:
2329 case Instruction::SUB_FLOAT:
2330 funcOffset = ENTRYPOINT_OFFSET(pFsub);
2331 break;
2332 case Instruction::DIV_FLOAT_2ADDR:
2333 case Instruction::DIV_FLOAT:
2334 funcOffset = ENTRYPOINT_OFFSET(pFdiv);
2335 break;
2336 case Instruction::MUL_FLOAT_2ADDR:
2337 case Instruction::MUL_FLOAT:
2338 funcOffset = ENTRYPOINT_OFFSET(pFmul);
2339 break;
2340 case Instruction::REM_FLOAT_2ADDR:
2341 case Instruction::REM_FLOAT:
2342 funcOffset = ENTRYPOINT_OFFSET(pFmodf);
2343 break;
2344 case Instruction::NEG_FLOAT: {
2345 genNegFloat(cUnit, rlDest, rlSrc1);
2346 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002347 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002348 default:
2349 return true;
2350 }
2351 oatFlushAllRegs(cUnit); /* Send everything to home location */
2352 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
2353 rlResult = oatGetReturn(cUnit, true);
2354 storeValue(cUnit, rlDest, rlResult);
2355 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002356}
2357
2358void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
2359bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
2360 RegLocation rlDest, RegLocation rlSrc1,
2361 RegLocation rlSrc2)
2362{
Bill Buzbeea114add2012-05-03 15:00:40 -07002363 RegLocation rlResult;
2364 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002365
Bill Buzbeea114add2012-05-03 15:00:40 -07002366 switch (mir->dalvikInsn.opcode) {
2367 case Instruction::ADD_DOUBLE_2ADDR:
2368 case Instruction::ADD_DOUBLE:
2369 funcOffset = ENTRYPOINT_OFFSET(pDadd);
2370 break;
2371 case Instruction::SUB_DOUBLE_2ADDR:
2372 case Instruction::SUB_DOUBLE:
2373 funcOffset = ENTRYPOINT_OFFSET(pDsub);
2374 break;
2375 case Instruction::DIV_DOUBLE_2ADDR:
2376 case Instruction::DIV_DOUBLE:
2377 funcOffset = ENTRYPOINT_OFFSET(pDdiv);
2378 break;
2379 case Instruction::MUL_DOUBLE_2ADDR:
2380 case Instruction::MUL_DOUBLE:
2381 funcOffset = ENTRYPOINT_OFFSET(pDmul);
2382 break;
2383 case Instruction::REM_DOUBLE_2ADDR:
2384 case Instruction::REM_DOUBLE:
2385 funcOffset = ENTRYPOINT_OFFSET(pFmod);
2386 break;
2387 case Instruction::NEG_DOUBLE: {
2388 genNegDouble(cUnit, rlDest, rlSrc1);
2389 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002390 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002391 default:
2392 return true;
2393 }
2394 oatFlushAllRegs(cUnit); /* Send everything to home location */
2395 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
2396 rlResult = oatGetReturnWide(cUnit, true);
2397 storeValueWide(cUnit, rlDest, rlResult);
2398 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002399}
2400
2401bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2402{
Bill Buzbeea114add2012-05-03 15:00:40 -07002403 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08002404
Bill Buzbeea114add2012-05-03 15:00:40 -07002405 switch (opcode) {
2406 case Instruction::INT_TO_FLOAT:
2407 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pI2f),
2408 1, 1);
2409 case Instruction::FLOAT_TO_INT:
2410 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pF2iz),
2411 1, 1);
2412 case Instruction::DOUBLE_TO_FLOAT:
2413 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pD2f),
2414 2, 1);
2415 case Instruction::FLOAT_TO_DOUBLE:
2416 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pF2d),
2417 1, 2);
2418 case Instruction::INT_TO_DOUBLE:
2419 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pI2d),
2420 1, 2);
2421 case Instruction::DOUBLE_TO_INT:
2422 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pD2iz),
2423 2, 1);
2424 case Instruction::FLOAT_TO_LONG:
2425 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pF2l),
2426 1, 2);
2427 case Instruction::LONG_TO_FLOAT:
2428 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pL2f),
2429 2, 1);
2430 case Instruction::DOUBLE_TO_LONG:
2431 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pD2l),
2432 2, 2);
2433 case Instruction::LONG_TO_DOUBLE:
2434 return genConversionCall(cUnit, mir, ENTRYPOINT_OFFSET(pL2d),
2435 2, 2);
2436 default:
2437 return true;
2438 }
2439 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002440}
2441
2442/*
2443 * Generate callout to updateDebugger. Note that we're overloading
2444 * the use of rSUSPEND here. When the debugger is active, this
2445 * register holds the address of the update function. So, if it's
2446 * non-null, we call out to it.
2447 *
2448 * Note also that rRET0 and rRET1 must be preserved across this
2449 * code. This must be handled by the stub.
2450 */
2451void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2452{
Bill Buzbeea114add2012-05-03 15:00:40 -07002453 // Following DCHECK verifies that dPC is in range of single load immediate
2454 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2455 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2456 oatClobberCalleeSave(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002457#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002458 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
2459 opIT(cUnit, kArmCondNe, "T");
2460 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2461 opReg(cUnit, kOpBlx, rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002462#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002463 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002464#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002465 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
2466 loadConstant(cUnit, rARG2, offset);
2467 opReg(cUnit, kOpBlx, rSUSPEND);
2468 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
2469 branch->target = (LIR*)target;
buzbee31a4a6f2012-02-28 15:36:15 -08002470#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002471 oatFreeTemp(cUnit, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08002472}
2473
2474/* Check if we need to check for pending suspend request */
2475void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2476{
Bill Buzbeea114add2012-05-03 15:00:40 -07002477 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2478 return;
2479 }
2480 oatFlushAllRegs(cUnit);
2481 if (cUnit->genDebugger) {
2482 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002483#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002484 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002485#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002486 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
2487 opReg(cUnit, kOpBlx, rTgt);
2488 // Refresh rSUSPEND
2489 loadWordDisp(cUnit, rSELF,
2490 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode),
2491 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002492#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002493 } else {
2494 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002495#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002496 // In non-debug case, only check periodically
2497 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2498 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002499#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002500 newLIR2(cUnit, kX86Cmp32TI8, Thread::SuspendCountOffset().Int32Value(), 0);
2501 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002502#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002503 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2504 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002505#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002506 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2507 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2508 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
2509 branch->target = (LIR*)target;
2510 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
2511 }
buzbee31a4a6f2012-02-28 15:36:15 -08002512}
2513
buzbeefead2932012-03-30 14:02:01 -07002514/* Check if we need to check for pending suspend request */
2515void genSuspendTestAndBranch(CompilationUnit* cUnit, MIR* mir, LIR* target)
2516{
Bill Buzbeea114add2012-05-03 15:00:40 -07002517 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2518 opUnconditionalBranch(cUnit, target);
2519 return;
2520 }
2521 if (cUnit->genDebugger) {
2522 genSuspendTest(cUnit, mir);
2523 opUnconditionalBranch(cUnit, target);
2524 } else {
buzbeefead2932012-03-30 14:02:01 -07002525#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002526 // In non-debug case, only check periodically
2527 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2528 opCondBranch(cUnit, kCondNe, target);
buzbeefead2932012-03-30 14:02:01 -07002529#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002530 newLIR2(cUnit, kX86Cmp32TI8, Thread::SuspendCountOffset().Int32Value(), 0);
2531 opCondBranch(cUnit, kCondEq, target);
buzbeefead2932012-03-30 14:02:01 -07002532#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002533 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2534 opCmpImmBranch(cUnit, kCondNe, rSUSPEND, 0, target);
buzbeefead2932012-03-30 14:02:01 -07002535#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002536 LIR* launchPad = rawLIR(cUnit, cUnit->currentDalvikOffset,
2537 kPseudoSuspendTarget, (intptr_t)target, mir->offset);
2538 oatFlushAllRegs(cUnit);
2539 opUnconditionalBranch(cUnit, launchPad);
2540 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads,
2541 (intptr_t)launchPad);
2542 }
buzbeefead2932012-03-30 14:02:01 -07002543}
2544
buzbee31a4a6f2012-02-28 15:36:15 -08002545} // namespace art