blob: baa4b48bbe3c3a6cd1d4b956b531a22893ae7ee5 [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 */
buzbee3b3dbdd2012-06-13 13:39:34 -070026void genInvoke(CompilationUnit* cUnit, CallInfo* info);
buzbee31a4a6f2012-02-28 15:36:15 -080027#if defined(TARGET_ARM)
buzbee82488f52012-03-02 08:20:26 -080028LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide);
buzbeef3aac972012-04-11 16:33:36 -070029bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
30 RegLocation rlSrc, RegLocation rlDest, int lit);
buzbee31a4a6f2012-02-28 15:36:15 -080031#endif
32
Ian Rogersab2b55d2012-03-18 00:06:11 -070033void callRuntimeHelperImm(CompilationUnit* cUnit, int helperOffset, int arg0) {
34#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070035 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070036#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070037 loadConstant(cUnit, rARG0, arg0);
38 oatClobberCalleeSave(cUnit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070039#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070040 opReg(cUnit, kOpBlx, rTgt);
41 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070042#else
Bill Buzbeea114add2012-05-03 15:00:40 -070043 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070044#endif
45}
46
Ian Rogers7caad772012-03-30 01:07:54 -070047void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0) {
48#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070049 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogers7caad772012-03-30 01:07:54 -070050#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070051 opRegCopy(cUnit, rARG0, arg0);
52 oatClobberCalleeSave(cUnit);
Ian Rogers7caad772012-03-30 01:07:54 -070053#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070054 opReg(cUnit, kOpBlx, rTgt);
55 oatFreeTemp(cUnit, rTgt);
Ian Rogers7caad772012-03-30 01:07:54 -070056#else
Bill Buzbeea114add2012-05-03 15:00:40 -070057 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogers7caad772012-03-30 01:07:54 -070058#endif
59}
60
Ian Rogersab2b55d2012-03-18 00:06:11 -070061void callRuntimeHelperRegLocation(CompilationUnit* cUnit, int helperOffset,
62 RegLocation arg0) {
63#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070064 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070065#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070066 if (arg0.wide == 0) {
67 loadValueDirectFixed(cUnit, arg0, rARG0);
68 } else {
69 loadValueDirectWideFixed(cUnit, arg0, rARG0, rARG1);
70 }
71 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -070072#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070073 opReg(cUnit, kOpBlx, rTgt);
74 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -070075#else
Bill Buzbeea114add2012-05-03 15:00:40 -070076 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070077#endif
78}
79
80void callRuntimeHelperImmImm(CompilationUnit* cUnit, int helperOffset,
81 int arg0, int arg1) {
82#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070083 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070084#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070085 loadConstant(cUnit, rARG0, arg0);
86 loadConstant(cUnit, rARG1, arg1);
87 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -070088#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070089 opReg(cUnit, kOpBlx, rTgt);
90 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -070091#else
Bill Buzbeea114add2012-05-03 15:00:40 -070092 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070093#endif
94}
95
96void callRuntimeHelperImmRegLocation(CompilationUnit* cUnit, int helperOffset,
97 int arg0, RegLocation arg1) {
98#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070099 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700100#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700101 if (arg1.wide == 0) {
102 loadValueDirectFixed(cUnit, arg1, rARG1);
103 } else {
104 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
105 }
106 loadConstant(cUnit, rARG0, arg0);
107 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700108#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700109 opReg(cUnit, kOpBlx, rTgt);
110 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700111#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700112 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700113#endif
114}
115
116void callRuntimeHelperRegLocationImm(CompilationUnit* cUnit, int helperOffset,
117 RegLocation arg0, int arg1) {
118#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700119 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700120#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700121 loadValueDirectFixed(cUnit, arg0, rARG0);
122 loadConstant(cUnit, rARG1, arg1);
123 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700124#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700125 opReg(cUnit, kOpBlx, rTgt);
126 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700127#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700128 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700129#endif
130}
131
132void callRuntimeHelperImmReg(CompilationUnit* cUnit, int helperOffset,
133 int arg0, int arg1) {
134#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700135 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700136#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700137 opRegCopy(cUnit, rARG1, arg1);
138 loadConstant(cUnit, rARG0, arg0);
139 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700140#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700141 opReg(cUnit, kOpBlx, rTgt);
142 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700143#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700144 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700145#endif
146}
147
148void callRuntimeHelperRegImm(CompilationUnit* cUnit, int helperOffset,
149 int arg0, int arg1) {
150#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700151 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700152#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700153 opRegCopy(cUnit, rARG0, arg0);
154 loadConstant(cUnit, rARG1, arg1);
155 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700156#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700157 opReg(cUnit, kOpBlx, rTgt);
158 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700159#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700160 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700161#endif
162}
163
164void callRuntimeHelperImmMethod(CompilationUnit* cUnit, int helperOffset,
165 int arg0) {
166#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700167 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700168#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700169 loadCurrMethodDirect(cUnit, rARG1);
170 loadConstant(cUnit, rARG0, arg0);
171 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700172#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700173 opReg(cUnit, kOpBlx, rTgt);
174 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700175#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700176 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700177#endif
178}
179
180void callRuntimeHelperRegLocationRegLocation(CompilationUnit* cUnit,
181 int helperOffset,
182 RegLocation arg0,
183 RegLocation arg1) {
184#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700185 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700186#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700187 if (arg0.wide == 0) {
188 loadValueDirectFixed(cUnit, arg0, rARG0);
189 if (arg1.wide == 0) {
190 loadValueDirectFixed(cUnit, arg1, rARG1);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700191 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700192 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700193 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700194 } else {
195 loadValueDirectWideFixed(cUnit, arg0, rARG0, rARG1);
196 if (arg1.wide == 0) {
197 loadValueDirectFixed(cUnit, arg1, rARG2);
198 } else {
199 loadValueDirectWideFixed(cUnit, arg1, rARG2, rARG3);
200 }
201 }
202 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700203#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700204 opReg(cUnit, kOpBlx, rTgt);
205 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700206#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700207 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700208#endif
209}
210
211void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset,
212 int arg0, int arg1) {
213#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700214 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700215#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700216 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
217 opRegCopy(cUnit, rARG0, arg0);
218 opRegCopy(cUnit, rARG1, arg1);
219 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700220#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700221 opReg(cUnit, kOpBlx, rTgt);
222 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700223#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700224 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700225#endif
226}
227
228void callRuntimeHelperRegRegImm(CompilationUnit* cUnit, int helperOffset,
229 int arg0, int arg1, int arg2) {
230#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700231 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700232#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700233 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
234 opRegCopy(cUnit, rARG0, arg0);
235 opRegCopy(cUnit, rARG1, arg1);
236 loadConstant(cUnit, rARG2, arg2);
237 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700238#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700239 opReg(cUnit, kOpBlx, rTgt);
240 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700241#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700242 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700243#endif
244}
245
Bill Buzbeea114add2012-05-03 15:00:40 -0700246void callRuntimeHelperImmMethodRegLocation(CompilationUnit* cUnit,
247 int helperOffset,
248 int arg0, RegLocation arg2) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700249#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700250 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700251#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700252 loadValueDirectFixed(cUnit, arg2, rARG2);
253 loadCurrMethodDirect(cUnit, rARG1);
254 loadConstant(cUnit, rARG0, arg0);
255 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700256#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700257 opReg(cUnit, kOpBlx, rTgt);
258 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700259#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700260 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700261#endif
262}
263
264void callRuntimeHelperImmMethodImm(CompilationUnit* cUnit, int helperOffset,
265 int arg0, int arg2) {
266#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700268#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700269 loadCurrMethodDirect(cUnit, rARG1);
270 loadConstant(cUnit, rARG2, arg2);
271 loadConstant(cUnit, rARG0, arg0);
272 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700273#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700274 opReg(cUnit, kOpBlx, rTgt);
275 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700276#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700277 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700278#endif
279}
280
281void callRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cUnit,
282 int helperOffset,
283 int arg0, RegLocation arg1,
284 RegLocation arg2) {
285#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700286 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700287#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700288 loadValueDirectFixed(cUnit, arg1, rARG1);
289 if (arg2.wide == 0) {
290 loadValueDirectFixed(cUnit, arg2, rARG2);
291 } else {
292 loadValueDirectWideFixed(cUnit, arg2, rARG2, rARG3);
293 }
294 loadConstant(cUnit, rARG0, arg0);
295 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700296#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700297 opReg(cUnit, kOpBlx, rTgt);
298 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700299#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700300 opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700301#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800302}
303
304/*
305 * Generate an kPseudoBarrier marker to indicate the boundary of special
306 * blocks.
307 */
308void genBarrier(CompilationUnit* cUnit)
309{
Bill Buzbeea114add2012-05-03 15:00:40 -0700310 LIR* barrier = newLIR0(cUnit, kPseudoBarrier);
311 /* Mark all resources as being clobbered */
312 barrier->defMask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800313}
314
buzbee31a4a6f2012-02-28 15:36:15 -0800315
316/* Generate unconditional branch instructions */
buzbee82488f52012-03-02 08:20:26 -0800317LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -0800318{
Bill Buzbeea114add2012-05-03 15:00:40 -0700319 LIR* branch = opBranchUnconditional(cUnit, kOpUncondBr);
320 branch->target = (LIR*) target;
321 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800322}
323
buzbee5de34942012-03-01 14:51:57 -0800324// FIXME: need to do some work to split out targets with
325// condition codes and those without
326#if defined(TARGET_ARM) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -0700327LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee31a4a6f2012-02-28 15:36:15 -0800328 ThrowKind kind)
329{
Bill Buzbeea114add2012-05-03 15:00:40 -0700330 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700331 cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700332 LIR* branch = opCondBranch(cUnit, cCode, tgt);
333 // Remember branch target - will process later
334 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
335 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800336}
buzbee5de34942012-03-01 14:51:57 -0800337#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800338
339LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -0700340 int reg, int immVal, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800341{
buzbee408ad162012-06-06 16:45:18 -0700342 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
343 cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700344 LIR* branch;
345 if (cCode == kCondAl) {
346 branch = opUnconditionalBranch(cUnit, tgt);
347 } else {
348 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
349 }
350 // Remember branch target - will process later
351 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
352 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800353}
354
355/* Perform null-check on a register. */
buzbee408ad162012-06-06 16:45:18 -0700356LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -0800357{
Bill Buzbeea114add2012-05-03 15:00:40 -0700358 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
buzbee408ad162012-06-06 16:45:18 -0700359 optFlags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700360 return NULL;
361 }
buzbee408ad162012-06-06 16:45:18 -0700362 return genImmedCheck(cUnit, kCondEq, mReg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -0800363}
364
365/* Perform check on two registers */
366LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -0700367 int reg1, int reg2, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800368{
Bill Buzbeea114add2012-05-03 15:00:40 -0700369 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700370 cUnit->currentDalvikOffset, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800371#if defined(TARGET_MIPS)
Bill Buzbeea114add2012-05-03 15:00:40 -0700372 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800373#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700374 opRegReg(cUnit, kOpCmp, reg1, reg2);
375 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800376#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700377 // Remember branch target - will process later
378 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
379 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800380}
381
buzbee3b3dbdd2012-06-13 13:39:34 -0700382void genCompareAndBranch(CompilationUnit* cUnit, Instruction::Code opcode,
383 RegLocation rlSrc1, RegLocation rlSrc2, LIR* taken,
384 LIR* fallThrough)
buzbee31a4a6f2012-02-28 15:36:15 -0800385{
Bill Buzbeea114add2012-05-03 15:00:40 -0700386 ConditionCode cond;
387 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
388 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700389 switch (opcode) {
390 case Instruction::IF_EQ:
391 cond = kCondEq;
392 break;
393 case Instruction::IF_NE:
394 cond = kCondNe;
395 break;
396 case Instruction::IF_LT:
397 cond = kCondLt;
398 break;
399 case Instruction::IF_GE:
400 cond = kCondGe;
401 break;
402 case Instruction::IF_GT:
403 cond = kCondGt;
404 break;
405 case Instruction::IF_LE:
406 cond = kCondLe;
407 break;
408 default:
409 cond = (ConditionCode)0;
410 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
411 }
buzbee5de34942012-03-01 14:51:57 -0800412#if defined(TARGET_MIPS)
buzbee3b3dbdd2012-06-13 13:39:34 -0700413 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg, taken);
buzbee5de34942012-03-01 14:51:57 -0800414#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700415 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee3b3dbdd2012-06-13 13:39:34 -0700416 opCondBranch(cUnit, cond, taken);
buzbee5de34942012-03-01 14:51:57 -0800417#endif
buzbee3b3dbdd2012-06-13 13:39:34 -0700418 opUnconditionalBranch(cUnit, fallThrough);
buzbee31a4a6f2012-02-28 15:36:15 -0800419}
420
buzbee3b3dbdd2012-06-13 13:39:34 -0700421void genCompareZeroAndBranch(CompilationUnit* cUnit, Instruction::Code opcode,
422 RegLocation rlSrc, LIR* taken, LIR* fallThrough)
buzbee31a4a6f2012-02-28 15:36:15 -0800423{
Bill Buzbeea114add2012-05-03 15:00:40 -0700424 ConditionCode cond;
425 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700426 switch (opcode) {
427 case Instruction::IF_EQZ:
428 cond = kCondEq;
429 break;
430 case Instruction::IF_NEZ:
431 cond = kCondNe;
432 break;
433 case Instruction::IF_LTZ:
434 cond = kCondLt;
435 break;
436 case Instruction::IF_GEZ:
437 cond = kCondGe;
438 break;
439 case Instruction::IF_GTZ:
440 cond = kCondGt;
441 break;
442 case Instruction::IF_LEZ:
443 cond = kCondLe;
444 break;
445 default:
446 cond = (ConditionCode)0;
447 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
448 }
Ian Rogers7caad772012-03-30 01:07:54 -0700449#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee3b3dbdd2012-06-13 13:39:34 -0700450 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, taken);
buzbee5de34942012-03-01 14:51:57 -0800451#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700452 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
buzbee3b3dbdd2012-06-13 13:39:34 -0700453 opCondBranch(cUnit, cond, taken);
buzbee5de34942012-03-01 14:51:57 -0800454#endif
buzbee3b3dbdd2012-06-13 13:39:34 -0700455 opUnconditionalBranch(cUnit, fallThrough);
buzbee31a4a6f2012-02-28 15:36:15 -0800456}
457
buzbee408ad162012-06-06 16:45:18 -0700458void genIntToLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800459 RegLocation rlSrc)
460{
Bill Buzbeea114add2012-05-03 15:00:40 -0700461 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
462 if (rlSrc.location == kLocPhysReg) {
463 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
464 } else {
465 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
466 }
467 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
468 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800469}
470
buzbee408ad162012-06-06 16:45:18 -0700471void genIntNarrowing(CompilationUnit* cUnit, Instruction::Code opcode,
472 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800473{
Bill Buzbeea114add2012-05-03 15:00:40 -0700474 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
475 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
476 OpKind op = kOpInvalid;
buzbee408ad162012-06-06 16:45:18 -0700477 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700478 case Instruction::INT_TO_BYTE:
479 op = kOp2Byte;
480 break;
481 case Instruction::INT_TO_SHORT:
482 op = kOp2Short;
483 break;
484 case Instruction::INT_TO_CHAR:
485 op = kOp2Char;
486 break;
487 default:
488 LOG(ERROR) << "Bad int conversion type";
489 }
490 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
491 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800492}
493
494/*
495 * Let helper function take care of everything. Will call
496 * Array::AllocFromCode(type_idx, method, count);
497 * Note: AllocFromCode will handle checks for errNegativeArraySize.
498 */
buzbee408ad162012-06-06 16:45:18 -0700499void genNewArray(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800500 RegLocation rlSrc)
501{
Bill Buzbeea114add2012-05-03 15:00:40 -0700502 oatFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700503 int funcOffset;
504 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
505 cUnit->dex_cache,
506 *cUnit->dex_file,
507 type_idx)) {
508 funcOffset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
509 } else {
510 funcOffset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
511 }
512 callRuntimeHelperImmMethodRegLocation(cUnit, funcOffset, type_idx, rlSrc);
513 RegLocation rlResult = oatGetReturn(cUnit, false);
514 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800515}
516
517/*
518 * Similar to genNewArray, but with post-allocation initialization.
519 * Verifier guarantees we're dealing with an array class. Current
520 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
521 * Current code also throws internal unimp if not 'L', '[' or 'I'.
522 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700523void genFilledNewArray(CompilationUnit* cUnit, CallInfo* info)
buzbee31a4a6f2012-02-28 15:36:15 -0800524{
buzbee3b3dbdd2012-06-13 13:39:34 -0700525 int elems = info->numArgWords;
526 int typeIdx = info->index;
Bill Buzbeea114add2012-05-03 15:00:40 -0700527 oatFlushAllRegs(cUnit); /* Everything to home location */
528 int funcOffset;
529 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
530 cUnit->dex_cache,
531 *cUnit->dex_file,
532 typeIdx)) {
533 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
534 } else {
535 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
536 }
537 callRuntimeHelperImmMethodImm(cUnit, funcOffset, typeIdx, elems);
538 oatFreeTemp(cUnit, rARG2);
539 oatFreeTemp(cUnit, rARG1);
540 /*
541 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
542 * return region. Because AllocFromCode placed the new array
543 * in rRET0, we'll just lock it into place. When debugger support is
544 * added, it may be necessary to additionally copy all return
545 * values to a home location in thread-local storage
546 */
547 oatLockTemp(cUnit, rRET0);
548
549 // TODO: use the correct component size, currently all supported types
550 // share array alignment with ints (see comment at head of function)
551 size_t component_size = sizeof(int32_t);
552
553 // Having a range of 0 is legal
buzbee3b3dbdd2012-06-13 13:39:34 -0700554 if (info->isRange && (elems > 0)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800555 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700556 * Bit of ugliness here. We're going generate a mem copy loop
557 * on the register range, but it is possible that some regs
558 * in the range have been promoted. This is unlikely, but
559 * before generating the copy, we'll just force a flush
560 * of any regs in the source range that have been promoted to
561 * home location.
buzbee31a4a6f2012-02-28 15:36:15 -0800562 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700563 for (int i = 0; i < elems; i++) {
564 RegLocation loc = oatUpdateLoc(cUnit, info->args[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700565 if (loc.location == kLocPhysReg) {
566 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
567 loc.lowReg, kWord);
568 }
buzbee31a4a6f2012-02-28 15:36:15 -0800569 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700570 /*
571 * TUNING note: generated code here could be much improved, but
572 * this is an uncommon operation and isn't especially performance
573 * critical.
574 */
575 int rSrc = oatAllocTemp(cUnit);
576 int rDst = oatAllocTemp(cUnit);
577 int rIdx = oatAllocTemp(cUnit);
578#if defined(TARGET_ARM)
579 int rVal = rLR; // Using a lot of temps, rLR is known free here
580#elif defined(TARGET_X86)
jeffhao5772bab2012-05-18 11:51:26 -0700581 oatFreeTemp(cUnit, rRET0);
582 int rVal = oatAllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700583#else
584 int rVal = oatAllocTemp(cUnit);
585#endif
586 // Set up source pointer
buzbee3b3dbdd2012-06-13 13:39:34 -0700587 RegLocation rlFirst = info->args[0];
Bill Buzbeea114add2012-05-03 15:00:40 -0700588 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
589 oatSRegOffset(cUnit, rlFirst.sRegLow));
590 // Set up the target pointer
591 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
592 Array::DataOffset(component_size).Int32Value());
593 // Set up the loop counter (known to be > 0)
buzbee3b3dbdd2012-06-13 13:39:34 -0700594 loadConstant(cUnit, rIdx, elems - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700595 // Generate the copy loop. Going backwards for convenience
596 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
597 // Copy next element
598 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
599 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
600#if defined(TARGET_ARM)
601 // Combine sub & test using sub setflags encoding here
602 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
603 opCondBranch(cUnit, kCondGe, target);
604#else
605 oatFreeTemp(cUnit, rVal);
606 opRegImm(cUnit, kOpSub, rIdx, 1);
607 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
608#endif
jeffhao5772bab2012-05-18 11:51:26 -0700609#if defined(TARGET_X86)
610 // Restore the target pointer
611 opRegRegImm(cUnit, kOpAdd, rRET0, rDst,
612 -Array::DataOffset(component_size).Int32Value());
613#endif
buzbee3b3dbdd2012-06-13 13:39:34 -0700614 } else if (!info->isRange) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700615 // TUNING: interleave
buzbee3b3dbdd2012-06-13 13:39:34 -0700616 for (int i = 0; i < elems; i++) {
617 RegLocation rlArg = loadValue(cUnit, info->args[i], kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700618 storeBaseDisp(cUnit, rRET0,
619 Array::DataOffset(component_size).Int32Value() +
620 i * 4, rlArg.lowReg, kWord);
621 // If the loadValue caused a temp to be allocated, free it
622 if (oatIsTemp(cUnit, rlArg.lowReg)) {
623 oatFreeTemp(cUnit, rlArg.lowReg);
624 }
625 }
626 }
buzbeee5f01222012-06-14 15:19:35 -0700627 if (info->result.location != kLocInvalid) {
628 storeValue(cUnit, info->result, oatGetReturn(cUnit, false /* not fp */));
629 }
buzbee31a4a6f2012-02-28 15:36:15 -0800630}
631
buzbee408ad162012-06-06 16:45:18 -0700632void genSput(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlSrc,
Bill Buzbeea114add2012-05-03 15:00:40 -0700633 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800634{
Bill Buzbeea114add2012-05-03 15:00:40 -0700635 int fieldOffset;
636 int ssbIndex;
637 bool isVolatile;
638 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800639
Bill Buzbeea114add2012-05-03 15:00:40 -0700640 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
641 *cUnit->dex_file, *cUnit->dex_cache,
642 cUnit->code_item, cUnit->method_idx,
643 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800644
Bill Buzbeea114add2012-05-03 15:00:40 -0700645 bool fastPath =
646 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
647 fieldOffset, ssbIndex,
648 isReferrersClass, isVolatile,
649 true);
650 if (fastPath && !SLOW_FIELD_PATH) {
651 DCHECK_GE(fieldOffset, 0);
652 int rBase;
653 if (isReferrersClass) {
654 // Fast path, static storage base is this method's class
655 RegLocation rlMethod = loadCurrMethod(cUnit);
656 rBase = oatAllocTemp(cUnit);
657 loadWordDisp(cUnit, rlMethod.lowReg,
658 Method::DeclaringClassOffset().Int32Value(), rBase);
659 if (oatIsTemp(cUnit, rlMethod.lowReg)) {
660 oatFreeTemp(cUnit, rlMethod.lowReg);
661 }
buzbee31a4a6f2012-02-28 15:36:15 -0800662 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700663 // Medium path, static storage base in a different class which
664 // requires checks that the other class is initialized.
665 DCHECK_GE(ssbIndex, 0);
666 // May do runtime call so everything to home locations.
667 oatFlushAllRegs(cUnit);
668 // Using fixed register to sync with possible call to runtime
669 // support.
670 int rMethod = rARG1;
671 oatLockTemp(cUnit, rMethod);
672 loadCurrMethodDirect(cUnit, rMethod);
673 rBase = rARG0;
674 oatLockTemp(cUnit, rBase);
675 loadWordDisp(cUnit, rMethod,
676 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
677 rBase);
678 loadWordDisp(cUnit, rBase,
679 Array::DataOffset(sizeof(Object*)).Int32Value() +
680 sizeof(int32_t*) * ssbIndex, rBase);
681 // rBase now points at appropriate static storage base (Class*)
682 // or NULL if not initialized. Check for NULL and call helper if NULL.
683 // TUNING: fast path should fall through
684 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
685 loadConstant(cUnit, rARG0, ssbIndex);
686 callRuntimeHelperImm(cUnit,
687 ENTRYPOINT_OFFSET(pInitializeStaticStorage),
688 ssbIndex);
689#if defined(TARGET_MIPS)
690 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
691 opRegCopy(cUnit, rBase, rRET0);
692#endif
693 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
694 branchOver->target = (LIR*)skipTarget;
695 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800696 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700697 // rBase now holds static storage base
698 if (isLongOrDouble) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700699 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
700 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700701 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
702 }
703//FIXME: need to generalize the barrier call
704 if (isVolatile) {
705 oatGenMemBarrier(cUnit, kST);
706 }
707 if (isLongOrDouble) {
708 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
709 rlSrc.highReg);
710 } else {
711 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
712 }
713 if (isVolatile) {
714 oatGenMemBarrier(cUnit, kSY);
715 }
716 if (isObject) {
717 markGCCard(cUnit, rlSrc.lowReg, rBase);
718 }
719 oatFreeTemp(cUnit, rBase);
720 } else {
721 oatFlushAllRegs(cUnit); // Everything to home locations
722 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Static) :
723 (isObject ? ENTRYPOINT_OFFSET(pSetObjStatic)
724 : ENTRYPOINT_OFFSET(pSet32Static));
725 callRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc);
726 }
buzbee31a4a6f2012-02-28 15:36:15 -0800727}
728
buzbee408ad162012-06-06 16:45:18 -0700729void genSget(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700730 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800731{
Bill Buzbeea114add2012-05-03 15:00:40 -0700732 int fieldOffset;
733 int ssbIndex;
734 bool isVolatile;
735 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800736
Bill Buzbeea114add2012-05-03 15:00:40 -0700737 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
738 *cUnit->dex_file, *cUnit->dex_cache,
739 cUnit->code_item, cUnit->method_idx,
740 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800741
Bill Buzbeea114add2012-05-03 15:00:40 -0700742 bool fastPath =
743 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
744 fieldOffset, ssbIndex,
745 isReferrersClass, isVolatile,
746 false);
747 if (fastPath && !SLOW_FIELD_PATH) {
748 DCHECK_GE(fieldOffset, 0);
749 int rBase;
750 if (isReferrersClass) {
751 // Fast path, static storage base is this method's class
752 RegLocation rlMethod = loadCurrMethod(cUnit);
753 rBase = oatAllocTemp(cUnit);
754 loadWordDisp(cUnit, rlMethod.lowReg,
755 Method::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800756 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700757 // Medium path, static storage base in a different class which
758 // requires checks that the other class is initialized
759 DCHECK_GE(ssbIndex, 0);
760 // May do runtime call so everything to home locations.
761 oatFlushAllRegs(cUnit);
762 // Using fixed register to sync with possible call to runtime
763 // support
764 int rMethod = rARG1;
765 oatLockTemp(cUnit, rMethod);
766 loadCurrMethodDirect(cUnit, rMethod);
767 rBase = rARG0;
768 oatLockTemp(cUnit, rBase);
769 loadWordDisp(cUnit, rMethod,
770 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
771 rBase);
772 loadWordDisp(cUnit, rBase,
773 Array::DataOffset(sizeof(Object*)).Int32Value() +
774 sizeof(int32_t*) * ssbIndex, rBase);
775 // rBase now points at appropriate static storage base (Class*)
776 // or NULL if not initialized. Check for NULL and call helper if NULL.
777 // TUNING: fast path should fall through
778 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
779 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage),
780 ssbIndex);
781#if defined(TARGET_MIPS)
782 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
783 opRegCopy(cUnit, rBase, rRET0);
784#endif
785 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
786 branchOver->target = (LIR*)skipTarget;
787 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800788 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700789 // rBase now holds static storage base
Bill Buzbeea114add2012-05-03 15:00:40 -0700790 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
791 if (isVolatile) {
792 oatGenMemBarrier(cUnit, kSY);
793 }
794 if (isLongOrDouble) {
buzbee408ad162012-06-06 16:45:18 -0700795 loadBaseDispWide(cUnit, rBase, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700796 rlResult.highReg, INVALID_SREG);
797 } else {
798 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
799 }
800 oatFreeTemp(cUnit, rBase);
801 if (isLongOrDouble) {
802 storeValueWide(cUnit, rlDest, rlResult);
803 } else {
804 storeValue(cUnit, rlDest, rlResult);
805 }
806 } else {
807 oatFlushAllRegs(cUnit); // Everything to home locations
808 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Static) :
809 (isObject ? ENTRYPOINT_OFFSET(pGetObjStatic)
810 : ENTRYPOINT_OFFSET(pGet32Static));
811 callRuntimeHelperImm(cUnit, getterOffset, fieldIdx);
812 if (isLongOrDouble) {
813 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
814 storeValueWide(cUnit, rlDest, rlResult);
815 } else {
816 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
817 storeValue(cUnit, rlDest, rlResult);
818 }
819 }
buzbee31a4a6f2012-02-28 15:36:15 -0800820}
821
822
823// Debugging routine - if null target, branch to DebugMe
824void genShowTarget(CompilationUnit* cUnit)
825{
buzbeea7678db2012-03-05 15:35:46 -0800826#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700827 UNIMPLEMENTED(WARNING) << "genShowTarget";
buzbeea7678db2012-03-05 15:35:46 -0800828#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700829 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
830 loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pDebugMe), rINVOKE_TGT);
831 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
832 branchOver->target = (LIR*)target;
buzbeea7678db2012-03-05 15:35:46 -0800833#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800834}
835
buzbee408ad162012-06-06 16:45:18 -0700836void genThrowVerificationError(CompilationUnit* cUnit, int info1, int info2)
buzbee31a4a6f2012-02-28 15:36:15 -0800837{
Bill Buzbeea114add2012-05-03 15:00:40 -0700838 callRuntimeHelperImmImm(cUnit,
839 ENTRYPOINT_OFFSET(pThrowVerificationErrorFromCode),
buzbee408ad162012-06-06 16:45:18 -0700840 info1, info2);
buzbee31a4a6f2012-02-28 15:36:15 -0800841}
842
843void handleSuspendLaunchpads(CompilationUnit *cUnit)
844{
Bill Buzbeea114add2012-05-03 15:00:40 -0700845 LIR** suspendLabel = (LIR **)cUnit->suspendLaunchpads.elemList;
846 int numElems = cUnit->suspendLaunchpads.numUsed;
847 for (int i = 0; i < numElems; i++) {
848 oatResetRegPool(cUnit);
849 oatResetDefTracking(cUnit);
850 LIR* lab = suspendLabel[i];
851 LIR* resumeLab = (LIR*)lab->operands[0];
852 cUnit->currentDalvikOffset = lab->operands[1];
853 oatAppendLIR(cUnit, lab);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700854#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700855 opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700856#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700857 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
858 opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700859#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700860 opUnconditionalBranch(cUnit, resumeLab);
861 }
buzbee31a4a6f2012-02-28 15:36:15 -0800862}
863
buzbeefc9e6fa2012-03-23 15:14:29 -0700864void handleIntrinsicLaunchpads(CompilationUnit *cUnit)
865{
Bill Buzbeea114add2012-05-03 15:00:40 -0700866 LIR** intrinsicLabel = (LIR **)cUnit->intrinsicLaunchpads.elemList;
867 int numElems = cUnit->intrinsicLaunchpads.numUsed;
868 for (int i = 0; i < numElems; i++) {
869 oatResetRegPool(cUnit);
870 oatResetDefTracking(cUnit);
871 LIR* lab = intrinsicLabel[i];
buzbee3b3dbdd2012-06-13 13:39:34 -0700872 CallInfo* info = (CallInfo*)lab->operands[0];
buzbee15bf9802012-06-12 17:49:27 -0700873 cUnit->currentDalvikOffset = info->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700874 oatAppendLIR(cUnit, lab);
buzbee15bf9802012-06-12 17:49:27 -0700875 genInvoke(cUnit, info);
Bill Buzbeea114add2012-05-03 15:00:40 -0700876 LIR* resumeLab = (LIR*)lab->operands[2];
877 if (resumeLab != NULL) {
878 opUnconditionalBranch(cUnit, resumeLab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700879 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700880 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700881}
882
buzbee31a4a6f2012-02-28 15:36:15 -0800883void handleThrowLaunchpads(CompilationUnit *cUnit)
884{
Bill Buzbeea114add2012-05-03 15:00:40 -0700885 LIR** throwLabel = (LIR **)cUnit->throwLaunchpads.elemList;
886 int numElems = cUnit->throwLaunchpads.numUsed;
887 for (int i = 0; i < numElems; i++) {
888 oatResetRegPool(cUnit);
889 oatResetDefTracking(cUnit);
890 LIR* lab = throwLabel[i];
891 cUnit->currentDalvikOffset = lab->operands[1];
892 oatAppendLIR(cUnit, lab);
893 int funcOffset = 0;
894 int v1 = lab->operands[2];
895 int v2 = lab->operands[3];
896 switch (lab->operands[0]) {
897 case kThrowNullPointer:
898 funcOffset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
899 break;
900 case kThrowArrayBounds:
jeffhao44335e12012-06-18 13:48:25 -0700901 // Move v1 (array index) to rARG0 and v2 (array length) to rARG1
Bill Buzbeea114add2012-05-03 15:00:40 -0700902 if (v2 != rARG0) {
903 opRegCopy(cUnit, rARG0, v1);
jeffhao703f2cd2012-07-13 17:25:52 -0700904#if defined (TARGET_X86)
905 // x86 leaves the array pointer in v2, so load the array length that the handler expects
906 opRegMem(cUnit, kOpMov, rARG1, v2, Array::LengthOffset().Int32Value());
907#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700908 opRegCopy(cUnit, rARG1, v2);
jeffhao703f2cd2012-07-13 17:25:52 -0700909#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700910 } else {
911 if (v1 == rARG1) {
jeffhao44335e12012-06-18 13:48:25 -0700912 // Swap v1 and v2, using rARG2 as a temp
913 opRegCopy(cUnit, rARG2, v1);
jeffhao703f2cd2012-07-13 17:25:52 -0700914#if defined (TARGET_X86)
915 // x86 leaves the array pointer in v2, so load the array length that the handler expects
916 opRegMem(cUnit, kOpMov, rARG1, v2, Array::LengthOffset().Int32Value());
917#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700918 opRegCopy(cUnit, rARG1, v2);
jeffhao703f2cd2012-07-13 17:25:52 -0700919#endif
jeffhao44335e12012-06-18 13:48:25 -0700920 opRegCopy(cUnit, rARG0, rARG2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700921 } else {
jeffhao703f2cd2012-07-13 17:25:52 -0700922#if defined (TARGET_X86)
923 // x86 leaves the array pointer in v2, so load the array length that the handler expects
924 opRegMem(cUnit, kOpMov, rARG1, v2, Array::LengthOffset().Int32Value());
925#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700926 opRegCopy(cUnit, rARG1, v2);
jeffhao703f2cd2012-07-13 17:25:52 -0700927#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700928 opRegCopy(cUnit, rARG0, v1);
929 }
buzbee31a4a6f2012-02-28 15:36:15 -0800930 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700931 funcOffset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
932 break;
933 case kThrowDivZero:
934 funcOffset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
935 break;
936 case kThrowVerificationError:
937 loadConstant(cUnit, rARG0, v1);
938 loadConstant(cUnit, rARG1, v2);
939 funcOffset =
940 ENTRYPOINT_OFFSET(pThrowVerificationErrorFromCode);
941 break;
942 case kThrowNoSuchMethod:
943 opRegCopy(cUnit, rARG0, v1);
944 funcOffset =
945 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
946 break;
947 case kThrowStackOverflow:
948 funcOffset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
949 // Restore stack alignment
Ian Rogersab2b55d2012-03-18 00:06:11 -0700950#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 opRegImm(cUnit, kOpAdd, rSP,
952 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700953#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700954 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700955#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700956 break;
957 default:
958 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
buzbee31a4a6f2012-02-28 15:36:15 -0800959 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700960 oatClobberCalleeSave(cUnit);
961#if !defined(TARGET_X86)
962 int rTgt = loadHelper(cUnit, funcOffset);
963 opReg(cUnit, kOpBlx, rTgt);
964 oatFreeTemp(cUnit, rTgt);
965#else
966 opThreadMem(cUnit, kOpBlx, funcOffset);
967#endif
968 }
buzbee31a4a6f2012-02-28 15:36:15 -0800969}
970
971/* Needed by the Assembler */
972void oatSetupResourceMasks(LIR* lir)
973{
Bill Buzbeea114add2012-05-03 15:00:40 -0700974 setupResourceMasks(lir);
buzbee31a4a6f2012-02-28 15:36:15 -0800975}
976
buzbee16da88c2012-03-20 10:38:17 -0700977bool fastInstance(CompilationUnit* cUnit, uint32_t fieldIdx,
978 int& fieldOffset, bool& isVolatile, bool isPut)
979{
Bill Buzbeea114add2012-05-03 15:00:40 -0700980 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
981 *cUnit->dex_file, *cUnit->dex_cache,
982 cUnit->code_item, cUnit->method_idx,
983 cUnit->access_flags);
984 return cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
985 fieldOffset, isVolatile, isPut);
buzbee16da88c2012-03-20 10:38:17 -0700986}
987
buzbee408ad162012-06-06 16:45:18 -0700988void genIGet(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -0800989 RegLocation rlDest, RegLocation rlObj,
Bill Buzbeea114add2012-05-03 15:00:40 -0700990 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800991{
Bill Buzbeea114add2012-05-03 15:00:40 -0700992 int fieldOffset;
993 bool isVolatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800994
Bill Buzbeea114add2012-05-03 15:00:40 -0700995 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800996
Bill Buzbeea114add2012-05-03 15:00:40 -0700997 if (fastPath && !SLOW_FIELD_PATH) {
998 RegLocation rlResult;
999 RegisterClass regClass = oatRegClassBySize(size);
1000 DCHECK_GE(fieldOffset, 0);
1001 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1002 if (isLongOrDouble) {
1003 DCHECK(rlDest.wide);
buzbee408ad162012-06-06 16:45:18 -07001004 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001005#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001006 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001007 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
1008 loadBaseDispWide(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -07001009 rlResult.highReg, rlObj.sRegLow);
1010 if (isVolatile) {
1011 oatGenMemBarrier(cUnit, kSY);
1012 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001013#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001014 int regPtr = oatAllocTemp(cUnit);
1015 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1016 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1017 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1018 if (isVolatile) {
1019 oatGenMemBarrier(cUnit, kSY);
1020 }
1021 oatFreeTemp(cUnit, regPtr);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001022#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001023 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001024 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001025 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001026 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
1027 loadBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -07001028 kWord, rlObj.sRegLow);
1029 if (isVolatile) {
1030 oatGenMemBarrier(cUnit, kSY);
1031 }
1032 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001033 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001034 } else {
1035 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Instance) :
1036 (isObject ? ENTRYPOINT_OFFSET(pGetObjInstance)
1037 : ENTRYPOINT_OFFSET(pGet32Instance));
1038 callRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj);
1039 if (isLongOrDouble) {
1040 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
1041 storeValueWide(cUnit, rlDest, rlResult);
1042 } else {
1043 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
1044 storeValue(cUnit, rlDest, rlResult);
1045 }
1046 }
buzbee31a4a6f2012-02-28 15:36:15 -08001047}
1048
buzbee408ad162012-06-06 16:45:18 -07001049void genIPut(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
1050 RegLocation rlSrc, RegLocation rlObj, bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -08001051{
Bill Buzbeea114add2012-05-03 15:00:40 -07001052 int fieldOffset;
1053 bool isVolatile;
buzbee31a4a6f2012-02-28 15:36:15 -08001054
Bill Buzbeea114add2012-05-03 15:00:40 -07001055 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
1056 true);
1057 if (fastPath && !SLOW_FIELD_PATH) {
1058 RegisterClass regClass = oatRegClassBySize(size);
1059 DCHECK_GE(fieldOffset, 0);
1060 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1061 if (isLongOrDouble) {
1062 int regPtr;
1063 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee408ad162012-06-06 16:45:18 -07001064 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07001065 regPtr = oatAllocTemp(cUnit);
1066 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1067 if (isVolatile) {
1068 oatGenMemBarrier(cUnit, kST);
1069 }
jeffhao41005dd2012-05-09 17:58:52 -07001070 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001071 if (isVolatile) {
1072 oatGenMemBarrier(cUnit, kSY);
1073 }
1074 oatFreeTemp(cUnit, regPtr);
buzbee31a4a6f2012-02-28 15:36:15 -08001075 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001076 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee408ad162012-06-06 16:45:18 -07001077 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07001078 if (isVolatile) {
1079 oatGenMemBarrier(cUnit, kST);
1080 }
1081 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
1082 if (isVolatile) {
1083 oatGenMemBarrier(cUnit, kSY);
1084 }
1085 if (isObject) {
1086 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
1087 }
buzbee31a4a6f2012-02-28 15:36:15 -08001088 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001089 } else {
1090 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Instance) :
1091 (isObject ? ENTRYPOINT_OFFSET(pSetObjInstance)
1092 : ENTRYPOINT_OFFSET(pSet32Instance));
1093 callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset,
1094 fieldIdx, rlObj, rlSrc);
1095 }
buzbee31a4a6f2012-02-28 15:36:15 -08001096}
1097
buzbee6969d502012-06-15 16:40:31 -07001098void genConstClass(CompilationUnit* cUnit, uint32_t type_idx,
1099 RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001100{
Bill Buzbeea114add2012-05-03 15:00:40 -07001101 RegLocation rlMethod = loadCurrMethod(cUnit);
1102 int resReg = oatAllocTemp(cUnit);
1103 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1104 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1105 cUnit->dex_cache,
1106 *cUnit->dex_file,
1107 type_idx)) {
1108 // Call out to helper which resolves type and verifies access.
1109 // Resolved type returned in rRET0.
1110 callRuntimeHelperImmReg(cUnit,
1111 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1112 type_idx, rlMethod.lowReg);
1113 RegLocation rlResult = oatGetReturn(cUnit, false);
1114 storeValue(cUnit, rlDest, rlResult);
1115 } else {
1116 // We're don't need access checks, load type from dex cache
1117 int32_t dex_cache_offset =
1118 Method::DexCacheResolvedTypesOffset().Int32Value();
1119 loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
1120 int32_t offset_of_type =
1121 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1122 * type_idx);
1123 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
1124 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
1125 type_idx) || SLOW_TYPE_PATH) {
1126 // Slow path, at runtime test if type is null and if so initialize
1127 oatFlushAllRegs(cUnit);
1128 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0, NULL);
1129 // Resolved, store and hop over following code
1130 storeValue(cUnit, rlDest, rlResult);
1131 /*
1132 * Because we have stores of the target value on two paths,
1133 * clobber temp tracking for the destination using the ssa name
1134 */
1135 oatClobberSReg(cUnit, rlDest.sRegLow);
1136 LIR* branch2 = opUnconditionalBranch(cUnit,0);
1137 // TUNING: move slow path to end & remove unconditional branch
1138 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
1139 // Call out to helper, which will return resolved type in rARG0
1140 callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1141 type_idx, rlMethod.lowReg);
1142 RegLocation rlResult = oatGetReturn(cUnit, false);
1143 storeValue(cUnit, rlDest, rlResult);
1144 /*
1145 * Because we have stores of the target value on two paths,
1146 * clobber temp tracking for the destination using the ssa name
1147 */
1148 oatClobberSReg(cUnit, rlDest.sRegLow);
1149 // Rejoin code paths
1150 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
1151 branch1->target = (LIR*)target1;
1152 branch2->target = (LIR*)target2;
buzbee31a4a6f2012-02-28 15:36:15 -08001153 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001154 // Fast path, we're done - just store result
1155 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001156 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001157 }
buzbee31a4a6f2012-02-28 15:36:15 -08001158}
Ian Rogersab2b55d2012-03-18 00:06:11 -07001159
buzbee6969d502012-06-15 16:40:31 -07001160void genConstString(CompilationUnit* cUnit, uint32_t string_idx,
1161 RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001162{
Bill Buzbeea114add2012-05-03 15:00:40 -07001163 /* NOTE: Most strings should be available at compile time */
Bill Buzbeea114add2012-05-03 15:00:40 -07001164 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1165 (sizeof(String*) * string_idx);
1166 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
1167 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
1168 // slow path, resolve string if not in dex cache
1169 oatFlushAllRegs(cUnit);
1170 oatLockCallTemps(cUnit); // Using explicit registers
1171 loadCurrMethodDirect(cUnit, rARG2);
1172 loadWordDisp(cUnit, rARG2,
1173 Method::DexCacheStringsOffset().Int32Value(), rARG0);
1174 // Might call out to helper, which will return resolved string in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001175#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001176 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001177#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001178 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
1179 loadConstant(cUnit, rARG1, string_idx);
buzbee31a4a6f2012-02-28 15:36:15 -08001180#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001181 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
1182 genBarrier(cUnit);
1183 // For testing, always force through helper
1184 if (!EXERCISE_SLOWEST_STRING_PATH) {
1185 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08001186 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001187 opRegCopy(cUnit, rARG0, rARG2); // .eq
1188 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
1189 oatFreeTemp(cUnit, rTgt);
1190#elif defined(TARGET_MIPS)
1191 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
1192 opRegCopy(cUnit, rARG0, rARG2); // .eq
1193 opReg(cUnit, kOpBlx, rTgt);
1194 oatFreeTemp(cUnit, rTgt);
1195 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1196 branch->target = target;
1197#else
1198 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode),
1199 rARG2, rARG1);
1200#endif
1201 genBarrier(cUnit);
1202 storeValue(cUnit, rlDest, oatGetReturn(cUnit, false));
1203 } else {
1204 RegLocation rlMethod = loadCurrMethod(cUnit);
1205 int resReg = oatAllocTemp(cUnit);
1206 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1207 loadWordDisp(cUnit, rlMethod.lowReg,
1208 Method::DexCacheStringsOffset().Int32Value(), resReg);
1209 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1210 storeValue(cUnit, rlDest, rlResult);
1211 }
buzbee31a4a6f2012-02-28 15:36:15 -08001212}
1213
1214/*
1215 * Let helper function take care of everything. Will
1216 * call Class::NewInstanceFromCode(type_idx, method);
1217 */
buzbee408ad162012-06-06 16:45:18 -07001218void genNewInstance(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001219{
Bill Buzbeea114add2012-05-03 15:00:40 -07001220 oatFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -07001221 // alloc will always check for resolution, do we also need to verify
1222 // access because the verifier was unable to?
1223 int funcOffset;
1224 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
1225 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
1226 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
1227 } else {
1228 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
1229 }
1230 callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx);
1231 RegLocation rlResult = oatGetReturn(cUnit, false);
1232 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001233}
1234
buzbee408ad162012-06-06 16:45:18 -07001235void genThrow(CompilationUnit* cUnit, RegLocation rlSrc)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001236{
Bill Buzbeea114add2012-05-03 15:00:40 -07001237 oatFlushAllRegs(cUnit);
1238 callRuntimeHelperRegLocation(cUnit, ENTRYPOINT_OFFSET(pDeliverException),
1239 rlSrc);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001240}
1241
buzbee408ad162012-06-06 16:45:18 -07001242void genInstanceof(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001243 RegLocation rlSrc)
1244{
Bill Buzbeea114add2012-05-03 15:00:40 -07001245 oatFlushAllRegs(cUnit);
1246 // May generate a call - use explicit registers
1247 oatLockCallTemps(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001248 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1249 int classReg = rARG2; // rARG2 will hold the Class*
1250 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1251 cUnit->dex_cache,
1252 *cUnit->dex_file,
1253 type_idx)) {
1254 // Check we have access to type_idx and if not throw IllegalAccessError,
1255 // returns Class* in rARG0
1256 callRuntimeHelperImm(cUnit,
1257 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1258 type_idx);
1259 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1260 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1261 } else {
1262 // Load dex cache entry into classReg (rARG2)
1263 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1264 loadWordDisp(cUnit, rARG1,
1265 Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
1266 int32_t offset_of_type =
1267 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1268 * type_idx);
1269 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1270 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1271 cUnit->dex_cache, type_idx)) {
1272 // Need to test presence of type in dex cache at runtime
1273 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1274 // Not resolved
1275 // Call out to helper, which will return resolved type in rRET0
1276 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1277 type_idx);
1278 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
1279 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1280 // Rejoin code paths
1281 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1282 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001283 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001284 }
1285 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
1286 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1287 /* load object->klass_ */
1288 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1289 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1290 /* rARG0 is ref, rARG1 is ref->klass_, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001291#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001292 /* Uses conditional nullification */
1293 int rTgt = loadHelper(cUnit,
1294 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1295 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
1296 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
1297 loadConstant(cUnit, rARG0, 1); // .eq case - load true
1298 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1299 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1300 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001301#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001302 /* Uses branchovers */
1303 loadConstant(cUnit, rARG0, 1); // assume true
1304 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001305#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001306 int rTgt = loadHelper(cUnit,
1307 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1308 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1309 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1310 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001311#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001312 opRegCopy(cUnit, rARG0, rARG2);
1313 opThreadMem(cUnit, kOpBlx,
1314 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001315#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001316#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001317 oatClobberCalleeSave(cUnit);
1318 /* branch targets here */
1319 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1320 RegLocation rlResult = oatGetReturn(cUnit, false);
1321 storeValue(cUnit, rlDest, rlResult);
1322 branch1->target = target;
buzbee0398c422012-03-02 15:22:47 -08001323#if !defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001324 branchover->target = target;
buzbee0398c422012-03-02 15:22:47 -08001325#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001326}
1327
buzbee408ad162012-06-06 16:45:18 -07001328void genCheckCast(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08001329{
Bill Buzbeea114add2012-05-03 15:00:40 -07001330 oatFlushAllRegs(cUnit);
1331 // May generate a call - use explicit registers
1332 oatLockCallTemps(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001333 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1334 int classReg = rARG2; // rARG2 will hold the Class*
1335 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1336 cUnit->dex_cache,
1337 *cUnit->dex_file,
1338 type_idx)) {
1339 // Check we have access to type_idx and if not throw IllegalAccessError,
1340 // returns Class* in rRET0
1341 // InitializeTypeAndVerifyAccess(idx, method)
1342 callRuntimeHelperImmReg(cUnit,
1343 ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1344 type_idx, rARG1);
1345 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1346 } else {
1347 // Load dex cache entry into classReg (rARG2)
1348 loadWordDisp(cUnit, rARG1,
1349 Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
1350 int32_t offset_of_type =
1351 Array::DataOffset(sizeof(Class*)).Int32Value() +
1352 (sizeof(Class*) * type_idx);
1353 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1354 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1355 cUnit->dex_cache, type_idx)) {
1356 // Need to test presence of type in dex cache at runtime
1357 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1358 // Not resolved
1359 // Call out to helper, which will return resolved type in rARG0
1360 // InitializeTypeFromCode(idx, method)
1361 callRuntimeHelperImmReg(cUnit,
1362 ENTRYPOINT_OFFSET(pInitializeTypeFromCode),
1363 type_idx, rARG1);
1364 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
1365 // Rejoin code paths
1366 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1367 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001368 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001369 }
1370 // At this point, classReg (rARG2) has class
1371 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1372 /* Null is OK - continue */
1373 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1374 /* load object->klass_ */
1375 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1376 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1377 /* rARG1 now contains object->klass_ */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001378#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001379 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
1380 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode),
1381 rARG1, rARG2);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001382#else // defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001383 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1384 opRegReg(cUnit, kOpCmp, rARG1, classReg);
1385 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1386 opRegCopy(cUnit, rARG0, rARG1);
1387 opRegCopy(cUnit, rARG1, rARG2);
1388 oatClobberCalleeSave(cUnit);
1389 opReg(cUnit, kOpBlx, rTgt);
1390 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001391#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001392 /* branch target here */
1393 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1394 branch1->target = target;
1395 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001396}
1397
buzbee31a4a6f2012-02-28 15:36:15 -08001398/*
1399 * Generate array store
1400 *
1401 */
buzbee408ad162012-06-06 16:45:18 -07001402void genArrayObjPut(CompilationUnit* cUnit, int optFlags, RegLocation rlArray,
Bill Buzbeea114add2012-05-03 15:00:40 -07001403 RegLocation rlIndex, RegLocation rlSrc, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001404{
Bill Buzbeea114add2012-05-03 15:00:40 -07001405 int lenOffset = Array::LengthOffset().Int32Value();
1406 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
buzbee31a4a6f2012-02-28 15:36:15 -08001407
Bill Buzbeea114add2012-05-03 15:00:40 -07001408 oatFlushAllRegs(cUnit); // Use explicit registers
1409 oatLockCallTemps(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001410
Bill Buzbeea114add2012-05-03 15:00:40 -07001411 int rValue = rARG0; // Register holding value
1412 int rArrayClass = rARG1; // Register holding array's Class
1413 int rArray = rARG2; // Register holding array
1414 int rIndex = rARG3; // Register holding index into array
Ian Rogersd36c52e2012-04-09 16:29:25 -07001415
Bill Buzbeea114add2012-05-03 15:00:40 -07001416 loadValueDirectFixed(cUnit, rlArray, rArray); // Grab array
1417 loadValueDirectFixed(cUnit, rlSrc, rValue); // Grab value
1418 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Grab index
Ian Rogersd36c52e2012-04-09 16:29:25 -07001419
buzbee408ad162012-06-06 16:45:18 -07001420 genNullCheck(cUnit, rlArray.sRegLow, rArray, optFlags); // NPE?
Ian Rogersd36c52e2012-04-09 16:29:25 -07001421
Bill Buzbeea114add2012-05-03 15:00:40 -07001422 // Store of null?
1423 LIR* null_value_check = opCmpImmBranch(cUnit, kCondEq, rValue, 0, NULL);
Ian Rogersd36c52e2012-04-09 16:29:25 -07001424
Bill Buzbeea114add2012-05-03 15:00:40 -07001425 // Get the array's class.
1426 loadWordDisp(cUnit, rArray, Object::ClassOffset().Int32Value(), rArrayClass);
1427 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode),
1428 rValue, rArrayClass);
1429 // Redo loadValues in case they didn't survive the call.
1430 loadValueDirectFixed(cUnit, rlArray, rArray); // Reload array
1431 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Reload index
1432 loadValueDirectFixed(cUnit, rlSrc, rValue); // Reload value
1433 rArrayClass = INVALID_REG;
buzbee31a4a6f2012-02-28 15:36:15 -08001434
Bill Buzbeea114add2012-05-03 15:00:40 -07001435 // Branch here if value to be stored == null
1436 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1437 null_value_check->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001438
Ian Rogersb41b33b2012-03-20 14:22:54 -07001439#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001440 // make an extra temp available for card mark below
1441 oatFreeTemp(cUnit, rARG1);
buzbee408ad162012-06-06 16:45:18 -07001442 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001443 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
buzbee408ad162012-06-06 16:45:18 -07001444 genRegMemCheck(cUnit, kCondUge, rIndex, rArray, lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001445 }
buzbee408ad162012-06-06 16:45:18 -07001446 storeBaseIndexedDisp(cUnit, rArray, rIndex, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -07001447 dataOffset, rValue, INVALID_REG, kWord, INVALID_SREG);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001448#else
buzbee408ad162012-06-06 16:45:18 -07001449 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001450 int regLen = INVALID_REG;
1451 if (needsRangeCheck) {
1452 regLen = rARG1;
buzbeef1f86362012-07-10 15:18:31 -07001453 loadWordDisp(cUnit, rArray, lenOffset, regLen); // Get len
Bill Buzbeea114add2012-05-03 15:00:40 -07001454 }
1455 /* rPtr -> array data */
1456 int rPtr = oatAllocTemp(cUnit);
1457 opRegRegImm(cUnit, kOpAdd, rPtr, rArray, dataOffset);
1458 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001459 genRegRegCheck(cUnit, kCondCs, rIndex, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001460 }
1461 storeBaseIndexed(cUnit, rPtr, rIndex, rValue, scale, kWord);
1462 oatFreeTemp(cUnit, rPtr);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001463#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001464 oatFreeTemp(cUnit, rIndex);
1465 markGCCard(cUnit, rValue, rArray);
buzbee31a4a6f2012-02-28 15:36:15 -08001466}
1467
1468/*
1469 * Generate array load
1470 */
buzbee408ad162012-06-06 16:45:18 -07001471void genArrayGet(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001472 RegLocation rlArray, RegLocation rlIndex,
1473 RegLocation rlDest, int scale)
1474{
Bill Buzbeea114add2012-05-03 15:00:40 -07001475 RegisterClass regClass = oatRegClassBySize(size);
1476 int lenOffset = Array::LengthOffset().Int32Value();
1477 int dataOffset;
1478 RegLocation rlResult;
1479 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1480 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001481
Bill Buzbeea114add2012-05-03 15:00:40 -07001482 if (size == kLong || size == kDouble) {
1483 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1484 } else {
1485 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1486 }
buzbee31a4a6f2012-02-28 15:36:15 -08001487
Bill Buzbeea114add2012-05-03 15:00:40 -07001488 /* null object? */
buzbee408ad162012-06-06 16:45:18 -07001489 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001490
Ian Rogersb5d09b22012-03-06 22:14:17 -08001491#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07001492 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001493 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1494 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
buzbee408ad162012-06-06 16:45:18 -07001495 lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001496 }
1497 if ((size == kLong) || (size == kDouble)) {
jeffhao3f9ace82012-05-25 11:25:36 -07001498 int regAddr = oatAllocTemp(cUnit);
1499 newLIR5(cUnit, kX86Lea32RA, regAddr, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset);
1500 oatFreeTemp(cUnit, rlArray.lowReg);
1501 oatFreeTemp(cUnit, rlIndex.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001502 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001503 loadBaseIndexedDisp(cUnit, regAddr, INVALID_REG, 0, 0, rlResult.lowReg,
jeffhao21e12712012-05-25 19:06:18 -07001504 rlResult.highReg, size, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001505 storeValueWide(cUnit, rlDest, rlResult);
1506 } else {
1507 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001508
buzbee408ad162012-06-06 16:45:18 -07001509 loadBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -07001510 dataOffset, rlResult.lowReg, INVALID_REG, size,
1511 INVALID_SREG);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001512
Bill Buzbeea114add2012-05-03 15:00:40 -07001513 storeValue(cUnit, rlDest, rlResult);
1514 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001515#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001516 int regPtr = oatAllocTemp(cUnit);
buzbee408ad162012-06-06 16:45:18 -07001517 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001518 int regLen = INVALID_REG;
1519 if (needsRangeCheck) {
1520 regLen = oatAllocTemp(cUnit);
1521 /* Get len */
1522 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1523 }
1524 /* regPtr -> array data */
1525 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1526 oatFreeTemp(cUnit, rlArray.lowReg);
1527 if ((size == kLong) || (size == kDouble)) {
1528 if (scale) {
1529 int rNewIndex = oatAllocTemp(cUnit);
1530 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1531 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1532 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001533 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001534 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001535 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001536 oatFreeTemp(cUnit, rlIndex.lowReg);
1537 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1538
1539 if (needsRangeCheck) {
1540 // TODO: change kCondCS to a more meaningful name, is the sense of
1541 // carry-set/clear flipped?
buzbee408ad162012-06-06 16:45:18 -07001542 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001543 oatFreeTemp(cUnit, regLen);
1544 }
1545 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1546
1547 oatFreeTemp(cUnit, regPtr);
1548 storeValueWide(cUnit, rlDest, rlResult);
1549 } else {
1550 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1551
1552 if (needsRangeCheck) {
1553 // TODO: change kCondCS to a more meaningful name, is the sense of
1554 // carry-set/clear flipped?
buzbee408ad162012-06-06 16:45:18 -07001555 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001556 oatFreeTemp(cUnit, regLen);
1557 }
1558 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1559 scale, size);
1560
1561 oatFreeTemp(cUnit, regPtr);
1562 storeValue(cUnit, rlDest, rlResult);
1563 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001564#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001565}
1566
1567/*
1568 * Generate array store
1569 *
1570 */
buzbee408ad162012-06-06 16:45:18 -07001571void genArrayPut(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001572 RegLocation rlArray, RegLocation rlIndex,
1573 RegLocation rlSrc, int scale)
1574{
Bill Buzbeea114add2012-05-03 15:00:40 -07001575 RegisterClass regClass = oatRegClassBySize(size);
1576 int lenOffset = Array::LengthOffset().Int32Value();
1577 int dataOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001578
Bill Buzbeea114add2012-05-03 15:00:40 -07001579 if (size == kLong || size == kDouble) {
1580 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1581 } else {
1582 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1583 }
buzbee31a4a6f2012-02-28 15:36:15 -08001584
Bill Buzbeea114add2012-05-03 15:00:40 -07001585 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1586 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001587#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001588 int regPtr;
1589 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1590 oatClobber(cUnit, rlArray.lowReg);
1591 regPtr = rlArray.lowReg;
1592 } else {
1593 regPtr = oatAllocTemp(cUnit);
1594 opRegCopy(cUnit, regPtr, rlArray.lowReg);
1595 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001596#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001597
Bill Buzbeea114add2012-05-03 15:00:40 -07001598 /* null object? */
buzbee408ad162012-06-06 16:45:18 -07001599 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001600
Ian Rogersb41b33b2012-03-20 14:22:54 -07001601#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07001602 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001603 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1604 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
buzbee408ad162012-06-06 16:45:18 -07001605 lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001606 }
1607 if ((size == kLong) || (size == kDouble)) {
1608 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1609 } else {
1610 rlSrc = loadValue(cUnit, rlSrc, regClass);
1611 }
jeffhao703f2cd2012-07-13 17:25:52 -07001612 // If the src reg can't be byte accessed, move it to a temp first.
1613 if ((size == kSignedByte || size == kUnsignedByte) && rlSrc.lowReg >= 4) {
1614 int temp = oatAllocTemp(cUnit);
1615 opRegCopy(cUnit, temp, rlSrc.lowReg);
1616 storeBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
1617 dataOffset, temp, INVALID_REG, size,
1618 INVALID_SREG);
1619 } else {
1620 storeBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
1621 dataOffset, rlSrc.lowReg, rlSrc.highReg, size,
1622 INVALID_SREG);
1623 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001624#else
buzbee408ad162012-06-06 16:45:18 -07001625 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001626 int regLen = INVALID_REG;
1627 if (needsRangeCheck) {
1628 regLen = oatAllocTemp(cUnit);
1629 //NOTE: max live temps(4) here.
1630 /* Get len */
1631 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1632 }
1633 /* regPtr -> array data */
1634 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1635 /* at this point, regPtr points to array, 2 live temps */
1636 if ((size == kLong) || (size == kDouble)) {
1637 //TUNING: specific wide routine that can handle fp regs
1638 if (scale) {
1639 int rNewIndex = oatAllocTemp(cUnit);
1640 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1641 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1642 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001643 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001644 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001645 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001646 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1647
1648 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001649 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001650 oatFreeTemp(cUnit, regLen);
1651 }
1652
jeffhao41005dd2012-05-09 17:58:52 -07001653 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001654
1655 oatFreeTemp(cUnit, regPtr);
1656 } else {
1657 rlSrc = loadValue(cUnit, rlSrc, regClass);
1658 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001659 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001660 oatFreeTemp(cUnit, regLen);
1661 }
1662 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1663 scale, size);
1664 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001665#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001666}
1667
buzbee408ad162012-06-06 16:45:18 -07001668void genLong3Addr(CompilationUnit* cUnit, OpKind firstOp,
buzbee31a4a6f2012-02-28 15:36:15 -08001669 OpKind secondOp, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001670 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001671{
Bill Buzbeea114add2012-05-03 15:00:40 -07001672 RegLocation rlResult;
buzbee31a4a6f2012-02-28 15:36:15 -08001673#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001674 /*
1675 * NOTE: This is the one place in the code in which we might have
1676 * as many as six live temporary registers. There are 5 in the normal
1677 * set for Arm. Until we have spill capabilities, temporarily add
1678 * lr to the temp set. It is safe to do this locally, but note that
1679 * lr is used explicitly elsewhere in the code generator and cannot
1680 * normally be used as a general temp register.
1681 */
1682 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1683 oatFreeTemp(cUnit, rLR); // and make it available
buzbee31a4a6f2012-02-28 15:36:15 -08001684#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001685 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1686 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1687 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1688 // The longs may overlap - use intermediate temp if so
1689 if (rlResult.lowReg == rlSrc1.highReg) {
1690 int tReg = oatAllocTemp(cUnit);
1691 opRegCopy(cUnit, tReg, rlSrc1.highReg);
1692 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1693 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg, rlSrc2.highReg);
1694 oatFreeTemp(cUnit, tReg);
1695 } else {
1696 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1697 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1698 rlSrc2.highReg);
1699 }
1700 /*
1701 * NOTE: If rlDest refers to a frame variable in a large frame, the
1702 * following storeValueWide might need to allocate a temp register.
1703 * To further work around the lack of a spill capability, explicitly
1704 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1705 * Remove when spill is functional.
1706 */
1707 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1708 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1709 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001710#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001711 oatClobber(cUnit, rLR);
1712 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee31a4a6f2012-02-28 15:36:15 -08001713#endif
1714}
1715
1716
buzbee408ad162012-06-06 16:45:18 -07001717bool genShiftOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001718 RegLocation rlSrc1, RegLocation rlShift)
1719{
Bill Buzbeea114add2012-05-03 15:00:40 -07001720 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001721
buzbee408ad162012-06-06 16:45:18 -07001722 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001723 case Instruction::SHL_LONG:
1724 case Instruction::SHL_LONG_2ADDR:
1725 funcOffset = ENTRYPOINT_OFFSET(pShlLong);
1726 break;
1727 case Instruction::SHR_LONG:
1728 case Instruction::SHR_LONG_2ADDR:
1729 funcOffset = ENTRYPOINT_OFFSET(pShrLong);
1730 break;
1731 case Instruction::USHR_LONG:
1732 case Instruction::USHR_LONG_2ADDR:
1733 funcOffset = ENTRYPOINT_OFFSET(pUshrLong);
1734 break;
1735 default:
1736 LOG(FATAL) << "Unexpected case";
1737 return true;
1738 }
1739 oatFlushAllRegs(cUnit); /* Send everything to home location */
1740 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift);
1741 RegLocation rlResult = oatGetReturnWide(cUnit, false);
1742 storeValueWide(cUnit, rlDest, rlResult);
1743 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001744}
1745
1746
buzbee408ad162012-06-06 16:45:18 -07001747bool genArithOpInt(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001748 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001749{
Bill Buzbeea114add2012-05-03 15:00:40 -07001750 OpKind op = kOpBkpt;
1751 bool callOut = false;
1752 bool checkZero = false;
1753 bool unary = false;
1754 RegLocation rlResult;
1755 bool shiftOp = false;
1756 int funcOffset;
1757 int retReg = rRET0;
buzbee408ad162012-06-06 16:45:18 -07001758 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001759 case Instruction::NEG_INT:
1760 op = kOpNeg;
1761 unary = true;
1762 break;
1763 case Instruction::NOT_INT:
1764 op = kOpMvn;
1765 unary = true;
1766 break;
1767 case Instruction::ADD_INT:
1768 case Instruction::ADD_INT_2ADDR:
1769 op = kOpAdd;
1770 break;
1771 case Instruction::SUB_INT:
1772 case Instruction::SUB_INT_2ADDR:
1773 op = kOpSub;
1774 break;
1775 case Instruction::MUL_INT:
1776 case Instruction::MUL_INT_2ADDR:
1777 op = kOpMul;
1778 break;
1779 case Instruction::DIV_INT:
1780 case Instruction::DIV_INT_2ADDR:
1781 checkZero = true;
1782 op = kOpDiv;
1783 callOut = true;
1784 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
1785 retReg = rRET0;
1786 break;
1787 /* NOTE: returns in rARG1 */
1788 case Instruction::REM_INT:
1789 case Instruction::REM_INT_2ADDR:
1790 checkZero = true;
1791 op = kOpRem;
1792 callOut = true;
1793 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
1794 retReg = rRET1;
1795 break;
1796 case Instruction::AND_INT:
1797 case Instruction::AND_INT_2ADDR:
1798 op = kOpAnd;
1799 break;
1800 case Instruction::OR_INT:
1801 case Instruction::OR_INT_2ADDR:
1802 op = kOpOr;
1803 break;
1804 case Instruction::XOR_INT:
1805 case Instruction::XOR_INT_2ADDR:
1806 op = kOpXor;
1807 break;
1808 case Instruction::SHL_INT:
1809 case Instruction::SHL_INT_2ADDR:
1810 shiftOp = true;
1811 op = kOpLsl;
1812 break;
1813 case Instruction::SHR_INT:
1814 case Instruction::SHR_INT_2ADDR:
1815 shiftOp = true;
1816 op = kOpAsr;
1817 break;
1818 case Instruction::USHR_INT:
1819 case Instruction::USHR_INT_2ADDR:
1820 shiftOp = true;
1821 op = kOpLsr;
1822 break;
1823 default:
1824 LOG(FATAL) << "Invalid word arith op: " <<
buzbee408ad162012-06-06 16:45:18 -07001825 (int)opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001826 }
1827 if (!callOut) {
1828 if (unary) {
1829 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1830 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1831 opRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001832 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001833 if (shiftOp) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001834#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001835 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1836 int tReg = oatAllocTemp(cUnit);
1837 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001838#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001839 // X86 doesn't require masking and must use ECX
1840 loadValueDirectFixed(cUnit, rlSrc2, rCX);
1841 int tReg = rCX;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001842#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001843 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1844 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1845 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, tReg);
1846 oatFreeTemp(cUnit, tReg);
1847 } else {
1848 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1849 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1850 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1851 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1852 }
buzbee31a4a6f2012-02-28 15:36:15 -08001853 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001854 storeValue(cUnit, rlDest, rlResult);
1855 } else {
1856 RegLocation rlResult;
1857 oatFlushAllRegs(cUnit); /* Send everything to home location */
1858 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
1859#if !defined(TARGET_X86)
1860 int rTgt = loadHelper(cUnit, funcOffset);
1861#endif
1862 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1863 if (checkZero) {
buzbee408ad162012-06-06 16:45:18 -07001864 genImmedCheck(cUnit, kCondEq, rARG1, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07001865 }
1866#if !defined(TARGET_X86)
1867 opReg(cUnit, kOpBlx, rTgt);
1868 oatFreeTemp(cUnit, rTgt);
1869#else
1870 opThreadMem(cUnit, kOpBlx, funcOffset);
1871#endif
1872 if (retReg == rRET0)
1873 rlResult = oatGetReturn(cUnit, false);
1874 else
1875 rlResult = oatGetReturnAlt(cUnit);
1876 storeValue(cUnit, rlDest, rlResult);
1877 }
1878 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001879}
1880
1881/*
1882 * The following are the first-level codegen routines that analyze the format
1883 * of each bytecode then either dispatch special purpose codegen routines
1884 * or produce corresponding Thumb instructions directly.
1885 */
1886
1887bool isPowerOfTwo(int x)
1888{
Bill Buzbeea114add2012-05-03 15:00:40 -07001889 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001890}
1891
1892// Returns true if no more than two bits are set in 'x'.
1893bool isPopCountLE2(unsigned int x)
1894{
Bill Buzbeea114add2012-05-03 15:00:40 -07001895 x &= x - 1;
1896 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001897}
1898
1899// Returns the index of the lowest set bit in 'x'.
1900int lowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001901 int bit_posn = 0;
1902 while ((x & 0xf) == 0) {
1903 bit_posn += 4;
1904 x >>= 4;
1905 }
1906 while ((x & 1) == 0) {
1907 bit_posn++;
1908 x >>= 1;
1909 }
1910 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001911}
1912
1913// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1914// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001915bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
Bill Buzbeea114add2012-05-03 15:00:40 -07001916 RegLocation rlSrc, RegLocation rlDest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001917{
buzbeef3aac972012-04-11 16:33:36 -07001918#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001919 // No divide instruction for Arm, so check for more special cases
1920 if (lit < 2) {
1921 return false;
1922 }
1923 if (!isPowerOfTwo(lit)) {
1924 return smallLiteralDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit);
1925 }
buzbeef3aac972012-04-11 16:33:36 -07001926#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001927 if (lit < 2 || !isPowerOfTwo(lit)) {
1928 return false;
1929 }
buzbeef3aac972012-04-11 16:33:36 -07001930#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001931 int k = lowestSetBit(lit);
1932 if (k >= 30) {
1933 // Avoid special cases.
1934 return false;
1935 }
1936 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1937 dalvikOpcode == Instruction::DIV_INT_LIT16);
1938 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1939 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1940 if (div) {
1941 int tReg = oatAllocTemp(cUnit);
1942 if (lit == 2) {
1943 // Division by 2 is by far the most common division by constant.
1944 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1945 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1946 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001947 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001948 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1949 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1950 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1951 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001952 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001953 } else {
1954 int tReg1 = oatAllocTemp(cUnit);
1955 int tReg2 = oatAllocTemp(cUnit);
1956 if (lit == 2) {
1957 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1958 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1959 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit -1);
1960 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1961 } else {
1962 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1963 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1964 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1965 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit - 1);
1966 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1967 }
1968 }
1969 storeValue(cUnit, rlDest, rlResult);
1970 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001971}
1972
1973void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1974 RegLocation rlResult, int lit,
1975 int firstBit, int secondBit)
1976{
buzbee0398c422012-03-02 15:22:47 -08001977#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001978 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1979 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001980#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001981 int tReg = oatAllocTemp(cUnit);
1982 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1983 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1984 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001985#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001986 if (firstBit != 0) {
1987 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1988 }
buzbee31a4a6f2012-02-28 15:36:15 -08001989}
1990
1991// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1992// and store the result in 'rlDest'.
1993bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1994 RegLocation rlDest, int lit)
1995{
Bill Buzbeea114add2012-05-03 15:00:40 -07001996 // Can we simplify this multiplication?
1997 bool powerOfTwo = false;
1998 bool popCountLE2 = false;
1999 bool powerOfTwoMinusOne = false;
2000 if (lit < 2) {
2001 // Avoid special cases.
2002 return false;
2003 } else if (isPowerOfTwo(lit)) {
2004 powerOfTwo = true;
2005 } else if (isPopCountLE2(lit)) {
2006 popCountLE2 = true;
2007 } else if (isPowerOfTwo(lit + 1)) {
2008 powerOfTwoMinusOne = true;
2009 } else {
2010 return false;
2011 }
2012 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2013 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2014 if (powerOfTwo) {
2015 // Shift.
2016 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
2017 lowestSetBit(lit));
2018 } else if (popCountLE2) {
2019 // Shift and add and shift.
2020 int firstBit = lowestSetBit(lit);
2021 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
2022 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
2023 firstBit, secondBit);
2024 } else {
2025 // Reverse subtract: (src << (shift + 1)) - src.
2026 DCHECK(powerOfTwoMinusOne);
2027 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
2028 int tReg = oatAllocTemp(cUnit);
2029 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
2030 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2031 }
2032 storeValue(cUnit, rlDest, rlResult);
2033 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08002034}
2035
buzbee408ad162012-06-06 16:45:18 -07002036bool genArithOpIntLit(CompilationUnit* cUnit, Instruction::Code opcode,
2037 RegLocation rlDest, RegLocation rlSrc, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08002038{
Bill Buzbeea114add2012-05-03 15:00:40 -07002039 RegLocation rlResult;
2040 OpKind op = (OpKind)0; /* Make gcc happy */
2041 int shiftOp = false;
2042 bool isDiv = false;
2043 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002044
buzbee408ad162012-06-06 16:45:18 -07002045 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002046 case Instruction::RSUB_INT_LIT8:
2047 case Instruction::RSUB_INT: {
2048 int tReg;
2049 //TUNING: add support for use of Arm rsub op
2050 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2051 tReg = oatAllocTemp(cUnit);
2052 loadConstant(cUnit, tReg, lit);
2053 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2054 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2055 storeValue(cUnit, rlDest, rlResult);
2056 return false;
2057 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002058 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002059
2060 case Instruction::ADD_INT_LIT8:
2061 case Instruction::ADD_INT_LIT16:
2062 op = kOpAdd;
2063 break;
2064 case Instruction::MUL_INT_LIT8:
2065 case Instruction::MUL_INT_LIT16: {
2066 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2067 return false;
2068 }
2069 op = kOpMul;
2070 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002071 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002072 case Instruction::AND_INT_LIT8:
2073 case Instruction::AND_INT_LIT16:
2074 op = kOpAnd;
2075 break;
2076 case Instruction::OR_INT_LIT8:
2077 case Instruction::OR_INT_LIT16:
2078 op = kOpOr;
2079 break;
2080 case Instruction::XOR_INT_LIT8:
2081 case Instruction::XOR_INT_LIT16:
2082 op = kOpXor;
2083 break;
2084 case Instruction::SHL_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07002085 case Instruction::SHL_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07002086 lit &= 31;
2087 shiftOp = true;
2088 op = kOpLsl;
2089 break;
2090 case Instruction::SHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07002091 case Instruction::SHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07002092 lit &= 31;
2093 shiftOp = true;
2094 op = kOpAsr;
2095 break;
2096 case Instruction::USHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07002097 case Instruction::USHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07002098 lit &= 31;
2099 shiftOp = true;
2100 op = kOpLsr;
2101 break;
2102
2103 case Instruction::DIV_INT_LIT8:
2104 case Instruction::DIV_INT_LIT16:
2105 case Instruction::REM_INT_LIT8:
2106 case Instruction::REM_INT_LIT16:
2107 if (lit == 0) {
buzbee408ad162012-06-06 16:45:18 -07002108 genImmedCheck(cUnit, kCondAl, 0, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002109 return false;
2110 }
buzbee408ad162012-06-06 16:45:18 -07002111 if (handleEasyDivide(cUnit, opcode, rlSrc, rlDest, lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002112 return false;
2113 }
2114 oatFlushAllRegs(cUnit); /* Everything to home location */
2115 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2116 oatClobber(cUnit, rARG0);
2117 funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee408ad162012-06-06 16:45:18 -07002118 if ((opcode == Instruction::DIV_INT_LIT8) ||
2119 (opcode == Instruction::DIV_INT_LIT16)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002120 isDiv = true;
2121 } else {
2122 isDiv = false;
2123 }
2124 callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit);
2125 if (isDiv)
2126 rlResult = oatGetReturn(cUnit, false);
2127 else
2128 rlResult = oatGetReturnAlt(cUnit);
2129 storeValue(cUnit, rlDest, rlResult);
2130 return false;
2131 break;
2132 default:
2133 return true;
2134 }
2135 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2136 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2137 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2138 if (shiftOp && (lit == 0)) {
2139 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2140 } else {
2141 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2142 }
2143 storeValue(cUnit, rlDest, rlResult);
2144 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002145}
2146
buzbee408ad162012-06-06 16:45:18 -07002147bool genArithOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07002148 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08002149{
Bill Buzbeea114add2012-05-03 15:00:40 -07002150 RegLocation rlResult;
2151 OpKind firstOp = kOpBkpt;
2152 OpKind secondOp = kOpBkpt;
2153 bool callOut = false;
2154 bool checkZero = false;
2155 int funcOffset;
2156 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08002157
buzbee408ad162012-06-06 16:45:18 -07002158 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002159 case Instruction::NOT_LONG:
2160 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2161 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2162 // Check for destructive overlap
2163 if (rlResult.lowReg == rlSrc2.highReg) {
2164 int tReg = oatAllocTemp(cUnit);
2165 opRegCopy(cUnit, tReg, rlSrc2.highReg);
2166 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2167 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2168 oatFreeTemp(cUnit, tReg);
2169 } else {
2170 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2171 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2172 }
2173 storeValueWide(cUnit, rlDest, rlResult);
2174 return false;
2175 break;
2176 case Instruction::ADD_LONG:
2177 case Instruction::ADD_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002178#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002179 return genAddLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeec5159d52012-03-03 11:48:39 -08002180#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002181 firstOp = kOpAdd;
2182 secondOp = kOpAdc;
2183 break;
buzbeec5159d52012-03-03 11:48:39 -08002184#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002185 case Instruction::SUB_LONG:
2186 case Instruction::SUB_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002187#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002188 return genSubLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002189#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002190 firstOp = kOpSub;
2191 secondOp = kOpSbc;
2192 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002193#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002194 case Instruction::MUL_LONG:
2195 case Instruction::MUL_LONG_2ADDR:
2196 callOut = true;
2197 retReg = rRET0;
2198 funcOffset = ENTRYPOINT_OFFSET(pLmul);
2199 break;
2200 case Instruction::DIV_LONG:
2201 case Instruction::DIV_LONG_2ADDR:
2202 callOut = true;
2203 checkZero = true;
2204 retReg = rRET0;
jeffhao644d5312012-05-03 19:04:49 -07002205 funcOffset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002206 break;
2207 case Instruction::REM_LONG:
2208 case Instruction::REM_LONG_2ADDR:
2209 callOut = true;
2210 checkZero = true;
jeffhao644d5312012-05-03 19:04:49 -07002211 funcOffset = ENTRYPOINT_OFFSET(pLdivmod);
Ian Rogers55bd45f2012-04-04 17:31:20 -07002212#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002213 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2214 retReg = rARG2;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002215#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002216 retReg = rRET0;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002217#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002218 break;
2219 case Instruction::AND_LONG_2ADDR:
2220 case Instruction::AND_LONG:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002221#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002222 return genAndLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002223#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002224 firstOp = kOpAnd;
2225 secondOp = kOpAnd;
2226 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002227#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002228 case Instruction::OR_LONG:
2229 case Instruction::OR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002230#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002231 return genOrLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002232#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002233 firstOp = kOpOr;
2234 secondOp = kOpOr;
2235 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002236#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002237 case Instruction::XOR_LONG:
2238 case Instruction::XOR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002239#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002240 return genXorLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002241#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002242 firstOp = kOpXor;
2243 secondOp = kOpXor;
2244 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002245#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002246 case Instruction::NEG_LONG: {
buzbee408ad162012-06-06 16:45:18 -07002247 return genNegLong(cUnit, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002248 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002249 default:
2250 LOG(FATAL) << "Invalid long arith op";
2251 }
2252 if (!callOut) {
buzbee408ad162012-06-06 16:45:18 -07002253 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -07002254 } else {
2255 oatFlushAllRegs(cUnit); /* Send everything to home location */
2256 if (checkZero) {
2257 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2258#if !defined(TARGET_X86)
2259 int rTgt = loadHelper(cUnit, funcOffset);
2260#endif
2261 int tReg = oatAllocTemp(cUnit);
2262#if defined(TARGET_ARM)
2263 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2264 oatFreeTemp(cUnit, tReg);
buzbee408ad162012-06-06 16:45:18 -07002265 genCheck(cUnit, kCondEq, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002266#else
2267 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
2268#endif
buzbee408ad162012-06-06 16:45:18 -07002269 genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002270 oatFreeTemp(cUnit, tReg);
2271 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2272#if !defined(TARGET_X86)
2273 opReg(cUnit, kOpBlx, rTgt);
2274 oatFreeTemp(cUnit, rTgt);
2275#else
2276 opThreadMem(cUnit, kOpBlx, funcOffset);
2277#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002278 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07002279 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset,
2280 rlSrc1, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002281 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002282 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2283 if (retReg == rRET0)
2284 rlResult = oatGetReturnWide(cUnit, false);
2285 else
2286 rlResult = oatGetReturnWideAlt(cUnit);
2287 storeValueWide(cUnit, rlDest, rlResult);
2288 }
2289 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002290}
2291
buzbee408ad162012-06-06 16:45:18 -07002292bool genConversionCall(CompilationUnit* cUnit, int funcOffset,
2293 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002294{
Bill Buzbeea114add2012-05-03 15:00:40 -07002295 /*
2296 * Don't optimize the register usage since it calls out to support
2297 * functions
2298 */
Bill Buzbeea114add2012-05-03 15:00:40 -07002299 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee408ad162012-06-06 16:45:18 -07002300 if (rlSrc.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002301 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
buzbee408ad162012-06-06 16:45:18 -07002302 } else {
2303 loadValueDirectFixed(cUnit, rlSrc, rARG0);
Bill Buzbeea114add2012-05-03 15:00:40 -07002304 }
2305 callRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002306 if (rlDest.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002307 RegLocation rlResult;
Bill Buzbeea114add2012-05-03 15:00:40 -07002308 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
2309 storeValueWide(cUnit, rlDest, rlResult);
buzbee408ad162012-06-06 16:45:18 -07002310 } else {
2311 RegLocation rlResult;
2312 rlResult = oatGetReturn(cUnit, rlDest.fp);
2313 storeValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002314 }
2315 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002316}
2317
2318void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002319bool genArithOpFloatPortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002320 RegLocation rlDest, RegLocation rlSrc1,
2321 RegLocation rlSrc2)
2322{
Bill Buzbeea114add2012-05-03 15:00:40 -07002323 RegLocation rlResult;
2324 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002325
buzbee408ad162012-06-06 16:45:18 -07002326 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002327 case Instruction::ADD_FLOAT_2ADDR:
2328 case Instruction::ADD_FLOAT:
2329 funcOffset = ENTRYPOINT_OFFSET(pFadd);
2330 break;
2331 case Instruction::SUB_FLOAT_2ADDR:
2332 case Instruction::SUB_FLOAT:
2333 funcOffset = ENTRYPOINT_OFFSET(pFsub);
2334 break;
2335 case Instruction::DIV_FLOAT_2ADDR:
2336 case Instruction::DIV_FLOAT:
2337 funcOffset = ENTRYPOINT_OFFSET(pFdiv);
2338 break;
2339 case Instruction::MUL_FLOAT_2ADDR:
2340 case Instruction::MUL_FLOAT:
2341 funcOffset = ENTRYPOINT_OFFSET(pFmul);
2342 break;
2343 case Instruction::REM_FLOAT_2ADDR:
2344 case Instruction::REM_FLOAT:
2345 funcOffset = ENTRYPOINT_OFFSET(pFmodf);
2346 break;
2347 case Instruction::NEG_FLOAT: {
2348 genNegFloat(cUnit, rlDest, rlSrc1);
2349 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002350 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002351 default:
2352 return true;
2353 }
2354 oatFlushAllRegs(cUnit); /* Send everything to home location */
2355 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
2356 rlResult = oatGetReturn(cUnit, true);
2357 storeValue(cUnit, rlDest, rlResult);
2358 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002359}
2360
2361void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002362bool genArithOpDoublePortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002363 RegLocation rlDest, RegLocation rlSrc1,
2364 RegLocation rlSrc2)
2365{
Bill Buzbeea114add2012-05-03 15:00:40 -07002366 RegLocation rlResult;
2367 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002368
buzbee408ad162012-06-06 16:45:18 -07002369 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002370 case Instruction::ADD_DOUBLE_2ADDR:
2371 case Instruction::ADD_DOUBLE:
2372 funcOffset = ENTRYPOINT_OFFSET(pDadd);
2373 break;
2374 case Instruction::SUB_DOUBLE_2ADDR:
2375 case Instruction::SUB_DOUBLE:
2376 funcOffset = ENTRYPOINT_OFFSET(pDsub);
2377 break;
2378 case Instruction::DIV_DOUBLE_2ADDR:
2379 case Instruction::DIV_DOUBLE:
2380 funcOffset = ENTRYPOINT_OFFSET(pDdiv);
2381 break;
2382 case Instruction::MUL_DOUBLE_2ADDR:
2383 case Instruction::MUL_DOUBLE:
2384 funcOffset = ENTRYPOINT_OFFSET(pDmul);
2385 break;
2386 case Instruction::REM_DOUBLE_2ADDR:
2387 case Instruction::REM_DOUBLE:
2388 funcOffset = ENTRYPOINT_OFFSET(pFmod);
2389 break;
2390 case Instruction::NEG_DOUBLE: {
2391 genNegDouble(cUnit, rlDest, rlSrc1);
2392 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002393 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002394 default:
2395 return true;
2396 }
2397 oatFlushAllRegs(cUnit); /* Send everything to home location */
2398 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2);
2399 rlResult = oatGetReturnWide(cUnit, true);
2400 storeValueWide(cUnit, rlDest, rlResult);
2401 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002402}
2403
buzbee408ad162012-06-06 16:45:18 -07002404bool genConversionPortable(CompilationUnit* cUnit, Instruction::Code opcode,
2405 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002406{
buzbee31a4a6f2012-02-28 15:36:15 -08002407
Bill Buzbeea114add2012-05-03 15:00:40 -07002408 switch (opcode) {
2409 case Instruction::INT_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002410 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2f),
2411 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002412 case Instruction::FLOAT_TO_INT:
buzbee408ad162012-06-06 16:45:18 -07002413 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2iz),
2414 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002415 case Instruction::DOUBLE_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002416 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2f),
2417 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002418 case Instruction::FLOAT_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002419 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2d),
2420 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002421 case Instruction::INT_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002422 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2d),
2423 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002424 case Instruction::DOUBLE_TO_INT:
buzbee408ad162012-06-06 16:45:18 -07002425 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2iz),
2426 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002427 case Instruction::FLOAT_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -07002428 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2l),
2429 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002430 case Instruction::LONG_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002431 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2f),
2432 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002433 case Instruction::DOUBLE_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -07002434 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2l),
2435 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002436 case Instruction::LONG_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002437 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2d),
2438 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002439 default:
2440 return true;
2441 }
2442 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002443}
2444
2445/*
2446 * Generate callout to updateDebugger. Note that we're overloading
2447 * the use of rSUSPEND here. When the debugger is active, this
2448 * register holds the address of the update function. So, if it's
2449 * non-null, we call out to it.
2450 *
2451 * Note also that rRET0 and rRET1 must be preserved across this
2452 * code. This must be handled by the stub.
2453 */
2454void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2455{
Bill Buzbeea114add2012-05-03 15:00:40 -07002456 // Following DCHECK verifies that dPC is in range of single load immediate
2457 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2458 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2459 oatClobberCalleeSave(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002460#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002461 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
2462 opIT(cUnit, kArmCondNe, "T");
2463 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2464 opReg(cUnit, kOpBlx, rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002465#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002466 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002467#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002468 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
2469 loadConstant(cUnit, rARG2, offset);
2470 opReg(cUnit, kOpBlx, rSUSPEND);
2471 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
2472 branch->target = (LIR*)target;
buzbee31a4a6f2012-02-28 15:36:15 -08002473#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002474 oatFreeTemp(cUnit, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08002475}
2476
2477/* Check if we need to check for pending suspend request */
buzbee408ad162012-06-06 16:45:18 -07002478void genSuspendTest(CompilationUnit* cUnit, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -08002479{
buzbee408ad162012-06-06 16:45:18 -07002480 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002481 return;
2482 }
2483 oatFlushAllRegs(cUnit);
2484 if (cUnit->genDebugger) {
2485 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002486#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002487 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002488#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002489 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
2490 opReg(cUnit, kOpBlx, rTgt);
2491 // Refresh rSUSPEND
2492 loadWordDisp(cUnit, rSELF,
2493 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode),
2494 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002495#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002496 } else {
2497 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002498#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002499 // In non-debug case, only check periodically
2500 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2501 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002502#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002503 newLIR2(cUnit, kX86Cmp32TI8, Thread::SuspendCountOffset().Int32Value(), 0);
2504 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002505#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002506 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2507 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002508#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002509 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2510 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
buzbee408ad162012-06-06 16:45:18 -07002511 kPseudoSuspendTarget, (intptr_t)retLab, cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -07002512 branch->target = (LIR*)target;
2513 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
2514 }
buzbee31a4a6f2012-02-28 15:36:15 -08002515}
2516
buzbeefead2932012-03-30 14:02:01 -07002517/* Check if we need to check for pending suspend request */
buzbee408ad162012-06-06 16:45:18 -07002518void genSuspendTestAndBranch(CompilationUnit* cUnit, int optFlags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07002519{
buzbee408ad162012-06-06 16:45:18 -07002520 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002521 opUnconditionalBranch(cUnit, target);
2522 return;
2523 }
2524 if (cUnit->genDebugger) {
buzbee408ad162012-06-06 16:45:18 -07002525 genSuspendTest(cUnit, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07002526 opUnconditionalBranch(cUnit, target);
2527 } else {
buzbeefead2932012-03-30 14:02:01 -07002528#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002529 // In non-debug case, only check periodically
2530 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2531 opCondBranch(cUnit, kCondNe, target);
buzbeefead2932012-03-30 14:02:01 -07002532#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002533 newLIR2(cUnit, kX86Cmp32TI8, Thread::SuspendCountOffset().Int32Value(), 0);
2534 opCondBranch(cUnit, kCondEq, target);
buzbeefead2932012-03-30 14:02:01 -07002535#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002536 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2537 opCmpImmBranch(cUnit, kCondNe, rSUSPEND, 0, target);
buzbeefead2932012-03-30 14:02:01 -07002538#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002539 LIR* launchPad = rawLIR(cUnit, cUnit->currentDalvikOffset,
buzbee408ad162012-06-06 16:45:18 -07002540 kPseudoSuspendTarget, (intptr_t)target, cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -07002541 oatFlushAllRegs(cUnit);
2542 opUnconditionalBranch(cUnit, launchPad);
2543 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads,
2544 (intptr_t)launchPad);
2545 }
buzbeefead2932012-03-30 14:02:01 -07002546}
2547
buzbee31a4a6f2012-02-28 15:36:15 -08002548} // namespace art