Strengthen type assertions post-dominated by checks during type propagation.

If a type assertion for a value is post-dominated by a class or smi check over the same value then raise the check over the assertion.

This allows to eliminate type assertions in the cases like:

AssertAssignable(x, int)
CheckSmi(x)

Currently post-domination is computed within a single block because post-dominators are not available.

R=fschneider@google.com
BUG=

Review URL: https://codereview.chromium.org//12317013

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@18777 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
vegorov@google.com 2013-02-20 19:40:26 +00:00
parent 8d24d2b98a
commit bb0c073ff9
5 changed files with 119 additions and 2 deletions

View file

@ -24,6 +24,7 @@ DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, print_ast);
DECLARE_FLAG(bool, print_scopes);
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, eliminate_type_checks);
@ -624,6 +625,12 @@ void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
if (!is_optimizing()) {
if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
AssertAssignableInstr* assert = instr->AsAssertAssignable();
AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
assert->deopt_id(),
assert->token_pos());
}
AllocateRegistersLocally(instr);
}
}

View file

@ -23,6 +23,7 @@ DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, print_ast);
DECLARE_FLAG(bool, print_scopes);
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, eliminate_type_checks);
@ -620,6 +621,12 @@ void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
if (!is_optimizing()) {
if (FLAG_enable_type_checks && instr->IsAssertAssignable()) {
AssertAssignableInstr* assert = instr->AsAssertAssignable();
AddCurrentDescriptor(PcDescriptors::kDeoptBefore,
assert->deopt_id(),
assert->token_pos());
}
AllocateRegistersLocally(instr);
}
}

View file

@ -21,10 +21,22 @@ FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph)
: FlowGraphVisitor(flow_graph->reverse_postorder()),
flow_graph_(flow_graph),
types_(flow_graph->current_ssa_temp_index()),
in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())) {
in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())),
asserts_(NULL),
collected_asserts_(NULL) {
for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
types_.Add(NULL);
}
if (FLAG_enable_type_checks) {
asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>(
flow_graph->current_ssa_temp_index());
for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
asserts_->Add(NULL);
}
collected_asserts_ = new ZoneGrowableArray<intptr_t>(10);
}
}
@ -82,6 +94,10 @@ void FlowGraphTypePropagator::Propagate() {
void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
const intptr_t rollback_point = rollback_.length();
if (FLAG_enable_type_checks) {
StrengthenAsserts(block);
}
block->Accept(this);
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
@ -203,6 +219,86 @@ Definition* FlowGraphTypePropagator::RemoveLastFromWorklist() {
}
// Unwrap all assert assignable and get a real definition of the value.
static Definition* UnwrapAsserts(Definition* defn) {
while (defn->IsAssertAssignable()) {
defn = defn->AsAssertAssignable()->value()->definition();
}
return defn;
}
// In the given block strengthen type assertions by hoisting first class or smi
// check over the same value up to the point before the assertion. This allows
// to eliminate type assertions that are postdominated by class or smi checks as
// these checks are strongly stricter than type assertions.
void FlowGraphTypePropagator::StrengthenAsserts(BlockEntryInstr* block) {
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
Instruction* instr = it.Current();
if (instr->IsCheckSmi() || instr->IsCheckClass()) {
StrengthenAssertWith(instr);
}
// If this is the first type assertion checking given value record it.
AssertAssignableInstr* assert = instr->AsAssertAssignable();
if (assert != NULL) {
Definition* defn = UnwrapAsserts(assert->value()->definition());
if ((*asserts_)[defn->ssa_temp_index()] == NULL) {
(*asserts_)[defn->ssa_temp_index()] = assert;
collected_asserts_->Add(defn->ssa_temp_index());
}
}
}
for (intptr_t i = 0; i < collected_asserts_->length(); i++) {
(*asserts_)[(*collected_asserts_)[i]] = NULL;
}
collected_asserts_->TruncateTo(0);
}
void FlowGraphTypePropagator::StrengthenAssertWith(Instruction* check) {
// Marker that is used to mark values that already had type assertion
// strengthened.
AssertAssignableInstr* kStrengthenedAssertMarker =
reinterpret_cast<AssertAssignableInstr*>(-1);
Definition* defn = UnwrapAsserts(check->InputAt(0)->definition());
AssertAssignableInstr* assert = (*asserts_)[defn->ssa_temp_index()];
if ((assert == NULL) || (assert == kStrengthenedAssertMarker)) {
return;
}
Instruction* check_clone = NULL;
if (check->IsCheckSmi()) {
check_clone =
new CheckSmiInstr(assert->value()->Copy(),
assert->env()->deopt_id());
} else {
ASSERT(check->IsCheckClass());
check_clone =
new CheckClassInstr(assert->value()->Copy(),
assert->env()->deopt_id(),
check->AsCheckClass()->unary_checks());
}
ASSERT(check_clone != NULL);
ASSERT(assert->deopt_id() == assert->env()->deopt_id());
Value* use = check_clone->InputAt(0);
use->set_instruction(check_clone);
use->set_use_index(0);
use->definition()->AddInputUse(use);
assert->env()->DeepCopyTo(check_clone);
check_clone->InsertBefore(assert);
(*asserts_)[defn->ssa_temp_index()] = kStrengthenedAssertMarker;
}
void CompileType::Union(CompileType* other) {
if (other->IsNone()) {
return;

View file

@ -38,6 +38,10 @@ class FlowGraphTypePropagator : public FlowGraphVisitor {
void AddToWorklist(Definition* defn);
Definition* RemoveLastFromWorklist();
// Type assertion strengthening.
void StrengthenAsserts(BlockEntryInstr* block);
void StrengthenAssertWith(Instruction* check);
FlowGraph* flow_graph_;
// Mapping between SSA values and their current reaching types. Valid
@ -48,6 +52,9 @@ class FlowGraphTypePropagator : public FlowGraphVisitor {
GrowableArray<Definition*> worklist_;
BitVector* in_worklist_;
ZoneGrowableArray<AssertAssignableInstr*>* asserts_;
ZoneGrowableArray<intptr_t>* collected_asserts_;
// RollbackEntry is used to track and rollback changed in the types_ array
// done during dominator tree traversal.
class RollbackEntry {

View file

@ -1111,7 +1111,7 @@ Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
return value()->definition();
}
// (3) For uninstantiated target types: If the instantiator type arguments
// For uninstantiated target types: If the instantiator type arguments
// are constant, instantiate the target type here.
if (dst_type().IsInstantiated()) return this;