Custom codegen for small frameless methods.
Added a general mechanism that will allow pattern matching of
small methods and (generally) frameless code generation. Prevously,
all frames were at least 16 bytes, not you can have zero-length
frames (and thus some old asserts had to go).
Change-Id: Ic786940a602e25b48cbc317ac601ac84cc307762
diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h
index 1137db3..8f854da 100644
--- a/src/compiler/codegen/CompilerCodegen.h
+++ b/src/compiler/codegen/CompilerCodegen.h
@@ -29,6 +29,9 @@
/* Lower middle-level IR to low-level IR for the whole method */
void oatMethodMIR2LIR(CompilationUnit* cUnit);
+/* Lower middle-level IR to low-level IR for the simple methods */
+void oatSpecialMIR2LIR(CompilationUnit* cUnit, SpecialCaseHandler specialCase );
+
/* Assemble LIR into machine code */
void oatAssembleLIR(CompilationUnit* cUnit);
AssemblerStatus oatAssembleInstructions(CompilationUnit* cUnit,
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index c5b28b3..f63ad4c 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -931,6 +931,17 @@
setupResourceMasks(lir);
}
+bool fastInstance(CompilationUnit* cUnit, uint32_t fieldIdx,
+ int& fieldOffset, bool& isVolatile, bool isPut)
+{
+ OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
+ *cUnit->dex_file, *cUnit->dex_cache,
+ cUnit->code_item, cUnit->method_idx,
+ cUnit->access_flags);
+ return cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
+ fieldOffset, isVolatile, isPut);
+}
+
void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
RegLocation rlDest, RegLocation rlObj,
bool isLongOrDouble, bool isObject)
@@ -939,13 +950,8 @@
bool isVolatile;
uint32_t fieldIdx = mir->dalvikInsn.vC;
- OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
- *cUnit->dex_file, *cUnit->dex_cache,
- cUnit->code_item, cUnit->method_idx,
- cUnit->access_flags);
-
- bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
- fieldOffset, isVolatile, false);
+ bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+ false);
if (fastPath && !SLOW_FIELD_PATH) {
RegLocation rlResult;
@@ -1006,13 +1012,8 @@
bool isVolatile;
uint32_t fieldIdx = mir->dalvikInsn.vC;
- OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
- *cUnit->dex_file, *cUnit->dex_cache,
- cUnit->code_item, cUnit->method_idx,
- cUnit->access_flags);
-
- bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
- fieldOffset, isVolatile, true);
+ bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+ true);
if (fastPath && !SLOW_FIELD_PATH) {
RegisterClass regClass = oatRegClassBySize(size);
DCHECK_GE(fieldOffset, 0);
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 8f4df47..671eb73 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -887,6 +887,50 @@
return false;
}
+/* Set basic block labels */
+bool labelBlocks(CompilationUnit* cUnit, BasicBlock* bb)
+{
+ LIR* labelList = (LIR*) cUnit->blockLabelList;
+ int blockId = bb->id;
+
+ cUnit->curBlock = bb;
+ labelList[blockId].operands[0] = bb->startOffset;
+
+ /* Insert the block label */
+ labelList[blockId].opcode = kPseudoNormalBlockLabel;
+ return false;
+}
+
+void oatSpecialMIR2LIR(CompilationUnit* cUnit, SpecialCaseHandler specialCase)
+{
+ /* Find the first DalvikByteCode block */
+ int numReachableBlocks = cUnit->numReachableBlocks;
+ const GrowableList *blockList = &cUnit->blockList;
+ BasicBlock*bb = NULL;
+ for (int idx = 0; idx < numReachableBlocks; idx++) {
+ int dfsIndex = cUnit->dfsOrder.elemList[idx];
+ bb = (BasicBlock*)oatGrowableListGetElement(blockList, dfsIndex);
+ if (bb->blockType == kDalvikByteCode) {
+ break;
+ }
+ }
+ if (bb == NULL) {
+ return;
+ }
+ DCHECK_EQ(bb->startOffset, 0);
+ DCHECK(bb->firstMIRInsn != 0);
+
+ /* Get the first instruction */
+ MIR* mir = bb->firstMIRInsn;
+
+ /* Free temp registers and reset redundant store tracking */
+ oatResetRegPool(cUnit);
+ oatResetDefTracking(cUnit);
+ oatClobberAllRegs(cUnit);
+
+ genSpecialCase(cUnit, bb, mir, specialCase);
+}
+
void oatMethodMIR2LIR(CompilationUnit* cUnit)
{
/* Used to hold the labels of each block */
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 74412ab..8e72227 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -26,6 +26,196 @@
namespace art {
+/* Return a RegLocation that describes an in-register argument */
+RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc, int sReg)
+{
+ loc.location = kLocPhysReg;
+ int base = SRegToVReg(cUnit, sReg) - cUnit->numRegs;
+ loc.sRegLow = sReg;
+ loc.lowReg = rARG1 + base;
+ loc.home = true;
+ if (loc.wide) {
+ loc.highReg = loc.lowReg + 1;
+ oatLockTemp(cUnit, loc.lowReg);
+ oatLockTemp(cUnit, loc.highReg);
+ } else {
+ oatLockTemp(cUnit, loc.lowReg);
+ }
+ return loc;
+}
+
+/* Find the next MIR, which may be in a following basic block */
+MIR* getNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
+{
+ BasicBlock* bb = *pBb;
+ MIR* origMir = mir;
+ while (bb != NULL) {
+ if (mir != NULL) {
+ mir = mir->next;
+ }
+ if (mir != NULL) {
+ return mir;
+ } else {
+ bb = bb->fallThrough;
+ *pBb = bb;
+ if (bb) {
+ mir = bb->firstMIRInsn;
+ if (mir != NULL) {
+ return mir;
+ }
+ }
+ }
+ }
+ return origMir;
+}
+
+/* Used for the "printMe" listing */
+void genPrintLabel(CompilationUnit *cUnit, MIR* mir)
+{
+ LIR* boundaryLIR;
+ /* Mark the beginning of a Dalvik instruction for line tracking */
+ char* instStr = cUnit->printMe ?
+ oatGetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL;
+ boundaryLIR = newLIR1(cUnit, kPseudoDalvikByteCodeBoundary,
+ (intptr_t) instStr);
+ cUnit->boundaryMap.insert(std::make_pair(mir->offset,
+ (LIR*)boundaryLIR));
+ /* Don't generate the SSA annotation unless verbose mode is on */
+ if (cUnit->printMe && mir->ssaRep) {
+ char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
+ newLIR1(cUnit, kPseudoSSARep, (int) ssaString);
+ }
+}
+
+MIR* specialIGet(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
+ OpSize size, bool longOrDouble, bool isObject)
+{
+ int fieldOffset;
+ bool isVolatile;
+ uint32_t fieldIdx = mir->dalvikInsn.vC;
+ bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+ false);
+ if (!fastPath) {
+ return NULL;
+ }
+ mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+ genPrintLabel(cUnit, mir);
+ RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
+ rlObj = argLoc(cUnit, rlObj, mir->ssaRep->uses[0]);
+ RegLocation rlDest;
+ if (longOrDouble) {
+ rlDest = oatGetReturnWide(cUnit, false);
+ } else {
+ rlDest = oatGetReturn(cUnit, false);
+ }
+ genIGet(cUnit, mir, size, rlDest, rlObj, longOrDouble, isObject);
+ return getNextMir(cUnit, bb, mir);
+}
+
+MIR* specialIPut(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
+ OpSize size, bool longOrDouble, bool isObject)
+{
+ int fieldOffset;
+ bool isVolatile;
+ uint32_t fieldIdx = mir->dalvikInsn.vC;
+ bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+ false);
+ if (!fastPath) {
+ return NULL;
+ }
+ mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+ genPrintLabel(cUnit, mir);
+ RegLocation rlSrc;
+ RegLocation rlObj;
+ int sSreg = mir->ssaRep->uses[0];
+ int oSreg;
+ if (longOrDouble) {
+ rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+ rlObj = oatGetSrc(cUnit, mir, 2);
+ oSreg = mir->ssaRep->uses[2];
+ } else {
+ rlSrc = oatGetSrc(cUnit, mir, 0);
+ rlObj = oatGetSrc(cUnit, mir, 1);
+ oSreg = mir->ssaRep->uses[1];
+ }
+ rlSrc = argLoc(cUnit, rlSrc, sSreg);
+ rlObj = argLoc(cUnit, rlObj, oSreg);
+ genIPut(cUnit, mir, size, rlSrc, rlObj, longOrDouble, isObject);
+ return getNextMir(cUnit, bb, mir);
+}
+
+/*
+ * Special-case code genration for simple non-throwing leaf methods.
+ */
+void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+ SpecialCaseHandler specialCase)
+{
+ cUnit->currentDalvikOffset = mir->offset;
+ MIR* nextMir = NULL;
+ switch(specialCase) {
+ case kNullMethod:
+ DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
+ nextMir = mir;
+ break;
+ case kConstFunction:
+ genPrintLabel(cUnit, mir);
+ loadConstant(cUnit, rRET0, mir->dalvikInsn.vB);
+ nextMir = getNextMir(cUnit, &bb, mir);
+ break;
+ case kIGet:
+ nextMir = specialIGet(cUnit, &bb, mir, kWord, false, false);
+ break;;
+ case kIGetBoolean:
+ case kIGetByte:
+ nextMir = specialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
+ break;;
+ case kIGetObject:
+ nextMir = specialIGet(cUnit, &bb, mir, kWord, false, true);
+ break;;
+ case kIGetChar:
+ nextMir = specialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
+ break;;
+ case kIGetShort:
+ nextMir = specialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
+ break;;
+ case kIGetWide:
+ nextMir = specialIGet(cUnit, &bb, mir, kLong, true, false);
+ break;;
+ case kIPut:
+ nextMir = specialIPut(cUnit, &bb, mir, kWord, false, false);
+ break;;
+ case kIPutBoolean:
+ case kIPutByte:
+ nextMir = specialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
+ break;;
+ case kIPutObject:
+ nextMir = specialIPut(cUnit, &bb, mir, kWord, false, true);
+ break;;
+ case kIPutChar:
+ nextMir = specialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
+ break;;
+ case kIPutShort:
+ nextMir = specialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
+ break;;
+ case kIPutWide:
+ nextMir = specialIPut(cUnit, &bb, mir, kLong, true, false);
+ break;;
+ default:
+ return;
+ }
+ if (nextMir != NULL) {
+ cUnit->currentDalvikOffset = nextMir->offset;
+ genPrintLabel(cUnit, nextMir);
+ newLIR1(cUnit, kThumbBx, rLR);
+ cUnit->coreSpillMask = 0;
+ cUnit->numCoreSpills = 0;
+ cUnit->fpSpillMask = 0;
+ cUnit->numFPSpills = 0;
+ cUnit->frameSize = 0;
+ cUnit->coreVmapTable.clear();
+ cUnit->fpVmapTable.clear();
+ }
+}
/*
* Generate a Thumb2 IT instruction, which can nullify up to
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
index 5b89e6a..4530517 100644
--- a/src/compiler/codegen/mips/Mips32/Gen.cc
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -24,6 +24,12 @@
namespace art {
+void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+ SpecialCaseHandler specialCase)
+{
+ // TODO
+}
+
/*
* The lack of pc-relative loads on Mips presents somewhat of a challenge
* for our PIC switch table strategy. To materialize the current location
diff --git a/src/compiler/codegen/x86/X86/Gen.cc b/src/compiler/codegen/x86/X86/Gen.cc
index 6f33b56..c6cd55c 100644
--- a/src/compiler/codegen/x86/X86/Gen.cc
+++ b/src/compiler/codegen/x86/X86/Gen.cc
@@ -24,6 +24,12 @@
namespace art {
+void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+ SpecialCaseHandler specialCase)
+{
+ // TODO
+}
+
/*
* Perform register memory operation.
*/