1 /*
   2  * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.phases.common;
  26 
  27 import jdk.internal.vm.compiler.collections.EconomicMap;
  28 import jdk.internal.vm.compiler.collections.MapCursor;
  29 import org.graalvm.compiler.core.common.GraalOptions;
  30 import org.graalvm.compiler.core.common.cfg.BlockMap;
  31 import org.graalvm.compiler.core.common.type.FloatStamp;
  32 import org.graalvm.compiler.core.common.type.Stamp;
  33 import org.graalvm.compiler.core.common.type.StampFactory;
  34 import org.graalvm.compiler.debug.CounterKey;
  35 import org.graalvm.compiler.debug.DebugContext;
  36 import org.graalvm.compiler.graph.Node;
  37 import org.graalvm.compiler.graph.NodeMap;
  38 import org.graalvm.compiler.graph.NodeStack;
  39 import org.graalvm.compiler.graph.Position;
  40 import org.graalvm.compiler.nodeinfo.InputType;
  41 import org.graalvm.compiler.nodes.AbstractBeginNode;
  42 import org.graalvm.compiler.nodes.AbstractMergeNode;
  43 import org.graalvm.compiler.nodes.BinaryOpLogicNode;
  44 import org.graalvm.compiler.nodes.ConstantNode;
  45 import org.graalvm.compiler.nodes.EndNode;
  46 import org.graalvm.compiler.nodes.IfNode;
  47 import org.graalvm.compiler.nodes.LogicNode;
  48 import org.graalvm.compiler.nodes.MergeNode;
  49 import org.graalvm.compiler.nodes.NodeView;
  50 import org.graalvm.compiler.nodes.PhiNode;
  51 import org.graalvm.compiler.nodes.PiNode;
  52 import org.graalvm.compiler.nodes.StructuredGraph;
  53 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
  54 import org.graalvm.compiler.nodes.UnaryOpLogicNode;
  55 import org.graalvm.compiler.nodes.ValueNode;
  56 import org.graalvm.compiler.nodes.ValuePhiNode;
  57 import org.graalvm.compiler.nodes.calc.BinaryNode;
  58 import org.graalvm.compiler.nodes.calc.ConditionalNode;
  59 import org.graalvm.compiler.nodes.calc.UnaryNode;
  60 import org.graalvm.compiler.nodes.cfg.Block;
  61 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
  62 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph.RecursiveVisitor;
  63 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
  64 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
  65 import org.graalvm.compiler.nodes.memory.FloatingAccessNode;
  66 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
  67 import org.graalvm.compiler.nodes.memory.MemoryAccess;
  68 import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
  69 import org.graalvm.compiler.nodes.util.GraphUtil;
  70 import org.graalvm.compiler.phases.BasePhase;
  71 import org.graalvm.compiler.phases.Phase;
  72 import org.graalvm.compiler.phases.graph.ScheduledNodeIterator;
  73 import org.graalvm.compiler.phases.schedule.SchedulePhase;
  74 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
  75 import org.graalvm.compiler.phases.tiers.LowTierContext;
  76 import org.graalvm.compiler.phases.tiers.PhaseContext;
  77 
  78 import jdk.vm.ci.meta.Constant;
  79 import jdk.vm.ci.meta.MetaAccessProvider;
  80 import jdk.vm.ci.meta.TriState;
  81 
  82 /**
  83  * This phase lowers {@link FloatingReadNode FloatingReadNodes} into corresponding fixed reads.
  84  */
  85 public class FixReadsPhase extends BasePhase<LowTierContext> {
  86 
  87     private static final CounterKey counterStampsRegistered = DebugContext.counter("FixReads_StampsRegistered");
  88     private static final CounterKey counterIfsKilled = DebugContext.counter("FixReads_KilledIfs");
  89     private static final CounterKey counterConditionalsKilled = DebugContext.counter("FixReads_KilledConditionals");
  90     private static final CounterKey counterCanonicalizedSwitches = DebugContext.counter("FixReads_CanonicalizedSwitches");
  91     private static final CounterKey counterConstantReplacements = DebugContext.counter("FixReads_ConstantReplacement");
  92     private static final CounterKey counterConstantInputReplacements = DebugContext.counter("FixReads_ConstantInputReplacement");
  93     private static final CounterKey counterBetterMergedStamps = DebugContext.counter("FixReads_BetterMergedStamp");
  94 
  95     protected boolean replaceInputsWithConstants;
  96     protected Phase schedulePhase;
  97 
  98     @Override
  99     public float codeSizeIncrease() {
 100         return 2.0f;
 101     }
 102 
 103     private static class FixReadsClosure extends ScheduledNodeIterator {
 104 
 105         @Override
 106         protected void processNode(Node node) {
 107             if (node instanceof AbstractMergeNode) {
 108                 AbstractMergeNode mergeNode = (AbstractMergeNode) node;
 109                 for (MemoryPhiNode memoryPhi : mergeNode.memoryPhis().snapshot()) {
 110                     // Memory phi nodes are no longer necessary at this point.
 111                     memoryPhi.replaceAtUsages(null);
 112                     memoryPhi.safeDelete();
 113                 }
 114             } else if (node instanceof FloatingAccessNode) {
 115                 FloatingAccessNode floatingAccessNode = (FloatingAccessNode) node;
 116                 floatingAccessNode.setLastLocationAccess(null);
 117                 FixedAccessNode fixedAccess = floatingAccessNode.asFixedNode();
 118                 replaceCurrent(fixedAccess);
 119             } else if (node instanceof PiNode) {
 120                 PiNode piNode = (PiNode) node;
 121                 if (piNode.stamp(NodeView.DEFAULT).isCompatible(piNode.getOriginalNode().stamp(NodeView.DEFAULT))) {
 122                     // Pi nodes are no longer necessary at this point.
 123                     piNode.replaceAndDelete(piNode.getOriginalNode());
 124                 }
 125             } else if (node instanceof MemoryAccess) {
 126                 MemoryAccess memoryAccess = (MemoryAccess) node;
 127                 memoryAccess.setLastLocationAccess(null);
 128             }
 129         }
 130 
 131     }
 132 
 133     protected static class RawConditionalEliminationVisitor implements RecursiveVisitor<Integer> {
 134 
 135         protected final NodeMap<StampElement> stampMap;
 136         protected final NodeStack undoOperations;
 137         private final ScheduleResult schedule;
 138         private final StructuredGraph graph;
 139         private final MetaAccessProvider metaAccess;
 140         private final boolean replaceConstantInputs;
 141         private final BlockMap<Integer> blockActionStart;
 142         private final EconomicMap<MergeNode, EconomicMap<ValueNode, Stamp>> endMaps;
 143         private final DebugContext debug;
 144 
 145         protected RawConditionalEliminationVisitor(StructuredGraph graph, ScheduleResult schedule, MetaAccessProvider metaAccess, boolean replaceInputsWithConstants) {
 146             this.graph = graph;
 147             this.debug = graph.getDebug();
 148             this.schedule = schedule;
 149             this.metaAccess = metaAccess;
 150             blockActionStart = new BlockMap<>(schedule.getCFG());
 151             endMaps = EconomicMap.create();
 152             stampMap = graph.createNodeMap();
 153             undoOperations = new NodeStack();
 154             replaceConstantInputs = replaceInputsWithConstants && GraalOptions.ReplaceInputsWithConstantsBasedOnStamps.getValue(graph.getOptions());
 155         }
 156 
 157         protected void replaceInput(Position p, Node oldInput, Node newConstantInput) {
 158             p.set(oldInput, newConstantInput);
 159         }
 160 
 161         protected int replaceConstantInputs(Node node) {
 162             int replacements = 0;
 163             // Check if we can replace any of the inputs with a constant.
 164             for (Position p : node.inputPositions()) {
 165                 Node input = p.get(node);
 166                 if (p.getInputType() == InputType.Value) {
 167                     if (input instanceof ValueNode) {
 168                         ValueNode valueNode = (ValueNode) input;
 169                         if (valueNode instanceof ConstantNode) {
 170                             // Input already is a constant.
 171                         } else {
 172                             Stamp bestStamp = getBestStamp(valueNode);
 173                             Constant constant = bestStamp.asConstant();
 174                             if (constant != null) {
 175                                 if (bestStamp instanceof FloatStamp) {
 176                                     FloatStamp floatStamp = (FloatStamp) bestStamp;
 177                                     if (floatStamp.contains(0.0d)) {
 178                                         // Could also be -0.0d.
 179                                         continue;
 180                                     }
 181                                 }
 182                                 counterConstantInputReplacements.increment(node.getDebug());
 183                                 ConstantNode stampConstant = ConstantNode.forConstant(bestStamp, constant, metaAccess, graph);
 184                                 assert stampConstant.stamp(NodeView.DEFAULT).isCompatible(valueNode.stamp(NodeView.DEFAULT));
 185                                 replaceInput(p, node, stampConstant);
 186                                 replacements++;
 187                             }
 188                         }
 189                     }
 190                 }
 191             }
 192             return replacements;
 193         }
 194 
 195         protected void processNode(Node node) {
 196             assert node.isAlive();
 197 
 198             if (replaceConstantInputs) {
 199                 replaceConstantInputs(node);
 200             }
 201 
 202             if (node instanceof MergeNode) {
 203                 registerCombinedStamps((MergeNode) node);
 204             }
 205 
 206             if (node instanceof AbstractBeginNode) {
 207                 processAbstractBegin((AbstractBeginNode) node);
 208             } else if (node instanceof IfNode) {
 209                 processIf((IfNode) node);
 210             } else if (node instanceof IntegerSwitchNode) {
 211                 processIntegerSwitch((IntegerSwitchNode) node);
 212             } else if (node instanceof BinaryNode) {
 213                 processBinary((BinaryNode) node);
 214             } else if (node instanceof ConditionalNode) {
 215                 processConditional((ConditionalNode) node);
 216             } else if (node instanceof UnaryNode) {
 217                 processUnary((UnaryNode) node);
 218             } else if (node instanceof EndNode) {
 219                 processEnd((EndNode) node);
 220             }
 221         }
 222 
 223         protected void registerCombinedStamps(MergeNode node) {
 224             EconomicMap<ValueNode, Stamp> endMap = endMaps.get(node);
 225             MapCursor<ValueNode, Stamp> entries = endMap.getEntries();
 226             while (entries.advance()) {
 227                 ValueNode value = entries.getKey();
 228                 if (value.isDeleted()) {
 229                     // nodes from this map can be deleted when a loop dies
 230                     continue;
 231                 }
 232                 if (registerNewValueStamp(value, entries.getValue())) {
 233                     counterBetterMergedStamps.increment(debug);
 234                 }
 235             }
 236         }
 237 
 238         protected void processEnd(EndNode node) {
 239             AbstractMergeNode abstractMerge = node.merge();
 240             if (abstractMerge instanceof MergeNode) {
 241                 MergeNode merge = (MergeNode) abstractMerge;
 242 
 243                 NodeMap<Block> blockToNodeMap = this.schedule.getNodeToBlockMap();
 244                 Block mergeBlock = blockToNodeMap.get(merge);
 245                 Block mergeBlockDominator = mergeBlock.getDominator();
 246                 Block currentBlock = blockToNodeMap.get(node);
 247 
 248                 EconomicMap<ValueNode, Stamp> currentEndMap = endMaps.get(merge);
 249 
 250                 if (currentEndMap == null || !currentEndMap.isEmpty()) {
 251 
 252                     EconomicMap<ValueNode, Stamp> endMap = EconomicMap.create();
 253 
 254                     // Process phis
 255                     for (ValuePhiNode phi : merge.valuePhis()) {
 256                         if (currentEndMap == null || currentEndMap.containsKey(phi)) {
 257                             ValueNode valueAt = phi.valueAt(node);
 258                             Stamp bestStamp = getBestStamp(valueAt);
 259 
 260                             if (currentEndMap != null) {
 261                                 bestStamp = bestStamp.meet(currentEndMap.get(phi));
 262                             }
 263 
 264                             if (!bestStamp.equals(phi.stamp(NodeView.DEFAULT))) {
 265                                 endMap.put(phi, bestStamp);
 266                             }
 267                         }
 268                     }
 269 
 270                     int lastMark = undoOperations.size();
 271                     while (currentBlock != mergeBlockDominator) {
 272                         int mark = blockActionStart.get(currentBlock);
 273                         for (int i = lastMark - 1; i >= mark; --i) {
 274                             ValueNode nodeWithNewStamp = (ValueNode) undoOperations.get(i);
 275 
 276                             if (nodeWithNewStamp.isDeleted() || nodeWithNewStamp instanceof LogicNode || nodeWithNewStamp instanceof ConstantNode || blockToNodeMap.isNew(nodeWithNewStamp)) {
 277                                 continue;
 278                             }
 279 
 280                             Block block = getBlock(nodeWithNewStamp, blockToNodeMap);
 281                             if (block == null || block.getId() <= mergeBlockDominator.getId()) {
 282                                 // Node with new stamp in path to the merge block dominator and that
 283                                 // at the same time was defined at least in the merge block
 284                                 // dominator (i.e., therefore can be used after the merge.)
 285 
 286                                 Stamp bestStamp = getBestStamp(nodeWithNewStamp);
 287                                 assert bestStamp != null;
 288 
 289                                 if (currentEndMap != null) {
 290                                     Stamp otherEndsStamp = currentEndMap.get(nodeWithNewStamp);
 291                                     if (otherEndsStamp == null) {
 292                                         // No stamp registered in one of the previously processed
 293                                         // ends => skip.
 294                                         continue;
 295                                     }
 296                                     bestStamp = bestStamp.meet(otherEndsStamp);
 297                                 }
 298 
 299                                 if (nodeWithNewStamp.stamp(NodeView.DEFAULT).tryImproveWith(bestStamp) == null) {
 300                                     // No point in registering the stamp.
 301                                 } else {
 302                                     endMap.put(nodeWithNewStamp, bestStamp);
 303                                 }
 304                             }
 305                         }
 306                         currentBlock = currentBlock.getDominator();
 307                     }
 308 
 309                     endMaps.put(merge, endMap);
 310                 }
 311             }
 312         }
 313 
 314         private static Block getBlock(ValueNode node, NodeMap<Block> blockToNodeMap) {
 315             if (node instanceof PhiNode) {
 316                 PhiNode phiNode = (PhiNode) node;
 317                 return blockToNodeMap.get(phiNode.merge());
 318             }
 319             return blockToNodeMap.get(node);
 320         }
 321 
 322         protected void processUnary(UnaryNode node) {
 323             Stamp newStamp = node.foldStamp(getBestStamp(node.getValue()));
 324             if (!checkReplaceWithConstant(newStamp, node)) {
 325                 registerNewValueStamp(node, newStamp);
 326             }
 327         }
 328 
 329         protected boolean checkReplaceWithConstant(Stamp newStamp, ValueNode node) {
 330             Constant constant = newStamp.asConstant();
 331             if (constant != null && !(node instanceof ConstantNode)) {
 332                 ConstantNode stampConstant = ConstantNode.forConstant(newStamp, constant, metaAccess, graph);
 333                 debug.log("RawConditionElimination: constant stamp replaces %1s with %1s", node, stampConstant);
 334                 counterConstantReplacements.increment(debug);
 335                 node.replaceAtUsages(InputType.Value, stampConstant);
 336                 GraphUtil.tryKillUnused(node);
 337                 return true;
 338             }
 339             return false;
 340         }
 341 
 342         protected void processBinary(BinaryNode node) {
 343             Stamp xStamp = getBestStamp(node.getX());
 344             Stamp yStamp = getBestStamp(node.getY());
 345             Stamp newStamp = node.foldStamp(xStamp, yStamp);
 346             if (!checkReplaceWithConstant(newStamp, node)) {
 347                 registerNewValueStamp(node, newStamp);
 348             }
 349         }
 350 
 351         protected void processIntegerSwitch(IntegerSwitchNode node) {
 352             Stamp bestStamp = getBestStamp(node.value());
 353             if (node.tryRemoveUnreachableKeys(null, bestStamp)) {
 354                 debug.log("\t Canonicalized integer switch %s for value %s and stamp %s", node, node.value(), bestStamp);
 355                 counterCanonicalizedSwitches.increment(debug);
 356             }
 357         }
 358 
 359         protected void processIf(IfNode node) {
 360             TriState result = tryProveCondition(node.condition());
 361             if (result != TriState.UNKNOWN) {
 362                 boolean isTrue = (result == TriState.TRUE);
 363                 AbstractBeginNode survivingSuccessor = node.getSuccessor(isTrue);
 364                 survivingSuccessor.replaceAtUsages(null);
 365                 survivingSuccessor.replaceAtPredecessor(null);
 366                 node.replaceAtPredecessor(survivingSuccessor);
 367                 GraphUtil.killCFG(node);
 368 
 369                 counterIfsKilled.increment(debug);
 370             }
 371         }
 372 
 373         protected void processConditional(ConditionalNode node) {
 374             TriState result = tryProveCondition(node.condition());
 375             if (result != TriState.UNKNOWN) {
 376                 boolean isTrue = (result == TriState.TRUE);
 377                 counterConditionalsKilled.increment(debug);
 378                 node.replaceAndDelete(isTrue ? node.trueValue() : node.falseValue());
 379             } else {
 380                 Stamp trueStamp = getBestStamp(node.trueValue());
 381                 Stamp falseStamp = getBestStamp(node.falseValue());
 382                 registerNewStamp(node, trueStamp.meet(falseStamp));
 383             }
 384         }
 385 
 386         protected TriState tryProveCondition(LogicNode condition) {
 387             Stamp conditionStamp = this.getBestStamp(condition);
 388             if (conditionStamp == StampFactory.tautology()) {
 389                 return TriState.TRUE;
 390             } else if (conditionStamp == StampFactory.contradiction()) {
 391                 return TriState.FALSE;
 392             }
 393 
 394             if (condition instanceof UnaryOpLogicNode) {
 395                 UnaryOpLogicNode unaryOpLogicNode = (UnaryOpLogicNode) condition;
 396                 return unaryOpLogicNode.tryFold(this.getBestStamp(unaryOpLogicNode.getValue()));
 397             } else if (condition instanceof BinaryOpLogicNode) {
 398                 BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) condition;
 399                 return binaryOpLogicNode.tryFold(this.getBestStamp(binaryOpLogicNode.getX()), this.getBestStamp(binaryOpLogicNode.getY()));
 400             }
 401 
 402             return TriState.UNKNOWN;
 403         }
 404 
 405         protected void processAbstractBegin(AbstractBeginNode beginNode) {
 406             Node predecessor = beginNode.predecessor();
 407             if (predecessor instanceof IfNode) {
 408                 IfNode ifNode = (IfNode) predecessor;
 409                 boolean negated = (ifNode.falseSuccessor() == beginNode);
 410                 LogicNode condition = ifNode.condition();
 411                 registerNewCondition(condition, negated);
 412             } else if (predecessor instanceof IntegerSwitchNode) {
 413                 IntegerSwitchNode integerSwitchNode = (IntegerSwitchNode) predecessor;
 414                 registerIntegerSwitch(beginNode, integerSwitchNode);
 415             }
 416         }
 417 
 418         private void registerIntegerSwitch(AbstractBeginNode beginNode, IntegerSwitchNode integerSwitchNode) {
 419             registerNewValueStamp(integerSwitchNode.value(), integerSwitchNode.getValueStampForSuccessor(beginNode));
 420         }
 421 
 422         protected void registerNewCondition(LogicNode condition, boolean negated) {
 423             if (condition instanceof UnaryOpLogicNode) {
 424                 UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) condition;
 425                 ValueNode value = unaryLogicNode.getValue();
 426                 Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(negated);
 427                 registerNewValueStamp(value, newStamp);
 428             } else if (condition instanceof BinaryOpLogicNode) {
 429                 BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) condition;
 430                 ValueNode x = binaryOpLogicNode.getX();
 431                 ValueNode y = binaryOpLogicNode.getY();
 432                 Stamp xStamp = getBestStamp(x);
 433                 Stamp yStamp = getBestStamp(y);
 434                 registerNewValueStamp(x, binaryOpLogicNode.getSucceedingStampForX(negated, xStamp, yStamp));
 435                 registerNewValueStamp(y, binaryOpLogicNode.getSucceedingStampForY(negated, xStamp, yStamp));
 436             }
 437             registerCondition(condition, negated);
 438         }
 439 
 440         protected void registerCondition(LogicNode condition, boolean negated) {
 441             registerNewStamp(condition, negated ? StampFactory.contradiction() : StampFactory.tautology());
 442         }
 443 
 444         protected boolean registerNewValueStamp(ValueNode value, Stamp newStamp) {
 445             if (newStamp != null && !value.isConstant()) {
 446                 Stamp currentStamp = getBestStamp(value);
 447                 Stamp betterStamp = currentStamp.tryImproveWith(newStamp);
 448                 if (betterStamp != null) {
 449                     registerNewStamp(value, betterStamp);
 450                     return true;
 451                 }
 452             }
 453             return false;
 454         }
 455 
 456         protected void registerNewStamp(ValueNode value, Stamp newStamp) {
 457             counterStampsRegistered.increment(debug);
 458             debug.log("\t Saving stamp for node %s stamp %s", value, newStamp);
 459             ValueNode originalNode = value;
 460             stampMap.setAndGrow(originalNode, new StampElement(newStamp, stampMap.getAndGrow(originalNode)));
 461             undoOperations.push(originalNode);
 462         }
 463 
 464         protected Stamp getBestStamp(ValueNode value) {
 465             ValueNode originalNode = value;
 466             StampElement currentStamp = stampMap.getAndGrow(originalNode);
 467             if (currentStamp == null) {
 468                 return value.stamp(NodeView.DEFAULT);
 469             }
 470             return currentStamp.getStamp();
 471         }
 472 
 473         @Override
 474         public Integer enter(Block b) {
 475             int mark = undoOperations.size();
 476             blockActionStart.put(b, mark);
 477             for (Node n : schedule.getBlockToNodesMap().get(b)) {
 478                 if (n.isAlive()) {
 479                     processNode(n);
 480                 }
 481             }
 482             return mark;
 483         }
 484 
 485         @Override
 486         public void exit(Block b, Integer state) {
 487             int mark = state;
 488             while (undoOperations.size() > mark) {
 489                 Node node = undoOperations.pop();
 490                 if (node.isAlive()) {
 491                     stampMap.set(node, stampMap.get(node).getParent());
 492                 }
 493             }
 494         }
 495 
 496     }
 497 
 498     public FixReadsPhase(boolean replaceInputsWithConstants, Phase schedulePhase) {
 499         this.replaceInputsWithConstants = replaceInputsWithConstants;
 500         this.schedulePhase = schedulePhase;
 501     }
 502 
 503     @Override
 504     protected void run(StructuredGraph graph, LowTierContext context) {
 505         schedulePhase.apply(graph);
 506         ScheduleResult schedule = graph.getLastSchedule();
 507         FixReadsClosure fixReadsClosure = new FixReadsClosure();
 508         for (Block block : schedule.getCFG().getBlocks()) {
 509             fixReadsClosure.processNodes(block, schedule);
 510         }
 511         if (GraalOptions.RawConditionalElimination.getValue(graph.getOptions())) {
 512             schedule.getCFG().visitDominatorTree(createVisitor(graph, schedule, context), false);
 513         }
 514         graph.setAfterFixReadPhase(true);
 515     }
 516 
 517     public static class RawCEPhase extends BasePhase<LowTierContext> {
 518 
 519         private final boolean replaceInputsWithConstants;
 520 
 521         public RawCEPhase(boolean replaceInputsWithConstants) {
 522             this.replaceInputsWithConstants = replaceInputsWithConstants;
 523         }
 524 
 525         @Override
 526         protected CharSequence getName() {
 527             return "RawCEPhase";
 528         }
 529 
 530         @Override
 531         protected void run(StructuredGraph graph, LowTierContext context) {
 532             if (GraalOptions.RawConditionalElimination.getValue(graph.getOptions())) {
 533                 SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST, true);
 534                 schedulePhase.apply(graph);
 535                 ScheduleResult schedule = graph.getLastSchedule();
 536                 schedule.getCFG().visitDominatorTree(new RawConditionalEliminationVisitor(graph, schedule, context.getMetaAccess(), replaceInputsWithConstants), false);
 537             }
 538         }
 539     }
 540 
 541     protected ControlFlowGraph.RecursiveVisitor<?> createVisitor(StructuredGraph graph, ScheduleResult schedule, PhaseContext context) {
 542         return new RawConditionalEliminationVisitor(graph, schedule, context.getMetaAccess(), replaceInputsWithConstants);
 543     }
 544 
 545     protected static final class StampElement {
 546         private final Stamp stamp;
 547         private final StampElement parent;
 548 
 549         public StampElement(Stamp stamp, StampElement parent) {
 550             this.stamp = stamp;
 551             this.parent = parent;
 552         }
 553 
 554         public StampElement getParent() {
 555             return parent;
 556         }
 557 
 558         public Stamp getStamp() {
 559             return stamp;
 560         }
 561 
 562         @Override
 563         public String toString() {
 564             StringBuilder result = new StringBuilder();
 565             result.append(stamp);
 566             if (this.parent != null) {
 567                 result.append(" (");
 568                 result.append(this.parent.toString());
 569                 result.append(")");
 570             }
 571             return result.toString();
 572         }
 573     }
 574 
 575     public void setReplaceInputsWithConstants(boolean replaceInputsWithConstants) {
 576         this.replaceInputsWithConstants = replaceInputsWithConstants;
 577     }
 578 }