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 static void lockArgRegs(CompilationUnit *cUnit)
    467 {
    468     dvmCompilerLockTemp(cUnit, r0);
    469     dvmCompilerLockTemp(cUnit, r1);
    470     dvmCompilerLockTemp(cUnit, r2);
    471     dvmCompilerLockTemp(cUnit, r3);
    472 }
    473 
    474 /* Clobber all regs that might be used by an external C call */
    475 extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit)
    476 {
    477     dvmCompilerClobber(cUnit, r0);
    478     dvmCompilerClobber(cUnit, r1);
    479     dvmCompilerClobber(cUnit, r2);
    480     dvmCompilerClobber(cUnit, r3);
    481     dvmCompilerClobber(cUnit, r9); // Need to do this?, be conservative
    482     dvmCompilerClobber(cUnit, r11);
    483     dvmCompilerClobber(cUnit, r12);
    484     dvmCompilerClobber(cUnit, rlr);
    485 }
    486 
    487 /* Clobber all of the temps that might be used by a handler. */
    488 extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit)
    489 {
    490     //TUNING: reduce the set of regs used by handlers.  Only a few need lots.
    491     dvmCompilerClobberCallRegs(cUnit);
    492     dvmCompilerClobber(cUnit, r4PC);
    493     dvmCompilerClobber(cUnit, r7);
    494     dvmCompilerClobber(cUnit, r8);
    495     dvmCompilerClobber(cUnit, r9);
    496     dvmCompilerClobber(cUnit, r10);
    497 }
    498 
    499 extern void dvmCompilerResetDef(CompilationUnit *cUnit, int reg)
    500 {
    501     RegisterInfo *p = getRegInfo(cUnit, reg);
    502     p->defStart = NULL;
    503     p->defEnd = NULL;
    504 }
    505 
    506 static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
    507                          int sReg1, int sReg2)
    508 {
    509     if (start && finish) {
    510         LIR *p;
    511         assert(sReg1 == sReg2);
    512         for (p = start; ;p = p->next) {
    513             ((ArmLIR *)p)->isNop = true;
    514             if (p == finish)
    515                 break;
    516         }
    517     }
    518 }
    519 
    520 /*
    521  * Mark the beginning and end LIR of a def sequence.  Note that
    522  * on entry start points to the LIR prior to the beginning of the
    523  * sequence.
    524  */
    525 extern void dvmCompilerMarkDef(CompilationUnit *cUnit, RegLocation rl,
    526                     LIR *start, LIR *finish)
    527 {
    528     assert(!rl.wide);
    529     assert(start && start->next);
    530     assert(finish);
    531     RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
    532     p->defStart = start->next;
    533     p->defEnd = finish;
    534 }
    535 
    536 /*
    537  * Mark the beginning and end LIR of a def sequence.  Note that
    538  * on entry start points to the LIR prior to the beginning of the
    539  * sequence.
    540  */
    541 extern void dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl,
    542                         LIR *start, LIR *finish)
    543 {
    544     assert(rl.wide);
    545     assert(start && start->next);
    546     assert(finish);
    547     RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
    548     dvmCompilerResetDef(cUnit, rl.highReg);  // Only track low of pair
    549     p->defStart = start->next;
    550     p->defEnd = finish;
    551 }
    552 
    553 extern RegLocation dvmCompilerWideToNarrow(CompilationUnit *cUnit,
    554                                            RegLocation rl)
    555 {
    556     assert(rl.wide);
    557     if (rl.location == kLocPhysReg) {
    558         RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
    559         RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
    560         if (!infoLo->pair) {
    561             dumpRegPool(cUnit->regPool->coreTemps,
    562                         cUnit->regPool->numCoreTemps);
    563             assert(infoLo->pair);
    564         }
    565         if (!infoHi->pair) {
    566             dumpRegPool(cUnit->regPool->coreTemps,
    567                         cUnit->regPool->numCoreTemps);
    568             assert(infoHi->pair);
    569         }
    570         assert(infoLo->pair);
    571         assert(infoHi->pair);
    572         assert(infoLo->partner == infoHi->reg);
    573         assert(infoHi->partner == infoLo->reg);
    574         infoLo->pair = false;
    575         infoHi->pair = false;
    576         infoLo->defStart = NULL;
    577         infoLo->defEnd = NULL;
    578         infoHi->defStart = NULL;
    579         infoHi->defEnd = NULL;
    580     }
    581     rl.wide = false;
    582     return rl;
    583 }
    584 
    585 extern void dvmCompilerResetDefLoc(CompilationUnit *cUnit, RegLocation rl)
    586 {
    587     assert(!rl.wide);
    588     if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
    589         RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
    590         assert(!p->pair);
    591         nullifyRange(cUnit, p->defStart, p->defEnd,
    592                      p->sReg, rl.sRegLow);
    593     }
    594     dvmCompilerResetDef(cUnit, rl.lowReg);
    595 }
    596 
    597 extern void dvmCompilerResetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
    598 {
    599     assert(rl.wide);
    600     if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
    601         RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
    602         assert(p->pair);
    603         nullifyRange(cUnit, p->defStart, p->defEnd,
    604                      p->sReg, rl.sRegLow);
    605     }
    606     dvmCompilerResetDef(cUnit, rl.lowReg);
    607     dvmCompilerResetDef(cUnit, rl.highReg);
    608 }
    609 
    610 extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit)
    611 {
    612     int i;
    613     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
    614         dvmCompilerResetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
    615     }
    616     for (i=0; i< cUnit->regPool->numFPTemps; i++) {
    617         dvmCompilerResetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
    618     }
    619 }
    620 
    621 extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit)
    622 {
    623     int i;
    624     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
    625         dvmCompilerClobber(cUnit, cUnit->regPool->coreTemps[i].reg);
    626     }
    627     for (i=0; i< cUnit->regPool->numFPTemps; i++) {
    628         dvmCompilerClobber(cUnit, cUnit->regPool->FPTemps[i].reg);
    629     }
    630 }
    631 
    632 /* To be used when explicitly managing register use */
    633 extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit)
    634 {
    635     int i;
    636     for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
    637         dvmCompilerLockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
    638     }
    639 }
    640 
    641 // Make sure nothing is live and dirty
    642 static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
    643                              int numRegs)
    644 {
    645     int i;
    646     for (i=0; i < numRegs; i++) {
    647         if (info[i].live && info[i].dirty) {
    648             if (info[i].pair) {
    649                 flushRegWide(cUnit, info[i].reg, info[i].partner);
    650             } else {
    651                 flushReg(cUnit, info[i].reg);
    652             }
    653         }
    654     }
    655 }
    656 
    657 extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit)
    658 {
    659     flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
    660                      cUnit->regPool->numCoreTemps);
    661     flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
    662                      cUnit->regPool->numFPTemps);
    663     dvmCompilerClobberAllRegs(cUnit);
    664 }
    665 
    666 
    667 //TUNING: rewrite all of this reg stuff.  Probably use an attribute table
    668 static bool regClassMatches(int regClass, int reg)
    669 {
    670     if (regClass == kAnyReg) {
    671         return true;
    672     } else if (regClass == kCoreReg) {
    673         return !FPREG(reg);
    674     } else {
    675         return FPREG(reg);
    676     }
    677 }
    678 
    679 extern void dvmCompilerMarkLive(CompilationUnit *cUnit, int reg, int sReg)
    680 {
    681     RegisterInfo *info = getRegInfo(cUnit, reg);
    682     if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
    683         return;  /* already live */
    684     } else if (sReg != INVALID_SREG) {
    685         dvmCompilerClobberSReg(cUnit, sReg);
    686         info->live = true;
    687     } else {
    688         /* Can't be live if no associated sReg */
    689         info->live = false;
    690     }
    691     info->sReg = sReg;
    692 }
    693 
    694 extern void dvmCompilerMarkPair(CompilationUnit *cUnit, int lowReg, int highReg)
    695 {
    696     RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
    697     RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
    698     infoLo->pair = infoHi->pair = true;
    699     infoLo->partner = highReg;
    700     infoHi->partner = lowReg;
    701 }
    702 
    703 static void markRegSingle(CompilationUnit *cUnit, int reg)
    704 {
    705     RegisterInfo *info = getRegInfo(cUnit, reg);
    706     info->pair = false;
    707 }
    708 
    709 extern void dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
    710 {
    711     RegisterInfo *info = getRegInfo(cUnit, reg);
    712     info->dirty = false;
    713 }
    714 
    715 extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg)
    716 {
    717     RegisterInfo *info = getRegInfo(cUnit, reg);
    718     info->dirty = true;
    719 }
    720 
    721 extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg)
    722 {
    723       RegisterInfo *info = getRegInfo(cUnit, reg);
    724           info->inUse = true;
    725 }
    726 
    727 /* Return true if live & dirty */
    728 static bool isDirty(CompilationUnit *cUnit, int reg)
    729 {
    730     RegisterInfo *info = getRegInfo(cUnit, reg);
    731     return (info && info->live && info->dirty);
    732 }
    733 
    734 void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
    735 {
    736     RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
    737     RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
    738     *newInfo = *oldInfo;
    739     newInfo->reg = newReg;
    740 }
    741 
    742 /*
    743  * Return an updated location record with current in-register status.
    744  * If the value lives in live temps, reflect that fact.  No code
    745  * is generated.  The the live value is part of an older pair,
    746  * clobber both low and high.
    747  * TUNING: clobbering both is a bit heavy-handed, but the alternative
    748  * is a bit complex when dealing with FP regs.  Examine code to see
    749  * if it's worthwhile trying to be more clever here.
    750  */
    751 extern RegLocation dvmCompilerUpdateLoc(CompilationUnit *cUnit, RegLocation loc)
    752 {
    753     assert(!loc.wide);
    754     if (loc.location == kLocDalvikFrame) {
    755         RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
    756         if (infoLo) {
    757             if (infoLo->pair) {
    758                 dvmCompilerClobber(cUnit, infoLo->reg);
    759                 dvmCompilerClobber(cUnit, infoLo->partner);
    760             } else {
    761                 loc.lowReg = infoLo->reg;
    762                 loc.location = kLocPhysReg;
    763             }
    764         }
    765     }
    766 
    767     return loc;
    768 }
    769 
    770 /* see comments for updateLoc */
    771 extern RegLocation dvmCompilerUpdateLocWide(CompilationUnit *cUnit,
    772                                             RegLocation loc)
    773 {
    774     assert(loc.wide);
    775     if (loc.location == kLocDalvikFrame) {
    776         // Are the dalvik regs already live in physical registers?
    777         RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
    778         RegisterInfo *infoHi = allocLive(cUnit,
    779               dvmCompilerSRegHi(loc.sRegLow), kAnyReg);
    780         bool match = true;
    781         match = match && (infoLo != NULL);
    782         match = match && (infoHi != NULL);
    783         // Are they both core or both FP?
    784         match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
    785         // If a pair of floating point singles, are they properly aligned?
    786         if (match && FPREG(infoLo->reg)) {
    787             match &= ((infoLo->reg & 0x1) == 0);
    788             match &= ((infoHi->reg - infoLo->reg) == 1);
    789         }
    790         // If previously used as a pair, it is the same pair?
    791         if (match && (infoLo->pair || infoHi->pair)) {
    792             match = (infoLo->pair == infoHi->pair);
    793             match &= ((infoLo->reg == infoHi->partner) &&
    794                       (infoHi->reg == infoLo->partner));
    795         }
    796         if (match) {
    797             // Can reuse - update the register usage info
    798             loc.lowReg = infoLo->reg;
    799             loc.highReg = infoHi->reg;
    800             loc.location = kLocPhysReg;
    801             dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
    802             assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
    803             return loc;
    804         }
    805         // Can't easily reuse - clobber any overlaps
    806         if (infoLo) {
    807             dvmCompilerClobber(cUnit, infoLo->reg);
    808             if (infoLo->pair)
    809                 dvmCompilerClobber(cUnit, infoLo->partner);
    810         }
    811         if (infoHi) {
    812             dvmCompilerClobber(cUnit, infoHi->reg);
    813             if (infoHi->pair)
    814                 dvmCompilerClobber(cUnit, infoHi->partner);
    815         }
    816     }
    817 
    818     return loc;
    819 }
    820 
    821 static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
    822                                int regClass, bool update)
    823 {
    824     assert(loc.wide);
    825     int newRegs;
    826     int lowReg;
    827     int highReg;
    828 
    829     loc = dvmCompilerUpdateLocWide(cUnit, loc);
    830 
    831     /* If already in registers, we can assume proper form.  Right reg class? */
    832     if (loc.location == kLocPhysReg) {
    833         assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
    834         assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
    835         if (!regClassMatches(regClass, loc.lowReg)) {
    836             /* Wrong register class.  Reallocate and copy */
    837             newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
    838             lowReg = newRegs & 0xff;
    839             highReg = (newRegs >> 8) & 0xff;
    840             dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
    841                                    loc.highReg);
    842             copyRegInfo(cUnit, lowReg, loc.lowReg);
    843             copyRegInfo(cUnit, highReg, loc.highReg);
    844             dvmCompilerClobber(cUnit, loc.lowReg);
    845             dvmCompilerClobber(cUnit, loc.highReg);
    846             loc.lowReg = lowReg;
    847             loc.highReg = highReg;
    848             dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
    849             assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
    850         }
    851         return loc;
    852     }
    853 
    854     assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
    855     assert((loc.location != kLocRetval) ||
    856            (dvmCompilerSRegHi(loc.sRegLow) == INVALID_SREG));
    857 
    858     newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
    859     loc.lowReg = newRegs & 0xff;
    860     loc.highReg = (newRegs >> 8) & 0xff;
    861 
    862     dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
    863     if (update) {
    864         loc.location = kLocPhysReg;
    865         dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
    866         dvmCompilerMarkLive(cUnit, loc.highReg, dvmCompilerSRegHi(loc.sRegLow));
    867     }
    868     assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
    869     return loc;
    870 }
    871 
    872 extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
    873                                       int regClass, bool update)
    874 {
    875     RegisterInfo *infoLo = NULL;
    876     int newReg;
    877     if (loc.wide)
    878         return evalLocWide(cUnit, loc, regClass, update);
    879     loc = dvmCompilerUpdateLoc(cUnit, loc);
    880 
    881     if (loc.location == kLocPhysReg) {
    882         if (!regClassMatches(regClass, loc.lowReg)) {
    883             /* Wrong register class.  Realloc, copy and transfer ownership */
    884             newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
    885             dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
    886             copyRegInfo(cUnit, newReg, loc.lowReg);
    887             dvmCompilerClobber(cUnit, loc.lowReg);
    888             loc.lowReg = newReg;
    889         }
    890         return loc;
    891     }
    892 
    893     assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
    894 
    895     newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
    896     loc.lowReg = newReg;
    897 
    898     if (update) {
    899         loc.location = kLocPhysReg;
    900         dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
    901     }
    902     return loc;
    903 }
    904 
    905 static inline int getDestSSAName(MIR *mir, int num)
    906 {
    907     assert(mir->ssaRep->numDefs > num);
    908     return mir->ssaRep->defs[num];
    909 }
    910 
    911 // Get the LocRecord associated with an SSA name use.
    912 extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num)
    913 {
    914     RegLocation loc = cUnit->regLocation[
    915          SREG(cUnit, dvmCompilerSSASrc(mir, num))];
    916     loc.fp = cUnit->regLocation[dvmCompilerSSASrc(mir, num)].fp;
    917     loc.wide = false;
    918     return loc;
    919 }
    920 
    921 // Get the LocRecord associated with an SSA name def.
    922 extern RegLocation dvmCompilerGetDest(CompilationUnit *cUnit, MIR *mir,
    923                                       int num)
    924 {
    925     RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
    926     loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
    927     loc.wide = false;
    928     return loc;
    929 }
    930 
    931 static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
    932                               int low, int high, bool isSrc)
    933 {
    934     RegLocation lowLoc;
    935     RegLocation highLoc;
    936     /* Copy loc record for low word and patch in data from high word */
    937     if (isSrc) {
    938         lowLoc = dvmCompilerGetSrc(cUnit, mir, low);
    939         highLoc = dvmCompilerGetSrc(cUnit, mir, high);
    940     } else {
    941         lowLoc = dvmCompilerGetDest(cUnit, mir, low);
    942         highLoc = dvmCompilerGetDest(cUnit, mir, high);
    943     }
    944     /* Avoid this case by either promoting both or neither. */
    945     assert(lowLoc.location == highLoc.location);
    946     if (lowLoc.location == kLocPhysReg) {
    947         /* This case shouldn't happen if we've named correctly */
    948         assert(lowLoc.fp == highLoc.fp);
    949     }
    950     lowLoc.wide = true;
    951     lowLoc.highReg = highLoc.lowReg;
    952     return lowLoc;
    953 }
    954 
    955 extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
    956                                           int low, int high)
    957 {
    958     return getLocWide(cUnit, mir, low, high, false);
    959 }
    960 
    961 extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
    962                                          int low, int high)
    963 {
    964     return getLocWide(cUnit, mir, low, high, true);
    965 }
    966 
    967 extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit)
    968 {
    969     RegLocation res = LOC_C_RETURN_WIDE;
    970     dvmCompilerClobber(cUnit, r0);
    971     dvmCompilerClobber(cUnit, r1);
    972     dvmCompilerMarkInUse(cUnit, r0);
    973     dvmCompilerMarkInUse(cUnit, r1);
    974     dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
    975     return res;
    976 }
    977 
    978 extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit)
    979 {
    980     RegLocation res = LOC_C_RETURN_WIDE;
    981     res.lowReg = r2;
    982     res.highReg = r3;
    983     dvmCompilerClobber(cUnit, r2);
    984     dvmCompilerClobber(cUnit, r3);
    985     dvmCompilerMarkInUse(cUnit, r2);
    986     dvmCompilerMarkInUse(cUnit, r3);
    987     dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
    988     return res;
    989 }
    990 
    991 extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit)
    992 {
    993     RegLocation res = LOC_C_RETURN;
    994     dvmCompilerClobber(cUnit, r0);
    995     dvmCompilerMarkInUse(cUnit, r0);
    996     return res;
    997 }
    998 
    999 extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit)
   1000 {
   1001     RegLocation res = LOC_C_RETURN;
   1002     res.lowReg = r1;
   1003     dvmCompilerClobber(cUnit, r1);
   1004     dvmCompilerMarkInUse(cUnit, r1);
   1005     return res;
   1006 }
   1007 
   1008 /* Kill the corresponding bit in the null-checked register list */
   1009 extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit,
   1010                                           RegLocation loc)
   1011 {
   1012     if (loc.location != kLocRetval) {
   1013         assert(loc.sRegLow != INVALID_SREG);
   1014         dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
   1015         if (loc.wide) {
   1016             assert(dvmCompilerSRegHi(loc.sRegLow) != INVALID_SREG);
   1017             dvmClearBit(cUnit->regPool->nullCheckedRegs,
   1018                         dvmCompilerSRegHi(loc.sRegLow));
   1019         }
   1020     }
   1021 }
   1022 
   1023 extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
   1024                                               int reg1, int reg2)
   1025 {
   1026     flushRegWide(cUnit, reg1, reg2);
   1027 }
   1028 
   1029 extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
   1030 {
   1031     flushReg(cUnit, reg);
   1032 }
   1033