blob: af7d4e004ea3c118bd76bdd9df85dfc3010a88c5 [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"
buzbee1bc37c62012-11-20 13:35:41 -080018#include "../compiler_ir.h"
19#include "ralloc_util.h"
20#include "codegen_util.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070021
buzbee31a4a6f2012-02-28 15:36:15 -080022namespace art {
23
buzbeeeaf09bc2012-11-15 14:51:41 -080024//TODO: remove decl.
buzbee52a77fc2012-11-20 19:50:46 -080025void GenInvoke(CompilationUnit* cUnit, CallInfo* info);
buzbeeeaf09bc2012-11-15 14:51:41 -080026
buzbee31a4a6f2012-02-28 15:36:15 -080027/*
28 * This source files contains "gen" codegen routines that should
29 * be applicable to most targets. Only mid-level support utilities
30 * and "op" calls may be used here.
31 */
buzbee31a4a6f2012-02-28 15:36:15 -080032
buzbee52a77fc2012-11-20 19:50:46 -080033void MarkSafepointPC(CompilationUnit* cUnit, LIR* inst)
buzbee8320f382012-09-11 16:29:42 -070034{
35 inst->defMask = ENCODE_ALL;
buzbee52a77fc2012-11-20 19:50:46 -080036 LIR* safepointPC = NewLIR0(cUnit, kPseudoSafepointPC);
buzbee8320f382012-09-11 16:29:42 -070037 DCHECK_EQ(safepointPC->defMask, ENCODE_ALL);
38}
39
buzbeeb046e162012-10-30 15:48:42 -070040/*
41 * To save scheduling time, helper calls are broken into two parts: generation of
42 * the helper target address, and the actuall call to the helper. Because x86
43 * has a memory call operation, part 1 is a NOP for x86. For other targets,
44 * load arguments between the two parts.
45 */
buzbee52a77fc2012-11-20 19:50:46 -080046int CallHelperSetup(CompilationUnit* cUnit, int helperOffset)
buzbeeb046e162012-10-30 15:48:42 -070047{
buzbee52a77fc2012-11-20 19:50:46 -080048 return (cUnit->instructionSet == kX86) ? 0 : LoadHelper(cUnit, helperOffset);
buzbeeb046e162012-10-30 15:48:42 -070049}
50
51/* NOTE: if rTgt is a temp, it will be freed following use */
buzbee52a77fc2012-11-20 19:50:46 -080052LIR* CallHelper(CompilationUnit* cUnit, int rTgt, int helperOffset, bool safepointPC)
buzbeeb046e162012-10-30 15:48:42 -070053{
54 LIR* callInst;
55 if (cUnit->instructionSet == kX86) {
buzbee52a77fc2012-11-20 19:50:46 -080056 callInst = OpThreadMem(cUnit, kOpBlx, helperOffset);
buzbeeb046e162012-10-30 15:48:42 -070057 } else {
buzbee52a77fc2012-11-20 19:50:46 -080058 callInst = OpReg(cUnit, kOpBlx, rTgt);
59 FreeTemp(cUnit, rTgt);
buzbeeb046e162012-10-30 15:48:42 -070060 }
buzbee8320f382012-09-11 16:29:42 -070061 if (safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -080062 MarkSafepointPC(cUnit, callInst);
buzbee8320f382012-09-11 16:29:42 -070063 }
buzbeeb046e162012-10-30 15:48:42 -070064 return callInst;
65}
66
buzbee52a77fc2012-11-20 19:50:46 -080067void CallRuntimeHelperImm(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) {
68 int rTgt = CallHelperSetup(cUnit, helperOffset);
69 LoadConstant(cUnit, TargetReg(kArg0), arg0);
70 ClobberCalleeSave(cUnit);
71 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -070072}
73
buzbee52a77fc2012-11-20 19:50:46 -080074void CallRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) {
75 int rTgt = CallHelperSetup(cUnit, helperOffset);
76 OpRegCopy(cUnit, TargetReg(kArg0), arg0);
77 ClobberCalleeSave(cUnit);
78 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogers7caad772012-03-30 01:07:54 -070079}
80
buzbee52a77fc2012-11-20 19:50:46 -080081void CallRuntimeHelperRegLocation(CompilationUnit* cUnit, int helperOffset, RegLocation arg0,
buzbee8320f382012-09-11 16:29:42 -070082 bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -080083 int rTgt = CallHelperSetup(cUnit, helperOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -070084 if (arg0.wide == 0) {
buzbee52a77fc2012-11-20 19:50:46 -080085 LoadValueDirectFixed(cUnit, arg0, TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -070086 } else {
buzbee52a77fc2012-11-20 19:50:46 -080087 LoadValueDirectWideFixed(cUnit, arg0, TargetReg(kArg0), TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -070088 }
buzbee52a77fc2012-11-20 19:50:46 -080089 ClobberCalleeSave(cUnit);
90 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -070091}
92
buzbee52a77fc2012-11-20 19:50:46 -080093void CallRuntimeHelperImmImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
buzbee8320f382012-09-11 16:29:42 -070094 bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -080095 int rTgt = CallHelperSetup(cUnit, helperOffset);
96 LoadConstant(cUnit, TargetReg(kArg0), arg0);
97 LoadConstant(cUnit, TargetReg(kArg1), arg1);
98 ClobberCalleeSave(cUnit);
99 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700100}
101
buzbee52a77fc2012-11-20 19:50:46 -0800102void CallRuntimeHelperImmRegLocation(CompilationUnit* cUnit, int helperOffset, int arg0,
buzbee8320f382012-09-11 16:29:42 -0700103 RegLocation arg1, bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800104 int rTgt = CallHelperSetup(cUnit, helperOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700105 if (arg1.wide == 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800106 LoadValueDirectFixed(cUnit, arg1, TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700107 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800108 LoadValueDirectWideFixed(cUnit, arg1, TargetReg(kArg1), TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700109 }
buzbee52a77fc2012-11-20 19:50:46 -0800110 LoadConstant(cUnit, TargetReg(kArg0), arg0);
111 ClobberCalleeSave(cUnit);
112 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700113}
114
buzbee52a77fc2012-11-20 19:50:46 -0800115void CallRuntimeHelperRegLocationImm(CompilationUnit* cUnit, int helperOffset, RegLocation arg0,
buzbee8320f382012-09-11 16:29:42 -0700116 int arg1, bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800117 int rTgt = CallHelperSetup(cUnit, helperOffset);
118 LoadValueDirectFixed(cUnit, arg0, TargetReg(kArg0));
119 LoadConstant(cUnit, TargetReg(kArg1), arg1);
120 ClobberCalleeSave(cUnit);
121 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700122}
123
buzbee52a77fc2012-11-20 19:50:46 -0800124void CallRuntimeHelperImmReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
buzbee8320f382012-09-11 16:29:42 -0700125 bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800126 int rTgt = CallHelperSetup(cUnit, helperOffset);
127 OpRegCopy(cUnit, TargetReg(kArg1), arg1);
128 LoadConstant(cUnit, TargetReg(kArg0), arg0);
129 ClobberCalleeSave(cUnit);
130 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700131}
132
buzbee52a77fc2012-11-20 19:50:46 -0800133void CallRuntimeHelperRegImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
buzbee8320f382012-09-11 16:29:42 -0700134 bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800135 int rTgt = CallHelperSetup(cUnit, helperOffset);
136 OpRegCopy(cUnit, TargetReg(kArg0), arg0);
137 LoadConstant(cUnit, TargetReg(kArg1), arg1);
138 ClobberCalleeSave(cUnit);
139 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700140}
141
buzbee52a77fc2012-11-20 19:50:46 -0800142void CallRuntimeHelperImmMethod(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC) {
143 int rTgt = CallHelperSetup(cUnit, helperOffset);
144 LoadCurrMethodDirect(cUnit, TargetReg(kArg1));
145 LoadConstant(cUnit, TargetReg(kArg0), arg0);
146 ClobberCalleeSave(cUnit);
147 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700148}
149
buzbee52a77fc2012-11-20 19:50:46 -0800150void CallRuntimeHelperRegLocationRegLocation(CompilationUnit* cUnit, int helperOffset,
buzbee8320f382012-09-11 16:29:42 -0700151 RegLocation arg0, RegLocation arg1, bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800152 int rTgt = CallHelperSetup(cUnit, helperOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700153 if (arg0.wide == 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800154 LoadValueDirectFixed(cUnit, arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700155 if (arg1.wide == 0) {
buzbeeb046e162012-10-30 15:48:42 -0700156 if (cUnit->instructionSet == kMips) {
buzbee52a77fc2012-11-20 19:50:46 -0800157 LoadValueDirectFixed(cUnit, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
buzbeeb046e162012-10-30 15:48:42 -0700158 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800159 LoadValueDirectFixed(cUnit, arg1, TargetReg(kArg1));
buzbeeb046e162012-10-30 15:48:42 -0700160 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700161 } else {
buzbeeb046e162012-10-30 15:48:42 -0700162 if (cUnit->instructionSet == kMips) {
buzbee52a77fc2012-11-20 19:50:46 -0800163 LoadValueDirectWideFixed(cUnit, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
buzbeeb046e162012-10-30 15:48:42 -0700164 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800165 LoadValueDirectWideFixed(cUnit, arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbeeb046e162012-10-30 15:48:42 -0700166 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700167 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700168 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800169 LoadValueDirectWideFixed(cUnit, arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700170 if (arg1.wide == 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800171 LoadValueDirectFixed(cUnit, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800173 LoadValueDirectWideFixed(cUnit, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 }
175 }
buzbee52a77fc2012-11-20 19:50:46 -0800176 ClobberCalleeSave(cUnit);
177 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700178}
179
buzbee52a77fc2012-11-20 19:50:46 -0800180void CallRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
buzbee8320f382012-09-11 16:29:42 -0700181 bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800182 int rTgt = CallHelperSetup(cUnit, helperOffset);
183 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
184 OpRegCopy(cUnit, TargetReg(kArg0), arg0);
185 OpRegCopy(cUnit, TargetReg(kArg1), arg1);
186 ClobberCalleeSave(cUnit);
187 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700188}
189
buzbee52a77fc2012-11-20 19:50:46 -0800190void CallRuntimeHelperRegRegImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1,
buzbee8320f382012-09-11 16:29:42 -0700191 int arg2, bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800192 int rTgt = CallHelperSetup(cUnit, helperOffset);
193 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
194 OpRegCopy(cUnit, TargetReg(kArg0), arg0);
195 OpRegCopy(cUnit, TargetReg(kArg1), arg1);
196 LoadConstant(cUnit, TargetReg(kArg2), arg2);
197 ClobberCalleeSave(cUnit);
198 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700199}
200
buzbee52a77fc2012-11-20 19:50:46 -0800201void CallRuntimeHelperImmMethodRegLocation(CompilationUnit* cUnit, int helperOffset, int arg0,
buzbee8320f382012-09-11 16:29:42 -0700202 RegLocation arg2, bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800203 int rTgt = CallHelperSetup(cUnit, helperOffset);
204 LoadValueDirectFixed(cUnit, arg2, TargetReg(kArg2));
205 LoadCurrMethodDirect(cUnit, TargetReg(kArg1));
206 LoadConstant(cUnit, TargetReg(kArg0), arg0);
207 ClobberCalleeSave(cUnit);
208 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700209}
210
buzbee52a77fc2012-11-20 19:50:46 -0800211void CallRuntimeHelperImmMethodImm(CompilationUnit* cUnit, int helperOffset, int arg0, int arg2,
buzbee8320f382012-09-11 16:29:42 -0700212 bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800213 int rTgt = CallHelperSetup(cUnit, helperOffset);
214 LoadCurrMethodDirect(cUnit, TargetReg(kArg1));
215 LoadConstant(cUnit, TargetReg(kArg2), arg2);
216 LoadConstant(cUnit, TargetReg(kArg0), arg0);
217 ClobberCalleeSave(cUnit);
218 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700219}
220
buzbee52a77fc2012-11-20 19:50:46 -0800221void CallRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cUnit, int helperOffset,
buzbee8320f382012-09-11 16:29:42 -0700222 int arg0, RegLocation arg1, RegLocation arg2,
223 bool safepointPC) {
buzbee52a77fc2012-11-20 19:50:46 -0800224 int rTgt = CallHelperSetup(cUnit, helperOffset);
225 LoadValueDirectFixed(cUnit, arg1, TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700226 if (arg2.wide == 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800227 LoadValueDirectFixed(cUnit, arg2, TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700228 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800229 LoadValueDirectWideFixed(cUnit, arg2, TargetReg(kArg2), TargetReg(kArg3));
Bill Buzbeea114add2012-05-03 15:00:40 -0700230 }
buzbee52a77fc2012-11-20 19:50:46 -0800231 LoadConstant(cUnit, TargetReg(kArg0), arg0);
232 ClobberCalleeSave(cUnit);
233 CallHelper(cUnit, rTgt, helperOffset, safepointPC);
buzbee31a4a6f2012-02-28 15:36:15 -0800234}
235
236/*
237 * Generate an kPseudoBarrier marker to indicate the boundary of special
238 * blocks.
239 */
buzbee52a77fc2012-11-20 19:50:46 -0800240void GenBarrier(CompilationUnit* cUnit)
buzbee31a4a6f2012-02-28 15:36:15 -0800241{
buzbee52a77fc2012-11-20 19:50:46 -0800242 LIR* barrier = NewLIR0(cUnit, kPseudoBarrier);
Bill Buzbeea114add2012-05-03 15:00:40 -0700243 /* Mark all resources as being clobbered */
244 barrier->defMask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800245}
246
buzbee31a4a6f2012-02-28 15:36:15 -0800247
248/* Generate unconditional branch instructions */
buzbee52a77fc2012-11-20 19:50:46 -0800249LIR* OpUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -0800250{
buzbee52a77fc2012-11-20 19:50:46 -0800251 LIR* branch = OpBranchUnconditional(cUnit, kOpUncondBr);
buzbeecbd6d442012-11-17 14:11:25 -0800252 branch->target = target;
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800254}
255
buzbee5de34942012-03-01 14:51:57 -0800256// FIXME: need to do some work to split out targets with
257// condition codes and those without
buzbee52a77fc2012-11-20 19:50:46 -0800258LIR* GenCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee31a4a6f2012-02-28 15:36:15 -0800259 ThrowKind kind)
260{
buzbeeb046e162012-10-30 15:48:42 -0700261 DCHECK_NE(cUnit->instructionSet, kMips);
buzbee52a77fc2012-11-20 19:50:46 -0800262 LIR* tgt = RawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700263 cUnit->currentDalvikOffset);
buzbee52a77fc2012-11-20 19:50:46 -0800264 LIR* branch = OpCondBranch(cUnit, cCode, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700265 // Remember branch target - will process later
buzbee52a77fc2012-11-20 19:50:46 -0800266 InsertGrowableList(cUnit, &cUnit->throwLaunchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800268}
269
buzbee52a77fc2012-11-20 19:50:46 -0800270LIR* GenImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -0700271 int reg, int immVal, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800272{
buzbee52a77fc2012-11-20 19:50:46 -0800273 LIR* tgt = RawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700274 cUnit->currentDalvikOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 LIR* branch;
276 if (cCode == kCondAl) {
buzbee52a77fc2012-11-20 19:50:46 -0800277 branch = OpUnconditionalBranch(cUnit, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700278 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800279 branch = OpCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700280 }
281 // Remember branch target - will process later
buzbee52a77fc2012-11-20 19:50:46 -0800282 InsertGrowableList(cUnit, &cUnit->throwLaunchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700283 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800284}
285
286/* Perform null-check on a register. */
buzbee52a77fc2012-11-20 19:50:46 -0800287LIR* GenNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -0800288{
Bill Buzbeea114add2012-05-03 15:00:40 -0700289 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
buzbee408ad162012-06-06 16:45:18 -0700290 optFlags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700291 return NULL;
292 }
buzbee52a77fc2012-11-20 19:50:46 -0800293 return GenImmedCheck(cUnit, kCondEq, mReg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -0800294}
295
296/* Perform check on two registers */
buzbee52a77fc2012-11-20 19:50:46 -0800297LIR* GenRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -0700298 int reg1, int reg2, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800299{
buzbee52a77fc2012-11-20 19:50:46 -0800300 LIR* tgt = RawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -0700301 cUnit->currentDalvikOffset, reg1, reg2);
buzbee52a77fc2012-11-20 19:50:46 -0800302 LIR* branch = OpCmpBranch(cUnit, cCode, reg1, reg2, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700303 // Remember branch target - will process later
buzbee52a77fc2012-11-20 19:50:46 -0800304 InsertGrowableList(cUnit, &cUnit->throwLaunchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700305 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800306}
307
buzbee52a77fc2012-11-20 19:50:46 -0800308void GenCompareAndBranch(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee3b3dbdd2012-06-13 13:39:34 -0700309 RegLocation rlSrc1, RegLocation rlSrc2, LIR* taken,
310 LIR* fallThrough)
buzbee31a4a6f2012-02-28 15:36:15 -0800311{
Bill Buzbeea114add2012-05-03 15:00:40 -0700312 ConditionCode cond;
buzbee52a77fc2012-11-20 19:50:46 -0800313 rlSrc1 = LoadValue(cUnit, rlSrc1, kCoreReg);
314 rlSrc2 = LoadValue(cUnit, rlSrc2, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700315 switch (opcode) {
316 case Instruction::IF_EQ:
317 cond = kCondEq;
318 break;
319 case Instruction::IF_NE:
320 cond = kCondNe;
321 break;
322 case Instruction::IF_LT:
323 cond = kCondLt;
324 break;
325 case Instruction::IF_GE:
326 cond = kCondGe;
327 break;
328 case Instruction::IF_GT:
329 cond = kCondGt;
330 break;
331 case Instruction::IF_LE:
332 cond = kCondLe;
333 break;
334 default:
buzbeecbd6d442012-11-17 14:11:25 -0800335 cond = static_cast<ConditionCode>(0);
336 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700337 }
buzbee52a77fc2012-11-20 19:50:46 -0800338 OpCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg, taken);
339 OpUnconditionalBranch(cUnit, fallThrough);
buzbee31a4a6f2012-02-28 15:36:15 -0800340}
341
buzbee52a77fc2012-11-20 19:50:46 -0800342void GenCompareZeroAndBranch(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee3b3dbdd2012-06-13 13:39:34 -0700343 RegLocation rlSrc, LIR* taken, LIR* fallThrough)
buzbee31a4a6f2012-02-28 15:36:15 -0800344{
Bill Buzbeea114add2012-05-03 15:00:40 -0700345 ConditionCode cond;
buzbee52a77fc2012-11-20 19:50:46 -0800346 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700347 switch (opcode) {
348 case Instruction::IF_EQZ:
349 cond = kCondEq;
350 break;
351 case Instruction::IF_NEZ:
352 cond = kCondNe;
353 break;
354 case Instruction::IF_LTZ:
355 cond = kCondLt;
356 break;
357 case Instruction::IF_GEZ:
358 cond = kCondGe;
359 break;
360 case Instruction::IF_GTZ:
361 cond = kCondGt;
362 break;
363 case Instruction::IF_LEZ:
364 cond = kCondLe;
365 break;
366 default:
buzbeecbd6d442012-11-17 14:11:25 -0800367 cond = static_cast<ConditionCode>(0);
368 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700369 }
buzbeeb046e162012-10-30 15:48:42 -0700370 if (cUnit->instructionSet == kThumb2) {
buzbee52a77fc2012-11-20 19:50:46 -0800371 OpRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
372 OpCondBranch(cUnit, cond, taken);
buzbeeb046e162012-10-30 15:48:42 -0700373 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800374 OpCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, taken);
buzbeeb046e162012-10-30 15:48:42 -0700375 }
buzbee52a77fc2012-11-20 19:50:46 -0800376 OpUnconditionalBranch(cUnit, fallThrough);
buzbee31a4a6f2012-02-28 15:36:15 -0800377}
378
buzbee52a77fc2012-11-20 19:50:46 -0800379void GenIntToLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800380 RegLocation rlSrc)
381{
buzbee52a77fc2012-11-20 19:50:46 -0800382 RegLocation rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700383 if (rlSrc.location == kLocPhysReg) {
buzbee52a77fc2012-11-20 19:50:46 -0800384 OpRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800386 LoadValueDirect(cUnit, rlSrc, rlResult.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700387 }
buzbee52a77fc2012-11-20 19:50:46 -0800388 OpRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
389 StoreValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800390}
391
buzbee52a77fc2012-11-20 19:50:46 -0800392void GenIntNarrowing(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee408ad162012-06-06 16:45:18 -0700393 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800394{
buzbee52a77fc2012-11-20 19:50:46 -0800395 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
396 RegLocation rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700397 OpKind op = kOpInvalid;
buzbee408ad162012-06-06 16:45:18 -0700398 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700399 case Instruction::INT_TO_BYTE:
400 op = kOp2Byte;
401 break;
402 case Instruction::INT_TO_SHORT:
403 op = kOp2Short;
404 break;
405 case Instruction::INT_TO_CHAR:
406 op = kOp2Char;
407 break;
408 default:
409 LOG(ERROR) << "Bad int conversion type";
410 }
buzbee52a77fc2012-11-20 19:50:46 -0800411 OpRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
412 StoreValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800413}
414
415/*
416 * Let helper function take care of everything. Will call
417 * Array::AllocFromCode(type_idx, method, count);
418 * Note: AllocFromCode will handle checks for errNegativeArraySize.
419 */
buzbee52a77fc2012-11-20 19:50:46 -0800420void GenNewArray(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800421 RegLocation rlSrc)
422{
buzbee52a77fc2012-11-20 19:50:46 -0800423 FlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700424 int funcOffset;
425 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -0700426 *cUnit->dex_file,
427 type_idx)) {
428 funcOffset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
429 } else {
430 funcOffset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
431 }
buzbee52a77fc2012-11-20 19:50:46 -0800432 CallRuntimeHelperImmMethodRegLocation(cUnit, funcOffset, type_idx, rlSrc, true);
433 RegLocation rlResult = GetReturn(cUnit, false);
434 StoreValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800435}
436
437/*
buzbee52a77fc2012-11-20 19:50:46 -0800438 * Similar to GenNewArray, but with post-allocation initialization.
buzbee31a4a6f2012-02-28 15:36:15 -0800439 * Verifier guarantees we're dealing with an array class. Current
440 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
441 * Current code also throws internal unimp if not 'L', '[' or 'I'.
442 */
buzbee52a77fc2012-11-20 19:50:46 -0800443void GenFilledNewArray(CompilationUnit* cUnit, CallInfo* info)
buzbee31a4a6f2012-02-28 15:36:15 -0800444{
buzbee3b3dbdd2012-06-13 13:39:34 -0700445 int elems = info->numArgWords;
446 int typeIdx = info->index;
buzbee52a77fc2012-11-20 19:50:46 -0800447 FlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700448 int funcOffset;
449 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -0700450 *cUnit->dex_file,
451 typeIdx)) {
452 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
453 } else {
454 funcOffset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
455 }
buzbee52a77fc2012-11-20 19:50:46 -0800456 CallRuntimeHelperImmMethodImm(cUnit, funcOffset, typeIdx, elems, true);
457 FreeTemp(cUnit, TargetReg(kArg2));
458 FreeTemp(cUnit, TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700459 /*
460 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
461 * return region. Because AllocFromCode placed the new array
buzbeef0504cd2012-11-13 16:31:10 -0800462 * in kRet0, we'll just lock it into place. When debugger support is
Bill Buzbeea114add2012-05-03 15:00:40 -0700463 * added, it may be necessary to additionally copy all return
464 * values to a home location in thread-local storage
465 */
buzbee52a77fc2012-11-20 19:50:46 -0800466 LockTemp(cUnit, TargetReg(kRet0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700467
468 // TODO: use the correct component size, currently all supported types
469 // share array alignment with ints (see comment at head of function)
470 size_t component_size = sizeof(int32_t);
471
472 // Having a range of 0 is legal
buzbee3b3dbdd2012-06-13 13:39:34 -0700473 if (info->isRange && (elems > 0)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800474 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700475 * Bit of ugliness here. We're going generate a mem copy loop
476 * on the register range, but it is possible that some regs
477 * in the range have been promoted. This is unlikely, but
478 * before generating the copy, we'll just force a flush
479 * of any regs in the source range that have been promoted to
480 * home location.
buzbee31a4a6f2012-02-28 15:36:15 -0800481 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700482 for (int i = 0; i < elems; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800483 RegLocation loc = UpdateLoc(cUnit, info->args[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700484 if (loc.location == kLocPhysReg) {
buzbee52a77fc2012-11-20 19:50:46 -0800485 StoreBaseDisp(cUnit, TargetReg(kSp), SRegOffset(cUnit, loc.sRegLow),
Bill Buzbeea114add2012-05-03 15:00:40 -0700486 loc.lowReg, kWord);
487 }
buzbee31a4a6f2012-02-28 15:36:15 -0800488 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700489 /*
490 * TUNING note: generated code here could be much improved, but
491 * this is an uncommon operation and isn't especially performance
492 * critical.
493 */
buzbee52a77fc2012-11-20 19:50:46 -0800494 int rSrc = AllocTemp(cUnit);
495 int rDst = AllocTemp(cUnit);
496 int rIdx = AllocTemp(cUnit);
buzbeeb046e162012-10-30 15:48:42 -0700497 int rVal = INVALID_REG;
498 switch(cUnit->instructionSet) {
499 case kThumb2:
buzbee52a77fc2012-11-20 19:50:46 -0800500 rVal = TargetReg(kLr);
buzbeeb046e162012-10-30 15:48:42 -0700501 break;
502 case kX86:
buzbee52a77fc2012-11-20 19:50:46 -0800503 FreeTemp(cUnit, TargetReg(kRet0));
504 rVal = AllocTemp(cUnit);
buzbeeb046e162012-10-30 15:48:42 -0700505 break;
506 case kMips:
buzbee52a77fc2012-11-20 19:50:46 -0800507 rVal = AllocTemp(cUnit);
buzbeeb046e162012-10-30 15:48:42 -0700508 break;
509 default: LOG(FATAL) << "Unexpected instruction set: " << cUnit->instructionSet;
510 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700511 // Set up source pointer
buzbee3b3dbdd2012-06-13 13:39:34 -0700512 RegLocation rlFirst = info->args[0];
buzbee52a77fc2012-11-20 19:50:46 -0800513 OpRegRegImm(cUnit, kOpAdd, rSrc, TargetReg(kSp),
514 SRegOffset(cUnit, rlFirst.sRegLow));
Bill Buzbeea114add2012-05-03 15:00:40 -0700515 // Set up the target pointer
buzbee52a77fc2012-11-20 19:50:46 -0800516 OpRegRegImm(cUnit, kOpAdd, rDst, TargetReg(kRet0),
Bill Buzbeea114add2012-05-03 15:00:40 -0700517 Array::DataOffset(component_size).Int32Value());
518 // Set up the loop counter (known to be > 0)
buzbee52a77fc2012-11-20 19:50:46 -0800519 LoadConstant(cUnit, rIdx, elems - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700520 // Generate the copy loop. Going backwards for convenience
buzbee52a77fc2012-11-20 19:50:46 -0800521 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -0700522 // Copy next element
buzbee52a77fc2012-11-20 19:50:46 -0800523 LoadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
524 StoreBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
525 FreeTemp(cUnit, rVal);
526 OpDecAndBranch(cUnit, kCondGe, rIdx, target);
buzbeeb046e162012-10-30 15:48:42 -0700527 if (cUnit->instructionSet == kX86) {
528 // Restore the target pointer
buzbee52a77fc2012-11-20 19:50:46 -0800529 OpRegRegImm(cUnit, kOpAdd, TargetReg(kRet0), rDst, -Array::DataOffset(component_size).Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700530 }
buzbee3b3dbdd2012-06-13 13:39:34 -0700531 } else if (!info->isRange) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700532 // TUNING: interleave
buzbee3b3dbdd2012-06-13 13:39:34 -0700533 for (int i = 0; i < elems; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800534 RegLocation rlArg = LoadValue(cUnit, info->args[i], kCoreReg);
535 StoreBaseDisp(cUnit, TargetReg(kRet0),
Bill Buzbeea114add2012-05-03 15:00:40 -0700536 Array::DataOffset(component_size).Int32Value() +
537 i * 4, rlArg.lowReg, kWord);
buzbee52a77fc2012-11-20 19:50:46 -0800538 // If the LoadValue caused a temp to be allocated, free it
539 if (IsTemp(cUnit, rlArg.lowReg)) {
540 FreeTemp(cUnit, rlArg.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700541 }
542 }
543 }
buzbeee5f01222012-06-14 15:19:35 -0700544 if (info->result.location != kLocInvalid) {
buzbee52a77fc2012-11-20 19:50:46 -0800545 StoreValue(cUnit, info->result, GetReturn(cUnit, false /* not fp */));
buzbeee5f01222012-06-14 15:19:35 -0700546 }
buzbee31a4a6f2012-02-28 15:36:15 -0800547}
548
buzbee52a77fc2012-11-20 19:50:46 -0800549void GenSput(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlSrc,
Bill Buzbeea114add2012-05-03 15:00:40 -0700550 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800551{
Bill Buzbeea114add2012-05-03 15:00:40 -0700552 int fieldOffset;
553 int ssbIndex;
554 bool isVolatile;
555 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800556
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700557 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker, *cUnit->dex_file,
558 cUnit->code_item, cUnit->method_idx, cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800559
Bill Buzbeea114add2012-05-03 15:00:40 -0700560 bool fastPath =
561 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
562 fieldOffset, ssbIndex,
563 isReferrersClass, isVolatile,
564 true);
565 if (fastPath && !SLOW_FIELD_PATH) {
566 DCHECK_GE(fieldOffset, 0);
567 int rBase;
568 if (isReferrersClass) {
569 // Fast path, static storage base is this method's class
buzbee52a77fc2012-11-20 19:50:46 -0800570 RegLocation rlMethod = LoadCurrMethod(cUnit);
571 rBase = AllocTemp(cUnit);
572 LoadWordDisp(cUnit, rlMethod.lowReg,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700573 AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbee52a77fc2012-11-20 19:50:46 -0800574 if (IsTemp(cUnit, rlMethod.lowReg)) {
575 FreeTemp(cUnit, rlMethod.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700576 }
buzbee31a4a6f2012-02-28 15:36:15 -0800577 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700578 // Medium path, static storage base in a different class which
579 // requires checks that the other class is initialized.
580 DCHECK_GE(ssbIndex, 0);
581 // May do runtime call so everything to home locations.
buzbee52a77fc2012-11-20 19:50:46 -0800582 FlushAllRegs(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700583 // Using fixed register to sync with possible call to runtime
584 // support.
buzbee52a77fc2012-11-20 19:50:46 -0800585 int rMethod = TargetReg(kArg1);
586 LockTemp(cUnit, rMethod);
587 LoadCurrMethodDirect(cUnit, rMethod);
588 rBase = TargetReg(kArg0);
589 LockTemp(cUnit, rBase);
590 LoadWordDisp(cUnit, rMethod,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700591 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700592 rBase);
buzbee52a77fc2012-11-20 19:50:46 -0800593 LoadWordDisp(cUnit, rBase,
Bill Buzbeea114add2012-05-03 15:00:40 -0700594 Array::DataOffset(sizeof(Object*)).Int32Value() +
595 sizeof(int32_t*) * ssbIndex, rBase);
596 // rBase now points at appropriate static storage base (Class*)
597 // or NULL if not initialized. Check for NULL and call helper if NULL.
598 // TUNING: fast path should fall through
buzbee52a77fc2012-11-20 19:50:46 -0800599 LIR* branchOver = OpCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
600 LoadConstant(cUnit, TargetReg(kArg0), ssbIndex);
601 CallRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssbIndex, true);
buzbeeb046e162012-10-30 15:48:42 -0700602 if (cUnit->instructionSet == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800603 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbee52a77fc2012-11-20 19:50:46 -0800604 OpRegCopy(cUnit, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700605 }
buzbee52a77fc2012-11-20 19:50:46 -0800606 LIR* skipTarget = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800607 branchOver->target = skipTarget;
buzbee52a77fc2012-11-20 19:50:46 -0800608 FreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800609 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700610 // rBase now holds static storage base
611 if (isLongOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800612 rlSrc = LoadValueWide(cUnit, rlSrc, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700613 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800614 rlSrc = LoadValue(cUnit, rlSrc, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700615 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700616 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800617 GenMemBarrier(cUnit, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700618 }
619 if (isLongOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800620 StoreBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700621 rlSrc.highReg);
622 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800623 StoreWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700624 }
625 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800626 GenMemBarrier(cUnit, kStoreLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700627 }
628 if (isObject) {
buzbee52a77fc2012-11-20 19:50:46 -0800629 MarkGCCard(cUnit, rlSrc.lowReg, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700630 }
buzbee52a77fc2012-11-20 19:50:46 -0800631 FreeTemp(cUnit, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700632 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800633 FlushAllRegs(cUnit); // Everything to home locations
Bill Buzbeea114add2012-05-03 15:00:40 -0700634 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Static) :
635 (isObject ? ENTRYPOINT_OFFSET(pSetObjStatic)
636 : ENTRYPOINT_OFFSET(pSet32Static));
buzbee52a77fc2012-11-20 19:50:46 -0800637 CallRuntimeHelperImmRegLocation(cUnit, setterOffset, fieldIdx, rlSrc, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700638 }
buzbee31a4a6f2012-02-28 15:36:15 -0800639}
640
buzbee52a77fc2012-11-20 19:50:46 -0800641void GenSget(CompilationUnit* cUnit, uint32_t fieldIdx, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700642 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800643{
Bill Buzbeea114add2012-05-03 15:00:40 -0700644 int fieldOffset;
645 int ssbIndex;
646 bool isVolatile;
647 bool isReferrersClass;
buzbee31a4a6f2012-02-28 15:36:15 -0800648
Bill Buzbeea114add2012-05-03 15:00:40 -0700649 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700650 *cUnit->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700651 cUnit->code_item, cUnit->method_idx,
652 cUnit->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800653
Bill Buzbeea114add2012-05-03 15:00:40 -0700654 bool fastPath =
655 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
656 fieldOffset, ssbIndex,
657 isReferrersClass, isVolatile,
658 false);
659 if (fastPath && !SLOW_FIELD_PATH) {
660 DCHECK_GE(fieldOffset, 0);
661 int rBase;
662 if (isReferrersClass) {
663 // Fast path, static storage base is this method's class
buzbee52a77fc2012-11-20 19:50:46 -0800664 RegLocation rlMethod = LoadCurrMethod(cUnit);
665 rBase = AllocTemp(cUnit);
666 LoadWordDisp(cUnit, rlMethod.lowReg,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700667 AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800668 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700669 // Medium path, static storage base in a different class which
670 // requires checks that the other class is initialized
671 DCHECK_GE(ssbIndex, 0);
672 // May do runtime call so everything to home locations.
buzbee52a77fc2012-11-20 19:50:46 -0800673 FlushAllRegs(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700674 // Using fixed register to sync with possible call to runtime
675 // support
buzbee52a77fc2012-11-20 19:50:46 -0800676 int rMethod = TargetReg(kArg1);
677 LockTemp(cUnit, rMethod);
678 LoadCurrMethodDirect(cUnit, rMethod);
679 rBase = TargetReg(kArg0);
680 LockTemp(cUnit, rBase);
681 LoadWordDisp(cUnit, rMethod,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700682 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700683 rBase);
buzbee52a77fc2012-11-20 19:50:46 -0800684 LoadWordDisp(cUnit, rBase,
Bill Buzbeea114add2012-05-03 15:00:40 -0700685 Array::DataOffset(sizeof(Object*)).Int32Value() +
686 sizeof(int32_t*) * ssbIndex, rBase);
687 // rBase now points at appropriate static storage base (Class*)
688 // or NULL if not initialized. Check for NULL and call helper if NULL.
689 // TUNING: fast path should fall through
buzbee52a77fc2012-11-20 19:50:46 -0800690 LIR* branchOver = OpCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
691 CallRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssbIndex, true);
buzbeeb046e162012-10-30 15:48:42 -0700692 if (cUnit->instructionSet == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800693 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbee52a77fc2012-11-20 19:50:46 -0800694 OpRegCopy(cUnit, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700695 }
buzbee52a77fc2012-11-20 19:50:46 -0800696 LIR* skipTarget = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800697 branchOver->target = skipTarget;
buzbee52a77fc2012-11-20 19:50:46 -0800698 FreeTemp(cUnit, rMethod);
buzbee31a4a6f2012-02-28 15:36:15 -0800699 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700700 // rBase now holds static storage base
buzbee52a77fc2012-11-20 19:50:46 -0800701 RegLocation rlResult = EvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700702 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800703 GenMemBarrier(cUnit, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700704 }
705 if (isLongOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800706 LoadBaseDispWide(cUnit, rBase, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700707 rlResult.highReg, INVALID_SREG);
708 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800709 LoadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700710 }
buzbee52a77fc2012-11-20 19:50:46 -0800711 FreeTemp(cUnit, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700712 if (isLongOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800713 StoreValueWide(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -0700714 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800715 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -0700716 }
717 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800718 FlushAllRegs(cUnit); // Everything to home locations
Bill Buzbeea114add2012-05-03 15:00:40 -0700719 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Static) :
720 (isObject ? ENTRYPOINT_OFFSET(pGetObjStatic)
721 : ENTRYPOINT_OFFSET(pGet32Static));
buzbee52a77fc2012-11-20 19:50:46 -0800722 CallRuntimeHelperImm(cUnit, getterOffset, fieldIdx, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700723 if (isLongOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800724 RegLocation rlResult = GetReturnWide(cUnit, rlDest.fp);
725 StoreValueWide(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -0700726 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800727 RegLocation rlResult = GetReturn(cUnit, rlDest.fp);
728 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -0700729 }
730 }
buzbee31a4a6f2012-02-28 15:36:15 -0800731}
732
733
734// Debugging routine - if null target, branch to DebugMe
buzbee52a77fc2012-11-20 19:50:46 -0800735void GenShowTarget(CompilationUnit* cUnit)
buzbee31a4a6f2012-02-28 15:36:15 -0800736{
buzbee52a77fc2012-11-20 19:50:46 -0800737 DCHECK_NE(cUnit->instructionSet, kX86) << "unimplemented GenShowTarget";
738 LIR* branchOver = OpCmpImmBranch(cUnit, kCondNe, TargetReg(kInvokeTgt), 0, NULL);
739 LoadWordDisp(cUnit, TargetReg(kSelf), ENTRYPOINT_OFFSET(pDebugMe), TargetReg(kInvokeTgt));
740 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800741 branchOver->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -0800742}
743
buzbee52a77fc2012-11-20 19:50:46 -0800744void HandleSuspendLaunchPads(CompilationUnit *cUnit)
buzbee31a4a6f2012-02-28 15:36:15 -0800745{
buzbeecbd6d442012-11-17 14:11:25 -0800746 LIR** suspendLabel = reinterpret_cast<LIR**>(cUnit->suspendLaunchpads.elemList);
Bill Buzbeea114add2012-05-03 15:00:40 -0700747 int numElems = cUnit->suspendLaunchpads.numUsed;
buzbeeb046e162012-10-30 15:48:42 -0700748 int helperOffset = ENTRYPOINT_OFFSET(pTestSuspendFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700749 for (int i = 0; i < numElems; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800750 ResetRegPool(cUnit);
751 ResetDefTracking(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700752 LIR* lab = suspendLabel[i];
buzbeecbd6d442012-11-17 14:11:25 -0800753 LIR* resumeLab = reinterpret_cast<LIR*>(lab->operands[0]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700754 cUnit->currentDalvikOffset = lab->operands[1];
buzbee52a77fc2012-11-20 19:50:46 -0800755 AppendLIR(cUnit, lab);
756 int rTgt = CallHelperSetup(cUnit, helperOffset);
757 CallHelper(cUnit, rTgt, helperOffset, true /* MarkSafepointPC */);
758 OpUnconditionalBranch(cUnit, resumeLab);
Bill Buzbeea114add2012-05-03 15:00:40 -0700759 }
buzbee31a4a6f2012-02-28 15:36:15 -0800760}
761
buzbee52a77fc2012-11-20 19:50:46 -0800762void HandleIntrinsicLaunchPads(CompilationUnit *cUnit)
buzbeefc9e6fa2012-03-23 15:14:29 -0700763{
buzbeecbd6d442012-11-17 14:11:25 -0800764 LIR** intrinsicLabel = reinterpret_cast<LIR**>(cUnit->intrinsicLaunchpads.elemList);
Bill Buzbeea114add2012-05-03 15:00:40 -0700765 int numElems = cUnit->intrinsicLaunchpads.numUsed;
766 for (int i = 0; i < numElems; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800767 ResetRegPool(cUnit);
768 ResetDefTracking(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700769 LIR* lab = intrinsicLabel[i];
buzbeecbd6d442012-11-17 14:11:25 -0800770 CallInfo* info = reinterpret_cast<CallInfo*>(lab->operands[0]);
buzbee15bf9802012-06-12 17:49:27 -0700771 cUnit->currentDalvikOffset = info->offset;
buzbee52a77fc2012-11-20 19:50:46 -0800772 AppendLIR(cUnit, lab);
773 // NOTE: GenInvoke handles MarkSafepointPC
774 GenInvoke(cUnit, info);
buzbeecbd6d442012-11-17 14:11:25 -0800775 LIR* resumeLab = reinterpret_cast<LIR*>(lab->operands[2]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700776 if (resumeLab != NULL) {
buzbee52a77fc2012-11-20 19:50:46 -0800777 OpUnconditionalBranch(cUnit, resumeLab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700778 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700779 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700780}
781
buzbee52a77fc2012-11-20 19:50:46 -0800782void HandleThrowLaunchPads(CompilationUnit *cUnit)
buzbee31a4a6f2012-02-28 15:36:15 -0800783{
buzbeecbd6d442012-11-17 14:11:25 -0800784 LIR** throwLabel = reinterpret_cast<LIR**>(cUnit->throwLaunchpads.elemList);
Bill Buzbeea114add2012-05-03 15:00:40 -0700785 int numElems = cUnit->throwLaunchpads.numUsed;
786 for (int i = 0; i < numElems; i++) {
buzbee52a77fc2012-11-20 19:50:46 -0800787 ResetRegPool(cUnit);
788 ResetDefTracking(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700789 LIR* lab = throwLabel[i];
790 cUnit->currentDalvikOffset = lab->operands[1];
buzbee52a77fc2012-11-20 19:50:46 -0800791 AppendLIR(cUnit, lab);
Bill Buzbeea114add2012-05-03 15:00:40 -0700792 int funcOffset = 0;
793 int v1 = lab->operands[2];
794 int v2 = lab->operands[3];
buzbeeb046e162012-10-30 15:48:42 -0700795 bool targetX86 = (cUnit->instructionSet == kX86);
Bill Buzbeea114add2012-05-03 15:00:40 -0700796 switch (lab->operands[0]) {
797 case kThrowNullPointer:
798 funcOffset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
799 break;
800 case kThrowArrayBounds:
buzbeef0504cd2012-11-13 16:31:10 -0800801 // Move v1 (array index) to kArg0 and v2 (array length) to kArg1
buzbee52a77fc2012-11-20 19:50:46 -0800802 if (v2 != TargetReg(kArg0)) {
803 OpRegCopy(cUnit, TargetReg(kArg0), v1);
buzbeeb046e162012-10-30 15:48:42 -0700804 if (targetX86) {
805 // x86 leaves the array pointer in v2, so load the array length that the handler expects
buzbee52a77fc2012-11-20 19:50:46 -0800806 OpRegMem(cUnit, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700807 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800808 OpRegCopy(cUnit, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700809 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700810 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800811 if (v1 == TargetReg(kArg1)) {
buzbeef0504cd2012-11-13 16:31:10 -0800812 // Swap v1 and v2, using kArg2 as a temp
buzbee52a77fc2012-11-20 19:50:46 -0800813 OpRegCopy(cUnit, TargetReg(kArg2), v1);
buzbeeb046e162012-10-30 15:48:42 -0700814 if (targetX86) {
815 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbee52a77fc2012-11-20 19:50:46 -0800816 OpRegMem(cUnit, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700817 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800818 OpRegCopy(cUnit, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700819 }
buzbee52a77fc2012-11-20 19:50:46 -0800820 OpRegCopy(cUnit, TargetReg(kArg0), TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700821 } else {
buzbeeb046e162012-10-30 15:48:42 -0700822 if (targetX86) {
823 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbee52a77fc2012-11-20 19:50:46 -0800824 OpRegMem(cUnit, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700825 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800826 OpRegCopy(cUnit, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700827 }
buzbee52a77fc2012-11-20 19:50:46 -0800828 OpRegCopy(cUnit, TargetReg(kArg0), v1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700829 }
buzbee31a4a6f2012-02-28 15:36:15 -0800830 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700831 funcOffset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
832 break;
833 case kThrowDivZero:
834 funcOffset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
835 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700836 case kThrowNoSuchMethod:
buzbee52a77fc2012-11-20 19:50:46 -0800837 OpRegCopy(cUnit, TargetReg(kArg0), v1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700838 funcOffset =
839 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
840 break;
841 case kThrowStackOverflow:
842 funcOffset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
843 // Restore stack alignment
buzbeeb046e162012-10-30 15:48:42 -0700844 if (targetX86) {
buzbee52a77fc2012-11-20 19:50:46 -0800845 OpRegImm(cUnit, kOpAdd, TargetReg(kSp), cUnit->frameSize);
buzbeeb046e162012-10-30 15:48:42 -0700846 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800847 OpRegImm(cUnit, kOpAdd, TargetReg(kSp), (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeb046e162012-10-30 15:48:42 -0700848 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700849 break;
850 default:
851 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
buzbee31a4a6f2012-02-28 15:36:15 -0800852 }
buzbee52a77fc2012-11-20 19:50:46 -0800853 ClobberCalleeSave(cUnit);
854 int rTgt = CallHelperSetup(cUnit, funcOffset);
855 CallHelper(cUnit, rTgt, funcOffset, true /* MarkSafepointPC */);
Bill Buzbeea114add2012-05-03 15:00:40 -0700856 }
buzbee31a4a6f2012-02-28 15:36:15 -0800857}
858
buzbee52a77fc2012-11-20 19:50:46 -0800859bool FastInstance(CompilationUnit* cUnit, uint32_t fieldIdx,
buzbee16da88c2012-03-20 10:38:17 -0700860 int& fieldOffset, bool& isVolatile, bool isPut)
861{
Bill Buzbeea114add2012-05-03 15:00:40 -0700862 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700863 *cUnit->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700864 cUnit->code_item, cUnit->method_idx,
865 cUnit->access_flags);
866 return cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
867 fieldOffset, isVolatile, isPut);
buzbee16da88c2012-03-20 10:38:17 -0700868}
869
buzbee52a77fc2012-11-20 19:50:46 -0800870void GenIGet(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -0800871 RegLocation rlDest, RegLocation rlObj,
Bill Buzbeea114add2012-05-03 15:00:40 -0700872 bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800873{
Bill Buzbeea114add2012-05-03 15:00:40 -0700874 int fieldOffset;
875 bool isVolatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800876
buzbee52a77fc2012-11-20 19:50:46 -0800877 bool fastPath = FastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800878
Bill Buzbeea114add2012-05-03 15:00:40 -0700879 if (fastPath && !SLOW_FIELD_PATH) {
880 RegLocation rlResult;
881 RegisterClass regClass = oatRegClassBySize(size);
882 DCHECK_GE(fieldOffset, 0);
buzbee52a77fc2012-11-20 19:50:46 -0800883 rlObj = LoadValue(cUnit, rlObj, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700884 if (isLongOrDouble) {
885 DCHECK(rlDest.wide);
buzbee52a77fc2012-11-20 19:50:46 -0800886 GenNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
buzbeeb046e162012-10-30 15:48:42 -0700887 if (cUnit->instructionSet == kX86) {
buzbee52a77fc2012-11-20 19:50:46 -0800888 rlResult = EvalLoc(cUnit, rlDest, regClass, true);
889 GenNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
890 LoadBaseDispWide(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
buzbeeb046e162012-10-30 15:48:42 -0700891 rlResult.highReg, rlObj.sRegLow);
892 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800893 GenMemBarrier(cUnit, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700894 }
895 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800896 int regPtr = AllocTemp(cUnit);
897 OpRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
898 rlResult = EvalLoc(cUnit, rlDest, regClass, true);
899 LoadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
buzbeeb046e162012-10-30 15:48:42 -0700900 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800901 GenMemBarrier(cUnit, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700902 }
buzbee52a77fc2012-11-20 19:50:46 -0800903 FreeTemp(cUnit, regPtr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700904 }
buzbee52a77fc2012-11-20 19:50:46 -0800905 StoreValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800906 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800907 rlResult = EvalLoc(cUnit, rlDest, regClass, true);
908 GenNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
909 LoadBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlResult.lowReg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700910 kWord, rlObj.sRegLow);
911 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800912 GenMemBarrier(cUnit, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700913 }
buzbee52a77fc2012-11-20 19:50:46 -0800914 StoreValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -0800915 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700916 } else {
917 int getterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pGet64Instance) :
918 (isObject ? ENTRYPOINT_OFFSET(pGetObjInstance)
919 : ENTRYPOINT_OFFSET(pGet32Instance));
buzbee52a77fc2012-11-20 19:50:46 -0800920 CallRuntimeHelperImmRegLocation(cUnit, getterOffset, fieldIdx, rlObj, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700921 if (isLongOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800922 RegLocation rlResult = GetReturnWide(cUnit, rlDest.fp);
923 StoreValueWide(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -0700924 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800925 RegLocation rlResult = GetReturn(cUnit, rlDest.fp);
926 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -0700927 }
928 }
buzbee31a4a6f2012-02-28 15:36:15 -0800929}
930
buzbee52a77fc2012-11-20 19:50:46 -0800931void GenIPut(CompilationUnit* cUnit, uint32_t fieldIdx, int optFlags, OpSize size,
buzbee408ad162012-06-06 16:45:18 -0700932 RegLocation rlSrc, RegLocation rlObj, bool isLongOrDouble, bool isObject)
buzbee31a4a6f2012-02-28 15:36:15 -0800933{
Bill Buzbeea114add2012-05-03 15:00:40 -0700934 int fieldOffset;
935 bool isVolatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800936
buzbee52a77fc2012-11-20 19:50:46 -0800937 bool fastPath = FastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700938 true);
939 if (fastPath && !SLOW_FIELD_PATH) {
940 RegisterClass regClass = oatRegClassBySize(size);
941 DCHECK_GE(fieldOffset, 0);
buzbee52a77fc2012-11-20 19:50:46 -0800942 rlObj = LoadValue(cUnit, rlObj, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700943 if (isLongOrDouble) {
944 int regPtr;
buzbee52a77fc2012-11-20 19:50:46 -0800945 rlSrc = LoadValueWide(cUnit, rlSrc, kAnyReg);
946 GenNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
947 regPtr = AllocTemp(cUnit);
948 OpRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700949 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800950 GenMemBarrier(cUnit, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 }
buzbee52a77fc2012-11-20 19:50:46 -0800952 StoreBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700953 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800954 GenMemBarrier(cUnit, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700955 }
buzbee52a77fc2012-11-20 19:50:46 -0800956 FreeTemp(cUnit, regPtr);
buzbee31a4a6f2012-02-28 15:36:15 -0800957 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800958 rlSrc = LoadValue(cUnit, rlSrc, regClass);
959 GenNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700960 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800961 GenMemBarrier(cUnit, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700962 }
buzbee52a77fc2012-11-20 19:50:46 -0800963 StoreBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700964 if (isVolatile) {
buzbee52a77fc2012-11-20 19:50:46 -0800965 GenMemBarrier(cUnit, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700966 }
967 if (isObject) {
buzbee52a77fc2012-11-20 19:50:46 -0800968 MarkGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700969 }
buzbee31a4a6f2012-02-28 15:36:15 -0800970 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700971 } else {
972 int setterOffset = isLongOrDouble ? ENTRYPOINT_OFFSET(pSet64Instance) :
973 (isObject ? ENTRYPOINT_OFFSET(pSetObjInstance)
974 : ENTRYPOINT_OFFSET(pSet32Instance));
buzbee52a77fc2012-11-20 19:50:46 -0800975 CallRuntimeHelperImmRegLocationRegLocation(cUnit, setterOffset, fieldIdx, rlObj, rlSrc, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700976 }
buzbee31a4a6f2012-02-28 15:36:15 -0800977}
978
buzbee52a77fc2012-11-20 19:50:46 -0800979void GenConstClass(CompilationUnit* cUnit, uint32_t type_idx,
buzbee6969d502012-06-15 16:40:31 -0700980 RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -0800981{
buzbee52a77fc2012-11-20 19:50:46 -0800982 RegLocation rlMethod = LoadCurrMethod(cUnit);
983 int resReg = AllocTemp(cUnit);
984 RegLocation rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700985 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -0700986 *cUnit->dex_file,
987 type_idx)) {
988 // Call out to helper which resolves type and verifies access.
buzbeef0504cd2012-11-13 16:31:10 -0800989 // Resolved type returned in kRet0.
buzbee52a77fc2012-11-20 19:50:46 -0800990 CallRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee8320f382012-09-11 16:29:42 -0700991 type_idx, rlMethod.lowReg, true);
buzbee52a77fc2012-11-20 19:50:46 -0800992 RegLocation rlResult = GetReturn(cUnit, false);
993 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -0700994 } else {
995 // We're don't need access checks, load type from dex cache
996 int32_t dex_cache_offset =
Mathieu Chartier66f19252012-09-18 08:57:04 -0700997 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value();
buzbee52a77fc2012-11-20 19:50:46 -0800998 LoadWordDisp(cUnit, rlMethod.lowReg, dex_cache_offset, resReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700999 int32_t offset_of_type =
1000 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1001 * type_idx);
buzbee52a77fc2012-11-20 19:50:46 -08001002 LoadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001003 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(*cUnit->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -07001004 type_idx) || SLOW_TYPE_PATH) {
1005 // Slow path, at runtime test if type is null and if so initialize
buzbee52a77fc2012-11-20 19:50:46 -08001006 FlushAllRegs(cUnit);
1007 LIR* branch1 = OpCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001008 // Resolved, store and hop over following code
buzbee52a77fc2012-11-20 19:50:46 -08001009 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001010 /*
1011 * Because we have stores of the target value on two paths,
1012 * clobber temp tracking for the destination using the ssa name
1013 */
buzbee52a77fc2012-11-20 19:50:46 -08001014 ClobberSReg(cUnit, rlDest.sRegLow);
1015 LIR* branch2 = OpUnconditionalBranch(cUnit,0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001016 // TUNING: move slow path to end & remove unconditional branch
buzbee52a77fc2012-11-20 19:50:46 -08001017 LIR* target1 = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeef0504cd2012-11-13 16:31:10 -08001018 // Call out to helper, which will return resolved type in kArg0
buzbee52a77fc2012-11-20 19:50:46 -08001019 CallRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx,
buzbee8320f382012-09-11 16:29:42 -07001020 rlMethod.lowReg, true);
buzbee52a77fc2012-11-20 19:50:46 -08001021 RegLocation rlResult = GetReturn(cUnit, false);
1022 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001023 /*
1024 * Because we have stores of the target value on two paths,
1025 * clobber temp tracking for the destination using the ssa name
1026 */
buzbee52a77fc2012-11-20 19:50:46 -08001027 ClobberSReg(cUnit, rlDest.sRegLow);
Bill Buzbeea114add2012-05-03 15:00:40 -07001028 // Rejoin code paths
buzbee52a77fc2012-11-20 19:50:46 -08001029 LIR* target2 = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -08001030 branch1->target = target1;
1031 branch2->target = target2;
buzbee31a4a6f2012-02-28 15:36:15 -08001032 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001033 // Fast path, we're done - just store result
buzbee52a77fc2012-11-20 19:50:46 -08001034 StoreValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001035 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001036 }
buzbee31a4a6f2012-02-28 15:36:15 -08001037}
Ian Rogersab2b55d2012-03-18 00:06:11 -07001038
buzbee52a77fc2012-11-20 19:50:46 -08001039void GenConstString(CompilationUnit* cUnit, uint32_t string_idx,
buzbee6969d502012-06-15 16:40:31 -07001040 RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001041{
Bill Buzbeea114add2012-05-03 15:00:40 -07001042 /* NOTE: Most strings should be available at compile time */
Bill Buzbeea114add2012-05-03 15:00:40 -07001043 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
1044 (sizeof(String*) * string_idx);
1045 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001046 *cUnit->dex_file, string_idx) || SLOW_STRING_PATH) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001047 // slow path, resolve string if not in dex cache
buzbee52a77fc2012-11-20 19:50:46 -08001048 FlushAllRegs(cUnit);
1049 LockCallTemps(cUnit); // Using explicit registers
1050 LoadCurrMethodDirect(cUnit, TargetReg(kArg2));
1051 LoadWordDisp(cUnit, TargetReg(kArg2),
1052 AbstractMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -08001053 // Might call out to helper, which will return resolved string in kRet0
buzbee52a77fc2012-11-20 19:50:46 -08001054 int rTgt = CallHelperSetup(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode));
1055 LoadWordDisp(cUnit, TargetReg(kArg0), offset_of_string, TargetReg(kRet0));
1056 LoadConstant(cUnit, TargetReg(kArg1), string_idx);
buzbeeb046e162012-10-30 15:48:42 -07001057 if (cUnit->instructionSet == kThumb2) {
buzbee52a77fc2012-11-20 19:50:46 -08001058 OpRegImm(cUnit, kOpCmp, TargetReg(kRet0), 0); // Is resolved?
1059 GenBarrier(cUnit);
buzbeeb046e162012-10-30 15:48:42 -07001060 // For testing, always force through helper
1061 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee52a77fc2012-11-20 19:50:46 -08001062 OpIT(cUnit, kArmCondEq, "T");
buzbeeb046e162012-10-30 15:48:42 -07001063 }
buzbee52a77fc2012-11-20 19:50:46 -08001064 OpRegCopy(cUnit, TargetReg(kArg0), TargetReg(kArg2)); // .eq
1065 LIR* callInst = OpReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
1066 MarkSafepointPC(cUnit, callInst);
1067 FreeTemp(cUnit, rTgt);
buzbeeb046e162012-10-30 15:48:42 -07001068 } else if (cUnit->instructionSet == kMips) {
buzbee52a77fc2012-11-20 19:50:46 -08001069 LIR* branch = OpCmpImmBranch(cUnit, kCondNe, TargetReg(kRet0), 0, NULL);
1070 OpRegCopy(cUnit, TargetReg(kArg0), TargetReg(kArg2)); // .eq
1071 LIR* callInst = OpReg(cUnit, kOpBlx, rTgt);
1072 MarkSafepointPC(cUnit, callInst);
1073 FreeTemp(cUnit, rTgt);
1074 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeeb046e162012-10-30 15:48:42 -07001075 branch->target = target;
1076 } else {
1077 DCHECK_EQ(cUnit->instructionSet, kX86);
buzbee52a77fc2012-11-20 19:50:46 -08001078 CallRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pResolveStringFromCode), TargetReg(kArg2), TargetReg(kArg1), true);
buzbee31a4a6f2012-02-28 15:36:15 -08001079 }
buzbee52a77fc2012-11-20 19:50:46 -08001080 GenBarrier(cUnit);
1081 StoreValue(cUnit, rlDest, GetReturn(cUnit, false));
Bill Buzbeea114add2012-05-03 15:00:40 -07001082 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001083 RegLocation rlMethod = LoadCurrMethod(cUnit);
1084 int resReg = AllocTemp(cUnit);
1085 RegLocation rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
1086 LoadWordDisp(cUnit, rlMethod.lowReg,
Mathieu Chartier66f19252012-09-18 08:57:04 -07001087 AbstractMethod::DexCacheStringsOffset().Int32Value(), resReg);
buzbee52a77fc2012-11-20 19:50:46 -08001088 LoadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
1089 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001090 }
buzbee31a4a6f2012-02-28 15:36:15 -08001091}
1092
1093/*
1094 * Let helper function take care of everything. Will
1095 * call Class::NewInstanceFromCode(type_idx, method);
1096 */
buzbee52a77fc2012-11-20 19:50:46 -08001097void GenNewInstance(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest)
buzbee31a4a6f2012-02-28 15:36:15 -08001098{
buzbee52a77fc2012-11-20 19:50:46 -08001099 FlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -07001100 // alloc will always check for resolution, do we also need to verify
1101 // access because the verifier was unable to?
1102 int funcOffset;
1103 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001104 cUnit->method_idx, *cUnit->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001105 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
1106 } else {
1107 funcOffset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
1108 }
buzbee52a77fc2012-11-20 19:50:46 -08001109 CallRuntimeHelperImmMethod(cUnit, funcOffset, type_idx, true);
1110 RegLocation rlResult = GetReturn(cUnit, false);
1111 StoreValue(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001112}
1113
buzbee52a77fc2012-11-20 19:50:46 -08001114void GenMoveException(CompilationUnit* cUnit, RegLocation rlDest)
Ian Rogers474b6da2012-09-25 00:20:38 -07001115{
buzbee52a77fc2012-11-20 19:50:46 -08001116 FlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers474b6da2012-09-25 00:20:38 -07001117 int funcOffset = ENTRYPOINT_OFFSET(pGetAndClearException);
buzbeeb046e162012-10-30 15:48:42 -07001118 if (cUnit->instructionSet == kX86) {
1119 // Runtime helper will load argument for x86.
buzbee52a77fc2012-11-20 19:50:46 -08001120 CallRuntimeHelperReg(cUnit, funcOffset, TargetReg(kArg0), false);
buzbeeb046e162012-10-30 15:48:42 -07001121 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001122 CallRuntimeHelperReg(cUnit, funcOffset, TargetReg(kSelf), false);
buzbeeb046e162012-10-30 15:48:42 -07001123 }
buzbee52a77fc2012-11-20 19:50:46 -08001124 RegLocation rlResult = GetReturn(cUnit, false);
1125 StoreValue(cUnit, rlDest, rlResult);
Ian Rogers474b6da2012-09-25 00:20:38 -07001126}
1127
buzbee52a77fc2012-11-20 19:50:46 -08001128void GenThrow(CompilationUnit* cUnit, RegLocation rlSrc)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001129{
buzbee52a77fc2012-11-20 19:50:46 -08001130 FlushAllRegs(cUnit);
1131 CallRuntimeHelperRegLocation(cUnit, ENTRYPOINT_OFFSET(pDeliverException), rlSrc, true);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001132}
1133
buzbee52a77fc2012-11-20 19:50:46 -08001134void GenInstanceof(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001135 RegLocation rlSrc)
1136{
buzbee52a77fc2012-11-20 19:50:46 -08001137 FlushAllRegs(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001138 // May generate a call - use explicit registers
buzbee52a77fc2012-11-20 19:50:46 -08001139 LockCallTemps(cUnit);
1140 LoadCurrMethodDirect(cUnit, TargetReg(kArg1)); // kArg1 <= current Method*
1141 int classReg = TargetReg(kArg2); // kArg2 will hold the Class*
Bill Buzbeea114add2012-05-03 15:00:40 -07001142 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -07001143 *cUnit->dex_file,
1144 type_idx)) {
1145 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -08001146 // returns Class* in kArg0
buzbee52a77fc2012-11-20 19:50:46 -08001147 CallRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee8320f382012-09-11 16:29:42 -07001148 type_idx, true);
buzbee52a77fc2012-11-20 19:50:46 -08001149 OpRegCopy(cUnit, classReg, TargetReg(kRet0)); // Align usage with fast path
1150 LoadValueDirectFixed(cUnit, rlSrc, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001151 } else {
buzbeef0504cd2012-11-13 16:31:10 -08001152 // Load dex cache entry into classReg (kArg2)
buzbee52a77fc2012-11-20 19:50:46 -08001153 LoadValueDirectFixed(cUnit, rlSrc, TargetReg(kArg0)); // kArg0 <= ref
1154 LoadWordDisp(cUnit, TargetReg(kArg1),
Mathieu Chartier66f19252012-09-18 08:57:04 -07001155 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), classReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001156 int32_t offset_of_type =
1157 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1158 * type_idx);
buzbee52a77fc2012-11-20 19:50:46 -08001159 LoadWordDisp(cUnit, classReg, offset_of_type, classReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001160 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001161 *cUnit->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001162 // Need to test presence of type in dex cache at runtime
buzbee52a77fc2012-11-20 19:50:46 -08001163 LIR* hopBranch = OpCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001164 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -08001165 // Call out to helper, which will return resolved type in kRet0
buzbee52a77fc2012-11-20 19:50:46 -08001166 CallRuntimeHelperImm(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true);
1167 OpRegCopy(cUnit, TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path
1168 LoadValueDirectFixed(cUnit, rlSrc, TargetReg(kArg0)); /* reload Ref */
Bill Buzbeea114add2012-05-03 15:00:40 -07001169 // Rejoin code paths
buzbee52a77fc2012-11-20 19:50:46 -08001170 LIR* hopTarget = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -08001171 hopBranch->target = hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001172 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001173 }
buzbeef0504cd2012-11-13 16:31:10 -08001174 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
buzbee52a77fc2012-11-20 19:50:46 -08001175 RegLocation rlResult = GetReturn(cUnit, false);
buzbeeb046e162012-10-30 15:48:42 -07001176 if (cUnit->instructionSet == kMips) {
buzbee52a77fc2012-11-20 19:50:46 -08001177 LoadConstant(cUnit, rlResult.lowReg, 0); // store false result for if branch is taken
buzbeeb046e162012-10-30 15:48:42 -07001178 }
buzbee52a77fc2012-11-20 19:50:46 -08001179 LIR* branch1 = OpCmpImmBranch(cUnit, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001180 /* load object->klass_ */
1181 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee52a77fc2012-11-20 19:50:46 -08001182 LoadWordDisp(cUnit, TargetReg(kArg0), Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -08001183 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
buzbee8320f382012-09-11 16:29:42 -07001184 LIR* callInst;
buzbeeb046e162012-10-30 15:48:42 -07001185 LIR* branchover = NULL;
1186 if (cUnit->instructionSet == kThumb2) {
1187 /* Uses conditional nullification */
buzbee52a77fc2012-11-20 19:50:46 -08001188 int rTgt = LoadHelper(cUnit, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1189 OpRegReg(cUnit, kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
1190 OpIT(cUnit, kArmCondEq, "EE"); // if-convert the test
1191 LoadConstant(cUnit, TargetReg(kArg0), 1); // .eq case - load true
1192 OpRegCopy(cUnit, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
1193 callInst = OpReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1194 FreeTemp(cUnit, rTgt);
buzbeeb046e162012-10-30 15:48:42 -07001195 } else {
1196 /* Uses branchovers */
buzbee52a77fc2012-11-20 19:50:46 -08001197 LoadConstant(cUnit, rlResult.lowReg, 1); // assume true
1198 branchover = OpCmpBranch(cUnit, kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
buzbeeb046e162012-10-30 15:48:42 -07001199 if (cUnit->instructionSet != kX86) {
buzbee52a77fc2012-11-20 19:50:46 -08001200 int rTgt = LoadHelper(cUnit, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1201 OpRegCopy(cUnit, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
1202 callInst = OpReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
1203 FreeTemp(cUnit, rTgt);
buzbeeb046e162012-10-30 15:48:42 -07001204 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001205 OpRegCopy(cUnit, TargetReg(kArg0), TargetReg(kArg2));
1206 callInst = OpThreadMem(cUnit, kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
buzbeeb046e162012-10-30 15:48:42 -07001207 }
1208 }
buzbee52a77fc2012-11-20 19:50:46 -08001209 MarkSafepointPC(cUnit, callInst);
1210 ClobberCalleeSave(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001211 /* branch targets here */
buzbee52a77fc2012-11-20 19:50:46 -08001212 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
1213 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001214 branch1->target = target;
buzbeeb046e162012-10-30 15:48:42 -07001215 if (cUnit->instructionSet != kThumb2) {
1216 branchover->target = target;
1217 }
buzbee31a4a6f2012-02-28 15:36:15 -08001218}
1219
buzbee52a77fc2012-11-20 19:50:46 -08001220void GenCheckCast(CompilationUnit* cUnit, uint32_t type_idx, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08001221{
buzbee52a77fc2012-11-20 19:50:46 -08001222 FlushAllRegs(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001223 // May generate a call - use explicit registers
buzbee52a77fc2012-11-20 19:50:46 -08001224 LockCallTemps(cUnit);
1225 LoadCurrMethodDirect(cUnit, TargetReg(kArg1)); // kArg1 <= current Method*
1226 int classReg = TargetReg(kArg2); // kArg2 will hold the Class*
Bill Buzbeea114add2012-05-03 15:00:40 -07001227 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
Bill Buzbeea114add2012-05-03 15:00:40 -07001228 *cUnit->dex_file,
1229 type_idx)) {
1230 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -08001231 // returns Class* in kRet0
Bill Buzbeea114add2012-05-03 15:00:40 -07001232 // InitializeTypeAndVerifyAccess(idx, method)
buzbee52a77fc2012-11-20 19:50:46 -08001233 CallRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
1234 type_idx, TargetReg(kArg1), true);
1235 OpRegCopy(cUnit, classReg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001236 } else {
buzbeef0504cd2012-11-13 16:31:10 -08001237 // Load dex cache entry into classReg (kArg2)
buzbee52a77fc2012-11-20 19:50:46 -08001238 LoadWordDisp(cUnit, TargetReg(kArg1),
Mathieu Chartier66f19252012-09-18 08:57:04 -07001239 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), classReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001240 int32_t offset_of_type =
1241 Array::DataOffset(sizeof(Class*)).Int32Value() +
1242 (sizeof(Class*) * type_idx);
buzbee52a77fc2012-11-20 19:50:46 -08001243 LoadWordDisp(cUnit, classReg, offset_of_type, classReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001244 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001245 *cUnit->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001246 // Need to test presence of type in dex cache at runtime
buzbee52a77fc2012-11-20 19:50:46 -08001247 LIR* hopBranch = OpCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001248 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -08001249 // Call out to helper, which will return resolved type in kArg0
Bill Buzbeea114add2012-05-03 15:00:40 -07001250 // InitializeTypeFromCode(idx, method)
buzbee52a77fc2012-11-20 19:50:46 -08001251 CallRuntimeHelperImmReg(cUnit, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, TargetReg(kArg1),
buzbee8320f382012-09-11 16:29:42 -07001252 true);
buzbee52a77fc2012-11-20 19:50:46 -08001253 OpRegCopy(cUnit, classReg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001254 // Rejoin code paths
buzbee52a77fc2012-11-20 19:50:46 -08001255 LIR* hopTarget = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -08001256 hopBranch->target = hopTarget;
buzbee31a4a6f2012-02-28 15:36:15 -08001257 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001258 }
buzbeef0504cd2012-11-13 16:31:10 -08001259 // At this point, classReg (kArg2) has class
buzbee52a77fc2012-11-20 19:50:46 -08001260 LoadValueDirectFixed(cUnit, rlSrc, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001261 /* Null is OK - continue */
buzbee52a77fc2012-11-20 19:50:46 -08001262 LIR* branch1 = OpCmpImmBranch(cUnit, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001263 /* load object->klass_ */
1264 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee52a77fc2012-11-20 19:50:46 -08001265 LoadWordDisp(cUnit, TargetReg(kArg0), Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -08001266 /* kArg1 now contains object->klass_ */
buzbeeb046e162012-10-30 15:48:42 -07001267 LIR* branch2;
1268 if (cUnit->instructionSet == kThumb2) {
buzbee52a77fc2012-11-20 19:50:46 -08001269 int rTgt = LoadHelper(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1270 OpRegReg(cUnit, kOpCmp, TargetReg(kArg1), classReg);
1271 branch2 = OpCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
1272 OpRegCopy(cUnit, TargetReg(kArg0), TargetReg(kArg1));
1273 OpRegCopy(cUnit, TargetReg(kArg1), TargetReg(kArg2));
1274 ClobberCalleeSave(cUnit);
1275 LIR* callInst = OpReg(cUnit, kOpBlx, rTgt);
1276 MarkSafepointPC(cUnit, callInst);
1277 FreeTemp(cUnit, rTgt);
buzbeeb046e162012-10-30 15:48:42 -07001278 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001279 branch2 = OpCmpBranch(cUnit, kCondEq, TargetReg(kArg1), classReg, NULL);
1280 CallRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), true);
buzbeeb046e162012-10-30 15:48:42 -07001281 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001282 /* branch target here */
buzbee52a77fc2012-11-20 19:50:46 -08001283 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001284 branch1->target = target;
1285 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001286}
1287
buzbee31a4a6f2012-02-28 15:36:15 -08001288/*
1289 * Generate array store
1290 *
1291 */
buzbee52a77fc2012-11-20 19:50:46 -08001292void GenArrayObjPut(CompilationUnit* cUnit, int optFlags, RegLocation rlArray,
Bill Buzbeea114add2012-05-03 15:00:40 -07001293 RegLocation rlIndex, RegLocation rlSrc, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001294{
Bill Buzbeea114add2012-05-03 15:00:40 -07001295 int lenOffset = Array::LengthOffset().Int32Value();
1296 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
buzbee31a4a6f2012-02-28 15:36:15 -08001297
buzbee52a77fc2012-11-20 19:50:46 -08001298 FlushAllRegs(cUnit); // Use explicit registers
1299 LockCallTemps(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08001300
buzbee52a77fc2012-11-20 19:50:46 -08001301 int rValue = TargetReg(kArg0); // Register holding value
1302 int rArrayClass = TargetReg(kArg1); // Register holding array's Class
1303 int rArray = TargetReg(kArg2); // Register holding array
1304 int rIndex = TargetReg(kArg3); // Register holding index into array
Ian Rogersd36c52e2012-04-09 16:29:25 -07001305
buzbee52a77fc2012-11-20 19:50:46 -08001306 LoadValueDirectFixed(cUnit, rlArray, rArray); // Grab array
1307 LoadValueDirectFixed(cUnit, rlSrc, rValue); // Grab value
1308 LoadValueDirectFixed(cUnit, rlIndex, rIndex); // Grab index
Ian Rogersd36c52e2012-04-09 16:29:25 -07001309
buzbee52a77fc2012-11-20 19:50:46 -08001310 GenNullCheck(cUnit, rlArray.sRegLow, rArray, optFlags); // NPE?
Ian Rogersd36c52e2012-04-09 16:29:25 -07001311
Bill Buzbeea114add2012-05-03 15:00:40 -07001312 // Store of null?
buzbee52a77fc2012-11-20 19:50:46 -08001313 LIR* null_value_check = OpCmpImmBranch(cUnit, kCondEq, rValue, 0, NULL);
Ian Rogersd36c52e2012-04-09 16:29:25 -07001314
Bill Buzbeea114add2012-05-03 15:00:40 -07001315 // Get the array's class.
buzbee52a77fc2012-11-20 19:50:46 -08001316 LoadWordDisp(cUnit, rArray, Object::ClassOffset().Int32Value(), rArrayClass);
1317 CallRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), rValue,
buzbee8320f382012-09-11 16:29:42 -07001318 rArrayClass, true);
buzbee52a77fc2012-11-20 19:50:46 -08001319 // Redo LoadValues in case they didn't survive the call.
1320 LoadValueDirectFixed(cUnit, rlArray, rArray); // Reload array
1321 LoadValueDirectFixed(cUnit, rlIndex, rIndex); // Reload index
1322 LoadValueDirectFixed(cUnit, rlSrc, rValue); // Reload value
Bill Buzbeea114add2012-05-03 15:00:40 -07001323 rArrayClass = INVALID_REG;
buzbee31a4a6f2012-02-28 15:36:15 -08001324
Bill Buzbeea114add2012-05-03 15:00:40 -07001325 // Branch here if value to be stored == null
buzbee52a77fc2012-11-20 19:50:46 -08001326 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001327 null_value_check->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001328
buzbeeb046e162012-10-30 15:48:42 -07001329 if (cUnit->instructionSet == kX86) {
1330 // make an extra temp available for card mark below
buzbee52a77fc2012-11-20 19:50:46 -08001331 FreeTemp(cUnit, TargetReg(kArg1));
buzbeeb046e162012-10-30 15:48:42 -07001332 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
1333 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
buzbee52a77fc2012-11-20 19:50:46 -08001334 GenRegMemCheck(cUnit, kCondUge, rIndex, rArray, lenOffset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001335 }
buzbee52a77fc2012-11-20 19:50:46 -08001336 StoreBaseIndexedDisp(cUnit, rArray, rIndex, scale,
buzbeeb046e162012-10-30 15:48:42 -07001337 dataOffset, rValue, INVALID_REG, kWord, INVALID_SREG);
1338 } else {
1339 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
1340 int regLen = INVALID_REG;
1341 if (needsRangeCheck) {
buzbee52a77fc2012-11-20 19:50:46 -08001342 regLen = TargetReg(kArg1);
1343 LoadWordDisp(cUnit, rArray, lenOffset, regLen); // Get len
buzbeeb046e162012-10-30 15:48:42 -07001344 }
1345 /* rPtr -> array data */
buzbee52a77fc2012-11-20 19:50:46 -08001346 int rPtr = AllocTemp(cUnit);
1347 OpRegRegImm(cUnit, kOpAdd, rPtr, rArray, dataOffset);
buzbeeb046e162012-10-30 15:48:42 -07001348 if (needsRangeCheck) {
buzbee52a77fc2012-11-20 19:50:46 -08001349 GenRegRegCheck(cUnit, kCondCs, rIndex, regLen, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001350 }
buzbee52a77fc2012-11-20 19:50:46 -08001351 StoreBaseIndexed(cUnit, rPtr, rIndex, rValue, scale, kWord);
1352 FreeTemp(cUnit, rPtr);
Bill Buzbeea114add2012-05-03 15:00:40 -07001353 }
buzbee52a77fc2012-11-20 19:50:46 -08001354 FreeTemp(cUnit, rIndex);
1355 MarkGCCard(cUnit, rValue, rArray);
buzbee31a4a6f2012-02-28 15:36:15 -08001356}
1357
1358/*
1359 * Generate array load
1360 */
buzbee52a77fc2012-11-20 19:50:46 -08001361void GenArrayGet(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001362 RegLocation rlArray, RegLocation rlIndex,
1363 RegLocation rlDest, int scale)
1364{
Bill Buzbeea114add2012-05-03 15:00:40 -07001365 RegisterClass regClass = oatRegClassBySize(size);
1366 int lenOffset = Array::LengthOffset().Int32Value();
1367 int dataOffset;
1368 RegLocation rlResult;
buzbee52a77fc2012-11-20 19:50:46 -08001369 rlArray = LoadValue(cUnit, rlArray, kCoreReg);
1370 rlIndex = LoadValue(cUnit, rlIndex, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001371
Bill Buzbeea114add2012-05-03 15:00:40 -07001372 if (size == kLong || size == kDouble) {
1373 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1374 } else {
1375 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1376 }
buzbee31a4a6f2012-02-28 15:36:15 -08001377
Bill Buzbeea114add2012-05-03 15:00:40 -07001378 /* null object? */
buzbee52a77fc2012-11-20 19:50:46 -08001379 GenNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001380
buzbeeb046e162012-10-30 15:48:42 -07001381 if (cUnit->instructionSet == kX86) {
1382 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
1383 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
buzbee52a77fc2012-11-20 19:50:46 -08001384 GenRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg,
buzbeeb046e162012-10-30 15:48:42 -07001385 lenOffset, kThrowArrayBounds);
1386 }
1387 if ((size == kLong) || (size == kDouble)) {
buzbee52a77fc2012-11-20 19:50:46 -08001388 int regAddr = AllocTemp(cUnit);
1389 OpLea(cUnit, regAddr, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset);
1390 FreeTemp(cUnit, rlArray.lowReg);
1391 FreeTemp(cUnit, rlIndex.lowReg);
1392 rlResult = EvalLoc(cUnit, rlDest, regClass, true);
1393 LoadBaseIndexedDisp(cUnit, regAddr, INVALID_REG, 0, 0, rlResult.lowReg,
buzbeeb046e162012-10-30 15:48:42 -07001394 rlResult.highReg, size, INVALID_SREG);
buzbee52a77fc2012-11-20 19:50:46 -08001395 StoreValueWide(cUnit, rlDest, rlResult);
buzbee31a4a6f2012-02-28 15:36:15 -08001396 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001397 rlResult = EvalLoc(cUnit, rlDest, regClass, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001398
buzbee52a77fc2012-11-20 19:50:46 -08001399 LoadBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale,
buzbeeb046e162012-10-30 15:48:42 -07001400 dataOffset, rlResult.lowReg, INVALID_REG, size,
1401 INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001402
buzbee52a77fc2012-11-20 19:50:46 -08001403 StoreValue(cUnit, rlDest, rlResult);
buzbeeb046e162012-10-30 15:48:42 -07001404 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001405 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001406 int regPtr = AllocTemp(cUnit);
buzbeeb046e162012-10-30 15:48:42 -07001407 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
1408 int regLen = INVALID_REG;
Bill Buzbeea114add2012-05-03 15:00:40 -07001409 if (needsRangeCheck) {
buzbee52a77fc2012-11-20 19:50:46 -08001410 regLen = AllocTemp(cUnit);
buzbeeb046e162012-10-30 15:48:42 -07001411 /* Get len */
buzbee52a77fc2012-11-20 19:50:46 -08001412 LoadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
Bill Buzbeea114add2012-05-03 15:00:40 -07001413 }
buzbeeb046e162012-10-30 15:48:42 -07001414 /* regPtr -> array data */
buzbee52a77fc2012-11-20 19:50:46 -08001415 OpRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1416 FreeTemp(cUnit, rlArray.lowReg);
buzbeeb046e162012-10-30 15:48:42 -07001417 if ((size == kLong) || (size == kDouble)) {
1418 if (scale) {
buzbee52a77fc2012-11-20 19:50:46 -08001419 int rNewIndex = AllocTemp(cUnit);
1420 OpRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1421 OpRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1422 FreeTemp(cUnit, rNewIndex);
buzbeeb046e162012-10-30 15:48:42 -07001423 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001424 OpRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbeeb046e162012-10-30 15:48:42 -07001425 }
buzbee52a77fc2012-11-20 19:50:46 -08001426 FreeTemp(cUnit, rlIndex.lowReg);
1427 rlResult = EvalLoc(cUnit, rlDest, regClass, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001428
buzbeeb046e162012-10-30 15:48:42 -07001429 if (needsRangeCheck) {
1430 // TODO: change kCondCS to a more meaningful name, is the sense of
1431 // carry-set/clear flipped?
buzbee52a77fc2012-11-20 19:50:46 -08001432 GenRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
1433 FreeTemp(cUnit, regLen);
buzbeeb046e162012-10-30 15:48:42 -07001434 }
buzbee52a77fc2012-11-20 19:50:46 -08001435 LoadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
buzbeeb046e162012-10-30 15:48:42 -07001436
buzbee52a77fc2012-11-20 19:50:46 -08001437 FreeTemp(cUnit, regPtr);
1438 StoreValueWide(cUnit, rlDest, rlResult);
buzbeeb046e162012-10-30 15:48:42 -07001439 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001440 rlResult = EvalLoc(cUnit, rlDest, regClass, true);
buzbeeb046e162012-10-30 15:48:42 -07001441
1442 if (needsRangeCheck) {
1443 // TODO: change kCondCS to a more meaningful name, is the sense of
1444 // carry-set/clear flipped?
buzbee52a77fc2012-11-20 19:50:46 -08001445 GenRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
1446 FreeTemp(cUnit, regLen);
buzbeeb046e162012-10-30 15:48:42 -07001447 }
buzbee52a77fc2012-11-20 19:50:46 -08001448 LoadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg, scale, size);
buzbeeb046e162012-10-30 15:48:42 -07001449
buzbee52a77fc2012-11-20 19:50:46 -08001450 FreeTemp(cUnit, regPtr);
1451 StoreValue(cUnit, rlDest, rlResult);
buzbeeb046e162012-10-30 15:48:42 -07001452 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001453 }
buzbee31a4a6f2012-02-28 15:36:15 -08001454}
1455
1456/*
1457 * Generate array store
1458 *
1459 */
buzbee52a77fc2012-11-20 19:50:46 -08001460void GenArrayPut(CompilationUnit* cUnit, int optFlags, OpSize size,
buzbee31a4a6f2012-02-28 15:36:15 -08001461 RegLocation rlArray, RegLocation rlIndex,
1462 RegLocation rlSrc, int scale)
1463{
Bill Buzbeea114add2012-05-03 15:00:40 -07001464 RegisterClass regClass = oatRegClassBySize(size);
1465 int lenOffset = Array::LengthOffset().Int32Value();
1466 int dataOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001467
Bill Buzbeea114add2012-05-03 15:00:40 -07001468 if (size == kLong || size == kDouble) {
1469 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1470 } else {
1471 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1472 }
buzbee31a4a6f2012-02-28 15:36:15 -08001473
buzbee52a77fc2012-11-20 19:50:46 -08001474 rlArray = LoadValue(cUnit, rlArray, kCoreReg);
1475 rlIndex = LoadValue(cUnit, rlIndex, kCoreReg);
buzbeeb046e162012-10-30 15:48:42 -07001476 int regPtr = INVALID_REG;
1477 if (cUnit->instructionSet != kX86) {
buzbee52a77fc2012-11-20 19:50:46 -08001478 if (IsTemp(cUnit, rlArray.lowReg)) {
1479 Clobber(cUnit, rlArray.lowReg);
buzbeeb046e162012-10-30 15:48:42 -07001480 regPtr = rlArray.lowReg;
1481 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001482 regPtr = AllocTemp(cUnit);
1483 OpRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbeeb046e162012-10-30 15:48:42 -07001484 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001485 }
buzbee31a4a6f2012-02-28 15:36:15 -08001486
Bill Buzbeea114add2012-05-03 15:00:40 -07001487 /* null object? */
buzbee52a77fc2012-11-20 19:50:46 -08001488 GenNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, optFlags);
buzbee31a4a6f2012-02-28 15:36:15 -08001489
buzbeeb046e162012-10-30 15:48:42 -07001490 if (cUnit->instructionSet == kX86) {
1491 if (!(optFlags & MIR_IGNORE_RANGE_CHECK)) {
1492 /* if (rlIndex >= [rlArray + lenOffset]) goto kThrowArrayBounds */
buzbee52a77fc2012-11-20 19:50:46 -08001493 GenRegMemCheck(cUnit, kCondUge, rlIndex.lowReg, rlArray.lowReg, lenOffset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001494 }
1495 if ((size == kLong) || (size == kDouble)) {
buzbee52a77fc2012-11-20 19:50:46 -08001496 rlSrc = LoadValueWide(cUnit, rlSrc, regClass);
buzbee31a4a6f2012-02-28 15:36:15 -08001497 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001498 rlSrc = LoadValue(cUnit, rlSrc, regClass);
buzbee31a4a6f2012-02-28 15:36:15 -08001499 }
buzbeeb046e162012-10-30 15:48:42 -07001500 // If the src reg can't be byte accessed, move it to a temp first.
1501 if ((size == kSignedByte || size == kUnsignedByte) && rlSrc.lowReg >= 4) {
buzbee52a77fc2012-11-20 19:50:46 -08001502 int temp = AllocTemp(cUnit);
1503 OpRegCopy(cUnit, temp, rlSrc.lowReg);
1504 StoreBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset, temp,
buzbeeb046e162012-10-30 15:48:42 -07001505 INVALID_REG, size, INVALID_SREG);
1506 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001507 StoreBaseIndexedDisp(cUnit, rlArray.lowReg, rlIndex.lowReg, scale, dataOffset, rlSrc.lowReg,
buzbeeb046e162012-10-30 15:48:42 -07001508 rlSrc.highReg, size, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001509 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001510 } else {
buzbeeb046e162012-10-30 15:48:42 -07001511 bool needsRangeCheck = (!(optFlags & MIR_IGNORE_RANGE_CHECK));
1512 int regLen = INVALID_REG;
Bill Buzbeea114add2012-05-03 15:00:40 -07001513 if (needsRangeCheck) {
buzbee52a77fc2012-11-20 19:50:46 -08001514 regLen = AllocTemp(cUnit);
buzbeeb046e162012-10-30 15:48:42 -07001515 //NOTE: max live temps(4) here.
1516 /* Get len */
buzbee52a77fc2012-11-20 19:50:46 -08001517 LoadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
Bill Buzbeea114add2012-05-03 15:00:40 -07001518 }
buzbeeb046e162012-10-30 15:48:42 -07001519 /* regPtr -> array data */
buzbee52a77fc2012-11-20 19:50:46 -08001520 OpRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeb046e162012-10-30 15:48:42 -07001521 /* at this point, regPtr points to array, 2 live temps */
1522 if ((size == kLong) || (size == kDouble)) {
1523 //TUNING: specific wide routine that can handle fp regs
1524 if (scale) {
buzbee52a77fc2012-11-20 19:50:46 -08001525 int rNewIndex = AllocTemp(cUnit);
1526 OpRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1527 OpRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1528 FreeTemp(cUnit, rNewIndex);
buzbeeb046e162012-10-30 15:48:42 -07001529 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001530 OpRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
buzbeeb046e162012-10-30 15:48:42 -07001531 }
buzbee52a77fc2012-11-20 19:50:46 -08001532 rlSrc = LoadValueWide(cUnit, rlSrc, regClass);
buzbeeb046e162012-10-30 15:48:42 -07001533
1534 if (needsRangeCheck) {
buzbee52a77fc2012-11-20 19:50:46 -08001535 GenRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
1536 FreeTemp(cUnit, regLen);
buzbeeb046e162012-10-30 15:48:42 -07001537 }
1538
buzbee52a77fc2012-11-20 19:50:46 -08001539 StoreBaseDispWide(cUnit, regPtr, 0, rlSrc.lowReg, rlSrc.highReg);
buzbeeb046e162012-10-30 15:48:42 -07001540
buzbee52a77fc2012-11-20 19:50:46 -08001541 FreeTemp(cUnit, regPtr);
buzbeeb046e162012-10-30 15:48:42 -07001542 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001543 rlSrc = LoadValue(cUnit, rlSrc, regClass);
buzbeeb046e162012-10-30 15:48:42 -07001544 if (needsRangeCheck) {
buzbee52a77fc2012-11-20 19:50:46 -08001545 GenRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, kThrowArrayBounds);
1546 FreeTemp(cUnit, regLen);
buzbeeb046e162012-10-30 15:48:42 -07001547 }
buzbee52a77fc2012-11-20 19:50:46 -08001548 StoreBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
buzbeeb046e162012-10-30 15:48:42 -07001549 scale, size);
1550 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001551 }
buzbee31a4a6f2012-02-28 15:36:15 -08001552}
1553
buzbee52a77fc2012-11-20 19:50:46 -08001554void GenLong3Addr(CompilationUnit* cUnit, OpKind firstOp,
buzbee31a4a6f2012-02-28 15:36:15 -08001555 OpKind secondOp, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001556 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001557{
Bill Buzbeea114add2012-05-03 15:00:40 -07001558 RegLocation rlResult;
buzbeeb046e162012-10-30 15:48:42 -07001559 if (cUnit->instructionSet == kThumb2) {
1560 /*
1561 * NOTE: This is the one place in the code in which we might have
1562 * as many as six live temporary registers. There are 5 in the normal
1563 * set for Arm. Until we have spill capabilities, temporarily add
1564 * lr to the temp set. It is safe to do this locally, but note that
1565 * lr is used explicitly elsewhere in the code generator and cannot
1566 * normally be used as a general temp register.
1567 */
buzbee52a77fc2012-11-20 19:50:46 -08001568 MarkTemp(cUnit, TargetReg(kLr)); // Add lr to the temp pool
1569 FreeTemp(cUnit, TargetReg(kLr)); // and make it available
buzbeeb046e162012-10-30 15:48:42 -07001570 }
buzbee52a77fc2012-11-20 19:50:46 -08001571 rlSrc1 = LoadValueWide(cUnit, rlSrc1, kCoreReg);
1572 rlSrc2 = LoadValueWide(cUnit, rlSrc2, kCoreReg);
1573 rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001574 // The longs may overlap - use intermediate temp if so
buzbeea4a970a2012-11-08 07:54:03 -08001575 if ((rlResult.lowReg == rlSrc1.highReg) || (rlResult.lowReg == rlSrc2.highReg)){
buzbee52a77fc2012-11-20 19:50:46 -08001576 int tReg = AllocTemp(cUnit);
1577 OpRegRegReg(cUnit, firstOp, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
1578 OpRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
1579 OpRegCopy(cUnit, rlResult.lowReg, tReg);
1580 FreeTemp(cUnit, tReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001581 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001582 OpRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
1583 OpRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
Bill Buzbeea114add2012-05-03 15:00:40 -07001584 rlSrc2.highReg);
1585 }
1586 /*
1587 * NOTE: If rlDest refers to a frame variable in a large frame, the
buzbee52a77fc2012-11-20 19:50:46 -08001588 * following StoreValueWide might need to allocate a temp register.
Bill Buzbeea114add2012-05-03 15:00:40 -07001589 * To further work around the lack of a spill capability, explicitly
1590 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1591 * Remove when spill is functional.
1592 */
buzbee52a77fc2012-11-20 19:50:46 -08001593 FreeRegLocTemps(cUnit, rlResult, rlSrc1);
1594 FreeRegLocTemps(cUnit, rlResult, rlSrc2);
1595 StoreValueWide(cUnit, rlDest, rlResult);
buzbeeb046e162012-10-30 15:48:42 -07001596 if (cUnit->instructionSet == kThumb2) {
buzbee52a77fc2012-11-20 19:50:46 -08001597 Clobber(cUnit, TargetReg(kLr));
1598 UnmarkTemp(cUnit, TargetReg(kLr)); // Remove lr from the temp pool
buzbeeb046e162012-10-30 15:48:42 -07001599 }
buzbee31a4a6f2012-02-28 15:36:15 -08001600}
1601
1602
buzbee52a77fc2012-11-20 19:50:46 -08001603bool GenShiftOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -08001604 RegLocation rlSrc1, RegLocation rlShift)
1605{
Bill Buzbeea114add2012-05-03 15:00:40 -07001606 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08001607
buzbee408ad162012-06-06 16:45:18 -07001608 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001609 case Instruction::SHL_LONG:
1610 case Instruction::SHL_LONG_2ADDR:
1611 funcOffset = ENTRYPOINT_OFFSET(pShlLong);
1612 break;
1613 case Instruction::SHR_LONG:
1614 case Instruction::SHR_LONG_2ADDR:
1615 funcOffset = ENTRYPOINT_OFFSET(pShrLong);
1616 break;
1617 case Instruction::USHR_LONG:
1618 case Instruction::USHR_LONG_2ADDR:
1619 funcOffset = ENTRYPOINT_OFFSET(pUshrLong);
1620 break;
1621 default:
1622 LOG(FATAL) << "Unexpected case";
1623 return true;
1624 }
buzbee52a77fc2012-11-20 19:50:46 -08001625 FlushAllRegs(cUnit); /* Send everything to home location */
1626 CallRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlShift, false);
1627 RegLocation rlResult = GetReturnWide(cUnit, false);
1628 StoreValueWide(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001629 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001630}
1631
1632
buzbee52a77fc2012-11-20 19:50:46 -08001633bool GenArithOpInt(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07001634 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08001635{
Bill Buzbeea114add2012-05-03 15:00:40 -07001636 OpKind op = kOpBkpt;
jeffhao4f8f04a2012-10-02 18:10:35 -07001637 bool isDivRem = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001638 bool checkZero = false;
1639 bool unary = false;
1640 RegLocation rlResult;
1641 bool shiftOp = false;
buzbee408ad162012-06-06 16:45:18 -07001642 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001643 case Instruction::NEG_INT:
1644 op = kOpNeg;
1645 unary = true;
1646 break;
1647 case Instruction::NOT_INT:
1648 op = kOpMvn;
1649 unary = true;
1650 break;
1651 case Instruction::ADD_INT:
1652 case Instruction::ADD_INT_2ADDR:
1653 op = kOpAdd;
1654 break;
1655 case Instruction::SUB_INT:
1656 case Instruction::SUB_INT_2ADDR:
1657 op = kOpSub;
1658 break;
1659 case Instruction::MUL_INT:
1660 case Instruction::MUL_INT_2ADDR:
1661 op = kOpMul;
1662 break;
1663 case Instruction::DIV_INT:
1664 case Instruction::DIV_INT_2ADDR:
1665 checkZero = true;
1666 op = kOpDiv;
jeffhao4f8f04a2012-10-02 18:10:35 -07001667 isDivRem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001668 break;
buzbeef0504cd2012-11-13 16:31:10 -08001669 /* NOTE: returns in kArg1 */
Bill Buzbeea114add2012-05-03 15:00:40 -07001670 case Instruction::REM_INT:
1671 case Instruction::REM_INT_2ADDR:
1672 checkZero = true;
1673 op = kOpRem;
jeffhao4f8f04a2012-10-02 18:10:35 -07001674 isDivRem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001675 break;
1676 case Instruction::AND_INT:
1677 case Instruction::AND_INT_2ADDR:
1678 op = kOpAnd;
1679 break;
1680 case Instruction::OR_INT:
1681 case Instruction::OR_INT_2ADDR:
1682 op = kOpOr;
1683 break;
1684 case Instruction::XOR_INT:
1685 case Instruction::XOR_INT_2ADDR:
1686 op = kOpXor;
1687 break;
1688 case Instruction::SHL_INT:
1689 case Instruction::SHL_INT_2ADDR:
1690 shiftOp = true;
1691 op = kOpLsl;
1692 break;
1693 case Instruction::SHR_INT:
1694 case Instruction::SHR_INT_2ADDR:
1695 shiftOp = true;
1696 op = kOpAsr;
1697 break;
1698 case Instruction::USHR_INT:
1699 case Instruction::USHR_INT_2ADDR:
1700 shiftOp = true;
1701 op = kOpLsr;
1702 break;
1703 default:
buzbeecbd6d442012-11-17 14:11:25 -08001704 LOG(FATAL) << "Invalid word arith op: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001705 }
jeffhao4f8f04a2012-10-02 18:10:35 -07001706 if (!isDivRem) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001707 if (unary) {
buzbee52a77fc2012-11-20 19:50:46 -08001708 rlSrc1 = LoadValue(cUnit, rlSrc1, kCoreReg);
1709 rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
1710 OpRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001711 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -07001712 if (shiftOp) {
buzbeeb046e162012-10-30 15:48:42 -07001713 int tReg = INVALID_REG;
1714 if (cUnit->instructionSet == kX86) {
1715 // X86 doesn't require masking and must use ECX
buzbee52a77fc2012-11-20 19:50:46 -08001716 tReg = TargetReg(kCount); // rCX
1717 LoadValueDirectFixed(cUnit, rlSrc2, tReg);
buzbeeb046e162012-10-30 15:48:42 -07001718 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001719 rlSrc2 = LoadValue(cUnit, rlSrc2, kCoreReg);
1720 tReg = AllocTemp(cUnit);
1721 OpRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
buzbeeb046e162012-10-30 15:48:42 -07001722 }
buzbee52a77fc2012-11-20 19:50:46 -08001723 rlSrc1 = LoadValue(cUnit, rlSrc1, kCoreReg);
1724 rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
1725 OpRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, tReg);
1726 FreeTemp(cUnit, tReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001727 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001728 rlSrc1 = LoadValue(cUnit, rlSrc1, kCoreReg);
1729 rlSrc2 = LoadValue(cUnit, rlSrc2, kCoreReg);
1730 rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
1731 OpRegRegReg(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001732 }
buzbee31a4a6f2012-02-28 15:36:15 -08001733 }
buzbee52a77fc2012-11-20 19:50:46 -08001734 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001735 } else {
buzbeeb046e162012-10-30 15:48:42 -07001736 if (cUnit->instructionSet == kMips) {
buzbee52a77fc2012-11-20 19:50:46 -08001737 rlSrc1 = LoadValue(cUnit, rlSrc1, kCoreReg);
1738 rlSrc2 = LoadValue(cUnit, rlSrc2, kCoreReg);
buzbeeb046e162012-10-30 15:48:42 -07001739 if (checkZero) {
buzbee52a77fc2012-11-20 19:50:46 -08001740 GenImmedCheck(cUnit, kCondEq, rlSrc2.lowReg, 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001741 }
buzbee52a77fc2012-11-20 19:50:46 -08001742 rlResult = GenDivRem(cUnit, rlDest, rlSrc1.lowReg, rlSrc2.lowReg, op == kOpDiv);
jeffhao4f8f04a2012-10-02 18:10:35 -07001743 } else {
buzbeeb046e162012-10-30 15:48:42 -07001744 int funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee52a77fc2012-11-20 19:50:46 -08001745 FlushAllRegs(cUnit); /* Send everything to home location */
1746 LoadValueDirectFixed(cUnit, rlSrc2, TargetReg(kArg1));
1747 int rTgt = CallHelperSetup(cUnit, funcOffset);
1748 LoadValueDirectFixed(cUnit, rlSrc1, TargetReg(kArg0));
buzbeeb046e162012-10-30 15:48:42 -07001749 if (checkZero) {
buzbee52a77fc2012-11-20 19:50:46 -08001750 GenImmedCheck(cUnit, kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001751 }
1752 // NOTE: callout here is not a safepoint
buzbee52a77fc2012-11-20 19:50:46 -08001753 CallHelper(cUnit, rTgt, funcOffset, false /* not a safepoint */ );
buzbeeb046e162012-10-30 15:48:42 -07001754 if (op == kOpDiv)
buzbee52a77fc2012-11-20 19:50:46 -08001755 rlResult = GetReturn(cUnit, false);
buzbeeb046e162012-10-30 15:48:42 -07001756 else
buzbee52a77fc2012-11-20 19:50:46 -08001757 rlResult = GetReturnAlt(cUnit);
jeffhao4f8f04a2012-10-02 18:10:35 -07001758 }
buzbee52a77fc2012-11-20 19:50:46 -08001759 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001760 }
1761 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001762}
1763
1764/*
1765 * The following are the first-level codegen routines that analyze the format
1766 * of each bytecode then either dispatch special purpose codegen routines
1767 * or produce corresponding Thumb instructions directly.
1768 */
1769
buzbee52a77fc2012-11-20 19:50:46 -08001770bool IsPowerOfTwo(int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001771{
Bill Buzbeea114add2012-05-03 15:00:40 -07001772 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001773}
1774
1775// Returns true if no more than two bits are set in 'x'.
buzbee52a77fc2012-11-20 19:50:46 -08001776bool IsPopCountLE2(unsigned int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001777{
Bill Buzbeea114add2012-05-03 15:00:40 -07001778 x &= x - 1;
1779 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001780}
1781
1782// Returns the index of the lowest set bit in 'x'.
buzbee52a77fc2012-11-20 19:50:46 -08001783int LowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001784 int bit_posn = 0;
1785 while ((x & 0xf) == 0) {
1786 bit_posn += 4;
1787 x >>= 4;
1788 }
1789 while ((x & 1) == 0) {
1790 bit_posn++;
1791 x >>= 1;
1792 }
1793 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001794}
1795
1796// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1797// and store the result in 'rlDest'.
buzbee52a77fc2012-11-20 19:50:46 -08001798bool HandleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
Bill Buzbeea114add2012-05-03 15:00:40 -07001799 RegLocation rlSrc, RegLocation rlDest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001800{
buzbee52a77fc2012-11-20 19:50:46 -08001801 if ((lit < 2) || ((cUnit->instructionSet != kThumb2) && !IsPowerOfTwo(lit))) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001802 return false;
buzbee0f79d722012-11-01 15:35:27 -07001803 }
buzbeeb046e162012-10-30 15:48:42 -07001804 // No divide instruction for Arm, so check for more special cases
buzbee52a77fc2012-11-20 19:50:46 -08001805 if ((cUnit->instructionSet == kThumb2) && !IsPowerOfTwo(lit)) {
1806 return SmallLiteralDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001807 }
buzbee52a77fc2012-11-20 19:50:46 -08001808 int k = LowestSetBit(lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001809 if (k >= 30) {
1810 // Avoid special cases.
1811 return false;
1812 }
1813 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1814 dalvikOpcode == Instruction::DIV_INT_LIT16);
buzbee52a77fc2012-11-20 19:50:46 -08001815 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
1816 RegLocation rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001817 if (div) {
buzbee52a77fc2012-11-20 19:50:46 -08001818 int tReg = AllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001819 if (lit == 2) {
1820 // Division by 2 is by far the most common division by constant.
buzbee52a77fc2012-11-20 19:50:46 -08001821 OpRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1822 OpRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1823 OpRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001824 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001825 OpRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1826 OpRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1827 OpRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1828 OpRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001829 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001830 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001831 int tReg1 = AllocTemp(cUnit);
1832 int tReg2 = AllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001833 if (lit == 2) {
buzbee52a77fc2012-11-20 19:50:46 -08001834 OpRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1835 OpRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1836 OpRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit -1);
1837 OpRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001838 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001839 OpRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1840 OpRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1841 OpRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1842 OpRegRegImm(cUnit, kOpAnd, tReg2, tReg2, lit - 1);
1843 OpRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001844 }
1845 }
buzbee52a77fc2012-11-20 19:50:46 -08001846 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001847 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001848}
1849
buzbee31a4a6f2012-02-28 15:36:15 -08001850// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1851// and store the result in 'rlDest'.
buzbee52a77fc2012-11-20 19:50:46 -08001852bool HandleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
buzbee31a4a6f2012-02-28 15:36:15 -08001853 RegLocation rlDest, int lit)
1854{
Bill Buzbeea114add2012-05-03 15:00:40 -07001855 // Can we simplify this multiplication?
1856 bool powerOfTwo = false;
1857 bool popCountLE2 = false;
1858 bool powerOfTwoMinusOne = false;
1859 if (lit < 2) {
1860 // Avoid special cases.
1861 return false;
buzbee52a77fc2012-11-20 19:50:46 -08001862 } else if (IsPowerOfTwo(lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001863 powerOfTwo = true;
buzbee52a77fc2012-11-20 19:50:46 -08001864 } else if (IsPopCountLE2(lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001865 popCountLE2 = true;
buzbee52a77fc2012-11-20 19:50:46 -08001866 } else if (IsPowerOfTwo(lit + 1)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001867 powerOfTwoMinusOne = true;
1868 } else {
1869 return false;
1870 }
buzbee52a77fc2012-11-20 19:50:46 -08001871 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
1872 RegLocation rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001873 if (powerOfTwo) {
1874 // Shift.
buzbee52a77fc2012-11-20 19:50:46 -08001875 OpRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1876 LowestSetBit(lit));
Bill Buzbeea114add2012-05-03 15:00:40 -07001877 } else if (popCountLE2) {
1878 // Shift and add and shift.
buzbee52a77fc2012-11-20 19:50:46 -08001879 int firstBit = LowestSetBit(lit);
1880 int secondBit = LowestSetBit(lit ^ (1 << firstBit));
1881 GenMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
Bill Buzbeea114add2012-05-03 15:00:40 -07001882 firstBit, secondBit);
1883 } else {
1884 // Reverse subtract: (src << (shift + 1)) - src.
1885 DCHECK(powerOfTwoMinusOne);
buzbee52a77fc2012-11-20 19:50:46 -08001886 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
1887 int tReg = AllocTemp(cUnit);
1888 OpRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, LowestSetBit(lit + 1));
1889 OpRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001890 }
buzbee52a77fc2012-11-20 19:50:46 -08001891 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001892 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001893}
1894
buzbee52a77fc2012-11-20 19:50:46 -08001895bool GenArithOpIntLit(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee408ad162012-06-06 16:45:18 -07001896 RegLocation rlDest, RegLocation rlSrc, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001897{
Bill Buzbeea114add2012-05-03 15:00:40 -07001898 RegLocation rlResult;
buzbeecbd6d442012-11-17 14:11:25 -08001899 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */
Bill Buzbeea114add2012-05-03 15:00:40 -07001900 int shiftOp = false;
1901 bool isDiv = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001902
buzbee408ad162012-06-06 16:45:18 -07001903 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001904 case Instruction::RSUB_INT_LIT8:
1905 case Instruction::RSUB_INT: {
1906 int tReg;
1907 //TUNING: add support for use of Arm rsub op
buzbee52a77fc2012-11-20 19:50:46 -08001908 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
1909 tReg = AllocTemp(cUnit);
1910 LoadConstant(cUnit, tReg, lit);
1911 rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
1912 OpRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1913 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001914 return false;
1915 break;
buzbee31a4a6f2012-02-28 15:36:15 -08001916 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001917
1918 case Instruction::ADD_INT_LIT8:
1919 case Instruction::ADD_INT_LIT16:
1920 op = kOpAdd;
1921 break;
1922 case Instruction::MUL_INT_LIT8:
1923 case Instruction::MUL_INT_LIT16: {
buzbee52a77fc2012-11-20 19:50:46 -08001924 if (HandleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001925 return false;
1926 }
1927 op = kOpMul;
1928 break;
buzbee31a4a6f2012-02-28 15:36:15 -08001929 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001930 case Instruction::AND_INT_LIT8:
1931 case Instruction::AND_INT_LIT16:
1932 op = kOpAnd;
1933 break;
1934 case Instruction::OR_INT_LIT8:
1935 case Instruction::OR_INT_LIT16:
1936 op = kOpOr;
1937 break;
1938 case Instruction::XOR_INT_LIT8:
1939 case Instruction::XOR_INT_LIT16:
1940 op = kOpXor;
1941 break;
1942 case Instruction::SHL_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001943 case Instruction::SHL_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07001944 lit &= 31;
1945 shiftOp = true;
1946 op = kOpLsl;
1947 break;
1948 case Instruction::SHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001949 case Instruction::SHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07001950 lit &= 31;
1951 shiftOp = true;
1952 op = kOpAsr;
1953 break;
1954 case Instruction::USHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001955 case Instruction::USHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07001956 lit &= 31;
1957 shiftOp = true;
1958 op = kOpLsr;
1959 break;
1960
1961 case Instruction::DIV_INT_LIT8:
1962 case Instruction::DIV_INT_LIT16:
1963 case Instruction::REM_INT_LIT8:
jeffhao4f8f04a2012-10-02 18:10:35 -07001964 case Instruction::REM_INT_LIT16: {
Bill Buzbeea114add2012-05-03 15:00:40 -07001965 if (lit == 0) {
buzbee52a77fc2012-11-20 19:50:46 -08001966 GenImmedCheck(cUnit, kCondAl, 0, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07001967 return false;
1968 }
buzbee52a77fc2012-11-20 19:50:46 -08001969 if (HandleEasyDivide(cUnit, opcode, rlSrc, rlDest, lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001970 return false;
1971 }
buzbee408ad162012-06-06 16:45:18 -07001972 if ((opcode == Instruction::DIV_INT_LIT8) ||
1973 (opcode == Instruction::DIV_INT_LIT16)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001974 isDiv = true;
1975 } else {
1976 isDiv = false;
1977 }
buzbeeb046e162012-10-30 15:48:42 -07001978 if (cUnit->instructionSet == kMips) {
buzbee52a77fc2012-11-20 19:50:46 -08001979 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
1980 rlResult = GenDivRemLit(cUnit, rlDest, rlSrc.lowReg, lit, isDiv);
jeffhao4f8f04a2012-10-02 18:10:35 -07001981 } else {
buzbee52a77fc2012-11-20 19:50:46 -08001982 FlushAllRegs(cUnit); /* Everything to home location */
1983 LoadValueDirectFixed(cUnit, rlSrc, TargetReg(kArg0));
1984 Clobber(cUnit, TargetReg(kArg0));
buzbeeb046e162012-10-30 15:48:42 -07001985 int funcOffset = ENTRYPOINT_OFFSET(pIdivmod);
buzbee52a77fc2012-11-20 19:50:46 -08001986 CallRuntimeHelperRegImm(cUnit, funcOffset, TargetReg(kArg0), lit, false);
buzbeeb046e162012-10-30 15:48:42 -07001987 if (isDiv)
buzbee52a77fc2012-11-20 19:50:46 -08001988 rlResult = GetReturn(cUnit, false);
buzbeeb046e162012-10-30 15:48:42 -07001989 else
buzbee52a77fc2012-11-20 19:50:46 -08001990 rlResult = GetReturnAlt(cUnit);
jeffhao4f8f04a2012-10-02 18:10:35 -07001991 }
buzbee52a77fc2012-11-20 19:50:46 -08001992 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07001993 return false;
1994 break;
jeffhao4f8f04a2012-10-02 18:10:35 -07001995 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001996 default:
1997 return true;
1998 }
buzbee52a77fc2012-11-20 19:50:46 -08001999 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
2000 rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07002001 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2002 if (shiftOp && (lit == 0)) {
buzbee52a77fc2012-11-20 19:50:46 -08002003 OpRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07002004 } else {
buzbee52a77fc2012-11-20 19:50:46 -08002005 OpRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07002006 }
buzbee52a77fc2012-11-20 19:50:46 -08002007 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002008 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002009}
2010
buzbee52a77fc2012-11-20 19:50:46 -08002011bool GenArithOpLong(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -07002012 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee31a4a6f2012-02-28 15:36:15 -08002013{
Bill Buzbeea114add2012-05-03 15:00:40 -07002014 RegLocation rlResult;
2015 OpKind firstOp = kOpBkpt;
2016 OpKind secondOp = kOpBkpt;
2017 bool callOut = false;
2018 bool checkZero = false;
2019 int funcOffset;
buzbee52a77fc2012-11-20 19:50:46 -08002020 int retReg = TargetReg(kRet0);
buzbee31a4a6f2012-02-28 15:36:15 -08002021
buzbee408ad162012-06-06 16:45:18 -07002022 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002023 case Instruction::NOT_LONG:
buzbee52a77fc2012-11-20 19:50:46 -08002024 rlSrc2 = LoadValueWide(cUnit, rlSrc2, kCoreReg);
2025 rlResult = EvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07002026 // Check for destructive overlap
2027 if (rlResult.lowReg == rlSrc2.highReg) {
buzbee52a77fc2012-11-20 19:50:46 -08002028 int tReg = AllocTemp(cUnit);
2029 OpRegCopy(cUnit, tReg, rlSrc2.highReg);
2030 OpRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2031 OpRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
2032 FreeTemp(cUnit, tReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07002033 } else {
buzbee52a77fc2012-11-20 19:50:46 -08002034 OpRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
2035 OpRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -07002036 }
buzbee52a77fc2012-11-20 19:50:46 -08002037 StoreValueWide(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002038 return false;
2039 break;
2040 case Instruction::ADD_LONG:
2041 case Instruction::ADD_LONG_2ADDR:
buzbeeb046e162012-10-30 15:48:42 -07002042 if (cUnit->instructionSet != kThumb2) {
buzbee52a77fc2012-11-20 19:50:46 -08002043 return GenAddLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeeb046e162012-10-30 15:48:42 -07002044 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002045 firstOp = kOpAdd;
2046 secondOp = kOpAdc;
2047 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002048 case Instruction::SUB_LONG:
2049 case Instruction::SUB_LONG_2ADDR:
buzbeeb046e162012-10-30 15:48:42 -07002050 if (cUnit->instructionSet != kThumb2) {
buzbee52a77fc2012-11-20 19:50:46 -08002051 return GenSubLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeeb046e162012-10-30 15:48:42 -07002052 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002053 firstOp = kOpSub;
2054 secondOp = kOpSbc;
2055 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002056 case Instruction::MUL_LONG:
2057 case Instruction::MUL_LONG_2ADDR:
2058 callOut = true;
buzbee52a77fc2012-11-20 19:50:46 -08002059 retReg = TargetReg(kRet0);
Bill Buzbeea114add2012-05-03 15:00:40 -07002060 funcOffset = ENTRYPOINT_OFFSET(pLmul);
2061 break;
2062 case Instruction::DIV_LONG:
2063 case Instruction::DIV_LONG_2ADDR:
2064 callOut = true;
2065 checkZero = true;
buzbee52a77fc2012-11-20 19:50:46 -08002066 retReg = TargetReg(kRet0);
jeffhao644d5312012-05-03 19:04:49 -07002067 funcOffset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002068 break;
2069 case Instruction::REM_LONG:
2070 case Instruction::REM_LONG_2ADDR:
2071 callOut = true;
2072 checkZero = true;
jeffhao644d5312012-05-03 19:04:49 -07002073 funcOffset = ENTRYPOINT_OFFSET(pLdivmod);
buzbeef0504cd2012-11-13 16:31:10 -08002074 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
buzbee52a77fc2012-11-20 19:50:46 -08002075 retReg = (cUnit->instructionSet == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0);
Bill Buzbeea114add2012-05-03 15:00:40 -07002076 break;
2077 case Instruction::AND_LONG_2ADDR:
2078 case Instruction::AND_LONG:
buzbeeb046e162012-10-30 15:48:42 -07002079 if (cUnit->instructionSet == kX86) {
buzbee52a77fc2012-11-20 19:50:46 -08002080 return GenAndLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeeb046e162012-10-30 15:48:42 -07002081 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002082 firstOp = kOpAnd;
2083 secondOp = kOpAnd;
2084 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002085 case Instruction::OR_LONG:
2086 case Instruction::OR_LONG_2ADDR:
buzbeeb046e162012-10-30 15:48:42 -07002087 if (cUnit->instructionSet == kX86) {
buzbee52a77fc2012-11-20 19:50:46 -08002088 return GenOrLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeeb046e162012-10-30 15:48:42 -07002089 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002090 firstOp = kOpOr;
2091 secondOp = kOpOr;
2092 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002093 case Instruction::XOR_LONG:
2094 case Instruction::XOR_LONG_2ADDR:
buzbeeb046e162012-10-30 15:48:42 -07002095 if (cUnit->instructionSet == kX86) {
buzbee52a77fc2012-11-20 19:50:46 -08002096 return GenXorLong(cUnit, rlDest, rlSrc1, rlSrc2);
buzbeeb046e162012-10-30 15:48:42 -07002097 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002098 firstOp = kOpXor;
2099 secondOp = kOpXor;
2100 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002101 case Instruction::NEG_LONG: {
buzbee52a77fc2012-11-20 19:50:46 -08002102 return GenNegLong(cUnit, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08002103 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002104 default:
2105 LOG(FATAL) << "Invalid long arith op";
2106 }
2107 if (!callOut) {
buzbee52a77fc2012-11-20 19:50:46 -08002108 GenLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -07002109 } else {
buzbee52a77fc2012-11-20 19:50:46 -08002110 FlushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -07002111 if (checkZero) {
buzbee52a77fc2012-11-20 19:50:46 -08002112 LoadValueDirectWideFixed(cUnit, rlSrc2, TargetReg(kArg2), TargetReg(kArg3));
2113 int rTgt = CallHelperSetup(cUnit, funcOffset);
2114 GenDivZeroCheck(cUnit, TargetReg(kArg2), TargetReg(kArg3));
2115 LoadValueDirectWideFixed(cUnit, rlSrc1, TargetReg(kArg0), TargetReg(kArg1));
buzbee8320f382012-09-11 16:29:42 -07002116 // NOTE: callout here is not a safepoint
buzbee52a77fc2012-11-20 19:50:46 -08002117 CallHelper(cUnit, rTgt, funcOffset, false /* not safepoint */);
buzbee31a4a6f2012-02-28 15:36:15 -08002118 } else {
buzbee52a77fc2012-11-20 19:50:46 -08002119 CallRuntimeHelperRegLocationRegLocation(cUnit, funcOffset,
buzbee8320f382012-09-11 16:29:42 -07002120 rlSrc1, rlSrc2, false);
buzbee31a4a6f2012-02-28 15:36:15 -08002121 }
buzbeef0504cd2012-11-13 16:31:10 -08002122 // Adjust return regs in to handle case of rem returning kArg2/kArg3
buzbee52a77fc2012-11-20 19:50:46 -08002123 if (retReg == TargetReg(kRet0))
2124 rlResult = GetReturnWide(cUnit, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07002125 else
buzbee52a77fc2012-11-20 19:50:46 -08002126 rlResult = GetReturnWideAlt(cUnit);
2127 StoreValueWide(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002128 }
2129 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002130}
2131
buzbee52a77fc2012-11-20 19:50:46 -08002132bool GenConversionCall(CompilationUnit* cUnit, int funcOffset,
buzbee408ad162012-06-06 16:45:18 -07002133 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002134{
Bill Buzbeea114add2012-05-03 15:00:40 -07002135 /*
2136 * Don't optimize the register usage since it calls out to support
2137 * functions
2138 */
buzbee52a77fc2012-11-20 19:50:46 -08002139 FlushAllRegs(cUnit); /* Send everything to home location */
buzbee408ad162012-06-06 16:45:18 -07002140 if (rlSrc.wide) {
buzbee52a77fc2012-11-20 19:50:46 -08002141 LoadValueDirectWideFixed(cUnit, rlSrc, rlSrc.fp ? TargetReg(kFArg0) : TargetReg(kArg0),
2142 rlSrc.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee408ad162012-06-06 16:45:18 -07002143 } else {
buzbee52a77fc2012-11-20 19:50:46 -08002144 LoadValueDirectFixed(cUnit, rlSrc, rlSrc.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -07002145 }
buzbee52a77fc2012-11-20 19:50:46 -08002146 CallRuntimeHelperRegLocation(cUnit, funcOffset, rlSrc, false);
buzbee408ad162012-06-06 16:45:18 -07002147 if (rlDest.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002148 RegLocation rlResult;
buzbee52a77fc2012-11-20 19:50:46 -08002149 rlResult = GetReturnWide(cUnit, rlDest.fp);
2150 StoreValueWide(cUnit, rlDest, rlResult);
buzbee408ad162012-06-06 16:45:18 -07002151 } else {
2152 RegLocation rlResult;
buzbee52a77fc2012-11-20 19:50:46 -08002153 rlResult = GetReturn(cUnit, rlDest.fp);
2154 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002155 }
2156 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002157}
2158
buzbee52a77fc2012-11-20 19:50:46 -08002159bool GenArithOpFloatPortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002160 RegLocation rlDest, RegLocation rlSrc1,
2161 RegLocation rlSrc2)
2162{
Bill Buzbeea114add2012-05-03 15:00:40 -07002163 RegLocation rlResult;
2164 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002165
buzbee408ad162012-06-06 16:45:18 -07002166 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002167 case Instruction::ADD_FLOAT_2ADDR:
2168 case Instruction::ADD_FLOAT:
2169 funcOffset = ENTRYPOINT_OFFSET(pFadd);
2170 break;
2171 case Instruction::SUB_FLOAT_2ADDR:
2172 case Instruction::SUB_FLOAT:
2173 funcOffset = ENTRYPOINT_OFFSET(pFsub);
2174 break;
2175 case Instruction::DIV_FLOAT_2ADDR:
2176 case Instruction::DIV_FLOAT:
2177 funcOffset = ENTRYPOINT_OFFSET(pFdiv);
2178 break;
2179 case Instruction::MUL_FLOAT_2ADDR:
2180 case Instruction::MUL_FLOAT:
2181 funcOffset = ENTRYPOINT_OFFSET(pFmul);
2182 break;
2183 case Instruction::REM_FLOAT_2ADDR:
2184 case Instruction::REM_FLOAT:
2185 funcOffset = ENTRYPOINT_OFFSET(pFmodf);
2186 break;
2187 case Instruction::NEG_FLOAT: {
buzbee52a77fc2012-11-20 19:50:46 -08002188 GenNegFloat(cUnit, rlDest, rlSrc1);
Bill Buzbeea114add2012-05-03 15:00:40 -07002189 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002190 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002191 default:
2192 return true;
2193 }
buzbee52a77fc2012-11-20 19:50:46 -08002194 FlushAllRegs(cUnit); /* Send everything to home location */
2195 CallRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2, false);
2196 rlResult = GetReturn(cUnit, true);
2197 StoreValue(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002198 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002199}
2200
buzbee52a77fc2012-11-20 19:50:46 -08002201bool GenArithOpDoublePortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee31a4a6f2012-02-28 15:36:15 -08002202 RegLocation rlDest, RegLocation rlSrc1,
2203 RegLocation rlSrc2)
2204{
Bill Buzbeea114add2012-05-03 15:00:40 -07002205 RegLocation rlResult;
2206 int funcOffset;
buzbee31a4a6f2012-02-28 15:36:15 -08002207
buzbee408ad162012-06-06 16:45:18 -07002208 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002209 case Instruction::ADD_DOUBLE_2ADDR:
2210 case Instruction::ADD_DOUBLE:
2211 funcOffset = ENTRYPOINT_OFFSET(pDadd);
2212 break;
2213 case Instruction::SUB_DOUBLE_2ADDR:
2214 case Instruction::SUB_DOUBLE:
2215 funcOffset = ENTRYPOINT_OFFSET(pDsub);
2216 break;
2217 case Instruction::DIV_DOUBLE_2ADDR:
2218 case Instruction::DIV_DOUBLE:
2219 funcOffset = ENTRYPOINT_OFFSET(pDdiv);
2220 break;
2221 case Instruction::MUL_DOUBLE_2ADDR:
2222 case Instruction::MUL_DOUBLE:
2223 funcOffset = ENTRYPOINT_OFFSET(pDmul);
2224 break;
2225 case Instruction::REM_DOUBLE_2ADDR:
2226 case Instruction::REM_DOUBLE:
2227 funcOffset = ENTRYPOINT_OFFSET(pFmod);
2228 break;
2229 case Instruction::NEG_DOUBLE: {
buzbee52a77fc2012-11-20 19:50:46 -08002230 GenNegDouble(cUnit, rlDest, rlSrc1);
Bill Buzbeea114add2012-05-03 15:00:40 -07002231 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002232 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002233 default:
2234 return true;
2235 }
buzbee52a77fc2012-11-20 19:50:46 -08002236 FlushAllRegs(cUnit); /* Send everything to home location */
2237 CallRuntimeHelperRegLocationRegLocation(cUnit, funcOffset, rlSrc1, rlSrc2, false);
2238 rlResult = GetReturnWide(cUnit, true);
2239 StoreValueWide(cUnit, rlDest, rlResult);
Bill Buzbeea114add2012-05-03 15:00:40 -07002240 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002241}
2242
buzbee52a77fc2012-11-20 19:50:46 -08002243bool GenConversionPortable(CompilationUnit* cUnit, Instruction::Code opcode,
buzbee408ad162012-06-06 16:45:18 -07002244 RegLocation rlDest, RegLocation rlSrc)
buzbee31a4a6f2012-02-28 15:36:15 -08002245{
buzbee31a4a6f2012-02-28 15:36:15 -08002246
Bill Buzbeea114add2012-05-03 15:00:40 -07002247 switch (opcode) {
2248 case Instruction::INT_TO_FLOAT:
buzbee52a77fc2012-11-20 19:50:46 -08002249 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2f),
buzbee408ad162012-06-06 16:45:18 -07002250 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002251 case Instruction::FLOAT_TO_INT:
buzbee52a77fc2012-11-20 19:50:46 -08002252 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2iz),
buzbee408ad162012-06-06 16:45:18 -07002253 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002254 case Instruction::DOUBLE_TO_FLOAT:
buzbee52a77fc2012-11-20 19:50:46 -08002255 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2f),
buzbee408ad162012-06-06 16:45:18 -07002256 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002257 case Instruction::FLOAT_TO_DOUBLE:
buzbee52a77fc2012-11-20 19:50:46 -08002258 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2d),
buzbee408ad162012-06-06 16:45:18 -07002259 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002260 case Instruction::INT_TO_DOUBLE:
buzbee52a77fc2012-11-20 19:50:46 -08002261 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pI2d),
buzbee408ad162012-06-06 16:45:18 -07002262 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002263 case Instruction::DOUBLE_TO_INT:
buzbee52a77fc2012-11-20 19:50:46 -08002264 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2iz),
buzbee408ad162012-06-06 16:45:18 -07002265 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002266 case Instruction::FLOAT_TO_LONG:
buzbee52a77fc2012-11-20 19:50:46 -08002267 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pF2l),
buzbee408ad162012-06-06 16:45:18 -07002268 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002269 case Instruction::LONG_TO_FLOAT:
buzbee52a77fc2012-11-20 19:50:46 -08002270 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2f),
buzbee408ad162012-06-06 16:45:18 -07002271 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002272 case Instruction::DOUBLE_TO_LONG:
buzbee52a77fc2012-11-20 19:50:46 -08002273 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pD2l),
buzbee408ad162012-06-06 16:45:18 -07002274 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002275 case Instruction::LONG_TO_DOUBLE:
buzbee52a77fc2012-11-20 19:50:46 -08002276 return GenConversionCall(cUnit, ENTRYPOINT_OFFSET(pL2d),
buzbee408ad162012-06-06 16:45:18 -07002277 rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07002278 default:
2279 return true;
2280 }
2281 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002282}
2283
buzbee31a4a6f2012-02-28 15:36:15 -08002284/* Check if we need to check for pending suspend request */
buzbee52a77fc2012-11-20 19:50:46 -08002285void GenSuspendTest(CompilationUnit* cUnit, int optFlags)
buzbee31a4a6f2012-02-28 15:36:15 -08002286{
buzbee408ad162012-06-06 16:45:18 -07002287 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002288 return;
2289 }
buzbee52a77fc2012-11-20 19:50:46 -08002290 FlushAllRegs(cUnit);
2291 LIR* branch = OpTestSuspend(cUnit, NULL);
2292 LIR* retLab = NewLIR0(cUnit, kPseudoTargetLabel);
2293 LIR* target = RawLIR(cUnit, cUnit->currentDalvikOffset, kPseudoSuspendTarget,
buzbeecbd6d442012-11-17 14:11:25 -08002294 reinterpret_cast<uintptr_t>(retLab), cUnit->currentDalvikOffset);
2295 branch->target = target;
buzbee52a77fc2012-11-20 19:50:46 -08002296 InsertGrowableList(cUnit, &cUnit->suspendLaunchpads, reinterpret_cast<uintptr_t>(target));
buzbee31a4a6f2012-02-28 15:36:15 -08002297}
2298
buzbeefead2932012-03-30 14:02:01 -07002299/* Check if we need to check for pending suspend request */
buzbee52a77fc2012-11-20 19:50:46 -08002300void GenSuspendTestAndBranch(CompilationUnit* cUnit, int optFlags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07002301{
buzbee408ad162012-06-06 16:45:18 -07002302 if (NO_SUSPEND || (optFlags & MIR_IGNORE_SUSPEND_CHECK)) {
buzbee52a77fc2012-11-20 19:50:46 -08002303 OpUnconditionalBranch(cUnit, target);
Bill Buzbeea114add2012-05-03 15:00:40 -07002304 return;
2305 }
buzbee52a77fc2012-11-20 19:50:46 -08002306 OpTestSuspend(cUnit, target);
buzbeecbd6d442012-11-17 14:11:25 -08002307 LIR* launchPad =
buzbee52a77fc2012-11-20 19:50:46 -08002308 RawLIR(cUnit, cUnit->currentDalvikOffset, kPseudoSuspendTarget,
buzbeecbd6d442012-11-17 14:11:25 -08002309 reinterpret_cast<uintptr_t>(target), cUnit->currentDalvikOffset);
buzbee52a77fc2012-11-20 19:50:46 -08002310 FlushAllRegs(cUnit);
2311 OpUnconditionalBranch(cUnit, launchPad);
2312 InsertGrowableList(cUnit, &cUnit->suspendLaunchpads, reinterpret_cast<uintptr_t>(launchPad));
buzbeefead2932012-03-30 14:02:01 -07002313}
2314
buzbee31a4a6f2012-02-28 15:36:15 -08002315} // namespace art