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 for the Thumb ISA and is intended to be
19 * includes by:and support common to all supported
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25 #include "Codegen.h"
26
27 /* Routines which must be supplied here */
28 static void loadConstant(CompilationUnit *cUnit, int rDest, int value);
29 static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr);
30 static void genConditionalBranch(CompilationUnit *cUnit,
31 ArmConditionCode cond,
32 ArmLIR *target);
33 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target);
34 static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
35 int rDestHi);
36 static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
37 int vDest, int rScratch);
38 static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int vDest);
39 static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest);
40 static void loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
41 int rDest);
42 static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
43 int rScratch);
44 static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
45 ArmConditionCode cond, int reg,
46 int checkValue, int dOffset,
47 ArmLIR *pcrLabel);
48 ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
49
50 /*****************************************************************************/
51
52 /*
53 * Support for register allocation
54 */
55
56 /* non-existent register */
57 #define vNone (-1)
58
59 /* get the next register in r0..r3 in a round-robin fashion */
60 #define NEXT_REG(reg) ((reg + 1) & 3)
61 /*
62 * The following are utility routines to help maintain the RegisterScoreboard
63 * state to facilitate register renaming.
64 */
65
66 /* Reset the tracker to unknown state */
resetRegisterScoreboard(CompilationUnit * cUnit)67 static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
68 {
69 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
70
71 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
72 registerScoreboard->liveDalvikReg = vNone;
73 registerScoreboard->nativeReg = vNone;
74 registerScoreboard->nativeRegHi = vNone;
75 }
76
77 /* Kill the corresponding bit in the null-checked register list */
killNullCheckedRegister(CompilationUnit * cUnit,int vReg)78 static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
79 {
80 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
81 }
82
83 /* The Dalvik register pair held in native registers have changed */
updateLiveRegisterPair(CompilationUnit * cUnit,int vReg,int mRegLo,int mRegHi)84 static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
85 int vReg, int mRegLo, int mRegHi)
86 {
87 cUnit->registerScoreboard.liveDalvikReg = vReg;
88 cUnit->registerScoreboard.nativeReg = mRegLo;
89 cUnit->registerScoreboard.nativeRegHi = mRegHi;
90 cUnit->registerScoreboard.isWide = true;
91 }
92
93 /* The Dalvik register held in a native register has changed */
updateLiveRegister(CompilationUnit * cUnit,int vReg,int mReg)94 static inline void updateLiveRegister(CompilationUnit *cUnit,
95 int vReg, int mReg)
96 {
97 cUnit->registerScoreboard.liveDalvikReg = vReg;
98 cUnit->registerScoreboard.nativeReg = mReg;
99 cUnit->registerScoreboard.isWide = false;
100 }
101
102 /*
103 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
104 * the lifetime of cached Dalvik value in a native register.
105 */
selectFirstRegister(CompilationUnit * cUnit,int vSrc,bool isWide)106 static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
107 bool isWide)
108 {
109 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
110
111 /* No live value - suggest to use r0 */
112 if (registerScoreboard->liveDalvikReg == vNone)
113 return r0;
114
115 /* Reuse the previously used native reg */
116 if (registerScoreboard->liveDalvikReg == vSrc) {
117 if (isWide != true) {
118 return registerScoreboard->nativeReg;
119 } else {
120 /* Return either r0 or r2 */
121 return (registerScoreboard->nativeReg + 1) & 2;
122 }
123 }
124
125 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
126 if (isWide) {
127 return (registerScoreboard->nativeReg + 2) & 2;
128 } else {
129 return (registerScoreboard->nativeReg + 1) & 3;
130 }
131
132 }
133
134 /*****************************************************************************/
135
dvmCompilerRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)136 ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
137 {
138 ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
139 assert(LOWREG(rDest) && LOWREG(rSrc));
140 res->operands[0] = rDest;
141 res->operands[1] = rSrc;
142 res->opCode = THUMB_MOV_RR;
143 if (rDest == rSrc) {
144 res->isNop = true;
145 }
146 return res;
147 }
148
149 /*
150 * Load a immediate using a shortcut if possible; otherwise
151 * grab from the per-translation literal pool
152 */
loadConstant(CompilationUnit * cUnit,int rDest,int value)153 static void loadConstant(CompilationUnit *cUnit, int rDest, int value)
154 {
155 /* See if the value can be constructed cheaply */
156 if ((value >= 0) && (value <= 255)) {
157 newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
158 return;
159 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
160 newLIR2(cUnit, THUMB_MOV_IMM, rDest, ~value);
161 newLIR2(cUnit, THUMB_MVN, rDest, rDest);
162 return;
163 }
164 /* No shortcut - go ahead and use literal pool */
165 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
166 if (dataTarget == NULL) {
167 dataTarget = addWordData(cUnit, value, false);
168 }
169 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
170 loadPcRel->opCode = THUMB_LDR_PC_REL;
171 loadPcRel->generic.target = (LIR *) dataTarget;
172 loadPcRel->operands[0] = rDest;
173 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
174
175 /*
176 * To save space in the constant pool, we use the ADD_RRI8 instruction to
177 * add up to 255 to an existing constant value.
178 */
179 if (dataTarget->operands[0] != value) {
180 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
181 }
182 }
183
184 /* Export the Dalvik PC assicated with an instruction to the StackSave area */
genExportPC(CompilationUnit * cUnit,MIR * mir,int rDPC,int rAddr)185 static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr)
186 {
187 int offset = offsetof(StackSaveArea, xtra.currentPc);
188 loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
189 newLIR2(cUnit, THUMB_MOV_RR, rAddr, rFP);
190 newLIR2(cUnit, THUMB_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
191 newLIR3(cUnit, THUMB_STR_RRI5, rDPC, rAddr, 0);
192 }
193
194 /* Generate conditional branch instructions */
genConditionalBranch(CompilationUnit * cUnit,ArmConditionCode cond,ArmLIR * target)195 static void genConditionalBranch(CompilationUnit *cUnit,
196 ArmConditionCode cond,
197 ArmLIR *target)
198 {
199 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
200 branch->generic.target = (LIR *) target;
201 }
202
203 /* Generate unconditional branch instructions */
genUnconditionalBranch(CompilationUnit * cUnit,ArmLIR * target)204 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
205 {
206 ArmLIR *branch = newLIR0(cUnit, THUMB_B_UNCOND);
207 branch->generic.target = (LIR *) target;
208 return branch;
209 }
210
211 /*
212 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
213 * rDestHi
214 */
loadValuePair(CompilationUnit * cUnit,int vSrc,int rDestLo,int rDestHi)215 static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
216 int rDestHi)
217 {
218 /* Use reg + imm5*4 to load the values if possible */
219 if (vSrc <= 30) {
220 newLIR3(cUnit, THUMB_LDR_RRI5, rDestLo, rFP, vSrc);
221 newLIR3(cUnit, THUMB_LDR_RRI5, rDestHi, rFP, vSrc+1);
222 } else {
223 if (vSrc <= 64) {
224 /* Sneak 4 into the base address first */
225 newLIR3(cUnit, THUMB_ADD_RRI3, rDestLo, rFP, 4);
226 newLIR2(cUnit, THUMB_ADD_RI8, rDestLo, (vSrc-1)*4);
227 } else {
228 /* Offset too far from rFP */
229 loadConstant(cUnit, rDestLo, vSrc*4);
230 newLIR3(cUnit, THUMB_ADD_RRR, rDestLo, rFP, rDestLo);
231 }
232 assert(rDestLo < rDestHi);
233 newLIR2(cUnit, THUMB_LDMIA, rDestLo, (1<<rDestLo) | (1<<(rDestHi)));
234 }
235 }
236
237 /*
238 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
239 * vDest+1
240 */
storeValuePair(CompilationUnit * cUnit,int rSrcLo,int rSrcHi,int vDest,int rScratch)241 static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
242 int vDest, int rScratch)
243 {
244 killNullCheckedRegister(cUnit, vDest);
245 killNullCheckedRegister(cUnit, vDest+1);
246 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
247
248 /* Use reg + imm5*4 to store the values if possible */
249 if (vDest <= 30) {
250 newLIR3(cUnit, THUMB_STR_RRI5, rSrcLo, rFP, vDest);
251 newLIR3(cUnit, THUMB_STR_RRI5, rSrcHi, rFP, vDest+1);
252 } else {
253 if (vDest <= 64) {
254 /* Sneak 4 into the base address first */
255 newLIR3(cUnit, THUMB_ADD_RRI3, rScratch, rFP, 4);
256 newLIR2(cUnit, THUMB_ADD_RI8, rScratch, (vDest-1)*4);
257 } else {
258 /* Offset too far from rFP */
259 loadConstant(cUnit, rScratch, vDest*4);
260 newLIR3(cUnit, THUMB_ADD_RRR, rScratch, rFP, rScratch);
261 }
262 assert(rSrcLo < rSrcHi);
263 newLIR2(cUnit, THUMB_STMIA, rScratch, (1<<rSrcLo) | (1 << (rSrcHi)));
264 }
265 }
266
267 /* Load the address of a Dalvik register on the frame */
loadValueAddress(CompilationUnit * cUnit,int vSrc,int rDest)268 static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
269 {
270 /* RRI3 can add up to 7 */
271 if (vSrc <= 1) {
272 newLIR3(cUnit, THUMB_ADD_RRI3, rDest, rFP, vSrc*4);
273 } else if (vSrc <= 64) {
274 /* Sneak 4 into the base address first */
275 newLIR3(cUnit, THUMB_ADD_RRI3, rDest, rFP, 4);
276 newLIR2(cUnit, THUMB_ADD_RI8, rDest, (vSrc-1)*4);
277 } else {
278 loadConstant(cUnit, rDest, vSrc*4);
279 newLIR3(cUnit, THUMB_ADD_RRR, rDest, rFP, rDest);
280 }
281 }
282
283 /* Load a single value from rFP[src] and store them into rDest */
loadValue(CompilationUnit * cUnit,int vSrc,int rDest)284 static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
285 {
286 /* Use reg + imm5*4 to load the value if possible */
287 if (vSrc <= 31) {
288 newLIR3(cUnit, THUMB_LDR_RRI5, rDest, rFP, vSrc);
289 } else {
290 loadConstant(cUnit, rDest, vSrc*4);
291 newLIR3(cUnit, THUMB_LDR_RRR, rDest, rFP, rDest);
292 }
293 }
294
295 /* Load a word at base + displacement. Displacement must be word multiple */
loadWordDisp(CompilationUnit * cUnit,int rBase,int displacement,int rDest)296 static void loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
297 int rDest)
298 {
299 assert((displacement & 0x3) == 0);
300 /* Can it fit in a RRI5? */
301 if (displacement < 128) {
302 newLIR3(cUnit, THUMB_LDR_RRI5, rDest, rBase, displacement >> 2);
303 } else {
304 loadConstant(cUnit, rDest, displacement);
305 newLIR3(cUnit, THUMB_LDR_RRR, rDest, rBase, rDest);
306 }
307 }
308
309 /* Store a value from rSrc to vDest */
storeValue(CompilationUnit * cUnit,int rSrc,int vDest,int rScratch)310 static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
311 int rScratch)
312 {
313 killNullCheckedRegister(cUnit, vDest);
314 updateLiveRegister(cUnit, vDest, rSrc);
315
316 /* Use reg + imm5*4 to store the value if possible */
317 if (vDest <= 31) {
318 newLIR3(cUnit, THUMB_STR_RRI5, rSrc, rFP, vDest);
319 } else {
320 loadConstant(cUnit, rScratch, vDest*4);
321 newLIR3(cUnit, THUMB_STR_RRR, rSrc, rFP, rScratch);
322 }
323 }
324
325 /*
326 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
327 * satisfies.
328 */
genRegImmCheck(CompilationUnit * cUnit,ArmConditionCode cond,int reg,int checkValue,int dOffset,ArmLIR * pcrLabel)329 static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
330 ArmConditionCode cond, int reg,
331 int checkValue, int dOffset,
332 ArmLIR *pcrLabel)
333 {
334 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
335 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
336 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
337 }
338