Quick compiler code layout
Minor tweaks to the code layout for the Quick compiler. Repair
damage caused by bitcode conversion & additionally add a new
optimization pass to move unlikely targets to the end of the code
(flipping branch conditons if necessary). For now, this will only
be applied to target blocks which do an explicit throw and are
dominated by a block terminated by a conditional branch. Later,
we might want to generalize this capability to enable profile
guidance.
Also, tweaked the basic block combine pass to include blocks
terminated by array access operations whose null check and
range checks have been eliminated.
With this CL, the run-time performance difference between
art-buzbee and art-Quick is in the noise.
Change-Id: Iaf9921220eb6cb33c2418c76e7a6b7b31472dace
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index a5cdbde..6fe0659 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -1970,6 +1970,54 @@
return false;
}
+/* Try to make common case the fallthrough path */
+bool layoutBlocks(struct CompilationUnit* cUnit, struct BasicBlock* bb)
+{
+ // TODO: For now, just looking for direct throws. Consider generalizing for profile feedback
+ if (!bb->explicitThrow) {
+ return false;
+ }
+ BasicBlock* walker = bb;
+ while (true) {
+ // Check termination conditions
+ if ((walker->blockType == kEntryBlock) || (walker->predecessors->numUsed != 1)) {
+ break;
+ }
+ BasicBlock* prev = GET_ELEM_N(walker->predecessors, BasicBlock*, 0);
+ if (prev->conditionalBranch) {
+ if (prev->fallThrough == walker) {
+ // Already done - return
+ break;
+ }
+ DCHECK_EQ(walker, prev->taken);
+ // Got one. Flip it and exit
+ Instruction::Code opcode = prev->lastMIRInsn->dalvikInsn.opcode;
+ switch (opcode) {
+ case Instruction::IF_EQ: opcode = Instruction::IF_NE; break;
+ case Instruction::IF_NE: opcode = Instruction::IF_EQ; break;
+ case Instruction::IF_LT: opcode = Instruction::IF_GE; break;
+ case Instruction::IF_GE: opcode = Instruction::IF_LT; break;
+ case Instruction::IF_GT: opcode = Instruction::IF_LE; break;
+ case Instruction::IF_LE: opcode = Instruction::IF_GT; break;
+ case Instruction::IF_EQZ: opcode = Instruction::IF_NEZ; break;
+ case Instruction::IF_NEZ: opcode = Instruction::IF_EQZ; break;
+ case Instruction::IF_LTZ: opcode = Instruction::IF_GEZ; break;
+ case Instruction::IF_GEZ: opcode = Instruction::IF_LTZ; break;
+ case Instruction::IF_GTZ: opcode = Instruction::IF_LEZ; break;
+ case Instruction::IF_LEZ: opcode = Instruction::IF_GTZ; break;
+ default: LOG(FATAL) << "Unexpected opcode 0x" << std::hex << (int)opcode;
+ }
+ prev->lastMIRInsn->dalvikInsn.opcode = opcode;
+ BasicBlock* tBB = prev->taken;
+ prev->taken = prev->fallThrough;
+ prev->fallThrough = tBB;
+ break;
+ }
+ walker = prev;
+ }
+ return false;
+}
+
/* Combine any basic blocks terminated by instructions that we now know can't throw */
bool combineBlocks(struct CompilationUnit* cUnit, struct BasicBlock* bb)
{
@@ -1992,9 +2040,14 @@
// Grab the attributes from the paired opcode
MIR* throwInsn = mir->meta.throwInsn;
int dfAttributes = oatDataFlowAttributes[throwInsn->dalvikInsn.opcode];
- // Only null checks, and null checks eliminated?
- if (((dfAttributes & DF_HAS_NULL_CHKS) == 0) || ((dfAttributes & DF_HAS_RANGE_CHKS) != 0)
- || !(throwInsn->optimizationFlags & MIR_IGNORE_NULL_CHECK)) {
+ bool canCombine = true;
+ if (dfAttributes & DF_HAS_NULL_CHKS) {
+ canCombine &= ((throwInsn->optimizationFlags & MIR_IGNORE_NULL_CHECK) != 0);
+ }
+ if (dfAttributes & DF_HAS_RANGE_CHKS) {
+ canCombine &= ((throwInsn->optimizationFlags & MIR_IGNORE_RANGE_CHECK) != 0);
+ }
+ if (!canCombine) {
break;
}
// OK - got one. Combine
@@ -2180,6 +2233,11 @@
oatDataFlowAnalysisDispatcher(cUnit, combineBlocks, kPreOrderDFSTraversal, false);
}
+void oatMethodCodeLayout(CompilationUnit* cUnit)
+{
+ oatDataFlowAnalysisDispatcher(cUnit, layoutBlocks, kAllNodes, false);
+}
+
void oatDumpCheckStats(CompilationUnit *cUnit)
{
Checkstats* stats = (Checkstats*)oatNew(cUnit, sizeof(Checkstats), true, kAllocDFInfo);