Home | History | Annotate | Download | only in mips
      1 /*
      2  * Copyright (C) 2012 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 Mips ISA */
     18 
     19 #include "codegen_mips.h"
     20 
     21 #include "base/logging.h"
     22 #include "dex/mir_graph.h"
     23 #include "dex/quick/mir_to_lir-inl.h"
     24 #include "dex/reg_storage_eq.h"
     25 #include "entrypoints/quick/quick_entrypoints.h"
     26 #include "mips_lir.h"
     27 #include "mirror/array-inl.h"
     28 
     29 namespace art {
     30 
     31 /*
     32  * Compare two 64-bit values
     33  *    x = y     return  0
     34  *    x < y     return -1
     35  *    x > y     return  1
     36  *
     37  * Mips32 implementation
     38  *    slt   t0,  x.hi, y.hi;        # (x.hi < y.hi) ? 1:0
     39  *    sgt   t1,  x.hi, y.hi;        # (y.hi > x.hi) ? 1:0
     40  *    subu  res, t0, t1             # res = -1:1:0 for [ < > = ]
     41  *    bnez  res, finish
     42  *    sltu  t0, x.lo, y.lo
     43  *    sgtu  r1, x.lo, y.lo
     44  *    subu  res, t0, t1
     45  * finish:
     46  *
     47  * Mips64 implementation
     48  *    slt   temp, x, y;             # (x < y) ? 1:0
     49  *    slt   res, y, x;              # (x > y) ? 1:0
     50  *    subu  res, res, temp;         # res = -1:1:0 for [ < > = ]
     51  *
     52  */
     53 void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
     54   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
     55   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
     56   if (cu_->target64) {
     57     RegStorage temp = AllocTempWide();
     58     RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
     59     NewLIR3(kMipsSlt, temp.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
     60     NewLIR3(kMipsSlt, rl_result.reg.GetReg(), rl_src2.reg.GetReg(), rl_src1.reg.GetReg());
     61     NewLIR3(kMipsSubu, rl_result.reg.GetReg(), rl_result.reg.GetReg(), temp.GetReg());
     62     FreeTemp(temp);
     63     StoreValue(rl_dest, rl_result);
     64   } else {
     65     RegStorage t0 = AllocTemp();
     66     RegStorage t1 = AllocTemp();
     67     RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
     68     NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
     69     NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
     70     NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
     71     LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, nullptr);
     72     NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
     73     NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
     74     NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
     75     FreeTemp(t0);
     76     FreeTemp(t1);
     77     LIR* target = NewLIR0(kPseudoTargetLabel);
     78     branch->target = target;
     79     StoreValue(rl_dest, rl_result);
     80   }
     81 }
     82 
     83 LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
     84   LIR* branch;
     85   MipsOpCode slt_op;
     86   MipsOpCode br_op;
     87   bool cmp_zero = false;
     88   bool swapped = false;
     89   switch (cond) {
     90     case kCondEq:
     91       br_op = kMipsBeq;
     92       cmp_zero = true;
     93       break;
     94     case kCondNe:
     95       br_op = kMipsBne;
     96       cmp_zero = true;
     97       break;
     98     case kCondUlt:
     99       slt_op = kMipsSltu;
    100       br_op = kMipsBnez;
    101       break;
    102     case kCondUge:
    103       slt_op = kMipsSltu;
    104       br_op = kMipsBeqz;
    105       break;
    106     case kCondGe:
    107       slt_op = kMipsSlt;
    108       br_op = kMipsBeqz;
    109       break;
    110     case kCondGt:
    111       slt_op = kMipsSlt;
    112       br_op = kMipsBnez;
    113       swapped = true;
    114       break;
    115     case kCondLe:
    116       slt_op = kMipsSlt;
    117       br_op = kMipsBeqz;
    118       swapped = true;
    119       break;
    120     case kCondLt:
    121       slt_op = kMipsSlt;
    122       br_op = kMipsBnez;
    123       break;
    124     case kCondHi:  // Gtu
    125       slt_op = kMipsSltu;
    126       br_op = kMipsBnez;
    127       swapped = true;
    128       break;
    129     default:
    130       LOG(FATAL) << "No support for ConditionCode: " << cond;
    131       return nullptr;
    132   }
    133   if (cmp_zero) {
    134     branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
    135   } else {
    136     RegStorage t_reg = AllocTemp();
    137     if (swapped) {
    138       NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
    139     } else {
    140       NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
    141     }
    142     branch = NewLIR1(br_op, t_reg.GetReg());
    143     FreeTemp(t_reg);
    144   }
    145   branch->target = target;
    146   return branch;
    147 }
    148 
    149 LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
    150   LIR* branch;
    151   if (check_value != 0) {
    152     // TUNING: handle s16 & kCondLt/Mi case using slti.
    153     RegStorage t_reg = AllocTemp();
    154     LoadConstant(t_reg, check_value);
    155     branch = OpCmpBranch(cond, reg, t_reg, target);
    156     FreeTemp(t_reg);
    157     return branch;
    158   }
    159   MipsOpCode opc;
    160   switch (cond) {
    161     case kCondEq: opc = kMipsBeqz; break;
    162     case kCondGe: opc = kMipsBgez; break;
    163     case kCondGt: opc = kMipsBgtz; break;
    164     case kCondLe: opc = kMipsBlez; break;
    165     // case KCondMi:
    166     case kCondLt: opc = kMipsBltz; break;
    167     case kCondNe: opc = kMipsBnez; break;
    168     default:
    169       // Tuning: use slti when applicable
    170       RegStorage t_reg = AllocTemp();
    171       LoadConstant(t_reg, check_value);
    172       branch = OpCmpBranch(cond, reg, t_reg, target);
    173       FreeTemp(t_reg);
    174       return branch;
    175   }
    176   branch = NewLIR1(opc, reg.GetReg());
    177   branch->target = target;
    178   return branch;
    179 }
    180 
    181 LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
    182   LIR* res;
    183   MipsOpCode opcode;
    184 
    185   if (!cu_->target64) {
    186     // If src or dest is a pair, we'll be using low reg.
    187     if (r_dest.IsPair()) {
    188       r_dest = r_dest.GetLow();
    189     }
    190     if (r_src.IsPair()) {
    191       r_src = r_src.GetLow();
    192     }
    193   } else {
    194     DCHECK(!r_dest.IsPair() && !r_src.IsPair());
    195   }
    196 
    197   if (r_dest.IsFloat() || r_src.IsFloat())
    198     return OpFpRegCopy(r_dest, r_src);
    199   if (cu_->target64) {
    200     // TODO: Check that r_src and r_dest are both 32 or both 64 bits length on Mips64.
    201     if (r_dest.Is64Bit() || r_src.Is64Bit()) {
    202       opcode = kMipsMove;
    203     } else {
    204       opcode = kMipsSll;
    205     }
    206   } else {
    207     opcode = kMipsMove;
    208   }
    209   res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
    210   if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
    211     res->flags.is_nop = true;
    212   }
    213   return res;
    214 }
    215 
    216 void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
    217   if (r_dest != r_src) {
    218     LIR *res = OpRegCopyNoInsert(r_dest, r_src);
    219     AppendLIR(res);
    220   }
    221 }
    222 
    223 void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
    224   if (cu_->target64) {
    225     OpRegCopy(r_dest, r_src);
    226     return;
    227   }
    228   if (r_dest != r_src) {
    229     bool dest_fp = r_dest.IsFloat();
    230     bool src_fp = r_src.IsFloat();
    231     if (dest_fp) {
    232       if (src_fp) {
    233         // Here if both src and dest are fp registers. OpRegCopy will choose the right copy
    234         // (solo or pair).
    235         OpRegCopy(r_dest, r_src);
    236       } else {
    237         // note the operands are swapped for the mtc1 and mthc1 instr.
    238         // Here if dest is fp reg and src is core reg.
    239         if (fpuIs32Bit_) {
    240           NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
    241           NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
    242         } else {
    243           r_dest = Fp64ToSolo32(r_dest);
    244           NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetReg());
    245           NewLIR2(kMipsMthc1, r_src.GetHighReg(), r_dest.GetReg());
    246         }
    247       }
    248     } else {
    249       if (src_fp) {
    250         // Here if dest is core reg and src is fp reg.
    251         if (fpuIs32Bit_) {
    252           NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
    253           NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
    254         } else {
    255           r_src = Fp64ToSolo32(r_src);
    256           NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetReg());
    257           NewLIR2(kMipsMfhc1, r_dest.GetHighReg(), r_src.GetReg());
    258         }
    259       } else {
    260         // Here if both src and dest are core registers.
    261         // Handle overlap
    262         if (r_src.GetHighReg() != r_dest.GetLowReg()) {
    263           OpRegCopy(r_dest.GetLow(), r_src.GetLow());
    264           OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
    265         } else if (r_src.GetLowReg() != r_dest.GetHighReg()) {
    266           OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
    267           OpRegCopy(r_dest.GetLow(), r_src.GetLow());
    268         } else {
    269           RegStorage r_tmp = AllocTemp();
    270           OpRegCopy(r_tmp, r_src.GetHigh());
    271           OpRegCopy(r_dest.GetLow(), r_src.GetLow());
    272           OpRegCopy(r_dest.GetHigh(), r_tmp);
    273           FreeTemp(r_tmp);
    274         }
    275       }
    276     }
    277   }
    278 }
    279 
    280 void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
    281                                    int32_t true_val, int32_t false_val, RegStorage rs_dest,
    282                                    RegisterClass dest_reg_class) {
    283   UNUSED(dest_reg_class);
    284   // Implement as a branch-over.
    285   // TODO: Conditional move?
    286   LoadConstant(rs_dest, true_val);
    287   LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, nullptr);
    288   LoadConstant(rs_dest, false_val);
    289   LIR* target_label = NewLIR0(kPseudoTargetLabel);
    290   ne_branchover->target = target_label;
    291 }
    292 
    293 void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
    294   UNUSED(bb, mir);
    295   UNIMPLEMENTED(FATAL) << "Need codegen for select";
    296 }
    297 
    298 void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
    299   UNUSED(bb, mir);
    300   UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
    301 }
    302 
    303 RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
    304                                    bool is_div) {
    305   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    306 
    307   if (isaIsR6_) {
    308     NewLIR3(is_div ? kMipsR6Div : kMipsR6Mod, rl_result.reg.GetReg(), reg1.GetReg(), reg2.GetReg());
    309   } else {
    310     NewLIR2(kMipsR2Div, reg1.GetReg(), reg2.GetReg());
    311     NewLIR1(is_div ? kMipsR2Mflo : kMipsR2Mfhi, rl_result.reg.GetReg());
    312   }
    313   return rl_result;
    314 }
    315 
    316 RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, bool is_div) {
    317   RegStorage t_reg = AllocTemp();
    318   // lit is guarantee to be a 16-bit constant
    319   if (IsUint<16>(lit)) {
    320     NewLIR3(kMipsOri, t_reg.GetReg(), rZERO, lit);
    321   } else {
    322     // Addiu will sign extend the entire width (32 or 64) of the register.
    323     NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
    324   }
    325   RegLocation rl_result = GenDivRem(rl_dest, reg1, t_reg, is_div);
    326   FreeTemp(t_reg);
    327   return rl_result;
    328 }
    329 
    330 RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
    331                                    bool is_div, int flags) {
    332   UNUSED(rl_dest, rl_src1, rl_src2, is_div, flags);
    333   LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
    334   UNREACHABLE();
    335 }
    336 
    337 RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit,
    338                                       bool is_div) {
    339   UNUSED(rl_dest, rl_src1, lit, is_div);
    340   LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
    341   UNREACHABLE();
    342 }
    343 
    344 bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
    345   UNUSED(info, is_long, is_object);
    346   return false;
    347 }
    348 
    349 bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
    350   UNUSED(info);
    351   // TODO: add Mips implementation.
    352   return false;
    353 }
    354 
    355 bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
    356   UNUSED(info);
    357   // TODO: add Mips implementation.
    358   return false;
    359 }
    360 
    361 bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
    362   UNUSED(info);
    363   return false;
    364 }
    365 
    366 bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
    367   if (size != kSignedByte) {
    368     // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
    369     return false;
    370   }
    371   RegLocation rl_src_address = info->args[0];       // Long address.
    372   if (!cu_->target64) {
    373     rl_src_address = NarrowRegLoc(rl_src_address);  // Ignore high half in info->args[1].
    374   }
    375   RegLocation rl_dest = InlineTarget(info);
    376   RegLocation rl_address;
    377   if (cu_->target64) {
    378     rl_address = LoadValueWide(rl_src_address, kCoreReg);
    379   } else {
    380     rl_address = LoadValue(rl_src_address, kCoreReg);
    381   }
    382   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    383   DCHECK(size == kSignedByte);
    384   LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
    385   StoreValue(rl_dest, rl_result);
    386   return true;
    387 }
    388 
    389 bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
    390   if (size != kSignedByte) {
    391     // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
    392     return false;
    393   }
    394   RegLocation rl_src_address = info->args[0];       // Long address.
    395   if (!cu_->target64) {
    396     rl_src_address = NarrowRegLoc(rl_src_address);  // Ignore high half in info->args[1].
    397   }
    398   RegLocation rl_src_value = info->args[2];         // [size] value.
    399   RegLocation rl_address;
    400   if (cu_->target64) {
    401     rl_address = LoadValueWide(rl_src_address, kCoreReg);
    402   } else {
    403     rl_address = LoadValue(rl_src_address, kCoreReg);
    404   }
    405   DCHECK(size == kSignedByte);
    406   RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
    407   StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
    408   return true;
    409 }
    410 
    411 void MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
    412   UNUSED(reg, target);
    413   LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
    414   UNREACHABLE();
    415 }
    416 
    417 LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
    418   UNUSED(r_base, count);
    419   LOG(FATAL) << "Unexpected use of OpVldm for Mips";
    420   UNREACHABLE();
    421 }
    422 
    423 LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
    424   UNUSED(r_base, count);
    425   LOG(FATAL) << "Unexpected use of OpVstm for Mips";
    426   UNREACHABLE();
    427 }
    428 
    429 void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
    430                                                 int first_bit, int second_bit) {
    431   UNUSED(lit);
    432   RegStorage t_reg = AllocTemp();
    433   OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
    434   OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
    435   FreeTemp(t_reg);
    436   if (first_bit != 0) {
    437     OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
    438   }
    439 }
    440 
    441 void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
    442   if (cu_->target64) {
    443     GenDivZeroCheck(reg);
    444   } else {
    445     DCHECK(reg.IsPair());   // TODO: support k64BitSolo.
    446     RegStorage t_reg = AllocTemp();
    447     OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
    448     GenDivZeroCheck(t_reg);
    449     FreeTemp(t_reg);
    450   }
    451 }
    452 
    453 // Test suspend flag, return target of taken suspend branch.
    454 LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
    455   OpRegImm(kOpSub, TargetPtrReg(kSuspend), 1);
    456   return OpCmpImmBranch((target == nullptr) ? kCondEq : kCondNe, TargetPtrReg(kSuspend), 0, target);
    457 }
    458 
    459 // Decrement register and branch on condition.
    460 LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
    461   OpRegImm(kOpSub, reg, 1);
    462   return OpCmpImmBranch(c_code, reg, 0, target);
    463 }
    464 
    465 bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
    466                                      RegLocation rl_src, RegLocation rl_dest, int lit) {
    467   UNUSED(dalvik_opcode, is_div, rl_src, rl_dest, lit);
    468   LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
    469   UNREACHABLE();
    470 }
    471 
    472 bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
    473   UNUSED(rl_src, rl_dest, lit);
    474   LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
    475   UNREACHABLE();
    476 }
    477 
    478 LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
    479   UNUSED(cond, guide);
    480   LOG(FATAL) << "Unexpected use of OpIT in Mips";
    481   UNREACHABLE();
    482 }
    483 
    484 void MipsMir2Lir::OpEndIT(LIR* it) {
    485   UNUSED(it);
    486   LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
    487 }
    488 
    489 void MipsMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
    490   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    491   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
    492   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    493   /*
    494    *  [v1 v0] =  [a1 a0] + [a3 a2];
    495    *  addu v0,a2,a0
    496    *  addu t1,a3,a1
    497    *  sltu v1,v0,a2
    498    *  addu v1,v1,t1
    499    */
    500 
    501   OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
    502   RegStorage t_reg = AllocTemp();
    503   OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
    504   NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(),
    505           rl_src2.reg.GetLowReg());
    506   OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
    507   FreeTemp(t_reg);
    508   StoreValueWide(rl_dest, rl_result);
    509 }
    510 
    511 void MipsMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
    512   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    513   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
    514   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
    515   /*
    516    *  [v1 v0] =  [a1 a0] - [a3 a2];
    517    *  sltu  t1,a0,a2
    518    *  subu  v0,a0,a2
    519    *  subu  v1,a1,a3
    520    *  subu  v1,v1,t1
    521    */
    522 
    523   RegStorage t_reg = AllocTemp();
    524   NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
    525   OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
    526   OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
    527   OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
    528   FreeTemp(t_reg);
    529   StoreValueWide(rl_dest, rl_result);
    530 }
    531 
    532 void MipsMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
    533                                  RegLocation rl_src2, int flags) {
    534   if (cu_->target64) {
    535     switch (opcode) {
    536       case Instruction::NOT_LONG:
    537         GenNotLong(rl_dest, rl_src2);
    538         return;
    539       case Instruction::ADD_LONG:
    540       case Instruction::ADD_LONG_2ADDR:
    541         GenLongOp(kOpAdd, rl_dest, rl_src1, rl_src2);
    542         return;
    543       case Instruction::SUB_LONG:
    544       case Instruction::SUB_LONG_2ADDR:
    545         GenLongOp(kOpSub, rl_dest, rl_src1, rl_src2);
    546         return;
    547       case Instruction::MUL_LONG:
    548       case Instruction::MUL_LONG_2ADDR:
    549         GenMulLong(rl_dest, rl_src1, rl_src2);
    550         return;
    551       case Instruction::DIV_LONG:
    552       case Instruction::DIV_LONG_2ADDR:
    553         GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ true, flags);
    554         return;
    555       case Instruction::REM_LONG:
    556       case Instruction::REM_LONG_2ADDR:
    557         GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ false, flags);
    558         return;
    559       case Instruction::AND_LONG:
    560       case Instruction::AND_LONG_2ADDR:
    561         GenLongOp(kOpAnd, rl_dest, rl_src1, rl_src2);
    562         return;
    563       case Instruction::OR_LONG:
    564       case Instruction::OR_LONG_2ADDR:
    565         GenLongOp(kOpOr, rl_dest, rl_src1, rl_src2);
    566         return;
    567       case Instruction::XOR_LONG:
    568       case Instruction::XOR_LONG_2ADDR:
    569         GenLongOp(kOpXor, rl_dest, rl_src1, rl_src2);
    570         return;
    571       case Instruction::NEG_LONG:
    572         GenNegLong(rl_dest, rl_src2);
    573         return;
    574 
    575       default:
    576         LOG(FATAL) << "Invalid long arith op";
    577         return;
    578     }
    579   } else {
    580     switch (opcode) {
    581       case Instruction::ADD_LONG:
    582       case Instruction::ADD_LONG_2ADDR:
    583         GenAddLong(rl_dest, rl_src1, rl_src2);
    584         return;
    585       case Instruction::SUB_LONG:
    586       case Instruction::SUB_LONG_2ADDR:
    587         GenSubLong(rl_dest, rl_src1, rl_src2);
    588         return;
    589       case Instruction::NEG_LONG:
    590         GenNegLong(rl_dest, rl_src2);
    591         return;
    592       default:
    593         break;
    594     }
    595     // Fallback for all other ops.
    596     Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
    597   }
    598 }
    599 
    600 void MipsMir2Lir::GenLongOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
    601                             RegLocation rl_src2) {
    602   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    603   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
    604   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    605   OpRegRegReg(op, rl_result.reg, rl_src1.reg, rl_src2.reg);
    606   StoreValueWide(rl_dest, rl_result);
    607 }
    608 
    609 void MipsMir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
    610   rl_src = LoadValueWide(rl_src, kCoreReg);
    611   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    612   OpRegReg(kOpMvn, rl_result.reg, rl_src.reg);
    613   StoreValueWide(rl_dest, rl_result);
    614 }
    615 
    616 void MipsMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
    617   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    618   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
    619   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    620   NewLIR3(kMips64Dmul, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
    621   StoreValueWide(rl_dest, rl_result);
    622 }
    623 
    624 void MipsMir2Lir::GenDivRemLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
    625                                 RegLocation rl_src2, bool is_div, int flags) {
    626   UNUSED(opcode);
    627   // TODO: Implement easy div/rem?
    628   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    629   rl_src2 = LoadValueWide(rl_src2, kCoreReg);
    630   if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
    631     GenDivZeroCheckWide(rl_src2.reg);
    632   }
    633   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    634   NewLIR3(is_div ? kMips64Ddiv : kMips64Dmod, rl_result.reg.GetReg(), rl_src1.reg.GetReg(),
    635           rl_src2.reg.GetReg());
    636   StoreValueWide(rl_dest, rl_result);
    637 }
    638 
    639 void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
    640   rl_src = LoadValueWide(rl_src, kCoreReg);
    641   RegLocation rl_result;
    642 
    643   if (cu_->target64) {
    644     rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    645     OpRegReg(kOpNeg, rl_result.reg, rl_src.reg);
    646     StoreValueWide(rl_dest, rl_result);
    647   } else {
    648     rl_result = EvalLoc(rl_dest, kCoreReg, true);
    649     //  [v1 v0] =  -[a1 a0]
    650     //  negu  v0,a0
    651     //  negu  v1,a1
    652     //  sltu  t1,r_zero
    653     //  subu  v1,v1,t1
    654     OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
    655     OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
    656     RegStorage t_reg = AllocTemp();
    657     NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
    658     OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
    659     FreeTemp(t_reg);
    660     StoreValueWide(rl_dest, rl_result);
    661   }
    662 }
    663 
    664 /*
    665  * Generate array load
    666  */
    667 void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
    668                               RegLocation rl_index, RegLocation rl_dest, int scale) {
    669   RegisterClass reg_class = RegClassBySize(size);
    670   int len_offset = mirror::Array::LengthOffset().Int32Value();
    671   int data_offset;
    672   RegLocation rl_result;
    673   rl_array = LoadValue(rl_array, kRefReg);
    674   rl_index = LoadValue(rl_index, kCoreReg);
    675 
    676   // FIXME: need to add support for rl_index.is_const.
    677 
    678   if (size == k64 || size == kDouble) {
    679     data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
    680   } else {
    681     data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
    682   }
    683 
    684   // Null object?
    685   GenNullCheck(rl_array.reg, opt_flags);
    686 
    687   RegStorage reg_ptr = (cu_->target64) ? AllocTempRef() : AllocTemp();
    688   bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
    689   RegStorage reg_len;
    690   if (needs_range_check) {
    691     reg_len = AllocTemp();
    692     // Get len.
    693     Load32Disp(rl_array.reg, len_offset, reg_len);
    694     MarkPossibleNullPointerException(opt_flags);
    695   } else {
    696     ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
    697   }
    698   // reg_ptr -> array data.
    699   OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
    700   FreeTemp(rl_array.reg);
    701   if ((size == k64) || (size == kDouble)) {
    702     if (scale) {
    703       RegStorage r_new_index = AllocTemp();
    704       OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
    705       OpRegReg(kOpAdd, reg_ptr, r_new_index);
    706       FreeTemp(r_new_index);
    707     } else {
    708       OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
    709     }
    710     FreeTemp(rl_index.reg);
    711     rl_result = EvalLoc(rl_dest, reg_class, true);
    712 
    713     if (needs_range_check) {
    714       GenArrayBoundsCheck(rl_index.reg, reg_len);
    715       FreeTemp(reg_len);
    716     }
    717     LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
    718 
    719     FreeTemp(reg_ptr);
    720     StoreValueWide(rl_dest, rl_result);
    721   } else {
    722     rl_result = EvalLoc(rl_dest, reg_class, true);
    723 
    724     if (needs_range_check) {
    725       GenArrayBoundsCheck(rl_index.reg, reg_len);
    726       FreeTemp(reg_len);
    727     }
    728 
    729     if (cu_->target64) {
    730       if (rl_result.ref) {
    731         LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), As32BitReg(rl_result.reg), scale,
    732                         kReference);
    733       } else {
    734         LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale, size);
    735       }
    736     } else {
    737       LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
    738     }
    739 
    740     FreeTemp(reg_ptr);
    741     StoreValue(rl_dest, rl_result);
    742   }
    743 }
    744 
    745 /*
    746  * Generate array store
    747  *
    748  */
    749 void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
    750                               RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
    751   RegisterClass reg_class = RegClassBySize(size);
    752   int len_offset = mirror::Array::LengthOffset().Int32Value();
    753   int data_offset;
    754 
    755   if (size == k64 || size == kDouble) {
    756     data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
    757   } else {
    758     data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
    759   }
    760 
    761   rl_array = LoadValue(rl_array, kRefReg);
    762   rl_index = LoadValue(rl_index, kCoreReg);
    763 
    764   // FIXME: need to add support for rl_index.is_const.
    765 
    766   RegStorage reg_ptr;
    767   bool allocated_reg_ptr_temp = false;
    768   if (IsTemp(rl_array.reg) && !card_mark) {
    769     Clobber(rl_array.reg);
    770     reg_ptr = rl_array.reg;
    771   } else {
    772     reg_ptr = AllocTemp();
    773     OpRegCopy(reg_ptr, rl_array.reg);
    774     allocated_reg_ptr_temp = true;
    775   }
    776 
    777   // Null object?
    778   GenNullCheck(rl_array.reg, opt_flags);
    779 
    780   bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
    781   RegStorage reg_len;
    782   if (needs_range_check) {
    783     reg_len = AllocTemp();
    784     // NOTE: max live temps(4) here.
    785     // Get len.
    786     Load32Disp(rl_array.reg, len_offset, reg_len);
    787     MarkPossibleNullPointerException(opt_flags);
    788   } else {
    789     ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
    790   }
    791   // reg_ptr -> array data.
    792   OpRegImm(kOpAdd, reg_ptr, data_offset);
    793   // At this point, reg_ptr points to array, 2 live temps.
    794   if ((size == k64) || (size == kDouble)) {
    795     // TUNING: specific wide routine that can handle fp regs.
    796     if (scale) {
    797       RegStorage r_new_index = AllocTemp();
    798       OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
    799       OpRegReg(kOpAdd, reg_ptr, r_new_index);
    800       FreeTemp(r_new_index);
    801     } else {
    802       OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
    803     }
    804     rl_src = LoadValueWide(rl_src, reg_class);
    805 
    806     if (needs_range_check) {
    807       GenArrayBoundsCheck(rl_index.reg, reg_len);
    808       FreeTemp(reg_len);
    809     }
    810 
    811     StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
    812   } else {
    813     rl_src = LoadValue(rl_src, reg_class);
    814     if (needs_range_check) {
    815       GenArrayBoundsCheck(rl_index.reg, reg_len);
    816       FreeTemp(reg_len);
    817     }
    818     StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
    819   }
    820   if (allocated_reg_ptr_temp) {
    821     FreeTemp(reg_ptr);
    822   }
    823   if (card_mark) {
    824     MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
    825   }
    826 }
    827 
    828 void MipsMir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
    829                                  RegLocation rl_shift) {
    830   if (!cu_->target64) {
    831     Mir2Lir::GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
    832     return;
    833   }
    834   OpKind op = kOpBkpt;
    835   switch (opcode) {
    836     case Instruction::SHL_LONG:
    837     case Instruction::SHL_LONG_2ADDR:
    838       op = kOpLsl;
    839       break;
    840     case Instruction::SHR_LONG:
    841     case Instruction::SHR_LONG_2ADDR:
    842       op = kOpAsr;
    843       break;
    844     case Instruction::USHR_LONG:
    845     case Instruction::USHR_LONG_2ADDR:
    846       op = kOpLsr;
    847       break;
    848     default:
    849       LOG(FATAL) << "Unexpected case: " << opcode;
    850   }
    851   rl_shift = LoadValue(rl_shift, kCoreReg);
    852   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    853   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    854   OpRegRegReg(op, rl_result.reg, rl_src1.reg, As64BitReg(rl_shift.reg));
    855   StoreValueWide(rl_dest, rl_result);
    856 }
    857 
    858 void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
    859                                     RegLocation rl_src1, RegLocation rl_shift, int flags) {
    860   UNUSED(flags);
    861   if (!cu_->target64) {
    862     // Default implementation is just to ignore the constant case.
    863     GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
    864     return;
    865   }
    866   OpKind op = kOpBkpt;
    867   // Per spec, we only care about low 6 bits of shift amount.
    868   int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
    869   rl_src1 = LoadValueWide(rl_src1, kCoreReg);
    870   if (shift_amount == 0) {
    871     StoreValueWide(rl_dest, rl_src1);
    872     return;
    873   }
    874 
    875   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    876   switch (opcode) {
    877     case Instruction::SHL_LONG:
    878     case Instruction::SHL_LONG_2ADDR:
    879       op = kOpLsl;
    880       break;
    881     case Instruction::SHR_LONG:
    882     case Instruction::SHR_LONG_2ADDR:
    883       op = kOpAsr;
    884       break;
    885     case Instruction::USHR_LONG:
    886     case Instruction::USHR_LONG_2ADDR:
    887       op = kOpLsr;
    888       break;
    889     default:
    890       LOG(FATAL) << "Unexpected case";
    891   }
    892   OpRegRegImm(op, rl_result.reg, rl_src1.reg, shift_amount);
    893   StoreValueWide(rl_dest, rl_result);
    894 }
    895 
    896 void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
    897                                     RegLocation rl_src1, RegLocation rl_src2, int flags) {
    898   // Default - bail to non-const handler.
    899   GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
    900 }
    901 
    902 void MipsMir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
    903   if (!cu_->target64) {
    904     Mir2Lir::GenIntToLong(rl_dest, rl_src);
    905     return;
    906   }
    907   rl_src = LoadValue(rl_src, kCoreReg);
    908   RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
    909   NewLIR3(kMipsSll, rl_result.reg.GetReg(), As64BitReg(rl_src.reg).GetReg(), 0);
    910   StoreValueWide(rl_dest, rl_result);
    911 }
    912 
    913 void MipsMir2Lir::GenConversionCall(QuickEntrypointEnum trampoline, RegLocation rl_dest,
    914                                     RegLocation rl_src, RegisterClass reg_class) {
    915   FlushAllRegs();   // Send everything to home location.
    916   CallRuntimeHelperRegLocation(trampoline, rl_src, false);
    917   if (rl_dest.wide) {
    918     RegLocation rl_result;
    919     rl_result = GetReturnWide(reg_class);
    920     StoreValueWide(rl_dest, rl_result);
    921   } else {
    922     RegLocation rl_result;
    923     rl_result = GetReturn(reg_class);
    924     StoreValue(rl_dest, rl_result);
    925   }
    926 }
    927 
    928 }  // namespace art
    929