blob: eec74af2da155c764e3792c576655f757e72a614 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -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
buzbee1bc37c62012-11-20 13:35:41 -080017#include "../compiler_ir.h"
18#include "ralloc_util.h"
19#include "codegen_util.h"
20
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080021namespace art {
22
buzbeeb046e162012-10-30 15:48:42 -070023/* This file contains target-independent codegen and support. */
buzbee67bf8852011-08-17 17:51:35 -070024
buzbee31a4a6f2012-02-28 15:36:15 -080025/*
26 * Load an immediate value into a fixed or temp register. Target
buzbeefa57c472012-11-21 12:06:18 -080027 * register is clobbered, and marked in_use.
buzbee31a4a6f2012-02-28 15:36:15 -080028 */
buzbee02031b12012-11-23 09:41:35 -080029LIR* Codegen::LoadConstant(CompilationUnit* cu, int r_dest, int value)
buzbee31a4a6f2012-02-28 15:36:15 -080030{
buzbeefa57c472012-11-21 12:06:18 -080031 if (IsTemp(cu, r_dest)) {
32 Clobber(cu, r_dest);
33 MarkInUse(cu, r_dest);
Bill Buzbeea114add2012-05-03 15:00:40 -070034 }
buzbeefa57c472012-11-21 12:06:18 -080035 return LoadConstantNoClobber(cu, r_dest, value);
buzbee31a4a6f2012-02-28 15:36:15 -080036}
buzbee67bf8852011-08-17 17:51:35 -070037
buzbee5f61f672012-11-28 17:22:17 -080038/*
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 */
buzbee7da142f2012-11-29 16:33:42 -080043void Codegen::Workaround7250540(CompilationUnit* cu, RegLocation rl_dest, int zero_reg)
buzbee5f61f672012-11-28 17:22:17 -080044{
buzbee7da142f2012-11-29 16:33:42 -080045 if (rl_dest.fp) {
buzbee5f61f672012-11-28 17:22:17 -080046 int pmap_index = SRegToPMap(cu, rl_dest.s_reg_low);
47 if (cu->promotion_map[pmap_index].fp_location == kLocPhysReg) {
buzbee7da142f2012-11-29 16:33:42 -080048 // Now, determine if this vreg is ever used as a reference. If not, we're done.
49 bool used_as_reference = false;
50 int base_vreg = SRegToVReg(cu, rl_dest.s_reg_low);
51 for (int i = 0; !used_as_reference && (i < cu->num_ssa_regs); i++) {
52 if (SRegToVReg(cu, cu->reg_location[i].s_reg_low) == base_vreg) {
53 used_as_reference |= cu->reg_location[i].ref;
54 }
55 }
56 if (!used_as_reference) {
57 return;
58 }
buzbee5f61f672012-11-28 17:22:17 -080059 if (cu->promotion_map[pmap_index].core_location == kLocPhysReg) {
60 // Promoted - just copy in a zero
buzbee7da142f2012-11-29 16:33:42 -080061 OpRegCopy(cu, cu->promotion_map[pmap_index].core_reg, zero_reg);
buzbee5f61f672012-11-28 17:22:17 -080062 } else {
63 // Lives in the frame, need to store.
buzbee7da142f2012-11-29 16:33:42 -080064 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low), zero_reg, kWord);
buzbee5f61f672012-11-28 17:22:17 -080065 }
66 }
67 }
68}
69
buzbee67bf8852011-08-17 17:51:35 -070070/* Load a word at base + displacement. Displacement must be word multiple */
buzbee02031b12012-11-23 09:41:35 -080071LIR* Codegen::LoadWordDisp(CompilationUnit* cu, int rBase, int displacement, int r_dest)
buzbee67bf8852011-08-17 17:51:35 -070072{
buzbeefa57c472012-11-21 12:06:18 -080073 return LoadBaseDisp(cu, rBase, displacement, r_dest, kWord,
Bill Buzbeea114add2012-05-03 15:00:40 -070074 INVALID_SREG);
buzbee67bf8852011-08-17 17:51:35 -070075}
76
buzbee02031b12012-11-23 09:41:35 -080077LIR* Codegen::StoreWordDisp(CompilationUnit* cu, int rBase, int displacement, int r_src)
buzbee67bf8852011-08-17 17:51:35 -070078{
buzbeefa57c472012-11-21 12:06:18 -080079 return StoreBaseDisp(cu, rBase, displacement, r_src, kWord);
buzbee67bf8852011-08-17 17:51:35 -070080}
81
82/*
83 * Load a Dalvik register into a physical register. Take care when
84 * using this routine, as it doesn't perform any bookkeeping regarding
85 * register liveness. That is the responsibility of the caller.
86 */
buzbee02031b12012-11-23 09:41:35 -080087void Codegen::LoadValueDirect(CompilationUnit* cu, RegLocation rl_src, int r_dest)
buzbee67bf8852011-08-17 17:51:35 -070088{
buzbeefa57c472012-11-21 12:06:18 -080089 rl_src = UpdateLoc(cu, rl_src);
90 if (rl_src.location == kLocPhysReg) {
91 OpRegCopy(cu, r_dest, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -070092 } else {
buzbeefa57c472012-11-21 12:06:18 -080093 DCHECK((rl_src.location == kLocDalvikFrame) ||
94 (rl_src.location == kLocCompilerTemp));
buzbeee6285f92012-12-06 15:57:46 -080095 if (rl_src.is_const && InexpensiveConstant(r_dest, cu->constant_values[rl_src.orig_sreg])) {
96 LoadConstantNoClobber(cu, r_dest, cu->constant_values[rl_src.orig_sreg]);
97 } else {
98 LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_src.s_reg_low), r_dest);
99 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700100 }
buzbee67bf8852011-08-17 17:51:35 -0700101}
102
103/*
buzbee52a77fc2012-11-20 19:50:46 -0800104 * Similar to LoadValueDirect, but clobbers and allocates the target
buzbee67bf8852011-08-17 17:51:35 -0700105 * register. Should be used when loading to a fixed register (for example,
106 * loading arguments to an out of line call.
107 */
buzbee02031b12012-11-23 09:41:35 -0800108void Codegen::LoadValueDirectFixed(CompilationUnit* cu, RegLocation rl_src, int r_dest)
buzbee67bf8852011-08-17 17:51:35 -0700109{
buzbeefa57c472012-11-21 12:06:18 -0800110 Clobber(cu, r_dest);
111 MarkInUse(cu, r_dest);
112 LoadValueDirect(cu, rl_src, r_dest);
buzbee67bf8852011-08-17 17:51:35 -0700113}
114
115/*
116 * Load a Dalvik register pair into a physical register[s]. Take care when
117 * using this routine, as it doesn't perform any bookkeeping regarding
118 * register liveness. That is the responsibility of the caller.
119 */
buzbee02031b12012-11-23 09:41:35 -0800120void Codegen::LoadValueDirectWide(CompilationUnit* cu, RegLocation rl_src, int reg_lo,
buzbeefa57c472012-11-21 12:06:18 -0800121 int reg_hi)
buzbee67bf8852011-08-17 17:51:35 -0700122{
buzbeefa57c472012-11-21 12:06:18 -0800123 rl_src = UpdateLocWide(cu, rl_src);
124 if (rl_src.location == kLocPhysReg) {
125 OpRegCopyWide(cu, reg_lo, reg_hi, rl_src.low_reg, rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700126 } else {
buzbeefa57c472012-11-21 12:06:18 -0800127 DCHECK((rl_src.location == kLocDalvikFrame) ||
128 (rl_src.location == kLocCompilerTemp));
129 LoadBaseDispWide(cu, TargetReg(kSp), SRegOffset(cu, rl_src.s_reg_low),
130 reg_lo, reg_hi, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -0700131 }
buzbee67bf8852011-08-17 17:51:35 -0700132}
133
134/*
buzbee52a77fc2012-11-20 19:50:46 -0800135 * Similar to LoadValueDirect, but clobbers and allocates the target
buzbee67bf8852011-08-17 17:51:35 -0700136 * registers. Should be used when loading to a fixed registers (for example,
137 * loading arguments to an out of line call.
138 */
buzbee02031b12012-11-23 09:41:35 -0800139void Codegen::LoadValueDirectWideFixed(CompilationUnit* cu, RegLocation rl_src, int reg_lo,
140 int reg_hi)
buzbee67bf8852011-08-17 17:51:35 -0700141{
buzbeefa57c472012-11-21 12:06:18 -0800142 Clobber(cu, reg_lo);
143 Clobber(cu, reg_hi);
144 MarkInUse(cu, reg_lo);
145 MarkInUse(cu, reg_hi);
146 LoadValueDirectWide(cu, rl_src, reg_lo, reg_hi);
buzbee67bf8852011-08-17 17:51:35 -0700147}
148
buzbee02031b12012-11-23 09:41:35 -0800149RegLocation Codegen::LoadValue(CompilationUnit* cu, RegLocation rl_src, RegisterClass op_kind)
buzbee67bf8852011-08-17 17:51:35 -0700150{
buzbeefa57c472012-11-21 12:06:18 -0800151 rl_src = EvalLoc(cu, rl_src, op_kind, false);
152 if (rl_src.location != kLocPhysReg) {
153 DCHECK((rl_src.location == kLocDalvikFrame) ||
154 (rl_src.location == kLocCompilerTemp));
155 LoadValueDirect(cu, rl_src, rl_src.low_reg);
156 rl_src.location = kLocPhysReg;
157 MarkLive(cu, rl_src.low_reg, rl_src.s_reg_low);
Bill Buzbeea114add2012-05-03 15:00:40 -0700158 }
buzbeefa57c472012-11-21 12:06:18 -0800159 return rl_src;
buzbee67bf8852011-08-17 17:51:35 -0700160}
161
buzbee02031b12012-11-23 09:41:35 -0800162void Codegen::StoreValue(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700163{
buzbee3d661942012-03-14 17:37:27 -0700164#ifndef NDEBUG
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 /*
166 * Sanity checking - should never try to store to the same
167 * ssa name during the compilation of a single instruction
buzbee52a77fc2012-11-20 19:50:46 -0800168 * without an intervening ClobberSReg().
Bill Buzbeea114add2012-05-03 15:00:40 -0700169 */
buzbeefa57c472012-11-21 12:06:18 -0800170 DCHECK((cu->live_sreg == INVALID_SREG) ||
171 (rl_dest.s_reg_low != cu->live_sreg));
172 cu->live_sreg = rl_dest.s_reg_low;
buzbee3d661942012-03-14 17:37:27 -0700173#endif
buzbeefa57c472012-11-21 12:06:18 -0800174 LIR* def_start;
175 LIR* def_end;
176 DCHECK(!rl_dest.wide);
177 DCHECK(!rl_src.wide);
178 rl_src = UpdateLoc(cu, rl_src);
179 rl_dest = UpdateLoc(cu, rl_dest);
180 if (rl_src.location == kLocPhysReg) {
181 if (IsLive(cu, rl_src.low_reg) ||
182 IsPromoted(cu, rl_src.low_reg) ||
183 (rl_dest.location == kLocPhysReg)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700184 // Src is live/promoted or Dest has assigned reg.
buzbeefa57c472012-11-21 12:06:18 -0800185 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
186 OpRegCopy(cu, rl_dest.low_reg, rl_src.low_reg);
buzbee67bf8852011-08-17 17:51:35 -0700187 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700188 // Just re-assign the registers. Dest gets Src's regs
buzbeefa57c472012-11-21 12:06:18 -0800189 rl_dest.low_reg = rl_src.low_reg;
190 Clobber(cu, rl_src.low_reg);
buzbee67bf8852011-08-17 17:51:35 -0700191 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700192 } else {
193 // Load Src either into promoted Dest or temps allocated for Dest
buzbeefa57c472012-11-21 12:06:18 -0800194 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
195 LoadValueDirect(cu, rl_src, rl_dest.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700196 }
buzbee67bf8852011-08-17 17:51:35 -0700197
Bill Buzbeea114add2012-05-03 15:00:40 -0700198 // Dest is now live and dirty (until/if we flush it to home location)
buzbeefa57c472012-11-21 12:06:18 -0800199 MarkLive(cu, rl_dest.low_reg, rl_dest.s_reg_low);
200 MarkDirty(cu, rl_dest);
buzbee67bf8852011-08-17 17:51:35 -0700201
202
buzbeefa57c472012-11-21 12:06:18 -0800203 ResetDefLoc(cu, rl_dest);
204 if (IsDirty(cu, rl_dest.low_reg) &&
205 oat_live_out(cu, rl_dest.s_reg_low)) {
206 def_start = cu->last_lir_insn;
207 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low),
208 rl_dest.low_reg, kWord);
209 MarkClean(cu, rl_dest);
210 def_end = cu->last_lir_insn;
buzbee5f61f672012-11-28 17:22:17 -0800211 if (!rl_dest.ref) {
212 // Exclude references from store elimination
213 MarkDef(cu, rl_dest, def_start, def_end);
214 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700215 }
buzbee67bf8852011-08-17 17:51:35 -0700216}
217
buzbee02031b12012-11-23 09:41:35 -0800218RegLocation Codegen::LoadValueWide(CompilationUnit* cu, RegLocation rl_src, RegisterClass op_kind)
buzbee67bf8852011-08-17 17:51:35 -0700219{
buzbeefa57c472012-11-21 12:06:18 -0800220 DCHECK(rl_src.wide);
221 rl_src = EvalLoc(cu, rl_src, op_kind, false);
222 if (rl_src.location != kLocPhysReg) {
223 DCHECK((rl_src.location == kLocDalvikFrame) ||
224 (rl_src.location == kLocCompilerTemp));
225 LoadValueDirectWide(cu, rl_src, rl_src.low_reg, rl_src.high_reg);
226 rl_src.location = kLocPhysReg;
227 MarkLive(cu, rl_src.low_reg, rl_src.s_reg_low);
228 MarkLive(cu, rl_src.high_reg,
229 GetSRegHi(rl_src.s_reg_low));
Bill Buzbeea114add2012-05-03 15:00:40 -0700230 }
buzbeefa57c472012-11-21 12:06:18 -0800231 return rl_src;
buzbee67bf8852011-08-17 17:51:35 -0700232}
233
buzbee02031b12012-11-23 09:41:35 -0800234void Codegen::StoreValueWide(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700235{
buzbee3d661942012-03-14 17:37:27 -0700236#ifndef NDEBUG
Bill Buzbeea114add2012-05-03 15:00:40 -0700237 /*
238 * Sanity checking - should never try to store to the same
239 * ssa name during the compilation of a single instruction
buzbee52a77fc2012-11-20 19:50:46 -0800240 * without an intervening ClobberSReg().
Bill Buzbeea114add2012-05-03 15:00:40 -0700241 */
buzbeefa57c472012-11-21 12:06:18 -0800242 DCHECK((cu->live_sreg == INVALID_SREG) ||
243 (rl_dest.s_reg_low != cu->live_sreg));
244 cu->live_sreg = rl_dest.s_reg_low;
buzbee3d661942012-03-14 17:37:27 -0700245#endif
buzbeefa57c472012-11-21 12:06:18 -0800246 LIR* def_start;
247 LIR* def_end;
buzbee02031b12012-11-23 09:41:35 -0800248 DCHECK_EQ(IsFpReg(rl_src.low_reg), IsFpReg(rl_src.high_reg));
buzbeefa57c472012-11-21 12:06:18 -0800249 DCHECK(rl_dest.wide);
250 DCHECK(rl_src.wide);
251 if (rl_src.location == kLocPhysReg) {
252 if (IsLive(cu, rl_src.low_reg) ||
253 IsLive(cu, rl_src.high_reg) ||
254 IsPromoted(cu, rl_src.low_reg) ||
255 IsPromoted(cu, rl_src.high_reg) ||
256 (rl_dest.location == kLocPhysReg)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700257 // Src is live or promoted or Dest has assigned reg.
buzbeefa57c472012-11-21 12:06:18 -0800258 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
259 OpRegCopyWide(cu, rl_dest.low_reg, rl_dest.high_reg,
260 rl_src.low_reg, rl_src.high_reg);
buzbee67bf8852011-08-17 17:51:35 -0700261 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700262 // Just re-assign the registers. Dest gets Src's regs
buzbeefa57c472012-11-21 12:06:18 -0800263 rl_dest.low_reg = rl_src.low_reg;
264 rl_dest.high_reg = rl_src.high_reg;
265 Clobber(cu, rl_src.low_reg);
266 Clobber(cu, rl_src.high_reg);
buzbee67bf8852011-08-17 17:51:35 -0700267 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700268 } else {
269 // Load Src either into promoted Dest or temps allocated for Dest
buzbeefa57c472012-11-21 12:06:18 -0800270 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
271 LoadValueDirectWide(cu, rl_src, rl_dest.low_reg, rl_dest.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700272 }
buzbee67bf8852011-08-17 17:51:35 -0700273
Bill Buzbeea114add2012-05-03 15:00:40 -0700274 // Dest is now live and dirty (until/if we flush it to home location)
buzbeefa57c472012-11-21 12:06:18 -0800275 MarkLive(cu, rl_dest.low_reg, rl_dest.s_reg_low);
276 MarkLive(cu, rl_dest.high_reg, GetSRegHi(rl_dest.s_reg_low));
277 MarkDirty(cu, rl_dest);
278 MarkPair(cu, rl_dest.low_reg, rl_dest.high_reg);
buzbee67bf8852011-08-17 17:51:35 -0700279
280
buzbeefa57c472012-11-21 12:06:18 -0800281 ResetDefLocWide(cu, rl_dest);
282 if ((IsDirty(cu, rl_dest.low_reg) ||
283 IsDirty(cu, rl_dest.high_reg)) &&
284 (oat_live_out(cu, rl_dest.s_reg_low) ||
285 oat_live_out(cu, GetSRegHi(rl_dest.s_reg_low)))) {
286 def_start = cu->last_lir_insn;
287 DCHECK_EQ((SRegToVReg(cu, rl_dest.s_reg_low)+1),
288 SRegToVReg(cu, GetSRegHi(rl_dest.s_reg_low)));
289 StoreBaseDispWide(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low),
290 rl_dest.low_reg, rl_dest.high_reg);
291 MarkClean(cu, rl_dest);
292 def_end = cu->last_lir_insn;
293 MarkDefWide(cu, rl_dest, def_start, def_end);
Bill Buzbeea114add2012-05-03 15:00:40 -0700294 }
buzbee67bf8852011-08-17 17:51:35 -0700295}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800296
buzbeee1965672012-03-11 18:39:19 -0700297/* Utilities to load the current Method* */
buzbee02031b12012-11-23 09:41:35 -0800298void Codegen::LoadCurrMethodDirect(CompilationUnit *cu, int r_tgt)
buzbee31a4a6f2012-02-28 15:36:15 -0800299{
buzbeefa57c472012-11-21 12:06:18 -0800300 LoadValueDirectFixed(cu, cu->method_loc, r_tgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800301}
302
buzbee02031b12012-11-23 09:41:35 -0800303RegLocation Codegen::LoadCurrMethod(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800304{
buzbeefa57c472012-11-21 12:06:18 -0800305 return LoadValue(cu, cu->method_loc, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800306}
307
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800308} // namespace art