Home | History | Annotate | Download | only in Thumb2
      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, r8, r9, r10, r11, r12};
     26 static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
     27                         fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
     28 
     29 static int encodeImmSingle(int value)
     30 {
     31     int res;
     32     int bitA =    (value & 0x80000000) >> 31;
     33     int notBitB = (value & 0x40000000) >> 30;
     34     int bitB =    (value & 0x20000000) >> 29;
     35     int bSmear =  (value & 0x3e000000) >> 25;
     36     int slice =   (value & 0x01f80000) >> 19;
     37     int zeroes =  (value & 0x0007ffff);
     38     if (zeroes != 0)
     39         return -1;
     40     if (bitB) {
     41         if ((notBitB != 0) || (bSmear != 0x1f))
     42             return -1;
     43     } else {
     44         if ((notBitB != 1) || (bSmear != 0x0))
     45             return -1;
     46     }
     47     res = (bitA << 7) | (bitB << 6) | slice;
     48     return res;
     49 }
     50 
     51 static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
     52                                    int value)
     53 {
     54     int encodedImm = encodeImmSingle(value);
     55     assert(SINGLEREG(rDest));
     56     if (encodedImm >= 0) {
     57         return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
     58     }
     59     ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
     60     if (dataTarget == NULL) {
     61         dataTarget = addWordData(cUnit, value, false);
     62     }
     63     ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
     64     loadPcRel->opCode = kThumb2Vldrs;
     65     loadPcRel->generic.target = (LIR *) dataTarget;
     66     loadPcRel->operands[0] = rDest;
     67     loadPcRel->operands[1] = rpc;
     68     setupResourceMasks(loadPcRel);
     69     // Self-cosim workaround.
     70     if (rDest != rlr)
     71         setMemRefType(loadPcRel, true, kLiteral);
     72     loadPcRel->aliasInfo = dataTarget->operands[0];
     73     dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
     74     return loadPcRel;
     75 }
     76 
     77 static int leadingZeros(u4 val)
     78 {
     79     u4 alt;
     80     int n;
     81     int count;
     82 
     83     count = 16;
     84     n = 32;
     85     do {
     86         alt = val >> count;
     87         if (alt != 0) {
     88             n = n - count;
     89             val = alt;
     90         }
     91         count >>= 1;
     92     } while (count);
     93     return n - val;
     94 }
     95 
     96 /*
     97  * Determine whether value can be encoded as a Thumb2 modified
     98  * immediate.  If not, return -1.  If so, return i:imm3:a:bcdefgh form.
     99  */
    100 static int modifiedImmediate(u4 value)
    101 {
    102    int zLeading;
    103    int zTrailing;
    104    u4 b0 = value & 0xff;
    105 
    106    /* Note: case of value==0 must use 0:000:0:0000000 encoding */
    107    if (value <= 0xFF)
    108        return b0;  // 0:000:a:bcdefgh
    109    if (value == ((b0 << 16) | b0))
    110        return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
    111    if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
    112        return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
    113    b0 = (value >> 8) & 0xff;
    114    if (value == ((b0 << 24) | (b0 << 8)))
    115        return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
    116    /* Can we do it with rotation? */
    117    zLeading = leadingZeros(value);
    118    zTrailing = 32 - leadingZeros(~value & (value - 1));
    119    /* A run of eight or fewer active bits? */
    120    if ((zLeading + zTrailing) < 24)
    121        return -1;  /* No - bail */
    122    /* left-justify the constant, discarding msb (known to be 1) */
    123    value <<= zLeading + 1;
    124    /* Create bcdefgh */
    125    value >>= 25;
    126    /* Put it all together */
    127    return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
    128 }
    129 
    130 /*
    131  * Load a immediate using a shortcut if possible; otherwise
    132  * grab from the per-translation literal pool.
    133  *
    134  * No additional register clobbering operation performed. Use this version when
    135  * 1) rDest is freshly returned from dvmCompilerAllocTemp or
    136  * 2) The codegen is under fixed register usage
    137  */
    138 static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
    139                                      int value)
    140 {
    141     ArmLIR *res;
    142     int modImm;
    143 
    144     if (FPREG(rDest)) {
    145         return loadFPConstantValue(cUnit, rDest, value);
    146     }
    147 
    148     /* See if the value can be constructed cheaply */
    149     if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
    150         return newLIR2(cUnit, kThumbMovImm, rDest, value);
    151     }
    152     /* Check Modified immediate special cases */
    153     modImm = modifiedImmediate(value);
    154     if (modImm >= 0) {
    155         res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
    156         return res;
    157     }
    158     modImm = modifiedImmediate(~value);
    159     if (modImm >= 0) {
    160         res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
    161         return res;
    162     }
    163     /* 16-bit immediate? */
    164     if ((value & 0xffff) == value) {
    165         res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
    166         return res;
    167     }
    168     /* No shortcut - go ahead and use literal pool */
    169     ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
    170     if (dataTarget == NULL) {
    171         dataTarget = addWordData(cUnit, value, false);
    172     }
    173     ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
    174     loadPcRel->opCode = kThumb2LdrPcRel12;
    175     loadPcRel->generic.target = (LIR *) dataTarget;
    176     loadPcRel->operands[0] = rDest;
    177     setupResourceMasks(loadPcRel);
    178     /*
    179      * Special case for literal loads with a link register target.
    180      * Self-cosim mode will insert calls prior to heap references
    181      * after optimization, and those will destroy r14.  The easy
    182      * workaround is to treat literal loads into r14 as heap references
    183      * to prevent them from being hoisted.  Use of r14 in this manner
    184      * is currently rare.  Revisit if that changes.
    185      */
    186     if (rDest != rlr)
    187         setMemRefType(loadPcRel, true, kLiteral);
    188     loadPcRel->aliasInfo = dataTarget->operands[0];
    189     res = loadPcRel;
    190     dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
    191 
    192     /*
    193      * To save space in the constant pool, we use the ADD_RRI8 instruction to
    194      * add up to 255 to an existing constant value.
    195      */
    196     if (dataTarget->operands[0] != value) {
    197         opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
    198     }
    199     return res;
    200 }
    201 
    202 /*
    203  * Load an immediate value into a fixed or temp register.  Target
    204  * register is clobbered, and marked inUse.
    205  */
    206 static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
    207 {
    208     if (dvmCompilerIsTemp(cUnit, rDest)) {
    209         dvmCompilerClobber(cUnit, rDest);
    210         dvmCompilerMarkInUse(cUnit, rDest);
    211     }
    212     return loadConstantNoClobber(cUnit, rDest, value);
    213 }
    214 
    215 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
    216 {
    217     ArmOpCode opCode = kThumbBkpt;
    218     switch (op) {
    219         case kOpUncondBr:
    220             opCode = kThumbBUncond;
    221             break;
    222         default:
    223             assert(0);
    224     }
    225     return newLIR0(cUnit, opCode);
    226 }
    227 
    228 static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
    229 {
    230     return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc);
    231 }
    232 
    233 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
    234 {
    235     ArmOpCode opCode = kThumbBkpt;
    236     switch (op) {
    237         case kOpPush:
    238             opCode = ((value & 0xff00) != 0) ? kThumb2Push : kThumbPush;
    239             break;
    240         case kOpPop:
    241             opCode = ((value & 0xff00) != 0) ? kThumb2Pop : kThumbPop;
    242             break;
    243         default:
    244             assert(0);
    245     }
    246     return newLIR1(cUnit, opCode, value);
    247 }
    248 
    249 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
    250 {
    251     ArmOpCode opCode = kThumbBkpt;
    252     switch (op) {
    253         case kOpBlx:
    254             opCode = kThumbBlxR;
    255             break;
    256         default:
    257             assert(0);
    258     }
    259     return newLIR1(cUnit, opCode, rDestSrc);
    260 }
    261 
    262 static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
    263                         int rSrc2, int shift)
    264 {
    265     bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
    266     ArmOpCode opCode = kThumbBkpt;
    267     switch (op) {
    268         case kOpAdc:
    269             opCode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
    270             break;
    271         case kOpAnd:
    272             opCode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
    273             break;
    274         case kOpBic:
    275             opCode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
    276             break;
    277         case kOpCmn:
    278             assert(shift == 0);
    279             opCode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
    280             break;
    281         case kOpCmp:
    282             if (thumbForm)
    283                 opCode = kThumbCmpRR;
    284             else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
    285                 opCode = kThumbCmpHH;
    286             else if ((shift == 0) && LOWREG(rDestSrc1))
    287                 opCode = kThumbCmpLH;
    288             else if (shift == 0)
    289                 opCode = kThumbCmpHL;
    290             else
    291                 opCode = kThumb2CmpRR;
    292             break;
    293         case kOpXor:
    294             opCode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
    295             break;
    296         case kOpMov:
    297             assert(shift == 0);
    298             if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
    299                 opCode = kThumbMovRR;
    300             else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
    301                 opCode = kThumbMovRR_H2H;
    302             else if (LOWREG(rDestSrc1))
    303                 opCode = kThumbMovRR_H2L;
    304             else
    305                 opCode = kThumbMovRR_L2H;
    306             break;
    307         case kOpMul:
    308             assert(shift == 0);
    309             opCode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
    310             break;
    311         case kOpMvn:
    312             opCode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
    313             break;
    314         case kOpNeg:
    315             assert(shift == 0);
    316             opCode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
    317             break;
    318         case kOpOr:
    319             opCode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
    320             break;
    321         case kOpSbc:
    322             opCode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
    323             break;
    324         case kOpTst:
    325             opCode = (thumbForm) ? kThumbTst : kThumb2TstRR;
    326             break;
    327         case kOpLsl:
    328             assert(shift == 0);
    329             opCode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
    330             break;
    331         case kOpLsr:
    332             assert(shift == 0);
    333             opCode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
    334             break;
    335         case kOpAsr:
    336             assert(shift == 0);
    337             opCode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
    338             break;
    339         case kOpRor:
    340             assert(shift == 0);
    341             opCode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
    342             break;
    343         case kOpAdd:
    344             opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
    345             break;
    346         case kOpSub:
    347             opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
    348             break;
    349         case kOp2Byte:
    350             assert(shift == 0);
    351             return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
    352         case kOp2Short:
    353             assert(shift == 0);
    354             return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
    355         case kOp2Char:
    356             assert(shift == 0);
    357             return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
    358         default:
    359             assert(0);
    360             break;
    361     }
    362     assert(opCode >= 0);
    363     if (EncodingMap[opCode].flags & IS_BINARY_OP)
    364         return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
    365     else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
    366         if (EncodingMap[opCode].fieldLoc[2].kind == kFmtShift)
    367             return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
    368         else
    369             return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
    370     } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
    371         return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
    372     else {
    373         assert(0);
    374         return NULL;
    375     }
    376 }
    377 
    378 static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
    379                         int rSrc2)
    380 {
    381     return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
    382 }
    383 
    384 static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
    385                                 int rDest, int rSrc1, int rSrc2, int shift)
    386 {
    387     ArmOpCode opCode = kThumbBkpt;
    388     bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
    389                       LOWREG(rSrc2);
    390     switch (op) {
    391         case kOpAdd:
    392             opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
    393             break;
    394         case kOpSub:
    395             opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
    396             break;
    397         case kOpAdc:
    398             opCode = kThumb2AdcRRR;
    399             break;
    400         case kOpAnd:
    401             opCode = kThumb2AndRRR;
    402             break;
    403         case kOpBic:
    404             opCode = kThumb2BicRRR;
    405             break;
    406         case kOpXor:
    407             opCode = kThumb2EorRRR;
    408             break;
    409         case kOpMul:
    410             assert(shift == 0);
    411             opCode = kThumb2MulRRR;
    412             break;
    413         case kOpOr:
    414             opCode = kThumb2OrrRRR;
    415             break;
    416         case kOpSbc:
    417             opCode = kThumb2SbcRRR;
    418             break;
    419         case kOpLsl:
    420             assert(shift == 0);
    421             opCode = kThumb2LslRRR;
    422             break;
    423         case kOpLsr:
    424             assert(shift == 0);
    425             opCode = kThumb2LsrRRR;
    426             break;
    427         case kOpAsr:
    428             assert(shift == 0);
    429             opCode = kThumb2AsrRRR;
    430             break;
    431         case kOpRor:
    432             assert(shift == 0);
    433             opCode = kThumb2RorRRR;
    434             break;
    435         default:
    436             assert(0);
    437             break;
    438     }
    439     assert(opCode >= 0);
    440     if (EncodingMap[opCode].flags & IS_QUAD_OP)
    441         return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
    442     else {
    443         assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
    444         return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
    445     }
    446 }
    447 
    448 static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
    449                            int rSrc1, int rSrc2)
    450 {
    451     return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
    452 }
    453 
    454 static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
    455                            int rSrc1, int value)
    456 {
    457     ArmLIR *res;
    458     bool neg = (value < 0);
    459     int absValue = (neg) ? -value : value;
    460     ArmOpCode opCode = kThumbBkpt;
    461     ArmOpCode altOpCode = kThumbBkpt;
    462     bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
    463     int modImm = modifiedImmediate(value);
    464     int modImmNeg = modifiedImmediate(-value);
    465 
    466     switch(op) {
    467         case kOpLsl:
    468             if (allLowRegs)
    469                 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
    470             else
    471                 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
    472         case kOpLsr:
    473             if (allLowRegs)
    474                 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
    475             else
    476                 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
    477         case kOpAsr:
    478             if (allLowRegs)
    479                 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
    480             else
    481                 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
    482         case kOpRor:
    483             return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
    484         case kOpAdd:
    485             if (LOWREG(rDest) && (rSrc1 == 13) &&
    486                 (value <= 1020) && ((value & 0x3)==0)) {
    487                 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
    488                                value >> 2);
    489             } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
    490                        (value <= 1020) && ((value & 0x3)==0)) {
    491                 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
    492                                value >> 2);
    493             }
    494             opCode = kThumb2AddRRI8;
    495             altOpCode = kThumb2AddRRR;
    496             // Note: intentional fallthrough
    497         case kOpSub:
    498             if (allLowRegs && ((absValue & 0x7) == absValue)) {
    499                 if (op == kOpAdd)
    500                     opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
    501                 else
    502                     opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
    503                 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
    504             } else if ((absValue & 0xff) == absValue) {
    505                 if (op == kOpAdd)
    506                     opCode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
    507                 else
    508                     opCode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
    509                 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
    510             }
    511             if (modImmNeg >= 0) {
    512                 op = (op == kOpAdd) ? kOpSub : kOpAdd;
    513                 modImm = modImmNeg;
    514             }
    515             if (op == kOpSub) {
    516                 opCode = kThumb2SubRRI8;
    517                 altOpCode = kThumb2SubRRR;
    518             }
    519             break;
    520         case kOpAdc:
    521             opCode = kThumb2AdcRRI8;
    522             altOpCode = kThumb2AdcRRR;
    523             break;
    524         case kOpSbc:
    525             opCode = kThumb2SbcRRI8;
    526             altOpCode = kThumb2SbcRRR;
    527             break;
    528         case kOpOr:
    529             opCode = kThumb2OrrRRI8;
    530             altOpCode = kThumb2OrrRRR;
    531             break;
    532         case kOpAnd:
    533             opCode = kThumb2AndRRI8;
    534             altOpCode = kThumb2AndRRR;
    535             break;
    536         case kOpXor:
    537             opCode = kThumb2EorRRI8;
    538             altOpCode = kThumb2EorRRR;
    539             break;
    540         case kOpMul:
    541             //TUNING: power of 2, shift & add
    542             modImm = -1;
    543             altOpCode = kThumb2MulRRR;
    544             break;
    545         case kOpCmp: {
    546             int modImm = modifiedImmediate(value);
    547             ArmLIR *res;
    548             if (modImm >= 0) {
    549                 res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
    550             } else {
    551                 int rTmp = dvmCompilerAllocTemp(cUnit);
    552                 res = loadConstant(cUnit, rTmp, value);
    553                 opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
    554                 dvmCompilerFreeTemp(cUnit, rTmp);
    555             }
    556             return res;
    557         }
    558         default:
    559             assert(0);
    560     }
    561 
    562     if (modImm >= 0) {
    563         return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
    564     } else {
    565         int rScratch = dvmCompilerAllocTemp(cUnit);
    566         loadConstant(cUnit, rScratch, value);
    567         if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
    568             res = newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
    569         else
    570             res = newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
    571         dvmCompilerFreeTemp(cUnit, rScratch);
    572         return res;
    573     }
    574 }
    575 
    576 /* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
    577 static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
    578                         int value)
    579 {
    580     bool neg = (value < 0);
    581     int absValue = (neg) ? -value : value;
    582     bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
    583     ArmOpCode opCode = kThumbBkpt;
    584     switch (op) {
    585         case kOpAdd:
    586             if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
    587                 assert((value & 0x3) == 0);
    588                 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
    589             } else if (shortForm) {
    590                 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
    591             }
    592             break;
    593         case kOpSub:
    594             if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
    595                 assert((value & 0x3) == 0);
    596                 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
    597             } else if (shortForm) {
    598                 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
    599             }
    600             break;
    601         case kOpCmp:
    602             if (LOWREG(rDestSrc1) && shortForm)
    603                 opCode = (shortForm) ?  kThumbCmpRI8 : kThumbCmpRR;
    604             else if (LOWREG(rDestSrc1))
    605                 opCode = kThumbCmpRR;
    606             else {
    607                 shortForm = false;
    608                 opCode = kThumbCmpHL;
    609             }
    610             break;
    611         default:
    612             /* Punt to opRegRegImm - if bad case catch it there */
    613             shortForm = false;
    614             break;
    615     }
    616     if (shortForm)
    617         return newLIR2(cUnit, opCode, rDestSrc1, absValue);
    618     else {
    619         return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
    620     }
    621 }
    622 
    623 /*
    624  * Determine whether value can be encoded as a Thumb2 floating point
    625  * immediate.  If not, return -1.  If so return encoded 8-bit value.
    626  */
    627 static int encodeImmDoubleHigh(int value)
    628 {
    629     int res;
    630     int bitA =    (value & 0x80000000) >> 31;
    631     int notBitB = (value & 0x40000000) >> 30;
    632     int bitB =    (value & 0x20000000) >> 29;
    633     int bSmear =  (value & 0x3fc00000) >> 22;
    634     int slice =   (value & 0x003f0000) >> 16;
    635     int zeroes =  (value & 0x0000ffff);
    636     if (zeroes != 0)
    637         return -1;
    638     if (bitB) {
    639         if ((notBitB != 0) || (bSmear != 0x1f))
    640             return -1;
    641     } else {
    642         if ((notBitB != 1) || (bSmear != 0x0))
    643             return -1;
    644     }
    645     res = (bitA << 7) | (bitB << 6) | slice;
    646     return res;
    647 }
    648 
    649 static int encodeImmDouble(int valLo, int valHi)
    650 {
    651     int res = -1;
    652     if (valLo == 0)
    653         res = encodeImmDoubleHigh(valHi);
    654     return res;
    655 }
    656 
    657 static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
    658                                      int rDestHi, int valLo, int valHi)
    659 {
    660     int encodedImm = encodeImmDouble(valLo, valHi);
    661     ArmLIR *res;
    662     if (FPREG(rDestLo) && (encodedImm >= 0)) {
    663         res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
    664                       encodedImm);
    665     } else {
    666         res = loadConstantNoClobber(cUnit, rDestLo, valLo);
    667         loadConstantNoClobber(cUnit, rDestHi, valHi);
    668     }
    669     return res;
    670 }
    671 
    672 static int encodeShift(int code, int amount) {
    673     return ((amount & 0x1f) << 2) | code;
    674 }
    675 
    676 static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
    677                                int rIndex, int rDest, int scale, OpSize size)
    678 {
    679     bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
    680     ArmLIR *load;
    681     ArmOpCode opCode = kThumbBkpt;
    682     bool thumbForm = (allLowRegs && (scale == 0));
    683     int regPtr;
    684 
    685     if (FPREG(rDest)) {
    686         assert(SINGLEREG(rDest));
    687         assert((size == kWord) || (size == kSingle));
    688         opCode = kThumb2Vldrs;
    689         size = kSingle;
    690     } else {
    691         if (size == kSingle)
    692             size = kWord;
    693     }
    694 
    695     switch (size) {
    696         case kSingle:
    697             regPtr = dvmCompilerAllocTemp(cUnit);
    698             if (scale) {
    699                 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
    700                         encodeShift(kArmLsl, scale));
    701             } else {
    702                 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
    703             }
    704             load = newLIR3(cUnit, opCode, rDest, regPtr, 0);
    705 #if defined(WITH_SELF_VERIFICATION)
    706             if (cUnit->heapMemOp)
    707                 load->branchInsertSV = true;
    708 #endif
    709             return load;
    710         case kWord:
    711             opCode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
    712             break;
    713         case kUnsignedHalf:
    714             opCode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
    715             break;
    716         case kSignedHalf:
    717             opCode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
    718             break;
    719         case kUnsignedByte:
    720             opCode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
    721             break;
    722         case kSignedByte:
    723             opCode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
    724             break;
    725         default:
    726             assert(0);
    727     }
    728     if (thumbForm)
    729         load = newLIR3(cUnit, opCode, rDest, rBase, rIndex);
    730     else
    731         load = newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
    732 
    733 #if defined(WITH_SELF_VERIFICATION)
    734     if (cUnit->heapMemOp)
    735         load->branchInsertSV = true;
    736 #endif
    737     return load;
    738 }
    739 
    740 static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
    741                                 int rIndex, int rSrc, int scale, OpSize size)
    742 {
    743     bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
    744     ArmLIR *store;
    745     ArmOpCode opCode = kThumbBkpt;
    746     bool thumbForm = (allLowRegs && (scale == 0));
    747     int regPtr;
    748 
    749     if (FPREG(rSrc)) {
    750         assert(SINGLEREG(rSrc));
    751         assert((size == kWord) || (size == kSingle));
    752         opCode = kThumb2Vstrs;
    753         size = kSingle;
    754     } else {
    755         if (size == kSingle)
    756             size = kWord;
    757     }
    758 
    759     switch (size) {
    760         case kSingle:
    761             regPtr = dvmCompilerAllocTemp(cUnit);
    762             if (scale) {
    763                 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
    764                         encodeShift(kArmLsl, scale));
    765             } else {
    766                 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
    767             }
    768             store = newLIR3(cUnit, opCode, rSrc, regPtr, 0);
    769 #if defined(WITH_SELF_VERIFICATION)
    770             if (cUnit->heapMemOp)
    771                 store->branchInsertSV = true;
    772 #endif
    773             return store;
    774         case kWord:
    775             opCode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
    776             break;
    777         case kUnsignedHalf:
    778         case kSignedHalf:
    779             opCode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
    780             break;
    781         case kUnsignedByte:
    782         case kSignedByte:
    783             opCode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
    784             break;
    785         default:
    786             assert(0);
    787     }
    788     if (thumbForm)
    789         store = newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
    790     else
    791         store = newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
    792 
    793 #if defined(WITH_SELF_VERIFICATION)
    794     if (cUnit->heapMemOp)
    795         store->branchInsertSV = true;
    796 #endif
    797     return store;
    798 }
    799 
    800 /*
    801  * Load value from base + displacement.  Optionally perform null check
    802  * on base (which must have an associated sReg and MIR).  If not
    803  * performing null check, incoming MIR can be null.
    804  */
    805 static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
    806                                 int displacement, int rDest, int rDestHi,
    807                                 OpSize size, int sReg)
    808 {
    809     ArmLIR *res, *load;
    810     ArmOpCode opCode = kThumbBkpt;
    811     bool shortForm = false;
    812     bool thumb2Form = (displacement < 4092 && displacement >= 0);
    813     bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
    814     int encodedDisp = displacement;
    815 
    816     switch (size) {
    817         case kDouble:
    818         case kLong:
    819             if (FPREG(rDest)) {
    820                 if (SINGLEREG(rDest)) {
    821                     assert(FPREG(rDestHi));
    822                     rDest = S2D(rDest, rDestHi);
    823                 }
    824                 opCode = kThumb2Vldrd;
    825                 if (displacement <= 1020) {
    826                     shortForm = true;
    827                     encodedDisp >>= 2;
    828                 }
    829                 break;
    830             } else {
    831                 res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
    832                                        -1, kWord, sReg);
    833                 loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
    834                                  -1, kWord, INVALID_SREG);
    835                 return res;
    836             }
    837         case kSingle:
    838         case kWord:
    839             if (FPREG(rDest)) {
    840                 opCode = kThumb2Vldrs;
    841                 if (displacement <= 1020) {
    842                     shortForm = true;
    843                     encodedDisp >>= 2;
    844                 }
    845                 break;
    846             }
    847             if (LOWREG(rDest) && (rBase == rpc) &&
    848                 (displacement <= 1020) && (displacement >= 0)) {
    849                 shortForm = true;
    850                 encodedDisp >>= 2;
    851                 opCode = kThumbLdrPcRel;
    852             } else if (LOWREG(rDest) && (rBase == r13) &&
    853                       (displacement <= 1020) && (displacement >= 0)) {
    854                 shortForm = true;
    855                 encodedDisp >>= 2;
    856                 opCode = kThumbLdrSpRel;
    857             } else if (allLowRegs && displacement < 128 && displacement >= 0) {
    858                 assert((displacement & 0x3) == 0);
    859                 shortForm = true;
    860                 encodedDisp >>= 2;
    861                 opCode = kThumbLdrRRI5;
    862             } else if (thumb2Form) {
    863                 shortForm = true;
    864                 opCode = kThumb2LdrRRI12;
    865             }
    866             break;
    867         case kUnsignedHalf:
    868             if (allLowRegs && displacement < 64 && displacement >= 0) {
    869                 assert((displacement & 0x1) == 0);
    870                 shortForm = true;
    871                 encodedDisp >>= 1;
    872                 opCode = kThumbLdrhRRI5;
    873             } else if (displacement < 4092 && displacement >= 0) {
    874                 shortForm = true;
    875                 opCode = kThumb2LdrhRRI12;
    876             }
    877             break;
    878         case kSignedHalf:
    879             if (thumb2Form) {
    880                 shortForm = true;
    881                 opCode = kThumb2LdrshRRI12;
    882             }
    883             break;
    884         case kUnsignedByte:
    885             if (allLowRegs && displacement < 32 && displacement >= 0) {
    886                 shortForm = true;
    887                 opCode = kThumbLdrbRRI5;
    888             } else if (thumb2Form) {
    889                 shortForm = true;
    890                 opCode = kThumb2LdrbRRI12;
    891             }
    892             break;
    893         case kSignedByte:
    894             if (thumb2Form) {
    895                 shortForm = true;
    896                 opCode = kThumb2LdrsbRRI12;
    897             }
    898             break;
    899         default:
    900             assert(0);
    901     }
    902 
    903     if (shortForm) {
    904         load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
    905     } else {
    906         int regOffset = dvmCompilerAllocTemp(cUnit);
    907         res = loadConstant(cUnit, regOffset, encodedDisp);
    908         load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
    909         dvmCompilerFreeTemp(cUnit, regOffset);
    910     }
    911 
    912     if (rBase == rFP) {
    913         annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
    914     }
    915 #if defined(WITH_SELF_VERIFICATION)
    916     if (cUnit->heapMemOp)
    917         load->branchInsertSV = true;
    918 #endif
    919     return res;
    920 }
    921 
    922 static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
    923                             int displacement, int rDest, OpSize size,
    924                             int sReg)
    925 {
    926     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
    927                             size, sReg);
    928 }
    929 
    930 static  ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
    931                                  int displacement, int rDestLo, int rDestHi,
    932                                  int sReg)
    933 {
    934     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
    935                             kLong, sReg);
    936 }
    937 
    938 
    939 static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
    940                                  int displacement, int rSrc, int rSrcHi,
    941                                  OpSize size)
    942 {
    943     ArmLIR *res, *store;
    944     ArmOpCode opCode = kThumbBkpt;
    945     bool shortForm = false;
    946     bool thumb2Form = (displacement < 4092 && displacement >= 0);
    947     bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
    948     int encodedDisp = displacement;
    949 
    950     switch (size) {
    951         case kLong:
    952         case kDouble:
    953             if (!FPREG(rSrc)) {
    954                 res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
    955                                         -1, kWord);
    956                 storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
    957                                   -1, kWord);
    958                 return res;
    959             }
    960             if (SINGLEREG(rSrc)) {
    961                 assert(FPREG(rSrcHi));
    962                 rSrc = S2D(rSrc, rSrcHi);
    963             }
    964             opCode = kThumb2Vstrd;
    965             if (displacement <= 1020) {
    966                 shortForm = true;
    967                 encodedDisp >>= 2;
    968             }
    969             break;
    970         case kSingle:
    971         case kWord:
    972             if (FPREG(rSrc)) {
    973                 assert(SINGLEREG(rSrc));
    974                 opCode = kThumb2Vstrs;
    975                 if (displacement <= 1020) {
    976                     shortForm = true;
    977                     encodedDisp >>= 2;
    978                 }
    979             break;
    980             }
    981             if (allLowRegs && displacement < 128 && displacement >= 0) {
    982                 assert((displacement & 0x3) == 0);
    983                 shortForm = true;
    984                 encodedDisp >>= 2;
    985                 opCode = kThumbStrRRI5;
    986             } else if (thumb2Form) {
    987                 shortForm = true;
    988                 opCode = kThumb2StrRRI12;
    989             }
    990             break;
    991         case kUnsignedHalf:
    992         case kSignedHalf:
    993             if (allLowRegs && displacement < 64 && displacement >= 0) {
    994                 assert((displacement & 0x1) == 0);
    995                 shortForm = true;
    996                 encodedDisp >>= 1;
    997                 opCode = kThumbStrhRRI5;
    998             } else if (thumb2Form) {
    999                 shortForm = true;
   1000                 opCode = kThumb2StrhRRI12;
   1001             }
   1002             break;
   1003         case kUnsignedByte:
   1004         case kSignedByte:
   1005             if (allLowRegs && displacement < 32 && displacement >= 0) {
   1006                 shortForm = true;
   1007                 opCode = kThumbStrbRRI5;
   1008             } else if (thumb2Form) {
   1009                 shortForm = true;
   1010                 opCode = kThumb2StrbRRI12;
   1011             }
   1012             break;
   1013         default:
   1014             assert(0);
   1015     }
   1016     if (shortForm) {
   1017         store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
   1018     } else {
   1019         int rScratch = dvmCompilerAllocTemp(cUnit);
   1020         res = loadConstant(cUnit, rScratch, encodedDisp);
   1021         store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
   1022         dvmCompilerFreeTemp(cUnit, rScratch);
   1023     }
   1024 
   1025     if (rBase == rFP) {
   1026         annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
   1027     }
   1028 #if defined(WITH_SELF_VERIFICATION)
   1029     if (cUnit->heapMemOp)
   1030         store->branchInsertSV = true;
   1031 #endif
   1032     return res;
   1033 }
   1034 
   1035 static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
   1036                              int displacement, int rSrc, OpSize size)
   1037 {
   1038     return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
   1039 }
   1040 
   1041 static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
   1042                                  int displacement, int rSrcLo, int rSrcHi)
   1043 {
   1044     return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
   1045 }
   1046 
   1047 static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
   1048 {
   1049     ArmLIR *res;
   1050     genBarrier(cUnit);
   1051     if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
   1052         res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
   1053     } else {
   1054         res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask);
   1055     }
   1056 #if defined(WITH_SELF_VERIFICATION)
   1057     if (cUnit->heapMemOp)
   1058         res->branchInsertSV = true;
   1059 #endif
   1060     genBarrier(cUnit);
   1061     return res;
   1062 }
   1063 
   1064 static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
   1065 {
   1066     ArmLIR *res;
   1067     genBarrier(cUnit);
   1068     if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
   1069         res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
   1070     } else {
   1071         res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask);
   1072     }
   1073 #if defined(WITH_SELF_VERIFICATION)
   1074     if (cUnit->heapMemOp)
   1075         res->branchInsertSV = true;
   1076 #endif
   1077     genBarrier(cUnit);
   1078     return res;
   1079 }
   1080 
   1081 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
   1082 {
   1083     storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
   1084 }
   1085 
   1086 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
   1087 {
   1088     loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
   1089 }
   1090 
   1091 
   1092 /*
   1093  * Perform a "reg cmp imm" operation and jump to the PCR region if condition
   1094  * satisfies.
   1095  */
   1096 static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
   1097                               ArmConditionCode cond, int reg,
   1098                               int checkValue, int dOffset,
   1099                               ArmLIR *pcrLabel)
   1100 {
   1101     ArmLIR *branch;
   1102     int modImm;
   1103     if ((LOWREG(reg)) && (checkValue == 0) &&
   1104        ((cond == kArmCondEq) || (cond == kArmCondNe))) {
   1105         branch = newLIR2(cUnit,
   1106                          (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
   1107                          reg, 0);
   1108     } else {
   1109         modImm = modifiedImmediate(checkValue);
   1110         if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
   1111             newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
   1112         } else if (modImm >= 0) {
   1113             newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
   1114         } else {
   1115             int tReg = dvmCompilerAllocTemp(cUnit);
   1116             loadConstant(cUnit, tReg, checkValue);
   1117             opRegReg(cUnit, kOpCmp, reg, tReg);
   1118         }
   1119         branch = newLIR2(cUnit, kThumbBCond, 0, cond);
   1120     }
   1121     return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
   1122 }
   1123 
   1124 static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
   1125 {
   1126     ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
   1127     res->operands[0] = rDest;
   1128     res->operands[1] = rSrc;
   1129     if (rDest == rSrc) {
   1130         res->isNop = true;
   1131     } else {
   1132         assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
   1133         if (DOUBLEREG(rDest)) {
   1134             res->opCode = kThumb2Vmovd;
   1135         } else {
   1136             if (SINGLEREG(rDest)) {
   1137                 res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
   1138             } else {
   1139                 assert(SINGLEREG(rSrc));
   1140                 res->opCode = kThumb2Fmrs;
   1141             }
   1142         }
   1143         res->operands[0] = rDest;
   1144         res->operands[1] = rSrc;
   1145     }
   1146     setupResourceMasks(res);
   1147     return res;
   1148 }
   1149 
   1150 static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
   1151 {
   1152     ArmLIR* res;
   1153     ArmOpCode opCode;
   1154     if (FPREG(rDest) || FPREG(rSrc))
   1155         return fpRegCopy(cUnit, rDest, rSrc);
   1156     res = dvmCompilerNew(sizeof(ArmLIR), true);
   1157     if (LOWREG(rDest) && LOWREG(rSrc))
   1158         opCode = kThumbMovRR;
   1159     else if (!LOWREG(rDest) && !LOWREG(rSrc))
   1160          opCode = kThumbMovRR_H2H;
   1161     else if (LOWREG(rDest))
   1162          opCode = kThumbMovRR_H2L;
   1163     else
   1164          opCode = kThumbMovRR_L2H;
   1165 
   1166     res->operands[0] = rDest;
   1167     res->operands[1] = rSrc;
   1168     res->opCode = opCode;
   1169     setupResourceMasks(res);
   1170     if (rDest == rSrc) {
   1171         res->isNop = true;
   1172     }
   1173     return res;
   1174 }
   1175 
   1176 static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
   1177 {
   1178     ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
   1179     dvmCompilerAppendLIR(cUnit, (LIR*)res);
   1180     return res;
   1181 }
   1182 
   1183 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
   1184                            int srcLo, int srcHi)
   1185 {
   1186     bool destFP = FPREG(destLo) && FPREG(destHi);
   1187     bool srcFP = FPREG(srcLo) && FPREG(srcHi);
   1188     assert(FPREG(srcLo) == FPREG(srcHi));
   1189     assert(FPREG(destLo) == FPREG(destHi));
   1190     if (destFP) {
   1191         if (srcFP) {
   1192             genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
   1193         } else {
   1194             newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
   1195         }
   1196     } else {
   1197         if (srcFP) {
   1198             newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
   1199         } else {
   1200             // Handle overlap
   1201             if (srcHi == destLo) {
   1202                 genRegCopy(cUnit, destHi, srcHi);
   1203                 genRegCopy(cUnit, destLo, srcLo);
   1204             } else {
   1205                 genRegCopy(cUnit, destLo, srcLo);
   1206                 genRegCopy(cUnit, destHi, srcHi);
   1207             }
   1208         }
   1209     }
   1210 }
   1211