blob: e927b13181fe1c98629e44f427cd17875123dd75 [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
buzbeef662a7c2013-02-12 16:19:43 -0800185void ArmCodegen::GenSelect(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
186{
187 RegLocation rl_result;
188 RegLocation rl_src = GetSrc(cu, mir, 0);
buzbeea0e8bbd2013-02-27 10:01:37 -0800189 // Temporary debugging code
190 int dest_sreg = mir->ssa_rep->defs[0];
191 if ((dest_sreg < 0) || (dest_sreg >= cu->num_ssa_regs)) {
192 LOG(INFO) << "Bad target sreg: " << dest_sreg << ", in "
193 << PrettyMethod(cu->method_idx,*cu->dex_file);
194 LOG(INFO) << "at dex offset 0x" << std::hex << mir->offset;
195 LOG(INFO) << "vreg = " << SRegToVReg(cu, dest_sreg);
196 LOG(INFO) << "num uses = " << mir->ssa_rep->num_uses;
197 if (mir->ssa_rep->num_uses == 1) {
198 LOG(INFO) << "CONST case, vals = " << mir->dalvikInsn.vB << ", " << mir->dalvikInsn.vC;
199 } else {
200 LOG(INFO) << "MOVE case, operands = " << mir->ssa_rep->uses[1] << ", "
201 << mir->ssa_rep->uses[2];
202 }
203 CHECK(false) << "Invalid target sreg on Select.";
204 }
205 // End temporary debugging code
buzbeef662a7c2013-02-12 16:19:43 -0800206 RegLocation rl_dest = GetDest(cu, mir);
207 rl_src = LoadValue(cu, rl_src, kCoreReg);
208 if (mir->ssa_rep->num_uses == 1) {
209 // CONST case
210 int true_val = mir->dalvikInsn.vB;
211 int false_val = mir->dalvikInsn.vC;
212 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
213 if ((true_val == 1) && (false_val == 0)) {
214 OpRegRegImm(cu, kOpRsub, rl_result.low_reg, rl_src.low_reg, 1);
215 OpIT(cu, kCondCc, "");
216 LoadConstant(cu, rl_result.low_reg, 0);
217 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
218 } else if (InexpensiveConstantInt(true_val) && InexpensiveConstantInt(false_val)) {
219 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
220 OpIT(cu, kCondEq, "E");
221 LoadConstant(cu, rl_result.low_reg, true_val);
222 LoadConstant(cu, rl_result.low_reg, false_val);
223 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
224 } else {
225 // Unlikely case - could be tuned.
226 int t_reg1 = AllocTemp(cu);
227 int t_reg2 = AllocTemp(cu);
228 LoadConstant(cu, t_reg1, true_val);
229 LoadConstant(cu, t_reg2, false_val);
230 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
231 OpIT(cu, kCondEq, "E");
232 OpRegCopy(cu, rl_result.low_reg, t_reg1);
233 OpRegCopy(cu, rl_result.low_reg, t_reg2);
234 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
235 }
236 } else {
237 // MOVE case
238 RegLocation rl_true = cu->reg_location[mir->ssa_rep->uses[1]];
239 RegLocation rl_false = cu->reg_location[mir->ssa_rep->uses[2]];
240 rl_true = LoadValue(cu, rl_true, kCoreReg);
241 rl_false = LoadValue(cu, rl_false, kCoreReg);
242 rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
243 OpRegImm(cu, kOpCmp, rl_src.low_reg, 0);
244 OpIT(cu, kCondEq, "E");
245 LIR* l1 = OpRegCopy(cu, rl_result.low_reg, rl_true.low_reg);
246 l1->flags.is_nop = false; // Make sure this instruction isn't optimized away
247 LIR* l2 = OpRegCopy(cu, rl_result.low_reg, rl_false.low_reg);
248 l2->flags.is_nop = false; // Make sure this instruction isn't optimized away
249 GenBarrier(cu); // Add a scheduling barrier to keep the IT shadow intact
250 }
251 StoreValue(cu, rl_dest, rl_result);
252}
buzbee4ef3e452012-12-14 13:35:28 -0800253
254void ArmCodegen::GenFusedLongCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
255{
buzbeefa57c472012-11-21 12:06:18 -0800256 RegLocation rl_src1 = GetSrcWide(cu, mir, 0);
257 RegLocation rl_src2 = GetSrcWide(cu, mir, 2);
buzbee4ef3e452012-12-14 13:35:28 -0800258 // Normalize such that if either operand is constant, src2 will be constant.
259 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
260 if (rl_src1.is_const) {
261 RegLocation rl_temp = rl_src1;
262 rl_src1 = rl_src2;
263 rl_src2 = rl_temp;
264 ccode = FlipComparisonOrder(ccode);
265 }
266 if (rl_src2.is_const) {
267 RegLocation rl_temp = UpdateLocWide(cu, rl_src2);
268 // Do special compare/branch against simple const operand if not already in registers.
269 int64_t val = ConstantValueWide(cu, rl_src2);
270 if ((rl_temp.location != kLocPhysReg) &&
271 ((ModifiedImmediate(Low32Bits(val)) >= 0) && (ModifiedImmediate(High32Bits(val)) >= 0))) {
272 GenFusedLongCmpImmBranch(cu, bb, rl_src1, val, ccode);
273 return;
274 }
275 }
276 LIR* label_list = cu->block_label_list;
277 LIR* taken = &label_list[bb->taken->id];
278 LIR* not_taken = &label_list[bb->fall_through->id];
buzbeefa57c472012-11-21 12:06:18 -0800279 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
280 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800281 OpRegReg(cu, kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800282 switch(ccode) {
283 case kCondEq:
buzbeefa57c472012-11-21 12:06:18 -0800284 OpCondBranch(cu, kCondNe, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800285 break;
286 case kCondNe:
buzbeefa57c472012-11-21 12:06:18 -0800287 OpCondBranch(cu, kCondNe, taken);
buzbeeefc63692012-11-14 16:31:52 -0800288 break;
289 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800290 OpCondBranch(cu, kCondLt, taken);
291 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800292 ccode = kCondCc;
293 break;
294 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800295 OpCondBranch(cu, kCondLt, taken);
296 OpCondBranch(cu, kCondGt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800297 ccode = kCondLs;
298 break;
299 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -0800300 OpCondBranch(cu, kCondGt, taken);
301 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800302 ccode = kCondHi;
303 break;
304 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -0800305 OpCondBranch(cu, kCondGt, taken);
306 OpCondBranch(cu, kCondLt, not_taken);
buzbeeefc63692012-11-14 16:31:52 -0800307 ccode = kCondCs;
308 break;
309 default:
buzbeecbd6d442012-11-17 14:11:25 -0800310 LOG(FATAL) << "Unexpected ccode: " << ccode;
buzbeeefc63692012-11-14 16:31:52 -0800311 }
buzbeefa57c472012-11-21 12:06:18 -0800312 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
313 OpCondBranch(cu, ccode, taken);
buzbeeefc63692012-11-14 16:31:52 -0800314}
315
316/*
317 * Generate a register comparison to an immediate and branch. Caller
318 * is responsible for setting branch target field.
319 */
buzbee02031b12012-11-23 09:41:35 -0800320LIR* ArmCodegen::OpCmpImmBranch(CompilationUnit* cu, ConditionCode cond, int reg, int check_value,
321 LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800322{
323 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -0800324 int mod_imm;
325 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
326 if ((ARM_LOWREG(reg)) && (check_value == 0) &&
327 ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
328 branch = NewLIR2(cu, (arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
buzbeeefc63692012-11-14 16:31:52 -0800329 reg, 0);
330 } else {
buzbeefa57c472012-11-21 12:06:18 -0800331 mod_imm = ModifiedImmediate(check_value);
332 if (ARM_LOWREG(reg) && ((check_value & 0xff) == check_value)) {
333 NewLIR2(cu, kThumbCmpRI8, reg, check_value);
334 } else if (mod_imm >= 0) {
buzbee4ef3e452012-12-14 13:35:28 -0800335 NewLIR2(cu, kThumb2CmpRI12, reg, mod_imm);
buzbeeefc63692012-11-14 16:31:52 -0800336 } else {
buzbeefa57c472012-11-21 12:06:18 -0800337 int t_reg = AllocTemp(cu);
338 LoadConstant(cu, t_reg, check_value);
339 OpRegReg(cu, kOpCmp, reg, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800340 }
buzbeefa57c472012-11-21 12:06:18 -0800341 branch = NewLIR2(cu, kThumbBCond, 0, arm_cond);
buzbeeefc63692012-11-14 16:31:52 -0800342 }
343 branch->target = target;
344 return branch;
345}
buzbee02031b12012-11-23 09:41:35 -0800346
347LIR* ArmCodegen::OpRegCopyNoInsert(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800348{
349 LIR* res;
350 int opcode;
buzbeefa57c472012-11-21 12:06:18 -0800351 if (ARM_FPREG(r_dest) || ARM_FPREG(r_src))
buzbee02031b12012-11-23 09:41:35 -0800352 return OpFpRegCopy(cu, r_dest, r_src);
buzbeefa57c472012-11-21 12:06:18 -0800353 if (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800354 opcode = kThumbMovRR;
buzbeefa57c472012-11-21 12:06:18 -0800355 else if (!ARM_LOWREG(r_dest) && !ARM_LOWREG(r_src))
buzbeeefc63692012-11-14 16:31:52 -0800356 opcode = kThumbMovRR_H2H;
buzbeefa57c472012-11-21 12:06:18 -0800357 else if (ARM_LOWREG(r_dest))
buzbeeefc63692012-11-14 16:31:52 -0800358 opcode = kThumbMovRR_H2L;
359 else
360 opcode = kThumbMovRR_L2H;
buzbeefa57c472012-11-21 12:06:18 -0800361 res = RawLIR(cu, cu->current_dalvik_offset, opcode, r_dest, r_src);
362 if (!(cu->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
363 res->flags.is_nop = true;
buzbeeefc63692012-11-14 16:31:52 -0800364 }
365 return res;
366}
367
buzbee02031b12012-11-23 09:41:35 -0800368LIR* ArmCodegen::OpRegCopy(CompilationUnit* cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800369{
buzbeefa57c472012-11-21 12:06:18 -0800370 LIR* res = OpRegCopyNoInsert(cu, r_dest, r_src);
371 AppendLIR(cu, res);
buzbeeefc63692012-11-14 16:31:52 -0800372 return res;
373}
374
buzbee02031b12012-11-23 09:41:35 -0800375void ArmCodegen::OpRegCopyWide(CompilationUnit* cu, int dest_lo, int dest_hi, int src_lo,
376 int src_hi)
buzbeeefc63692012-11-14 16:31:52 -0800377{
buzbeefa57c472012-11-21 12:06:18 -0800378 bool dest_fp = ARM_FPREG(dest_lo) && ARM_FPREG(dest_hi);
379 bool src_fp = ARM_FPREG(src_lo) && ARM_FPREG(src_hi);
380 DCHECK_EQ(ARM_FPREG(src_lo), ARM_FPREG(src_hi));
381 DCHECK_EQ(ARM_FPREG(dest_lo), ARM_FPREG(dest_hi));
382 if (dest_fp) {
383 if (src_fp) {
384 OpRegCopy(cu, S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800385 } else {
buzbeefa57c472012-11-21 12:06:18 -0800386 NewLIR3(cu, kThumb2Fmdrr, S2d(dest_lo, dest_hi), src_lo, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800387 }
388 } else {
buzbeefa57c472012-11-21 12:06:18 -0800389 if (src_fp) {
390 NewLIR3(cu, kThumb2Fmrrd, dest_lo, dest_hi, S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800391 } else {
392 // Handle overlap
buzbeefa57c472012-11-21 12:06:18 -0800393 if (src_hi == dest_lo) {
394 OpRegCopy(cu, dest_hi, src_hi);
395 OpRegCopy(cu, dest_lo, src_lo);
buzbeeefc63692012-11-14 16:31:52 -0800396 } else {
buzbeefa57c472012-11-21 12:06:18 -0800397 OpRegCopy(cu, dest_lo, src_lo);
398 OpRegCopy(cu, dest_hi, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800399 }
400 }
401 }
402}
403
404// Table of magic divisors
buzbeeefc63692012-11-14 16:31:52 -0800405struct MagicTable {
406 uint32_t magic;
407 uint32_t shift;
408 DividePattern pattern;
409};
410
buzbeefa57c472012-11-21 12:06:18 -0800411static const MagicTable magic_table[] = {
buzbeeefc63692012-11-14 16:31:52 -0800412 {0, 0, DivideNone}, // 0
413 {0, 0, DivideNone}, // 1
414 {0, 0, DivideNone}, // 2
415 {0x55555556, 0, Divide3}, // 3
416 {0, 0, DivideNone}, // 4
417 {0x66666667, 1, Divide5}, // 5
418 {0x2AAAAAAB, 0, Divide3}, // 6
419 {0x92492493, 2, Divide7}, // 7
420 {0, 0, DivideNone}, // 8
421 {0x38E38E39, 1, Divide5}, // 9
422 {0x66666667, 2, Divide5}, // 10
423 {0x2E8BA2E9, 1, Divide5}, // 11
424 {0x2AAAAAAB, 1, Divide5}, // 12
425 {0x4EC4EC4F, 2, Divide5}, // 13
426 {0x92492493, 3, Divide7}, // 14
427 {0x88888889, 3, Divide7}, // 15
428};
429
430// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
buzbee02031b12012-11-23 09:41:35 -0800431bool ArmCodegen::SmallLiteralDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
432 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbeeefc63692012-11-14 16:31:52 -0800433{
buzbeefa57c472012-11-21 12:06:18 -0800434 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
buzbeeefc63692012-11-14 16:31:52 -0800435 return false;
436 }
buzbeefa57c472012-11-21 12:06:18 -0800437 DividePattern pattern = magic_table[lit].pattern;
buzbeeefc63692012-11-14 16:31:52 -0800438 if (pattern == DivideNone) {
439 return false;
440 }
441 // Tuning: add rem patterns
buzbeefa57c472012-11-21 12:06:18 -0800442 if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
buzbeeefc63692012-11-14 16:31:52 -0800443 return false;
444 }
445
buzbeefa57c472012-11-21 12:06:18 -0800446 int r_magic = AllocTemp(cu);
447 LoadConstant(cu, r_magic, magic_table[lit].magic);
448 rl_src = LoadValue(cu, rl_src, kCoreReg);
449 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
450 int r_hi = AllocTemp(cu);
451 int r_lo = AllocTemp(cu);
452 NewLIR4(cu, kThumb2Smull, r_lo, r_hi, r_magic, rl_src.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800453 switch(pattern) {
454 case Divide3:
buzbeefa57c472012-11-21 12:06:18 -0800455 OpRegRegRegShift(cu, kOpSub, rl_result.low_reg, r_hi,
456 rl_src.low_reg, EncodeShift(kArmAsr, 31));
buzbeeefc63692012-11-14 16:31:52 -0800457 break;
458 case Divide5:
buzbeefa57c472012-11-21 12:06:18 -0800459 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
460 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
461 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800462 break;
463 case Divide7:
buzbeefa57c472012-11-21 12:06:18 -0800464 OpRegReg(cu, kOpAdd, r_hi, rl_src.low_reg);
465 OpRegRegImm(cu, kOpAsr, r_lo, rl_src.low_reg, 31);
466 OpRegRegRegShift(cu, kOpRsub, rl_result.low_reg, r_lo, r_hi,
467 EncodeShift(kArmAsr, magic_table[lit].shift));
buzbeeefc63692012-11-14 16:31:52 -0800468 break;
469 default:
buzbeecbd6d442012-11-17 14:11:25 -0800470 LOG(FATAL) << "Unexpected pattern: " << pattern;
buzbeeefc63692012-11-14 16:31:52 -0800471 }
buzbeefa57c472012-11-21 12:06:18 -0800472 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800473 return true;
474}
475
buzbee02031b12012-11-23 09:41:35 -0800476LIR* ArmCodegen::GenRegMemCheck(CompilationUnit* cu, ConditionCode c_code,
buzbeeefc63692012-11-14 16:31:52 -0800477 int reg1, int base, int offset, ThrowKind kind)
478{
buzbee52a77fc2012-11-20 19:50:46 -0800479 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800480 return NULL;
481}
482
buzbee02031b12012-11-23 09:41:35 -0800483RegLocation ArmCodegen::GenDivRemLit(CompilationUnit* cu, RegLocation rl_dest, int reg1, int lit,
484 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800485{
buzbee52a77fc2012-11-20 19:50:46 -0800486 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800487 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800488}
489
buzbee02031b12012-11-23 09:41:35 -0800490RegLocation ArmCodegen::GenDivRem(CompilationUnit* cu, RegLocation rl_dest, int reg1, int reg2,
491 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800492{
buzbee52a77fc2012-11-20 19:50:46 -0800493 LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
buzbeefa57c472012-11-21 12:06:18 -0800494 return rl_dest;
buzbeeefc63692012-11-14 16:31:52 -0800495}
496
buzbee02031b12012-11-23 09:41:35 -0800497bool ArmCodegen::GenInlinedMinMaxInt(CompilationUnit *cu, CallInfo* info, bool is_min)
buzbeeefc63692012-11-14 16:31:52 -0800498{
buzbeefa57c472012-11-21 12:06:18 -0800499 DCHECK_EQ(cu->instruction_set, kThumb2);
500 RegLocation rl_src1 = info->args[0];
501 RegLocation rl_src2 = info->args[1];
502 rl_src1 = LoadValue(cu, rl_src1, kCoreReg);
503 rl_src2 = LoadValue(cu, rl_src2, kCoreReg);
504 RegLocation rl_dest = InlineTarget(cu, info);
505 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
506 OpRegReg(cu, kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
buzbee02031b12012-11-23 09:41:35 -0800507 OpIT(cu, (is_min) ? kCondGt : kCondLt, "E");
buzbeefa57c472012-11-21 12:06:18 -0800508 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src2.low_reg);
509 OpRegReg(cu, kOpMov, rl_result.low_reg, rl_src1.low_reg);
510 GenBarrier(cu);
511 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800512 return true;
513}
514
buzbee02031b12012-11-23 09:41:35 -0800515void ArmCodegen::OpLea(CompilationUnit* cu, int rBase, int reg1, int reg2, int scale, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800516{
buzbee52a77fc2012-11-20 19:50:46 -0800517 LOG(FATAL) << "Unexpected use of OpLea for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800518}
519
buzbee02031b12012-11-23 09:41:35 -0800520void ArmCodegen::OpTlsCmp(CompilationUnit* cu, int offset, int val)
buzbeeefc63692012-11-14 16:31:52 -0800521{
buzbee52a77fc2012-11-20 19:50:46 -0800522 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800523}
524
buzbee02031b12012-11-23 09:41:35 -0800525bool ArmCodegen::GenInlinedCas32(CompilationUnit* cu, CallInfo* info, bool need_write_barrier) {
buzbeefa57c472012-11-21 12:06:18 -0800526 DCHECK_EQ(cu->instruction_set, kThumb2);
527 // Unused - RegLocation rl_src_unsafe = info->args[0];
528 RegLocation rl_src_obj= info->args[1]; // Object - known non-null
529 RegLocation rl_src_offset= info->args[2]; // long low
530 rl_src_offset.wide = 0; // ignore high half in info->args[3]
531 RegLocation rl_src_expected= info->args[4]; // int or Object
532 RegLocation rl_src_new_value= info->args[5]; // int or Object
533 RegLocation rl_dest = InlineTarget(cu, info); // boolean place for result
buzbeeefc63692012-11-14 16:31:52 -0800534
535
buzbee1bc37c62012-11-20 13:35:41 -0800536 // Release store semantics, get the barrier out of the way. TODO: revisit
buzbeefa57c472012-11-21 12:06:18 -0800537 GenMemBarrier(cu, kStoreLoad);
buzbeeefc63692012-11-14 16:31:52 -0800538
buzbeefa57c472012-11-21 12:06:18 -0800539 RegLocation rl_object = LoadValue(cu, rl_src_obj, kCoreReg);
540 RegLocation rl_new_value = LoadValue(cu, rl_src_new_value, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800541
buzbee6a791b22013-02-07 05:35:08 -0800542 if (need_write_barrier && !IsConstantNullRef(cu, rl_new_value)) {
buzbeeefc63692012-11-14 16:31:52 -0800543 // Mark card for object assuming new value is stored.
buzbeefa57c472012-11-21 12:06:18 -0800544 MarkGCCard(cu, rl_new_value.low_reg, rl_object.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800545 }
546
buzbeefa57c472012-11-21 12:06:18 -0800547 RegLocation rl_offset = LoadValue(cu, rl_src_offset, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800548
buzbeefa57c472012-11-21 12:06:18 -0800549 int r_ptr = AllocTemp(cu);
550 OpRegRegReg(cu, kOpAdd, r_ptr, rl_object.low_reg, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800551
buzbeefa57c472012-11-21 12:06:18 -0800552 // Free now unneeded rl_object and rl_offset to give more temps.
553 ClobberSReg(cu, rl_object.s_reg_low);
554 FreeTemp(cu, rl_object.low_reg);
555 ClobberSReg(cu, rl_offset.s_reg_low);
556 FreeTemp(cu, rl_offset.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800557
buzbeefa57c472012-11-21 12:06:18 -0800558 int r_old_value = AllocTemp(cu);
559 NewLIR3(cu, kThumb2Ldrex, r_old_value, r_ptr, 0); // r_old_value := [r_ptr]
buzbeeefc63692012-11-14 16:31:52 -0800560
buzbeefa57c472012-11-21 12:06:18 -0800561 RegLocation rl_expected = LoadValue(cu, rl_src_expected, kCoreReg);
buzbeeefc63692012-11-14 16:31:52 -0800562
buzbeefa57c472012-11-21 12:06:18 -0800563 // if (r_old_value == rExpected) {
564 // [r_ptr] <- r_new_value && r_result := success ? 0 : 1
565 // r_result ^= 1
buzbeeefc63692012-11-14 16:31:52 -0800566 // } else {
buzbeefa57c472012-11-21 12:06:18 -0800567 // r_result := 0
buzbeeefc63692012-11-14 16:31:52 -0800568 // }
buzbeefa57c472012-11-21 12:06:18 -0800569 OpRegReg(cu, kOpCmp, r_old_value, rl_expected.low_reg);
570 FreeTemp(cu, r_old_value); // Now unneeded.
571 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbee02031b12012-11-23 09:41:35 -0800572 OpIT(cu, kCondEq, "TE");
buzbeefa57c472012-11-21 12:06:18 -0800573 NewLIR4(cu, kThumb2Strex, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
574 FreeTemp(cu, r_ptr); // Now unneeded.
575 OpRegImm(cu, kOpXor, rl_result.low_reg, 1);
576 OpRegReg(cu, kOpXor, rl_result.low_reg, rl_result.low_reg);
buzbeeefc63692012-11-14 16:31:52 -0800577
buzbeefa57c472012-11-21 12:06:18 -0800578 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800579
580 return true;
581}
582
buzbee02031b12012-11-23 09:41:35 -0800583LIR* ArmCodegen::OpPcRelLoad(CompilationUnit* cu, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800584{
buzbeefa57c472012-11-21 12:06:18 -0800585 return RawLIR(cu, cu->current_dalvik_offset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800586}
587
buzbee02031b12012-11-23 09:41:35 -0800588LIR* ArmCodegen::OpVldm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800589{
buzbeefa57c472012-11-21 12:06:18 -0800590 return NewLIR3(cu, kThumb2Vldms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800591}
592
buzbee02031b12012-11-23 09:41:35 -0800593LIR* ArmCodegen::OpVstm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800594{
buzbeefa57c472012-11-21 12:06:18 -0800595 return NewLIR3(cu, kThumb2Vstms, rBase, fr0, count);
buzbeeefc63692012-11-14 16:31:52 -0800596}
597
buzbee02031b12012-11-23 09:41:35 -0800598void ArmCodegen::GenMultiplyByTwoBitMultiplier(CompilationUnit* cu, RegLocation rl_src,
599 RegLocation rl_result, int lit,
600 int first_bit, int second_bit)
buzbeeefc63692012-11-14 16:31:52 -0800601{
buzbeefa57c472012-11-21 12:06:18 -0800602 OpRegRegRegShift(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg,
603 EncodeShift(kArmLsl, second_bit - first_bit));
604 if (first_bit != 0) {
605 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
buzbeeefc63692012-11-14 16:31:52 -0800606 }
607}
608
buzbee02031b12012-11-23 09:41:35 -0800609void ArmCodegen::GenDivZeroCheck(CompilationUnit* cu, int reg_lo, int reg_hi)
buzbeeefc63692012-11-14 16:31:52 -0800610{
buzbeefa57c472012-11-21 12:06:18 -0800611 int t_reg = AllocTemp(cu);
612 NewLIR4(cu, kThumb2OrrRRRs, t_reg, reg_lo, reg_hi, 0);
613 FreeTemp(cu, t_reg);
614 GenCheck(cu, kCondEq, kThrowDivZero);
buzbeeefc63692012-11-14 16:31:52 -0800615}
616
617// Test suspend flag, return target of taken suspend branch
buzbee02031b12012-11-23 09:41:35 -0800618LIR* ArmCodegen::OpTestSuspend(CompilationUnit* cu, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800619{
buzbeefa57c472012-11-21 12:06:18 -0800620 NewLIR2(cu, kThumbSubRI8, rARM_SUSPEND, 1);
621 return OpCondBranch(cu, (target == NULL) ? kCondEq : kCondNe, target);
buzbeeefc63692012-11-14 16:31:52 -0800622}
623
624// Decrement register and branch on condition
buzbee02031b12012-11-23 09:41:35 -0800625LIR* ArmCodegen::OpDecAndBranch(CompilationUnit* cu, ConditionCode c_code, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800626{
627 // Combine sub & test using sub setflags encoding here
buzbeefa57c472012-11-21 12:06:18 -0800628 NewLIR3(cu, kThumb2SubsRRI12, reg, reg, 1);
629 return OpCondBranch(cu, c_code, target);
buzbeeefc63692012-11-14 16:31:52 -0800630}
631
buzbee02031b12012-11-23 09:41:35 -0800632void ArmCodegen::GenMemBarrier(CompilationUnit* cu, MemBarrierKind barrier_kind)
buzbeeefc63692012-11-14 16:31:52 -0800633{
634#if ANDROID_SMP != 0
buzbeefa57c472012-11-21 12:06:18 -0800635 int dmb_flavor;
buzbee1bc37c62012-11-20 13:35:41 -0800636 // TODO: revisit Arm barrier kinds
buzbeefa57c472012-11-21 12:06:18 -0800637 switch (barrier_kind) {
638 case kLoadStore: dmb_flavor = kSY; break;
639 case kLoadLoad: dmb_flavor = kSY; break;
640 case kStoreStore: dmb_flavor = kST; break;
641 case kStoreLoad: dmb_flavor = kSY; break;
buzbee1bc37c62012-11-20 13:35:41 -0800642 default:
buzbeefa57c472012-11-21 12:06:18 -0800643 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
644 dmb_flavor = kSY; // quiet gcc.
buzbee1bc37c62012-11-20 13:35:41 -0800645 break;
646 }
buzbeefa57c472012-11-21 12:06:18 -0800647 LIR* dmb = NewLIR1(cu, kThumb2Dmb, dmb_flavor);
648 dmb->def_mask = ENCODE_ALL;
buzbeeefc63692012-11-14 16:31:52 -0800649#endif
650}
651
buzbeea5954be2013-02-07 10:41:40 -0800652void ArmCodegen::GenNegLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800653{
buzbeefa57c472012-11-21 12:06:18 -0800654 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
655 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
656 int z_reg = AllocTemp(cu);
657 LoadConstantNoClobber(cu, z_reg, 0);
buzbeeefc63692012-11-14 16:31:52 -0800658 // Check for destructive overlap
buzbeefa57c472012-11-21 12:06:18 -0800659 if (rl_result.low_reg == rl_src.high_reg) {
660 int t_reg = AllocTemp(cu);
661 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
662 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, t_reg);
663 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800664 } else {
buzbeefa57c472012-11-21 12:06:18 -0800665 OpRegRegReg(cu, kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
666 OpRegRegReg(cu, kOpSbc, rl_result.high_reg, z_reg, rl_src.high_reg);
buzbeeefc63692012-11-14 16:31:52 -0800667 }
buzbeefa57c472012-11-21 12:06:18 -0800668 FreeTemp(cu, z_reg);
669 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800670}
671
buzbee4ef3e452012-12-14 13:35:28 -0800672
673 /*
674 * Check to see if a result pair has a misaligned overlap with an operand pair. This
675 * is not usual for dx to generate, but it is legal (for now). In a future rev of
676 * dex, we'll want to make this case illegal.
677 */
678static bool BadOverlap(CompilationUnit* cu, RegLocation rl_src, RegLocation rl_dest)
679{
680 DCHECK(rl_src.wide);
681 DCHECK(rl_dest.wide);
682 return (abs(SRegToVReg(cu, rl_src.s_reg_low) - SRegToVReg(cu, rl_dest.s_reg_low)) == 1);
683}
684
685void ArmCodegen::GenMulLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
686 RegLocation rl_src2)
687{
688 /*
689 * To pull off inline multiply, we have a worst-case requirement of 8 temporary
690 * registers. Normally for Arm, we get 5. We can get to 6 by including
691 * lr in the temp set. The only problematic case is all operands and result are
692 * distinct, and none have been promoted. In that case, we can succeed by aggressively
693 * freeing operand temp registers after they are no longer needed. All other cases
694 * can proceed normally. We'll just punt on the case of the result having a misaligned
695 * overlap with either operand and send that case to a runtime handler.
696 */
697 RegLocation rl_result;
698 if (BadOverlap(cu, rl_src1, rl_dest) || (BadOverlap(cu, rl_src2, rl_dest))) {
699 int func_offset = ENTRYPOINT_OFFSET(pLmul);
700 FlushAllRegs(cu);
701 CallRuntimeHelperRegLocationRegLocation(cu, func_offset, rl_src1, rl_src2, false);
702 rl_result = GetReturnWide(cu, false);
703 StoreValueWide(cu, rl_dest, rl_result);
704 return;
705 }
706 // Temporarily add LR to the temp pool, and assign it to tmp1
707 MarkTemp(cu, rARM_LR);
708 FreeTemp(cu, rARM_LR);
709 int tmp1 = rARM_LR;
710 LockTemp(cu, rARM_LR);
711
712 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
713 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
714
715 bool special_case = true;
716 // If operands are the same, or any pair has been promoted we're not the special case.
717 if ((rl_src1.s_reg_low == rl_src2.s_reg_low) ||
718 (!IsTemp(cu, rl_src1.low_reg) && !IsTemp(cu, rl_src1.high_reg)) ||
719 (!IsTemp(cu, rl_src2.low_reg) && !IsTemp(cu, rl_src2.high_reg))) {
720 special_case = false;
721 }
722 // Tuning: if rl_dest has been promoted and is *not* either operand, could use directly.
723 int res_lo = AllocTemp(cu);
724 int res_hi;
725 if (rl_src1.low_reg == rl_src2.low_reg) {
726 res_hi = AllocTemp(cu);
727 NewLIR3(cu, kThumb2MulRRR, tmp1, rl_src1.low_reg, rl_src1.high_reg);
728 NewLIR4(cu, kThumb2Umull, res_lo, res_hi, rl_src1.low_reg, rl_src1.low_reg);
729 OpRegRegRegShift(cu, kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1));
730 } else {
731 // In the special case, all temps are now allocated
732 NewLIR3(cu, kThumb2MulRRR, tmp1, rl_src2.low_reg, rl_src1.high_reg);
733 if (special_case) {
734 DCHECK_NE(rl_src1.low_reg, rl_src2.low_reg);
735 DCHECK_NE(rl_src1.high_reg, rl_src2.high_reg);
736 FreeTemp(cu, rl_src1.high_reg);
737 }
738 res_hi = AllocTemp(cu);
739
740 NewLIR4(cu, kThumb2Umull, res_lo, res_hi, rl_src2.low_reg, rl_src1.low_reg);
741 NewLIR4(cu, kThumb2Mla, tmp1, rl_src1.low_reg, rl_src2.high_reg, tmp1);
742 NewLIR4(cu, kThumb2AddRRR, res_hi, tmp1, res_hi, 0);
743 if (special_case) {
744 FreeTemp(cu, rl_src1.low_reg);
745 Clobber(cu, rl_src1.low_reg);
746 Clobber(cu, rl_src1.high_reg);
747 }
748 }
749 FreeTemp(cu, tmp1);
750 rl_result = GetReturnWide(cu, false); // Just using as a template.
751 rl_result.low_reg = res_lo;
752 rl_result.high_reg = res_hi;
753 StoreValueWide(cu, rl_dest, rl_result);
754 // Now, restore lr to its non-temp status.
755 Clobber(cu, rARM_LR);
756 UnmarkTemp(cu, rARM_LR);
757}
758
buzbeea5954be2013-02-07 10:41:40 -0800759void ArmCodegen::GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800760 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800761{
buzbee52a77fc2012-11-20 19:50:46 -0800762 LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800763}
764
buzbeea5954be2013-02-07 10:41:40 -0800765void ArmCodegen::GenSubLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800766 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800767{
buzbee52a77fc2012-11-20 19:50:46 -0800768 LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800769}
770
buzbeea5954be2013-02-07 10:41:40 -0800771void ArmCodegen::GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800772 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800773{
buzbee52a77fc2012-11-20 19:50:46 -0800774 LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800775}
776
buzbeea5954be2013-02-07 10:41:40 -0800777void ArmCodegen::GenOrLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800778 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800779{
buzbee52a77fc2012-11-20 19:50:46 -0800780 LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800781}
782
buzbeea5954be2013-02-07 10:41:40 -0800783void ArmCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800784 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800785{
786 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800787}
788
buzbeee6285f92012-12-06 15:57:46 -0800789/*
790 * Generate array load
791 */
792void ArmCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
793 RegLocation rl_index, RegLocation rl_dest, int scale)
794{
795 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800796 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800797 int data_offset;
798 RegLocation rl_result;
buzbee4ef3e452012-12-14 13:35:28 -0800799 bool constant_index = rl_index.is_const;
buzbeee6285f92012-12-06 15:57:46 -0800800 rl_array = LoadValue(cu, rl_array, kCoreReg);
buzbee4ef3e452012-12-14 13:35:28 -0800801 if (!constant_index) {
802 rl_index = LoadValue(cu, rl_index, kCoreReg);
803 }
buzbeee6285f92012-12-06 15:57:46 -0800804
805 if (rl_dest.wide) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800806 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800807 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800808 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800809 }
810
buzbee4ef3e452012-12-14 13:35:28 -0800811 // If index is constant, just fold it into the data offset
812 if (constant_index) {
813 data_offset += ConstantValue(cu, rl_index) << scale;
814 }
815
buzbeee6285f92012-12-06 15:57:46 -0800816 /* null object? */
817 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
818
819 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
820 int reg_len = INVALID_REG;
821 if (needs_range_check) {
822 reg_len = AllocTemp(cu);
823 /* Get len */
824 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
825 }
buzbee4ef3e452012-12-14 13:35:28 -0800826 if (rl_dest.wide || rl_dest.fp || constant_index) {
827 int reg_ptr;
828 if (constant_index) {
829 reg_ptr = rl_array.low_reg; // NOTE: must not alter reg_ptr in constant case.
830 } else {
831 // No special indexed operation, lea + load w/ displacement
832 reg_ptr = AllocTemp(cu);
833 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
834 EncodeShift(kArmLsl, scale));
835 FreeTemp(cu, rl_index.low_reg);
836 }
buzbeee6285f92012-12-06 15:57:46 -0800837 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
838
839 if (needs_range_check) {
buzbee4ef3e452012-12-14 13:35:28 -0800840 if (constant_index) {
841 GenImmedCheck(cu, kCondLs, reg_len, ConstantValue(cu, rl_index), kThrowConstantArrayBounds);
842 } else {
843 GenRegRegCheck(cu, kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
844 }
buzbeee6285f92012-12-06 15:57:46 -0800845 FreeTemp(cu, reg_len);
846 }
847 if (rl_dest.wide) {
848 LoadBaseDispWide(cu, reg_ptr, data_offset, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
buzbee4ef3e452012-12-14 13:35:28 -0800849 if (!constant_index) {
850 FreeTemp(cu, reg_ptr);
851 }
buzbeee6285f92012-12-06 15:57:46 -0800852 StoreValueWide(cu, rl_dest, rl_result);
853 } else {
854 LoadBaseDisp(cu, reg_ptr, data_offset, rl_result.low_reg, size, INVALID_SREG);
buzbee4ef3e452012-12-14 13:35:28 -0800855 if (!constant_index) {
856 FreeTemp(cu, reg_ptr);
857 }
buzbeee6285f92012-12-06 15:57:46 -0800858 StoreValue(cu, rl_dest, rl_result);
859 }
860 } else {
861 // Offset base, then use indexed load
862 int reg_ptr = AllocTemp(cu);
863 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
864 FreeTemp(cu, rl_array.low_reg);
865 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
866
867 if (needs_range_check) {
868 // TODO: change kCondCS to a more meaningful name, is the sense of
869 // carry-set/clear flipped?
870 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
871 FreeTemp(cu, reg_len);
872 }
873 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
874 FreeTemp(cu, reg_ptr);
875 StoreValue(cu, rl_dest, rl_result);
876 }
877}
878
879/*
880 * Generate array store
881 *
882 */
883void ArmCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
884 RegLocation rl_index, RegLocation rl_src, int scale)
885{
886 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800887 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800888 int data_offset;
buzbee4ef3e452012-12-14 13:35:28 -0800889 bool constant_index = rl_index.is_const;
buzbeee6285f92012-12-06 15:57:46 -0800890
buzbee4ef3e452012-12-14 13:35:28 -0800891 if (rl_src.wide) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800892 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800893 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800894 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800895 }
896
buzbee4ef3e452012-12-14 13:35:28 -0800897 // If index is constant, just fold it into the data offset.
898 if (constant_index) {
899 data_offset += ConstantValue(cu, rl_index) << scale;
900 }
901
buzbeee6285f92012-12-06 15:57:46 -0800902 rl_array = LoadValue(cu, rl_array, kCoreReg);
buzbee4ef3e452012-12-14 13:35:28 -0800903 if (!constant_index) {
904 rl_index = LoadValue(cu, rl_index, kCoreReg);
905 }
906
907 int reg_ptr;
908 if (constant_index) {
909 reg_ptr = rl_array.low_reg;
910 } else if (IsTemp(cu, rl_array.low_reg)) {
buzbeee6285f92012-12-06 15:57:46 -0800911 Clobber(cu, rl_array.low_reg);
912 reg_ptr = rl_array.low_reg;
913 } else {
914 reg_ptr = AllocTemp(cu);
915 }
916
917 /* null object? */
918 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
919
920 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
921 int reg_len = INVALID_REG;
922 if (needs_range_check) {
923 reg_len = AllocTemp(cu);
924 //NOTE: max live temps(4) here.
925 /* Get len */
926 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
927 }
928 /* at this point, reg_ptr points to array, 2 live temps */
buzbee4ef3e452012-12-14 13:35:28 -0800929 if (rl_src.wide || rl_src.fp || constant_index) {
buzbeee6285f92012-12-06 15:57:46 -0800930 if (rl_src.wide) {
931 rl_src = LoadValueWide(cu, rl_src, reg_class);
932 } else {
933 rl_src = LoadValue(cu, rl_src, reg_class);
934 }
buzbee4ef3e452012-12-14 13:35:28 -0800935 if (!constant_index) {
936 OpRegRegRegShift(cu, kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
937 EncodeShift(kArmLsl, scale));
938 }
buzbeee6285f92012-12-06 15:57:46 -0800939 if (needs_range_check) {
buzbee4ef3e452012-12-14 13:35:28 -0800940 if (constant_index) {
941 GenImmedCheck(cu, kCondLs, reg_len, ConstantValue(cu, rl_index), kThrowConstantArrayBounds);
942 } else {
943 GenRegRegCheck(cu, kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
944 }
buzbeee6285f92012-12-06 15:57:46 -0800945 FreeTemp(cu, reg_len);
946 }
buzbee4ef3e452012-12-14 13:35:28 -0800947
buzbeee6285f92012-12-06 15:57:46 -0800948 if (rl_src.wide) {
949 StoreBaseDispWide(cu, reg_ptr, data_offset, rl_src.low_reg, rl_src.high_reg);
950 } else {
951 StoreBaseDisp(cu, reg_ptr, data_offset, rl_src.low_reg, size);
952 }
953 } else {
954 /* reg_ptr -> array data */
955 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
956 rl_src = LoadValue(cu, rl_src, reg_class);
957 if (needs_range_check) {
958 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
959 FreeTemp(cu, reg_len);
960 }
961 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
962 scale, size);
963 }
buzbee4ef3e452012-12-14 13:35:28 -0800964 if (!constant_index) {
965 FreeTemp(cu, reg_ptr);
966 }
buzbeee6285f92012-12-06 15:57:46 -0800967}
968
969/*
970 * Generate array store
971 *
972 */
973void ArmCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
974 RegLocation rl_index, RegLocation rl_src, int scale)
975{
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800976 int len_offset = mirror::Array::LengthOffset().Int32Value();
977 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800978
979 FlushAllRegs(cu); // Use explicit registers
980 LockCallTemps(cu);
981
982 int r_value = TargetReg(kArg0); // Register holding value
983 int r_array_class = TargetReg(kArg1); // Register holding array's Class
984 int r_array = TargetReg(kArg2); // Register holding array
985 int r_index = TargetReg(kArg3); // Register holding index into array
986
987 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
988 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
989 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
990
991 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
992
993 // Store of null?
994 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
995
996 // Get the array's class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800997 LoadWordDisp(cu, r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
buzbeee6285f92012-12-06 15:57:46 -0800998 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
999 r_array_class, true);
1000 // Redo LoadValues in case they didn't survive the call.
1001 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
1002 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
1003 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
1004 r_array_class = INVALID_REG;
1005
1006 // Branch here if value to be stored == null
1007 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
1008 null_value_check->target = target;
1009
1010 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1011 int reg_len = INVALID_REG;
1012 if (needs_range_check) {
1013 reg_len = TargetReg(kArg1);
1014 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
1015 }
1016 /* r_ptr -> array data */
1017 int r_ptr = AllocTemp(cu);
1018 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
1019 if (needs_range_check) {
1020 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
1021 }
1022 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
1023 FreeTemp(cu, r_ptr);
1024 FreeTemp(cu, r_index);
buzbee6a791b22013-02-07 05:35:08 -08001025 if (!IsConstantNullRef(cu, rl_src)) {
1026 MarkGCCard(cu, r_value, r_array);
1027 }
buzbeee6285f92012-12-06 15:57:46 -08001028}
1029
buzbeea5954be2013-02-07 10:41:40 -08001030void ArmCodegen::GenShiftImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
buzbee4ef3e452012-12-14 13:35:28 -08001031 RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift)
1032{
1033 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
1034 // Per spec, we only care about low 6 bits of shift amount.
1035 int shift_amount = ConstantValue(cu, rl_shift) & 0x3f;
1036 if (shift_amount == 0) {
1037 StoreValueWide(cu, rl_dest, rl_src);
buzbeea5954be2013-02-07 10:41:40 -08001038 return;
buzbee4ef3e452012-12-14 13:35:28 -08001039 }
1040 if (BadOverlap(cu, rl_src, rl_dest)) {
buzbeea5954be2013-02-07 10:41:40 -08001041 GenShiftOpLong(cu, opcode, rl_dest, rl_src, rl_shift);
1042 return;
buzbee4ef3e452012-12-14 13:35:28 -08001043 }
1044 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1045 switch(opcode) {
1046 case Instruction::SHL_LONG:
1047 case Instruction::SHL_LONG_2ADDR:
1048 if (shift_amount == 1) {
1049 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg);
1050 OpRegRegReg(cu, kOpAdc, rl_result.high_reg, rl_src.high_reg, rl_src.high_reg);
1051 } else if (shift_amount == 32) {
1052 OpRegCopy(cu, rl_result.high_reg, rl_src.low_reg);
1053 LoadConstant(cu, rl_result.low_reg, 0);
1054 } else if (shift_amount > 31) {
1055 OpRegRegImm(cu, kOpLsl, rl_result.high_reg, rl_src.low_reg, shift_amount - 32);
1056 LoadConstant(cu, rl_result.low_reg, 0);
1057 } else {
1058 OpRegRegImm(cu, kOpLsl, rl_result.high_reg, rl_src.high_reg, shift_amount);
1059 OpRegRegRegShift(cu, kOpOr, rl_result.high_reg, rl_result.high_reg, rl_src.low_reg,
1060 EncodeShift(kArmLsr, 32 - shift_amount));
1061 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_src.low_reg, shift_amount);
1062 }
1063 break;
1064 case Instruction::SHR_LONG:
1065 case Instruction::SHR_LONG_2ADDR:
1066 if (shift_amount == 32) {
1067 OpRegCopy(cu, rl_result.low_reg, rl_src.high_reg);
1068 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1069 } else if (shift_amount > 31) {
1070 OpRegRegImm(cu, kOpAsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1071 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1072 } else {
1073 int t_reg = AllocTemp(cu);
1074 OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1075 OpRegRegRegShift(cu, kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1076 EncodeShift(kArmLsl, 32 - shift_amount));
1077 FreeTemp(cu, t_reg);
1078 OpRegRegImm(cu, kOpAsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1079 }
1080 break;
1081 case Instruction::USHR_LONG:
1082 case Instruction::USHR_LONG_2ADDR:
1083 if (shift_amount == 32) {
1084 OpRegCopy(cu, rl_result.low_reg, rl_src.high_reg);
1085 LoadConstant(cu, rl_result.high_reg, 0);
1086 } else if (shift_amount > 31) {
1087 OpRegRegImm(cu, kOpLsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1088 LoadConstant(cu, rl_result.high_reg, 0);
1089 } else {
1090 int t_reg = AllocTemp(cu);
1091 OpRegRegImm(cu, kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1092 OpRegRegRegShift(cu, kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1093 EncodeShift(kArmLsl, 32 - shift_amount));
1094 FreeTemp(cu, t_reg);
1095 OpRegRegImm(cu, kOpLsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1096 }
1097 break;
1098 default:
1099 LOG(FATAL) << "Unexpected case";
buzbee4ef3e452012-12-14 13:35:28 -08001100 }
1101 StoreValueWide(cu, rl_dest, rl_result);
buzbee4ef3e452012-12-14 13:35:28 -08001102}
1103
buzbeea5954be2013-02-07 10:41:40 -08001104void ArmCodegen::GenArithImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
buzbee4ef3e452012-12-14 13:35:28 -08001105 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
1106{
1107 if ((opcode == Instruction::SUB_LONG_2ADDR) || (opcode == Instruction::SUB_LONG)) {
1108 if (!rl_src2.is_const) {
1109 // Don't bother with special handling for subtract from immediate.
buzbeea5954be2013-02-07 10:41:40 -08001110 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1111 return;
buzbee4ef3e452012-12-14 13:35:28 -08001112 }
1113 } else {
1114 // Normalize
1115 if (!rl_src2.is_const) {
1116 DCHECK(rl_src1.is_const);
1117 RegLocation rl_temp = rl_src1;
1118 rl_src1 = rl_src2;
1119 rl_src2 = rl_temp;
1120 }
1121 }
1122 if (BadOverlap(cu, rl_src1, rl_dest)) {
buzbeea5954be2013-02-07 10:41:40 -08001123 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1124 return;
buzbee4ef3e452012-12-14 13:35:28 -08001125 }
1126 DCHECK(rl_src2.is_const);
1127 int64_t val = ConstantValueWide(cu, rl_src2);
1128 uint32_t val_lo = Low32Bits(val);
1129 uint32_t val_hi = High32Bits(val);
1130 int32_t mod_imm_lo = ModifiedImmediate(val_lo);
1131 int32_t mod_imm_hi = ModifiedImmediate(val_hi);
1132
1133 // Only a subset of add/sub immediate instructions set carry - so bail if we don't fit
1134 switch(opcode) {
1135 case Instruction::ADD_LONG:
1136 case Instruction::ADD_LONG_2ADDR:
1137 case Instruction::SUB_LONG:
1138 case Instruction::SUB_LONG_2ADDR:
1139 if ((mod_imm_lo < 0) || (mod_imm_hi < 0)) {
buzbeea5954be2013-02-07 10:41:40 -08001140 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
1141 return;
buzbee4ef3e452012-12-14 13:35:28 -08001142 }
1143 break;
1144 default:
1145 break;
1146 }
1147 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
1148 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
1149 // NOTE: once we've done the EvalLoc on dest, we can no longer bail.
1150 switch (opcode) {
1151 case Instruction::ADD_LONG:
1152 case Instruction::ADD_LONG_2ADDR:
1153 NewLIR3(cu, kThumb2AddRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1154 NewLIR3(cu, kThumb2AdcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1155 break;
1156 case Instruction::OR_LONG:
1157 case Instruction::OR_LONG_2ADDR:
1158 if ((val_lo != 0) || (rl_result.low_reg != rl_src1.low_reg)) {
1159 OpRegRegImm(cu, kOpOr, rl_result.low_reg, rl_src1.low_reg, val_lo);
1160 }
1161 if ((val_hi != 0) || (rl_result.high_reg != rl_src1.high_reg)) {
1162 OpRegRegImm(cu, kOpOr, rl_result.high_reg, rl_src1.high_reg, val_hi);
1163 }
1164 break;
1165 case Instruction::XOR_LONG:
1166 case Instruction::XOR_LONG_2ADDR:
1167 OpRegRegImm(cu, kOpXor, rl_result.low_reg, rl_src1.low_reg, val_lo);
1168 OpRegRegImm(cu, kOpXor, rl_result.high_reg, rl_src1.high_reg, val_hi);
1169 break;
1170 case Instruction::AND_LONG:
1171 case Instruction::AND_LONG_2ADDR:
1172 if ((val_lo != 0xffffffff) || (rl_result.low_reg != rl_src1.low_reg)) {
1173 OpRegRegImm(cu, kOpAnd, rl_result.low_reg, rl_src1.low_reg, val_lo);
1174 }
1175 if ((val_hi != 0xffffffff) || (rl_result.high_reg != rl_src1.high_reg)) {
1176 OpRegRegImm(cu, kOpAnd, rl_result.high_reg, rl_src1.high_reg, val_hi);
1177 }
1178 break;
1179 case Instruction::SUB_LONG_2ADDR:
1180 case Instruction::SUB_LONG:
1181 NewLIR3(cu, kThumb2SubRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1182 NewLIR3(cu, kThumb2SbcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1183 break;
1184 default:
1185 LOG(FATAL) << "Unexpected opcode " << opcode;
1186 }
1187 StoreValueWide(cu, rl_dest, rl_result);
buzbee4ef3e452012-12-14 13:35:28 -08001188}
1189
buzbeeefc63692012-11-14 16:31:52 -08001190} // namespace art