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