Home | History | Annotate | Download | only in Mips32
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * This file contains codegen for the Mips ISA and is intended to be
     19  * includes by:
     20  *
     21  *        Codegen-$(TARGET_ARCH_VARIANT).c
     22  *
     23  */
     24 
     25 /*
     26  * Reserve 8 bytes at the beginning of the trace
     27  *        +----------------------------+
     28  *        | prof count addr (4 bytes)  |
     29  *        +----------------------------+
     30  *        | chain cell offset (4 bytes)|
     31  *        +----------------------------+
     32  *
     33  * ...and then code to increment the execution
     34  *
     35  * For continuous profiling (24 bytes)
     36  *       lahi  a0, addr    # get ptr to prof count addr into a0
     37  *       lalo  a0, addr
     38  *       lw    a0, 0(a0)   # read prof count addr into a0
     39  *       lw    a1, 0(a0)   # read prof count into a1
     40  *       addiu a1, a1, 1   # increment count
     41  *       sw    a1, 0(a0)   # store count
     42  *
     43  * For periodic profiling (8 bytes)
     44  *       call  TEMPLATE_PERIODIC_PROFILING
     45  *       nop
     46  *
     47  * and return the size (in bytes) of the generated code.
     48  */
     49 static int genTraceProfileEntry(CompilationUnit *cUnit)
     50 {
     51     intptr_t addr = (intptr_t)dvmJitNextTraceCounter();
     52     assert(__BYTE_ORDER == __LITTLE_ENDIAN);
     53     MipsLIR *executionCount = newLIR1(cUnit, kMips32BitData, addr);
     54     cUnit->chainCellOffsetLIR =
     55         (LIR *) newLIR1(cUnit, kMips32BitData, CHAIN_CELL_OFFSET_TAG);
     56     cUnit->headerSize = 8;
     57     if ((gDvmJit.profileMode == kTraceProfilingContinuous) ||
     58         (gDvmJit.profileMode == kTraceProfilingDisabled)) {
     59         MipsLIR *loadAddr = newLIR2(cUnit, kMipsLahi, r_A0, 0);
     60         loadAddr->generic.target = (LIR *) executionCount;
     61         loadAddr = newLIR3(cUnit, kMipsLalo, r_A0, r_A0, 0);
     62         loadAddr ->generic.target = (LIR *) executionCount;
     63         newLIR3(cUnit, kMipsLw, r_A0, 0, r_A0);
     64         newLIR3(cUnit, kMipsLw, r_A1, 0, r_A0);
     65         newLIR3(cUnit, kMipsAddiu, r_A1, r_A1, 1);
     66         newLIR3(cUnit, kMipsSw, r_A1, 0, r_A0);
     67         return 24;
     68     } else {
     69         int opcode = TEMPLATE_PERIODIC_PROFILING;
     70         newLIR1(cUnit, kMipsJal,
     71             (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
     72         newLIR0(cUnit, kMipsNop); /* delay slot */
     73         return 8;
     74     }
     75 }
     76 
     77 /*
     78  * Perform a "reg cmp imm" operation and jump to the PCR region if condition
     79  * satisfies.
     80  */
     81 static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
     82                         RegLocation rlSrc)
     83 {
     84     RegLocation rlResult;
     85     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
     86     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
     87     opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
     88                 rlSrc.lowReg, 0x80000000);
     89     storeValue(cUnit, rlDest, rlResult);
     90 }
     91 
     92 static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
     93                          RegLocation rlSrc)
     94 {
     95     RegLocation rlResult;
     96     rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
     97     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
     98     opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
     99                         0x80000000);
    100     genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
    101     storeValueWide(cUnit, rlDest, rlResult);
    102 }
    103 
    104 static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
    105                        RegLocation rlSrc1, RegLocation rlSrc2)
    106 {
    107     RegLocation rlResult;
    108     loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
    109     loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
    110     genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
    111     rlResult = dvmCompilerGetReturnWide(cUnit);
    112     storeValueWide(cUnit, rlDest, rlResult);
    113 }
    114 
    115 static bool partialOverlap(int sreg1, int sreg2)
    116 {
    117     return abs(sreg1 - sreg2) == 1;
    118 }
    119 
    120 static void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc,
    121                             RegLocation rlDest, RegLocation rlSrc1,
    122                             RegLocation rlSrc2, int sltuSrc1, int sltuSrc2)
    123 {
    124     int tReg = dvmCompilerAllocTemp(cUnit);
    125     newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
    126     newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2);
    127     newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg);
    128     newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg);
    129     dvmCompilerFreeTemp(cUnit, tReg);
    130 }
    131 
    132 static void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
    133                          OpKind secondOp, RegLocation rlDest,
    134                          RegLocation rlSrc1, RegLocation rlSrc2)
    135 {
    136     RegLocation rlResult;
    137     int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc);
    138 
    139     if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
    140         partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
    141         partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
    142         // Rare case - not enough registers to properly handle
    143         genInterpSingleStep(cUnit, mir);
    144     } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
    145         rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
    146         rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
    147         if (!carryOp) {
    148             opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg);
    149             opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg);
    150         } else if (secondOp == kOpAdc) {
    151             withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2,
    152                             rlResult.lowReg, rlSrc2.lowReg);
    153         } else {
    154             int tReg = dvmCompilerAllocTemp(cUnit);
    155             newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg);
    156             withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2,
    157                             tReg, rlResult.lowReg);
    158             dvmCompilerFreeTemp(cUnit, tReg);
    159         }
    160         storeValueWide(cUnit, rlDest, rlResult);
    161     } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
    162         rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
    163         rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
    164         if (!carryOp) {
    165             opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg);
    166             opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg);
    167         } else if (secondOp == kOpAdc) {
    168             withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult,
    169                             rlResult.lowReg, rlSrc1.lowReg);
    170         } else {
    171             withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult,
    172                             rlSrc1.lowReg, rlResult.lowReg);
    173         }
    174         storeValueWide(cUnit, rlDest, rlResult);
    175     } else {
    176         rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
    177         rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
    178         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
    179         if (!carryOp) {
    180             opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
    181             opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
    182         } else if (secondOp == kOpAdc) {
    183             withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2,
    184                             rlResult.lowReg, rlSrc1.lowReg);
    185         } else {
    186             withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2,
    187                             rlSrc1.lowReg, rlResult.lowReg);
    188         }
    189         storeValueWide(cUnit, rlDest, rlResult);
    190     }
    191 }
    192 
    193 void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
    194 {
    195     int numTemps = sizeof(coreTemps)/sizeof(int);
    196     RegisterPool *pool = (RegisterPool *) dvmCompilerNew(sizeof(*pool), true);
    197     cUnit->regPool = pool;
    198     pool->numCoreTemps = numTemps;
    199     pool->coreTemps =
    200             (RegisterInfo *) dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
    201     dvmCompilerInitPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
    202 #ifdef __mips_hard_float
    203     int numFPTemps = sizeof(fpTemps)/sizeof(int);
    204     pool->numFPTemps = numFPTemps;
    205     pool->FPTemps =
    206             (RegisterInfo *) dvmCompilerNew(numFPTemps * sizeof(*pool->FPTemps), true);
    207     dvmCompilerInitPool(pool->FPTemps, fpTemps, pool->numFPTemps);
    208 #else
    209     pool->numFPTemps = 0;
    210     pool->FPTemps = NULL;
    211     dvmCompilerInitPool(pool->FPTemps, NULL, 0);
    212 #endif
    213     pool->nullCheckedRegs =
    214         dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
    215 }
    216 
    217 /* Export the Dalvik PC assicated with an instruction to the StackSave area */
    218 static MipsLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
    219 {
    220     MipsLIR *res;
    221     int rDPC = dvmCompilerAllocTemp(cUnit);
    222     int rAddr = dvmCompilerAllocTemp(cUnit);
    223     int offset = offsetof(StackSaveArea, xtra.currentPc);
    224     res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
    225     newLIR3(cUnit, kMipsAddiu, rAddr, rFP, -(sizeof(StackSaveArea) - offset));
    226     storeWordDisp( cUnit, rAddr, 0, rDPC);
    227     return res;
    228 }
    229 
    230 static void genMonitor(CompilationUnit *cUnit, MIR *mir)
    231 {
    232     genMonitorPortable(cUnit, mir);
    233 }
    234 
    235 static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
    236                        RegLocation rlSrc1, RegLocation rlSrc2)
    237 {
    238     RegLocation rlResult;
    239     loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
    240     loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
    241     genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
    242     rlResult = dvmCompilerGetReturn(cUnit);
    243     storeValue(cUnit, rlDest, rlResult);
    244 }
    245 
    246 static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
    247 {
    248     int offset = offsetof(Thread, interpSave.retval);
    249     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
    250     int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
    251 #if __mips_isa_rev>=2
    252     newLIR4(cUnit, kMipsExt, reg0, reg0, 0, 31-1 /* size-1 */);
    253 #else
    254     newLIR2(cUnit, kMipsSll, reg0, 1);
    255     newLIR2(cUnit, kMipsSrl, reg0, 1);
    256 #endif
    257     storeWordDisp(cUnit, rSELF, offset, reg0);
    258     //TUNING: rewrite this to not clobber
    259     dvmCompilerClobber(cUnit, reg0);
    260     return false;
    261 }
    262 
    263 static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
    264 {
    265     int offset = offsetof(Thread, interpSave.retval);
    266     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    267     RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
    268     int reglo = regSrc.lowReg;
    269     int reghi = regSrc.highReg;
    270     storeWordDisp(cUnit, rSELF, offset + LOWORD_OFFSET, reglo);
    271 #if __mips_isa_rev>=2
    272     newLIR4(cUnit, kMipsExt, reghi, reghi, 0, 31-1 /* size-1 */);
    273 #else
    274     newLIR2(cUnit, kMipsSll, reghi, 1);
    275     newLIR2(cUnit, kMipsSrl, reghi, 1);
    276 #endif
    277     storeWordDisp(cUnit, rSELF, offset + HIWORD_OFFSET, reghi);
    278     //TUNING: rewrite this to not clobber
    279     dvmCompilerClobber(cUnit, reghi);
    280     return false;
    281 }
    282 
    283 /* No select in thumb, so we need to branch.  Thumb2 will do better */
    284 static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
    285 {
    286     int offset = offsetof(Thread, interpSave.retval);
    287     RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
    288     RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
    289     int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
    290     int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
    291     int tReg = dvmCompilerAllocTemp(cUnit);
    292     if (isMin) {
    293        newLIR3(cUnit, kMipsSlt, tReg, reg0, reg1);
    294     }
    295     else {
    296        newLIR3(cUnit, kMipsSlt, tReg, reg1, reg0);
    297     }
    298     newLIR3(cUnit, kMipsMovz, reg0, reg1, tReg);
    299     dvmCompilerFreeTemp(cUnit, tReg);
    300     newLIR3(cUnit, kMipsSw, reg0, offset, rSELF);
    301     //TUNING: rewrite this to not clobber
    302     dvmCompilerClobber(cUnit,reg0);
    303     return false;
    304 }
    305 
    306 static void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
    307         RegLocation rlSrc, RegLocation rlResult, int lit,
    308         int firstBit, int secondBit)
    309 {
    310     // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
    311     // to do a regular multiply.
    312     opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
    313 }
    314