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(int 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, int 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       int temp_reg = zero_reg;
     59       if (temp_reg == INVALID_REG) {
     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(promotion_map_[pmap_index].core_reg, temp_reg);
     66       } else {
     67         // Lives in the frame, need to store.
     68         StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), temp_reg, kWord);
     69       }
     70       if (zero_reg == INVALID_REG) {
     71         FreeTemp(temp_reg);
     72       }
     73     }
     74   }
     75 }
     76 
     77 /* Load a word at base + displacement.  Displacement must be word multiple */
     78 LIR* Mir2Lir::LoadWordDisp(int rBase, int displacement, int r_dest) {
     79   return LoadBaseDisp(rBase, displacement, r_dest, kWord,
     80                       INVALID_SREG);
     81 }
     82 
     83 LIR* Mir2Lir::StoreWordDisp(int rBase, int displacement, int r_src) {
     84   return StoreBaseDisp(rBase, displacement, r_src, kWord);
     85 }
     86 
     87 /*
     88  * Load a Dalvik register into a physical register.  Take care when
     89  * using this routine, as it doesn't perform any bookkeeping regarding
     90  * register liveness.  That is the responsibility of the caller.
     91  */
     92 void Mir2Lir::LoadValueDirect(RegLocation rl_src, int r_dest) {
     93   rl_src = UpdateLoc(rl_src);
     94   if (rl_src.location == kLocPhysReg) {
     95     OpRegCopy(r_dest, rl_src.low_reg);
     96   } else if (IsInexpensiveConstant(rl_src)) {
     97     LoadConstantNoClobber(r_dest, mir_graph_->ConstantValue(rl_src));
     98   } else {
     99     DCHECK((rl_src.location == kLocDalvikFrame) ||
    100            (rl_src.location == kLocCompilerTemp));
    101     LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest);
    102   }
    103 }
    104 
    105 /*
    106  * Similar to LoadValueDirect, but clobbers and allocates the target
    107  * register.  Should be used when loading to a fixed register (for example,
    108  * loading arguments to an out of line call.
    109  */
    110 void Mir2Lir::LoadValueDirectFixed(RegLocation rl_src, int r_dest) {
    111   Clobber(r_dest);
    112   MarkInUse(r_dest);
    113   LoadValueDirect(rl_src, r_dest);
    114 }
    115 
    116 /*
    117  * Load a Dalvik register pair into a physical register[s].  Take care when
    118  * using this routine, as it doesn't perform any bookkeeping regarding
    119  * register liveness.  That is the responsibility of the caller.
    120  */
    121 void Mir2Lir::LoadValueDirectWide(RegLocation rl_src, int reg_lo,
    122              int reg_hi) {
    123   rl_src = UpdateLocWide(rl_src);
    124   if (rl_src.location == kLocPhysReg) {
    125     OpRegCopyWide(reg_lo, reg_hi, rl_src.low_reg, rl_src.high_reg);
    126   } else if (IsInexpensiveConstant(rl_src)) {
    127     LoadConstantWide(reg_lo, reg_hi, mir_graph_->ConstantValueWide(rl_src));
    128   } else {
    129     DCHECK((rl_src.location == kLocDalvikFrame) ||
    130            (rl_src.location == kLocCompilerTemp));
    131     LoadBaseDispWide(TargetReg(kSp), SRegOffset(rl_src.s_reg_low),
    132                      reg_lo, reg_hi, INVALID_SREG);
    133   }
    134 }
    135 
    136 /*
    137  * Similar to LoadValueDirect, but clobbers and allocates the target
    138  * registers.  Should be used when loading to a fixed registers (for example,
    139  * loading arguments to an out of line call.
    140  */
    141 void Mir2Lir::LoadValueDirectWideFixed(RegLocation rl_src, int reg_lo,
    142                                        int reg_hi) {
    143   Clobber(reg_lo);
    144   Clobber(reg_hi);
    145   MarkInUse(reg_lo);
    146   MarkInUse(reg_hi);
    147   LoadValueDirectWide(rl_src, reg_lo, reg_hi);
    148 }
    149 
    150 RegLocation Mir2Lir::LoadValue(RegLocation rl_src, RegisterClass op_kind) {
    151   rl_src = EvalLoc(rl_src, op_kind, false);
    152   if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
    153     LoadValueDirect(rl_src, rl_src.low_reg);
    154     rl_src.location = kLocPhysReg;
    155     MarkLive(rl_src.low_reg, rl_src.s_reg_low);
    156   }
    157   return rl_src;
    158 }
    159 
    160 void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src) {
    161   /*
    162    * Sanity checking - should never try to store to the same
    163    * ssa name during the compilation of a single instruction
    164    * without an intervening ClobberSReg().
    165    */
    166   if (kIsDebugBuild) {
    167     DCHECK((live_sreg_ == INVALID_SREG) ||
    168            (rl_dest.s_reg_low != live_sreg_));
    169     live_sreg_ = rl_dest.s_reg_low;
    170   }
    171   LIR* def_start;
    172   LIR* def_end;
    173   DCHECK(!rl_dest.wide);
    174   DCHECK(!rl_src.wide);
    175   rl_src = UpdateLoc(rl_src);
    176   rl_dest = UpdateLoc(rl_dest);
    177   if (rl_src.location == kLocPhysReg) {
    178     if (IsLive(rl_src.low_reg) ||
    179       IsPromoted(rl_src.low_reg) ||
    180       (rl_dest.location == kLocPhysReg)) {
    181       // Src is live/promoted or Dest has assigned reg.
    182       rl_dest = EvalLoc(rl_dest, kAnyReg, false);
    183       OpRegCopy(rl_dest.low_reg, rl_src.low_reg);
    184     } else {
    185       // Just re-assign the registers.  Dest gets Src's regs
    186       rl_dest.low_reg = rl_src.low_reg;
    187       Clobber(rl_src.low_reg);
    188     }
    189   } else {
    190     // Load Src either into promoted Dest or temps allocated for Dest
    191     rl_dest = EvalLoc(rl_dest, kAnyReg, false);
    192     LoadValueDirect(rl_src, rl_dest.low_reg);
    193   }
    194 
    195   // Dest is now live and dirty (until/if we flush it to home location)
    196   MarkLive(rl_dest.low_reg, rl_dest.s_reg_low);
    197   MarkDirty(rl_dest);
    198 
    199 
    200   ResetDefLoc(rl_dest);
    201   if (IsDirty(rl_dest.low_reg) &&
    202       oat_live_out(rl_dest.s_reg_low)) {
    203     def_start = last_lir_insn_;
    204     StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low),
    205                   rl_dest.low_reg, kWord);
    206     MarkClean(rl_dest);
    207     def_end = last_lir_insn_;
    208     if (!rl_dest.ref) {
    209       // Exclude references from store elimination
    210       MarkDef(rl_dest, def_start, def_end);
    211     }
    212   }
    213 }
    214 
    215 RegLocation Mir2Lir::LoadValueWide(RegLocation rl_src, RegisterClass op_kind) {
    216   DCHECK(rl_src.wide);
    217   rl_src = EvalLoc(rl_src, op_kind, false);
    218   if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) {
    219     LoadValueDirectWide(rl_src, rl_src.low_reg, rl_src.high_reg);
    220     rl_src.location = kLocPhysReg;
    221     MarkLive(rl_src.low_reg, rl_src.s_reg_low);
    222     MarkLive(rl_src.high_reg, GetSRegHi(rl_src.s_reg_low));
    223   }
    224   return rl_src;
    225 }
    226 
    227 void Mir2Lir::StoreValueWide(RegLocation rl_dest, RegLocation rl_src) {
    228   /*
    229    * Sanity checking - should never try to store to the same
    230    * ssa name during the compilation of a single instruction
    231    * without an intervening ClobberSReg().
    232    */
    233   if (kIsDebugBuild) {
    234     DCHECK((live_sreg_ == INVALID_SREG) ||
    235            (rl_dest.s_reg_low != live_sreg_));
    236     live_sreg_ = rl_dest.s_reg_low;
    237   }
    238   LIR* def_start;
    239   LIR* def_end;
    240   DCHECK_EQ(IsFpReg(rl_src.low_reg), IsFpReg(rl_src.high_reg));
    241   DCHECK(rl_dest.wide);
    242   DCHECK(rl_src.wide);
    243   if (rl_src.location == kLocPhysReg) {
    244     if (IsLive(rl_src.low_reg) ||
    245         IsLive(rl_src.high_reg) ||
    246         IsPromoted(rl_src.low_reg) ||
    247         IsPromoted(rl_src.high_reg) ||
    248         (rl_dest.location == kLocPhysReg)) {
    249       // Src is live or promoted or Dest has assigned reg.
    250       rl_dest = EvalLoc(rl_dest, kAnyReg, false);
    251       OpRegCopyWide(rl_dest.low_reg, rl_dest.high_reg,
    252                     rl_src.low_reg, rl_src.high_reg);
    253     } else {
    254       // Just re-assign the registers.  Dest gets Src's regs
    255       rl_dest.low_reg = rl_src.low_reg;
    256       rl_dest.high_reg = rl_src.high_reg;
    257       Clobber(rl_src.low_reg);
    258       Clobber(rl_src.high_reg);
    259     }
    260   } else {
    261     // Load Src either into promoted Dest or temps allocated for Dest
    262     rl_dest = EvalLoc(rl_dest, kAnyReg, false);
    263     LoadValueDirectWide(rl_src, rl_dest.low_reg, rl_dest.high_reg);
    264   }
    265 
    266   // Dest is now live and dirty (until/if we flush it to home location)
    267   MarkLive(rl_dest.low_reg, rl_dest.s_reg_low);
    268   MarkLive(rl_dest.high_reg, GetSRegHi(rl_dest.s_reg_low));
    269   MarkDirty(rl_dest);
    270   MarkPair(rl_dest.low_reg, rl_dest.high_reg);
    271 
    272 
    273   ResetDefLocWide(rl_dest);
    274   if ((IsDirty(rl_dest.low_reg) ||
    275       IsDirty(rl_dest.high_reg)) &&
    276       (oat_live_out(rl_dest.s_reg_low) ||
    277       oat_live_out(GetSRegHi(rl_dest.s_reg_low)))) {
    278     def_start = last_lir_insn_;
    279     DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1),
    280               mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low)));
    281     StoreBaseDispWide(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low),
    282                       rl_dest.low_reg, rl_dest.high_reg);
    283     MarkClean(rl_dest);
    284     def_end = last_lir_insn_;
    285     MarkDefWide(rl_dest, def_start, def_end);
    286   }
    287 }
    288 
    289 /* Utilities to load the current Method* */
    290 void Mir2Lir::LoadCurrMethodDirect(int r_tgt) {
    291   LoadValueDirectFixed(mir_graph_->GetMethodLoc(), r_tgt);
    292 }
    293 
    294 RegLocation Mir2Lir::LoadCurrMethod() {
    295   return LoadValue(mir_graph_->GetMethodLoc(), kCoreReg);
    296 }
    297 
    298 }  // namespace art
    299