• 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 register alloction support and is intended to be
19  * included by:
20  *
21  *        Codegen-$(TARGET_ARCH_VARIANT).c
22  *
23  */
24 
25 #include "compiler/CompilerUtility.h"
26 #include "compiler/CompilerIR.h"
27 #include "compiler/Dataflow.h"
28 #include "ArmLIR.h"
29 #include "Codegen.h"
30 #include "Ralloc.h"
31 
32 /*
33  * Register usage for 16-bit Thumb systems:
34  *     r0-r3: Temp/argument
35  *     lr(r14):      Temp for translations, return address for handlers
36  *     rGLUE(r6):    Pointer to InterpState
37  *     rFP(r5):      Dalvik frame pointer
38  *     r4, r7:       Temp for translations
39  *     r8, r9, r10:   Temp preserved across C calls
40  *     r11, ip(r12):  Temp not preserved across C calls
41  *
42  * Register usage for 32-bit Thumb systems:
43  *     r0-r3: Temp/argument
44  *     lr(r14):      Temp for translations, return address for handlers
45  *     rGLUE(r6):    Pointer to InterpState
46  *     rFP(r5):      Dalvik frame pointer
47  *     r4, r7:       Temp for translations
48  *     r8, r9, r10   Temp preserved across C calls
49  *     r11, ip(r12):      Temp not preserved across C calls
50  *     fp0-fp15:     Hot temps, not preserved across C calls
51  *     fp16-fp31:    Promotion pool
52  *
53  */
54 
55 #define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
56 /*
57  * Get the "real" sreg number associated with an sReg slot.  In general,
58  * sReg values passed through codegen are the SSA names created by
59  * dataflow analysis and refer to slot numbers in the cUnit->regLocation
60  * array.  However, renaming is accomplished by simply replacing RegLocation
61  * entries in the cUnit->reglocation[] array.  Therefore, when location
62  * records for operands are first created, we need to ask the locRecord
63  * identified by the dataflow pass what it's new name is.
64  */
65 
66 /*
67  * Free all allocated temps in the temp pools.  Note that this does
68  * not affect the "liveness" of a temp register, which will stay
69  * live until it is either explicitly killed or reallocated.
70  */
dvmCompilerResetRegPool(CompilationUnit * cUnit)71 extern void dvmCompilerResetRegPool(CompilationUnit *cUnit)
72 {
73     int i;
74     for (i=0; i < cUnit->regPool->numCoreTemps; i++) {
75         cUnit->regPool->coreTemps[i].inUse = false;
76     }
77     for (i=0; i < cUnit->regPool->numFPTemps; i++) {
78         cUnit->regPool->FPTemps[i].inUse = false;
79     }
80 }
81 
82  /* Set up temp & preserved register pools specialized by target */
dvmCompilerInitPool(RegisterInfo * regs,int * regNums,int num)83 extern void dvmCompilerInitPool(RegisterInfo *regs, int *regNums, int num)
84 {
85     int i;
86     for (i=0; i < num; i++) {
87         regs[i].reg = regNums[i];
88         regs[i].inUse = false;
89         regs[i].pair = false;
90         regs[i].live = false;
91         regs[i].dirty = false;
92         regs[i].sReg = INVALID_SREG;
93     }
94 }
95 
dumpRegPool(RegisterInfo * p,int numRegs)96 static void dumpRegPool(RegisterInfo *p, int numRegs)
97 {
98     int i;
99     LOGE("================================================");
100     for (i=0; i < numRegs; i++ ){
101         LOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
102            p[i].reg, p[i].inUse, p[i].pair, p[i].partner, p[i].live,
103            p[i].dirty, p[i].sReg,(int)p[i].defStart, (int)p[i].defEnd);
104     }
105     LOGE("================================================");
106 }
107 
getRegInfo(CompilationUnit * cUnit,int reg)108 static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
109 {
110     int numTemps = cUnit->regPool->numCoreTemps;
111     RegisterInfo *p = cUnit->regPool->coreTemps;
112     int i;
113     for (i=0; i< numTemps; i++) {
114         if (p[i].reg == reg) {
115             return &p[i];
116         }
117     }
118     p = cUnit->regPool->FPTemps;
119     numTemps = cUnit->regPool->numFPTemps;
120     for (i=0; i< numTemps; i++) {
121         if (p[i].reg == reg) {
122             return &p[i];
123         }
124     }
125     LOGE("Tried to get info on a non-existant temp: r%d",reg);
126     dvmCompilerAbort(cUnit);
127     return NULL;
128 }
129 
flushRegWide(CompilationUnit * cUnit,int reg1,int reg2)130 static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
131 {
132     RegisterInfo *info1 = getRegInfo(cUnit, reg1);
133     RegisterInfo *info2 = getRegInfo(cUnit, reg2);
134     assert(info1 && info2 && info1->pair && info2->pair &&
135            (info1->partner == info2->reg) &&
136            (info2->partner == info1->reg));
137     if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
138         info1->dirty = false;
139         info2->dirty = false;
140         if (dvmCompilerS2VReg(cUnit, info2->sReg) <
141             dvmCompilerS2VReg(cUnit, info1->sReg))
142             info1 = info2;
143         dvmCompilerFlushRegWideImpl(cUnit, rFP,
144                                     dvmCompilerS2VReg(cUnit, info1->sReg) << 2,
145                                     info1->reg, info1->partner);
146     }
147 }
148 
flushReg(CompilationUnit * cUnit,int reg)149 static void flushReg(CompilationUnit *cUnit, int reg)
150 {
151     RegisterInfo *info = getRegInfo(cUnit, reg);
152     if (info->live && info->dirty) {
153         info->dirty = false;
154         dvmCompilerFlushRegImpl(cUnit, rFP,
155                                 dvmCompilerS2VReg(cUnit, info->sReg) << 2,
156                                 reg, kWord);
157     }
158 }
159 
160 /* return true if found reg to clobber */
clobberRegBody(CompilationUnit * cUnit,RegisterInfo * p,int numTemps,int reg)161 static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
162                            int numTemps, int reg)
163 {
164     int i;
165     for (i=0; i< numTemps; i++) {
166         if (p[i].reg == reg) {
167             if (p[i].live && p[i].dirty) {
168                 if (p[i].pair) {
169                     flushRegWide(cUnit, p[i].reg, p[i].partner);
170                 } else {
171                     flushReg(cUnit, p[i].reg);
172                 }
173             }
174             p[i].live = false;
175             p[i].sReg = INVALID_SREG;
176             p[i].defStart = NULL;
177             p[i].defEnd = NULL;
178             if (p[i].pair) {
179                 p[i].pair = false;
180                 /* partners should be in same pool */
181                 clobberRegBody(cUnit, p, numTemps, p[i].partner);
182             }
183             return true;
184         }
185     }
186     return false;
187 }
188 
189 /* Mark a temp register as dead.  Does not affect allocation state. */
dvmCompilerClobber(CompilationUnit * cUnit,int reg)190 void dvmCompilerClobber(CompilationUnit *cUnit, int reg)
191 {
192     if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
193                         cUnit->regPool->numCoreTemps, reg)) {
194         clobberRegBody(cUnit, cUnit->regPool->FPTemps,
195                        cUnit->regPool->numFPTemps, reg);
196     }
197 }
198 
clobberSRegBody(RegisterInfo * p,int numTemps,int sReg)199 static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
200 {
201     int i;
202     for (i=0; i< numTemps; i++) {
203         if (p[i].sReg == sReg) {
204             p[i].live = false;
205             p[i].defStart = NULL;
206             p[i].defEnd = NULL;
207         }
208     }
209 }
210 
211 /* Clobber any temp associated with an sReg.  Could be in either class */
dvmCompilerClobberSReg(CompilationUnit * cUnit,int sReg)212 extern void dvmCompilerClobberSReg(CompilationUnit *cUnit, int sReg)
213 {
214     clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
215                     sReg);
216     clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
217                     sReg);
218 }
219 
allocTempBody(CompilationUnit * cUnit,RegisterInfo * p,int numTemps,int * nextTemp,bool required)220 static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
221                          int *nextTemp, bool required)
222 {
223     int i;
224     int next = *nextTemp;
225     for (i=0; i< numTemps; i++) {
226         if (next >= numTemps)
227             next = 0;
228         if (!p[next].inUse && !p[next].live) {
229             dvmCompilerClobber(cUnit, p[next].reg);
230             p[next].inUse = true;
231             p[next].pair = false;
232             *nextTemp = next + 1;
233             return p[next].reg;
234         }
235         next++;
236     }
237     next = *nextTemp;
238     for (i=0; i< numTemps; i++) {
239         if (next >= numTemps)
240             next = 0;
241         if (!p[next].inUse) {
242             dvmCompilerClobber(cUnit, p[next].reg);
243             p[next].inUse = true;
244             p[next].pair = false;
245             *nextTemp = next + 1;
246             return p[next].reg;
247         }
248         next++;
249     }
250     if (required) {
251         LOGE("No free temp registers");
252         dvmCompilerAbort(cUnit);
253     }
254     return -1;  // No register available
255 }
256 
257 //REDO: too many assumptions.
dvmCompilerAllocTempDouble(CompilationUnit * cUnit)258 extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit)
259 {
260     RegisterInfo *p = cUnit->regPool->FPTemps;
261     int numTemps = cUnit->regPool->numFPTemps;
262     int next = cUnit->regPool->nextFPTemp;
263     int i;
264 
265     for (i=0; i < numTemps; i+=2) {
266         /* Cleanup - not all targets need aligned regs */
267         if (next & 1)
268             next++;
269         if (next >= numTemps)
270             next = 0;
271         if ((!p[next].inUse && !p[next].live) &&
272             (!p[next+1].inUse && !p[next+1].live)) {
273             dvmCompilerClobber(cUnit, p[next].reg);
274             dvmCompilerClobber(cUnit, p[next+1].reg);
275             p[next].inUse = true;
276             p[next+1].inUse = true;
277             assert((p[next].reg+1) == p[next+1].reg);
278             assert((p[next].reg & 0x1) == 0);
279             cUnit->regPool->nextFPTemp += 2;
280             return p[next].reg;
281         }
282         next += 2;
283     }
284     next = cUnit->regPool->nextFPTemp;
285     for (i=0; i < numTemps; i+=2) {
286         if (next >= numTemps)
287             next = 0;
288         if (!p[next].inUse && !p[next+1].inUse) {
289             dvmCompilerClobber(cUnit, p[next].reg);
290             dvmCompilerClobber(cUnit, p[next+1].reg);
291             p[next].inUse = true;
292             p[next+1].inUse = true;
293             assert((p[next].reg+1) == p[next+1].reg);
294             assert((p[next].reg & 0x1) == 0);
295             cUnit->regPool->nextFPTemp += 2;
296             return p[next].reg;
297         }
298         next += 2;
299     }
300     LOGE("No free temp registers");
301     dvmCompilerAbort(cUnit);
302     return -1;
303 }
304 
305 /* Return a temp if one is available, -1 otherwise */
dvmCompilerAllocFreeTemp(CompilationUnit * cUnit)306 extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit)
307 {
308     return allocTempBody(cUnit, cUnit->regPool->coreTemps,
309                          cUnit->regPool->numCoreTemps,
310                          &cUnit->regPool->nextCoreTemp, true);
311 }
312 
dvmCompilerAllocTemp(CompilationUnit * cUnit)313 extern int dvmCompilerAllocTemp(CompilationUnit *cUnit)
314 {
315     return allocTempBody(cUnit, cUnit->regPool->coreTemps,
316                          cUnit->regPool->numCoreTemps,
317                          &cUnit->regPool->nextCoreTemp, true);
318 }
319 
dvmCompilerAllocTempFloat(CompilationUnit * cUnit)320 extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit)
321 {
322     return allocTempBody(cUnit, cUnit->regPool->FPTemps,
323                          cUnit->regPool->numFPTemps,
324                          &cUnit->regPool->nextFPTemp, true);
325 }
326 
allocLiveBody(RegisterInfo * p,int numTemps,int sReg)327 static RegisterInfo *allocLiveBody(RegisterInfo *p, int numTemps, int sReg)
328 {
329     int i;
330     if (sReg == -1)
331         return NULL;
332     for (i=0; i < numTemps; i++) {
333         if (p[i].live && (p[i].sReg == sReg)) {
334             p[i].inUse = true;
335             return &p[i];
336         }
337     }
338     return NULL;
339 }
340 
allocLive(CompilationUnit * cUnit,int sReg,int regClass)341 static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
342                                int regClass)
343 {
344     RegisterInfo *res = NULL;
345     switch(regClass) {
346         case kAnyReg:
347             res = allocLiveBody(cUnit->regPool->FPTemps,
348                                 cUnit->regPool->numFPTemps, sReg);
349             if (res)
350                 break;
351             /* Intentional fallthrough */
352         case kCoreReg:
353             res = allocLiveBody(cUnit->regPool->coreTemps,
354                                 cUnit->regPool->numCoreTemps, sReg);
355             break;
356         case kFPReg:
357             res = allocLiveBody(cUnit->regPool->FPTemps,
358                                 cUnit->regPool->numFPTemps, sReg);
359             break;
360         default:
361             LOGE("Invalid register type");
362             dvmCompilerAbort(cUnit);
363     }
364     return res;
365 }
366 
dvmCompilerFreeTemp(CompilationUnit * cUnit,int reg)367 extern void dvmCompilerFreeTemp(CompilationUnit *cUnit, int reg)
368 {
369     RegisterInfo *p = cUnit->regPool->coreTemps;
370     int numTemps = cUnit->regPool->numCoreTemps;
371     int i;
372     for (i=0; i< numTemps; i++) {
373         if (p[i].reg == reg) {
374             p[i].inUse = false;
375             p[i].pair = false;
376             return;
377         }
378     }
379     p = cUnit->regPool->FPTemps;
380     numTemps = cUnit->regPool->numFPTemps;
381     for (i=0; i< numTemps; i++) {
382         if (p[i].reg == reg) {
383             p[i].inUse = false;
384             p[i].pair = false;
385             return;
386         }
387     }
388     LOGE("Tried to free a non-existant temp: r%d",reg);
389     dvmCompilerAbort(cUnit);
390 }
391 
392 /*
393  * FIXME - this needs to also check the preserved pool once we start
394  * start using preserved registers.
395  */
dvmCompilerIsLive(CompilationUnit * cUnit,int reg)396 extern RegisterInfo *dvmCompilerIsLive(CompilationUnit *cUnit, int reg)
397 {
398     RegisterInfo *p = cUnit->regPool->coreTemps;
399     int numTemps = cUnit->regPool->numCoreTemps;
400     int i;
401     for (i=0; i< numTemps; i++) {
402         if (p[i].reg == reg) {
403             return p[i].live ? &p[i] : NULL;
404         }
405     }
406     p = cUnit->regPool->FPTemps;
407     numTemps = cUnit->regPool->numFPTemps;
408     for (i=0; i< numTemps; i++) {
409         if (p[i].reg == reg) {
410             return p[i].live ? &p[i] : NULL;
411         }
412     }
413     return NULL;
414 }
415 
dvmCompilerIsTemp(CompilationUnit * cUnit,int reg)416 extern RegisterInfo *dvmCompilerIsTemp(CompilationUnit *cUnit, int reg)
417 {
418     RegisterInfo *p = cUnit->regPool->coreTemps;
419     int numTemps = cUnit->regPool->numCoreTemps;
420     int i;
421     for (i=0; i< numTemps; i++) {
422         if (p[i].reg == reg) {
423             return &p[i];
424         }
425     }
426     p = cUnit->regPool->FPTemps;
427     numTemps = cUnit->regPool->numFPTemps;
428     for (i=0; i< numTemps; i++) {
429         if (p[i].reg == reg) {
430             return &p[i];
431         }
432     }
433     return NULL;
434 }
435 
436 /*
437  * Similar to dvmCompilerAllocTemp(), but forces the allocation of a specific
438  * register.  No check is made to see if the register was previously
439  * allocated.  Use with caution.
440  */
dvmCompilerLockTemp(CompilationUnit * cUnit,int reg)441 extern void dvmCompilerLockTemp(CompilationUnit *cUnit, int reg)
442 {
443     RegisterInfo *p = cUnit->regPool->coreTemps;
444     int numTemps = cUnit->regPool->numCoreTemps;
445     int i;
446     for (i=0; i< numTemps; i++) {
447         if (p[i].reg == reg) {
448             p[i].inUse = true;
449             p[i].live = false;
450             return;
451         }
452     }
453     p = cUnit->regPool->FPTemps;
454     numTemps = cUnit->regPool->numFPTemps;
455     for (i=0; i< numTemps; i++) {
456         if (p[i].reg == reg) {
457             p[i].inUse = true;
458             p[i].live = false;
459             return;
460         }
461     }
462     LOGE("Tried to lock a non-existant temp: r%d",reg);
463     dvmCompilerAbort(cUnit);
464 }
465 
466 /* Clobber all regs that might be used by an external C call */
dvmCompilerClobberCallRegs(CompilationUnit * cUnit)467 extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit)
468 {
469     dvmCompilerClobber(cUnit, r0);
470     dvmCompilerClobber(cUnit, r1);
471     dvmCompilerClobber(cUnit, r2);
472     dvmCompilerClobber(cUnit, r3);
473     dvmCompilerClobber(cUnit, r9); // Need to do this?, be conservative
474     dvmCompilerClobber(cUnit, r11);
475     dvmCompilerClobber(cUnit, r12);
476     dvmCompilerClobber(cUnit, rlr);
477 }
478 
479 /* Clobber all of the temps that might be used by a handler. */
dvmCompilerClobberHandlerRegs(CompilationUnit * cUnit)480 extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit)
481 {
482     //TUNING: reduce the set of regs used by handlers.  Only a few need lots.
483     dvmCompilerClobberCallRegs(cUnit);
484     dvmCompilerClobber(cUnit, r4PC);
485     dvmCompilerClobber(cUnit, r7);
486     dvmCompilerClobber(cUnit, r8);
487     dvmCompilerClobber(cUnit, r9);
488     dvmCompilerClobber(cUnit, r10);
489 }
490 
dvmCompilerResetDef(CompilationUnit * cUnit,int reg)491 extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg)
492 {
493     RegisterInfo *p = getRegInfo(cUnit, reg);
494     p->defStart = NULL;
495     p->defEnd = NULL;
496 }
497 
nullifyRange(CompilationUnit * cUnit,LIR * start,LIR * finish,int sReg1,int sReg2)498 static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
499                          int sReg1, int sReg2)
500 {
501     if (start && finish) {
502         LIR *p;
503         assert(sReg1 == sReg2);
504         for (p = start; ;p = p->next) {
505             ((ArmLIR *)p)->isNop = true;
506             if (p == finish)
507                 break;
508         }
509     }
510 }
511 
512 /*
513  * Mark the beginning and end LIR of a def sequence.  Note that
514  * on entry start points to the LIR prior to the beginning of the
515  * sequence.
516  */
dvmCompilerMarkDef(CompilationUnit * cUnit,RegLocation rl,LIR * start,LIR * finish)517 extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl,
518                     LIR *start, LIR *finish)
519 {
520     assert(!rl.wide);
521     assert(start && start->next);
522     assert(finish);
523     RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
524     p->defStart = start->next;
525     p->defEnd = finish;
526 }
527 
528 /*
529  * Mark the beginning and end LIR of a def sequence.  Note that
530  * on entry start points to the LIR prior to the beginning of the
531  * sequence.
532  */
dvmCompilerMarkDefWide(CompilationUnit * cUnit,RegLocation rl,LIR * start,LIR * finish)533 extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl,
534                         LIR *start, LIR *finish)
535 {
536     assert(rl.wide);
537     assert(start && start->next);
538     assert(finish);
539     RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
540     dvmCompilerResetDef(cUnit, rl.highReg);  // Only track low of pair
541     p->defStart = start->next;
542     p->defEnd = finish;
543 }
544 
dvmCompilerWideToNarrow(CompilationUnit * cUnit,RegLocation rl)545 extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit,
546                                            RegLocation rl)
547 {
548     assert(rl.wide);
549     if (rl.location == kLocPhysReg) {
550         RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
551         RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
552         if (!infoLo->pair) {
553             dumpRegPool(cUnit->regPool->coreTemps,
554                         cUnit->regPool->numCoreTemps);
555             assert(infoLo->pair);
556         }
557         if (!infoHi->pair) {
558             dumpRegPool(cUnit->regPool->coreTemps,
559                         cUnit->regPool->numCoreTemps);
560             assert(infoHi->pair);
561         }
562         assert(infoLo->pair);
563         assert(infoHi->pair);
564         assert(infoLo->partner == infoHi->reg);
565         assert(infoHi->partner == infoLo->reg);
566         infoLo->pair = false;
567         infoHi->pair = false;
568         infoLo->defStart = NULL;
569         infoLo->defEnd = NULL;
570         infoHi->defStart = NULL;
571         infoHi->defEnd = NULL;
572     }
573     rl.wide = false;
574     return rl;
575 }
576 
dvmCompilerResetDefLoc(CompilationUnit * cUnit,RegLocation rl)577 extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl)
578 {
579     assert(!rl.wide);
580     if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
581         RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
582         assert(!p->pair);
583         nullifyRange(cUnit, p->defStart, p->defEnd,
584                      p->sReg, rl.sRegLow);
585     }
586     dvmCompilerResetDef(cUnit, rl.lowReg);
587 }
588 
dvmCompilerResetDefLocWide(CompilationUnit * cUnit,RegLocation rl)589 extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
590 {
591     assert(rl.wide);
592     if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
593         RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
594         assert(p->pair);
595         nullifyRange(cUnit, p->defStart, p->defEnd,
596                      p->sReg, rl.sRegLow);
597     }
598     dvmCompilerResetDef(cUnit, rl.lowReg);
599     dvmCompilerResetDef(cUnit, rl.highReg);
600 }
601 
dvmCompilerResetDefTracking(CompilationUnit * cUnit)602 extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit)
603 {
604     int i;
605     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
606         dvmCompilerResetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
607     }
608     for (i=0; i< cUnit->regPool->numFPTemps; i++) {
609         dvmCompilerResetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
610     }
611 }
612 
dvmCompilerClobberAllRegs(CompilationUnit * cUnit)613 extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit)
614 {
615     int i;
616     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
617         dvmCompilerClobber(cUnit, cUnit->regPool->coreTemps[i].reg);
618     }
619     for (i=0; i< cUnit->regPool->numFPTemps; i++) {
620         dvmCompilerClobber(cUnit, cUnit->regPool->FPTemps[i].reg);
621     }
622 }
623 
624 /* To be used when explicitly managing register use */
dvmCompilerLockAllTemps(CompilationUnit * cUnit)625 extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit)
626 {
627     int i;
628     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
629         dvmCompilerLockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
630     }
631 }
632 
633 // Make sure nothing is live and dirty
flushAllRegsBody(CompilationUnit * cUnit,RegisterInfo * info,int numRegs)634 static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
635                              int numRegs)
636 {
637     int i;
638     for (i=0; i < numRegs; i++) {
639         if (info[i].live && info[i].dirty) {
640             if (info[i].pair) {
641                 flushRegWide(cUnit, info[i].reg, info[i].partner);
642             } else {
643                 flushReg(cUnit, info[i].reg);
644             }
645         }
646     }
647 }
648 
dvmCompilerFlushAllRegs(CompilationUnit * cUnit)649 extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit)
650 {
651     flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
652                      cUnit->regPool->numCoreTemps);
653     flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
654                      cUnit->regPool->numFPTemps);
655     dvmCompilerClobberAllRegs(cUnit);
656 }
657 
658 
659 //TUNING: rewrite all of this reg stuff.  Probably use an attribute table
regClassMatches(int regClass,int reg)660 static bool regClassMatches(int regClass, int reg)
661 {
662     if (regClass == kAnyReg) {
663         return true;
664     } else if (regClass == kCoreReg) {
665         return !FPREG(reg);
666     } else {
667         return FPREG(reg);
668     }
669 }
670 
dvmCompilerMarkLive(CompilationUnit * cUnit,int reg,int sReg)671 extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg)
672 {
673     RegisterInfo *info = getRegInfo(cUnit, reg);
674     if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
675         return;  /* already live */
676     } else if (sReg != INVALID_SREG) {
677         dvmCompilerClobberSReg(cUnit, sReg);
678         info->live = true;
679     } else {
680         /* Can't be live if no associated sReg */
681         info->live = false;
682     }
683     info->sReg = sReg;
684 }
685 
dvmCompilerMarkPair(CompilationUnit * cUnit,int lowReg,int highReg)686 extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg, int highReg)
687 {
688     RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
689     RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
690     infoLo->pair = infoHi->pair = true;
691     infoLo->partner = highReg;
692     infoHi->partner = lowReg;
693 }
694 
dvmCompilerMarkClean(CompilationUnit * cUnit,int reg)695 extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
696 {
697     RegisterInfo *info = getRegInfo(cUnit, reg);
698     info->dirty = false;
699 }
700 
dvmCompilerMarkDirty(CompilationUnit * cUnit,int reg)701 extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg)
702 {
703     RegisterInfo *info = getRegInfo(cUnit, reg);
704     info->dirty = true;
705 }
706 
dvmCompilerMarkInUse(CompilationUnit * cUnit,int reg)707 extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg)
708 {
709       RegisterInfo *info = getRegInfo(cUnit, reg);
710           info->inUse = true;
711 }
712 
copyRegInfo(CompilationUnit * cUnit,int newReg,int oldReg)713 void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
714 {
715     RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
716     RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
717     *newInfo = *oldInfo;
718     newInfo->reg = newReg;
719 }
720 
721 /*
722  * Return an updated location record with current in-register status.
723  * If the value lives in live temps, reflect that fact.  No code
724  * is generated.  The the live value is part of an older pair,
725  * clobber both low and high.
726  * TUNING: clobbering both is a bit heavy-handed, but the alternative
727  * is a bit complex when dealing with FP regs.  Examine code to see
728  * if it's worthwhile trying to be more clever here.
729  */
dvmCompilerUpdateLoc(CompilationUnit * cUnit,RegLocation loc)730 extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit, RegLocation loc)
731 {
732     assert(!loc.wide);
733     if (loc.location == kLocDalvikFrame) {
734         RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
735         if (infoLo) {
736             if (infoLo->pair) {
737                 dvmCompilerClobber(cUnit, infoLo->reg);
738                 dvmCompilerClobber(cUnit, infoLo->partner);
739             } else {
740                 loc.lowReg = infoLo->reg;
741                 loc.location = kLocPhysReg;
742             }
743         }
744     }
745 
746     return loc;
747 }
748 
749 /* see comments for updateLoc */
dvmCompilerUpdateLocWide(CompilationUnit * cUnit,RegLocation loc)750 extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit,
751                                             RegLocation loc)
752 {
753     assert(loc.wide);
754     if (loc.location == kLocDalvikFrame) {
755         // Are the dalvik regs already live in physical registers?
756         RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
757         RegisterInfo *infoHi = allocLive(cUnit,
758               dvmCompilerSRegHi(loc.sRegLow), kAnyReg);
759         bool match = true;
760         match = match && (infoLo != NULL);
761         match = match && (infoHi != NULL);
762         // Are they both core or both FP?
763         match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
764         // If a pair of floating point singles, are they properly aligned?
765         if (match && FPREG(infoLo->reg)) {
766             match &= ((infoLo->reg & 0x1) == 0);
767             match &= ((infoHi->reg - infoLo->reg) == 1);
768         }
769         // If previously used as a pair, it is the same pair?
770         if (match && (infoLo->pair || infoHi->pair)) {
771             match = (infoLo->pair == infoHi->pair);
772             match &= ((infoLo->reg == infoHi->partner) &&
773                       (infoHi->reg == infoLo->partner));
774         }
775         if (match) {
776             // Can reuse - update the register usage info
777             loc.lowReg = infoLo->reg;
778             loc.highReg = infoHi->reg;
779             loc.location = kLocPhysReg;
780             dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
781             assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
782             return loc;
783         }
784         // Can't easily reuse - clobber any overlaps
785         if (infoLo) {
786             dvmCompilerClobber(cUnit, infoLo->reg);
787             if (infoLo->pair)
788                 dvmCompilerClobber(cUnit, infoLo->partner);
789         }
790         if (infoHi) {
791             dvmCompilerClobber(cUnit, infoHi->reg);
792             if (infoHi->pair)
793                 dvmCompilerClobber(cUnit, infoHi->partner);
794         }
795     }
796 
797     return loc;
798 }
799 
evalLocWide(CompilationUnit * cUnit,RegLocation loc,int regClass,bool update)800 static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
801                                int regClass, bool update)
802 {
803     assert(loc.wide);
804     int newRegs;
805     int lowReg;
806     int highReg;
807 
808     loc = dvmCompilerUpdateLocWide(cUnit, loc);
809 
810     /* If already in registers, we can assume proper form.  Right reg class? */
811     if (loc.location == kLocPhysReg) {
812         assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
813         assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
814         if (!regClassMatches(regClass, loc.lowReg)) {
815             /* Wrong register class.  Reallocate and copy */
816             newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
817             lowReg = newRegs & 0xff;
818             highReg = (newRegs >> 8) & 0xff;
819             dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
820                                    loc.highReg);
821             copyRegInfo(cUnit, lowReg, loc.lowReg);
822             copyRegInfo(cUnit, highReg, loc.highReg);
823             dvmCompilerClobber(cUnit, loc.lowReg);
824             dvmCompilerClobber(cUnit, loc.highReg);
825             loc.lowReg = lowReg;
826             loc.highReg = highReg;
827             dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
828             assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
829         }
830         return loc;
831     }
832 
833     assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
834     assert((loc.location != kLocRetval) ||
835            (dvmCompilerSRegHi(loc.sRegLow) == INVALID_SREG));
836 
837     newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
838     loc.lowReg = newRegs & 0xff;
839     loc.highReg = (newRegs >> 8) & 0xff;
840 
841     dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
842     if (update) {
843         loc.location = kLocPhysReg;
844         dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
845         dvmCompilerMarkLive(cUnit, loc.highReg, dvmCompilerSRegHi(loc.sRegLow));
846     }
847     assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
848     return loc;
849 }
850 
dvmCompilerEvalLoc(CompilationUnit * cUnit,RegLocation loc,int regClass,bool update)851 extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
852                                       int regClass, bool update)
853 {
854     int newReg;
855     if (loc.wide)
856         return evalLocWide(cUnit, loc, regClass, update);
857     loc = dvmCompilerUpdateLoc(cUnit, loc);
858 
859     if (loc.location == kLocPhysReg) {
860         if (!regClassMatches(regClass, loc.lowReg)) {
861             /* Wrong register class.  Realloc, copy and transfer ownership */
862             newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
863             dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
864             copyRegInfo(cUnit, newReg, loc.lowReg);
865             dvmCompilerClobber(cUnit, loc.lowReg);
866             loc.lowReg = newReg;
867         }
868         return loc;
869     }
870 
871     assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
872 
873     newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
874     loc.lowReg = newReg;
875 
876     if (update) {
877         loc.location = kLocPhysReg;
878         dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
879     }
880     return loc;
881 }
882 
getDestSSAName(MIR * mir,int num)883 static inline int getDestSSAName(MIR *mir, int num)
884 {
885     assert(mir->ssaRep->numDefs > num);
886     return mir->ssaRep->defs[num];
887 }
888 
889 // Get the LocRecord associated with an SSA name use.
dvmCompilerGetSrc(CompilationUnit * cUnit,MIR * mir,int num)890 extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num)
891 {
892     RegLocation loc = cUnit->regLocation[
893          SREG(cUnit, dvmCompilerSSASrc(mir, num))];
894     loc.fp = cUnit->regLocation[dvmCompilerSSASrc(mir, num)].fp;
895     loc.wide = false;
896     return loc;
897 }
898 
899 // Get the LocRecord associated with an SSA name def.
dvmCompilerGetDest(CompilationUnit * cUnit,MIR * mir,int num)900 extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir,
901                                       int num)
902 {
903     RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
904     loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
905     loc.wide = false;
906     return loc;
907 }
908 
getLocWide(CompilationUnit * cUnit,MIR * mir,int low,int high,bool isSrc)909 static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
910                               int low, int high, bool isSrc)
911 {
912     RegLocation lowLoc;
913     RegLocation highLoc;
914     /* Copy loc record for low word and patch in data from high word */
915     if (isSrc) {
916         lowLoc = dvmCompilerGetSrc(cUnit, mir, low);
917         highLoc = dvmCompilerGetSrc(cUnit, mir, high);
918     } else {
919         lowLoc = dvmCompilerGetDest(cUnit, mir, low);
920         highLoc = dvmCompilerGetDest(cUnit, mir, high);
921     }
922     /* Avoid this case by either promoting both or neither. */
923     assert(lowLoc.location == highLoc.location);
924     if (lowLoc.location == kLocPhysReg) {
925         /* This case shouldn't happen if we've named correctly */
926         assert(lowLoc.fp == highLoc.fp);
927     }
928     lowLoc.wide = true;
929     lowLoc.highReg = highLoc.lowReg;
930     return lowLoc;
931 }
932 
dvmCompilerGetDestWide(CompilationUnit * cUnit,MIR * mir,int low,int high)933 extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
934                                           int low, int high)
935 {
936     return getLocWide(cUnit, mir, low, high, false);
937 }
938 
dvmCompilerGetSrcWide(CompilationUnit * cUnit,MIR * mir,int low,int high)939 extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
940                                          int low, int high)
941 {
942     return getLocWide(cUnit, mir, low, high, true);
943 }
944 
dvmCompilerGetReturnWide(CompilationUnit * cUnit)945 extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit)
946 {
947     RegLocation res = LOC_C_RETURN_WIDE;
948     dvmCompilerClobber(cUnit, r0);
949     dvmCompilerClobber(cUnit, r1);
950     dvmCompilerMarkInUse(cUnit, r0);
951     dvmCompilerMarkInUse(cUnit, r1);
952     dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
953     return res;
954 }
955 
dvmCompilerGetReturnWideAlt(CompilationUnit * cUnit)956 extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit)
957 {
958     RegLocation res = LOC_C_RETURN_WIDE;
959     res.lowReg = r2;
960     res.highReg = r3;
961     dvmCompilerClobber(cUnit, r2);
962     dvmCompilerClobber(cUnit, r3);
963     dvmCompilerMarkInUse(cUnit, r2);
964     dvmCompilerMarkInUse(cUnit, r3);
965     dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
966     return res;
967 }
968 
dvmCompilerGetReturn(CompilationUnit * cUnit)969 extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit)
970 {
971     RegLocation res = LOC_C_RETURN;
972     dvmCompilerClobber(cUnit, r0);
973     dvmCompilerMarkInUse(cUnit, r0);
974     return res;
975 }
976 
dvmCompilerGetReturnAlt(CompilationUnit * cUnit)977 extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit)
978 {
979     RegLocation res = LOC_C_RETURN;
980     res.lowReg = r1;
981     dvmCompilerClobber(cUnit, r1);
982     dvmCompilerMarkInUse(cUnit, r1);
983     return res;
984 }
985 
986 /* Kill the corresponding bit in the null-checked register list */
dvmCompilerKillNullCheckedLoc(CompilationUnit * cUnit,RegLocation loc)987 extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit,
988                                           RegLocation loc)
989 {
990     if (loc.location != kLocRetval) {
991         assert(loc.sRegLow != INVALID_SREG);
992         dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
993         if (loc.wide) {
994             assert(dvmCompilerSRegHi(loc.sRegLow) != INVALID_SREG);
995             dvmClearBit(cUnit->regPool->nullCheckedRegs,
996                         dvmCompilerSRegHi(loc.sRegLow));
997         }
998     }
999 }
1000 
dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit * cUnit,int reg1,int reg2)1001 extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
1002                                               int reg1, int reg2)
1003 {
1004     flushRegWide(cUnit, reg1, reg2);
1005 }
1006 
dvmCompilerFlushRegForV5TEVFP(CompilationUnit * cUnit,int reg)1007 extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
1008 {
1009     flushReg(cUnit, reg);
1010 }
1011