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