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

Unified Diff: frog/leg/ssa/optimize.dart

Issue 9873021: Move frog/leg to lib/compiler/implementation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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
« no previous file with comments | « frog/leg/ssa/nodes.dart ('k') | frog/leg/ssa/ssa.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/ssa/optimize.dart
===================================================================
--- frog/leg/ssa/optimize.dart (revision 5925)
+++ frog/leg/ssa/optimize.dart (working copy)
@@ -1,709 +0,0 @@
-// Copyright (c) 2011, 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.
-
-interface OptimizationPhase {
- String get name();
- void visitGraph(HGraph graph);
-}
-
-class SsaOptimizerTask extends CompilerTask {
- SsaOptimizerTask(Compiler compiler) : super(compiler);
- String get name() => 'SSA optimizer';
-
- void runPhases(HGraph graph, List<OptimizationPhase> phases) {
- for (OptimizationPhase phase in phases) {
- phase.visitGraph(graph);
- compiler.tracer.traceGraph(phase.name, graph);
- }
- }
-
- void optimize(WorkItem work, HGraph graph) {
- measure(() {
- List<OptimizationPhase> phases = <OptimizationPhase>[
- new SsaConstantFolder(compiler),
- new SsaRedundantPhiEliminator(),
- new SsaDeadPhiEliminator(),
- new SsaGlobalValueNumberer(compiler),
- new SsaCodeMotion(),
- new SsaDeadCodeEliminator()];
- runPhases(graph, phases);
- });
- }
-
- bool trySpeculativeOptimizations(WorkItem work, HGraph graph) {
- return measure(() {
- // Run the phases that will generate type guards. We must also run
- // [SsaCheckInserter] because the type propagator also propagates
- // types non-speculatively. For example, it propagates the type
- // array for a call to the List constructor.
- List<OptimizationPhase> phases = <OptimizationPhase>[
- new SsaTypePropagator(compiler),
- new SsaTypeGuardBuilder(compiler, work),
- new SsaCheckInserter(compiler)];
- runPhases(graph, phases);
- return !work.guards.isEmpty();
- });
- }
-
- void prepareForSpeculativeOptimizations(WorkItem work, HGraph graph) {
- measure(() {
- // In order to generate correct code for the bailout version, we did not
- // propagate types from the instruction to the type guard. We do it
- // now to be able to optimize further.
- work.guards.forEach((HTypeGuard guard) {
- guard.type = guard.guarded.type;
- guard.guarded.type = HType.UNKNOWN;
- });
- // We also need to insert range and integer checks for the type guards,
- // now that they know their type. We did not need to do that
- // before because instructions that reference a guard would
- // have not tried to use, e.g. native array access, since the
- // guard was not typed.
- runPhases(graph, <OptimizationPhase>[new SsaCheckInserter(compiler)]);
- });
- }
-}
-
-/**
- * If both inputs to known operations are available execute the operation at
- * compile-time.
- */
-class SsaConstantFolder extends HBaseVisitor implements OptimizationPhase {
- final String name = "SsaConstantFolder";
- final Compiler compiler;
- HGraph graph;
-
- SsaConstantFolder(this.compiler);
-
- void visitGraph(HGraph graph) {
- this.graph = graph;
- visitDominatorTree(graph);
- }
-
- visitBasicBlock(HBasicBlock block) {
- HInstruction instruction = block.first;
- while (instruction !== null) {
- HInstruction next = instruction.next;
- HInstruction replacement = instruction.accept(this);
- if (replacement !== instruction) {
- if (!replacement.isInBasicBlock()) {
- // The constant folding can return an instruction that is already
- // part of the graph (like an input), so we only add the replacement
- // if necessary.
- block.addAfter(instruction, replacement);
- }
- block.rewrite(instruction, replacement);
- block.remove(instruction);
- // Because the constant folder runs after type propagation, we
- // must update the type of this instruction manually. Later
- // phases can then optimize this instruction based on its
- // type.
- replacement.updateType();
- }
- instruction = next;
- }
- }
-
- HInstruction visitInstruction(HInstruction node) {
- return node;
- }
-
- HInstruction visitBoolify(HBoolify node) {
- List<HInstruction> inputs = node.inputs;
- assert(inputs.length == 1);
- HInstruction input = inputs[0];
- if (input.isBoolean()) return input;
- // All values !== true are boolified to false.
- if (input.type.isKnown()) {
- return graph.addConstantBool(false);
- }
- return node;
- }
-
- HInstruction visitNot(HNot node) {
- List<HInstruction> inputs = node.inputs;
- assert(inputs.length == 1);
- HInstruction input = inputs[0];
- if (input is HConstant) {
- HConstant constant = input;
- bool isTrue = constant.constant.isTrue();
- return graph.addConstantBool(!isTrue);
- }
- return node;
- }
-
- HInstruction visitInvokeUnary(HInvokeUnary node) {
- HInstruction operand = node.operand;
- if (operand is HConstant) {
- UnaryOperation operation = node.operation;
- HConstant receiver = operand;
- Constant folded = operation.fold(receiver.constant);
- if (folded !== null) return graph.addConstant(folded);
- }
- return node;
- }
-
- HInstruction visitInvokeInterceptor(HInvokeInterceptor node) {
- if (node.name == const SourceString('length') &&
- node.inputs[1].isConstantString()) {
- HConstant input = node.inputs[1];
- StringConstant constant = input.constant;
- DartString string = constant.value;
- return graph.addConstantInt(string.length);
- }
- return node;
- }
-
- HInstruction visitInvokeBinary(HInvokeBinary node) {
- HInstruction left = node.left;
- HInstruction right = node.right;
- if (left is HConstant && right is HConstant) {
- BinaryOperation operation = node.operation;
- HConstant op1 = left;
- HConstant op2 = right;
- Constant folded = operation.fold(op1.constant, op2.constant);
- if (folded !== null) return graph.addConstant(folded);
- }
- return node;
- }
-
- HInstruction visitEquals(HEquals node) {
- HInstruction left = node.left;
- HInstruction right = node.right;
- if (!left.isConstant() && right.isConstantNull()) {
- // TODO(floitsch): cache interceptors.
- HStatic target = new HStatic(
- compiler.builder.interceptors.getEqualsNullInterceptor());
- node.block.addBefore(node,target);
- return new HEquals(target, node.left, node.right);
- }
- // All other cases are dealt with by the [visitInvokeBinary].
- return visitInvokeBinary(node);
- }
-
- HInstruction visitTypeGuard(HTypeGuard node) {
- HInstruction value = node.guarded;
- return (value.type.combine(node.type) == value.type) ? value : node;
- }
-
- HInstruction visitIntegerCheck(HIntegerCheck node) {
- HInstruction value = node.value;
- return value.isInteger() ? value : node;
- }
-
- HInstruction visitIs(HIs node) {
- Element element = node.typeExpression;
- if (element.kind === ElementKind.TYPE_VARIABLE) {
- compiler.unimplemented("visitIs for type variables");
- }
-
- HType expressionType = node.expression.type;
- if (element === compiler.objectClass
- || element === compiler.dynamicClass) {
- return graph.addConstantBool(true);
- } else if (expressionType.isInteger()) {
- if (element === compiler.intClass || element === compiler.numClass) {
- return graph.addConstantBool(true);
- } else if (element === compiler.doubleClass) {
- // We let the JS semantics decide for that check. Currently
- // the code we emit will always return true.
- return node;
- } else {
- return graph.addConstantBool(false);
- }
- } else if (expressionType.isDouble()) {
- if (element === compiler.doubleClass || element === compiler.numClass) {
- return graph.addConstantBool(true);
- } else if (element === compiler.intClass) {
- // We let the JS semantics decide for that check. Currently
- // the code we emit will return true for a double that can be
- // represented as a 31-bit integer.
- return node;
- } else {
- return graph.addConstantBool(false);
- }
- } else if (expressionType.isNumber()) {
- if (element === compiler.numClass) {
- return graph.addConstantBool(true);
- }
- // We cannot just return false, because the expression may be of
- // type int or double.
- } else if (expressionType.isString()) {
- if (element === compiler.stringClass
- || Elements.isStringSupertype(element, compiler)) {
- return graph.addConstantBool(true);
- } else {
- return graph.addConstantBool(false);
- }
- } else if (expressionType.isArray()) {
- if (element === compiler.listClass
- || Elements.isListSupertype(element, compiler)) {
- return graph.addConstantBool(true);
- } else {
- return graph.addConstantBool(false);
- }
- }
- return node;
- }
-}
-
-class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
- final String name = "SsaCheckInserter";
- Element lengthInterceptor;
-
- SsaCheckInserter(Compiler compiler) {
- SourceString lengthString = const SourceString('length');
- lengthInterceptor =
- compiler.builder.interceptors.getStaticGetInterceptor(lengthString);
- }
-
- void visitGraph(HGraph graph) {
- visitDominatorTree(graph);
- }
-
- void visitBasicBlock(HBasicBlock block) {
- HInstruction instruction = block.first;
- while (instruction !== null) {
- HInstruction next = instruction.next;
- instruction = instruction.accept(this);
- instruction = next;
- }
- }
-
- HBoundsCheck insertBoundsCheck(HInstruction node,
- HInstruction receiver,
- HInstruction index) {
- HStatic interceptor = new HStatic(lengthInterceptor);
- node.block.addBefore(node, interceptor);
- HInvokeInterceptor length = new HInvokeInterceptor(
- Selector.INVOCATION_0,
- const SourceString("length"),
- true,
- <HInstruction>[interceptor, receiver]);
- length.type = HType.NUMBER;
- node.block.addBefore(node, length);
-
- HBoundsCheck check = new HBoundsCheck(length, index);
- node.block.addBefore(node, check);
- return check;
- }
-
- HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) {
- HIntegerCheck check = new HIntegerCheck(value);
- node.block.addBefore(node, check);
- return check;
- }
-
- void visitIndex(HIndex node) {
- if (!node.builtin) return;
- HInstruction index = insertIntegerCheck(node, node.index);
- index = insertBoundsCheck(node, node.receiver, index);
- HIndex newInstruction = new HIndex(node.target, node.receiver, index);
- node.block.addBefore(node, newInstruction);
- node.block.rewrite(node, newInstruction);
- node.block.remove(node);
- }
-
- void visitIndexAssign(HIndexAssign node) {
- if (!node.builtin) return;
- HInstruction index = insertIntegerCheck(node, node.index);
- index = insertBoundsCheck(node, node.receiver, index);
- HIndexAssign newInstruction =
- new HIndexAssign(node.target, node.receiver, index, node.value);
- node.block.addBefore(node, newInstruction);
- node.block.rewrite(node, newInstruction);
- node.block.remove(node);
- }
-}
-
-class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
- final String name = "SsaDeadCodeEliminator";
-
- static bool isDeadCode(HInstruction instruction) {
- // TODO(ngeoffray): the way we handle side effects is not right
- // (e.g. branching instructions have side effects).
- return !instruction.hasSideEffects()
- && instruction.usedBy.isEmpty()
- && instruction is !HCheck
- && instruction is !HTypeGuard;
- }
-
- void visitGraph(HGraph graph) {
- visitPostDominatorTree(graph);
- }
-
- void visitBasicBlock(HBasicBlock block) {
- HInstruction instruction = block.last;
- while (instruction !== null) {
- var previous = instruction.previous;
- if (isDeadCode(instruction)) block.remove(instruction);
- instruction = previous;
- }
- }
-}
-
-class SsaDeadPhiEliminator implements OptimizationPhase {
- final String name = "SsaDeadPhiEliminator";
-
- void visitGraph(HGraph graph) {
- final List<HPhi> worklist = <HPhi>[];
- // A set to keep track of the live phis that we found.
- final Set<HPhi> livePhis = new Set<HPhi>();
-
- // Add to the worklist all live phis: phis referenced by non-phi
- // instructions.
- for (final block in graph.blocks) {
- block.forEachPhi((HPhi phi) {
- for (final user in phi.usedBy) {
- if (user is !HPhi) {
- worklist.add(phi);
- livePhis.add(phi);
- break;
- }
- }
- });
- }
-
- // Process the worklist by propagating liveness to phi inputs.
- while (!worklist.isEmpty()) {
- HPhi phi = worklist.removeLast();
- for (final input in phi.inputs) {
- if (input is HPhi && !livePhis.contains(input)) {
- worklist.add(input);
- livePhis.add(input);
- }
- }
- }
-
- // Remove phis that are not live.
- // Traverse in reverse order to remove phis with no uses before the
- // phis that they might use.
- // NOTICE: Doesn't handle circular references, but we don't currently
- // create any.
- List<HBasicBlock> blocks = graph.blocks;
- for (int i = blocks.length - 1; i >= 0; i--) {
- HBasicBlock block = blocks[i];
- HPhi current = block.phis.first;
- HPhi next = null;
- while (current != null) {
- next = current.next;
- if (!livePhis.contains(current)
- // TODO(ahe): Not sure the following is correct.
- && current.usedBy.isEmpty()) {
- block.removePhi(current);
- }
- current = next;
- }
- }
- }
-}
-
-class SsaRedundantPhiEliminator implements OptimizationPhase {
- final String name = "SsaRedundantPhiEliminator";
-
- void visitGraph(HGraph graph) {
- final List<HPhi> worklist = <HPhi>[];
-
- // Add all phis in the worklist.
- for (final block in graph.blocks) {
- block.forEachPhi((HPhi phi) => worklist.add(phi));
- }
-
- while (!worklist.isEmpty()) {
- HPhi phi = worklist.removeLast();
-
- // If the phi has already been processed, continue.
- if (!phi.isInBasicBlock()) continue;
-
- // Find if the inputs of the phi are the same instruction.
- // The builder ensures that phi.inputs[0] cannot be the phi
- // itself.
- assert(phi.inputs[0] !== phi);
- HInstruction candidate = phi.inputs[0];
- for (int i = 1; i < phi.inputs.length; i++) {
- HInstruction input = phi.inputs[i];
- // If the input is the phi, the phi is still candidate for
- // elimination.
- if (input !== candidate && input !== phi) {
- candidate = null;
- break;
- }
- }
-
- // If the inputs are not the same, continue.
- if (candidate == null) continue;
-
- // Because we're updating the users of this phi, we may have new
- // phis candidate for elimination. Add phis that used this phi
- // to the worklist.
- for (final user in phi.usedBy) {
- if (user is HPhi) worklist.add(user);
- }
- phi.block.rewrite(phi, candidate);
- phi.block.removePhi(phi);
- }
- }
-}
-
-class SsaGlobalValueNumberer implements OptimizationPhase {
- final String name = "SsaGlobalValueNumberer";
- final Compiler compiler;
- final Set<int> visited;
-
- List<int> blockChangesFlags;
- List<int> loopChangesFlags;
-
- SsaGlobalValueNumberer(this.compiler) : visited = new Set<int>();
-
- void visitGraph(HGraph graph) {
- computeChangesFlags(graph);
- moveLoopInvariantCode(graph);
- visitBasicBlock(graph.entry, new ValueSet());
- }
-
- void moveLoopInvariantCode(HGraph graph) {
- for (int i = graph.blocks.length - 1; i >= 0; i--) {
- HBasicBlock block = graph.blocks[i];
- if (block.isLoopHeader()) {
- int changesFlags = loopChangesFlags[block.id];
- HBasicBlock last = block.loopInformation.getLastBackEdge();
- for (int j = block.id; j <= last.id; j++) {
- moveLoopInvariantCodeFromBlock(graph.blocks[j], block, changesFlags);
- }
- }
- }
- }
-
- void moveLoopInvariantCodeFromBlock(HBasicBlock block,
- HBasicBlock loopHeader,
- int changesFlags) {
- HBasicBlock preheader = loopHeader.predecessors[0];
- int dependsFlags = HInstruction.computeDependsOnFlags(changesFlags);
- HInstruction instruction = block.first;
- while (instruction != null) {
- HInstruction next = instruction.next;
- if (instruction.useGvn()
- && (instruction is !HCheck)
- && (instruction.flags & dependsFlags) == 0) {
- bool loopInvariantInputs = true;
- List<HInstruction> inputs = instruction.inputs;
- for (int i = 0, length = inputs.length; i < length; i++) {
- if (isInputDefinedAfterDominator(inputs[i], preheader)) {
- loopInvariantInputs = false;
- break;
- }
- }
-
- // If the inputs are loop invariant, we can move the
- // instruction from the current block to the pre-header block.
- if (loopInvariantInputs) {
- block.detach(instruction);
- preheader.moveAtExit(instruction);
- }
- }
- instruction = next;
- }
- }
-
- bool isInputDefinedAfterDominator(HInstruction input,
- HBasicBlock dominator) {
- return input.block.id > dominator.id;
- }
-
- void visitBasicBlock(HBasicBlock block, ValueSet values) {
- HInstruction instruction = block.first;
- while (instruction !== null) {
- HInstruction next = instruction.next;
- int flags = instruction.getChangesFlags();
- if (flags != 0) {
- assert(!instruction.useGvn());
- values.kill(flags);
- } else if (instruction.useGvn()) {
- HInstruction other = values.lookup(instruction);
- if (other !== null) {
- assert(other.gvnEquals(instruction) && instruction.gvnEquals(other));
- block.rewrite(instruction, other);
- block.remove(instruction);
- } else {
- values.add(instruction);
- }
- }
- instruction = next;
- }
-
- List<HBasicBlock> dominatedBlocks = block.dominatedBlocks;
- for (int i = 0, length = dominatedBlocks.length; i < length; i++) {
- HBasicBlock dominated = dominatedBlocks[i];
- // No need to copy the value set for the last child.
- ValueSet successorValues = (i == length - 1) ? values : values.copy();
- // If we have no values in our set, we do not have to kill
- // anything. Also, if the range of block ids from the current
- // block to the dominated block is empty, there is no blocks on
- // any path from the current block to the dominated block so we
- // don't have to do anything either.
- assert(block.id < dominated.id);
- if (!successorValues.isEmpty() && block.id + 1 < dominated.id) {
- visited.clear();
- int changesFlags = getChangesFlagsForDominatedBlock(block, dominated);
- successorValues.kill(changesFlags);
- }
- visitBasicBlock(dominated, successorValues);
- }
- }
-
- void computeChangesFlags(HGraph graph) {
- // Create the changes flags lists. Make sure to initialize the
- // loop changes flags list to zero so we can use bitwise or when
- // propagating loop changes upwards.
- final int length = graph.blocks.length;
- blockChangesFlags = new List<int>(length);
- loopChangesFlags = new List<int>(length);
- for (int i = 0; i < length; i++) loopChangesFlags[i] = 0;
-
- // Run through all the basic blocks in the graph and fill in the
- // changes flags lists.
- for (int i = length - 1; i >= 0; i--) {
- final HBasicBlock block = graph.blocks[i];
- final int id = block.id;
-
- // Compute block changes flags for the block.
- int changesFlags = 0;
- HInstruction instruction = block.first;
- while (instruction !== null) {
- instruction.prepareGvn();
- changesFlags |= instruction.getChangesFlags();
- instruction = instruction.next;
- }
- assert(blockChangesFlags[id] === null);
- blockChangesFlags[id] = changesFlags;
-
- // Loop headers are part of their loop, so update the loop
- // changes flags accordingly.
- if (block.isLoopHeader()) {
- loopChangesFlags[id] |= changesFlags;
- }
-
- // Propagate loop changes flags upwards.
- HBasicBlock parentLoopHeader = block.parentLoopHeader;
- if (parentLoopHeader !== null) {
- loopChangesFlags[parentLoopHeader.id] |= (block.isLoopHeader())
- ? loopChangesFlags[id]
- : changesFlags;
- }
- }
- }
-
- int getChangesFlagsForDominatedBlock(HBasicBlock dominator,
- HBasicBlock dominated) {
- int changesFlags = 0;
- List<HBasicBlock> predecessors = dominated.predecessors;
- for (int i = 0, length = predecessors.length; i < length; i++) {
- HBasicBlock block = predecessors[i];
- int id = block.id;
- // If the current predecessor block is on the path from the
- // dominator to the dominated, it must have an id that is in the
- // range from the dominator to the dominated.
- if (dominator.id < id && id < dominated.id && !visited.contains(id)) {
- visited.add(id);
- changesFlags |= blockChangesFlags[id];
- changesFlags |= getChangesFlagsForDominatedBlock(dominator, block);
- }
- }
- return changesFlags;
- }
-}
-
-// This phase merges equivalent instructions on different paths into
-// one instruction in a dominator block. It runs through the graph
-// post dominator order and computes a ValueSet for each block of
-// instructions that can be moved to a dominator block. These
-// instructions are the ones that:
-// 1) can be used for GVN, and
-// 2) do not use definitions of their own block.
-//
-// A basic block looks at its sucessors and finds the intersection of
-// these computed ValueSet. It moves all instructions of the
-// intersection into its own list of instructions.
-class SsaCodeMotion extends HBaseVisitor implements OptimizationPhase {
- final String name = "SsaCodeMotion";
-
- List<ValueSet> values;
-
- void visitGraph(HGraph graph) {
- values = new List<ValueSet>(graph.blocks.length);
- for (int i = 0; i < graph.blocks.length; i++) {
- values[graph.blocks[i].id] = new ValueSet();
- }
- visitPostDominatorTree(graph);
- }
-
- void visitBasicBlock(HBasicBlock block) {
- List<HBasicBlock> successors = block.successors;
-
- // Phase 1: get the ValueSet of all successors, compute the
- // intersection and move the instructions of the intersection into
- // this block.
- if (successors.length != 0) {
- ValueSet instructions = values[successors[0].id];
- for (int i = 1; i < successors.length; i++) {
- ValueSet other = values[successors[i].id];
- instructions = instructions.intersection(other);
- }
-
- if (!instructions.isEmpty()) {
- List<HInstruction> list = instructions.toList();
- for (HInstruction instruction in list) {
- // Move the instruction to the current block.
- instruction.block.detach(instruction);
- block.moveAtExit(instruction);
- // Go through all successors and rewrite their instruction
- // to the shared one.
- for (final successor in successors) {
- HInstruction toRewrite = values[successor.id].lookup(instruction);
- if (toRewrite != instruction) {
- successor.rewrite(toRewrite, instruction);
- successor.remove(toRewrite);
- }
- }
- }
- }
- }
-
- // Don't try to merge instructions to a dominator if we have
- // multiple predecessors.
- if (block.predecessors.length != 1) return;
-
- // Phase 2: Go through all instructions of this block and find
- // which instructions can be moved to a dominator block.
- ValueSet set_ = values[block.id];
- HInstruction instruction = block.first;
- int flags = 0;
- while (instruction !== null) {
- int dependsFlags = HInstruction.computeDependsOnFlags(flags);
- flags |= instruction.getChangesFlags();
-
- HInstruction current = instruction;
- instruction = instruction.next;
-
- // TODO(ngeoffray): this check is needed because we currently do
- // not have flags to express 'Gvn'able', but not movable.
- if (current is HCheck) continue;
- if (!current.useGvn()) continue;
- if ((current.flags & dependsFlags) != 0) continue;
-
- bool canBeMoved = true;
- for (final HInstruction input in current.inputs) {
- if (input.block == block) {
- canBeMoved = false;
- break;
- }
- }
- if (!canBeMoved) continue;
-
- // This is safe because we are running after GVN.
- // TODO(ngeoffray): ensure GVN has been run.
- set_.add(current);
- }
- }
-}
« no previous file with comments | « frog/leg/ssa/nodes.dart ('k') | frog/leg/ssa/ssa.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698