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