1 /*
2 * Copyright (C) 2009 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
17 /*
18 * This file contains codegen and support common to all supported
19 * Mips variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
27
28 /* Load a word at base + displacement. Displacement must be word multiple */
loadWordDisp(CompilationUnit * cUnit,int rBase,int displacement,int rDest)29 static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
30 int rDest)
31 {
32 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
33 INVALID_SREG);
34 }
35
storeWordDisp(CompilationUnit * cUnit,int rBase,int displacement,int rSrc)36 static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
37 int displacement, int rSrc)
38 {
39 return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
40 }
41
42 /*
43 * Load a Dalvik register into a physical register. Take care when
44 * using this routine, as it doesn't perform any bookkeeping regarding
45 * register liveness. That is the responsibility of the caller.
46 */
loadValueDirect(CompilationUnit * cUnit,RegLocation rlSrc,int reg1)47 static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
48 int reg1)
49 {
50 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
51 if (rlSrc.location == kLocPhysReg) {
52 genRegCopy(cUnit, reg1, rlSrc.lowReg);
53 } else if (rlSrc.location == kLocRetval) {
54 loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1);
55 } else {
56 assert(rlSrc.location == kLocDalvikFrame);
57 loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
58 reg1);
59 }
60 }
61
62 /*
63 * Similar to loadValueDirect, but clobbers and allocates the target
64 * register. Should be used when loading to a fixed register (for example,
65 * loading arguments to an out of line call.
66 */
loadValueDirectFixed(CompilationUnit * cUnit,RegLocation rlSrc,int reg1)67 static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
68 int reg1)
69 {
70 dvmCompilerClobber(cUnit, reg1);
71 dvmCompilerMarkInUse(cUnit, reg1);
72 loadValueDirect(cUnit, rlSrc, reg1);
73 }
74
75 /*
76 * Load a Dalvik register pair into a physical register[s]. Take care when
77 * using this routine, as it doesn't perform any bookkeeping regarding
78 * register liveness. That is the responsibility of the caller.
79 */
loadValueDirectWide(CompilationUnit * cUnit,RegLocation rlSrc,int regLo,int regHi)80 static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
81 int regLo, int regHi)
82 {
83 rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
84 if (rlSrc.location == kLocPhysReg) {
85 genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
86 } else if (rlSrc.location == kLocRetval) {
87 loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
88 regLo, regHi, INVALID_SREG);
89 } else {
90 assert(rlSrc.location == kLocDalvikFrame);
91 loadBaseDispWide(cUnit, NULL, rFP,
92 dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
93 regLo, regHi, INVALID_SREG);
94 }
95 }
96
97 /*
98 * Similar to loadValueDirect, but clobbers and allocates the target
99 * registers. Should be used when loading to a fixed registers (for example,
100 * loading arguments to an out of line call.
101 */
loadValueDirectWideFixed(CompilationUnit * cUnit,RegLocation rlSrc,int regLo,int regHi)102 static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
103 int regLo, int regHi)
104 {
105 dvmCompilerClobber(cUnit, regLo);
106 dvmCompilerClobber(cUnit, regHi);
107 dvmCompilerMarkInUse(cUnit, regLo);
108 dvmCompilerMarkInUse(cUnit, regHi);
109 loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
110 }
111
loadValue(CompilationUnit * cUnit,RegLocation rlSrc,RegisterClass opKind)112 static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
113 RegisterClass opKind)
114 {
115 rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
116 if (rlSrc.location == kLocDalvikFrame) {
117 loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
118 rlSrc.location = kLocPhysReg;
119 dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
120 } else if (rlSrc.location == kLocRetval) {
121 loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), rlSrc.lowReg);
122 rlSrc.location = kLocPhysReg;
123 dvmCompilerClobber(cUnit, rlSrc.lowReg);
124 }
125 return rlSrc;
126 }
127
storeValue(CompilationUnit * cUnit,RegLocation rlDest,RegLocation rlSrc)128 static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
129 RegLocation rlSrc)
130 {
131 LIR *defStart;
132 LIR *defEnd;
133 assert(!rlDest.wide);
134 assert(!rlSrc.wide);
135 dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
136 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
137 rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
138 if (rlSrc.location == kLocPhysReg) {
139 if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
140 (rlDest.location == kLocPhysReg)) {
141 // Src is live or Dest has assigned reg.
142 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
143 genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
144 } else {
145 // Just re-assign the registers. Dest gets Src's regs
146 rlDest.lowReg = rlSrc.lowReg;
147 dvmCompilerClobber(cUnit, rlSrc.lowReg);
148 }
149 } else {
150 // Load Src either into promoted Dest or temps allocated for Dest
151 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
152 loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
153 }
154
155 // Dest is now live and dirty (until/if we flush it to home location)
156 dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
157 dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
158
159
160 if (rlDest.location == kLocRetval) {
161 storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
162 rlDest.lowReg, kWord);
163 dvmCompilerClobber(cUnit, rlDest.lowReg);
164 } else {
165 dvmCompilerResetDefLoc(cUnit, rlDest);
166 if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
167 defStart = (LIR *)cUnit->lastLIRInsn;
168 int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
169 storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
170 dvmCompilerMarkClean(cUnit, rlDest.lowReg);
171 defEnd = (LIR *)cUnit->lastLIRInsn;
172 dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
173 }
174 }
175 }
176
loadValueWide(CompilationUnit * cUnit,RegLocation rlSrc,RegisterClass opKind)177 static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
178 RegisterClass opKind)
179 {
180 assert(rlSrc.wide);
181 rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
182 if (rlSrc.location == kLocDalvikFrame) {
183 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
184 rlSrc.location = kLocPhysReg;
185 dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
186 dvmCompilerMarkLive(cUnit, rlSrc.highReg,
187 dvmCompilerSRegHi(rlSrc.sRegLow));
188 } else if (rlSrc.location == kLocRetval) {
189 loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
190 rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
191 rlSrc.location = kLocPhysReg;
192 dvmCompilerClobber(cUnit, rlSrc.lowReg);
193 dvmCompilerClobber(cUnit, rlSrc.highReg);
194 }
195 return rlSrc;
196 }
197
storeValueWide(CompilationUnit * cUnit,RegLocation rlDest,RegLocation rlSrc)198 static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
199 RegLocation rlSrc)
200 {
201 LIR *defStart;
202 LIR *defEnd;
203 assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
204 assert(rlDest.wide);
205 assert(rlSrc.wide);
206 dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
207 if (rlSrc.location == kLocPhysReg) {
208 if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
209 dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
210 (rlDest.location == kLocPhysReg)) {
211 // Src is live or Dest has assigned reg.
212 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
213 genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
214 rlSrc.lowReg, rlSrc.highReg);
215 } else {
216 // Just re-assign the registers. Dest gets Src's regs
217 rlDest.lowReg = rlSrc.lowReg;
218 rlDest.highReg = rlSrc.highReg;
219 dvmCompilerClobber(cUnit, rlSrc.lowReg);
220 dvmCompilerClobber(cUnit, rlSrc.highReg);
221 }
222 } else {
223 // Load Src either into promoted Dest or temps allocated for Dest
224 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
225 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
226 rlDest.highReg);
227 }
228
229 // Dest is now live and dirty (until/if we flush it to home location)
230 dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
231 dvmCompilerMarkLive(cUnit, rlDest.highReg,
232 dvmCompilerSRegHi(rlDest.sRegLow));
233 dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
234 dvmCompilerMarkDirty(cUnit, rlDest.highReg);
235 dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
236
237
238 if (rlDest.location == kLocRetval) {
239 storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval),
240 rlDest.lowReg, rlDest.highReg);
241 dvmCompilerClobber(cUnit, rlDest.lowReg);
242 dvmCompilerClobber(cUnit, rlDest.highReg);
243 } else {
244 dvmCompilerResetDefLocWide(cUnit, rlDest);
245 if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
246 dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
247 defStart = (LIR *)cUnit->lastLIRInsn;
248 int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
249 assert((vReg+1) == dvmCompilerS2VReg(cUnit,
250 dvmCompilerSRegHi(rlDest.sRegLow)));
251 storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
252 rlDest.highReg);
253 dvmCompilerMarkClean(cUnit, rlDest.lowReg);
254 dvmCompilerMarkClean(cUnit, rlDest.highReg);
255 defEnd = (LIR *)cUnit->lastLIRInsn;
256 dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
257 }
258 }
259 }
260 /*
261 * Perform null-check on a register. sReg is the ssa register being checked,
262 * and mReg is the machine register holding the actual value. If internal state
263 * indicates that sReg has been checked before the check request is ignored.
264 */
genNullCheck(CompilationUnit * cUnit,int sReg,int mReg,int dOffset,MipsLIR * pcrLabel)265 static MipsLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
266 int dOffset, MipsLIR *pcrLabel)
267 {
268 /* This particular Dalvik register has been null-checked */
269 if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
270 return pcrLabel;
271 }
272 dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
273 return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
274 }
275
276
277
278 /*
279 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
280 * satisfies.
281 */
genRegRegCheck(CompilationUnit * cUnit,MipsConditionCode cond,int reg1,int reg2,int dOffset,MipsLIR * pcrLabel)282 static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
283 MipsConditionCode cond,
284 int reg1, int reg2, int dOffset,
285 MipsLIR *pcrLabel)
286 {
287 MipsLIR *res = NULL;
288 if (cond == kMipsCondGe) { /* signed >= case */
289 int tReg = dvmCompilerAllocTemp(cUnit);
290 res = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
291 MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
292 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
293 } else if (cond == kMipsCondCs) { /* unsigned >= case */
294 int tReg = dvmCompilerAllocTemp(cUnit);
295 res = newLIR3(cUnit, kMipsSltu, tReg, reg1, reg2);
296 MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
297 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
298 } else {
299 ALOGE("Unexpected condition in genRegRegCheck: %d\n", (int) cond);
300 dvmAbort();
301 }
302 return res;
303 }
304
305 /*
306 * Perform zero-check on a register. Similar to genNullCheck but the value being
307 * checked does not have a corresponding Dalvik register.
308 */
genZeroCheck(CompilationUnit * cUnit,int mReg,int dOffset,MipsLIR * pcrLabel)309 static MipsLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
310 int dOffset, MipsLIR *pcrLabel)
311 {
312 return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
313 }
314
315 /* Perform bound check on two registers */
genBoundsCheck(CompilationUnit * cUnit,int rIndex,int rBound,int dOffset,MipsLIR * pcrLabel)316 static MipsLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
317 int rBound, int dOffset, MipsLIR *pcrLabel)
318 {
319 return genRegRegCheck(cUnit, kMipsCondCs, rIndex, rBound, dOffset,
320 pcrLabel);
321 }
322
323 /*
324 * Jump to the out-of-line handler to finish executing the
325 * remaining of more complex instructions.
326 */
genDispatchToHandler(CompilationUnit * cUnit,TemplateOpcode opCode)327 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opCode)
328 {
329 /*
330 * We're jumping from a trace to a template. Using jal is preferable to jalr,
331 * but we need to ensure source and target addresses allow the use of jal.
332 * This should almost always be the case, but if source and target are in
333 * different 256mb regions then use jalr. The test below is very conservative
334 * since we don't have a source address yet, but this is ok for now given that
335 * we expect this case to be very rare. The test can be made less conservative
336 * as needed in the future in coordination with address assignment during
337 * the assembly process.
338 */
339 dvmCompilerClobberHandlerRegs(cUnit);
340 int targetAddr = (int) gDvmJit.codeCache + templateEntryOffsets[opCode];
341 int maxSourceAddr = (int) gDvmJit.codeCache + gDvmJit.codeCacheSize;
342
343 if ((targetAddr & 0xF0000000) == (maxSourceAddr & 0xF0000000)) {
344 newLIR1(cUnit, kMipsJal, targetAddr);
345 } else {
346 loadConstant(cUnit, r_T9, targetAddr);
347 newLIR2(cUnit, kMipsJalr, r_RA, r_T9);
348 }
349 }
350