1 /*
   2  * Copyright (c) 2011, 2015, 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.nodes;
  24 
  25 import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
  26 
  27 import org.graalvm.compiler.core.common.type.IntegerStamp;
  28 import org.graalvm.compiler.graph.IterableNodeType;
  29 import org.graalvm.compiler.graph.Node;
  30 import org.graalvm.compiler.graph.NodeClass;
  31 import org.graalvm.compiler.graph.iterators.NodeIterable;
  32 import org.graalvm.compiler.graph.spi.SimplifierTool;
  33 import org.graalvm.compiler.nodeinfo.InputType;
  34 import org.graalvm.compiler.nodeinfo.NodeInfo;
  35 import org.graalvm.compiler.nodes.calc.AddNode;
  36 import org.graalvm.compiler.nodes.extended.GuardingNode;
  37 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  38 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  39 import org.graalvm.compiler.nodes.util.GraphUtil;
  40 
  41 @NodeInfo
  42 public final class LoopBeginNode extends AbstractMergeNode implements IterableNodeType, LIRLowerable {
  43 
  44     public static final NodeClass<LoopBeginNode> TYPE = NodeClass.create(LoopBeginNode.class);
  45     protected double loopFrequency;
  46     protected double loopOrigFrequency;
  47     protected int nextEndIndex;
  48     protected int unswitches;
  49     protected int splits;
  50     protected int inversionCount;
  51     protected LoopType loopType;
  52     protected int unrollFactor;
  53 
  54     public enum LoopType {
  55         SIMPLE_LOOP,
  56         PRE_LOOP,
  57         MAIN_LOOP,
  58         POST_LOOP
  59     }
  60 
  61     /** See {@link LoopEndNode#canSafepoint} for more information. */
  62     boolean canEndsSafepoint;
  63 
  64     @OptionalInput(InputType.Guard) GuardingNode overflowGuard;
  65 
  66     public LoopBeginNode() {
  67         super(TYPE);
  68         loopFrequency = 1;
  69         loopOrigFrequency = 1;
  70         unswitches = 0;
  71         splits = 0;
  72         this.canEndsSafepoint = true;
  73         loopType = LoopType.SIMPLE_LOOP;
  74         unrollFactor = 1;
  75     }
  76 
  77     public boolean isSimpleLoop() {
  78         return (loopType == LoopType.SIMPLE_LOOP);
  79     }
  80 
  81     public void setPreLoop() {
  82         assert isSimpleLoop();
  83         loopType = LoopType.PRE_LOOP;
  84     }
  85 
  86     public boolean isPreLoop() {
  87         return (loopType == LoopType.PRE_LOOP);
  88     }
  89 
  90     public void setMainLoop() {
  91         assert isSimpleLoop();
  92         loopType = LoopType.MAIN_LOOP;
  93     }
  94 
  95     public boolean isMainLoop() {
  96         return (loopType == LoopType.MAIN_LOOP);
  97     }
  98 
  99     public void setPostLoop() {
 100         assert isSimpleLoop();
 101         loopType = LoopType.POST_LOOP;
 102     }
 103 
 104     public boolean isPostLoop() {
 105         return (loopType == LoopType.POST_LOOP);
 106     }
 107 
 108     public int getUnrollFactor() {
 109         return unrollFactor;
 110     }
 111 
 112     public void setUnrollFactor(int currentUnrollFactor) {
 113         unrollFactor = currentUnrollFactor;
 114     }
 115 
 116     /** Disables safepoint for the whole loop, i.e., for all {@link LoopEndNode loop ends}. */
 117     public void disableSafepoint() {
 118         /* Store flag locally in case new loop ends are created later on. */
 119         this.canEndsSafepoint = false;
 120         /* Propagate flag to all existing loop ends. */
 121         for (LoopEndNode loopEnd : loopEnds()) {
 122             loopEnd.disableSafepoint();
 123         }
 124     }
 125 
 126     public double loopOrigFrequency() {
 127         return loopOrigFrequency;
 128     }
 129 
 130     public void setLoopOrigFrequency(double loopOrigFrequency) {
 131         assert loopOrigFrequency >= 0;
 132         this.loopOrigFrequency = loopOrigFrequency;
 133     }
 134 
 135     public double loopFrequency() {
 136         return loopFrequency;
 137     }
 138 
 139     public void setLoopFrequency(double loopFrequency) {
 140         assert loopFrequency >= 0;
 141         this.loopFrequency = loopFrequency;
 142     }
 143 
 144     /**
 145      * Returns the <b>unordered</b> set of {@link LoopEndNode} that correspond to back-edges for
 146      * this loop. The order of the back-edges is unspecified, if you need to get an ordering
 147      * compatible for {@link PhiNode} creation, use {@link #orderedLoopEnds()}.
 148      *
 149      * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
 150      */
 151     public NodeIterable<LoopEndNode> loopEnds() {
 152         return usages().filter(LoopEndNode.class);
 153     }
 154 
 155     public NodeIterable<LoopExitNode> loopExits() {
 156         return usages().filter(LoopExitNode.class);
 157     }
 158 
 159     @Override
 160     public NodeIterable<Node> anchored() {
 161         return super.anchored().filter(isNotA(LoopEndNode.class).nor(LoopExitNode.class));
 162     }
 163 
 164     /**
 165      * Returns the set of {@link LoopEndNode} that correspond to back-edges for this loop, in
 166      * increasing {@link #phiPredecessorIndex} order. This method is suited to create new loop
 167      * {@link PhiNode}.<br>
 168      *
 169      * For example a new PhiNode may be added as follow:
 170      *
 171      * <pre>
 172      * PhiNode phi = new ValuePhiNode(stamp, loop);
 173      * phi.addInput(forwardEdgeValue);
 174      * for (LoopEndNode loopEnd : loop.orderedLoopEnds()) {
 175      *     phi.addInput(backEdgeValue(loopEnd));
 176      * }
 177      * </pre>
 178      *
 179      * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
 180      */
 181     public LoopEndNode[] orderedLoopEnds() {
 182         LoopEndNode[] result = new LoopEndNode[this.getLoopEndCount()];
 183         for (LoopEndNode end : loopEnds()) {
 184             result[end.endIndex()] = end;
 185         }
 186         return result;
 187     }
 188 
 189     public boolean isSingleEntryLoop() {
 190         return (forwardEndCount() == 1);
 191     }
 192 
 193     public AbstractEndNode forwardEnd() {
 194         assert forwardEndCount() == 1;
 195         return forwardEndAt(0);
 196     }
 197 
 198     public int splits() {
 199         return splits;
 200     }
 201 
 202     public void incrementSplits() {
 203         splits++;
 204     }
 205 
 206     @Override
 207     public void generate(NodeLIRBuilderTool gen) {
 208         // Nothing to emit, since this is node is used for structural purposes only.
 209     }
 210 
 211     @Override
 212     protected void deleteEnd(AbstractEndNode end) {
 213         if (end instanceof LoopEndNode) {
 214             LoopEndNode loopEnd = (LoopEndNode) end;
 215             loopEnd.setLoopBegin(null);
 216             int idx = loopEnd.endIndex();
 217             for (LoopEndNode le : loopEnds()) {
 218                 int leIdx = le.endIndex();
 219                 assert leIdx != idx;
 220                 if (leIdx > idx) {
 221                     le.setEndIndex(leIdx - 1);
 222                 }
 223             }
 224             nextEndIndex--;
 225         } else {
 226             super.deleteEnd(end);
 227         }
 228     }
 229 
 230     @Override
 231     public int phiPredecessorCount() {
 232         return forwardEndCount() + loopEnds().count();
 233     }
 234 
 235     @Override
 236     public int phiPredecessorIndex(AbstractEndNode pred) {
 237         if (pred instanceof LoopEndNode) {
 238             LoopEndNode loopEnd = (LoopEndNode) pred;
 239             if (loopEnd.loopBegin() == this) {
 240                 assert loopEnd.endIndex() < loopEnds().count() : "Invalid endIndex : " + loopEnd;
 241                 return loopEnd.endIndex() + forwardEndCount();
 242             }
 243         } else {
 244             return super.forwardEndIndex((EndNode) pred);
 245         }
 246         throw ValueNodeUtil.shouldNotReachHere("unknown pred : " + pred);
 247     }
 248 
 249     @Override
 250     public AbstractEndNode phiPredecessorAt(int index) {
 251         if (index < forwardEndCount()) {
 252             return forwardEndAt(index);
 253         }
 254         for (LoopEndNode end : loopEnds()) {
 255             int idx = index - forwardEndCount();
 256             assert idx >= 0;
 257             if (end.endIndex() == idx) {
 258                 return end;
 259             }
 260         }
 261         throw ValueNodeUtil.shouldNotReachHere();
 262     }
 263 
 264     @Override
 265     public boolean verify() {
 266         assertTrue(loopEnds().isNotEmpty(), "missing loopEnd");
 267         return super.verify();
 268     }
 269 
 270     int nextEndIndex() {
 271         return nextEndIndex++;
 272     }
 273 
 274     public int getLoopEndCount() {
 275         return nextEndIndex;
 276     }
 277 
 278     public int unswitches() {
 279         return unswitches;
 280     }
 281 
 282     public void incrementUnswitches() {
 283         unswitches++;
 284     }
 285 
 286     public int getInversionCount() {
 287         return inversionCount;
 288     }
 289 
 290     public void setInversionCount(int count) {
 291         inversionCount = count;
 292     }
 293 
 294     @Override
 295     public void simplify(SimplifierTool tool) {
 296         canonicalizePhis(tool);
 297     }
 298 
 299     public boolean isLoopExit(AbstractBeginNode begin) {
 300         return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this;
 301     }
 302 
 303     public void removeExits() {
 304         for (LoopExitNode loopexit : loopExits().snapshot()) {
 305             loopexit.removeProxies();
 306             FrameState loopStateAfter = loopexit.stateAfter();
 307             graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode()));
 308             if (loopStateAfter != null) {
 309                 GraphUtil.tryKillUnused(loopStateAfter);
 310             }
 311         }
 312     }
 313 
 314     public GuardingNode getOverflowGuard() {
 315         return overflowGuard;
 316     }
 317 
 318     public void setOverflowGuard(GuardingNode overflowGuard) {
 319         updateUsagesInterface(this.overflowGuard, overflowGuard);
 320         this.overflowGuard = overflowGuard;
 321     }
 322 
 323     private static final int NO_INCREMENT = Integer.MIN_VALUE;
 324 
 325     /**
 326      * Returns an array with one entry for each input of the phi, which is either
 327      * {@link #NO_INCREMENT} or the increment, i.e., the value by which the phi is incremented in
 328      * the corresponding branch.
 329      */
 330     private static int[] getSelfIncrements(PhiNode phi) {
 331         int[] selfIncrement = new int[phi.valueCount()];
 332         for (int i = 0; i < phi.valueCount(); i++) {
 333             ValueNode input = phi.valueAt(i);
 334             long increment = NO_INCREMENT;
 335             if (input != null && input instanceof AddNode && input.stamp() instanceof IntegerStamp) {
 336                 AddNode add = (AddNode) input;
 337                 if (add.getX() == phi && add.getY().isConstant()) {
 338                     increment = add.getY().asJavaConstant().asLong();
 339                 } else if (add.getY() == phi && add.getX().isConstant()) {
 340                     increment = add.getX().asJavaConstant().asLong();
 341                 }
 342             } else if (input == phi) {
 343                 increment = 0;
 344             }
 345             if (increment < Integer.MIN_VALUE || increment > Integer.MAX_VALUE || increment == NO_INCREMENT) {
 346                 increment = NO_INCREMENT;
 347             }
 348             selfIncrement[i] = (int) increment;
 349         }
 350         return selfIncrement;
 351     }
 352 
 353     /**
 354      * Coalesces loop phis that represent the same value (which is not handled by normal Global
 355      * Value Numbering).
 356      */
 357     public void canonicalizePhis(SimplifierTool tool) {
 358         int phiCount = phis().count();
 359         if (phiCount > 1) {
 360             int phiInputCount = phiPredecessorCount();
 361             int phiIndex = 0;
 362             int[][] selfIncrement = new int[phiCount][];
 363             PhiNode[] phis = this.phis().snapshot().toArray(new PhiNode[phiCount]);
 364 
 365             for (phiIndex = 0; phiIndex < phiCount; phiIndex++) {
 366                 PhiNode phi = phis[phiIndex];
 367                 if (phi != null) {
 368                     nextPhi: for (int otherPhiIndex = phiIndex + 1; otherPhiIndex < phiCount; otherPhiIndex++) {
 369                         PhiNode otherPhi = phis[otherPhiIndex];
 370                         if (otherPhi == null || phi.getNodeClass() != otherPhi.getNodeClass() || !phi.valueEquals(otherPhi)) {
 371                             continue nextPhi;
 372                         }
 373                         if (selfIncrement[phiIndex] == null) {
 374                             selfIncrement[phiIndex] = getSelfIncrements(phi);
 375                         }
 376                         if (selfIncrement[otherPhiIndex] == null) {
 377                             selfIncrement[otherPhiIndex] = getSelfIncrements(otherPhi);
 378                         }
 379                         int[] phiIncrement = selfIncrement[phiIndex];
 380                         int[] otherPhiIncrement = selfIncrement[otherPhiIndex];
 381                         for (int inputIndex = 0; inputIndex < phiInputCount; inputIndex++) {
 382                             if (phiIncrement[inputIndex] == NO_INCREMENT) {
 383                                 if (phi.valueAt(inputIndex) != otherPhi.valueAt(inputIndex)) {
 384                                     continue nextPhi;
 385                                 }
 386                             }
 387                             if (phiIncrement[inputIndex] != otherPhiIncrement[inputIndex]) {
 388                                 continue nextPhi;
 389                             }
 390                         }
 391                         if (tool != null) {
 392                             tool.addToWorkList(otherPhi.usages());
 393                         }
 394                         otherPhi.replaceAtUsages(phi);
 395                         GraphUtil.killWithUnusedFloatingInputs(otherPhi);
 396                         phis[otherPhiIndex] = null;
 397                     }
 398                 }
 399             }
 400         }
 401     }
 402 }