blob: e1df1a5b45ff7489501ecbb0455c15d483f9935f [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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080017namespace art {
18
buzbee67bf8852011-08-17 17:51:35 -070019/*
20 * This file contains target-independent codegen and support, and is
21 * included by:
22 *
23 * $(TARGET_ARCH)/Codegen-$(TARGET_ARCH_VARIANT).c
24 *
25 * which combines this common code with specific support found in the
26 * applicable directories below this one.
27 *
buzbee67bf8852011-08-17 17:51:35 -070028 */
29
buzbee31a4a6f2012-02-28 15:36:15 -080030/*
31 * Load an immediate value into a fixed or temp register. Target
32 * register is clobbered, and marked inUse.
33 */
34LIR* loadConstant(CompilationUnit* cUnit, int rDest, int value)
35{
36 if (oatIsTemp(cUnit, rDest)) {
37 oatClobber(cUnit, rDest);
38 oatMarkInUse(cUnit, rDest);
39 }
40 return loadConstantNoClobber(cUnit, rDest, value);
41}
buzbee67bf8852011-08-17 17:51:35 -070042
43/* Load a word at base + displacement. Displacement must be word multiple */
buzbee31a4a6f2012-02-28 15:36:15 -080044LIR* loadWordDisp(CompilationUnit* cUnit, int rBase, int displacement,
45 int rDest)
buzbee67bf8852011-08-17 17:51:35 -070046{
47 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
48 INVALID_SREG);
49}
50
buzbee31a4a6f2012-02-28 15:36:15 -080051LIR* storeWordDisp(CompilationUnit* cUnit, int rBase, int displacement,
52 int rSrc)
buzbee67bf8852011-08-17 17:51:35 -070053{
54 return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
55}
56
57/*
58 * Load a Dalvik register into a physical register. Take care when
59 * using this routine, as it doesn't perform any bookkeeping regarding
60 * register liveness. That is the responsibility of the caller.
61 */
Ian Rogersab2b55d2012-03-18 00:06:11 -070062void loadValueDirect(CompilationUnit* cUnit, RegLocation rlSrc, int rDest)
buzbee67bf8852011-08-17 17:51:35 -070063{
64 rlSrc = oatUpdateLoc(cUnit, rlSrc);
65 if (rlSrc.location == kLocPhysReg) {
Ian Rogersab2b55d2012-03-18 00:06:11 -070066 opRegCopy(cUnit, rDest, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -070067 } else {
buzbeee1965672012-03-11 18:39:19 -070068 DCHECK((rlSrc.location == kLocDalvikFrame) ||
69 (rlSrc.location == kLocCompilerTemp));
Ian Rogersab2b55d2012-03-18 00:06:11 -070070 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, rlSrc.sRegLow), rDest);
buzbee67bf8852011-08-17 17:51:35 -070071 }
72}
73
74/*
75 * Similar to loadValueDirect, but clobbers and allocates the target
76 * register. Should be used when loading to a fixed register (for example,
77 * loading arguments to an out of line call.
78 */
Ian Rogersab2b55d2012-03-18 00:06:11 -070079void loadValueDirectFixed(CompilationUnit* cUnit, RegLocation rlSrc, int rDest)
buzbee67bf8852011-08-17 17:51:35 -070080{
Ian Rogersab2b55d2012-03-18 00:06:11 -070081 oatClobber(cUnit, rDest);
82 oatMarkInUse(cUnit, rDest);
83 loadValueDirect(cUnit, rlSrc, rDest);
buzbee67bf8852011-08-17 17:51:35 -070084}
85
86/*
87 * Load a Dalvik register pair into a physical register[s]. Take care when
88 * using this routine, as it doesn't perform any bookkeeping regarding
89 * register liveness. That is the responsibility of the caller.
90 */
buzbee31a4a6f2012-02-28 15:36:15 -080091void loadValueDirectWide(CompilationUnit* cUnit, RegLocation rlSrc, int regLo,
92 int regHi)
buzbee67bf8852011-08-17 17:51:35 -070093{
94 rlSrc = oatUpdateLocWide(cUnit, rlSrc);
95 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -080096 opRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
buzbee67bf8852011-08-17 17:51:35 -070097 } else {
buzbeee1965672012-03-11 18:39:19 -070098 DCHECK((rlSrc.location == kLocDalvikFrame) ||
99 (rlSrc.location == kLocCompilerTemp));
buzbee67bc2362011-10-11 18:08:40 -0700100 loadBaseDispWide(cUnit, NULL, rSP,
101 oatSRegOffset(cUnit, rlSrc.sRegLow),
buzbee67bf8852011-08-17 17:51:35 -0700102 regLo, regHi, INVALID_SREG);
103 }
104}
105
106/*
107 * Similar to loadValueDirect, but clobbers and allocates the target
108 * registers. Should be used when loading to a fixed registers (for example,
109 * loading arguments to an out of line call.
110 */
buzbee31a4a6f2012-02-28 15:36:15 -0800111void loadValueDirectWideFixed(CompilationUnit* cUnit, RegLocation rlSrc,
112 int regLo, int regHi)
buzbee67bf8852011-08-17 17:51:35 -0700113{
114 oatClobber(cUnit, regLo);
115 oatClobber(cUnit, regHi);
116 oatMarkInUse(cUnit, regLo);
117 oatMarkInUse(cUnit, regHi);
118 loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
119}
120
buzbee31a4a6f2012-02-28 15:36:15 -0800121RegLocation loadValue(CompilationUnit* cUnit, RegLocation rlSrc,
122 RegisterClass opKind)
buzbee67bf8852011-08-17 17:51:35 -0700123{
124 rlSrc = oatEvalLoc(cUnit, rlSrc, opKind, false);
buzbeee1965672012-03-11 18:39:19 -0700125 if (rlSrc.location != kLocPhysReg) {
126 DCHECK((rlSrc.location == kLocDalvikFrame) ||
127 (rlSrc.location == kLocCompilerTemp));
buzbee67bf8852011-08-17 17:51:35 -0700128 loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
129 rlSrc.location = kLocPhysReg;
130 oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
131 }
132 return rlSrc;
133}
134
buzbee31a4a6f2012-02-28 15:36:15 -0800135void storeValue(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700136{
buzbee3d661942012-03-14 17:37:27 -0700137#ifndef NDEBUG
138 /*
139 * Sanity checking - should never try to store to the same
140 * ssa name during the compilation of a single instruction
141 * without an intervening oatClobberSReg().
142 */
143 DCHECK((cUnit->liveSReg == INVALID_SREG) ||
144 (rlDest.sRegLow != cUnit->liveSReg));
145 cUnit->liveSReg = rlDest.sRegLow;
146#endif
buzbee67bf8852011-08-17 17:51:35 -0700147 LIR* defStart;
148 LIR* defEnd;
buzbeeed3e9302011-09-23 17:34:19 -0700149 DCHECK(!rlDest.wide);
150 DCHECK(!rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700151 rlSrc = oatUpdateLoc(cUnit, rlSrc);
152 rlDest = oatUpdateLoc(cUnit, rlDest);
153 if (rlSrc.location == kLocPhysReg) {
154 if (oatIsLive(cUnit, rlSrc.lowReg) ||
buzbeeb29e4d12011-09-26 15:05:48 -0700155 oatIsPromoted(cUnit, rlSrc.lowReg) ||
buzbee67bf8852011-08-17 17:51:35 -0700156 (rlDest.location == kLocPhysReg)) {
buzbeeb29e4d12011-09-26 15:05:48 -0700157 // Src is live/promoted or Dest has assigned reg.
buzbee67bf8852011-08-17 17:51:35 -0700158 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
buzbee82488f52012-03-02 08:20:26 -0800159 opRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700160 } else {
161 // Just re-assign the registers. Dest gets Src's regs
162 rlDest.lowReg = rlSrc.lowReg;
163 oatClobber(cUnit, rlSrc.lowReg);
164 }
165 } else {
166 // Load Src either into promoted Dest or temps allocated for Dest
167 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
168 loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
169 }
170
171 // Dest is now live and dirty (until/if we flush it to home location)
172 oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
173 oatMarkDirty(cUnit, rlDest);
174
175
176 oatResetDefLoc(cUnit, rlDest);
177 if (oatIsDirty(cUnit, rlDest.lowReg) &&
178 oatLiveOut(cUnit, rlDest.sRegLow)) {
179 defStart = (LIR* )cUnit->lastLIRInsn;
buzbee67bc2362011-10-11 18:08:40 -0700180 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, rlDest.sRegLow),
181 rlDest.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700182 oatMarkClean(cUnit, rlDest);
183 defEnd = (LIR* )cUnit->lastLIRInsn;
184 oatMarkDef(cUnit, rlDest, defStart, defEnd);
185 }
186}
187
buzbee31a4a6f2012-02-28 15:36:15 -0800188RegLocation loadValueWide(CompilationUnit* cUnit, RegLocation rlSrc,
189 RegisterClass opKind)
buzbee67bf8852011-08-17 17:51:35 -0700190{
buzbeeed3e9302011-09-23 17:34:19 -0700191 DCHECK(rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700192 rlSrc = oatEvalLoc(cUnit, rlSrc, opKind, false);
buzbeee1965672012-03-11 18:39:19 -0700193 if (rlSrc.location != kLocPhysReg) {
194 DCHECK((rlSrc.location == kLocDalvikFrame) ||
195 (rlSrc.location == kLocCompilerTemp));
buzbee67bf8852011-08-17 17:51:35 -0700196 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
197 rlSrc.location = kLocPhysReg;
198 oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
199 oatMarkLive(cUnit, rlSrc.highReg,
200 oatSRegHi(rlSrc.sRegLow));
201 }
202 return rlSrc;
203}
204
buzbee31a4a6f2012-02-28 15:36:15 -0800205void storeValueWide(CompilationUnit* cUnit, RegLocation rlDest,
206 RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700207{
buzbee3d661942012-03-14 17:37:27 -0700208#ifndef NDEBUG
209 /*
210 * Sanity checking - should never try to store to the same
211 * ssa name during the compilation of a single instruction
212 * without an intervening oatClobberSReg().
213 */
214 DCHECK((cUnit->liveSReg == INVALID_SREG) ||
215 (rlDest.sRegLow != cUnit->liveSReg));
216 cUnit->liveSReg = rlDest.sRegLow;
217#endif
buzbee67bf8852011-08-17 17:51:35 -0700218 LIR* defStart;
219 LIR* defEnd;
buzbeeed3e9302011-09-23 17:34:19 -0700220 DCHECK_EQ(FPREG(rlSrc.lowReg), FPREG(rlSrc.highReg));
221 DCHECK(rlDest.wide);
222 DCHECK(rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700223 if (rlSrc.location == kLocPhysReg) {
224 if (oatIsLive(cUnit, rlSrc.lowReg) ||
225 oatIsLive(cUnit, rlSrc.highReg) ||
buzbeeb29e4d12011-09-26 15:05:48 -0700226 oatIsPromoted(cUnit, rlSrc.lowReg) ||
227 oatIsPromoted(cUnit, rlSrc.highReg) ||
buzbee67bf8852011-08-17 17:51:35 -0700228 (rlDest.location == kLocPhysReg)) {
buzbeeb29e4d12011-09-26 15:05:48 -0700229 // Src is live or promoted or Dest has assigned reg.
buzbee67bf8852011-08-17 17:51:35 -0700230 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
buzbee82488f52012-03-02 08:20:26 -0800231 opRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
buzbee67bf8852011-08-17 17:51:35 -0700232 rlSrc.lowReg, rlSrc.highReg);
233 } else {
234 // Just re-assign the registers. Dest gets Src's regs
235 rlDest.lowReg = rlSrc.lowReg;
236 rlDest.highReg = rlSrc.highReg;
237 oatClobber(cUnit, rlSrc.lowReg);
238 oatClobber(cUnit, rlSrc.highReg);
239 }
240 } else {
241 // Load Src either into promoted Dest or temps allocated for Dest
242 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
243 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
244 rlDest.highReg);
245 }
246
247 // Dest is now live and dirty (until/if we flush it to home location)
248 oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
249 oatMarkLive(cUnit, rlDest.highReg,
250 oatSRegHi(rlDest.sRegLow));
251 oatMarkDirty(cUnit, rlDest);
252 oatMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
253
254
255 oatResetDefLocWide(cUnit, rlDest);
256 if ((oatIsDirty(cUnit, rlDest.lowReg) ||
257 oatIsDirty(cUnit, rlDest.highReg)) &&
258 (oatLiveOut(cUnit, rlDest.sRegLow) ||
259 oatLiveOut(cUnit, oatSRegHi(rlDest.sRegLow)))) {
260 defStart = (LIR*)cUnit->lastLIRInsn;
buzbeee1965672012-03-11 18:39:19 -0700261 DCHECK_EQ((SRegToVReg(cUnit, rlDest.sRegLow)+1),
262 SRegToVReg(cUnit, oatSRegHi(rlDest.sRegLow)));
buzbee67bc2362011-10-11 18:08:40 -0700263 storeBaseDispWide(cUnit, rSP, oatSRegOffset(cUnit, rlDest.sRegLow),
buzbee67bf8852011-08-17 17:51:35 -0700264 rlDest.lowReg, rlDest.highReg);
265 oatMarkClean(cUnit, rlDest);
266 defEnd = (LIR*)cUnit->lastLIRInsn;
267 oatMarkDefWide(cUnit, rlDest, defStart, defEnd);
268 }
269}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800270
buzbee31a4a6f2012-02-28 15:36:15 -0800271/*
272 * Mark garbage collection card. Skip if the value we're storing is null.
273 */
274void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
275{
buzbeea7678db2012-03-05 15:35:46 -0800276#if defined(TARGET_X86)
277 UNIMPLEMENTED(WARNING) << "markGCCard";
278#else
buzbee31a4a6f2012-02-28 15:36:15 -0800279 int regCardBase = oatAllocTemp(cUnit);
280 int regCardNo = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800281 LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800282 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
283 regCardBase);
284 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
285 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
286 kUnsignedByte);
287 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800288 branchOver->target = (LIR*)target;
289 oatFreeTemp(cUnit, regCardBase);
290 oatFreeTemp(cUnit, regCardNo);
buzbeea7678db2012-03-05 15:35:46 -0800291#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800292}
293
buzbeee1965672012-03-11 18:39:19 -0700294/* Utilities to load the current Method* */
buzbee31a4a6f2012-02-28 15:36:15 -0800295void loadCurrMethodDirect(CompilationUnit *cUnit, int rTgt)
296{
buzbeee1965672012-03-11 18:39:19 -0700297 loadValueDirectFixed(cUnit, cUnit->regLocation[cUnit->methodSReg], rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800298}
299
buzbeee1965672012-03-11 18:39:19 -0700300RegLocation loadCurrMethod(CompilationUnit *cUnit)
buzbee31a4a6f2012-02-28 15:36:15 -0800301{
buzbeee1965672012-03-11 18:39:19 -0700302 return loadValue(cUnit, cUnit->regLocation[cUnit->methodSReg], kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800303}
304
buzbee9c044ce2012-03-18 13:24:07 -0700305bool methodStarInReg(CompilationUnit* cUnit)
306{
307 return (cUnit->regLocation[cUnit->methodSReg].location == kLocPhysReg);
308}
309
buzbee31a4a6f2012-02-28 15:36:15 -0800310
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800311} // namespace art