Home | History | Annotate | Download | only in Mips32
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * This file contains codegen for the Thumb ISA and is intended to be
     19  * includes by:
     20  *
     21  *        Codegen-$(TARGET_ARCH_VARIANT).c
     22  *
     23  */
     24 
     25 static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
     26                           r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9, r_S0, r_S4};
     27 #ifdef __mips_hard_float
     28 static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
     29                         r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
     30 #endif
     31 
     32 static void storePair(CompilationUnit *cUnit, int base, int lowReg,
     33                       int highReg);
     34 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
     35 static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
     36                             int rDest);
     37 static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
     38                              int displacement, int rSrc);
     39 static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
     40                               MipsConditionCode cond,
     41                               int reg1, int reg2, int dOffset,
     42                               MipsLIR *pcrLabel);
     43 static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
     44 
     45 #ifdef __mips_hard_float
     46 static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
     47 {
     48     MipsLIR* res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
     49     res->operands[0] = rDest;
     50     res->operands[1] = rSrc;
     51     if (rDest == rSrc) {
     52         res->flags.isNop = true;
     53     } else {
     54         /* must be both DOUBLE or both not DOUBLE */
     55         assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
     56         if (DOUBLEREG(rDest)) {
     57             res->opcode = kMipsFmovd;
     58         } else {
     59             if (SINGLEREG(rDest)) {
     60                 if (SINGLEREG(rSrc)) {
     61                     res->opcode = kMipsFmovs;
     62                 } else {
     63                     /* note the operands are swapped for the mtc1 instr */
     64                     res->opcode = kMipsMtc1;
     65                     res->operands[0] = rSrc;
     66                     res->operands[1] = rDest;
     67                 }
     68             } else {
     69                 assert(SINGLEREG(rSrc));
     70                 res->opcode = kMipsMfc1;
     71             }
     72         }
     73     }
     74     setupResourceMasks(res);
     75     return res;
     76 }
     77 #endif
     78 
     79 /*
     80  * Load a immediate using a shortcut if possible; otherwise
     81  * grab from the per-translation literal pool.  If target is
     82  * a high register, build constant into a low register and copy.
     83  *
     84  * No additional register clobbering operation performed. Use this version when
     85  * 1) rDest is freshly returned from dvmCompilerAllocTemp or
     86  * 2) The codegen is under fixed register usage
     87  */
     88 static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
     89                                      int value)
     90 {
     91     MipsLIR *res;
     92 
     93 #ifdef __mips_hard_float
     94     int rDestSave = rDest;
     95     int isFpReg = FPREG(rDest);
     96     if (isFpReg) {
     97         assert(SINGLEREG(rDest));
     98         rDest = dvmCompilerAllocTemp(cUnit);
     99     }
    100 #endif
    101 
    102     /* See if the value can be constructed cheaply */
    103     if (value == 0) {
    104         res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO);
    105     } else if ((value > 0) && (value <= 65535)) {
    106         res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value);
    107     } else if ((value < 0) && (value >= -32768)) {
    108         res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value);
    109     } else {
    110         res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
    111         if (value & 0xffff)
    112 	    newLIR3(cUnit, kMipsOri, rDest, rDest, value);
    113     }
    114 
    115 #ifdef __mips_hard_float
    116     if (isFpReg) {
    117         newLIR2(cUnit, kMipsMtc1, rDest, rDestSave);
    118         dvmCompilerFreeTemp(cUnit, rDest);
    119     }
    120 #endif
    121 
    122     return res;
    123 }
    124 
    125 /*
    126  * Load an immediate value into a fixed or temp register.  Target
    127  * register is clobbered, and marked inUse.
    128  */
    129 static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
    130 {
    131     if (dvmCompilerIsTemp(cUnit, rDest)) {
    132         dvmCompilerClobber(cUnit, rDest);
    133         dvmCompilerMarkInUse(cUnit, rDest);
    134     }
    135     return loadConstantNoClobber(cUnit, rDest, value);
    136 }
    137 
    138 /*
    139  * Load a class pointer value into a fixed or temp register.  Target
    140  * register is clobbered, and marked inUse.
    141  */
    142 static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
    143 {
    144     MipsLIR *res;
    145     if (dvmCompilerIsTemp(cUnit, rDest)) {
    146         dvmCompilerClobber(cUnit, rDest);
    147         dvmCompilerMarkInUse(cUnit, rDest);
    148     }
    149     res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
    150     if (value & 0xffff)
    151         newLIR3(cUnit, kMipsOri, rDest, rDest, value);
    152     return res;
    153 }
    154 
    155 static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op)
    156 {
    157     MipsLIR *res;
    158     MipsOpCode opcode = kMipsNop;
    159     switch (op) {
    160         case kOpUncondBr:
    161             opcode = kMipsB;
    162             break;
    163         default:
    164             ALOGE("Jit: bad case in opNone");
    165             dvmCompilerAbort(cUnit);
    166     }
    167     res = newLIR0(cUnit, opcode);
    168     return res;
    169 }
    170 
    171 static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt)
    172 {
    173     MipsLIR *res;
    174     if (rt < 0) {
    175       assert(opc >= kMipsBeqz && opc <= kMipsBnez);
    176       res = newLIR1(cUnit, opc, rs);
    177     } else  {
    178       assert(opc == kMipsBeq || opc == kMipsBne);
    179       res = newLIR2(cUnit, opc, rs, rt);
    180     }
    181     return res;
    182 }
    183 
    184 static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
    185 
    186 static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
    187 {
    188     MipsOpCode opcode = kMipsNop;
    189     switch (op) {
    190         case kOpBlx:
    191             opcode = kMipsJalr;
    192             break;
    193         default:
    194             assert(0);
    195     }
    196     return newLIR2(cUnit, opcode, r_RA, rDestSrc);
    197 }
    198 
    199 static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
    200                            int rSrc1, int value);
    201 static MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
    202                         int value)
    203 {
    204     MipsLIR *res;
    205     bool neg = (value < 0);
    206     int absValue = (neg) ? -value : value;
    207     bool shortForm = (absValue & 0xff) == absValue;
    208     MipsOpCode opcode = kMipsNop;
    209     switch (op) {
    210         case kOpAdd:
    211             return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
    212             break;
    213         case kOpSub:
    214             return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
    215             break;
    216         default:
    217             ALOGE("Jit: bad case in opRegImm");
    218             dvmCompilerAbort(cUnit);
    219             break;
    220     }
    221     if (shortForm)
    222         res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
    223     else {
    224         int rScratch = dvmCompilerAllocTemp(cUnit);
    225         res = loadConstant(cUnit, rScratch, value);
    226         if (op == kOpCmp)
    227             newLIR2(cUnit, opcode, rDestSrc1, rScratch);
    228         else
    229             newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
    230     }
    231     return res;
    232 }
    233 
    234 static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
    235                            int rSrc1, int rSrc2)
    236 {
    237     MipsOpCode opcode = kMipsNop;
    238     switch (op) {
    239         case kOpAdd:
    240             opcode = kMipsAddu;
    241             break;
    242         case kOpSub:
    243             opcode = kMipsSubu;
    244             break;
    245         case kOpAnd:
    246             opcode = kMipsAnd;
    247             break;
    248         case kOpMul:
    249             opcode = kMipsMul;
    250             break;
    251         case kOpOr:
    252             opcode = kMipsOr;
    253             break;
    254         case kOpXor:
    255             opcode = kMipsXor;
    256             break;
    257         case kOpLsl:
    258             opcode = kMipsSllv;
    259             break;
    260         case kOpLsr:
    261             opcode = kMipsSrlv;
    262             break;
    263         case kOpAsr:
    264             opcode = kMipsSrav;
    265             break;
    266         default:
    267             ALOGE("Jit: bad case in opRegRegReg");
    268             dvmCompilerAbort(cUnit);
    269             break;
    270     }
    271     return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
    272 }
    273 
    274 static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
    275                            int rSrc1, int value)
    276 {
    277     MipsLIR *res;
    278     MipsOpCode opcode = kMipsNop;
    279     bool shortForm = true;
    280 
    281     switch(op) {
    282         case kOpAdd:
    283             if (IS_SIMM16(value)) {
    284                 opcode = kMipsAddiu;
    285             }
    286             else {
    287                 shortForm = false;
    288                 opcode = kMipsAddu;
    289             }
    290             break;
    291         case kOpSub:
    292             if (IS_SIMM16((-value))) {
    293                 value = -value;
    294                 opcode = kMipsAddiu;
    295             }
    296             else {
    297                 shortForm = false;
    298                 opcode = kMipsSubu;
    299             }
    300             break;
    301         case kOpLsl:
    302                 assert(value >= 0 && value <= 31);
    303                 opcode = kMipsSll;
    304                 break;
    305         case kOpLsr:
    306                 assert(value >= 0 && value <= 31);
    307                 opcode = kMipsSrl;
    308                 break;
    309         case kOpAsr:
    310                 assert(value >= 0 && value <= 31);
    311                 opcode = kMipsSra;
    312                 break;
    313         case kOpAnd:
    314             if (IS_UIMM16((value))) {
    315                 opcode = kMipsAndi;
    316             }
    317             else {
    318                 shortForm = false;
    319                 opcode = kMipsAnd;
    320             }
    321             break;
    322         case kOpOr:
    323             if (IS_UIMM16((value))) {
    324                 opcode = kMipsOri;
    325             }
    326             else {
    327                 shortForm = false;
    328                 opcode = kMipsOr;
    329             }
    330             break;
    331         case kOpXor:
    332             if (IS_UIMM16((value))) {
    333                 opcode = kMipsXori;
    334             }
    335             else {
    336                 shortForm = false;
    337                 opcode = kMipsXor;
    338             }
    339             break;
    340         case kOpMul:
    341             shortForm = false;
    342             opcode = kMipsMul;
    343             break;
    344         default:
    345             ALOGE("Jit: bad case in opRegRegImm");
    346             dvmCompilerAbort(cUnit);
    347             break;
    348     }
    349 
    350     if (shortForm)
    351         res = newLIR3(cUnit, opcode, rDest, rSrc1, value);
    352     else {
    353         if (rDest != rSrc1) {
    354             res = loadConstant(cUnit, rDest, value);
    355             newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
    356         } else {
    357             int rScratch = dvmCompilerAllocTemp(cUnit);
    358             res = loadConstant(cUnit, rScratch, value);
    359             newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
    360         }
    361     }
    362     return res;
    363 }
    364 
    365 static MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
    366                         int rSrc2)
    367 {
    368     MipsOpCode opcode = kMipsNop;
    369     MipsLIR *res;
    370     switch (op) {
    371         case kOpMov:
    372             opcode = kMipsMove;
    373             break;
    374         case kOpMvn:
    375             return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO);
    376         case kOpNeg:
    377             return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2);
    378         case kOpAdd:
    379         case kOpAnd:
    380         case kOpMul:
    381         case kOpOr:
    382         case kOpSub:
    383         case kOpXor:
    384             return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
    385         case kOp2Byte:
    386 #if __mips_isa_rev>=2
    387             res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2);
    388 #else
    389             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
    390             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
    391 #endif
    392             return res;
    393         case kOp2Short:
    394 #if __mips_isa_rev>=2
    395             res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2);
    396 #else
    397             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
    398             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
    399 #endif
    400             return res;
    401         case kOp2Char:
    402              return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF);
    403         default:
    404             ALOGE("Jit: bad case in opRegReg");
    405             dvmCompilerAbort(cUnit);
    406             break;
    407     }
    408     return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
    409 }
    410 
    411 static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
    412                                      int rDestHi, int valLo, int valHi)
    413 {
    414     MipsLIR *res;
    415     res = loadConstantNoClobber(cUnit, rDestLo, valLo);
    416     loadConstantNoClobber(cUnit, rDestHi, valHi);
    417     return res;
    418 }
    419 
    420 /* Load value from base + scaled index. */
    421 static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
    422                                int rIndex, int rDest, int scale, OpSize size)
    423 {
    424     MipsLIR *first = NULL;
    425     MipsLIR *res;
    426     MipsOpCode opcode = kMipsNop;
    427     int tReg = dvmCompilerAllocTemp(cUnit);
    428 
    429 #ifdef __mips_hard_float
    430     if (FPREG(rDest)) {
    431         assert(SINGLEREG(rDest));
    432         assert((size == kWord) || (size == kSingle));
    433         size = kSingle;
    434     } else {
    435         if (size == kSingle)
    436             size = kWord;
    437     }
    438 #endif
    439 
    440     if (!scale) {
    441         first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
    442     } else {
    443         first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
    444         newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
    445     }
    446 
    447     switch (size) {
    448 #ifdef __mips_hard_float
    449         case kSingle:
    450             opcode = kMipsFlwc1;
    451             break;
    452 #endif
    453         case kWord:
    454             opcode = kMipsLw;
    455             break;
    456         case kUnsignedHalf:
    457             opcode = kMipsLhu;
    458             break;
    459         case kSignedHalf:
    460             opcode = kMipsLh;
    461             break;
    462         case kUnsignedByte:
    463             opcode = kMipsLbu;
    464             break;
    465         case kSignedByte:
    466             opcode = kMipsLb;
    467             break;
    468         default:
    469             ALOGE("Jit: bad case in loadBaseIndexed");
    470             dvmCompilerAbort(cUnit);
    471     }
    472 
    473     res = newLIR3(cUnit, opcode, rDest, 0, tReg);
    474 #if defined(WITH_SELF_VERIFICATION)
    475     if (cUnit->heapMemOp)
    476         res->flags.insertWrapper = true;
    477 #endif
    478     dvmCompilerFreeTemp(cUnit, tReg);
    479     return (first) ? first : res;
    480 }
    481 
    482 /* store value base base + scaled index. */
    483 static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
    484                                 int rIndex, int rSrc, int scale, OpSize size)
    485 {
    486     MipsLIR *first = NULL;
    487     MipsLIR *res;
    488     MipsOpCode opcode = kMipsNop;
    489     int rNewIndex = rIndex;
    490     int tReg = dvmCompilerAllocTemp(cUnit);
    491 
    492 #ifdef __mips_hard_float
    493     if (FPREG(rSrc)) {
    494         assert(SINGLEREG(rSrc));
    495         assert((size == kWord) || (size == kSingle));
    496         size = kSingle;
    497     } else {
    498         if (size == kSingle)
    499             size = kWord;
    500     }
    501 #endif
    502 
    503     if (!scale) {
    504         first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
    505     } else {
    506         first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
    507         newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
    508     }
    509 
    510     switch (size) {
    511 #ifdef __mips_hard_float
    512         case kSingle:
    513             opcode = kMipsFswc1;
    514             break;
    515 #endif
    516         case kWord:
    517             opcode = kMipsSw;
    518             break;
    519         case kUnsignedHalf:
    520         case kSignedHalf:
    521             opcode = kMipsSh;
    522             break;
    523         case kUnsignedByte:
    524         case kSignedByte:
    525             opcode = kMipsSb;
    526             break;
    527         default:
    528             ALOGE("Jit: bad case in storeBaseIndexed");
    529             dvmCompilerAbort(cUnit);
    530     }
    531     res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
    532 #if defined(WITH_SELF_VERIFICATION)
    533     if (cUnit->heapMemOp)
    534         res->flags.insertWrapper = true;
    535 #endif
    536     dvmCompilerFreeTemp(cUnit, rNewIndex);
    537     return first;
    538 }
    539 
    540 static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
    541 {
    542     int i;
    543     int loadCnt = 0;
    544     MipsLIR *res = NULL ;
    545     genBarrier(cUnit);
    546 
    547     for (i = 0; i < 8; i++, rMask >>= 1) {
    548         if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
    549             newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase);
    550             loadCnt++;
    551         }
    552     }
    553 
    554     if (loadCnt) {/* increment after */
    555         newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4);
    556     }
    557 
    558 #if defined(WITH_SELF_VERIFICATION)
    559     if (cUnit->heapMemOp)
    560         res->flags.insertWrapper = true;
    561 #endif
    562     genBarrier(cUnit);
    563     return res; /* NULL always returned which should be ok since no callers use it */
    564 }
    565 
    566 static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
    567 {
    568     int i;
    569     int storeCnt = 0;
    570     MipsLIR *res = NULL ;
    571     genBarrier(cUnit);
    572 
    573     for (i = 0; i < 8; i++, rMask >>= 1) {
    574         if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
    575             newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase);
    576             storeCnt++;
    577         }
    578     }
    579 
    580     if (storeCnt) { /* increment after */
    581         newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4);
    582     }
    583 
    584 #if defined(WITH_SELF_VERIFICATION)
    585     if (cUnit->heapMemOp)
    586         res->flags.insertWrapper = true;
    587 #endif
    588     genBarrier(cUnit);
    589     return res; /* NULL always returned which should be ok since no callers use it */
    590 }
    591 
    592 static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
    593                                 int displacement, int rDest, int rDestHi,
    594                                 OpSize size, int sReg)
    595 /*
    596  * Load value from base + displacement.  Optionally perform null check
    597  * on base (which must have an associated sReg and MIR).  If not
    598  * performing null check, incoming MIR can be null. IMPORTANT: this
    599  * code must not allocate any new temps.  If a new register is needed
    600  * and base and dest are the same, spill some other register to
    601  * rlp and then restore.
    602  */
    603 {
    604     MipsLIR *res;
    605     MipsLIR *load = NULL;
    606     MipsLIR *load2 = NULL;
    607     MipsOpCode opcode = kMipsNop;
    608     bool shortForm = IS_SIMM16(displacement);
    609     bool pair = false;
    610 
    611     switch (size) {
    612         case kLong:
    613         case kDouble:
    614             pair = true;
    615             opcode = kMipsLw;
    616 #ifdef __mips_hard_float
    617             if (FPREG(rDest)) {
    618                 opcode = kMipsFlwc1;
    619                 if (DOUBLEREG(rDest)) {
    620                     rDest = rDest - FP_DOUBLE;
    621                 } else {
    622                     assert(FPREG(rDestHi));
    623                     assert(rDest == (rDestHi - 1));
    624                 }
    625                 rDestHi = rDest + 1;
    626             }
    627 #endif
    628             shortForm = IS_SIMM16_2WORD(displacement);
    629             assert((displacement & 0x3) == 0);
    630             break;
    631         case kWord:
    632         case kSingle:
    633             opcode = kMipsLw;
    634 #ifdef __mips_hard_float
    635             if (FPREG(rDest)) {
    636                 opcode = kMipsFlwc1;
    637                 assert(SINGLEREG(rDest));
    638             }
    639 #endif
    640             assert((displacement & 0x3) == 0);
    641             break;
    642         case kUnsignedHalf:
    643             opcode = kMipsLhu;
    644             assert((displacement & 0x1) == 0);
    645             break;
    646         case kSignedHalf:
    647             opcode = kMipsLh;
    648             assert((displacement & 0x1) == 0);
    649             break;
    650         case kUnsignedByte:
    651             opcode = kMipsLbu;
    652             break;
    653         case kSignedByte:
    654             opcode = kMipsLb;
    655             break;
    656         default:
    657             ALOGE("Jit: bad case in loadBaseIndexedBody");
    658             dvmCompilerAbort(cUnit);
    659     }
    660 
    661     if (shortForm) {
    662         if (!pair) {
    663             load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase);
    664         } else {
    665             load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase);
    666             load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase);
    667         }
    668     } else {
    669         if (pair) {
    670             int rTmp = dvmCompilerAllocFreeTemp(cUnit);
    671             res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
    672             load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp);
    673             load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp);
    674             dvmCompilerFreeTemp(cUnit, rTmp);
    675         } else {
    676             int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit)
    677                                         : rDest;
    678             res = loadConstant(cUnit, rTmp, displacement);
    679             load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
    680             if (rTmp != rDest)
    681                 dvmCompilerFreeTemp(cUnit, rTmp);
    682         }
    683     }
    684 
    685     if (rBase == rFP) {
    686         if (load != NULL)
    687             annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
    688                                     true /* isLoad */);
    689         if (load2 != NULL)
    690             annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
    691                                     true /* isLoad */);
    692     }
    693 #if defined(WITH_SELF_VERIFICATION)
    694     if (load != NULL && cUnit->heapMemOp)
    695         load->flags.insertWrapper = true;
    696     if (load2 != NULL && cUnit->heapMemOp)
    697         load2->flags.insertWrapper = true;
    698 #endif
    699     return load;
    700 }
    701 
    702 static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
    703                             int displacement, int rDest, OpSize size,
    704                             int sReg)
    705 {
    706     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
    707                             size, sReg);
    708 }
    709 
    710 static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
    711                                 int displacement, int rDestLo, int rDestHi,
    712                                 int sReg)
    713 {
    714     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
    715                             kLong, sReg);
    716 }
    717 
    718 static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
    719                                  int displacement, int rSrc, int rSrcHi,
    720                                  OpSize size)
    721 {
    722     MipsLIR *res;
    723     MipsLIR *store = NULL;
    724     MipsLIR *store2 = NULL;
    725     MipsOpCode opcode = kMipsNop;
    726     bool shortForm = IS_SIMM16(displacement);
    727     bool pair = false;
    728 
    729     switch (size) {
    730         case kLong:
    731         case kDouble:
    732             pair = true;
    733             opcode = kMipsSw;
    734 #ifdef __mips_hard_float
    735             if (FPREG(rSrc)) {
    736                 opcode = kMipsFswc1;
    737                 if (DOUBLEREG(rSrc)) {
    738                     rSrc = rSrc - FP_DOUBLE;
    739                 } else {
    740                     assert(FPREG(rSrcHi));
    741                     assert(rSrc == (rSrcHi - 1));
    742                 }
    743                 rSrcHi = rSrc + 1;
    744             }
    745 #endif
    746             shortForm = IS_SIMM16_2WORD(displacement);
    747             assert((displacement & 0x3) == 0);
    748             break;
    749         case kWord:
    750         case kSingle:
    751             opcode = kMipsSw;
    752 #ifdef __mips_hard_float
    753             if (FPREG(rSrc)) {
    754                 opcode = kMipsFswc1;
    755                 assert(SINGLEREG(rSrc));
    756             }
    757 #endif
    758             assert((displacement & 0x3) == 0);
    759             break;
    760         case kUnsignedHalf:
    761         case kSignedHalf:
    762             opcode = kMipsSh;
    763             assert((displacement & 0x1) == 0);
    764             break;
    765         case kUnsignedByte:
    766         case kSignedByte:
    767             opcode = kMipsSb;
    768             break;
    769         default:
    770             ALOGE("Jit: bad case in storeBaseIndexedBody");
    771             dvmCompilerAbort(cUnit);
    772     }
    773 
    774     if (shortForm) {
    775         if (!pair) {
    776             store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase);
    777         } else {
    778             store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase);
    779             store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase);
    780         }
    781     } else {
    782         int rScratch = dvmCompilerAllocTemp(cUnit);
    783         res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
    784         if (!pair) {
    785             store =  newLIR3(cUnit, opcode, rSrc, 0, rScratch);
    786         } else {
    787             store =  newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch);
    788             store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch);
    789         }
    790         dvmCompilerFreeTemp(cUnit, rScratch);
    791     }
    792 
    793     if (rBase == rFP) {
    794         if (store != NULL)
    795             annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
    796                                     false /* isLoad */);
    797         if (store2 != NULL)
    798             annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
    799                                     false /* isLoad */);
    800     }
    801 
    802 #if defined(WITH_SELF_VERIFICATION)
    803     if (store != NULL && cUnit->heapMemOp)
    804         store->flags.insertWrapper = true;
    805     if (store2 != NULL && cUnit->heapMemOp)
    806         store2->flags.insertWrapper = true;
    807 #endif
    808     return res;
    809 }
    810 
    811 static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
    812                              int displacement, int rSrc, OpSize size)
    813 {
    814     return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
    815 }
    816 
    817 static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
    818                                  int displacement, int rSrcLo, int rSrcHi)
    819 {
    820     return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
    821 }
    822 
    823 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
    824 {
    825     storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
    826     storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
    827 }
    828 
    829 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
    830 {
    831     loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
    832     loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg);
    833 }
    834 
    835 static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
    836 {
    837     MipsLIR* res;
    838     MipsOpCode opcode;
    839 #ifdef __mips_hard_float
    840     if (FPREG(rDest) || FPREG(rSrc))
    841         return fpRegCopy(cUnit, rDest, rSrc);
    842 #endif
    843     res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
    844     opcode = kMipsMove;
    845     assert(LOWREG(rDest) && LOWREG(rSrc));
    846     res->operands[0] = rDest;
    847     res->operands[1] = rSrc;
    848     res->opcode = opcode;
    849     setupResourceMasks(res);
    850     if (rDest == rSrc) {
    851         res->flags.isNop = true;
    852     }
    853     return res;
    854 }
    855 
    856 static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
    857 {
    858     MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
    859     dvmCompilerAppendLIR(cUnit, (LIR*)res);
    860     return res;
    861 }
    862 
    863 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
    864                            int srcLo, int srcHi)
    865 {
    866 #ifdef __mips_hard_float
    867     bool destFP = FPREG(destLo) && FPREG(destHi);
    868     bool srcFP = FPREG(srcLo) && FPREG(srcHi);
    869     assert(FPREG(srcLo) == FPREG(srcHi));
    870     assert(FPREG(destLo) == FPREG(destHi));
    871     if (destFP) {
    872         if (srcFP) {
    873             genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
    874         } else {
    875            /* note the operands are swapped for the mtc1 instr */
    876             newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
    877             newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
    878         }
    879     } else {
    880         if (srcFP) {
    881             newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
    882             newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
    883         } else {
    884             // Handle overlap
    885             if (srcHi == destLo) {
    886                 genRegCopy(cUnit, destHi, srcHi);
    887                 genRegCopy(cUnit, destLo, srcLo);
    888             } else {
    889                 genRegCopy(cUnit, destLo, srcLo);
    890                 genRegCopy(cUnit, destHi, srcHi);
    891             }
    892         }
    893     }
    894 #else
    895     // Handle overlap
    896     if (srcHi == destLo) {
    897         genRegCopy(cUnit, destHi, srcHi);
    898         genRegCopy(cUnit, destLo, srcLo);
    899     } else {
    900         genRegCopy(cUnit, destLo, srcLo);
    901         genRegCopy(cUnit, destHi, srcHi);
    902     }
    903 #endif
    904 }
    905 
    906 static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit,
    907                                      MipsConditionCode cond, int reg,
    908                                      int checkValue, int dOffset,
    909                                      MipsLIR *pcrLabel)
    910 {
    911     MipsLIR *branch = NULL;
    912 
    913     if (checkValue == 0) {
    914         MipsOpCode opc = kMipsNop;
    915         if (cond == kMipsCondEq) {
    916             opc = kMipsBeqz;
    917 	} else if (cond == kMipsCondNe) {
    918             opc = kMipsBnez;
    919         } else if (cond == kMipsCondLt || cond == kMipsCondMi) {
    920             opc = kMipsBltz;
    921         } else if (cond == kMipsCondLe) {
    922             opc = kMipsBlez;
    923         } else if (cond == kMipsCondGt) {
    924             opc = kMipsBgtz;
    925         } else if (cond == kMipsCondGe) {
    926             opc = kMipsBgez;
    927         } else {
    928             ALOGE("Jit: bad case in genRegImmCheck");
    929             dvmCompilerAbort(cUnit);
    930         }
    931         branch = opCompareBranch(cUnit, opc, reg, -1);
    932     } else if (IS_SIMM16(checkValue)) {
    933         if (cond == kMipsCondLt) {
    934             int tReg = dvmCompilerAllocTemp(cUnit);
    935             newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue);
    936             branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO);
    937             dvmCompilerFreeTemp(cUnit, tReg);
    938         } else {
    939             ALOGE("Jit: bad case in genRegImmCheck");
    940             dvmCompilerAbort(cUnit);
    941         }
    942     } else {
    943         ALOGE("Jit: bad case in genRegImmCheck");
    944         dvmCompilerAbort(cUnit);
    945     }
    946 
    947     if (cUnit->jitMode == kJitMethod) {
    948         BasicBlock *bb = cUnit->curBlock;
    949         if (bb->taken) {
    950             MipsLIR  *exceptionLabel = (MipsLIR *) cUnit->blockLabelList;
    951             exceptionLabel += bb->taken->id;
    952             branch->generic.target = (LIR *) exceptionLabel;
    953             return exceptionLabel;
    954         } else {
    955             ALOGE("Catch blocks not handled yet");
    956             dvmAbort();
    957             return NULL;
    958         }
    959     } else {
    960         return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
    961     }
    962 }
    963 
    964 #if defined(WITH_SELF_VERIFICATION)
    965 static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
    966                                          MipsLIR *origLIR) {
    967 // DOUGLAS - this still needs to be implemented for MIPS.
    968 #if 0
    969     /*
    970      * We need two separate pushes, since we want r5 to be pushed first.
    971      * Store multiple will push LR first.
    972      */
    973     MipsLIR *pushFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
    974     pushFP->opcode = kThumbPush;
    975     pushFP->operands[0] = 1 << r5FP;
    976     setupResourceMasks(pushFP);
    977     dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP);
    978 
    979     MipsLIR *pushLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
    980     pushLR->opcode = kThumbPush;
    981     /* Thumb push can handle LR, but is encoded differently at bit 8 */
    982     pushLR->operands[0] = 1 << 8;
    983     setupResourceMasks(pushLR);
    984     dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR);
    985 #endif
    986 }
    987 
    988 static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
    989                                          MipsLIR *origLIR) {
    990 // DOUGLAS - this still needs to be implemented for MIPS.
    991 #if 0
    992     /*
    993      * Since Thumb cannot pop memory content into LR, we have to pop LR
    994      * to a temp first (r5 in this case). Then we move r5 to LR, then pop the
    995      * original r5 from stack.
    996      */
    997     /* Pop memory content(LR) into r5 first */
    998     MipsLIR *popForLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
    999     popForLR->opcode = kThumbPop;
   1000     popForLR->operands[0] = 1 << r5FP;
   1001     setupResourceMasks(popForLR);
   1002     dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR);
   1003 
   1004     MipsLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP);
   1005     dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy);
   1006 
   1007     /* Now restore the original r5 */
   1008     MipsLIR *popFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
   1009     popFP->opcode = kThumbPop;
   1010     popFP->operands[0] = 1 << r5FP;
   1011     setupResourceMasks(popFP);
   1012     dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP);
   1013 #endif
   1014 }
   1015 #endif
   1016