diff options
Diffstat (limited to 'vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp')
-rw-r--r-- | vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp new file mode 100644 index 0000000..4ddad69 --- /dev/null +++ b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Rebuild the interpreter frame then punt to the interpreter to execute + * instruction at specified PC. + * + * Currently parameters are passed to the current frame, so we just need to + * grow the stack save area above it, fill certain fields in StackSaveArea and + * Thread that are skipped during whole-method invocation (specified below), + * then return to the interpreter. + * + * StackSaveArea: + * - prevSave + * - prevFrame + * - savedPc + * - returnAddr + * - method + * + * Thread: + * - method + * - methodClassDex + * - curFrame + */ +static void genMethodInflateAndPunt(CompilationUnit *cUnit, MIR *mir, + BasicBlock *bb) +{ + int oldStackSave = r0; + int newStackSave = r1; + int oldFP = r2; + int savedPC = r3; + int currentPC = r4PC; + int returnAddr = r7; + int method = r8; + int pDvmDex = r9; + + /* + * TODO: check whether to raise the stack overflow exception when growing + * the stack save area. + */ + + /* Send everything to home location */ + dvmCompilerFlushAllRegs(cUnit); + + /* oldStackSave = r5FP + sizeof(current frame) */ + opRegRegImm(cUnit, kOpAdd, oldStackSave, r5FP, + cUnit->method->registersSize * 4); + /* oldFP = oldStackSave + sizeof(stackSaveArea) */ + opRegRegImm(cUnit, kOpAdd, oldFP, oldStackSave, sizeof(StackSaveArea)); + /* newStackSave = r5FP - sizeof(StackSaveArea) */ + opRegRegImm(cUnit, kOpSub, newStackSave, r5FP, sizeof(StackSaveArea)); + + loadWordDisp(cUnit, r13sp, 0, savedPC); + loadConstant(cUnit, currentPC, (int) (cUnit->method->insns + mir->offset)); + loadConstant(cUnit, method, (int) cUnit->method); + loadConstant(cUnit, pDvmDex, (int) cUnit->method->clazz->pDvmDex); +#ifdef EASY_GDB + /* newStackSave->prevSave = oldStackSave */ + storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevSave), + oldStackSave); +#endif + /* newStackSave->prevSave = oldStackSave */ + storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, prevFrame), + oldFP); + /* newStackSave->savedPc = savedPC */ + storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, savedPc), + savedPC); + /* return address */ + loadConstant(cUnit, returnAddr, 0); + storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, returnAddr), + returnAddr); + /* newStackSave->method = method */ + storeWordDisp(cUnit, newStackSave, offsetof(StackSaveArea, method), method); + /* thread->method = method */ + storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, method), method); + /* thread->interpSave.curFrame = current FP */ + storeWordDisp(cUnit, r6SELF, offsetof(Thread, interpSave.curFrame), r5FP); + /* thread->methodClassDex = pDvmDex */ + storeWordDisp(cUnit, r6SELF, offsetof(InterpSaveState, methodClassDex), + pDvmDex); + /* Restore the stack pointer */ + opRegImm(cUnit, kOpAdd, r13sp, 16); + genPuntToInterp(cUnit, mir->offset); +} + +/* + * The following are the first-level codegen routines that analyze the format + * of each bytecode then either dispatch special purpose codegen routines + * or produce corresponding Thumb instructions directly. + * + * TODO - most them are just pass-through to the trace-based versions for now + */ +static bool handleMethodFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir, + BasicBlock *bb, ArmLIR *labelList) +{ + /* backward branch? */ + bool backwardBranch = (bb->taken->startOffset <= mir->offset); + + if (backwardBranch && gDvmJit.genSuspendPoll) { + genSuspendPoll(cUnit, mir); + } + + /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */ + genUnconditionalBranch(cUnit, &labelList[bb->taken->id]); + return false; +} + +static bool handleMethodFmt10x(CompilationUnit *cUnit, MIR *mir) +{ + Opcode dalvikOpcode = mir->dalvikInsn.opcode; + switch (dalvikOpcode) { + case OP_RETURN_VOID: + return false; + default: + return handleFmt10x(cUnit, mir); + } +} + +static bool handleMethodFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt11n_Fmt31i(cUnit, mir); +} + +static bool handleMethodFmt11x(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, + ArmLIR *labelList) +{ + Opcode dalvikOpcode = mir->dalvikInsn.opcode; + switch (dalvikOpcode) { + case OP_THROW: + genMethodInflateAndPunt(cUnit, mir, bb); + return false; + default: + return handleFmt11x(cUnit, mir); + } +} + +static bool handleMethodFmt12x(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt12x(cUnit, mir); +} + +static bool handleMethodFmt20bc_Fmt40sc(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt20bc_Fmt40sc(cUnit, mir); +} + +static bool handleMethodFmt21c_Fmt31c_Fmt41c(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt21c_Fmt31c_Fmt41c(cUnit, mir); +} + +static bool handleMethodFmt21h(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt21h(cUnit, mir); +} + +static bool handleMethodFmt21s(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt21s(cUnit, mir); +} + +static bool handleMethodFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, + ArmLIR *labelList) +{ + return handleFmt21t(cUnit, mir, bb, labelList); +} + +static bool handleMethodFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt22b_Fmt22s(cUnit, mir); +} + +static bool handleMethodFmt22c_Fmt52c(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt22c_Fmt52c(cUnit, mir); +} + +static bool handleMethodFmt22cs(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt22cs(cUnit, mir); +} + +static bool handleMethodFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, + ArmLIR *labelList) +{ + return handleFmt22t(cUnit, mir, bb, labelList); +} + +static bool handleMethodFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt22x_Fmt32x(cUnit, mir); +} + +static bool handleMethodFmt23x(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt23x(cUnit, mir); +} + +static bool handleMethodFmt31t(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt31t(cUnit, mir); +} + +static bool handleMethodFmt35c_3rc_5rc(CompilationUnit *cUnit, MIR *mir, + BasicBlock *bb, ArmLIR *labelList) +{ + return handleFmt35c_3rc_5rc(cUnit, mir, bb, labelList); +} + +static bool handleMethodFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, + BasicBlock *bb, ArmLIR *labelList) +{ + return handleFmt35ms_3rms(cUnit, mir, bb, labelList); +} + +static bool handleMethodExecuteInline(CompilationUnit *cUnit, MIR *mir) +{ + return handleExecuteInline(cUnit, mir); +} + +static bool handleMethodFmt51l(CompilationUnit *cUnit, MIR *mir) +{ + return handleFmt51l(cUnit, mir); +} + +/* Handle the content in each basic block */ +static bool methodBlockCodeGen(CompilationUnit *cUnit, BasicBlock *bb) +{ + MIR *mir; + ArmLIR *labelList = (ArmLIR *) cUnit->blockLabelList; + int blockId = bb->id; + + cUnit->curBlock = bb; + labelList[blockId].operands[0] = bb->startOffset; + + /* Insert the block label */ + labelList[blockId].opcode = kArmPseudoNormalBlockLabel; + dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]); + + dvmCompilerClobberAllRegs(cUnit); + dvmCompilerResetNullCheck(cUnit); + + ArmLIR *headLIR = NULL; + + if (bb->blockType == kEntryBlock) { + /* r0 = callsitePC */ + opImm(cUnit, kOpPush, (1 << r0 | 1 << r1 | 1 << r5FP | 1 << r14lr)); + opRegImm(cUnit, kOpSub, r5FP, + sizeof(StackSaveArea) + cUnit->method->registersSize * 4); + + } else if (bb->blockType == kExitBlock) { + /* No need to pop r0 and r1 */ + opRegImm(cUnit, kOpAdd, r13sp, 8); + opImm(cUnit, kOpPop, (1 << r5FP | 1 << r15pc)); + } + + for (mir = bb->firstMIRInsn; mir; mir = mir->next) { + + dvmCompilerResetRegPool(cUnit); + if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) { + dvmCompilerClobberAllRegs(cUnit); + } + + if (gDvmJit.disableOpt & (1 << kSuppressLoads)) { + dvmCompilerResetDefTracking(cUnit); + } + + Opcode dalvikOpcode = mir->dalvikInsn.opcode; + InstructionFormat dalvikFormat = + dexGetFormatFromOpcode(dalvikOpcode); + + ArmLIR *boundaryLIR; + + /* + * Don't generate the boundary LIR unless we are debugging this + * trace or we need a scheduling barrier. + */ + if (headLIR == NULL || cUnit->printMe == true) { + boundaryLIR = + newLIR2(cUnit, kArmPseudoDalvikByteCodeBoundary, + mir->offset, + (int) dvmCompilerGetDalvikDisassembly( + &mir->dalvikInsn, "")); + /* Remember the first LIR for this block */ + if (headLIR == NULL) { + headLIR = boundaryLIR; + /* Set the first boundaryLIR as a scheduling barrier */ + headLIR->defMask = ENCODE_ALL; + } + } + + /* Don't generate the SSA annotation unless verbose mode is on */ + if (cUnit->printMe && mir->ssaRep) { + char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep); + newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString); + } + + bool notHandled; + switch (dalvikFormat) { + case kFmt10t: + case kFmt20t: + case kFmt30t: + notHandled = handleMethodFmt10t_Fmt20t_Fmt30t(cUnit, mir, bb, + labelList); + break; + case kFmt10x: + notHandled = handleMethodFmt10x(cUnit, mir); + break; + case kFmt11n: + case kFmt31i: + notHandled = handleMethodFmt11n_Fmt31i(cUnit, mir); + break; + case kFmt11x: + notHandled = handleMethodFmt11x(cUnit, mir, bb, labelList); + break; + case kFmt12x: + notHandled = handleMethodFmt12x(cUnit, mir); + break; + case kFmt20bc: + case kFmt40sc: + notHandled = handleMethodFmt20bc_Fmt40sc(cUnit, mir); + break; + case kFmt21c: + case kFmt31c: + case kFmt41c: + notHandled = handleMethodFmt21c_Fmt31c_Fmt41c(cUnit, mir); + break; + case kFmt21h: + notHandled = handleMethodFmt21h(cUnit, mir); + break; + case kFmt21s: + notHandled = handleMethodFmt21s(cUnit, mir); + break; + case kFmt21t: + notHandled = handleMethodFmt21t(cUnit, mir, bb, labelList); + break; + case kFmt22b: + case kFmt22s: + notHandled = handleMethodFmt22b_Fmt22s(cUnit, mir); + break; + case kFmt22c: + case kFmt52c: + notHandled = handleMethodFmt22c_Fmt52c(cUnit, mir); + break; + case kFmt22cs: + notHandled = handleMethodFmt22cs(cUnit, mir); + break; + case kFmt22t: + notHandled = handleMethodFmt22t(cUnit, mir, bb, labelList); + break; + case kFmt22x: + case kFmt32x: + notHandled = handleMethodFmt22x_Fmt32x(cUnit, mir); + break; + case kFmt23x: + notHandled = handleMethodFmt23x(cUnit, mir); + break; + case kFmt31t: + notHandled = handleMethodFmt31t(cUnit, mir); + break; + case kFmt3rc: + case kFmt35c: + case kFmt5rc: + notHandled = handleMethodFmt35c_3rc_5rc(cUnit, mir, bb, + labelList); + break; + case kFmt3rms: + case kFmt35ms: + notHandled = handleMethodFmt35ms_3rms(cUnit, mir, bb, + labelList); + break; + case kFmt35mi: + case kFmt3rmi: + notHandled = handleMethodExecuteInline(cUnit, mir); + break; + case kFmt51l: + notHandled = handleMethodFmt51l(cUnit, mir); + break; + default: + notHandled = true; + break; + } + + /* FIXME - to be implemented */ + if (notHandled == true && dalvikOpcode >= kNumPackedOpcodes) { + notHandled = false; + } + + if (notHandled) { + LOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled", + mir->offset, + dalvikOpcode, dexGetOpcodeName(dalvikOpcode), + dalvikFormat); + dvmCompilerAbort(cUnit); + break; + } + } + + if (headLIR) { + /* + * Eliminate redundant loads/stores and delay stores into later + * slots + */ + dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR, + cUnit->lastLIRInsn); + + /* + * Generate an unconditional branch to the fallthrough block. + */ + if (bb->fallThrough) { + genUnconditionalBranch(cUnit, + &labelList[bb->fallThrough->id]); + } + } + return false; +} + +void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit) +{ + // FIXME - enable method compilation for selected routines here + if (strcmp(cUnit->method->name, "add")) return; + + /* Used to hold the labels of each block */ + cUnit->blockLabelList = + (void *) dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true); + + dvmCompilerDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen, + kPreOrderDFSTraversal, + false /* isIterative */); + + dvmCompilerApplyGlobalOptimizations(cUnit); + + // FIXME - temporarily enable verbose printing for all methods + cUnit->printMe = true; + +#if defined(WITH_SELF_VERIFICATION) + selfVerificationBranchInsertPass(cUnit); +#endif +} |