summaryrefslogtreecommitdiff
path: root/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp')
-rw-r--r--vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp452
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
+}