blob: feea896e9fe9edb3c6d5f47aa954c85c10556e0f [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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 "arm_lir.h"
20#include "codegen_arm.h"
21#include "dex/quick/mir_to_lir-inl.h"
22#include "mirror/array.h"
23#include "oat/runtime/oat_support_entrypoints.h"
24
25namespace art {
26
27LIR* ArmMir2Lir::OpCmpBranch(ConditionCode cond, int src1,
28 int src2, LIR* target)
29{
30 OpRegReg(kOpCmp, src1, src2);
31 return OpCondBranch(cond, target);
32}
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 */
44LIR* ArmMir2Lir::OpIT(ConditionCode ccode, const char* guide)
45{
46 int mask;
47 int mask3 = 0;
48 int mask2 = 0;
49 int mask1 = 0;
50 ArmConditionCode code = ArmConditionEncoding(ccode);
51 int cond_bit = code & 1;
52 int alt_bit = cond_bit ^ 1;
53
54 //Note: case fallthroughs intentional
55 switch (strlen(guide)) {
56 case 3:
57 mask1 = (guide[2] == 'T') ? cond_bit : alt_bit;
58 case 2:
59 mask2 = (guide[1] == 'T') ? cond_bit : alt_bit;
60 case 1:
61 mask3 = (guide[0] == 'T') ? cond_bit : alt_bit;
62 break;
63 case 0:
64 break;
65 default:
66 LOG(FATAL) << "OAT: bad case in OpIT";
67 }
68 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
69 (1 << (3 - strlen(guide)));
70 return NewLIR2(kThumb2It, code, mask);
71}
72
73/*
74 * 64-bit 3way compare function.
75 * mov rX, #-1
76 * cmp op1hi, op2hi
77 * blt done
78 * bgt flip
79 * sub rX, op1lo, op2lo (treat as unsigned)
80 * beq done
81 * ite hi
82 * mov(hi) rX, #-1
83 * mov(!hi) rX, #1
84 * flip:
85 * neg rX
86 * done:
87 */
88void ArmMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
89 RegLocation rl_src2)
90{
91 LIR* target1;
92 LIR* target2;
93 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
94 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
95 int t_reg = AllocTemp();
96 LoadConstant(t_reg, -1);
97 OpRegReg(kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
98 LIR* branch1 = OpCondBranch(kCondLt, NULL);
99 LIR* branch2 = OpCondBranch(kCondGt, NULL);
100 OpRegRegReg(kOpSub, t_reg, rl_src1.low_reg, rl_src2.low_reg);
101 LIR* branch3 = OpCondBranch(kCondEq, NULL);
102
103 OpIT(kCondHi, "E");
104 NewLIR2(kThumb2MovImmShift, t_reg, ModifiedImmediate(-1));
105 LoadConstant(t_reg, 1);
106 GenBarrier();
107
108 target2 = NewLIR0(kPseudoTargetLabel);
109 OpRegReg(kOpNeg, t_reg, t_reg);
110
111 target1 = NewLIR0(kPseudoTargetLabel);
112
113 RegLocation rl_temp = LocCReturn(); // Just using as template, will change
114 rl_temp.low_reg = t_reg;
115 StoreValue(rl_dest, rl_temp);
116 FreeTemp(t_reg);
117
118 branch1->target = target1;
119 branch2->target = target2;
120 branch3->target = branch1->target;
121}
122
123void ArmMir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
124 int64_t val, ConditionCode ccode)
125{
126 int32_t val_lo = Low32Bits(val);
127 int32_t val_hi = High32Bits(val);
128 DCHECK(ModifiedImmediate(val_lo) >= 0);
129 DCHECK(ModifiedImmediate(val_hi) >= 0);
130 LIR* taken = &block_label_list_[bb->taken->id];
131 LIR* not_taken = &block_label_list_[bb->fall_through->id];
132 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
133 int32_t low_reg = rl_src1.low_reg;
134 int32_t high_reg = rl_src1.high_reg;
135
136 switch(ccode) {
137 case kCondEq:
138 case kCondNe:
139 LIR* target;
140 ConditionCode condition;
141 if (ccode == kCondEq) {
142 target = not_taken;
143 condition = kCondEq;
144 } else {
145 target = taken;
146 condition = kCondNe;
147 }
148 if (val == 0) {
149 int t_reg = AllocTemp();
150 NewLIR4(kThumb2OrrRRRs, t_reg, low_reg, high_reg, 0);
151 FreeTemp(t_reg);
152 OpCondBranch(condition, taken);
153 return;
154 }
155 OpCmpImmBranch(kCondNe, high_reg, val_hi, target);
156 break;
157 case kCondLt:
158 OpCmpImmBranch(kCondLt, high_reg, val_hi, taken);
159 OpCmpImmBranch(kCondGt, high_reg, val_hi, not_taken);
160 ccode = kCondCc;
161 break;
162 case kCondLe:
163 OpCmpImmBranch(kCondLt, high_reg, val_hi, taken);
164 OpCmpImmBranch(kCondGt, high_reg, val_hi, not_taken);
165 ccode = kCondLs;
166 break;
167 case kCondGt:
168 OpCmpImmBranch(kCondGt, high_reg, val_hi, taken);
169 OpCmpImmBranch(kCondLt, high_reg, val_hi, not_taken);
170 ccode = kCondHi;
171 break;
172 case kCondGe:
173 OpCmpImmBranch(kCondGt, high_reg, val_hi, taken);
174 OpCmpImmBranch(kCondLt, high_reg, val_hi, not_taken);
175 ccode = kCondCs;
176 break;
177 default:
178 LOG(FATAL) << "Unexpected ccode: " << ccode;
179 }
180 OpCmpImmBranch(ccode, low_reg, val_lo, taken);
181}
182
183void ArmMir2Lir::GenSelect(BasicBlock* bb, MIR* mir)
184{
185 RegLocation rl_result;
186 RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
187 // Temporary debugging code
188 int dest_sreg = mir->ssa_rep->defs[0];
189 if ((dest_sreg < 0) || (dest_sreg >= mir_graph_->GetNumSSARegs())) {
190 LOG(INFO) << "Bad target sreg: " << dest_sreg << ", in "
191 << PrettyMethod(cu_->method_idx,*cu_->dex_file);
192 LOG(INFO) << "at dex offset 0x" << std::hex << mir->offset;
193 LOG(INFO) << "vreg = " << mir_graph_->SRegToVReg(dest_sreg);
194 LOG(INFO) << "num uses = " << mir->ssa_rep->num_uses;
195 if (mir->ssa_rep->num_uses == 1) {
196 LOG(INFO) << "CONST case, vals = " << mir->dalvikInsn.vB << ", " << mir->dalvikInsn.vC;
197 } else {
198 LOG(INFO) << "MOVE case, operands = " << mir->ssa_rep->uses[1] << ", "
199 << mir->ssa_rep->uses[2];
200 }
201 CHECK(false) << "Invalid target sreg on Select.";
202 }
203 // End temporary debugging code
204 RegLocation rl_dest = mir_graph_->GetDest(mir);
205 rl_src = LoadValue(rl_src, kCoreReg);
206 if (mir->ssa_rep->num_uses == 1) {
207 // CONST case
208 int true_val = mir->dalvikInsn.vB;
209 int false_val = mir->dalvikInsn.vC;
210 rl_result = EvalLoc(rl_dest, kCoreReg, true);
211 if ((true_val == 1) && (false_val == 0)) {
212 OpRegRegImm(kOpRsub, rl_result.low_reg, rl_src.low_reg, 1);
213 OpIT(kCondCc, "");
214 LoadConstant(rl_result.low_reg, 0);
215 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
216 } else if (InexpensiveConstantInt(true_val) && InexpensiveConstantInt(false_val)) {
217 OpRegImm(kOpCmp, rl_src.low_reg, 0);
218 OpIT(kCondEq, "E");
219 LoadConstant(rl_result.low_reg, true_val);
220 LoadConstant(rl_result.low_reg, false_val);
221 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
222 } else {
223 // Unlikely case - could be tuned.
224 int t_reg1 = AllocTemp();
225 int t_reg2 = AllocTemp();
226 LoadConstant(t_reg1, true_val);
227 LoadConstant(t_reg2, false_val);
228 OpRegImm(kOpCmp, rl_src.low_reg, 0);
229 OpIT(kCondEq, "E");
230 OpRegCopy(rl_result.low_reg, t_reg1);
231 OpRegCopy(rl_result.low_reg, t_reg2);
232 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
233 }
234 } else {
235 // MOVE case
236 RegLocation rl_true = mir_graph_->reg_location_[mir->ssa_rep->uses[1]];
237 RegLocation rl_false = mir_graph_->reg_location_[mir->ssa_rep->uses[2]];
238 rl_true = LoadValue(rl_true, kCoreReg);
239 rl_false = LoadValue(rl_false, kCoreReg);
240 rl_result = EvalLoc(rl_dest, kCoreReg, true);
241 OpRegImm(kOpCmp, rl_src.low_reg, 0);
242 OpIT(kCondEq, "E");
243 LIR* l1 = OpRegCopy(rl_result.low_reg, rl_true.low_reg);
244 l1->flags.is_nop = false; // Make sure this instruction isn't optimized away
245 LIR* l2 = OpRegCopy(rl_result.low_reg, rl_false.low_reg);
246 l2->flags.is_nop = false; // Make sure this instruction isn't optimized away
247 GenBarrier(); // Add a scheduling barrier to keep the IT shadow intact
248 }
249 StoreValue(rl_dest, rl_result);
250}
251
252void ArmMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir)
253{
254 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
255 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
256 // Normalize such that if either operand is constant, src2 will be constant.
257 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
258 if (rl_src1.is_const) {
259 RegLocation rl_temp = rl_src1;
260 rl_src1 = rl_src2;
261 rl_src2 = rl_temp;
262 ccode = FlipComparisonOrder(ccode);
263 }
264 if (rl_src2.is_const) {
265 RegLocation rl_temp = UpdateLocWide(rl_src2);
266 // Do special compare/branch against simple const operand if not already in registers.
267 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
268 if ((rl_temp.location != kLocPhysReg) &&
269 ((ModifiedImmediate(Low32Bits(val)) >= 0) && (ModifiedImmediate(High32Bits(val)) >= 0))) {
270 GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
271 return;
272 }
273 }
274 LIR* taken = &block_label_list_[bb->taken->id];
275 LIR* not_taken = &block_label_list_[bb->fall_through->id];
276 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
277 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
278 OpRegReg(kOpCmp, rl_src1.high_reg, rl_src2.high_reg);
279 switch(ccode) {
280 case kCondEq:
281 OpCondBranch(kCondNe, not_taken);
282 break;
283 case kCondNe:
284 OpCondBranch(kCondNe, taken);
285 break;
286 case kCondLt:
287 OpCondBranch(kCondLt, taken);
288 OpCondBranch(kCondGt, not_taken);
289 ccode = kCondCc;
290 break;
291 case kCondLe:
292 OpCondBranch(kCondLt, taken);
293 OpCondBranch(kCondGt, not_taken);
294 ccode = kCondLs;
295 break;
296 case kCondGt:
297 OpCondBranch(kCondGt, taken);
298 OpCondBranch(kCondLt, not_taken);
299 ccode = kCondHi;
300 break;
301 case kCondGe:
302 OpCondBranch(kCondGt, taken);
303 OpCondBranch(kCondLt, not_taken);
304 ccode = kCondCs;
305 break;
306 default:
307 LOG(FATAL) << "Unexpected ccode: " << ccode;
308 }
309 OpRegReg(kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
310 OpCondBranch(ccode, taken);
311}
312
313/*
314 * Generate a register comparison to an immediate and branch. Caller
315 * is responsible for setting branch target field.
316 */
317LIR* ArmMir2Lir::OpCmpImmBranch(ConditionCode cond, int reg, int check_value,
318 LIR* target)
319{
320 LIR* branch;
321 int mod_imm;
322 ArmConditionCode arm_cond = ArmConditionEncoding(cond);
323 if ((ARM_LOWREG(reg)) && (check_value == 0) &&
324 ((arm_cond == kArmCondEq) || (arm_cond == kArmCondNe))) {
325 branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
326 reg, 0);
327 } else {
328 mod_imm = ModifiedImmediate(check_value);
329 if (ARM_LOWREG(reg) && ((check_value & 0xff) == check_value)) {
330 NewLIR2(kThumbCmpRI8, reg, check_value);
331 } else if (mod_imm >= 0) {
332 NewLIR2(kThumb2CmpRI12, reg, mod_imm);
333 } else {
334 int t_reg = AllocTemp();
335 LoadConstant(t_reg, check_value);
336 OpRegReg(kOpCmp, reg, t_reg);
337 }
338 branch = NewLIR2(kThumbBCond, 0, arm_cond);
339 }
340 branch->target = target;
341 return branch;
342}
343
344LIR* ArmMir2Lir::OpRegCopyNoInsert(int r_dest, int r_src)
345{
346 LIR* res;
347 int opcode;
348 if (ARM_FPREG(r_dest) || ARM_FPREG(r_src))
349 return OpFpRegCopy(r_dest, r_src);
350 if (ARM_LOWREG(r_dest) && ARM_LOWREG(r_src))
351 opcode = kThumbMovRR;
352 else if (!ARM_LOWREG(r_dest) && !ARM_LOWREG(r_src))
353 opcode = kThumbMovRR_H2H;
354 else if (ARM_LOWREG(r_dest))
355 opcode = kThumbMovRR_H2L;
356 else
357 opcode = kThumbMovRR_L2H;
358 res = RawLIR(current_dalvik_offset_, opcode, r_dest, r_src);
359 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
360 res->flags.is_nop = true;
361 }
362 return res;
363}
364
365LIR* ArmMir2Lir::OpRegCopy(int r_dest, int r_src)
366{
367 LIR* res = OpRegCopyNoInsert(r_dest, r_src);
368 AppendLIR(res);
369 return res;
370}
371
372void ArmMir2Lir::OpRegCopyWide(int dest_lo, int dest_hi, int src_lo,
373 int src_hi)
374{
375 bool dest_fp = ARM_FPREG(dest_lo) && ARM_FPREG(dest_hi);
376 bool src_fp = ARM_FPREG(src_lo) && ARM_FPREG(src_hi);
377 DCHECK_EQ(ARM_FPREG(src_lo), ARM_FPREG(src_hi));
378 DCHECK_EQ(ARM_FPREG(dest_lo), ARM_FPREG(dest_hi));
379 if (dest_fp) {
380 if (src_fp) {
381 OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
382 } else {
383 NewLIR3(kThumb2Fmdrr, S2d(dest_lo, dest_hi), src_lo, src_hi);
384 }
385 } else {
386 if (src_fp) {
387 NewLIR3(kThumb2Fmrrd, dest_lo, dest_hi, S2d(src_lo, src_hi));
388 } else {
389 // Handle overlap
390 if (src_hi == dest_lo) {
391 OpRegCopy(dest_hi, src_hi);
392 OpRegCopy(dest_lo, src_lo);
393 } else {
394 OpRegCopy(dest_lo, src_lo);
395 OpRegCopy(dest_hi, src_hi);
396 }
397 }
398 }
399}
400
401// Table of magic divisors
402struct MagicTable {
403 uint32_t magic;
404 uint32_t shift;
405 DividePattern pattern;
406};
407
408static const MagicTable magic_table[] = {
409 {0, 0, DivideNone}, // 0
410 {0, 0, DivideNone}, // 1
411 {0, 0, DivideNone}, // 2
412 {0x55555556, 0, Divide3}, // 3
413 {0, 0, DivideNone}, // 4
414 {0x66666667, 1, Divide5}, // 5
415 {0x2AAAAAAB, 0, Divide3}, // 6
416 {0x92492493, 2, Divide7}, // 7
417 {0, 0, DivideNone}, // 8
418 {0x38E38E39, 1, Divide5}, // 9
419 {0x66666667, 2, Divide5}, // 10
420 {0x2E8BA2E9, 1, Divide5}, // 11
421 {0x2AAAAAAB, 1, Divide5}, // 12
422 {0x4EC4EC4F, 2, Divide5}, // 13
423 {0x92492493, 3, Divide7}, // 14
424 {0x88888889, 3, Divide7}, // 15
425};
426
427// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
428bool ArmMir2Lir::SmallLiteralDivide(Instruction::Code dalvik_opcode,
429 RegLocation rl_src, RegLocation rl_dest, int lit)
430{
431 if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
432 return false;
433 }
434 DividePattern pattern = magic_table[lit].pattern;
435 if (pattern == DivideNone) {
436 return false;
437 }
438 // Tuning: add rem patterns
439 if (dalvik_opcode != Instruction::DIV_INT_LIT8) {
440 return false;
441 }
442
443 int r_magic = AllocTemp();
444 LoadConstant(r_magic, magic_table[lit].magic);
445 rl_src = LoadValue(rl_src, kCoreReg);
446 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
447 int r_hi = AllocTemp();
448 int r_lo = AllocTemp();
449 NewLIR4(kThumb2Smull, r_lo, r_hi, r_magic, rl_src.low_reg);
450 switch(pattern) {
451 case Divide3:
452 OpRegRegRegShift(kOpSub, rl_result.low_reg, r_hi,
453 rl_src.low_reg, EncodeShift(kArmAsr, 31));
454 break;
455 case Divide5:
456 OpRegRegImm(kOpAsr, r_lo, rl_src.low_reg, 31);
457 OpRegRegRegShift(kOpRsub, rl_result.low_reg, r_lo, r_hi,
458 EncodeShift(kArmAsr, magic_table[lit].shift));
459 break;
460 case Divide7:
461 OpRegReg(kOpAdd, r_hi, rl_src.low_reg);
462 OpRegRegImm(kOpAsr, r_lo, rl_src.low_reg, 31);
463 OpRegRegRegShift(kOpRsub, rl_result.low_reg, r_lo, r_hi,
464 EncodeShift(kArmAsr, magic_table[lit].shift));
465 break;
466 default:
467 LOG(FATAL) << "Unexpected pattern: " << pattern;
468 }
469 StoreValue(rl_dest, rl_result);
470 return true;
471}
472
473LIR* ArmMir2Lir::GenRegMemCheck(ConditionCode c_code,
474 int reg1, int base, int offset, ThrowKind kind)
475{
476 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
477 return NULL;
478}
479
480RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit,
481 bool is_div)
482{
483 LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
484 return rl_dest;
485}
486
487RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, int reg1, int reg2,
488 bool is_div)
489{
490 LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
491 return rl_dest;
492}
493
494bool ArmMir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min)
495{
496 DCHECK_EQ(cu_->instruction_set, kThumb2);
497 RegLocation rl_src1 = info->args[0];
498 RegLocation rl_src2 = info->args[1];
499 rl_src1 = LoadValue(rl_src1, kCoreReg);
500 rl_src2 = LoadValue(rl_src2, kCoreReg);
501 RegLocation rl_dest = InlineTarget(info);
502 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
503 OpRegReg(kOpCmp, rl_src1.low_reg, rl_src2.low_reg);
504 OpIT((is_min) ? kCondGt : kCondLt, "E");
505 OpRegReg(kOpMov, rl_result.low_reg, rl_src2.low_reg);
506 OpRegReg(kOpMov, rl_result.low_reg, rl_src1.low_reg);
507 GenBarrier();
508 StoreValue(rl_dest, rl_result);
509 return true;
510}
511
512void ArmMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset)
513{
514 LOG(FATAL) << "Unexpected use of OpLea for Arm";
515}
516
517void ArmMir2Lir::OpTlsCmp(int offset, int val)
518{
519 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
520}
521
522bool ArmMir2Lir::GenInlinedCas32(CallInfo* info, bool need_write_barrier) {
523 DCHECK_EQ(cu_->instruction_set, kThumb2);
524 // Unused - RegLocation rl_src_unsafe = info->args[0];
525 RegLocation rl_src_obj= info->args[1]; // Object - known non-null
526 RegLocation rl_src_offset= info->args[2]; // long low
527 rl_src_offset.wide = 0; // ignore high half in info->args[3]
528 RegLocation rl_src_expected= info->args[4]; // int or Object
529 RegLocation rl_src_new_value= info->args[5]; // int or Object
530 RegLocation rl_dest = InlineTarget(info); // boolean place for result
531
532
533 // Release store semantics, get the barrier out of the way. TODO: revisit
534 GenMemBarrier(kStoreLoad);
535
536 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
537 RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
538
539 if (need_write_barrier && !mir_graph_->IsConstantNullRef(rl_new_value)) {
540 // Mark card for object assuming new value is stored.
541 MarkGCCard(rl_new_value.low_reg, rl_object.low_reg);
542 }
543
544 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
545
546 int r_ptr = AllocTemp();
547 OpRegRegReg(kOpAdd, r_ptr, rl_object.low_reg, rl_offset.low_reg);
548
549 // Free now unneeded rl_object and rl_offset to give more temps.
550 ClobberSReg(rl_object.s_reg_low);
551 FreeTemp(rl_object.low_reg);
552 ClobberSReg(rl_offset.s_reg_low);
553 FreeTemp(rl_offset.low_reg);
554
555 int r_old_value = AllocTemp();
556 NewLIR3(kThumb2Ldrex, r_old_value, r_ptr, 0); // r_old_value := [r_ptr]
557
558 RegLocation rl_expected = LoadValue(rl_src_expected, kCoreReg);
559
560 // if (r_old_value == rExpected) {
561 // [r_ptr] <- r_new_value && r_result := success ? 0 : 1
562 // r_result ^= 1
563 // } else {
564 // r_result := 0
565 // }
566 OpRegReg(kOpCmp, r_old_value, rl_expected.low_reg);
567 FreeTemp(r_old_value); // Now unneeded.
568 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
569 OpIT(kCondEq, "TE");
570 NewLIR4(kThumb2Strex, rl_result.low_reg, rl_new_value.low_reg, r_ptr, 0);
571 FreeTemp(r_ptr); // Now unneeded.
572 OpRegImm(kOpXor, rl_result.low_reg, 1);
573 OpRegReg(kOpXor, rl_result.low_reg, rl_result.low_reg);
574
575 StoreValue(rl_dest, rl_result);
576
577 return true;
578}
579
580LIR* ArmMir2Lir::OpPcRelLoad(int reg, LIR* target)
581{
582 return RawLIR(current_dalvik_offset_, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
583}
584
585LIR* ArmMir2Lir::OpVldm(int rBase, int count)
586{
587 return NewLIR3(kThumb2Vldms, rBase, fr0, count);
588}
589
590LIR* ArmMir2Lir::OpVstm(int rBase, int count)
591{
592 return NewLIR3(kThumb2Vstms, rBase, fr0, count);
593}
594
595void ArmMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
596 RegLocation rl_result, int lit,
597 int first_bit, int second_bit)
598{
599 OpRegRegRegShift(kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg,
600 EncodeShift(kArmLsl, second_bit - first_bit));
601 if (first_bit != 0) {
602 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
603 }
604}
605
606void ArmMir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi)
607{
608 int t_reg = AllocTemp();
609 NewLIR4(kThumb2OrrRRRs, t_reg, reg_lo, reg_hi, 0);
610 FreeTemp(t_reg);
611 GenCheck(kCondEq, kThrowDivZero);
612}
613
614// Test suspend flag, return target of taken suspend branch
615LIR* ArmMir2Lir::OpTestSuspend(LIR* target)
616{
617 NewLIR2(kThumbSubRI8, rARM_SUSPEND, 1);
618 return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
619}
620
621// Decrement register and branch on condition
622LIR* ArmMir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target)
623{
624 // Combine sub & test using sub setflags encoding here
625 NewLIR3(kThumb2SubsRRI12, reg, reg, 1);
626 return OpCondBranch(c_code, target);
627}
628
629void ArmMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind)
630{
631#if ANDROID_SMP != 0
632 int dmb_flavor;
633 // TODO: revisit Arm barrier kinds
634 switch (barrier_kind) {
635 case kLoadStore: dmb_flavor = kSY; break;
636 case kLoadLoad: dmb_flavor = kSY; break;
637 case kStoreStore: dmb_flavor = kST; break;
638 case kStoreLoad: dmb_flavor = kSY; break;
639 default:
640 LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
641 dmb_flavor = kSY; // quiet gcc.
642 break;
643 }
644 LIR* dmb = NewLIR1(kThumb2Dmb, dmb_flavor);
645 dmb->def_mask = ENCODE_ALL;
646#endif
647}
648
649void ArmMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src)
650{
651 rl_src = LoadValueWide(rl_src, kCoreReg);
652 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
653 int z_reg = AllocTemp();
654 LoadConstantNoClobber(z_reg, 0);
655 // Check for destructive overlap
656 if (rl_result.low_reg == rl_src.high_reg) {
657 int t_reg = AllocTemp();
658 OpRegRegReg(kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
659 OpRegRegReg(kOpSbc, rl_result.high_reg, z_reg, t_reg);
660 FreeTemp(t_reg);
661 } else {
662 OpRegRegReg(kOpSub, rl_result.low_reg, z_reg, rl_src.low_reg);
663 OpRegRegReg(kOpSbc, rl_result.high_reg, z_reg, rl_src.high_reg);
664 }
665 FreeTemp(z_reg);
666 StoreValueWide(rl_dest, rl_result);
667}
668
669
670 /*
671 * Check to see if a result pair has a misaligned overlap with an operand pair. This
672 * is not usual for dx to generate, but it is legal (for now). In a future rev of
673 * dex, we'll want to make this case illegal.
674 */
675bool ArmMir2Lir::BadOverlap(RegLocation rl_src, RegLocation rl_dest)
676{
677 DCHECK(rl_src.wide);
678 DCHECK(rl_dest.wide);
679 return (abs(mir_graph_->SRegToVReg(rl_src.s_reg_low) - mir_graph_->SRegToVReg(rl_dest.s_reg_low)) == 1);
680}
681
682void ArmMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1,
683 RegLocation rl_src2)
684{
685 /*
686 * To pull off inline multiply, we have a worst-case requirement of 8 temporary
687 * registers. Normally for Arm, we get 5. We can get to 6 by including
688 * lr in the temp set. The only problematic case is all operands and result are
689 * distinct, and none have been promoted. In that case, we can succeed by aggressively
690 * freeing operand temp registers after they are no longer needed. All other cases
691 * can proceed normally. We'll just punt on the case of the result having a misaligned
692 * overlap with either operand and send that case to a runtime handler.
693 */
694 RegLocation rl_result;
695 if (BadOverlap(rl_src1, rl_dest) || (BadOverlap(rl_src2, rl_dest))) {
696 int func_offset = ENTRYPOINT_OFFSET(pLmul);
697 FlushAllRegs();
698 CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false);
699 rl_result = GetReturnWide(false);
700 StoreValueWide(rl_dest, rl_result);
701 return;
702 }
703 // Temporarily add LR to the temp pool, and assign it to tmp1
704 MarkTemp(rARM_LR);
705 FreeTemp(rARM_LR);
706 int tmp1 = rARM_LR;
707 LockTemp(rARM_LR);
708
709 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
710 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
711
712 bool special_case = true;
713 // If operands are the same, or any pair has been promoted we're not the special case.
714 if ((rl_src1.s_reg_low == rl_src2.s_reg_low) ||
715 (!IsTemp(rl_src1.low_reg) && !IsTemp(rl_src1.high_reg)) ||
716 (!IsTemp(rl_src2.low_reg) && !IsTemp(rl_src2.high_reg))) {
717 special_case = false;
718 }
719 // Tuning: if rl_dest has been promoted and is *not* either operand, could use directly.
720 int res_lo = AllocTemp();
721 int res_hi;
722 if (rl_src1.low_reg == rl_src2.low_reg) {
723 res_hi = AllocTemp();
724 NewLIR3(kThumb2MulRRR, tmp1, rl_src1.low_reg, rl_src1.high_reg);
725 NewLIR4(kThumb2Umull, res_lo, res_hi, rl_src1.low_reg, rl_src1.low_reg);
726 OpRegRegRegShift(kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1));
727 } else {
728 // In the special case, all temps are now allocated
729 NewLIR3(kThumb2MulRRR, tmp1, rl_src2.low_reg, rl_src1.high_reg);
730 if (special_case) {
731 DCHECK_NE(rl_src1.low_reg, rl_src2.low_reg);
732 DCHECK_NE(rl_src1.high_reg, rl_src2.high_reg);
733 FreeTemp(rl_src1.high_reg);
734 }
735 res_hi = AllocTemp();
736
737 NewLIR4(kThumb2Umull, res_lo, res_hi, rl_src2.low_reg, rl_src1.low_reg);
738 NewLIR4(kThumb2Mla, tmp1, rl_src1.low_reg, rl_src2.high_reg, tmp1);
739 NewLIR4(kThumb2AddRRR, res_hi, tmp1, res_hi, 0);
740 if (special_case) {
741 FreeTemp(rl_src1.low_reg);
742 Clobber(rl_src1.low_reg);
743 Clobber(rl_src1.high_reg);
744 }
745 }
746 FreeTemp(tmp1);
747 rl_result = GetReturnWide(false); // Just using as a template.
748 rl_result.low_reg = res_lo;
749 rl_result.high_reg = res_hi;
750 StoreValueWide(rl_dest, rl_result);
751 // Now, restore lr to its non-temp status.
752 Clobber(rARM_LR);
753 UnmarkTemp(rARM_LR);
754}
755
756void ArmMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
757 RegLocation rl_src2)
758{
759 LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
760}
761
762void ArmMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
763 RegLocation rl_src2)
764{
765 LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
766}
767
768void ArmMir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
769 RegLocation rl_src2)
770{
771 LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
772}
773
774void ArmMir2Lir::GenOrLong(RegLocation rl_dest, RegLocation rl_src1,
775 RegLocation rl_src2)
776{
777 LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
778}
779
780void ArmMir2Lir::GenXorLong(RegLocation rl_dest, RegLocation rl_src1,
781 RegLocation rl_src2)
782{
783 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
784}
785
786/*
787 * Generate array load
788 */
789void ArmMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
790 RegLocation rl_index, RegLocation rl_dest, int scale)
791{
792 RegisterClass reg_class = oat_reg_class_by_size(size);
793 int len_offset = mirror::Array::LengthOffset().Int32Value();
794 int data_offset;
795 RegLocation rl_result;
796 bool constant_index = rl_index.is_const;
797 rl_array = LoadValue(rl_array, kCoreReg);
798 if (!constant_index) {
799 rl_index = LoadValue(rl_index, kCoreReg);
800 }
801
802 if (rl_dest.wide) {
803 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
804 } else {
805 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
806 }
807
808 // If index is constant, just fold it into the data offset
809 if (constant_index) {
810 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
811 }
812
813 /* null object? */
814 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
815
816 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
817 int reg_len = INVALID_REG;
818 if (needs_range_check) {
819 reg_len = AllocTemp();
820 /* Get len */
821 LoadWordDisp(rl_array.low_reg, len_offset, reg_len);
822 }
823 if (rl_dest.wide || rl_dest.fp || constant_index) {
824 int reg_ptr;
825 if (constant_index) {
826 reg_ptr = rl_array.low_reg; // NOTE: must not alter reg_ptr in constant case.
827 } else {
828 // No special indexed operation, lea + load w/ displacement
829 reg_ptr = AllocTemp();
830 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
831 EncodeShift(kArmLsl, scale));
832 FreeTemp(rl_index.low_reg);
833 }
834 rl_result = EvalLoc(rl_dest, reg_class, true);
835
836 if (needs_range_check) {
837 if (constant_index) {
838 GenImmedCheck(kCondLs, reg_len, mir_graph_->ConstantValue(rl_index), kThrowConstantArrayBounds);
839 } else {
840 GenRegRegCheck(kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
841 }
842 FreeTemp(reg_len);
843 }
844 if (rl_dest.wide) {
845 LoadBaseDispWide(reg_ptr, data_offset, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
846 if (!constant_index) {
847 FreeTemp(reg_ptr);
848 }
849 StoreValueWide(rl_dest, rl_result);
850 } else {
851 LoadBaseDisp(reg_ptr, data_offset, rl_result.low_reg, size, INVALID_SREG);
852 if (!constant_index) {
853 FreeTemp(reg_ptr);
854 }
855 StoreValue(rl_dest, rl_result);
856 }
857 } else {
858 // Offset base, then use indexed load
859 int reg_ptr = AllocTemp();
860 OpRegRegImm(kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
861 FreeTemp(rl_array.low_reg);
862 rl_result = EvalLoc(rl_dest, reg_class, true);
863
864 if (needs_range_check) {
865 // TODO: change kCondCS to a more meaningful name, is the sense of
866 // carry-set/clear flipped?
867 GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
868 FreeTemp(reg_len);
869 }
870 LoadBaseIndexed(reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
871 FreeTemp(reg_ptr);
872 StoreValue(rl_dest, rl_result);
873 }
874}
875
876/*
877 * Generate array store
878 *
879 */
880void ArmMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
881 RegLocation rl_index, RegLocation rl_src, int scale)
882{
883 RegisterClass reg_class = oat_reg_class_by_size(size);
884 int len_offset = mirror::Array::LengthOffset().Int32Value();
885 int data_offset;
886 bool constant_index = rl_index.is_const;
887
888 if (rl_src.wide) {
889 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
890 } else {
891 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
892 }
893
894 // If index is constant, just fold it into the data offset.
895 if (constant_index) {
896 data_offset += mir_graph_->ConstantValue(rl_index) << scale;
897 }
898
899 rl_array = LoadValue(rl_array, kCoreReg);
900 if (!constant_index) {
901 rl_index = LoadValue(rl_index, kCoreReg);
902 }
903
904 int reg_ptr;
905 if (constant_index) {
906 reg_ptr = rl_array.low_reg;
907 } else if (IsTemp(rl_array.low_reg)) {
908 Clobber(rl_array.low_reg);
909 reg_ptr = rl_array.low_reg;
910 } else {
911 reg_ptr = AllocTemp();
912 }
913
914 /* null object? */
915 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
916
917 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
918 int reg_len = INVALID_REG;
919 if (needs_range_check) {
920 reg_len = AllocTemp();
921 //NOTE: max live temps(4) here.
922 /* Get len */
923 LoadWordDisp(rl_array.low_reg, len_offset, reg_len);
924 }
925 /* at this point, reg_ptr points to array, 2 live temps */
926 if (rl_src.wide || rl_src.fp || constant_index) {
927 if (rl_src.wide) {
928 rl_src = LoadValueWide(rl_src, reg_class);
929 } else {
930 rl_src = LoadValue(rl_src, reg_class);
931 }
932 if (!constant_index) {
933 OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.low_reg, rl_index.low_reg,
934 EncodeShift(kArmLsl, scale));
935 }
936 if (needs_range_check) {
937 if (constant_index) {
938 GenImmedCheck(kCondLs, reg_len, mir_graph_->ConstantValue(rl_index), kThrowConstantArrayBounds);
939 } else {
940 GenRegRegCheck(kCondLs, reg_len, rl_index.low_reg, kThrowArrayBounds);
941 }
942 FreeTemp(reg_len);
943 }
944
945 if (rl_src.wide) {
946 StoreBaseDispWide(reg_ptr, data_offset, rl_src.low_reg, rl_src.high_reg);
947 } else {
948 StoreBaseDisp(reg_ptr, data_offset, rl_src.low_reg, size);
949 }
950 } else {
951 /* reg_ptr -> array data */
952 OpRegRegImm(kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
953 rl_src = LoadValue(rl_src, reg_class);
954 if (needs_range_check) {
955 GenRegRegCheck(kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
956 FreeTemp(reg_len);
957 }
958 StoreBaseIndexed(reg_ptr, rl_index.low_reg, rl_src.low_reg,
959 scale, size);
960 }
961 if (!constant_index) {
962 FreeTemp(reg_ptr);
963 }
964}
965
966/*
967 * Generate array store
968 *
969 */
970void ArmMir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array,
971 RegLocation rl_index, RegLocation rl_src, int scale)
972{
973 int len_offset = mirror::Array::LengthOffset().Int32Value();
974 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
975
976 FlushAllRegs(); // Use explicit registers
977 LockCallTemps();
978
979 int r_value = TargetReg(kArg0); // Register holding value
980 int r_array_class = TargetReg(kArg1); // Register holding array's Class
981 int r_array = TargetReg(kArg2); // Register holding array
982 int r_index = TargetReg(kArg3); // Register holding index into array
983
984 LoadValueDirectFixed(rl_array, r_array); // Grab array
985 LoadValueDirectFixed(rl_src, r_value); // Grab value
986 LoadValueDirectFixed(rl_index, r_index); // Grab index
987
988 GenNullCheck(rl_array.s_reg_low, r_array, opt_flags); // NPE?
989
990 // Store of null?
991 LIR* null_value_check = OpCmpImmBranch(kCondEq, r_value, 0, NULL);
992
993 // Get the array's class.
994 LoadWordDisp(r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
995 CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
996 r_array_class, true);
997 // Redo LoadValues in case they didn't survive the call.
998 LoadValueDirectFixed(rl_array, r_array); // Reload array
999 LoadValueDirectFixed(rl_index, r_index); // Reload index
1000 LoadValueDirectFixed(rl_src, r_value); // Reload value
1001 r_array_class = INVALID_REG;
1002
1003 // Branch here if value to be stored == null
1004 LIR* target = NewLIR0(kPseudoTargetLabel);
1005 null_value_check->target = target;
1006
1007 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
1008 int reg_len = INVALID_REG;
1009 if (needs_range_check) {
1010 reg_len = TargetReg(kArg1);
1011 LoadWordDisp(r_array, len_offset, reg_len); // Get len
1012 }
1013 /* r_ptr -> array data */
1014 int r_ptr = AllocTemp();
1015 OpRegRegImm(kOpAdd, r_ptr, r_array, data_offset);
1016 if (needs_range_check) {
1017 GenRegRegCheck(kCondCs, r_index, reg_len, kThrowArrayBounds);
1018 }
1019 StoreBaseIndexed(r_ptr, r_index, r_value, scale, kWord);
1020 FreeTemp(r_ptr);
1021 FreeTemp(r_index);
1022 if (!mir_graph_->IsConstantNullRef(rl_src)) {
1023 MarkGCCard(r_value, r_array);
1024 }
1025}
1026
1027void ArmMir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
1028 RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift)
1029{
1030 rl_src = LoadValueWide(rl_src, kCoreReg);
1031 // Per spec, we only care about low 6 bits of shift amount.
1032 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
1033 if (shift_amount == 0) {
1034 StoreValueWide(rl_dest, rl_src);
1035 return;
1036 }
1037 if (BadOverlap(rl_src, rl_dest)) {
1038 GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift);
1039 return;
1040 }
1041 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1042 switch(opcode) {
1043 case Instruction::SHL_LONG:
1044 case Instruction::SHL_LONG_2ADDR:
1045 if (shift_amount == 1) {
1046 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, rl_src.low_reg);
1047 OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, rl_src.high_reg);
1048 } else if (shift_amount == 32) {
1049 OpRegCopy(rl_result.high_reg, rl_src.low_reg);
1050 LoadConstant(rl_result.low_reg, 0);
1051 } else if (shift_amount > 31) {
1052 OpRegRegImm(kOpLsl, rl_result.high_reg, rl_src.low_reg, shift_amount - 32);
1053 LoadConstant(rl_result.low_reg, 0);
1054 } else {
1055 OpRegRegImm(kOpLsl, rl_result.high_reg, rl_src.high_reg, shift_amount);
1056 OpRegRegRegShift(kOpOr, rl_result.high_reg, rl_result.high_reg, rl_src.low_reg,
1057 EncodeShift(kArmLsr, 32 - shift_amount));
1058 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_src.low_reg, shift_amount);
1059 }
1060 break;
1061 case Instruction::SHR_LONG:
1062 case Instruction::SHR_LONG_2ADDR:
1063 if (shift_amount == 32) {
1064 OpRegCopy(rl_result.low_reg, rl_src.high_reg);
1065 OpRegRegImm(kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1066 } else if (shift_amount > 31) {
1067 OpRegRegImm(kOpAsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1068 OpRegRegImm(kOpAsr, rl_result.high_reg, rl_src.high_reg, 31);
1069 } else {
1070 int t_reg = AllocTemp();
1071 OpRegRegImm(kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1072 OpRegRegRegShift(kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1073 EncodeShift(kArmLsl, 32 - shift_amount));
1074 FreeTemp(t_reg);
1075 OpRegRegImm(kOpAsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1076 }
1077 break;
1078 case Instruction::USHR_LONG:
1079 case Instruction::USHR_LONG_2ADDR:
1080 if (shift_amount == 32) {
1081 OpRegCopy(rl_result.low_reg, rl_src.high_reg);
1082 LoadConstant(rl_result.high_reg, 0);
1083 } else if (shift_amount > 31) {
1084 OpRegRegImm(kOpLsr, rl_result.low_reg, rl_src.high_reg, shift_amount - 32);
1085 LoadConstant(rl_result.high_reg, 0);
1086 } else {
1087 int t_reg = AllocTemp();
1088 OpRegRegImm(kOpLsr, t_reg, rl_src.low_reg, shift_amount);
1089 OpRegRegRegShift(kOpOr, rl_result.low_reg, t_reg, rl_src.high_reg,
1090 EncodeShift(kArmLsl, 32 - shift_amount));
1091 FreeTemp(t_reg);
1092 OpRegRegImm(kOpLsr, rl_result.high_reg, rl_src.high_reg, shift_amount);
1093 }
1094 break;
1095 default:
1096 LOG(FATAL) << "Unexpected case";
1097 }
1098 StoreValueWide(rl_dest, rl_result);
1099}
1100
1101void ArmMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
1102 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
1103{
1104 if ((opcode == Instruction::SUB_LONG_2ADDR) || (opcode == Instruction::SUB_LONG)) {
1105 if (!rl_src2.is_const) {
1106 // Don't bother with special handling for subtract from immediate.
1107 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
1108 return;
1109 }
1110 } else {
1111 // Normalize
1112 if (!rl_src2.is_const) {
1113 DCHECK(rl_src1.is_const);
1114 RegLocation rl_temp = rl_src1;
1115 rl_src1 = rl_src2;
1116 rl_src2 = rl_temp;
1117 }
1118 }
1119 if (BadOverlap(rl_src1, rl_dest)) {
1120 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
1121 return;
1122 }
1123 DCHECK(rl_src2.is_const);
1124 int64_t val = mir_graph_->ConstantValueWide(rl_src2);
1125 uint32_t val_lo = Low32Bits(val);
1126 uint32_t val_hi = High32Bits(val);
1127 int32_t mod_imm_lo = ModifiedImmediate(val_lo);
1128 int32_t mod_imm_hi = ModifiedImmediate(val_hi);
1129
1130 // Only a subset of add/sub immediate instructions set carry - so bail if we don't fit
1131 switch(opcode) {
1132 case Instruction::ADD_LONG:
1133 case Instruction::ADD_LONG_2ADDR:
1134 case Instruction::SUB_LONG:
1135 case Instruction::SUB_LONG_2ADDR:
1136 if ((mod_imm_lo < 0) || (mod_imm_hi < 0)) {
1137 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
1138 return;
1139 }
1140 break;
1141 default:
1142 break;
1143 }
1144 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
1145 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1146 // NOTE: once we've done the EvalLoc on dest, we can no longer bail.
1147 switch (opcode) {
1148 case Instruction::ADD_LONG:
1149 case Instruction::ADD_LONG_2ADDR:
1150 NewLIR3(kThumb2AddRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1151 NewLIR3(kThumb2AdcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1152 break;
1153 case Instruction::OR_LONG:
1154 case Instruction::OR_LONG_2ADDR:
1155 if ((val_lo != 0) || (rl_result.low_reg != rl_src1.low_reg)) {
1156 OpRegRegImm(kOpOr, rl_result.low_reg, rl_src1.low_reg, val_lo);
1157 }
1158 if ((val_hi != 0) || (rl_result.high_reg != rl_src1.high_reg)) {
1159 OpRegRegImm(kOpOr, rl_result.high_reg, rl_src1.high_reg, val_hi);
1160 }
1161 break;
1162 case Instruction::XOR_LONG:
1163 case Instruction::XOR_LONG_2ADDR:
1164 OpRegRegImm(kOpXor, rl_result.low_reg, rl_src1.low_reg, val_lo);
1165 OpRegRegImm(kOpXor, rl_result.high_reg, rl_src1.high_reg, val_hi);
1166 break;
1167 case Instruction::AND_LONG:
1168 case Instruction::AND_LONG_2ADDR:
1169 if ((val_lo != 0xffffffff) || (rl_result.low_reg != rl_src1.low_reg)) {
1170 OpRegRegImm(kOpAnd, rl_result.low_reg, rl_src1.low_reg, val_lo);
1171 }
1172 if ((val_hi != 0xffffffff) || (rl_result.high_reg != rl_src1.high_reg)) {
1173 OpRegRegImm(kOpAnd, rl_result.high_reg, rl_src1.high_reg, val_hi);
1174 }
1175 break;
1176 case Instruction::SUB_LONG_2ADDR:
1177 case Instruction::SUB_LONG:
1178 NewLIR3(kThumb2SubRRI8, rl_result.low_reg, rl_src1.low_reg, mod_imm_lo);
1179 NewLIR3(kThumb2SbcRRI8, rl_result.high_reg, rl_src1.high_reg, mod_imm_hi);
1180 break;
1181 default:
1182 LOG(FATAL) << "Unexpected opcode " << opcode;
1183 }
1184 StoreValueWide(rl_dest, rl_result);
1185}
1186
1187} // namespace art