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 /*
     26  * Perform a "reg cmp imm" operation and jump to the PCR region if condition
     27  * satisfies.
     28  */
     29 static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
     30                         RegLocation rlSrc)
     31 {
     32     RegLocation rlResult;
     33     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
     34     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
     35     opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
     36                 rlSrc.lowReg, 0x80000000);
     37     storeValue(cUnit, rlDest, rlResult);
     38 }
     39 
     40 static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
     41                          RegLocation rlSrc)
     42 {
     43     RegLocation rlResult;
     44     rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
     45     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
     46     opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
     47                         0x80000000);
     48     genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
     49     storeValueWide(cUnit, rlDest, rlResult);
     50 }
     51 
     52 static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
     53                        RegLocation rlSrc1, RegLocation rlSrc2)
     54 {
     55     RegLocation rlResult;
     56     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
     57     loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
     58     genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
     59     rlResult = dvmCompilerGetReturnWide(cUnit);
     60     storeValueWide(cUnit, rlDest, rlResult);
     61 }
     62 
     63 static bool partialOverlap(int sreg1, int sreg2)
     64 {
     65     return abs(sreg1 - sreg2) == 1;
     66 }
     67 
     68 static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
     69                          OpKind secondOp, RegLocation rlDest,
     70                          RegLocation rlSrc1, RegLocation rlSrc2)
     71 {
     72     RegLocation rlResult;
     73     if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
     74         partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
     75         partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
     76         // Rare case - not enough registers to properly handle
     77         genInterpSingleStep(cUnit, mir);
     78     } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
     79         // Already 2-operand
     80         rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
     81         rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
     82         opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
     83         opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
     84         storeValueWide(cUnit, rlDest, rlResult);
     85     } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
     86         // Bad case - must use/clobber Src1 and reassign Dest
     87         rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
     88         rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
     89         opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg);
     90         opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg);
     91         // Old reg assignments are now invalid
     92         dvmCompilerClobber(cUnit, rlResult.lowReg);
     93         dvmCompilerClobber(cUnit, rlResult.highReg);
     94         dvmCompilerClobber(cUnit, rlSrc1.lowReg);
     95         dvmCompilerClobber(cUnit, rlSrc1.highReg);
     96         rlDest.location = kLocDalvikFrame;
     97         assert(rlSrc1.location == kLocPhysReg);
     98         // Reassign registers - rlDest will now get rlSrc1's old regs
     99         storeValueWide(cUnit, rlDest, rlSrc1);
    100     } else {
    101         // Copy Src1 to Dest
    102         rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
    103         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, false);
    104         loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg,
    105                             rlResult.highReg);
    106         rlResult.location = kLocPhysReg;
    107         opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
    108         opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
    109         storeValueWide(cUnit, rlDest, rlResult);
    110     }
    111 }
    112 
    113 void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
    114 {
    115     int numTemps = sizeof(coreTemps)/sizeof(int);
    116     RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
    117     cUnit->regPool = pool;
    118     pool->numCoreTemps = numTemps;
    119     pool->coreTemps =
    120             dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
    121     pool->numFPTemps = 0;
    122     pool->FPTemps = NULL;
    123     pool->numCoreRegs = 0;
    124     pool->coreRegs = NULL;
    125     pool->numFPRegs = 0;
    126     pool->FPRegs = NULL;
    127     dvmCompilerInitPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
    128     dvmCompilerInitPool(pool->FPTemps, NULL, 0);
    129     dvmCompilerInitPool(pool->coreRegs, NULL, 0);
    130     dvmCompilerInitPool(pool->FPRegs, NULL, 0);
    131     pool->nullCheckedRegs =
    132         dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
    133 }
    134 
    135 /* Export the Dalvik PC assicated with an instruction to the StackSave area */
    136 static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
    137 {
    138     ArmLIR *res;
    139     int rDPC = dvmCompilerAllocTemp(cUnit);
    140     int rAddr = dvmCompilerAllocTemp(cUnit);
    141     int offset = offsetof(StackSaveArea, xtra.currentPc);
    142     res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
    143     newLIR2(cUnit, kThumbMovRR, rAddr, rFP);
    144     newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset);
    145     storeWordDisp( cUnit, rAddr, 0, rDPC);
    146     return res;
    147 }
    148 
    149 static void genMonitor(CompilationUnit *cUnit, MIR *mir)
    150 {
    151     genMonitorPortable(cUnit, mir);
    152 }
    153 
    154 static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
    155                        RegLocation rlSrc1, RegLocation rlSrc2)
    156 {
    157     RegLocation rlResult;
    158     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
    159     loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
    160     genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
    161     rlResult = dvmCompilerGetReturn(cUnit);
    162     storeValue(cUnit, rlDest, rlResult);
    163 }
    164 
    165 static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
    166 {
    167     int offset = offsetof(InterpState, retval);
    168     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
    169     int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
    170     int signMask = dvmCompilerAllocTemp(cUnit);
    171     loadConstant(cUnit, signMask, 0x7fffffff);
    172     newLIR2(cUnit, kThumbAndRR, reg0, signMask);
    173     dvmCompilerFreeTemp(cUnit, signMask);
    174     storeWordDisp(cUnit, rGLUE, offset, reg0);
    175     //TUNING: rewrite this to not clobber
    176     dvmCompilerClobber(cUnit, reg0);
    177     return true;
    178 }
    179 
    180 static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
    181 {
    182     int offset = offsetof(InterpState, retval);
    183     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    184     RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
    185     int reglo = regSrc.lowReg;
    186     int reghi = regSrc.highReg;
    187     int signMask = dvmCompilerAllocTemp(cUnit);
    188     loadConstant(cUnit, signMask, 0x7fffffff);
    189     storeWordDisp(cUnit, rGLUE, offset, reglo);
    190     newLIR2(cUnit, kThumbAndRR, reghi, signMask);
    191     dvmCompilerFreeTemp(cUnit, signMask);
    192     storeWordDisp(cUnit, rGLUE, offset + 4, reghi);
    193     //TUNING: rewrite this to not clobber
    194     dvmCompilerClobber(cUnit, reghi);
    195     return true;
    196 }
    197 
    198 /* No select in thumb, so we need to branch.  Thumb2 will do better */
    199 static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
    200 {
    201     int offset = offsetof(InterpState, retval);
    202     RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
    203     RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
    204     int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
    205     int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
    206     newLIR2(cUnit, kThumbCmpRR, reg0, reg1);
    207     ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2,
    208            isMin ? kArmCondLt : kArmCondGt);
    209     newLIR2(cUnit, kThumbMovRR, reg0, reg1);
    210     ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
    211     target->defMask = ENCODE_ALL;
    212     newLIR3(cUnit, kThumbStrRRI5, reg0, rGLUE, offset >> 2);
    213     branch1->generic.target = (LIR *)target;
    214     //TUNING: rewrite this to not clobber
    215     dvmCompilerClobber(cUnit,reg0);
    216     return false;
    217 }
    218 
    219 static void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
    220         RegLocation rlSrc, RegLocation rlResult, int lit,
    221         int firstBit, int secondBit)
    222 {
    223     // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
    224     // to do a regular multiply.
    225     opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
    226 }
    227