Compiler constant handling rework
In preparation for de-optimization, reworked the constant
handling mechanism. Also took advantage of knowledge of
constant operands (particularly for long operations).
Significant performance improvements for Mandelbrot
(~60 seconds to ~34 seconds). Minor improvements in other
benchmarks.
The new constant handling breaks two of the existing
optimization passes: "Skip Large Method" and "Load/Store
Elimization."
I don't intend to update the large method optimization
because it will be superceeded by the upcoming interpreter/
fingerprinting mechanism. Leaving the code in place for
now in order to compare compile-time improvements with
fingerprinting/interpret. All related code will be deleted
when that is complete.
The load/store elimination pass needs some rework to handle
uses of multiple-register loads and stores. It will be
updated & restored in a future CL.
Change-Id: Ia979abaf51b8ae81bbb0428031cbcea854625fac
diff --git a/src/compiler/dataflow.cc b/src/compiler/dataflow.cc
index 16065ab..1e20cbd 100644
--- a/src/compiler/dataflow.cc
+++ b/src/compiler/dataflow.cc
@@ -867,16 +867,15 @@
// Pre-SSA - just use the standard name
return GetSSAName(cu, ssa_reg);
}
- if (cu->reg_location[ssa_reg].is_const) {
+ if (IsConst(cu, cu->reg_location[ssa_reg])) {
if (!singles_only && cu->reg_location[ssa_reg].wide) {
- int64_t immval = cu->constant_values[ssa_reg + 1];
- immval = (immval << 32) | cu->constant_values[ssa_reg];
return StringPrintf("v%d_%d#0x%llx", SRegToVReg(cu, ssa_reg),
- SRegToSubscript(cu, ssa_reg), immval);
+ SRegToSubscript(cu, ssa_reg),
+ ConstantValueWide(cu, cu->reg_location[ssa_reg]));
} else {
- int32_t immval = cu->constant_values[ssa_reg];
return StringPrintf("v%d_%d#0x%x", SRegToVReg(cu, ssa_reg),
- SRegToSubscript(cu, ssa_reg), immval);
+ SRegToSubscript(cu, ssa_reg),
+ ConstantValue(cu, cu->reg_location[ssa_reg]));
}
} else {
return StringPrintf("v%d_%d", SRegToVReg(cu, ssa_reg), SRegToSubscript(cu, ssa_reg));
@@ -1300,12 +1299,19 @@
}
/* Setup a constant value for opcodes thare have the DF_SETS_CONST attribute */
-static void SetConstant(CompilationUnit* cu, int ssa_reg, int value)
+static void SetConstant(CompilationUnit* cu, int32_t ssa_reg, int value)
{
SetBit(cu, cu->is_constant_v, ssa_reg);
cu->constant_values[ssa_reg] = value;
}
+static void SetConstantWide(CompilationUnit* cu, int ssa_reg, int64_t value)
+{
+ SetBit(cu, cu->is_constant_v, ssa_reg);
+ cu->constant_values[ssa_reg] = Low32Bits(value);
+ cu->constant_values[ssa_reg + 1] = High32Bits(value);
+}
+
bool DoConstantPropogation(CompilationUnit* cu, BasicBlock* bb)
{
MIR* mir;
@@ -1321,27 +1327,25 @@
/* Handle instructions that set up constants directly */
if (df_attributes & DF_SETS_CONST) {
if (df_attributes & DF_DA) {
+ int32_t vB = static_cast<int32_t>(d_insn->vB);
switch (d_insn->opcode) {
case Instruction::CONST_4:
case Instruction::CONST_16:
case Instruction::CONST:
- SetConstant(cu, mir->ssa_rep->defs[0], d_insn->vB);
+ SetConstant(cu, mir->ssa_rep->defs[0], vB);
break;
case Instruction::CONST_HIGH16:
- SetConstant(cu, mir->ssa_rep->defs[0], d_insn->vB << 16);
+ SetConstant(cu, mir->ssa_rep->defs[0], vB << 16);
break;
case Instruction::CONST_WIDE_16:
case Instruction::CONST_WIDE_32:
- SetConstant(cu, mir->ssa_rep->defs[0], d_insn->vB);
- SetConstant(cu, mir->ssa_rep->defs[1], 0);
+ SetConstantWide(cu, mir->ssa_rep->defs[0], static_cast<int64_t>(vB));
break;
case Instruction::CONST_WIDE:
- SetConstant(cu, mir->ssa_rep->defs[0], static_cast<int>(d_insn->vB_wide));
- SetConstant(cu, mir->ssa_rep->defs[1], static_cast<int>(d_insn->vB_wide >> 32));
+ SetConstantWide(cu, mir->ssa_rep->defs[0],d_insn->vB_wide);
break;
case Instruction::CONST_WIDE_HIGH16:
- SetConstant(cu, mir->ssa_rep->defs[0], 0);
- SetConstant(cu, mir->ssa_rep->defs[1], d_insn->vB << 16);
+ SetConstantWide(cu, mir->ssa_rep->defs[0], static_cast<int64_t>(vB) << 48);
break;
default:
break;
@@ -1363,6 +1367,18 @@
cu->constant_values[mir->ssa_rep->uses[1]]);
}
}
+ } else if (df_attributes & DF_NULL_TRANSFER_N) {
+ /*
+ * Mark const sregs that appear in merges. Need to flush those to home location.
+ * TUNING: instead of flushing on def, we could insert a flush on the appropriate
+ * edge[s].
+ */
+ DCHECK_EQ(static_cast<int32_t>(d_insn->opcode), kMirOpPhi);
+ for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
+ if (IsConst(cu, mir->ssa_rep->uses[i])) {
+ SetBit(cu, cu->must_flush_constant_v, mir->ssa_rep->uses[i]);
+ }
+ }
}
}
/* TODO: implement code to handle arithmetic operations */
@@ -1708,6 +1724,28 @@
}
}
break;
+ case Instruction::GOTO:
+ case Instruction::GOTO_16:
+ case Instruction::GOTO_32:
+ case Instruction::IF_EQ:
+ case Instruction::IF_NE:
+ case Instruction::IF_LT:
+ case Instruction::IF_GE:
+ case Instruction::IF_GT:
+ case Instruction::IF_LE:
+ case Instruction::IF_EQZ:
+ case Instruction::IF_NEZ:
+ case Instruction::IF_LTZ:
+ case Instruction::IF_GEZ:
+ case Instruction::IF_GTZ:
+ case Instruction::IF_LEZ:
+ if (bb->taken->dominates_return) {
+ mir->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK;
+ if (cu->verbose) {
+ LOG(INFO) << "Suppressed suspend check at 0x" << std::hex << mir->offset;
+ }
+ }
+ break;
default:
break;
}
@@ -2056,15 +2094,26 @@
if (cu->verbose) {
LOG(INFO) << "Extended bb head " << bb->id;
}
+ BasicBlock* start_bb = bb;
cu->extended_basic_blocks.push_back(bb);
+ bool has_return = false;
// Visit blocks strictly dominated by this head.
while (bb != NULL) {
bb->visited = true;
+ has_return |= bb->has_return;
bb = NextDominatedBlock(cu, bb);
if (cu->verbose && (bb != NULL)) {
LOG(INFO) << "...added bb " << bb->id;
}
}
+ if (has_return) {
+ // This extended basic block contains a return, so mark all members.
+ bb = start_bb;
+ while (bb != NULL) {
+ bb->dominates_return = true;
+ bb = NextDominatedBlock(cu, bb);
+ }
+ }
return false; // Not iterative - return value will be ignored
}