Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Unified Diff: sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart

Issue 312793002: dart2dart: Preserve variable names throughout the IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Properly linearize phi assignments, remove unused write count Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
index 7f303f6e943bacaa18c8b61ba1cb5697464481af..502ca6c38fda070075b51a03828171cec7c68386 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/dart_tree.dart
@@ -83,18 +83,11 @@ class Label {
* Variables are [Expression]s.
*/
class Variable extends Expression {
- // A counter used to generate names. The counter is reset to 0 for each
- // function emitted.
- static int counter = 0;
- static String _newName() => 'v${counter++}';
-
+ /// Element used for synthesizing a name for the variable.
+ /// Different variables may have the same element. May be null.
Element element;
- String cachedName;
- String get name {
- if (cachedName != null) return cachedName;
- return cachedName = ((element == null) ? _newName() : element.name);
- }
+ int readCount = 0;
Variable(this.element);
@@ -271,9 +264,10 @@ class Assign extends Statement {
Statement next;
final Variable variable;
Expression definition;
- final bool hasExactlyOneUse;
- Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse);
+ Assign(this.variable, this.definition, this.next);
+
+ bool get hasExactlyOneUse => variable.readCount == 1;
accept(Visitor visitor) => visitor.visitAssign(this);
}
@@ -301,19 +295,12 @@ class Return extends Statement {
* labeled statement's successor statement.
*/
class Break extends Statement {
- Label _target;
-
- Label get target => _target;
- void set target(Label newTarget) {
- ++newTarget.breakCount;
- --_target.breakCount;
- _target = newTarget;
- }
+ Label target;
Statement get next => null;
void set next(Statement s) => throw 'UNREACHABLE';
- Break(this._target) {
+ Break(this.target) {
++target.breakCount;
}
@@ -444,9 +431,9 @@ abstract class Visitor<S, E> {
class Builder extends ir.Visitor<Node> {
final dart2js.Compiler compiler;
- // Uses of IR primitives are replaced with Tree variables. This is the
- // mapping from primitives to variables.
- final Map<ir.Primitive, Variable> variables = <ir.Primitive, Variable>{};
+ /// Maps variable/parameter elements to the Tree variables that represent it.
+ final Map<Element, List<Variable>> element2variables =
+ <Element,List<Variable>>{};
// Continuations with more than one use are replaced with Tree labels. This
// is the mapping from continuations to labels.
@@ -457,36 +444,140 @@ class Builder extends ir.Visitor<Node> {
Builder(this.compiler);
+ /// Obtains the variable representing the given primitive. Returns null for
+ /// primitives that have no reference and do not need a variable.
+ Variable getVariable(ir.Primitive primitive) {
+ if (primitive.registerIndex == null) {
+ return null; // variable is unused
+ }
+ List<Variable> variables = element2variables[primitive.element];
+ if (variables == null) {
+ variables = <Variable>[];
+ element2variables[primitive.element] = variables;
+ }
+ while (variables.length <= primitive.registerIndex) {
+ variables.add(new Variable(primitive.element));
+ }
+ return variables[primitive.registerIndex];
+ }
+
+ /// Obtains a reference to the tree Variable corresponding to the IR primitive
+ /// referred to by [reference].
+ /// This increments the reference count for the given variable, so the
+ /// returned expression must be used in the tree.
+ Expression getVariableReference(ir.Reference reference) {
+ Variable variable = getVariable(reference.definition);
+ if (variable == null) {
+ compiler.internalError(
+ compiler.currentElement,
+ "Reference to ${reference.definition} has no register");
+ }
+ ++variable.readCount;
+ return variable;
+ }
+
FunctionDefinition build(ir.FunctionDefinition node) {
+ new ir.RegisterAllocator().visit(node);
visit(node);
return function;
}
List<Expression> translateArguments(List<ir.Reference> args) {
return new List<Expression>.generate(args.length,
- (int index) => variables[args[index].definition]);
+ (int index) => getVariableReference(args[index]));
+ }
+
+ List<Variable> translatePhiArguments(List<ir.Reference> args) {
+ return new List<Variable>.generate(args.length,
+ (int index) => getVariableReference(args[index]));
+ }
+
+ Statement buildContinuationAssignment(
+ ir.Parameter parameter,
+ Expression argument,
+ Statement buildRest()) {
+ Variable variable = getVariable(parameter);
+ Statement assignment;
+ if (variable == null) {
+ assignment = new ExpressionStatement(argument, null);
+ } else {
+ assignment = new Assign(variable, argument, null);
+ }
+ assignment.next = buildRest();
+ return assignment;
}
- Statement buildParameterAssignments(
+ /// Simultaneously assigns each argument to the corresponding parameter,
+ /// then continues at the statement created by [buildRest].
+ Statement buildPhiAssignments(
List<ir.Parameter> parameters,
- List<Expression> arguments,
+ List<Variable> arguments,
Statement buildRest()) {
assert(parameters.length == arguments.length);
- Statement first, current;
- for (int i = 0; i < parameters.length; ++i) {
- ir.Parameter parameter = parameters[i];
- Statement assignment;
- if (parameter.hasAtLeastOneUse) {
- assignment = new Assign(variables[parameter], arguments[i], null,
- parameter.hasExactlyOneUse);
- } else {
- assignment = new ExpressionStatement(arguments[i], null);
+ // We want a parallel assignment to all parameters simultaneously.
+ // Since we do not have parallel assignments in dart_tree, we must linearize
+ // the assignments without attempting to read a previously-overwritten
+ // value. For example {x,y = y,x} cannot be linearized to {x = y; y = x},
+ // for this we must introduce a temporary variable: {t = x; x = y; y = t}.
+
+ // [rightHand] is the inverse of [arguments], that is, it maps variables
+ // to the assignments on which is occurs as the right-hand side.
+ Map<Variable, List<int>> rightHand = <Variable, List<int>>{};
+ for (int i = 0; i < parameters.length; i++) {
+ Variable param = getVariable(parameters[i]);
+ Variable arg = arguments[i];
+ if (param == null || param == arg)
+ continue; // No assignment necessary.
+ List<int> list = rightHand[arg];
+ if (list == null) {
+ rightHand[arg] = list = <int>[];
}
+ list.add(i);
+ }
+ Statement first, current;
+ void addAssignment(Variable dst, Variable src) {
if (first == null) {
- current = first = assignment;
+ first = current = new Assign(dst, src, null);
} else {
- current = current.next = assignment;
+ current = current.next = new Assign(dst, src, null);
+ }
+ }
+
+ Variable temp = new Variable(null);
+ List<Variable> assignmentSrc = new List<Variable>(parameters.length);
+ List<bool> done = new List<bool>(parameters.length);
+ void visitAssignment(int i) {
+ if (done[i] == true)
+ return;
sigurdm 2014/06/12 14:12:19 Can be on one line
asgerf 2014/06/12 15:24:11 Thanks.
+ Variable param = getVariable(parameters[i]);
+ Variable arg = arguments[i];
+ if (param == null || param == arg)
+ return; // No assignment necessary.
+ if (assignmentSrc[i] != null) {
+ // Cycle found; store argument in a temporary variable.
+ // The temporary will then be used as right-hand side when the
+ // assignment gets added.
+ if (assignmentSrc[i] != temp) { // Only move to temporary once.
+ assignmentSrc[i] = temp;
+ addAssignment(temp, arg);
+ }
+ return;
+ }
+ assignmentSrc[i] = arg;
+ List<int> paramUses = rightHand[param];
+ if (paramUses != null) {
+ for (int useIndex in paramUses) {
+ visitAssignment(useIndex);
+ }
+ }
+ addAssignment(param, assignmentSrc[i]);
+ done[i] = true;
+ }
+
+ for (int i = 0; i < parameters.length; i++) {
+ if (done[i] == null) {
+ visitAssignment(i);
}
}
@@ -502,22 +593,20 @@ class Builder extends ir.Visitor<Node> {
returnContinuation = node.returnContinuation;
List<Variable> parameters = <Variable>[];
for (ir.Parameter p in node.parameters) {
- Variable parameter = new Variable(p.element);
+ Variable parameter = getVariable(p);
+ assert(parameter != null);
parameters.add(parameter);
- variables[p] = parameter;
}
function = new FunctionDefinition(parameters, visit(node.body));
return null;
}
Statement visitLetPrim(ir.LetPrim node) {
- // LetPrim is translated to LetVal.
+ // LetPrim is translated to Assign.
Expression definition = visit(node.primitive);
- if (node.primitive.hasAtLeastOneUse) {
- Variable variable = new Variable(null);
- variables[node.primitive] = variable;
- return new Assign(variable, definition, visit(node.body),
- node.primitive.hasExactlyOneUse);
+ Variable variable = getVariable(node.primitive);
+ if (variable != null) { // Variable is null if primitive is unused.
+ return new Assign(variable, definition, visit(node.body));
} else if (node.primitive is ir.Constant) {
// TODO(kmillikin): Implement more systematic treatment of pure CPS
// values (e.g., as part of a shrinking reductions pass).
@@ -533,9 +622,6 @@ class Builder extends ir.Visitor<Node> {
label = new Label();
labels[node.continuation] = label;
}
- node.continuation.parameters.forEach((p) {
- if (p.hasAtLeastOneUse) variables[p] = new Variable(null);
- });
Statement body = visit(node.body);
// The continuation's body is not always translated directly here because
// it may have been already translated:
@@ -559,13 +645,13 @@ class Builder extends ir.Visitor<Node> {
} else {
assert(cont.hasExactlyOneUse);
assert(cont.parameters.length == 1);
- return buildParameterAssignments(cont.parameters, [invoke],
+ return buildContinuationAssignment(cont.parameters[0], invoke,
sigurdm 2014/06/12 14:12:19 You can use cont.parameters.single, it also assert
asgerf 2014/06/12 15:24:15 single is only defined for Link. cont.parameters i
sigurdm 2014/06/13 07:40:07 No - single is defined on Iterable which List impl
() => visit(cont.body));
}
}
Statement visitInvokeMethod(ir.InvokeMethod node) {
- Variable receiver = variables[node.receiver.definition];
+ Expression receiver = getVariableReference(node.receiver);
List<Expression> arguments = translateArguments(node.arguments);
Expression invoke = new InvokeMethod(receiver, node.selector, arguments);
ir.Continuation cont = node.continuation.definition;
@@ -574,7 +660,7 @@ class Builder extends ir.Visitor<Node> {
} else {
assert(cont.hasExactlyOneUse);
assert(cont.parameters.length == 1);
- return buildParameterAssignments(cont.parameters, [invoke],
+ return buildContinuationAssignment(cont.parameters[0], invoke,
() => visit(cont.body));
}
}
@@ -588,7 +674,7 @@ class Builder extends ir.Visitor<Node> {
} else {
assert(cont.hasExactlyOneUse);
assert(cont.parameters.length == 1);
- return buildParameterAssignments(cont.parameters, [concat],
+ return buildContinuationAssignment(cont.parameters[0], concat,
() => visit(cont.body));
}
}
@@ -603,7 +689,7 @@ class Builder extends ir.Visitor<Node> {
} else {
assert(cont.hasExactlyOneUse);
assert(cont.parameters.length == 1);
- return buildParameterAssignments(cont.parameters, [invoke],
+ return buildContinuationAssignment(cont.parameters[0], invoke,
() => visit(cont.body));
}
}
@@ -617,10 +703,10 @@ class Builder extends ir.Visitor<Node> {
ir.Continuation cont = node.continuation.definition;
if (cont == returnContinuation) {
assert(node.arguments.length == 1);
- return new Return(variables[node.arguments[0].definition]);
+ return new Return(getVariableReference(node.arguments[0]));
} else {
- List<Expression> arguments = translateArguments(node.arguments);
- return buildParameterAssignments(cont.parameters, arguments,
+ List<Expression> arguments = translatePhiArguments(node.arguments);
+ return buildPhiAssignments(cont.parameters, arguments,
() {
// Translate invocations of recursive and non-recursive
// continuations differently.
@@ -694,7 +780,7 @@ class Builder extends ir.Visitor<Node> {
}
Expression visitIsTrue(ir.IsTrue node) {
- return variables[node.value.definition];
+ return getVariableReference(node.value);
}
}
@@ -940,7 +1026,7 @@ class StatementRewriter extends Visitor<Statement, Expression> {
Break next = node.next;
Label newTarget = redirect(next.target);
labelRedirects[node.label] = newTarget;
- newTarget.breakCount += node.label.breakCount;
+ newTarget.breakCount += node.label.breakCount - 1;
node.label.breakCount = 0;
Statement result = visitStatement(node.body);
labelRedirects.remove(node.label); // Save some space.
@@ -954,7 +1040,13 @@ class StatementRewriter extends Visitor<Statement, Expression> {
return node.body;
}
+ // Do not propagate assignments into the successor statements, since they
+ // may be overwritten by assignments in the body.
+ List<Assign> savedEnvironment = environment;
+ environment = <Assign>[];
node.next = visitStatement(node.next);
+ environment = savedEnvironment;
+
return node;
}
@@ -1067,8 +1159,7 @@ class StatementRewriter extends Visitor<Statement, Expression> {
if (next != null) {
return new Assign(s.variable,
combine(s.definition, t.definition),
- next,
- s.hasExactlyOneUse);
+ next);
}
}
if (s is ExpressionStatement && t is ExpressionStatement) {
@@ -1091,24 +1182,27 @@ class StatementRewriter extends Visitor<Statement, Expression> {
--t.target.breakCount; // Two breaks become one.
return s;
}
- if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) {
- return s;
+ if (s is Return && t is Return) {
+ Expression e = combineExpressions(s.value, t.value);
+ if (e != null) {
+ return new Return(e);
+ }
}
return null;
}
- /// True if the two expressions both syntactically and semantically
- /// equivalent.
- static bool equivalentExpressions(Expression e1, Expression e2) {
- if (e1 == e2) { // Detect same variable reference
- // TODO(asgerf): This might turn the variable into a single-use,
- // but we currently don't discover this.
- return true;
+ /// Returns an expression equivalent to both [e1] and [e2].
+ /// If non-null is returned, the caller must discard [e1] and [e2] and use
+ /// the resulting expression in the tree.
+ static Expression combineExpressions(Expression e1, Expression e2) {
+ if (e1 is Variable && e1 == e2) {
+ --e1.readCount; // Two references become one.
+ return e1;
}
- if (e1 is Constant && e2 is Constant) {
- return e1.value == e2.value;
+ if (e1 is Constant && e2 is Constant && e1.value == e2.value) {
+ return e1;
}
- return false;
+ return null;
}
/// Try to collapse nested ifs using && and || expressions.

Powered by Google App Engine
This is Rietveld 408576698