blob: db99a306e18e52174fe0a8395664396518747734 [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
24/*
25 * This source files contains "gen" codegen routines that should
26 * be applicable to most targets. Only mid-level support utilities
27 * and "op" calls may be used here.
28 */
buzbee31a4a6f2012-02-28 15:36:15 -080029
buzbee31a4a6f2012-02-28 15:36:15 -080030/*
31 * Generate an kPseudoBarrier marker to indicate the boundary of special
32 * blocks.
33 */
buzbee02031b12012-11-23 09:41:35 -080034void Codegen::GenBarrier(CompilationUnit* cu)
buzbee31a4a6f2012-02-28 15:36:15 -080035{
buzbeefa57c472012-11-21 12:06:18 -080036 LIR* barrier = NewLIR0(cu, kPseudoBarrier);
Bill Buzbeea114add2012-05-03 15:00:40 -070037 /* Mark all resources as being clobbered */
buzbeefa57c472012-11-21 12:06:18 -080038 barrier->def_mask = -1;
buzbee31a4a6f2012-02-28 15:36:15 -080039}
40
buzbee5de34942012-03-01 14:51:57 -080041// FIXME: need to do some work to split out targets with
42// condition codes and those without
buzbee02031b12012-11-23 09:41:35 -080043LIR* Codegen::GenCheck(CompilationUnit* cu, ConditionCode c_code, ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080044{
buzbeefa57c472012-11-21 12:06:18 -080045 DCHECK_NE(cu->instruction_set, kMips);
46 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
47 cu->current_dalvik_offset);
48 LIR* branch = OpCondBranch(cu, c_code, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070049 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -080050 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -070051 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080052}
53
buzbee02031b12012-11-23 09:41:35 -080054LIR* Codegen::GenImmedCheck(CompilationUnit* cu, ConditionCode c_code, int reg, int imm_val,
55 ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080056{
buzbeefa57c472012-11-21 12:06:18 -080057 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
58 cu->current_dalvik_offset);
Bill Buzbeea114add2012-05-03 15:00:40 -070059 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -080060 if (c_code == kCondAl) {
61 branch = OpUnconditionalBranch(cu, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070062 } else {
buzbeefa57c472012-11-21 12:06:18 -080063 branch = OpCmpImmBranch(cu, c_code, reg, imm_val, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070064 }
65 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -080066 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -070067 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080068}
69
70/* Perform null-check on a register. */
buzbee02031b12012-11-23 09:41:35 -080071LIR* Codegen::GenNullCheck(CompilationUnit* cu, int s_reg, int m_reg, int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -080072{
buzbeefa57c472012-11-21 12:06:18 -080073 if (!(cu->disable_opt & (1 << kNullCheckElimination)) &&
74 opt_flags & MIR_IGNORE_NULL_CHECK) {
Bill Buzbeea114add2012-05-03 15:00:40 -070075 return NULL;
76 }
buzbeefa57c472012-11-21 12:06:18 -080077 return GenImmedCheck(cu, kCondEq, m_reg, 0, kThrowNullPointer);
buzbee31a4a6f2012-02-28 15:36:15 -080078}
79
80/* Perform check on two registers */
buzbee02031b12012-11-23 09:41:35 -080081LIR* Codegen::GenRegRegCheck(CompilationUnit* cu, ConditionCode c_code, int reg1, int reg2,
82 ThrowKind kind)
buzbee31a4a6f2012-02-28 15:36:15 -080083{
buzbeefa57c472012-11-21 12:06:18 -080084 LIR* tgt = RawLIR(cu, 0, kPseudoThrowTarget, kind,
85 cu->current_dalvik_offset, reg1, reg2);
86 LIR* branch = OpCmpBranch(cu, c_code, reg1, reg2, tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -070087 // Remember branch target - will process later
buzbeefa57c472012-11-21 12:06:18 -080088 InsertGrowableList(cu, &cu->throw_launchpads, reinterpret_cast<uintptr_t>(tgt));
Bill Buzbeea114add2012-05-03 15:00:40 -070089 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -080090}
91
buzbee02031b12012-11-23 09:41:35 -080092void Codegen::GenCompareAndBranch(CompilationUnit* cu, Instruction::Code opcode,
93 RegLocation rl_src1, RegLocation rl_src2, LIR* taken,
94 LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -080095{
Bill Buzbeea114add2012-05-03 15:00:40 -070096 ConditionCode cond;
buzbeefa57c472012-11-21 12:06:18 -080097 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
98 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -070099 switch (opcode) {
100 case Instruction::IF_EQ:
101 cond = kCondEq;
102 break;
103 case Instruction::IF_NE:
104 cond = kCondNe;
105 break;
106 case Instruction::IF_LT:
107 cond = kCondLt;
108 break;
109 case Instruction::IF_GE:
110 cond = kCondGe;
111 break;
112 case Instruction::IF_GT:
113 cond = kCondGt;
114 break;
115 case Instruction::IF_LE:
116 cond = kCondLe;
117 break;
118 default:
buzbeecbd6d442012-11-17 14:11:25 -0800119 cond = static_cast<ConditionCode>(0);
120 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700121 }
buzbeefa57c472012-11-21 12:06:18 -0800122 OpCmpBranch(cu, cond, rl_src1.low_reg, rl_src2.low_reg, taken);
123 OpUnconditionalBranch(cu, fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800124}
125
buzbee02031b12012-11-23 09:41:35 -0800126void Codegen::GenCompareZeroAndBranch(CompilationUnit* cu, Instruction::Code opcode,
127 RegLocation rl_src, LIR* taken, LIR* fall_through)
buzbee31a4a6f2012-02-28 15:36:15 -0800128{
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 ConditionCode cond;
buzbeefa57c472012-11-21 12:06:18 -0800130 rl_src = LoadValue(cu, rl_src, kCoreReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700131 switch (opcode) {
132 case Instruction::IF_EQZ:
133 cond = kCondEq;
134 break;
135 case Instruction::IF_NEZ:
136 cond = kCondNe;
137 break;
138 case Instruction::IF_LTZ:
139 cond = kCondLt;
140 break;
141 case Instruction::IF_GEZ:
142 cond = kCondGe;
143 break;
144 case Instruction::IF_GTZ:
145 cond = kCondGt;
146 break;
147 case Instruction::IF_LEZ:
148 cond = kCondLe;
149 break;
150 default:
buzbeecbd6d442012-11-17 14:11:25 -0800151 cond = static_cast<ConditionCode>(0);
152 LOG(FATAL) << "Unexpected opcode " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700153 }
buzbeefa57c472012-11-21 12:06:18 -0800154 if (cu->instruction_set == kThumb2) {
155 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
156 OpCondBranch(cu, cond, taken);
buzbeeb046e162012-10-30 15:48:42 -0700157 } else {
buzbeefa57c472012-11-21 12:06:18 -0800158 OpCmpImmBranch(cu, cond, rl_src.low_reg, 0, taken);
buzbeeb046e162012-10-30 15:48:42 -0700159 }
buzbeefa57c472012-11-21 12:06:18 -0800160 OpUnconditionalBranch(cu, fall_through);
buzbee31a4a6f2012-02-28 15:36:15 -0800161}
162
buzbee02031b12012-11-23 09:41:35 -0800163void Codegen::GenIntToLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800164{
buzbeefa57c472012-11-21 12:06:18 -0800165 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
166 if (rl_src.location == kLocPhysReg) {
167 OpRegCopy(cu, rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700168 } else {
buzbeefa57c472012-11-21 12:06:18 -0800169 LoadValueDirect(cu, rl_src, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700170 }
buzbeefa57c472012-11-21 12:06:18 -0800171 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_result.low_reg, 31);
172 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800173}
174
buzbee02031b12012-11-23 09:41:35 -0800175void Codegen::GenIntNarrowing(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
176 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800177{
buzbeefa57c472012-11-21 12:06:18 -0800178 rl_src = LoadValue(cu, rl_src, kCoreReg);
179 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700180 OpKind op = kOpInvalid;
buzbee408ad162012-06-06 16:45:18 -0700181 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700182 case Instruction::INT_TO_BYTE:
183 op = kOp2Byte;
184 break;
185 case Instruction::INT_TO_SHORT:
186 op = kOp2Short;
187 break;
188 case Instruction::INT_TO_CHAR:
189 op = kOp2Char;
190 break;
191 default:
192 LOG(ERROR) << "Bad int conversion type";
193 }
buzbeefa57c472012-11-21 12:06:18 -0800194 OpRegReg(cu, op, rl_result.low_reg, rl_src.low_reg);
195 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800196}
197
198/*
199 * Let helper function take care of everything. Will call
200 * Array::AllocFromCode(type_idx, method, count);
201 * Note: AllocFromCode will handle checks for errNegativeArraySize.
202 */
buzbee02031b12012-11-23 09:41:35 -0800203void Codegen::GenNewArray(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest,
204 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800205{
buzbeefa57c472012-11-21 12:06:18 -0800206 FlushAllRegs(cu); /* Everything to home location */
207 int func_offset;
208 if (cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
209 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700210 type_idx)) {
buzbeefa57c472012-11-21 12:06:18 -0800211 func_offset = ENTRYPOINT_OFFSET(pAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700212 } else {
buzbeefa57c472012-11-21 12:06:18 -0800213 func_offset= ENTRYPOINT_OFFSET(pAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700214 }
buzbeefa57c472012-11-21 12:06:18 -0800215 CallRuntimeHelperImmMethodRegLocation(cu, func_offset, type_idx, rl_src, true);
216 RegLocation rl_result = GetReturn(cu, false);
217 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800218}
219
220/*
buzbee52a77fc2012-11-20 19:50:46 -0800221 * Similar to GenNewArray, but with post-allocation initialization.
buzbee31a4a6f2012-02-28 15:36:15 -0800222 * Verifier guarantees we're dealing with an array class. Current
223 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
224 * Current code also throws internal unimp if not 'L', '[' or 'I'.
225 */
buzbee02031b12012-11-23 09:41:35 -0800226void Codegen::GenFilledNewArray(CompilationUnit* cu, CallInfo* info)
buzbee31a4a6f2012-02-28 15:36:15 -0800227{
buzbeefa57c472012-11-21 12:06:18 -0800228 int elems = info->num_arg_words;
229 int type_idx = info->index;
230 FlushAllRegs(cu); /* Everything to home location */
231 int func_offset;
232 if (cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
233 *cu->dex_file,
234 type_idx)) {
235 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700236 } else {
buzbeefa57c472012-11-21 12:06:18 -0800237 func_offset = ENTRYPOINT_OFFSET(pCheckAndAllocArrayFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700238 }
buzbeefa57c472012-11-21 12:06:18 -0800239 CallRuntimeHelperImmMethodImm(cu, func_offset, type_idx, elems, true);
240 FreeTemp(cu, TargetReg(kArg2));
241 FreeTemp(cu, TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700242 /*
243 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
244 * return region. Because AllocFromCode placed the new array
buzbeef0504cd2012-11-13 16:31:10 -0800245 * in kRet0, we'll just lock it into place. When debugger support is
Bill Buzbeea114add2012-05-03 15:00:40 -0700246 * added, it may be necessary to additionally copy all return
247 * values to a home location in thread-local storage
248 */
buzbeefa57c472012-11-21 12:06:18 -0800249 LockTemp(cu, TargetReg(kRet0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700250
251 // TODO: use the correct component size, currently all supported types
252 // share array alignment with ints (see comment at head of function)
253 size_t component_size = sizeof(int32_t);
254
255 // Having a range of 0 is legal
buzbeefa57c472012-11-21 12:06:18 -0800256 if (info->is_range && (elems > 0)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800257 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 * Bit of ugliness here. We're going generate a mem copy loop
259 * on the register range, but it is possible that some regs
260 * in the range have been promoted. This is unlikely, but
261 * before generating the copy, we'll just force a flush
262 * of any regs in the source range that have been promoted to
263 * home location.
buzbee31a4a6f2012-02-28 15:36:15 -0800264 */
buzbee3b3dbdd2012-06-13 13:39:34 -0700265 for (int i = 0; i < elems; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800266 RegLocation loc = UpdateLoc(cu, info->args[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 if (loc.location == kLocPhysReg) {
buzbeefa57c472012-11-21 12:06:18 -0800268 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, loc.s_reg_low),
269 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700270 }
buzbee31a4a6f2012-02-28 15:36:15 -0800271 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700272 /*
273 * TUNING note: generated code here could be much improved, but
274 * this is an uncommon operation and isn't especially performance
275 * critical.
276 */
buzbeefa57c472012-11-21 12:06:18 -0800277 int r_src = AllocTemp(cu);
278 int r_dst = AllocTemp(cu);
279 int r_idx = AllocTemp(cu);
280 int r_val = INVALID_REG;
281 switch(cu->instruction_set) {
buzbeeb046e162012-10-30 15:48:42 -0700282 case kThumb2:
buzbeefa57c472012-11-21 12:06:18 -0800283 r_val = TargetReg(kLr);
buzbeeb046e162012-10-30 15:48:42 -0700284 break;
285 case kX86:
buzbeefa57c472012-11-21 12:06:18 -0800286 FreeTemp(cu, TargetReg(kRet0));
287 r_val = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700288 break;
289 case kMips:
buzbeefa57c472012-11-21 12:06:18 -0800290 r_val = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700291 break;
buzbeefa57c472012-11-21 12:06:18 -0800292 default: LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
buzbeeb046e162012-10-30 15:48:42 -0700293 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700294 // Set up source pointer
buzbeefa57c472012-11-21 12:06:18 -0800295 RegLocation rl_first = info->args[0];
296 OpRegRegImm(cu, kOpAdd, r_src, TargetReg(kSp),
297 SRegOffset(cu, rl_first.s_reg_low));
Bill Buzbeea114add2012-05-03 15:00:40 -0700298 // Set up the target pointer
buzbeefa57c472012-11-21 12:06:18 -0800299 OpRegRegImm(cu, kOpAdd, r_dst, TargetReg(kRet0),
Bill Buzbeea114add2012-05-03 15:00:40 -0700300 Array::DataOffset(component_size).Int32Value());
301 // Set up the loop counter (known to be > 0)
buzbeefa57c472012-11-21 12:06:18 -0800302 LoadConstant(cu, r_idx, elems - 1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700303 // Generate the copy loop. Going backwards for convenience
buzbeefa57c472012-11-21 12:06:18 -0800304 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -0700305 // Copy next element
buzbeefa57c472012-11-21 12:06:18 -0800306 LoadBaseIndexed(cu, r_src, r_idx, r_val, 2, kWord);
307 StoreBaseIndexed(cu, r_dst, r_idx, r_val, 2, kWord);
308 FreeTemp(cu, r_val);
309 OpDecAndBranch(cu, kCondGe, r_idx, target);
310 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700311 // Restore the target pointer
buzbeefa57c472012-11-21 12:06:18 -0800312 OpRegRegImm(cu, kOpAdd, TargetReg(kRet0), r_dst, -Array::DataOffset(component_size).Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700313 }
buzbeefa57c472012-11-21 12:06:18 -0800314 } else if (!info->is_range) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700315 // TUNING: interleave
buzbee3b3dbdd2012-06-13 13:39:34 -0700316 for (int i = 0; i < elems; i++) {
buzbeefa57c472012-11-21 12:06:18 -0800317 RegLocation rl_arg = LoadValue(cu, info->args[i], kCoreReg);
318 StoreBaseDisp(cu, TargetReg(kRet0),
Bill Buzbeea114add2012-05-03 15:00:40 -0700319 Array::DataOffset(component_size).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800320 i * 4, rl_arg.low_reg, kWord);
buzbee52a77fc2012-11-20 19:50:46 -0800321 // If the LoadValue caused a temp to be allocated, free it
buzbeefa57c472012-11-21 12:06:18 -0800322 if (IsTemp(cu, rl_arg.low_reg)) {
323 FreeTemp(cu, rl_arg.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700324 }
325 }
326 }
buzbeee5f01222012-06-14 15:19:35 -0700327 if (info->result.location != kLocInvalid) {
buzbeefa57c472012-11-21 12:06:18 -0800328 StoreValue(cu, info->result, GetReturn(cu, false /* not fp */));
buzbeee5f01222012-06-14 15:19:35 -0700329 }
buzbee31a4a6f2012-02-28 15:36:15 -0800330}
331
buzbee02031b12012-11-23 09:41:35 -0800332void Codegen::GenSput(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_src,
333 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800334{
buzbeefa57c472012-11-21 12:06:18 -0800335 int field_offset;
336 int ssb_index;
337 bool is_volatile;
338 bool is_referrers_class;
buzbee31a4a6f2012-02-28 15:36:15 -0800339
buzbeefa57c472012-11-21 12:06:18 -0800340 OatCompilationUnit m_unit(cu->class_loader, cu->class_linker, *cu->dex_file,
341 cu->code_item, cu->method_idx, cu->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800342
buzbeefa57c472012-11-21 12:06:18 -0800343 bool fast_path =
344 cu->compiler->ComputeStaticFieldInfo(field_idx, &m_unit,
345 field_offset, ssb_index,
346 is_referrers_class, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700347 true);
buzbeefa57c472012-11-21 12:06:18 -0800348 if (fast_path && !SLOW_FIELD_PATH) {
349 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700350 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800351 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700352 // Fast path, static storage base is this method's class
buzbeefa57c472012-11-21 12:06:18 -0800353 RegLocation rl_method = LoadCurrMethod(cu);
354 rBase = AllocTemp(cu);
355 LoadWordDisp(cu, rl_method.low_reg,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700356 AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbeefa57c472012-11-21 12:06:18 -0800357 if (IsTemp(cu, rl_method.low_reg)) {
358 FreeTemp(cu, rl_method.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700359 }
buzbee31a4a6f2012-02-28 15:36:15 -0800360 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700361 // Medium path, static storage base in a different class which
362 // requires checks that the other class is initialized.
buzbeefa57c472012-11-21 12:06:18 -0800363 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700364 // May do runtime call so everything to home locations.
buzbeefa57c472012-11-21 12:06:18 -0800365 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700366 // Using fixed register to sync with possible call to runtime
367 // support.
buzbeefa57c472012-11-21 12:06:18 -0800368 int r_method = TargetReg(kArg1);
369 LockTemp(cu, r_method);
370 LoadCurrMethodDirect(cu, r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800371 rBase = TargetReg(kArg0);
buzbeefa57c472012-11-21 12:06:18 -0800372 LockTemp(cu, rBase);
373 LoadWordDisp(cu, r_method,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700374 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700375 rBase);
buzbeefa57c472012-11-21 12:06:18 -0800376 LoadWordDisp(cu, rBase,
Bill Buzbeea114add2012-05-03 15:00:40 -0700377 Array::DataOffset(sizeof(Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800378 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700379 // rBase now points at appropriate static storage base (Class*)
380 // or NULL if not initialized. Check for NULL and call helper if NULL.
381 // TUNING: fast path should fall through
buzbeefa57c472012-11-21 12:06:18 -0800382 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, rBase, 0, NULL);
383 LoadConstant(cu, TargetReg(kArg0), ssb_index);
384 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
385 if (cu->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800386 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbeefa57c472012-11-21 12:06:18 -0800387 OpRegCopy(cu, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700388 }
buzbeefa57c472012-11-21 12:06:18 -0800389 LIR* skip_target = NewLIR0(cu, kPseudoTargetLabel);
390 branch_over->target = skip_target;
391 FreeTemp(cu, r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800392 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700393 // rBase now holds static storage base
buzbeefa57c472012-11-21 12:06:18 -0800394 if (is_long_or_double) {
395 rl_src = LoadValueWide(cu, rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700396 } else {
buzbeefa57c472012-11-21 12:06:18 -0800397 rl_src = LoadValue(cu, rl_src, kAnyReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700398 }
buzbeefa57c472012-11-21 12:06:18 -0800399 if (is_volatile) {
400 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700401 }
buzbeefa57c472012-11-21 12:06:18 -0800402 if (is_long_or_double) {
403 StoreBaseDispWide(cu, rBase, field_offset, rl_src.low_reg,
404 rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700405 } else {
buzbeefa57c472012-11-21 12:06:18 -0800406 StoreWordDisp(cu, rBase, field_offset, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700407 }
buzbeefa57c472012-11-21 12:06:18 -0800408 if (is_volatile) {
409 GenMemBarrier(cu, kStoreLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700410 }
buzbeefa57c472012-11-21 12:06:18 -0800411 if (is_object) {
412 MarkGCCard(cu, rl_src.low_reg, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700413 }
buzbeefa57c472012-11-21 12:06:18 -0800414 FreeTemp(cu, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700415 } else {
buzbeefa57c472012-11-21 12:06:18 -0800416 FlushAllRegs(cu); // Everything to home locations
417 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Static) :
418 (is_object ? ENTRYPOINT_OFFSET(pSetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700419 : ENTRYPOINT_OFFSET(pSet32Static));
buzbeefa57c472012-11-21 12:06:18 -0800420 CallRuntimeHelperImmRegLocation(cu, setter_offset, field_idx, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700421 }
buzbee31a4a6f2012-02-28 15:36:15 -0800422}
423
buzbee02031b12012-11-23 09:41:35 -0800424void Codegen::GenSget(CompilationUnit* cu, uint32_t field_idx, RegLocation rl_dest,
425 bool is_long_or_double, bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800426{
buzbeefa57c472012-11-21 12:06:18 -0800427 int field_offset;
428 int ssb_index;
429 bool is_volatile;
430 bool is_referrers_class;
buzbee31a4a6f2012-02-28 15:36:15 -0800431
buzbeefa57c472012-11-21 12:06:18 -0800432 OatCompilationUnit m_unit(cu->class_loader, cu->class_linker,
433 *cu->dex_file,
434 cu->code_item, cu->method_idx,
435 cu->access_flags);
buzbee31a4a6f2012-02-28 15:36:15 -0800436
buzbeefa57c472012-11-21 12:06:18 -0800437 bool fast_path =
438 cu->compiler->ComputeStaticFieldInfo(field_idx, &m_unit,
439 field_offset, ssb_index,
440 is_referrers_class, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700441 false);
buzbeefa57c472012-11-21 12:06:18 -0800442 if (fast_path && !SLOW_FIELD_PATH) {
443 DCHECK_GE(field_offset, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700444 int rBase;
buzbeefa57c472012-11-21 12:06:18 -0800445 if (is_referrers_class) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700446 // Fast path, static storage base is this method's class
buzbeefa57c472012-11-21 12:06:18 -0800447 RegLocation rl_method = LoadCurrMethod(cu);
448 rBase = AllocTemp(cu);
449 LoadWordDisp(cu, rl_method.low_reg,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700450 AbstractMethod::DeclaringClassOffset().Int32Value(), rBase);
buzbee31a4a6f2012-02-28 15:36:15 -0800451 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700452 // Medium path, static storage base in a different class which
453 // requires checks that the other class is initialized
buzbeefa57c472012-11-21 12:06:18 -0800454 DCHECK_GE(ssb_index, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700455 // May do runtime call so everything to home locations.
buzbeefa57c472012-11-21 12:06:18 -0800456 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700457 // Using fixed register to sync with possible call to runtime
458 // support
buzbeefa57c472012-11-21 12:06:18 -0800459 int r_method = TargetReg(kArg1);
460 LockTemp(cu, r_method);
461 LoadCurrMethodDirect(cu, r_method);
buzbee52a77fc2012-11-20 19:50:46 -0800462 rBase = TargetReg(kArg0);
buzbeefa57c472012-11-21 12:06:18 -0800463 LockTemp(cu, rBase);
464 LoadWordDisp(cu, r_method,
Mathieu Chartier66f19252012-09-18 08:57:04 -0700465 AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(),
Bill Buzbeea114add2012-05-03 15:00:40 -0700466 rBase);
buzbeefa57c472012-11-21 12:06:18 -0800467 LoadWordDisp(cu, rBase,
Bill Buzbeea114add2012-05-03 15:00:40 -0700468 Array::DataOffset(sizeof(Object*)).Int32Value() +
buzbeefa57c472012-11-21 12:06:18 -0800469 sizeof(int32_t*) * ssb_index, rBase);
Bill Buzbeea114add2012-05-03 15:00:40 -0700470 // rBase now points at appropriate static storage base (Class*)
471 // or NULL if not initialized. Check for NULL and call helper if NULL.
472 // TUNING: fast path should fall through
buzbeefa57c472012-11-21 12:06:18 -0800473 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, rBase, 0, NULL);
474 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true);
475 if (cu->instruction_set == kMips) {
buzbeef0504cd2012-11-13 16:31:10 -0800476 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy
buzbeefa57c472012-11-21 12:06:18 -0800477 OpRegCopy(cu, rBase, TargetReg(kRet0));
buzbeeb046e162012-10-30 15:48:42 -0700478 }
buzbeefa57c472012-11-21 12:06:18 -0800479 LIR* skip_target = NewLIR0(cu, kPseudoTargetLabel);
480 branch_over->target = skip_target;
481 FreeTemp(cu, r_method);
buzbee31a4a6f2012-02-28 15:36:15 -0800482 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700483 // rBase now holds static storage base
buzbeefa57c472012-11-21 12:06:18 -0800484 RegLocation rl_result = EvalLoc(cu, rl_dest, kAnyReg, true);
485 if (is_volatile) {
486 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700487 }
buzbeefa57c472012-11-21 12:06:18 -0800488 if (is_long_or_double) {
489 LoadBaseDispWide(cu, rBase, field_offset, rl_result.low_reg,
490 rl_result.high_reg, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -0700491 } else {
buzbeefa57c472012-11-21 12:06:18 -0800492 LoadWordDisp(cu, rBase, field_offset, rl_result.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700493 }
buzbeefa57c472012-11-21 12:06:18 -0800494 FreeTemp(cu, rBase);
495 if (is_long_or_double) {
496 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700497 } else {
buzbeefa57c472012-11-21 12:06:18 -0800498 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700499 }
500 } else {
buzbeefa57c472012-11-21 12:06:18 -0800501 FlushAllRegs(cu); // Everything to home locations
502 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Static) :
503 (is_object ? ENTRYPOINT_OFFSET(pGetObjStatic)
Bill Buzbeea114add2012-05-03 15:00:40 -0700504 : ENTRYPOINT_OFFSET(pGet32Static));
buzbeefa57c472012-11-21 12:06:18 -0800505 CallRuntimeHelperImm(cu, getterOffset, field_idx, true);
506 if (is_long_or_double) {
507 RegLocation rl_result = GetReturnWide(cu, rl_dest.fp);
508 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700509 } else {
buzbeefa57c472012-11-21 12:06:18 -0800510 RegLocation rl_result = GetReturn(cu, rl_dest.fp);
511 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700512 }
513 }
buzbee31a4a6f2012-02-28 15:36:15 -0800514}
515
516
517// Debugging routine - if null target, branch to DebugMe
buzbee02031b12012-11-23 09:41:35 -0800518void Codegen::GenShowTarget(CompilationUnit* cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800519{
buzbeefa57c472012-11-21 12:06:18 -0800520 DCHECK_NE(cu->instruction_set, kX86) << "unimplemented GenShowTarget";
521 LIR* branch_over = OpCmpImmBranch(cu, kCondNe, TargetReg(kInvokeTgt), 0, NULL);
522 LoadWordDisp(cu, TargetReg(kSelf), ENTRYPOINT_OFFSET(pDebugMe), TargetReg(kInvokeTgt));
523 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
524 branch_over->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -0800525}
526
buzbee02031b12012-11-23 09:41:35 -0800527void Codegen::HandleSuspendLaunchPads(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800528{
buzbeefa57c472012-11-21 12:06:18 -0800529 LIR** suspend_label = reinterpret_cast<LIR**>(cu->suspend_launchpads.elem_list);
530 int num_elems = cu->suspend_launchpads.num_used;
531 int helper_offset = ENTRYPOINT_OFFSET(pTestSuspendFromCode);
532 for (int i = 0; i < num_elems; i++) {
533 ResetRegPool(cu);
534 ResetDefTracking(cu);
535 LIR* lab = suspend_label[i];
536 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[0]);
537 cu->current_dalvik_offset = lab->operands[1];
538 AppendLIR(cu, lab);
539 int r_tgt = CallHelperSetup(cu, helper_offset);
540 CallHelper(cu, r_tgt, helper_offset, true /* MarkSafepointPC */);
541 OpUnconditionalBranch(cu, resume_lab);
Bill Buzbeea114add2012-05-03 15:00:40 -0700542 }
buzbee31a4a6f2012-02-28 15:36:15 -0800543}
544
buzbee02031b12012-11-23 09:41:35 -0800545void Codegen::HandleIntrinsicLaunchPads(CompilationUnit *cu)
buzbeefc9e6fa2012-03-23 15:14:29 -0700546{
buzbeefa57c472012-11-21 12:06:18 -0800547 LIR** intrinsic_label = reinterpret_cast<LIR**>(cu->intrinsic_launchpads.elem_list);
548 int num_elems = cu->intrinsic_launchpads.num_used;
549 for (int i = 0; i < num_elems; i++) {
550 ResetRegPool(cu);
551 ResetDefTracking(cu);
552 LIR* lab = intrinsic_label[i];
buzbeecbd6d442012-11-17 14:11:25 -0800553 CallInfo* info = reinterpret_cast<CallInfo*>(lab->operands[0]);
buzbeefa57c472012-11-21 12:06:18 -0800554 cu->current_dalvik_offset = info->offset;
555 AppendLIR(cu, lab);
buzbee52a77fc2012-11-20 19:50:46 -0800556 // NOTE: GenInvoke handles MarkSafepointPC
buzbeefa57c472012-11-21 12:06:18 -0800557 GenInvoke(cu, info);
558 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[2]);
559 if (resume_lab != NULL) {
560 OpUnconditionalBranch(cu, resume_lab);
buzbeefc9e6fa2012-03-23 15:14:29 -0700561 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700562 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700563}
564
buzbee02031b12012-11-23 09:41:35 -0800565void Codegen::HandleThrowLaunchPads(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800566{
buzbeefa57c472012-11-21 12:06:18 -0800567 LIR** throw_label = reinterpret_cast<LIR**>(cu->throw_launchpads.elem_list);
568 int num_elems = cu->throw_launchpads.num_used;
569 for (int i = 0; i < num_elems; i++) {
570 ResetRegPool(cu);
571 ResetDefTracking(cu);
572 LIR* lab = throw_label[i];
573 cu->current_dalvik_offset = lab->operands[1];
574 AppendLIR(cu, lab);
575 int func_offset = 0;
Bill Buzbeea114add2012-05-03 15:00:40 -0700576 int v1 = lab->operands[2];
577 int v2 = lab->operands[3];
buzbeefa57c472012-11-21 12:06:18 -0800578 bool target_x86 = (cu->instruction_set == kX86);
Bill Buzbeea114add2012-05-03 15:00:40 -0700579 switch (lab->operands[0]) {
580 case kThrowNullPointer:
buzbeefa57c472012-11-21 12:06:18 -0800581 func_offset = ENTRYPOINT_OFFSET(pThrowNullPointerFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700582 break;
583 case kThrowArrayBounds:
buzbeef0504cd2012-11-13 16:31:10 -0800584 // Move v1 (array index) to kArg0 and v2 (array length) to kArg1
buzbee52a77fc2012-11-20 19:50:46 -0800585 if (v2 != TargetReg(kArg0)) {
buzbeefa57c472012-11-21 12:06:18 -0800586 OpRegCopy(cu, TargetReg(kArg0), v1);
587 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700588 // x86 leaves the array pointer in v2, so load the array length that the handler expects
buzbeefa57c472012-11-21 12:06:18 -0800589 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700590 } else {
buzbeefa57c472012-11-21 12:06:18 -0800591 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700592 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700593 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800594 if (v1 == TargetReg(kArg1)) {
buzbeef0504cd2012-11-13 16:31:10 -0800595 // Swap v1 and v2, using kArg2 as a temp
buzbeefa57c472012-11-21 12:06:18 -0800596 OpRegCopy(cu, TargetReg(kArg2), v1);
597 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700598 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbeefa57c472012-11-21 12:06:18 -0800599 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700600 } else {
buzbeefa57c472012-11-21 12:06:18 -0800601 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700602 }
buzbeefa57c472012-11-21 12:06:18 -0800603 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700604 } else {
buzbeefa57c472012-11-21 12:06:18 -0800605 if (target_x86) {
buzbeeb046e162012-10-30 15:48:42 -0700606 // x86 leaves the array pointer in v2; load the array length that the handler expects
buzbeefa57c472012-11-21 12:06:18 -0800607 OpRegMem(cu, kOpMov, TargetReg(kArg1), v2, Array::LengthOffset().Int32Value());
buzbeeb046e162012-10-30 15:48:42 -0700608 } else {
buzbeefa57c472012-11-21 12:06:18 -0800609 OpRegCopy(cu, TargetReg(kArg1), v2);
buzbeeb046e162012-10-30 15:48:42 -0700610 }
buzbeefa57c472012-11-21 12:06:18 -0800611 OpRegCopy(cu, TargetReg(kArg0), v1);
Bill Buzbeea114add2012-05-03 15:00:40 -0700612 }
buzbee31a4a6f2012-02-28 15:36:15 -0800613 }
buzbeefa57c472012-11-21 12:06:18 -0800614 func_offset = ENTRYPOINT_OFFSET(pThrowArrayBoundsFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700615 break;
616 case kThrowDivZero:
buzbeefa57c472012-11-21 12:06:18 -0800617 func_offset = ENTRYPOINT_OFFSET(pThrowDivZeroFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700618 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700619 case kThrowNoSuchMethod:
buzbeefa57c472012-11-21 12:06:18 -0800620 OpRegCopy(cu, TargetReg(kArg0), v1);
621 func_offset =
Bill Buzbeea114add2012-05-03 15:00:40 -0700622 ENTRYPOINT_OFFSET(pThrowNoSuchMethodFromCode);
623 break;
624 case kThrowStackOverflow:
buzbeefa57c472012-11-21 12:06:18 -0800625 func_offset = ENTRYPOINT_OFFSET(pThrowStackOverflowFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700626 // Restore stack alignment
buzbeefa57c472012-11-21 12:06:18 -0800627 if (target_x86) {
628 OpRegImm(cu, kOpAdd, TargetReg(kSp), cu->frame_size);
buzbeeb046e162012-10-30 15:48:42 -0700629 } else {
buzbeefa57c472012-11-21 12:06:18 -0800630 OpRegImm(cu, kOpAdd, TargetReg(kSp), (cu->num_core_spills + cu->num_fp_spills) * 4);
buzbeeb046e162012-10-30 15:48:42 -0700631 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700632 break;
633 default:
634 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
buzbee31a4a6f2012-02-28 15:36:15 -0800635 }
buzbeefa57c472012-11-21 12:06:18 -0800636 ClobberCalleeSave(cu);
637 int r_tgt = CallHelperSetup(cu, func_offset);
638 CallHelper(cu, r_tgt, func_offset, true /* MarkSafepointPC */);
Bill Buzbeea114add2012-05-03 15:00:40 -0700639 }
buzbee31a4a6f2012-02-28 15:36:15 -0800640}
641
buzbee02031b12012-11-23 09:41:35 -0800642void Codegen::GenIGet(CompilationUnit* cu, uint32_t field_idx, int opt_flags, OpSize size,
643 RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double,
644 bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800645{
buzbeefa57c472012-11-21 12:06:18 -0800646 int field_offset;
647 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800648
buzbeefa57c472012-11-21 12:06:18 -0800649 bool fast_path = FastInstance(cu, field_idx, field_offset, is_volatile, false);
buzbee31a4a6f2012-02-28 15:36:15 -0800650
buzbeefa57c472012-11-21 12:06:18 -0800651 if (fast_path && !SLOW_FIELD_PATH) {
652 RegLocation rl_result;
653 RegisterClass reg_class = oat_reg_class_by_size(size);
654 DCHECK_GE(field_offset, 0);
655 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
656 if (is_long_or_double) {
657 DCHECK(rl_dest.wide);
658 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
659 if (cu->instruction_set == kX86) {
660 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
661 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
662 LoadBaseDispWide(cu, rl_obj.low_reg, field_offset, rl_result.low_reg,
663 rl_result.high_reg, rl_obj.s_reg_low);
664 if (is_volatile) {
665 GenMemBarrier(cu, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700666 }
667 } else {
buzbeefa57c472012-11-21 12:06:18 -0800668 int reg_ptr = AllocTemp(cu);
669 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
670 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
671 LoadPair(cu, reg_ptr, rl_result.low_reg, rl_result.high_reg);
672 if (is_volatile) {
673 GenMemBarrier(cu, kLoadLoad);
buzbeeb046e162012-10-30 15:48:42 -0700674 }
buzbeefa57c472012-11-21 12:06:18 -0800675 FreeTemp(cu, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700676 }
buzbeefa57c472012-11-21 12:06:18 -0800677 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800678 } else {
buzbeefa57c472012-11-21 12:06:18 -0800679 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
680 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
681 LoadBaseDisp(cu, rl_obj.low_reg, field_offset, rl_result.low_reg,
682 kWord, rl_obj.s_reg_low);
683 if (is_volatile) {
684 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700685 }
buzbeefa57c472012-11-21 12:06:18 -0800686 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800687 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700688 } else {
buzbeefa57c472012-11-21 12:06:18 -0800689 int getterOffset = is_long_or_double ? ENTRYPOINT_OFFSET(pGet64Instance) :
690 (is_object ? ENTRYPOINT_OFFSET(pGetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700691 : ENTRYPOINT_OFFSET(pGet32Instance));
buzbeefa57c472012-11-21 12:06:18 -0800692 CallRuntimeHelperImmRegLocation(cu, getterOffset, field_idx, rl_obj, true);
693 if (is_long_or_double) {
694 RegLocation rl_result = GetReturnWide(cu, rl_dest.fp);
695 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700696 } else {
buzbeefa57c472012-11-21 12:06:18 -0800697 RegLocation rl_result = GetReturn(cu, rl_dest.fp);
698 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700699 }
700 }
buzbee31a4a6f2012-02-28 15:36:15 -0800701}
702
buzbee02031b12012-11-23 09:41:35 -0800703void Codegen::GenIPut(CompilationUnit* cu, uint32_t field_idx, int opt_flags, OpSize size,
704 RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double,
705 bool is_object)
buzbee31a4a6f2012-02-28 15:36:15 -0800706{
buzbeefa57c472012-11-21 12:06:18 -0800707 int field_offset;
708 bool is_volatile;
buzbee31a4a6f2012-02-28 15:36:15 -0800709
buzbeefa57c472012-11-21 12:06:18 -0800710 bool fast_path = FastInstance(cu, field_idx, field_offset, is_volatile,
Bill Buzbeea114add2012-05-03 15:00:40 -0700711 true);
buzbeefa57c472012-11-21 12:06:18 -0800712 if (fast_path && !SLOW_FIELD_PATH) {
713 RegisterClass reg_class = oat_reg_class_by_size(size);
714 DCHECK_GE(field_offset, 0);
715 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
716 if (is_long_or_double) {
717 int reg_ptr;
718 rl_src = LoadValueWide(cu, rl_src, kAnyReg);
719 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
720 reg_ptr = AllocTemp(cu);
721 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_obj.low_reg, field_offset);
722 if (is_volatile) {
723 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700724 }
buzbeefa57c472012-11-21 12:06:18 -0800725 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
726 if (is_volatile) {
727 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700728 }
buzbeefa57c472012-11-21 12:06:18 -0800729 FreeTemp(cu, reg_ptr);
buzbee31a4a6f2012-02-28 15:36:15 -0800730 } else {
buzbeefa57c472012-11-21 12:06:18 -0800731 rl_src = LoadValue(cu, rl_src, reg_class);
732 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, opt_flags);
733 if (is_volatile) {
734 GenMemBarrier(cu, kStoreStore);
Bill Buzbeea114add2012-05-03 15:00:40 -0700735 }
buzbeefa57c472012-11-21 12:06:18 -0800736 StoreBaseDisp(cu, rl_obj.low_reg, field_offset, rl_src.low_reg, kWord);
737 if (is_volatile) {
738 GenMemBarrier(cu, kLoadLoad);
Bill Buzbeea114add2012-05-03 15:00:40 -0700739 }
buzbeefa57c472012-11-21 12:06:18 -0800740 if (is_object) {
741 MarkGCCard(cu, rl_src.low_reg, rl_obj.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700742 }
buzbee31a4a6f2012-02-28 15:36:15 -0800743 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700744 } else {
buzbeefa57c472012-11-21 12:06:18 -0800745 int setter_offset = is_long_or_double ? ENTRYPOINT_OFFSET(pSet64Instance) :
746 (is_object ? ENTRYPOINT_OFFSET(pSetObjInstance)
Bill Buzbeea114add2012-05-03 15:00:40 -0700747 : ENTRYPOINT_OFFSET(pSet32Instance));
buzbeefa57c472012-11-21 12:06:18 -0800748 CallRuntimeHelperImmRegLocationRegLocation(cu, setter_offset, field_idx, rl_obj, rl_src, true);
Bill Buzbeea114add2012-05-03 15:00:40 -0700749 }
buzbee31a4a6f2012-02-28 15:36:15 -0800750}
751
buzbee02031b12012-11-23 09:41:35 -0800752void Codegen::GenConstClass(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800753{
buzbeefa57c472012-11-21 12:06:18 -0800754 RegLocation rl_method = LoadCurrMethod(cu);
755 int res_reg = AllocTemp(cu);
756 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
757 if (!cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
758 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700759 type_idx)) {
760 // Call out to helper which resolves type and verifies access.
buzbeef0504cd2012-11-13 16:31:10 -0800761 // Resolved type returned in kRet0.
buzbeefa57c472012-11-21 12:06:18 -0800762 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
763 type_idx, rl_method.low_reg, true);
764 RegLocation rl_result = GetReturn(cu, false);
765 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700766 } else {
767 // We're don't need access checks, load type from dex cache
768 int32_t dex_cache_offset =
Mathieu Chartier66f19252012-09-18 08:57:04 -0700769 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value();
buzbeefa57c472012-11-21 12:06:18 -0800770 LoadWordDisp(cu, rl_method.low_reg, dex_cache_offset, res_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700771 int32_t offset_of_type =
772 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
773 * type_idx);
buzbeefa57c472012-11-21 12:06:18 -0800774 LoadWordDisp(cu, res_reg, offset_of_type, rl_result.low_reg);
775 if (!cu->compiler->CanAssumeTypeIsPresentInDexCache(*cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700776 type_idx) || SLOW_TYPE_PATH) {
777 // Slow path, at runtime test if type is null and if so initialize
buzbeefa57c472012-11-21 12:06:18 -0800778 FlushAllRegs(cu);
779 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, rl_result.low_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700780 // Resolved, store and hop over following code
buzbeefa57c472012-11-21 12:06:18 -0800781 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700782 /*
783 * Because we have stores of the target value on two paths,
784 * clobber temp tracking for the destination using the ssa name
785 */
buzbeefa57c472012-11-21 12:06:18 -0800786 ClobberSReg(cu, rl_dest.s_reg_low);
787 LIR* branch2 = OpUnconditionalBranch(cu,0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700788 // TUNING: move slow path to end & remove unconditional branch
buzbeefa57c472012-11-21 12:06:18 -0800789 LIR* target1 = NewLIR0(cu, kPseudoTargetLabel);
buzbeef0504cd2012-11-13 16:31:10 -0800790 // Call out to helper, which will return resolved type in kArg0
buzbeefa57c472012-11-21 12:06:18 -0800791 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx,
792 rl_method.low_reg, true);
793 RegLocation rl_result = GetReturn(cu, false);
794 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700795 /*
796 * Because we have stores of the target value on two paths,
797 * clobber temp tracking for the destination using the ssa name
798 */
buzbeefa57c472012-11-21 12:06:18 -0800799 ClobberSReg(cu, rl_dest.s_reg_low);
Bill Buzbeea114add2012-05-03 15:00:40 -0700800 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -0800801 LIR* target2 = NewLIR0(cu, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800802 branch1->target = target1;
803 branch2->target = target2;
buzbee31a4a6f2012-02-28 15:36:15 -0800804 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700805 // Fast path, we're done - just store result
buzbeefa57c472012-11-21 12:06:18 -0800806 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800807 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700808 }
buzbee31a4a6f2012-02-28 15:36:15 -0800809}
Ian Rogersab2b55d2012-03-18 00:06:11 -0700810
buzbee02031b12012-11-23 09:41:35 -0800811void Codegen::GenConstString(CompilationUnit* cu, uint32_t string_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800812{
Bill Buzbeea114add2012-05-03 15:00:40 -0700813 /* NOTE: Most strings should be available at compile time */
Bill Buzbeea114add2012-05-03 15:00:40 -0700814 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
815 (sizeof(String*) * string_idx);
buzbeefa57c472012-11-21 12:06:18 -0800816 if (!cu->compiler->CanAssumeStringIsPresentInDexCache(
817 *cu->dex_file, string_idx) || SLOW_STRING_PATH) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700818 // slow path, resolve string if not in dex cache
buzbeefa57c472012-11-21 12:06:18 -0800819 FlushAllRegs(cu);
820 LockCallTemps(cu); // Using explicit registers
821 LoadCurrMethodDirect(cu, TargetReg(kArg2));
822 LoadWordDisp(cu, TargetReg(kArg2),
buzbee52a77fc2012-11-20 19:50:46 -0800823 AbstractMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800824 // Might call out to helper, which will return resolved string in kRet0
buzbeefa57c472012-11-21 12:06:18 -0800825 int r_tgt = CallHelperSetup(cu, ENTRYPOINT_OFFSET(pResolveStringFromCode));
826 LoadWordDisp(cu, TargetReg(kArg0), offset_of_string, TargetReg(kRet0));
827 LoadConstant(cu, TargetReg(kArg1), string_idx);
828 if (cu->instruction_set == kThumb2) {
829 OpRegImm(cu, kOpCmp, TargetReg(kRet0), 0); // Is resolved?
830 GenBarrier(cu);
buzbeeb046e162012-10-30 15:48:42 -0700831 // For testing, always force through helper
832 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee02031b12012-11-23 09:41:35 -0800833 OpIT(cu, kCondEq, "T");
buzbeeb046e162012-10-30 15:48:42 -0700834 }
buzbeefa57c472012-11-21 12:06:18 -0800835 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .eq
836 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt); // .eq, helper(Method*, string_idx)
837 MarkSafepointPC(cu, call_inst);
838 FreeTemp(cu, r_tgt);
839 } else if (cu->instruction_set == kMips) {
840 LIR* branch = OpCmpImmBranch(cu, kCondNe, TargetReg(kRet0), 0, NULL);
841 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .eq
842 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt);
843 MarkSafepointPC(cu, call_inst);
844 FreeTemp(cu, r_tgt);
845 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
buzbeeb046e162012-10-30 15:48:42 -0700846 branch->target = target;
847 } else {
buzbeefa57c472012-11-21 12:06:18 -0800848 DCHECK_EQ(cu->instruction_set, kX86);
849 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pResolveStringFromCode), TargetReg(kArg2), TargetReg(kArg1), true);
buzbee31a4a6f2012-02-28 15:36:15 -0800850 }
buzbeefa57c472012-11-21 12:06:18 -0800851 GenBarrier(cu);
852 StoreValue(cu, rl_dest, GetReturn(cu, false));
Bill Buzbeea114add2012-05-03 15:00:40 -0700853 } else {
buzbeefa57c472012-11-21 12:06:18 -0800854 RegLocation rl_method = LoadCurrMethod(cu);
855 int res_reg = AllocTemp(cu);
856 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
857 LoadWordDisp(cu, rl_method.low_reg,
858 AbstractMethod::DexCacheStringsOffset().Int32Value(), res_reg);
859 LoadWordDisp(cu, res_reg, offset_of_string, rl_result.low_reg);
860 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700861 }
buzbee31a4a6f2012-02-28 15:36:15 -0800862}
863
864/*
865 * Let helper function take care of everything. Will
866 * call Class::NewInstanceFromCode(type_idx, method);
867 */
buzbee02031b12012-11-23 09:41:35 -0800868void Codegen::GenNewInstance(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest)
buzbee31a4a6f2012-02-28 15:36:15 -0800869{
buzbeefa57c472012-11-21 12:06:18 -0800870 FlushAllRegs(cu); /* Everything to home location */
Bill Buzbeea114add2012-05-03 15:00:40 -0700871 // alloc will always check for resolution, do we also need to verify
872 // access because the verifier was unable to?
buzbeefa57c472012-11-21 12:06:18 -0800873 int func_offset;
874 if (cu->compiler->CanAccessInstantiableTypeWithoutChecks(
875 cu->method_idx, *cu->dex_file, type_idx)) {
876 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCode);
Bill Buzbeea114add2012-05-03 15:00:40 -0700877 } else {
buzbeefa57c472012-11-21 12:06:18 -0800878 func_offset = ENTRYPOINT_OFFSET(pAllocObjectFromCodeWithAccessCheck);
Bill Buzbeea114add2012-05-03 15:00:40 -0700879 }
buzbeefa57c472012-11-21 12:06:18 -0800880 CallRuntimeHelperImmMethod(cu, func_offset, type_idx, true);
881 RegLocation rl_result = GetReturn(cu, false);
882 StoreValue(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -0800883}
884
buzbee02031b12012-11-23 09:41:35 -0800885void Codegen::GenMoveException(CompilationUnit* cu, RegLocation rl_dest)
Ian Rogers474b6da2012-09-25 00:20:38 -0700886{
buzbeefa57c472012-11-21 12:06:18 -0800887 FlushAllRegs(cu); /* Everything to home location */
888 int func_offset = ENTRYPOINT_OFFSET(pGetAndClearException);
889 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700890 // Runtime helper will load argument for x86.
buzbeefa57c472012-11-21 12:06:18 -0800891 CallRuntimeHelperReg(cu, func_offset, TargetReg(kArg0), false);
buzbeeb046e162012-10-30 15:48:42 -0700892 } else {
buzbeefa57c472012-11-21 12:06:18 -0800893 CallRuntimeHelperReg(cu, func_offset, TargetReg(kSelf), false);
buzbeeb046e162012-10-30 15:48:42 -0700894 }
buzbeefa57c472012-11-21 12:06:18 -0800895 RegLocation rl_result = GetReturn(cu, false);
896 StoreValue(cu, rl_dest, rl_result);
Ian Rogers474b6da2012-09-25 00:20:38 -0700897}
898
buzbee02031b12012-11-23 09:41:35 -0800899void Codegen::GenThrow(CompilationUnit* cu, RegLocation rl_src)
Ian Rogersab2b55d2012-03-18 00:06:11 -0700900{
buzbeefa57c472012-11-21 12:06:18 -0800901 FlushAllRegs(cu);
902 CallRuntimeHelperRegLocation(cu, ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700903}
904
buzbee02031b12012-11-23 09:41:35 -0800905void Codegen::GenInstanceof(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_dest,
906 RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800907{
buzbeefa57c472012-11-21 12:06:18 -0800908 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700909 // May generate a call - use explicit registers
buzbeefa57c472012-11-21 12:06:18 -0800910 LockCallTemps(cu);
911 LoadCurrMethodDirect(cu, TargetReg(kArg1)); // kArg1 <= current Method*
912 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
913 if (!cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
914 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -0700915 type_idx)) {
916 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -0800917 // returns Class* in kArg0
buzbeefa57c472012-11-21 12:06:18 -0800918 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee8320f382012-09-11 16:29:42 -0700919 type_idx, true);
buzbeefa57c472012-11-21 12:06:18 -0800920 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
921 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -0700922 } else {
buzbeefa57c472012-11-21 12:06:18 -0800923 // Load dex cache entry into class_reg (kArg2)
924 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
925 LoadWordDisp(cu, TargetReg(kArg1),
926 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700927 int32_t offset_of_type =
928 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
929 * type_idx);
buzbeefa57c472012-11-21 12:06:18 -0800930 LoadWordDisp(cu, class_reg, offset_of_type, class_reg);
931 if (!cu->compiler->CanAssumeTypeIsPresentInDexCache(
932 *cu->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700933 // Need to test presence of type in dex cache at runtime
buzbeefa57c472012-11-21 12:06:18 -0800934 LIR* hop_branch = OpCmpImmBranch(cu, kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700935 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -0800936 // Call out to helper, which will return resolved type in kRet0
buzbeefa57c472012-11-21 12:06:18 -0800937 CallRuntimeHelperImm(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, true);
938 OpRegCopy(cu, TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path
939 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); /* reload Ref */
Bill Buzbeea114add2012-05-03 15:00:40 -0700940 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -0800941 LIR* hop_target = NewLIR0(cu, kPseudoTargetLabel);
942 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -0800943 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700944 }
buzbeef0504cd2012-11-13 16:31:10 -0800945 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
buzbeefa57c472012-11-21 12:06:18 -0800946 RegLocation rl_result = GetReturn(cu, false);
947 if (cu->instruction_set == kMips) {
948 LoadConstant(cu, rl_result.low_reg, 0); // store false result for if branch is taken
buzbeeb046e162012-10-30 15:48:42 -0700949 }
buzbeefa57c472012-11-21 12:06:18 -0800950 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 /* load object->klass_ */
952 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbeefa57c472012-11-21 12:06:18 -0800953 LoadWordDisp(cu, TargetReg(kArg0), Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -0800954 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
buzbeefa57c472012-11-21 12:06:18 -0800955 LIR* call_inst;
buzbeeb046e162012-10-30 15:48:42 -0700956 LIR* branchover = NULL;
buzbeefa57c472012-11-21 12:06:18 -0800957 if (cu->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700958 /* Uses conditional nullification */
buzbeefa57c472012-11-21 12:06:18 -0800959 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
960 OpRegReg(cu, kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same?
buzbee02031b12012-11-23 09:41:35 -0800961 OpIT(cu, kCondEq, "EE"); // if-convert the test
buzbeefa57c472012-11-21 12:06:18 -0800962 LoadConstant(cu, TargetReg(kArg0), 1); // .eq case - load true
963 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
964 call_inst = OpReg(cu, kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
965 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -0700966 } else {
967 /* Uses branchovers */
buzbeefa57c472012-11-21 12:06:18 -0800968 LoadConstant(cu, rl_result.low_reg, 1); // assume true
969 branchover = OpCmpBranch(cu, kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
970 if (cu->instruction_set != kX86) {
971 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
972 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class
973 call_inst = OpReg(cu, kOpBlx, r_tgt); // .ne case: helper(class, ref->class)
974 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -0700975 } else {
buzbeefa57c472012-11-21 12:06:18 -0800976 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg2));
977 call_inst = OpThreadMem(cu, kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
buzbeeb046e162012-10-30 15:48:42 -0700978 }
979 }
buzbeefa57c472012-11-21 12:06:18 -0800980 MarkSafepointPC(cu, call_inst);
981 ClobberCalleeSave(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700982 /* branch targets here */
buzbeefa57c472012-11-21 12:06:18 -0800983 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
984 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700985 branch1->target = target;
buzbeefa57c472012-11-21 12:06:18 -0800986 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700987 branchover->target = target;
988 }
buzbee31a4a6f2012-02-28 15:36:15 -0800989}
990
buzbee02031b12012-11-23 09:41:35 -0800991void Codegen::GenCheckCast(CompilationUnit* cu, uint32_t type_idx, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -0800992{
buzbeefa57c472012-11-21 12:06:18 -0800993 FlushAllRegs(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700994 // May generate a call - use explicit registers
buzbeefa57c472012-11-21 12:06:18 -0800995 LockCallTemps(cu);
996 LoadCurrMethodDirect(cu, TargetReg(kArg1)); // kArg1 <= current Method*
997 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*
998 if (!cu->compiler->CanAccessTypeWithoutChecks(cu->method_idx,
999 *cu->dex_file,
Bill Buzbeea114add2012-05-03 15:00:40 -07001000 type_idx)) {
1001 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbeef0504cd2012-11-13 16:31:10 -08001002 // returns Class* in kRet0
Bill Buzbeea114add2012-05-03 15:00:40 -07001003 // InitializeTypeAndVerifyAccess(idx, method)
buzbeefa57c472012-11-21 12:06:18 -08001004 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
buzbee52a77fc2012-11-20 19:50:46 -08001005 type_idx, TargetReg(kArg1), true);
buzbeefa57c472012-11-21 12:06:18 -08001006 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001007 } else {
buzbeefa57c472012-11-21 12:06:18 -08001008 // Load dex cache entry into class_reg (kArg2)
1009 LoadWordDisp(cu, TargetReg(kArg1),
1010 AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001011 int32_t offset_of_type =
1012 Array::DataOffset(sizeof(Class*)).Int32Value() +
1013 (sizeof(Class*) * type_idx);
buzbeefa57c472012-11-21 12:06:18 -08001014 LoadWordDisp(cu, class_reg, offset_of_type, class_reg);
1015 if (!cu->compiler->CanAssumeTypeIsPresentInDexCache(
1016 *cu->dex_file, type_idx)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001017 // Need to test presence of type in dex cache at runtime
buzbeefa57c472012-11-21 12:06:18 -08001018 LIR* hop_branch = OpCmpImmBranch(cu, kCondNe, class_reg, 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001019 // Not resolved
buzbeef0504cd2012-11-13 16:31:10 -08001020 // Call out to helper, which will return resolved type in kArg0
Bill Buzbeea114add2012-05-03 15:00:40 -07001021 // InitializeTypeFromCode(idx, method)
buzbeefa57c472012-11-21 12:06:18 -08001022 CallRuntimeHelperImmReg(cu, ENTRYPOINT_OFFSET(pInitializeTypeFromCode), type_idx, TargetReg(kArg1),
buzbee8320f382012-09-11 16:29:42 -07001023 true);
buzbeefa57c472012-11-21 12:06:18 -08001024 OpRegCopy(cu, class_reg, TargetReg(kRet0)); // Align usage with fast path
Bill Buzbeea114add2012-05-03 15:00:40 -07001025 // Rejoin code paths
buzbeefa57c472012-11-21 12:06:18 -08001026 LIR* hop_target = NewLIR0(cu, kPseudoTargetLabel);
1027 hop_branch->target = hop_target;
buzbee31a4a6f2012-02-28 15:36:15 -08001028 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001029 }
buzbeefa57c472012-11-21 12:06:18 -08001030 // At this point, class_reg (kArg2) has class
1031 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0)); // kArg0 <= ref
Bill Buzbeea114add2012-05-03 15:00:40 -07001032 /* Null is OK - continue */
buzbeefa57c472012-11-21 12:06:18 -08001033 LIR* branch1 = OpCmpImmBranch(cu, kCondEq, TargetReg(kArg0), 0, NULL);
Bill Buzbeea114add2012-05-03 15:00:40 -07001034 /* load object->klass_ */
1035 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbeefa57c472012-11-21 12:06:18 -08001036 LoadWordDisp(cu, TargetReg(kArg0), Object::ClassOffset().Int32Value(), TargetReg(kArg1));
buzbeef0504cd2012-11-13 16:31:10 -08001037 /* kArg1 now contains object->klass_ */
buzbeeb046e162012-10-30 15:48:42 -07001038 LIR* branch2;
buzbeefa57c472012-11-21 12:06:18 -08001039 if (cu->instruction_set == kThumb2) {
1040 int r_tgt = LoadHelper(cu, ENTRYPOINT_OFFSET(pCheckCastFromCode));
1041 OpRegReg(cu, kOpCmp, TargetReg(kArg1), class_reg);
1042 branch2 = OpCondBranch(cu, kCondEq, NULL); /* If eq, trivial yes */
1043 OpRegCopy(cu, TargetReg(kArg0), TargetReg(kArg1));
1044 OpRegCopy(cu, TargetReg(kArg1), TargetReg(kArg2));
1045 ClobberCalleeSave(cu);
1046 LIR* call_inst = OpReg(cu, kOpBlx, r_tgt);
1047 MarkSafepointPC(cu, call_inst);
1048 FreeTemp(cu, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001049 } else {
buzbeefa57c472012-11-21 12:06:18 -08001050 branch2 = OpCmpBranch(cu, kCondEq, TargetReg(kArg1), class_reg, NULL);
1051 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), true);
buzbeeb046e162012-10-30 15:48:42 -07001052 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001053 /* branch target here */
buzbeefa57c472012-11-21 12:06:18 -08001054 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001055 branch1->target = target;
1056 branch2->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001057}
1058
buzbee31a4a6f2012-02-28 15:36:15 -08001059/*
1060 * Generate array store
1061 *
1062 */
buzbee02031b12012-11-23 09:41:35 -08001063void Codegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
1064 RegLocation rl_index, RegLocation rl_src, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001065{
buzbeefa57c472012-11-21 12:06:18 -08001066 int len_offset = Array::LengthOffset().Int32Value();
1067 int data_offset = Array::DataOffset(sizeof(Object*)).Int32Value();
buzbee31a4a6f2012-02-28 15:36:15 -08001068
buzbeefa57c472012-11-21 12:06:18 -08001069 FlushAllRegs(cu); // Use explicit registers
1070 LockCallTemps(cu);
buzbee31a4a6f2012-02-28 15:36:15 -08001071
buzbeefa57c472012-11-21 12:06:18 -08001072 int r_value = TargetReg(kArg0); // Register holding value
1073 int r_array_class = TargetReg(kArg1); // Register holding array's Class
1074 int r_array = TargetReg(kArg2); // Register holding array
1075 int r_index = TargetReg(kArg3); // Register holding index into array
Ian Rogersd36c52e2012-04-09 16:29:25 -07001076
buzbeefa57c472012-11-21 12:06:18 -08001077 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
1078 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
1079 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
Ian Rogersd36c52e2012-04-09 16:29:25 -07001080
buzbeefa57c472012-11-21 12:06:18 -08001081 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
Ian Rogersd36c52e2012-04-09 16:29:25 -07001082
Bill Buzbeea114add2012-05-03 15:00:40 -07001083 // Store of null?
buzbeefa57c472012-11-21 12:06:18 -08001084 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
Ian Rogersd36c52e2012-04-09 16:29:25 -07001085
Bill Buzbeea114add2012-05-03 15:00:40 -07001086 // Get the array's class.
buzbeefa57c472012-11-21 12:06:18 -08001087 LoadWordDisp(cu, r_array, Object::ClassOffset().Int32Value(), r_array_class);
1088 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
1089 r_array_class, true);
buzbee52a77fc2012-11-20 19:50:46 -08001090 // Redo LoadValues in case they didn't survive the call.
buzbeefa57c472012-11-21 12:06:18 -08001091 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
1092 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
1093 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
1094 r_array_class = INVALID_REG;
buzbee31a4a6f2012-02-28 15:36:15 -08001095
Bill Buzbeea114add2012-05-03 15:00:40 -07001096 // Branch here if value to be stored == null
buzbeefa57c472012-11-21 12:06:18 -08001097 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
Bill Buzbeea114add2012-05-03 15:00:40 -07001098 null_value_check->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -08001099
buzbeefa57c472012-11-21 12:06:18 -08001100 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001101 // make an extra temp available for card mark below
buzbeefa57c472012-11-21 12:06:18 -08001102 FreeTemp(cu, TargetReg(kArg1));
1103 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
1104 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
1105 GenRegMemCheck(cu, kCondUge, r_index, r_array, len_offset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001106 }
buzbeefa57c472012-11-21 12:06:18 -08001107 StoreBaseIndexedDisp(cu, r_array, r_index, scale,
1108 data_offset, r_value, INVALID_REG, kWord, INVALID_SREG);
buzbeeb046e162012-10-30 15:48:42 -07001109 } else {
buzbeefa57c472012-11-21 12:06:18 -08001110 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1111 int reg_len = INVALID_REG;
1112 if (needs_range_check) {
1113 reg_len = TargetReg(kArg1);
1114 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
buzbeeb046e162012-10-30 15:48:42 -07001115 }
buzbeefa57c472012-11-21 12:06:18 -08001116 /* r_ptr -> array data */
1117 int r_ptr = AllocTemp(cu);
1118 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
1119 if (needs_range_check) {
1120 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001121 }
buzbeefa57c472012-11-21 12:06:18 -08001122 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
1123 FreeTemp(cu, r_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -07001124 }
buzbeefa57c472012-11-21 12:06:18 -08001125 FreeTemp(cu, r_index);
1126 MarkGCCard(cu, r_value, r_array);
buzbee31a4a6f2012-02-28 15:36:15 -08001127}
1128
1129/*
1130 * Generate array load
1131 */
buzbee02031b12012-11-23 09:41:35 -08001132void Codegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
1133 RegLocation rl_index, RegLocation rl_dest, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001134{
buzbeefa57c472012-11-21 12:06:18 -08001135 RegisterClass reg_class = oat_reg_class_by_size(size);
1136 int len_offset = Array::LengthOffset().Int32Value();
1137 int data_offset;
1138 RegLocation rl_result;
1139 rl_array = LoadValue(cu, rl_array, kCoreReg);
1140 rl_index = LoadValue(cu, rl_index, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001141
Bill Buzbeea114add2012-05-03 15:00:40 -07001142 if (size == kLong || size == kDouble) {
buzbeefa57c472012-11-21 12:06:18 -08001143 data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001144 } else {
buzbeefa57c472012-11-21 12:06:18 -08001145 data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001146 }
buzbee31a4a6f2012-02-28 15:36:15 -08001147
Bill Buzbeea114add2012-05-03 15:00:40 -07001148 /* null object? */
buzbeefa57c472012-11-21 12:06:18 -08001149 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
buzbee31a4a6f2012-02-28 15:36:15 -08001150
buzbeefa57c472012-11-21 12:06:18 -08001151 if (cu->instruction_set == kX86) {
1152 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
1153 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
1154 GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg,
1155 len_offset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001156 }
1157 if ((size == kLong) || (size == kDouble)) {
buzbeefa57c472012-11-21 12:06:18 -08001158 int reg_addr = AllocTemp(cu);
1159 OpLea(cu, reg_addr, rl_array.low_reg, rl_index.low_reg, scale, data_offset);
1160 FreeTemp(cu, rl_array.low_reg);
1161 FreeTemp(cu, rl_index.low_reg);
1162 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
1163 LoadBaseIndexedDisp(cu, reg_addr, INVALID_REG, 0, 0, rl_result.low_reg,
1164 rl_result.high_reg, size, INVALID_SREG);
1165 StoreValueWide(cu, rl_dest, rl_result);
buzbee31a4a6f2012-02-28 15:36:15 -08001166 } else {
buzbeefa57c472012-11-21 12:06:18 -08001167 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001168
buzbeefa57c472012-11-21 12:06:18 -08001169 LoadBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale,
1170 data_offset, rl_result.low_reg, INVALID_REG, size,
buzbeeb046e162012-10-30 15:48:42 -07001171 INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001172
buzbeefa57c472012-11-21 12:06:18 -08001173 StoreValue(cu, rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001174 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001175 } else {
buzbeefa57c472012-11-21 12:06:18 -08001176 int reg_ptr = AllocTemp(cu);
1177 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1178 int reg_len = INVALID_REG;
1179 if (needs_range_check) {
1180 reg_len = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -07001181 /* Get len */
buzbeefa57c472012-11-21 12:06:18 -08001182 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
Bill Buzbeea114add2012-05-03 15:00:40 -07001183 }
buzbeefa57c472012-11-21 12:06:18 -08001184 /* reg_ptr -> array data */
1185 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
1186 FreeTemp(cu, rl_array.low_reg);
buzbeeb046e162012-10-30 15:48:42 -07001187 if ((size == kLong) || (size == kDouble)) {
1188 if (scale) {
buzbeefa57c472012-11-21 12:06:18 -08001189 int r_new_index = AllocTemp(cu);
1190 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
1191 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
1192 FreeTemp(cu, r_new_index);
buzbeeb046e162012-10-30 15:48:42 -07001193 } else {
buzbeefa57c472012-11-21 12:06:18 -08001194 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
buzbeeb046e162012-10-30 15:48:42 -07001195 }
buzbeefa57c472012-11-21 12:06:18 -08001196 FreeTemp(cu, rl_index.low_reg);
1197 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001198
buzbeefa57c472012-11-21 12:06:18 -08001199 if (needs_range_check) {
buzbeeb046e162012-10-30 15:48:42 -07001200 // TODO: change kCondCS to a more meaningful name, is the sense of
1201 // carry-set/clear flipped?
buzbeefa57c472012-11-21 12:06:18 -08001202 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1203 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001204 }
buzbeefa57c472012-11-21 12:06:18 -08001205 LoadPair(cu, reg_ptr, rl_result.low_reg, rl_result.high_reg);
buzbeeb046e162012-10-30 15:48:42 -07001206
buzbeefa57c472012-11-21 12:06:18 -08001207 FreeTemp(cu, reg_ptr);
1208 StoreValueWide(cu, rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001209 } else {
buzbeefa57c472012-11-21 12:06:18 -08001210 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
buzbeeb046e162012-10-30 15:48:42 -07001211
buzbeefa57c472012-11-21 12:06:18 -08001212 if (needs_range_check) {
buzbeeb046e162012-10-30 15:48:42 -07001213 // TODO: change kCondCS to a more meaningful name, is the sense of
1214 // carry-set/clear flipped?
buzbeefa57c472012-11-21 12:06:18 -08001215 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1216 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001217 }
buzbeefa57c472012-11-21 12:06:18 -08001218 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
buzbeeb046e162012-10-30 15:48:42 -07001219
buzbeefa57c472012-11-21 12:06:18 -08001220 FreeTemp(cu, reg_ptr);
1221 StoreValue(cu, rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001222 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001223 }
buzbee31a4a6f2012-02-28 15:36:15 -08001224}
1225
1226/*
1227 * Generate array store
1228 *
1229 */
buzbee02031b12012-11-23 09:41:35 -08001230void Codegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
1231 RegLocation rl_index, RegLocation rl_src, int scale)
buzbee31a4a6f2012-02-28 15:36:15 -08001232{
buzbeefa57c472012-11-21 12:06:18 -08001233 RegisterClass reg_class = oat_reg_class_by_size(size);
1234 int len_offset = Array::LengthOffset().Int32Value();
1235 int data_offset;
buzbee31a4a6f2012-02-28 15:36:15 -08001236
Bill Buzbeea114add2012-05-03 15:00:40 -07001237 if (size == kLong || size == kDouble) {
buzbeefa57c472012-11-21 12:06:18 -08001238 data_offset = Array::DataOffset(sizeof(int64_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001239 } else {
buzbeefa57c472012-11-21 12:06:18 -08001240 data_offset = Array::DataOffset(sizeof(int32_t)).Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -07001241 }
buzbee31a4a6f2012-02-28 15:36:15 -08001242
buzbeefa57c472012-11-21 12:06:18 -08001243 rl_array = LoadValue(cu, rl_array, kCoreReg);
1244 rl_index = LoadValue(cu, rl_index, kCoreReg);
1245 int reg_ptr = INVALID_REG;
1246 if (cu->instruction_set != kX86) {
1247 if (IsTemp(cu, rl_array.low_reg)) {
1248 Clobber(cu, rl_array.low_reg);
1249 reg_ptr = rl_array.low_reg;
buzbeeb046e162012-10-30 15:48:42 -07001250 } else {
buzbeefa57c472012-11-21 12:06:18 -08001251 reg_ptr = AllocTemp(cu);
1252 OpRegCopy(cu, reg_ptr, rl_array.low_reg);
buzbeeb046e162012-10-30 15:48:42 -07001253 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001254 }
buzbee31a4a6f2012-02-28 15:36:15 -08001255
Bill Buzbeea114add2012-05-03 15:00:40 -07001256 /* null object? */
buzbeefa57c472012-11-21 12:06:18 -08001257 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
buzbee31a4a6f2012-02-28 15:36:15 -08001258
buzbeefa57c472012-11-21 12:06:18 -08001259 if (cu->instruction_set == kX86) {
1260 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
1261 /* if (rl_index >= [rl_array + len_offset]) goto kThrowArrayBounds */
1262 GenRegMemCheck(cu, kCondUge, rl_index.low_reg, rl_array.low_reg, len_offset, kThrowArrayBounds);
buzbeeb046e162012-10-30 15:48:42 -07001263 }
1264 if ((size == kLong) || (size == kDouble)) {
buzbeefa57c472012-11-21 12:06:18 -08001265 rl_src = LoadValueWide(cu, rl_src, reg_class);
buzbee31a4a6f2012-02-28 15:36:15 -08001266 } else {
buzbeefa57c472012-11-21 12:06:18 -08001267 rl_src = LoadValue(cu, rl_src, reg_class);
buzbee31a4a6f2012-02-28 15:36:15 -08001268 }
buzbeeb046e162012-10-30 15:48:42 -07001269 // If the src reg can't be byte accessed, move it to a temp first.
buzbeefa57c472012-11-21 12:06:18 -08001270 if ((size == kSignedByte || size == kUnsignedByte) && rl_src.low_reg >= 4) {
1271 int temp = AllocTemp(cu);
1272 OpRegCopy(cu, temp, rl_src.low_reg);
1273 StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, temp,
buzbeeb046e162012-10-30 15:48:42 -07001274 INVALID_REG, size, INVALID_SREG);
1275 } else {
buzbeefa57c472012-11-21 12:06:18 -08001276 StoreBaseIndexedDisp(cu, rl_array.low_reg, rl_index.low_reg, scale, data_offset, rl_src.low_reg,
1277 rl_src.high_reg, size, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -07001278 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001279 } else {
buzbeefa57c472012-11-21 12:06:18 -08001280 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1281 int reg_len = INVALID_REG;
1282 if (needs_range_check) {
1283 reg_len = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -07001284 //NOTE: max live temps(4) here.
1285 /* Get len */
buzbeefa57c472012-11-21 12:06:18 -08001286 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
Bill Buzbeea114add2012-05-03 15:00:40 -07001287 }
buzbeefa57c472012-11-21 12:06:18 -08001288 /* reg_ptr -> array data */
1289 OpRegImm(cu, kOpAdd, reg_ptr, data_offset);
1290 /* at this point, reg_ptr points to array, 2 live temps */
buzbeeb046e162012-10-30 15:48:42 -07001291 if ((size == kLong) || (size == kDouble)) {
1292 //TUNING: specific wide routine that can handle fp regs
1293 if (scale) {
buzbeefa57c472012-11-21 12:06:18 -08001294 int r_new_index = AllocTemp(cu);
1295 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
1296 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
1297 FreeTemp(cu, r_new_index);
buzbeeb046e162012-10-30 15:48:42 -07001298 } else {
buzbeefa57c472012-11-21 12:06:18 -08001299 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
buzbeeb046e162012-10-30 15:48:42 -07001300 }
buzbeefa57c472012-11-21 12:06:18 -08001301 rl_src = LoadValueWide(cu, rl_src, reg_class);
buzbeeb046e162012-10-30 15:48:42 -07001302
buzbeefa57c472012-11-21 12:06:18 -08001303 if (needs_range_check) {
1304 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1305 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001306 }
1307
buzbeefa57c472012-11-21 12:06:18 -08001308 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
buzbeeb046e162012-10-30 15:48:42 -07001309
buzbeefa57c472012-11-21 12:06:18 -08001310 FreeTemp(cu, reg_ptr);
buzbeeb046e162012-10-30 15:48:42 -07001311 } else {
buzbeefa57c472012-11-21 12:06:18 -08001312 rl_src = LoadValue(cu, rl_src, reg_class);
1313 if (needs_range_check) {
1314 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
1315 FreeTemp(cu, reg_len);
buzbeeb046e162012-10-30 15:48:42 -07001316 }
buzbeefa57c472012-11-21 12:06:18 -08001317 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
buzbeeb046e162012-10-30 15:48:42 -07001318 scale, size);
1319 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001320 }
buzbee31a4a6f2012-02-28 15:36:15 -08001321}
1322
buzbee02031b12012-11-23 09:41:35 -08001323void Codegen::GenLong3Addr(CompilationUnit* cu, OpKind first_op, OpKind second_op,
1324 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001325{
buzbeefa57c472012-11-21 12:06:18 -08001326 RegLocation rl_result;
1327 if (cu->instruction_set == kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -07001328 /*
1329 * NOTE: This is the one place in the code in which we might have
1330 * as many as six live temporary registers. There are 5 in the normal
1331 * set for Arm. Until we have spill capabilities, temporarily add
1332 * lr to the temp set. It is safe to do this locally, but note that
1333 * lr is used explicitly elsewhere in the code generator and cannot
1334 * normally be used as a general temp register.
1335 */
buzbeefa57c472012-11-21 12:06:18 -08001336 MarkTemp(cu, TargetReg(kLr)); // Add lr to the temp pool
1337 FreeTemp(cu, TargetReg(kLr)); // and make it available
buzbeeb046e162012-10-30 15:48:42 -07001338 }
buzbeefa57c472012-11-21 12:06:18 -08001339 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
1340 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
1341 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001342 // The longs may overlap - use intermediate temp if so
buzbeefa57c472012-11-21 12:06:18 -08001343 if ((rl_result.low_reg == rl_src1.high_reg) || (rl_result.low_reg == rl_src2.high_reg)){
1344 int t_reg = AllocTemp(cu);
1345 OpRegRegReg(cu, first_op, t_reg, rl_src1.low_reg, rl_src2.low_reg);
1346 OpRegRegReg(cu, second_op, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
1347 OpRegCopy(cu, rl_result.low_reg, t_reg);
1348 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001349 } else {
buzbeefa57c472012-11-21 12:06:18 -08001350 OpRegRegReg(cu, first_op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
1351 OpRegRegReg(cu, second_op, rl_result.high_reg, rl_src1.high_reg,
1352 rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001353 }
1354 /*
buzbeefa57c472012-11-21 12:06:18 -08001355 * NOTE: If rl_dest refers to a frame variable in a large frame, the
buzbee52a77fc2012-11-20 19:50:46 -08001356 * following StoreValueWide might need to allocate a temp register.
Bill Buzbeea114add2012-05-03 15:00:40 -07001357 * To further work around the lack of a spill capability, explicitly
buzbeefa57c472012-11-21 12:06:18 -08001358 * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result.
Bill Buzbeea114add2012-05-03 15:00:40 -07001359 * Remove when spill is functional.
1360 */
buzbeefa57c472012-11-21 12:06:18 -08001361 FreeRegLocTemps(cu, rl_result, rl_src1);
1362 FreeRegLocTemps(cu, rl_result, rl_src2);
1363 StoreValueWide(cu, rl_dest, rl_result);
1364 if (cu->instruction_set == kThumb2) {
1365 Clobber(cu, TargetReg(kLr));
1366 UnmarkTemp(cu, TargetReg(kLr)); // Remove lr from the temp pool
buzbeeb046e162012-10-30 15:48:42 -07001367 }
buzbee31a4a6f2012-02-28 15:36:15 -08001368}
1369
1370
buzbee02031b12012-11-23 09:41:35 -08001371bool Codegen::GenShiftOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
1372 RegLocation rl_src1, RegLocation rl_shift)
buzbee31a4a6f2012-02-28 15:36:15 -08001373{
buzbeefa57c472012-11-21 12:06:18 -08001374 int func_offset;
buzbee31a4a6f2012-02-28 15:36:15 -08001375
buzbee408ad162012-06-06 16:45:18 -07001376 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001377 case Instruction::SHL_LONG:
1378 case Instruction::SHL_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001379 func_offset = ENTRYPOINT_OFFSET(pShlLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001380 break;
1381 case Instruction::SHR_LONG:
1382 case Instruction::SHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001383 func_offset = ENTRYPOINT_OFFSET(pShrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001384 break;
1385 case Instruction::USHR_LONG:
1386 case Instruction::USHR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001387 func_offset = ENTRYPOINT_OFFSET(pUshrLong);
Bill Buzbeea114add2012-05-03 15:00:40 -07001388 break;
1389 default:
1390 LOG(FATAL) << "Unexpected case";
1391 return true;
1392 }
buzbeefa57c472012-11-21 12:06:18 -08001393 FlushAllRegs(cu); /* Send everything to home location */
1394 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_shift, false);
1395 RegLocation rl_result = GetReturnWide(cu, false);
1396 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001397 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001398}
1399
1400
buzbee02031b12012-11-23 09:41:35 -08001401bool Codegen::GenArithOpInt(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
1402 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001403{
Bill Buzbeea114add2012-05-03 15:00:40 -07001404 OpKind op = kOpBkpt;
buzbeefa57c472012-11-21 12:06:18 -08001405 bool is_div_rem = false;
1406 bool check_zero = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001407 bool unary = false;
buzbeefa57c472012-11-21 12:06:18 -08001408 RegLocation rl_result;
1409 bool shift_op = false;
buzbee408ad162012-06-06 16:45:18 -07001410 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001411 case Instruction::NEG_INT:
1412 op = kOpNeg;
1413 unary = true;
1414 break;
1415 case Instruction::NOT_INT:
1416 op = kOpMvn;
1417 unary = true;
1418 break;
1419 case Instruction::ADD_INT:
1420 case Instruction::ADD_INT_2ADDR:
1421 op = kOpAdd;
1422 break;
1423 case Instruction::SUB_INT:
1424 case Instruction::SUB_INT_2ADDR:
1425 op = kOpSub;
1426 break;
1427 case Instruction::MUL_INT:
1428 case Instruction::MUL_INT_2ADDR:
1429 op = kOpMul;
1430 break;
1431 case Instruction::DIV_INT:
1432 case Instruction::DIV_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001433 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001434 op = kOpDiv;
buzbeefa57c472012-11-21 12:06:18 -08001435 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001436 break;
buzbeef0504cd2012-11-13 16:31:10 -08001437 /* NOTE: returns in kArg1 */
Bill Buzbeea114add2012-05-03 15:00:40 -07001438 case Instruction::REM_INT:
1439 case Instruction::REM_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001440 check_zero = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001441 op = kOpRem;
buzbeefa57c472012-11-21 12:06:18 -08001442 is_div_rem = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001443 break;
1444 case Instruction::AND_INT:
1445 case Instruction::AND_INT_2ADDR:
1446 op = kOpAnd;
1447 break;
1448 case Instruction::OR_INT:
1449 case Instruction::OR_INT_2ADDR:
1450 op = kOpOr;
1451 break;
1452 case Instruction::XOR_INT:
1453 case Instruction::XOR_INT_2ADDR:
1454 op = kOpXor;
1455 break;
1456 case Instruction::SHL_INT:
1457 case Instruction::SHL_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001458 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001459 op = kOpLsl;
1460 break;
1461 case Instruction::SHR_INT:
1462 case Instruction::SHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001463 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001464 op = kOpAsr;
1465 break;
1466 case Instruction::USHR_INT:
1467 case Instruction::USHR_INT_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001468 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001469 op = kOpLsr;
1470 break;
1471 default:
buzbeecbd6d442012-11-17 14:11:25 -08001472 LOG(FATAL) << "Invalid word arith op: " << opcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001473 }
buzbeefa57c472012-11-21 12:06:18 -08001474 if (!is_div_rem) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001475 if (unary) {
buzbeefa57c472012-11-21 12:06:18 -08001476 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1477 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1478 OpRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg);
buzbee31a4a6f2012-02-28 15:36:15 -08001479 } else {
buzbeefa57c472012-11-21 12:06:18 -08001480 if (shift_op) {
1481 int t_reg = INVALID_REG;
1482 if (cu->instruction_set == kX86) {
buzbeeb046e162012-10-30 15:48:42 -07001483 // X86 doesn't require masking and must use ECX
buzbeefa57c472012-11-21 12:06:18 -08001484 t_reg = TargetReg(kCount); // rCX
1485 LoadValueDirectFixed(cu, rl_src2, t_reg);
buzbeeb046e162012-10-30 15:48:42 -07001486 } else {
buzbeefa57c472012-11-21 12:06:18 -08001487 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1488 t_reg = AllocTemp(cu);
1489 OpRegRegImm(cu, kOpAnd, t_reg, rl_src2.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -07001490 }
buzbeefa57c472012-11-21 12:06:18 -08001491 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1492 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1493 OpRegRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg, t_reg);
1494 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001495 } else {
buzbeefa57c472012-11-21 12:06:18 -08001496 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1497 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1498 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1499 OpRegRegReg(cu, op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001500 }
buzbee31a4a6f2012-02-28 15:36:15 -08001501 }
buzbeefa57c472012-11-21 12:06:18 -08001502 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001503 } else {
buzbeefa57c472012-11-21 12:06:18 -08001504 if (cu->instruction_set == kMips) {
1505 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
1506 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
1507 if (check_zero) {
1508 GenImmedCheck(cu, kCondEq, rl_src2.low_reg, 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001509 }
buzbeefa57c472012-11-21 12:06:18 -08001510 rl_result = GenDivRem(cu, rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv);
jeffhao4f8f04a2012-10-02 18:10:35 -07001511 } else {
buzbeefa57c472012-11-21 12:06:18 -08001512 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
1513 FlushAllRegs(cu); /* Send everything to home location */
1514 LoadValueDirectFixed(cu, rl_src2, TargetReg(kArg1));
1515 int r_tgt = CallHelperSetup(cu, func_offset);
1516 LoadValueDirectFixed(cu, rl_src1, TargetReg(kArg0));
1517 if (check_zero) {
1518 GenImmedCheck(cu, kCondEq, TargetReg(kArg1), 0, kThrowDivZero);
buzbeeb046e162012-10-30 15:48:42 -07001519 }
1520 // NOTE: callout here is not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08001521 CallHelper(cu, r_tgt, func_offset, false /* not a safepoint */ );
buzbeeb046e162012-10-30 15:48:42 -07001522 if (op == kOpDiv)
buzbeefa57c472012-11-21 12:06:18 -08001523 rl_result = GetReturn(cu, false);
buzbeeb046e162012-10-30 15:48:42 -07001524 else
buzbeefa57c472012-11-21 12:06:18 -08001525 rl_result = GetReturnAlt(cu);
jeffhao4f8f04a2012-10-02 18:10:35 -07001526 }
buzbeefa57c472012-11-21 12:06:18 -08001527 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001528 }
1529 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001530}
1531
1532/*
1533 * The following are the first-level codegen routines that analyze the format
1534 * of each bytecode then either dispatch special purpose codegen routines
1535 * or produce corresponding Thumb instructions directly.
1536 */
1537
buzbeeaad94382012-11-21 07:40:50 -08001538static bool IsPowerOfTwo(int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001539{
Bill Buzbeea114add2012-05-03 15:00:40 -07001540 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001541}
1542
1543// Returns true if no more than two bits are set in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001544static bool IsPopCountLE2(unsigned int x)
buzbee31a4a6f2012-02-28 15:36:15 -08001545{
Bill Buzbeea114add2012-05-03 15:00:40 -07001546 x &= x - 1;
1547 return (x & (x - 1)) == 0;
buzbee31a4a6f2012-02-28 15:36:15 -08001548}
1549
1550// Returns the index of the lowest set bit in 'x'.
buzbeeaad94382012-11-21 07:40:50 -08001551static int LowestSetBit(unsigned int x) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001552 int bit_posn = 0;
1553 while ((x & 0xf) == 0) {
1554 bit_posn += 4;
1555 x >>= 4;
1556 }
1557 while ((x & 1) == 0) {
1558 bit_posn++;
1559 x >>= 1;
1560 }
1561 return bit_posn;
buzbee31a4a6f2012-02-28 15:36:15 -08001562}
1563
buzbeefa57c472012-11-21 12:06:18 -08001564// Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit'
1565// and store the result in 'rl_dest'.
1566static bool HandleEasyDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
1567 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001568{
buzbeefa57c472012-11-21 12:06:18 -08001569 if ((lit < 2) || ((cu->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001570 return false;
buzbee0f79d722012-11-01 15:35:27 -07001571 }
buzbee02031b12012-11-23 09:41:35 -08001572 Codegen* cg = cu->cg.get();
buzbeeb046e162012-10-30 15:48:42 -07001573 // No divide instruction for Arm, so check for more special cases
buzbeefa57c472012-11-21 12:06:18 -08001574 if ((cu->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) {
buzbee02031b12012-11-23 09:41:35 -08001575 return cg->SmallLiteralDivide(cu, dalvik_opcode, rl_src, rl_dest, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001576 }
buzbee52a77fc2012-11-20 19:50:46 -08001577 int k = LowestSetBit(lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001578 if (k >= 30) {
1579 // Avoid special cases.
1580 return false;
1581 }
buzbeefa57c472012-11-21 12:06:18 -08001582 bool div = (dalvik_opcode == Instruction::DIV_INT_LIT8 ||
1583 dalvik_opcode == Instruction::DIV_INT_LIT16);
buzbee02031b12012-11-23 09:41:35 -08001584 rl_src = cg->LoadValue(cu, rl_src, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -08001585 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001586 if (div) {
buzbeefa57c472012-11-21 12:06:18 -08001587 int t_reg = AllocTemp(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001588 if (lit == 2) {
1589 // Division by 2 is by far the most common division by constant.
buzbee02031b12012-11-23 09:41:35 -08001590 cg->OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, 32 - k);
1591 cg->OpRegRegReg(cu, kOpAdd, t_reg, t_reg, rl_src.low_reg);
1592 cg->OpRegRegImm(cu, kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001593 } else {
buzbee02031b12012-11-23 09:41:35 -08001594 cg->OpRegRegImm(cu, kOpAsr, t_reg, rl_src.low_reg, 31);
1595 cg->OpRegRegImm(cu, kOpLsr, t_reg, t_reg, 32 - k);
1596 cg->OpRegRegReg(cu, kOpAdd, t_reg, t_reg, rl_src.low_reg);
1597 cg->OpRegRegImm(cu, kOpAsr, rl_result.low_reg, t_reg, k);
buzbee31a4a6f2012-02-28 15:36:15 -08001598 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001599 } else {
buzbeefa57c472012-11-21 12:06:18 -08001600 int t_reg1 = AllocTemp(cu);
1601 int t_reg2 = AllocTemp(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -07001602 if (lit == 2) {
buzbee02031b12012-11-23 09:41:35 -08001603 cg->OpRegRegImm(cu, kOpLsr, t_reg1, rl_src.low_reg, 32 - k);
1604 cg->OpRegRegReg(cu, kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1605 cg->OpRegRegImm(cu, kOpAnd, t_reg2, t_reg2, lit -1);
1606 cg->OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001607 } else {
buzbee02031b12012-11-23 09:41:35 -08001608 cg->OpRegRegImm(cu, kOpAsr, t_reg1, rl_src.low_reg, 31);
1609 cg->OpRegRegImm(cu, kOpLsr, t_reg1, t_reg1, 32 - k);
1610 cg->OpRegRegReg(cu, kOpAdd, t_reg2, t_reg1, rl_src.low_reg);
1611 cg->OpRegRegImm(cu, kOpAnd, t_reg2, t_reg2, lit - 1);
1612 cg->OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg2, t_reg1);
Bill Buzbeea114add2012-05-03 15:00:40 -07001613 }
1614 }
buzbee02031b12012-11-23 09:41:35 -08001615 cg->StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001616 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001617}
1618
buzbeefa57c472012-11-21 12:06:18 -08001619// Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit'
1620// and store the result in 'rl_dest'.
1621static bool HandleEasyMultiply(CompilationUnit* cu, RegLocation rl_src,
1622 RegLocation rl_dest, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001623{
Bill Buzbeea114add2012-05-03 15:00:40 -07001624 // Can we simplify this multiplication?
buzbeefa57c472012-11-21 12:06:18 -08001625 bool power_of_two = false;
1626 bool pop_count_le2 = false;
1627 bool power_of_two_minus_one = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001628 if (lit < 2) {
1629 // Avoid special cases.
1630 return false;
buzbee52a77fc2012-11-20 19:50:46 -08001631 } else if (IsPowerOfTwo(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001632 power_of_two = true;
buzbee52a77fc2012-11-20 19:50:46 -08001633 } else if (IsPopCountLE2(lit)) {
buzbeefa57c472012-11-21 12:06:18 -08001634 pop_count_le2 = true;
buzbee52a77fc2012-11-20 19:50:46 -08001635 } else if (IsPowerOfTwo(lit + 1)) {
buzbeefa57c472012-11-21 12:06:18 -08001636 power_of_two_minus_one = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001637 } else {
1638 return false;
1639 }
buzbee02031b12012-11-23 09:41:35 -08001640 Codegen* cg = cu->cg.get();
1641 rl_src = cg->LoadValue(cu, rl_src, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -08001642 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1643 if (power_of_two) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001644 // Shift.
buzbee02031b12012-11-23 09:41:35 -08001645 cg->OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_src.low_reg, LowestSetBit(lit));
buzbeefa57c472012-11-21 12:06:18 -08001646 } else if (pop_count_le2) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001647 // Shift and add and shift.
buzbeefa57c472012-11-21 12:06:18 -08001648 int first_bit = LowestSetBit(lit);
1649 int second_bit = LowestSetBit(lit ^ (1 << first_bit));
buzbee02031b12012-11-23 09:41:35 -08001650 cg->GenMultiplyByTwoBitMultiplier(cu, rl_src, rl_result, lit, first_bit, second_bit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001651 } else {
1652 // Reverse subtract: (src << (shift + 1)) - src.
buzbeefa57c472012-11-21 12:06:18 -08001653 DCHECK(power_of_two_minus_one);
buzbee52a77fc2012-11-20 19:50:46 -08001654 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1)
buzbeefa57c472012-11-21 12:06:18 -08001655 int t_reg = AllocTemp(cu);
buzbee02031b12012-11-23 09:41:35 -08001656 cg->OpRegRegImm(cu, kOpLsl, t_reg, rl_src.low_reg, LowestSetBit(lit + 1));
1657 cg->OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001658 }
buzbee02031b12012-11-23 09:41:35 -08001659 cg->StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001660 return true;
buzbee31a4a6f2012-02-28 15:36:15 -08001661}
1662
buzbee02031b12012-11-23 09:41:35 -08001663bool Codegen::GenArithOpIntLit(CompilationUnit* cu, Instruction::Code opcode,
1664 RegLocation rl_dest, RegLocation rl_src, int lit)
buzbee31a4a6f2012-02-28 15:36:15 -08001665{
buzbeefa57c472012-11-21 12:06:18 -08001666 RegLocation rl_result;
buzbeecbd6d442012-11-17 14:11:25 -08001667 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */
buzbeefa57c472012-11-21 12:06:18 -08001668 int shift_op = false;
1669 bool is_div = false;
buzbee31a4a6f2012-02-28 15:36:15 -08001670
buzbee408ad162012-06-06 16:45:18 -07001671 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001672 case Instruction::RSUB_INT_LIT8:
1673 case Instruction::RSUB_INT: {
buzbeefa57c472012-11-21 12:06:18 -08001674 int t_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -07001675 //TUNING: add support for use of Arm rsub op
buzbeefa57c472012-11-21 12:06:18 -08001676 rl_src = LoadValue(cu, rl_src, kCoreReg);
1677 t_reg = AllocTemp(cu);
1678 LoadConstant(cu, t_reg, lit);
1679 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1680 OpRegRegReg(cu, kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg);
1681 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001682 return false;
1683 break;
buzbee31a4a6f2012-02-28 15:36:15 -08001684 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001685
1686 case Instruction::ADD_INT_LIT8:
1687 case Instruction::ADD_INT_LIT16:
1688 op = kOpAdd;
1689 break;
1690 case Instruction::MUL_INT_LIT8:
1691 case Instruction::MUL_INT_LIT16: {
buzbeefa57c472012-11-21 12:06:18 -08001692 if (HandleEasyMultiply(cu, rl_src, rl_dest, lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001693 return false;
1694 }
1695 op = kOpMul;
1696 break;
buzbee31a4a6f2012-02-28 15:36:15 -08001697 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001698 case Instruction::AND_INT_LIT8:
1699 case Instruction::AND_INT_LIT16:
1700 op = kOpAnd;
1701 break;
1702 case Instruction::OR_INT_LIT8:
1703 case Instruction::OR_INT_LIT16:
1704 op = kOpOr;
1705 break;
1706 case Instruction::XOR_INT_LIT8:
1707 case Instruction::XOR_INT_LIT16:
1708 op = kOpXor;
1709 break;
1710 case Instruction::SHL_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001711 case Instruction::SHL_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07001712 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001713 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001714 op = kOpLsl;
1715 break;
1716 case Instruction::SHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001717 case Instruction::SHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07001718 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001719 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001720 op = kOpAsr;
1721 break;
1722 case Instruction::USHR_INT_LIT8:
buzbee2a83e8f2012-07-13 16:42:30 -07001723 case Instruction::USHR_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -07001724 lit &= 31;
buzbeefa57c472012-11-21 12:06:18 -08001725 shift_op = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001726 op = kOpLsr;
1727 break;
1728
1729 case Instruction::DIV_INT_LIT8:
1730 case Instruction::DIV_INT_LIT16:
1731 case Instruction::REM_INT_LIT8:
jeffhao4f8f04a2012-10-02 18:10:35 -07001732 case Instruction::REM_INT_LIT16: {
Bill Buzbeea114add2012-05-03 15:00:40 -07001733 if (lit == 0) {
buzbeefa57c472012-11-21 12:06:18 -08001734 GenImmedCheck(cu, kCondAl, 0, 0, kThrowDivZero);
Bill Buzbeea114add2012-05-03 15:00:40 -07001735 return false;
1736 }
buzbeefa57c472012-11-21 12:06:18 -08001737 if (HandleEasyDivide(cu, opcode, rl_src, rl_dest, lit)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001738 return false;
1739 }
buzbee408ad162012-06-06 16:45:18 -07001740 if ((opcode == Instruction::DIV_INT_LIT8) ||
1741 (opcode == Instruction::DIV_INT_LIT16)) {
buzbeefa57c472012-11-21 12:06:18 -08001742 is_div = true;
Bill Buzbeea114add2012-05-03 15:00:40 -07001743 } else {
buzbeefa57c472012-11-21 12:06:18 -08001744 is_div = false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001745 }
buzbeefa57c472012-11-21 12:06:18 -08001746 if (cu->instruction_set == kMips) {
1747 rl_src = LoadValue(cu, rl_src, kCoreReg);
1748 rl_result = GenDivRemLit(cu, rl_dest, rl_src.low_reg, lit, is_div);
jeffhao4f8f04a2012-10-02 18:10:35 -07001749 } else {
buzbeefa57c472012-11-21 12:06:18 -08001750 FlushAllRegs(cu); /* Everything to home location */
1751 LoadValueDirectFixed(cu, rl_src, TargetReg(kArg0));
1752 Clobber(cu, TargetReg(kArg0));
1753 int func_offset = ENTRYPOINT_OFFSET(pIdivmod);
1754 CallRuntimeHelperRegImm(cu, func_offset, TargetReg(kArg0), lit, false);
1755 if (is_div)
1756 rl_result = GetReturn(cu, false);
buzbeeb046e162012-10-30 15:48:42 -07001757 else
buzbeefa57c472012-11-21 12:06:18 -08001758 rl_result = GetReturnAlt(cu);
jeffhao4f8f04a2012-10-02 18:10:35 -07001759 }
buzbeefa57c472012-11-21 12:06:18 -08001760 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001761 return false;
1762 break;
jeffhao4f8f04a2012-10-02 18:10:35 -07001763 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001764 default:
1765 return true;
1766 }
buzbeefa57c472012-11-21 12:06:18 -08001767 rl_src = LoadValue(cu, rl_src, kCoreReg);
1768 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001769 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
buzbeefa57c472012-11-21 12:06:18 -08001770 if (shift_op && (lit == 0)) {
1771 OpRegCopy(cu, rl_result.low_reg, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001772 } else {
buzbeefa57c472012-11-21 12:06:18 -08001773 OpRegRegImm(cu, op, rl_result.low_reg, rl_src.low_reg, lit);
Bill Buzbeea114add2012-05-03 15:00:40 -07001774 }
buzbeefa57c472012-11-21 12:06:18 -08001775 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001776 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001777}
1778
buzbee02031b12012-11-23 09:41:35 -08001779bool Codegen::GenArithOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
1780 RegLocation rl_src1, RegLocation rl_src2)
buzbee31a4a6f2012-02-28 15:36:15 -08001781{
buzbeefa57c472012-11-21 12:06:18 -08001782 RegLocation rl_result;
1783 OpKind first_op = kOpBkpt;
1784 OpKind second_op = kOpBkpt;
1785 bool call_out = false;
1786 bool check_zero = false;
1787 int func_offset;
1788 int ret_reg = TargetReg(kRet0);
buzbee31a4a6f2012-02-28 15:36:15 -08001789
buzbee408ad162012-06-06 16:45:18 -07001790 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001791 case Instruction::NOT_LONG:
buzbeefa57c472012-11-21 12:06:18 -08001792 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
1793 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
Bill Buzbeea114add2012-05-03 15:00:40 -07001794 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -08001795 if (rl_result.low_reg == rl_src2.high_reg) {
1796 int t_reg = AllocTemp(cu);
1797 OpRegCopy(cu, t_reg, rl_src2.high_reg);
1798 OpRegReg(cu, kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1799 OpRegReg(cu, kOpMvn, rl_result.high_reg, t_reg);
1800 FreeTemp(cu, t_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001801 } else {
buzbeefa57c472012-11-21 12:06:18 -08001802 OpRegReg(cu, kOpMvn, rl_result.low_reg, rl_src2.low_reg);
1803 OpRegReg(cu, kOpMvn, rl_result.high_reg, rl_src2.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -07001804 }
buzbeefa57c472012-11-21 12:06:18 -08001805 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001806 return false;
1807 break;
1808 case Instruction::ADD_LONG:
1809 case Instruction::ADD_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001810 if (cu->instruction_set != kThumb2) {
1811 return GenAddLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001812 }
buzbeefa57c472012-11-21 12:06:18 -08001813 first_op = kOpAdd;
1814 second_op = kOpAdc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001815 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001816 case Instruction::SUB_LONG:
1817 case Instruction::SUB_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001818 if (cu->instruction_set != kThumb2) {
1819 return GenSubLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001820 }
buzbeefa57c472012-11-21 12:06:18 -08001821 first_op = kOpSub;
1822 second_op = kOpSbc;
Bill Buzbeea114add2012-05-03 15:00:40 -07001823 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001824 case Instruction::MUL_LONG:
1825 case Instruction::MUL_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001826 call_out = true;
1827 ret_reg = TargetReg(kRet0);
1828 func_offset = ENTRYPOINT_OFFSET(pLmul);
Bill Buzbeea114add2012-05-03 15:00:40 -07001829 break;
1830 case Instruction::DIV_LONG:
1831 case Instruction::DIV_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001832 call_out = true;
1833 check_zero = true;
1834 ret_reg = TargetReg(kRet0);
1835 func_offset = ENTRYPOINT_OFFSET(pLdiv);
Bill Buzbeea114add2012-05-03 15:00:40 -07001836 break;
1837 case Instruction::REM_LONG:
1838 case Instruction::REM_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001839 call_out = true;
1840 check_zero = true;
1841 func_offset = ENTRYPOINT_OFFSET(pLdivmod);
buzbeef0504cd2012-11-13 16:31:10 -08001842 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */
buzbeefa57c472012-11-21 12:06:18 -08001843 ret_reg = (cu->instruction_set == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001844 break;
1845 case Instruction::AND_LONG_2ADDR:
1846 case Instruction::AND_LONG:
buzbeefa57c472012-11-21 12:06:18 -08001847 if (cu->instruction_set == kX86) {
1848 return GenAndLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001849 }
buzbeefa57c472012-11-21 12:06:18 -08001850 first_op = kOpAnd;
1851 second_op = kOpAnd;
Bill Buzbeea114add2012-05-03 15:00:40 -07001852 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001853 case Instruction::OR_LONG:
1854 case Instruction::OR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001855 if (cu->instruction_set == kX86) {
1856 return GenOrLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001857 }
buzbeefa57c472012-11-21 12:06:18 -08001858 first_op = kOpOr;
1859 second_op = kOpOr;
Bill Buzbeea114add2012-05-03 15:00:40 -07001860 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001861 case Instruction::XOR_LONG:
1862 case Instruction::XOR_LONG_2ADDR:
buzbeefa57c472012-11-21 12:06:18 -08001863 if (cu->instruction_set == kX86) {
1864 return GenXorLong(cu, rl_dest, rl_src1, rl_src2);
buzbeeb046e162012-10-30 15:48:42 -07001865 }
buzbeefa57c472012-11-21 12:06:18 -08001866 first_op = kOpXor;
1867 second_op = kOpXor;
Bill Buzbeea114add2012-05-03 15:00:40 -07001868 break;
Bill Buzbeea114add2012-05-03 15:00:40 -07001869 case Instruction::NEG_LONG: {
buzbeefa57c472012-11-21 12:06:18 -08001870 return GenNegLong(cu, rl_dest, rl_src2);
buzbee31a4a6f2012-02-28 15:36:15 -08001871 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001872 default:
1873 LOG(FATAL) << "Invalid long arith op";
1874 }
buzbeefa57c472012-11-21 12:06:18 -08001875 if (!call_out) {
1876 GenLong3Addr(cu, first_op, second_op, rl_dest, rl_src1, rl_src2);
Bill Buzbeea114add2012-05-03 15:00:40 -07001877 } else {
buzbeefa57c472012-11-21 12:06:18 -08001878 FlushAllRegs(cu); /* Send everything to home location */
1879 if (check_zero) {
1880 LoadValueDirectWideFixed(cu, rl_src2, TargetReg(kArg2), TargetReg(kArg3));
1881 int r_tgt = CallHelperSetup(cu, func_offset);
1882 GenDivZeroCheck(cu, TargetReg(kArg2), TargetReg(kArg3));
1883 LoadValueDirectWideFixed(cu, rl_src1, TargetReg(kArg0), TargetReg(kArg1));
buzbee8320f382012-09-11 16:29:42 -07001884 // NOTE: callout here is not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08001885 CallHelper(cu, r_tgt, func_offset, false /* not safepoint */);
buzbee31a4a6f2012-02-28 15:36:15 -08001886 } else {
buzbeefa57c472012-11-21 12:06:18 -08001887 CallRuntimeHelperRegLocationRegLocation(cu, func_offset,
1888 rl_src1, rl_src2, false);
buzbee31a4a6f2012-02-28 15:36:15 -08001889 }
buzbeef0504cd2012-11-13 16:31:10 -08001890 // Adjust return regs in to handle case of rem returning kArg2/kArg3
buzbeefa57c472012-11-21 12:06:18 -08001891 if (ret_reg == TargetReg(kRet0))
1892 rl_result = GetReturnWide(cu, false);
Bill Buzbeea114add2012-05-03 15:00:40 -07001893 else
buzbeefa57c472012-11-21 12:06:18 -08001894 rl_result = GetReturnWideAlt(cu);
1895 StoreValueWide(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001896 }
1897 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001898}
1899
buzbee02031b12012-11-23 09:41:35 -08001900bool Codegen::GenConversionCall(CompilationUnit* cu, int func_offset,
1901 RegLocation rl_dest, RegLocation rl_src)
buzbee31a4a6f2012-02-28 15:36:15 -08001902{
Bill Buzbeea114add2012-05-03 15:00:40 -07001903 /*
1904 * Don't optimize the register usage since it calls out to support
1905 * functions
1906 */
buzbeefa57c472012-11-21 12:06:18 -08001907 FlushAllRegs(cu); /* Send everything to home location */
1908 if (rl_src.wide) {
1909 LoadValueDirectWideFixed(cu, rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0),
1910 rl_src.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee408ad162012-06-06 16:45:18 -07001911 } else {
buzbeefa57c472012-11-21 12:06:18 -08001912 LoadValueDirectFixed(cu, rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -07001913 }
buzbeefa57c472012-11-21 12:06:18 -08001914 CallRuntimeHelperRegLocation(cu, func_offset, rl_src, false);
1915 if (rl_dest.wide) {
1916 RegLocation rl_result;
1917 rl_result = GetReturnWide(cu, rl_dest.fp);
1918 StoreValueWide(cu, rl_dest, rl_result);
buzbee408ad162012-06-06 16:45:18 -07001919 } else {
buzbeefa57c472012-11-21 12:06:18 -08001920 RegLocation rl_result;
1921 rl_result = GetReturn(cu, rl_dest.fp);
1922 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -07001923 }
1924 return false;
buzbee31a4a6f2012-02-28 15:36:15 -08001925}
1926
buzbee31a4a6f2012-02-28 15:36:15 -08001927/* Check if we need to check for pending suspend request */
buzbee02031b12012-11-23 09:41:35 -08001928void Codegen::GenSuspendTest(CompilationUnit* cu, int opt_flags)
buzbee31a4a6f2012-02-28 15:36:15 -08001929{
buzbeefa57c472012-11-21 12:06:18 -08001930 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001931 return;
1932 }
buzbeefa57c472012-11-21 12:06:18 -08001933 FlushAllRegs(cu);
1934 LIR* branch = OpTestSuspend(cu, NULL);
1935 LIR* ret_lab = NewLIR0(cu, kPseudoTargetLabel);
1936 LIR* target = RawLIR(cu, cu->current_dalvik_offset, kPseudoSuspendTarget,
1937 reinterpret_cast<uintptr_t>(ret_lab), cu->current_dalvik_offset);
buzbeecbd6d442012-11-17 14:11:25 -08001938 branch->target = target;
buzbeefa57c472012-11-21 12:06:18 -08001939 InsertGrowableList(cu, &cu->suspend_launchpads, reinterpret_cast<uintptr_t>(target));
buzbee31a4a6f2012-02-28 15:36:15 -08001940}
1941
buzbeefead2932012-03-30 14:02:01 -07001942/* Check if we need to check for pending suspend request */
buzbee02031b12012-11-23 09:41:35 -08001943void Codegen::GenSuspendTestAndBranch(CompilationUnit* cu, int opt_flags, LIR* target)
buzbeefead2932012-03-30 14:02:01 -07001944{
buzbeefa57c472012-11-21 12:06:18 -08001945 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
1946 OpUnconditionalBranch(cu, target);
Bill Buzbeea114add2012-05-03 15:00:40 -07001947 return;
1948 }
buzbeefa57c472012-11-21 12:06:18 -08001949 OpTestSuspend(cu, target);
1950 LIR* launch_pad =
1951 RawLIR(cu, cu->current_dalvik_offset, kPseudoSuspendTarget,
1952 reinterpret_cast<uintptr_t>(target), cu->current_dalvik_offset);
1953 FlushAllRegs(cu);
1954 OpUnconditionalBranch(cu, launch_pad);
1955 InsertGrowableList(cu, &cu->suspend_launchpads, reinterpret_cast<uintptr_t>(launch_pad));
buzbeefead2932012-03-30 14:02:01 -07001956}
1957
buzbee31a4a6f2012-02-28 15:36:15 -08001958} // namespace art