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