blob: 5444816ddf43cd266d534b4bccd3b0de12318ee1 [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 */
buzbee31a4a6f2012-02-28 15:36:15 -080062void loadValueDirect(CompilationUnit* cUnit, RegLocation rlSrc, int reg1)
buzbee67bf8852011-08-17 17:51:35 -070063{
64 rlSrc = oatUpdateLoc(cUnit, rlSrc);
65 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -080066 opRegCopy(cUnit, reg1, 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));
buzbee67bc2362011-10-11 18:08:40 -070070 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, rlSrc.sRegLow), reg1);
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 */
buzbee31a4a6f2012-02-28 15:36:15 -080079void loadValueDirectFixed(CompilationUnit* cUnit, RegLocation rlSrc, int reg1)
buzbee67bf8852011-08-17 17:51:35 -070080{
81 oatClobber(cUnit, reg1);
82 oatMarkInUse(cUnit, reg1);
83 loadValueDirect(cUnit, rlSrc, reg1);
84}
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{
137 LIR* defStart;
138 LIR* defEnd;
buzbeeed3e9302011-09-23 17:34:19 -0700139 DCHECK(!rlDest.wide);
140 DCHECK(!rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700141 rlSrc = oatUpdateLoc(cUnit, rlSrc);
142 rlDest = oatUpdateLoc(cUnit, rlDest);
143 if (rlSrc.location == kLocPhysReg) {
144 if (oatIsLive(cUnit, rlSrc.lowReg) ||
buzbeeb29e4d12011-09-26 15:05:48 -0700145 oatIsPromoted(cUnit, rlSrc.lowReg) ||
buzbee67bf8852011-08-17 17:51:35 -0700146 (rlDest.location == kLocPhysReg)) {
buzbeeb29e4d12011-09-26 15:05:48 -0700147 // Src is live/promoted or Dest has assigned reg.
buzbee67bf8852011-08-17 17:51:35 -0700148 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
buzbee82488f52012-03-02 08:20:26 -0800149 opRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700150 } else {
151 // Just re-assign the registers. Dest gets Src's regs
152 rlDest.lowReg = rlSrc.lowReg;
153 oatClobber(cUnit, rlSrc.lowReg);
154 }
155 } else {
156 // Load Src either into promoted Dest or temps allocated for Dest
157 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
158 loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
159 }
160
161 // Dest is now live and dirty (until/if we flush it to home location)
162 oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
163 oatMarkDirty(cUnit, rlDest);
164
165
166 oatResetDefLoc(cUnit, rlDest);
167 if (oatIsDirty(cUnit, rlDest.lowReg) &&
168 oatLiveOut(cUnit, rlDest.sRegLow)) {
169 defStart = (LIR* )cUnit->lastLIRInsn;
buzbee67bc2362011-10-11 18:08:40 -0700170 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, rlDest.sRegLow),
171 rlDest.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700172 oatMarkClean(cUnit, rlDest);
173 defEnd = (LIR* )cUnit->lastLIRInsn;
174 oatMarkDef(cUnit, rlDest, defStart, defEnd);
175 }
176}
177
buzbee31a4a6f2012-02-28 15:36:15 -0800178RegLocation loadValueWide(CompilationUnit* cUnit, RegLocation rlSrc,
179 RegisterClass opKind)
buzbee67bf8852011-08-17 17:51:35 -0700180{
buzbeeed3e9302011-09-23 17:34:19 -0700181 DCHECK(rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700182 rlSrc = oatEvalLoc(cUnit, rlSrc, opKind, false);
buzbeee1965672012-03-11 18:39:19 -0700183 if (rlSrc.location != kLocPhysReg) {
184 DCHECK((rlSrc.location == kLocDalvikFrame) ||
185 (rlSrc.location == kLocCompilerTemp));
buzbee67bf8852011-08-17 17:51:35 -0700186 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
187 rlSrc.location = kLocPhysReg;
188 oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
189 oatMarkLive(cUnit, rlSrc.highReg,
190 oatSRegHi(rlSrc.sRegLow));
191 }
192 return rlSrc;
193}
194
buzbee31a4a6f2012-02-28 15:36:15 -0800195void storeValueWide(CompilationUnit* cUnit, RegLocation rlDest,
196 RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700197{
198 LIR* defStart;
199 LIR* defEnd;
buzbeeed3e9302011-09-23 17:34:19 -0700200 DCHECK_EQ(FPREG(rlSrc.lowReg), FPREG(rlSrc.highReg));
201 DCHECK(rlDest.wide);
202 DCHECK(rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700203 if (rlSrc.location == kLocPhysReg) {
204 if (oatIsLive(cUnit, rlSrc.lowReg) ||
205 oatIsLive(cUnit, rlSrc.highReg) ||
buzbeeb29e4d12011-09-26 15:05:48 -0700206 oatIsPromoted(cUnit, rlSrc.lowReg) ||
207 oatIsPromoted(cUnit, rlSrc.highReg) ||
buzbee67bf8852011-08-17 17:51:35 -0700208 (rlDest.location == kLocPhysReg)) {
buzbeeb29e4d12011-09-26 15:05:48 -0700209 // Src is live or promoted or Dest has assigned reg.
buzbee67bf8852011-08-17 17:51:35 -0700210 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
buzbee82488f52012-03-02 08:20:26 -0800211 opRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
buzbee67bf8852011-08-17 17:51:35 -0700212 rlSrc.lowReg, rlSrc.highReg);
213 } else {
214 // Just re-assign the registers. Dest gets Src's regs
215 rlDest.lowReg = rlSrc.lowReg;
216 rlDest.highReg = rlSrc.highReg;
217 oatClobber(cUnit, rlSrc.lowReg);
218 oatClobber(cUnit, rlSrc.highReg);
219 }
220 } else {
221 // Load Src either into promoted Dest or temps allocated for Dest
222 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
223 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
224 rlDest.highReg);
225 }
226
227 // Dest is now live and dirty (until/if we flush it to home location)
228 oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
229 oatMarkLive(cUnit, rlDest.highReg,
230 oatSRegHi(rlDest.sRegLow));
231 oatMarkDirty(cUnit, rlDest);
232 oatMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
233
234
235 oatResetDefLocWide(cUnit, rlDest);
236 if ((oatIsDirty(cUnit, rlDest.lowReg) ||
237 oatIsDirty(cUnit, rlDest.highReg)) &&
238 (oatLiveOut(cUnit, rlDest.sRegLow) ||
239 oatLiveOut(cUnit, oatSRegHi(rlDest.sRegLow)))) {
240 defStart = (LIR*)cUnit->lastLIRInsn;
buzbeee1965672012-03-11 18:39:19 -0700241 DCHECK_EQ((SRegToVReg(cUnit, rlDest.sRegLow)+1),
242 SRegToVReg(cUnit, oatSRegHi(rlDest.sRegLow)));
buzbee67bc2362011-10-11 18:08:40 -0700243 storeBaseDispWide(cUnit, rSP, oatSRegOffset(cUnit, rlDest.sRegLow),
buzbee67bf8852011-08-17 17:51:35 -0700244 rlDest.lowReg, rlDest.highReg);
245 oatMarkClean(cUnit, rlDest);
246 defEnd = (LIR*)cUnit->lastLIRInsn;
247 oatMarkDefWide(cUnit, rlDest, defStart, defEnd);
248 }
249}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800250
buzbee31a4a6f2012-02-28 15:36:15 -0800251/*
252 * Mark garbage collection card. Skip if the value we're storing is null.
253 */
254void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
255{
buzbeea7678db2012-03-05 15:35:46 -0800256#if defined(TARGET_X86)
257 UNIMPLEMENTED(WARNING) << "markGCCard";
258#else
buzbee31a4a6f2012-02-28 15:36:15 -0800259 int regCardBase = oatAllocTemp(cUnit);
260 int regCardNo = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800261 LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800262 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
263 regCardBase);
264 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
265 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
266 kUnsignedByte);
267 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800268 branchOver->target = (LIR*)target;
269 oatFreeTemp(cUnit, regCardBase);
270 oatFreeTemp(cUnit, regCardNo);
buzbeea7678db2012-03-05 15:35:46 -0800271#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800272}
273
buzbeee1965672012-03-11 18:39:19 -0700274/* Utilities to load the current Method* */
buzbee31a4a6f2012-02-28 15:36:15 -0800275void loadCurrMethodDirect(CompilationUnit *cUnit, int rTgt)
276{
buzbeee1965672012-03-11 18:39:19 -0700277 loadValueDirectFixed(cUnit, cUnit->regLocation[cUnit->methodSReg], rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800278}
279
buzbeee1965672012-03-11 18:39:19 -0700280RegLocation loadCurrMethod(CompilationUnit *cUnit)
buzbee31a4a6f2012-02-28 15:36:15 -0800281{
buzbeee1965672012-03-11 18:39:19 -0700282 return loadValue(cUnit, cUnit->regLocation[cUnit->methodSReg], kCoreReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800283}
284
285
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800286} // namespace art