• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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