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