• 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     res->operands[0] = rDest;
140     res->operands[1] = rSrc;
141     if (rDest == rSrc) {
142         res->isNop = true;
143     } else {
144         if (LOWREG(rDest) && LOWREG(rSrc)) {
145             res->opCode = THUMB_MOV_RR;
146         } else if (FPREG(rDest) && FPREG(rSrc)) {
147             if (DOUBLEREG(rDest)) {
148                 assert(DOUBLEREG(rSrc));
149                 res->opCode = THUMB2_VMOVD;
150             } else {
151                 assert(SINGLEREG(rSrc));
152                 res->opCode = THUMB2_VMOVS;
153             }
154         } else {
155             // TODO: support copy between FP and gen regs.
156             assert(!FPREG(rDest));
157             assert(!FPREG(rSrc));
158             res->opCode = THUMB2_MOV_RR;
159         }
160     }
161     return res;
162 }
163 
leadingZeros(u4 val)164 static int leadingZeros(u4 val)
165 {
166     u4 alt;
167     int n;
168     int count;
169 
170     count = 16;
171     n = 32;
172     do {
173         alt = val >> count;
174         if (alt != 0) {
175             n = n - count;
176             val = alt;
177         }
178         count >>= 1;
179     } while (count);
180     return n - val;
181 }
182 
183 /*
184  * Determine whether value can be encoded as a Thumb modified
185  * immediate.  If not, return -1.  If so, return i:imm3:a:bcdefgh form.
186  */
modifiedImmediate(u4 value)187 static int modifiedImmediate(u4 value)
188 {
189    int zLeading;
190    int zTrailing;
191    u4 b0 = value & 0xff;
192 
193    /* Note: case of value==0 must use 0:000:0:0000000 encoding */
194    if (value <= 0xFF)
195        return b0;  // 0:000:a:bcdefgh
196    if (value == ((b0 << 16) | b0))
197        return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
198    if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
199        return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
200    b0 = (value >> 8) & 0xff;
201    if (value == ((b0 << 24) | (b0 << 8)))
202        return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
203    /* Can we do it with rotation? */
204    zLeading = leadingZeros(value);
205    zTrailing = 32 - leadingZeros(~value & (value - 1));
206    /* A run of eight or fewer active bits? */
207    if ((zLeading + zTrailing) < 24)
208        return -1;  /* No - bail */
209    /* left-justify the constant, discarding msb (known to be 1) */
210    value <<= zLeading + 1;
211    /* Create bcdefgh */
212    value >>= 25;
213    /* Put it all together */
214    return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
215 }
216 
217 /*
218  * Load a immediate using a shortcut if possible; otherwise
219  * grab from the per-translation literal pool
220  */
loadConstant(CompilationUnit * cUnit,int rDest,int value)221 static void loadConstant(CompilationUnit *cUnit, int rDest, int value)
222 {
223     int modImm;
224     /* See if the value can be constructed cheaply */
225     if ((value & 0xff) == value) {
226         newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
227         return;
228     } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
229         newLIR2(cUnit, THUMB_MOV_IMM, rDest, ~value);
230         newLIR2(cUnit, THUMB_MVN, rDest, rDest);
231         return;
232     }
233     /* Check Modified immediate special cases */
234     modImm = modifiedImmediate(value);
235     if (modImm >= 0) {
236         newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, rDest, modImm);
237         return;
238     }
239     /* 16-bit immediate? */
240     if ((value & 0xffff) == value) {
241         newLIR2(cUnit, THUMB2_MOV_IMM16, rDest, value);
242         return;
243     }
244     /* No shortcut - go ahead and use literal pool */
245     ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
246     if (dataTarget == NULL) {
247         dataTarget = addWordData(cUnit, value, false);
248     }
249     ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
250     loadPcRel->opCode = THUMB_LDR_PC_REL;
251     loadPcRel->generic.target = (LIR *) dataTarget;
252     loadPcRel->operands[0] = rDest;
253     dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
254 
255     /*
256      * To save space in the constant pool, we use the ADD_RRI8 instruction to
257      * add up to 255 to an existing constant value.
258      */
259     if (dataTarget->operands[0] != value) {
260         newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
261     }
262 }
263 
264 /* Export the Dalvik PC assicated with an instruction to the StackSave area */
genExportPC(CompilationUnit * cUnit,MIR * mir,int rDPC,int rAddr)265 static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr)
266 {
267     int offset = offsetof(StackSaveArea, xtra.currentPc);
268     loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
269     newLIR3(cUnit, THUMB2_STR_RRI8_PREDEC, rDPC, rFP,
270             sizeof(StackSaveArea) - offset);
271 }
272 
273 /* Generate conditional branch instructions */
genConditionalBranch(CompilationUnit * cUnit,ArmConditionCode cond,ArmLIR * target)274 static void genConditionalBranch(CompilationUnit *cUnit,
275                                  ArmConditionCode cond,
276                                  ArmLIR *target)
277 {
278     ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
279     branch->generic.target = (LIR *) target;
280 }
281 
282 /* Generate unconditional branch instructions */
genUnconditionalBranch(CompilationUnit * cUnit,ArmLIR * target)283 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
284 {
285     ArmLIR *branch = newLIR0(cUnit, THUMB_B_UNCOND);
286     branch->generic.target = (LIR *) target;
287     return branch;
288 }
289 
290 /*
291  * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
292  * rDestHi
293  */
loadValuePair(CompilationUnit * cUnit,int vSrc,int rDestLo,int rDestHi)294 static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
295                           int rDestHi)
296 {
297     bool allLowRegs = (LOWREG(rDestLo) && LOWREG(rDestHi));
298 
299     /* Use reg + imm5*4 to load the values if possible */
300     if (allLowRegs && vSrc <= 30) {
301         newLIR3(cUnit, THUMB_LDR_RRI5, rDestLo, rFP, vSrc);
302         newLIR3(cUnit, THUMB_LDR_RRI5, rDestHi, rFP, vSrc+1);
303     } else {
304         assert(rDestLo < rDestHi);
305         loadValueAddress(cUnit, vSrc, rDestLo);
306         if (allLowRegs) {
307             newLIR2(cUnit, THUMB_LDMIA, rDestLo, (1<<rDestLo) | (1<<(rDestHi)));
308         } else {
309             assert(0); // Unimp - need Thumb2 ldmia
310         }
311     }
312 }
313 
314 /*
315  * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
316  * vDest+1
317  */
storeValuePair(CompilationUnit * cUnit,int rSrcLo,int rSrcHi,int vDest,int rScratch)318 static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
319                            int vDest, int rScratch)
320 {
321     bool allLowRegs = (LOWREG(rSrcLo) && LOWREG(rSrcHi));
322     killNullCheckedRegister(cUnit, vDest);
323     killNullCheckedRegister(cUnit, vDest+1);
324     updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
325 
326     /* Use reg + imm5*4 to store the values if possible */
327     if (allLowRegs && vDest <= 30) {
328         newLIR3(cUnit, THUMB_STR_RRI5, rSrcLo, rFP, vDest);
329         newLIR3(cUnit, THUMB_STR_RRI5, rSrcHi, rFP, vDest+1);
330     } else {
331         assert(rSrcLo < rSrcHi);
332         loadValueAddress(cUnit, vDest, rScratch);
333         if (allLowRegs) {
334             newLIR2(cUnit, THUMB_STMIA, rScratch,
335                     (1<<rSrcLo) | (1 << (rSrcHi)));
336         } else {
337             assert(0); // Unimp - need Thumb2 stmia
338         }
339     }
340 }
341 
addRegisterRegister(CompilationUnit * cUnit,int rDest,int rSrc1,int rSrc2)342 static void addRegisterRegister(CompilationUnit *cUnit, int rDest,
343                                 int rSrc1, int rSrc2)
344 {
345     if (!LOWREG(rDest) || !LOWREG(rSrc1) || !LOWREG(rSrc2)) {
346         assert(0); // Unimp
347         //newLIR3(cUnit, THUMB2_ADD_RRR, rDest, rFP, rDest);
348     } else {
349         newLIR3(cUnit, THUMB_ADD_RRR, rDest, rFP, rDest);
350     }
351 }
352 
353 /* Add in immediate to a register. */
addRegisterImmediate(CompilationUnit * cUnit,int rDest,int rSrc,int value)354 static void addRegisterImmediate(CompilationUnit *cUnit, int rDest, int rSrc,
355                                  int value)
356 {
357 // TODO: check for modified immediate form
358     if (LOWREG(rDest) && LOWREG(rSrc) && (value <= 7)) {
359         newLIR3(cUnit, THUMB_ADD_RRI3, rDest, rSrc, value);
360     } else if (LOWREG(rDest) && (rDest == rSrc) && ((value & 0xff) == 0xff)) {
361         newLIR2(cUnit, THUMB_ADD_RI8, rDest, value);
362     } else if (value <= 4095) {
363         newLIR3(cUnit, THUMB2_ADD_RRI12, rDest, rSrc, value);
364     } else {
365         loadConstant(cUnit, rDest, value);
366         addRegisterRegister(cUnit, rDest, rDest, rFP);
367     }
368 }
369 
370 /* Load the address of a Dalvik register on the frame */
loadValueAddress(CompilationUnit * cUnit,int vSrc,int rDest)371 static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
372 {
373     addRegisterImmediate(cUnit, rDest, rFP, vSrc*4);
374 }
375 
376 /*
377  * FIXME: We need a general register temp for all of these coprocessor
378  * operations in case we can't reach in 1 shot.  Might just want to
379  * designate a hot temp that all codegen routines could use in their
380  * scope.  Alternately, callers will need to allocate a temp and
381  * pass it in to each of these.
382  */
383 
384 /* Load a float from a Dalvik register */
loadFloat(CompilationUnit * cUnit,int vSrc,int rDest)385 static void loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
386 {
387     assert(vSrc <= 255); // FIXME - temp limit to 1st 256
388     assert(SINGLEREG(rDest));
389     newLIR3(cUnit, THUMB2_VLDRS, rDest, rFP, vSrc);
390 }
391 
392 /* Store a float to a Dalvik register */
storeFloat(CompilationUnit * cUnit,int rSrc,int vDest,int rScratch)393 static void storeFloat(CompilationUnit *cUnit, int rSrc, int vDest,
394                        int rScratch)
395 {
396     assert(vSrc <= 255); // FIXME - temp limit to 1st 256
397     assert(SINGLEREG(rSrc));
398     newLIR3(cUnit, THUMB2_VSTRS, rSrc, rFP, vDest);
399 }
400 
401 /* Load a double from a Dalvik register */
loadDouble(CompilationUnit * cUnit,int vSrc,int rDest)402 static void loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
403 {
404     assert(vSrc <= 255); // FIXME - temp limit to 1st 256
405     assert(DOUBLEREG(rDest));
406     newLIR3(cUnit, THUMB2_VLDRD, rDest, rFP, vSrc);
407 }
408 
409 /* Store a double to a Dalvik register */
storeDouble(CompilationUnit * cUnit,int rSrc,int vDest,int rScratch)410 static void storeDouble(CompilationUnit *cUnit, int rSrc, int vDest,
411                        int rScratch)
412 {
413     assert(vSrc <= 255); // FIXME - temp limit to 1st 256
414     assert(DOUBLEREG(rSrc));
415     newLIR3(cUnit, THUMB2_VSTRD, rSrc, rFP, vDest);
416 }
417 
418 
419 /* Load a single value from rFP[src] and store them into rDest */
loadValue(CompilationUnit * cUnit,int vSrc,int rDest)420 static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
421 {
422     loadWordDisp(cUnit, rFP, vSrc * 4, rDest);
423 }
424 
425 /* Load a word at base + displacement.  Displacement must be word multiple */
loadWordDisp(CompilationUnit * cUnit,int rBase,int displacement,int rDest)426 static void loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
427                          int rDest)
428 {
429     bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
430     assert((displacement & 0x3) == 0);
431     /* Can it fit in a RRI5? */
432     if (allLowRegs && displacement < 128) {
433         newLIR3(cUnit, THUMB_LDR_RRI5, rDest, rBase, displacement >> 2);
434     } else if (displacement < 4092) {
435         newLIR3(cUnit, THUMB2_LDR_RRI12, rDest, rFP, displacement);
436     } else {
437         loadConstant(cUnit, rDest, displacement);
438         if (allLowRegs) {
439             newLIR3(cUnit, THUMB_LDR_RRR, rDest, rBase, rDest);
440         } else {
441             assert(0); // Unimp - need Thumb2 ldr_rrr
442         }
443     }
444 }
445 
446 /* Store a value from rSrc to vDest */
storeValue(CompilationUnit * cUnit,int rSrc,int vDest,int rScratch)447 static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
448                        int rScratch)
449 {
450     killNullCheckedRegister(cUnit, vDest);
451     updateLiveRegister(cUnit, vDest, rSrc);
452 
453     /* Use reg + imm5*4 to store the value if possible */
454     if (LOWREG(rSrc) && vDest <= 31) {
455         newLIR3(cUnit, THUMB_STR_RRI5, rSrc, rFP, vDest);
456     } else if (vDest <= 1023) {
457         newLIR3(cUnit, THUMB2_STR_RRI12, rSrc, rFP, vDest*4);
458     } else {
459         loadConstant(cUnit, rScratch, vDest*4);
460         if (LOWREG(rSrc)) {
461             newLIR3(cUnit, THUMB_STR_RRR, rSrc, rFP, rScratch);
462         } else {
463             assert(0); // Unimp: Need generic str_rrr routine
464         }
465     }
466 }
467 
468 /*
469  * Perform a "reg cmp imm" operation and jump to the PCR region if condition
470  * satisfies.
471  */
genRegImmCheck(CompilationUnit * cUnit,ArmConditionCode cond,int reg,int checkValue,int dOffset,ArmLIR * pcrLabel)472 static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
473                                          ArmConditionCode cond, int reg,
474                                          int checkValue, int dOffset,
475                                          ArmLIR *pcrLabel)
476 {
477     ArmLIR *branch;
478     if ((LOWREG(reg)) && (checkValue == 0) &&
479        ((cond == ARM_COND_EQ) || (cond == ARM_COND_NE))) {
480         branch = newLIR2(cUnit,
481                          (cond == ARM_COND_EQ) ? THUMB2_CBZ : THUMB2_CBNZ,
482                          reg, 0);
483     } else {
484         newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
485         branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
486     }
487     return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
488 }
489