blob: e467ea0e9dcd721abf3e895f6393801e21509156 [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 {
buzbeeed3e9302011-09-23 17:34:19 -070068 DCHECK(rlSrc.location == kLocDalvikFrame);
buzbee67bc2362011-10-11 18:08:40 -070069 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, rlSrc.sRegLow), reg1);
buzbee67bf8852011-08-17 17:51:35 -070070 }
71}
72
73/*
74 * Similar to loadValueDirect, but clobbers and allocates the target
75 * register. Should be used when loading to a fixed register (for example,
76 * loading arguments to an out of line call.
77 */
buzbee31a4a6f2012-02-28 15:36:15 -080078void loadValueDirectFixed(CompilationUnit* cUnit, RegLocation rlSrc, int reg1)
buzbee67bf8852011-08-17 17:51:35 -070079{
80 oatClobber(cUnit, reg1);
81 oatMarkInUse(cUnit, reg1);
82 loadValueDirect(cUnit, rlSrc, reg1);
83}
84
85/*
86 * Load a Dalvik register pair into a physical register[s]. Take care when
87 * using this routine, as it doesn't perform any bookkeeping regarding
88 * register liveness. That is the responsibility of the caller.
89 */
buzbee31a4a6f2012-02-28 15:36:15 -080090void loadValueDirectWide(CompilationUnit* cUnit, RegLocation rlSrc, int regLo,
91 int regHi)
buzbee67bf8852011-08-17 17:51:35 -070092{
93 rlSrc = oatUpdateLocWide(cUnit, rlSrc);
94 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -080095 opRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
buzbee67bf8852011-08-17 17:51:35 -070096 } else {
buzbeeed3e9302011-09-23 17:34:19 -070097 DCHECK(rlSrc.location == kLocDalvikFrame);
buzbee67bc2362011-10-11 18:08:40 -070098 loadBaseDispWide(cUnit, NULL, rSP,
99 oatSRegOffset(cUnit, rlSrc.sRegLow),
buzbee67bf8852011-08-17 17:51:35 -0700100 regLo, regHi, INVALID_SREG);
101 }
102}
103
104/*
105 * Similar to loadValueDirect, but clobbers and allocates the target
106 * registers. Should be used when loading to a fixed registers (for example,
107 * loading arguments to an out of line call.
108 */
buzbee31a4a6f2012-02-28 15:36:15 -0800109void loadValueDirectWideFixed(CompilationUnit* cUnit, RegLocation rlSrc,
110 int regLo, int regHi)
buzbee67bf8852011-08-17 17:51:35 -0700111{
112 oatClobber(cUnit, regLo);
113 oatClobber(cUnit, regHi);
114 oatMarkInUse(cUnit, regLo);
115 oatMarkInUse(cUnit, regHi);
116 loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
117}
118
buzbee31a4a6f2012-02-28 15:36:15 -0800119RegLocation loadValue(CompilationUnit* cUnit, RegLocation rlSrc,
120 RegisterClass opKind)
buzbee67bf8852011-08-17 17:51:35 -0700121{
122 rlSrc = oatEvalLoc(cUnit, rlSrc, opKind, false);
123 if (rlSrc.location == kLocDalvikFrame) {
124 loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
125 rlSrc.location = kLocPhysReg;
126 oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
127 }
128 return rlSrc;
129}
130
buzbee31a4a6f2012-02-28 15:36:15 -0800131void storeValue(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700132{
133 LIR* defStart;
134 LIR* defEnd;
buzbeeed3e9302011-09-23 17:34:19 -0700135 DCHECK(!rlDest.wide);
136 DCHECK(!rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700137 rlSrc = oatUpdateLoc(cUnit, rlSrc);
138 rlDest = oatUpdateLoc(cUnit, rlDest);
139 if (rlSrc.location == kLocPhysReg) {
140 if (oatIsLive(cUnit, rlSrc.lowReg) ||
buzbeeb29e4d12011-09-26 15:05:48 -0700141 oatIsPromoted(cUnit, rlSrc.lowReg) ||
buzbee67bf8852011-08-17 17:51:35 -0700142 (rlDest.location == kLocPhysReg)) {
buzbeeb29e4d12011-09-26 15:05:48 -0700143 // Src is live/promoted or Dest has assigned reg.
buzbee67bf8852011-08-17 17:51:35 -0700144 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
buzbee82488f52012-03-02 08:20:26 -0800145 opRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700146 } else {
147 // Just re-assign the registers. Dest gets Src's regs
148 rlDest.lowReg = rlSrc.lowReg;
149 oatClobber(cUnit, rlSrc.lowReg);
150 }
151 } else {
152 // Load Src either into promoted Dest or temps allocated for Dest
153 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
154 loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
155 }
156
157 // Dest is now live and dirty (until/if we flush it to home location)
158 oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
159 oatMarkDirty(cUnit, rlDest);
160
161
162 oatResetDefLoc(cUnit, rlDest);
163 if (oatIsDirty(cUnit, rlDest.lowReg) &&
164 oatLiveOut(cUnit, rlDest.sRegLow)) {
165 defStart = (LIR* )cUnit->lastLIRInsn;
buzbee67bc2362011-10-11 18:08:40 -0700166 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, rlDest.sRegLow),
167 rlDest.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700168 oatMarkClean(cUnit, rlDest);
169 defEnd = (LIR* )cUnit->lastLIRInsn;
170 oatMarkDef(cUnit, rlDest, defStart, defEnd);
171 }
172}
173
buzbee31a4a6f2012-02-28 15:36:15 -0800174RegLocation loadValueWide(CompilationUnit* cUnit, RegLocation rlSrc,
175 RegisterClass opKind)
buzbee67bf8852011-08-17 17:51:35 -0700176{
buzbeeed3e9302011-09-23 17:34:19 -0700177 DCHECK(rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700178 rlSrc = oatEvalLoc(cUnit, rlSrc, opKind, false);
179 if (rlSrc.location == kLocDalvikFrame) {
180 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
181 rlSrc.location = kLocPhysReg;
182 oatMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
183 oatMarkLive(cUnit, rlSrc.highReg,
184 oatSRegHi(rlSrc.sRegLow));
185 }
186 return rlSrc;
187}
188
buzbee31a4a6f2012-02-28 15:36:15 -0800189void storeValueWide(CompilationUnit* cUnit, RegLocation rlDest,
190 RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700191{
192 LIR* defStart;
193 LIR* defEnd;
buzbeeed3e9302011-09-23 17:34:19 -0700194 DCHECK_EQ(FPREG(rlSrc.lowReg), FPREG(rlSrc.highReg));
195 DCHECK(rlDest.wide);
196 DCHECK(rlSrc.wide);
buzbee67bf8852011-08-17 17:51:35 -0700197 if (rlSrc.location == kLocPhysReg) {
198 if (oatIsLive(cUnit, rlSrc.lowReg) ||
199 oatIsLive(cUnit, rlSrc.highReg) ||
buzbeeb29e4d12011-09-26 15:05:48 -0700200 oatIsPromoted(cUnit, rlSrc.lowReg) ||
201 oatIsPromoted(cUnit, rlSrc.highReg) ||
buzbee67bf8852011-08-17 17:51:35 -0700202 (rlDest.location == kLocPhysReg)) {
buzbeeb29e4d12011-09-26 15:05:48 -0700203 // Src is live or promoted or Dest has assigned reg.
buzbee67bf8852011-08-17 17:51:35 -0700204 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
buzbee82488f52012-03-02 08:20:26 -0800205 opRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
buzbee67bf8852011-08-17 17:51:35 -0700206 rlSrc.lowReg, rlSrc.highReg);
207 } else {
208 // Just re-assign the registers. Dest gets Src's regs
209 rlDest.lowReg = rlSrc.lowReg;
210 rlDest.highReg = rlSrc.highReg;
211 oatClobber(cUnit, rlSrc.lowReg);
212 oatClobber(cUnit, rlSrc.highReg);
213 }
214 } else {
215 // Load Src either into promoted Dest or temps allocated for Dest
216 rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
217 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
218 rlDest.highReg);
219 }
220
221 // Dest is now live and dirty (until/if we flush it to home location)
222 oatMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
223 oatMarkLive(cUnit, rlDest.highReg,
224 oatSRegHi(rlDest.sRegLow));
225 oatMarkDirty(cUnit, rlDest);
226 oatMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
227
228
229 oatResetDefLocWide(cUnit, rlDest);
230 if ((oatIsDirty(cUnit, rlDest.lowReg) ||
231 oatIsDirty(cUnit, rlDest.highReg)) &&
232 (oatLiveOut(cUnit, rlDest.sRegLow) ||
233 oatLiveOut(cUnit, oatSRegHi(rlDest.sRegLow)))) {
234 defStart = (LIR*)cUnit->lastLIRInsn;
buzbeeed3e9302011-09-23 17:34:19 -0700235 DCHECK_EQ((oatS2VReg(cUnit, rlDest.sRegLow)+1),
buzbee67bf8852011-08-17 17:51:35 -0700236 oatS2VReg(cUnit, oatSRegHi(rlDest.sRegLow)));
buzbee67bc2362011-10-11 18:08:40 -0700237 storeBaseDispWide(cUnit, rSP, oatSRegOffset(cUnit, rlDest.sRegLow),
buzbee67bf8852011-08-17 17:51:35 -0700238 rlDest.lowReg, rlDest.highReg);
239 oatMarkClean(cUnit, rlDest);
240 defEnd = (LIR*)cUnit->lastLIRInsn;
241 oatMarkDefWide(cUnit, rlDest, defStart, defEnd);
242 }
243}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800244
buzbee31a4a6f2012-02-28 15:36:15 -0800245/*
246 * Mark garbage collection card. Skip if the value we're storing is null.
247 */
248void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
249{
250 int regCardBase = oatAllocTemp(cUnit);
251 int regCardNo = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800252 LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800253 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
254 regCardBase);
255 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
256 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
257 kUnsignedByte);
258 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800259 branchOver->target = (LIR*)target;
260 oatFreeTemp(cUnit, regCardBase);
261 oatFreeTemp(cUnit, regCardNo);
262}
263
264/*
265 * Utiltiy to load the current Method*. Broken out
266 * to allow easy change between placing the current Method* in a
267 * dedicated register or its home location in the frame.
268 */
269void loadCurrMethodDirect(CompilationUnit *cUnit, int rTgt)
270{
271#if defined(METHOD_IN_REG)
buzbee82488f52012-03-02 08:20:26 -0800272 opRegCopy(cUnit, rTgt, rMETHOD);
buzbee31a4a6f2012-02-28 15:36:15 -0800273#else
274 loadWordDisp(cUnit, rSP, 0, rTgt);
275#endif
276}
277
278int loadCurrMethod(CompilationUnit *cUnit)
279{
280#if defined(METHOD_IN_REG)
281 return rMETHOD;
282#else
283 int mReg = oatAllocTemp(cUnit);
284 loadCurrMethodDirect(cUnit, mReg);
285 return mReg;
286#endif
287}
288
289
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800290} // namespace art