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