blob: 730527115e9eccfb275d51fe371809ec9e1310ff [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
buzbee8320f382012-09-11 16:29:42 -070033void markSafepointPC(CompilationUnit* cUnit, LIR* inst)
34{
35 inst->defMask = ENCODE_ALL;
36 LIR* safepointPC = newLIR0(cUnit, kPseudoSafepointPC);
37 DCHECK_EQ(safepointPC->defMask, ENCODE_ALL);
38}
39
40void callRuntimeHelperImm(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -070041#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070042 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070043#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070044 loadConstant(cUnit, rARG0, arg0);
45 oatClobberCalleeSave(cUnit);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070046#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -070047 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070048 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -070049#else
buzbee8320f382012-09-11 16:29:42 -070050 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070051#endif
buzbee8320f382012-09-11 16:29:42 -070052 if (safepointPC) {
53 markSafepointPC(cUnit, callInst);
54 }
Ian Rogersab2b55d2012-03-18 00:06:11 -070055}
56
buzbee8320f382012-09-11 16:29:42 -070057void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) {
Ian Rogers7caad772012-03-30 01:07:54 -070058#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070059 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogers7caad772012-03-30 01:07:54 -070060#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070061 opRegCopy(cUnit, rARG0, arg0);
62 oatClobberCalleeSave(cUnit);
Ian Rogers7caad772012-03-30 01:07:54 -070063#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -070064 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070065 oatFreeTemp(cUnit, rTgt);
Ian Rogers7caad772012-03-30 01:07:54 -070066#else
buzbee8320f382012-09-11 16:29:42 -070067 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogers7caad772012-03-30 01:07:54 -070068#endif
buzbee8320f382012-09-11 16:29:42 -070069 if (safepointPC) {
70 markSafepointPC(cUnit, callInst);
71 }
Ian Rogers7caad772012-03-30 01:07:54 -070072}
73
buzbee8320f382012-09-11 16:29:42 -070074void callRuntimeHelperRegLocation(CompilationUnit* cUnit, int helperOffset, RegLocation arg0,
75 bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -070076#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -070077 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070078#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070079 if (arg0.wide == 0) {
80 loadValueDirectFixed(cUnit, arg0, rARG0);
81 } else {
82 loadValueDirectWideFixed(cUnit, arg0, rARG0, rARG1);
83 }
84 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -070085#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -070086 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070087 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -070088#else
buzbee8320f382012-09-11 16:29:42 -070089 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -070090#endif
buzbee8320f382012-09-11 16:29:42 -070091 if (safepointPC) {
92 markSafepointPC(cUnit, callInst);
93 }
Ian Rogersab2b55d2012-03-18 00:06:11 -070094}
95
buzbee8320f382012-09-11 16:29:42 -070096void callRuntimeHelperImmImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
97 bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -070098#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 loadConstant(cUnit, rARG0, arg0);
102 loadConstant(cUnit, rARG1, arg1);
103 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700104#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700105 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700106 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700107#else
buzbee8320f382012-09-11 16:29:42 -0700108 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700109#endif
buzbee8320f382012-09-11 16:29:42 -0700110 if (safepointPC) {
111 markSafepointPC(cUnit, callInst);
112 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700113}
114
buzbee8320f382012-09-11 16:29:42 -0700115void callRuntimeHelperImmRegLocation(CompilationUnit* cUnit, int helperOffset, int arg0,
116 RegLocation arg1, bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700117#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700118 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700119#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700120 if (arg1.wide == 0) {
121 loadValueDirectFixed(cUnit, arg1, rARG1);
122 } else {
123 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
124 }
125 loadConstant(cUnit, rARG0, arg0);
126 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700127#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700128 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700130#else
buzbee8320f382012-09-11 16:29:42 -0700131 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700132#endif
buzbee8320f382012-09-11 16:29:42 -0700133 if (safepointPC) {
134 markSafepointPC(cUnit, callInst);
135 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700136}
137
buzbee8320f382012-09-11 16:29:42 -0700138void callRuntimeHelperRegLocationImm(CompilationUnit* cUnit, int helperOffset, RegLocation arg0,
139 int arg1, bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700140#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700141 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700142#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700143 loadValueDirectFixed(cUnit, arg0, rARG0);
144 loadConstant(cUnit, rARG1, arg1);
145 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700146#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700147 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700148 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700149#else
buzbee8320f382012-09-11 16:29:42 -0700150 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700151#endif
buzbee8320f382012-09-11 16:29:42 -0700152 if (safepointPC) {
153 markSafepointPC(cUnit, callInst);
154 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700155}
156
buzbee8320f382012-09-11 16:29:42 -0700157void callRuntimeHelperImmReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
158 bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700159#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700160 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700161#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700162 opRegCopy(cUnit, rARG1, arg1);
163 loadConstant(cUnit, rARG0, arg0);
164 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700165#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700166 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700167 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700168#else
buzbee8320f382012-09-11 16:29:42 -0700169 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700170#endif
buzbee8320f382012-09-11 16:29:42 -0700171 if (safepointPC) {
172 markSafepointPC(cUnit, callInst);
173 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700174}
175
buzbee8320f382012-09-11 16:29:42 -0700176void callRuntimeHelperRegImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
177 bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700178#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700179 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700180#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700181 opRegCopy(cUnit, rARG0, arg0);
182 loadConstant(cUnit, rARG1, arg1);
183 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700184#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700185 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700186 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700187#else
buzbee8320f382012-09-11 16:29:42 -0700188 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700189#endif
buzbee8320f382012-09-11 16:29:42 -0700190 if (safepointPC) {
191 markSafepointPC(cUnit, callInst);
192 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700193}
194
buzbee8320f382012-09-11 16:29:42 -0700195void callRuntimeHelperImmMethod(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700196#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700197 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700198#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700199 loadCurrMethodDirect(cUnit, rARG1);
200 loadConstant(cUnit, rARG0, arg0);
201 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700202#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700203 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700204 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700205#else
buzbee8320f382012-09-11 16:29:42 -0700206 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700207#endif
buzbee8320f382012-09-11 16:29:42 -0700208 if (safepointPC) {
209 markSafepointPC(cUnit, callInst);
210 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700211}
212
buzbee8320f382012-09-11 16:29:42 -0700213void callRuntimeHelperRegLocationRegLocation(CompilationUnit* cUnit, int helperOffset,
214 RegLocation arg0, RegLocation arg1, bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700215#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700216 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700217#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700218 if (arg0.wide == 0) {
jeffhao30a33172012-10-22 18:16:22 -0700219 loadValueDirectFixed(cUnit, arg0, arg0.fp ? rFARG0 : rARG0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700220 if (arg1.wide == 0) {
jeffhao30a33172012-10-22 18:16:22 -0700221#if defined(TARGET_MIPS)
222 loadValueDirectFixed(cUnit, arg1, arg1.fp ? rFARG2 : rARG1);
223#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700224 loadValueDirectFixed(cUnit, arg1, rARG1);
jeffhao30a33172012-10-22 18:16:22 -0700225#endif
Ian Rogersab2b55d2012-03-18 00:06:11 -0700226 } else {
jeffhao30a33172012-10-22 18:16:22 -0700227#if defined(TARGET_MIPS)
228 loadValueDirectWideFixed(cUnit, arg1, arg1.fp ? rFARG2 : rARG1, arg1.fp ? rFARG3 : rARG2);
229#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700230 loadValueDirectWideFixed(cUnit, arg1, rARG1, rARG2);
jeffhao30a33172012-10-22 18:16:22 -0700231#endif
Ian Rogersab2b55d2012-03-18 00:06:11 -0700232 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700233 } else {
jeffhao30a33172012-10-22 18:16:22 -0700234 loadValueDirectWideFixed(cUnit, arg0, arg0.fp ? rFARG0 : rARG0, arg0.fp ? rFARG1 : rARG1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700235 if (arg1.wide == 0) {
jeffhao30a33172012-10-22 18:16:22 -0700236 loadValueDirectFixed(cUnit, arg1, arg1.fp ? rFARG2 : rARG2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700237 } else {
jeffhao30a33172012-10-22 18:16:22 -0700238 loadValueDirectWideFixed(cUnit, arg1, arg1.fp ? rFARG2 : rARG2, arg1.fp ? rFARG3 : rARG3);
Bill Buzbeea114add2012-05-03 15:00:40 -0700239 }
240 }
241 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700242#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700243 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700244 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700245#else
buzbee8320f382012-09-11 16:29:42 -0700246 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700247#endif
buzbee8320f382012-09-11 16:29:42 -0700248 if (safepointPC) {
249 markSafepointPC(cUnit, callInst);
250 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700251}
252
buzbee8320f382012-09-11 16:29:42 -0700253void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
254 bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700255#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700256 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700257#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
259 opRegCopy(cUnit, rARG0, arg0);
260 opRegCopy(cUnit, rARG1, arg1);
261 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700262#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700263 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700264 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700265#else
buzbee8320f382012-09-11 16:29:42 -0700266 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700267#endif
buzbee8320f382012-09-11 16:29:42 -0700268 if (safepointPC) {
269 markSafepointPC(cUnit, callInst);
270 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700271}
272
buzbee8320f382012-09-11 16:29:42 -0700273void callRuntimeHelperRegRegImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
274 int arg2, bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700275#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700276 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700277#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700278 DCHECK_NE((int)rARG0, arg1); // check copy into arg0 won't clobber arg1
279 opRegCopy(cUnit, rARG0, arg0);
280 opRegCopy(cUnit, rARG1, arg1);
281 loadConstant(cUnit, rARG2, arg2);
282 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700283#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700284 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700285 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700286#else
buzbee8320f382012-09-11 16:29:42 -0700287 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700288#endif
buzbee8320f382012-09-11 16:29:42 -0700289 if (safepointPC) {
290 markSafepointPC(cUnit, callInst);
291 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700292}
293
buzbee8320f382012-09-11 16:29:42 -0700294void callRuntimeHelperImmMethodRegLocation(CompilationUnit* cUnit, int helperOffset, int arg0,
295 RegLocation arg2, bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700296#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700297 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700298#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700299 loadValueDirectFixed(cUnit, arg2, rARG2);
300 loadCurrMethodDirect(cUnit, rARG1);
301 loadConstant(cUnit, rARG0, arg0);
302 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700303#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700304 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700305 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700306#else
buzbee8320f382012-09-11 16:29:42 -0700307 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700308#endif
buzbee8320f382012-09-11 16:29:42 -0700309 if (safepointPC) {
310 markSafepointPC(cUnit, callInst);
311 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700312}
313
buzbee8320f382012-09-11 16:29:42 -0700314void callRuntimeHelperImmMethodImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg2,
315 bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700316#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700317 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700318#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700319 loadCurrMethodDirect(cUnit, rARG1);
320 loadConstant(cUnit, rARG2, arg2);
321 loadConstant(cUnit, rARG0, arg0);
322 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700323#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700324 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700325 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700326#else
buzbee8320f382012-09-11 16:29:42 -0700327 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700328#endif
buzbee8320f382012-09-11 16:29:42 -0700329 if (safepointPC) {
330 markSafepointPC(cUnit, callInst);
331 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700332}
333
buzbee8320f382012-09-11 16:29:42 -0700334void callRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cUnit, int helperOffset,
335 int arg0, RegLocation arg1, RegLocation arg2,
336 bool safepointPC) {
Ian Rogersab2b55d2012-03-18 00:06:11 -0700337#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700338 int rTgt = loadHelper(cUnit, helperOffset);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700339#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700340 loadValueDirectFixed(cUnit, arg1, rARG1);
341 if (arg2.wide == 0) {
342 loadValueDirectFixed(cUnit, arg2, rARG2);
343 } else {
344 loadValueDirectWideFixed(cUnit, arg2, rARG2, rARG3);
345 }
346 loadConstant(cUnit, rARG0, arg0);
347 oatClobberCalleeSave(cUnit);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700348#if !defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700349 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700350 oatFreeTemp(cUnit, rTgt);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700351#else
buzbee8320f382012-09-11 16:29:42 -0700352 LIR* callInst = opThreadMem(cUnit, kOpBlx, helperOffset);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700353#endif
buzbee8320f382012-09-11 16:29:42 -0700354 if (safepointPC) {
355 markSafepointPC(cUnit, callInst);
356 }
buzbee31a4a6f2012-02-28 15:36:15 -0800357}
358
359/*
360 * Generate an kPseudoBarrier marker to indicate the boundary of special
361 * blocks.
362 */
363void genBarrier(CompilationUnit* cUnit)
364{
Bill Buzbeea114add2012-05-03 15:00:40 -0700365 LIR* barrier = newLIR0(cUnit, kPseudoBarrier);
366 /* Mark all resources as being clobbered */
367 barrier->defMask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800368}
369
buzbee31a4a6f2012-02-28 15:36:15 -0800370
371/* Generate unconditional branch instructions */
buzbee82488f52012-03-02 08:20:26 -0800372LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -0800373{
Bill Buzbeea114add2012-05-03 15:00:40 -0700374 LIR* branch = opBranchUnconditional(cUnit, kOpUncondBr);
375 branch->target = (LIR*) target;
376 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800377}
378
buzbee5de34942012-03-01 14:51:57 -0800379// FIXME: need to do some work to split out targets with
380// condition codes and those without
381#if defined(TARGET_ARM) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -0700382LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee31a4a6f2012-02-28 15:36:15 -0800383 ThrowKind kind)
384{
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700386 cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700387 LIR* branch = opCondBranch(cUnit, cCode, tgt);
388 // Remember branch target - will process later
389 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
390 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800391}
buzbee5de34942012-03-01 14:51:57 -0800392#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800393
394LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -0700395 int reg, int immVal, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800396{
buzbee408ad162012-06-06 16:45:18 -0700397 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
398 cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700399 LIR* branch;
400 if (cCode == kCondAl) {
401 branch = opUnconditionalBranch(cUnit, tgt);
402 } else {
403 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
404 }
405 // Remember branch target - will process later
406 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
407 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800408}
409
410/* Perform null-check on a register. */
buzbee408ad162012-06-06 16:45:18 -0700411LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -0800412{
Bill Buzbeea114add2012-05-03 15:00:40 -0700413 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
buzbee408ad162012-06-06 16:45:18 -0700414 optFlags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700415 return NULL;
416 }
buzbee408ad162012-06-06 16:45:18 -0700417 return genImmedCheck(cUnit, kCondEq, mReg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -0800418}
419
420/* Perform check on two registers */
421LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -0700422 int reg1, int reg2, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800423{
Bill Buzbeea114add2012-05-03 15:00:40 -0700424 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700425 cUnit->currentDalvikOffset, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800426#if defined(TARGET_MIPS)
Bill Buzbeea114add2012-05-03 15:00:40 -0700427 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800428#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700429 opRegReg(cUnit, kOpCmp, reg1, reg2);
430 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800431#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700432 // Remember branch target - will process later
433 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
434 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800435}
436
buzbee3b3dbdd2012-06-13 13:39:34 -0700437void genCompareAndBranch(CompilationUnit* cUnit, Instruction::Code opcode,
438 RegLocation rlSrc1, RegLocation rlSrc2, LIR* taken,
439 LIR* fallThrough)
buzbee31a4a6f2012-02-28 15:36:15 -0800440{
Bill Buzbeea114add2012-05-03 15:00:40 -0700441 ConditionCode cond;
442 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
443 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700444 switch (opcode) {
445 case Instruction::IF_EQ:
446 cond = kCondEq;
447 break;
448 case Instruction::IF_NE:
449 cond = kCondNe;
450 break;
451 case Instruction::IF_LT:
452 cond = kCondLt;
453 break;
454 case Instruction::IF_GE:
455 cond = kCondGe;
456 break;
457 case Instruction::IF_GT:
458 cond = kCondGt;
459 break;
460 case Instruction::IF_LE:
461 cond = kCondLe;
462 break;
463 default:
464 cond = (ConditionCode)0;
465 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
466 }
buzbee5de34942012-03-01 14:51:57 -0800467#if defined(TARGET_MIPS)
buzbee3b3dbdd2012-06-13 13:39:34 -0700468 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg, taken);
buzbee5de34942012-03-01 14:51:57 -0800469#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700470 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee3b3dbdd2012-06-13 13:39:34 -0700471 opCondBranch(cUnit, cond, taken);
buzbee5de34942012-03-01 14:51:57 -0800472#endif
buzbee3b3dbdd2012-06-13 13:39:34 -0700473 opUnconditionalBranch(cUnit, fallThrough);
buzbee31a4a6f2012-02-28 15:36:15 -0800474}
475
buzbee3b3dbdd2012-06-13 13:39:34 -0700476void genCompareZeroAndBranch(CompilationUnit* cUnit, Instruction::Code opcode,
477 RegLocation rlSrc, LIR* taken, LIR* fallThrough)
buzbee31a4a6f2012-02-28 15:36:15 -0800478{
Bill Buzbeea114add2012-05-03 15:00:40 -0700479 ConditionCode cond;
480 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700481 switch (opcode) {
482 case Instruction::IF_EQZ:
483 cond = kCondEq;
484 break;
485 case Instruction::IF_NEZ:
486 cond = kCondNe;
487 break;
488 case Instruction::IF_LTZ:
489 cond = kCondLt;
490 break;
491 case Instruction::IF_GEZ:
492 cond = kCondGe;
493 break;
494 case Instruction::IF_GTZ:
495 cond = kCondGt;
496 break;
497 case Instruction::IF_LEZ:
498 cond = kCondLe;
499 break;
500 default:
501 cond = (ConditionCode)0;
502 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
503 }
Ian Rogers7caad772012-03-30 01:07:54 -0700504#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee3b3dbdd2012-06-13 13:39:34 -0700505 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, taken);
buzbee5de34942012-03-01 14:51:57 -0800506#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700507 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
buzbee3b3dbdd2012-06-13 13:39:34 -0700508 opCondBranch(cUnit, cond, taken);
buzbee5de34942012-03-01 14:51:57 -0800509#endif
buzbee3b3dbdd2012-06-13 13:39:34 -0700510 opUnconditionalBranch(cUnit, fallThrough);
buzbee31a4a6f2012-02-28 15:36:15 -0800511}
512
buzbee408ad162012-06-06 16:45:18 -0700513void genIntToLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800514 RegLocation rlSrc)
515{
Bill Buzbeea114add2012-05-03 15:00:40 -0700516 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
517 if (rlSrc.location == kLocPhysReg) {
518 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
519 } else {
520 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
521 }
522 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
523 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800524}
525
buzbee408ad162012-06-06 16:45:18 -0700526void genIntNarrowing(CompilationUnit* cUnit, Instruction::Code opcode,
527 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800528{
Bill Buzbeea114add2012-05-03 15:00:40 -0700529 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
530 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
531 OpKind op = kOpInvalid;
buzbee408ad162012-06-06 16:45:18 -0700532 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700533 case Instruction::INT_TO_BYTE:
534 op = kOp2Byte;
535 break;
536 case Instruction::INT_TO_SHORT:
537 op = kOp2Short;
538 break;
539 case Instruction::INT_TO_CHAR:
540 op = kOp2Char;
541 break;
542 default:
543 LOG(ERROR) << "Bad int conversion type";
544 }
545 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
546 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800547}
548
549/*
550 * Let helper function take care of everything. Will call
551 * Array::AllocFromCode(type_idx, method, count);
552 * Note: AllocFromCode will handle checks for errNegativeArraySize.
553 */
buzbee408ad162012-06-06 16:45:18 -0700554void genNewArray(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800555 RegLocation rlSrc)
556{
Bill Buzbeea114add2012-05-03 15:00:40 -0700557 oatFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700558 int funcOffset;
559 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -0700560 *cUnit->dex_file,
561 type_idx)) {
562 funcOffset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
563 } else {
564 funcOffset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
565 }
buzbee8320f382012-09-11 16:29:42 -0700566 callRuntimeHelperImmMethodRegLocation(cUnit, funcOffset, type_idx, rlSrc, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700567 RegLocation rlResult = oatGetReturn(cUnit, false);
568 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800569}
570
571/*
572 * Similar to genNewArray, but with post-allocation initialization.
573 * Verifier guarantees we're dealing with an array class. Current
574 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
575 * Current code also throws internal unimp if not 'L', '[' or 'I'.
576 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700577void genFilledNewArray(CompilationUnit* cUnit, CallInfo* info)
buzbee31a4a6f2012-02-28 15:36:15 -0800578{
buzbee3b3dbdd2012-06-13 13:39:34 -0700579 int elems = info->numArgWords;
580 int typeIdx = info->index;
Bill Buzbeea114add2012-05-03 15:00:40 -0700581 oatFlushAllRegs(cUnit); /* Everything to home location */
582 int funcOffset;
583 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -0700584 *cUnit->dex_file,
585 typeIdx)) {
586 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
587 } else {
588 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
589 }
buzbee8320f382012-09-11 16:29:42 -0700590 callRuntimeHelperImmMethodImm(cUnit, funcOffset, typeIdx, elems, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700591 oatFreeTemp(cUnit, rARG2);
592 oatFreeTemp(cUnit, rARG1);
593 /*
594 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
595 * return region. Because AllocFromCode placed the new array
596 * in rRET0, we'll just lock it into place. When debugger support is
597 * added, it may be necessary to additionally copy all return
598 * values to a home location in thread-local storage
599 */
600 oatLockTemp(cUnit, rRET0);
601
602 // TODO: use the correct component size, currently all supported types
603 // share array alignment with ints (see comment at head of function)
604 size_t component_size = sizeof(int32_t);
605
606 // Having a range of 0 is legal
buzbee3b3dbdd2012-06-13 13:39:34 -0700607 if (info->isRange && (elems > 0)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800608 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700609 * Bit of ugliness here. We're going generate a mem copy loop
610 * on the register range, but it is possible that some regs
611 * in the range have been promoted. This is unlikely, but
612 * before generating the copy, we'll just force a flush
613 * of any regs in the source range that have been promoted to
614 * home location.
buzbee31a4a6f2012-02-28 15:36:15 -0800615 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700616 for (int i = 0; i < elems; i++) {
617 RegLocation loc = oatUpdateLoc(cUnit, info->args[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700618 if (loc.location == kLocPhysReg) {
619 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
620 loc.lowReg, kWord);
621 }
buzbee31a4a6f2012-02-28 15:36:15 -0800622 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700623 /*
624 * TUNING note: generated code here could be much improved, but
625 * this is an uncommon operation and isn't especially performance
626 * critical.
627 */
628 int rSrc = oatAllocTemp(cUnit);
629 int rDst = oatAllocTemp(cUnit);
630 int rIdx = oatAllocTemp(cUnit);
631#if defined(TARGET_ARM)
632 int rVal = rLR; // Using a lot of temps, rLR is known free here
633#elif defined(TARGET_X86)
jeffhao5772bab2012-05-18 11:51:26 -0700634 oatFreeTemp(cUnit, rRET0);
635 int rVal = oatAllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700636#else
637 int rVal = oatAllocTemp(cUnit);
638#endif
639 // Set up source pointer
buzbee3b3dbdd2012-06-13 13:39:34 -0700640 RegLocation rlFirst = info->args[0];
Bill Buzbeea114add2012-05-03 15:00:40 -0700641 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
642 oatSRegOffset(cUnit, rlFirst.sRegLow));
643 // Set up the target pointer
644 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
645 Array::DataOffset(component_size).Int32Value());
646 // Set up the loop counter (known to be > 0)
buzbee3b3dbdd2012-06-13 13:39:34 -0700647 loadConstant(cUnit, rIdx, elems - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700648 // Generate the copy loop. Going backwards for convenience
649 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
650 // Copy next element
651 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
652 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
653#if defined(TARGET_ARM)
654 // Combine sub & test using sub setflags encoding here
655 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
656 opCondBranch(cUnit, kCondGe, target);
657#else
658 oatFreeTemp(cUnit, rVal);
659 opRegImm(cUnit, kOpSub, rIdx, 1);
660 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
661#endif
jeffhao5772bab2012-05-18 11:51:26 -0700662#if defined(TARGET_X86)
663 // Restore the target pointer
664 opRegRegImm(cUnit, kOpAdd, rRET0, rDst,
665 -Array::DataOffset(component_size).Int32Value());
666#endif
buzbee3b3dbdd2012-06-13 13:39:34 -0700667 } else if (!info->isRange) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700668 // TUNING: interleave
buzbee3b3dbdd2012-06-13 13:39:34 -0700669 for (int i = 0; i < elems; i++) {
670 RegLocation rlArg = loadValue(cUnit, info->args[i], kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700671 storeBaseDisp(cUnit, rRET0,
672 Array::DataOffset(component_size).Int32Value() +
673 i * 4, rlArg.lowReg, kWord);
674 // If the loadValue caused a temp to be allocated, free it
675 if (oatIsTemp(cUnit, rlArg.lowReg)) {
676 oatFreeTemp(cUnit, rlArg.lowReg);
677 }
678 }
679 }
buzbeee5f01222012-06-14 15:19:35 -0700680 if (info->result.location != kLocInvalid) {
681 storeValue(cUnit, info->result, oatGetReturn(cUnit, false /* not fp */));
682 }
buzbee31a4a6f2012-02-28 15:36:15 -0800683}
684
buzbee408ad162012-06-06 16:45:18 -0700685void genSput(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlSrc,
Bill Buzbeea114add2012-05-03 15:00:40 -0700686 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800687{
Bill Buzbeea114add2012-05-03 15:00:40 -0700688 int fieldOffset;
689 int ssbIndex;
690 bool isVolatile;
691 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800692
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700693 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker, *cUnit->dex_file,
694 cUnit->code_item, cUnit->method_idx, cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800695
Bill Buzbeea114add2012-05-03 15:00:40 -0700696 bool fastPath =
697 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
698 fieldOffset, ssbIndex,
699 isReferrersClass, isVolatile,
700 true);
701 if (fastPath && !SLOW_FIELD_PATH) {
702 DCHECK_GE(fieldOffset, 0);
703 int rBase;
704 if (isReferrersClass) {
705 // Fast path, static storage base is this method's class
706 RegLocation rlMethod = loadCurrMethod(cUnit);
707 rBase = oatAllocTemp(cUnit);
708 loadWordDisp(cUnit, rlMethod.lowReg,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700709 AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700710 if (oatIsTemp(cUnit, rlMethod.lowReg)) {
711 oatFreeTemp(cUnit, rlMethod.lowReg);
712 }
buzbee31a4a6f2012-02-28 15:36:15 -0800713 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700714 // Medium path, static storage base in a different class which
715 // requires checks that the other class is initialized.
716 DCHECK_GE(ssbIndex, 0);
717 // May do runtime call so everything to home locations.
718 oatFlushAllRegs(cUnit);
719 // Using fixed register to sync with possible call to runtime
720 // support.
721 int rMethod = rARG1;
722 oatLockTemp(cUnit, rMethod);
723 loadCurrMethodDirect(cUnit, rMethod);
724 rBase = rARG0;
725 oatLockTemp(cUnit, rBase);
726 loadWordDisp(cUnit, rMethod,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700727 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700728 rBase);
729 loadWordDisp(cUnit, rBase,
730 Array::DataOffset(sizeof(Object*)).Int32Value() +
731 sizeof(int32_t*) * ssbIndex, rBase);
732 // rBase now points at appropriate static storage base (Class*)
733 // or NULL if not initialized. Check for NULL and call helper if NULL.
734 // TUNING: fast path should fall through
735 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
736 loadConstant(cUnit, rARG0, ssbIndex);
buzbee8320f382012-09-11 16:29:42 -0700737 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssbIndex, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700738#if defined(TARGET_MIPS)
739 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
740 opRegCopy(cUnit, rBase, rRET0);
741#endif
742 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
743 branchOver->target = (LIR*)skipTarget;
744 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800745 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700746 // rBase now holds static storage base
747 if (isLongOrDouble) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700748 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
749 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700750 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
751 }
752//FIXME: need to generalize the barrier call
753 if (isVolatile) {
754 oatGenMemBarrier(cUnit, kST);
755 }
756 if (isLongOrDouble) {
757 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
758 rlSrc.highReg);
759 } else {
760 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
761 }
762 if (isVolatile) {
763 oatGenMemBarrier(cUnit, kSY);
764 }
765 if (isObject) {
766 markGCCard(cUnit, rlSrc.lowReg, rBase);
767 }
768 oatFreeTemp(cUnit, rBase);
769 } else {
770 oatFlushAllRegs(cUnit); // Everything to home locations
771 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Static) :
772 (isObject ? ENTRYPOINT_OFFSET(pSetObjStatic)
773 : ENTRYPOINT_OFFSET(pSet32Static));
buzbee8320f382012-09-11 16:29:42 -0700774 callRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700775 }
buzbee31a4a6f2012-02-28 15:36:15 -0800776}
777
buzbee408ad162012-06-06 16:45:18 -0700778void genSget(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700779 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800780{
Bill Buzbeea114add2012-05-03 15:00:40 -0700781 int fieldOffset;
782 int ssbIndex;
783 bool isVolatile;
784 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800785
Bill Buzbeea114add2012-05-03 15:00:40 -0700786 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700787 *cUnit->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700788 cUnit->code_item, cUnit->method_idx,
789 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800790
Bill Buzbeea114add2012-05-03 15:00:40 -0700791 bool fastPath =
792 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
793 fieldOffset, ssbIndex,
794 isReferrersClass, isVolatile,
795 false);
796 if (fastPath && !SLOW_FIELD_PATH) {
797 DCHECK_GE(fieldOffset, 0);
798 int rBase;
799 if (isReferrersClass) {
800 // Fast path, static storage base is this method's class
801 RegLocation rlMethod = loadCurrMethod(cUnit);
802 rBase = oatAllocTemp(cUnit);
803 loadWordDisp(cUnit, rlMethod.lowReg,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700804 AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800805 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700806 // Medium path, static storage base in a different class which
807 // requires checks that the other class is initialized
808 DCHECK_GE(ssbIndex, 0);
809 // May do runtime call so everything to home locations.
810 oatFlushAllRegs(cUnit);
811 // Using fixed register to sync with possible call to runtime
812 // support
813 int rMethod = rARG1;
814 oatLockTemp(cUnit, rMethod);
815 loadCurrMethodDirect(cUnit, rMethod);
816 rBase = rARG0;
817 oatLockTemp(cUnit, rBase);
818 loadWordDisp(cUnit, rMethod,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700819 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700820 rBase);
821 loadWordDisp(cUnit, rBase,
822 Array::DataOffset(sizeof(Object*)).Int32Value() +
823 sizeof(int32_t*) * ssbIndex, rBase);
824 // rBase now points at appropriate static storage base (Class*)
825 // or NULL if not initialized. Check for NULL and call helper if NULL.
826 // TUNING: fast path should fall through
827 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee8320f382012-09-11 16:29:42 -0700828 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssbIndex, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700829#if defined(TARGET_MIPS)
830 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
831 opRegCopy(cUnit, rBase, rRET0);
832#endif
833 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
834 branchOver->target = (LIR*)skipTarget;
835 oatFreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800836 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700837 // rBase now holds static storage base
Bill Buzbeea114add2012-05-03 15:00:40 -0700838 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
839 if (isVolatile) {
840 oatGenMemBarrier(cUnit, kSY);
841 }
842 if (isLongOrDouble) {
buzbee408ad162012-06-06 16:45:18 -0700843 loadBaseDispWide(cUnit, rBase, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700844 rlResult.highReg, INVALID_SREG);
845 } else {
846 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
847 }
848 oatFreeTemp(cUnit, rBase);
849 if (isLongOrDouble) {
850 storeValueWide(cUnit, rlDest, rlResult);
851 } else {
852 storeValue(cUnit, rlDest, rlResult);
853 }
854 } else {
855 oatFlushAllRegs(cUnit); // Everything to home locations
856 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Static) :
857 (isObject ? ENTRYPOINT_OFFSET(pGetObjStatic)
858 : ENTRYPOINT_OFFSET(pGet32Static));
buzbee8320f382012-09-11 16:29:42 -0700859 callRuntimeHelperImm(cUnit, getterOffset, fieldIdx, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700860 if (isLongOrDouble) {
861 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
862 storeValueWide(cUnit, rlDest, rlResult);
863 } else {
864 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
865 storeValue(cUnit, rlDest, rlResult);
866 }
867 }
buzbee31a4a6f2012-02-28 15:36:15 -0800868}
869
870
871// Debugging routine - if null target, branch to DebugMe
872void genShowTarget(CompilationUnit* cUnit)
873{
buzbeea7678db2012-03-05 15:35:46 -0800874#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700875 UNIMPLEMENTED(WARNING) << "genShowTarget";
buzbeea7678db2012-03-05 15:35:46 -0800876#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700877 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
878 loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pDebugMe), rINVOKE_TGT);
879 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
880 branchOver->target = (LIR*)target;
buzbeea7678db2012-03-05 15:35:46 -0800881#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800882}
883
buzbee31a4a6f2012-02-28 15:36:15 -0800884void handleSuspendLaunchpads(CompilationUnit *cUnit)
885{
Bill Buzbeea114add2012-05-03 15:00:40 -0700886 LIR** suspendLabel = (LIR **)cUnit->suspendLaunchpads.elemList;
887 int numElems = cUnit->suspendLaunchpads.numUsed;
888 for (int i = 0; i < numElems; i++) {
889 oatResetRegPool(cUnit);
890 oatResetDefTracking(cUnit);
891 LIR* lab = suspendLabel[i];
892 LIR* resumeLab = (LIR*)lab->operands[0];
893 cUnit->currentDalvikOffset = lab->operands[1];
894 oatAppendLIR(cUnit, lab);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700895#if defined(TARGET_X86)
buzbee8320f382012-09-11 16:29:42 -0700896 LIR* callInst = opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700897#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700898 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
buzbee8320f382012-09-11 16:29:42 -0700899 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700900#endif
buzbee8320f382012-09-11 16:29:42 -0700901 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -0700902 opUnconditionalBranch(cUnit, resumeLab);
903 }
buzbee31a4a6f2012-02-28 15:36:15 -0800904}
905
buzbeefc9e6fa2012-03-23 15:14:29 -0700906void handleIntrinsicLaunchpads(CompilationUnit *cUnit)
907{
Bill Buzbeea114add2012-05-03 15:00:40 -0700908 LIR** intrinsicLabel = (LIR **)cUnit->intrinsicLaunchpads.elemList;
909 int numElems = cUnit->intrinsicLaunchpads.numUsed;
910 for (int i = 0; i < numElems; i++) {
911 oatResetRegPool(cUnit);
912 oatResetDefTracking(cUnit);
913 LIR* lab = intrinsicLabel[i];
buzbee3b3dbdd2012-06-13 13:39:34 -0700914 CallInfo* info = (CallInfo*)lab->operands[0];
buzbee15bf9802012-06-12 17:49:27 -0700915 cUnit->currentDalvikOffset = info->offset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700916 oatAppendLIR(cUnit, lab);
buzbee8320f382012-09-11 16:29:42 -0700917 // NOTE: genInvoke handles markSafepointPC
buzbee15bf9802012-06-12 17:49:27 -0700918 genInvoke(cUnit, info);
Bill Buzbeea114add2012-05-03 15:00:40 -0700919 LIR* resumeLab = (LIR*)lab->operands[2];
920 if (resumeLab != NULL) {
921 opUnconditionalBranch(cUnit, resumeLab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700922 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700923 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700924}
925
buzbee31a4a6f2012-02-28 15:36:15 -0800926void handleThrowLaunchpads(CompilationUnit *cUnit)
927{
Bill Buzbeea114add2012-05-03 15:00:40 -0700928 LIR** throwLabel = (LIR **)cUnit->throwLaunchpads.elemList;
929 int numElems = cUnit->throwLaunchpads.numUsed;
930 for (int i = 0; i < numElems; i++) {
931 oatResetRegPool(cUnit);
932 oatResetDefTracking(cUnit);
933 LIR* lab = throwLabel[i];
934 cUnit->currentDalvikOffset = lab->operands[1];
935 oatAppendLIR(cUnit, lab);
936 int funcOffset = 0;
937 int v1 = lab->operands[2];
938 int v2 = lab->operands[3];
939 switch (lab->operands[0]) {
940 case kThrowNullPointer:
941 funcOffset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
942 break;
943 case kThrowArrayBounds:
jeffhao44335e12012-06-18 13:48:25 -0700944 // Move v1 (array index) to rARG0 and v2 (array length) to rARG1
Bill Buzbeea114add2012-05-03 15:00:40 -0700945 if (v2 != rARG0) {
946 opRegCopy(cUnit, rARG0, v1);
jeffhao703f2cd2012-07-13 17:25:52 -0700947#if defined (TARGET_X86)
948 // x86 leaves the array pointer in v2, so load the array length that the handler expects
949 opRegMem(cUnit, kOpMov, rARG1, v2, Array::LengthOffset().Int32Value());
950#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 opRegCopy(cUnit, rARG1, v2);
jeffhao703f2cd2012-07-13 17:25:52 -0700952#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700953 } else {
954 if (v1 == rARG1) {
jeffhao44335e12012-06-18 13:48:25 -0700955 // Swap v1 and v2, using rARG2 as a temp
956 opRegCopy(cUnit, rARG2, v1);
jeffhao703f2cd2012-07-13 17:25:52 -0700957#if defined (TARGET_X86)
958 // x86 leaves the array pointer in v2, so load the array length that the handler expects
959 opRegMem(cUnit, kOpMov, rARG1, v2, Array::LengthOffset().Int32Value());
960#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700961 opRegCopy(cUnit, rARG1, v2);
jeffhao703f2cd2012-07-13 17:25:52 -0700962#endif
jeffhao44335e12012-06-18 13:48:25 -0700963 opRegCopy(cUnit, rARG0, rARG2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700964 } else {
jeffhao703f2cd2012-07-13 17:25:52 -0700965#if defined (TARGET_X86)
966 // x86 leaves the array pointer in v2, so load the array length that the handler expects
967 opRegMem(cUnit, kOpMov, rARG1, v2, Array::LengthOffset().Int32Value());
968#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700969 opRegCopy(cUnit, rARG1, v2);
jeffhao703f2cd2012-07-13 17:25:52 -0700970#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700971 opRegCopy(cUnit, rARG0, v1);
972 }
buzbee31a4a6f2012-02-28 15:36:15 -0800973 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700974 funcOffset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
975 break;
976 case kThrowDivZero:
977 funcOffset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
978 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700979 case kThrowNoSuchMethod:
980 opRegCopy(cUnit, rARG0, v1);
981 funcOffset =
982 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
983 break;
984 case kThrowStackOverflow:
985 funcOffset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
986 // Restore stack alignment
Ian Rogersab2b55d2012-03-18 00:06:11 -0700987#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -0700988 opRegImm(cUnit, kOpAdd, rSP,
989 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700990#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700991 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -0700992#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700993 break;
994 default:
995 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
buzbee31a4a6f2012-02-28 15:36:15 -0800996 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700997 oatClobberCalleeSave(cUnit);
998#if !defined(TARGET_X86)
999 int rTgt = loadHelper(cUnit, funcOffset);
buzbee8320f382012-09-11 16:29:42 -07001000 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
Bill Buzbeea114add2012-05-03 15:00:40 -07001001 oatFreeTemp(cUnit, rTgt);
1002#else
buzbee8320f382012-09-11 16:29:42 -07001003 LIR* callInst = opThreadMem(cUnit, kOpBlx, funcOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -07001004#endif
buzbee8320f382012-09-11 16:29:42 -07001005 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -07001006 }
buzbee31a4a6f2012-02-28 15:36:15 -08001007}
1008
1009/* Needed by the Assembler */
1010void oatSetupResourceMasks(LIR* lir)
1011{
Bill Buzbeea114add2012-05-03 15:00:40 -07001012 setupResourceMasks(lir);
buzbee31a4a6f2012-02-28 15:36:15 -08001013}
1014
buzbee16da88c2012-03-20 10:38:17 -07001015bool fastInstance(CompilationUnit* cUnit, uint32_t fieldIdx,
1016 int& fieldOffset, bool& isVolatile, bool isPut)
1017{
Bill Buzbeea114add2012-05-03 15:00:40 -07001018 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001019 *cUnit->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -07001020 cUnit->code_item, cUnit->method_idx,
1021 cUnit->access_flags);
1022 return cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
1023 fieldOffset, isVolatile, isPut);
buzbee16da88c2012-03-20 10:38:17 -07001024}
1025
buzbee408ad162012-06-06 16:45:18 -07001026void genIGet(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001027 RegLocation rlDest, RegLocation rlObj,
Bill Buzbeea114add2012-05-03 15:00:40 -07001028 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -08001029{
Bill Buzbeea114add2012-05-03 15:00:40 -07001030 int fieldOffset;
1031 bool isVolatile;
buzbee31a4a6f2012-02-28 15:36:15 -08001032
Bill Buzbeea114add2012-05-03 15:00:40 -07001033 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001034
Bill Buzbeea114add2012-05-03 15:00:40 -07001035 if (fastPath && !SLOW_FIELD_PATH) {
1036 RegLocation rlResult;
1037 RegisterClass regClass = oatRegClassBySize(size);
1038 DCHECK_GE(fieldOffset, 0);
1039 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1040 if (isLongOrDouble) {
1041 DCHECK(rlDest.wide);
buzbee408ad162012-06-06 16:45:18 -07001042 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001043#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001044 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001045 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
1046 loadBaseDispWide(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -07001047 rlResult.highReg, rlObj.sRegLow);
1048 if (isVolatile) {
1049 oatGenMemBarrier(cUnit, kSY);
1050 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001051#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001052 int regPtr = oatAllocTemp(cUnit);
1053 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1054 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1055 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1056 if (isVolatile) {
1057 oatGenMemBarrier(cUnit, kSY);
1058 }
1059 oatFreeTemp(cUnit, regPtr);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001060#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001061 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001062 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001063 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001064 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
1065 loadBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -07001066 kWord, rlObj.sRegLow);
1067 if (isVolatile) {
1068 oatGenMemBarrier(cUnit, kSY);
1069 }
1070 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001071 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001072 } else {
1073 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Instance) :
1074 (isObject ? ENTRYPOINT_OFFSET(pGetObjInstance)
1075 : ENTRYPOINT_OFFSET(pGet32Instance));
buzbee8320f382012-09-11 16:29:42 -07001076 callRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001077 if (isLongOrDouble) {
1078 RegLocation rlResult = oatGetReturnWide(cUnit, rlDest.fp);
1079 storeValueWide(cUnit, rlDest, rlResult);
1080 } else {
1081 RegLocation rlResult = oatGetReturn(cUnit, rlDest.fp);
1082 storeValue(cUnit, rlDest, rlResult);
1083 }
1084 }
buzbee31a4a6f2012-02-28 15:36:15 -08001085}
1086
buzbee408ad162012-06-06 16:45:18 -07001087void genIPut(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
1088 RegLocation rlSrc, RegLocation rlObj, bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -08001089{
Bill Buzbeea114add2012-05-03 15:00:40 -07001090 int fieldOffset;
1091 bool isVolatile;
buzbee31a4a6f2012-02-28 15:36:15 -08001092
Bill Buzbeea114add2012-05-03 15:00:40 -07001093 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
1094 true);
1095 if (fastPath && !SLOW_FIELD_PATH) {
1096 RegisterClass regClass = oatRegClassBySize(size);
1097 DCHECK_GE(fieldOffset, 0);
1098 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1099 if (isLongOrDouble) {
1100 int regPtr;
1101 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee408ad162012-06-06 16:45:18 -07001102 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07001103 regPtr = oatAllocTemp(cUnit);
1104 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1105 if (isVolatile) {
1106 oatGenMemBarrier(cUnit, kST);
1107 }
jeffhao41005dd2012-05-09 17:58:52 -07001108 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001109 if (isVolatile) {
1110 oatGenMemBarrier(cUnit, kSY);
1111 }
1112 oatFreeTemp(cUnit, regPtr);
buzbee31a4a6f2012-02-28 15:36:15 -08001113 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001114 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee408ad162012-06-06 16:45:18 -07001115 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07001116 if (isVolatile) {
1117 oatGenMemBarrier(cUnit, kST);
1118 }
1119 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
1120 if (isVolatile) {
1121 oatGenMemBarrier(cUnit, kSY);
1122 }
1123 if (isObject) {
1124 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
1125 }
buzbee31a4a6f2012-02-28 15:36:15 -08001126 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001127 } else {
1128 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Instance) :
1129 (isObject ? ENTRYPOINT_OFFSET(pSetObjInstance)
1130 : ENTRYPOINT_OFFSET(pSet32Instance));
buzbee8320f382012-09-11 16:29:42 -07001131 callRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset, fieldIdx, rlObj, rlSrc, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001132 }
buzbee31a4a6f2012-02-28 15:36:15 -08001133}
1134
buzbee6969d502012-06-15 16:40:31 -07001135void genConstClass(CompilationUnit* cUnit, uint32_t type_idx,
1136 RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001137{
Bill Buzbeea114add2012-05-03 15:00:40 -07001138 RegLocation rlMethod = loadCurrMethod(cUnit);
1139 int resReg = oatAllocTemp(cUnit);
1140 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1141 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -07001142 *cUnit->dex_file,
1143 type_idx)) {
1144 // Call out to helper which resolves type and verifies access.
1145 // Resolved type returned in rRET0.
buzbee8320f382012-09-11 16:29:42 -07001146 callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1147 type_idx, rlMethod.lowReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001148 RegLocation rlResult = oatGetReturn(cUnit, false);
1149 storeValue(cUnit, rlDest, rlResult);
1150 } else {
1151 // We're don't need access checks, load type from dex cache
1152 int32_t dex_cache_offset =
Mathieu Chartier66f19252012-09-18 08:57:04 -07001153 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001154 loadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
1155 int32_t offset_of_type =
1156 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1157 * type_idx);
1158 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001159 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(*cUnit->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -07001160 type_idx) || SLOW_TYPE_PATH) {
1161 // Slow path, at runtime test if type is null and if so initialize
1162 oatFlushAllRegs(cUnit);
1163 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0, NULL);
1164 // Resolved, store and hop over following code
1165 storeValue(cUnit, rlDest, rlResult);
1166 /*
1167 * Because we have stores of the target value on two paths,
1168 * clobber temp tracking for the destination using the ssa name
1169 */
1170 oatClobberSReg(cUnit, rlDest.sRegLow);
1171 LIR* branch2 = opUnconditionalBranch(cUnit,0);
1172 // TUNING: move slow path to end & remove unconditional branch
1173 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
1174 // Call out to helper, which will return resolved type in rARG0
buzbee8320f382012-09-11 16:29:42 -07001175 callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx,
1176 rlMethod.lowReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001177 RegLocation rlResult = oatGetReturn(cUnit, false);
1178 storeValue(cUnit, rlDest, rlResult);
1179 /*
1180 * Because we have stores of the target value on two paths,
1181 * clobber temp tracking for the destination using the ssa name
1182 */
1183 oatClobberSReg(cUnit, rlDest.sRegLow);
1184 // Rejoin code paths
1185 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
1186 branch1->target = (LIR*)target1;
1187 branch2->target = (LIR*)target2;
buzbee31a4a6f2012-02-28 15:36:15 -08001188 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001189 // Fast path, we're done - just store result
1190 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001191 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001192 }
buzbee31a4a6f2012-02-28 15:36:15 -08001193}
Ian Rogersab2b55d2012-03-18 00:06:11 -07001194
buzbee6969d502012-06-15 16:40:31 -07001195void genConstString(CompilationUnit* cUnit, uint32_t string_idx,
1196 RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001197{
Bill Buzbeea114add2012-05-03 15:00:40 -07001198 /* NOTE: Most strings should be available at compile time */
Bill Buzbeea114add2012-05-03 15:00:40 -07001199 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1200 (sizeof(String*) * string_idx);
1201 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001202 *cUnit->dex_file, string_idx) || SLOW_STRING_PATH) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001203 // slow path, resolve string if not in dex cache
1204 oatFlushAllRegs(cUnit);
1205 oatLockCallTemps(cUnit); // Using explicit registers
1206 loadCurrMethodDirect(cUnit, rARG2);
1207 loadWordDisp(cUnit, rARG2,
Mathieu Chartier66f19252012-09-18 08:57:04 -07001208 AbstractMethod::DexCacheStringsOffset().Int32Value(), rARG0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001209 // Might call out to helper, which will return resolved string in rRET0
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001210#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001211 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001212#endif
jeffhaofa147e22012-10-12 17:03:32 -07001213 loadWordDisp(cUnit, rARG0, offset_of_string, rRET0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001214 loadConstant(cUnit, rARG1, string_idx);
buzbee31a4a6f2012-02-28 15:36:15 -08001215#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001216 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
1217 genBarrier(cUnit);
1218 // For testing, always force through helper
1219 if (!EXERCISE_SLOWEST_STRING_PATH) {
1220 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08001221 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001222 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee8320f382012-09-11 16:29:42 -07001223 LIR* callInst = opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
1224 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -07001225 oatFreeTemp(cUnit, rTgt);
1226#elif defined(TARGET_MIPS)
1227 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
1228 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee8320f382012-09-11 16:29:42 -07001229 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
1230 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -07001231 oatFreeTemp(cUnit, rTgt);
1232 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1233 branch->target = target;
1234#else
buzbee8320f382012-09-11 16:29:42 -07001235 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode), rARG2, rARG1, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001236#endif
1237 genBarrier(cUnit);
1238 storeValue(cUnit, rlDest, oatGetReturn(cUnit, false));
1239 } else {
1240 RegLocation rlMethod = loadCurrMethod(cUnit);
1241 int resReg = oatAllocTemp(cUnit);
1242 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1243 loadWordDisp(cUnit, rlMethod.lowReg,
Mathieu Chartier66f19252012-09-18 08:57:04 -07001244 AbstractMethod::DexCacheStringsOffset().Int32Value(), resReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001245 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1246 storeValue(cUnit, rlDest, rlResult);
1247 }
buzbee31a4a6f2012-02-28 15:36:15 -08001248}
1249
1250/*
1251 * Let helper function take care of everything. Will
1252 * call Class::NewInstanceFromCode(type_idx, method);
1253 */
buzbee408ad162012-06-06 16:45:18 -07001254void genNewInstance(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001255{
Bill Buzbeea114add2012-05-03 15:00:40 -07001256 oatFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -07001257 // alloc will always check for resolution, do we also need to verify
1258 // access because the verifier was unable to?
1259 int funcOffset;
1260 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001261 cUnit->method_idx, *cUnit->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001262 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
1263 } else {
1264 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
1265 }
buzbee8320f382012-09-11 16:29:42 -07001266 callRuntimeHelperImmMethod(cUnit, funcOffset, type_idx, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001267 RegLocation rlResult = oatGetReturn(cUnit, false);
1268 storeValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001269}
1270
Ian Rogers474b6da2012-09-25 00:20:38 -07001271void genMoveException(CompilationUnit* cUnit, RegLocation rlDest)
1272{
1273 oatFlushAllRegs(cUnit); /* Everything to home location */
1274 int funcOffset = ENTRYPOINT_OFFSET(pGetAndClearException);
1275#if defined(TARGET_X86)
1276 // Runtime helper will load argument for x86.
1277 callRuntimeHelperReg(cUnit, funcOffset, rARG0, false);
1278#else
1279 callRuntimeHelperReg(cUnit, funcOffset, rSELF, false);
1280#endif
1281 RegLocation rlResult = oatGetReturn(cUnit, false);
1282 storeValue(cUnit, rlDest, rlResult);
1283}
1284
buzbee408ad162012-06-06 16:45:18 -07001285void genThrow(CompilationUnit* cUnit, RegLocation rlSrc)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001286{
Bill Buzbeea114add2012-05-03 15:00:40 -07001287 oatFlushAllRegs(cUnit);
buzbee8320f382012-09-11 16:29:42 -07001288 callRuntimeHelperRegLocation(cUnit, ENTRYPOINT_OFFSET(pDeliverException), rlSrc, true);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001289}
1290
buzbee408ad162012-06-06 16:45:18 -07001291void genInstanceof(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001292 RegLocation rlSrc)
1293{
Bill Buzbeea114add2012-05-03 15:00:40 -07001294 oatFlushAllRegs(cUnit);
1295 // May generate a call - use explicit registers
1296 oatLockCallTemps(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001297 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1298 int classReg = rARG2; // rARG2 will hold the Class*
1299 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -07001300 *cUnit->dex_file,
1301 type_idx)) {
1302 // Check we have access to type_idx and if not throw IllegalAccessError,
1303 // returns Class* in rARG0
buzbee8320f382012-09-11 16:29:42 -07001304 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1305 type_idx, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001306 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1307 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1308 } else {
1309 // Load dex cache entry into classReg (rARG2)
1310 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1311 loadWordDisp(cUnit, rARG1,
Mathieu Chartier66f19252012-09-18 08:57:04 -07001312 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), classReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001313 int32_t offset_of_type =
1314 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1315 * type_idx);
1316 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1317 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001318 *cUnit->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001319 // Need to test presence of type in dex cache at runtime
1320 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1321 // Not resolved
1322 // Call out to helper, which will return resolved type in rRET0
buzbee8320f382012-09-11 16:29:42 -07001323 callRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001324 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
1325 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1326 // Rejoin code paths
1327 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1328 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001329 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001330 }
1331 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
jeffhao4eb68ed2012-10-17 16:41:07 -07001332 RegLocation rlResult = oatGetReturn(cUnit, false);
1333#if defined(TARGET_MIPS)
1334 opRegCopy(cUnit, rlResult.lowReg, r_ZERO); // store false result for if branch is taken
1335#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001336 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1337 /* load object->klass_ */
1338 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1339 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1340 /* rARG0 is ref, rARG1 is ref->klass_, rARG2 is class */
buzbee8320f382012-09-11 16:29:42 -07001341 LIR* callInst;
buzbee0398c422012-03-02 15:22:47 -08001342#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001343 /* Uses conditional nullification */
1344 int rTgt = loadHelper(cUnit,
1345 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1346 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
1347 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
1348 loadConstant(cUnit, rARG0, 1); // .eq case - load true
1349 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee8320f382012-09-11 16:29:42 -07001350 callInst = opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
Bill Buzbeea114add2012-05-03 15:00:40 -07001351 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -08001352#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001353 /* Uses branchovers */
jeffhao4eb68ed2012-10-17 16:41:07 -07001354 loadConstant(cUnit, rlResult.lowReg, 1); // assume true
Bill Buzbeea114add2012-05-03 15:00:40 -07001355 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001356#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001357 int rTgt = loadHelper(cUnit,
1358 ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1359 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee8320f382012-09-11 16:29:42 -07001360 callInst = opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
Bill Buzbeea114add2012-05-03 15:00:40 -07001361 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001362#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001363 opRegCopy(cUnit, rARG0, rARG2);
buzbee8320f382012-09-11 16:29:42 -07001364 callInst = opThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001365#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001366#endif
buzbee8320f382012-09-11 16:29:42 -07001367 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -07001368 oatClobberCalleeSave(cUnit);
1369 /* branch targets here */
1370 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001371 storeValue(cUnit, rlDest, rlResult);
1372 branch1->target = target;
buzbee0398c422012-03-02 15:22:47 -08001373#if !defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001374 branchover->target = target;
buzbee0398c422012-03-02 15:22:47 -08001375#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001376}
1377
buzbee408ad162012-06-06 16:45:18 -07001378void genCheckCast(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08001379{
Bill Buzbeea114add2012-05-03 15:00:40 -07001380 oatFlushAllRegs(cUnit);
1381 // May generate a call - use explicit registers
1382 oatLockCallTemps(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001383 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1384 int classReg = rARG2; // rARG2 will hold the Class*
1385 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -07001386 *cUnit->dex_file,
1387 type_idx)) {
1388 // Check we have access to type_idx and if not throw IllegalAccessError,
1389 // returns Class* in rRET0
1390 // InitializeTypeAndVerifyAccess(idx, method)
buzbee8320f382012-09-11 16:29:42 -07001391 callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1392 type_idx, rARG1, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001393 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
1394 } else {
1395 // Load dex cache entry into classReg (rARG2)
1396 loadWordDisp(cUnit, rARG1,
Mathieu Chartier66f19252012-09-18 08:57:04 -07001397 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), classReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001398 int32_t offset_of_type =
1399 Array::DataOffset(sizeof(Class*)).Int32Value() +
1400 (sizeof(Class*) * type_idx);
1401 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1402 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001403 *cUnit->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001404 // Need to test presence of type in dex cache at runtime
1405 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
1406 // Not resolved
1407 // Call out to helper, which will return resolved type in rARG0
1408 // InitializeTypeFromCode(idx, method)
buzbee8320f382012-09-11 16:29:42 -07001409 callRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, rARG1,
1410 true);
jeffhao30a33172012-10-22 18:16:22 -07001411 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001412 // Rejoin code paths
1413 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
1414 hopBranch->target = (LIR*)hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001415 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001416 }
1417 // At this point, classReg (rARG2) has class
1418 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1419 /* Null is OK - continue */
1420 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
1421 /* load object->klass_ */
1422 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1423 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1424 /* rARG1 now contains object->klass_ */
Ian Rogersab2b55d2012-03-18 00:06:11 -07001425#if defined(TARGET_MIPS) || defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001426 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
buzbee8320f382012-09-11 16:29:42 -07001427 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode), rARG1, rARG2, true);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001428#else // defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001429 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1430 opRegReg(cUnit, kOpCmp, rARG1, classReg);
1431 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1432 opRegCopy(cUnit, rARG0, rARG1);
1433 opRegCopy(cUnit, rARG1, rARG2);
1434 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -07001435 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
1436 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -07001437 oatFreeTemp(cUnit, rTgt);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001438#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001439 /* branch target here */
1440 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1441 branch1->target = target;
1442 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001443}
1444
buzbee31a4a6f2012-02-28 15:36:15 -08001445/*
1446 * Generate array store
1447 *
1448 */
buzbee408ad162012-06-06 16:45:18 -07001449void genArrayObjPut(CompilationUnit* cUnit, int optFlags, RegLocation rlArray,
Bill Buzbeea114add2012-05-03 15:00:40 -07001450 RegLocation rlIndex, RegLocation rlSrc, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001451{
Bill Buzbeea114add2012-05-03 15:00:40 -07001452 int lenOffset = Array::LengthOffset().Int32Value();
1453 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
buzbee31a4a6f2012-02-28 15:36:15 -08001454
Bill Buzbeea114add2012-05-03 15:00:40 -07001455 oatFlushAllRegs(cUnit); // Use explicit registers
1456 oatLockCallTemps(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001457
Bill Buzbeea114add2012-05-03 15:00:40 -07001458 int rValue = rARG0; // Register holding value
1459 int rArrayClass = rARG1; // Register holding array's Class
1460 int rArray = rARG2; // Register holding array
1461 int rIndex = rARG3; // Register holding index into array
Ian Rogersd36c52e2012-04-09 16:29:25 -07001462
Bill Buzbeea114add2012-05-03 15:00:40 -07001463 loadValueDirectFixed(cUnit, rlArray, rArray); // Grab array
1464 loadValueDirectFixed(cUnit, rlSrc, rValue); // Grab value
1465 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Grab index
Ian Rogersd36c52e2012-04-09 16:29:25 -07001466
buzbee408ad162012-06-06 16:45:18 -07001467 genNullCheck(cUnit, rlArray.sRegLow, rArray, optFlags); // NPE?
Ian Rogersd36c52e2012-04-09 16:29:25 -07001468
Bill Buzbeea114add2012-05-03 15:00:40 -07001469 // Store of null?
1470 LIR* null_value_check = opCmpImmBranch(cUnit, kCondEq, rValue, 0, NULL);
Ian Rogersd36c52e2012-04-09 16:29:25 -07001471
Bill Buzbeea114add2012-05-03 15:00:40 -07001472 // Get the array's class.
1473 loadWordDisp(cUnit, rArray, Object::ClassOffset().Int32Value(), rArrayClass);
buzbee8320f382012-09-11 16:29:42 -07001474 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), rValue,
1475 rArrayClass, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001476 // Redo loadValues in case they didn't survive the call.
1477 loadValueDirectFixed(cUnit, rlArray, rArray); // Reload array
1478 loadValueDirectFixed(cUnit, rlIndex, rIndex); // Reload index
1479 loadValueDirectFixed(cUnit, rlSrc, rValue); // Reload value
1480 rArrayClass = INVALID_REG;
buzbee31a4a6f2012-02-28 15:36:15 -08001481
Bill Buzbeea114add2012-05-03 15:00:40 -07001482 // Branch here if value to be stored == null
1483 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
1484 null_value_check->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001485
Ian Rogersb41b33b2012-03-20 14:22:54 -07001486#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001487 // make an extra temp available for card mark below
1488 oatFreeTemp(cUnit, rARG1);
buzbee408ad162012-06-06 16:45:18 -07001489 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001490 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
buzbee408ad162012-06-06 16:45:18 -07001491 genRegMemCheck(cUnit, kCondUge, rIndex, rArray, lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001492 }
buzbee408ad162012-06-06 16:45:18 -07001493 storeBaseIndexedDisp(cUnit, rArray, rIndex, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -07001494 dataOffset, rValue, INVALID_REG, kWord, INVALID_SREG);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001495#else
buzbee408ad162012-06-06 16:45:18 -07001496 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001497 int regLen = INVALID_REG;
1498 if (needsRangeCheck) {
1499 regLen = rARG1;
buzbeef1f86362012-07-10 15:18:31 -07001500 loadWordDisp(cUnit, rArray, lenOffset, regLen); // Get len
Bill Buzbeea114add2012-05-03 15:00:40 -07001501 }
1502 /* rPtr -> array data */
1503 int rPtr = oatAllocTemp(cUnit);
1504 opRegRegImm(cUnit, kOpAdd, rPtr, rArray, dataOffset);
1505 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001506 genRegRegCheck(cUnit, kCondCs, rIndex, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001507 }
1508 storeBaseIndexed(cUnit, rPtr, rIndex, rValue, scale, kWord);
1509 oatFreeTemp(cUnit, rPtr);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001510#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001511 oatFreeTemp(cUnit, rIndex);
1512 markGCCard(cUnit, rValue, rArray);
buzbee31a4a6f2012-02-28 15:36:15 -08001513}
1514
1515/*
1516 * Generate array load
1517 */
buzbee408ad162012-06-06 16:45:18 -07001518void genArrayGet(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001519 RegLocation rlArray, RegLocation rlIndex,
1520 RegLocation rlDest, int scale)
1521{
Bill Buzbeea114add2012-05-03 15:00:40 -07001522 RegisterClass regClass = oatRegClassBySize(size);
1523 int lenOffset = Array::LengthOffset().Int32Value();
1524 int dataOffset;
1525 RegLocation rlResult;
1526 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1527 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001528
Bill Buzbeea114add2012-05-03 15:00:40 -07001529 if (size == kLong || size == kDouble) {
1530 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1531 } else {
1532 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1533 }
buzbee31a4a6f2012-02-28 15:36:15 -08001534
Bill Buzbeea114add2012-05-03 15:00:40 -07001535 /* null object? */
buzbee408ad162012-06-06 16:45:18 -07001536 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001537
Ian Rogersb5d09b22012-03-06 22:14:17 -08001538#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07001539 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001540 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1541 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
buzbee408ad162012-06-06 16:45:18 -07001542 lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001543 }
1544 if ((size == kLong) || (size == kDouble)) {
jeffhao3f9ace82012-05-25 11:25:36 -07001545 int regAddr = oatAllocTemp(cUnit);
1546 newLIR5(cUnit, kX86Lea32RA, regAddr, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset);
1547 oatFreeTemp(cUnit, rlArray.lowReg);
1548 oatFreeTemp(cUnit, rlIndex.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001549 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee408ad162012-06-06 16:45:18 -07001550 loadBaseIndexedDisp(cUnit, regAddr, INVALID_REG, 0, 0, rlResult.lowReg,
jeffhao21e12712012-05-25 19:06:18 -07001551 rlResult.highReg, size, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001552 storeValueWide(cUnit, rlDest, rlResult);
1553 } else {
1554 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001555
buzbee408ad162012-06-06 16:45:18 -07001556 loadBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
Bill Buzbeea114add2012-05-03 15:00:40 -07001557 dataOffset, rlResult.lowReg, INVALID_REG, size,
1558 INVALID_SREG);
Ian Rogersb5d09b22012-03-06 22:14:17 -08001559
Bill Buzbeea114add2012-05-03 15:00:40 -07001560 storeValue(cUnit, rlDest, rlResult);
1561 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001562#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001563 int regPtr = oatAllocTemp(cUnit);
buzbee408ad162012-06-06 16:45:18 -07001564 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001565 int regLen = INVALID_REG;
1566 if (needsRangeCheck) {
1567 regLen = oatAllocTemp(cUnit);
1568 /* Get len */
1569 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1570 }
1571 /* regPtr -> array data */
1572 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1573 oatFreeTemp(cUnit, rlArray.lowReg);
1574 if ((size == kLong) || (size == kDouble)) {
1575 if (scale) {
1576 int rNewIndex = oatAllocTemp(cUnit);
1577 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1578 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1579 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001580 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001581 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001582 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001583 oatFreeTemp(cUnit, rlIndex.lowReg);
1584 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1585
1586 if (needsRangeCheck) {
1587 // TODO: change kCondCS to a more meaningful name, is the sense of
1588 // carry-set/clear flipped?
buzbee408ad162012-06-06 16:45:18 -07001589 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001590 oatFreeTemp(cUnit, regLen);
1591 }
1592 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1593
1594 oatFreeTemp(cUnit, regPtr);
1595 storeValueWide(cUnit, rlDest, rlResult);
1596 } else {
1597 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1598
1599 if (needsRangeCheck) {
1600 // TODO: change kCondCS to a more meaningful name, is the sense of
1601 // carry-set/clear flipped?
buzbee408ad162012-06-06 16:45:18 -07001602 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001603 oatFreeTemp(cUnit, regLen);
1604 }
1605 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1606 scale, size);
1607
1608 oatFreeTemp(cUnit, regPtr);
1609 storeValue(cUnit, rlDest, rlResult);
1610 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001611#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001612}
1613
1614/*
1615 * Generate array store
1616 *
1617 */
buzbee408ad162012-06-06 16:45:18 -07001618void genArrayPut(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001619 RegLocation rlArray, RegLocation rlIndex,
1620 RegLocation rlSrc, int scale)
1621{
Bill Buzbeea114add2012-05-03 15:00:40 -07001622 RegisterClass regClass = oatRegClassBySize(size);
1623 int lenOffset = Array::LengthOffset().Int32Value();
1624 int dataOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001625
Bill Buzbeea114add2012-05-03 15:00:40 -07001626 if (size == kLong || size == kDouble) {
1627 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1628 } else {
1629 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1630 }
buzbee31a4a6f2012-02-28 15:36:15 -08001631
Bill Buzbeea114add2012-05-03 15:00:40 -07001632 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1633 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ian Rogersb41b33b2012-03-20 14:22:54 -07001634#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001635 int regPtr;
1636 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1637 oatClobber(cUnit, rlArray.lowReg);
1638 regPtr = rlArray.lowReg;
1639 } else {
1640 regPtr = oatAllocTemp(cUnit);
1641 opRegCopy(cUnit, regPtr, rlArray.lowReg);
1642 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001643#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001644
Bill Buzbeea114add2012-05-03 15:00:40 -07001645 /* null object? */
buzbee408ad162012-06-06 16:45:18 -07001646 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001647
Ian Rogersb41b33b2012-03-20 14:22:54 -07001648#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07001649 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001650 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
1651 genRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
buzbee408ad162012-06-06 16:45:18 -07001652 lenOffset, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001653 }
1654 if ((size == kLong) || (size == kDouble)) {
1655 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1656 } else {
1657 rlSrc = loadValue(cUnit, rlSrc, regClass);
1658 }
jeffhao703f2cd2012-07-13 17:25:52 -07001659 // If the src reg can't be byte accessed, move it to a temp first.
1660 if ((size == kSignedByte || size == kUnsignedByte) && rlSrc.lowReg >= 4) {
1661 int temp = oatAllocTemp(cUnit);
1662 opRegCopy(cUnit, temp, rlSrc.lowReg);
1663 storeBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
1664 dataOffset, temp, INVALID_REG, size,
1665 INVALID_SREG);
1666 } else {
1667 storeBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
1668 dataOffset, rlSrc.lowReg, rlSrc.highReg, size,
1669 INVALID_SREG);
1670 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001671#else
buzbee408ad162012-06-06 16:45:18 -07001672 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
Bill Buzbeea114add2012-05-03 15:00:40 -07001673 int regLen = INVALID_REG;
1674 if (needsRangeCheck) {
1675 regLen = oatAllocTemp(cUnit);
1676 //NOTE: max live temps(4) here.
1677 /* Get len */
1678 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1679 }
1680 /* regPtr -> array data */
1681 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1682 /* at this point, regPtr points to array, 2 live temps */
1683 if ((size == kLong) || (size == kDouble)) {
1684 //TUNING: specific wide routine that can handle fp regs
1685 if (scale) {
1686 int rNewIndex = oatAllocTemp(cUnit);
1687 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1688 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1689 oatFreeTemp(cUnit, rNewIndex);
buzbee31a4a6f2012-02-28 15:36:15 -08001690 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001691 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001692 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001693 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1694
1695 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001696 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001697 oatFreeTemp(cUnit, regLen);
1698 }
1699
jeffhao41005dd2012-05-09 17:58:52 -07001700 storeBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001701
1702 oatFreeTemp(cUnit, regPtr);
1703 } else {
1704 rlSrc = loadValue(cUnit, rlSrc, regClass);
1705 if (needsRangeCheck) {
buzbee408ad162012-06-06 16:45:18 -07001706 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
Bill Buzbeea114add2012-05-03 15:00:40 -07001707 oatFreeTemp(cUnit, regLen);
1708 }
1709 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1710 scale, size);
1711 }
Ian Rogersb41b33b2012-03-20 14:22:54 -07001712#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001713}
1714
buzbee408ad162012-06-06 16:45:18 -07001715void genLong3Addr(CompilationUnit* cUnit, OpKind firstOp,
buzbee31a4a6f2012-02-28 15:36:15 -08001716 OpKind secondOp, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001717 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001718{
Bill Buzbeea114add2012-05-03 15:00:40 -07001719 RegLocation rlResult;
buzbee31a4a6f2012-02-28 15:36:15 -08001720#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001721 /*
1722 * NOTE: This is the one place in the code in which we might have
1723 * as many as six live temporary registers. There are 5 in the normal
1724 * set for Arm. Until we have spill capabilities, temporarily add
1725 * lr to the temp set. It is safe to do this locally, but note that
1726 * lr is used explicitly elsewhere in the code generator and cannot
1727 * normally be used as a general temp register.
1728 */
1729 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1730 oatFreeTemp(cUnit, rLR); // and make it available
buzbee31a4a6f2012-02-28 15:36:15 -08001731#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001732 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1733 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1734 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1735 // The longs may overlap - use intermediate temp if so
1736 if (rlResult.lowReg == rlSrc1.highReg) {
1737 int tReg = oatAllocTemp(cUnit);
1738 opRegCopy(cUnit, tReg, rlSrc1.highReg);
1739 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1740 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg, rlSrc2.highReg);
1741 oatFreeTemp(cUnit, tReg);
1742 } else {
1743 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1744 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1745 rlSrc2.highReg);
1746 }
1747 /*
1748 * NOTE: If rlDest refers to a frame variable in a large frame, the
1749 * following storeValueWide might need to allocate a temp register.
1750 * To further work around the lack of a spill capability, explicitly
1751 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1752 * Remove when spill is functional.
1753 */
1754 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1755 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1756 storeValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001757#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001758 oatClobber(cUnit, rLR);
1759 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee31a4a6f2012-02-28 15:36:15 -08001760#endif
1761}
1762
1763
buzbee408ad162012-06-06 16:45:18 -07001764bool genShiftOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001765 RegLocation rlSrc1, RegLocation rlShift)
1766{
Bill Buzbeea114add2012-05-03 15:00:40 -07001767 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001768
buzbee408ad162012-06-06 16:45:18 -07001769 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001770 case Instruction::SHL_LONG:
1771 case Instruction::SHL_LONG_2ADDR:
1772 funcOffset = ENTRYPOINT_OFFSET(pShlLong);
1773 break;
1774 case Instruction::SHR_LONG:
1775 case Instruction::SHR_LONG_2ADDR:
1776 funcOffset = ENTRYPOINT_OFFSET(pShrLong);
1777 break;
1778 case Instruction::USHR_LONG:
1779 case Instruction::USHR_LONG_2ADDR:
1780 funcOffset = ENTRYPOINT_OFFSET(pUshrLong);
1781 break;
1782 default:
1783 LOG(FATAL) << "Unexpected case";
1784 return true;
1785 }
1786 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee8320f382012-09-11 16:29:42 -07001787 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07001788 RegLocation rlResult = oatGetReturnWide(cUnit, false);
1789 storeValueWide(cUnit, rlDest, rlResult);
1790 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001791}
1792
1793
buzbee408ad162012-06-06 16:45:18 -07001794bool genArithOpInt(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001795 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001796{
Bill Buzbeea114add2012-05-03 15:00:40 -07001797 OpKind op = kOpBkpt;
jeffhao4f8f04a2012-10-02 18:10:35 -07001798 bool isDivRem = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001799 bool checkZero = false;
1800 bool unary = false;
1801 RegLocation rlResult;
1802 bool shiftOp = false;
buzbee408ad162012-06-06 16:45:18 -07001803 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001804 case Instruction::NEG_INT:
1805 op = kOpNeg;
1806 unary = true;
1807 break;
1808 case Instruction::NOT_INT:
1809 op = kOpMvn;
1810 unary = true;
1811 break;
1812 case Instruction::ADD_INT:
1813 case Instruction::ADD_INT_2ADDR:
1814 op = kOpAdd;
1815 break;
1816 case Instruction::SUB_INT:
1817 case Instruction::SUB_INT_2ADDR:
1818 op = kOpSub;
1819 break;
1820 case Instruction::MUL_INT:
1821 case Instruction::MUL_INT_2ADDR:
1822 op = kOpMul;
1823 break;
1824 case Instruction::DIV_INT:
1825 case Instruction::DIV_INT_2ADDR:
1826 checkZero = true;
1827 op = kOpDiv;
jeffhao4f8f04a2012-10-02 18:10:35 -07001828 isDivRem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001829 break;
1830 /* NOTE: returns in rARG1 */
1831 case Instruction::REM_INT:
1832 case Instruction::REM_INT_2ADDR:
1833 checkZero = true;
1834 op = kOpRem;
jeffhao4f8f04a2012-10-02 18:10:35 -07001835 isDivRem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001836 break;
1837 case Instruction::AND_INT:
1838 case Instruction::AND_INT_2ADDR:
1839 op = kOpAnd;
1840 break;
1841 case Instruction::OR_INT:
1842 case Instruction::OR_INT_2ADDR:
1843 op = kOpOr;
1844 break;
1845 case Instruction::XOR_INT:
1846 case Instruction::XOR_INT_2ADDR:
1847 op = kOpXor;
1848 break;
1849 case Instruction::SHL_INT:
1850 case Instruction::SHL_INT_2ADDR:
1851 shiftOp = true;
1852 op = kOpLsl;
1853 break;
1854 case Instruction::SHR_INT:
1855 case Instruction::SHR_INT_2ADDR:
1856 shiftOp = true;
1857 op = kOpAsr;
1858 break;
1859 case Instruction::USHR_INT:
1860 case Instruction::USHR_INT_2ADDR:
1861 shiftOp = true;
1862 op = kOpLsr;
1863 break;
1864 default:
1865 LOG(FATAL) << "Invalid word arith op: " <<
buzbee408ad162012-06-06 16:45:18 -07001866 (int)opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001867 }
jeffhao4f8f04a2012-10-02 18:10:35 -07001868 if (!isDivRem) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001869 if (unary) {
1870 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1871 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1872 opRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001873 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001874 if (shiftOp) {
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001875#if !defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07001876 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1877 int tReg = oatAllocTemp(cUnit);
1878 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001879#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001880 // X86 doesn't require masking and must use ECX
1881 loadValueDirectFixed(cUnit, rlSrc2, rCX);
1882 int tReg = rCX;
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07001883#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001884 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1885 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1886 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, tReg);
1887 oatFreeTemp(cUnit, tReg);
1888 } else {
1889 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1890 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1891 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1892 opRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1893 }
buzbee31a4a6f2012-02-28 15:36:15 -08001894 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001895 storeValue(cUnit, rlDest, rlResult);
1896 } else {
jeffhao4f8f04a2012-10-02 18:10:35 -07001897#if defined(TARGET_MIPS)
jeffhao4eb68ed2012-10-17 16:41:07 -07001898 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
jeffhao4f8f04a2012-10-02 18:10:35 -07001899 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1900 if (checkZero) {
jeffhao4eb68ed2012-10-17 16:41:07 -07001901 genImmedCheck(cUnit, kCondEq, rlSrc2.lowReg, 0, kThrowDivZero);
jeffhao4f8f04a2012-10-02 18:10:35 -07001902 }
1903 newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc1.lowReg, rlSrc2.lowReg);
1904 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1905 if (op == kOpDiv) {
1906 newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
1907 } else {
1908 newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
1909 }
1910#else
1911 int funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
Bill Buzbeea114add2012-05-03 15:00:40 -07001912 RegLocation rlResult;
1913 oatFlushAllRegs(cUnit); /* Send everything to home location */
1914 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
jeffhao4f8f04a2012-10-02 18:10:35 -07001915#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001916 int rTgt = loadHelper(cUnit, funcOffset);
1917#endif
1918 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1919 if (checkZero) {
buzbee408ad162012-06-06 16:45:18 -07001920 genImmedCheck(cUnit, kCondEq, rARG1, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07001921 }
buzbee8320f382012-09-11 16:29:42 -07001922 // NOTE: callout here is not a safepoint
jeffhao4f8f04a2012-10-02 18:10:35 -07001923#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001924 opReg(cUnit, kOpBlx, rTgt);
1925 oatFreeTemp(cUnit, rTgt);
1926#else
1927 opThreadMem(cUnit, kOpBlx, funcOffset);
1928#endif
jeffhao4f8f04a2012-10-02 18:10:35 -07001929 if (op == kOpDiv)
Bill Buzbeea114add2012-05-03 15:00:40 -07001930 rlResult = oatGetReturn(cUnit, false);
1931 else
1932 rlResult = oatGetReturnAlt(cUnit);
jeffhao4f8f04a2012-10-02 18:10:35 -07001933#endif
jeffhao4eb68ed2012-10-17 16:41:07 -07001934 storeValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001935 }
1936 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001937}
1938
1939/*
1940 * The following are the first-level codegen routines that analyze the format
1941 * of each bytecode then either dispatch special purpose codegen routines
1942 * or produce corresponding Thumb instructions directly.
1943 */
1944
1945bool isPowerOfTwo(int x)
1946{
Bill Buzbeea114add2012-05-03 15:00:40 -07001947 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001948}
1949
1950// Returns true if no more than two bits are set in 'x'.
1951bool isPopCountLE2(unsigned int x)
1952{
Bill Buzbeea114add2012-05-03 15:00:40 -07001953 x &= x - 1;
1954 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001955}
1956
1957// Returns the index of the lowest set bit in 'x'.
1958int lowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001959 int bit_posn = 0;
1960 while ((x & 0xf) == 0) {
1961 bit_posn += 4;
1962 x >>= 4;
1963 }
1964 while ((x & 1) == 0) {
1965 bit_posn++;
1966 x >>= 1;
1967 }
1968 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001969}
1970
1971// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1972// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001973bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
Bill Buzbeea114add2012-05-03 15:00:40 -07001974 RegLocation rlSrc, RegLocation rlDest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001975{
buzbeef3aac972012-04-11 16:33:36 -07001976#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07001977 // No divide instruction for Arm, so check for more special cases
1978 if (lit < 2) {
1979 return false;
1980 }
1981 if (!isPowerOfTwo(lit)) {
1982 return smallLiteralDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit);
1983 }
buzbeef3aac972012-04-11 16:33:36 -07001984#else
Bill Buzbeea114add2012-05-03 15:00:40 -07001985 if (lit < 2 || !isPowerOfTwo(lit)) {
1986 return false;
1987 }
buzbeef3aac972012-04-11 16:33:36 -07001988#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07001989 int k = lowestSetBit(lit);
1990 if (k >= 30) {
1991 // Avoid special cases.
1992 return false;
1993 }
1994 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1995 dalvikOpcode == Instruction::DIV_INT_LIT16);
1996 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1997 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1998 if (div) {
1999 int tReg = oatAllocTemp(cUnit);
2000 if (lit == 2) {
2001 // Division by 2 is by far the most common division by constant.
2002 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
2003 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
2004 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08002005 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07002006 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
2007 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
2008 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
2009 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08002010 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002011 } else {
2012 int tReg1 = oatAllocTemp(cUnit);
2013 int tReg2 = oatAllocTemp(cUnit);
2014 if (lit == 2) {
2015 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
2016 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
2017 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit -1);
2018 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
2019 } else {
2020 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
2021 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
2022 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
2023 opRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit - 1);
2024 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
2025 }
2026 }
2027 storeValue(cUnit, rlDest, rlResult);
2028 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08002029}
2030
2031void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
2032 RegLocation rlResult, int lit,
2033 int firstBit, int secondBit)
2034{
buzbee0398c422012-03-02 15:22:47 -08002035#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002036 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
2037 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08002038#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002039 int tReg = oatAllocTemp(cUnit);
2040 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
2041 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
2042 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08002043#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002044 if (firstBit != 0) {
2045 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
2046 }
buzbee31a4a6f2012-02-28 15:36:15 -08002047}
2048
2049// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
2050// and store the result in 'rlDest'.
2051bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
2052 RegLocation rlDest, int lit)
2053{
Bill Buzbeea114add2012-05-03 15:00:40 -07002054 // Can we simplify this multiplication?
2055 bool powerOfTwo = false;
2056 bool popCountLE2 = false;
2057 bool powerOfTwoMinusOne = false;
2058 if (lit < 2) {
2059 // Avoid special cases.
2060 return false;
2061 } else if (isPowerOfTwo(lit)) {
2062 powerOfTwo = true;
2063 } else if (isPopCountLE2(lit)) {
2064 popCountLE2 = true;
2065 } else if (isPowerOfTwo(lit + 1)) {
2066 powerOfTwoMinusOne = true;
2067 } else {
2068 return false;
2069 }
2070 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2071 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2072 if (powerOfTwo) {
2073 // Shift.
2074 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
2075 lowestSetBit(lit));
2076 } else if (popCountLE2) {
2077 // Shift and add and shift.
2078 int firstBit = lowestSetBit(lit);
2079 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
2080 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
2081 firstBit, secondBit);
2082 } else {
2083 // Reverse subtract: (src << (shift + 1)) - src.
2084 DCHECK(powerOfTwoMinusOne);
2085 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
2086 int tReg = oatAllocTemp(cUnit);
2087 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
2088 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2089 }
2090 storeValue(cUnit, rlDest, rlResult);
2091 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08002092}
2093
buzbee408ad162012-06-06 16:45:18 -07002094bool genArithOpIntLit(CompilationUnit* cUnit, Instruction::Code opcode,
2095 RegLocation rlDest, RegLocation rlSrc, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08002096{
Bill Buzbeea114add2012-05-03 15:00:40 -07002097 RegLocation rlResult;
2098 OpKind op = (OpKind)0; /* Make gcc happy */
2099 int shiftOp = false;
2100 bool isDiv = false;
buzbee31a4a6f2012-02-28 15:36:15 -08002101
buzbee408ad162012-06-06 16:45:18 -07002102 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002103 case Instruction::RSUB_INT_LIT8:
2104 case Instruction::RSUB_INT: {
2105 int tReg;
2106 //TUNING: add support for use of Arm rsub op
2107 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2108 tReg = oatAllocTemp(cUnit);
2109 loadConstant(cUnit, tReg, lit);
2110 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2111 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
2112 storeValue(cUnit, rlDest, rlResult);
2113 return false;
2114 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002115 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002116
2117 case Instruction::ADD_INT_LIT8:
2118 case Instruction::ADD_INT_LIT16:
2119 op = kOpAdd;
2120 break;
2121 case Instruction::MUL_INT_LIT8:
2122 case Instruction::MUL_INT_LIT16: {
2123 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
2124 return false;
2125 }
2126 op = kOpMul;
2127 break;
buzbee31a4a6f2012-02-28 15:36:15 -08002128 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002129 case Instruction::AND_INT_LIT8:
2130 case Instruction::AND_INT_LIT16:
2131 op = kOpAnd;
2132 break;
2133 case Instruction::OR_INT_LIT8:
2134 case Instruction::OR_INT_LIT16:
2135 op = kOpOr;
2136 break;
2137 case Instruction::XOR_INT_LIT8:
2138 case Instruction::XOR_INT_LIT16:
2139 op = kOpXor;
2140 break;
2141 case Instruction::SHL_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07002142 case Instruction::SHL_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07002143 lit &= 31;
2144 shiftOp = true;
2145 op = kOpLsl;
2146 break;
2147 case Instruction::SHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07002148 case Instruction::SHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07002149 lit &= 31;
2150 shiftOp = true;
2151 op = kOpAsr;
2152 break;
2153 case Instruction::USHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07002154 case Instruction::USHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07002155 lit &= 31;
2156 shiftOp = true;
2157 op = kOpLsr;
2158 break;
2159
2160 case Instruction::DIV_INT_LIT8:
2161 case Instruction::DIV_INT_LIT16:
2162 case Instruction::REM_INT_LIT8:
jeffhao4f8f04a2012-10-02 18:10:35 -07002163 case Instruction::REM_INT_LIT16: {
Bill Buzbeea114add2012-05-03 15:00:40 -07002164 if (lit == 0) {
buzbee408ad162012-06-06 16:45:18 -07002165 genImmedCheck(cUnit, kCondAl, 0, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002166 return false;
2167 }
buzbee408ad162012-06-06 16:45:18 -07002168 if (handleEasyDivide(cUnit, opcode, rlSrc, rlDest, lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002169 return false;
2170 }
buzbee408ad162012-06-06 16:45:18 -07002171 if ((opcode == Instruction::DIV_INT_LIT8) ||
2172 (opcode == Instruction::DIV_INT_LIT16)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002173 isDiv = true;
2174 } else {
2175 isDiv = false;
2176 }
jeffhao4f8f04a2012-10-02 18:10:35 -07002177#if defined(TARGET_MIPS)
2178 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2179 int tReg = oatAllocTemp(cUnit);
2180 newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit);
2181 newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc.lowReg, tReg);
2182 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2183 if (isDiv) {
2184 newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
2185 } else {
2186 newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
2187 }
2188 oatFreeTemp(cUnit, tReg);
2189#else
2190 oatFlushAllRegs(cUnit); /* Everything to home location */
2191 loadValueDirectFixed(cUnit, rlSrc, rARG0);
2192 oatClobber(cUnit, rARG0);
2193 int funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee8320f382012-09-11 16:29:42 -07002194 callRuntimeHelperRegImm(cUnit, funcOffset, rARG0, lit, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07002195 if (isDiv)
2196 rlResult = oatGetReturn(cUnit, false);
2197 else
2198 rlResult = oatGetReturnAlt(cUnit);
jeffhao4f8f04a2012-10-02 18:10:35 -07002199#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002200 storeValue(cUnit, rlDest, rlResult);
2201 return false;
2202 break;
jeffhao4f8f04a2012-10-02 18:10:35 -07002203 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002204 default:
2205 return true;
2206 }
2207 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2208 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2209 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2210 if (shiftOp && (lit == 0)) {
2211 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2212 } else {
2213 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2214 }
2215 storeValue(cUnit, rlDest, rlResult);
2216 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002217}
2218
buzbee408ad162012-06-06 16:45:18 -07002219bool genArithOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07002220 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08002221{
Bill Buzbeea114add2012-05-03 15:00:40 -07002222 RegLocation rlResult;
2223 OpKind firstOp = kOpBkpt;
2224 OpKind secondOp = kOpBkpt;
2225 bool callOut = false;
2226 bool checkZero = false;
2227 int funcOffset;
2228 int retReg = rRET0;
buzbee31a4a6f2012-02-28 15:36:15 -08002229
buzbee408ad162012-06-06 16:45:18 -07002230 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002231 case Instruction::NOT_LONG:
2232 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
2233 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2234 // Check for destructive overlap
2235 if (rlResult.lowReg == rlSrc2.highReg) {
2236 int tReg = oatAllocTemp(cUnit);
2237 opRegCopy(cUnit, tReg, rlSrc2.highReg);
2238 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2239 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2240 oatFreeTemp(cUnit, tReg);
2241 } else {
2242 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2243 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
2244 }
2245 storeValueWide(cUnit, rlDest, rlResult);
2246 return false;
2247 break;
2248 case Instruction::ADD_LONG:
2249 case Instruction::ADD_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002250#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002251 return genAddLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeec5159d52012-03-03 11:48:39 -08002252#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002253 firstOp = kOpAdd;
2254 secondOp = kOpAdc;
2255 break;
buzbeec5159d52012-03-03 11:48:39 -08002256#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002257 case Instruction::SUB_LONG:
2258 case Instruction::SUB_LONG_2ADDR:
Ian Rogers7caad772012-03-30 01:07:54 -07002259#if defined(TARGET_MIPS) || defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002260 return genSubLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002261#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002262 firstOp = kOpSub;
2263 secondOp = kOpSbc;
2264 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002265#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002266 case Instruction::MUL_LONG:
2267 case Instruction::MUL_LONG_2ADDR:
2268 callOut = true;
2269 retReg = rRET0;
2270 funcOffset = ENTRYPOINT_OFFSET(pLmul);
2271 break;
2272 case Instruction::DIV_LONG:
2273 case Instruction::DIV_LONG_2ADDR:
2274 callOut = true;
2275 checkZero = true;
2276 retReg = rRET0;
jeffhao644d5312012-05-03 19:04:49 -07002277 funcOffset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002278 break;
2279 case Instruction::REM_LONG:
2280 case Instruction::REM_LONG_2ADDR:
2281 callOut = true;
2282 checkZero = true;
jeffhao644d5312012-05-03 19:04:49 -07002283 funcOffset = ENTRYPOINT_OFFSET(pLdivmod);
Ian Rogers55bd45f2012-04-04 17:31:20 -07002284#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002285 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
2286 retReg = rARG2;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002287#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002288 retReg = rRET0;
Ian Rogers55bd45f2012-04-04 17:31:20 -07002289#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002290 break;
2291 case Instruction::AND_LONG_2ADDR:
2292 case Instruction::AND_LONG:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002293#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002294 return genAndLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002295#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002296 firstOp = kOpAnd;
2297 secondOp = kOpAnd;
2298 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002299#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002300 case Instruction::OR_LONG:
2301 case Instruction::OR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002302#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002303 return genOrLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002304#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002305 firstOp = kOpOr;
2306 secondOp = kOpOr;
2307 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002308#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002309 case Instruction::XOR_LONG:
2310 case Instruction::XOR_LONG_2ADDR:
Ian Rogersc6f3bb82012-03-21 20:40:33 -07002311#if defined(TARGET_X86)
buzbee408ad162012-06-06 16:45:18 -07002312 return genXorLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ian Rogers7caad772012-03-30 01:07:54 -07002313#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002314 firstOp = kOpXor;
2315 secondOp = kOpXor;
2316 break;
Ian Rogers7caad772012-03-30 01:07:54 -07002317#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002318 case Instruction::NEG_LONG: {
buzbee408ad162012-06-06 16:45:18 -07002319 return genNegLong(cUnit, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002320 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002321 default:
2322 LOG(FATAL) << "Invalid long arith op";
2323 }
2324 if (!callOut) {
buzbee408ad162012-06-06 16:45:18 -07002325 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -07002326 } else {
2327 oatFlushAllRegs(cUnit); /* Send everything to home location */
2328 if (checkZero) {
2329 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2330#if !defined(TARGET_X86)
2331 int rTgt = loadHelper(cUnit, funcOffset);
2332#endif
2333 int tReg = oatAllocTemp(cUnit);
2334#if defined(TARGET_ARM)
2335 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
2336 oatFreeTemp(cUnit, tReg);
buzbee408ad162012-06-06 16:45:18 -07002337 genCheck(cUnit, kCondEq, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002338#else
2339 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
2340#endif
buzbee408ad162012-06-06 16:45:18 -07002341 genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07002342 oatFreeTemp(cUnit, tReg);
2343 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
buzbee8320f382012-09-11 16:29:42 -07002344 // NOTE: callout here is not a safepoint
Bill Buzbeea114add2012-05-03 15:00:40 -07002345#if !defined(TARGET_X86)
2346 opReg(cUnit, kOpBlx, rTgt);
2347 oatFreeTemp(cUnit, rTgt);
2348#else
2349 opThreadMem(cUnit, kOpBlx, funcOffset);
2350#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002351 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07002352 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset,
buzbee8320f382012-09-11 16:29:42 -07002353 rlSrc1, rlSrc2, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002354 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002355 // Adjust return regs in to handle case of rem returning rARG2/rARG3
2356 if (retReg == rRET0)
2357 rlResult = oatGetReturnWide(cUnit, false);
2358 else
2359 rlResult = oatGetReturnWideAlt(cUnit);
2360 storeValueWide(cUnit, rlDest, rlResult);
2361 }
2362 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002363}
2364
buzbee408ad162012-06-06 16:45:18 -07002365bool genConversionCall(CompilationUnit* cUnit, int funcOffset,
2366 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002367{
Bill Buzbeea114add2012-05-03 15:00:40 -07002368 /*
2369 * Don't optimize the register usage since it calls out to support
2370 * functions
2371 */
Bill Buzbeea114add2012-05-03 15:00:40 -07002372 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee408ad162012-06-06 16:45:18 -07002373 if (rlSrc.wide) {
jeffhao30a33172012-10-22 18:16:22 -07002374 loadValueDirectWideFixed(cUnit, rlSrc, rlSrc.fp ? rFARG0 : rARG0, rlSrc.fp ? rFARG1 : rARG1);
buzbee408ad162012-06-06 16:45:18 -07002375 } else {
jeffhao30a33172012-10-22 18:16:22 -07002376 loadValueDirectFixed(cUnit, rlSrc, rlSrc.fp ? rFARG0 : rARG0);
Bill Buzbeea114add2012-05-03 15:00:40 -07002377 }
buzbee8320f382012-09-11 16:29:42 -07002378 callRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc, false);
buzbee408ad162012-06-06 16:45:18 -07002379 if (rlDest.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002380 RegLocation rlResult;
Bill Buzbeea114add2012-05-03 15:00:40 -07002381 rlResult = oatGetReturnWide(cUnit, rlDest.fp);
2382 storeValueWide(cUnit, rlDest, rlResult);
buzbee408ad162012-06-06 16:45:18 -07002383 } else {
2384 RegLocation rlResult;
2385 rlResult = oatGetReturn(cUnit, rlDest.fp);
2386 storeValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002387 }
2388 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002389}
2390
2391void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002392bool genArithOpFloatPortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002393 RegLocation rlDest, RegLocation rlSrc1,
2394 RegLocation rlSrc2)
2395{
Bill Buzbeea114add2012-05-03 15:00:40 -07002396 RegLocation rlResult;
2397 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002398
buzbee408ad162012-06-06 16:45:18 -07002399 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002400 case Instruction::ADD_FLOAT_2ADDR:
2401 case Instruction::ADD_FLOAT:
2402 funcOffset = ENTRYPOINT_OFFSET(pFadd);
2403 break;
2404 case Instruction::SUB_FLOAT_2ADDR:
2405 case Instruction::SUB_FLOAT:
2406 funcOffset = ENTRYPOINT_OFFSET(pFsub);
2407 break;
2408 case Instruction::DIV_FLOAT_2ADDR:
2409 case Instruction::DIV_FLOAT:
2410 funcOffset = ENTRYPOINT_OFFSET(pFdiv);
2411 break;
2412 case Instruction::MUL_FLOAT_2ADDR:
2413 case Instruction::MUL_FLOAT:
2414 funcOffset = ENTRYPOINT_OFFSET(pFmul);
2415 break;
2416 case Instruction::REM_FLOAT_2ADDR:
2417 case Instruction::REM_FLOAT:
2418 funcOffset = ENTRYPOINT_OFFSET(pFmodf);
2419 break;
2420 case Instruction::NEG_FLOAT: {
2421 genNegFloat(cUnit, rlDest, rlSrc1);
2422 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002423 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002424 default:
2425 return true;
2426 }
2427 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee8320f382012-09-11 16:29:42 -07002428 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07002429 rlResult = oatGetReturn(cUnit, true);
2430 storeValue(cUnit, rlDest, rlResult);
2431 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002432}
2433
2434void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
buzbee408ad162012-06-06 16:45:18 -07002435bool genArithOpDoublePortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002436 RegLocation rlDest, RegLocation rlSrc1,
2437 RegLocation rlSrc2)
2438{
Bill Buzbeea114add2012-05-03 15:00:40 -07002439 RegLocation rlResult;
2440 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002441
buzbee408ad162012-06-06 16:45:18 -07002442 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002443 case Instruction::ADD_DOUBLE_2ADDR:
2444 case Instruction::ADD_DOUBLE:
2445 funcOffset = ENTRYPOINT_OFFSET(pDadd);
2446 break;
2447 case Instruction::SUB_DOUBLE_2ADDR:
2448 case Instruction::SUB_DOUBLE:
2449 funcOffset = ENTRYPOINT_OFFSET(pDsub);
2450 break;
2451 case Instruction::DIV_DOUBLE_2ADDR:
2452 case Instruction::DIV_DOUBLE:
2453 funcOffset = ENTRYPOINT_OFFSET(pDdiv);
2454 break;
2455 case Instruction::MUL_DOUBLE_2ADDR:
2456 case Instruction::MUL_DOUBLE:
2457 funcOffset = ENTRYPOINT_OFFSET(pDmul);
2458 break;
2459 case Instruction::REM_DOUBLE_2ADDR:
2460 case Instruction::REM_DOUBLE:
2461 funcOffset = ENTRYPOINT_OFFSET(pFmod);
2462 break;
2463 case Instruction::NEG_DOUBLE: {
2464 genNegDouble(cUnit, rlDest, rlSrc1);
2465 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002466 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002467 default:
2468 return true;
2469 }
2470 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee8320f382012-09-11 16:29:42 -07002471 callRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07002472 rlResult = oatGetReturnWide(cUnit, true);
2473 storeValueWide(cUnit, rlDest, rlResult);
2474 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002475}
2476
buzbee408ad162012-06-06 16:45:18 -07002477bool genConversionPortable(CompilationUnit* cUnit, Instruction::Code opcode,
2478 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002479{
buzbee31a4a6f2012-02-28 15:36:15 -08002480
Bill Buzbeea114add2012-05-03 15:00:40 -07002481 switch (opcode) {
2482 case Instruction::INT_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002483 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2f),
2484 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002485 case Instruction::FLOAT_TO_INT:
buzbee408ad162012-06-06 16:45:18 -07002486 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2iz),
2487 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002488 case Instruction::DOUBLE_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002489 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2f),
2490 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002491 case Instruction::FLOAT_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002492 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2d),
2493 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002494 case Instruction::INT_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002495 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2d),
2496 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002497 case Instruction::DOUBLE_TO_INT:
buzbee408ad162012-06-06 16:45:18 -07002498 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2iz),
2499 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002500 case Instruction::FLOAT_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -07002501 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2l),
2502 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002503 case Instruction::LONG_TO_FLOAT:
buzbee408ad162012-06-06 16:45:18 -07002504 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2f),
2505 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002506 case Instruction::DOUBLE_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -07002507 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2l),
2508 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002509 case Instruction::LONG_TO_DOUBLE:
buzbee408ad162012-06-06 16:45:18 -07002510 return genConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2d),
2511 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002512 default:
2513 return true;
2514 }
2515 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002516}
2517
2518/*
2519 * Generate callout to updateDebugger. Note that we're overloading
2520 * the use of rSUSPEND here. When the debugger is active, this
2521 * register holds the address of the update function. So, if it's
2522 * non-null, we call out to it.
2523 *
2524 * Note also that rRET0 and rRET1 must be preserved across this
2525 * code. This must be handled by the stub.
2526 */
2527void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2528{
Bill Buzbeea114add2012-05-03 15:00:40 -07002529 // Following DCHECK verifies that dPC is in range of single load immediate
2530 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2531 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2532 oatClobberCalleeSave(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002533#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002534 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
2535 opIT(cUnit, kArmCondNe, "T");
2536 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
buzbee8320f382012-09-11 16:29:42 -07002537 LIR* callInst = opReg(cUnit, kOpBlx, rSUSPEND);
2538 markSafepointPC(cUnit, callInst);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002539#elif defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002540 UNIMPLEMENTED(FATAL);
buzbee31a4a6f2012-02-28 15:36:15 -08002541#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002542 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
2543 loadConstant(cUnit, rARG2, offset);
buzbee8320f382012-09-11 16:29:42 -07002544 LIR* callInst = opReg(cUnit, kOpBlx, rSUSPEND);
2545 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -07002546 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
2547 branch->target = (LIR*)target;
buzbee31a4a6f2012-02-28 15:36:15 -08002548#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002549 oatFreeTemp(cUnit, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08002550}
2551
2552/* Check if we need to check for pending suspend request */
buzbee408ad162012-06-06 16:45:18 -07002553void genSuspendTest(CompilationUnit* cUnit, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -08002554{
buzbee408ad162012-06-06 16:45:18 -07002555 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002556 return;
2557 }
2558 oatFlushAllRegs(cUnit);
2559 if (cUnit->genDebugger) {
2560 // If generating code for the debugger, always check for suspension
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002561#if defined(TARGET_X86)
Bill Buzbeea114add2012-05-03 15:00:40 -07002562 UNIMPLEMENTED(FATAL);
Ian Rogers6cbb2bd2012-03-16 13:45:30 -07002563#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002564 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pTestSuspendFromCode));
buzbee8320f382012-09-11 16:29:42 -07002565 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
2566 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -07002567 // Refresh rSUSPEND
2568 loadWordDisp(cUnit, rSELF,
2569 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode),
2570 rSUSPEND);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002571#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002572 } else {
2573 LIR* branch = NULL;
buzbee31a4a6f2012-02-28 15:36:15 -08002574#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002575 // In non-debug case, only check periodically
2576 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2577 branch = opCondBranch(cUnit, kCondEq, NULL);
Ian Rogersb5d09b22012-03-06 22:14:17 -08002578#elif defined(TARGET_X86)
Ian Rogers474b6da2012-09-25 00:20:38 -07002579 newLIR2(cUnit, kX86Cmp16TI8, Thread::ThreadFlagsOffset().Int32Value(), 0);
Bill Buzbeea114add2012-05-03 15:00:40 -07002580 branch = opCondBranch(cUnit, kCondNe, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002581#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002582 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2583 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002584#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002585 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2586 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
buzbee408ad162012-06-06 16:45:18 -07002587 kPseudoSuspendTarget, (intptr_t)retLab, cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -07002588 branch->target = (LIR*)target;
2589 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
2590 }
buzbee31a4a6f2012-02-28 15:36:15 -08002591}
2592
buzbeefead2932012-03-30 14:02:01 -07002593/* Check if we need to check for pending suspend request */
buzbee408ad162012-06-06 16:45:18 -07002594void genSuspendTestAndBranch(CompilationUnit* cUnit, int optFlags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07002595{
buzbee408ad162012-06-06 16:45:18 -07002596 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002597 opUnconditionalBranch(cUnit, target);
2598 return;
2599 }
2600 if (cUnit->genDebugger) {
buzbee408ad162012-06-06 16:45:18 -07002601 genSuspendTest(cUnit, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -07002602 opUnconditionalBranch(cUnit, target);
2603 } else {
buzbeefead2932012-03-30 14:02:01 -07002604#if defined(TARGET_ARM)
Bill Buzbeea114add2012-05-03 15:00:40 -07002605 // In non-debug case, only check periodically
2606 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
2607 opCondBranch(cUnit, kCondNe, target);
buzbeefead2932012-03-30 14:02:01 -07002608#elif defined(TARGET_X86)
Ian Rogers474b6da2012-09-25 00:20:38 -07002609 newLIR2(cUnit, kX86Cmp16TI8, Thread::ThreadFlagsOffset().Int32Value(), 0);
Bill Buzbeea114add2012-05-03 15:00:40 -07002610 opCondBranch(cUnit, kCondEq, target);
buzbeefead2932012-03-30 14:02:01 -07002611#else
Bill Buzbeea114add2012-05-03 15:00:40 -07002612 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
2613 opCmpImmBranch(cUnit, kCondNe, rSUSPEND, 0, target);
buzbeefead2932012-03-30 14:02:01 -07002614#endif
Bill Buzbeea114add2012-05-03 15:00:40 -07002615 LIR* launchPad = rawLIR(cUnit, cUnit->currentDalvikOffset,
buzbee408ad162012-06-06 16:45:18 -07002616 kPseudoSuspendTarget, (intptr_t)target, cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -07002617 oatFlushAllRegs(cUnit);
2618 opUnconditionalBranch(cUnit, launchPad);
2619 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads,
2620 (intptr_t)launchPad);
2621 }
buzbeefead2932012-03-30 14:02:01 -07002622}
2623
buzbee31a4a6f2012-02-28 15:36:15 -08002624} // namespace art