blob: 6a1178e34062788c5e1f5f15fe9a5c900bef867f [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
2 * Copyright (C) 2011 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
17/* This file contains codegen for the Thumb2 ISA. */
18
19#include "oat_compilation_unit.h"
20#include "oat/runtime/oat_support_entrypoints.h"
buzbee1bc37c62012-11-20 13:35:41 -080021#include "arm_lir.h"
buzbee02031b12012-11-23 09:41:35 -080022#include "codegen_arm.h"
buzbee1bc37c62012-11-20 13:35:41 -080023#include "../codegen_util.h"
24#include "../ralloc_util.h"
buzbeeefc63692012-11-14 16:31:52 -080025
26namespace art {
27
buzbee02031b12012-11-23 09:41:35 -080028LIR* ArmCodegen::OpCmpBranch(CompilationUnit* cu, ConditionCode cond, int src1,
buzbeeefc63692012-11-14 16:31:52 -080029 int src2, LIR* target)
30{
buzbeefa57c472012-11-21 12:06:18 -080031 OpRegReg(cu, kOpCmp, src1, src2);
32 return OpCondBranch(cu, cond, target);
buzbeeefc63692012-11-14 16:31:52 -080033}
34
35/*
36 * Generate a Thumb2 IT instruction, which can nullify up to
37 * four subsequent instructions based on a condition and its
38 * inverse. The condition applies to the first instruction, which
39 * is executed if the condition is met. The string "guide" consists
40 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
41 * A "T" means the instruction is executed if the condition is
42 * met, and an "E" means the instruction is executed if the condition
43 * is not met.
44 */
buzbee02031b12012-11-23 09:41:35 -080045LIR* ArmCodegen::OpIT(CompilationUnit* cu, ConditionCode ccode, const char* guide)
buzbeeefc63692012-11-14 16:31:52 -080046{
47 int mask;
buzbeeefc63692012-11-14 16:31:52 -080048 int mask3 = 0;
49 int mask2 = 0;
50 int mask1 = 0;
buzbee02031b12012-11-23 09:41:35 -080051 ArmConditionCode code = ArmConditionEncoding(ccode);
52 int cond_bit = code & 1;
53 int alt_bit = cond_bit ^ 1;
buzbeeefc63692012-11-14 16:31:52 -080054
55 //Note: case fallthroughs intentional
56 switch (strlen(guide)) {
57 case 3:
buzbeefa57c472012-11-21 12:06:18 -080058 mask1 = (guide[2] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080059 case 2:
buzbeefa57c472012-11-21 12:06:18 -080060 mask2 = (guide[1] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080061 case 1:
buzbeefa57c472012-11-21 12:06:18 -080062 mask3 = (guide[0] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080063 break;
64 case 0:
65 break;
66 default:
buzbee52a77fc2012-11-20 19:50:46 -080067 LOG(FATAL) << "OAT: bad case in OpIT";
buzbeeefc63692012-11-14 16:31:52 -080068 }
69 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
70 (1 << (3 - strlen(guide)));
buzbeefa57c472012-11-21 12:06:18 -080071 return NewLIR2(cu, kThumb2It, code, mask);
buzbeeefc63692012-11-14 16:31:52 -080072}
73
74/*
75 * 64-bit 3way compare function.
76 * mov rX, #-1
77 * cmp op1hi, op2hi
78 * blt done
79 * bgt flip
80 * sub rX, op1lo, op2lo (treat as unsigned)
81 * beq done
82 * ite hi
83 * mov(hi) rX, #-1
84 * mov(!hi) rX, #1
85 * flip:
86 * neg rX
87 * done:
88 */
buzbee02031b12012-11-23 09:41:35 -080089void ArmCodegen::GenCmpLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
90 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -080091{
92 LIR* target1;
93 LIR* target2;
buzbeefa57c472012-11-21 12:06:18 -080094 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
95 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
96 int t_reg = AllocTemp(cu);
97 LoadConstant(cu, t_reg, -1);
98 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
99 LIR* branch1 = OpCondBranch(cu, kCondLt, NULL);
100 LIR* branch2 = OpCondBranch(cu, kCondGt, NULL);
101 OpRegRegReg(cu, kOpSub, t_reg, rl_src1.low_reg, rl_src2.low_reg);
102 LIR* branch3 = OpCondBranch(cu, kCondEq, NULL);
buzbeeefc63692012-11-14 16:31:52 -0800103
buzbee02031b12012-11-23 09:41:35 -0800104 OpIT(cu, kCondHi, "E");
buzbeefa57c472012-11-21 12:06:18 -0800105 NewLIR2(cu, kThumb2MovImmShift, t_reg, ModifiedImmediate(-1));
106 LoadConstant(cu, t_reg, 1);
107 GenBarrier(cu);
buzbeeefc63692012-11-14 16:31:52 -0800108
buzbeefa57c472012-11-21 12:06:18 -0800109 target2 = NewLIR0(cu, kPseudoTargetLabel);
110 OpRegReg(cu, kOpNeg, t_reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800111
buzbeefa57c472012-11-21 12:06:18 -0800112 target1 = NewLIR0(cu, kPseudoTargetLabel);
buzbeeefc63692012-11-14 16:31:52 -0800113
buzbeefa57c472012-11-21 12:06:18 -0800114 RegLocation rl_temp = LocCReturn(); // Just using as template, will change
115 rl_temp.low_reg = t_reg;
116 StoreValue(cu, rl_dest, rl_temp);
117 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800118
buzbeecbd6d442012-11-17 14:11:25 -0800119 branch1->target = target1;
120 branch2->target = target2;
buzbeeefc63692012-11-14 16:31:52 -0800121 branch3->target = branch1->target;
122}
123
buzbee02031b12012-11-23 09:41:35 -0800124void ArmCodegen::GenFusedLongCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -0800125{
buzbeefa57c472012-11-21 12:06:18 -0800126 LIR* label_list = cu->block_label_list;
127 LIR* taken = &label_list[bb->taken->id];
128 LIR* not_taken = &label_list[bb->fall_through->id];
129 RegLocation rl_src1 = GetSrcWide(cu, mir, 0);
130 RegLocation rl_src2 = GetSrcWide(cu, mir, 2);
131 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
132 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800133 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
buzbeefa57c472012-11-21 12:06:18 -0800134 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800135 switch(ccode) {
136 case kCondEq:
buzbeefa57c472012-11-21 12:06:18 -0800137 OpCondBranch(cu, kCondNe, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800138 break;
139 case kCondNe:
buzbeefa57c472012-11-21 12:06:18 -0800140 OpCondBranch(cu, kCondNe, taken);
buzbeeefc63692012-11-14 16:31:52 -0800141 break;
142 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800143 OpCondBranch(cu, kCondLt, taken);
144 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800145 ccode = kCondCc;
146 break;
147 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800148 OpCondBranch(cu, kCondLt, taken);
149 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800150 ccode = kCondLs;
151 break;
152 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800153 OpCondBranch(cu, kCondGt, taken);
154 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800155 ccode = kCondHi;
156 break;
157 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800158 OpCondBranch(cu, kCondGt, taken);
159 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800160 ccode = kCondCs;
161 break;
162 default:
buzbeecbd6d442012-11-17 14:11:25 -0800163 LOG(FATAL) << "Unexpected ccode: " << ccode;
buzbeeefc63692012-11-14 16:31:52 -0800164 }
buzbeefa57c472012-11-21 12:06:18 -0800165 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
166 OpCondBranch(cu, ccode, taken);
buzbeeefc63692012-11-14 16:31:52 -0800167}
168
169/*
170 * Generate a register comparison to an immediate and branch. Caller
171 * is responsible for setting branch target field.
172 */
buzbee02031b12012-11-23 09:41:35 -0800173LIR* ArmCodegen::OpCmpImmBranch(CompilationUnit* cu, ConditionCode cond, int reg, int check_value,
174 LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800175{
176 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -0800177 int mod_imm;
178 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
179 if ((ARM_LOWREG(reg)) && (check_value == 0) &&
180 ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
181 branch = NewLIR2(cu, (arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
buzbeeefc63692012-11-14 16:31:52 -0800182 reg, 0);
183 } else {
buzbeefa57c472012-11-21 12:06:18 -0800184 mod_imm = ModifiedImmediate(check_value);
185 if (ARM_LOWREG(reg) && ((check_value & 0xff) == check_value)) {
186 NewLIR2(cu, kThumbCmpRI8, reg, check_value);
187 } else if (mod_imm >= 0) {
188 NewLIR2(cu, kThumb2CmpRI8, reg, mod_imm);
buzbeeefc63692012-11-14 16:31:52 -0800189 } else {
buzbeefa57c472012-11-21 12:06:18 -0800190 int t_reg = AllocTemp(cu);
191 LoadConstant(cu, t_reg, check_value);
192 OpRegReg(cu, kOpCmp, reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800193 }
buzbeefa57c472012-11-21 12:06:18 -0800194 branch = NewLIR2(cu, kThumbBCond, 0, arm_cond);
buzbeeefc63692012-11-14 16:31:52 -0800195 }
196 branch->target = target;
197 return branch;
198}
buzbee02031b12012-11-23 09:41:35 -0800199
200LIR* ArmCodegen::OpRegCopyNoInsert(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800201{
202 LIR* res;
203 int opcode;
buzbeefa57c472012-11-21 12:06:18 -0800204 if (ARM_FPREG(r_dest) || ARM_FPREG(r_src))
buzbee02031b12012-11-23 09:41:35 -0800205 return OpFpRegCopy(cu, r_dest, r_src);
buzbeefa57c472012-11-21 12:06:18 -0800206 if (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800207 opcode = kThumbMovRR;
buzbeefa57c472012-11-21 12:06:18 -0800208 else if (!ARM_LOWREG(r_dest) && !ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800209 opcode = kThumbMovRR_H2H;
buzbeefa57c472012-11-21 12:06:18 -0800210 else if (ARM_LOWREG(r_dest))
buzbeeefc63692012-11-14 16:31:52 -0800211 opcode = kThumbMovRR_H2L;
212 else
213 opcode = kThumbMovRR_L2H;
buzbeefa57c472012-11-21 12:06:18 -0800214 res = RawLIR(cu, cu->current_dalvik_offset, opcode, r_dest, r_src);
215 if (!(cu->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
216 res->flags.is_nop = true;
buzbeeefc63692012-11-14 16:31:52 -0800217 }
218 return res;
219}
220
buzbee02031b12012-11-23 09:41:35 -0800221LIR* ArmCodegen::OpRegCopy(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800222{
buzbeefa57c472012-11-21 12:06:18 -0800223 LIR* res = OpRegCopyNoInsert(cu, r_dest, r_src);
224 AppendLIR(cu, res);
buzbeeefc63692012-11-14 16:31:52 -0800225 return res;
226}
227
buzbee02031b12012-11-23 09:41:35 -0800228void ArmCodegen::OpRegCopyWide(CompilationUnit* cu, int dest_lo, int dest_hi, int src_lo,
229 int src_hi)
buzbeeefc63692012-11-14 16:31:52 -0800230{
buzbeefa57c472012-11-21 12:06:18 -0800231 bool dest_fp = ARM_FPREG(dest_lo) && ARM_FPREG(dest_hi);
232 bool src_fp = ARM_FPREG(src_lo) && ARM_FPREG(src_hi);
233 DCHECK_EQ(ARM_FPREG(src_lo), ARM_FPREG(src_hi));
234 DCHECK_EQ(ARM_FPREG(dest_lo), ARM_FPREG(dest_hi));
235 if (dest_fp) {
236 if (src_fp) {
237 OpRegCopy(cu, S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800238 } else {
buzbeefa57c472012-11-21 12:06:18 -0800239 NewLIR3(cu, kThumb2Fmdrr, S2d(dest_lo, dest_hi), src_lo, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800240 }
241 } else {
buzbeefa57c472012-11-21 12:06:18 -0800242 if (src_fp) {
243 NewLIR3(cu, kThumb2Fmrrd, dest_lo, dest_hi, S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800244 } else {
245 // Handle overlap
buzbeefa57c472012-11-21 12:06:18 -0800246 if (src_hi == dest_lo) {
247 OpRegCopy(cu, dest_hi, src_hi);
248 OpRegCopy(cu, dest_lo, src_lo);
buzbeeefc63692012-11-14 16:31:52 -0800249 } else {
buzbeefa57c472012-11-21 12:06:18 -0800250 OpRegCopy(cu, dest_lo, src_lo);
251 OpRegCopy(cu, dest_hi, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800252 }
253 }
254 }
255}
256
257// Table of magic divisors
buzbeeefc63692012-11-14 16:31:52 -0800258struct MagicTable {
259 uint32_t magic;
260 uint32_t shift;
261 DividePattern pattern;
262};
263
buzbeefa57c472012-11-21 12:06:18 -0800264static const MagicTable magic_table[] = {
buzbeeefc63692012-11-14 16:31:52 -0800265 {0, 0, DivideNone}, // 0
266 {0, 0, DivideNone}, // 1
267 {0, 0, DivideNone}, // 2
268 {0x55555556, 0, Divide3}, // 3
269 {0, 0, DivideNone}, // 4
270 {0x66666667, 1, Divide5}, // 5
271 {0x2AAAAAAB, 0, Divide3}, // 6
272 {0x92492493, 2, Divide7}, // 7
273 {0, 0, DivideNone}, // 8
274 {0x38E38E39, 1, Divide5}, // 9
275 {0x66666667, 2, Divide5}, // 10
276 {0x2E8BA2E9, 1, Divide5}, // 11
277 {0x2AAAAAAB, 1, Divide5}, // 12
278 {0x4EC4EC4F, 2, Divide5}, // 13
279 {0x92492493, 3, Divide7}, // 14
280 {0x88888889, 3, Divide7}, // 15
281};
282
283// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
buzbee02031b12012-11-23 09:41:35 -0800284bool ArmCodegen::SmallLiteralDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
285 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbeeefc63692012-11-14 16:31:52 -0800286{
buzbeefa57c472012-11-21 12:06:18 -0800287 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
buzbeeefc63692012-11-14 16:31:52 -0800288 return false;
289 }
buzbeefa57c472012-11-21 12:06:18 -0800290 DividePattern pattern = magic_table[lit].pattern;
buzbeeefc63692012-11-14 16:31:52 -0800291 if (pattern == DivideNone) {
292 return false;
293 }
294 // Tuning: add rem patterns
buzbeefa57c472012-11-21 12:06:18 -0800295 if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
buzbeeefc63692012-11-14 16:31:52 -0800296 return false;
297 }
298
buzbeefa57c472012-11-21 12:06:18 -0800299 int r_magic = AllocTemp(cu);
300 LoadConstant(cu, r_magic, magic_table[lit].magic);
301 rl_src = LoadValue(cu, rl_src, kCoreReg);
302 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
303 int r_hi = AllocTemp(cu);
304 int r_lo = AllocTemp(cu);
305 NewLIR4(cu, kThumb2Smull, r_lo, r_hi, r_magic, rl_src.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800306 switch(pattern) {
307 case Divide3:
buzbeefa57c472012-11-21 12:06:18 -0800308 OpRegRegRegShift(cu, kOpSub, rl_result.low_reg, r_hi,
309 rl_src.low_reg, EncodeShift(kArmAsr, 31));
buzbeeefc63692012-11-14 16:31:52 -0800310 break;
311 case Divide5:
buzbeefa57c472012-11-21 12:06:18 -0800312 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
313 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
314 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800315 break;
316 case Divide7:
buzbeefa57c472012-11-21 12:06:18 -0800317 OpRegReg(cu, kOpAdd, r_hi, rl_src.low_reg);
318 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
319 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
320 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800321 break;
322 default:
buzbeecbd6d442012-11-17 14:11:25 -0800323 LOG(FATAL) << "Unexpected pattern: " << pattern;
buzbeeefc63692012-11-14 16:31:52 -0800324 }
buzbeefa57c472012-11-21 12:06:18 -0800325 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800326 return true;
327}
328
buzbee02031b12012-11-23 09:41:35 -0800329LIR* ArmCodegen::GenRegMemCheck(CompilationUnit* cu, ConditionCode c_code,
buzbeeefc63692012-11-14 16:31:52 -0800330 int reg1, int base, int offset, ThrowKind kind)
331{
buzbee52a77fc2012-11-20 19:50:46 -0800332 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800333 return NULL;
334}
335
buzbee02031b12012-11-23 09:41:35 -0800336RegLocation ArmCodegen::GenDivRemLit(CompilationUnit* cu, RegLocation rl_dest, int reg1, int lit,
337 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800338{
buzbee52a77fc2012-11-20 19:50:46 -0800339 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800340 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800341}
342
buzbee02031b12012-11-23 09:41:35 -0800343RegLocation ArmCodegen::GenDivRem(CompilationUnit* cu, RegLocation rl_dest, int reg1, int reg2,
344 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800345{
buzbee52a77fc2012-11-20 19:50:46 -0800346 LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800347 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800348}
349
buzbee02031b12012-11-23 09:41:35 -0800350bool ArmCodegen::GenInlinedMinMaxInt(CompilationUnit *cu, CallInfo* info, bool is_min)
buzbeeefc63692012-11-14 16:31:52 -0800351{
buzbeefa57c472012-11-21 12:06:18 -0800352 DCHECK_EQ(cu->instruction_set, kThumb2);
353 RegLocation rl_src1 = info->args[0];
354 RegLocation rl_src2 = info->args[1];
355 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
356 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
357 RegLocation rl_dest = InlineTarget(cu, info);
358 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
359 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
buzbee02031b12012-11-23 09:41:35 -0800360 OpIT(cu, (is_min) ? kCondGt : kCondLt, "E");
buzbeefa57c472012-11-21 12:06:18 -0800361 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src2.low_reg);
362 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src1.low_reg);
363 GenBarrier(cu);
364 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800365 return true;
366}
367
buzbee02031b12012-11-23 09:41:35 -0800368void ArmCodegen::OpLea(CompilationUnit* cu, int rBase, int reg1, int reg2, int scale, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800369{
buzbee52a77fc2012-11-20 19:50:46 -0800370 LOG(FATAL) << "Unexpected use of OpLea for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800371}
372
buzbee02031b12012-11-23 09:41:35 -0800373void ArmCodegen::OpTlsCmp(CompilationUnit* cu, int offset, int val)
buzbeeefc63692012-11-14 16:31:52 -0800374{
buzbee52a77fc2012-11-20 19:50:46 -0800375 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800376}
377
buzbee02031b12012-11-23 09:41:35 -0800378bool ArmCodegen::GenInlinedCas32(CompilationUnit* cu, CallInfo* info, bool need_write_barrier) {
buzbeefa57c472012-11-21 12:06:18 -0800379 DCHECK_EQ(cu->instruction_set, kThumb2);
380 // Unused - RegLocation rl_src_unsafe = info->args[0];
381 RegLocation rl_src_obj= info->args[1]; // Object - known non-null
382 RegLocation rl_src_offset= info->args[2]; // long low
383 rl_src_offset.wide = 0; // ignore high half in info->args[3]
384 RegLocation rl_src_expected= info->args[4]; // int or Object
385 RegLocation rl_src_new_value= info->args[5]; // int or Object
386 RegLocation rl_dest = InlineTarget(cu, info); // boolean place for result
buzbeeefc63692012-11-14 16:31:52 -0800387
388
buzbee1bc37c62012-11-20 13:35:41 -0800389 // Release store semantics, get the barrier out of the way. TODO: revisit
buzbeefa57c472012-11-21 12:06:18 -0800390 GenMemBarrier(cu, kStoreLoad);
buzbeeefc63692012-11-14 16:31:52 -0800391
buzbeefa57c472012-11-21 12:06:18 -0800392 RegLocation rl_object = LoadValue(cu, rl_src_obj, kCoreReg);
393 RegLocation rl_new_value = LoadValue(cu, rl_src_new_value, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800394
395 if (need_write_barrier) {
396 // Mark card for object assuming new value is stored.
buzbeefa57c472012-11-21 12:06:18 -0800397 MarkGCCard(cu, rl_new_value.low_reg, rl_object.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800398 }
399
buzbeefa57c472012-11-21 12:06:18 -0800400 RegLocation rl_offset = LoadValue(cu, rl_src_offset, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800401
buzbeefa57c472012-11-21 12:06:18 -0800402 int r_ptr = AllocTemp(cu);
403 OpRegRegReg(cu, kOpAdd, r_ptr, rl_object.low_reg, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800404
buzbeefa57c472012-11-21 12:06:18 -0800405 // Free now unneeded rl_object and rl_offset to give more temps.
406 ClobberSReg(cu, rl_object.s_reg_low);
407 FreeTemp(cu, rl_object.low_reg);
408 ClobberSReg(cu, rl_offset.s_reg_low);
409 FreeTemp(cu, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800410
buzbeefa57c472012-11-21 12:06:18 -0800411 int r_old_value = AllocTemp(cu);
412 NewLIR3(cu, kThumb2Ldrex, r_old_value, r_ptr, 0); // r_old_value := [r_ptr]
buzbeeefc63692012-11-14 16:31:52 -0800413
buzbeefa57c472012-11-21 12:06:18 -0800414 RegLocation rl_expected = LoadValue(cu, rl_src_expected, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800415
buzbeefa57c472012-11-21 12:06:18 -0800416 // if (r_old_value == rExpected) {
417 // [r_ptr] <- r_new_value && r_result := success ? 0 : 1
418 // r_result ^= 1
buzbeeefc63692012-11-14 16:31:52 -0800419 // } else {
buzbeefa57c472012-11-21 12:06:18 -0800420 // r_result := 0
buzbeeefc63692012-11-14 16:31:52 -0800421 // }
buzbeefa57c472012-11-21 12:06:18 -0800422 OpRegReg(cu, kOpCmp, r_old_value, rl_expected.low_reg);
423 FreeTemp(cu, r_old_value); // Now unneeded.
424 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbee02031b12012-11-23 09:41:35 -0800425 OpIT(cu, kCondEq, "TE");
buzbeefa57c472012-11-21 12:06:18 -0800426 NewLIR4(cu, kThumb2Strex, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
427 FreeTemp(cu, r_ptr); // Now unneeded.
428 OpRegImm(cu, kOpXor, rl_result.low_reg, 1);
429 OpRegReg(cu, kOpXor, rl_result.low_reg, rl_result.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800430
buzbeefa57c472012-11-21 12:06:18 -0800431 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800432
433 return true;
434}
435
buzbee02031b12012-11-23 09:41:35 -0800436LIR* ArmCodegen::OpPcRelLoad(CompilationUnit* cu, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800437{
buzbeefa57c472012-11-21 12:06:18 -0800438 return RawLIR(cu, cu->current_dalvik_offset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800439}
440
buzbee02031b12012-11-23 09:41:35 -0800441LIR* ArmCodegen::OpVldm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800442{
buzbeefa57c472012-11-21 12:06:18 -0800443 return NewLIR3(cu, kThumb2Vldms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800444}
445
buzbee02031b12012-11-23 09:41:35 -0800446LIR* ArmCodegen::OpVstm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800447{
buzbeefa57c472012-11-21 12:06:18 -0800448 return NewLIR3(cu, kThumb2Vstms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800449}
450
buzbee02031b12012-11-23 09:41:35 -0800451void ArmCodegen::GenMultiplyByTwoBitMultiplier(CompilationUnit* cu, RegLocation rl_src,
452 RegLocation rl_result, int lit,
453 int first_bit, int second_bit)
buzbeeefc63692012-11-14 16:31:52 -0800454{
buzbeefa57c472012-11-21 12:06:18 -0800455 OpRegRegRegShift(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg,
456 EncodeShift(kArmLsl, second_bit - first_bit));
457 if (first_bit != 0) {
458 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
buzbeeefc63692012-11-14 16:31:52 -0800459 }
460}
461
buzbee02031b12012-11-23 09:41:35 -0800462void ArmCodegen::GenDivZeroCheck(CompilationUnit* cu, int reg_lo, int reg_hi)
buzbeeefc63692012-11-14 16:31:52 -0800463{
buzbeefa57c472012-11-21 12:06:18 -0800464 int t_reg = AllocTemp(cu);
465 NewLIR4(cu, kThumb2OrrRRRs, t_reg, reg_lo, reg_hi, 0);
466 FreeTemp(cu, t_reg);
467 GenCheck(cu, kCondEq, kThrowDivZero);
buzbeeefc63692012-11-14 16:31:52 -0800468}
469
470// Test suspend flag, return target of taken suspend branch
buzbee02031b12012-11-23 09:41:35 -0800471LIR* ArmCodegen::OpTestSuspend(CompilationUnit* cu, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800472{
buzbeefa57c472012-11-21 12:06:18 -0800473 NewLIR2(cu, kThumbSubRI8, rARM_SUSPEND, 1);
474 return OpCondBranch(cu, (target == NULL) ? kCondEq : kCondNe, target);
buzbeeefc63692012-11-14 16:31:52 -0800475}
476
477// Decrement register and branch on condition
buzbee02031b12012-11-23 09:41:35 -0800478LIR* ArmCodegen::OpDecAndBranch(CompilationUnit* cu, ConditionCode c_code, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800479{
480 // Combine sub & test using sub setflags encoding here
buzbeefa57c472012-11-21 12:06:18 -0800481 NewLIR3(cu, kThumb2SubsRRI12, reg, reg, 1);
482 return OpCondBranch(cu, c_code, target);
buzbeeefc63692012-11-14 16:31:52 -0800483}
484
buzbee02031b12012-11-23 09:41:35 -0800485void ArmCodegen::GenMemBarrier(CompilationUnit* cu, MemBarrierKind barrier_kind)
buzbeeefc63692012-11-14 16:31:52 -0800486{
487#if ANDROID_SMP != 0
buzbeefa57c472012-11-21 12:06:18 -0800488 int dmb_flavor;
buzbee1bc37c62012-11-20 13:35:41 -0800489 // TODO: revisit Arm barrier kinds
buzbeefa57c472012-11-21 12:06:18 -0800490 switch (barrier_kind) {
491 case kLoadStore: dmb_flavor = kSY; break;
492 case kLoadLoad: dmb_flavor = kSY; break;
493 case kStoreStore: dmb_flavor = kST; break;
494 case kStoreLoad: dmb_flavor = kSY; break;
buzbee1bc37c62012-11-20 13:35:41 -0800495 default:
buzbeefa57c472012-11-21 12:06:18 -0800496 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
497 dmb_flavor = kSY; // quiet gcc.
buzbee1bc37c62012-11-20 13:35:41 -0800498 break;
499 }
buzbeefa57c472012-11-21 12:06:18 -0800500 LIR* dmb = NewLIR1(cu, kThumb2Dmb, dmb_flavor);
501 dmb->def_mask = ENCODE_ALL;
buzbeeefc63692012-11-14 16:31:52 -0800502#endif
503}
504
buzbee02031b12012-11-23 09:41:35 -0800505bool ArmCodegen::GenNegLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800506{
buzbeefa57c472012-11-21 12:06:18 -0800507 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
508 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
509 int z_reg = AllocTemp(cu);
510 LoadConstantNoClobber(cu, z_reg, 0);
buzbeeefc63692012-11-14 16:31:52 -0800511 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -0800512 if (rl_result.low_reg == rl_src.high_reg) {
513 int t_reg = AllocTemp(cu);
514 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
515 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, t_reg);
516 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800517 } else {
buzbeefa57c472012-11-21 12:06:18 -0800518 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
519 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, rl_src.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800520 }
buzbeefa57c472012-11-21 12:06:18 -0800521 FreeTemp(cu, z_reg);
522 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800523 return false;
524}
525
buzbee02031b12012-11-23 09:41:35 -0800526bool ArmCodegen::GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
527 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800528{
buzbee52a77fc2012-11-20 19:50:46 -0800529 LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800530 return false;
531}
532
buzbee02031b12012-11-23 09:41:35 -0800533bool ArmCodegen::GenSubLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
534 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800535{
buzbee52a77fc2012-11-20 19:50:46 -0800536 LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800537 return false;
538}
539
buzbee02031b12012-11-23 09:41:35 -0800540bool ArmCodegen::GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
541 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800542{
buzbee52a77fc2012-11-20 19:50:46 -0800543 LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800544 return false;
545}
546
buzbee02031b12012-11-23 09:41:35 -0800547bool ArmCodegen::GenOrLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
548 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800549{
buzbee52a77fc2012-11-20 19:50:46 -0800550 LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800551 return false;
552}
553
buzbee02031b12012-11-23 09:41:35 -0800554bool ArmCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
555 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800556{
557 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
558 return false;
559}
560
buzbeee6285f92012-12-06 15:57:46 -0800561/*
562 * Generate array load
563 */
564void ArmCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
565 RegLocation rl_index, RegLocation rl_dest, int scale)
566{
567 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800568 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800569 int data_offset;
570 RegLocation rl_result;
571 rl_array = LoadValue(cu, rl_array, kCoreReg);
572 rl_index = LoadValue(cu, rl_index, kCoreReg);
573
574 if (rl_dest.wide) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800575 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800576 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800577 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800578 }
579
580 /* null object? */
581 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
582
583 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
584 int reg_len = INVALID_REG;
585 if (needs_range_check) {
586 reg_len = AllocTemp(cu);
587 /* Get len */
588 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
589 }
590 if (rl_dest.wide || rl_dest.fp) {
591 // No special indexed operation, lea + load w/ displacement
592 int reg_ptr = AllocTemp(cu);
593 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
594 EncodeShift(kArmLsl, scale));
595 FreeTemp(cu, rl_index.low_reg);
596 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
597
598 if (needs_range_check) {
599 // TODO: change kCondCS to a more meaningful name, is the sense of
600 // carry-set/clear flipped?
601 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
602 FreeTemp(cu, reg_len);
603 }
604 if (rl_dest.wide) {
605 LoadBaseDispWide(cu, reg_ptr, data_offset, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
606 FreeTemp(cu, reg_ptr);
607 StoreValueWide(cu, rl_dest, rl_result);
608 } else {
609 LoadBaseDisp(cu, reg_ptr, data_offset, rl_result.low_reg, size, INVALID_SREG);
610 FreeTemp(cu, reg_ptr);
611 StoreValue(cu, rl_dest, rl_result);
612 }
613 } else {
614 // Offset base, then use indexed load
615 int reg_ptr = AllocTemp(cu);
616 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
617 FreeTemp(cu, rl_array.low_reg);
618 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
619
620 if (needs_range_check) {
621 // TODO: change kCondCS to a more meaningful name, is the sense of
622 // carry-set/clear flipped?
623 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
624 FreeTemp(cu, reg_len);
625 }
626 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
627 FreeTemp(cu, reg_ptr);
628 StoreValue(cu, rl_dest, rl_result);
629 }
630}
631
632/*
633 * Generate array store
634 *
635 */
636void ArmCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
637 RegLocation rl_index, RegLocation rl_src, int scale)
638{
639 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800640 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800641 int data_offset;
642
643 if (size == kLong || size == kDouble) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800644 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800645 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800646 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800647 }
648
649 rl_array = LoadValue(cu, rl_array, kCoreReg);
650 rl_index = LoadValue(cu, rl_index, kCoreReg);
651 int reg_ptr = INVALID_REG;
652 if (IsTemp(cu, rl_array.low_reg)) {
653 Clobber(cu, rl_array.low_reg);
654 reg_ptr = rl_array.low_reg;
655 } else {
656 reg_ptr = AllocTemp(cu);
657 }
658
659 /* null object? */
660 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
661
662 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
663 int reg_len = INVALID_REG;
664 if (needs_range_check) {
665 reg_len = AllocTemp(cu);
666 //NOTE: max live temps(4) here.
667 /* Get len */
668 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
669 }
670 /* at this point, reg_ptr points to array, 2 live temps */
671 if (rl_src.wide || rl_src.fp) {
672 if (rl_src.wide) {
673 rl_src = LoadValueWide(cu, rl_src, reg_class);
674 } else {
675 rl_src = LoadValue(cu, rl_src, reg_class);
676 }
677 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
678 EncodeShift(kArmLsl, scale));
679 if (needs_range_check) {
680 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
681 FreeTemp(cu, reg_len);
682 }
683 if (rl_src.wide) {
684 StoreBaseDispWide(cu, reg_ptr, data_offset, rl_src.low_reg, rl_src.high_reg);
685 } else {
686 StoreBaseDisp(cu, reg_ptr, data_offset, rl_src.low_reg, size);
687 }
688 } else {
689 /* reg_ptr -> array data */
690 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
691 rl_src = LoadValue(cu, rl_src, reg_class);
692 if (needs_range_check) {
693 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
694 FreeTemp(cu, reg_len);
695 }
696 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
697 scale, size);
698 }
699 FreeTemp(cu, reg_ptr);
700}
701
702/*
703 * Generate array store
704 *
705 */
706void ArmCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
707 RegLocation rl_index, RegLocation rl_src, int scale)
708{
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800709 int len_offset = mirror::Array::LengthOffset().Int32Value();
710 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800711
712 FlushAllRegs(cu); // Use explicit registers
713 LockCallTemps(cu);
714
715 int r_value = TargetReg(kArg0); // Register holding value
716 int r_array_class = TargetReg(kArg1); // Register holding array's Class
717 int r_array = TargetReg(kArg2); // Register holding array
718 int r_index = TargetReg(kArg3); // Register holding index into array
719
720 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
721 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
722 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
723
724 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
725
726 // Store of null?
727 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
728
729 // Get the array's class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800730 LoadWordDisp(cu, r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
buzbeee6285f92012-12-06 15:57:46 -0800731 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
732 r_array_class, true);
733 // Redo LoadValues in case they didn't survive the call.
734 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
735 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
736 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
737 r_array_class = INVALID_REG;
738
739 // Branch here if value to be stored == null
740 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
741 null_value_check->target = target;
742
743 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
744 int reg_len = INVALID_REG;
745 if (needs_range_check) {
746 reg_len = TargetReg(kArg1);
747 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
748 }
749 /* r_ptr -> array data */
750 int r_ptr = AllocTemp(cu);
751 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
752 if (needs_range_check) {
753 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
754 }
755 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
756 FreeTemp(cu, r_ptr);
757 FreeTemp(cu, r_index);
758 MarkGCCard(cu, r_value, r_array);
759}
760
buzbeeefc63692012-11-14 16:31:52 -0800761} // namespace art