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