blob: 2bd93331a6966e37c9c84eea14191cd39fcc86c3 [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)
buzbee408ad162012-06-06 16:45:18 -0700328LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee31a4a6f2012-02-28 15:36:15 -0800329 ThrowKind kind)
330{
Bill Buzbeea114add2012-05-03 15:00:40 -0700331 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700332 cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700333 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,
buzbee408ad162012-06-06 16:45:18 -0700341 int reg, int immVal, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800342{
buzbee408ad162012-06-06 16:45:18 -0700343 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
344 cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700345 LIR* branch;
346 if (cCode == kCondAl) {
347 branch = opUnconditionalBranch(cUnit, tgt);
348 } else {
349 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
350 }
351 // Remember branch target - will process later
352 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
353 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800354}
355
356/* Perform null-check on a register. */
buzbee408ad162012-06-06 16:45:18 -0700357LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -0800358{
Bill Buzbeea114add2012-05-03 15:00:40 -0700359 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
buzbee408ad162012-06-06 16:45:18 -0700360 optFlags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700361 return NULL;
362 }
buzbee408ad162012-06-06 16:45:18 -0700363 return genImmedCheck(cUnit, kCondEq, mReg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -0800364}
365
366/* Perform check on two registers */
367LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -0700368 int reg1, int reg2, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800369{
Bill Buzbeea114add2012-05-03 15:00:40 -0700370 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700371 cUnit->currentDalvikOffset, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800372#if defined(TARGET_MIPS)
Bill Buzbeea114add2012-05-03 15:00:40 -0700373 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800374#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700375 opRegReg(cUnit, kOpCmp, reg1, reg2);
376 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800377#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700378 // Remember branch target - will process later
379 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
380 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800381}
382
buzbee408ad162012-06-06 16:45:18 -0700383void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
384 Instruction::Code opcode, RegLocation rlSrc1,
385 RegLocation rlSrc2, LIR* labelList)
buzbee31a4a6f2012-02-28 15:36:15 -0800386{
Bill Buzbeea114add2012-05-03 15:00:40 -0700387 ConditionCode cond;
388 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
389 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700390 switch (opcode) {
391 case Instruction::IF_EQ:
392 cond = kCondEq;
393 break;
394 case Instruction::IF_NE:
395 cond = kCondNe;
396 break;
397 case Instruction::IF_LT:
398 cond = kCondLt;
399 break;
400 case Instruction::IF_GE:
401 cond = kCondGe;
402 break;
403 case Instruction::IF_GT:
404 cond = kCondGt;
405 break;
406 case Instruction::IF_LE:
407 cond = kCondLe;
408 break;
409 default:
410 cond = (ConditionCode)0;
411 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
412 }
buzbee5de34942012-03-01 14:51:57 -0800413#if defined(TARGET_MIPS)
Bill Buzbeea114add2012-05-03 15:00:40 -0700414 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg,
415 &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800416#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700417 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
418 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800419#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700420 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800421}
422
buzbee408ad162012-06-06 16:45:18 -0700423void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
424 Instruction::Code opcode, RegLocation rlSrc,
425 LIR* labelList)
buzbee31a4a6f2012-02-28 15:36:15 -0800426{
Bill Buzbeea114add2012-05-03 15:00:40 -0700427 ConditionCode cond;
428 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700429 switch (opcode) {
430 case Instruction::IF_EQZ:
431 cond = kCondEq;
432 break;
433 case Instruction::IF_NEZ:
434 cond = kCondNe;
435 break;
436 case Instruction::IF_LTZ:
437 cond = kCondLt;
438 break;
439 case Instruction::IF_GEZ:
440 cond = kCondGe;
441 break;
442 case Instruction::IF_GTZ:
443 cond = kCondGt;
444 break;
445 case Instruction::IF_LEZ:
446 cond = kCondLe;
447 break;
448 default:
449 cond = (ConditionCode)0;
450 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
451 }
Ian Rogers7caad772012-03-30 01:07:54 -0700452#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700453 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800454#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700455 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
456 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800457#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700458 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800459}
460
buzbee408ad162012-06-06 16:45:18 -0700461void genIntToLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800462 RegLocation rlSrc)
463{
Bill Buzbeea114add2012-05-03 15:00:40 -0700464 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
465 if (rlSrc.location == kLocPhysReg) {
466 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
467 } else {
468 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
469 }
470 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
471 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800472}
473
buzbee408ad162012-06-06 16:45:18 -0700474void genIntNarrowing(CompilationUnit* cUnit, Instruction::Code opcode,
475 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800476{
Bill Buzbeea114add2012-05-03 15:00:40 -0700477 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
478 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
479 OpKind op = kOpInvalid;
buzbee408ad162012-06-06 16:45:18 -0700480 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700481 case Instruction::INT_TO_BYTE:
482 op = kOp2Byte;
483 break;
484 case Instruction::INT_TO_SHORT:
485 op = kOp2Short;
486 break;
487 case Instruction::INT_TO_CHAR:
488 op = kOp2Char;
489 break;
490 default:
491 LOG(ERROR) << "Bad int conversion type";
492 }
493 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
494 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800495}
496
497/*
498 * Let helper function take care of everything. Will call
499 * Array::AllocFromCode(type_idx, method, count);
500 * Note: AllocFromCode will handle checks for errNegativeArraySize.
501 */
buzbee408ad162012-06-06 16:45:18 -0700502void genNewArray(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800503 RegLocation rlSrc)
504{
Bill Buzbeea114add2012-05-03 15:00:40 -0700505 oatFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700506 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)
jeffhao5772bab2012-05-18 11:51:26 -0700585 oatFreeTemp(cUnit, rRET0);
586 int rVal = oatAllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700587#else
588 int rVal = oatAllocTemp(cUnit);
589#endif
590 // Set up source pointer
591 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
592 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
593 oatSRegOffset(cUnit, rlFirst.sRegLow));
594 // Set up the target pointer
595 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
596 Array::DataOffset(component_size).Int32Value());
597 // Set up the loop counter (known to be > 0)
598 loadConstant(cUnit, rIdx, dInsn->vA - 1);
599 // Generate the copy loop. Going backwards for convenience
600 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
601 // Copy next element
602 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
603 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
604#if defined(TARGET_ARM)
605 // Combine sub & test using sub setflags encoding here
606 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
607 opCondBranch(cUnit, kCondGe, target);
608#else
609 oatFreeTemp(cUnit, rVal);
610 opRegImm(cUnit, kOpSub, rIdx, 1);
611 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
612#endif
jeffhao5772bab2012-05-18 11:51:26 -0700613#if defined(TARGET_X86)
614 // Restore the target pointer
615 opRegRegImm(cUnit, kOpAdd, rRET0, rDst,
616 -Array::DataOffset(component_size).Int32Value());
617#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700618 } else if (!isRange) {
619 // TUNING: interleave
620 for (unsigned int i = 0; i < dInsn->vA; i++) {
621 RegLocation rlArg = loadValue(cUnit, oatGetSrc(cUnit, mir, i), kCoreReg);
622 storeBaseDisp(cUnit, rRET0,
623 Array::DataOffset(component_size).Int32Value() +
624 i * 4, rlArg.lowReg, kWord);
625 // If the loadValue caused a temp to be allocated, free it
626 if (oatIsTemp(cUnit, rlArg.lowReg)) {
627 oatFreeTemp(cUnit, rlArg.lowReg);
628 }
629 }
630 }
buzbee31a4a6f2012-02-28 15:36:15 -0800631}
632
buzbee408ad162012-06-06 16:45:18 -0700633void genSput(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlSrc,
Bill Buzbeea114add2012-05-03 15:00:40 -0700634 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800635{
Bill Buzbeea114add2012-05-03 15:00:40 -0700636 int fieldOffset;
637 int ssbIndex;
638 bool isVolatile;
639 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800640
Bill Buzbeea114add2012-05-03 15:00:40 -0700641 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
642 *cUnit->dex_file, *cUnit->dex_cache,
643 cUnit->code_item, cUnit->method_idx,
644 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800645
Bill Buzbeea114add2012-05-03 15:00:40 -0700646 bool fastPath =
647 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
648 fieldOffset, ssbIndex,
649 isReferrersClass, isVolatile,
650 true);
651 if (fastPath && !SLOW_FIELD_PATH) {
652 DCHECK_GE(fieldOffset, 0);
653 int rBase;
654 if (isReferrersClass) {
655 // Fast path, static storage base is this method's class
656 RegLocation rlMethod = loadCurrMethod(cUnit);
657 rBase = oatAllocTemp(cUnit);
658 loadWordDisp(cUnit, rlMethod.lowReg,
659 Method::DeclaringClassOffset().Int32Value(), rBase);
660 if (oatIsTemp(cUnit, rlMethod.lowReg)) {
661 oatFreeTemp(cUnit, rlMethod.lowReg);
662 }
buzbee31a4a6f2012-02-28 15:36:15 -0800663 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700664 // Medium path, static storage base in a different class which
665 // requires checks that the other class is initialized.
666 DCHECK_GE(ssbIndex, 0);
667 // May do runtime call so everything to home locations.
668 oatFlushAllRegs(cUnit);
669 // Using fixed register to sync with possible call to runtime
670 // support.
671 int rMethod = rARG1;
672 oatLockTemp(cUnit, rMethod);
673 loadCurrMethodDirect(cUnit, rMethod);
674 rBase = rARG0;
675 oatLockTemp(cUnit, rBase);
676 loadWordDisp(cUnit, rMethod,
677 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
678 rBase);
679 loadWordDisp(cUnit, rBase,
680 Array::DataOffset(sizeof(Object*)).Int32Value() +
681 sizeof(int32_t*) * ssbIndex, rBase);
682 // rBase now points at appropriate static storage base (Class*)
683 // or NULL if not initialized. Check for NULL and call helper if NULL.
684 // TUNING: fast path should fall through
685 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
686 loadConstant(cUnit, rARG0, ssbIndex);
687 callRuntimeHelperImm(cUnit,
688 ENTRYPOINT_OFFSET(pInitializeStaticStorage),
689 ssbIndex);
690#if defined(TARGET_MIPS)
691 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
692 opRegCopy(cUnit, rBase, rRET0);
693#endif
694 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
695 branchOver->target = (LIR*)skipTarget;
696 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800697 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700698 // rBase now holds static storage base
699 if (isLongOrDouble) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700700 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
701 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700702 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
703 }
704//FIXME: need to generalize the barrier call
705 if (isVolatile) {
706 oatGenMemBarrier(cUnit, kST);
707 }
708 if (isLongOrDouble) {
709 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
710 rlSrc.highReg);
711 } else {
712 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
713 }
714 if (isVolatile) {
715 oatGenMemBarrier(cUnit, kSY);
716 }
717 if (isObject) {
718 markGCCard(cUnit, rlSrc.lowReg, rBase);
719 }
720 oatFreeTemp(cUnit, rBase);
721 } else {
722 oatFlushAllRegs(cUnit); // Everything to home locations
723 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Static) :
724 (isObject ? ENTRYPOINT_OFFSET(pSetObjStatic)
725 : ENTRYPOINT_OFFSET(pSet32Static));
726 callRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc);
727 }
buzbee31a4a6f2012-02-28 15:36:15 -0800728}
729
buzbee408ad162012-06-06 16:45:18 -0700730void genSget(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700731 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800732{
Bill Buzbeea114add2012-05-03 15:00:40 -0700733 int fieldOffset;
734 int ssbIndex;
735 bool isVolatile;
736 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800737
Bill Buzbeea114add2012-05-03 15:00:40 -0700738 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
739 *cUnit->dex_file, *cUnit->dex_cache,
740 cUnit->code_item, cUnit->method_idx,
741 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800742
Bill Buzbeea114add2012-05-03 15:00:40 -0700743 bool fastPath =
744 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
745 fieldOffset, ssbIndex,
746 isReferrersClass, isVolatile,
747 false);
748 if (fastPath && !SLOW_FIELD_PATH) {
749 DCHECK_GE(fieldOffset, 0);
750 int rBase;
751 if (isReferrersClass) {
752 // Fast path, static storage base is this method's class
753 RegLocation rlMethod = loadCurrMethod(cUnit);
754 rBase = oatAllocTemp(cUnit);
755 loadWordDisp(cUnit, rlMethod.lowReg,
756 Method::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800757 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700758 // Medium path, static storage base in a different class which
759 // requires checks that the other class is initialized
760 DCHECK_GE(ssbIndex, 0);
761 // May do runtime call so everything to home locations.
762 oatFlushAllRegs(cUnit);
763 // Using fixed register to sync with possible call to runtime
764 // support
765 int rMethod = rARG1;
766 oatLockTemp(cUnit, rMethod);
767 loadCurrMethodDirect(cUnit, rMethod);
768 rBase = rARG0;
769 oatLockTemp(cUnit, rBase);
770 loadWordDisp(cUnit, rMethod,
771 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
772 rBase);
773 loadWordDisp(cUnit, rBase,
774 Array::DataOffset(sizeof(Object*)).Int32Value() +
775 sizeof(int32_t*) * ssbIndex, rBase);
776 // rBase now points at appropriate static storage base (Class*)
777 // or NULL if not initialized. Check for NULL and call helper if NULL.
778 // TUNING: fast path should fall through
779 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
780 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage),
781 ssbIndex);
782#if defined(TARGET_MIPS)
783 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
784 opRegCopy(cUnit, rBase, rRET0);
785#endif
786 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
787 branchOver->target = (LIR*)skipTarget;
788 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800789 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700790 // rBase now holds static storage base
Bill Buzbeea114add2012-05-03 15:00:40 -0700791 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
792 if (isVolatile) {
793 oatGenMemBarrier(cUnit, kSY);
794 }
795 if (isLongOrDouble) {
buzbee408ad162012-06-06 16:45:18 -0700796 loadBaseDispWide(cUnit, rBase, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700797 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
buzbee408ad162012-06-06 16:45:18 -0700837void genThrowVerificationError(CompilationUnit* cUnit, int info1, int info2)
buzbee31a4a6f2012-02-28 15:36:15 -0800838{
Bill Buzbeea114add2012-05-03 15:00:40 -0700839 callRuntimeHelperImmImm(cUnit,
840 ENTRYPOINT_OFFSET(pThrowVerificationErrorFromCode),
buzbee408ad162012-06-06 16:45:18 -0700841 info1, info2);
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
buzbee408ad162012-06-06 16:45:18 -0700979void genIGet(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -0800980 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;
buzbee31a4a6f2012-02-28 15:36:15 -0800985
Bill Buzbeea114add2012-05-03 15:00:40 -0700986 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800987
Bill Buzbeea114add2012-05-03 15:00:40 -0700988 if (fastPath && !SLOW_FIELD_PATH) {
989 RegLocation rlResult;
990 RegisterClass regClass = oatRegClassBySize(size);
991 DCHECK_GE(fieldOffset, 0);
992 rlObj = loadValue(cUnit, rlObj, kCoreReg);
993 if (isLongOrDouble) {
994 DCHECK(rlDest.wide);
buzbee408ad162012-06-06 16:45:18 -0700995 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800996#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700997 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -0700998 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
999 loadBaseDispWide(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -07001000 rlResult.highReg, rlObj.sRegLow);
1001 if (isVolatile) {
1002 oatGenMemBarrier(cUnit, kSY);
1003 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001004#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001005 int regPtr = oatAllocTemp(cUnit);
1006 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1007 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1008 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1009 if (isVolatile) {
1010 oatGenMemBarrier(cUnit, kSY);
1011 }
1012 oatFreeTemp(cUnit, regPtr);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001013#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001014 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001015 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001016 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001017 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
1018 loadBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -07001019 kWord, rlObj.sRegLow);
1020 if (isVolatile) {
1021 oatGenMemBarrier(cUnit, kSY);
1022 }
1023 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001024 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001025 } else {
1026 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Instance) :
1027 (isObject ? ENTRYPOINT_OFFSET(pGetObjInstance)
1028 : ENTRYPOINT_OFFSET(pGet32Instance));
1029 callRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj);
1030 if (isLongOrDouble) {
1031 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
1032 storeValueWide(cUnit, rlDest, rlResult);
1033 } else {
1034 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
1035 storeValue(cUnit, rlDest, rlResult);
1036 }
1037 }
buzbee31a4a6f2012-02-28 15:36:15 -08001038}
1039
buzbee408ad162012-06-06 16:45:18 -07001040void genIPut(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
1041 RegLocation rlSrc, RegLocation rlObj, bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -08001042{
Bill Buzbeea114add2012-05-03 15:00:40 -07001043 int fieldOffset;
1044 bool isVolatile;
buzbee31a4a6f2012-02-28 15:36:15 -08001045
Bill Buzbeea114add2012-05-03 15:00:40 -07001046 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
1047 true);
1048 if (fastPath && !SLOW_FIELD_PATH) {
1049 RegisterClass regClass = oatRegClassBySize(size);
1050 DCHECK_GE(fieldOffset, 0);
1051 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1052 if (isLongOrDouble) {
1053 int regPtr;
1054 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee408ad162012-06-06 16:45:18 -07001055 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07001056 regPtr = oatAllocTemp(cUnit);
1057 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1058 if (isVolatile) {
1059 oatGenMemBarrier(cUnit, kST);
1060 }
jeffhao41005dd2012-05-09 17:58:52 -07001061 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001062 if (isVolatile) {
1063 oatGenMemBarrier(cUnit, kSY);
1064 }
1065 oatFreeTemp(cUnit, regPtr);
buzbee31a4a6f2012-02-28 15:36:15 -08001066 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001067 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee408ad162012-06-06 16:45:18 -07001068 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07001069 if (isVolatile) {
1070 oatGenMemBarrier(cUnit, kST);
1071 }
1072 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
1073 if (isVolatile) {
1074 oatGenMemBarrier(cUnit, kSY);
1075 }
1076 if (isObject) {
1077 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
1078 }
buzbee31a4a6f2012-02-28 15:36:15 -08001079 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001080 } else {
1081 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Instance) :
1082 (isObject ? ENTRYPOINT_OFFSET(pSetObjInstance)
1083 : ENTRYPOINT_OFFSET(pSet32Instance));
1084 callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset,
1085 fieldIdx, rlObj, rlSrc);
1086 }
buzbee31a4a6f2012-02-28 15:36:15 -08001087}
1088
buzbee408ad162012-06-06 16:45:18 -07001089void genConstClass(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001090 RegLocation rlSrc)
1091{
Bill Buzbeea114add2012-05-03 15:00:40 -07001092 RegLocation rlMethod = loadCurrMethod(cUnit);
1093 int resReg = oatAllocTemp(cUnit);
1094 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1095 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1096 cUnit->dex_cache,
1097 *cUnit->dex_file,
1098 type_idx)) {
1099 // Call out to helper which resolves type and verifies access.
1100 // Resolved type returned in rRET0.
1101 callRuntimeHelperImmReg(cUnit,
1102 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1103 type_idx, rlMethod.lowReg);
1104 RegLocation rlResult = oatGetReturn(cUnit, false);
1105 storeValue(cUnit, rlDest, rlResult);
1106 } else {
1107 // We're don't need access checks, load type from dex cache
1108 int32_t dex_cache_offset =
1109 Method::DexCacheResolvedTypesOffset().Int32Value();
1110 loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
1111 int32_t offset_of_type =
1112 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1113 * type_idx);
1114 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
1115 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
1116 type_idx) || SLOW_TYPE_PATH) {
1117 // Slow path, at runtime test if type is null and if so initialize
1118 oatFlushAllRegs(cUnit);
1119 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0, NULL);
1120 // Resolved, store and hop over following code
1121 storeValue(cUnit, rlDest, rlResult);
1122 /*
1123 * Because we have stores of the target value on two paths,
1124 * clobber temp tracking for the destination using the ssa name
1125 */
1126 oatClobberSReg(cUnit, rlDest.sRegLow);
1127 LIR* branch2 = opUnconditionalBranch(cUnit,0);
1128 // TUNING: move slow path to end & remove unconditional branch
1129 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
1130 // Call out to helper, which will return resolved type in rARG0
1131 callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1132 type_idx, rlMethod.lowReg);
1133 RegLocation rlResult = oatGetReturn(cUnit, false);
1134 storeValue(cUnit, rlDest, rlResult);
1135 /*
1136 * Because we have stores of the target value on two paths,
1137 * clobber temp tracking for the destination using the ssa name
1138 */
1139 oatClobberSReg(cUnit, rlDest.sRegLow);
1140 // Rejoin code paths
1141 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
1142 branch1->target = (LIR*)target1;
1143 branch2->target = (LIR*)target2;
buzbee31a4a6f2012-02-28 15:36:15 -08001144 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001145 // Fast path, we're done - just store result
1146 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001147 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001148 }
buzbee31a4a6f2012-02-28 15:36:15 -08001149}
Ian Rogersab2b55d2012-03-18 00:06:11 -07001150
buzbee408ad162012-06-06 16:45:18 -07001151void genConstString(CompilationUnit* cUnit, uint32_t string_idx, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001152 RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08001153{
Bill Buzbeea114add2012-05-03 15:00:40 -07001154 /* NOTE: Most strings should be available at compile time */
Bill Buzbeea114add2012-05-03 15:00:40 -07001155 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1156 (sizeof(String*) * string_idx);
1157 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
1158 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
1159 // slow path, resolve string if not in dex cache
1160 oatFlushAllRegs(cUnit);
1161 oatLockCallTemps(cUnit); // Using explicit registers
1162 loadCurrMethodDirect(cUnit, rARG2);
1163 loadWordDisp(cUnit, rARG2,
1164 Method::DexCacheStringsOffset().Int32Value(), rARG0);
1165 // Might call out to helper, which will return resolved string in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001166#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001167 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001168#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001169 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
1170 loadConstant(cUnit, rARG1, string_idx);
buzbee31a4a6f2012-02-28 15:36:15 -08001171#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001172 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
1173 genBarrier(cUnit);
1174 // For testing, always force through helper
1175 if (!EXERCISE_SLOWEST_STRING_PATH) {
1176 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08001177 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001178 opRegCopy(cUnit, rARG0, rARG2); // .eq
1179 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
1180 oatFreeTemp(cUnit, rTgt);
1181#elif defined(TARGET_MIPS)
1182 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
1183 opRegCopy(cUnit, rARG0, rARG2); // .eq
1184 opReg(cUnit, kOpBlx, rTgt);
1185 oatFreeTemp(cUnit, rTgt);
1186 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1187 branch->target = target;
1188#else
1189 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode),
1190 rARG2, rARG1);
1191#endif
1192 genBarrier(cUnit);
1193 storeValue(cUnit, rlDest, oatGetReturn(cUnit, false));
1194 } else {
1195 RegLocation rlMethod = loadCurrMethod(cUnit);
1196 int resReg = oatAllocTemp(cUnit);
1197 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1198 loadWordDisp(cUnit, rlMethod.lowReg,
1199 Method::DexCacheStringsOffset().Int32Value(), resReg);
1200 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1201 storeValue(cUnit, rlDest, rlResult);
1202 }
buzbee31a4a6f2012-02-28 15:36:15 -08001203}
1204
1205/*
1206 * Let helper function take care of everything. Will
1207 * call Class::NewInstanceFromCode(type_idx, method);
1208 */
buzbee408ad162012-06-06 16:45:18 -07001209void genNewInstance(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001210{
Bill Buzbeea114add2012-05-03 15:00:40 -07001211 oatFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -07001212 // alloc will always check for resolution, do we also need to verify
1213 // access because the verifier was unable to?
1214 int funcOffset;
1215 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
1216 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
1217 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
1218 } else {
1219 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
1220 }
1221 callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx);
1222 RegLocation rlResult = oatGetReturn(cUnit, false);
1223 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001224}
1225
buzbee408ad162012-06-06 16:45:18 -07001226void genThrow(CompilationUnit* cUnit, RegLocation rlSrc)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001227{
Bill Buzbeea114add2012-05-03 15:00:40 -07001228 oatFlushAllRegs(cUnit);
1229 callRuntimeHelperRegLocation(cUnit, ENTRYPOINT_OFFSET(pDeliverException),
1230 rlSrc);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001231}
1232
buzbee408ad162012-06-06 16:45:18 -07001233void genInstanceof(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001234 RegLocation rlSrc)
1235{
Bill Buzbeea114add2012-05-03 15:00:40 -07001236 oatFlushAllRegs(cUnit);
1237 // May generate a call - use explicit registers
1238 oatLockCallTemps(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001239 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1240 int classReg = rARG2; // rARG2 will hold the Class*
1241 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1242 cUnit->dex_cache,
1243 *cUnit->dex_file,
1244 type_idx)) {
1245 // Check we have access to type_idx and if not throw IllegalAccessError,
1246 // returns Class* in rARG0
1247 callRuntimeHelperImm(cUnit,
1248 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1249 type_idx);
1250 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1251 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1252 } else {
1253 // Load dex cache entry into classReg (rARG2)
1254 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1255 loadWordDisp(cUnit, rARG1,
1256 Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
1257 int32_t offset_of_type =
1258 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1259 * type_idx);
1260 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1261 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1262 cUnit->dex_cache, type_idx)) {
1263 // Need to test presence of type in dex cache at runtime
1264 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1265 // Not resolved
1266 // Call out to helper, which will return resolved type in rRET0
1267 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1268 type_idx);
1269 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
1270 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1271 // Rejoin code paths
1272 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1273 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001274 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001275 }
1276 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
1277 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1278 /* load object->klass_ */
1279 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1280 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1281 /* rARG0 is ref, rARG1 is ref->klass_, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001282#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001283 /* Uses conditional nullification */
1284 int rTgt = loadHelper(cUnit,
1285 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1286 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
1287 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
1288 loadConstant(cUnit, rARG0, 1); // .eq case - load true
1289 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1290 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1291 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001292#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001293 /* Uses branchovers */
1294 loadConstant(cUnit, rARG0, 1); // assume true
1295 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001296#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001297 int rTgt = loadHelper(cUnit,
1298 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1299 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1300 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1301 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001302#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001303 opRegCopy(cUnit, rARG0, rARG2);
1304 opThreadMem(cUnit, kOpBlx,
1305 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001306#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001307#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001308 oatClobberCalleeSave(cUnit);
1309 /* branch targets here */
1310 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1311 RegLocation rlResult = oatGetReturn(cUnit, false);
1312 storeValue(cUnit, rlDest, rlResult);
1313 branch1->target = target;
buzbee0398c422012-03-02 15:22:47 -08001314#if !defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001315 branchover->target = target;
buzbee0398c422012-03-02 15:22:47 -08001316#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001317}
1318
buzbee408ad162012-06-06 16:45:18 -07001319void genCheckCast(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08001320{
Bill Buzbeea114add2012-05-03 15:00:40 -07001321 oatFlushAllRegs(cUnit);
1322 // May generate a call - use explicit registers
1323 oatLockCallTemps(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001324 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1325 int classReg = rARG2; // rARG2 will hold the Class*
1326 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1327 cUnit->dex_cache,
1328 *cUnit->dex_file,
1329 type_idx)) {
1330 // Check we have access to type_idx and if not throw IllegalAccessError,
1331 // returns Class* in rRET0
1332 // InitializeTypeAndVerifyAccess(idx, method)
1333 callRuntimeHelperImmReg(cUnit,
1334 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1335 type_idx, rARG1);
1336 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1337 } else {
1338 // Load dex cache entry into classReg (rARG2)
1339 loadWordDisp(cUnit, rARG1,
1340 Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
1341 int32_t offset_of_type =
1342 Array::DataOffset(sizeof(Class*)).Int32Value() +
1343 (sizeof(Class*) * type_idx);
1344 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1345 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1346 cUnit->dex_cache, type_idx)) {
1347 // Need to test presence of type in dex cache at runtime
1348 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1349 // Not resolved
1350 // Call out to helper, which will return resolved type in rARG0
1351 // InitializeTypeFromCode(idx, method)
1352 callRuntimeHelperImmReg(cUnit,
1353 ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1354 type_idx, rARG1);
1355 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
1356 // Rejoin code paths
1357 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1358 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001359 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001360 }
1361 // At this point, classReg (rARG2) has class
1362 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1363 /* Null is OK - continue */
1364 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1365 /* load object->klass_ */
1366 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1367 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1368 /* rARG1 now contains object->klass_ */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001369#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001370 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
1371 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode),
1372 rARG1, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001373#else // defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001374 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1375 opRegReg(cUnit, kOpCmp, rARG1, classReg);
1376 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1377 opRegCopy(cUnit, rARG0, rARG1);
1378 opRegCopy(cUnit, rARG1, rARG2);
1379 oatClobberCalleeSave(cUnit);
1380 opReg(cUnit, kOpBlx, rTgt);
1381 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001382#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001383 /* branch target here */
1384 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1385 branch1->target = target;
1386 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001387}
1388
buzbee31a4a6f2012-02-28 15:36:15 -08001389/*
1390 * Generate array store
1391 *
1392 */
buzbee408ad162012-06-06 16:45:18 -07001393void genArrayObjPut(CompilationUnit* cUnit, int optFlags, RegLocation rlArray,
Bill Buzbeea114add2012-05-03 15:00:40 -07001394 RegLocation rlIndex, RegLocation rlSrc, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001395{
Bill Buzbeea114add2012-05-03 15:00:40 -07001396 int lenOffset = Array::LengthOffset().Int32Value();
1397 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
buzbee31a4a6f2012-02-28 15:36:15 -08001398
Bill Buzbeea114add2012-05-03 15:00:40 -07001399 oatFlushAllRegs(cUnit); // Use explicit registers
1400 oatLockCallTemps(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001401
Bill Buzbeea114add2012-05-03 15:00:40 -07001402 int rValue = rARG0; // Register holding value
1403 int rArrayClass = rARG1; // Register holding array's Class
1404 int rArray = rARG2; // Register holding array
1405 int rIndex = rARG3; // Register holding index into array
Ian Rogersd36c52e2012-04-09 16:29:25 -07001406
Bill Buzbeea114add2012-05-03 15:00:40 -07001407 loadValueDirectFixed(cUnit, rlArray, rArray); // Grab array
1408 loadValueDirectFixed(cUnit, rlSrc, rValue); // Grab value
1409 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Grab index
Ian Rogersd36c52e2012-04-09 16:29:25 -07001410
buzbee408ad162012-06-06 16:45:18 -07001411 genNullCheck(cUnit, rlArray.sRegLow, rArray, optFlags); // NPE?
Ian Rogersd36c52e2012-04-09 16:29:25 -07001412
Bill Buzbeea114add2012-05-03 15:00:40 -07001413 // Store of null?
1414 LIR* null_value_check = opCmpImmBranch(cUnit, kCondEq, rValue, 0, NULL);
Ian Rogersd36c52e2012-04-09 16:29:25 -07001415
Bill Buzbeea114add2012-05-03 15:00:40 -07001416 // Get the array's class.
1417 loadWordDisp(cUnit, rArray, Object::ClassOffset().Int32Value(), rArrayClass);
1418 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode),
1419 rValue, rArrayClass);
1420 // Redo loadValues in case they didn't survive the call.
1421 loadValueDirectFixed(cUnit, rlArray, rArray); // Reload array
1422 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Reload index
1423 loadValueDirectFixed(cUnit, rlSrc, rValue); // Reload value
1424 rArrayClass = INVALID_REG;
buzbee31a4a6f2012-02-28 15:36:15 -08001425
Bill Buzbeea114add2012-05-03 15:00:40 -07001426 // Branch here if value to be stored == null
1427 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1428 null_value_check->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001429
Ian Rogersb41b33b2012-03-20 14:22:54 -07001430#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001431 // make an extra temp available for card mark below
1432 oatFreeTemp(cUnit, rARG1);
buzbee408ad162012-06-06 16:45:18 -07001433 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001434 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
buzbee408ad162012-06-06 16:45:18 -07001435 genRegMemCheck(cUnit, kCondUge, rIndex, rArray, lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001436 }
buzbee408ad162012-06-06 16:45:18 -07001437 storeBaseIndexedDisp(cUnit, rArray, rIndex, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -07001438 dataOffset, rValue, INVALID_REG, kWord, INVALID_SREG);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001439#else
buzbee408ad162012-06-06 16:45:18 -07001440 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001441 int regLen = INVALID_REG;
1442 if (needsRangeCheck) {
1443 regLen = rARG1;
1444 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen); // Get len
1445 }
1446 /* rPtr -> array data */
1447 int rPtr = oatAllocTemp(cUnit);
1448 opRegRegImm(cUnit, kOpAdd, rPtr, rArray, dataOffset);
1449 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001450 genRegRegCheck(cUnit, kCondCs, rIndex, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001451 }
1452 storeBaseIndexed(cUnit, rPtr, rIndex, rValue, scale, kWord);
1453 oatFreeTemp(cUnit, rPtr);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001454#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001455 oatFreeTemp(cUnit, rIndex);
1456 markGCCard(cUnit, rValue, rArray);
buzbee31a4a6f2012-02-28 15:36:15 -08001457}
1458
1459/*
1460 * Generate array load
1461 */
buzbee408ad162012-06-06 16:45:18 -07001462void genArrayGet(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001463 RegLocation rlArray, RegLocation rlIndex,
1464 RegLocation rlDest, int scale)
1465{
Bill Buzbeea114add2012-05-03 15:00:40 -07001466 RegisterClass regClass = oatRegClassBySize(size);
1467 int lenOffset = Array::LengthOffset().Int32Value();
1468 int dataOffset;
1469 RegLocation rlResult;
1470 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1471 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001472
Bill Buzbeea114add2012-05-03 15:00:40 -07001473 if (size == kLong || size == kDouble) {
1474 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1475 } else {
1476 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1477 }
buzbee31a4a6f2012-02-28 15:36:15 -08001478
Bill Buzbeea114add2012-05-03 15:00:40 -07001479 /* null object? */
buzbee408ad162012-06-06 16:45:18 -07001480 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001481
Ian Rogersb5d09b22012-03-06 22:14:17 -08001482#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07001483 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001484 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1485 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
buzbee408ad162012-06-06 16:45:18 -07001486 lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001487 }
1488 if ((size == kLong) || (size == kDouble)) {
jeffhao3f9ace82012-05-25 11:25:36 -07001489 int regAddr = oatAllocTemp(cUnit);
1490 newLIR5(cUnit, kX86Lea32RA, regAddr, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset);
1491 oatFreeTemp(cUnit, rlArray.lowReg);
1492 oatFreeTemp(cUnit, rlIndex.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001493 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001494 loadBaseIndexedDisp(cUnit, regAddr, INVALID_REG, 0, 0, rlResult.lowReg,
jeffhao21e12712012-05-25 19:06:18 -07001495 rlResult.highReg, size, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001496 storeValueWide(cUnit, rlDest, rlResult);
1497 } else {
1498 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001499
buzbee408ad162012-06-06 16:45:18 -07001500 loadBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -07001501 dataOffset, rlResult.lowReg, INVALID_REG, size,
1502 INVALID_SREG);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001503
Bill Buzbeea114add2012-05-03 15:00:40 -07001504 storeValue(cUnit, rlDest, rlResult);
1505 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001506#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001507 int regPtr = oatAllocTemp(cUnit);
buzbee408ad162012-06-06 16:45:18 -07001508 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001509 int regLen = INVALID_REG;
1510 if (needsRangeCheck) {
1511 regLen = oatAllocTemp(cUnit);
1512 /* Get len */
1513 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1514 }
1515 /* regPtr -> array data */
1516 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1517 oatFreeTemp(cUnit, rlArray.lowReg);
1518 if ((size == kLong) || (size == kDouble)) {
1519 if (scale) {
1520 int rNewIndex = oatAllocTemp(cUnit);
1521 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1522 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1523 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001524 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001525 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001526 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001527 oatFreeTemp(cUnit, rlIndex.lowReg);
1528 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1529
1530 if (needsRangeCheck) {
1531 // TODO: change kCondCS to a more meaningful name, is the sense of
1532 // carry-set/clear flipped?
buzbee408ad162012-06-06 16:45:18 -07001533 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001534 oatFreeTemp(cUnit, regLen);
1535 }
1536 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1537
1538 oatFreeTemp(cUnit, regPtr);
1539 storeValueWide(cUnit, rlDest, rlResult);
1540 } else {
1541 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1542
1543 if (needsRangeCheck) {
1544 // TODO: change kCondCS to a more meaningful name, is the sense of
1545 // carry-set/clear flipped?
buzbee408ad162012-06-06 16:45:18 -07001546 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001547 oatFreeTemp(cUnit, regLen);
1548 }
1549 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1550 scale, size);
1551
1552 oatFreeTemp(cUnit, regPtr);
1553 storeValue(cUnit, rlDest, rlResult);
1554 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001555#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001556}
1557
1558/*
1559 * Generate array store
1560 *
1561 */
buzbee408ad162012-06-06 16:45:18 -07001562void genArrayPut(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001563 RegLocation rlArray, RegLocation rlIndex,
1564 RegLocation rlSrc, int scale)
1565{
Bill Buzbeea114add2012-05-03 15:00:40 -07001566 RegisterClass regClass = oatRegClassBySize(size);
1567 int lenOffset = Array::LengthOffset().Int32Value();
1568 int dataOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001569
Bill Buzbeea114add2012-05-03 15:00:40 -07001570 if (size == kLong || size == kDouble) {
1571 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1572 } else {
1573 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1574 }
buzbee31a4a6f2012-02-28 15:36:15 -08001575
Bill Buzbeea114add2012-05-03 15:00:40 -07001576 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1577 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001578#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001579 int regPtr;
1580 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1581 oatClobber(cUnit, rlArray.lowReg);
1582 regPtr = rlArray.lowReg;
1583 } else {
1584 regPtr = oatAllocTemp(cUnit);
1585 opRegCopy(cUnit, regPtr, rlArray.lowReg);
1586 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001587#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001588
Bill Buzbeea114add2012-05-03 15:00:40 -07001589 /* null object? */
buzbee408ad162012-06-06 16:45:18 -07001590 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001591
Ian Rogersb41b33b2012-03-20 14:22:54 -07001592#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07001593 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001594 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1595 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
buzbee408ad162012-06-06 16:45:18 -07001596 lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001597 }
1598 if ((size == kLong) || (size == kDouble)) {
1599 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1600 } else {
1601 rlSrc = loadValue(cUnit, rlSrc, regClass);
1602 }
buzbee408ad162012-06-06 16:45:18 -07001603 storeBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -07001604 dataOffset, rlSrc.lowReg, rlSrc.highReg, size,
1605 INVALID_SREG);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001606#else
buzbee408ad162012-06-06 16:45:18 -07001607 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001608 int regLen = INVALID_REG;
1609 if (needsRangeCheck) {
1610 regLen = oatAllocTemp(cUnit);
1611 //NOTE: max live temps(4) here.
1612 /* Get len */
1613 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1614 }
1615 /* regPtr -> array data */
1616 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1617 /* at this point, regPtr points to array, 2 live temps */
1618 if ((size == kLong) || (size == kDouble)) {
1619 //TUNING: specific wide routine that can handle fp regs
1620 if (scale) {
1621 int rNewIndex = oatAllocTemp(cUnit);
1622 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1623 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1624 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001625 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001626 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001627 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001628 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1629
1630 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001631 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001632 oatFreeTemp(cUnit, regLen);
1633 }
1634
jeffhao41005dd2012-05-09 17:58:52 -07001635 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001636
1637 oatFreeTemp(cUnit, regPtr);
1638 } else {
1639 rlSrc = loadValue(cUnit, rlSrc, regClass);
1640 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001641 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001642 oatFreeTemp(cUnit, regLen);
1643 }
1644 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1645 scale, size);
1646 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001647#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001648}
1649
buzbee408ad162012-06-06 16:45:18 -07001650void genLong3Addr(CompilationUnit* cUnit, OpKind firstOp,
buzbee31a4a6f2012-02-28 15:36:15 -08001651 OpKind secondOp, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001652 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001653{
Bill Buzbeea114add2012-05-03 15:00:40 -07001654 RegLocation rlResult;
buzbee31a4a6f2012-02-28 15:36:15 -08001655#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001656 /*
1657 * NOTE: This is the one place in the code in which we might have
1658 * as many as six live temporary registers. There are 5 in the normal
1659 * set for Arm. Until we have spill capabilities, temporarily add
1660 * lr to the temp set. It is safe to do this locally, but note that
1661 * lr is used explicitly elsewhere in the code generator and cannot
1662 * normally be used as a general temp register.
1663 */
1664 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1665 oatFreeTemp(cUnit, rLR); // and make it available
buzbee31a4a6f2012-02-28 15:36:15 -08001666#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001667 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1668 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1669 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1670 // The longs may overlap - use intermediate temp if so
1671 if (rlResult.lowReg == rlSrc1.highReg) {
1672 int tReg = oatAllocTemp(cUnit);
1673 opRegCopy(cUnit, tReg, rlSrc1.highReg);
1674 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1675 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg, rlSrc2.highReg);
1676 oatFreeTemp(cUnit, tReg);
1677 } else {
1678 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1679 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1680 rlSrc2.highReg);
1681 }
1682 /*
1683 * NOTE: If rlDest refers to a frame variable in a large frame, the
1684 * following storeValueWide might need to allocate a temp register.
1685 * To further work around the lack of a spill capability, explicitly
1686 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1687 * Remove when spill is functional.
1688 */
1689 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1690 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1691 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001692#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001693 oatClobber(cUnit, rLR);
1694 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee31a4a6f2012-02-28 15:36:15 -08001695#endif
1696}
1697
1698
buzbee408ad162012-06-06 16:45:18 -07001699bool genShiftOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001700 RegLocation rlSrc1, RegLocation rlShift)
1701{
Bill Buzbeea114add2012-05-03 15:00:40 -07001702 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001703
buzbee408ad162012-06-06 16:45:18 -07001704 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001705 case Instruction::SHL_LONG:
1706 case Instruction::SHL_LONG_2ADDR:
1707 funcOffset = ENTRYPOINT_OFFSET(pShlLong);
1708 break;
1709 case Instruction::SHR_LONG:
1710 case Instruction::SHR_LONG_2ADDR:
1711 funcOffset = ENTRYPOINT_OFFSET(pShrLong);
1712 break;
1713 case Instruction::USHR_LONG:
1714 case Instruction::USHR_LONG_2ADDR:
1715 funcOffset = ENTRYPOINT_OFFSET(pUshrLong);
1716 break;
1717 default:
1718 LOG(FATAL) << "Unexpected case";
1719 return true;
1720 }
1721 oatFlushAllRegs(cUnit); /* Send everything to home location */
1722 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift);
1723 RegLocation rlResult = oatGetReturnWide(cUnit, false);
1724 storeValueWide(cUnit, rlDest, rlResult);
1725 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001726}
1727
1728
buzbee408ad162012-06-06 16:45:18 -07001729bool genArithOpInt(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001730 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001731{
Bill Buzbeea114add2012-05-03 15:00:40 -07001732 OpKind op = kOpBkpt;
1733 bool callOut = false;
1734 bool checkZero = false;
1735 bool unary = false;
1736 RegLocation rlResult;
1737 bool shiftOp = false;
1738 int funcOffset;
1739 int retReg = rRET0;
buzbee408ad162012-06-06 16:45:18 -07001740 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001741 case Instruction::NEG_INT:
1742 op = kOpNeg;
1743 unary = true;
1744 break;
1745 case Instruction::NOT_INT:
1746 op = kOpMvn;
1747 unary = true;
1748 break;
1749 case Instruction::ADD_INT:
1750 case Instruction::ADD_INT_2ADDR:
1751 op = kOpAdd;
1752 break;
1753 case Instruction::SUB_INT:
1754 case Instruction::SUB_INT_2ADDR:
1755 op = kOpSub;
1756 break;
1757 case Instruction::MUL_INT:
1758 case Instruction::MUL_INT_2ADDR:
1759 op = kOpMul;
1760 break;
1761 case Instruction::DIV_INT:
1762 case Instruction::DIV_INT_2ADDR:
1763 checkZero = true;
1764 op = kOpDiv;
1765 callOut = true;
1766 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
1767 retReg = rRET0;
1768 break;
1769 /* NOTE: returns in rARG1 */
1770 case Instruction::REM_INT:
1771 case Instruction::REM_INT_2ADDR:
1772 checkZero = true;
1773 op = kOpRem;
1774 callOut = true;
1775 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
1776 retReg = rRET1;
1777 break;
1778 case Instruction::AND_INT:
1779 case Instruction::AND_INT_2ADDR:
1780 op = kOpAnd;
1781 break;
1782 case Instruction::OR_INT:
1783 case Instruction::OR_INT_2ADDR:
1784 op = kOpOr;
1785 break;
1786 case Instruction::XOR_INT:
1787 case Instruction::XOR_INT_2ADDR:
1788 op = kOpXor;
1789 break;
1790 case Instruction::SHL_INT:
1791 case Instruction::SHL_INT_2ADDR:
1792 shiftOp = true;
1793 op = kOpLsl;
1794 break;
1795 case Instruction::SHR_INT:
1796 case Instruction::SHR_INT_2ADDR:
1797 shiftOp = true;
1798 op = kOpAsr;
1799 break;
1800 case Instruction::USHR_INT:
1801 case Instruction::USHR_INT_2ADDR:
1802 shiftOp = true;
1803 op = kOpLsr;
1804 break;
1805 default:
1806 LOG(FATAL) << "Invalid word arith op: " <<
buzbee408ad162012-06-06 16:45:18 -07001807 (int)opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001808 }
1809 if (!callOut) {
1810 if (unary) {
1811 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1812 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1813 opRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001814 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001815 if (shiftOp) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001816#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001817 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1818 int tReg = oatAllocTemp(cUnit);
1819 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001820#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001821 // X86 doesn't require masking and must use ECX
1822 loadValueDirectFixed(cUnit, rlSrc2, rCX);
1823 int tReg = rCX;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001824#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001825 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1826 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1827 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, tReg);
1828 oatFreeTemp(cUnit, tReg);
1829 } else {
1830 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1831 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1832 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1833 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1834 }
buzbee31a4a6f2012-02-28 15:36:15 -08001835 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001836 storeValue(cUnit, rlDest, rlResult);
1837 } else {
1838 RegLocation rlResult;
1839 oatFlushAllRegs(cUnit); /* Send everything to home location */
1840 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
1841#if !defined(TARGET_X86)
1842 int rTgt = loadHelper(cUnit, funcOffset);
1843#endif
1844 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1845 if (checkZero) {
buzbee408ad162012-06-06 16:45:18 -07001846 genImmedCheck(cUnit, kCondEq, rARG1, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07001847 }
1848#if !defined(TARGET_X86)
1849 opReg(cUnit, kOpBlx, rTgt);
1850 oatFreeTemp(cUnit, rTgt);
1851#else
1852 opThreadMem(cUnit, kOpBlx, funcOffset);
1853#endif
1854 if (retReg == rRET0)
1855 rlResult = oatGetReturn(cUnit, false);
1856 else
1857 rlResult = oatGetReturnAlt(cUnit);
1858 storeValue(cUnit, rlDest, rlResult);
1859 }
1860 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001861}
1862
1863/*
1864 * The following are the first-level codegen routines that analyze the format
1865 * of each bytecode then either dispatch special purpose codegen routines
1866 * or produce corresponding Thumb instructions directly.
1867 */
1868
1869bool isPowerOfTwo(int x)
1870{
Bill Buzbeea114add2012-05-03 15:00:40 -07001871 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001872}
1873
1874// Returns true if no more than two bits are set in 'x'.
1875bool isPopCountLE2(unsigned int x)
1876{
Bill Buzbeea114add2012-05-03 15:00:40 -07001877 x &= x - 1;
1878 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001879}
1880
1881// Returns the index of the lowest set bit in 'x'.
1882int lowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001883 int bit_posn = 0;
1884 while ((x & 0xf) == 0) {
1885 bit_posn += 4;
1886 x >>= 4;
1887 }
1888 while ((x & 1) == 0) {
1889 bit_posn++;
1890 x >>= 1;
1891 }
1892 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001893}
1894
1895// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1896// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001897bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
Bill Buzbeea114add2012-05-03 15:00:40 -07001898 RegLocation rlSrc, RegLocation rlDest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001899{
buzbeef3aac972012-04-11 16:33:36 -07001900#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001901 // No divide instruction for Arm, so check for more special cases
1902 if (lit < 2) {
1903 return false;
1904 }
1905 if (!isPowerOfTwo(lit)) {
1906 return smallLiteralDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit);
1907 }
buzbeef3aac972012-04-11 16:33:36 -07001908#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001909 if (lit < 2 || !isPowerOfTwo(lit)) {
1910 return false;
1911 }
buzbeef3aac972012-04-11 16:33:36 -07001912#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001913 int k = lowestSetBit(lit);
1914 if (k >= 30) {
1915 // Avoid special cases.
1916 return false;
1917 }
1918 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1919 dalvikOpcode == Instruction::DIV_INT_LIT16);
1920 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1921 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1922 if (div) {
1923 int tReg = oatAllocTemp(cUnit);
1924 if (lit == 2) {
1925 // Division by 2 is by far the most common division by constant.
1926 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1927 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1928 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001929 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001930 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1931 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1932 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1933 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001934 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001935 } else {
1936 int tReg1 = oatAllocTemp(cUnit);
1937 int tReg2 = oatAllocTemp(cUnit);
1938 if (lit == 2) {
1939 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1940 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1941 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit -1);
1942 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1943 } else {
1944 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1945 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1946 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1947 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit - 1);
1948 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1949 }
1950 }
1951 storeValue(cUnit, rlDest, rlResult);
1952 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001953}
1954
1955void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1956 RegLocation rlResult, int lit,
1957 int firstBit, int secondBit)
1958{
buzbee0398c422012-03-02 15:22:47 -08001959#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001960 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1961 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001962#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001963 int tReg = oatAllocTemp(cUnit);
1964 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1965 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1966 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001967#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001968 if (firstBit != 0) {
1969 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1970 }
buzbee31a4a6f2012-02-28 15:36:15 -08001971}
1972
1973// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1974// and store the result in 'rlDest'.
1975bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1976 RegLocation rlDest, int lit)
1977{
Bill Buzbeea114add2012-05-03 15:00:40 -07001978 // Can we simplify this multiplication?
1979 bool powerOfTwo = false;
1980 bool popCountLE2 = false;
1981 bool powerOfTwoMinusOne = false;
1982 if (lit < 2) {
1983 // Avoid special cases.
1984 return false;
1985 } else if (isPowerOfTwo(lit)) {
1986 powerOfTwo = true;
1987 } else if (isPopCountLE2(lit)) {
1988 popCountLE2 = true;
1989 } else if (isPowerOfTwo(lit + 1)) {
1990 powerOfTwoMinusOne = true;
1991 } else {
1992 return false;
1993 }
1994 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1995 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1996 if (powerOfTwo) {
1997 // Shift.
1998 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1999 lowestSetBit(lit));
2000 } else if (popCountLE2) {
2001 // Shift and add and shift.
2002 int firstBit = lowestSetBit(lit);
2003 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
2004 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
2005 firstBit, secondBit);
2006 } else {
2007 // Reverse subtract: (src << (shift + 1)) - src.
2008 DCHECK(powerOfTwoMinusOne);
2009 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
2010 int tReg = oatAllocTemp(cUnit);
2011 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
2012 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2013 }
2014 storeValue(cUnit, rlDest, rlResult);
2015 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08002016}
2017
buzbee408ad162012-06-06 16:45:18 -07002018bool genArithOpIntLit(CompilationUnit* cUnit, Instruction::Code opcode,
2019 RegLocation rlDest, RegLocation rlSrc, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08002020{
Bill Buzbeea114add2012-05-03 15:00:40 -07002021 RegLocation rlResult;
2022 OpKind op = (OpKind)0; /* Make gcc happy */
2023 int shiftOp = false;
2024 bool isDiv = false;
2025 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002026
buzbee408ad162012-06-06 16:45:18 -07002027 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002028 case Instruction::RSUB_INT_LIT8:
2029 case Instruction::RSUB_INT: {
2030 int tReg;
2031 //TUNING: add support for use of Arm rsub op
2032 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2033 tReg = oatAllocTemp(cUnit);
2034 loadConstant(cUnit, tReg, lit);
2035 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2036 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2037 storeValue(cUnit, rlDest, rlResult);
2038 return false;
2039 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002040 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002041
2042 case Instruction::ADD_INT_LIT8:
2043 case Instruction::ADD_INT_LIT16:
2044 op = kOpAdd;
2045 break;
2046 case Instruction::MUL_INT_LIT8:
2047 case Instruction::MUL_INT_LIT16: {
2048 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2049 return false;
2050 }
2051 op = kOpMul;
2052 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002053 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002054 case Instruction::AND_INT_LIT8:
2055 case Instruction::AND_INT_LIT16:
2056 op = kOpAnd;
2057 break;
2058 case Instruction::OR_INT_LIT8:
2059 case Instruction::OR_INT_LIT16:
2060 op = kOpOr;
2061 break;
2062 case Instruction::XOR_INT_LIT8:
2063 case Instruction::XOR_INT_LIT16:
2064 op = kOpXor;
2065 break;
2066 case Instruction::SHL_INT_LIT8:
2067 lit &= 31;
2068 shiftOp = true;
2069 op = kOpLsl;
2070 break;
2071 case Instruction::SHR_INT_LIT8:
2072 lit &= 31;
2073 shiftOp = true;
2074 op = kOpAsr;
2075 break;
2076 case Instruction::USHR_INT_LIT8:
2077 lit &= 31;
2078 shiftOp = true;
2079 op = kOpLsr;
2080 break;
2081
2082 case Instruction::DIV_INT_LIT8:
2083 case Instruction::DIV_INT_LIT16:
2084 case Instruction::REM_INT_LIT8:
2085 case Instruction::REM_INT_LIT16:
2086 if (lit == 0) {
buzbee408ad162012-06-06 16:45:18 -07002087 genImmedCheck(cUnit, kCondAl, 0, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002088 return false;
2089 }
buzbee408ad162012-06-06 16:45:18 -07002090 if (handleEasyDivide(cUnit, opcode, rlSrc, rlDest, lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002091 return false;
2092 }
2093 oatFlushAllRegs(cUnit); /* Everything to home location */
2094 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2095 oatClobber(cUnit, rARG0);
2096 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee408ad162012-06-06 16:45:18 -07002097 if ((opcode == Instruction::DIV_INT_LIT8) ||
2098 (opcode == Instruction::DIV_INT_LIT16)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002099 isDiv = true;
2100 } else {
2101 isDiv = false;
2102 }
2103 callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit);
2104 if (isDiv)
2105 rlResult = oatGetReturn(cUnit, false);
2106 else
2107 rlResult = oatGetReturnAlt(cUnit);
2108 storeValue(cUnit, rlDest, rlResult);
2109 return false;
2110 break;
2111 default:
2112 return true;
2113 }
2114 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2115 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2116 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2117 if (shiftOp && (lit == 0)) {
2118 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2119 } else {
2120 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2121 }
2122 storeValue(cUnit, rlDest, rlResult);
2123 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002124}
2125
buzbee408ad162012-06-06 16:45:18 -07002126bool genArithOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07002127 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08002128{
Bill Buzbeea114add2012-05-03 15:00:40 -07002129 RegLocation rlResult;
2130 OpKind firstOp = kOpBkpt;
2131 OpKind secondOp = kOpBkpt;
2132 bool callOut = false;
2133 bool checkZero = false;
2134 int funcOffset;
2135 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08002136
buzbee408ad162012-06-06 16:45:18 -07002137 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002138 case Instruction::NOT_LONG:
2139 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2140 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2141 // Check for destructive overlap
2142 if (rlResult.lowReg == rlSrc2.highReg) {
2143 int tReg = oatAllocTemp(cUnit);
2144 opRegCopy(cUnit, tReg, rlSrc2.highReg);
2145 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2146 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2147 oatFreeTemp(cUnit, tReg);
2148 } else {
2149 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2150 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2151 }
2152 storeValueWide(cUnit, rlDest, rlResult);
2153 return false;
2154 break;
2155 case Instruction::ADD_LONG:
2156 case Instruction::ADD_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002157#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002158 return genAddLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeec5159d52012-03-03 11:48:39 -08002159#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002160 firstOp = kOpAdd;
2161 secondOp = kOpAdc;
2162 break;
buzbeec5159d52012-03-03 11:48:39 -08002163#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002164 case Instruction::SUB_LONG:
2165 case Instruction::SUB_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002166#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002167 return genSubLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002168#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002169 firstOp = kOpSub;
2170 secondOp = kOpSbc;
2171 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002172#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002173 case Instruction::MUL_LONG:
2174 case Instruction::MUL_LONG_2ADDR:
2175 callOut = true;
2176 retReg = rRET0;
2177 funcOffset = ENTRYPOINT_OFFSET(pLmul);
2178 break;
2179 case Instruction::DIV_LONG:
2180 case Instruction::DIV_LONG_2ADDR:
2181 callOut = true;
2182 checkZero = true;
2183 retReg = rRET0;
jeffhao644d5312012-05-03 19:04:49 -07002184 funcOffset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002185 break;
2186 case Instruction::REM_LONG:
2187 case Instruction::REM_LONG_2ADDR:
2188 callOut = true;
2189 checkZero = true;
jeffhao644d5312012-05-03 19:04:49 -07002190 funcOffset = ENTRYPOINT_OFFSET(pLdivmod);
Ian Rogers55bd45f2012-04-04 17:31:20 -07002191#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002192 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2193 retReg = rARG2;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002194#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002195 retReg = rRET0;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002196#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002197 break;
2198 case Instruction::AND_LONG_2ADDR:
2199 case Instruction::AND_LONG:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002200#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002201 return genAndLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002202#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002203 firstOp = kOpAnd;
2204 secondOp = kOpAnd;
2205 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002206#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002207 case Instruction::OR_LONG:
2208 case Instruction::OR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002209#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002210 return genOrLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002211#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002212 firstOp = kOpOr;
2213 secondOp = kOpOr;
2214 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002215#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002216 case Instruction::XOR_LONG:
2217 case Instruction::XOR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002218#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002219 return genXorLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002220#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002221 firstOp = kOpXor;
2222 secondOp = kOpXor;
2223 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002224#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002225 case Instruction::NEG_LONG: {
buzbee408ad162012-06-06 16:45:18 -07002226 return genNegLong(cUnit, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002227 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002228 default:
2229 LOG(FATAL) << "Invalid long arith op";
2230 }
2231 if (!callOut) {
buzbee408ad162012-06-06 16:45:18 -07002232 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -07002233 } else {
2234 oatFlushAllRegs(cUnit); /* Send everything to home location */
2235 if (checkZero) {
2236 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2237#if !defined(TARGET_X86)
2238 int rTgt = loadHelper(cUnit, funcOffset);
2239#endif
2240 int tReg = oatAllocTemp(cUnit);
2241#if defined(TARGET_ARM)
2242 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2243 oatFreeTemp(cUnit, tReg);
buzbee408ad162012-06-06 16:45:18 -07002244 genCheck(cUnit, kCondEq, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002245#else
2246 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
2247#endif
buzbee408ad162012-06-06 16:45:18 -07002248 genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002249 oatFreeTemp(cUnit, tReg);
2250 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2251#if !defined(TARGET_X86)
2252 opReg(cUnit, kOpBlx, rTgt);
2253 oatFreeTemp(cUnit, rTgt);
2254#else
2255 opThreadMem(cUnit, kOpBlx, funcOffset);
2256#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002257 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07002258 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset,
2259 rlSrc1, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002260 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002261 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2262 if (retReg == rRET0)
2263 rlResult = oatGetReturnWide(cUnit, false);
2264 else
2265 rlResult = oatGetReturnWideAlt(cUnit);
2266 storeValueWide(cUnit, rlDest, rlResult);
2267 }
2268 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002269}
2270
buzbee408ad162012-06-06 16:45:18 -07002271bool genConversionCall(CompilationUnit* cUnit, int funcOffset,
2272 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002273{
Bill Buzbeea114add2012-05-03 15:00:40 -07002274 /*
2275 * Don't optimize the register usage since it calls out to support
2276 * functions
2277 */
Bill Buzbeea114add2012-05-03 15:00:40 -07002278 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee408ad162012-06-06 16:45:18 -07002279 if (rlSrc.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002280 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
buzbee408ad162012-06-06 16:45:18 -07002281 } else {
2282 loadValueDirectFixed(cUnit, rlSrc, rARG0);
Bill Buzbeea114add2012-05-03 15:00:40 -07002283 }
2284 callRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002285 if (rlDest.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002286 RegLocation rlResult;
Bill Buzbeea114add2012-05-03 15:00:40 -07002287 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
2288 storeValueWide(cUnit, rlDest, rlResult);
buzbee408ad162012-06-06 16:45:18 -07002289 } else {
2290 RegLocation rlResult;
2291 rlResult = oatGetReturn(cUnit, rlDest.fp);
2292 storeValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002293 }
2294 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002295}
2296
2297void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002298bool genArithOpFloatPortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002299 RegLocation rlDest, RegLocation rlSrc1,
2300 RegLocation rlSrc2)
2301{
Bill Buzbeea114add2012-05-03 15:00:40 -07002302 RegLocation rlResult;
2303 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002304
buzbee408ad162012-06-06 16:45:18 -07002305 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002306 case Instruction::ADD_FLOAT_2ADDR:
2307 case Instruction::ADD_FLOAT:
2308 funcOffset = ENTRYPOINT_OFFSET(pFadd);
2309 break;
2310 case Instruction::SUB_FLOAT_2ADDR:
2311 case Instruction::SUB_FLOAT:
2312 funcOffset = ENTRYPOINT_OFFSET(pFsub);
2313 break;
2314 case Instruction::DIV_FLOAT_2ADDR:
2315 case Instruction::DIV_FLOAT:
2316 funcOffset = ENTRYPOINT_OFFSET(pFdiv);
2317 break;
2318 case Instruction::MUL_FLOAT_2ADDR:
2319 case Instruction::MUL_FLOAT:
2320 funcOffset = ENTRYPOINT_OFFSET(pFmul);
2321 break;
2322 case Instruction::REM_FLOAT_2ADDR:
2323 case Instruction::REM_FLOAT:
2324 funcOffset = ENTRYPOINT_OFFSET(pFmodf);
2325 break;
2326 case Instruction::NEG_FLOAT: {
2327 genNegFloat(cUnit, rlDest, rlSrc1);
2328 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002329 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002330 default:
2331 return true;
2332 }
2333 oatFlushAllRegs(cUnit); /* Send everything to home location */
2334 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
2335 rlResult = oatGetReturn(cUnit, true);
2336 storeValue(cUnit, rlDest, rlResult);
2337 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002338}
2339
2340void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002341bool genArithOpDoublePortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002342 RegLocation rlDest, RegLocation rlSrc1,
2343 RegLocation rlSrc2)
2344{
Bill Buzbeea114add2012-05-03 15:00:40 -07002345 RegLocation rlResult;
2346 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002347
buzbee408ad162012-06-06 16:45:18 -07002348 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002349 case Instruction::ADD_DOUBLE_2ADDR:
2350 case Instruction::ADD_DOUBLE:
2351 funcOffset = ENTRYPOINT_OFFSET(pDadd);
2352 break;
2353 case Instruction::SUB_DOUBLE_2ADDR:
2354 case Instruction::SUB_DOUBLE:
2355 funcOffset = ENTRYPOINT_OFFSET(pDsub);
2356 break;
2357 case Instruction::DIV_DOUBLE_2ADDR:
2358 case Instruction::DIV_DOUBLE:
2359 funcOffset = ENTRYPOINT_OFFSET(pDdiv);
2360 break;
2361 case Instruction::MUL_DOUBLE_2ADDR:
2362 case Instruction::MUL_DOUBLE:
2363 funcOffset = ENTRYPOINT_OFFSET(pDmul);
2364 break;
2365 case Instruction::REM_DOUBLE_2ADDR:
2366 case Instruction::REM_DOUBLE:
2367 funcOffset = ENTRYPOINT_OFFSET(pFmod);
2368 break;
2369 case Instruction::NEG_DOUBLE: {
2370 genNegDouble(cUnit, rlDest, rlSrc1);
2371 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002372 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002373 default:
2374 return true;
2375 }
2376 oatFlushAllRegs(cUnit); /* Send everything to home location */
2377 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
2378 rlResult = oatGetReturnWide(cUnit, true);
2379 storeValueWide(cUnit, rlDest, rlResult);
2380 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002381}
2382
buzbee408ad162012-06-06 16:45:18 -07002383bool genConversionPortable(CompilationUnit* cUnit, Instruction::Code opcode,
2384 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002385{
buzbee31a4a6f2012-02-28 15:36:15 -08002386
Bill Buzbeea114add2012-05-03 15:00:40 -07002387 switch (opcode) {
2388 case Instruction::INT_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002389 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2f),
2390 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002391 case Instruction::FLOAT_TO_INT:
buzbee408ad162012-06-06 16:45:18 -07002392 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2iz),
2393 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002394 case Instruction::DOUBLE_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002395 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2f),
2396 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002397 case Instruction::FLOAT_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002398 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2d),
2399 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002400 case Instruction::INT_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002401 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2d),
2402 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002403 case Instruction::DOUBLE_TO_INT:
buzbee408ad162012-06-06 16:45:18 -07002404 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2iz),
2405 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002406 case Instruction::FLOAT_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -07002407 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2l),
2408 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002409 case Instruction::LONG_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002410 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2f),
2411 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002412 case Instruction::DOUBLE_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -07002413 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2l),
2414 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002415 case Instruction::LONG_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002416 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2d),
2417 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002418 default:
2419 return true;
2420 }
2421 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002422}
2423
2424/*
2425 * Generate callout to updateDebugger. Note that we're overloading
2426 * the use of rSUSPEND here. When the debugger is active, this
2427 * register holds the address of the update function. So, if it's
2428 * non-null, we call out to it.
2429 *
2430 * Note also that rRET0 and rRET1 must be preserved across this
2431 * code. This must be handled by the stub.
2432 */
2433void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2434{
Bill Buzbeea114add2012-05-03 15:00:40 -07002435 // Following DCHECK verifies that dPC is in range of single load immediate
2436 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2437 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2438 oatClobberCalleeSave(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002439#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002440 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
2441 opIT(cUnit, kArmCondNe, "T");
2442 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2443 opReg(cUnit, kOpBlx, rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002444#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002445 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002446#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002447 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
2448 loadConstant(cUnit, rARG2, offset);
2449 opReg(cUnit, kOpBlx, rSUSPEND);
2450 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
2451 branch->target = (LIR*)target;
buzbee31a4a6f2012-02-28 15:36:15 -08002452#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002453 oatFreeTemp(cUnit, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08002454}
2455
2456/* Check if we need to check for pending suspend request */
buzbee408ad162012-06-06 16:45:18 -07002457void genSuspendTest(CompilationUnit* cUnit, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -08002458{
buzbee408ad162012-06-06 16:45:18 -07002459 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002460 return;
2461 }
2462 oatFlushAllRegs(cUnit);
2463 if (cUnit->genDebugger) {
2464 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002465#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002466 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002467#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002468 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
2469 opReg(cUnit, kOpBlx, rTgt);
2470 // Refresh rSUSPEND
2471 loadWordDisp(cUnit, rSELF,
2472 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode),
2473 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002474#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002475 } else {
2476 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002477#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002478 // In non-debug case, only check periodically
2479 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2480 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002481#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002482 newLIR2(cUnit, kX86Cmp32TI8, Thread::SuspendCountOffset().Int32Value(), 0);
2483 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002484#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002485 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2486 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002487#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002488 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2489 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
buzbee408ad162012-06-06 16:45:18 -07002490 kPseudoSuspendTarget, (intptr_t)retLab, cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -07002491 branch->target = (LIR*)target;
2492 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
2493 }
buzbee31a4a6f2012-02-28 15:36:15 -08002494}
2495
buzbeefead2932012-03-30 14:02:01 -07002496/* Check if we need to check for pending suspend request */
buzbee408ad162012-06-06 16:45:18 -07002497void genSuspendTestAndBranch(CompilationUnit* cUnit, int optFlags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07002498{
buzbee408ad162012-06-06 16:45:18 -07002499 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002500 opUnconditionalBranch(cUnit, target);
2501 return;
2502 }
2503 if (cUnit->genDebugger) {
buzbee408ad162012-06-06 16:45:18 -07002504 genSuspendTest(cUnit, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07002505 opUnconditionalBranch(cUnit, target);
2506 } else {
buzbeefead2932012-03-30 14:02:01 -07002507#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002508 // In non-debug case, only check periodically
2509 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2510 opCondBranch(cUnit, kCondNe, target);
buzbeefead2932012-03-30 14:02:01 -07002511#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002512 newLIR2(cUnit, kX86Cmp32TI8, Thread::SuspendCountOffset().Int32Value(), 0);
2513 opCondBranch(cUnit, kCondEq, target);
buzbeefead2932012-03-30 14:02:01 -07002514#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002515 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2516 opCmpImmBranch(cUnit, kCondNe, rSUSPEND, 0, target);
buzbeefead2932012-03-30 14:02:01 -07002517#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002518 LIR* launchPad = rawLIR(cUnit, cUnit->currentDalvikOffset,
buzbee408ad162012-06-06 16:45:18 -07002519 kPseudoSuspendTarget, (intptr_t)target, cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -07002520 oatFlushAllRegs(cUnit);
2521 opUnconditionalBranch(cUnit, launchPad);
2522 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads,
2523 (intptr_t)launchPad);
2524 }
buzbeefead2932012-03-30 14:02:01 -07002525}
2526
buzbee31a4a6f2012-02-28 15:36:15 -08002527} // namespace art