• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
LoadConstant(int r_dest,int value)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  */
Workaround7250540(RegLocation rl_dest,int zero_reg)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 */
LoadWordDisp(int rBase,int displacement,int r_dest)78 LIR* Mir2Lir::LoadWordDisp(int rBase, int displacement, int r_dest) {
79   return LoadBaseDisp(rBase, displacement, r_dest, kWord,
80                       INVALID_SREG);
81 }
82 
StoreWordDisp(int rBase,int displacement,int r_src)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  */
LoadValueDirect(RegLocation rl_src,int r_dest)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  */
LoadValueDirectFixed(RegLocation rl_src,int r_dest)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  */
LoadValueDirectWide(RegLocation rl_src,int reg_lo,int reg_hi)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  */
LoadValueDirectWideFixed(RegLocation rl_src,int reg_lo,int reg_hi)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 
LoadValue(RegLocation rl_src,RegisterClass op_kind)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 
StoreValue(RegLocation rl_dest,RegLocation rl_src)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 
LoadValueWide(RegLocation rl_src,RegisterClass op_kind)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 
StoreValueWide(RegLocation rl_dest,RegLocation rl_src)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* */
LoadCurrMethodDirect(int r_tgt)290 void Mir2Lir::LoadCurrMethodDirect(int r_tgt) {
291   LoadValueDirectFixed(mir_graph_->GetMethodLoc(), r_tgt);
292 }
293 
LoadCurrMethod()294 RegLocation Mir2Lir::LoadCurrMethod() {
295   return LoadValue(mir_graph_->GetMethodLoc(), kCoreReg);
296 }
297 
298 }  // namespace art
299