blob: 45fe807da3e8dfe18124f5296f82b56b95b4c933 [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"
22#include "../codegen_util.h"
23#include "../ralloc_util.h"
buzbeeefc63692012-11-14 16:31:52 -080024
25namespace art {
26
buzbeefa57c472012-11-21 12:06:18 -080027LIR* OpCmpBranch(CompilationUnit* cu, ConditionCode cond, int src1,
buzbeeefc63692012-11-14 16:31:52 -080028 int src2, LIR* target)
29{
buzbeefa57c472012-11-21 12:06:18 -080030 OpRegReg(cu, kOpCmp, src1, src2);
31 return OpCondBranch(cu, cond, target);
buzbeeefc63692012-11-14 16:31:52 -080032}
33
34/*
35 * Generate a Thumb2 IT instruction, which can nullify up to
36 * four subsequent instructions based on a condition and its
37 * inverse. The condition applies to the first instruction, which
38 * is executed if the condition is met. The string "guide" consists
39 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
40 * A "T" means the instruction is executed if the condition is
41 * met, and an "E" means the instruction is executed if the condition
42 * is not met.
43 */
buzbeefa57c472012-11-21 12:06:18 -080044LIR* OpIT(CompilationUnit* cu, ArmConditionCode code, const char* guide)
buzbeeefc63692012-11-14 16:31:52 -080045{
46 int mask;
buzbeefa57c472012-11-21 12:06:18 -080047 int cond_bit = code & 1;
48 int alt_bit = cond_bit ^ 1;
buzbeeefc63692012-11-14 16:31:52 -080049 int mask3 = 0;
50 int mask2 = 0;
51 int mask1 = 0;
52
53 //Note: case fallthroughs intentional
54 switch (strlen(guide)) {
55 case 3:
buzbeefa57c472012-11-21 12:06:18 -080056 mask1 = (guide[2] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080057 case 2:
buzbeefa57c472012-11-21 12:06:18 -080058 mask2 = (guide[1] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080059 case 1:
buzbeefa57c472012-11-21 12:06:18 -080060 mask3 = (guide[0] == 'T') ? cond_bit : alt_bit;
buzbeeefc63692012-11-14 16:31:52 -080061 break;
62 case 0:
63 break;
64 default:
buzbee52a77fc2012-11-20 19:50:46 -080065 LOG(FATAL) << "OAT: bad case in OpIT";
buzbeeefc63692012-11-14 16:31:52 -080066 }
67 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
68 (1 << (3 - strlen(guide)));
buzbeefa57c472012-11-21 12:06:18 -080069 return NewLIR2(cu, kThumb2It, code, mask);
buzbeeefc63692012-11-14 16:31:52 -080070}
71
72/*
73 * 64-bit 3way compare function.
74 * mov rX, #-1
75 * cmp op1hi, op2hi
76 * blt done
77 * bgt flip
78 * sub rX, op1lo, op2lo (treat as unsigned)
79 * beq done
80 * ite hi
81 * mov(hi) rX, #-1
82 * mov(!hi) rX, #1
83 * flip:
84 * neg rX
85 * done:
86 */
buzbeefa57c472012-11-21 12:06:18 -080087void GenCmpLong(CompilationUnit* cu, RegLocation rl_dest,
88 RegLocation rl_src1, RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -080089{
90 LIR* target1;
91 LIR* target2;
buzbeefa57c472012-11-21 12:06:18 -080092 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
93 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
94 int t_reg = AllocTemp(cu);
95 LoadConstant(cu, t_reg, -1);
96 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
97 LIR* branch1 = OpCondBranch(cu, kCondLt, NULL);
98 LIR* branch2 = OpCondBranch(cu, kCondGt, NULL);
99 OpRegRegReg(cu, kOpSub, t_reg, rl_src1.low_reg, rl_src2.low_reg);
100 LIR* branch3 = OpCondBranch(cu, kCondEq, NULL);
buzbeeefc63692012-11-14 16:31:52 -0800101
buzbeefa57c472012-11-21 12:06:18 -0800102 OpIT(cu, kArmCondHi, "E");
103 NewLIR2(cu, kThumb2MovImmShift, t_reg, ModifiedImmediate(-1));
104 LoadConstant(cu, t_reg, 1);
105 GenBarrier(cu);
buzbeeefc63692012-11-14 16:31:52 -0800106
buzbeefa57c472012-11-21 12:06:18 -0800107 target2 = NewLIR0(cu, kPseudoTargetLabel);
108 OpRegReg(cu, kOpNeg, t_reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800109
buzbeefa57c472012-11-21 12:06:18 -0800110 target1 = NewLIR0(cu, kPseudoTargetLabel);
buzbeeefc63692012-11-14 16:31:52 -0800111
buzbeefa57c472012-11-21 12:06:18 -0800112 RegLocation rl_temp = LocCReturn(); // Just using as template, will change
113 rl_temp.low_reg = t_reg;
114 StoreValue(cu, rl_dest, rl_temp);
115 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800116
buzbeecbd6d442012-11-17 14:11:25 -0800117 branch1->target = target1;
118 branch2->target = target2;
buzbeeefc63692012-11-14 16:31:52 -0800119 branch3->target = branch1->target;
120}
121
buzbeefa57c472012-11-21 12:06:18 -0800122void GenFusedLongCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -0800123{
buzbeefa57c472012-11-21 12:06:18 -0800124 LIR* label_list = cu->block_label_list;
125 LIR* taken = &label_list[bb->taken->id];
126 LIR* not_taken = &label_list[bb->fall_through->id];
127 RegLocation rl_src1 = GetSrcWide(cu, mir, 0);
128 RegLocation rl_src2 = GetSrcWide(cu, mir, 2);
129 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
130 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800131 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
buzbeefa57c472012-11-21 12:06:18 -0800132 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800133 switch(ccode) {
134 case kCondEq:
buzbeefa57c472012-11-21 12:06:18 -0800135 OpCondBranch(cu, kCondNe, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800136 break;
137 case kCondNe:
buzbeefa57c472012-11-21 12:06:18 -0800138 OpCondBranch(cu, kCondNe, taken);
buzbeeefc63692012-11-14 16:31:52 -0800139 break;
140 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800141 OpCondBranch(cu, kCondLt, taken);
142 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800143 ccode = kCondCc;
144 break;
145 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800146 OpCondBranch(cu, kCondLt, taken);
147 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800148 ccode = kCondLs;
149 break;
150 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800151 OpCondBranch(cu, kCondGt, taken);
152 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800153 ccode = kCondHi;
154 break;
155 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800156 OpCondBranch(cu, kCondGt, taken);
157 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800158 ccode = kCondCs;
159 break;
160 default:
buzbeecbd6d442012-11-17 14:11:25 -0800161 LOG(FATAL) << "Unexpected ccode: " << ccode;
buzbeeefc63692012-11-14 16:31:52 -0800162 }
buzbeefa57c472012-11-21 12:06:18 -0800163 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
164 OpCondBranch(cu, ccode, taken);
buzbeeefc63692012-11-14 16:31:52 -0800165}
166
167/*
168 * Generate a register comparison to an immediate and branch. Caller
169 * is responsible for setting branch target field.
170 */
buzbeefa57c472012-11-21 12:06:18 -0800171LIR* OpCmpImmBranch(CompilationUnit* cu, ConditionCode cond, int reg,
172 int check_value, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800173{
174 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -0800175 int mod_imm;
176 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
177 if ((ARM_LOWREG(reg)) && (check_value == 0) &&
178 ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
179 branch = NewLIR2(cu, (arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
buzbeeefc63692012-11-14 16:31:52 -0800180 reg, 0);
181 } else {
buzbeefa57c472012-11-21 12:06:18 -0800182 mod_imm = ModifiedImmediate(check_value);
183 if (ARM_LOWREG(reg) && ((check_value & 0xff) == check_value)) {
184 NewLIR2(cu, kThumbCmpRI8, reg, check_value);
185 } else if (mod_imm >= 0) {
186 NewLIR2(cu, kThumb2CmpRI8, reg, mod_imm);
buzbeeefc63692012-11-14 16:31:52 -0800187 } else {
buzbeefa57c472012-11-21 12:06:18 -0800188 int t_reg = AllocTemp(cu);
189 LoadConstant(cu, t_reg, check_value);
190 OpRegReg(cu, kOpCmp, reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800191 }
buzbeefa57c472012-11-21 12:06:18 -0800192 branch = NewLIR2(cu, kThumbBCond, 0, arm_cond);
buzbeeefc63692012-11-14 16:31:52 -0800193 }
194 branch->target = target;
195 return branch;
196}
buzbeefa57c472012-11-21 12:06:18 -0800197LIR* OpRegCopyNoInsert(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800198{
199 LIR* res;
200 int opcode;
buzbeefa57c472012-11-21 12:06:18 -0800201 if (ARM_FPREG(r_dest) || ARM_FPREG(r_src))
202 return FpRegCopy(cu, r_dest, r_src);
203 if (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800204 opcode = kThumbMovRR;
buzbeefa57c472012-11-21 12:06:18 -0800205 else if (!ARM_LOWREG(r_dest) && !ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800206 opcode = kThumbMovRR_H2H;
buzbeefa57c472012-11-21 12:06:18 -0800207 else if (ARM_LOWREG(r_dest))
buzbeeefc63692012-11-14 16:31:52 -0800208 opcode = kThumbMovRR_H2L;
209 else
210 opcode = kThumbMovRR_L2H;
buzbeefa57c472012-11-21 12:06:18 -0800211 res = RawLIR(cu, cu->current_dalvik_offset, opcode, r_dest, r_src);
212 if (!(cu->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
213 res->flags.is_nop = true;
buzbeeefc63692012-11-14 16:31:52 -0800214 }
215 return res;
216}
217
buzbeefa57c472012-11-21 12:06:18 -0800218LIR* OpRegCopy(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800219{
buzbeefa57c472012-11-21 12:06:18 -0800220 LIR* res = OpRegCopyNoInsert(cu, r_dest, r_src);
221 AppendLIR(cu, res);
buzbeeefc63692012-11-14 16:31:52 -0800222 return res;
223}
224
buzbeefa57c472012-11-21 12:06:18 -0800225void OpRegCopyWide(CompilationUnit* cu, int dest_lo, int dest_hi,
226 int src_lo, int src_hi)
buzbeeefc63692012-11-14 16:31:52 -0800227{
buzbeefa57c472012-11-21 12:06:18 -0800228 bool dest_fp = ARM_FPREG(dest_lo) && ARM_FPREG(dest_hi);
229 bool src_fp = ARM_FPREG(src_lo) && ARM_FPREG(src_hi);
230 DCHECK_EQ(ARM_FPREG(src_lo), ARM_FPREG(src_hi));
231 DCHECK_EQ(ARM_FPREG(dest_lo), ARM_FPREG(dest_hi));
232 if (dest_fp) {
233 if (src_fp) {
234 OpRegCopy(cu, S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800235 } else {
buzbeefa57c472012-11-21 12:06:18 -0800236 NewLIR3(cu, kThumb2Fmdrr, S2d(dest_lo, dest_hi), src_lo, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800237 }
238 } else {
buzbeefa57c472012-11-21 12:06:18 -0800239 if (src_fp) {
240 NewLIR3(cu, kThumb2Fmrrd, dest_lo, dest_hi, S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800241 } else {
242 // Handle overlap
buzbeefa57c472012-11-21 12:06:18 -0800243 if (src_hi == dest_lo) {
244 OpRegCopy(cu, dest_hi, src_hi);
245 OpRegCopy(cu, dest_lo, src_lo);
buzbeeefc63692012-11-14 16:31:52 -0800246 } else {
buzbeefa57c472012-11-21 12:06:18 -0800247 OpRegCopy(cu, dest_lo, src_lo);
248 OpRegCopy(cu, dest_hi, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800249 }
250 }
251 }
252}
253
254// Table of magic divisors
buzbeeefc63692012-11-14 16:31:52 -0800255struct MagicTable {
256 uint32_t magic;
257 uint32_t shift;
258 DividePattern pattern;
259};
260
buzbeefa57c472012-11-21 12:06:18 -0800261static const MagicTable magic_table[] = {
buzbeeefc63692012-11-14 16:31:52 -0800262 {0, 0, DivideNone}, // 0
263 {0, 0, DivideNone}, // 1
264 {0, 0, DivideNone}, // 2
265 {0x55555556, 0, Divide3}, // 3
266 {0, 0, DivideNone}, // 4
267 {0x66666667, 1, Divide5}, // 5
268 {0x2AAAAAAB, 0, Divide3}, // 6
269 {0x92492493, 2, Divide7}, // 7
270 {0, 0, DivideNone}, // 8
271 {0x38E38E39, 1, Divide5}, // 9
272 {0x66666667, 2, Divide5}, // 10
273 {0x2E8BA2E9, 1, Divide5}, // 11
274 {0x2AAAAAAB, 1, Divide5}, // 12
275 {0x4EC4EC4F, 2, Divide5}, // 13
276 {0x92492493, 3, Divide7}, // 14
277 {0x88888889, 3, Divide7}, // 15
278};
279
280// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
buzbeefa57c472012-11-21 12:06:18 -0800281bool SmallLiteralDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
282 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbeeefc63692012-11-14 16:31:52 -0800283{
buzbeefa57c472012-11-21 12:06:18 -0800284 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
buzbeeefc63692012-11-14 16:31:52 -0800285 return false;
286 }
buzbeefa57c472012-11-21 12:06:18 -0800287 DividePattern pattern = magic_table[lit].pattern;
buzbeeefc63692012-11-14 16:31:52 -0800288 if (pattern == DivideNone) {
289 return false;
290 }
291 // Tuning: add rem patterns
buzbeefa57c472012-11-21 12:06:18 -0800292 if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
buzbeeefc63692012-11-14 16:31:52 -0800293 return false;
294 }
295
buzbeefa57c472012-11-21 12:06:18 -0800296 int r_magic = AllocTemp(cu);
297 LoadConstant(cu, r_magic, magic_table[lit].magic);
298 rl_src = LoadValue(cu, rl_src, kCoreReg);
299 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
300 int r_hi = AllocTemp(cu);
301 int r_lo = AllocTemp(cu);
302 NewLIR4(cu, kThumb2Smull, r_lo, r_hi, r_magic, rl_src.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800303 switch(pattern) {
304 case Divide3:
buzbeefa57c472012-11-21 12:06:18 -0800305 OpRegRegRegShift(cu, kOpSub, rl_result.low_reg, r_hi,
306 rl_src.low_reg, EncodeShift(kArmAsr, 31));
buzbeeefc63692012-11-14 16:31:52 -0800307 break;
308 case Divide5:
buzbeefa57c472012-11-21 12:06:18 -0800309 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
310 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
311 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800312 break;
313 case Divide7:
buzbeefa57c472012-11-21 12:06:18 -0800314 OpRegReg(cu, kOpAdd, r_hi, rl_src.low_reg);
315 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
316 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
317 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800318 break;
319 default:
buzbeecbd6d442012-11-17 14:11:25 -0800320 LOG(FATAL) << "Unexpected pattern: " << pattern;
buzbeeefc63692012-11-14 16:31:52 -0800321 }
buzbeefa57c472012-11-21 12:06:18 -0800322 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800323 return true;
324}
325
buzbeefa57c472012-11-21 12:06:18 -0800326LIR* GenRegMemCheck(CompilationUnit* cu, ConditionCode c_code,
buzbeeefc63692012-11-14 16:31:52 -0800327 int reg1, int base, int offset, ThrowKind kind)
328{
buzbee52a77fc2012-11-20 19:50:46 -0800329 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800330 return NULL;
331}
332
buzbeefa57c472012-11-21 12:06:18 -0800333RegLocation GenDivRemLit(CompilationUnit* cu, RegLocation rl_dest, int reg1, int lit, bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800334{
buzbee52a77fc2012-11-20 19:50:46 -0800335 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800336 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800337}
338
buzbeefa57c472012-11-21 12:06:18 -0800339RegLocation GenDivRem(CompilationUnit* cu, RegLocation rl_dest, int reg1, int reg2, bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800340{
buzbee52a77fc2012-11-20 19:50:46 -0800341 LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800342 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800343}
344
buzbeefa57c472012-11-21 12:06:18 -0800345bool GenInlinedMinMaxInt(CompilationUnit *cu, CallInfo* info, bool is_min)
buzbeeefc63692012-11-14 16:31:52 -0800346{
buzbeefa57c472012-11-21 12:06:18 -0800347 DCHECK_EQ(cu->instruction_set, kThumb2);
348 RegLocation rl_src1 = info->args[0];
349 RegLocation rl_src2 = info->args[1];
350 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
351 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
352 RegLocation rl_dest = InlineTarget(cu, info);
353 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
354 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
355 OpIT(cu, (is_min) ? kArmCondGt : kArmCondLt, "E");
356 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src2.low_reg);
357 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src1.low_reg);
358 GenBarrier(cu);
359 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800360 return true;
361}
362
buzbeefa57c472012-11-21 12:06:18 -0800363void OpLea(CompilationUnit* cu, int rBase, int reg1, int reg2, int scale, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800364{
buzbee52a77fc2012-11-20 19:50:46 -0800365 LOG(FATAL) << "Unexpected use of OpLea for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800366}
367
buzbeefa57c472012-11-21 12:06:18 -0800368void OpTlsCmp(CompilationUnit* cu, int offset, int val)
buzbeeefc63692012-11-14 16:31:52 -0800369{
buzbee52a77fc2012-11-20 19:50:46 -0800370 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800371}
372
buzbeefa57c472012-11-21 12:06:18 -0800373bool GenInlinedCas32(CompilationUnit* cu, CallInfo* info, bool need_write_barrier) {
374 DCHECK_EQ(cu->instruction_set, kThumb2);
375 // Unused - RegLocation rl_src_unsafe = info->args[0];
376 RegLocation rl_src_obj= info->args[1]; // Object - known non-null
377 RegLocation rl_src_offset= info->args[2]; // long low
378 rl_src_offset.wide = 0; // ignore high half in info->args[3]
379 RegLocation rl_src_expected= info->args[4]; // int or Object
380 RegLocation rl_src_new_value= info->args[5]; // int or Object
381 RegLocation rl_dest = InlineTarget(cu, info); // boolean place for result
buzbeeefc63692012-11-14 16:31:52 -0800382
383
buzbee1bc37c62012-11-20 13:35:41 -0800384 // Release store semantics, get the barrier out of the way. TODO: revisit
buzbeefa57c472012-11-21 12:06:18 -0800385 GenMemBarrier(cu, kStoreLoad);
buzbeeefc63692012-11-14 16:31:52 -0800386
buzbeefa57c472012-11-21 12:06:18 -0800387 RegLocation rl_object = LoadValue(cu, rl_src_obj, kCoreReg);
388 RegLocation rl_new_value = LoadValue(cu, rl_src_new_value, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800389
390 if (need_write_barrier) {
391 // Mark card for object assuming new value is stored.
buzbeefa57c472012-11-21 12:06:18 -0800392 MarkGCCard(cu, rl_new_value.low_reg, rl_object.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800393 }
394
buzbeefa57c472012-11-21 12:06:18 -0800395 RegLocation rl_offset = LoadValue(cu, rl_src_offset, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800396
buzbeefa57c472012-11-21 12:06:18 -0800397 int r_ptr = AllocTemp(cu);
398 OpRegRegReg(cu, kOpAdd, r_ptr, rl_object.low_reg, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800399
buzbeefa57c472012-11-21 12:06:18 -0800400 // Free now unneeded rl_object and rl_offset to give more temps.
401 ClobberSReg(cu, rl_object.s_reg_low);
402 FreeTemp(cu, rl_object.low_reg);
403 ClobberSReg(cu, rl_offset.s_reg_low);
404 FreeTemp(cu, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800405
buzbeefa57c472012-11-21 12:06:18 -0800406 int r_old_value = AllocTemp(cu);
407 NewLIR3(cu, kThumb2Ldrex, r_old_value, r_ptr, 0); // r_old_value := [r_ptr]
buzbeeefc63692012-11-14 16:31:52 -0800408
buzbeefa57c472012-11-21 12:06:18 -0800409 RegLocation rl_expected = LoadValue(cu, rl_src_expected, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800410
buzbeefa57c472012-11-21 12:06:18 -0800411 // if (r_old_value == rExpected) {
412 // [r_ptr] <- r_new_value && r_result := success ? 0 : 1
413 // r_result ^= 1
buzbeeefc63692012-11-14 16:31:52 -0800414 // } else {
buzbeefa57c472012-11-21 12:06:18 -0800415 // r_result := 0
buzbeeefc63692012-11-14 16:31:52 -0800416 // }
buzbeefa57c472012-11-21 12:06:18 -0800417 OpRegReg(cu, kOpCmp, r_old_value, rl_expected.low_reg);
418 FreeTemp(cu, r_old_value); // Now unneeded.
419 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
420 OpIT(cu, kArmCondEq, "TE");
421 NewLIR4(cu, kThumb2Strex, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
422 FreeTemp(cu, r_ptr); // Now unneeded.
423 OpRegImm(cu, kOpXor, rl_result.low_reg, 1);
424 OpRegReg(cu, kOpXor, rl_result.low_reg, rl_result.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800425
buzbeefa57c472012-11-21 12:06:18 -0800426 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800427
428 return true;
429}
430
buzbeefa57c472012-11-21 12:06:18 -0800431LIR* OpPcRelLoad(CompilationUnit* cu, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800432{
buzbeefa57c472012-11-21 12:06:18 -0800433 return RawLIR(cu, cu->current_dalvik_offset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800434}
435
buzbeefa57c472012-11-21 12:06:18 -0800436LIR* OpVldm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800437{
buzbeefa57c472012-11-21 12:06:18 -0800438 return NewLIR3(cu, kThumb2Vldms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800439}
440
buzbeefa57c472012-11-21 12:06:18 -0800441LIR* OpVstm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800442{
buzbeefa57c472012-11-21 12:06:18 -0800443 return NewLIR3(cu, kThumb2Vstms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800444}
445
buzbeefa57c472012-11-21 12:06:18 -0800446void GenMultiplyByTwoBitMultiplier(CompilationUnit* cu, RegLocation rl_src,
447 RegLocation rl_result, int lit,
448 int first_bit, int second_bit)
buzbeeefc63692012-11-14 16:31:52 -0800449{
buzbeefa57c472012-11-21 12:06:18 -0800450 OpRegRegRegShift(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg,
451 EncodeShift(kArmLsl, second_bit - first_bit));
452 if (first_bit != 0) {
453 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
buzbeeefc63692012-11-14 16:31:52 -0800454 }
455}
456
buzbeefa57c472012-11-21 12:06:18 -0800457void GenDivZeroCheck(CompilationUnit* cu, int reg_lo, int reg_hi)
buzbeeefc63692012-11-14 16:31:52 -0800458{
buzbeefa57c472012-11-21 12:06:18 -0800459 int t_reg = AllocTemp(cu);
460 NewLIR4(cu, kThumb2OrrRRRs, t_reg, reg_lo, reg_hi, 0);
461 FreeTemp(cu, t_reg);
462 GenCheck(cu, kCondEq, kThrowDivZero);
buzbeeefc63692012-11-14 16:31:52 -0800463}
464
465// Test suspend flag, return target of taken suspend branch
buzbeefa57c472012-11-21 12:06:18 -0800466LIR* OpTestSuspend(CompilationUnit* cu, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800467{
buzbeefa57c472012-11-21 12:06:18 -0800468 NewLIR2(cu, kThumbSubRI8, rARM_SUSPEND, 1);
469 return OpCondBranch(cu, (target == NULL) ? kCondEq : kCondNe, target);
buzbeeefc63692012-11-14 16:31:52 -0800470}
471
472// Decrement register and branch on condition
buzbeefa57c472012-11-21 12:06:18 -0800473LIR* OpDecAndBranch(CompilationUnit* cu, ConditionCode c_code, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800474{
475 // Combine sub & test using sub setflags encoding here
buzbeefa57c472012-11-21 12:06:18 -0800476 NewLIR3(cu, kThumb2SubsRRI12, reg, reg, 1);
477 return OpCondBranch(cu, c_code, target);
buzbeeefc63692012-11-14 16:31:52 -0800478}
479
buzbeefa57c472012-11-21 12:06:18 -0800480void GenMemBarrier(CompilationUnit* cu, MemBarrierKind barrier_kind)
buzbeeefc63692012-11-14 16:31:52 -0800481{
482#if ANDROID_SMP != 0
buzbeefa57c472012-11-21 12:06:18 -0800483 int dmb_flavor;
buzbee1bc37c62012-11-20 13:35:41 -0800484 // TODO: revisit Arm barrier kinds
buzbeefa57c472012-11-21 12:06:18 -0800485 switch (barrier_kind) {
486 case kLoadStore: dmb_flavor = kSY; break;
487 case kLoadLoad: dmb_flavor = kSY; break;
488 case kStoreStore: dmb_flavor = kST; break;
489 case kStoreLoad: dmb_flavor = kSY; break;
buzbee1bc37c62012-11-20 13:35:41 -0800490 default:
buzbeefa57c472012-11-21 12:06:18 -0800491 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
492 dmb_flavor = kSY; // quiet gcc.
buzbee1bc37c62012-11-20 13:35:41 -0800493 break;
494 }
buzbeefa57c472012-11-21 12:06:18 -0800495 LIR* dmb = NewLIR1(cu, kThumb2Dmb, dmb_flavor);
496 dmb->def_mask = ENCODE_ALL;
buzbeeefc63692012-11-14 16:31:52 -0800497#endif
498}
499
buzbeefa57c472012-11-21 12:06:18 -0800500bool GenNegLong(CompilationUnit* cu, RegLocation rl_dest,
501 RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800502{
buzbeefa57c472012-11-21 12:06:18 -0800503 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
504 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
505 int z_reg = AllocTemp(cu);
506 LoadConstantNoClobber(cu, z_reg, 0);
buzbeeefc63692012-11-14 16:31:52 -0800507 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -0800508 if (rl_result.low_reg == rl_src.high_reg) {
509 int t_reg = AllocTemp(cu);
510 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
511 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, t_reg);
512 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800513 } else {
buzbeefa57c472012-11-21 12:06:18 -0800514 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
515 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, rl_src.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800516 }
buzbeefa57c472012-11-21 12:06:18 -0800517 FreeTemp(cu, z_reg);
518 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800519 return false;
520}
521
buzbeefa57c472012-11-21 12:06:18 -0800522bool GenAddLong(CompilationUnit* cu, RegLocation rl_dest,
523 RegLocation rl_src1, RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800524{
buzbee52a77fc2012-11-20 19:50:46 -0800525 LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800526 return false;
527}
528
buzbeefa57c472012-11-21 12:06:18 -0800529bool GenSubLong(CompilationUnit* cu, RegLocation rl_dest,
530 RegLocation rl_src1, RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800531{
buzbee52a77fc2012-11-20 19:50:46 -0800532 LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800533 return false;
534}
535
buzbeefa57c472012-11-21 12:06:18 -0800536bool GenAndLong(CompilationUnit* cu, RegLocation rl_dest,
537 RegLocation rl_src1, RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800538{
buzbee52a77fc2012-11-20 19:50:46 -0800539 LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800540 return false;
541}
542
buzbeefa57c472012-11-21 12:06:18 -0800543bool GenOrLong(CompilationUnit* cu, RegLocation rl_dest,
544 RegLocation rl_src1, RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800545{
buzbee52a77fc2012-11-20 19:50:46 -0800546 LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800547 return false;
548}
549
buzbeefa57c472012-11-21 12:06:18 -0800550bool GenXorLong(CompilationUnit* cu, RegLocation rl_dest,
551 RegLocation rl_src1, RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800552{
553 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
554 return false;
555}
556
557} // namespace art