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