Home | History | Annotate | Download | only in armv7-a-neon
      1 /*
      2  * Copyright (C) 2011 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  * Rebuild the interpreter frame then punt to the interpreter to execute
     19  * instruction at specified PC.
     20  *
     21  * Currently parameters are passed to the current frame, so we just need to
     22  * grow the stack save area above it, fill certain fields in StackSaveArea and
     23  * Thread that are skipped during whole-method invocation (specified below),
     24  * then return to the interpreter.
     25  *
     26  * StackSaveArea:
     27  *  - prevSave
     28  *  - prevFrame
     29  *  - savedPc
     30  *  - returnAddr
     31  *  - method
     32  *
     33  * Thread:
     34  *  - method
     35  *  - methodClassDex
     36  *  - curFrame
     37  */
     38 static void genMethodInflateAndPunt(CompilationUnit *cUnit, MIR *mir,
     39                                     BasicBlock *bb)
     40 {
     41     int oldStackSave = r0;
     42     int newStackSave = r1;
     43     int oldFP = r2;
     44     int savedPC = r3;
     45     int currentPC = r4PC;
     46     int returnAddr = r7;
     47     int method = r8;
     48     int pDvmDex = r9;
     49 
     50     /*
     51      * TODO: check whether to raise the stack overflow exception when growing
     52      * the stack save area.
     53      */
     54 
     55     /* Send everything to home location */
     56     dvmCompilerFlushAllRegs(cUnit);
     57 
     58     /* oldStackSave = r5FP + sizeof(current frame) */
     59     opRegRegImm(cUnit, kOpAdd, oldStackSave, r5FP,
     60                 cUnit->method->registersSize * 4);
     61     /* oldFP = oldStackSave + sizeof(stackSaveArea) */
     62     opRegRegImm(cUnit, kOpAdd, oldFP, oldStackSave, sizeof(StackSaveArea));
     63     /* newStackSave = r5FP - sizeof(StackSaveArea) */
     64     opRegRegImm(cUnit, kOpSub, newStackSave, r5FP, sizeof(StackSaveArea));
     65 
     66     loadWordDisp(cUnit, r13sp, 0, savedPC);
     67     loadConstant(cUnit, currentPC, (int) (cUnit->method->insns + mir->offset));
     68     loadConstant(cUnit, method, (int) cUnit->method);
     69     loadConstant(cUnit, pDvmDex, (int) cUnit->method->clazz->pDvmDex);
     70 #ifdef EASY_GDB
     71     /* newStackSave->prevSave = oldStackSave */
     72     storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevSave),
     73                   oldStackSave);
     74 #endif
     75     /* newStackSave->prevSave = oldStackSave */
     76     storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevFrame),
     77                   oldFP);
     78     /* newStackSave->savedPc = savedPC */
     79     storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, savedPc),
     80                   savedPC);
     81     /* return address */
     82     loadConstant(cUnit, returnAddr, 0);
     83     storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, returnAddr),
     84                   returnAddr);
     85     /* newStackSave->method = method */
     86     storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, method), method);
     87     /* thread->method = method */
     88     storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, method), method);
     89     /* thread->interpSave.curFrame = current FP */
     90     storeWordDisp(cUnit, r6SELF, offsetof(Thread, interpSave.curFrame), r5FP);
     91     /* thread->methodClassDex = pDvmDex */
     92     storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, methodClassDex),
     93                   pDvmDex);
     94     /* Restore the stack pointer */
     95     opRegImm(cUnit, kOpAdd, r13sp, 16);
     96     genPuntToInterp(cUnit, mir->offset);
     97 }
     98 
     99 /*
    100  * The following are the first-level codegen routines that analyze the format
    101  * of each bytecode then either dispatch special purpose codegen routines
    102  * or produce corresponding Thumb instructions directly.
    103  *
    104  * TODO - most them are just pass-through to the trace-based versions for now
    105  */
    106 static bool handleMethodFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
    107                                              BasicBlock *bb, ArmLIR *labelList)
    108 {
    109     /* backward branch? */
    110     bool backwardBranch = (bb->taken->startOffset <= mir->offset);
    111 
    112     if (backwardBranch && gDvmJit.genSuspendPoll) {
    113         genSuspendPoll(cUnit, mir);
    114     }
    115 
    116     /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
    117     genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
    118     return false;
    119 }
    120 
    121 static bool handleMethodFmt10x(CompilationUnit *cUnit, MIR *mir)
    122 {
    123     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
    124     switch (dalvikOpcode) {
    125         case OP_RETURN_VOID:
    126             return false;
    127         default:
    128             return handleFmt10x(cUnit, mir);
    129     }
    130 }
    131 
    132 static bool handleMethodFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
    133 {
    134     return handleFmt11n_Fmt31i(cUnit, mir);
    135 }
    136 
    137 static bool handleMethodFmt11x(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
    138                                ArmLIR *labelList)
    139 {
    140     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
    141     switch (dalvikOpcode) {
    142         case OP_THROW:
    143             genMethodInflateAndPunt(cUnit, mir, bb);
    144             return false;
    145         default:
    146             return handleFmt11x(cUnit, mir);
    147     }
    148 }
    149 
    150 static bool handleMethodFmt12x(CompilationUnit *cUnit, MIR *mir)
    151 {
    152     return handleFmt12x(cUnit, mir);
    153 }
    154 
    155 static bool handleMethodFmt20bc(CompilationUnit *cUnit, MIR *mir)
    156 {
    157     return handleFmt20bc(cUnit, mir);
    158 }
    159 
    160 static bool handleMethodFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
    161 {
    162     return handleFmt21c_Fmt31c(cUnit, mir);
    163 }
    164 
    165 static bool handleMethodFmt21h(CompilationUnit *cUnit, MIR *mir)
    166 {
    167     return handleFmt21h(cUnit, mir);
    168 }
    169 
    170 static bool handleMethodFmt21s(CompilationUnit *cUnit, MIR *mir)
    171 {
    172     return handleFmt21s(cUnit, mir);
    173 }
    174 
    175 static bool handleMethodFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
    176                                ArmLIR *labelList)
    177 {
    178     return handleFmt21t(cUnit, mir, bb, labelList);
    179 }
    180 
    181 static bool handleMethodFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
    182 {
    183     return handleFmt22b_Fmt22s(cUnit, mir);
    184 }
    185 
    186 static bool handleMethodFmt22c(CompilationUnit *cUnit, MIR *mir)
    187 {
    188     return handleFmt22c(cUnit, mir);
    189 }
    190 
    191 static bool handleMethodFmt22cs(CompilationUnit *cUnit, MIR *mir)
    192 {
    193     return handleFmt22cs(cUnit, mir);
    194 }
    195 
    196 static bool handleMethodFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
    197                                ArmLIR *labelList)
    198 {
    199     return handleFmt22t(cUnit, mir, bb, labelList);
    200 }
    201 
    202 static bool handleMethodFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
    203 {
    204     return handleFmt22x_Fmt32x(cUnit, mir);
    205 }
    206 
    207 static bool handleMethodFmt23x(CompilationUnit *cUnit, MIR *mir)
    208 {
    209     return handleFmt23x(cUnit, mir);
    210 }
    211 
    212 static bool handleMethodFmt31t(CompilationUnit *cUnit, MIR *mir)
    213 {
    214     return handleFmt31t(cUnit, mir);
    215 }
    216 
    217 static bool handleMethodFmt35c_3rc(CompilationUnit *cUnit, MIR *mir,
    218                                        BasicBlock *bb, ArmLIR *labelList)
    219 {
    220     return handleFmt35c_3rc(cUnit, mir, bb, labelList);
    221 }
    222 
    223 static bool handleMethodFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
    224                                      BasicBlock *bb, ArmLIR *labelList)
    225 {
    226     return handleFmt35ms_3rms(cUnit, mir, bb, labelList);
    227 }
    228 
    229 static bool handleMethodExecuteInline(CompilationUnit *cUnit, MIR *mir)
    230 {
    231     return handleExecuteInline(cUnit, mir);
    232 }
    233 
    234 static bool handleMethodFmt51l(CompilationUnit *cUnit, MIR *mir)
    235 {
    236     return handleFmt51l(cUnit, mir);
    237 }
    238 
    239 /* Handle the content in each basic block */
    240 static bool methodBlockCodeGen(CompilationUnit *cUnit, BasicBlock *bb)
    241 {
    242     MIR *mir;
    243     ArmLIR *labelList = (ArmLIR *) cUnit->blockLabelList;
    244     int blockId = bb->id;
    245 
    246     cUnit->curBlock = bb;
    247     labelList[blockId].operands[0] = bb->startOffset;
    248 
    249     /* Insert the block label */
    250     labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
    251     dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
    252 
    253     dvmCompilerClobberAllRegs(cUnit);
    254     dvmCompilerResetNullCheck(cUnit);
    255 
    256     ArmLIR *headLIR = NULL;
    257 
    258     if (bb->blockType == kEntryBlock) {
    259         /* r0 = callsitePC */
    260         opImm(cUnit, kOpPush, (1 << r0 | 1 << r1 | 1 << r5FP | 1 << r14lr));
    261         opRegImm(cUnit, kOpSub, r5FP,
    262                  sizeof(StackSaveArea) + cUnit->method->registersSize * 4);
    263 
    264     } else if (bb->blockType == kExitBlock) {
    265         /* No need to pop r0 and r1 */
    266         opRegImm(cUnit, kOpAdd, r13sp, 8);
    267         opImm(cUnit, kOpPop, (1 << r5FP | 1 << r15pc));
    268     }
    269 
    270     for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
    271 
    272         dvmCompilerResetRegPool(cUnit);
    273         if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
    274             dvmCompilerClobberAllRegs(cUnit);
    275         }
    276 
    277         if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
    278             dvmCompilerResetDefTracking(cUnit);
    279         }
    280 
    281         Opcode dalvikOpcode = mir->dalvikInsn.opcode;
    282         InstructionFormat dalvikFormat =
    283             dexGetFormatFromOpcode(dalvikOpcode);
    284 
    285         ArmLIR *boundaryLIR;
    286 
    287         /*
    288          * Don't generate the boundary LIR unless we are debugging this
    289          * trace or we need a scheduling barrier.
    290          */
    291         if (headLIR == NULL || cUnit->printMe == true) {
    292             boundaryLIR =
    293                 newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary,
    294                         mir->offset,
    295                         (int) dvmCompilerGetDalvikDisassembly(
    296                             &mir->dalvikInsn, ""));
    297             /* Remember the first LIR for this block */
    298             if (headLIR == NULL) {
    299                 headLIR = boundaryLIR;
    300                 /* Set the first boundaryLIR as a scheduling barrier */
    301                 headLIR->defMask = ENCODE_ALL;
    302             }
    303         }
    304 
    305         /* Don't generate the SSA annotation unless verbose mode is on */
    306         if (cUnit->printMe && mir->ssaRep) {
    307             char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
    308             newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
    309         }
    310 
    311         bool notHandled;
    312         switch (dalvikFormat) {
    313             case kFmt10t:
    314             case kFmt20t:
    315             case kFmt30t:
    316                 notHandled = handleMethodFmt10t_Fmt20t_Fmt30t(cUnit, mir, bb,
    317                                                               labelList);
    318                 break;
    319             case kFmt10x:
    320                 notHandled = handleMethodFmt10x(cUnit, mir);
    321                 break;
    322             case kFmt11n:
    323             case kFmt31i:
    324                 notHandled = handleMethodFmt11n_Fmt31i(cUnit, mir);
    325                 break;
    326             case kFmt11x:
    327                 notHandled = handleMethodFmt11x(cUnit, mir, bb, labelList);
    328                 break;
    329             case kFmt12x:
    330                 notHandled = handleMethodFmt12x(cUnit, mir);
    331                 break;
    332             case kFmt20bc:
    333                 notHandled = handleMethodFmt20bc(cUnit, mir);
    334                 break;
    335             case kFmt21c:
    336             case kFmt31c:
    337                 notHandled = handleMethodFmt21c_Fmt31c(cUnit, mir);
    338                 break;
    339             case kFmt21h:
    340                 notHandled = handleMethodFmt21h(cUnit, mir);
    341                 break;
    342             case kFmt21s:
    343                 notHandled = handleMethodFmt21s(cUnit, mir);
    344                 break;
    345             case kFmt21t:
    346                 notHandled = handleMethodFmt21t(cUnit, mir, bb, labelList);
    347                 break;
    348             case kFmt22b:
    349             case kFmt22s:
    350                 notHandled = handleMethodFmt22b_Fmt22s(cUnit, mir);
    351                 break;
    352             case kFmt22c:
    353                 notHandled = handleMethodFmt22c(cUnit, mir);
    354                 break;
    355             case kFmt22cs:
    356                 notHandled = handleMethodFmt22cs(cUnit, mir);
    357                 break;
    358             case kFmt22t:
    359                 notHandled = handleMethodFmt22t(cUnit, mir, bb, labelList);
    360                 break;
    361             case kFmt22x:
    362             case kFmt32x:
    363                 notHandled = handleMethodFmt22x_Fmt32x(cUnit, mir);
    364                 break;
    365             case kFmt23x:
    366                 notHandled = handleMethodFmt23x(cUnit, mir);
    367                 break;
    368             case kFmt31t:
    369                 notHandled = handleMethodFmt31t(cUnit, mir);
    370                 break;
    371             case kFmt3rc:
    372             case kFmt35c:
    373                 notHandled = handleMethodFmt35c_3rc(cUnit, mir, bb, labelList);
    374                 break;
    375             case kFmt3rms:
    376             case kFmt35ms:
    377                 notHandled = handleMethodFmt35ms_3rms(cUnit, mir, bb,
    378                                                       labelList);
    379                 break;
    380             case kFmt35mi:
    381             case kFmt3rmi:
    382                 notHandled = handleMethodExecuteInline(cUnit, mir);
    383                 break;
    384             case kFmt51l:
    385                 notHandled = handleMethodFmt51l(cUnit, mir);
    386                 break;
    387             default:
    388                 notHandled = true;
    389                 break;
    390         }
    391 
    392         /* FIXME - to be implemented */
    393         if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) {
    394             notHandled = false;
    395         }
    396 
    397         if (notHandled) {
    398             ALOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled",
    399                  mir->offset,
    400                  dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
    401                  dalvikFormat);
    402             dvmCompilerAbort(cUnit);
    403             break;
    404         }
    405     }
    406 
    407     if (headLIR) {
    408         /*
    409          * Eliminate redundant loads/stores and delay stores into later
    410          * slots
    411          */
    412         dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
    413                                            cUnit->lastLIRInsn);
    414 
    415         /*
    416          * Generate an unconditional branch to the fallthrough block.
    417          */
    418         if (bb->fallThrough) {
    419             genUnconditionalBranch(cUnit,
    420                                    &labelList[bb->fallThrough->id]);
    421         }
    422     }
    423     return false;
    424 }
    425 
    426 void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
    427 {
    428     // FIXME - enable method compilation for selected routines here
    429     if (strcmp(cUnit->method->name, "add")) return;
    430 
    431     /* Used to hold the labels of each block */
    432     cUnit->blockLabelList =
    433         (void *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
    434 
    435     dvmCompilerDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
    436                                           kPreOrderDFSTraversal,
    437                                           false /* isIterative */);
    438 
    439     dvmCompilerApplyGlobalOptimizations(cUnit);
    440 
    441     // FIXME - temporarily enable verbose printing for all methods
    442     cUnit->printMe = true;
    443 
    444 #if defined(WITH_SELF_VERIFICATION)
    445     selfVerificationBranchInsertPass(cUnit);
    446 #endif
    447 }
    448