blob: fbc48d45b36c4fd23b9f38bd531f146357809bbd [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
buzbee1bc37c62012-11-20 13:35:41 -080019#include "arm_lir.h"
buzbee02031b12012-11-23 09:41:35 -080020#include "codegen_arm.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080021#include "compiler/codegen/codegen_util.h"
22#include "compiler/codegen/ralloc_util.h"
23#include "oat/runtime/oat_support_entrypoints.h"
24#include "oat_compilation_unit.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
buzbee4ef3e452012-12-14 13:35:28 -0800124void ArmCodegen::GenFusedLongCmpImmBranch(CompilationUnit* cu, BasicBlock* bb, RegLocation rl_src1,
125 int64_t val, ConditionCode ccode)
buzbeeefc63692012-11-14 16:31:52 -0800126{
buzbee4ef3e452012-12-14 13:35:28 -0800127 int32_t val_lo = Low32Bits(val);
128 int32_t val_hi = High32Bits(val);
129 DCHECK(ModifiedImmediate(val_lo) >= 0);
130 DCHECK(ModifiedImmediate(val_hi) >= 0);
buzbeefa57c472012-11-21 12:06:18 -0800131 LIR* label_list = cu->block_label_list;
132 LIR* taken = &label_list[bb->taken->id];
133 LIR* not_taken = &label_list[bb->fall_through->id];
buzbee4ef3e452012-12-14 13:35:28 -0800134 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
135 int32_t low_reg = rl_src1.low_reg;
136 int32_t high_reg = rl_src1.high_reg;
137
138 switch(ccode) {
139 case kCondEq:
buzbee4ef3e452012-12-14 13:35:28 -0800140 case kCondNe:
buzbeec7d1f912013-02-07 15:22:39 -0800141 LIR* target;
142 ConditionCode condition;
143 if (ccode == kCondEq) {
144 target = not_taken;
145 condition = kCondEq;
146 } else {
147 target = taken;
148 condition = kCondNe;
149 }
150 if (val == 0) {
151 int t_reg = AllocTemp(cu);
152 NewLIR4(cu, kThumb2OrrRRRs, t_reg, low_reg, high_reg, 0);
153 FreeTemp(cu, t_reg);
154 OpCondBranch(cu, condition, taken);
155 return;
156 }
157 OpCmpImmBranch(cu, kCondNe, high_reg, val_hi, target);
buzbee4ef3e452012-12-14 13:35:28 -0800158 break;
159 case kCondLt:
160 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, taken);
161 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, not_taken);
162 ccode = kCondCc;
163 break;
164 case kCondLe:
165 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, taken);
166 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, not_taken);
167 ccode = kCondLs;
168 break;
169 case kCondGt:
170 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, taken);
171 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, not_taken);
172 ccode = kCondHi;
173 break;
174 case kCondGe:
175 OpCmpImmBranch(cu, kCondGt, high_reg, val_hi, taken);
176 OpCmpImmBranch(cu, kCondLt, high_reg, val_hi, not_taken);
177 ccode = kCondCs;
178 break;
179 default:
180 LOG(FATAL) << "Unexpected ccode: " << ccode;
181 }
182 OpCmpImmBranch(cu, ccode, low_reg, val_lo, taken);
183}
184
185
186void ArmCodegen::GenFusedLongCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
187{
buzbeefa57c472012-11-21 12:06:18 -0800188 RegLocation rl_src1 = GetSrcWide(cu, mir, 0);
189 RegLocation rl_src2 = GetSrcWide(cu, mir, 2);
buzbee4ef3e452012-12-14 13:35:28 -0800190 // Normalize such that if either operand is constant, src2 will be constant.
191 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
192 if (rl_src1.is_const) {
193 RegLocation rl_temp = rl_src1;
194 rl_src1 = rl_src2;
195 rl_src2 = rl_temp;
196 ccode = FlipComparisonOrder(ccode);
197 }
198 if (rl_src2.is_const) {
199 RegLocation rl_temp = UpdateLocWide(cu, rl_src2);
200 // Do special compare/branch against simple const operand if not already in registers.
201 int64_t val = ConstantValueWide(cu, rl_src2);
202 if ((rl_temp.location != kLocPhysReg) &&
203 ((ModifiedImmediate(Low32Bits(val)) >= 0) && (ModifiedImmediate(High32Bits(val)) >= 0))) {
204 GenFusedLongCmpImmBranch(cu, bb, rl_src1, val, ccode);
205 return;
206 }
207 }
208 LIR* label_list = cu->block_label_list;
209 LIR* taken = &label_list[bb->taken->id];
210 LIR* not_taken = &label_list[bb->fall_through->id];
buzbeefa57c472012-11-21 12:06:18 -0800211 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
212 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800213 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800214 switch(ccode) {
215 case kCondEq:
buzbeefa57c472012-11-21 12:06:18 -0800216 OpCondBranch(cu, kCondNe, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800217 break;
218 case kCondNe:
buzbeefa57c472012-11-21 12:06:18 -0800219 OpCondBranch(cu, kCondNe, taken);
buzbeeefc63692012-11-14 16:31:52 -0800220 break;
221 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800222 OpCondBranch(cu, kCondLt, taken);
223 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800224 ccode = kCondCc;
225 break;
226 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800227 OpCondBranch(cu, kCondLt, taken);
228 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800229 ccode = kCondLs;
230 break;
231 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800232 OpCondBranch(cu, kCondGt, taken);
233 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800234 ccode = kCondHi;
235 break;
236 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800237 OpCondBranch(cu, kCondGt, taken);
238 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800239 ccode = kCondCs;
240 break;
241 default:
buzbeecbd6d442012-11-17 14:11:25 -0800242 LOG(FATAL) << "Unexpected ccode: " << ccode;
buzbeeefc63692012-11-14 16:31:52 -0800243 }
buzbeefa57c472012-11-21 12:06:18 -0800244 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
245 OpCondBranch(cu, ccode, taken);
buzbeeefc63692012-11-14 16:31:52 -0800246}
247
248/*
249 * Generate a register comparison to an immediate and branch. Caller
250 * is responsible for setting branch target field.
251 */
buzbee02031b12012-11-23 09:41:35 -0800252LIR* ArmCodegen::OpCmpImmBranch(CompilationUnit* cu, ConditionCode cond, int reg, int check_value,
253 LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800254{
255 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -0800256 int mod_imm;
257 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
258 if ((ARM_LOWREG(reg)) && (check_value == 0) &&
259 ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
260 branch = NewLIR2(cu, (arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
buzbeeefc63692012-11-14 16:31:52 -0800261 reg, 0);
262 } else {
buzbeefa57c472012-11-21 12:06:18 -0800263 mod_imm = ModifiedImmediate(check_value);
264 if (ARM_LOWREG(reg) && ((check_value & 0xff) == check_value)) {
265 NewLIR2(cu, kThumbCmpRI8, reg, check_value);
266 } else if (mod_imm >= 0) {
buzbee4ef3e452012-12-14 13:35:28 -0800267 NewLIR2(cu, kThumb2CmpRI12, reg, mod_imm);
buzbeeefc63692012-11-14 16:31:52 -0800268 } else {
buzbeefa57c472012-11-21 12:06:18 -0800269 int t_reg = AllocTemp(cu);
270 LoadConstant(cu, t_reg, check_value);
271 OpRegReg(cu, kOpCmp, reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800272 }
buzbeefa57c472012-11-21 12:06:18 -0800273 branch = NewLIR2(cu, kThumbBCond, 0, arm_cond);
buzbeeefc63692012-11-14 16:31:52 -0800274 }
275 branch->target = target;
276 return branch;
277}
buzbee02031b12012-11-23 09:41:35 -0800278
279LIR* ArmCodegen::OpRegCopyNoInsert(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800280{
281 LIR* res;
282 int opcode;
buzbeefa57c472012-11-21 12:06:18 -0800283 if (ARM_FPREG(r_dest) || ARM_FPREG(r_src))
buzbee02031b12012-11-23 09:41:35 -0800284 return OpFpRegCopy(cu, r_dest, r_src);
buzbeefa57c472012-11-21 12:06:18 -0800285 if (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800286 opcode = kThumbMovRR;
buzbeefa57c472012-11-21 12:06:18 -0800287 else if (!ARM_LOWREG(r_dest) && !ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800288 opcode = kThumbMovRR_H2H;
buzbeefa57c472012-11-21 12:06:18 -0800289 else if (ARM_LOWREG(r_dest))
buzbeeefc63692012-11-14 16:31:52 -0800290 opcode = kThumbMovRR_H2L;
291 else
292 opcode = kThumbMovRR_L2H;
buzbeefa57c472012-11-21 12:06:18 -0800293 res = RawLIR(cu, cu->current_dalvik_offset, opcode, r_dest, r_src);
294 if (!(cu->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
295 res->flags.is_nop = true;
buzbeeefc63692012-11-14 16:31:52 -0800296 }
297 return res;
298}
299
buzbee02031b12012-11-23 09:41:35 -0800300LIR* ArmCodegen::OpRegCopy(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800301{
buzbeefa57c472012-11-21 12:06:18 -0800302 LIR* res = OpRegCopyNoInsert(cu, r_dest, r_src);
303 AppendLIR(cu, res);
buzbeeefc63692012-11-14 16:31:52 -0800304 return res;
305}
306
buzbee02031b12012-11-23 09:41:35 -0800307void ArmCodegen::OpRegCopyWide(CompilationUnit* cu, int dest_lo, int dest_hi, int src_lo,
308 int src_hi)
buzbeeefc63692012-11-14 16:31:52 -0800309{
buzbeefa57c472012-11-21 12:06:18 -0800310 bool dest_fp = ARM_FPREG(dest_lo) && ARM_FPREG(dest_hi);
311 bool src_fp = ARM_FPREG(src_lo) && ARM_FPREG(src_hi);
312 DCHECK_EQ(ARM_FPREG(src_lo), ARM_FPREG(src_hi));
313 DCHECK_EQ(ARM_FPREG(dest_lo), ARM_FPREG(dest_hi));
314 if (dest_fp) {
315 if (src_fp) {
316 OpRegCopy(cu, S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800317 } else {
buzbeefa57c472012-11-21 12:06:18 -0800318 NewLIR3(cu, kThumb2Fmdrr, S2d(dest_lo, dest_hi), src_lo, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800319 }
320 } else {
buzbeefa57c472012-11-21 12:06:18 -0800321 if (src_fp) {
322 NewLIR3(cu, kThumb2Fmrrd, dest_lo, dest_hi, S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800323 } else {
324 // Handle overlap
buzbeefa57c472012-11-21 12:06:18 -0800325 if (src_hi == dest_lo) {
326 OpRegCopy(cu, dest_hi, src_hi);
327 OpRegCopy(cu, dest_lo, src_lo);
buzbeeefc63692012-11-14 16:31:52 -0800328 } else {
buzbeefa57c472012-11-21 12:06:18 -0800329 OpRegCopy(cu, dest_lo, src_lo);
330 OpRegCopy(cu, dest_hi, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800331 }
332 }
333 }
334}
335
336// Table of magic divisors
buzbeeefc63692012-11-14 16:31:52 -0800337struct MagicTable {
338 uint32_t magic;
339 uint32_t shift;
340 DividePattern pattern;
341};
342
buzbeefa57c472012-11-21 12:06:18 -0800343static const MagicTable magic_table[] = {
buzbeeefc63692012-11-14 16:31:52 -0800344 {0, 0, DivideNone}, // 0
345 {0, 0, DivideNone}, // 1
346 {0, 0, DivideNone}, // 2
347 {0x55555556, 0, Divide3}, // 3
348 {0, 0, DivideNone}, // 4
349 {0x66666667, 1, Divide5}, // 5
350 {0x2AAAAAAB, 0, Divide3}, // 6
351 {0x92492493, 2, Divide7}, // 7
352 {0, 0, DivideNone}, // 8
353 {0x38E38E39, 1, Divide5}, // 9
354 {0x66666667, 2, Divide5}, // 10
355 {0x2E8BA2E9, 1, Divide5}, // 11
356 {0x2AAAAAAB, 1, Divide5}, // 12
357 {0x4EC4EC4F, 2, Divide5}, // 13
358 {0x92492493, 3, Divide7}, // 14
359 {0x88888889, 3, Divide7}, // 15
360};
361
362// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
buzbee02031b12012-11-23 09:41:35 -0800363bool ArmCodegen::SmallLiteralDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
364 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbeeefc63692012-11-14 16:31:52 -0800365{
buzbeefa57c472012-11-21 12:06:18 -0800366 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
buzbeeefc63692012-11-14 16:31:52 -0800367 return false;
368 }
buzbeefa57c472012-11-21 12:06:18 -0800369 DividePattern pattern = magic_table[lit].pattern;
buzbeeefc63692012-11-14 16:31:52 -0800370 if (pattern == DivideNone) {
371 return false;
372 }
373 // Tuning: add rem patterns
buzbeefa57c472012-11-21 12:06:18 -0800374 if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
buzbeeefc63692012-11-14 16:31:52 -0800375 return false;
376 }
377
buzbeefa57c472012-11-21 12:06:18 -0800378 int r_magic = AllocTemp(cu);
379 LoadConstant(cu, r_magic, magic_table[lit].magic);
380 rl_src = LoadValue(cu, rl_src, kCoreReg);
381 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
382 int r_hi = AllocTemp(cu);
383 int r_lo = AllocTemp(cu);
384 NewLIR4(cu, kThumb2Smull, r_lo, r_hi, r_magic, rl_src.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800385 switch(pattern) {
386 case Divide3:
buzbeefa57c472012-11-21 12:06:18 -0800387 OpRegRegRegShift(cu, kOpSub, rl_result.low_reg, r_hi,
388 rl_src.low_reg, EncodeShift(kArmAsr, 31));
buzbeeefc63692012-11-14 16:31:52 -0800389 break;
390 case Divide5:
buzbeefa57c472012-11-21 12:06:18 -0800391 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
392 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
393 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800394 break;
395 case Divide7:
buzbeefa57c472012-11-21 12:06:18 -0800396 OpRegReg(cu, kOpAdd, r_hi, rl_src.low_reg);
397 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
398 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
399 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800400 break;
401 default:
buzbeecbd6d442012-11-17 14:11:25 -0800402 LOG(FATAL) << "Unexpected pattern: " << pattern;
buzbeeefc63692012-11-14 16:31:52 -0800403 }
buzbeefa57c472012-11-21 12:06:18 -0800404 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800405 return true;
406}
407
buzbee02031b12012-11-23 09:41:35 -0800408LIR* ArmCodegen::GenRegMemCheck(CompilationUnit* cu, ConditionCode c_code,
buzbeeefc63692012-11-14 16:31:52 -0800409 int reg1, int base, int offset, ThrowKind kind)
410{
buzbee52a77fc2012-11-20 19:50:46 -0800411 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800412 return NULL;
413}
414
buzbee02031b12012-11-23 09:41:35 -0800415RegLocation ArmCodegen::GenDivRemLit(CompilationUnit* cu, RegLocation rl_dest, int reg1, int lit,
416 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800417{
buzbee52a77fc2012-11-20 19:50:46 -0800418 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800419 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800420}
421
buzbee02031b12012-11-23 09:41:35 -0800422RegLocation ArmCodegen::GenDivRem(CompilationUnit* cu, RegLocation rl_dest, int reg1, int reg2,
423 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800424{
buzbee52a77fc2012-11-20 19:50:46 -0800425 LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800426 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800427}
428
buzbee02031b12012-11-23 09:41:35 -0800429bool ArmCodegen::GenInlinedMinMaxInt(CompilationUnit *cu, CallInfo* info, bool is_min)
buzbeeefc63692012-11-14 16:31:52 -0800430{
buzbeefa57c472012-11-21 12:06:18 -0800431 DCHECK_EQ(cu->instruction_set, kThumb2);
432 RegLocation rl_src1 = info->args[0];
433 RegLocation rl_src2 = info->args[1];
434 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
435 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
436 RegLocation rl_dest = InlineTarget(cu, info);
437 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
438 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
buzbee02031b12012-11-23 09:41:35 -0800439 OpIT(cu, (is_min) ? kCondGt : kCondLt, "E");
buzbeefa57c472012-11-21 12:06:18 -0800440 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src2.low_reg);
441 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src1.low_reg);
442 GenBarrier(cu);
443 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800444 return true;
445}
446
buzbee02031b12012-11-23 09:41:35 -0800447void ArmCodegen::OpLea(CompilationUnit* cu, int rBase, int reg1, int reg2, int scale, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800448{
buzbee52a77fc2012-11-20 19:50:46 -0800449 LOG(FATAL) << "Unexpected use of OpLea for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800450}
451
buzbee02031b12012-11-23 09:41:35 -0800452void ArmCodegen::OpTlsCmp(CompilationUnit* cu, int offset, int val)
buzbeeefc63692012-11-14 16:31:52 -0800453{
buzbee52a77fc2012-11-20 19:50:46 -0800454 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800455}
456
buzbee02031b12012-11-23 09:41:35 -0800457bool ArmCodegen::GenInlinedCas32(CompilationUnit* cu, CallInfo* info, bool need_write_barrier) {
buzbeefa57c472012-11-21 12:06:18 -0800458 DCHECK_EQ(cu->instruction_set, kThumb2);
459 // Unused - RegLocation rl_src_unsafe = info->args[0];
460 RegLocation rl_src_obj= info->args[1]; // Object - known non-null
461 RegLocation rl_src_offset= info->args[2]; // long low
462 rl_src_offset.wide = 0; // ignore high half in info->args[3]
463 RegLocation rl_src_expected= info->args[4]; // int or Object
464 RegLocation rl_src_new_value= info->args[5]; // int or Object
465 RegLocation rl_dest = InlineTarget(cu, info); // boolean place for result
buzbeeefc63692012-11-14 16:31:52 -0800466
467
buzbee1bc37c62012-11-20 13:35:41 -0800468 // Release store semantics, get the barrier out of the way. TODO: revisit
buzbeefa57c472012-11-21 12:06:18 -0800469 GenMemBarrier(cu, kStoreLoad);
buzbeeefc63692012-11-14 16:31:52 -0800470
buzbeefa57c472012-11-21 12:06:18 -0800471 RegLocation rl_object = LoadValue(cu, rl_src_obj, kCoreReg);
472 RegLocation rl_new_value = LoadValue(cu, rl_src_new_value, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800473
buzbee6a791b22013-02-07 05:35:08 -0800474 if (need_write_barrier && !IsConstantNullRef(cu, rl_new_value)) {
buzbeeefc63692012-11-14 16:31:52 -0800475 // Mark card for object assuming new value is stored.
buzbeefa57c472012-11-21 12:06:18 -0800476 MarkGCCard(cu, rl_new_value.low_reg, rl_object.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800477 }
478
buzbeefa57c472012-11-21 12:06:18 -0800479 RegLocation rl_offset = LoadValue(cu, rl_src_offset, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800480
buzbeefa57c472012-11-21 12:06:18 -0800481 int r_ptr = AllocTemp(cu);
482 OpRegRegReg(cu, kOpAdd, r_ptr, rl_object.low_reg, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800483
buzbeefa57c472012-11-21 12:06:18 -0800484 // Free now unneeded rl_object and rl_offset to give more temps.
485 ClobberSReg(cu, rl_object.s_reg_low);
486 FreeTemp(cu, rl_object.low_reg);
487 ClobberSReg(cu, rl_offset.s_reg_low);
488 FreeTemp(cu, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800489
buzbeefa57c472012-11-21 12:06:18 -0800490 int r_old_value = AllocTemp(cu);
491 NewLIR3(cu, kThumb2Ldrex, r_old_value, r_ptr, 0); // r_old_value := [r_ptr]
buzbeeefc63692012-11-14 16:31:52 -0800492
buzbeefa57c472012-11-21 12:06:18 -0800493 RegLocation rl_expected = LoadValue(cu, rl_src_expected, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800494
buzbeefa57c472012-11-21 12:06:18 -0800495 // if (r_old_value == rExpected) {
496 // [r_ptr] <- r_new_value && r_result := success ? 0 : 1
497 // r_result ^= 1
buzbeeefc63692012-11-14 16:31:52 -0800498 // } else {
buzbeefa57c472012-11-21 12:06:18 -0800499 // r_result := 0
buzbeeefc63692012-11-14 16:31:52 -0800500 // }
buzbeefa57c472012-11-21 12:06:18 -0800501 OpRegReg(cu, kOpCmp, r_old_value, rl_expected.low_reg);
502 FreeTemp(cu, r_old_value); // Now unneeded.
503 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbee02031b12012-11-23 09:41:35 -0800504 OpIT(cu, kCondEq, "TE");
buzbeefa57c472012-11-21 12:06:18 -0800505 NewLIR4(cu, kThumb2Strex, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
506 FreeTemp(cu, r_ptr); // Now unneeded.
507 OpRegImm(cu, kOpXor, rl_result.low_reg, 1);
508 OpRegReg(cu, kOpXor, rl_result.low_reg, rl_result.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800509
buzbeefa57c472012-11-21 12:06:18 -0800510 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800511
512 return true;
513}
514
buzbee02031b12012-11-23 09:41:35 -0800515LIR* ArmCodegen::OpPcRelLoad(CompilationUnit* cu, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800516{
buzbeefa57c472012-11-21 12:06:18 -0800517 return RawLIR(cu, cu->current_dalvik_offset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800518}
519
buzbee02031b12012-11-23 09:41:35 -0800520LIR* ArmCodegen::OpVldm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800521{
buzbeefa57c472012-11-21 12:06:18 -0800522 return NewLIR3(cu, kThumb2Vldms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800523}
524
buzbee02031b12012-11-23 09:41:35 -0800525LIR* ArmCodegen::OpVstm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800526{
buzbeefa57c472012-11-21 12:06:18 -0800527 return NewLIR3(cu, kThumb2Vstms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800528}
529
buzbee02031b12012-11-23 09:41:35 -0800530void ArmCodegen::GenMultiplyByTwoBitMultiplier(CompilationUnit* cu, RegLocation rl_src,
531 RegLocation rl_result, int lit,
532 int first_bit, int second_bit)
buzbeeefc63692012-11-14 16:31:52 -0800533{
buzbeefa57c472012-11-21 12:06:18 -0800534 OpRegRegRegShift(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg,
535 EncodeShift(kArmLsl, second_bit - first_bit));
536 if (first_bit != 0) {
537 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
buzbeeefc63692012-11-14 16:31:52 -0800538 }
539}
540
buzbee02031b12012-11-23 09:41:35 -0800541void ArmCodegen::GenDivZeroCheck(CompilationUnit* cu, int reg_lo, int reg_hi)
buzbeeefc63692012-11-14 16:31:52 -0800542{
buzbeefa57c472012-11-21 12:06:18 -0800543 int t_reg = AllocTemp(cu);
544 NewLIR4(cu, kThumb2OrrRRRs, t_reg, reg_lo, reg_hi, 0);
545 FreeTemp(cu, t_reg);
546 GenCheck(cu, kCondEq, kThrowDivZero);
buzbeeefc63692012-11-14 16:31:52 -0800547}
548
549// Test suspend flag, return target of taken suspend branch
buzbee02031b12012-11-23 09:41:35 -0800550LIR* ArmCodegen::OpTestSuspend(CompilationUnit* cu, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800551{
buzbeefa57c472012-11-21 12:06:18 -0800552 NewLIR2(cu, kThumbSubRI8, rARM_SUSPEND, 1);
553 return OpCondBranch(cu, (target == NULL) ? kCondEq : kCondNe, target);
buzbeeefc63692012-11-14 16:31:52 -0800554}
555
556// Decrement register and branch on condition
buzbee02031b12012-11-23 09:41:35 -0800557LIR* ArmCodegen::OpDecAndBranch(CompilationUnit* cu, ConditionCode c_code, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800558{
559 // Combine sub & test using sub setflags encoding here
buzbeefa57c472012-11-21 12:06:18 -0800560 NewLIR3(cu, kThumb2SubsRRI12, reg, reg, 1);
561 return OpCondBranch(cu, c_code, target);
buzbeeefc63692012-11-14 16:31:52 -0800562}
563
buzbee02031b12012-11-23 09:41:35 -0800564void ArmCodegen::GenMemBarrier(CompilationUnit* cu, MemBarrierKind barrier_kind)
buzbeeefc63692012-11-14 16:31:52 -0800565{
566#if ANDROID_SMP != 0
buzbeefa57c472012-11-21 12:06:18 -0800567 int dmb_flavor;
buzbee1bc37c62012-11-20 13:35:41 -0800568 // TODO: revisit Arm barrier kinds
buzbeefa57c472012-11-21 12:06:18 -0800569 switch (barrier_kind) {
570 case kLoadStore: dmb_flavor = kSY; break;
571 case kLoadLoad: dmb_flavor = kSY; break;
572 case kStoreStore: dmb_flavor = kST; break;
573 case kStoreLoad: dmb_flavor = kSY; break;
buzbee1bc37c62012-11-20 13:35:41 -0800574 default:
buzbeefa57c472012-11-21 12:06:18 -0800575 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
576 dmb_flavor = kSY; // quiet gcc.
buzbee1bc37c62012-11-20 13:35:41 -0800577 break;
578 }
buzbeefa57c472012-11-21 12:06:18 -0800579 LIR* dmb = NewLIR1(cu, kThumb2Dmb, dmb_flavor);
580 dmb->def_mask = ENCODE_ALL;
buzbeeefc63692012-11-14 16:31:52 -0800581#endif
582}
583
buzbeea5954be2013-02-07 10:41:40 -0800584void ArmCodegen::GenNegLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800585{
buzbeefa57c472012-11-21 12:06:18 -0800586 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
587 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
588 int z_reg = AllocTemp(cu);
589 LoadConstantNoClobber(cu, z_reg, 0);
buzbeeefc63692012-11-14 16:31:52 -0800590 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -0800591 if (rl_result.low_reg == rl_src.high_reg) {
592 int t_reg = AllocTemp(cu);
593 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
594 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, t_reg);
595 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800596 } else {
buzbeefa57c472012-11-21 12:06:18 -0800597 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
598 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, rl_src.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800599 }
buzbeefa57c472012-11-21 12:06:18 -0800600 FreeTemp(cu, z_reg);
601 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800602}
603
buzbee4ef3e452012-12-14 13:35:28 -0800604
605 /*
606 * Check to see if a result pair has a misaligned overlap with an operand pair. This
607 * is not usual for dx to generate, but it is legal (for now). In a future rev of
608 * dex, we'll want to make this case illegal.
609 */
610static bool BadOverlap(CompilationUnit* cu, RegLocation rl_src, RegLocation rl_dest)
611{
612 DCHECK(rl_src.wide);
613 DCHECK(rl_dest.wide);
614 return (abs(SRegToVReg(cu, rl_src.s_reg_low) - SRegToVReg(cu, rl_dest.s_reg_low)) == 1);
615}
616
617void ArmCodegen::GenMulLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
618 RegLocation rl_src2)
619{
620 /*
621 * To pull off inline multiply, we have a worst-case requirement of 8 temporary
622 * registers. Normally for Arm, we get 5. We can get to 6 by including
623 * lr in the temp set. The only problematic case is all operands and result are
624 * distinct, and none have been promoted. In that case, we can succeed by aggressively
625 * freeing operand temp registers after they are no longer needed. All other cases
626 * can proceed normally. We'll just punt on the case of the result having a misaligned
627 * overlap with either operand and send that case to a runtime handler.
628 */
629 RegLocation rl_result;
630 if (BadOverlap(cu, rl_src1, rl_dest) || (BadOverlap(cu, rl_src2, rl_dest))) {
631 int func_offset = ENTRYPOINT_OFFSET(pLmul);
632 FlushAllRegs(cu);
633 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_src2, false);
634 rl_result = GetReturnWide(cu, false);
635 StoreValueWide(cu, rl_dest, rl_result);
636 return;
637 }
638 // Temporarily add LR to the temp pool, and assign it to tmp1
639 MarkTemp(cu, rARM_LR);
640 FreeTemp(cu, rARM_LR);
641 int tmp1 = rARM_LR;
642 LockTemp(cu, rARM_LR);
643
644 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
645 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
646
647 bool special_case = true;
648 // If operands are the same, or any pair has been promoted we're not the special case.
649 if ((rl_src1.s_reg_low == rl_src2.s_reg_low) ||
650 (!IsTemp(cu, rl_src1.low_reg) && !IsTemp(cu, rl_src1.high_reg)) ||
651 (!IsTemp(cu, rl_src2.low_reg) && !IsTemp(cu, rl_src2.high_reg))) {
652 special_case = false;
653 }
654 // Tuning: if rl_dest has been promoted and is *not* either operand, could use directly.
655 int res_lo = AllocTemp(cu);
656 int res_hi;
657 if (rl_src1.low_reg == rl_src2.low_reg) {
658 res_hi = AllocTemp(cu);
659 NewLIR3(cu, kThumb2MulRRR, tmp1, rl_src1.low_reg, rl_src1.high_reg);
660 NewLIR4(cu, kThumb2Umull, res_lo, res_hi, rl_src1.low_reg, rl_src1.low_reg);
661 OpRegRegRegShift(cu, kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1));
662 } else {
663 // In the special case, all temps are now allocated
664 NewLIR3(cu, kThumb2MulRRR, tmp1, rl_src2.low_reg, rl_src1.high_reg);
665 if (special_case) {
666 DCHECK_NE(rl_src1.low_reg, rl_src2.low_reg);
667 DCHECK_NE(rl_src1.high_reg, rl_src2.high_reg);
668 FreeTemp(cu, rl_src1.high_reg);
669 }
670 res_hi = AllocTemp(cu);
671
672 NewLIR4(cu, kThumb2Umull, res_lo, res_hi, rl_src2.low_reg, rl_src1.low_reg);
673 NewLIR4(cu, kThumb2Mla, tmp1, rl_src1.low_reg, rl_src2.high_reg, tmp1);
674 NewLIR4(cu, kThumb2AddRRR, res_hi, tmp1, res_hi, 0);
675 if (special_case) {
676 FreeTemp(cu, rl_src1.low_reg);
677 Clobber(cu, rl_src1.low_reg);
678 Clobber(cu, rl_src1.high_reg);
679 }
680 }
681 FreeTemp(cu, tmp1);
682 rl_result = GetReturnWide(cu, false); // Just using as a template.
683 rl_result.low_reg = res_lo;
684 rl_result.high_reg = res_hi;
685 StoreValueWide(cu, rl_dest, rl_result);
686 // Now, restore lr to its non-temp status.
687 Clobber(cu, rARM_LR);
688 UnmarkTemp(cu, rARM_LR);
689}
690
buzbeea5954be2013-02-07 10:41:40 -0800691void ArmCodegen::GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800692 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800693{
buzbee52a77fc2012-11-20 19:50:46 -0800694 LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800695}
696
buzbeea5954be2013-02-07 10:41:40 -0800697void ArmCodegen::GenSubLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800698 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800699{
buzbee52a77fc2012-11-20 19:50:46 -0800700 LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800701}
702
buzbeea5954be2013-02-07 10:41:40 -0800703void ArmCodegen::GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800704 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800705{
buzbee52a77fc2012-11-20 19:50:46 -0800706 LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800707}
708
buzbeea5954be2013-02-07 10:41:40 -0800709void ArmCodegen::GenOrLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800710 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800711{
buzbee52a77fc2012-11-20 19:50:46 -0800712 LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800713}
714
buzbeea5954be2013-02-07 10:41:40 -0800715void ArmCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800716 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800717{
718 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800719}
720
buzbeee6285f92012-12-06 15:57:46 -0800721/*
722 * Generate array load
723 */
724void ArmCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
725 RegLocation rl_index, RegLocation rl_dest, int scale)
726{
727 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800728 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800729 int data_offset;
730 RegLocation rl_result;
buzbee4ef3e452012-12-14 13:35:28 -0800731 bool constant_index = rl_index.is_const;
buzbeee6285f92012-12-06 15:57:46 -0800732 rl_array = LoadValue(cu, rl_array, kCoreReg);
buzbee4ef3e452012-12-14 13:35:28 -0800733 if (!constant_index) {
734 rl_index = LoadValue(cu, rl_index, kCoreReg);
735 }
buzbeee6285f92012-12-06 15:57:46 -0800736
737 if (rl_dest.wide) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800738 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800739 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800740 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800741 }
742
buzbee4ef3e452012-12-14 13:35:28 -0800743 // If index is constant, just fold it into the data offset
744 if (constant_index) {
745 data_offset += ConstantValue(cu, rl_index) << scale;
746 }
747
buzbeee6285f92012-12-06 15:57:46 -0800748 /* null object? */
749 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
750
751 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
752 int reg_len = INVALID_REG;
753 if (needs_range_check) {
754 reg_len = AllocTemp(cu);
755 /* Get len */
756 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
757 }
buzbee4ef3e452012-12-14 13:35:28 -0800758 if (rl_dest.wide || rl_dest.fp || constant_index) {
759 int reg_ptr;
760 if (constant_index) {
761 reg_ptr = rl_array.low_reg; // NOTE: must not alter reg_ptr in constant case.
762 } else {
763 // No special indexed operation, lea + load w/ displacement
764 reg_ptr = AllocTemp(cu);
765 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
766 EncodeShift(kArmLsl, scale));
767 FreeTemp(cu, rl_index.low_reg);
768 }
buzbeee6285f92012-12-06 15:57:46 -0800769 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
770
771 if (needs_range_check) {
buzbee4ef3e452012-12-14 13:35:28 -0800772 if (constant_index) {
773 GenImmedCheck(cu, kCondLs, reg_len, ConstantValue(cu, rl_index), kThrowConstantArrayBounds);
774 } else {
775 GenRegRegCheck(cu, kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
776 }
buzbeee6285f92012-12-06 15:57:46 -0800777 FreeTemp(cu, reg_len);
778 }
779 if (rl_dest.wide) {
780 LoadBaseDispWide(cu, reg_ptr, data_offset, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
buzbee4ef3e452012-12-14 13:35:28 -0800781 if (!constant_index) {
782 FreeTemp(cu, reg_ptr);
783 }
buzbeee6285f92012-12-06 15:57:46 -0800784 StoreValueWide(cu, rl_dest, rl_result);
785 } else {
786 LoadBaseDisp(cu, reg_ptr, data_offset, rl_result.low_reg, size, INVALID_SREG);
buzbee4ef3e452012-12-14 13:35:28 -0800787 if (!constant_index) {
788 FreeTemp(cu, reg_ptr);
789 }
buzbeee6285f92012-12-06 15:57:46 -0800790 StoreValue(cu, rl_dest, rl_result);
791 }
792 } else {
793 // Offset base, then use indexed load
794 int reg_ptr = AllocTemp(cu);
795 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
796 FreeTemp(cu, rl_array.low_reg);
797 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
798
799 if (needs_range_check) {
800 // TODO: change kCondCS to a more meaningful name, is the sense of
801 // carry-set/clear flipped?
802 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
803 FreeTemp(cu, reg_len);
804 }
805 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
806 FreeTemp(cu, reg_ptr);
807 StoreValue(cu, rl_dest, rl_result);
808 }
809}
810
811/*
812 * Generate array store
813 *
814 */
815void ArmCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
816 RegLocation rl_index, RegLocation rl_src, int scale)
817{
818 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800819 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800820 int data_offset;
buzbee4ef3e452012-12-14 13:35:28 -0800821 bool constant_index = rl_index.is_const;
buzbeee6285f92012-12-06 15:57:46 -0800822
buzbee4ef3e452012-12-14 13:35:28 -0800823 if (rl_src.wide) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800824 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800825 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800826 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800827 }
828
buzbee4ef3e452012-12-14 13:35:28 -0800829 // If index is constant, just fold it into the data offset.
830 if (constant_index) {
831 data_offset += ConstantValue(cu, rl_index) << scale;
832 }
833
buzbeee6285f92012-12-06 15:57:46 -0800834 rl_array = LoadValue(cu, rl_array, kCoreReg);
buzbee4ef3e452012-12-14 13:35:28 -0800835 if (!constant_index) {
836 rl_index = LoadValue(cu, rl_index, kCoreReg);
837 }
838
839 int reg_ptr;
840 if (constant_index) {
841 reg_ptr = rl_array.low_reg;
842 } else if (IsTemp(cu, rl_array.low_reg)) {
buzbeee6285f92012-12-06 15:57:46 -0800843 Clobber(cu, rl_array.low_reg);
844 reg_ptr = rl_array.low_reg;
845 } else {
846 reg_ptr = AllocTemp(cu);
847 }
848
849 /* null object? */
850 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
851
852 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
853 int reg_len = INVALID_REG;
854 if (needs_range_check) {
855 reg_len = AllocTemp(cu);
856 //NOTE: max live temps(4) here.
857 /* Get len */
858 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
859 }
860 /* at this point, reg_ptr points to array, 2 live temps */
buzbee4ef3e452012-12-14 13:35:28 -0800861 if (rl_src.wide || rl_src.fp || constant_index) {
buzbeee6285f92012-12-06 15:57:46 -0800862 if (rl_src.wide) {
863 rl_src = LoadValueWide(cu, rl_src, reg_class);
864 } else {
865 rl_src = LoadValue(cu, rl_src, reg_class);
866 }
buzbee4ef3e452012-12-14 13:35:28 -0800867 if (!constant_index) {
868 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
869 EncodeShift(kArmLsl, scale));
870 }
buzbeee6285f92012-12-06 15:57:46 -0800871 if (needs_range_check) {
buzbee4ef3e452012-12-14 13:35:28 -0800872 if (constant_index) {
873 GenImmedCheck(cu, kCondLs, reg_len, ConstantValue(cu, rl_index), kThrowConstantArrayBounds);
874 } else {
875 GenRegRegCheck(cu, kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
876 }
buzbeee6285f92012-12-06 15:57:46 -0800877 FreeTemp(cu, reg_len);
878 }
buzbee4ef3e452012-12-14 13:35:28 -0800879
buzbeee6285f92012-12-06 15:57:46 -0800880 if (rl_src.wide) {
881 StoreBaseDispWide(cu, reg_ptr, data_offset, rl_src.low_reg, rl_src.high_reg);
882 } else {
883 StoreBaseDisp(cu, reg_ptr, data_offset, rl_src.low_reg, size);
884 }
885 } else {
886 /* reg_ptr -> array data */
887 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
888 rl_src = LoadValue(cu, rl_src, reg_class);
889 if (needs_range_check) {
890 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
891 FreeTemp(cu, reg_len);
892 }
893 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
894 scale, size);
895 }
buzbee4ef3e452012-12-14 13:35:28 -0800896 if (!constant_index) {
897 FreeTemp(cu, reg_ptr);
898 }
buzbeee6285f92012-12-06 15:57:46 -0800899}
900
901/*
902 * Generate array store
903 *
904 */
905void ArmCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
906 RegLocation rl_index, RegLocation rl_src, int scale)
907{
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800908 int len_offset = mirror::Array::LengthOffset().Int32Value();
909 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800910
911 FlushAllRegs(cu); // Use explicit registers
912 LockCallTemps(cu);
913
914 int r_value = TargetReg(kArg0); // Register holding value
915 int r_array_class = TargetReg(kArg1); // Register holding array's Class
916 int r_array = TargetReg(kArg2); // Register holding array
917 int r_index = TargetReg(kArg3); // Register holding index into array
918
919 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
920 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
921 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
922
923 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
924
925 // Store of null?
926 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
927
928 // Get the array's class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800929 LoadWordDisp(cu, r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
buzbeee6285f92012-12-06 15:57:46 -0800930 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
931 r_array_class, true);
932 // Redo LoadValues in case they didn't survive the call.
933 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
934 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
935 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
936 r_array_class = INVALID_REG;
937
938 // Branch here if value to be stored == null
939 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
940 null_value_check->target = target;
941
942 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
943 int reg_len = INVALID_REG;
944 if (needs_range_check) {
945 reg_len = TargetReg(kArg1);
946 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
947 }
948 /* r_ptr -> array data */
949 int r_ptr = AllocTemp(cu);
950 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
951 if (needs_range_check) {
952 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
953 }
954 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
955 FreeTemp(cu, r_ptr);
956 FreeTemp(cu, r_index);
buzbee6a791b22013-02-07 05:35:08 -0800957 if (!IsConstantNullRef(cu, rl_src)) {
958 MarkGCCard(cu, r_value, r_array);
959 }
buzbeee6285f92012-12-06 15:57:46 -0800960}
961
buzbeea5954be2013-02-07 10:41:40 -0800962void ArmCodegen::GenShiftImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
buzbee4ef3e452012-12-14 13:35:28 -0800963 RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift)
964{
965 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
966 // Per spec, we only care about low 6 bits of shift amount.
967 int shift_amount = ConstantValue(cu, rl_shift) & 0x3f;
968 if (shift_amount == 0) {
969 StoreValueWide(cu, rl_dest, rl_src);
buzbeea5954be2013-02-07 10:41:40 -0800970 return;
buzbee4ef3e452012-12-14 13:35:28 -0800971 }
972 if (BadOverlap(cu, rl_src, rl_dest)) {
buzbeea5954be2013-02-07 10:41:40 -0800973 GenShiftOpLong(cu, opcode, rl_dest, rl_src, rl_shift);
974 return;
buzbee4ef3e452012-12-14 13:35:28 -0800975 }
976 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
977 switch(opcode) {
978 case Instruction::SHL_LONG:
979 case Instruction::SHL_LONG_2ADDR:
980 if (shift_amount == 1) {
981 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg);
982 OpRegRegReg(cu, kOpAdc, rl_result.high_reg, rl_src.high_reg, rl_src.high_reg);
983 } else if (shift_amount == 32) {
984 OpRegCopy(cu, rl_result.high_reg, rl_src.low_reg);
985 LoadConstant(cu, rl_result.low_reg, 0);
986 } else if (shift_amount > 31) {
987 OpRegRegImm(cu, kOpLsl, rl_result.high_reg, rl_src.low_reg, shift_amount - 32);
988 LoadConstant(cu, rl_result.low_reg, 0);
989 } else {
990 OpRegRegImm(cu, kOpLsl, rl_result.high_reg, rl_src.high_reg, shift_amount);
991 OpRegRegRegShift(cu, kOpOr, rl_result.high_reg, rl_result.high_reg, rl_src.low_reg,
992 EncodeShift(kArmLsr, 32 - shift_amount));
993 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_src.low_reg, shift_amount);
994 }
995 break;
996 case Instruction::SHR_LONG:
997 case Instruction::SHR_LONG_2ADDR:
998 if (shift_amount == 32) {
999 OpRegCopy(cu, rl_result.low_reg, rl_src.high_reg);
1000 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1001 } else if (shift_amount > 31) {
1002 OpRegRegImm(cu, kOpAsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1003 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1004 } else {
1005 int t_reg = AllocTemp(cu);
1006 OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1007 OpRegRegRegShift(cu, kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1008 EncodeShift(kArmLsl, 32 - shift_amount));
1009 FreeTemp(cu, t_reg);
1010 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1011 }
1012 break;
1013 case Instruction::USHR_LONG:
1014 case Instruction::USHR_LONG_2ADDR:
1015 if (shift_amount == 32) {
1016 OpRegCopy(cu, rl_result.low_reg, rl_src.high_reg);
1017 LoadConstant(cu, rl_result.high_reg, 0);
1018 } else if (shift_amount > 31) {
1019 OpRegRegImm(cu, kOpLsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1020 LoadConstant(cu, rl_result.high_reg, 0);
1021 } else {
1022 int t_reg = AllocTemp(cu);
1023 OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1024 OpRegRegRegShift(cu, kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1025 EncodeShift(kArmLsl, 32 - shift_amount));
1026 FreeTemp(cu, t_reg);
1027 OpRegRegImm(cu, kOpLsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1028 }
1029 break;
1030 default:
1031 LOG(FATAL) << "Unexpected case";
buzbee4ef3e452012-12-14 13:35:28 -08001032 }
1033 StoreValueWide(cu, rl_dest, rl_result);
buzbee4ef3e452012-12-14 13:35:28 -08001034}
1035
buzbeea5954be2013-02-07 10:41:40 -08001036void ArmCodegen::GenArithImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
buzbee4ef3e452012-12-14 13:35:28 -08001037 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
1038{
1039 if ((opcode == Instruction::SUB_LONG_2ADDR) || (opcode == Instruction::SUB_LONG)) {
1040 if (!rl_src2.is_const) {
1041 // Don't bother with special handling for subtract from immediate.
buzbeea5954be2013-02-07 10:41:40 -08001042 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1043 return;
buzbee4ef3e452012-12-14 13:35:28 -08001044 }
1045 } else {
1046 // Normalize
1047 if (!rl_src2.is_const) {
1048 DCHECK(rl_src1.is_const);
1049 RegLocation rl_temp = rl_src1;
1050 rl_src1 = rl_src2;
1051 rl_src2 = rl_temp;
1052 }
1053 }
1054 if (BadOverlap(cu, rl_src1, rl_dest)) {
buzbeea5954be2013-02-07 10:41:40 -08001055 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1056 return;
buzbee4ef3e452012-12-14 13:35:28 -08001057 }
1058 DCHECK(rl_src2.is_const);
1059 int64_t val = ConstantValueWide(cu, rl_src2);
1060 uint32_t val_lo = Low32Bits(val);
1061 uint32_t val_hi = High32Bits(val);
1062 int32_t mod_imm_lo = ModifiedImmediate(val_lo);
1063 int32_t mod_imm_hi = ModifiedImmediate(val_hi);
1064
1065 // Only a subset of add/sub immediate instructions set carry - so bail if we don't fit
1066 switch(opcode) {
1067 case Instruction::ADD_LONG:
1068 case Instruction::ADD_LONG_2ADDR:
1069 case Instruction::SUB_LONG:
1070 case Instruction::SUB_LONG_2ADDR:
1071 if ((mod_imm_lo < 0) || (mod_imm_hi < 0)) {
buzbeea5954be2013-02-07 10:41:40 -08001072 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1073 return;
buzbee4ef3e452012-12-14 13:35:28 -08001074 }
1075 break;
1076 default:
1077 break;
1078 }
1079 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
1080 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1081 // NOTE: once we've done the EvalLoc on dest, we can no longer bail.
1082 switch (opcode) {
1083 case Instruction::ADD_LONG:
1084 case Instruction::ADD_LONG_2ADDR:
1085 NewLIR3(cu, kThumb2AddRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1086 NewLIR3(cu, kThumb2AdcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1087 break;
1088 case Instruction::OR_LONG:
1089 case Instruction::OR_LONG_2ADDR:
1090 if ((val_lo != 0) || (rl_result.low_reg != rl_src1.low_reg)) {
1091 OpRegRegImm(cu, kOpOr, rl_result.low_reg, rl_src1.low_reg, val_lo);
1092 }
1093 if ((val_hi != 0) || (rl_result.high_reg != rl_src1.high_reg)) {
1094 OpRegRegImm(cu, kOpOr, rl_result.high_reg, rl_src1.high_reg, val_hi);
1095 }
1096 break;
1097 case Instruction::XOR_LONG:
1098 case Instruction::XOR_LONG_2ADDR:
1099 OpRegRegImm(cu, kOpXor, rl_result.low_reg, rl_src1.low_reg, val_lo);
1100 OpRegRegImm(cu, kOpXor, rl_result.high_reg, rl_src1.high_reg, val_hi);
1101 break;
1102 case Instruction::AND_LONG:
1103 case Instruction::AND_LONG_2ADDR:
1104 if ((val_lo != 0xffffffff) || (rl_result.low_reg != rl_src1.low_reg)) {
1105 OpRegRegImm(cu, kOpAnd, rl_result.low_reg, rl_src1.low_reg, val_lo);
1106 }
1107 if ((val_hi != 0xffffffff) || (rl_result.high_reg != rl_src1.high_reg)) {
1108 OpRegRegImm(cu, kOpAnd, rl_result.high_reg, rl_src1.high_reg, val_hi);
1109 }
1110 break;
1111 case Instruction::SUB_LONG_2ADDR:
1112 case Instruction::SUB_LONG:
1113 NewLIR3(cu, kThumb2SubRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1114 NewLIR3(cu, kThumb2SbcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1115 break;
1116 default:
1117 LOG(FATAL) << "Unexpected opcode " << opcode;
1118 }
1119 StoreValueWide(cu, rl_dest, rl_result);
buzbee4ef3e452012-12-14 13:35:28 -08001120}
1121
buzbeeefc63692012-11-14 16:31:52 -08001122} // namespace art