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 "entrypoints/quick/quick_entrypoints.h"
     23 #include "mirror/array.h"
     24 
     25 namespace art {
     26 
     27 LIR* 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  */
     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 /*
     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  */
     86 void 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 
    120 void 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 
    179 void 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 
    247 void 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  */
    311 LIR* 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 
    337 LIR* 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 
    357 LIR* ArmMir2Lir::OpRegCopy(int r_dest, int r_src) {
    358   LIR* res = OpRegCopyNoInsert(r_dest, r_src);
    359   AppendLIR(res);
    360   return res;
    361 }
    362 
    363 void 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
    392 struct MagicTable {
    393   uint32_t magic;
    394   uint32_t shift;
    395   DividePattern pattern;
    396 };
    397 
    398 static 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)
    418 bool 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 
    462 LIR* 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 
    468 RegLocation 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 
    474 RegLocation 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 
    480 bool 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 
    497 void ArmMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
    498   LOG(FATAL) << "Unexpected use of OpLea for Arm";
    499 }
    500 
    501 void ArmMir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
    502   LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
    503 }
    504 
    505 bool 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 
    564 LIR* ArmMir2Lir::OpPcRelLoad(int reg, LIR* target) {
    565   return RawLIR(current_dalvik_offset_, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
    566 }
    567 
    568 LIR* ArmMir2Lir::OpVldm(int rBase, int count) {
    569   return NewLIR3(kThumb2Vldms, rBase, fr0, count);
    570 }
    571 
    572 LIR* ArmMir2Lir::OpVstm(int rBase, int count) {
    573   return NewLIR3(kThumb2Vstms, rBase, fr0, count);
    574 }
    575 
    576 void 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 
    586 void 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
    594 LIR* 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
    600 LIR* 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 
    606 void 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 
    625 void 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   */
    650 bool 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 
    656 void 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 
    729 void ArmMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1,
    730                             RegLocation rl_src2) {
    731   LOG(FATAL) << "Unexpected use of GenAddLong for Arm";
    732 }
    733 
    734 void ArmMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1,
    735                             RegLocation rl_src2) {
    736   LOG(FATAL) << "Unexpected use of GenSubLong for Arm";
    737 }
    738 
    739 void ArmMir2Lir::GenAndLong(RegLocation rl_dest, RegLocation rl_src1,
    740                             RegLocation rl_src2) {
    741   LOG(FATAL) << "Unexpected use of GenAndLong for Arm";
    742 }
    743 
    744 void ArmMir2Lir::GenOrLong(RegLocation rl_dest, RegLocation rl_src1,
    745                            RegLocation rl_src2) {
    746   LOG(FATAL) << "Unexpected use of GenOrLong for Arm";
    747 }
    748 
    749 void 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  */
    757 void 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  */
    847 void 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  */
    936 void 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 
    992 void 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 
   1065 void 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