Home | History | Annotate | Download | only in quick
      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 #include "dex/compiler_ir.h"
     18 #include "dex/compiler_internals.h"
     19 #include "dex/quick/mir_to_lir-inl.h"
     20 #include "invoke_type.h"
     21 
     22 namespace art {
     23 
     24 /* This file contains target-independent codegen and support. */
     25 
     26 /*
     27  * Load an immediate value into a fixed or temp register.  Target
     28  * register is clobbered, and marked in_use.
     29  */
     30 LIR* Mir2Lir::LoadConstant(RegStorage r_dest, int value) {
     31   if (IsTemp(r_dest)) {
     32     Clobber(r_dest);
     33     MarkInUse(r_dest);
     34   }
     35   return LoadConstantNoClobber(r_dest, value);
     36 }
     37 
     38 /*
     39  * Temporary workaround for Issue 7250540.  If we're loading a constant zero into a
     40  * promoted floating point register, also copy a zero into the int/ref identity of
     41  * that sreg.
     42  */
     43 void Mir2Lir::Workaround7250540(RegLocation rl_dest, RegStorage zero_reg) {
     44   if (rl_dest.fp) {
     45     int pmap_index = SRegToPMap(rl_dest.s_reg_low);
     46     if (promotion_map_[pmap_index].fp_location == kLocPhysReg) {
     47       // Now, determine if this vreg is ever used as a reference.  If not, we're done.
     48       bool used_as_reference = false;
     49       int base_vreg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
     50       for (int i = 0; !used_as_reference && (i < mir_graph_->GetNumSSARegs()); i++) {
     51         if (mir_graph_->SRegToVReg(mir_graph_->reg_location_[i].s_reg_low) == base_vreg) {
     52           used_as_reference |= mir_graph_->reg_location_[i].ref;
     53         }
     54       }
     55       if (!used_as_reference) {
     56         return;
     57       }
     58       RegStorage temp_reg = zero_reg;
     59       if (!temp_reg.Valid()) {
     60         temp_reg = AllocTemp();
     61         LoadConstant(temp_reg, 0);
     62       }
     63       if (promotion_map_[pmap_index].core_location == kLocPhysReg) {
     64         // Promoted - just copy in a zero
     65         OpRegCopy(RegStorage::Solo32(promotion_map_[pmap_index].core_reg), temp_reg);
     66       } else {
     67         // Lives in the frame, need to store.
     68         ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
     69         StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(rl_dest.s_reg_low), temp_reg, k32, kNotVolatile);
     70       }
     71       if (!zero_reg.Valid()) {
     72         FreeTemp(temp_reg);
     73       }
     74     }
     75   }
     76 }
     77 
     78 /*
     79  * Load a Dalvik register into a physical register.  Take care when
     80  * using this routine, as it doesn't perform any bookkeeping regarding
     81  * register liveness.  That is the responsibility of the caller.
     82  */
     83 void Mir2Lir::LoadValueDirect(RegLocation rl_src, RegStorage r_dest) {
     84   rl_src = UpdateLoc(rl_src);
     85   if (rl_src.location == kLocPhysReg) {
     86     OpRegCopy(r_dest, rl_src.reg);
     87   } else if (IsInexpensiveConstant(rl_src)) {
     88     // On 64-bit targets, will sign extend.  Make sure constant reference is always NULL.
     89     DCHECK(!rl_src.ref || (mir_graph_->ConstantValue(rl_src) == 0));
     90     LoadConstantNoClobber(r_dest, mir_graph_->ConstantValue(rl_src));
     91   } else {
     92     DCHECK((rl_src.location == kLocDalvikFrame) ||
     93            (rl_src.location == kLocCompilerTemp));
     94     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
     95     if (rl_src.ref) {
     96       LoadRefDisp(TargetPtrReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest, kNotVolatile);
     97     } else {
     98       Load32Disp(TargetPtrReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest);
     99     }
    100   }
    101 }
    102 
    103 /*
    104  * Similar to LoadValueDirect, but clobbers and allocates the target
    105  * register.  Should be used when loading to a fixed register (for example,
    106  * loading arguments to an out of line call.
    107  */
    108 void Mir2Lir::LoadValueDirectFixed(RegLocation rl_src, RegStorage r_dest) {
    109   Clobber(r_dest);
    110   MarkInUse(r_dest);
    111   LoadValueDirect(rl_src, r_dest);
    112 }
    113 
    114 /*
    115  * Load a Dalvik register pair into a physical register[s].  Take care when
    116  * using this routine, as it doesn't perform any bookkeeping regarding
    117  * register liveness.  That is the responsibility of the caller.
    118  */
    119 void Mir2Lir::LoadValueDirectWide(RegLocation rl_src, RegStorage r_dest) {
    120   rl_src = UpdateLocWide(rl_src);
    121   if (rl_src.location == kLocPhysReg) {
    122     OpRegCopyWide(r_dest, rl_src.reg);
    123   } else if (IsInexpensiveConstant(rl_src)) {
    124     LoadConstantWide(r_dest, mir_graph_->ConstantValueWide(rl_src));
    125   } else {
    126     DCHECK((rl_src.location == kLocDalvikFrame) ||
    127            (rl_src.location == kLocCompilerTemp));
    128     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
    129     LoadBaseDisp(TargetPtrReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest, k64, kNotVolatile);
    130   }
    131 }
    132 
    133 /*
    134  * Similar to LoadValueDirect, but clobbers and allocates the target
    135  * registers.  Should be used when loading to a fixed registers (for example,
    136  * loading arguments to an out of line call.
    137  */
    138 void Mir2Lir::LoadValueDirectWideFixed(RegLocation rl_src, RegStorage r_dest) {
    139   Clobber(r_dest);
    140   MarkInUse(r_dest);
    141   LoadValueDirectWide(rl_src, r_dest);
    142 }
    143 
    144 RegLocation Mir2Lir::LoadValue(RegLocation rl_src, RegisterClass op_kind) {
    145   DCHECK(!rl_src.ref || op_kind == kRefReg);
    146   rl_src = UpdateLoc(rl_src);
    147   if (rl_src.location == kLocPhysReg) {
    148     if (!RegClassMatches(op_kind, rl_src.reg)) {
    149       // Wrong register class, realloc, copy and transfer ownership.
    150       RegStorage new_reg = AllocTypedTemp(rl_src.fp, op_kind);
    151       OpRegCopy(new_reg, rl_src.reg);
    152       // Clobber the old reg.
    153       Clobber(rl_src.reg);
    154       // ...and mark the new one live.
    155       rl_src.reg = new_reg;
    156       MarkLive(rl_src);
    157     }
    158     return rl_src;
    159   }
    160 
    161   DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
    162   rl_src.reg = AllocTypedTemp(rl_src.fp, op_kind);
    163   LoadValueDirect(rl_src, rl_src.reg);
    164   rl_src.location = kLocPhysReg;
    165   MarkLive(rl_src);
    166   return rl_src;
    167 }
    168 
    169 RegLocation Mir2Lir::LoadValue(RegLocation rl_src) {
    170   return LoadValue(rl_src, LocToRegClass(rl_src));
    171 }
    172 
    173 void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src) {
    174   /*
    175    * Sanity checking - should never try to store to the same
    176    * ssa name during the compilation of a single instruction
    177    * without an intervening ClobberSReg().
    178    */
    179   if (kIsDebugBuild) {
    180     DCHECK((live_sreg_ == INVALID_SREG) ||
    181            (rl_dest.s_reg_low != live_sreg_));
    182     live_sreg_ = rl_dest.s_reg_low;
    183   }
    184   LIR* def_start;
    185   LIR* def_end;
    186   DCHECK(!rl_dest.wide);
    187   DCHECK(!rl_src.wide);
    188   rl_src = UpdateLoc(rl_src);
    189   rl_dest = UpdateLoc(rl_dest);
    190   if (rl_src.location == kLocPhysReg) {
    191     if (IsLive(rl_src.reg) ||
    192       IsPromoted(rl_src.reg) ||
    193       (rl_dest.location == kLocPhysReg)) {
    194       // Src is live/promoted or Dest has assigned reg.
    195       rl_dest = EvalLoc(rl_dest, rl_dest.ref || rl_src.ref ? kRefReg : kAnyReg, false);
    196       OpRegCopy(rl_dest.reg, rl_src.reg);
    197     } else {
    198       // Just re-assign the registers.  Dest gets Src's regs
    199       rl_dest.reg = rl_src.reg;
    200       Clobber(rl_src.reg);
    201     }
    202   } else {
    203     // Load Src either into promoted Dest or temps allocated for Dest
    204     rl_dest = EvalLoc(rl_dest, rl_dest.ref ? kRefReg : kAnyReg, false);
    205     LoadValueDirect(rl_src, rl_dest.reg);
    206   }
    207 
    208   // Dest is now live and dirty (until/if we flush it to home location)
    209   MarkLive(rl_dest);
    210   MarkDirty(rl_dest);
    211 
    212 
    213   ResetDefLoc(rl_dest);
    214   if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) {
    215     def_start = last_lir_insn_;
    216     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
    217     if (rl_dest.ref) {
    218       StoreRefDisp(TargetPtrReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, kNotVolatile);
    219     } else {
    220       Store32Disp(TargetPtrReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
    221     }
    222     MarkClean(rl_dest);
    223     def_end = last_lir_insn_;
    224     if (!rl_dest.ref) {
    225       // Exclude references from store elimination
    226       MarkDef(rl_dest, def_start, def_end);
    227     }
    228   }
    229 }
    230 
    231 RegLocation Mir2Lir::LoadValueWide(RegLocation rl_src, RegisterClass op_kind) {
    232   DCHECK(rl_src.wide);
    233   rl_src = UpdateLocWide(rl_src);
    234   if (rl_src.location == kLocPhysReg) {
    235     if (!RegClassMatches(op_kind, rl_src.reg)) {
    236       // Wrong register class, realloc, copy and transfer ownership.
    237       RegStorage new_regs = AllocTypedTempWide(rl_src.fp, op_kind);
    238       OpRegCopyWide(new_regs, rl_src.reg);
    239       // Clobber the old regs.
    240       Clobber(rl_src.reg);
    241       // ...and mark the new ones live.
    242       rl_src.reg = new_regs;
    243       MarkLive(rl_src);
    244     }
    245     return rl_src;
    246   }
    247 
    248   DCHECK_NE(rl_src.s_reg_low, INVALID_SREG);
    249   DCHECK_NE(GetSRegHi(rl_src.s_reg_low), INVALID_SREG);
    250   rl_src.reg = AllocTypedTempWide(rl_src.fp, op_kind);
    251   LoadValueDirectWide(rl_src, rl_src.reg);
    252   rl_src.location = kLocPhysReg;
    253   MarkLive(rl_src);
    254   return rl_src;
    255 }
    256 
    257 void Mir2Lir::StoreValueWide(RegLocation rl_dest, RegLocation rl_src) {
    258   /*
    259    * Sanity checking - should never try to store to the same
    260    * ssa name during the compilation of a single instruction
    261    * without an intervening ClobberSReg().
    262    */
    263   if (kIsDebugBuild) {
    264     DCHECK((live_sreg_ == INVALID_SREG) ||
    265            (rl_dest.s_reg_low != live_sreg_));
    266     live_sreg_ = rl_dest.s_reg_low;
    267   }
    268   LIR* def_start;
    269   LIR* def_end;
    270   DCHECK(rl_dest.wide);
    271   DCHECK(rl_src.wide);
    272   rl_src = UpdateLocWide(rl_src);
    273   rl_dest = UpdateLocWide(rl_dest);
    274   if (rl_src.location == kLocPhysReg) {
    275     if (IsLive(rl_src.reg) ||
    276         IsPromoted(rl_src.reg) ||
    277         (rl_dest.location == kLocPhysReg)) {
    278       /*
    279        * If src reg[s] are tied to the original Dalvik vreg via liveness or promotion, we
    280        * can't repurpose them.  Similarly, if the dest reg[s] are tied to Dalvik vregs via
    281        * promotion, we can't just re-assign.  In these cases, we have to copy.
    282        */
    283       rl_dest = EvalLoc(rl_dest, kAnyReg, false);
    284       OpRegCopyWide(rl_dest.reg, rl_src.reg);
    285     } else {
    286       // Just re-assign the registers.  Dest gets Src's regs
    287       rl_dest.reg = rl_src.reg;
    288       Clobber(rl_src.reg);
    289     }
    290   } else {
    291     // Load Src either into promoted Dest or temps allocated for Dest
    292     rl_dest = EvalLoc(rl_dest, kAnyReg, false);
    293     LoadValueDirectWide(rl_src, rl_dest.reg);
    294   }
    295 
    296   // Dest is now live and dirty (until/if we flush it to home location)
    297   MarkLive(rl_dest);
    298   MarkWide(rl_dest.reg);
    299   MarkDirty(rl_dest);
    300 
    301   ResetDefLocWide(rl_dest);
    302   if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) ||
    303       LiveOut(GetSRegHi(rl_dest.s_reg_low)))) {
    304     def_start = last_lir_insn_;
    305     DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
    306               mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
    307     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
    308     StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64, kNotVolatile);
    309     MarkClean(rl_dest);
    310     def_end = last_lir_insn_;
    311     MarkDefWide(rl_dest, def_start, def_end);
    312   }
    313 }
    314 
    315 void Mir2Lir::StoreFinalValue(RegLocation rl_dest, RegLocation rl_src) {
    316   DCHECK_EQ(rl_src.location, kLocPhysReg);
    317 
    318   if (rl_dest.location == kLocPhysReg) {
    319     OpRegCopy(rl_dest.reg, rl_src.reg);
    320   } else {
    321     // Just re-assign the register.  Dest gets Src's reg.
    322     rl_dest.location = kLocPhysReg;
    323     rl_dest.reg = rl_src.reg;
    324     Clobber(rl_src.reg);
    325   }
    326 
    327   // Dest is now live and dirty (until/if we flush it to home location)
    328   MarkLive(rl_dest);
    329   MarkDirty(rl_dest);
    330 
    331 
    332   ResetDefLoc(rl_dest);
    333   if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) {
    334     LIR *def_start = last_lir_insn_;
    335     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
    336     Store32Disp(TargetPtrReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg);
    337     MarkClean(rl_dest);
    338     LIR *def_end = last_lir_insn_;
    339     if (!rl_dest.ref) {
    340       // Exclude references from store elimination
    341       MarkDef(rl_dest, def_start, def_end);
    342     }
    343   }
    344 }
    345 
    346 void Mir2Lir::StoreFinalValueWide(RegLocation rl_dest, RegLocation rl_src) {
    347   DCHECK(rl_dest.wide);
    348   DCHECK(rl_src.wide);
    349   DCHECK_EQ(rl_src.location, kLocPhysReg);
    350 
    351   if (rl_dest.location == kLocPhysReg) {
    352     OpRegCopyWide(rl_dest.reg, rl_src.reg);
    353   } else {
    354     // Just re-assign the registers.  Dest gets Src's regs.
    355     rl_dest.location = kLocPhysReg;
    356     rl_dest.reg = rl_src.reg;
    357     Clobber(rl_src.reg);
    358   }
    359 
    360   // Dest is now live and dirty (until/if we flush it to home location).
    361   MarkLive(rl_dest);
    362   MarkWide(rl_dest.reg);
    363   MarkDirty(rl_dest);
    364 
    365   ResetDefLocWide(rl_dest);
    366   if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) ||
    367       LiveOut(GetSRegHi(rl_dest.s_reg_low)))) {
    368     LIR *def_start = last_lir_insn_;
    369     DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
    370               mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
    371     ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
    372     StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64, kNotVolatile);
    373     MarkClean(rl_dest);
    374     LIR *def_end = last_lir_insn_;
    375     MarkDefWide(rl_dest, def_start, def_end);
    376   }
    377 }
    378 
    379 /* Utilities to load the current Method* */
    380 void Mir2Lir::LoadCurrMethodDirect(RegStorage r_tgt) {
    381   LoadValueDirectFixed(mir_graph_->GetMethodLoc(), r_tgt);
    382 }
    383 
    384 RegLocation Mir2Lir::LoadCurrMethod() {
    385   return LoadValue(mir_graph_->GetMethodLoc(), kRefReg);
    386 }
    387 
    388 RegLocation Mir2Lir::ForceTemp(RegLocation loc) {
    389   DCHECK(!loc.wide);
    390   DCHECK(loc.location == kLocPhysReg);
    391   DCHECK(!loc.reg.IsFloat());
    392   if (IsTemp(loc.reg)) {
    393     Clobber(loc.reg);
    394   } else {
    395     RegStorage temp_low = AllocTemp();
    396     OpRegCopy(temp_low, loc.reg);
    397     loc.reg = temp_low;
    398   }
    399 
    400   // Ensure that this doesn't represent the original SR any more.
    401   loc.s_reg_low = INVALID_SREG;
    402   return loc;
    403 }
    404 
    405 RegLocation Mir2Lir::ForceTempWide(RegLocation loc) {
    406   DCHECK(loc.wide);
    407   DCHECK(loc.location == kLocPhysReg);
    408   DCHECK(!loc.reg.IsFloat());
    409 
    410   if (!loc.reg.IsPair()) {
    411     if (IsTemp(loc.reg)) {
    412       Clobber(loc.reg);
    413     } else {
    414       RegStorage temp = AllocTempWide();
    415       OpRegCopy(temp, loc.reg);
    416       loc.reg = temp;
    417     }
    418   } else {
    419     if (IsTemp(loc.reg.GetLow())) {
    420       Clobber(loc.reg.GetLow());
    421     } else {
    422       RegStorage temp_low = AllocTemp();
    423       OpRegCopy(temp_low, loc.reg.GetLow());
    424       loc.reg.SetLowReg(temp_low.GetReg());
    425     }
    426     if (IsTemp(loc.reg.GetHigh())) {
    427       Clobber(loc.reg.GetHigh());
    428     } else {
    429       RegStorage temp_high = AllocTemp();
    430       OpRegCopy(temp_high, loc.reg.GetHigh());
    431       loc.reg.SetHighReg(temp_high.GetReg());
    432     }
    433   }
    434 
    435   // Ensure that this doesn't represent the original SR any more.
    436   loc.s_reg_low = INVALID_SREG;
    437   return loc;
    438 }
    439 
    440 }  // namespace art
    441