blob: cff47d64fa4b757bb1014327bec6827408541cc6 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.cps_ir.redundant_refinement;
import 'cps_ir_nodes.dart';
import 'optimizers.dart' show Pass;
import 'type_mask_system.dart';
/// Removes [Refinement] nodes where the input value is already known to
/// satisfy the refinement type.
///
/// Note: This pass improves loop-invariant code motion in the GVN pass because
/// GVN will currently not hoist a primitive across a refinement guard.
/// But some opportunities for hoisting are still missed. A field access can
/// safely be hoisted across a non-redundant refinement as long as the less
/// refined value is still known to have the field. For example:
///
/// class A { var field; }
/// class B extends A {}
///
/// var x = getA(); // Return type is subclass of A.
/// while (x is B) { // Refinement to B is not redundant.
/// x.field.baz++; // x.field is safe for hoisting,
/// } // but blocked by the refinement node.
///
/// Ideally, this pass should go away and GVN should handle refinements
/// directly.
class RedundantRefinementEliminator extends TrampolineRecursiveVisitor
implements Pass {
String get passName => 'Redundant refinement elimination';
TypeMaskSystem typeSystem;
RedundantRefinementEliminator(this.typeSystem);
void rewrite(FunctionDefinition node) {
visit(node);
}
Expression traverseLetPrim(LetPrim node) {
Expression next = node.body;
if (node.primitive is Refinement) {
Refinement refinement = node.primitive;
Primitive value = refinement.value.definition;
if (typeSystem.isMorePreciseOrEqual(value.type, refinement.refineType)) {
refinement..replaceUsesWith(value)..destroy();
node.remove();
return next;
}
}
return next;
}
}