Home | History | Annotate | Download | only in Thumb
      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[] = {r0, r1, r2, r3, r4PC, r7};
     26 
     27 static void storePair(CompilationUnit *cUnit, int base, int lowReg,
     28                       int highReg);
     29 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
     30 static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
     31                             int rDest);
     32 static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
     33                              int displacement, int rSrc);
     34 static ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
     35                               ArmConditionCode cond,
     36                               int reg1, int reg2, int dOffset,
     37                               ArmLIR *pcrLabel);
     38 
     39 
     40 /*
     41  * Load a immediate using a shortcut if possible; otherwise
     42  * grab from the per-translation literal pool.  If target is
     43  * a high register, build constant into a low register and copy.
     44  *
     45  * No additional register clobbering operation performed. Use this version when
     46  * 1) rDest is freshly returned from dvmCompilerAllocTemp or
     47  * 2) The codegen is under fixed register usage
     48  */
     49 static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
     50                                      int value)
     51 {
     52     ArmLIR *res;
     53     int tDest = LOWREG(rDest) ? rDest : dvmCompilerAllocTemp(cUnit);
     54     /* See if the value can be constructed cheaply */
     55     if ((value >= 0) && (value <= 255)) {
     56         res = newLIR2(cUnit, kThumbMovImm, tDest, value);
     57         if (rDest != tDest) {
     58            opRegReg(cUnit, kOpMov, rDest, tDest);
     59            dvmCompilerFreeTemp(cUnit, tDest);
     60         }
     61         return res;
     62     } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
     63         res = newLIR2(cUnit, kThumbMovImm, tDest, ~value);
     64         newLIR2(cUnit, kThumbMvn, tDest, tDest);
     65         if (rDest != tDest) {
     66            opRegReg(cUnit, kOpMov, rDest, tDest);
     67            dvmCompilerFreeTemp(cUnit, tDest);
     68         }
     69         return res;
     70     }
     71     /* No shortcut - go ahead and use literal pool */
     72     ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
     73     if (dataTarget == NULL) {
     74         dataTarget = addWordData(cUnit, value, false);
     75     }
     76     ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
     77     loadPcRel->opCode = kThumbLdrPcRel;
     78     loadPcRel->generic.target = (LIR *) dataTarget;
     79     loadPcRel->operands[0] = tDest;
     80     setupResourceMasks(loadPcRel);
     81     /*
     82      * Special case for literal loads with a link register target.
     83      * Self-cosim mode will insert calls prior to heap references
     84      * after optimization, and those will destroy r14.  The easy
     85      * workaround is to treat literal loads into r14 as heap references
     86      * to prevent them from being hoisted.  Use of r14 in this manner
     87      * is currently rare.  Revist if that changes.
     88      */
     89     if (rDest != rlr)
     90         setMemRefType(loadPcRel, true, kLiteral);
     91     loadPcRel->aliasInfo = dataTarget->operands[0];
     92     res = loadPcRel;
     93     dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
     94 
     95     /*
     96      * To save space in the constant pool, we use the ADD_RRI8 instruction to
     97      * add up to 255 to an existing constant value.
     98      */
     99     if (dataTarget->operands[0] != value) {
    100         newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]);
    101     }
    102     if (rDest != tDest) {
    103        opRegReg(cUnit, kOpMov, rDest, tDest);
    104        dvmCompilerFreeTemp(cUnit, tDest);
    105     }
    106     return res;
    107 }
    108 
    109 /*
    110  * Load an immediate value into a fixed or temp register.  Target
    111  * register is clobbered, and marked inUse.
    112  */
    113 static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
    114 {
    115     if (dvmCompilerIsTemp(cUnit, rDest)) {
    116         dvmCompilerClobber(cUnit, rDest);
    117         dvmCompilerMarkInUse(cUnit, rDest);
    118     }
    119     return loadConstantNoClobber(cUnit, rDest, value);
    120 }
    121 
    122 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
    123 {
    124     ArmOpCode opCode = kThumbBkpt;
    125     switch (op) {
    126         case kOpUncondBr:
    127             opCode = kThumbBUncond;
    128             break;
    129         default:
    130             LOGE("Jit: bad case in opNone");
    131             dvmCompilerAbort(cUnit);
    132     }
    133     return newLIR0(cUnit, opCode);
    134 }
    135 
    136 static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
    137 {
    138     return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
    139 }
    140 
    141 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
    142 {
    143     ArmOpCode opCode = kThumbBkpt;
    144     switch (op) {
    145         case kOpPush:
    146             opCode = kThumbPush;
    147             break;
    148         case kOpPop:
    149             opCode = kThumbPop;
    150             break;
    151         default:
    152             LOGE("Jit: bad case in opCondBranch");
    153             dvmCompilerAbort(cUnit);
    154     }
    155     return newLIR1(cUnit, opCode, value);
    156 }
    157 
    158 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
    159 {
    160     ArmOpCode opCode = kThumbBkpt;
    161     switch (op) {
    162         case kOpBlx:
    163             opCode = kThumbBlxR;
    164             break;
    165         default:
    166             LOGE("Jit: bad case in opReg");
    167             dvmCompilerAbort(cUnit);
    168     }
    169     return newLIR1(cUnit, opCode, rDestSrc);
    170 }
    171 
    172 static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
    173                         int value)
    174 {
    175     ArmLIR *res;
    176     bool neg = (value < 0);
    177     int absValue = (neg) ? -value : value;
    178     bool shortForm = (absValue & 0xff) == absValue;
    179     ArmOpCode opCode = kThumbBkpt;
    180     switch (op) {
    181         case kOpAdd:
    182             if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
    183                 assert((value & 0x3) == 0);
    184                 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
    185             } else if (shortForm) {
    186                 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
    187             } else
    188                 opCode = kThumbAddRRR;
    189             break;
    190         case kOpSub:
    191             if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
    192                 assert((value & 0x3) == 0);
    193                 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
    194             } else if (shortForm) {
    195                 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
    196             } else
    197                 opCode = kThumbSubRRR;
    198             break;
    199         case kOpCmp:
    200             if (neg)
    201                shortForm = false;
    202             if (LOWREG(rDestSrc1) && shortForm) {
    203                 opCode = kThumbCmpRI8;
    204             } else if (LOWREG(rDestSrc1)) {
    205                 opCode = kThumbCmpRR;
    206             } else {
    207                 shortForm = false;
    208                 opCode = kThumbCmpHL;
    209             }
    210             break;
    211         default:
    212             LOGE("Jit: bad case in opRegImm");
    213             dvmCompilerAbort(cUnit);
    214             break;
    215     }
    216     if (shortForm)
    217         res = newLIR2(cUnit, opCode, rDestSrc1, absValue);
    218     else {
    219         int rScratch = dvmCompilerAllocTemp(cUnit);
    220         res = loadConstant(cUnit, rScratch, value);
    221         if (op == kOpCmp)
    222             newLIR2(cUnit, opCode, rDestSrc1, rScratch);
    223         else
    224             newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rScratch);
    225     }
    226     return res;
    227 }
    228 
    229 static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
    230                            int rSrc1, int rSrc2)
    231 {
    232     ArmOpCode opCode = kThumbBkpt;
    233     switch (op) {
    234         case kOpAdd:
    235             opCode = kThumbAddRRR;
    236             break;
    237         case kOpSub:
    238             opCode = kThumbSubRRR;
    239             break;
    240         default:
    241             if (rDest == rSrc1) {
    242                 return opRegReg(cUnit, op, rDest, rSrc2);
    243             } else if (rDest == rSrc2) {
    244                 assert(dvmCompilerIsTemp(cUnit, rSrc1));
    245                 dvmCompilerClobber(cUnit, rSrc1);
    246                 opRegReg(cUnit, op, rSrc1, rSrc2);
    247                 return opRegReg(cUnit, kOpMov, rDest, rSrc1);
    248             } else {
    249                 opRegReg(cUnit, kOpMov, rDest, rSrc1);
    250                 return opRegReg(cUnit, op, rDest, rSrc2);
    251             }
    252             break;
    253     }
    254     return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
    255 }
    256 
    257 static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
    258                            int rSrc1, int value)
    259 {
    260     ArmLIR *res;
    261     bool neg = (value < 0);
    262     int absValue = (neg) ? -value : value;
    263     ArmOpCode opCode = kThumbBkpt;
    264     bool shortForm = (absValue & 0x7) == absValue;
    265     switch(op) {
    266         case kOpAdd:
    267             if (rDest == rSrc1)
    268                 return opRegImm(cUnit, op, rDest, value);
    269             if ((rSrc1 == 13) && (value <= 1020)) { /* sp */
    270                 assert((value & 0x3) == 0);
    271                 shortForm = true;
    272                 opCode = kThumbAddSpRel;
    273                 value >>= 2;
    274             } else if ((rSrc1 == 15) && (value <= 1020)) { /* pc */
    275                 assert((value & 0x3) == 0);
    276                 shortForm = true;
    277                 opCode = kThumbAddPcRel;
    278                 value >>= 2;
    279             } else if (shortForm) {
    280                 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
    281             } else if ((absValue > 0) && (absValue <= (255 + 7))) {
    282                 /* Two shots - 1st handle the 7 */
    283                 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
    284                 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
    285                 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
    286                 newLIR2(cUnit, opCode, rDest, absValue - 7);
    287                 return res;
    288             } else
    289                 opCode = kThumbAddRRR;
    290             break;
    291 
    292         case kOpSub:
    293             if (rDest == rSrc1)
    294                 return opRegImm(cUnit, op, rDest, value);
    295             if (shortForm) {
    296                 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
    297             } else if ((absValue > 0) && (absValue <= (255 + 7))) {
    298                 /* Two shots - 1st handle the 7 */
    299                 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
    300                 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
    301                 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
    302                 newLIR2(cUnit, opCode, rDest, absValue - 7);
    303                 return res;
    304             } else
    305                 opCode = kThumbSubRRR;
    306             break;
    307         case kOpLsl:
    308                 shortForm = (!neg && value <= 31);
    309                 opCode = kThumbLslRRI5;
    310                 break;
    311         case kOpLsr:
    312                 shortForm = (!neg && value <= 31);
    313                 opCode = kThumbLsrRRI5;
    314                 break;
    315         case kOpAsr:
    316                 shortForm = (!neg && value <= 31);
    317                 opCode = kThumbAsrRRI5;
    318                 break;
    319         case kOpMul:
    320         case kOpAnd:
    321         case kOpOr:
    322         case kOpXor:
    323                 if (rDest == rSrc1) {
    324                     int rScratch = dvmCompilerAllocTemp(cUnit);
    325                     res = loadConstant(cUnit, rScratch, value);
    326                     opRegReg(cUnit, op, rDest, rScratch);
    327                 } else {
    328                     res = loadConstant(cUnit, rDest, value);
    329                     opRegReg(cUnit, op, rDest, rSrc1);
    330                 }
    331                 return res;
    332         default:
    333             LOGE("Jit: bad case in opRegRegImm");
    334             dvmCompilerAbort(cUnit);
    335             break;
    336     }
    337     if (shortForm)
    338         res = newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
    339     else {
    340         if (rDest != rSrc1) {
    341             res = loadConstant(cUnit, rDest, value);
    342             newLIR3(cUnit, opCode, rDest, rSrc1, rDest);
    343         } else {
    344             int rScratch = dvmCompilerAllocTemp(cUnit);
    345             res = loadConstant(cUnit, rScratch, value);
    346             newLIR3(cUnit, opCode, rDest, rSrc1, rScratch);
    347         }
    348     }
    349     return res;
    350 }
    351 
    352 static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
    353                         int rSrc2)
    354 {
    355     ArmLIR *res;
    356     ArmOpCode opCode = kThumbBkpt;
    357     switch (op) {
    358         case kOpAdc:
    359             opCode = kThumbAdcRR;
    360             break;
    361         case kOpAnd:
    362             opCode = kThumbAndRR;
    363             break;
    364         case kOpBic:
    365             opCode = kThumbBicRR;
    366             break;
    367         case kOpCmn:
    368             opCode = kThumbCmnRR;
    369             break;
    370         case kOpCmp:
    371             opCode = kThumbCmpRR;
    372             break;
    373         case kOpXor:
    374             opCode = kThumbEorRR;
    375             break;
    376         case kOpMov:
    377             if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
    378                 opCode = kThumbMovRR;
    379             else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
    380                 opCode = kThumbMovRR_H2H;
    381             else if (LOWREG(rDestSrc1))
    382                 opCode = kThumbMovRR_H2L;
    383             else
    384                 opCode = kThumbMovRR_L2H;
    385             break;
    386         case kOpMul:
    387             opCode = kThumbMul;
    388             break;
    389         case kOpMvn:
    390             opCode = kThumbMvn;
    391             break;
    392         case kOpNeg:
    393             opCode = kThumbNeg;
    394             break;
    395         case kOpOr:
    396             opCode = kThumbOrr;
    397             break;
    398         case kOpSbc:
    399             opCode = kThumbSbc;
    400             break;
    401         case kOpTst:
    402             opCode = kThumbTst;
    403             break;
    404         case kOpLsl:
    405             opCode = kThumbLslRR;
    406             break;
    407         case kOpLsr:
    408             opCode = kThumbLsrRR;
    409             break;
    410         case kOpAsr:
    411             opCode = kThumbAsrRR;
    412             break;
    413         case kOpRor:
    414             opCode = kThumbRorRR;
    415         case kOpAdd:
    416         case kOpSub:
    417             return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
    418         case kOp2Byte:
    419              res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
    420              opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
    421              return res;
    422         case kOp2Short:
    423              res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
    424              opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
    425              return res;
    426         case kOp2Char:
    427              res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
    428              opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16);
    429              return res;
    430         default:
    431             LOGE("Jit: bad case in opRegReg");
    432             dvmCompilerAbort(cUnit);
    433             break;
    434     }
    435     return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
    436 }
    437 
    438 static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
    439                                      int rDestHi, int valLo, int valHi)
    440 {
    441     ArmLIR *res;
    442     res = loadConstantNoClobber(cUnit, rDestLo, valLo);
    443     loadConstantNoClobber(cUnit, rDestHi, valHi);
    444     return res;
    445 }
    446 
    447 /* Load value from base + scaled index. */
    448 static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
    449                                int rIndex, int rDest, int scale, OpSize size)
    450 {
    451     ArmLIR *first = NULL;
    452     ArmLIR *res;
    453     ArmOpCode opCode = kThumbBkpt;
    454     int rNewIndex = rIndex;
    455     if (scale) {
    456         // Scale the index, but can't trash the original.
    457         rNewIndex = dvmCompilerAllocTemp(cUnit);
    458         first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
    459     }
    460     switch (size) {
    461         case kWord:
    462             opCode = kThumbLdrRRR;
    463             break;
    464         case kUnsignedHalf:
    465             opCode = kThumbLdrhRRR;
    466             break;
    467         case kSignedHalf:
    468             opCode = kThumbLdrshRRR;
    469             break;
    470         case kUnsignedByte:
    471             opCode = kThumbLdrbRRR;
    472             break;
    473         case kSignedByte:
    474             opCode = kThumbLdrsbRRR;
    475             break;
    476         default:
    477             LOGE("Jit: bad case in loadBaseIndexed");
    478             dvmCompilerAbort(cUnit);
    479     }
    480     res = newLIR3(cUnit, opCode, rDest, rBase, rNewIndex);
    481 #if defined(WITH_SELF_VERIFICATION)
    482     if (cUnit->heapMemOp)
    483         res->branchInsertSV = true;
    484 #endif
    485     if (scale)
    486         dvmCompilerFreeTemp(cUnit, rNewIndex);
    487     return (first) ? first : res;
    488 }
    489 
    490 /* store value base base + scaled index. */
    491 static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
    492                                 int rIndex, int rSrc, int scale, OpSize size)
    493 {
    494     ArmLIR *first = NULL;
    495     ArmLIR *res;
    496     ArmOpCode opCode = kThumbBkpt;
    497     int rNewIndex = rIndex;
    498     if (scale) {
    499         rNewIndex = dvmCompilerAllocTemp(cUnit);
    500         first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
    501     }
    502     switch (size) {
    503         case kWord:
    504             opCode = kThumbStrRRR;
    505             break;
    506         case kUnsignedHalf:
    507         case kSignedHalf:
    508             opCode = kThumbStrhRRR;
    509             break;
    510         case kUnsignedByte:
    511         case kSignedByte:
    512             opCode = kThumbStrbRRR;
    513             break;
    514         default:
    515             LOGE("Jit: bad case in storeBaseIndexed");
    516             dvmCompilerAbort(cUnit);
    517     }
    518     res = newLIR3(cUnit, opCode, rSrc, rBase, rNewIndex);
    519 #if defined(WITH_SELF_VERIFICATION)
    520     if (cUnit->heapMemOp)
    521         res->branchInsertSV = true;
    522 #endif
    523     if (scale)
    524         dvmCompilerFreeTemp(cUnit, rNewIndex);
    525     return (first) ? first : res;
    526 }
    527 
    528 static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
    529 {
    530     ArmLIR *res;
    531     genBarrier(cUnit);
    532     res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
    533 #if defined(WITH_SELF_VERIFICATION)
    534     if (cUnit->heapMemOp)
    535         res->branchInsertSV = true;
    536 #endif
    537     genBarrier(cUnit);
    538     return res;
    539 }
    540 
    541 static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
    542 {
    543     ArmLIR *res;
    544     genBarrier(cUnit);
    545     res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
    546 #if defined(WITH_SELF_VERIFICATION)
    547     if (cUnit->heapMemOp)
    548         res->branchInsertSV = true;
    549 #endif
    550     genBarrier(cUnit);
    551     return res;
    552 }
    553 
    554 static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
    555                                 int displacement, int rDest, int rDestHi,
    556                                 OpSize size, int sReg)
    557 /*
    558  * Load value from base + displacement.  Optionally perform null check
    559  * on base (which must have an associated sReg and MIR).  If not
    560  * performing null check, incoming MIR can be null. IMPORTANT: this
    561  * code must not allocate any new temps.  If a new register is needed
    562  * and base and dest are the same, spill some other register to
    563  * rlp and then restore.
    564  */
    565 {
    566     ArmLIR *res;
    567     ArmLIR *load = NULL;
    568     ArmLIR *load2 = NULL;
    569     ArmOpCode opCode = kThumbBkpt;
    570     bool shortForm = false;
    571     int encodedDisp = displacement;
    572     bool pair = false;
    573 
    574     switch (size) {
    575         case kLong:
    576         case kDouble:
    577             pair = true;
    578             if ((displacement < 124) && (displacement >= 0)) {
    579                 assert((displacement & 0x3) == 0);
    580                 shortForm = true;
    581                 encodedDisp >>= 2;
    582                 opCode = kThumbLdrRRI5;
    583             } else {
    584                 opCode = kThumbLdrRRR;
    585             }
    586             break;
    587         case kWord:
    588             if (LOWREG(rDest) && (rBase == rpc) &&
    589                 (displacement <= 1020) && (displacement >= 0)) {
    590                 shortForm = true;
    591                 encodedDisp >>= 2;
    592                 opCode = kThumbLdrPcRel;
    593             } else if (LOWREG(rDest) && (rBase == r13) &&
    594                       (displacement <= 1020) && (displacement >= 0)) {
    595                 shortForm = true;
    596                 encodedDisp >>= 2;
    597                 opCode = kThumbLdrSpRel;
    598             } else if (displacement < 128 && displacement >= 0) {
    599                 assert((displacement & 0x3) == 0);
    600                 shortForm = true;
    601                 encodedDisp >>= 2;
    602                 opCode = kThumbLdrRRI5;
    603             } else {
    604                 opCode = kThumbLdrRRR;
    605             }
    606             break;
    607         case kUnsignedHalf:
    608             if (displacement < 64 && displacement >= 0) {
    609                 assert((displacement & 0x1) == 0);
    610                 shortForm = true;
    611                 encodedDisp >>= 1;
    612                 opCode = kThumbLdrhRRI5;
    613             } else {
    614                 opCode = kThumbLdrhRRR;
    615             }
    616             break;
    617         case kSignedHalf:
    618             opCode = kThumbLdrshRRR;
    619             break;
    620         case kUnsignedByte:
    621             if (displacement < 32 && displacement >= 0) {
    622                 shortForm = true;
    623                 opCode = kThumbLdrbRRI5;
    624             } else {
    625                 opCode = kThumbLdrbRRR;
    626             }
    627             break;
    628         case kSignedByte:
    629             opCode = kThumbLdrsbRRR;
    630             break;
    631         default:
    632             LOGE("Jit: bad case in loadBaseIndexedBody");
    633             dvmCompilerAbort(cUnit);
    634     }
    635     if (shortForm) {
    636         load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
    637         if (pair) {
    638             load2 = newLIR3(cUnit, opCode, rDestHi, rBase, encodedDisp+1);
    639         }
    640     } else {
    641         if (pair) {
    642             int rTmp = dvmCompilerAllocFreeTemp(cUnit);
    643             res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
    644             load = newLIR3(cUnit, kThumbLdrRRI5, rDest, rTmp, 0);
    645             load2 = newLIR3(cUnit, kThumbLdrRRI5, rDestHi, rTmp, 1);
    646             dvmCompilerFreeTemp(cUnit, rTmp);
    647         } else {
    648             int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit)
    649                                         : rDest;
    650             res = loadConstant(cUnit, rTmp, displacement);
    651             load = newLIR3(cUnit, opCode, rDest, rBase, rTmp);
    652             if (rBase == rFP)
    653                 annotateDalvikRegAccess(load, displacement >> 2,
    654                                         true /* isLoad */);
    655             if (rTmp != rDest)
    656                 dvmCompilerFreeTemp(cUnit, rTmp);
    657         }
    658     }
    659     if (rBase == rFP) {
    660         if (load != NULL)
    661             annotateDalvikRegAccess(load, displacement >> 2,
    662                                     true /* isLoad */);
    663         if (load2 != NULL)
    664             annotateDalvikRegAccess(load2, (displacement >> 2) + 1,
    665                                     true /* isLoad */);
    666     }
    667 #if defined(WITH_SELF_VERIFICATION)
    668     if (load != NULL && cUnit->heapMemOp)
    669         load->branchInsertSV = true;
    670     if (load2 != NULL && cUnit->heapMemOp)
    671         load2->branchInsertSV = true;
    672 #endif
    673     return res;
    674 }
    675 
    676 static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
    677                             int displacement, int rDest, OpSize size,
    678                             int sReg)
    679 {
    680     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
    681                             size, sReg);
    682 }
    683 
    684 static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
    685                                 int displacement, int rDestLo, int rDestHi,
    686                                 int sReg)
    687 {
    688     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
    689                             kLong, sReg);
    690 }
    691 
    692 static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
    693                                  int displacement, int rSrc, int rSrcHi,
    694                                  OpSize size)
    695 {
    696     ArmLIR *res;
    697     ArmLIR *store = NULL;
    698     ArmLIR *store2 = NULL;
    699     ArmOpCode opCode = kThumbBkpt;
    700     bool shortForm = false;
    701     int encodedDisp = displacement;
    702     bool pair = false;
    703 
    704     switch (size) {
    705         case kLong:
    706         case kDouble:
    707             pair = true;
    708             if ((displacement < 124) && (displacement >= 0)) {
    709                 assert((displacement & 0x3) == 0);
    710                 pair = true;
    711                 shortForm = true;
    712                 encodedDisp >>= 2;
    713                 opCode = kThumbStrRRI5;
    714             } else {
    715                 opCode = kThumbStrRRR;
    716             }
    717             break;
    718         case kWord:
    719             if (displacement < 128 && displacement >= 0) {
    720                 assert((displacement & 0x3) == 0);
    721                 shortForm = true;
    722                 encodedDisp >>= 2;
    723                 opCode = kThumbStrRRI5;
    724             } else {
    725                 opCode = kThumbStrRRR;
    726             }
    727             break;
    728         case kUnsignedHalf:
    729         case kSignedHalf:
    730             if (displacement < 64 && displacement >= 0) {
    731                 assert((displacement & 0x1) == 0);
    732                 shortForm = true;
    733                 encodedDisp >>= 1;
    734                 opCode = kThumbStrhRRI5;
    735             } else {
    736                 opCode = kThumbStrhRRR;
    737             }
    738             break;
    739         case kUnsignedByte:
    740         case kSignedByte:
    741             if (displacement < 32 && displacement >= 0) {
    742                 shortForm = true;
    743                 opCode = kThumbStrbRRI5;
    744             } else {
    745                 opCode = kThumbStrbRRR;
    746             }
    747             break;
    748         default:
    749             LOGE("Jit: bad case in storeBaseIndexedBody");
    750             dvmCompilerAbort(cUnit);
    751     }
    752     if (shortForm) {
    753         store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
    754         if (pair) {
    755             store2 = newLIR3(cUnit, opCode, rSrcHi, rBase, encodedDisp + 1);
    756         }
    757     } else {
    758         int rScratch = dvmCompilerAllocTemp(cUnit);
    759         if (pair) {
    760             res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
    761             store =  newLIR3(cUnit, kThumbStrRRI5, rSrc, rScratch, 0);
    762             store2 = newLIR3(cUnit, kThumbStrRRI5, rSrcHi, rScratch, 1);
    763         } else {
    764             res = loadConstant(cUnit, rScratch, displacement);
    765             store = newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
    766         }
    767         dvmCompilerFreeTemp(cUnit, rScratch);
    768     }
    769     if (rBase == rFP) {
    770         if (store != NULL)
    771             annotateDalvikRegAccess(store, displacement >> 2,
    772                                     false /* isLoad */);
    773         if (store2 != NULL)
    774             annotateDalvikRegAccess(store2, (displacement >> 2) + 1,
    775                                     false /* isLoad */);
    776     }
    777 #if defined(WITH_SELF_VERIFICATION)
    778     if (store != NULL && cUnit->heapMemOp)
    779         store->branchInsertSV = true;
    780     if (store2 != NULL && cUnit->heapMemOp)
    781         store2->branchInsertSV = true;
    782 #endif
    783     return res;
    784 }
    785 
    786 static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
    787                              int displacement, int rSrc, OpSize size)
    788 {
    789     return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
    790 }
    791 
    792 static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
    793                                  int displacement, int rSrcLo, int rSrcHi)
    794 {
    795     return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
    796 }
    797 
    798 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
    799 {
    800     if (lowReg < highReg) {
    801         storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
    802     } else {
    803         storeWordDisp(cUnit, base, 0, lowReg);
    804         storeWordDisp(cUnit, base, 4, highReg);
    805     }
    806 }
    807 
    808 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
    809 {
    810     if (lowReg < highReg) {
    811         loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
    812     } else {
    813         loadWordDisp(cUnit, base, 0 , lowReg);
    814         loadWordDisp(cUnit, base, 4 , highReg);
    815     }
    816 }
    817 
    818 static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
    819 {
    820     ArmLIR* res;
    821     ArmOpCode opCode;
    822     res = dvmCompilerNew(sizeof(ArmLIR), true);
    823     if (LOWREG(rDest) && LOWREG(rSrc))
    824         opCode = kThumbMovRR;
    825     else if (!LOWREG(rDest) && !LOWREG(rSrc))
    826          opCode = kThumbMovRR_H2H;
    827     else if (LOWREG(rDest))
    828          opCode = kThumbMovRR_H2L;
    829     else
    830          opCode = kThumbMovRR_L2H;
    831 
    832     res->operands[0] = rDest;
    833     res->operands[1] = rSrc;
    834     res->opCode = opCode;
    835     setupResourceMasks(res);
    836     if (rDest == rSrc) {
    837         res->isNop = true;
    838     }
    839     return res;
    840 }
    841 
    842 static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
    843 {
    844     ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
    845     dvmCompilerAppendLIR(cUnit, (LIR*)res);
    846     return res;
    847 }
    848 
    849 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
    850                            int srcLo, int srcHi)
    851 {
    852     // Handle overlap
    853     if (srcHi == destLo) {
    854         genRegCopy(cUnit, destHi, srcHi);
    855         genRegCopy(cUnit, destLo, srcLo);
    856     } else {
    857         genRegCopy(cUnit, destLo, srcLo);
    858         genRegCopy(cUnit, destHi, srcHi);
    859     }
    860 }
    861 
    862 static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
    863                                      ArmConditionCode cond, int reg,
    864                                      int checkValue, int dOffset,
    865                                      ArmLIR *pcrLabel)
    866 {
    867     int tReg;
    868     ArmLIR *res;
    869     if ((checkValue & 0xff) != checkValue) {
    870         tReg = dvmCompilerAllocTemp(cUnit);
    871         loadConstant(cUnit, tReg, checkValue);
    872         res = genRegRegCheck(cUnit, cond, reg, tReg, dOffset, pcrLabel);
    873         dvmCompilerFreeTemp(cUnit, tReg);
    874         return res;
    875     }
    876     newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
    877     ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond);
    878     return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
    879 }
    880