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 java.lang.Math.abs;
28 import static org.graalvm.compiler.loop.MathUtil.unsignedDivBefore;
29 import static org.graalvm.compiler.nodes.calc.BinaryArithmeticNode.add;
30 import static org.graalvm.compiler.nodes.calc.BinaryArithmeticNode.sub;
31
32 import org.graalvm.compiler.core.common.NumUtil;
33 import org.graalvm.compiler.core.common.type.IntegerStamp;
34 import org.graalvm.compiler.core.common.type.Stamp;
35 import org.graalvm.compiler.core.common.util.UnsignedLong;
36 import org.graalvm.compiler.debug.DebugCloseable;
37 import org.graalvm.compiler.loop.InductionVariable.Direction;
38 import org.graalvm.compiler.nodes.AbstractBeginNode;
39 import org.graalvm.compiler.nodes.ConstantNode;
40 import org.graalvm.compiler.nodes.GuardNode;
41 import org.graalvm.compiler.nodes.IfNode;
42 import org.graalvm.compiler.nodes.LogicNode;
43 import org.graalvm.compiler.nodes.NodeView;
44 import org.graalvm.compiler.nodes.StructuredGraph;
45 import org.graalvm.compiler.nodes.ValueNode;
46 import org.graalvm.compiler.nodes.calc.ConditionalNode;
47 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
48 import org.graalvm.compiler.nodes.calc.NegateNode;
49 import org.graalvm.compiler.nodes.extended.GuardingNode;
50 import org.graalvm.compiler.nodes.util.GraphUtil;
51
52 import jdk.vm.ci.meta.DeoptimizationAction;
53 import jdk.vm.ci.meta.DeoptimizationReason;
54 import jdk.vm.ci.meta.SpeculationLog;
55
56 public class CountedLoopInfo {
57
58 private final LoopEx loop;
59 private InductionVariable iv;
60 private ValueNode end;
61 private boolean oneOff;
62 private AbstractBeginNode body;
63 private IfNode ifNode;
64
65 CountedLoopInfo(LoopEx loop, InductionVariable iv, IfNode ifNode, ValueNode end, boolean oneOff, AbstractBeginNode body) {
66 assert iv.direction() != null;
67 this.loop = loop;
68 this.iv = iv;
69 this.end = end;
70 this.oneOff = oneOff;
71 this.body = body;
72 this.ifNode = ifNode;
73 }
74
75 /**
76 * Returns a node that computes the maximum trip count of this loop. That is the trip count of
77 * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest()
78 * count check}.
79 *
80 * This count is exact if {@link #isExactTripCount()} returns true.
81 *
82 * THIS VALUE SHOULD BE TREATED AS UNSIGNED.
83 */
84 public ValueNode maxTripCountNode() {
85 return maxTripCountNode(false);
86 }
87
88 /**
89 * Returns a node that computes the maximum trip count of this loop. That is the trip count of
90 * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest()
91 * count check}.
92 *
93 * This count is exact if {@link #isExactTripCount()} returns true.
94 *
95 * THIS VALUE SHOULD BE TREATED AS UNSIGNED.
96 *
97 * @param assumeLoopEntered if true the check that the loop is entered at all will be omitted.
98 */
99 public ValueNode maxTripCountNode(boolean assumeLoopEntered) {
100 StructuredGraph graph = iv.valueNode().graph();
101 Stamp stamp = iv.valueNode().stamp(NodeView.DEFAULT);
102
103 ValueNode max;
104 ValueNode min;
105 ValueNode absStride;
106 if (iv.direction() == Direction.Up) {
107 absStride = iv.strideNode();
110 } else {
111 assert iv.direction() == Direction.Down;
112 absStride = NegateNode.create(iv.strideNode(), NodeView.DEFAULT);
113 max = iv.initNode();
114 min = end;
115 }
116 ValueNode range = sub(max, min);
117
118 ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1);
119 if (oneOff) {
120 range = add(range, one);
121 }
122 // round-away-from-zero divison: (range + stride -/+ 1) / stride
123 ValueNode denominator = add(range, sub(absStride, one));
124 ValueNode div = unsignedDivBefore(graph, loop.entryPoint(), denominator, absStride, null);
125
126 if (assumeLoopEntered) {
127 return graph.addOrUniqueWithInputs(div);
128 }
129 ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0);
130 LogicNode noEntryCheck = IntegerLessThanNode.create(max, min, NodeView.DEFAULT);
131 return graph.addOrUniqueWithInputs(ConditionalNode.create(noEntryCheck, zero, div, NodeView.DEFAULT));
132 }
133
134 /**
135 * @return true if the loop has constant bounds.
136 */
137 public boolean isConstantMaxTripCount() {
138 return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride();
139 }
140
141 public UnsignedLong constantMaxTripCount() {
142 assert isConstantMaxTripCount();
143 return new UnsignedLong(rawConstantMaxTripCount());
144 }
145
146 /**
147 * Compute the raw value of the trip count for this loop. THIS IS AN UNSIGNED VALUE;
148 */
149 private long rawConstantMaxTripCount() {
150 assert iv.direction() != null;
151 long endValue = end.asJavaConstant().asLong();
152 long initValue = iv.constantInit();
153 long range;
154 long absStride;
155 if (iv.direction() == Direction.Up) {
156 if (endValue < initValue) {
157 return 0;
158 }
159 range = endValue - iv.constantInit();
160 absStride = iv.constantStride();
161 } else {
162 assert iv.direction() == Direction.Down;
163 if (initValue < endValue) {
164 return 0;
165 }
166 range = iv.constantInit() - endValue;
167 absStride = -iv.constantStride();
168 }
169 if (oneOff) {
170 range += 1;
171 }
172 long denominator = range + absStride - 1;
173 return Long.divideUnsigned(denominator, absStride);
174 }
175
176 public boolean isExactTripCount() {
177 return loop.loop().getNaturalExits().size() == 1;
178 }
179
180 public ValueNode exactTripCountNode() {
181 assert isExactTripCount();
182 return maxTripCountNode();
183 }
184
185 public boolean isConstantExactTripCount() {
186 assert isExactTripCount();
187 return isConstantMaxTripCount();
188 }
189
190 public UnsignedLong constantExactTripCount() {
191 assert isExactTripCount();
192 return constantMaxTripCount();
193 }
194
195 @Override
229 public Direction getDirection() {
230 return iv.direction();
231 }
232
233 public InductionVariable getCounter() {
234 return iv;
235 }
236
237 public GuardingNode getOverFlowGuard() {
238 return loop.loopBegin().getOverflowGuard();
239 }
240
241 public boolean counterNeverOverflows() {
242 if (iv.isConstantStride() && abs(iv.constantStride()) == 1) {
243 return true;
244 }
245 IntegerStamp endStamp = (IntegerStamp) end.stamp(NodeView.DEFAULT);
246 ValueNode strideNode = iv.strideNode();
247 IntegerStamp strideStamp = (IntegerStamp) strideNode.stamp(NodeView.DEFAULT);
248 GraphUtil.tryKillUnused(strideNode);
249 if (getDirection() == Direction.Up) {
250 long max = NumUtil.maxValue(endStamp.getBits());
251 return endStamp.upperBound() <= max - (strideStamp.upperBound() - 1) - (oneOff ? 1 : 0);
252 } else if (getDirection() == Direction.Down) {
253 long min = NumUtil.minValue(endStamp.getBits());
254 return min + (1 - strideStamp.lowerBound()) + (oneOff ? 1 : 0) <= endStamp.lowerBound();
255 }
256 return false;
257 }
258
259 @SuppressWarnings("try")
260 public GuardingNode createOverFlowGuard() {
261 GuardingNode overflowGuard = getOverFlowGuard();
262 if (overflowGuard != null || counterNeverOverflows()) {
263 return overflowGuard;
264 }
265 try (DebugCloseable position = loop.loopBegin().withNodeSourcePosition()) {
266 IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp(NodeView.DEFAULT);
267 StructuredGraph graph = iv.valueNode().graph();
268 LogicNode cond; // we use a negated guard with a < condition to achieve a >=
269 ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
270 if (iv.direction() == Direction.Up) {
271 ValueNode v1 = sub(ConstantNode.forIntegerStamp(stamp, NumUtil.maxValue(stamp.getBits())), sub(iv.strideNode(), one));
272 if (oneOff) {
273 v1 = sub(v1, one);
274 }
275 cond = graph.addOrUniqueWithInputs(IntegerLessThanNode.create(v1, end, NodeView.DEFAULT));
276 } else {
277 assert iv.direction() == Direction.Down;
278 ValueNode v1 = add(ConstantNode.forIntegerStamp(stamp, NumUtil.minValue(stamp.getBits())), sub(one, iv.strideNode()));
279 if (oneOff) {
280 v1 = add(v1, one);
281 }
282 cond = graph.addOrUniqueWithInputs(IntegerLessThanNode.create(end, v1, NodeView.DEFAULT));
283 }
284 assert graph.getGuardsStage().allowsFloatingGuards();
285 overflowGuard = graph.unique(new GuardNode(cond, AbstractBeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true,
286 SpeculationLog.NO_SPECULATION, null)); // TODO gd: use speculation
287 loop.loopBegin().setOverflowGuard(overflowGuard);
288 return overflowGuard;
289 }
290 }
291
292 public IntegerStamp getStamp() {
293 return (IntegerStamp) iv.valueNode().stamp(NodeView.DEFAULT);
294 }
295 }
|
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 java.lang.Math.abs;
28 import static org.graalvm.compiler.loop.MathUtil.unsignedDivBefore;
29 import static org.graalvm.compiler.nodes.calc.BinaryArithmeticNode.add;
30 import static org.graalvm.compiler.nodes.calc.BinaryArithmeticNode.sub;
31
32 import org.graalvm.compiler.core.common.type.IntegerStamp;
33 import org.graalvm.compiler.core.common.type.Stamp;
34 import org.graalvm.compiler.core.common.util.UnsignedLong;
35 import org.graalvm.compiler.debug.DebugCloseable;
36 import org.graalvm.compiler.loop.InductionVariable.Direction;
37 import org.graalvm.compiler.nodes.AbstractBeginNode;
38 import org.graalvm.compiler.nodes.ConstantNode;
39 import org.graalvm.compiler.nodes.GuardNode;
40 import org.graalvm.compiler.nodes.IfNode;
41 import org.graalvm.compiler.nodes.LogicNode;
42 import org.graalvm.compiler.nodes.NodeView;
43 import org.graalvm.compiler.nodes.StructuredGraph;
44 import org.graalvm.compiler.nodes.ValueNode;
45 import org.graalvm.compiler.nodes.calc.ConditionalNode;
46 import org.graalvm.compiler.nodes.calc.NegateNode;
47 import org.graalvm.compiler.nodes.extended.GuardingNode;
48 import org.graalvm.compiler.nodes.util.GraphUtil;
49 import org.graalvm.compiler.nodes.util.IntegerHelper;
50 import org.graalvm.compiler.nodes.util.SignedIntegerHelper;
51 import org.graalvm.compiler.nodes.util.UnsignedIntegerHelper;
52
53 import jdk.vm.ci.meta.DeoptimizationAction;
54 import jdk.vm.ci.meta.DeoptimizationReason;
55 import jdk.vm.ci.meta.SpeculationLog;
56
57 public class CountedLoopInfo {
58
59 private final LoopEx loop;
60 private InductionVariable iv;
61 private ValueNode end;
62 private boolean oneOff;
63 private AbstractBeginNode body;
64 private IfNode ifNode;
65 private final boolean unsigned;
66
67 CountedLoopInfo(LoopEx loop, InductionVariable iv, IfNode ifNode, ValueNode end, boolean oneOff, AbstractBeginNode body, boolean unsigned) {
68 assert iv.direction() != null;
69 this.loop = loop;
70 this.iv = iv;
71 this.end = end;
72 this.oneOff = oneOff;
73 this.body = body;
74 this.ifNode = ifNode;
75 this.unsigned = unsigned;
76 }
77
78 /**
79 * Returns a node that computes the maximum trip count of this loop. That is the trip count of
80 * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest()
81 * count check}.
82 *
83 * This count is exact if {@link #isExactTripCount()} returns true.
84 *
85 * THIS VALUE SHOULD BE TREATED AS UNSIGNED.
86 */
87 public ValueNode maxTripCountNode() {
88 return maxTripCountNode(false);
89 }
90
91 public boolean isUnsignedCheck() {
92 return this.unsigned;
93 }
94
95 /**
96 * Returns a node that computes the maximum trip count of this loop. That is the trip count of
97 * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest()
98 * count check}.
99 *
100 * This count is exact if {@link #isExactTripCount()} returns true.
101 *
102 * THIS VALUE SHOULD BE TREATED AS UNSIGNED.
103 *
104 * @param assumeLoopEntered if true the check that the loop is entered at all will be omitted.
105 */
106 public ValueNode maxTripCountNode(boolean assumeLoopEntered) {
107 StructuredGraph graph = iv.valueNode().graph();
108 Stamp stamp = iv.valueNode().stamp(NodeView.DEFAULT);
109
110 ValueNode max;
111 ValueNode min;
112 ValueNode absStride;
113 if (iv.direction() == Direction.Up) {
114 absStride = iv.strideNode();
117 } else {
118 assert iv.direction() == Direction.Down;
119 absStride = NegateNode.create(iv.strideNode(), NodeView.DEFAULT);
120 max = iv.initNode();
121 min = end;
122 }
123 ValueNode range = sub(max, min);
124
125 ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1);
126 if (oneOff) {
127 range = add(range, one);
128 }
129 // round-away-from-zero divison: (range + stride -/+ 1) / stride
130 ValueNode denominator = add(range, sub(absStride, one));
131 ValueNode div = unsignedDivBefore(graph, loop.entryPoint(), denominator, absStride, null);
132
133 if (assumeLoopEntered) {
134 return graph.addOrUniqueWithInputs(div);
135 }
136 ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0);
137 // This check is "wide": it looks like min <= max
138 // That's OK even if the loop is strict (`!isLimitIncluded()`)
139 // because in this case, `div` will be zero when min == max
140 LogicNode noEntryCheck = getCounterIntegerHelper().createCompareNode(max, min, NodeView.DEFAULT);
141 return graph.addOrUniqueWithInputs(ConditionalNode.create(noEntryCheck, zero, div, NodeView.DEFAULT));
142 }
143
144 /**
145 * @return true if the loop has constant bounds.
146 */
147 public boolean isConstantMaxTripCount() {
148 return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride();
149 }
150
151 public UnsignedLong constantMaxTripCount() {
152 assert isConstantMaxTripCount();
153 return new UnsignedLong(rawConstantMaxTripCount());
154 }
155
156 /**
157 * Compute the raw value of the trip count for this loop. THIS IS AN UNSIGNED VALUE;
158 */
159 private long rawConstantMaxTripCount() {
160 assert iv.direction() != null;
161 long endValue = end.asJavaConstant().asLong();
162 long initValue = iv.constantInit();
163 long range;
164 long absStride;
165 IntegerHelper helper = getCounterIntegerHelper(64);
166 if (iv.direction() == Direction.Up) {
167 if (helper.compare(endValue, initValue) < 0) {
168 return 0;
169 }
170 range = endValue - iv.constantInit();
171 absStride = iv.constantStride();
172 } else {
173 assert iv.direction() == Direction.Down;
174 if (helper.compare(initValue, endValue) < 0) {
175 return 0;
176 }
177 range = iv.constantInit() - endValue;
178 absStride = -iv.constantStride();
179 }
180 if (oneOff) {
181 range += 1;
182 }
183 long denominator = range + absStride - 1;
184 return Long.divideUnsigned(denominator, absStride);
185 }
186
187 public IntegerHelper getCounterIntegerHelper() {
188 IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp(NodeView.DEFAULT);
189 return getCounterIntegerHelper(stamp.getBits());
190 }
191
192 public IntegerHelper getCounterIntegerHelper(int bits) {
193 IntegerHelper helper;
194 if (isUnsignedCheck()) {
195 helper = new UnsignedIntegerHelper(bits);
196 } else {
197 helper = new SignedIntegerHelper(bits);
198 }
199 return helper;
200 }
201
202 public boolean isExactTripCount() {
203 return loop.loop().getNaturalExits().size() == 1;
204 }
205
206 public ValueNode exactTripCountNode() {
207 assert isExactTripCount();
208 return maxTripCountNode();
209 }
210
211 public boolean isConstantExactTripCount() {
212 assert isExactTripCount();
213 return isConstantMaxTripCount();
214 }
215
216 public UnsignedLong constantExactTripCount() {
217 assert isExactTripCount();
218 return constantMaxTripCount();
219 }
220
221 @Override
255 public Direction getDirection() {
256 return iv.direction();
257 }
258
259 public InductionVariable getCounter() {
260 return iv;
261 }
262
263 public GuardingNode getOverFlowGuard() {
264 return loop.loopBegin().getOverflowGuard();
265 }
266
267 public boolean counterNeverOverflows() {
268 if (iv.isConstantStride() && abs(iv.constantStride()) == 1) {
269 return true;
270 }
271 IntegerStamp endStamp = (IntegerStamp) end.stamp(NodeView.DEFAULT);
272 ValueNode strideNode = iv.strideNode();
273 IntegerStamp strideStamp = (IntegerStamp) strideNode.stamp(NodeView.DEFAULT);
274 GraphUtil.tryKillUnused(strideNode);
275 IntegerHelper integerHelper = getCounterIntegerHelper();
276 if (getDirection() == Direction.Up) {
277 long max = integerHelper.maxValue();
278 return integerHelper.compare(endStamp.upperBound(), max - (strideStamp.upperBound() - 1) - (oneOff ? 1 : 0)) <= 0;
279 } else if (getDirection() == Direction.Down) {
280 long min = integerHelper.minValue();
281 return integerHelper.compare(min + (1 - strideStamp.lowerBound()) + (oneOff ? 1 : 0), endStamp.lowerBound()) <= 0;
282 }
283 return false;
284 }
285
286 @SuppressWarnings("try")
287 public GuardingNode createOverFlowGuard() {
288 GuardingNode overflowGuard = getOverFlowGuard();
289 if (overflowGuard != null || counterNeverOverflows()) {
290 return overflowGuard;
291 }
292 try (DebugCloseable position = loop.loopBegin().withNodeSourcePosition()) {
293 IntegerStamp stamp = (IntegerStamp) iv.valueNode().stamp(NodeView.DEFAULT);
294 IntegerHelper integerHelper = getCounterIntegerHelper();
295 StructuredGraph graph = iv.valueNode().graph();
296 LogicNode cond; // we use a negated guard with a < condition to achieve a >=
297 ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
298 if (iv.direction() == Direction.Up) {
299 ValueNode v1 = sub(ConstantNode.forIntegerStamp(stamp, integerHelper.maxValue()), sub(iv.strideNode(), one));
300 if (oneOff) {
301 v1 = sub(v1, one);
302 }
303 cond = graph.addOrUniqueWithInputs(integerHelper.createCompareNode(v1, end, NodeView.DEFAULT));
304 } else {
305 assert iv.direction() == Direction.Down;
306 ValueNode v1 = add(ConstantNode.forIntegerStamp(stamp, integerHelper.minValue()), sub(one, iv.strideNode()));
307 if (oneOff) {
308 v1 = add(v1, one);
309 }
310 cond = graph.addOrUniqueWithInputs(integerHelper.createCompareNode(end, v1, NodeView.DEFAULT));
311 }
312 assert graph.getGuardsStage().allowsFloatingGuards();
313 overflowGuard = graph.unique(new GuardNode(cond, AbstractBeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true,
314 SpeculationLog.NO_SPECULATION, null)); // TODO gd: use speculation
315 loop.loopBegin().setOverflowGuard(overflowGuard);
316 return overflowGuard;
317 }
318 }
319
320 public IntegerStamp getStamp() {
321 return (IntegerStamp) iv.valueNode().stamp(NodeView.DEFAULT);
322 }
323 }
|