Home | History | Annotate | Download | only in arm
      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 "dex/reg_storage_eq.h"
     23 #include "entrypoints/quick/quick_entrypoints.h"
     24 #include "mirror/array.h"
     25 
     26 namespace art {
     27 
     28 LIR* ArmMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage 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  */
     43 LIR* 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 void ArmMir2Lir::UpdateIT(LIR* it, const char* new_guide) {
     72   int mask;
     73   int mask3 = 0;
     74   int mask2 = 0;
     75   int mask1 = 0;
     76   ArmConditionCode code = static_cast<ArmConditionCode>(it->operands[0]);
     77   int cond_bit = code & 1;
     78   int alt_bit = cond_bit ^ 1;
     79 
     80   // Note: case fallthroughs intentional
     81   switch (strlen(new_guide)) {
     82     case 3:
     83       mask1 = (new_guide[2] == 'T') ? cond_bit : alt_bit;
     84     case 2:
     85       mask2 = (new_guide[1] == 'T') ? cond_bit : alt_bit;
     86     case 1:
     87       mask3 = (new_guide[0] == 'T') ? cond_bit : alt_bit;
     88       break;
     89     case 0:
     90       break;
     91     default:
     92       LOG(FATAL) << "OAT: bad case in UpdateIT";
     93   }
     94   mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
     95       (1 << (3 - strlen(new_guide)));
     96   it->operands[1] = mask;
     97 }
     98 
     99 void ArmMir2Lir::OpEndIT(LIR* it) {
    100   // TODO: use the 'it' pointer to do some checks with the LIR, for example
    101   //       we could check that the number of instructions matches the mask
    102   //       in the IT instruction.
    103   CHECK(it != nullptr);
    104   GenBarrier();
    105 }
    106 
    107 /*
    108  * 64-bit 3way compare function.
    109  *     mov   rX, #-1
    110  *     cmp   op1hi, op2hi
    111  *     blt   done
    112  *     bgt   flip
    113  *     sub   rX, op1lo, op2lo (treat as unsigned)
    114  *     beq   done
    115  *     ite   hi
    116  *     mov(hi)   rX, #-1
    117  *     mov(!hi)  rX, #1
    118  * flip:
    119  *     neg   rX
    120  * done:
    121  */
    122 void ArmMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
    123   LIR* target1;
    124   LIR* target2;
    125   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    126   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
    127   RegStorage t_reg = AllocTemp();
    128   LoadConstant(t_reg, -1);
    129   OpRegReg(kOpCmp, rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
    130   LIR* branch1 = OpCondBranch(kCondLt, NULL);
    131   LIR* branch2 = OpCondBranch(kCondGt, NULL);
    132   OpRegRegReg(kOpSub, t_reg, rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
    133   LIR* branch3 = OpCondBranch(kCondEq, NULL);
    134 
    135   LIR* it = OpIT(kCondHi, "E");
    136   NewLIR2(kThumb2MovI8M, t_reg.GetReg(), ModifiedImmediate(-1));
    137   LoadConstant(t_reg, 1);
    138   OpEndIT(it);
    139 
    140   target2 = NewLIR0(kPseudoTargetLabel);
    141   OpRegReg(kOpNeg, t_reg, t_reg);
    142 
    143   target1 = NewLIR0(kPseudoTargetLabel);
    144 
    145   RegLocation rl_temp = LocCReturn();  // Just using as template, will change
    146   rl_temp.reg.SetReg(t_reg.GetReg());
    147   StoreValue(rl_dest, rl_temp);
    148   FreeTemp(t_reg);
    149 
    150   branch1->target = target1;
    151   branch2->target = target2;
    152   branch3->target = branch1->target;
    153 }
    154 
    155 void ArmMir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1,
    156                                           int64_t val, ConditionCode ccode) {
    157   int32_t val_lo = Low32Bits(val);
    158   int32_t val_hi = High32Bits(val);
    159   DCHECK_GE(ModifiedImmediate(val_lo), 0);
    160   DCHECK_GE(ModifiedImmediate(val_hi), 0);
    161   LIR* taken = &block_label_list_[bb->taken];
    162   LIR* not_taken = &block_label_list_[bb->fall_through];
    163   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    164   RegStorage low_reg = rl_src1.reg.GetLow();
    165   RegStorage high_reg = rl_src1.reg.GetHigh();
    166 
    167   if (val == 0 && (ccode == kCondEq || ccode == kCondNe)) {
    168     RegStorage t_reg = AllocTemp();
    169     NewLIR4(kThumb2OrrRRRs, t_reg.GetReg(), low_reg.GetReg(), high_reg.GetReg(), 0);
    170     FreeTemp(t_reg);
    171     OpCondBranch(ccode, taken);
    172     return;
    173   }
    174 
    175   switch (ccode) {
    176     case kCondEq:
    177     case kCondNe:
    178       OpCmpImmBranch(kCondNe, high_reg, val_hi, (ccode == kCondEq) ? not_taken : taken);
    179       break;
    180     case kCondLt:
    181       OpCmpImmBranch(kCondLt, high_reg, val_hi, taken);
    182       OpCmpImmBranch(kCondGt, high_reg, val_hi, not_taken);
    183       ccode = kCondUlt;
    184       break;
    185     case kCondLe:
    186       OpCmpImmBranch(kCondLt, high_reg, val_hi, taken);
    187       OpCmpImmBranch(kCondGt, high_reg, val_hi, not_taken);
    188       ccode = kCondLs;
    189       break;
    190     case kCondGt:
    191       OpCmpImmBranch(kCondGt, high_reg, val_hi, taken);
    192       OpCmpImmBranch(kCondLt, high_reg, val_hi, not_taken);
    193       ccode = kCondHi;
    194       break;
    195     case kCondGe:
    196       OpCmpImmBranch(kCondGt, high_reg, val_hi, taken);
    197       OpCmpImmBranch(kCondLt, high_reg, val_hi, not_taken);
    198       ccode = kCondUge;
    199       break;
    200     default:
    201       LOG(FATAL) << "Unexpected ccode: " << ccode;
    202   }
    203   OpCmpImmBranch(ccode, low_reg, val_lo, taken);
    204 }
    205 
    206 void ArmMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
    207                                   int32_t true_val, int32_t false_val, RegStorage rs_dest,
    208                                   int dest_reg_class) {
    209   // TODO: Generalize the IT below to accept more than one-instruction loads.
    210   DCHECK(InexpensiveConstantInt(true_val));
    211   DCHECK(InexpensiveConstantInt(false_val));
    212 
    213   if ((true_val == 0 && code == kCondEq) ||
    214       (false_val == 0 && code == kCondNe)) {
    215     OpRegRegReg(kOpSub, rs_dest, left_op, right_op);
    216     DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
    217     LIR* it = OpIT(kCondNe, "");
    218     LoadConstant(rs_dest, code == kCondEq ? false_val : true_val);
    219     OpEndIT(it);
    220     return;
    221   }
    222 
    223   OpRegReg(kOpCmp, left_op, right_op);  // Same?
    224   LIR* it = OpIT(code, "E");   // if-convert the test
    225   LoadConstant(rs_dest, true_val);      // .eq case - load true
    226   LoadConstant(rs_dest, false_val);     // .eq case - load true
    227   OpEndIT(it);
    228 }
    229 
    230 void ArmMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
    231   RegLocation rl_result;
    232   RegLocation rl_src = mir_graph_->GetSrc(mir, 0);
    233   RegLocation rl_dest = mir_graph_->GetDest(mir);
    234   // Avoid using float regs here.
    235   RegisterClass src_reg_class = rl_src.ref ? kRefReg : kCoreReg;
    236   RegisterClass result_reg_class = rl_dest.ref ? kRefReg : kCoreReg;
    237   rl_src = LoadValue(rl_src, src_reg_class);
    238   ConditionCode ccode = mir->meta.ccode;
    239   if (mir->ssa_rep->num_uses == 1) {
    240     // CONST case
    241     int true_val = mir->dalvikInsn.vB;
    242     int false_val = mir->dalvikInsn.vC;
    243     rl_result = EvalLoc(rl_dest, result_reg_class, true);
    244     // Change kCondNe to kCondEq for the special cases below.
    245     if (ccode == kCondNe) {
    246       ccode = kCondEq;
    247       std::swap(true_val, false_val);
    248     }
    249     bool cheap_false_val = InexpensiveConstantInt(false_val);
    250     if (cheap_false_val && ccode == kCondEq && (true_val == 0 || true_val == -1)) {
    251       OpRegRegImm(kOpSub, rl_result.reg, rl_src.reg, -true_val);
    252       DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
    253       LIR* it = OpIT(true_val == 0 ? kCondNe : kCondUge, "");
    254       LoadConstant(rl_result.reg, false_val);
    255       OpEndIT(it);  // Add a scheduling barrier to keep the IT shadow intact
    256     } else if (cheap_false_val && ccode == kCondEq && true_val == 1) {
    257       OpRegRegImm(kOpRsub, rl_result.reg, rl_src.reg, 1);
    258       DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
    259       LIR* it = OpIT(kCondLs, "");
    260       LoadConstant(rl_result.reg, false_val);
    261       OpEndIT(it);  // Add a scheduling barrier to keep the IT shadow intact
    262     } else if (cheap_false_val && InexpensiveConstantInt(true_val)) {
    263       OpRegImm(kOpCmp, rl_src.reg, 0);
    264       LIR* it = OpIT(ccode, "E");
    265       LoadConstant(rl_result.reg, true_val);
    266       LoadConstant(rl_result.reg, false_val);
    267       OpEndIT(it);  // Add a scheduling barrier to keep the IT shadow intact
    268     } else {
    269       // Unlikely case - could be tuned.
    270       RegStorage t_reg1 = AllocTypedTemp(false, result_reg_class);
    271       RegStorage t_reg2 = AllocTypedTemp(false, result_reg_class);
    272       LoadConstant(t_reg1, true_val);
    273       LoadConstant(t_reg2, false_val);
    274       OpRegImm(kOpCmp, rl_src.reg, 0);
    275       LIR* it = OpIT(ccode, "E");
    276       OpRegCopy(rl_result.reg, t_reg1);
    277       OpRegCopy(rl_result.reg, t_reg2);
    278       OpEndIT(it);  // Add a scheduling barrier to keep the IT shadow intact
    279     }
    280   } else {
    281     // MOVE case
    282     RegLocation rl_true = mir_graph_->reg_location_[mir->ssa_rep->uses[1]];
    283     RegLocation rl_false = mir_graph_->reg_location_[mir->ssa_rep->uses[2]];
    284     rl_true = LoadValue(rl_true, result_reg_class);
    285     rl_false = LoadValue(rl_false, result_reg_class);
    286     rl_result = EvalLoc(rl_dest, result_reg_class, true);
    287     OpRegImm(kOpCmp, rl_src.reg, 0);
    288     LIR* it = nullptr;
    289     if (rl_result.reg.GetReg() == rl_true.reg.GetReg()) {  // Is the "true" case already in place?
    290       it = OpIT(NegateComparison(ccode), "");
    291       OpRegCopy(rl_result.reg, rl_false.reg);
    292     } else if (rl_result.reg.GetReg() == rl_false.reg.GetReg()) {  // False case in place?
    293       it = OpIT(ccode, "");
    294       OpRegCopy(rl_result.reg, rl_true.reg);
    295     } else {  // Normal - select between the two.
    296       it = OpIT(ccode, "E");
    297       OpRegCopy(rl_result.reg, rl_true.reg);
    298       OpRegCopy(rl_result.reg, rl_false.reg);
    299     }
    300     OpEndIT(it);  // Add a scheduling barrier to keep the IT shadow intact
    301   }
    302   StoreValue(rl_dest, rl_result);
    303 }
    304 
    305 void ArmMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
    306   RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0);
    307   RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2);
    308   // Normalize such that if either operand is constant, src2 will be constant.
    309   ConditionCode ccode = mir->meta.ccode;
    310   if (rl_src1.is_const) {
    311     std::swap(rl_src1, rl_src2);
    312     ccode = FlipComparisonOrder(ccode);
    313   }
    314   if (rl_src2.is_const) {
    315     rl_src2 = UpdateLocWide(rl_src2);
    316     // Do special compare/branch against simple const operand if not already in registers.
    317     int64_t val = mir_graph_->ConstantValueWide(rl_src2);
    318     if ((rl_src2.location != kLocPhysReg) &&
    319         ((ModifiedImmediate(Low32Bits(val)) >= 0) && (ModifiedImmediate(High32Bits(val)) >= 0))) {
    320       GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode);
    321       return;
    322     }
    323   }
    324   LIR* taken = &block_label_list_[bb->taken];
    325   LIR* not_taken = &block_label_list_[bb->fall_through];
    326   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    327   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
    328   OpRegReg(kOpCmp, rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
    329   switch (ccode) {
    330     case kCondEq:
    331       OpCondBranch(kCondNe, not_taken);
    332       break;
    333     case kCondNe:
    334       OpCondBranch(kCondNe, taken);
    335       break;
    336     case kCondLt:
    337       OpCondBranch(kCondLt, taken);
    338       OpCondBranch(kCondGt, not_taken);
    339       ccode = kCondUlt;
    340       break;
    341     case kCondLe:
    342       OpCondBranch(kCondLt, taken);
    343       OpCondBranch(kCondGt, not_taken);
    344       ccode = kCondLs;
    345       break;
    346     case kCondGt:
    347       OpCondBranch(kCondGt, taken);
    348       OpCondBranch(kCondLt, not_taken);
    349       ccode = kCondHi;
    350       break;
    351     case kCondGe:
    352       OpCondBranch(kCondGt, taken);
    353       OpCondBranch(kCondLt, not_taken);
    354       ccode = kCondUge;
    355       break;
    356     default:
    357       LOG(FATAL) << "Unexpected ccode: " << ccode;
    358   }
    359   OpRegReg(kOpCmp, rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
    360   OpCondBranch(ccode, taken);
    361 }
    362 
    363 /*
    364  * Generate a register comparison to an immediate and branch.  Caller
    365  * is responsible for setting branch target field.
    366  */
    367 LIR* ArmMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
    368   LIR* branch = nullptr;
    369   ArmConditionCode arm_cond = ArmConditionEncoding(cond);
    370   /*
    371    * A common use of OpCmpImmBranch is for null checks, and using the Thumb 16-bit
    372    * compare-and-branch if zero is ideal if it will reach.  However, because null checks
    373    * branch forward to a slow path, they will frequently not reach - and thus have to
    374    * be converted to a long form during assembly (which will trigger another assembly
    375    * pass).  Here we estimate the branch distance for checks, and if large directly
    376    * generate the long form in an attempt to avoid an extra assembly pass.
    377    * TODO: consider interspersing slowpaths in code following unconditional branches.
    378    */
    379   bool skip = ((target != NULL) && (target->opcode == kPseudoThrowTarget));
    380   skip &= ((cu_->code_item->insns_size_in_code_units_ - current_dalvik_offset_) > 64);
    381   if (!skip && reg.Low8() && (check_value == 0)) {
    382     if (arm_cond == kArmCondEq || arm_cond == kArmCondNe) {
    383       branch = NewLIR2((arm_cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
    384                        reg.GetReg(), 0);
    385     } else if (arm_cond == kArmCondLs) {
    386       // kArmCondLs is an unsigned less or equal. A comparison r <= 0 is then the same as cbz.
    387       // This case happens for a bounds check of array[0].
    388       branch = NewLIR2(kThumb2Cbz, reg.GetReg(), 0);
    389     }
    390   }
    391 
    392   if (branch == nullptr) {
    393     OpRegImm(kOpCmp, reg, check_value);
    394     branch = NewLIR2(kThumbBCond, 0, arm_cond);
    395   }
    396 
    397   branch->target = target;
    398   return branch;
    399 }
    400 
    401 LIR* ArmMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
    402   LIR* res;
    403   int opcode;
    404   // If src or dest is a pair, we'll be using low reg.
    405   if (r_dest.IsPair()) {
    406     r_dest = r_dest.GetLow();
    407   }
    408   if (r_src.IsPair()) {
    409     r_src = r_src.GetLow();
    410   }
    411   if (r_dest.IsFloat() || r_src.IsFloat())
    412     return OpFpRegCopy(r_dest, r_src);
    413   if (r_dest.Low8() && r_src.Low8())
    414     opcode = kThumbMovRR;
    415   else if (!r_dest.Low8() && !r_src.Low8())
    416      opcode = kThumbMovRR_H2H;
    417   else if (r_dest.Low8())
    418      opcode = kThumbMovRR_H2L;
    419   else
    420      opcode = kThumbMovRR_L2H;
    421   res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
    422   if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
    423     res->flags.is_nop = true;
    424   }
    425   return res;
    426 }
    427 
    428 void ArmMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
    429   if (r_dest != r_src) {
    430     LIR* res = OpRegCopyNoInsert(r_dest, r_src);
    431     AppendLIR(res);
    432   }
    433 }
    434 
    435 void ArmMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
    436   if (r_dest != r_src) {
    437     bool dest_fp = r_dest.IsFloat();
    438     bool src_fp = r_src.IsFloat();
    439     DCHECK(r_dest.Is64Bit());
    440     DCHECK(r_src.Is64Bit());
    441     if (dest_fp) {
    442       if (src_fp) {
    443         OpRegCopy(r_dest, r_src);
    444       } else {
    445         NewLIR3(kThumb2Fmdrr, r_dest.GetReg(), r_src.GetLowReg(), r_src.GetHighReg());
    446       }
    447     } else {
    448       if (src_fp) {
    449         NewLIR3(kThumb2Fmrrd, r_dest.GetLowReg(), r_dest.GetHighReg(), r_src.GetReg());
    450       } else {
    451         // Handle overlap
    452         if (r_src.GetHighReg() == r_dest.GetLowReg()) {
    453           DCHECK_NE(r_src.GetLowReg(), r_dest.GetHighReg());
    454           OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
    455           OpRegCopy(r_dest.GetLow(), r_src.GetLow());
    456         } else {
    457           OpRegCopy(r_dest.GetLow(), r_src.GetLow());
    458           OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
    459         }
    460       }
    461     }
    462   }
    463 }
    464 
    465 // Table of magic divisors
    466 struct MagicTable {
    467   uint32_t magic;
    468   uint32_t shift;
    469   DividePattern pattern;
    470 };
    471 
    472 static const MagicTable magic_table[] = {
    473   {0, 0, DivideNone},        // 0
    474   {0, 0, DivideNone},        // 1
    475   {0, 0, DivideNone},        // 2
    476   {0x55555556, 0, Divide3},  // 3
    477   {0, 0, DivideNone},        // 4
    478   {0x66666667, 1, Divide5},  // 5
    479   {0x2AAAAAAB, 0, Divide3},  // 6
    480   {0x92492493, 2, Divide7},  // 7
    481   {0, 0, DivideNone},        // 8
    482   {0x38E38E39, 1, Divide5},  // 9
    483   {0x66666667, 2, Divide5},  // 10
    484   {0x2E8BA2E9, 1, Divide5},  // 11
    485   {0x2AAAAAAB, 1, Divide5},  // 12
    486   {0x4EC4EC4F, 2, Divide5},  // 13
    487   {0x92492493, 3, Divide7},  // 14
    488   {0x88888889, 3, Divide7},  // 15
    489 };
    490 
    491 // Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
    492 bool ArmMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
    493                                     RegLocation rl_src, RegLocation rl_dest, int lit) {
    494   if ((lit < 0) || (lit >= static_cast<int>(sizeof(magic_table)/sizeof(magic_table[0])))) {
    495     return false;
    496   }
    497   DividePattern pattern = magic_table[lit].pattern;
    498   if (pattern == DivideNone) {
    499     return false;
    500   }
    501 
    502   RegStorage r_magic = AllocTemp();
    503   LoadConstant(r_magic, magic_table[lit].magic);
    504   rl_src = LoadValue(rl_src, kCoreReg);
    505   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    506   RegStorage r_hi = AllocTemp();
    507   RegStorage r_lo = AllocTemp();
    508 
    509   // rl_dest and rl_src might overlap.
    510   // Reuse r_hi to save the div result for reminder case.
    511   RegStorage r_div_result = is_div ? rl_result.reg : r_hi;
    512 
    513   NewLIR4(kThumb2Smull, r_lo.GetReg(), r_hi.GetReg(), r_magic.GetReg(), rl_src.reg.GetReg());
    514   switch (pattern) {
    515     case Divide3:
    516       OpRegRegRegShift(kOpSub, r_div_result, r_hi, rl_src.reg, EncodeShift(kArmAsr, 31));
    517       break;
    518     case Divide5:
    519       OpRegRegImm(kOpAsr, r_lo, rl_src.reg, 31);
    520       OpRegRegRegShift(kOpRsub, r_div_result, r_lo, r_hi,
    521                        EncodeShift(kArmAsr, magic_table[lit].shift));
    522       break;
    523     case Divide7:
    524       OpRegReg(kOpAdd, r_hi, rl_src.reg);
    525       OpRegRegImm(kOpAsr, r_lo, rl_src.reg, 31);
    526       OpRegRegRegShift(kOpRsub, r_div_result, r_lo, r_hi,
    527                        EncodeShift(kArmAsr, magic_table[lit].shift));
    528       break;
    529     default:
    530       LOG(FATAL) << "Unexpected pattern: " << pattern;
    531   }
    532 
    533   if (!is_div) {
    534     // div_result = src / lit
    535     // tmp1 = div_result * lit
    536     // dest = src - tmp1
    537     RegStorage tmp1 = r_lo;
    538     EasyMultiplyOp ops[2];
    539 
    540     bool canEasyMultiply = GetEasyMultiplyTwoOps(lit, ops);
    541     DCHECK_NE(canEasyMultiply, false);
    542 
    543     GenEasyMultiplyTwoOps(tmp1, r_div_result, ops);
    544     OpRegRegReg(kOpSub, rl_result.reg, rl_src.reg, tmp1);
    545   }
    546 
    547   StoreValue(rl_dest, rl_result);
    548   return true;
    549 }
    550 
    551 // Try to convert *lit to 1 RegRegRegShift/RegRegShift form.
    552 bool ArmMir2Lir::GetEasyMultiplyOp(int lit, ArmMir2Lir::EasyMultiplyOp* op) {
    553   if (lit == 0) {
    554     // Special case for *divide-by-zero*. The ops won't actually be used to generate code, as
    555     // GenArithOpIntLit will directly generate exception-throwing code, and multiply-by-zero will
    556     // have been optimized away earlier.
    557     op->op = kOpInvalid;
    558     return true;
    559   }
    560 
    561   if (IsPowerOfTwo(lit)) {
    562     op->op = kOpLsl;
    563     op->shift = LowestSetBit(lit);
    564     return true;
    565   }
    566 
    567   if (IsPowerOfTwo(lit - 1)) {
    568     op->op = kOpAdd;
    569     op->shift = LowestSetBit(lit - 1);
    570     return true;
    571   }
    572 
    573   if (IsPowerOfTwo(lit + 1)) {
    574     op->op = kOpRsub;
    575     op->shift = LowestSetBit(lit + 1);
    576     return true;
    577   }
    578 
    579   op->op = kOpInvalid;
    580   op->shift = 0;
    581   return false;
    582 }
    583 
    584 // Try to convert *lit to 1~2 RegRegRegShift/RegRegShift forms.
    585 bool ArmMir2Lir::GetEasyMultiplyTwoOps(int lit, EasyMultiplyOp* ops) {
    586   GetEasyMultiplyOp(lit, &ops[0]);
    587   if (GetEasyMultiplyOp(lit, &ops[0])) {
    588     ops[1].op = kOpInvalid;
    589     ops[1].shift = 0;
    590     return true;
    591   }
    592 
    593   int lit1 = lit;
    594   uint32_t shift = LowestSetBit(lit1);
    595   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
    596     ops[1].op = kOpLsl;
    597     ops[1].shift = shift;
    598     return true;
    599   }
    600 
    601   lit1 = lit - 1;
    602   shift = LowestSetBit(lit1);
    603   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
    604     ops[1].op = kOpAdd;
    605     ops[1].shift = shift;
    606     return true;
    607   }
    608 
    609   lit1 = lit + 1;
    610   shift = LowestSetBit(lit1);
    611   if (GetEasyMultiplyOp(lit1 >> shift, &ops[0])) {
    612     ops[1].op = kOpRsub;
    613     ops[1].shift = shift;
    614     return true;
    615   }
    616 
    617   return false;
    618 }
    619 
    620 // Generate instructions to do multiply.
    621 // Additional temporary register is required,
    622 // if it need to generate 2 instructions and src/dest overlap.
    623 void ArmMir2Lir::GenEasyMultiplyTwoOps(RegStorage r_dest, RegStorage r_src, EasyMultiplyOp* ops) {
    624   // tmp1 = ( src << shift1) + [ src | -src | 0 ]
    625   // dest = (tmp1 << shift2) + [ src | -src | 0 ]
    626 
    627   RegStorage r_tmp1;
    628   if (ops[1].op == kOpInvalid) {
    629     r_tmp1 = r_dest;
    630   } else if (r_dest.GetReg() != r_src.GetReg()) {
    631     r_tmp1 = r_dest;
    632   } else {
    633     r_tmp1 = AllocTemp();
    634   }
    635 
    636   switch (ops[0].op) {
    637     case kOpLsl:
    638       OpRegRegImm(kOpLsl, r_tmp1, r_src, ops[0].shift);
    639       break;
    640     case kOpAdd:
    641       OpRegRegRegShift(kOpAdd, r_tmp1, r_src, r_src, EncodeShift(kArmLsl, ops[0].shift));
    642       break;
    643     case kOpRsub:
    644       OpRegRegRegShift(kOpRsub, r_tmp1, r_src, r_src, EncodeShift(kArmLsl, ops[0].shift));
    645       break;
    646     default:
    647       DCHECK_EQ(ops[0].op, kOpInvalid);
    648       break;
    649   }
    650 
    651   switch (ops[1].op) {
    652     case kOpInvalid:
    653       return;
    654     case kOpLsl:
    655       OpRegRegImm(kOpLsl, r_dest, r_tmp1, ops[1].shift);
    656       break;
    657     case kOpAdd:
    658       OpRegRegRegShift(kOpAdd, r_dest, r_src, r_tmp1, EncodeShift(kArmLsl, ops[1].shift));
    659       break;
    660     case kOpRsub:
    661       OpRegRegRegShift(kOpRsub, r_dest, r_src, r_tmp1, EncodeShift(kArmLsl, ops[1].shift));
    662       break;
    663     default:
    664       LOG(FATAL) << "Unexpected opcode passed to GenEasyMultiplyTwoOps";
    665       break;
    666   }
    667 }
    668 
    669 bool ArmMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
    670   EasyMultiplyOp ops[2];
    671 
    672   if (!GetEasyMultiplyTwoOps(lit, ops)) {
    673     return false;
    674   }
    675 
    676   rl_src = LoadValue(rl_src, kCoreReg);
    677   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    678 
    679   GenEasyMultiplyTwoOps(rl_result.reg, rl_src.reg, ops);
    680   StoreValue(rl_dest, rl_result);
    681   return true;
    682 }
    683 
    684 RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
    685                       RegLocation rl_src2, bool is_div, bool check_zero) {
    686   LOG(FATAL) << "Unexpected use of GenDivRem for Arm";
    687   return rl_dest;
    688 }
    689 
    690 RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
    691   LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm";
    692   return rl_dest;
    693 }
    694 
    695 RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, bool is_div) {
    696   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    697 
    698   // Put the literal in a temp.
    699   RegStorage lit_temp = AllocTemp();
    700   LoadConstant(lit_temp, lit);
    701   // Use the generic case for div/rem with arg2 in a register.
    702   // TODO: The literal temp can be freed earlier during a modulus to reduce reg pressure.
    703   rl_result = GenDivRem(rl_result, reg1, lit_temp, is_div);
    704   FreeTemp(lit_temp);
    705 
    706   return rl_result;
    707 }
    708 
    709 RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
    710                                   bool is_div) {
    711   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    712   if (is_div) {
    713     // Simple case, use sdiv instruction.
    714     OpRegRegReg(kOpDiv, rl_result.reg, reg1, reg2);
    715   } else {
    716     // Remainder case, use the following code:
    717     // temp = reg1 / reg2      - integer division
    718     // temp = temp * reg2
    719     // dest = reg1 - temp
    720 
    721     RegStorage temp = AllocTemp();
    722     OpRegRegReg(kOpDiv, temp, reg1, reg2);
    723     OpRegReg(kOpMul, temp, reg2);
    724     OpRegRegReg(kOpSub, rl_result.reg, reg1, temp);
    725     FreeTemp(temp);
    726   }
    727 
    728   return rl_result;
    729 }
    730 
    731 bool ArmMir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
    732   DCHECK_EQ(cu_->instruction_set, kThumb2);
    733   if (is_long) {
    734     return false;
    735   }
    736   RegLocation rl_src1 = info->args[0];
    737   RegLocation rl_src2 = info->args[1];
    738   rl_src1 = LoadValue(rl_src1, kCoreReg);
    739   rl_src2 = LoadValue(rl_src2, kCoreReg);
    740   RegLocation rl_dest = InlineTarget(info);
    741   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    742   OpRegReg(kOpCmp, rl_src1.reg, rl_src2.reg);
    743   LIR* it = OpIT((is_min) ? kCondGt : kCondLt, "E");
    744   OpRegReg(kOpMov, rl_result.reg, rl_src2.reg);
    745   OpRegReg(kOpMov, rl_result.reg, rl_src1.reg);
    746   OpEndIT(it);
    747   StoreValue(rl_dest, rl_result);
    748   return true;
    749 }
    750 
    751 bool ArmMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
    752   RegLocation rl_src_address = info->args[0];  // long address
    753   rl_src_address = NarrowRegLoc(rl_src_address);  // ignore high half in info->args[1]
    754   RegLocation rl_dest = InlineTarget(info);
    755   RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
    756   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    757   if (size == k64) {
    758     // Fake unaligned LDRD by two unaligned LDR instructions on ARMv7 with SCTLR.A set to 0.
    759     if (rl_address.reg.GetReg() != rl_result.reg.GetLowReg()) {
    760       Load32Disp(rl_address.reg, 0, rl_result.reg.GetLow());
    761       Load32Disp(rl_address.reg, 4, rl_result.reg.GetHigh());
    762     } else {
    763       Load32Disp(rl_address.reg, 4, rl_result.reg.GetHigh());
    764       Load32Disp(rl_address.reg, 0, rl_result.reg.GetLow());
    765     }
    766     StoreValueWide(rl_dest, rl_result);
    767   } else {
    768     DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
    769     // Unaligned load with LDR and LDRSH is allowed on ARMv7 with SCTLR.A set to 0.
    770     LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
    771     StoreValue(rl_dest, rl_result);
    772   }
    773   return true;
    774 }
    775 
    776 bool ArmMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
    777   RegLocation rl_src_address = info->args[0];  // long address
    778   rl_src_address = NarrowRegLoc(rl_src_address);  // ignore high half in info->args[1]
    779   RegLocation rl_src_value = info->args[2];  // [size] value
    780   RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
    781   if (size == k64) {
    782     // Fake unaligned STRD by two unaligned STR instructions on ARMv7 with SCTLR.A set to 0.
    783     RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg);
    784     StoreBaseDisp(rl_address.reg, 0, rl_value.reg.GetLow(), k32, kNotVolatile);
    785     StoreBaseDisp(rl_address.reg, 4, rl_value.reg.GetHigh(), k32, kNotVolatile);
    786   } else {
    787     DCHECK(size == kSignedByte || size == kSignedHalf || size == k32);
    788     // Unaligned store with STR and STRSH is allowed on ARMv7 with SCTLR.A set to 0.
    789     RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
    790     StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
    791   }
    792   return true;
    793 }
    794 
    795 // Generate a CAS with memory_order_seq_cst semantics.
    796 bool ArmMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
    797   DCHECK_EQ(cu_->instruction_set, kThumb2);
    798   // Unused - RegLocation rl_src_unsafe = info->args[0];
    799   RegLocation rl_src_obj = info->args[1];  // Object - known non-null
    800   RegLocation rl_src_offset = info->args[2];  // long low
    801   rl_src_offset = NarrowRegLoc(rl_src_offset);  // ignore high half in info->args[3]
    802   RegLocation rl_src_expected = info->args[4];  // int, long or Object
    803   // If is_long, high half is in info->args[5]
    804   RegLocation rl_src_new_value = info->args[is_long ? 6 : 5];  // int, long or Object
    805   // If is_long, high half is in info->args[7]
    806   RegLocation rl_dest = InlineTarget(info);  // boolean place for result
    807 
    808   // We have only 5 temporary registers available and actually only 4 if the InlineTarget
    809   // above locked one of the temps. For a straightforward CAS64 we need 7 registers:
    810   // r_ptr (1), new_value (2), expected(2) and ldrexd result (2). If neither expected nor
    811   // new_value is in a non-temp core register we shall reload them in the ldrex/strex loop
    812   // into the same temps, reducing the number of required temps down to 5. We shall work
    813   // around the potentially locked temp by using LR for r_ptr, unconditionally.
    814   // TODO: Pass information about the need for more temps to the stack frame generation
    815   // code so that we can rely on being able to allocate enough temps.
    816   DCHECK(!GetRegInfo(rs_rARM_LR)->IsTemp());
    817   MarkTemp(rs_rARM_LR);
    818   FreeTemp(rs_rARM_LR);
    819   LockTemp(rs_rARM_LR);
    820   bool load_early = true;
    821   if (is_long) {
    822     RegStorage expected_reg = rl_src_expected.reg.IsPair() ? rl_src_expected.reg.GetLow() :
    823         rl_src_expected.reg;
    824     RegStorage new_val_reg = rl_src_new_value.reg.IsPair() ? rl_src_new_value.reg.GetLow() :
    825         rl_src_new_value.reg;
    826     bool expected_is_core_reg = rl_src_expected.location == kLocPhysReg && !expected_reg.IsFloat();
    827     bool new_value_is_core_reg = rl_src_new_value.location == kLocPhysReg && !new_val_reg.IsFloat();
    828     bool expected_is_good_reg = expected_is_core_reg && !IsTemp(expected_reg);
    829     bool new_value_is_good_reg = new_value_is_core_reg && !IsTemp(new_val_reg);
    830 
    831     if (!expected_is_good_reg && !new_value_is_good_reg) {
    832       // None of expected/new_value is non-temp reg, need to load both late
    833       load_early = false;
    834       // Make sure they are not in the temp regs and the load will not be skipped.
    835       if (expected_is_core_reg) {
    836         FlushRegWide(rl_src_expected.reg);
    837         ClobberSReg(rl_src_expected.s_reg_low);
    838         ClobberSReg(GetSRegHi(rl_src_expected.s_reg_low));
    839         rl_src_expected.location = kLocDalvikFrame;
    840       }
    841       if (new_value_is_core_reg) {
    842         FlushRegWide(rl_src_new_value.reg);
    843         ClobberSReg(rl_src_new_value.s_reg_low);
    844         ClobberSReg(GetSRegHi(rl_src_new_value.s_reg_low));
    845         rl_src_new_value.location = kLocDalvikFrame;
    846       }
    847     }
    848   }
    849 
    850   // Prevent reordering with prior memory operations.
    851   GenMemBarrier(kAnyStore);
    852 
    853   RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
    854   RegLocation rl_new_value;
    855   if (!is_long) {
    856     rl_new_value = LoadValue(rl_src_new_value);
    857   } else if (load_early) {
    858     rl_new_value = LoadValueWide(rl_src_new_value, kCoreReg);
    859   }
    860 
    861   if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
    862     // Mark card for object assuming new value is stored.
    863     MarkGCCard(rl_new_value.reg, rl_object.reg);
    864   }
    865 
    866   RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
    867 
    868   RegStorage r_ptr = rs_rARM_LR;
    869   OpRegRegReg(kOpAdd, r_ptr, rl_object.reg, rl_offset.reg);
    870 
    871   // Free now unneeded rl_object and rl_offset to give more temps.
    872   ClobberSReg(rl_object.s_reg_low);
    873   FreeTemp(rl_object.reg);
    874   ClobberSReg(rl_offset.s_reg_low);
    875   FreeTemp(rl_offset.reg);
    876 
    877   RegLocation rl_expected;
    878   if (!is_long) {
    879     rl_expected = LoadValue(rl_src_expected);
    880   } else if (load_early) {
    881     rl_expected = LoadValueWide(rl_src_expected, kCoreReg);
    882   } else {
    883     // NOTE: partially defined rl_expected & rl_new_value - but we just want the regs.
    884     RegStorage low_reg = AllocTemp();
    885     RegStorage high_reg = AllocTemp();
    886     rl_new_value.reg = RegStorage::MakeRegPair(low_reg, high_reg);
    887     rl_expected = rl_new_value;
    888   }
    889 
    890   // do {
    891   //   tmp = [r_ptr] - expected;
    892   // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
    893   // result = tmp != 0;
    894 
    895   RegStorage r_tmp = AllocTemp();
    896   LIR* target = NewLIR0(kPseudoTargetLabel);
    897 
    898   LIR* it = nullptr;
    899   if (is_long) {
    900     RegStorage r_tmp_high = AllocTemp();
    901     if (!load_early) {
    902       LoadValueDirectWide(rl_src_expected, rl_expected.reg);
    903     }
    904     NewLIR3(kThumb2Ldrexd, r_tmp.GetReg(), r_tmp_high.GetReg(), r_ptr.GetReg());
    905     OpRegReg(kOpSub, r_tmp, rl_expected.reg.GetLow());
    906     OpRegReg(kOpSub, r_tmp_high, rl_expected.reg.GetHigh());
    907     if (!load_early) {
    908       LoadValueDirectWide(rl_src_new_value, rl_new_value.reg);
    909     }
    910     // Make sure we use ORR that sets the ccode
    911     if (r_tmp.Low8() && r_tmp_high.Low8()) {
    912       NewLIR2(kThumbOrr, r_tmp.GetReg(), r_tmp_high.GetReg());
    913     } else {
    914       NewLIR4(kThumb2OrrRRRs, r_tmp.GetReg(), r_tmp.GetReg(), r_tmp_high.GetReg(), 0);
    915     }
    916     FreeTemp(r_tmp_high);  // Now unneeded
    917 
    918     DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
    919     it = OpIT(kCondEq, "T");
    920     NewLIR4(kThumb2Strexd /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetLowReg(), rl_new_value.reg.GetHighReg(), r_ptr.GetReg());
    921 
    922   } else {
    923     NewLIR3(kThumb2Ldrex, r_tmp.GetReg(), r_ptr.GetReg(), 0);
    924     OpRegReg(kOpSub, r_tmp, rl_expected.reg);
    925     DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
    926     it = OpIT(kCondEq, "T");
    927     NewLIR4(kThumb2Strex /* eq */, r_tmp.GetReg(), rl_new_value.reg.GetReg(), r_ptr.GetReg(), 0);
    928   }
    929 
    930   // Still one conditional left from OpIT(kCondEq, "T") from either branch
    931   OpRegImm(kOpCmp /* eq */, r_tmp, 1);
    932   OpEndIT(it);
    933 
    934   OpCondBranch(kCondEq, target);
    935 
    936   if (!load_early) {
    937     FreeTemp(rl_expected.reg);  // Now unneeded.
    938   }
    939 
    940   // Prevent reordering with subsequent memory operations.
    941   GenMemBarrier(kLoadAny);
    942 
    943   // result := (tmp1 != 0) ? 0 : 1;
    944   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    945   OpRegRegImm(kOpRsub, rl_result.reg, r_tmp, 1);
    946   DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
    947   it = OpIT(kCondUlt, "");
    948   LoadConstant(rl_result.reg, 0); /* cc */
    949   FreeTemp(r_tmp);  // Now unneeded.
    950   OpEndIT(it);     // Barrier to terminate OpIT.
    951 
    952   StoreValue(rl_dest, rl_result);
    953 
    954   // Now, restore lr to its non-temp status.
    955   Clobber(rs_rARM_LR);
    956   UnmarkTemp(rs_rARM_LR);
    957   return true;
    958 }
    959 
    960 bool ArmMir2Lir::GenInlinedArrayCopyCharArray(CallInfo* info) {
    961   constexpr int kLargeArrayThreshold = 256;
    962 
    963   RegLocation rl_src = info->args[0];
    964   RegLocation rl_src_pos = info->args[1];
    965   RegLocation rl_dst = info->args[2];
    966   RegLocation rl_dst_pos = info->args[3];
    967   RegLocation rl_length = info->args[4];
    968   // Compile time check, handle exception by non-inline method to reduce related meta-data.
    969   if ((rl_src_pos.is_const && (mir_graph_->ConstantValue(rl_src_pos) < 0)) ||
    970       (rl_dst_pos.is_const && (mir_graph_->ConstantValue(rl_dst_pos) < 0)) ||
    971       (rl_length.is_const && (mir_graph_->ConstantValue(rl_length) < 0))) {
    972     return false;
    973   }
    974 
    975   ClobberCallerSave();
    976   LockCallTemps();  // Prepare for explicit register usage.
    977   LockTemp(rs_r12);
    978   RegStorage rs_src = rs_r0;
    979   RegStorage rs_dst = rs_r1;
    980   LoadValueDirectFixed(rl_src, rs_src);
    981   LoadValueDirectFixed(rl_dst, rs_dst);
    982 
    983   // Handle null pointer exception in slow-path.
    984   LIR* src_check_branch = OpCmpImmBranch(kCondEq, rs_src, 0, nullptr);
    985   LIR* dst_check_branch = OpCmpImmBranch(kCondEq, rs_dst, 0, nullptr);
    986   // Handle potential overlapping in slow-path.
    987   LIR* src_dst_same = OpCmpBranch(kCondEq, rs_src, rs_dst, nullptr);
    988   // Handle exception or big length in slow-path.
    989   RegStorage rs_length = rs_r2;
    990   LoadValueDirectFixed(rl_length, rs_length);
    991   LIR* len_neg_or_too_big = OpCmpImmBranch(kCondHi, rs_length, kLargeArrayThreshold, nullptr);
    992   // Src bounds check.
    993   RegStorage rs_pos = rs_r3;
    994   RegStorage rs_arr_length = rs_r12;
    995   LoadValueDirectFixed(rl_src_pos, rs_pos);
    996   LIR* src_pos_negative = OpCmpImmBranch(kCondLt, rs_pos, 0, nullptr);
    997   Load32Disp(rs_src, mirror::Array::LengthOffset().Int32Value(), rs_arr_length);
    998   OpRegReg(kOpSub, rs_arr_length, rs_pos);
    999   LIR* src_bad_len = OpCmpBranch(kCondLt, rs_arr_length, rs_length, nullptr);
   1000   // Dst bounds check.
   1001   LoadValueDirectFixed(rl_dst_pos, rs_pos);
   1002   LIR* dst_pos_negative = OpCmpImmBranch(kCondLt, rs_pos, 0, nullptr);
   1003   Load32Disp(rs_dst, mirror::Array::LengthOffset().Int32Value(), rs_arr_length);
   1004   OpRegReg(kOpSub, rs_arr_length, rs_pos);
   1005   LIR* dst_bad_len = OpCmpBranch(kCondLt, rs_arr_length, rs_length, nullptr);
   1006 
   1007   // Everything is checked now.
   1008   OpRegImm(kOpAdd, rs_dst, mirror::Array::DataOffset(2).Int32Value());
   1009   OpRegReg(kOpAdd, rs_dst, rs_pos);
   1010   OpRegReg(kOpAdd, rs_dst, rs_pos);
   1011   OpRegImm(kOpAdd, rs_src, mirror::Array::DataOffset(2).Int32Value());
   1012   LoadValueDirectFixed(rl_src_pos, rs_pos);
   1013   OpRegReg(kOpAdd, rs_src, rs_pos);
   1014   OpRegReg(kOpAdd, rs_src, rs_pos);
   1015 
   1016   RegStorage rs_tmp = rs_pos;
   1017   OpRegRegImm(kOpLsl, rs_length, rs_length, 1);
   1018 
   1019   // Copy one element.
   1020   OpRegRegImm(kOpAnd, rs_tmp, rs_length, 2);
   1021   LIR* jmp_to_begin_loop = OpCmpImmBranch(kCondEq, rs_tmp, 0, nullptr);
   1022   OpRegImm(kOpSub, rs_length, 2);
   1023   LoadBaseIndexed(rs_src, rs_length, rs_tmp, 0, kSignedHalf);
   1024   StoreBaseIndexed(rs_dst, rs_length, rs_tmp, 0, kSignedHalf);
   1025 
   1026   // Copy two elements.
   1027   LIR *begin_loop = NewLIR0(kPseudoTargetLabel);
   1028   LIR* jmp_to_ret = OpCmpImmBranch(kCondEq, rs_length, 0, nullptr);
   1029   OpRegImm(kOpSub, rs_length, 4);
   1030   LoadBaseIndexed(rs_src, rs_length, rs_tmp, 0, k32);
   1031   StoreBaseIndexed(rs_dst, rs_length, rs_tmp, 0, k32);
   1032   OpUnconditionalBranch(begin_loop);
   1033 
   1034   LIR *check_failed = NewLIR0(kPseudoTargetLabel);
   1035   LIR* launchpad_branch = OpUnconditionalBranch(nullptr);
   1036   LIR* return_point = NewLIR0(kPseudoTargetLabel);
   1037 
   1038   src_check_branch->target = check_failed;
   1039   dst_check_branch->target = check_failed;
   1040   src_dst_same->target = check_failed;
   1041   len_neg_or_too_big->target = check_failed;
   1042   src_pos_negative->target = check_failed;
   1043   src_bad_len->target = check_failed;
   1044   dst_pos_negative->target = check_failed;
   1045   dst_bad_len->target = check_failed;
   1046   jmp_to_begin_loop->target = begin_loop;
   1047   jmp_to_ret->target = return_point;
   1048 
   1049   AddIntrinsicSlowPath(info, launchpad_branch, return_point);
   1050   ClobberCallerSave();  // We must clobber everything because slow path will return here
   1051 
   1052   return true;
   1053 }
   1054 
   1055 LIR* ArmMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
   1056   return RawLIR(current_dalvik_offset_, kThumb2LdrPcRel12, reg.GetReg(), 0, 0, 0, 0, target);
   1057 }
   1058 
   1059 LIR* ArmMir2Lir::OpVldm(RegStorage r_base, int count) {
   1060   return NewLIR3(kThumb2Vldms, r_base.GetReg(), rs_fr0.GetReg(), count);
   1061 }
   1062 
   1063 LIR* ArmMir2Lir::OpVstm(RegStorage r_base, int count) {
   1064   return NewLIR3(kThumb2Vstms, r_base.GetReg(), rs_fr0.GetReg(), count);
   1065 }
   1066 
   1067 void ArmMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
   1068                                                RegLocation rl_result, int lit,
   1069                                                int first_bit, int second_bit) {
   1070   OpRegRegRegShift(kOpAdd, rl_result.reg, rl_src.reg, rl_src.reg,
   1071                    EncodeShift(kArmLsl, second_bit - first_bit));
   1072   if (first_bit != 0) {
   1073     OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
   1074   }
   1075 }
   1076 
   1077 void ArmMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
   1078   DCHECK(reg.IsPair());   // TODO: support k64BitSolo.
   1079   RegStorage t_reg = AllocTemp();
   1080   NewLIR4(kThumb2OrrRRRs, t_reg.GetReg(), reg.GetLowReg(), reg.GetHighReg(), 0);
   1081   FreeTemp(t_reg);
   1082   GenDivZeroCheck(kCondEq);
   1083 }
   1084 
   1085 // Test suspend flag, return target of taken suspend branch
   1086 LIR* ArmMir2Lir::OpTestSuspend(LIR* target) {
   1087 #ifdef ARM_R4_SUSPEND_FLAG
   1088   NewLIR2(kThumbSubRI8, rs_rARM_SUSPEND.GetReg(), 1);
   1089   return OpCondBranch((target == NULL) ? kCondEq : kCondNe, target);
   1090 #else
   1091   RegStorage t_reg = AllocTemp();
   1092   LoadBaseDisp(rs_rARM_SELF, Thread::ThreadFlagsOffset<4>().Int32Value(),
   1093     t_reg, kUnsignedHalf);
   1094   LIR* cmp_branch = OpCmpImmBranch((target == NULL) ? kCondNe : kCondEq, t_reg,
   1095     0, target);
   1096   FreeTemp(t_reg);
   1097   return cmp_branch;
   1098 #endif
   1099 }
   1100 
   1101 // Decrement register and branch on condition
   1102 LIR* ArmMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
   1103   // Combine sub & test using sub setflags encoding here
   1104   OpRegRegImm(kOpSub, reg, reg, 1);  // For value == 1, this should set flags.
   1105   DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
   1106   return OpCondBranch(c_code, target);
   1107 }
   1108 
   1109 bool ArmMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
   1110 #if ANDROID_SMP != 0
   1111   // Start off with using the last LIR as the barrier. If it is not enough, then we will generate one.
   1112   LIR* barrier = last_lir_insn_;
   1113 
   1114   int dmb_flavor;
   1115   // TODO: revisit Arm barrier kinds
   1116   switch (barrier_kind) {
   1117     case kAnyStore: dmb_flavor = kISH; break;
   1118     case kLoadAny: dmb_flavor = kISH; break;
   1119     case kStoreStore: dmb_flavor = kISHST; break;
   1120     case kAnyAny: dmb_flavor = kISH; break;
   1121     default:
   1122       LOG(FATAL) << "Unexpected MemBarrierKind: " << barrier_kind;
   1123       dmb_flavor = kSY;  // quiet gcc.
   1124       break;
   1125   }
   1126 
   1127   bool ret = false;
   1128 
   1129   // If the same barrier already exists, don't generate another.
   1130   if (barrier == nullptr
   1131       || (barrier != nullptr && (barrier->opcode != kThumb2Dmb || barrier->operands[0] != dmb_flavor))) {
   1132     barrier = NewLIR1(kThumb2Dmb, dmb_flavor);
   1133     ret = true;
   1134   }
   1135 
   1136   // At this point we must have a memory barrier. Mark it as a scheduling barrier as well.
   1137   DCHECK(!barrier->flags.use_def_invalid);
   1138   barrier->u.m.def_mask = &kEncodeAll;
   1139   return ret;
   1140 #else
   1141   return false;
   1142 #endif
   1143 }
   1144 
   1145 void ArmMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
   1146   rl_src = LoadValueWide(rl_src, kCoreReg);
   1147   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   1148   RegStorage z_reg = AllocTemp();
   1149   LoadConstantNoClobber(z_reg, 0);
   1150   // Check for destructive overlap
   1151   if (rl_result.reg.GetLowReg() == rl_src.reg.GetHighReg()) {
   1152     RegStorage t_reg = AllocTemp();
   1153     OpRegCopy(t_reg, rl_result.reg.GetLow());
   1154     OpRegRegReg(kOpSub, rl_result.reg.GetLow(), z_reg, rl_src.reg.GetLow());
   1155     OpRegRegReg(kOpSbc, rl_result.reg.GetHigh(), z_reg, t_reg);
   1156     FreeTemp(t_reg);
   1157   } else {
   1158     OpRegRegReg(kOpSub, rl_result.reg.GetLow(), z_reg, rl_src.reg.GetLow());
   1159     OpRegRegReg(kOpSbc, rl_result.reg.GetHigh(), z_reg, rl_src.reg.GetHigh());
   1160   }
   1161   FreeTemp(z_reg);
   1162   StoreValueWide(rl_dest, rl_result);
   1163 }
   1164 
   1165 void ArmMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
   1166                             RegLocation rl_src1, RegLocation rl_src2) {
   1167     /*
   1168      * tmp1     = src1.hi * src2.lo;  // src1.hi is no longer needed
   1169      * dest     = src1.lo * src2.lo;
   1170      * tmp1    += src1.lo * src2.hi;
   1171      * dest.hi += tmp1;
   1172      *
   1173      * To pull off inline multiply, we have a worst-case requirement of 7 temporary
   1174      * registers.  Normally for Arm, we get 5.  We can get to 6 by including
   1175      * lr in the temp set.  The only problematic case is all operands and result are
   1176      * distinct, and none have been promoted.  In that case, we can succeed by aggressively
   1177      * freeing operand temp registers after they are no longer needed.  All other cases
   1178      * can proceed normally.  We'll just punt on the case of the result having a misaligned
   1179      * overlap with either operand and send that case to a runtime handler.
   1180      */
   1181     RegLocation rl_result;
   1182     if (BadOverlap(rl_src1, rl_dest) || (BadOverlap(rl_src2, rl_dest))) {
   1183       FlushAllRegs();
   1184       CallRuntimeHelperRegLocationRegLocation(kQuickLmul, rl_src1, rl_src2, false);
   1185       rl_result = GetReturnWide(kCoreReg);
   1186       StoreValueWide(rl_dest, rl_result);
   1187       return;
   1188     }
   1189 
   1190     rl_src1 = LoadValueWide(rl_src1, kCoreReg);
   1191     rl_src2 = LoadValueWide(rl_src2, kCoreReg);
   1192 
   1193     int reg_status = 0;
   1194     RegStorage res_lo;
   1195     RegStorage res_hi;
   1196     bool dest_promoted = rl_dest.location == kLocPhysReg && rl_dest.reg.Valid() &&
   1197         !IsTemp(rl_dest.reg.GetLow()) && !IsTemp(rl_dest.reg.GetHigh());
   1198     bool src1_promoted = !IsTemp(rl_src1.reg.GetLow()) && !IsTemp(rl_src1.reg.GetHigh());
   1199     bool src2_promoted = !IsTemp(rl_src2.reg.GetLow()) && !IsTemp(rl_src2.reg.GetHigh());
   1200     // Check if rl_dest is *not* either operand and we have enough temp registers.
   1201     if ((rl_dest.s_reg_low != rl_src1.s_reg_low && rl_dest.s_reg_low != rl_src2.s_reg_low) &&
   1202         (dest_promoted || src1_promoted || src2_promoted)) {
   1203       // In this case, we do not need to manually allocate temp registers for result.
   1204       rl_result = EvalLoc(rl_dest, kCoreReg, true);
   1205       res_lo = rl_result.reg.GetLow();
   1206       res_hi = rl_result.reg.GetHigh();
   1207     } else {
   1208       res_lo = AllocTemp();
   1209       if ((rl_src1.s_reg_low == rl_src2.s_reg_low) || src1_promoted || src2_promoted) {
   1210         // In this case, we have enough temp registers to be allocated for result.
   1211         res_hi = AllocTemp();
   1212         reg_status = 1;
   1213       } else {
   1214         // In this case, all temps are now allocated.
   1215         // res_hi will be allocated after we can free src1_hi.
   1216         reg_status = 2;
   1217       }
   1218     }
   1219 
   1220     // Temporarily add LR to the temp pool, and assign it to tmp1
   1221     MarkTemp(rs_rARM_LR);
   1222     FreeTemp(rs_rARM_LR);
   1223     RegStorage tmp1 = rs_rARM_LR;
   1224     LockTemp(rs_rARM_LR);
   1225 
   1226     if (rl_src1.reg == rl_src2.reg) {
   1227       DCHECK(res_hi.Valid());
   1228       DCHECK(res_lo.Valid());
   1229       NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg());
   1230       NewLIR4(kThumb2Umull, res_lo.GetReg(), res_hi.GetReg(), rl_src1.reg.GetLowReg(),
   1231               rl_src1.reg.GetLowReg());
   1232       OpRegRegRegShift(kOpAdd, res_hi, res_hi, tmp1, EncodeShift(kArmLsl, 1));
   1233     } else {
   1234       NewLIR3(kThumb2MulRRR, tmp1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetHighReg());
   1235       if (reg_status == 2) {
   1236         DCHECK(!res_hi.Valid());
   1237         DCHECK_NE(rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
   1238         DCHECK_NE(rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
   1239         // Will force free src1_hi, so must clobber.
   1240         Clobber(rl_src1.reg);
   1241         FreeTemp(rl_src1.reg.GetHigh());
   1242         res_hi = AllocTemp();
   1243       }
   1244       DCHECK(res_hi.Valid());
   1245       DCHECK(res_lo.Valid());
   1246       NewLIR4(kThumb2Umull, res_lo.GetReg(), res_hi.GetReg(), rl_src2.reg.GetLowReg(),
   1247               rl_src1.reg.GetLowReg());
   1248       NewLIR4(kThumb2Mla, tmp1.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg(),
   1249               tmp1.GetReg());
   1250       NewLIR4(kThumb2AddRRR, res_hi.GetReg(), tmp1.GetReg(), res_hi.GetReg(), 0);
   1251       if (reg_status == 2) {
   1252         FreeTemp(rl_src1.reg.GetLow());
   1253       }
   1254     }
   1255 
   1256     // Now, restore lr to its non-temp status.
   1257     FreeTemp(tmp1);
   1258     Clobber(rs_rARM_LR);
   1259     UnmarkTemp(rs_rARM_LR);
   1260 
   1261     if (reg_status != 0) {
   1262       // We had manually allocated registers for rl_result.
   1263       // Now construct a RegLocation.
   1264       rl_result = GetReturnWide(kCoreReg);  // Just using as a template.
   1265       rl_result.reg = RegStorage::MakeRegPair(res_lo, res_hi);
   1266     }
   1267 
   1268     StoreValueWide(rl_dest, rl_result);
   1269 }
   1270 
   1271 void ArmMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
   1272                                 RegLocation rl_src2) {
   1273   switch (opcode) {
   1274     case Instruction::MUL_LONG:
   1275     case Instruction::MUL_LONG_2ADDR:
   1276       GenMulLong(opcode, rl_dest, rl_src1, rl_src2);
   1277       return;
   1278     case Instruction::NEG_LONG:
   1279       GenNegLong(rl_dest, rl_src2);
   1280       return;
   1281 
   1282     default:
   1283       break;
   1284   }
   1285 
   1286   // Fallback for all other ops.
   1287   Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
   1288 }
   1289 
   1290 /*
   1291  * Generate array load
   1292  */
   1293 void ArmMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
   1294                              RegLocation rl_index, RegLocation rl_dest, int scale) {
   1295   RegisterClass reg_class = RegClassBySize(size);
   1296   int len_offset = mirror::Array::LengthOffset().Int32Value();
   1297   int data_offset;
   1298   RegLocation rl_result;
   1299   bool constant_index = rl_index.is_const;
   1300   rl_array = LoadValue(rl_array, kRefReg);
   1301   if (!constant_index) {
   1302     rl_index = LoadValue(rl_index, kCoreReg);
   1303   }
   1304 
   1305   if (rl_dest.wide) {
   1306     data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
   1307   } else {
   1308     data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
   1309   }
   1310 
   1311   // If index is constant, just fold it into the data offset
   1312   if (constant_index) {
   1313     data_offset += mir_graph_->ConstantValue(rl_index) << scale;
   1314   }
   1315 
   1316   /* null object? */
   1317   GenNullCheck(rl_array.reg, opt_flags);
   1318 
   1319   bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
   1320   RegStorage reg_len;
   1321   if (needs_range_check) {
   1322     reg_len = AllocTemp();
   1323     /* Get len */
   1324     Load32Disp(rl_array.reg, len_offset, reg_len);
   1325     MarkPossibleNullPointerException(opt_flags);
   1326   } else {
   1327     ForceImplicitNullCheck(rl_array.reg, opt_flags);
   1328   }
   1329   if (rl_dest.wide || rl_dest.fp || constant_index) {
   1330     RegStorage reg_ptr;
   1331     if (constant_index) {
   1332       reg_ptr = rl_array.reg;  // NOTE: must not alter reg_ptr in constant case.
   1333     } else {
   1334       // No special indexed operation, lea + load w/ displacement
   1335       reg_ptr = AllocTempRef();
   1336       OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kArmLsl, scale));
   1337       FreeTemp(rl_index.reg);
   1338     }
   1339     rl_result = EvalLoc(rl_dest, reg_class, true);
   1340 
   1341     if (needs_range_check) {
   1342       if (constant_index) {
   1343         GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
   1344       } else {
   1345         GenArrayBoundsCheck(rl_index.reg, reg_len);
   1346       }
   1347       FreeTemp(reg_len);
   1348     }
   1349     LoadBaseDisp(reg_ptr, data_offset, rl_result.reg, size, kNotVolatile);
   1350     MarkPossibleNullPointerException(opt_flags);
   1351     if (!constant_index) {
   1352       FreeTemp(reg_ptr);
   1353     }
   1354     if (rl_dest.wide) {
   1355       StoreValueWide(rl_dest, rl_result);
   1356     } else {
   1357       StoreValue(rl_dest, rl_result);
   1358     }
   1359   } else {
   1360     // Offset base, then use indexed load
   1361     RegStorage reg_ptr = AllocTempRef();
   1362     OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
   1363     FreeTemp(rl_array.reg);
   1364     rl_result = EvalLoc(rl_dest, reg_class, true);
   1365 
   1366     if (needs_range_check) {
   1367       GenArrayBoundsCheck(rl_index.reg, reg_len);
   1368       FreeTemp(reg_len);
   1369     }
   1370     LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
   1371     MarkPossibleNullPointerException(opt_flags);
   1372     FreeTemp(reg_ptr);
   1373     StoreValue(rl_dest, rl_result);
   1374   }
   1375 }
   1376 
   1377 /*
   1378  * Generate array store
   1379  *
   1380  */
   1381 void ArmMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
   1382                              RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
   1383   RegisterClass reg_class = RegClassBySize(size);
   1384   int len_offset = mirror::Array::LengthOffset().Int32Value();
   1385   bool constant_index = rl_index.is_const;
   1386 
   1387   int data_offset;
   1388   if (size == k64 || size == kDouble) {
   1389     data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
   1390   } else {
   1391     data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
   1392   }
   1393 
   1394   // If index is constant, just fold it into the data offset.
   1395   if (constant_index) {
   1396     data_offset += mir_graph_->ConstantValue(rl_index) << scale;
   1397   }
   1398 
   1399   rl_array = LoadValue(rl_array, kRefReg);
   1400   if (!constant_index) {
   1401     rl_index = LoadValue(rl_index, kCoreReg);
   1402   }
   1403 
   1404   RegStorage reg_ptr;
   1405   bool allocated_reg_ptr_temp = false;
   1406   if (constant_index) {
   1407     reg_ptr = rl_array.reg;
   1408   } else if (IsTemp(rl_array.reg) && !card_mark) {
   1409     Clobber(rl_array.reg);
   1410     reg_ptr = rl_array.reg;
   1411   } else {
   1412     allocated_reg_ptr_temp = true;
   1413     reg_ptr = AllocTempRef();
   1414   }
   1415 
   1416   /* null object? */
   1417   GenNullCheck(rl_array.reg, opt_flags);
   1418 
   1419   bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
   1420   RegStorage reg_len;
   1421   if (needs_range_check) {
   1422     reg_len = AllocTemp();
   1423     // NOTE: max live temps(4) here.
   1424     /* Get len */
   1425     Load32Disp(rl_array.reg, len_offset, reg_len);
   1426     MarkPossibleNullPointerException(opt_flags);
   1427   } else {
   1428     ForceImplicitNullCheck(rl_array.reg, opt_flags);
   1429   }
   1430   /* at this point, reg_ptr points to array, 2 live temps */
   1431   if (rl_src.wide || rl_src.fp || constant_index) {
   1432     if (rl_src.wide) {
   1433       rl_src = LoadValueWide(rl_src, reg_class);
   1434     } else {
   1435       rl_src = LoadValue(rl_src, reg_class);
   1436     }
   1437     if (!constant_index) {
   1438       OpRegRegRegShift(kOpAdd, reg_ptr, rl_array.reg, rl_index.reg, EncodeShift(kArmLsl, scale));
   1439     }
   1440     if (needs_range_check) {
   1441       if (constant_index) {
   1442         GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
   1443       } else {
   1444         GenArrayBoundsCheck(rl_index.reg, reg_len);
   1445       }
   1446       FreeTemp(reg_len);
   1447     }
   1448 
   1449     StoreBaseDisp(reg_ptr, data_offset, rl_src.reg, size, kNotVolatile);
   1450     MarkPossibleNullPointerException(opt_flags);
   1451   } else {
   1452     /* reg_ptr -> array data */
   1453     OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
   1454     rl_src = LoadValue(rl_src, reg_class);
   1455     if (needs_range_check) {
   1456       GenArrayBoundsCheck(rl_index.reg, reg_len);
   1457       FreeTemp(reg_len);
   1458     }
   1459     StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
   1460     MarkPossibleNullPointerException(opt_flags);
   1461   }
   1462   if (allocated_reg_ptr_temp) {
   1463     FreeTemp(reg_ptr);
   1464   }
   1465   if (card_mark) {
   1466     MarkGCCard(rl_src.reg, rl_array.reg);
   1467   }
   1468 }
   1469 
   1470 
   1471 void ArmMir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
   1472                                    RegLocation rl_dest, RegLocation rl_src, RegLocation rl_shift) {
   1473   rl_src = LoadValueWide(rl_src, kCoreReg);
   1474   // Per spec, we only care about low 6 bits of shift amount.
   1475   int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
   1476   if (shift_amount == 0) {
   1477     StoreValueWide(rl_dest, rl_src);
   1478     return;
   1479   }
   1480   if (BadOverlap(rl_src, rl_dest)) {
   1481     GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift);
   1482     return;
   1483   }
   1484   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   1485   switch (opcode) {
   1486     case Instruction::SHL_LONG:
   1487     case Instruction::SHL_LONG_2ADDR:
   1488       if (shift_amount == 1) {
   1489         OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src.reg.GetLow(), rl_src.reg.GetLow());
   1490         OpRegRegReg(kOpAdc, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), rl_src.reg.GetHigh());
   1491       } else if (shift_amount == 32) {
   1492         OpRegCopy(rl_result.reg.GetHigh(), rl_src.reg);
   1493         LoadConstant(rl_result.reg.GetLow(), 0);
   1494       } else if (shift_amount > 31) {
   1495         OpRegRegImm(kOpLsl, rl_result.reg.GetHigh(), rl_src.reg.GetLow(), shift_amount - 32);
   1496         LoadConstant(rl_result.reg.GetLow(), 0);
   1497       } else {
   1498         OpRegRegImm(kOpLsl, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), shift_amount);
   1499         OpRegRegRegShift(kOpOr, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), rl_src.reg.GetLow(),
   1500                          EncodeShift(kArmLsr, 32 - shift_amount));
   1501         OpRegRegImm(kOpLsl, rl_result.reg.GetLow(), rl_src.reg.GetLow(), shift_amount);
   1502       }
   1503       break;
   1504     case Instruction::SHR_LONG:
   1505     case Instruction::SHR_LONG_2ADDR:
   1506       if (shift_amount == 32) {
   1507         OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
   1508         OpRegRegImm(kOpAsr, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 31);
   1509       } else if (shift_amount > 31) {
   1510         OpRegRegImm(kOpAsr, rl_result.reg.GetLow(), rl_src.reg.GetHigh(), shift_amount - 32);
   1511         OpRegRegImm(kOpAsr, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 31);
   1512       } else {
   1513         RegStorage t_reg = AllocTemp();
   1514         OpRegRegImm(kOpLsr, t_reg, rl_src.reg.GetLow(), shift_amount);
   1515         OpRegRegRegShift(kOpOr, rl_result.reg.GetLow(), t_reg, rl_src.reg.GetHigh(),
   1516                          EncodeShift(kArmLsl, 32 - shift_amount));
   1517         FreeTemp(t_reg);
   1518         OpRegRegImm(kOpAsr, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), shift_amount);
   1519       }
   1520       break;
   1521     case Instruction::USHR_LONG:
   1522     case Instruction::USHR_LONG_2ADDR:
   1523       if (shift_amount == 32) {
   1524         OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetHigh());
   1525         LoadConstant(rl_result.reg.GetHigh(), 0);
   1526       } else if (shift_amount > 31) {
   1527         OpRegRegImm(kOpLsr, rl_result.reg.GetLow(), rl_src.reg.GetHigh(), shift_amount - 32);
   1528         LoadConstant(rl_result.reg.GetHigh(), 0);
   1529       } else {
   1530         RegStorage t_reg = AllocTemp();
   1531         OpRegRegImm(kOpLsr, t_reg, rl_src.reg.GetLow(), shift_amount);
   1532         OpRegRegRegShift(kOpOr, rl_result.reg.GetLow(), t_reg, rl_src.reg.GetHigh(),
   1533                          EncodeShift(kArmLsl, 32 - shift_amount));
   1534         FreeTemp(t_reg);
   1535         OpRegRegImm(kOpLsr, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), shift_amount);
   1536       }
   1537       break;
   1538     default:
   1539       LOG(FATAL) << "Unexpected case";
   1540   }
   1541   StoreValueWide(rl_dest, rl_result);
   1542 }
   1543 
   1544 void ArmMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
   1545                                    RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
   1546   if ((opcode == Instruction::SUB_LONG_2ADDR) || (opcode == Instruction::SUB_LONG)) {
   1547     if (!rl_src2.is_const) {
   1548       // Don't bother with special handling for subtract from immediate.
   1549       GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
   1550       return;
   1551     }
   1552   } else {
   1553     // Normalize
   1554     if (!rl_src2.is_const) {
   1555       DCHECK(rl_src1.is_const);
   1556       std::swap(rl_src1, rl_src2);
   1557     }
   1558   }
   1559   if (BadOverlap(rl_src1, rl_dest)) {
   1560     GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
   1561     return;
   1562   }
   1563   DCHECK(rl_src2.is_const);
   1564   int64_t val = mir_graph_->ConstantValueWide(rl_src2);
   1565   uint32_t val_lo = Low32Bits(val);
   1566   uint32_t val_hi = High32Bits(val);
   1567   int32_t mod_imm_lo = ModifiedImmediate(val_lo);
   1568   int32_t mod_imm_hi = ModifiedImmediate(val_hi);
   1569 
   1570   // Only a subset of add/sub immediate instructions set carry - so bail if we don't fit
   1571   switch (opcode) {
   1572     case Instruction::ADD_LONG:
   1573     case Instruction::ADD_LONG_2ADDR:
   1574     case Instruction::SUB_LONG:
   1575     case Instruction::SUB_LONG_2ADDR:
   1576       if ((mod_imm_lo < 0) || (mod_imm_hi < 0)) {
   1577         GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
   1578         return;
   1579       }
   1580       break;
   1581     default:
   1582       break;
   1583   }
   1584   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
   1585   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   1586   // NOTE: once we've done the EvalLoc on dest, we can no longer bail.
   1587   switch (opcode) {
   1588     case Instruction::ADD_LONG:
   1589     case Instruction::ADD_LONG_2ADDR:
   1590       NewLIR3(kThumb2AddRRI8M, rl_result.reg.GetLowReg(), rl_src1.reg.GetLowReg(), mod_imm_lo);
   1591       NewLIR3(kThumb2AdcRRI8M, rl_result.reg.GetHighReg(), rl_src1.reg.GetHighReg(), mod_imm_hi);
   1592       break;
   1593     case Instruction::OR_LONG:
   1594     case Instruction::OR_LONG_2ADDR:
   1595       if ((val_lo != 0) || (rl_result.reg.GetLowReg() != rl_src1.reg.GetLowReg())) {
   1596         OpRegRegImm(kOpOr, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), val_lo);
   1597       }
   1598       if ((val_hi != 0) || (rl_result.reg.GetHighReg() != rl_src1.reg.GetHighReg())) {
   1599         OpRegRegImm(kOpOr, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), val_hi);
   1600       }
   1601       break;
   1602     case Instruction::XOR_LONG:
   1603     case Instruction::XOR_LONG_2ADDR:
   1604       OpRegRegImm(kOpXor, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), val_lo);
   1605       OpRegRegImm(kOpXor, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), val_hi);
   1606       break;
   1607     case Instruction::AND_LONG:
   1608     case Instruction::AND_LONG_2ADDR:
   1609       if ((val_lo != 0xffffffff) || (rl_result.reg.GetLowReg() != rl_src1.reg.GetLowReg())) {
   1610         OpRegRegImm(kOpAnd, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), val_lo);
   1611       }
   1612       if ((val_hi != 0xffffffff) || (rl_result.reg.GetHighReg() != rl_src1.reg.GetHighReg())) {
   1613         OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), val_hi);
   1614       }
   1615       break;
   1616     case Instruction::SUB_LONG_2ADDR:
   1617     case Instruction::SUB_LONG:
   1618       NewLIR3(kThumb2SubRRI8M, rl_result.reg.GetLowReg(), rl_src1.reg.GetLowReg(), mod_imm_lo);
   1619       NewLIR3(kThumb2SbcRRI8M, rl_result.reg.GetHighReg(), rl_src1.reg.GetHighReg(), mod_imm_hi);
   1620       break;
   1621     default:
   1622       LOG(FATAL) << "Unexpected opcode " << opcode;
   1623   }
   1624   StoreValueWide(rl_dest, rl_result);
   1625 }
   1626 
   1627 }  // namespace art
   1628