1 /*
   2  * Copyright (c) 2012, 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.loop;
  26 
  27 import static org.graalvm.compiler.loop.MathUtil.add;
  28 import static org.graalvm.compiler.loop.MathUtil.mul;
  29 import static org.graalvm.compiler.loop.MathUtil.sub;
  30 
  31 import org.graalvm.compiler.core.common.type.IntegerStamp;
  32 import org.graalvm.compiler.core.common.type.Stamp;
  33 import org.graalvm.compiler.core.common.util.UnsignedLong;
  34 import org.graalvm.compiler.debug.GraalError;
  35 import org.graalvm.compiler.nodes.ConstantNode;
  36 import org.graalvm.compiler.nodes.NodeView;
  37 import org.graalvm.compiler.nodes.StructuredGraph;
  38 import org.graalvm.compiler.nodes.ValueNode;
  39 import org.graalvm.compiler.nodes.ValuePhiNode;
  40 import org.graalvm.compiler.nodes.calc.AddNode;
  41 import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
  42 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  43 import org.graalvm.compiler.nodes.calc.NegateNode;
  44 import org.graalvm.compiler.nodes.calc.SubNode;
  45 
  46 public class BasicInductionVariable extends InductionVariable {
  47 
  48     private final ValuePhiNode phi;
  49     private final ValueNode init;
  50     private ValueNode rawStride;
  51     private BinaryArithmeticNode<?> op;
  52 
  53     public BasicInductionVariable(LoopEx loop, ValuePhiNode phi, ValueNode init, ValueNode rawStride, BinaryArithmeticNode<?> op) {
  54         super(loop);
  55         this.phi = phi;
  56         this.init = init;
  57         this.rawStride = rawStride;
  58         this.op = op;
  59     }
  60 
  61     @Override
  62     public StructuredGraph graph() {
  63         return phi.graph();
  64     }
  65 
  66     public BinaryArithmeticNode<?> getOp() {
  67         return op;
  68     }
  69 
  70     public void setOP(BinaryArithmeticNode<?> newOp) {
  71         rawStride = newOp.getY();
  72         op = newOp;
  73     }
  74 
  75     @Override
  76     public Direction direction() {
  77         Stamp stamp = rawStride.stamp(NodeView.DEFAULT);
  78         if (stamp instanceof IntegerStamp) {
  79             IntegerStamp integerStamp = (IntegerStamp) stamp;
  80             Direction dir = null;
  81             if (integerStamp.isStrictlyPositive()) {
  82                 dir = Direction.Up;
  83             } else if (integerStamp.isStrictlyNegative()) {
  84                 dir = Direction.Down;
  85             }
  86             if (dir != null) {
  87                 if (op instanceof AddNode) {
  88                     return dir;
  89                 } else {
  90                     assert op instanceof SubNode;
  91                     return dir.opposite();
  92                 }
  93             }
  94         }
  95         return null;
  96     }
  97 
  98     @Override
  99     public ValuePhiNode valueNode() {
 100         return phi;
 101     }
 102 
 103     @Override
 104     public ValueNode initNode() {
 105         return init;
 106     }
 107 
 108     @Override
 109     public ValueNode strideNode() {
 110         if (op instanceof AddNode) {
 111             return rawStride;
 112         }
 113         if (op instanceof SubNode) {
 114             return graph().unique(new NegateNode(rawStride));
 115         }
 116         throw GraalError.shouldNotReachHere();
 117     }
 118 
 119     @Override
 120     public boolean isConstantInit() {
 121         return init.isConstant();
 122     }
 123 
 124     @Override
 125     public boolean isConstantStride() {
 126         return rawStride.isConstant();
 127     }
 128 
 129     @Override
 130     public long constantInit() {
 131         return init.asJavaConstant().asLong();
 132     }
 133 
 134     @Override
 135     public long constantStride() {
 136         if (op instanceof AddNode) {
 137             return rawStride.asJavaConstant().asLong();
 138         }
 139         if (op instanceof SubNode) {
 140             return -rawStride.asJavaConstant().asLong();
 141         }
 142         throw GraalError.shouldNotReachHere();
 143     }
 144 
 145     @Override
 146     public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp) {
 147         Stamp fromStamp = phi.stamp(NodeView.DEFAULT);
 148         StructuredGraph graph = graph();
 149         ValueNode stride = strideNode();
 150         ValueNode initNode = this.initNode();
 151         if (!fromStamp.isCompatible(stamp)) {
 152             stride = IntegerConvertNode.convert(stride, stamp, graph(), NodeView.DEFAULT);
 153             initNode = IntegerConvertNode.convert(initNode, stamp, graph(), NodeView.DEFAULT);
 154         }
 155         ValueNode maxTripCount = loop.counted().maxTripCountNode(assumeLoopEntered);
 156         if (!maxTripCount.stamp(NodeView.DEFAULT).isCompatible(stamp)) {
 157             maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph(), NodeView.DEFAULT);
 158         }
 159         return add(graph, mul(graph, stride, sub(graph, maxTripCount, ConstantNode.forIntegerStamp(stamp, 1, graph))), initNode);
 160     }
 161 
 162     @Override
 163     public ValueNode exitValueNode() {
 164         Stamp stamp = phi.stamp(NodeView.DEFAULT);
 165         ValueNode maxTripCount = loop.counted().maxTripCountNode();
 166         if (!maxTripCount.stamp(NodeView.DEFAULT).isCompatible(stamp)) {
 167             maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph(), NodeView.DEFAULT);
 168         }
 169         return add(graph(), mul(graph(), strideNode(), maxTripCount), initNode());
 170     }
 171 
 172     @Override
 173     public boolean isConstantExtremum() {
 174         return isConstantInit() && isConstantStride() && loop.counted().isConstantMaxTripCount();
 175     }
 176 
 177     @Override
 178     public long constantExtremum() {
 179         UnsignedLong tripCount = loop.counted().constantMaxTripCount();
 180         if (tripCount.isLessThan(1)) {
 181             return constantInit();
 182         }
 183         return tripCount.minus(1).wrappingTimes(constantStride()).wrappingPlus(constantInit()).asLong();
 184     }
 185 
 186     @Override
 187     public void deleteUnusedNodes() {
 188     }
 189 
 190     @Override
 191     public String toString() {
 192         return String.format("BasicInductionVariable %s %s %s %s", initNode(), phi, op.getNodeClass().shortName(), strideNode());
 193     }
 194 }