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 #include "codegen_mips.h"
     18 #include "dex/quick/mir_to_lir-inl.h"
     19 #include "dex/reg_storage_eq.h"
     20 #include "mips_lir.h"
     21 
     22 namespace art {
     23 
     24 /* This file contains codegen for the MIPS32 ISA. */
     25 LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
     26   int opcode;
     27   /* must be both DOUBLE or both not DOUBLE */
     28   DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
     29   if (r_dest.IsDouble()) {
     30     opcode = kMipsFmovd;
     31   } else {
     32     if (r_dest.IsSingle()) {
     33       if (r_src.IsSingle()) {
     34         opcode = kMipsFmovs;
     35       } else {
     36         /* note the operands are swapped for the mtc1 instr */
     37         RegStorage t_opnd = r_src;
     38         r_src = r_dest;
     39         r_dest = t_opnd;
     40         opcode = kMipsMtc1;
     41       }
     42     } else {
     43       DCHECK(r_src.IsSingle());
     44       opcode = kMipsMfc1;
     45     }
     46   }
     47   LIR* res = RawLIR(current_dalvik_offset_, opcode, r_src.GetReg(), r_dest.GetReg());
     48   if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
     49     res->flags.is_nop = true;
     50   }
     51   return res;
     52 }
     53 
     54 bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) {
     55   return ((value == 0) || IsUint(16, value) || ((value < 0) && (value >= -32768)));
     56 }
     57 
     58 bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) {
     59   return false;  // TUNING
     60 }
     61 
     62 bool MipsMir2Lir::InexpensiveConstantLong(int64_t value) {
     63   return false;  // TUNING
     64 }
     65 
     66 bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value) {
     67   return false;  // TUNING
     68 }
     69 
     70 /*
     71  * Load a immediate using a shortcut if possible; otherwise
     72  * grab from the per-translation literal pool.  If target is
     73  * a high register, build constant into a low register and copy.
     74  *
     75  * No additional register clobbering operation performed. Use this version when
     76  * 1) r_dest is freshly returned from AllocTemp or
     77  * 2) The codegen is under fixed register usage
     78  */
     79 LIR* MipsMir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
     80   LIR *res;
     81 
     82   RegStorage r_dest_save = r_dest;
     83   int is_fp_reg = r_dest.IsFloat();
     84   if (is_fp_reg) {
     85     DCHECK(r_dest.IsSingle());
     86     r_dest = AllocTemp();
     87   }
     88 
     89   /* See if the value can be constructed cheaply */
     90   if (value == 0) {
     91     res = NewLIR2(kMipsMove, r_dest.GetReg(), rZERO);
     92   } else if ((value > 0) && (value <= 65535)) {
     93     res = NewLIR3(kMipsOri, r_dest.GetReg(), rZERO, value);
     94   } else if ((value < 0) && (value >= -32768)) {
     95     res = NewLIR3(kMipsAddiu, r_dest.GetReg(), rZERO, value);
     96   } else {
     97     res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
     98     if (value & 0xffff)
     99       NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
    100   }
    101 
    102   if (is_fp_reg) {
    103     NewLIR2(kMipsMtc1, r_dest.GetReg(), r_dest_save.GetReg());
    104     FreeTemp(r_dest);
    105   }
    106 
    107   return res;
    108 }
    109 
    110 LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) {
    111   LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/);
    112   res->target = target;
    113   return res;
    114 }
    115 
    116 LIR* MipsMir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
    117   MipsOpCode opcode = kMipsNop;
    118   switch (op) {
    119     case kOpBlx:
    120       opcode = kMipsJalr;
    121       break;
    122     case kOpBx:
    123       return NewLIR1(kMipsJr, r_dest_src.GetReg());
    124       break;
    125     default:
    126       LOG(FATAL) << "Bad case in OpReg";
    127   }
    128   return NewLIR2(opcode, rRA, r_dest_src.GetReg());
    129 }
    130 
    131 LIR* MipsMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
    132   LIR *res;
    133   bool neg = (value < 0);
    134   int abs_value = (neg) ? -value : value;
    135   bool short_form = (abs_value & 0xff) == abs_value;
    136   MipsOpCode opcode = kMipsNop;
    137   switch (op) {
    138     case kOpAdd:
    139       return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
    140       break;
    141     case kOpSub:
    142       return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
    143       break;
    144     default:
    145       LOG(FATAL) << "Bad case in OpRegImm";
    146       break;
    147   }
    148   if (short_form) {
    149     res = NewLIR2(opcode, r_dest_src1.GetReg(), abs_value);
    150   } else {
    151     RegStorage r_scratch = AllocTemp();
    152     res = LoadConstant(r_scratch, value);
    153     if (op == kOpCmp)
    154       NewLIR2(opcode, r_dest_src1.GetReg(), r_scratch.GetReg());
    155     else
    156       NewLIR3(opcode, r_dest_src1.GetReg(), r_dest_src1.GetReg(), r_scratch.GetReg());
    157   }
    158   return res;
    159 }
    160 
    161 LIR* MipsMir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
    162   MipsOpCode opcode = kMipsNop;
    163   switch (op) {
    164     case kOpAdd:
    165       opcode = kMipsAddu;
    166       break;
    167     case kOpSub:
    168       opcode = kMipsSubu;
    169       break;
    170     case kOpAnd:
    171       opcode = kMipsAnd;
    172       break;
    173     case kOpMul:
    174       opcode = kMipsMul;
    175       break;
    176     case kOpOr:
    177       opcode = kMipsOr;
    178       break;
    179     case kOpXor:
    180       opcode = kMipsXor;
    181       break;
    182     case kOpLsl:
    183       opcode = kMipsSllv;
    184       break;
    185     case kOpLsr:
    186       opcode = kMipsSrlv;
    187       break;
    188     case kOpAsr:
    189       opcode = kMipsSrav;
    190       break;
    191     case kOpAdc:
    192     case kOpSbc:
    193       LOG(FATAL) << "No carry bit on MIPS";
    194       break;
    195     default:
    196       LOG(FATAL) << "bad case in OpRegRegReg";
    197       break;
    198   }
    199   return NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
    200 }
    201 
    202 LIR* MipsMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
    203   LIR *res;
    204   MipsOpCode opcode = kMipsNop;
    205   bool short_form = true;
    206 
    207   switch (op) {
    208     case kOpAdd:
    209       if (IS_SIMM16(value)) {
    210         opcode = kMipsAddiu;
    211       } else {
    212         short_form = false;
    213         opcode = kMipsAddu;
    214       }
    215       break;
    216     case kOpSub:
    217       if (IS_SIMM16((-value))) {
    218         value = -value;
    219         opcode = kMipsAddiu;
    220       } else {
    221         short_form = false;
    222         opcode = kMipsSubu;
    223       }
    224       break;
    225     case kOpLsl:
    226         DCHECK(value >= 0 && value <= 31);
    227         opcode = kMipsSll;
    228         break;
    229     case kOpLsr:
    230         DCHECK(value >= 0 && value <= 31);
    231         opcode = kMipsSrl;
    232         break;
    233     case kOpAsr:
    234         DCHECK(value >= 0 && value <= 31);
    235         opcode = kMipsSra;
    236         break;
    237     case kOpAnd:
    238       if (IS_UIMM16((value))) {
    239         opcode = kMipsAndi;
    240       } else {
    241         short_form = false;
    242         opcode = kMipsAnd;
    243       }
    244       break;
    245     case kOpOr:
    246       if (IS_UIMM16((value))) {
    247         opcode = kMipsOri;
    248       } else {
    249         short_form = false;
    250         opcode = kMipsOr;
    251       }
    252       break;
    253     case kOpXor:
    254       if (IS_UIMM16((value))) {
    255         opcode = kMipsXori;
    256       } else {
    257         short_form = false;
    258         opcode = kMipsXor;
    259       }
    260       break;
    261     case kOpMul:
    262       short_form = false;
    263       opcode = kMipsMul;
    264       break;
    265     default:
    266       LOG(FATAL) << "Bad case in OpRegRegImm";
    267       break;
    268   }
    269 
    270   if (short_form) {
    271     res = NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), value);
    272   } else {
    273     if (r_dest != r_src1) {
    274       res = LoadConstant(r_dest, value);
    275       NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_dest.GetReg());
    276     } else {
    277       RegStorage r_scratch = AllocTemp();
    278       res = LoadConstant(r_scratch, value);
    279       NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
    280     }
    281   }
    282   return res;
    283 }
    284 
    285 LIR* MipsMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
    286   MipsOpCode opcode = kMipsNop;
    287   LIR *res;
    288   switch (op) {
    289     case kOpMov:
    290       opcode = kMipsMove;
    291       break;
    292     case kOpMvn:
    293       return NewLIR3(kMipsNor, r_dest_src1.GetReg(), r_src2.GetReg(), rZERO);
    294     case kOpNeg:
    295       return NewLIR3(kMipsSubu, r_dest_src1.GetReg(), rZERO, r_src2.GetReg());
    296     case kOpAdd:
    297     case kOpAnd:
    298     case kOpMul:
    299     case kOpOr:
    300     case kOpSub:
    301     case kOpXor:
    302       return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
    303     case kOp2Byte:
    304 #if __mips_isa_rev >= 2
    305       res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
    306 #else
    307       res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
    308       OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
    309 #endif
    310       return res;
    311     case kOp2Short:
    312 #if __mips_isa_rev >= 2
    313       res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
    314 #else
    315       res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
    316       OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
    317 #endif
    318       return res;
    319     case kOp2Char:
    320        return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
    321     default:
    322       LOG(FATAL) << "Bad case in OpRegReg";
    323       break;
    324   }
    325   return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
    326 }
    327 
    328 LIR* MipsMir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
    329                               MoveType move_type) {
    330   UNIMPLEMENTED(FATAL);
    331   return nullptr;
    332 }
    333 
    334 LIR* MipsMir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
    335   UNIMPLEMENTED(FATAL);
    336   return nullptr;
    337 }
    338 
    339 LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
    340   LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
    341   return NULL;
    342 }
    343 
    344 LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
    345   LIR *res;
    346   if (!r_dest.IsPair()) {
    347     // Form 64-bit pair
    348     r_dest = Solo64ToPair64(r_dest);
    349   }
    350   res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
    351   LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
    352   return res;
    353 }
    354 
    355 /* Load value from base + scaled index. */
    356 LIR* MipsMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
    357                                   int scale, OpSize size) {
    358   LIR *first = NULL;
    359   LIR *res;
    360   MipsOpCode opcode = kMipsNop;
    361   RegStorage t_reg = AllocTemp();
    362 
    363   if (r_dest.IsFloat()) {
    364     DCHECK(r_dest.IsSingle());
    365     DCHECK((size == k32) || (size == kSingle) || (size == kReference));
    366     size = kSingle;
    367   } else {
    368     if (size == kSingle)
    369       size = k32;
    370   }
    371 
    372   if (!scale) {
    373     first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
    374   } else {
    375     first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
    376     NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
    377   }
    378 
    379   switch (size) {
    380     case kSingle:
    381       opcode = kMipsFlwc1;
    382       break;
    383     case k32:
    384     case kReference:
    385       opcode = kMipsLw;
    386       break;
    387     case kUnsignedHalf:
    388       opcode = kMipsLhu;
    389       break;
    390     case kSignedHalf:
    391       opcode = kMipsLh;
    392       break;
    393     case kUnsignedByte:
    394       opcode = kMipsLbu;
    395       break;
    396     case kSignedByte:
    397       opcode = kMipsLb;
    398       break;
    399     default:
    400       LOG(FATAL) << "Bad case in LoadBaseIndexed";
    401   }
    402 
    403   res = NewLIR3(opcode, r_dest.GetReg(), 0, t_reg.GetReg());
    404   FreeTemp(t_reg);
    405   return (first) ? first : res;
    406 }
    407 
    408 /* store value base base + scaled index. */
    409 LIR* MipsMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
    410                                    int scale, OpSize size) {
    411   LIR *first = NULL;
    412   MipsOpCode opcode = kMipsNop;
    413   RegStorage t_reg = AllocTemp();
    414 
    415   if (r_src.IsFloat()) {
    416     DCHECK(r_src.IsSingle());
    417     DCHECK((size == k32) || (size == kSingle) || (size == kReference));
    418     size = kSingle;
    419   } else {
    420     if (size == kSingle)
    421       size = k32;
    422   }
    423 
    424   if (!scale) {
    425     first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
    426   } else {
    427     first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
    428     NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
    429   }
    430 
    431   switch (size) {
    432     case kSingle:
    433       opcode = kMipsFswc1;
    434       break;
    435     case k32:
    436     case kReference:
    437       opcode = kMipsSw;
    438       break;
    439     case kUnsignedHalf:
    440     case kSignedHalf:
    441       opcode = kMipsSh;
    442       break;
    443     case kUnsignedByte:
    444     case kSignedByte:
    445       opcode = kMipsSb;
    446       break;
    447     default:
    448       LOG(FATAL) << "Bad case in StoreBaseIndexed";
    449   }
    450   NewLIR3(opcode, r_src.GetReg(), 0, t_reg.GetReg());
    451   return first;
    452 }
    453 
    454 // FIXME: don't split r_dest into 2 containers.
    455 LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
    456                                    OpSize size) {
    457 /*
    458  * Load value from base + displacement.  Optionally perform null check
    459  * on base (which must have an associated s_reg and MIR).  If not
    460  * performing null check, incoming MIR can be null. IMPORTANT: this
    461  * code must not allocate any new temps.  If a new register is needed
    462  * and base and dest are the same, spill some other register to
    463  * rlp and then restore.
    464  */
    465   LIR *res;
    466   LIR *load = NULL;
    467   LIR *load2 = NULL;
    468   MipsOpCode opcode = kMipsNop;
    469   bool short_form = IS_SIMM16(displacement);
    470   bool pair = r_dest.IsPair();
    471 
    472   switch (size) {
    473     case k64:
    474     case kDouble:
    475       if (!pair) {
    476         // Form 64-bit pair
    477         r_dest = Solo64ToPair64(r_dest);
    478         pair = 1;
    479       }
    480       if (r_dest.IsFloat()) {
    481         DCHECK_EQ(r_dest.GetLowReg(), r_dest.GetHighReg() - 1);
    482         opcode = kMipsFlwc1;
    483       } else {
    484         opcode = kMipsLw;
    485       }
    486       short_form = IS_SIMM16_2WORD(displacement);
    487       DCHECK_EQ((displacement & 0x3), 0);
    488       break;
    489     case k32:
    490     case kSingle:
    491     case kReference:
    492       opcode = kMipsLw;
    493       if (r_dest.IsFloat()) {
    494         opcode = kMipsFlwc1;
    495         DCHECK(r_dest.IsSingle());
    496       }
    497       DCHECK_EQ((displacement & 0x3), 0);
    498       break;
    499     case kUnsignedHalf:
    500       opcode = kMipsLhu;
    501       DCHECK_EQ((displacement & 0x1), 0);
    502       break;
    503     case kSignedHalf:
    504       opcode = kMipsLh;
    505       DCHECK_EQ((displacement & 0x1), 0);
    506       break;
    507     case kUnsignedByte:
    508       opcode = kMipsLbu;
    509       break;
    510     case kSignedByte:
    511       opcode = kMipsLb;
    512       break;
    513     default:
    514       LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
    515   }
    516 
    517   if (short_form) {
    518     if (!pair) {
    519       load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
    520     } else {
    521       load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
    522       load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
    523     }
    524   } else {
    525     if (pair) {
    526       RegStorage r_tmp = AllocTemp();
    527       res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
    528       load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
    529       load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
    530       FreeTemp(r_tmp);
    531     } else {
    532       RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
    533       res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
    534       load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
    535       if (r_tmp != r_dest)
    536         FreeTemp(r_tmp);
    537     }
    538   }
    539 
    540   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
    541     DCHECK(r_base == rs_rMIPS_SP);
    542     AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
    543                             true /* is_load */, pair /* is64bit */);
    544     if (pair) {
    545       AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
    546                               true /* is_load */, pair /* is64bit */);
    547     }
    548   }
    549   return load;
    550 }
    551 
    552 LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
    553                                OpSize size, VolatileKind is_volatile) {
    554   if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))) {
    555     // Do atomic 64-bit load.
    556     return GenAtomic64Load(r_base, displacement, r_dest);
    557   }
    558 
    559   // TODO: base this on target.
    560   if (size == kWord) {
    561     size = k32;
    562   }
    563   LIR* load;
    564   load = LoadBaseDispBody(r_base, displacement, r_dest, size);
    565 
    566   if (UNLIKELY(is_volatile == kVolatile)) {
    567     GenMemBarrier(kLoadAny);
    568   }
    569 
    570   return load;
    571 }
    572 
    573 // FIXME: don't split r_dest into 2 containers.
    574 LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement,
    575                                     RegStorage r_src, OpSize size) {
    576   LIR *res;
    577   LIR *store = NULL;
    578   LIR *store2 = NULL;
    579   MipsOpCode opcode = kMipsNop;
    580   bool short_form = IS_SIMM16(displacement);
    581   bool pair = r_src.IsPair();
    582 
    583   switch (size) {
    584     case k64:
    585     case kDouble:
    586       if (!pair) {
    587         // Form 64-bit pair
    588         r_src = Solo64ToPair64(r_src);
    589         pair = 1;
    590       }
    591       if (r_src.IsFloat()) {
    592         DCHECK_EQ(r_src.GetLowReg(), r_src.GetHighReg() - 1);
    593         opcode = kMipsFswc1;
    594       } else {
    595         opcode = kMipsSw;
    596       }
    597       short_form = IS_SIMM16_2WORD(displacement);
    598       DCHECK_EQ((displacement & 0x3), 0);
    599       break;
    600     case k32:
    601     case kSingle:
    602     case kReference:
    603       opcode = kMipsSw;
    604       if (r_src.IsFloat()) {
    605         opcode = kMipsFswc1;
    606         DCHECK(r_src.IsSingle());
    607       }
    608       DCHECK_EQ((displacement & 0x3), 0);
    609       break;
    610     case kUnsignedHalf:
    611     case kSignedHalf:
    612       opcode = kMipsSh;
    613       DCHECK_EQ((displacement & 0x1), 0);
    614       break;
    615     case kUnsignedByte:
    616     case kSignedByte:
    617       opcode = kMipsSb;
    618       break;
    619     default:
    620       LOG(FATAL) << "Bad case in StoreBaseDispBody";
    621   }
    622 
    623   if (short_form) {
    624     if (!pair) {
    625       store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
    626     } else {
    627       store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
    628       store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
    629     }
    630   } else {
    631     RegStorage r_scratch = AllocTemp();
    632     res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
    633     if (!pair) {
    634       store =  NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
    635     } else {
    636       store =  NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
    637       store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
    638     }
    639     FreeTemp(r_scratch);
    640   }
    641 
    642   if (mem_ref_type_ == ResourceMask::kDalvikReg) {
    643     DCHECK(r_base == rs_rMIPS_SP);
    644     AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
    645                             false /* is_load */, pair /* is64bit */);
    646     if (pair) {
    647       AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
    648                               false /* is_load */, pair /* is64bit */);
    649     }
    650   }
    651 
    652   return res;
    653 }
    654 
    655 LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
    656                                 OpSize size, VolatileKind is_volatile) {
    657   if (is_volatile == kVolatile) {
    658     // Ensure that prior accesses become visible to other threads first.
    659     GenMemBarrier(kAnyStore);
    660   }
    661 
    662   LIR* store;
    663   if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))) {
    664     // Do atomic 64-bit load.
    665     store = GenAtomic64Store(r_base, displacement, r_src);
    666   } else {
    667     // TODO: base this on target.
    668     if (size == kWord) {
    669       size = k32;
    670     }
    671     store = StoreBaseDispBody(r_base, displacement, r_src, size);
    672   }
    673 
    674   if (UNLIKELY(is_volatile == kVolatile)) {
    675     // Preserve order with respect to any subsequent volatile loads.
    676     // We need StoreLoad, but that generally requires the most expensive barrier.
    677     GenMemBarrier(kAnyAny);
    678   }
    679 
    680   return store;
    681 }
    682 
    683 LIR* MipsMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
    684   LOG(FATAL) << "Unexpected use of OpMem for MIPS";
    685   return NULL;
    686 }
    687 
    688 LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
    689   LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
    690   return NULL;
    691 }
    692 
    693 LIR* MipsMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
    694   return OpReg(op, r_tgt);
    695 }
    696 
    697 }  // namespace art
    698