Home | History | Annotate | Download | only in arm
      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  */
     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 */
     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 
     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 
    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 
    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 
    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 */
    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. */
    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 
    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 */
    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 
    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.
    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 */
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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  */
    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 */
    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. */
    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 
    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 
    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  */
    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  */
    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 
    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 
    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 
    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 
    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 
    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 */
    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
    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 
    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
    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 
    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 
    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 
    695 extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
    696 {
    697     RegisterInfo *info = getRegInfo(cUnit, reg);
    698     info->dirty = false;
    699 }
    700 
    701 extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg)
    702 {
    703     RegisterInfo *info = getRegInfo(cUnit, reg);
    704     info->dirty = true;
    705 }
    706 
    707 extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg)
    708 {
    709       RegisterInfo *info = getRegInfo(cUnit, reg);
    710           info->inUse = true;
    711 }
    712 
    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  */
    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 */
    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 
    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 
    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 
    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.
    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.
    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 
    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 
    933 extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
    934                                           int low, int high)
    935 {
    936     return getLocWide(cUnit, mir, low, high, false);
    937 }
    938 
    939 extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
    940                                          int low, int high)
    941 {
    942     return getLocWide(cUnit, mir, low, high, true);
    943 }
    944 
    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 
    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 
    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 
    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 */
    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 
   1001 extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
   1002                                               int reg1, int reg2)
   1003 {
   1004     flushRegWide(cUnit, reg1, reg2);
   1005 }
   1006 
   1007 extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
   1008 {
   1009     flushReg(cUnit, reg);
   1010 }
   1011