blob: 22b919a5bb25edbd2b69eff559ef0b4adb33002e [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.
buzbeefa57c472012-11-21 12:06:18 -080025void GenInvoke(CompilationUnit* cu, 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
buzbeefa57c472012-11-21 12:06:18 -080033void MarkSafepointPC(CompilationUnit* cu, LIR* inst)
buzbee8320f382012-09-11 16:29:42 -070034{
buzbeefa57c472012-11-21 12:06:18 -080035 inst->def_mask = ENCODE_ALL;
36 LIR* safepoint_pc = NewLIR0(cu, kPseudoSafepointPC);
37 DCHECK_EQ(safepoint_pc->def_mask, ENCODE_ALL);
buzbee8320f382012-09-11 16:29:42 -070038}
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 */
buzbeefa57c472012-11-21 12:06:18 -080046int CallHelperSetup(CompilationUnit* cu, int helper_offset)
buzbeeb046e162012-10-30 15:48:42 -070047{
buzbeefa57c472012-11-21 12:06:18 -080048 return (cu->instruction_set == kX86) ? 0 : LoadHelper(cu, helper_offset);
buzbeeb046e162012-10-30 15:48:42 -070049}
50
buzbeefa57c472012-11-21 12:06:18 -080051/* NOTE: if r_tgt is a temp, it will be freed following use */
52LIR* CallHelper(CompilationUnit* cu, int r_tgt, int helper_offset, bool safepoint_pc)
buzbeeb046e162012-10-30 15:48:42 -070053{
buzbeefa57c472012-11-21 12:06:18 -080054 LIR* call_inst;
55 if (cu->instruction_set == kX86) {
56 call_inst = OpThreadMem(cu, kOpBlx, helper_offset);
buzbeeb046e162012-10-30 15:48:42 -070057 } else {
buzbeefa57c472012-11-21 12:06:18 -080058 call_inst = OpReg(cu, kOpBlx, r_tgt);
59 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -070060 }
buzbeefa57c472012-11-21 12:06:18 -080061 if (safepoint_pc) {
62 MarkSafepointPC(cu, call_inst);
buzbee8320f382012-09-11 16:29:42 -070063 }
buzbeefa57c472012-11-21 12:06:18 -080064 return call_inst;
buzbeeb046e162012-10-30 15:48:42 -070065}
66
buzbeefa57c472012-11-21 12:06:18 -080067void CallRuntimeHelperImm(CompilationUnit* cu, int helper_offset, int arg0, bool safepoint_pc) {
68 int r_tgt = CallHelperSetup(cu, helper_offset);
69 LoadConstant(cu, TargetReg(kArg0), arg0);
70 ClobberCalleeSave(cu);
71 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -070072}
73
buzbeefa57c472012-11-21 12:06:18 -080074void CallRuntimeHelperReg(CompilationUnit* cu, int helper_offset, int arg0, bool safepoint_pc) {
75 int r_tgt = CallHelperSetup(cu, helper_offset);
76 OpRegCopy(cu, TargetReg(kArg0), arg0);
77 ClobberCalleeSave(cu);
78 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogers7caad772012-03-30 01:07:54 -070079}
80
buzbeefa57c472012-11-21 12:06:18 -080081void CallRuntimeHelperRegLocation(CompilationUnit* cu, int helper_offset, RegLocation arg0,
82 bool safepoint_pc) {
83 int r_tgt = CallHelperSetup(cu, helper_offset);
Bill Buzbeea114add2012-05-03 15:00:40 -070084 if (arg0.wide == 0) {
buzbeefa57c472012-11-21 12:06:18 -080085 LoadValueDirectFixed(cu, arg0, TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -070086 } else {
buzbeefa57c472012-11-21 12:06:18 -080087 LoadValueDirectWideFixed(cu, arg0, TargetReg(kArg0), TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -070088 }
buzbeefa57c472012-11-21 12:06:18 -080089 ClobberCalleeSave(cu);
90 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -070091}
92
buzbeefa57c472012-11-21 12:06:18 -080093void CallRuntimeHelperImmImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
94 bool safepoint_pc) {
95 int r_tgt = CallHelperSetup(cu, helper_offset);
96 LoadConstant(cu, TargetReg(kArg0), arg0);
97 LoadConstant(cu, TargetReg(kArg1), arg1);
98 ClobberCalleeSave(cu);
99 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700100}
101
buzbeefa57c472012-11-21 12:06:18 -0800102void CallRuntimeHelperImmRegLocation(CompilationUnit* cu, int helper_offset, int arg0,
103 RegLocation arg1, bool safepoint_pc) {
104 int r_tgt = CallHelperSetup(cu, helper_offset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700105 if (arg1.wide == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800106 LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700107 } else {
buzbeefa57c472012-11-21 12:06:18 -0800108 LoadValueDirectWideFixed(cu, arg1, TargetReg(kArg1), TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700109 }
buzbeefa57c472012-11-21 12:06:18 -0800110 LoadConstant(cu, TargetReg(kArg0), arg0);
111 ClobberCalleeSave(cu);
112 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700113}
114
buzbeefa57c472012-11-21 12:06:18 -0800115void CallRuntimeHelperRegLocationImm(CompilationUnit* cu, int helper_offset, RegLocation arg0,
116 int arg1, bool safepoint_pc) {
117 int r_tgt = CallHelperSetup(cu, helper_offset);
118 LoadValueDirectFixed(cu, arg0, TargetReg(kArg0));
119 LoadConstant(cu, TargetReg(kArg1), arg1);
120 ClobberCalleeSave(cu);
121 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700122}
123
buzbeefa57c472012-11-21 12:06:18 -0800124void CallRuntimeHelperImmReg(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
125 bool safepoint_pc) {
126 int r_tgt = CallHelperSetup(cu, helper_offset);
127 OpRegCopy(cu, TargetReg(kArg1), arg1);
128 LoadConstant(cu, TargetReg(kArg0), arg0);
129 ClobberCalleeSave(cu);
130 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700131}
132
buzbeefa57c472012-11-21 12:06:18 -0800133void CallRuntimeHelperRegImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
134 bool safepoint_pc) {
135 int r_tgt = CallHelperSetup(cu, helper_offset);
136 OpRegCopy(cu, TargetReg(kArg0), arg0);
137 LoadConstant(cu, TargetReg(kArg1), arg1);
138 ClobberCalleeSave(cu);
139 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700140}
141
buzbeefa57c472012-11-21 12:06:18 -0800142void CallRuntimeHelperImmMethod(CompilationUnit* cu, int helper_offset, int arg0, bool safepoint_pc) {
143 int r_tgt = CallHelperSetup(cu, helper_offset);
144 LoadCurrMethodDirect(cu, TargetReg(kArg1));
145 LoadConstant(cu, TargetReg(kArg0), arg0);
146 ClobberCalleeSave(cu);
147 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700148}
149
buzbeefa57c472012-11-21 12:06:18 -0800150void CallRuntimeHelperRegLocationRegLocation(CompilationUnit* cu, int helper_offset,
151 RegLocation arg0, RegLocation arg1, bool safepoint_pc) {
152 int r_tgt = CallHelperSetup(cu, helper_offset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700153 if (arg0.wide == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800154 LoadValueDirectFixed(cu, arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700155 if (arg1.wide == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800156 if (cu->instruction_set == kMips) {
157 LoadValueDirectFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
buzbeeb046e162012-10-30 15:48:42 -0700158 } else {
buzbeefa57c472012-11-21 12:06:18 -0800159 LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
buzbeeb046e162012-10-30 15:48:42 -0700160 }
Ian Rogersab2b55d2012-03-18 00:06:11 -0700161 } else {
buzbeefa57c472012-11-21 12:06:18 -0800162 if (cu->instruction_set == kMips) {
163 LoadValueDirectWideFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
buzbeeb046e162012-10-30 15:48:42 -0700164 } else {
buzbeefa57c472012-11-21 12:06:18 -0800165 LoadValueDirectWideFixed(cu, 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 {
buzbeefa57c472012-11-21 12:06:18 -0800169 LoadValueDirectWideFixed(cu, 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) {
buzbeefa57c472012-11-21 12:06:18 -0800171 LoadValueDirectFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 } else {
buzbeefa57c472012-11-21 12:06:18 -0800173 LoadValueDirectWideFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 }
175 }
buzbeefa57c472012-11-21 12:06:18 -0800176 ClobberCalleeSave(cu);
177 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700178}
179
buzbeefa57c472012-11-21 12:06:18 -0800180void CallRuntimeHelperRegReg(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
181 bool safepoint_pc) {
182 int r_tgt = CallHelperSetup(cu, helper_offset);
buzbee52a77fc2012-11-20 19:50:46 -0800183 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbeefa57c472012-11-21 12:06:18 -0800184 OpRegCopy(cu, TargetReg(kArg0), arg0);
185 OpRegCopy(cu, TargetReg(kArg1), arg1);
186 ClobberCalleeSave(cu);
187 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700188}
189
buzbeefa57c472012-11-21 12:06:18 -0800190void CallRuntimeHelperRegRegImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
191 int arg2, bool safepoint_pc) {
192 int r_tgt = CallHelperSetup(cu, helper_offset);
buzbee52a77fc2012-11-20 19:50:46 -0800193 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbeefa57c472012-11-21 12:06:18 -0800194 OpRegCopy(cu, TargetReg(kArg0), arg0);
195 OpRegCopy(cu, TargetReg(kArg1), arg1);
196 LoadConstant(cu, TargetReg(kArg2), arg2);
197 ClobberCalleeSave(cu);
198 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700199}
200
buzbeefa57c472012-11-21 12:06:18 -0800201void CallRuntimeHelperImmMethodRegLocation(CompilationUnit* cu, int helper_offset, int arg0,
202 RegLocation arg2, bool safepoint_pc) {
203 int r_tgt = CallHelperSetup(cu, helper_offset);
204 LoadValueDirectFixed(cu, arg2, TargetReg(kArg2));
205 LoadCurrMethodDirect(cu, TargetReg(kArg1));
206 LoadConstant(cu, TargetReg(kArg0), arg0);
207 ClobberCalleeSave(cu);
208 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700209}
210
buzbeefa57c472012-11-21 12:06:18 -0800211void CallRuntimeHelperImmMethodImm(CompilationUnit* cu, int helper_offset, int arg0, int arg2,
212 bool safepoint_pc) {
213 int r_tgt = CallHelperSetup(cu, helper_offset);
214 LoadCurrMethodDirect(cu, TargetReg(kArg1));
215 LoadConstant(cu, TargetReg(kArg2), arg2);
216 LoadConstant(cu, TargetReg(kArg0), arg0);
217 ClobberCalleeSave(cu);
218 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700219}
220
buzbeefa57c472012-11-21 12:06:18 -0800221void CallRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cu, int helper_offset,
buzbee8320f382012-09-11 16:29:42 -0700222 int arg0, RegLocation arg1, RegLocation arg2,
buzbeefa57c472012-11-21 12:06:18 -0800223 bool safepoint_pc) {
224 int r_tgt = CallHelperSetup(cu, helper_offset);
225 LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700226 if (arg2.wide == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800227 LoadValueDirectFixed(cu, arg2, TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700228 } else {
buzbeefa57c472012-11-21 12:06:18 -0800229 LoadValueDirectWideFixed(cu, arg2, TargetReg(kArg2), TargetReg(kArg3));
Bill Buzbeea114add2012-05-03 15:00:40 -0700230 }
buzbeefa57c472012-11-21 12:06:18 -0800231 LoadConstant(cu, TargetReg(kArg0), arg0);
232 ClobberCalleeSave(cu);
233 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
buzbee31a4a6f2012-02-28 15:36:15 -0800234}
235
236/*
237 * Generate an kPseudoBarrier marker to indicate the boundary of special
238 * blocks.
239 */
buzbeefa57c472012-11-21 12:06:18 -0800240void GenBarrier(CompilationUnit* cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800241{
buzbeefa57c472012-11-21 12:06:18 -0800242 LIR* barrier = NewLIR0(cu, kPseudoBarrier);
Bill Buzbeea114add2012-05-03 15:00:40 -0700243 /* Mark all resources as being clobbered */
buzbeefa57c472012-11-21 12:06:18 -0800244 barrier->def_mask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800245}
246
buzbee31a4a6f2012-02-28 15:36:15 -0800247
248/* Generate unconditional branch instructions */
buzbeefa57c472012-11-21 12:06:18 -0800249LIR* OpUnconditionalBranch(CompilationUnit* cu, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -0800250{
buzbeefa57c472012-11-21 12:06:18 -0800251 LIR* branch = OpBranchUnconditional(cu, 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
buzbeefa57c472012-11-21 12:06:18 -0800258LIR* GenCheck(CompilationUnit* cu, ConditionCode c_code,
buzbee31a4a6f2012-02-28 15:36:15 -0800259 ThrowKind kind)
260{
buzbeefa57c472012-11-21 12:06:18 -0800261 DCHECK_NE(cu->instruction_set, kMips);
262 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
263 cu->current_dalvik_offset);
264 LIR* branch = OpCondBranch(cu, c_code, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700265 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -0800266 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800268}
269
buzbeefa57c472012-11-21 12:06:18 -0800270LIR* GenImmedCheck(CompilationUnit* cu, ConditionCode c_code,
271 int reg, int imm_val, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800272{
buzbeefa57c472012-11-21 12:06:18 -0800273 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
274 cu->current_dalvik_offset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -0800276 if (c_code == kCondAl) {
277 branch = OpUnconditionalBranch(cu, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700278 } else {
buzbeefa57c472012-11-21 12:06:18 -0800279 branch = OpCmpImmBranch(cu, c_code, reg, imm_val, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700280 }
281 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -0800282 InsertGrowableList(cu, &cu->throw_launchpads, 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. */
buzbeefa57c472012-11-21 12:06:18 -0800287LIR* GenNullCheck(CompilationUnit* cu, int s_reg, int m_reg, int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -0800288{
buzbeefa57c472012-11-21 12:06:18 -0800289 if (!(cu->disable_opt & (1 << kNullCheckElimination)) &&
290 opt_flags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700291 return NULL;
292 }
buzbeefa57c472012-11-21 12:06:18 -0800293 return GenImmedCheck(cu, kCondEq, m_reg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -0800294}
295
296/* Perform check on two registers */
buzbeefa57c472012-11-21 12:06:18 -0800297LIR* GenRegRegCheck(CompilationUnit* cu, ConditionCode c_code,
buzbee408ad162012-06-06 16:45:18 -0700298 int reg1, int reg2, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -0800299{
buzbeefa57c472012-11-21 12:06:18 -0800300 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
301 cu->current_dalvik_offset, reg1, reg2);
302 LIR* branch = OpCmpBranch(cu, c_code, reg1, reg2, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -0700303 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -0800304 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700305 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800306}
307
buzbeefa57c472012-11-21 12:06:18 -0800308void GenCompareAndBranch(CompilationUnit* cu, Instruction::Code opcode,
309 RegLocation rl_src1, RegLocation rl_src2, LIR* taken,
310 LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -0800311{
Bill Buzbeea114add2012-05-03 15:00:40 -0700312 ConditionCode cond;
buzbeefa57c472012-11-21 12:06:18 -0800313 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
314 rl_src2 = LoadValue(cu, rl_src2, 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 }
buzbeefa57c472012-11-21 12:06:18 -0800338 OpCmpBranch(cu, cond, rl_src1.low_reg, rl_src2.low_reg, taken);
339 OpUnconditionalBranch(cu, fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800340}
341
buzbeefa57c472012-11-21 12:06:18 -0800342void GenCompareZeroAndBranch(CompilationUnit* cu, Instruction::Code opcode,
343 RegLocation rl_src, LIR* taken, LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -0800344{
Bill Buzbeea114add2012-05-03 15:00:40 -0700345 ConditionCode cond;
buzbeefa57c472012-11-21 12:06:18 -0800346 rl_src = LoadValue(cu, rl_src, 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 }
buzbeefa57c472012-11-21 12:06:18 -0800370 if (cu->instruction_set == kThumb2) {
371 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
372 OpCondBranch(cu, cond, taken);
buzbeeb046e162012-10-30 15:48:42 -0700373 } else {
buzbeefa57c472012-11-21 12:06:18 -0800374 OpCmpImmBranch(cu, cond, rl_src.low_reg, 0, taken);
buzbeeb046e162012-10-30 15:48:42 -0700375 }
buzbeefa57c472012-11-21 12:06:18 -0800376 OpUnconditionalBranch(cu, fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800377}
378
buzbeefa57c472012-11-21 12:06:18 -0800379void GenIntToLong(CompilationUnit* cu, RegLocation rl_dest,
380 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800381{
buzbeefa57c472012-11-21 12:06:18 -0800382 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
383 if (rl_src.location == kLocPhysReg) {
384 OpRegCopy(cu, rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 } else {
buzbeefa57c472012-11-21 12:06:18 -0800386 LoadValueDirect(cu, rl_src, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700387 }
buzbeefa57c472012-11-21 12:06:18 -0800388 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_result.low_reg, 31);
389 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800390}
391
buzbeefa57c472012-11-21 12:06:18 -0800392void GenIntNarrowing(CompilationUnit* cu, Instruction::Code opcode,
393 RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800394{
buzbeefa57c472012-11-21 12:06:18 -0800395 rl_src = LoadValue(cu, rl_src, kCoreReg);
396 RegLocation rl_result = EvalLoc(cu, rl_dest, 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 }
buzbeefa57c472012-11-21 12:06:18 -0800411 OpRegReg(cu, op, rl_result.low_reg, rl_src.low_reg);
412 StoreValue(cu, rl_dest, rl_result);
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 */
buzbeefa57c472012-11-21 12:06:18 -0800420void GenNewArray(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest,
421 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800422{
buzbeefa57c472012-11-21 12:06:18 -0800423 FlushAllRegs(cu); /* Everything to home location */
424 int func_offset;
425 if (cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
426 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700427 type_idx)) {
buzbeefa57c472012-11-21 12:06:18 -0800428 func_offset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700429 } else {
buzbeefa57c472012-11-21 12:06:18 -0800430 func_offset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700431 }
buzbeefa57c472012-11-21 12:06:18 -0800432 CallRuntimeHelperImmMethodRegLocation(cu, func_offset, type_idx, rl_src, true);
433 RegLocation rl_result = GetReturn(cu, false);
434 StoreValue(cu, rl_dest, rl_result);
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 */
buzbeefa57c472012-11-21 12:06:18 -0800443void GenFilledNewArray(CompilationUnit* cu, CallInfo* info)
buzbee31a4a6f2012-02-28 15:36:15 -0800444{
buzbeefa57c472012-11-21 12:06:18 -0800445 int elems = info->num_arg_words;
446 int type_idx = info->index;
447 FlushAllRegs(cu); /* Everything to home location */
448 int func_offset;
449 if (cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
450 *cu->dex_file,
451 type_idx)) {
452 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700453 } else {
buzbeefa57c472012-11-21 12:06:18 -0800454 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700455 }
buzbeefa57c472012-11-21 12:06:18 -0800456 CallRuntimeHelperImmMethodImm(cu, func_offset, type_idx, elems, true);
457 FreeTemp(cu, TargetReg(kArg2));
458 FreeTemp(cu, 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 */
buzbeefa57c472012-11-21 12:06:18 -0800466 LockTemp(cu, 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
buzbeefa57c472012-11-21 12:06:18 -0800473 if (info->is_range && (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++) {
buzbeefa57c472012-11-21 12:06:18 -0800483 RegLocation loc = UpdateLoc(cu, info->args[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700484 if (loc.location == kLocPhysReg) {
buzbeefa57c472012-11-21 12:06:18 -0800485 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, loc.s_reg_low),
486 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700487 }
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 */
buzbeefa57c472012-11-21 12:06:18 -0800494 int r_src = AllocTemp(cu);
495 int r_dst = AllocTemp(cu);
496 int r_idx = AllocTemp(cu);
497 int r_val = INVALID_REG;
498 switch(cu->instruction_set) {
buzbeeb046e162012-10-30 15:48:42 -0700499 case kThumb2:
buzbeefa57c472012-11-21 12:06:18 -0800500 r_val = TargetReg(kLr);
buzbeeb046e162012-10-30 15:48:42 -0700501 break;
502 case kX86:
buzbeefa57c472012-11-21 12:06:18 -0800503 FreeTemp(cu, TargetReg(kRet0));
504 r_val = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700505 break;
506 case kMips:
buzbeefa57c472012-11-21 12:06:18 -0800507 r_val = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700508 break;
buzbeefa57c472012-11-21 12:06:18 -0800509 default: LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
buzbeeb046e162012-10-30 15:48:42 -0700510 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700511 // Set up source pointer
buzbeefa57c472012-11-21 12:06:18 -0800512 RegLocation rl_first = info->args[0];
513 OpRegRegImm(cu, kOpAdd, r_src, TargetReg(kSp),
514 SRegOffset(cu, rl_first.s_reg_low));
Bill Buzbeea114add2012-05-03 15:00:40 -0700515 // Set up the target pointer
buzbeefa57c472012-11-21 12:06:18 -0800516 OpRegRegImm(cu, kOpAdd, r_dst, 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)
buzbeefa57c472012-11-21 12:06:18 -0800519 LoadConstant(cu, r_idx, elems - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700520 // Generate the copy loop. Going backwards for convenience
buzbeefa57c472012-11-21 12:06:18 -0800521 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -0700522 // Copy next element
buzbeefa57c472012-11-21 12:06:18 -0800523 LoadBaseIndexed(cu, r_src, r_idx, r_val, 2, kWord);
524 StoreBaseIndexed(cu, r_dst, r_idx, r_val, 2, kWord);
525 FreeTemp(cu, r_val);
526 OpDecAndBranch(cu, kCondGe, r_idx, target);
527 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700528 // Restore the target pointer
buzbeefa57c472012-11-21 12:06:18 -0800529 OpRegRegImm(cu, kOpAdd, TargetReg(kRet0), r_dst, -Array::DataOffset(component_size).Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700530 }
buzbeefa57c472012-11-21 12:06:18 -0800531 } else if (!info->is_range) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700532 // TUNING: interleave
buzbee3b3dbdd2012-06-13 13:39:34 -0700533 for (int i = 0; i < elems; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800534 RegLocation rl_arg = LoadValue(cu, info->args[i], kCoreReg);
535 StoreBaseDisp(cu, TargetReg(kRet0),
Bill Buzbeea114add2012-05-03 15:00:40 -0700536 Array::DataOffset(component_size).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800537 i * 4, rl_arg.low_reg, kWord);
buzbee52a77fc2012-11-20 19:50:46 -0800538 // If the LoadValue caused a temp to be allocated, free it
buzbeefa57c472012-11-21 12:06:18 -0800539 if (IsTemp(cu, rl_arg.low_reg)) {
540 FreeTemp(cu, rl_arg.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700541 }
542 }
543 }
buzbeee5f01222012-06-14 15:19:35 -0700544 if (info->result.location != kLocInvalid) {
buzbeefa57c472012-11-21 12:06:18 -0800545 StoreValue(cu, info->result, GetReturn(cu, false /* not fp */));
buzbeee5f01222012-06-14 15:19:35 -0700546 }
buzbee31a4a6f2012-02-28 15:36:15 -0800547}
548
buzbeefa57c472012-11-21 12:06:18 -0800549void GenSput(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_src,
550 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800551{
buzbeefa57c472012-11-21 12:06:18 -0800552 int field_offset;
553 int ssb_index;
554 bool is_volatile;
555 bool is_referrers_class;
buzbee31a4a6f2012-02-28 15:36:15 -0800556
buzbeefa57c472012-11-21 12:06:18 -0800557 OatCompilationUnit m_unit(cu->class_loader, cu->class_linker, *cu->dex_file,
558 cu->code_item, cu->method_idx, cu->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800559
buzbeefa57c472012-11-21 12:06:18 -0800560 bool fast_path =
561 cu->compiler->ComputeStaticFieldInfo(field_idx, &m_unit,
562 field_offset, ssb_index,
563 is_referrers_class, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700564 true);
buzbeefa57c472012-11-21 12:06:18 -0800565 if (fast_path && !SLOW_FIELD_PATH) {
566 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700567 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800568 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700569 // Fast path, static storage base is this method's class
buzbeefa57c472012-11-21 12:06:18 -0800570 RegLocation rl_method = LoadCurrMethod(cu);
571 rBase = AllocTemp(cu);
572 LoadWordDisp(cu, rl_method.low_reg,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700573 AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbeefa57c472012-11-21 12:06:18 -0800574 if (IsTemp(cu, rl_method.low_reg)) {
575 FreeTemp(cu, rl_method.low_reg);
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.
buzbeefa57c472012-11-21 12:06:18 -0800580 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700581 // May do runtime call so everything to home locations.
buzbeefa57c472012-11-21 12:06:18 -0800582 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700583 // Using fixed register to sync with possible call to runtime
584 // support.
buzbeefa57c472012-11-21 12:06:18 -0800585 int r_method = TargetReg(kArg1);
586 LockTemp(cu, r_method);
587 LoadCurrMethodDirect(cu, r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800588 rBase = TargetReg(kArg0);
buzbeefa57c472012-11-21 12:06:18 -0800589 LockTemp(cu, rBase);
590 LoadWordDisp(cu, r_method,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700591 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700592 rBase);
buzbeefa57c472012-11-21 12:06:18 -0800593 LoadWordDisp(cu, rBase,
Bill Buzbeea114add2012-05-03 15:00:40 -0700594 Array::DataOffset(sizeof(Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800595 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700596 // 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
buzbeefa57c472012-11-21 12:06:18 -0800599 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, rBase, 0, NULL);
600 LoadConstant(cu, TargetReg(kArg0), ssb_index);
601 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
602 if (cu->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800603 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbeefa57c472012-11-21 12:06:18 -0800604 OpRegCopy(cu, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700605 }
buzbeefa57c472012-11-21 12:06:18 -0800606 LIR* skip_target = NewLIR0(cu, kPseudoTargetLabel);
607 branch_over->target = skip_target;
608 FreeTemp(cu, r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800609 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700610 // rBase now holds static storage base
buzbeefa57c472012-11-21 12:06:18 -0800611 if (is_long_or_double) {
612 rl_src = LoadValueWide(cu, rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700613 } else {
buzbeefa57c472012-11-21 12:06:18 -0800614 rl_src = LoadValue(cu, rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700615 }
buzbeefa57c472012-11-21 12:06:18 -0800616 if (is_volatile) {
617 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700618 }
buzbeefa57c472012-11-21 12:06:18 -0800619 if (is_long_or_double) {
620 StoreBaseDispWide(cu, rBase, field_offset, rl_src.low_reg,
621 rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700622 } else {
buzbeefa57c472012-11-21 12:06:18 -0800623 StoreWordDisp(cu, rBase, field_offset, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700624 }
buzbeefa57c472012-11-21 12:06:18 -0800625 if (is_volatile) {
626 GenMemBarrier(cu, kStoreLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700627 }
buzbeefa57c472012-11-21 12:06:18 -0800628 if (is_object) {
629 MarkGCCard(cu, rl_src.low_reg, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700630 }
buzbeefa57c472012-11-21 12:06:18 -0800631 FreeTemp(cu, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700632 } else {
buzbeefa57c472012-11-21 12:06:18 -0800633 FlushAllRegs(cu); // Everything to home locations
634 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Static) :
635 (is_object ? ENTRYPOINT_OFFSET(pSetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700636 : ENTRYPOINT_OFFSET(pSet32Static));
buzbeefa57c472012-11-21 12:06:18 -0800637 CallRuntimeHelperImmRegLocation(cu, setter_offset, field_idx, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700638 }
buzbee31a4a6f2012-02-28 15:36:15 -0800639}
640
buzbeefa57c472012-11-21 12:06:18 -0800641void GenSget(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_dest,
642 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800643{
buzbeefa57c472012-11-21 12:06:18 -0800644 int field_offset;
645 int ssb_index;
646 bool is_volatile;
647 bool is_referrers_class;
buzbee31a4a6f2012-02-28 15:36:15 -0800648
buzbeefa57c472012-11-21 12:06:18 -0800649 OatCompilationUnit m_unit(cu->class_loader, cu->class_linker,
650 *cu->dex_file,
651 cu->code_item, cu->method_idx,
652 cu->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800653
buzbeefa57c472012-11-21 12:06:18 -0800654 bool fast_path =
655 cu->compiler->ComputeStaticFieldInfo(field_idx, &m_unit,
656 field_offset, ssb_index,
657 is_referrers_class, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700658 false);
buzbeefa57c472012-11-21 12:06:18 -0800659 if (fast_path && !SLOW_FIELD_PATH) {
660 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700661 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800662 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700663 // Fast path, static storage base is this method's class
buzbeefa57c472012-11-21 12:06:18 -0800664 RegLocation rl_method = LoadCurrMethod(cu);
665 rBase = AllocTemp(cu);
666 LoadWordDisp(cu, rl_method.low_reg,
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
buzbeefa57c472012-11-21 12:06:18 -0800671 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700672 // May do runtime call so everything to home locations.
buzbeefa57c472012-11-21 12:06:18 -0800673 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700674 // Using fixed register to sync with possible call to runtime
675 // support
buzbeefa57c472012-11-21 12:06:18 -0800676 int r_method = TargetReg(kArg1);
677 LockTemp(cu, r_method);
678 LoadCurrMethodDirect(cu, r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800679 rBase = TargetReg(kArg0);
buzbeefa57c472012-11-21 12:06:18 -0800680 LockTemp(cu, rBase);
681 LoadWordDisp(cu, r_method,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700682 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700683 rBase);
buzbeefa57c472012-11-21 12:06:18 -0800684 LoadWordDisp(cu, rBase,
Bill Buzbeea114add2012-05-03 15:00:40 -0700685 Array::DataOffset(sizeof(Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800686 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700687 // 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
buzbeefa57c472012-11-21 12:06:18 -0800690 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, rBase, 0, NULL);
691 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
692 if (cu->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800693 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbeefa57c472012-11-21 12:06:18 -0800694 OpRegCopy(cu, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700695 }
buzbeefa57c472012-11-21 12:06:18 -0800696 LIR* skip_target = NewLIR0(cu, kPseudoTargetLabel);
697 branch_over->target = skip_target;
698 FreeTemp(cu, r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800699 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700700 // rBase now holds static storage base
buzbeefa57c472012-11-21 12:06:18 -0800701 RegLocation rl_result = EvalLoc(cu, rl_dest, kAnyReg, true);
702 if (is_volatile) {
703 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700704 }
buzbeefa57c472012-11-21 12:06:18 -0800705 if (is_long_or_double) {
706 LoadBaseDispWide(cu, rBase, field_offset, rl_result.low_reg,
707 rl_result.high_reg, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -0700708 } else {
buzbeefa57c472012-11-21 12:06:18 -0800709 LoadWordDisp(cu, rBase, field_offset, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700710 }
buzbeefa57c472012-11-21 12:06:18 -0800711 FreeTemp(cu, rBase);
712 if (is_long_or_double) {
713 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700714 } else {
buzbeefa57c472012-11-21 12:06:18 -0800715 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700716 }
717 } else {
buzbeefa57c472012-11-21 12:06:18 -0800718 FlushAllRegs(cu); // Everything to home locations
719 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Static) :
720 (is_object ? ENTRYPOINT_OFFSET(pGetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700721 : ENTRYPOINT_OFFSET(pGet32Static));
buzbeefa57c472012-11-21 12:06:18 -0800722 CallRuntimeHelperImm(cu, getterOffset, field_idx, true);
723 if (is_long_or_double) {
724 RegLocation rl_result = GetReturnWide(cu, rl_dest.fp);
725 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700726 } else {
buzbeefa57c472012-11-21 12:06:18 -0800727 RegLocation rl_result = GetReturn(cu, rl_dest.fp);
728 StoreValue(cu, rl_dest, rl_result);
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
buzbeefa57c472012-11-21 12:06:18 -0800735void GenShowTarget(CompilationUnit* cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800736{
buzbeefa57c472012-11-21 12:06:18 -0800737 DCHECK_NE(cu->instruction_set, kX86) << "unimplemented GenShowTarget";
738 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, TargetReg(kInvokeTgt), 0, NULL);
739 LoadWordDisp(cu, TargetReg(kSelf), ENTRYPOINT_OFFSET(pDebugMe), TargetReg(kInvokeTgt));
740 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
741 branch_over->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -0800742}
743
buzbeefa57c472012-11-21 12:06:18 -0800744void HandleSuspendLaunchPads(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800745{
buzbeefa57c472012-11-21 12:06:18 -0800746 LIR** suspend_label = reinterpret_cast<LIR**>(cu->suspend_launchpads.elem_list);
747 int num_elems = cu->suspend_launchpads.num_used;
748 int helper_offset = ENTRYPOINT_OFFSET(pTestSuspendFromCode);
749 for (int i = 0; i < num_elems; i++) {
750 ResetRegPool(cu);
751 ResetDefTracking(cu);
752 LIR* lab = suspend_label[i];
753 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[0]);
754 cu->current_dalvik_offset = lab->operands[1];
755 AppendLIR(cu, lab);
756 int r_tgt = CallHelperSetup(cu, helper_offset);
757 CallHelper(cu, r_tgt, helper_offset, true /* MarkSafepointPC */);
758 OpUnconditionalBranch(cu, resume_lab);
Bill Buzbeea114add2012-05-03 15:00:40 -0700759 }
buzbee31a4a6f2012-02-28 15:36:15 -0800760}
761
buzbeefa57c472012-11-21 12:06:18 -0800762void HandleIntrinsicLaunchPads(CompilationUnit *cu)
buzbeefc9e6fa2012-03-23 15:14:29 -0700763{
buzbeefa57c472012-11-21 12:06:18 -0800764 LIR** intrinsic_label = reinterpret_cast<LIR**>(cu->intrinsic_launchpads.elem_list);
765 int num_elems = cu->intrinsic_launchpads.num_used;
766 for (int i = 0; i < num_elems; i++) {
767 ResetRegPool(cu);
768 ResetDefTracking(cu);
769 LIR* lab = intrinsic_label[i];
buzbeecbd6d442012-11-17 14:11:25 -0800770 CallInfo* info = reinterpret_cast<CallInfo*>(lab->operands[0]);
buzbeefa57c472012-11-21 12:06:18 -0800771 cu->current_dalvik_offset = info->offset;
772 AppendLIR(cu, lab);
buzbee52a77fc2012-11-20 19:50:46 -0800773 // NOTE: GenInvoke handles MarkSafepointPC
buzbeefa57c472012-11-21 12:06:18 -0800774 GenInvoke(cu, info);
775 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[2]);
776 if (resume_lab != NULL) {
777 OpUnconditionalBranch(cu, resume_lab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700778 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700779 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700780}
781
buzbeefa57c472012-11-21 12:06:18 -0800782void HandleThrowLaunchPads(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800783{
buzbeefa57c472012-11-21 12:06:18 -0800784 LIR** throw_label = reinterpret_cast<LIR**>(cu->throw_launchpads.elem_list);
785 int num_elems = cu->throw_launchpads.num_used;
786 for (int i = 0; i < num_elems; i++) {
787 ResetRegPool(cu);
788 ResetDefTracking(cu);
789 LIR* lab = throw_label[i];
790 cu->current_dalvik_offset = lab->operands[1];
791 AppendLIR(cu, lab);
792 int func_offset = 0;
Bill Buzbeea114add2012-05-03 15:00:40 -0700793 int v1 = lab->operands[2];
794 int v2 = lab->operands[3];
buzbeefa57c472012-11-21 12:06:18 -0800795 bool target_x86 = (cu->instruction_set == kX86);
Bill Buzbeea114add2012-05-03 15:00:40 -0700796 switch (lab->operands[0]) {
797 case kThrowNullPointer:
buzbeefa57c472012-11-21 12:06:18 -0800798 func_offset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700799 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)) {
buzbeefa57c472012-11-21 12:06:18 -0800803 OpRegCopy(cu, TargetReg(kArg0), v1);
804 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700805 // x86 leaves the array pointer in v2, so load the array length that the handler expects
buzbeefa57c472012-11-21 12:06:18 -0800806 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700807 } else {
buzbeefa57c472012-11-21 12:06:18 -0800808 OpRegCopy(cu, 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
buzbeefa57c472012-11-21 12:06:18 -0800813 OpRegCopy(cu, TargetReg(kArg2), v1);
814 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700815 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbeefa57c472012-11-21 12:06:18 -0800816 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700817 } else {
buzbeefa57c472012-11-21 12:06:18 -0800818 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700819 }
buzbeefa57c472012-11-21 12:06:18 -0800820 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700821 } else {
buzbeefa57c472012-11-21 12:06:18 -0800822 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700823 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbeefa57c472012-11-21 12:06:18 -0800824 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700825 } else {
buzbeefa57c472012-11-21 12:06:18 -0800826 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700827 }
buzbeefa57c472012-11-21 12:06:18 -0800828 OpRegCopy(cu, TargetReg(kArg0), v1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700829 }
buzbee31a4a6f2012-02-28 15:36:15 -0800830 }
buzbeefa57c472012-11-21 12:06:18 -0800831 func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700832 break;
833 case kThrowDivZero:
buzbeefa57c472012-11-21 12:06:18 -0800834 func_offset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700835 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700836 case kThrowNoSuchMethod:
buzbeefa57c472012-11-21 12:06:18 -0800837 OpRegCopy(cu, TargetReg(kArg0), v1);
838 func_offset =
Bill Buzbeea114add2012-05-03 15:00:40 -0700839 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
840 break;
841 case kThrowStackOverflow:
buzbeefa57c472012-11-21 12:06:18 -0800842 func_offset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700843 // Restore stack alignment
buzbeefa57c472012-11-21 12:06:18 -0800844 if (target_x86) {
845 OpRegImm(cu, kOpAdd, TargetReg(kSp), cu->frame_size);
buzbeeb046e162012-10-30 15:48:42 -0700846 } else {
buzbeefa57c472012-11-21 12:06:18 -0800847 OpRegImm(cu, kOpAdd, TargetReg(kSp), (cu->num_core_spills + cu->num_fp_spills) * 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 }
buzbeefa57c472012-11-21 12:06:18 -0800853 ClobberCalleeSave(cu);
854 int r_tgt = CallHelperSetup(cu, func_offset);
855 CallHelper(cu, r_tgt, func_offset, true /* MarkSafepointPC */);
Bill Buzbeea114add2012-05-03 15:00:40 -0700856 }
buzbee31a4a6f2012-02-28 15:36:15 -0800857}
858
buzbeefa57c472012-11-21 12:06:18 -0800859bool FastInstance(CompilationUnit* cu, uint32_t field_idx,
860 int& field_offset, bool& is_volatile, bool is_put)
buzbee16da88c2012-03-20 10:38:17 -0700861{
buzbeefa57c472012-11-21 12:06:18 -0800862 OatCompilationUnit m_unit(cu->class_loader, cu->class_linker,
863 *cu->dex_file,
864 cu->code_item, cu->method_idx,
865 cu->access_flags);
866 return cu->compiler->ComputeInstanceFieldInfo(field_idx, &m_unit,
867 field_offset, is_volatile, is_put);
buzbee16da88c2012-03-20 10:38:17 -0700868}
869
buzbeefa57c472012-11-21 12:06:18 -0800870void GenIGet(CompilationUnit* cu, uint32_t field_idx, int opt_flags, OpSize size,
871 RegLocation rl_dest, RegLocation rl_obj,
872 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800873{
buzbeefa57c472012-11-21 12:06:18 -0800874 int field_offset;
875 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800876
buzbeefa57c472012-11-21 12:06:18 -0800877 bool fast_path = FastInstance(cu, field_idx, field_offset, is_volatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800878
buzbeefa57c472012-11-21 12:06:18 -0800879 if (fast_path && !SLOW_FIELD_PATH) {
880 RegLocation rl_result;
881 RegisterClass reg_class = oat_reg_class_by_size(size);
882 DCHECK_GE(field_offset, 0);
883 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
884 if (is_long_or_double) {
885 DCHECK(rl_dest.wide);
886 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
887 if (cu->instruction_set == kX86) {
888 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
889 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
890 LoadBaseDispWide(cu, rl_obj.low_reg, field_offset, rl_result.low_reg,
891 rl_result.high_reg, rl_obj.s_reg_low);
892 if (is_volatile) {
893 GenMemBarrier(cu, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700894 }
895 } else {
buzbeefa57c472012-11-21 12:06:18 -0800896 int reg_ptr = AllocTemp(cu);
897 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
898 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
899 LoadPair(cu, reg_ptr, rl_result.low_reg, rl_result.high_reg);
900 if (is_volatile) {
901 GenMemBarrier(cu, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700902 }
buzbeefa57c472012-11-21 12:06:18 -0800903 FreeTemp(cu, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700904 }
buzbeefa57c472012-11-21 12:06:18 -0800905 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800906 } else {
buzbeefa57c472012-11-21 12:06:18 -0800907 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
908 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
909 LoadBaseDisp(cu, rl_obj.low_reg, field_offset, rl_result.low_reg,
910 kWord, rl_obj.s_reg_low);
911 if (is_volatile) {
912 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700913 }
buzbeefa57c472012-11-21 12:06:18 -0800914 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800915 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700916 } else {
buzbeefa57c472012-11-21 12:06:18 -0800917 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Instance) :
918 (is_object ? ENTRYPOINT_OFFSET(pGetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700919 : ENTRYPOINT_OFFSET(pGet32Instance));
buzbeefa57c472012-11-21 12:06:18 -0800920 CallRuntimeHelperImmRegLocation(cu, getterOffset, field_idx, rl_obj, true);
921 if (is_long_or_double) {
922 RegLocation rl_result = GetReturnWide(cu, rl_dest.fp);
923 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700924 } else {
buzbeefa57c472012-11-21 12:06:18 -0800925 RegLocation rl_result = GetReturn(cu, rl_dest.fp);
926 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700927 }
928 }
buzbee31a4a6f2012-02-28 15:36:15 -0800929}
930
buzbeefa57c472012-11-21 12:06:18 -0800931void GenIPut(CompilationUnit* cu, uint32_t field_idx, int opt_flags, OpSize size,
932 RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800933{
buzbeefa57c472012-11-21 12:06:18 -0800934 int field_offset;
935 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800936
buzbeefa57c472012-11-21 12:06:18 -0800937 bool fast_path = FastInstance(cu, field_idx, field_offset, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700938 true);
buzbeefa57c472012-11-21 12:06:18 -0800939 if (fast_path && !SLOW_FIELD_PATH) {
940 RegisterClass reg_class = oat_reg_class_by_size(size);
941 DCHECK_GE(field_offset, 0);
942 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
943 if (is_long_or_double) {
944 int reg_ptr;
945 rl_src = LoadValueWide(cu, rl_src, kAnyReg);
946 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
947 reg_ptr = AllocTemp(cu);
948 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
949 if (is_volatile) {
950 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 }
buzbeefa57c472012-11-21 12:06:18 -0800952 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
953 if (is_volatile) {
954 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700955 }
buzbeefa57c472012-11-21 12:06:18 -0800956 FreeTemp(cu, reg_ptr);
buzbee31a4a6f2012-02-28 15:36:15 -0800957 } else {
buzbeefa57c472012-11-21 12:06:18 -0800958 rl_src = LoadValue(cu, rl_src, reg_class);
959 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
960 if (is_volatile) {
961 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700962 }
buzbeefa57c472012-11-21 12:06:18 -0800963 StoreBaseDisp(cu, rl_obj.low_reg, field_offset, rl_src.low_reg, kWord);
964 if (is_volatile) {
965 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700966 }
buzbeefa57c472012-11-21 12:06:18 -0800967 if (is_object) {
968 MarkGCCard(cu, rl_src.low_reg, rl_obj.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700969 }
buzbee31a4a6f2012-02-28 15:36:15 -0800970 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700971 } else {
buzbeefa57c472012-11-21 12:06:18 -0800972 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Instance) :
973 (is_object ? ENTRYPOINT_OFFSET(pSetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700974 : ENTRYPOINT_OFFSET(pSet32Instance));
buzbeefa57c472012-11-21 12:06:18 -0800975 CallRuntimeHelperImmRegLocationRegLocation(cu, setter_offset, field_idx, rl_obj, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700976 }
buzbee31a4a6f2012-02-28 15:36:15 -0800977}
978
buzbeefa57c472012-11-21 12:06:18 -0800979void GenConstClass(CompilationUnit* cu, uint32_t type_idx,
980 RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800981{
buzbeefa57c472012-11-21 12:06:18 -0800982 RegLocation rl_method = LoadCurrMethod(cu);
983 int res_reg = AllocTemp(cu);
984 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
985 if (!cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
986 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700987 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.
buzbeefa57c472012-11-21 12:06:18 -0800990 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
991 type_idx, rl_method.low_reg, true);
992 RegLocation rl_result = GetReturn(cu, false);
993 StoreValue(cu, rl_dest, rl_result);
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();
buzbeefa57c472012-11-21 12:06:18 -0800998 LoadWordDisp(cu, rl_method.low_reg, dex_cache_offset, res_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700999 int32_t offset_of_type =
1000 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1001 * type_idx);
buzbeefa57c472012-11-21 12:06:18 -08001002 LoadWordDisp(cu, res_reg, offset_of_type, rl_result.low_reg);
1003 if (!cu->compiler->CanAssumeTypeIsPresentInDexCache(*cu->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
buzbeefa57c472012-11-21 12:06:18 -08001006 FlushAllRegs(cu);
1007 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, rl_result.low_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001008 // Resolved, store and hop over following code
buzbeefa57c472012-11-21 12:06:18 -08001009 StoreValue(cu, rl_dest, rl_result);
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 */
buzbeefa57c472012-11-21 12:06:18 -08001014 ClobberSReg(cu, rl_dest.s_reg_low);
1015 LIR* branch2 = OpUnconditionalBranch(cu,0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001016 // TUNING: move slow path to end & remove unconditional branch
buzbeefa57c472012-11-21 12:06:18 -08001017 LIR* target1 = NewLIR0(cu, kPseudoTargetLabel);
buzbeef0504cd2012-11-13 16:31:10 -08001018 // Call out to helper, which will return resolved type in kArg0
buzbeefa57c472012-11-21 12:06:18 -08001019 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx,
1020 rl_method.low_reg, true);
1021 RegLocation rl_result = GetReturn(cu, false);
1022 StoreValue(cu, rl_dest, rl_result);
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 */
buzbeefa57c472012-11-21 12:06:18 -08001027 ClobberSReg(cu, rl_dest.s_reg_low);
Bill Buzbeea114add2012-05-03 15:00:40 -07001028 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -08001029 LIR* target2 = NewLIR0(cu, 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
buzbeefa57c472012-11-21 12:06:18 -08001034 StoreValue(cu, rl_dest, rl_result);
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
buzbeefa57c472012-11-21 12:06:18 -08001039void GenConstString(CompilationUnit* cu, uint32_t string_idx,
1040 RegLocation rl_dest)
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);
buzbeefa57c472012-11-21 12:06:18 -08001045 if (!cu->compiler->CanAssumeStringIsPresentInDexCache(
1046 *cu->dex_file, string_idx) || SLOW_STRING_PATH) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001047 // slow path, resolve string if not in dex cache
buzbeefa57c472012-11-21 12:06:18 -08001048 FlushAllRegs(cu);
1049 LockCallTemps(cu); // Using explicit registers
1050 LoadCurrMethodDirect(cu, TargetReg(kArg2));
1051 LoadWordDisp(cu, TargetReg(kArg2),
buzbee52a77fc2012-11-20 19:50:46 -08001052 AbstractMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -08001053 // Might call out to helper, which will return resolved string in kRet0
buzbeefa57c472012-11-21 12:06:18 -08001054 int r_tgt = CallHelperSetup(cu, ENTRYPOINT_OFFSET(pResolveStringFromCode));
1055 LoadWordDisp(cu, TargetReg(kArg0), offset_of_string, TargetReg(kRet0));
1056 LoadConstant(cu, TargetReg(kArg1), string_idx);
1057 if (cu->instruction_set == kThumb2) {
1058 OpRegImm(cu, kOpCmp, TargetReg(kRet0), 0); // Is resolved?
1059 GenBarrier(cu);
buzbeeb046e162012-10-30 15:48:42 -07001060 // For testing, always force through helper
1061 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbeefa57c472012-11-21 12:06:18 -08001062 OpIT(cu, kArmCondEq, "T");
buzbeeb046e162012-10-30 15:48:42 -07001063 }
buzbeefa57c472012-11-21 12:06:18 -08001064 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .eq
1065 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt); // .eq, helper(Method*, string_idx)
1066 MarkSafepointPC(cu, call_inst);
1067 FreeTemp(cu, r_tgt);
1068 } else if (cu->instruction_set == kMips) {
1069 LIR* branch = OpCmpImmBranch(cu, kCondNe, TargetReg(kRet0), 0, NULL);
1070 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .eq
1071 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt);
1072 MarkSafepointPC(cu, call_inst);
1073 FreeTemp(cu, r_tgt);
1074 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
buzbeeb046e162012-10-30 15:48:42 -07001075 branch->target = target;
1076 } else {
buzbeefa57c472012-11-21 12:06:18 -08001077 DCHECK_EQ(cu->instruction_set, kX86);
1078 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pResolveStringFromCode), TargetReg(kArg2), TargetReg(kArg1), true);
buzbee31a4a6f2012-02-28 15:36:15 -08001079 }
buzbeefa57c472012-11-21 12:06:18 -08001080 GenBarrier(cu);
1081 StoreValue(cu, rl_dest, GetReturn(cu, false));
Bill Buzbeea114add2012-05-03 15:00:40 -07001082 } else {
buzbeefa57c472012-11-21 12:06:18 -08001083 RegLocation rl_method = LoadCurrMethod(cu);
1084 int res_reg = AllocTemp(cu);
1085 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1086 LoadWordDisp(cu, rl_method.low_reg,
1087 AbstractMethod::DexCacheStringsOffset().Int32Value(), res_reg);
1088 LoadWordDisp(cu, res_reg, offset_of_string, rl_result.low_reg);
1089 StoreValue(cu, rl_dest, rl_result);
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 */
buzbeefa57c472012-11-21 12:06:18 -08001097void GenNewInstance(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -08001098{
buzbeefa57c472012-11-21 12:06:18 -08001099 FlushAllRegs(cu); /* 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?
buzbeefa57c472012-11-21 12:06:18 -08001102 int func_offset;
1103 if (cu->compiler->CanAccessInstantiableTypeWithoutChecks(
1104 cu->method_idx, *cu->dex_file, type_idx)) {
1105 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -07001106 } else {
buzbeefa57c472012-11-21 12:06:18 -08001107 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -07001108 }
buzbeefa57c472012-11-21 12:06:18 -08001109 CallRuntimeHelperImmMethod(cu, func_offset, type_idx, true);
1110 RegLocation rl_result = GetReturn(cu, false);
1111 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001112}
1113
buzbeefa57c472012-11-21 12:06:18 -08001114void GenMoveException(CompilationUnit* cu, RegLocation rl_dest)
Ian Rogers474b6da2012-09-25 00:20:38 -07001115{
buzbeefa57c472012-11-21 12:06:18 -08001116 FlushAllRegs(cu); /* Everything to home location */
1117 int func_offset = ENTRYPOINT_OFFSET(pGetAndClearException);
1118 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001119 // Runtime helper will load argument for x86.
buzbeefa57c472012-11-21 12:06:18 -08001120 CallRuntimeHelperReg(cu, func_offset, TargetReg(kArg0), false);
buzbeeb046e162012-10-30 15:48:42 -07001121 } else {
buzbeefa57c472012-11-21 12:06:18 -08001122 CallRuntimeHelperReg(cu, func_offset, TargetReg(kSelf), false);
buzbeeb046e162012-10-30 15:48:42 -07001123 }
buzbeefa57c472012-11-21 12:06:18 -08001124 RegLocation rl_result = GetReturn(cu, false);
1125 StoreValue(cu, rl_dest, rl_result);
Ian Rogers474b6da2012-09-25 00:20:38 -07001126}
1127
buzbeefa57c472012-11-21 12:06:18 -08001128void GenThrow(CompilationUnit* cu, RegLocation rl_src)
Ian Rogersab2b55d2012-03-18 00:06:11 -07001129{
buzbeefa57c472012-11-21 12:06:18 -08001130 FlushAllRegs(cu);
1131 CallRuntimeHelperRegLocation(cu, ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
Ian Rogersab2b55d2012-03-18 00:06:11 -07001132}
1133
buzbeefa57c472012-11-21 12:06:18 -08001134void GenInstanceof(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest,
1135 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -08001136{
buzbeefa57c472012-11-21 12:06:18 -08001137 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001138 // May generate a call - use explicit registers
buzbeefa57c472012-11-21 12:06:18 -08001139 LockCallTemps(cu);
1140 LoadCurrMethodDirect(cu, TargetReg(kArg1)); // kArg1 <= current Method*
1141 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
1142 if (!cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
1143 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -07001144 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
buzbeefa57c472012-11-21 12:06:18 -08001147 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee8320f382012-09-11 16:29:42 -07001148 type_idx, true);
buzbeefa57c472012-11-21 12:06:18 -08001149 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
1150 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001151 } else {
buzbeefa57c472012-11-21 12:06:18 -08001152 // Load dex cache entry into class_reg (kArg2)
1153 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
1154 LoadWordDisp(cu, TargetReg(kArg1),
1155 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001156 int32_t offset_of_type =
1157 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
1158 * type_idx);
buzbeefa57c472012-11-21 12:06:18 -08001159 LoadWordDisp(cu, class_reg, offset_of_type, class_reg);
1160 if (!cu->compiler->CanAssumeTypeIsPresentInDexCache(
1161 *cu->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001162 // Need to test presence of type in dex cache at runtime
buzbeefa57c472012-11-21 12:06:18 -08001163 LIR* hop_branch = OpCmpImmBranch(cu, kCondNe, class_reg, 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
buzbeefa57c472012-11-21 12:06:18 -08001166 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true);
1167 OpRegCopy(cu, TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path
1168 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); /* reload Ref */
Bill Buzbeea114add2012-05-03 15:00:40 -07001169 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -08001170 LIR* hop_target = NewLIR0(cu, kPseudoTargetLabel);
1171 hop_branch->target = hop_target;
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 */
buzbeefa57c472012-11-21 12:06:18 -08001175 RegLocation rl_result = GetReturn(cu, false);
1176 if (cu->instruction_set == kMips) {
1177 LoadConstant(cu, rl_result.low_reg, 0); // store false result for if branch is taken
buzbeeb046e162012-10-30 15:48:42 -07001178 }
buzbeefa57c472012-11-21 12:06:18 -08001179 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001180 /* load object->klass_ */
1181 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbeefa57c472012-11-21 12:06:18 -08001182 LoadWordDisp(cu, TargetReg(kArg0), Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -08001183 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
buzbeefa57c472012-11-21 12:06:18 -08001184 LIR* call_inst;
buzbeeb046e162012-10-30 15:48:42 -07001185 LIR* branchover = NULL;
buzbeefa57c472012-11-21 12:06:18 -08001186 if (cu->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -07001187 /* Uses conditional nullification */
buzbeefa57c472012-11-21 12:06:18 -08001188 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1189 OpRegReg(cu, kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
1190 OpIT(cu, kArmCondEq, "EE"); // if-convert the test
1191 LoadConstant(cu, TargetReg(kArg0), 1); // .eq case - load true
1192 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
1193 call_inst = OpReg(cu, kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
1194 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001195 } else {
1196 /* Uses branchovers */
buzbeefa57c472012-11-21 12:06:18 -08001197 LoadConstant(cu, rl_result.low_reg, 1); // assume true
1198 branchover = OpCmpBranch(cu, kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
1199 if (cu->instruction_set != kX86) {
1200 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
1201 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
1202 call_inst = OpReg(cu, kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
1203 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001204 } else {
buzbeefa57c472012-11-21 12:06:18 -08001205 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2));
1206 call_inst = OpThreadMem(cu, kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
buzbeeb046e162012-10-30 15:48:42 -07001207 }
1208 }
buzbeefa57c472012-11-21 12:06:18 -08001209 MarkSafepointPC(cu, call_inst);
1210 ClobberCalleeSave(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001211 /* branch targets here */
buzbeefa57c472012-11-21 12:06:18 -08001212 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
1213 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001214 branch1->target = target;
buzbeefa57c472012-11-21 12:06:18 -08001215 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -07001216 branchover->target = target;
1217 }
buzbee31a4a6f2012-02-28 15:36:15 -08001218}
1219
buzbeefa57c472012-11-21 12:06:18 -08001220void GenCheckCast(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -08001221{
buzbeefa57c472012-11-21 12:06:18 -08001222 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001223 // May generate a call - use explicit registers
buzbeefa57c472012-11-21 12:06:18 -08001224 LockCallTemps(cu);
1225 LoadCurrMethodDirect(cu, TargetReg(kArg1)); // kArg1 <= current Method*
1226 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
1227 if (!cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
1228 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -07001229 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)
buzbeefa57c472012-11-21 12:06:18 -08001233 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee52a77fc2012-11-20 19:50:46 -08001234 type_idx, TargetReg(kArg1), true);
buzbeefa57c472012-11-21 12:06:18 -08001235 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001236 } else {
buzbeefa57c472012-11-21 12:06:18 -08001237 // Load dex cache entry into class_reg (kArg2)
1238 LoadWordDisp(cu, TargetReg(kArg1),
1239 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001240 int32_t offset_of_type =
1241 Array::DataOffset(sizeof(Class*)).Int32Value() +
1242 (sizeof(Class*) * type_idx);
buzbeefa57c472012-11-21 12:06:18 -08001243 LoadWordDisp(cu, class_reg, offset_of_type, class_reg);
1244 if (!cu->compiler->CanAssumeTypeIsPresentInDexCache(
1245 *cu->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001246 // Need to test presence of type in dex cache at runtime
buzbeefa57c472012-11-21 12:06:18 -08001247 LIR* hop_branch = OpCmpImmBranch(cu, kCondNe, class_reg, 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)
buzbeefa57c472012-11-21 12:06:18 -08001251 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, TargetReg(kArg1),
buzbee8320f382012-09-11 16:29:42 -07001252 true);
buzbeefa57c472012-11-21 12:06:18 -08001253 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001254 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -08001255 LIR* hop_target = NewLIR0(cu, kPseudoTargetLabel);
1256 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -08001257 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001258 }
buzbeefa57c472012-11-21 12:06:18 -08001259 // At this point, class_reg (kArg2) has class
1260 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001261 /* Null is OK - continue */
buzbeefa57c472012-11-21 12:06:18 -08001262 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001263 /* load object->klass_ */
1264 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbeefa57c472012-11-21 12:06:18 -08001265 LoadWordDisp(cu, 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;
buzbeefa57c472012-11-21 12:06:18 -08001268 if (cu->instruction_set == kThumb2) {
1269 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1270 OpRegReg(cu, kOpCmp, TargetReg(kArg1), class_reg);
1271 branch2 = OpCondBranch(cu, kCondEq, NULL); /* If eq, trivial yes */
1272 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg1));
1273 OpRegCopy(cu, TargetReg(kArg1), TargetReg(kArg2));
1274 ClobberCalleeSave(cu);
1275 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt);
1276 MarkSafepointPC(cu, call_inst);
1277 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001278 } else {
buzbeefa57c472012-11-21 12:06:18 -08001279 branch2 = OpCmpBranch(cu, kCondEq, TargetReg(kArg1), class_reg, NULL);
1280 CallRuntimeHelperRegReg(cu, 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 */
buzbeefa57c472012-11-21 12:06:18 -08001283 LIR* target = NewLIR0(cu, 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 */
buzbeefa57c472012-11-21 12:06:18 -08001292void GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
1293 RegLocation rl_index, RegLocation rl_src, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001294{
buzbeefa57c472012-11-21 12:06:18 -08001295 int len_offset = Array::LengthOffset().Int32Value();
1296 int data_offset = Array::DataOffset(sizeof(Object*)).Int32Value();
buzbee31a4a6f2012-02-28 15:36:15 -08001297
buzbeefa57c472012-11-21 12:06:18 -08001298 FlushAllRegs(cu); // Use explicit registers
1299 LockCallTemps(cu);
buzbee31a4a6f2012-02-28 15:36:15 -08001300
buzbeefa57c472012-11-21 12:06:18 -08001301 int r_value = TargetReg(kArg0); // Register holding value
1302 int r_array_class = TargetReg(kArg1); // Register holding array's Class
1303 int r_array = TargetReg(kArg2); // Register holding array
1304 int r_index = TargetReg(kArg3); // Register holding index into array
Ian Rogersd36c52e2012-04-09 16:29:25 -07001305
buzbeefa57c472012-11-21 12:06:18 -08001306 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
1307 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
1308 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
Ian Rogersd36c52e2012-04-09 16:29:25 -07001309
buzbeefa57c472012-11-21 12:06:18 -08001310 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
Ian Rogersd36c52e2012-04-09 16:29:25 -07001311
Bill Buzbeea114add2012-05-03 15:00:40 -07001312 // Store of null?
buzbeefa57c472012-11-21 12:06:18 -08001313 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
Ian Rogersd36c52e2012-04-09 16:29:25 -07001314
Bill Buzbeea114add2012-05-03 15:00:40 -07001315 // Get the array's class.
buzbeefa57c472012-11-21 12:06:18 -08001316 LoadWordDisp(cu, r_array, Object::ClassOffset().Int32Value(), r_array_class);
1317 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
1318 r_array_class, true);
buzbee52a77fc2012-11-20 19:50:46 -08001319 // Redo LoadValues in case they didn't survive the call.
buzbeefa57c472012-11-21 12:06:18 -08001320 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
1321 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
1322 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
1323 r_array_class = 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
buzbeefa57c472012-11-21 12:06:18 -08001326 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001327 null_value_check->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001328
buzbeefa57c472012-11-21 12:06:18 -08001329 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001330 // make an extra temp available for card mark below
buzbeefa57c472012-11-21 12:06:18 -08001331 FreeTemp(cu, TargetReg(kArg1));
1332 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
1333 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
1334 GenRegMemCheck(cu, kCondUge, r_index, r_array, len_offset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001335 }
buzbeefa57c472012-11-21 12:06:18 -08001336 StoreBaseIndexedDisp(cu, r_array, r_index, scale,
1337 data_offset, r_value, INVALID_REG, kWord, INVALID_SREG);
buzbeeb046e162012-10-30 15:48:42 -07001338 } else {
buzbeefa57c472012-11-21 12:06:18 -08001339 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1340 int reg_len = INVALID_REG;
1341 if (needs_range_check) {
1342 reg_len = TargetReg(kArg1);
1343 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
buzbeeb046e162012-10-30 15:48:42 -07001344 }
buzbeefa57c472012-11-21 12:06:18 -08001345 /* r_ptr -> array data */
1346 int r_ptr = AllocTemp(cu);
1347 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
1348 if (needs_range_check) {
1349 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001350 }
buzbeefa57c472012-11-21 12:06:18 -08001351 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
1352 FreeTemp(cu, r_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -07001353 }
buzbeefa57c472012-11-21 12:06:18 -08001354 FreeTemp(cu, r_index);
1355 MarkGCCard(cu, r_value, r_array);
buzbee31a4a6f2012-02-28 15:36:15 -08001356}
1357
1358/*
1359 * Generate array load
1360 */
buzbeefa57c472012-11-21 12:06:18 -08001361void GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size,
1362 RegLocation rl_array, RegLocation rl_index,
1363 RegLocation rl_dest, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001364{
buzbeefa57c472012-11-21 12:06:18 -08001365 RegisterClass reg_class = oat_reg_class_by_size(size);
1366 int len_offset = Array::LengthOffset().Int32Value();
1367 int data_offset;
1368 RegLocation rl_result;
1369 rl_array = LoadValue(cu, rl_array, kCoreReg);
1370 rl_index = LoadValue(cu, rl_index, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001371
Bill Buzbeea114add2012-05-03 15:00:40 -07001372 if (size == kLong || size == kDouble) {
buzbeefa57c472012-11-21 12:06:18 -08001373 data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001374 } else {
buzbeefa57c472012-11-21 12:06:18 -08001375 data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001376 }
buzbee31a4a6f2012-02-28 15:36:15 -08001377
Bill Buzbeea114add2012-05-03 15:00:40 -07001378 /* null object? */
buzbeefa57c472012-11-21 12:06:18 -08001379 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
buzbee31a4a6f2012-02-28 15:36:15 -08001380
buzbeefa57c472012-11-21 12:06:18 -08001381 if (cu->instruction_set == kX86) {
1382 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
1383 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
1384 GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg,
1385 len_offset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001386 }
1387 if ((size == kLong) || (size == kDouble)) {
buzbeefa57c472012-11-21 12:06:18 -08001388 int reg_addr = AllocTemp(cu);
1389 OpLea(cu, reg_addr, rl_array.low_reg, rl_index.low_reg, scale, data_offset);
1390 FreeTemp(cu, rl_array.low_reg);
1391 FreeTemp(cu, rl_index.low_reg);
1392 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
1393 LoadBaseIndexedDisp(cu, reg_addr, INVALID_REG, 0, 0, rl_result.low_reg,
1394 rl_result.high_reg, size, INVALID_SREG);
1395 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001396 } else {
buzbeefa57c472012-11-21 12:06:18 -08001397 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001398
buzbeefa57c472012-11-21 12:06:18 -08001399 LoadBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale,
1400 data_offset, rl_result.low_reg, INVALID_REG, size,
buzbeeb046e162012-10-30 15:48:42 -07001401 INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001402
buzbeefa57c472012-11-21 12:06:18 -08001403 StoreValue(cu, rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001404 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001405 } else {
buzbeefa57c472012-11-21 12:06:18 -08001406 int reg_ptr = AllocTemp(cu);
1407 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1408 int reg_len = INVALID_REG;
1409 if (needs_range_check) {
1410 reg_len = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -07001411 /* Get len */
buzbeefa57c472012-11-21 12:06:18 -08001412 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
Bill Buzbeea114add2012-05-03 15:00:40 -07001413 }
buzbeefa57c472012-11-21 12:06:18 -08001414 /* reg_ptr -> array data */
1415 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
1416 FreeTemp(cu, rl_array.low_reg);
buzbeeb046e162012-10-30 15:48:42 -07001417 if ((size == kLong) || (size == kDouble)) {
1418 if (scale) {
buzbeefa57c472012-11-21 12:06:18 -08001419 int r_new_index = AllocTemp(cu);
1420 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
1421 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
1422 FreeTemp(cu, r_new_index);
buzbeeb046e162012-10-30 15:48:42 -07001423 } else {
buzbeefa57c472012-11-21 12:06:18 -08001424 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
buzbeeb046e162012-10-30 15:48:42 -07001425 }
buzbeefa57c472012-11-21 12:06:18 -08001426 FreeTemp(cu, rl_index.low_reg);
1427 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001428
buzbeefa57c472012-11-21 12:06:18 -08001429 if (needs_range_check) {
buzbeeb046e162012-10-30 15:48:42 -07001430 // TODO: change kCondCS to a more meaningful name, is the sense of
1431 // carry-set/clear flipped?
buzbeefa57c472012-11-21 12:06:18 -08001432 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1433 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001434 }
buzbeefa57c472012-11-21 12:06:18 -08001435 LoadPair(cu, reg_ptr, rl_result.low_reg, rl_result.high_reg);
buzbeeb046e162012-10-30 15:48:42 -07001436
buzbeefa57c472012-11-21 12:06:18 -08001437 FreeTemp(cu, reg_ptr);
1438 StoreValueWide(cu, rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001439 } else {
buzbeefa57c472012-11-21 12:06:18 -08001440 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
buzbeeb046e162012-10-30 15:48:42 -07001441
buzbeefa57c472012-11-21 12:06:18 -08001442 if (needs_range_check) {
buzbeeb046e162012-10-30 15:48:42 -07001443 // TODO: change kCondCS to a more meaningful name, is the sense of
1444 // carry-set/clear flipped?
buzbeefa57c472012-11-21 12:06:18 -08001445 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1446 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001447 }
buzbeefa57c472012-11-21 12:06:18 -08001448 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
buzbeeb046e162012-10-30 15:48:42 -07001449
buzbeefa57c472012-11-21 12:06:18 -08001450 FreeTemp(cu, reg_ptr);
1451 StoreValue(cu, rl_dest, rl_result);
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 */
buzbeefa57c472012-11-21 12:06:18 -08001460void GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size,
1461 RegLocation rl_array, RegLocation rl_index,
1462 RegLocation rl_src, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001463{
buzbeefa57c472012-11-21 12:06:18 -08001464 RegisterClass reg_class = oat_reg_class_by_size(size);
1465 int len_offset = Array::LengthOffset().Int32Value();
1466 int data_offset;
buzbee31a4a6f2012-02-28 15:36:15 -08001467
Bill Buzbeea114add2012-05-03 15:00:40 -07001468 if (size == kLong || size == kDouble) {
buzbeefa57c472012-11-21 12:06:18 -08001469 data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001470 } else {
buzbeefa57c472012-11-21 12:06:18 -08001471 data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001472 }
buzbee31a4a6f2012-02-28 15:36:15 -08001473
buzbeefa57c472012-11-21 12:06:18 -08001474 rl_array = LoadValue(cu, rl_array, kCoreReg);
1475 rl_index = LoadValue(cu, rl_index, kCoreReg);
1476 int reg_ptr = INVALID_REG;
1477 if (cu->instruction_set != kX86) {
1478 if (IsTemp(cu, rl_array.low_reg)) {
1479 Clobber(cu, rl_array.low_reg);
1480 reg_ptr = rl_array.low_reg;
buzbeeb046e162012-10-30 15:48:42 -07001481 } else {
buzbeefa57c472012-11-21 12:06:18 -08001482 reg_ptr = AllocTemp(cu);
1483 OpRegCopy(cu, reg_ptr, rl_array.low_reg);
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? */
buzbeefa57c472012-11-21 12:06:18 -08001488 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
buzbee31a4a6f2012-02-28 15:36:15 -08001489
buzbeefa57c472012-11-21 12:06:18 -08001490 if (cu->instruction_set == kX86) {
1491 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
1492 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
1493 GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg, len_offset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001494 }
1495 if ((size == kLong) || (size == kDouble)) {
buzbeefa57c472012-11-21 12:06:18 -08001496 rl_src = LoadValueWide(cu, rl_src, reg_class);
buzbee31a4a6f2012-02-28 15:36:15 -08001497 } else {
buzbeefa57c472012-11-21 12:06:18 -08001498 rl_src = LoadValue(cu, rl_src, reg_class);
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.
buzbeefa57c472012-11-21 12:06:18 -08001501 if ((size == kSignedByte || size == kUnsignedByte) && rl_src.low_reg >= 4) {
1502 int temp = AllocTemp(cu);
1503 OpRegCopy(cu, temp, rl_src.low_reg);
1504 StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, temp,
buzbeeb046e162012-10-30 15:48:42 -07001505 INVALID_REG, size, INVALID_SREG);
1506 } else {
buzbeefa57c472012-11-21 12:06:18 -08001507 StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_src.low_reg,
1508 rl_src.high_reg, size, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001509 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001510 } else {
buzbeefa57c472012-11-21 12:06:18 -08001511 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1512 int reg_len = INVALID_REG;
1513 if (needs_range_check) {
1514 reg_len = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -07001515 //NOTE: max live temps(4) here.
1516 /* Get len */
buzbeefa57c472012-11-21 12:06:18 -08001517 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
Bill Buzbeea114add2012-05-03 15:00:40 -07001518 }
buzbeefa57c472012-11-21 12:06:18 -08001519 /* reg_ptr -> array data */
1520 OpRegImm(cu, kOpAdd, reg_ptr, data_offset);
1521 /* at this point, reg_ptr points to array, 2 live temps */
buzbeeb046e162012-10-30 15:48:42 -07001522 if ((size == kLong) || (size == kDouble)) {
1523 //TUNING: specific wide routine that can handle fp regs
1524 if (scale) {
buzbeefa57c472012-11-21 12:06:18 -08001525 int r_new_index = AllocTemp(cu);
1526 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
1527 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
1528 FreeTemp(cu, r_new_index);
buzbeeb046e162012-10-30 15:48:42 -07001529 } else {
buzbeefa57c472012-11-21 12:06:18 -08001530 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
buzbeeb046e162012-10-30 15:48:42 -07001531 }
buzbeefa57c472012-11-21 12:06:18 -08001532 rl_src = LoadValueWide(cu, rl_src, reg_class);
buzbeeb046e162012-10-30 15:48:42 -07001533
buzbeefa57c472012-11-21 12:06:18 -08001534 if (needs_range_check) {
1535 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1536 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001537 }
1538
buzbeefa57c472012-11-21 12:06:18 -08001539 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
buzbeeb046e162012-10-30 15:48:42 -07001540
buzbeefa57c472012-11-21 12:06:18 -08001541 FreeTemp(cu, reg_ptr);
buzbeeb046e162012-10-30 15:48:42 -07001542 } else {
buzbeefa57c472012-11-21 12:06:18 -08001543 rl_src = LoadValue(cu, rl_src, reg_class);
1544 if (needs_range_check) {
1545 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1546 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001547 }
buzbeefa57c472012-11-21 12:06:18 -08001548 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
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
buzbeefa57c472012-11-21 12:06:18 -08001554void GenLong3Addr(CompilationUnit* cu, OpKind first_op,
1555 OpKind second_op, RegLocation rl_dest,
1556 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001557{
buzbeefa57c472012-11-21 12:06:18 -08001558 RegLocation rl_result;
1559 if (cu->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -07001560 /*
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 */
buzbeefa57c472012-11-21 12:06:18 -08001568 MarkTemp(cu, TargetReg(kLr)); // Add lr to the temp pool
1569 FreeTemp(cu, TargetReg(kLr)); // and make it available
buzbeeb046e162012-10-30 15:48:42 -07001570 }
buzbeefa57c472012-11-21 12:06:18 -08001571 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
1572 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
1573 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001574 // The longs may overlap - use intermediate temp if so
buzbeefa57c472012-11-21 12:06:18 -08001575 if ((rl_result.low_reg == rl_src1.high_reg) || (rl_result.low_reg == rl_src2.high_reg)){
1576 int t_reg = AllocTemp(cu);
1577 OpRegRegReg(cu, first_op, t_reg, rl_src1.low_reg, rl_src2.low_reg);
1578 OpRegRegReg(cu, second_op, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
1579 OpRegCopy(cu, rl_result.low_reg, t_reg);
1580 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001581 } else {
buzbeefa57c472012-11-21 12:06:18 -08001582 OpRegRegReg(cu, first_op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
1583 OpRegRegReg(cu, second_op, rl_result.high_reg, rl_src1.high_reg,
1584 rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001585 }
1586 /*
buzbeefa57c472012-11-21 12:06:18 -08001587 * NOTE: If rl_dest 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
buzbeefa57c472012-11-21 12:06:18 -08001590 * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result.
Bill Buzbeea114add2012-05-03 15:00:40 -07001591 * Remove when spill is functional.
1592 */
buzbeefa57c472012-11-21 12:06:18 -08001593 FreeRegLocTemps(cu, rl_result, rl_src1);
1594 FreeRegLocTemps(cu, rl_result, rl_src2);
1595 StoreValueWide(cu, rl_dest, rl_result);
1596 if (cu->instruction_set == kThumb2) {
1597 Clobber(cu, TargetReg(kLr));
1598 UnmarkTemp(cu, TargetReg(kLr)); // Remove lr from the temp pool
buzbeeb046e162012-10-30 15:48:42 -07001599 }
buzbee31a4a6f2012-02-28 15:36:15 -08001600}
1601
1602
buzbeefa57c472012-11-21 12:06:18 -08001603bool GenShiftOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
1604 RegLocation rl_src1, RegLocation rl_shift)
buzbee31a4a6f2012-02-28 15:36:15 -08001605{
buzbeefa57c472012-11-21 12:06:18 -08001606 int func_offset;
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:
buzbeefa57c472012-11-21 12:06:18 -08001611 func_offset = ENTRYPOINT_OFFSET(pShlLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001612 break;
1613 case Instruction::SHR_LONG:
1614 case Instruction::SHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001615 func_offset = ENTRYPOINT_OFFSET(pShrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001616 break;
1617 case Instruction::USHR_LONG:
1618 case Instruction::USHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001619 func_offset = ENTRYPOINT_OFFSET(pUshrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001620 break;
1621 default:
1622 LOG(FATAL) << "Unexpected case";
1623 return true;
1624 }
buzbeefa57c472012-11-21 12:06:18 -08001625 FlushAllRegs(cu); /* Send everything to home location */
1626 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_shift, false);
1627 RegLocation rl_result = GetReturnWide(cu, false);
1628 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001629 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001630}
1631
1632
buzbeefa57c472012-11-21 12:06:18 -08001633bool GenArithOpInt(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
1634 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001635{
Bill Buzbeea114add2012-05-03 15:00:40 -07001636 OpKind op = kOpBkpt;
buzbeefa57c472012-11-21 12:06:18 -08001637 bool is_div_rem = false;
1638 bool check_zero = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001639 bool unary = false;
buzbeefa57c472012-11-21 12:06:18 -08001640 RegLocation rl_result;
1641 bool shift_op = 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:
buzbeefa57c472012-11-21 12:06:18 -08001665 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001666 op = kOpDiv;
buzbeefa57c472012-11-21 12:06:18 -08001667 is_div_rem = 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:
buzbeefa57c472012-11-21 12:06:18 -08001672 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001673 op = kOpRem;
buzbeefa57c472012-11-21 12:06:18 -08001674 is_div_rem = 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:
buzbeefa57c472012-11-21 12:06:18 -08001690 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001691 op = kOpLsl;
1692 break;
1693 case Instruction::SHR_INT:
1694 case Instruction::SHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001695 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001696 op = kOpAsr;
1697 break;
1698 case Instruction::USHR_INT:
1699 case Instruction::USHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001700 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001701 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 }
buzbeefa57c472012-11-21 12:06:18 -08001706 if (!is_div_rem) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001707 if (unary) {
buzbeefa57c472012-11-21 12:06:18 -08001708 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1709 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1710 OpRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg);
buzbee31a4a6f2012-02-28 15:36:15 -08001711 } else {
buzbeefa57c472012-11-21 12:06:18 -08001712 if (shift_op) {
1713 int t_reg = INVALID_REG;
1714 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001715 // X86 doesn't require masking and must use ECX
buzbeefa57c472012-11-21 12:06:18 -08001716 t_reg = TargetReg(kCount); // rCX
1717 LoadValueDirectFixed(cu, rl_src2, t_reg);
buzbeeb046e162012-10-30 15:48:42 -07001718 } else {
buzbeefa57c472012-11-21 12:06:18 -08001719 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1720 t_reg = AllocTemp(cu);
1721 OpRegRegImm(cu, kOpAnd, t_reg, rl_src2.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -07001722 }
buzbeefa57c472012-11-21 12:06:18 -08001723 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1724 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1725 OpRegRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg, t_reg);
1726 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001727 } else {
buzbeefa57c472012-11-21 12:06:18 -08001728 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1729 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1730 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1731 OpRegRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001732 }
buzbee31a4a6f2012-02-28 15:36:15 -08001733 }
buzbeefa57c472012-11-21 12:06:18 -08001734 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001735 } else {
buzbeefa57c472012-11-21 12:06:18 -08001736 if (cu->instruction_set == kMips) {
1737 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1738 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1739 if (check_zero) {
1740 GenImmedCheck(cu, kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001741 }
buzbeefa57c472012-11-21 12:06:18 -08001742 rl_result = GenDivRem(cu, rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
jeffhao4f8f04a2012-10-02 18:10:35 -07001743 } else {
buzbeefa57c472012-11-21 12:06:18 -08001744 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
1745 FlushAllRegs(cu); /* Send everything to home location */
1746 LoadValueDirectFixed(cu, rl_src2, TargetReg(kArg1));
1747 int r_tgt = CallHelperSetup(cu, func_offset);
1748 LoadValueDirectFixed(cu, rl_src1, TargetReg(kArg0));
1749 if (check_zero) {
1750 GenImmedCheck(cu, kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001751 }
1752 // NOTE: callout here is not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08001753 CallHelper(cu, r_tgt, func_offset, false /* not a safepoint */ );
buzbeeb046e162012-10-30 15:48:42 -07001754 if (op == kOpDiv)
buzbeefa57c472012-11-21 12:06:18 -08001755 rl_result = GetReturn(cu, false);
buzbeeb046e162012-10-30 15:48:42 -07001756 else
buzbeefa57c472012-11-21 12:06:18 -08001757 rl_result = GetReturnAlt(cu);
jeffhao4f8f04a2012-10-02 18:10:35 -07001758 }
buzbeefa57c472012-11-21 12:06:18 -08001759 StoreValue(cu, rl_dest, rl_result);
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
buzbeeaad94382012-11-21 07:40:50 -08001770static bool 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'.
buzbeeaad94382012-11-21 07:40:50 -08001776static bool 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'.
buzbeeaad94382012-11-21 07:40:50 -08001783static int 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
buzbeefa57c472012-11-21 12:06:18 -08001796// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
1797// and store the result in 'rl_dest'.
1798static bool HandleEasyDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
1799 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001800{
buzbeefa57c472012-11-21 12:06:18 -08001801 if ((lit < 2) || ((cu->instruction_set != 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
buzbeefa57c472012-11-21 12:06:18 -08001805 if ((cu->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
1806 return SmallLiteralDivide(cu, dalvik_opcode, rl_src, rl_dest, 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 }
buzbeefa57c472012-11-21 12:06:18 -08001813 bool div = (dalvik_opcode == Instruction::DIV_INT_LIT8 ||
1814 dalvik_opcode == Instruction::DIV_INT_LIT16);
1815 rl_src = LoadValue(cu, rl_src, kCoreReg);
1816 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001817 if (div) {
buzbeefa57c472012-11-21 12:06:18 -08001818 int t_reg = AllocTemp(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001819 if (lit == 2) {
1820 // Division by 2 is by far the most common division by constant.
buzbeefa57c472012-11-21 12:06:18 -08001821 OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, 32 - k);
1822 OpRegRegReg(cu, kOpAdd, t_reg, t_reg, rl_src.low_reg);
1823 OpRegRegImm(cu, kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001824 } else {
buzbeefa57c472012-11-21 12:06:18 -08001825 OpRegRegImm(cu, kOpAsr, t_reg, rl_src.low_reg, 31);
1826 OpRegRegImm(cu, kOpLsr, t_reg, t_reg, 32 - k);
1827 OpRegRegReg(cu, kOpAdd, t_reg, t_reg, rl_src.low_reg);
1828 OpRegRegImm(cu, kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001829 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001830 } else {
buzbeefa57c472012-11-21 12:06:18 -08001831 int t_reg1 = AllocTemp(cu);
1832 int t_reg2 = AllocTemp(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001833 if (lit == 2) {
buzbeefa57c472012-11-21 12:06:18 -08001834 OpRegRegImm(cu, kOpLsr, t_reg1, rl_src.low_reg, 32 - k);
1835 OpRegRegReg(cu, kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1836 OpRegRegImm(cu, kOpAnd, t_reg2, t_reg2, lit -1);
1837 OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001838 } else {
buzbeefa57c472012-11-21 12:06:18 -08001839 OpRegRegImm(cu, kOpAsr, t_reg1, rl_src.low_reg, 31);
1840 OpRegRegImm(cu, kOpLsr, t_reg1, t_reg1, 32 - k);
1841 OpRegRegReg(cu, kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1842 OpRegRegImm(cu, kOpAnd, t_reg2, t_reg2, lit - 1);
1843 OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001844 }
1845 }
buzbeefa57c472012-11-21 12:06:18 -08001846 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001847 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001848}
1849
buzbeefa57c472012-11-21 12:06:18 -08001850// Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit'
1851// and store the result in 'rl_dest'.
1852static bool HandleEasyMultiply(CompilationUnit* cu, RegLocation rl_src,
1853 RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001854{
Bill Buzbeea114add2012-05-03 15:00:40 -07001855 // Can we simplify this multiplication?
buzbeefa57c472012-11-21 12:06:18 -08001856 bool power_of_two = false;
1857 bool pop_count_le2 = false;
1858 bool power_of_two_minus_one = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001859 if (lit < 2) {
1860 // Avoid special cases.
1861 return false;
buzbee52a77fc2012-11-20 19:50:46 -08001862 } else if (IsPowerOfTwo(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001863 power_of_two = true;
buzbee52a77fc2012-11-20 19:50:46 -08001864 } else if (IsPopCountLE2(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001865 pop_count_le2 = true;
buzbee52a77fc2012-11-20 19:50:46 -08001866 } else if (IsPowerOfTwo(lit + 1)) {
buzbeefa57c472012-11-21 12:06:18 -08001867 power_of_two_minus_one = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001868 } else {
1869 return false;
1870 }
buzbeefa57c472012-11-21 12:06:18 -08001871 rl_src = LoadValue(cu, rl_src, kCoreReg);
1872 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1873 if (power_of_two) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001874 // Shift.
buzbeefa57c472012-11-21 12:06:18 -08001875 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_src.low_reg,
buzbee52a77fc2012-11-20 19:50:46 -08001876 LowestSetBit(lit));
buzbeefa57c472012-11-21 12:06:18 -08001877 } else if (pop_count_le2) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001878 // Shift and add and shift.
buzbeefa57c472012-11-21 12:06:18 -08001879 int first_bit = LowestSetBit(lit);
1880 int second_bit = LowestSetBit(lit ^ (1 << first_bit));
1881 GenMultiplyByTwoBitMultiplier(cu, rl_src, rl_result, lit,
1882 first_bit, second_bit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001883 } else {
1884 // Reverse subtract: (src << (shift + 1)) - src.
buzbeefa57c472012-11-21 12:06:18 -08001885 DCHECK(power_of_two_minus_one);
buzbee52a77fc2012-11-20 19:50:46 -08001886 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
buzbeefa57c472012-11-21 12:06:18 -08001887 int t_reg = AllocTemp(cu);
1888 OpRegRegImm(cu, kOpLsl, t_reg, rl_src.low_reg, LowestSetBit(lit + 1));
1889 OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001890 }
buzbeefa57c472012-11-21 12:06:18 -08001891 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001892 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001893}
1894
buzbeefa57c472012-11-21 12:06:18 -08001895bool GenArithOpIntLit(CompilationUnit* cu, Instruction::Code opcode,
1896 RegLocation rl_dest, RegLocation rl_src, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001897{
buzbeefa57c472012-11-21 12:06:18 -08001898 RegLocation rl_result;
buzbeecbd6d442012-11-17 14:11:25 -08001899 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */
buzbeefa57c472012-11-21 12:06:18 -08001900 int shift_op = false;
1901 bool is_div = 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: {
buzbeefa57c472012-11-21 12:06:18 -08001906 int t_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -07001907 //TUNING: add support for use of Arm rsub op
buzbeefa57c472012-11-21 12:06:18 -08001908 rl_src = LoadValue(cu, rl_src, kCoreReg);
1909 t_reg = AllocTemp(cu);
1910 LoadConstant(cu, t_reg, lit);
1911 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1912 OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
1913 StoreValue(cu, rl_dest, rl_result);
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: {
buzbeefa57c472012-11-21 12:06:18 -08001924 if (HandleEasyMultiply(cu, rl_src, rl_dest, 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;
buzbeefa57c472012-11-21 12:06:18 -08001945 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001946 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;
buzbeefa57c472012-11-21 12:06:18 -08001951 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001952 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;
buzbeefa57c472012-11-21 12:06:18 -08001957 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001958 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) {
buzbeefa57c472012-11-21 12:06:18 -08001966 GenImmedCheck(cu, kCondAl, 0, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07001967 return false;
1968 }
buzbeefa57c472012-11-21 12:06:18 -08001969 if (HandleEasyDivide(cu, opcode, rl_src, rl_dest, 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)) {
buzbeefa57c472012-11-21 12:06:18 -08001974 is_div = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001975 } else {
buzbeefa57c472012-11-21 12:06:18 -08001976 is_div = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001977 }
buzbeefa57c472012-11-21 12:06:18 -08001978 if (cu->instruction_set == kMips) {
1979 rl_src = LoadValue(cu, rl_src, kCoreReg);
1980 rl_result = GenDivRemLit(cu, rl_dest, rl_src.low_reg, lit, is_div);
jeffhao4f8f04a2012-10-02 18:10:35 -07001981 } else {
buzbeefa57c472012-11-21 12:06:18 -08001982 FlushAllRegs(cu); /* Everything to home location */
1983 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0));
1984 Clobber(cu, TargetReg(kArg0));
1985 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
1986 CallRuntimeHelperRegImm(cu, func_offset, TargetReg(kArg0), lit, false);
1987 if (is_div)
1988 rl_result = GetReturn(cu, false);
buzbeeb046e162012-10-30 15:48:42 -07001989 else
buzbeefa57c472012-11-21 12:06:18 -08001990 rl_result = GetReturnAlt(cu);
jeffhao4f8f04a2012-10-02 18:10:35 -07001991 }
buzbeefa57c472012-11-21 12:06:18 -08001992 StoreValue(cu, rl_dest, rl_result);
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 }
buzbeefa57c472012-11-21 12:06:18 -08001999 rl_src = LoadValue(cu, rl_src, kCoreReg);
2000 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07002001 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
buzbeefa57c472012-11-21 12:06:18 -08002002 if (shift_op && (lit == 0)) {
2003 OpRegCopy(cu, rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07002004 } else {
buzbeefa57c472012-11-21 12:06:18 -08002005 OpRegRegImm(cu, op, rl_result.low_reg, rl_src.low_reg, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07002006 }
buzbeefa57c472012-11-21 12:06:18 -08002007 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07002008 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002009}
2010
buzbeefa57c472012-11-21 12:06:18 -08002011bool GenArithOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
2012 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08002013{
buzbeefa57c472012-11-21 12:06:18 -08002014 RegLocation rl_result;
2015 OpKind first_op = kOpBkpt;
2016 OpKind second_op = kOpBkpt;
2017 bool call_out = false;
2018 bool check_zero = false;
2019 int func_offset;
2020 int ret_reg = 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:
buzbeefa57c472012-11-21 12:06:18 -08002024 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
2025 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07002026 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -08002027 if (rl_result.low_reg == rl_src2.high_reg) {
2028 int t_reg = AllocTemp(cu);
2029 OpRegCopy(cu, t_reg, rl_src2.high_reg);
2030 OpRegReg(cu, kOpMvn, rl_result.low_reg, rl_src2.low_reg);
2031 OpRegReg(cu, kOpMvn, rl_result.high_reg, t_reg);
2032 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07002033 } else {
buzbeefa57c472012-11-21 12:06:18 -08002034 OpRegReg(cu, kOpMvn, rl_result.low_reg, rl_src2.low_reg);
2035 OpRegReg(cu, kOpMvn, rl_result.high_reg, rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07002036 }
buzbeefa57c472012-11-21 12:06:18 -08002037 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07002038 return false;
2039 break;
2040 case Instruction::ADD_LONG:
2041 case Instruction::ADD_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08002042 if (cu->instruction_set != kThumb2) {
2043 return GenAddLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07002044 }
buzbeefa57c472012-11-21 12:06:18 -08002045 first_op = kOpAdd;
2046 second_op = kOpAdc;
Bill Buzbeea114add2012-05-03 15:00:40 -07002047 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002048 case Instruction::SUB_LONG:
2049 case Instruction::SUB_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08002050 if (cu->instruction_set != kThumb2) {
2051 return GenSubLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07002052 }
buzbeefa57c472012-11-21 12:06:18 -08002053 first_op = kOpSub;
2054 second_op = kOpSbc;
Bill Buzbeea114add2012-05-03 15:00:40 -07002055 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002056 case Instruction::MUL_LONG:
2057 case Instruction::MUL_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08002058 call_out = true;
2059 ret_reg = TargetReg(kRet0);
2060 func_offset = ENTRYPOINT_OFFSET(pLmul);
Bill Buzbeea114add2012-05-03 15:00:40 -07002061 break;
2062 case Instruction::DIV_LONG:
2063 case Instruction::DIV_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08002064 call_out = true;
2065 check_zero = true;
2066 ret_reg = TargetReg(kRet0);
2067 func_offset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002068 break;
2069 case Instruction::REM_LONG:
2070 case Instruction::REM_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08002071 call_out = true;
2072 check_zero = true;
2073 func_offset = ENTRYPOINT_OFFSET(pLdivmod);
buzbeef0504cd2012-11-13 16:31:10 -08002074 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
buzbeefa57c472012-11-21 12:06:18 -08002075 ret_reg = (cu->instruction_set == 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:
buzbeefa57c472012-11-21 12:06:18 -08002079 if (cu->instruction_set == kX86) {
2080 return GenAndLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07002081 }
buzbeefa57c472012-11-21 12:06:18 -08002082 first_op = kOpAnd;
2083 second_op = kOpAnd;
Bill Buzbeea114add2012-05-03 15:00:40 -07002084 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002085 case Instruction::OR_LONG:
2086 case Instruction::OR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08002087 if (cu->instruction_set == kX86) {
2088 return GenOrLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07002089 }
buzbeefa57c472012-11-21 12:06:18 -08002090 first_op = kOpOr;
2091 second_op = kOpOr;
Bill Buzbeea114add2012-05-03 15:00:40 -07002092 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002093 case Instruction::XOR_LONG:
2094 case Instruction::XOR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08002095 if (cu->instruction_set == kX86) {
2096 return GenXorLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07002097 }
buzbeefa57c472012-11-21 12:06:18 -08002098 first_op = kOpXor;
2099 second_op = kOpXor;
Bill Buzbeea114add2012-05-03 15:00:40 -07002100 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07002101 case Instruction::NEG_LONG: {
buzbeefa57c472012-11-21 12:06:18 -08002102 return GenNegLong(cu, rl_dest, rl_src2);
buzbee31a4a6f2012-02-28 15:36:15 -08002103 }
Bill Buzbeea114add2012-05-03 15:00:40 -07002104 default:
2105 LOG(FATAL) << "Invalid long arith op";
2106 }
buzbeefa57c472012-11-21 12:06:18 -08002107 if (!call_out) {
2108 GenLong3Addr(cu, first_op, second_op, rl_dest, rl_src1, rl_src2);
Bill Buzbeea114add2012-05-03 15:00:40 -07002109 } else {
buzbeefa57c472012-11-21 12:06:18 -08002110 FlushAllRegs(cu); /* Send everything to home location */
2111 if (check_zero) {
2112 LoadValueDirectWideFixed(cu, rl_src2, TargetReg(kArg2), TargetReg(kArg3));
2113 int r_tgt = CallHelperSetup(cu, func_offset);
2114 GenDivZeroCheck(cu, TargetReg(kArg2), TargetReg(kArg3));
2115 LoadValueDirectWideFixed(cu, rl_src1, TargetReg(kArg0), TargetReg(kArg1));
buzbee8320f382012-09-11 16:29:42 -07002116 // NOTE: callout here is not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08002117 CallHelper(cu, r_tgt, func_offset, false /* not safepoint */);
buzbee31a4a6f2012-02-28 15:36:15 -08002118 } else {
buzbeefa57c472012-11-21 12:06:18 -08002119 CallRuntimeHelperRegLocationRegLocation(cu, func_offset,
2120 rl_src1, rl_src2, 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
buzbeefa57c472012-11-21 12:06:18 -08002123 if (ret_reg == TargetReg(kRet0))
2124 rl_result = GetReturnWide(cu, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07002125 else
buzbeefa57c472012-11-21 12:06:18 -08002126 rl_result = GetReturnWideAlt(cu);
2127 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07002128 }
2129 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002130}
2131
buzbeefa57c472012-11-21 12:06:18 -08002132bool GenConversionCall(CompilationUnit* cu, int func_offset,
2133 RegLocation rl_dest, RegLocation rl_src)
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 */
buzbeefa57c472012-11-21 12:06:18 -08002139 FlushAllRegs(cu); /* Send everything to home location */
2140 if (rl_src.wide) {
2141 LoadValueDirectWideFixed(cu, rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0),
2142 rl_src.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee408ad162012-06-06 16:45:18 -07002143 } else {
buzbeefa57c472012-11-21 12:06:18 -08002144 LoadValueDirectFixed(cu, rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -07002145 }
buzbeefa57c472012-11-21 12:06:18 -08002146 CallRuntimeHelperRegLocation(cu, func_offset, rl_src, false);
2147 if (rl_dest.wide) {
2148 RegLocation rl_result;
2149 rl_result = GetReturnWide(cu, rl_dest.fp);
2150 StoreValueWide(cu, rl_dest, rl_result);
buzbee408ad162012-06-06 16:45:18 -07002151 } else {
buzbeefa57c472012-11-21 12:06:18 -08002152 RegLocation rl_result;
2153 rl_result = GetReturn(cu, rl_dest.fp);
2154 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07002155 }
2156 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002157}
2158
buzbeefa57c472012-11-21 12:06:18 -08002159bool GenArithOpFloatPortable(CompilationUnit* cu, Instruction::Code opcode,
2160 RegLocation rl_dest, RegLocation rl_src1,
2161 RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08002162{
buzbeefa57c472012-11-21 12:06:18 -08002163 RegLocation rl_result;
2164 int func_offset;
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:
buzbeefa57c472012-11-21 12:06:18 -08002169 func_offset = ENTRYPOINT_OFFSET(pFadd);
Bill Buzbeea114add2012-05-03 15:00:40 -07002170 break;
2171 case Instruction::SUB_FLOAT_2ADDR:
2172 case Instruction::SUB_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -08002173 func_offset = ENTRYPOINT_OFFSET(pFsub);
Bill Buzbeea114add2012-05-03 15:00:40 -07002174 break;
2175 case Instruction::DIV_FLOAT_2ADDR:
2176 case Instruction::DIV_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -08002177 func_offset = ENTRYPOINT_OFFSET(pFdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002178 break;
2179 case Instruction::MUL_FLOAT_2ADDR:
2180 case Instruction::MUL_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -08002181 func_offset = ENTRYPOINT_OFFSET(pFmul);
Bill Buzbeea114add2012-05-03 15:00:40 -07002182 break;
2183 case Instruction::REM_FLOAT_2ADDR:
2184 case Instruction::REM_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -08002185 func_offset = ENTRYPOINT_OFFSET(pFmodf);
Bill Buzbeea114add2012-05-03 15:00:40 -07002186 break;
2187 case Instruction::NEG_FLOAT: {
buzbeefa57c472012-11-21 12:06:18 -08002188 GenNegFloat(cu, rl_dest, rl_src1);
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 }
buzbeefa57c472012-11-21 12:06:18 -08002194 FlushAllRegs(cu); /* Send everything to home location */
2195 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_src2, false);
2196 rl_result = GetReturn(cu, true);
2197 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07002198 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002199}
2200
buzbeefa57c472012-11-21 12:06:18 -08002201bool GenArithOpDoublePortable(CompilationUnit* cu, Instruction::Code opcode,
2202 RegLocation rl_dest, RegLocation rl_src1,
2203 RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08002204{
buzbeefa57c472012-11-21 12:06:18 -08002205 RegLocation rl_result;
2206 int func_offset;
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:
buzbeefa57c472012-11-21 12:06:18 -08002211 func_offset = ENTRYPOINT_OFFSET(pDadd);
Bill Buzbeea114add2012-05-03 15:00:40 -07002212 break;
2213 case Instruction::SUB_DOUBLE_2ADDR:
2214 case Instruction::SUB_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -08002215 func_offset = ENTRYPOINT_OFFSET(pDsub);
Bill Buzbeea114add2012-05-03 15:00:40 -07002216 break;
2217 case Instruction::DIV_DOUBLE_2ADDR:
2218 case Instruction::DIV_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -08002219 func_offset = ENTRYPOINT_OFFSET(pDdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07002220 break;
2221 case Instruction::MUL_DOUBLE_2ADDR:
2222 case Instruction::MUL_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -08002223 func_offset = ENTRYPOINT_OFFSET(pDmul);
Bill Buzbeea114add2012-05-03 15:00:40 -07002224 break;
2225 case Instruction::REM_DOUBLE_2ADDR:
2226 case Instruction::REM_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -08002227 func_offset = ENTRYPOINT_OFFSET(pFmod);
Bill Buzbeea114add2012-05-03 15:00:40 -07002228 break;
2229 case Instruction::NEG_DOUBLE: {
buzbeefa57c472012-11-21 12:06:18 -08002230 GenNegDouble(cu, rl_dest, rl_src1);
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 }
buzbeefa57c472012-11-21 12:06:18 -08002236 FlushAllRegs(cu); /* Send everything to home location */
2237 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_src2, false);
2238 rl_result = GetReturnWide(cu, true);
2239 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07002240 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08002241}
2242
buzbeefa57c472012-11-21 12:06:18 -08002243bool GenConversionPortable(CompilationUnit* cu, Instruction::Code opcode,
2244 RegLocation rl_dest, RegLocation rl_src)
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:
buzbeefa57c472012-11-21 12:06:18 -08002249 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pI2f),
2250 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002251 case Instruction::FLOAT_TO_INT:
buzbeefa57c472012-11-21 12:06:18 -08002252 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pF2iz),
2253 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002254 case Instruction::DOUBLE_TO_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -08002255 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pD2f),
2256 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002257 case Instruction::FLOAT_TO_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -08002258 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pF2d),
2259 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002260 case Instruction::INT_TO_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -08002261 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pI2d),
2262 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002263 case Instruction::DOUBLE_TO_INT:
buzbeefa57c472012-11-21 12:06:18 -08002264 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pD2iz),
2265 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002266 case Instruction::FLOAT_TO_LONG:
buzbeefa57c472012-11-21 12:06:18 -08002267 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pF2l),
2268 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002269 case Instruction::LONG_TO_FLOAT:
buzbeefa57c472012-11-21 12:06:18 -08002270 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pL2f),
2271 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002272 case Instruction::DOUBLE_TO_LONG:
buzbeefa57c472012-11-21 12:06:18 -08002273 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pD2l),
2274 rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07002275 case Instruction::LONG_TO_DOUBLE:
buzbeefa57c472012-11-21 12:06:18 -08002276 return GenConversionCall(cu, ENTRYPOINT_OFFSET(pL2d),
2277 rl_dest, rl_src);
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 */
buzbeefa57c472012-11-21 12:06:18 -08002285void GenSuspendTest(CompilationUnit* cu, int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -08002286{
buzbeefa57c472012-11-21 12:06:18 -08002287 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07002288 return;
2289 }
buzbeefa57c472012-11-21 12:06:18 -08002290 FlushAllRegs(cu);
2291 LIR* branch = OpTestSuspend(cu, NULL);
2292 LIR* ret_lab = NewLIR0(cu, kPseudoTargetLabel);
2293 LIR* target = RawLIR(cu, cu->current_dalvik_offset, kPseudoSuspendTarget,
2294 reinterpret_cast<uintptr_t>(ret_lab), cu->current_dalvik_offset);
buzbeecbd6d442012-11-17 14:11:25 -08002295 branch->target = target;
buzbeefa57c472012-11-21 12:06:18 -08002296 InsertGrowableList(cu, &cu->suspend_launchpads, 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 */
buzbeefa57c472012-11-21 12:06:18 -08002300void GenSuspendTestAndBranch(CompilationUnit* cu, int opt_flags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07002301{
buzbeefa57c472012-11-21 12:06:18 -08002302 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
2303 OpUnconditionalBranch(cu, target);
Bill Buzbeea114add2012-05-03 15:00:40 -07002304 return;
2305 }
buzbeefa57c472012-11-21 12:06:18 -08002306 OpTestSuspend(cu, target);
2307 LIR* launch_pad =
2308 RawLIR(cu, cu->current_dalvik_offset, kPseudoSuspendTarget,
2309 reinterpret_cast<uintptr_t>(target), cu->current_dalvik_offset);
2310 FlushAllRegs(cu);
2311 OpUnconditionalBranch(cu, launch_pad);
2312 InsertGrowableList(cu, &cu->suspend_launchpads, reinterpret_cast<uintptr_t>(launch_pad));
buzbeefead2932012-03-30 14:02:01 -07002313}
2314
buzbee31a4a6f2012-02-28 15:36:15 -08002315} // namespace art