gen_loadstore.cc revision 30adc7383a74eb3cb6db3bf42cea3a5595055ce1
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 22namespace 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 */ 30LIR* 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 */ 43void 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 StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), temp_reg, k32); 69 } 70 if (!zero_reg.Valid()) { 71 FreeTemp(temp_reg); 72 } 73 } 74 } 75} 76 77/* 78 * Load a Dalvik register into a physical register. Take care when 79 * using this routine, as it doesn't perform any bookkeeping regarding 80 * register liveness. That is the responsibility of the caller. 81 */ 82void Mir2Lir::LoadValueDirect(RegLocation rl_src, RegStorage r_dest) { 83 rl_src = UpdateLoc(rl_src); 84 if (rl_src.location == kLocPhysReg) { 85 OpRegCopy(r_dest, rl_src.reg); 86 } else if (IsInexpensiveConstant(rl_src)) { 87 // On 64-bit targets, will sign extend. Make sure constant reference is always NULL. 88 DCHECK(!rl_src.ref || (mir_graph_->ConstantValue(rl_src) == 0)); 89 LoadConstantNoClobber(r_dest, mir_graph_->ConstantValue(rl_src)); 90 } else { 91 DCHECK((rl_src.location == kLocDalvikFrame) || 92 (rl_src.location == kLocCompilerTemp)); 93 if (rl_src.ref) { 94 LoadRefDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest); 95 } else { 96 Load32Disp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest); 97 } 98 } 99} 100 101/* 102 * Similar to LoadValueDirect, but clobbers and allocates the target 103 * register. Should be used when loading to a fixed register (for example, 104 * loading arguments to an out of line call. 105 */ 106void Mir2Lir::LoadValueDirectFixed(RegLocation rl_src, RegStorage r_dest) { 107 Clobber(r_dest); 108 MarkInUse(r_dest); 109 LoadValueDirect(rl_src, r_dest); 110} 111 112/* 113 * Load a Dalvik register pair into a physical register[s]. Take care when 114 * using this routine, as it doesn't perform any bookkeeping regarding 115 * register liveness. That is the responsibility of the caller. 116 */ 117void Mir2Lir::LoadValueDirectWide(RegLocation rl_src, RegStorage r_dest) { 118 rl_src = UpdateLocWide(rl_src); 119 if (rl_src.location == kLocPhysReg) { 120 OpRegCopyWide(r_dest, rl_src.reg); 121 } else if (IsInexpensiveConstant(rl_src)) { 122 LoadConstantWide(r_dest, mir_graph_->ConstantValueWide(rl_src)); 123 } else { 124 DCHECK((rl_src.location == kLocDalvikFrame) || 125 (rl_src.location == kLocCompilerTemp)); 126 LoadBaseDisp(TargetReg(kSp), SRegOffset(rl_src.s_reg_low), r_dest, k64); 127 } 128} 129 130/* 131 * Similar to LoadValueDirect, but clobbers and allocates the target 132 * registers. Should be used when loading to a fixed registers (for example, 133 * loading arguments to an out of line call. 134 */ 135void Mir2Lir::LoadValueDirectWideFixed(RegLocation rl_src, RegStorage r_dest) { 136 Clobber(r_dest); 137 MarkInUse(r_dest); 138 LoadValueDirectWide(rl_src, r_dest); 139} 140 141RegLocation Mir2Lir::LoadValue(RegLocation rl_src, RegisterClass op_kind) { 142 rl_src = EvalLoc(rl_src, op_kind, false); 143 if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) { 144 LoadValueDirect(rl_src, rl_src.reg); 145 rl_src.location = kLocPhysReg; 146 MarkLive(rl_src); 147 } 148 return rl_src; 149} 150 151void Mir2Lir::StoreValue(RegLocation rl_dest, RegLocation rl_src) { 152 /* 153 * Sanity checking - should never try to store to the same 154 * ssa name during the compilation of a single instruction 155 * without an intervening ClobberSReg(). 156 */ 157 if (kIsDebugBuild) { 158 DCHECK((live_sreg_ == INVALID_SREG) || 159 (rl_dest.s_reg_low != live_sreg_)); 160 live_sreg_ = rl_dest.s_reg_low; 161 } 162 LIR* def_start; 163 LIR* def_end; 164 DCHECK(!rl_dest.wide); 165 DCHECK(!rl_src.wide); 166 rl_src = UpdateLoc(rl_src); 167 rl_dest = UpdateLoc(rl_dest); 168 if (rl_src.location == kLocPhysReg) { 169 if (IsLive(rl_src.reg) || 170 IsPromoted(rl_src.reg) || 171 (rl_dest.location == kLocPhysReg)) { 172 // Src is live/promoted or Dest has assigned reg. 173 rl_dest = EvalLoc(rl_dest, kAnyReg, false); 174 OpRegCopy(rl_dest.reg, rl_src.reg); 175 } else { 176 // Just re-assign the registers. Dest gets Src's regs 177 rl_dest.reg = rl_src.reg; 178 Clobber(rl_src.reg); 179 } 180 } else { 181 // Load Src either into promoted Dest or temps allocated for Dest 182 rl_dest = EvalLoc(rl_dest, kAnyReg, false); 183 LoadValueDirect(rl_src, rl_dest.reg); 184 } 185 186 // Dest is now live and dirty (until/if we flush it to home location) 187 MarkLive(rl_dest); 188 MarkDirty(rl_dest); 189 190 191 ResetDefLoc(rl_dest); 192 if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) { 193 def_start = last_lir_insn_; 194 Store32Disp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg); 195 MarkClean(rl_dest); 196 def_end = last_lir_insn_; 197 if (!rl_dest.ref) { 198 // Exclude references from store elimination 199 MarkDef(rl_dest, def_start, def_end); 200 } 201 } 202} 203 204RegLocation Mir2Lir::LoadValueWide(RegLocation rl_src, RegisterClass op_kind) { 205 DCHECK(rl_src.wide); 206 rl_src = EvalLoc(rl_src, op_kind, false); 207 if (IsInexpensiveConstant(rl_src) || rl_src.location != kLocPhysReg) { 208 LoadValueDirectWide(rl_src, rl_src.reg); 209 rl_src.location = kLocPhysReg; 210 MarkLive(rl_src); 211 } 212 return rl_src; 213} 214 215void Mir2Lir::StoreValueWide(RegLocation rl_dest, RegLocation rl_src) { 216 /* 217 * Sanity checking - should never try to store to the same 218 * ssa name during the compilation of a single instruction 219 * without an intervening ClobberSReg(). 220 */ 221 if (kIsDebugBuild) { 222 DCHECK((live_sreg_ == INVALID_SREG) || 223 (rl_dest.s_reg_low != live_sreg_)); 224 live_sreg_ = rl_dest.s_reg_low; 225 } 226 LIR* def_start; 227 LIR* def_end; 228 DCHECK(rl_dest.wide); 229 DCHECK(rl_src.wide); 230 rl_src = UpdateLocWide(rl_src); 231 rl_dest = UpdateLocWide(rl_dest); 232 if (rl_src.location == kLocPhysReg) { 233 if (IsLive(rl_src.reg) || 234 IsPromoted(rl_src.reg) || 235 (rl_dest.location == kLocPhysReg)) { 236 /* 237 * If src reg[s] are tied to the original Dalvik vreg via liveness or promotion, we 238 * can't repurpose them. Similarly, if the dest reg[s] are tied to Dalvik vregs via 239 * promotion, we can't just re-assign. In these cases, we have to copy. 240 */ 241 rl_dest = EvalLoc(rl_dest, kAnyReg, false); 242 OpRegCopyWide(rl_dest.reg, rl_src.reg); 243 } else { 244 // Just re-assign the registers. Dest gets Src's regs 245 rl_dest.reg = rl_src.reg; 246 Clobber(rl_src.reg); 247 } 248 } else { 249 // Load Src either into promoted Dest or temps allocated for Dest 250 rl_dest = EvalLoc(rl_dest, kAnyReg, false); 251 LoadValueDirectWide(rl_src, rl_dest.reg); 252 } 253 254 // Dest is now live and dirty (until/if we flush it to home location) 255 MarkLive(rl_dest); 256 MarkWide(rl_dest.reg); 257 MarkDirty(rl_dest); 258 259 ResetDefLocWide(rl_dest); 260 if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) || 261 LiveOut(GetSRegHi(rl_dest.s_reg_low)))) { 262 def_start = last_lir_insn_; 263 DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1), 264 mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low))); 265 StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64); 266 MarkClean(rl_dest); 267 def_end = last_lir_insn_; 268 MarkDefWide(rl_dest, def_start, def_end); 269 } 270} 271 272void Mir2Lir::StoreFinalValue(RegLocation rl_dest, RegLocation rl_src) { 273 DCHECK_EQ(rl_src.location, kLocPhysReg); 274 275 if (rl_dest.location == kLocPhysReg) { 276 OpRegCopy(rl_dest.reg, rl_src.reg); 277 } else { 278 // Just re-assign the register. Dest gets Src's reg. 279 rl_dest.location = kLocPhysReg; 280 rl_dest.reg = rl_src.reg; 281 Clobber(rl_src.reg); 282 } 283 284 // Dest is now live and dirty (until/if we flush it to home location) 285 MarkLive(rl_dest); 286 MarkDirty(rl_dest); 287 288 289 ResetDefLoc(rl_dest); 290 if (IsDirty(rl_dest.reg) && LiveOut(rl_dest.s_reg_low)) { 291 LIR *def_start = last_lir_insn_; 292 Store32Disp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg); 293 MarkClean(rl_dest); 294 LIR *def_end = last_lir_insn_; 295 if (!rl_dest.ref) { 296 // Exclude references from store elimination 297 MarkDef(rl_dest, def_start, def_end); 298 } 299 } 300} 301 302void Mir2Lir::StoreFinalValueWide(RegLocation rl_dest, RegLocation rl_src) { 303 DCHECK(rl_dest.wide); 304 DCHECK(rl_src.wide); 305 DCHECK_EQ(rl_src.location, kLocPhysReg); 306 307 if (rl_dest.location == kLocPhysReg) { 308 OpRegCopyWide(rl_dest.reg, rl_src.reg); 309 } else { 310 // Just re-assign the registers. Dest gets Src's regs. 311 rl_dest.location = kLocPhysReg; 312 rl_dest.reg = rl_src.reg; 313 Clobber(rl_src.reg); 314 } 315 316 // Dest is now live and dirty (until/if we flush it to home location). 317 MarkLive(rl_dest); 318 MarkWide(rl_dest.reg); 319 MarkDirty(rl_dest); 320 321 ResetDefLocWide(rl_dest); 322 if (IsDirty(rl_dest.reg) && (LiveOut(rl_dest.s_reg_low) || 323 LiveOut(GetSRegHi(rl_dest.s_reg_low)))) { 324 LIR *def_start = last_lir_insn_; 325 DCHECK_EQ((mir_graph_->SRegToVReg(rl_dest.s_reg_low)+1), 326 mir_graph_->SRegToVReg(GetSRegHi(rl_dest.s_reg_low))); 327 StoreBaseDisp(TargetReg(kSp), SRegOffset(rl_dest.s_reg_low), rl_dest.reg, k64); 328 MarkClean(rl_dest); 329 LIR *def_end = last_lir_insn_; 330 MarkDefWide(rl_dest, def_start, def_end); 331 } 332} 333 334/* Utilities to load the current Method* */ 335void Mir2Lir::LoadCurrMethodDirect(RegStorage r_tgt) { 336 LoadValueDirectFixed(mir_graph_->GetMethodLoc(), r_tgt); 337} 338 339RegLocation Mir2Lir::LoadCurrMethod() { 340 return LoadValue(mir_graph_->GetMethodLoc(), kCoreReg); 341} 342 343RegLocation Mir2Lir::ForceTemp(RegLocation loc) { 344 DCHECK(!loc.wide); 345 DCHECK(loc.location == kLocPhysReg); 346 DCHECK(!loc.reg.IsFloat()); 347 if (IsTemp(loc.reg)) { 348 Clobber(loc.reg); 349 } else { 350 RegStorage temp_low = AllocTemp(); 351 OpRegCopy(temp_low, loc.reg); 352 loc.reg = temp_low; 353 } 354 355 // Ensure that this doesn't represent the original SR any more. 356 loc.s_reg_low = INVALID_SREG; 357 return loc; 358} 359 360// FIXME: will need an update for 64-bit core regs. 361RegLocation Mir2Lir::ForceTempWide(RegLocation loc) { 362 DCHECK(loc.wide); 363 DCHECK(loc.location == kLocPhysReg); 364 DCHECK(!loc.reg.IsFloat()); 365 if (IsTemp(loc.reg.GetLow())) { 366 Clobber(loc.reg.GetLow()); 367 } else { 368 RegStorage temp_low = AllocTemp(); 369 OpRegCopy(temp_low, loc.reg.GetLow()); 370 loc.reg.SetLowReg(temp_low.GetReg()); 371 } 372 if (IsTemp(loc.reg.GetHigh())) { 373 Clobber(loc.reg.GetHigh()); 374 } else { 375 RegStorage temp_high = AllocTemp(); 376 OpRegCopy(temp_high, loc.reg.GetHigh()); 377 loc.reg.SetHighReg(temp_high.GetReg()); 378 } 379 380 // Ensure that this doesn't represent the original SR any more. 381 loc.s_reg_low = INVALID_SREG; 382 return loc; 383} 384 385} // namespace art 386