blob: 11b4a6246997556b295f6c0689bd1687de19539b [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 */
43void Codegen::Workaround7250540(CompilationUnit* cu, RegLocation rl_dest, int value)
44{
45 if (rl_dest.fp && (value == 0)) {
46 int pmap_index = SRegToPMap(cu, rl_dest.s_reg_low);
47 if (cu->promotion_map[pmap_index].fp_location == kLocPhysReg) {
48 if (cu->promotion_map[pmap_index].core_location == kLocPhysReg) {
49 // Promoted - just copy in a zero
50 LoadConstant(cu, cu->promotion_map[pmap_index].core_reg, 0);
51 } else {
52 // Lives in the frame, need to store.
53 int temp_reg = AllocTemp(cu);
54 LoadConstant(cu, temp_reg, 0);
55 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low), temp_reg, kWord);
56 }
57 }
58 }
59}
60
buzbee67bf8852011-08-17 17:51:35 -070061/* Load a word at base + displacement. Displacement must be word multiple */
buzbee02031b12012-11-23 09:41:35 -080062LIR* Codegen::LoadWordDisp(CompilationUnit* cu, int rBase, int displacement, int r_dest)
buzbee67bf8852011-08-17 17:51:35 -070063{
buzbeefa57c472012-11-21 12:06:18 -080064 return LoadBaseDisp(cu, rBase, displacement, r_dest, kWord,
Bill Buzbeea114add2012-05-03 15:00:40 -070065 INVALID_SREG);
buzbee67bf8852011-08-17 17:51:35 -070066}
67
buzbee02031b12012-11-23 09:41:35 -080068LIR* Codegen::StoreWordDisp(CompilationUnit* cu, int rBase, int displacement, int r_src)
buzbee67bf8852011-08-17 17:51:35 -070069{
buzbeefa57c472012-11-21 12:06:18 -080070 return StoreBaseDisp(cu, rBase, displacement, r_src, kWord);
buzbee67bf8852011-08-17 17:51:35 -070071}
72
73/*
74 * Load a Dalvik register into a physical register. Take care when
75 * using this routine, as it doesn't perform any bookkeeping regarding
76 * register liveness. That is the responsibility of the caller.
77 */
buzbee02031b12012-11-23 09:41:35 -080078void Codegen::LoadValueDirect(CompilationUnit* cu, RegLocation rl_src, int r_dest)
buzbee67bf8852011-08-17 17:51:35 -070079{
buzbeefa57c472012-11-21 12:06:18 -080080 rl_src = UpdateLoc(cu, rl_src);
81 if (rl_src.location == kLocPhysReg) {
82 OpRegCopy(cu, r_dest, rl_src.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -070083 } else {
buzbeefa57c472012-11-21 12:06:18 -080084 DCHECK((rl_src.location == kLocDalvikFrame) ||
85 (rl_src.location == kLocCompilerTemp));
86 LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_src.s_reg_low), r_dest);
Bill Buzbeea114add2012-05-03 15:00:40 -070087 }
buzbee67bf8852011-08-17 17:51:35 -070088}
89
90/*
buzbee52a77fc2012-11-20 19:50:46 -080091 * Similar to LoadValueDirect, but clobbers and allocates the target
buzbee67bf8852011-08-17 17:51:35 -070092 * register. Should be used when loading to a fixed register (for example,
93 * loading arguments to an out of line call.
94 */
buzbee02031b12012-11-23 09:41:35 -080095void Codegen::LoadValueDirectFixed(CompilationUnit* cu, RegLocation rl_src, int r_dest)
buzbee67bf8852011-08-17 17:51:35 -070096{
buzbeefa57c472012-11-21 12:06:18 -080097 Clobber(cu, r_dest);
98 MarkInUse(cu, r_dest);
99 LoadValueDirect(cu, rl_src, r_dest);
buzbee67bf8852011-08-17 17:51:35 -0700100}
101
102/*
103 * Load a Dalvik register pair into a physical register[s]. Take care when
104 * using this routine, as it doesn't perform any bookkeeping regarding
105 * register liveness. That is the responsibility of the caller.
106 */
buzbee02031b12012-11-23 09:41:35 -0800107void Codegen::LoadValueDirectWide(CompilationUnit* cu, RegLocation rl_src, int reg_lo,
buzbeefa57c472012-11-21 12:06:18 -0800108 int reg_hi)
buzbee67bf8852011-08-17 17:51:35 -0700109{
buzbeefa57c472012-11-21 12:06:18 -0800110 rl_src = UpdateLocWide(cu, rl_src);
111 if (rl_src.location == kLocPhysReg) {
112 OpRegCopyWide(cu, reg_lo, reg_hi, rl_src.low_reg, rl_src.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700113 } else {
buzbeefa57c472012-11-21 12:06:18 -0800114 DCHECK((rl_src.location == kLocDalvikFrame) ||
115 (rl_src.location == kLocCompilerTemp));
116 LoadBaseDispWide(cu, TargetReg(kSp), SRegOffset(cu, rl_src.s_reg_low),
117 reg_lo, reg_hi, INVALID_SREG);
Bill Buzbeea114add2012-05-03 15:00:40 -0700118 }
buzbee67bf8852011-08-17 17:51:35 -0700119}
120
121/*
buzbee52a77fc2012-11-20 19:50:46 -0800122 * Similar to LoadValueDirect, but clobbers and allocates the target
buzbee67bf8852011-08-17 17:51:35 -0700123 * registers. Should be used when loading to a fixed registers (for example,
124 * loading arguments to an out of line call.
125 */
buzbee02031b12012-11-23 09:41:35 -0800126void Codegen::LoadValueDirectWideFixed(CompilationUnit* cu, RegLocation rl_src, int reg_lo,
127 int reg_hi)
buzbee67bf8852011-08-17 17:51:35 -0700128{
buzbeefa57c472012-11-21 12:06:18 -0800129 Clobber(cu, reg_lo);
130 Clobber(cu, reg_hi);
131 MarkInUse(cu, reg_lo);
132 MarkInUse(cu, reg_hi);
133 LoadValueDirectWide(cu, rl_src, reg_lo, reg_hi);
buzbee67bf8852011-08-17 17:51:35 -0700134}
135
buzbee02031b12012-11-23 09:41:35 -0800136RegLocation Codegen::LoadValue(CompilationUnit* cu, RegLocation rl_src, RegisterClass op_kind)
buzbee67bf8852011-08-17 17:51:35 -0700137{
buzbeefa57c472012-11-21 12:06:18 -0800138 rl_src = EvalLoc(cu, rl_src, op_kind, false);
139 if (rl_src.location != kLocPhysReg) {
140 DCHECK((rl_src.location == kLocDalvikFrame) ||
141 (rl_src.location == kLocCompilerTemp));
142 LoadValueDirect(cu, rl_src, rl_src.low_reg);
143 rl_src.location = kLocPhysReg;
144 MarkLive(cu, rl_src.low_reg, rl_src.s_reg_low);
Bill Buzbeea114add2012-05-03 15:00:40 -0700145 }
buzbeefa57c472012-11-21 12:06:18 -0800146 return rl_src;
buzbee67bf8852011-08-17 17:51:35 -0700147}
148
buzbee02031b12012-11-23 09:41:35 -0800149void Codegen::StoreValue(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700150{
buzbee3d661942012-03-14 17:37:27 -0700151#ifndef NDEBUG
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 /*
153 * Sanity checking - should never try to store to the same
154 * ssa name during the compilation of a single instruction
buzbee52a77fc2012-11-20 19:50:46 -0800155 * without an intervening ClobberSReg().
Bill Buzbeea114add2012-05-03 15:00:40 -0700156 */
buzbeefa57c472012-11-21 12:06:18 -0800157 DCHECK((cu->live_sreg == INVALID_SREG) ||
158 (rl_dest.s_reg_low != cu->live_sreg));
159 cu->live_sreg = rl_dest.s_reg_low;
buzbee3d661942012-03-14 17:37:27 -0700160#endif
buzbeefa57c472012-11-21 12:06:18 -0800161 LIR* def_start;
162 LIR* def_end;
163 DCHECK(!rl_dest.wide);
164 DCHECK(!rl_src.wide);
165 rl_src = UpdateLoc(cu, rl_src);
166 rl_dest = UpdateLoc(cu, rl_dest);
167 if (rl_src.location == kLocPhysReg) {
168 if (IsLive(cu, rl_src.low_reg) ||
169 IsPromoted(cu, rl_src.low_reg) ||
170 (rl_dest.location == kLocPhysReg)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700171 // Src is live/promoted or Dest has assigned reg.
buzbeefa57c472012-11-21 12:06:18 -0800172 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
173 OpRegCopy(cu, rl_dest.low_reg, rl_src.low_reg);
buzbee67bf8852011-08-17 17:51:35 -0700174 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700175 // Just re-assign the registers. Dest gets Src's regs
buzbeefa57c472012-11-21 12:06:18 -0800176 rl_dest.low_reg = rl_src.low_reg;
177 Clobber(cu, rl_src.low_reg);
buzbee67bf8852011-08-17 17:51:35 -0700178 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700179 } else {
180 // Load Src either into promoted Dest or temps allocated for Dest
buzbeefa57c472012-11-21 12:06:18 -0800181 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
182 LoadValueDirect(cu, rl_src, rl_dest.low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700183 }
buzbee67bf8852011-08-17 17:51:35 -0700184
Bill Buzbeea114add2012-05-03 15:00:40 -0700185 // Dest is now live and dirty (until/if we flush it to home location)
buzbeefa57c472012-11-21 12:06:18 -0800186 MarkLive(cu, rl_dest.low_reg, rl_dest.s_reg_low);
187 MarkDirty(cu, rl_dest);
buzbee67bf8852011-08-17 17:51:35 -0700188
189
buzbeefa57c472012-11-21 12:06:18 -0800190 ResetDefLoc(cu, rl_dest);
191 if (IsDirty(cu, rl_dest.low_reg) &&
192 oat_live_out(cu, rl_dest.s_reg_low)) {
193 def_start = cu->last_lir_insn;
194 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low),
195 rl_dest.low_reg, kWord);
196 MarkClean(cu, rl_dest);
197 def_end = cu->last_lir_insn;
buzbee5f61f672012-11-28 17:22:17 -0800198 if (!rl_dest.ref) {
199 // Exclude references from store elimination
200 MarkDef(cu, rl_dest, def_start, def_end);
201 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700202 }
buzbee67bf8852011-08-17 17:51:35 -0700203}
204
buzbee02031b12012-11-23 09:41:35 -0800205RegLocation Codegen::LoadValueWide(CompilationUnit* cu, RegLocation rl_src, RegisterClass op_kind)
buzbee67bf8852011-08-17 17:51:35 -0700206{
buzbeefa57c472012-11-21 12:06:18 -0800207 DCHECK(rl_src.wide);
208 rl_src = EvalLoc(cu, rl_src, op_kind, false);
209 if (rl_src.location != kLocPhysReg) {
210 DCHECK((rl_src.location == kLocDalvikFrame) ||
211 (rl_src.location == kLocCompilerTemp));
212 LoadValueDirectWide(cu, rl_src, rl_src.low_reg, rl_src.high_reg);
213 rl_src.location = kLocPhysReg;
214 MarkLive(cu, rl_src.low_reg, rl_src.s_reg_low);
215 MarkLive(cu, rl_src.high_reg,
216 GetSRegHi(rl_src.s_reg_low));
Bill Buzbeea114add2012-05-03 15:00:40 -0700217 }
buzbeefa57c472012-11-21 12:06:18 -0800218 return rl_src;
buzbee67bf8852011-08-17 17:51:35 -0700219}
220
buzbee02031b12012-11-23 09:41:35 -0800221void Codegen::StoreValueWide(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbee67bf8852011-08-17 17:51:35 -0700222{
buzbee3d661942012-03-14 17:37:27 -0700223#ifndef NDEBUG
Bill Buzbeea114add2012-05-03 15:00:40 -0700224 /*
225 * Sanity checking - should never try to store to the same
226 * ssa name during the compilation of a single instruction
buzbee52a77fc2012-11-20 19:50:46 -0800227 * without an intervening ClobberSReg().
Bill Buzbeea114add2012-05-03 15:00:40 -0700228 */
buzbeefa57c472012-11-21 12:06:18 -0800229 DCHECK((cu->live_sreg == INVALID_SREG) ||
230 (rl_dest.s_reg_low != cu->live_sreg));
231 cu->live_sreg = rl_dest.s_reg_low;
buzbee3d661942012-03-14 17:37:27 -0700232#endif
buzbeefa57c472012-11-21 12:06:18 -0800233 LIR* def_start;
234 LIR* def_end;
buzbee02031b12012-11-23 09:41:35 -0800235 DCHECK_EQ(IsFpReg(rl_src.low_reg), IsFpReg(rl_src.high_reg));
buzbeefa57c472012-11-21 12:06:18 -0800236 DCHECK(rl_dest.wide);
237 DCHECK(rl_src.wide);
238 if (rl_src.location == kLocPhysReg) {
239 if (IsLive(cu, rl_src.low_reg) ||
240 IsLive(cu, rl_src.high_reg) ||
241 IsPromoted(cu, rl_src.low_reg) ||
242 IsPromoted(cu, rl_src.high_reg) ||
243 (rl_dest.location == kLocPhysReg)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700244 // Src is live or promoted or Dest has assigned reg.
buzbeefa57c472012-11-21 12:06:18 -0800245 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
246 OpRegCopyWide(cu, rl_dest.low_reg, rl_dest.high_reg,
247 rl_src.low_reg, rl_src.high_reg);
buzbee67bf8852011-08-17 17:51:35 -0700248 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700249 // Just re-assign the registers. Dest gets Src's regs
buzbeefa57c472012-11-21 12:06:18 -0800250 rl_dest.low_reg = rl_src.low_reg;
251 rl_dest.high_reg = rl_src.high_reg;
252 Clobber(cu, rl_src.low_reg);
253 Clobber(cu, rl_src.high_reg);
buzbee67bf8852011-08-17 17:51:35 -0700254 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700255 } else {
256 // Load Src either into promoted Dest or temps allocated for Dest
buzbeefa57c472012-11-21 12:06:18 -0800257 rl_dest = EvalLoc(cu, rl_dest, kAnyReg, false);
258 LoadValueDirectWide(cu, rl_src, rl_dest.low_reg, rl_dest.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700259 }
buzbee67bf8852011-08-17 17:51:35 -0700260
Bill Buzbeea114add2012-05-03 15:00:40 -0700261 // Dest is now live and dirty (until/if we flush it to home location)
buzbeefa57c472012-11-21 12:06:18 -0800262 MarkLive(cu, rl_dest.low_reg, rl_dest.s_reg_low);
263 MarkLive(cu, rl_dest.high_reg, GetSRegHi(rl_dest.s_reg_low));
264 MarkDirty(cu, rl_dest);
265 MarkPair(cu, rl_dest.low_reg, rl_dest.high_reg);
buzbee67bf8852011-08-17 17:51:35 -0700266
267
buzbeefa57c472012-11-21 12:06:18 -0800268 ResetDefLocWide(cu, rl_dest);
269 if ((IsDirty(cu, rl_dest.low_reg) ||
270 IsDirty(cu, rl_dest.high_reg)) &&
271 (oat_live_out(cu, rl_dest.s_reg_low) ||
272 oat_live_out(cu, GetSRegHi(rl_dest.s_reg_low)))) {
273 def_start = cu->last_lir_insn;
274 DCHECK_EQ((SRegToVReg(cu, rl_dest.s_reg_low)+1),
275 SRegToVReg(cu, GetSRegHi(rl_dest.s_reg_low)));
276 StoreBaseDispWide(cu, TargetReg(kSp), SRegOffset(cu, rl_dest.s_reg_low),
277 rl_dest.low_reg, rl_dest.high_reg);
278 MarkClean(cu, rl_dest);
279 def_end = cu->last_lir_insn;
280 MarkDefWide(cu, rl_dest, def_start, def_end);
Bill Buzbeea114add2012-05-03 15:00:40 -0700281 }
buzbee67bf8852011-08-17 17:51:35 -0700282}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800283
buzbeee1965672012-03-11 18:39:19 -0700284/* Utilities to load the current Method* */
buzbee02031b12012-11-23 09:41:35 -0800285void Codegen::LoadCurrMethodDirect(CompilationUnit *cu, int r_tgt)
buzbee31a4a6f2012-02-28 15:36:15 -0800286{
buzbeefa57c472012-11-21 12:06:18 -0800287 LoadValueDirectFixed(cu, cu->method_loc, r_tgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800288}
289
buzbee02031b12012-11-23 09:41:35 -0800290RegLocation Codegen::LoadCurrMethod(CompilationUnit *cu)
buzbee31a4a6f2012-02-28 15:36:15 -0800291{
buzbeefa57c472012-11-21 12:06:18 -0800292 return LoadValue(cu, cu->method_loc, kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800293}
294
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800295} // namespace art