diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/amd64/test/AMD64AddressLoweringTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/amd64/test/AMD64AddressLoweringTest.java index 1c07347b5239b..1253a18f6714d 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/amd64/test/AMD64AddressLoweringTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/amd64/test/AMD64AddressLoweringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import jdk.graal.compiler.core.amd64.AMD64AddressNode; import jdk.graal.compiler.core.test.GraalCompilerTest; import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.ReturnNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.calc.AddNode; @@ -78,6 +79,40 @@ public void convertBaseAndShiftedIndexToDisplacement() { assertAddress(result, null, null, Stride.S2, 1020); } + /// Checks address scaling before the shift distance has been canonicalized. + @Test + public void convertRawShiftedIndexToDisplacement() { + for (int amount : new int[]{-64, -63, -62, -61, 64, 65, 66, 67}) { + ValueNode base = graph.addOrUniqueWithInputs(const64(1000)); + ValueNode index = graph.addOrUniqueWithInputs(new LeftShiftNode(const64(10), const32(amount))); + AddressNode result = lowering.lower(base, index); + assertAddress(result, null, null, Stride.fromLog2(amount & 63), 1000 + (int) (10L << amount)); + } + } + + /// Checks that a negative inner distance cannot cancel the scale of an outer shift. + @Test + public void preserveNestedShiftOverflow() { + ValueNode base = graph.addOrUniqueWithInputs(const64(0)); + ValueNode inner = graph.addOrUniqueWithInputs(new LeftShiftNode(const64(1), const32(-1))); + ValueNode outer = graph.addOrUniqueWithInputs(new LeftShiftNode(inner, const32(2))); + AMD64AddressNode address = (AMD64AddressNode) lowering.lower(base, outer); + + // Evaluates the selected addressing mode after lowering has inspected the raw distances. + ValueNode value = graph.addOrUniqueWithInputs(const64(address.getDisplacement())); + if (address.getBase() != null) { + value = graph.addOrUniqueWithInputs(new AddNode(value, address.getBase())); + } + if (address.getIndex() != null) { + ValueNode scaledIndex = new LeftShiftNode(address.getIndex(), const32(address.getScale().log2)); + value = graph.addOrUniqueWithInputs(new AddNode(value, scaledIndex)); + } + ReturnNode returnNode = graph.add(new ReturnNode(value)); + graph.start().setNext(returnNode); + createCanonicalizerPhase().apply(graph, getDefaultHighTierContext()); + Assert.assertEquals((1L << -1) << 2, returnNode.result().asJavaConstant().asLong()); + } + @Test public void convertBaseAndNegatedShiftedIndexToDisplacement() { ValueNode base = graph.addOrUniqueWithInputs(const64(1000)); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index 4e0e26bebac39..33b989b880d3a 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -394,6 +394,7 @@ public boolean add(String s) { verifiers.add(new VerifyPhaseNoDirectRecursion()); verifiers.add(new VerifyStringCaseUsage()); verifiers.add(new VerifyMathAbs()); + verifiers.add(new VerifyShiftAmounts()); verifiers.add(new VerifyLoopInfo()); verifiers.add(new VerifyGuardsStageUsages()); verifiers.add(new VerifyAArch64RegisterUsages()); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ShiftDistanceAnalysisTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ShiftDistanceAnalysisTest.java new file mode 100644 index 0000000000000..af1bf688a1320 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ShiftDistanceAnalysisTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.core.test; + +import org.junit.Assert; +import org.junit.Test; + +import jdk.graal.compiler.core.common.type.IntegerStamp; +import jdk.graal.compiler.core.common.type.StampPair; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.LogicNode; +import jdk.graal.compiler.nodes.NodeView; +import jdk.graal.compiler.nodes.ParameterNode; +import jdk.graal.compiler.nodes.ReturnNode; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.ConditionalNode; +import jdk.graal.compiler.nodes.calc.IntegerBelowNode; +import jdk.graal.compiler.nodes.calc.IntegerLessThanNode; +import jdk.graal.compiler.nodes.calc.LeftShiftNode; +import jdk.graal.compiler.nodes.calc.MulNode; +import jdk.graal.compiler.nodes.calc.NegateNode; +import jdk.graal.compiler.nodes.calc.RightShiftNode; +import jdk.graal.compiler.nodes.calc.UnsignedRightShiftNode; +import jdk.graal.compiler.nodes.loop.DerivedScaledInductionVariable; +import jdk.graal.compiler.nodes.loop.InductionVariable; +import jdk.graal.compiler.nodes.loop.Loop; +import jdk.graal.compiler.nodes.loop.LoopsData; + +/// Tests analyses of shifts before their constant distances have been canonicalized. +public class ShiftDistanceAnalysisTest extends GraalCompilerTest { + + /// Checks that comparison cancellation preserves Java results for raw shift constants. + private void checkComparison(int bits, int amount, boolean unsigned, long xValue, long yValue) { + StructuredGraph graph = new StructuredGraph.Builder(getInitialOptions(), getDebugContext()).build(); + IntegerStamp stamp = IntegerStamp.create(bits, 0, 3); + ParameterNode x = graph.addWithoutUnique(new ParameterNode(0, StampPair.createSingle(stamp))); + ParameterNode y = graph.addWithoutUnique(new ParameterNode(1, StampPair.createSingle(stamp))); + ConstantNode distance = ConstantNode.forInt(amount, graph); + // Retains the raw constant so comparison analysis runs before shift canonicalization. + LeftShiftNode shiftX = graph.unique(new LeftShiftNode(x, distance)); + LeftShiftNode shiftY = graph.unique(new LeftShiftNode(y, distance)); + LogicNode comparison = unsigned + ? IntegerBelowNode.create(getConstantReflection(), getMetaAccess(), graph.getOptions(), null, shiftX, shiftY, NodeView.DEFAULT) + : IntegerLessThanNode.create(getConstantReflection(), getMetaAccess(), graph.getOptions(), null, shiftX, shiftY, NodeView.DEFAULT); + comparison = graph.addOrUniqueWithInputs(comparison); + ValueNode result = graph.addOrUniqueWithInputs(ConditionalNode.create(comparison, NodeView.DEFAULT)); + ReturnNode returnNode = graph.add(new ReturnNode(result)); + graph.start().setNext(returnNode); + + x.replaceAtUsages(ConstantNode.forIntegerBits(bits, xValue, graph)); + y.replaceAtUsages(ConstantNode.forIntegerBits(bits, yValue, graph)); + createCanonicalizerPhase().apply(graph, getDefaultHighTierContext()); + + boolean expected; + if (bits == Integer.SIZE) { + int shiftedX = (int) xValue << amount; + int shiftedY = (int) yValue << amount; + expected = unsigned ? Integer.compareUnsigned(shiftedX, shiftedY) < 0 : shiftedX < shiftedY; + } else { + long shiftedX = xValue << amount; + long shiftedY = yValue << amount; + expected = unsigned ? Long.compareUnsigned(shiftedX, shiftedY) < 0 : shiftedX < shiftedY; + } + Assert.assertEquals(expected ? 1 : 0, returnNode.result().asJavaConstant().asInt()); + } + + /// Covers both comparison orders and distances on either side of each Java shift mask. + @Test + public void testComparisonCancellation() { + for (int bits : new int[]{Integer.SIZE, Long.SIZE}) { + for (int amount : new int[]{-1, -2, -bits, 0, 1, bits - 1, bits, bits + 1}) { + for (boolean unsigned : new boolean[]{false, true}) { + for (long x = 0; x <= 3; x++) { + for (long y = 0; y <= 3; y++) { + checkComparison(bits, amount, unsigned, x, y); + } + } + } + } + } + } + + /// Supplies an int induction variable with a shift that survives parsing. + public static int intLoop(int limit, int amount) { + int result = 0; + for (int i = 0; i < limit; i++) { + result += i << amount; + } + return result; + } + + /// Supplies a long induction variable with a shift that survives parsing. + public static long longLoop(long limit, int amount) { + long result = 0; + for (long i = 0; i < limit; i++) { + result += i << amount; + } + return result; + } + + /// Checks the scale inferred from the original shift width rather than the host long width. + private void checkLoopScale(String snippet, int amount) { + StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO); + LeftShiftNode shift = graph.getNodes().filter(LeftShiftNode.class).first(); + graph.getParameter(1).replaceAtUsages(ConstantNode.forInt(amount, graph)); + // Queries IV metadata before canonicalization can normalize the injected distance. + LoopsData loops = getDefaultHighTierContext().getLoopsDataProvider().getLoopsData(graph); + Assert.assertEquals(1, loops.loops().size()); + Loop loop = loops.loops().get(0); + InductionVariable iv = loop.getInductionVariables().get(shift); + assertTrue(iv instanceof DerivedScaledInductionVariable); + long expected = snippet.equals("intLoop") ? 1 << amount : 1L << amount; + Assert.assertEquals(expected, ((DerivedScaledInductionVariable) iv).getScale().asJavaConstant().asLong()); + } + + /// Covers int and long scales for negative, masked, and out-of-range distances. + @Test + public void testLoopScale() { + for (int amount : new int[]{-65, -33, -32, -1, 0, 1, 31, 32, 33, 63, 64, 65}) { + checkLoopScale("intLoop", amount); + checkLoopScale("longLoop", amount); + } + } + + /// Checks multiplication conversion using raw distances and the original operand width. + @Test + public void testEquivalentMultiplication() { + for (int bits : new int[]{Integer.SIZE, Long.SIZE}) { + ParameterNode x = new ParameterNode(0, StampPair.createSingle(IntegerStamp.create(bits))); + for (int amount : new int[]{Integer.MIN_VALUE, -65, -33, -32, -1, 0, 1, 31, 32, 33, 63, 64, 65, Integer.MAX_VALUE}) { + LeftShiftNode shift = new LeftShiftNode(x, ConstantNode.forInt(amount)); + MulNode mul = shift.getEquivalentMulNode(); + Assert.assertNotNull(mul); + long expected = bits == Integer.SIZE ? 1 << amount : 1L << amount; + Assert.assertEquals(expected, mul.getY().asJavaConstant().asLong()); + } + } + } + + /// Checks that negation recognizes a sign shift before its distance is canonicalized. + @Test + public void testSignShiftNegation() { + for (int bits : new int[]{Integer.SIZE, Long.SIZE}) { + ParameterNode x = new ParameterNode(0, StampPair.createSingle(IntegerStamp.create(bits))); + for (int amount : new int[]{-1, bits - 1, 2 * bits - 1, Integer.MAX_VALUE}) { + RightShiftNode shift = new RightShiftNode(x, ConstantNode.forInt(amount)); + ValueNode negated = NegateNode.create(shift, NodeView.DEFAULT); + assertTrue(negated instanceof UnsignedRightShiftNode); + Assert.assertSame(x, ((UnsignedRightShiftNode) negated).getX()); + } + } + } +} diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyShiftAmounts.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyShiftAmounts.java new file mode 100644 index 0000000000000..519b504157ba2 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyShiftAmounts.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.core.test; + +import jdk.graal.compiler.nodes.Invoke; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.BinaryNode; +import jdk.graal.compiler.nodes.calc.ShiftNode; +import jdk.graal.compiler.nodes.java.LoadFieldNode; +import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.nodes.type.StampTool; +import jdk.graal.compiler.nodes.util.GraphUtil; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/// Checks that constant distances of known shifts are read through `ShiftNode.getConstantShiftAmount()`. +/// +/// This check follows `getY()` results through local aliases and casts in the parsed graph. It +/// cannot identify shifts hidden behind a generic `BinaryNode` receiver or a separate method. +public class VerifyShiftAmounts extends VerifyPhase { + + @Override + public boolean checkContract() { + return false; + } + + @Override + protected void verify(StructuredGraph graph, CoreProviders context) { + ResolvedJavaType shiftType = context.getMetaAccess().lookupJavaType(ShiftNode.class); + ResolvedJavaType binaryType = context.getMetaAccess().lookupJavaType(BinaryNode.class); + ResolvedJavaType valueType = context.getMetaAccess().lookupJavaType(ValueNode.class); + ResolvedJavaMethod caller = graph.method(); + if (caller.getDeclaringClass().equals(shiftType) && caller.getName().equals("getConstantShiftAmount")) { + // The helper is the single place that reads and masks the raw constant distance. + return; + } + for (MethodCallTargetNode call : graph.getNodes(MethodCallTargetNode.TYPE)) { + ResolvedJavaMethod callee = call.targetMethod(); + if (callee.getDeclaringClass().equals(valueType) && (callee.getName().equals("asJavaConstant") || callee.getName().equals("asConstant"))) { + ValueNode receiver = GraphUtil.unproxify(call.arguments().get(0)); + ValueNode owner = operandOwner(receiver, binaryType); + if (owner != null) { + ResolvedJavaType receiverType = StampTool.typeOrNull(owner); + if (receiverType != null && shiftType.isAssignableFrom(receiverType)) { + throw new VerificationError(call, "Use ShiftNode.getConstantShiftAmount() instead of extracting a raw constant from ShiftNode.getY(); " + + "the distance may not yet have been masked by canonicalization."); + } + } + } + } + } + + /// Finds the binary node supplying its second operand, including an inlined getter. + private static ValueNode operandOwner(ValueNode distance, ResolvedJavaType binaryType) { + if (distance instanceof Invoke invoke && invoke.callTarget() instanceof MethodCallTargetNode getY) { + ResolvedJavaMethod accessor = getY.targetMethod(); + if (accessor.getDeclaringClass().equals(binaryType) && accessor.getName().equals("getY")) { + return getY.arguments().get(0); + } + } else if (distance instanceof LoadFieldNode load && load.field().getDeclaringClass().equals(binaryType) && load.field().getName().equals("y")) { + return load.object(); + } + return null; + } +} diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyShiftAmountsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyShiftAmountsTest.java new file mode 100644 index 0000000000000..8c605f078aa4a --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyShiftAmountsTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.core.test; + +import org.junit.Test; + +import jdk.graal.compiler.core.test.VerifyPhase.VerificationError; +import jdk.graal.compiler.debug.DebugCloseable; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.calc.AddNode; +import jdk.graal.compiler.nodes.calc.LeftShiftNode; +import jdk.graal.compiler.nodes.calc.ShiftNode; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.PrimitiveConstant; + +/// Tests rejection of raw shift constants while allowing the helper and unrelated constants. +public class VerifyShiftAmountsTest extends GraalCompilerTest { + + /// Supplies the direct extraction pattern that originally hid missing masks. + public static int rawDistance(LeftShiftNode shift) { + return shift.getY().asJavaConstant().asInt(); + } + + /// Supplies aliases of both the distance node and its Java constant. + public static int aliasedDistance(ShiftNode shift) { + ValueNode distance = shift.getY(); + JavaConstant constant = distance.asJavaConstant(); + return constant.asInt(); + } + + /// Supplies extraction through the more general constant API and long arithmetic. + public static long primitiveDistance(ShiftNode shift) { + return ((PrimitiveConstant) shift.getY().asConstant()).asLong(); + } + + /// Supplies a shift exposed by a type check on a generic value. + public static int checkedDistance(ValueNode node) { + if (node instanceof ShiftNode shift) { + return shift.getY().asJavaConstant().asInt(); + } + return 0; + } + + /// Supplies a distance read through the supported API. + public static int maskedDistance(ShiftNode shift) { + return shift.getConstantShiftAmount(); + } + + /// Supplies a constant operand that does not have shift semantics. + public static int addConstant(AddNode add) { + return add.getY().asJavaConstant().asInt(); + } + + /// Supplies a constant shifted value, which must not be treated as the distance. + public static long shiftedConstant(ShiftNode shift) { + return shift.getX().asJavaConstant().asLong(); + } + + /// Checks extraction before later optimizations can erase the calls inspected by the verifier. + private void verify(String snippet) { + StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO); + try (DebugCloseable _ = graph.getDebug().disableIntercept()) { + new VerifyShiftAmounts().apply(graph, getDefaultHighTierContext()); + } + } + + @Test(expected = VerificationError.class) + public void testRawDistance() { + verify("rawDistance"); + } + + @Test(expected = VerificationError.class) + public void testAliasedDistance() { + verify("aliasedDistance"); + } + + @Test(expected = VerificationError.class) + public void testPrimitiveDistance() { + verify("primitiveDistance"); + } + + @Test(expected = VerificationError.class) + public void testCheckedDistance() { + verify("checkedDistance"); + } + + /// Checks that unrelated operands do not trigger the verifier. + @Test + public void testAllowedConstants() { + verify("maskedDistance"); + verify("addConstant"); + verify("shiftedConstant"); + } + + /// Checks the exemption for the implementation that applies the mask. + @Test + public void testHelperImplementation() { + StructuredGraph graph = parseEager(getMetaAccess().lookupJavaMethod(getMethod(ShiftNode.class, "getConstantShiftAmount")), StructuredGraph.AllowAssumptions.NO); + new VerifyShiftAmounts().apply(graph, getDefaultHighTierContext()); + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressLoweringByUse.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressLoweringByUse.java index 4a45b0a5ad973..b77320b9e1193 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressLoweringByUse.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64AddressLoweringByUse.java @@ -193,10 +193,10 @@ private boolean improve(AArch64Kind kind, AArch64AddressNode ret) { ZeroExtendNode wordIndex = null; if (scaledIndex instanceof LeftShiftNode) { - ValueNode var = ((LeftShiftNode) scaledIndex).getX(); - ValueNode amount = ((LeftShiftNode) scaledIndex).getY(); - if (amount.isConstant() && var instanceof ZeroExtendNode) { - int s = amount.asJavaConstant().asInt(); + LeftShiftNode shift = (LeftShiftNode) scaledIndex; + ValueNode var = shift.getX(); + if (shift.getY().isConstant() && var instanceof ZeroExtendNode) { + int s = shift.getConstantShiftAmount(); if (s >= 0 && s <= 4) { wordIndex = (ZeroExtendNode) var; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64NodeMatchRules.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64NodeMatchRules.java index c2fd31fbf62fc..67af00f20600c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64NodeMatchRules.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64NodeMatchRules.java @@ -203,15 +203,6 @@ private AllocatableValue moveSp(AllocatableValue value) { return getLIRGeneratorTool().moveSp(value); } - /** - * Clamp shift amounts into range 0 <= shiftamt < size according to JLS. - */ - private static int getClampedShiftAmt(ShiftNode op) { - int clampMask = op.getShiftAmountMask(); - assert clampMask == 63 || clampMask == 31 : clampMask; - return op.getY().asJavaConstant().asInt() & clampMask; - } - protected ComplexMatchResult emitBinaryShift(AArch64ArithmeticOp op, ValueNode value, ShiftNode shift) { AArch64MacroAssembler.ShiftType shiftType = shiftTypeMap.get(shift.getClass()); assert shiftType != null; @@ -223,7 +214,7 @@ protected ComplexMatchResult emitBinaryShift(AArch64ArithmeticOp op, ValueNode v Variable result = gen.newVariable(LIRKind.combine(a, b)); AllocatableValue x = moveSp(gen.asAllocatable(a)); AllocatableValue y = moveSp(gen.asAllocatable(b)); - int shiftAmount = getClampedShiftAmt(shift); + int shiftAmount = shift.getConstantShiftAmount(); gen.append(new AArch64ArithmeticOp.BinaryShiftOp(op, result, x, y, shiftType, shiftAmount)); return result; }; @@ -310,7 +301,7 @@ private ComplexMatchResult emitExtendedAddSubShift(BinaryNode op, ValueNode x, V @MatchRule("(Sub=op x (LeftShift=lshift (ZeroExtend=ext y) Constant))") public ComplexMatchResult mergeSignExtendByShiftIntoAddSub(BinaryNode op, LeftShiftNode lshift, ValueNode ext, ValueNode x, ValueNode y) { assert isNumericInteger(lshift); - int shiftAmt = getClampedShiftAmt(lshift); + int shiftAmt = lshift.getConstantShiftAmount(); if (!isSupportedExtendedAddSubShift((IntegerConvertNode) ext, shiftAmt)) { return null; } @@ -331,7 +322,7 @@ public ComplexMatchResult mergeSignExtendByShiftIntoAddSub(BinaryNode op, LeftSh @MatchRule("(Sub=op x (LeftShift=lshift (And y Constant=constant) Constant))") public ComplexMatchResult mergeShiftDowncastIntoAddSub(BinaryNode op, LeftShiftNode lshift, ConstantNode constant, ValueNode x, ValueNode y) { assert isNumericInteger(lshift, constant); - int shiftAmt = getClampedShiftAmt(lshift); + int shiftAmt = lshift.getConstantShiftAmount(); if (shiftAmt > 4) { return null; } @@ -350,7 +341,7 @@ public ComplexMatchResult mergeShiftDowncastIntoAddSub(BinaryNode op, LeftShiftN @MatchRule("(Add=op x (RightShift=signExt (LeftShift y Constant=shiftConst) Constant=shiftConst))") @MatchRule("(Sub=op x (RightShift=signExt (LeftShift y Constant=shiftConst) Constant=shiftConst))") public ComplexMatchResult mergePairShiftIntoAddSub(BinaryNode op, RightShiftNode signExt, ValueNode x, ValueNode y) { - int signExtendAmt = getClampedShiftAmt(signExt); + int signExtendAmt = signExt.getConstantShiftAmount(); int opSize = op.getStackKind().getBitCount(); assert opSize == 32 || opSize == 64 : opSize; @@ -368,11 +359,11 @@ public ComplexMatchResult mergePairShiftIntoAddSub(BinaryNode op, RightShiftNode @MatchRule("(Add=op x (LeftShift=outerShift (RightShift=signExt (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant))") @MatchRule("(Sub=op x (LeftShift=outerShift (RightShift=signExt (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant))") public ComplexMatchResult mergeShiftedPairShiftIntoAddSub(BinaryNode op, LeftShiftNode outerShift, RightShiftNode signExt, ValueNode x, ValueNode y) { - int shiftAmt = getClampedShiftAmt(outerShift); + int shiftAmt = outerShift.getConstantShiftAmount(); if (shiftAmt > 4) { return null; } - int signExtendAmt = getClampedShiftAmt(signExt); + int signExtendAmt = signExt.getConstantShiftAmount(); int opSize = op.getStackKind().getBitCount(); assert opSize == 32 || opSize == 64 : opSize; @@ -399,7 +390,7 @@ public ComplexMatchResult extendedPointerAddShift(AArch64PointerAddNode addP) { } else { LeftShiftNode shift = (LeftShiftNode) offset; zeroExtend = (ZeroExtendNode) shift.getX(); - shiftAmt = getClampedShiftAmt(shift); + shiftAmt = shift.getConstantShiftAmount(); } if (!isSupportedExtendedAddSubShift(zeroExtend, shiftAmt)) { return null; @@ -444,7 +435,7 @@ private ComplexMatchResult unsignedBitFieldHelper(JavaKind finalOpKind, BinaryNo int maskSize = 64 - Long.numberOfLeadingZeros(mask); int shiftSize = shift.getStackKind().getBitCount(); - int shiftAmt = getClampedShiftAmt((ShiftNode) shift); + int shiftAmt = ((ShiftNode) shift).getConstantShiftAmount(); /* * The width of the insert/extract will be the bits which are not shifted out and/or not * part of the mask. @@ -498,7 +489,7 @@ public ComplexMatchResult signedBitField(LeftShiftNode shift, ValueNode value) { JavaKind kind = shift.getStackKind(); assert kind.getBitCount() == resultBits : Assertions.errorMessage(shift, value, kind); - int lsb = getClampedShiftAmt(shift); + int lsb = shift.getConstantShiftAmount(); /* * Get the min value of the inputBits and post-shift bits (resultBits - lsb) as the bitfield * width. Note if (resultBits-lsb) is smaller than inputBits, the in reality no sign @@ -520,8 +511,8 @@ public ComplexMatchResult bitFieldMove(BinaryNode rshift, LeftShiftNode lshift, JavaKind opKind = rshift.getStackKind(); int opSize = opKind.getBitCount(); - int lshiftAmt = getClampedShiftAmt(lshift); - int rshiftAmt = getClampedShiftAmt((ShiftNode) rshift); + int lshiftAmt = lshift.getConstantShiftAmount(); + int rshiftAmt = ((ShiftNode) rshift).getConstantShiftAmount(); /* * Get the width of the bitField. It will be in the range 1 to 32(64). @@ -569,8 +560,8 @@ public ComplexMatchResult rotationConstant(ValueNode op, ValueNode x, ValueNode assert isNumericInteger(src); assert src.getStackKind() == op.getStackKind() && op.getStackKind() == x.getStackKind() : src + " " + op + " " + x; - int shiftAmt1 = getClampedShiftAmt((ShiftNode) x); - int shiftAmt2 = getClampedShiftAmt((ShiftNode) y); + int shiftAmt1 = ((ShiftNode) x).getConstantShiftAmount(); + int shiftAmt2 = ((ShiftNode) y).getConstantShiftAmount(); if (shiftAmt1 + shiftAmt2 == 0 && op instanceof OrNode) { assert shiftAmt1 == 0 && shiftAmt2 == 0 : shiftAmt1 + " " + shiftAmt2; /* No shift performed: for or operation, this is equivalent to original value */ @@ -686,7 +677,7 @@ public ComplexMatchResult logicShift(BinaryNode binary, ValueNode a, BinaryNode @MatchRule("(Negate (LeftShift=shift a Constant=b))") public ComplexMatchResult negShift(BinaryNode shift, ValueNode a, ConstantNode b) { assert isNumericInteger(a, b); - int shiftAmt = getClampedShiftAmt((ShiftNode) shift); + int shiftAmt = ((ShiftNode) shift).getConstantShiftAmount(); AArch64Assembler.ShiftType shiftType = shiftTypeMap.get(shift.getClass()); return builder -> { AllocatableValue src = moveSp(gen.asAllocatable(operand(a))); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64AddressLowering.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64AddressLowering.java index 7c10a0b7f442a..a16c9340e00b1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64AddressLowering.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64AddressLowering.java @@ -93,7 +93,7 @@ protected boolean improve(StructuredGraph graph, DebugContext debug, AMD64Addres if (ret.getIndex() instanceof LeftShiftNode) { LeftShiftNode shift = (LeftShiftNode) ret.getIndex(); if (shift.getY().isConstant()) { - int amount = ret.getScale().log2 + shift.getY().asJavaConstant().asInt(); + int amount = ret.getScale().log2 + shift.getConstantShiftAmount(); if (AMD64Address.isScaleShiftSupported(amount)) { ret.setIndex(shift.getX()); ret.setScale(Stride.fromLog2(amount)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64NodeMatchRules.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64NodeMatchRules.java index 017e90b8d4412..de4390b964459 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64NodeMatchRules.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64NodeMatchRules.java @@ -584,14 +584,14 @@ public ComplexMatchResult ifLogicCas(IfNode root, CompareNode compare, ValueNode @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))") public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) { - JavaConstant lshiftConst = lshift.getY().asJavaConstant(); - JavaConstant rshiftConst = rshift.getY().asJavaConstant(); - if ((lshift.getShiftAmountMask() & (lshiftConst.asInt() + rshiftConst.asInt())) == 0) { + int lshiftAmount = lshift.getConstantShiftAmount(); + int rshiftAmount = rshift.getConstantShiftAmount(); + if ((lshift.getShiftAmountMask() & (lshiftAmount + rshiftAmount)) == 0) { return builder -> { Value a = operand(lshift.getX()); OperandSize size = OperandSize.get(a.getPlatformKind()); assert size == OperandSize.DWORD || size == OperandSize.QWORD : size; - return getArithmeticLIRGenerator().emitShiftConst(ROL, size, a, lshiftConst); + return getArithmeticLIRGenerator().emitShiftConst(ROL, size, a, JavaConstant.forInt(lshiftAmount)); }; } return null; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java index 7349127108f76..f0efbd87f50f6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerEqualsNode.java @@ -279,8 +279,7 @@ protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider con if (nonConstant instanceof LeftShiftNode) { LeftShiftNode shift = (LeftShiftNode) nonConstant; if (shift.getY().isConstant()) { - int mask = shift.getShiftAmountMask(); - int amount = shift.getY().asJavaConstant().asInt() & mask; + int amount = shift.getConstantShiftAmount(); if (shift.getX().getStackKind() == JavaKind.Int) { return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 >>> amount)); } else { @@ -291,8 +290,7 @@ protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider con } else if (nonConstant instanceof RightShiftNode) { RightShiftNode shift = (RightShiftNode) nonConstant; if (shift.getY().isConstant() && ((IntegerStamp) shift.getX().stamp(view)).isPositive()) { - int mask = shift.getShiftAmountMask(); - int amount = shift.getY().asJavaConstant().asInt() & mask; + int amount = shift.getConstantShiftAmount(); if (shift.getX().getStackKind() == JavaKind.Int) { return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount)); } else { @@ -303,8 +301,7 @@ protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider con } else if (nonConstant instanceof UnsignedRightShiftNode) { UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant; if (shift.getY().isConstant()) { - int mask = shift.getShiftAmountMask(); - int amount = shift.getY().asJavaConstant().asInt() & mask; + int amount = shift.getConstantShiftAmount(); if (shift.getX().getStackKind() == JavaKind.Int) { return new IntegerTestNode(shift.getX(), ConstantNode.forInt(-1 << amount)); } else { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerLowerThanNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerLowerThanNode.java index d0435af718ba8..5dee900202b96 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerLowerThanNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/IntegerLowerThanNode.java @@ -46,7 +46,6 @@ import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.TriState; /** @@ -427,17 +426,16 @@ protected LogicNode canonicalizeCommonArithmetic(ValueNode forX, ValueNode forY, if (forX instanceof LeftShiftNode && forY instanceof LeftShiftNode) { LeftShiftNode leftShiftX = (LeftShiftNode) forX; LeftShiftNode leftShiftY = (LeftShiftNode) forY; - if (leftShiftX.getY() == leftShiftY.getY() && - leftShiftX.getY().isConstant() && leftShiftX.getY().asConstant() instanceof PrimitiveConstant) { - PrimitiveConstant constant = (PrimitiveConstant) leftShiftX.getY().asConstant(); - if (constant.getJavaKind().isNumericInteger()) { - ValueNode v1 = leftShiftX.getX(); - ValueNode v2 = leftShiftY.getX(); - IntegerStamp stamp1 = (IntegerStamp) v1.stamp(view); - IntegerStamp stamp2 = (IntegerStamp) v2.stamp(view); - if (!leftShiftCanOverflow(stamp1, constant.asLong()) && !leftShiftCanOverflow(stamp2, constant.asLong())) { - return create(v1, v2, view); - } + if (leftShiftX.getY() == leftShiftY.getY() && leftShiftX.getY().isJavaConstant()) { + ValueNode v1 = leftShiftX.getX(); + ValueNode v2 = leftShiftY.getX(); + IntegerStamp stamp1 = (IntegerStamp) v1.stamp(view); + IntegerStamp stamp2 = (IntegerStamp) v2.stamp(view); + // Removing the same left shift from both sides of the comparison preserves the + // result only if neither shift overflows for the masked distance. + int shiftAmount = leftShiftX.getConstantShiftAmount(); + if (!leftShiftCanOverflow(stamp1, shiftAmount) && !leftShiftCanOverflow(stamp2, shiftAmount)) { + return create(v1, v2, view); } } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/LeftShiftNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/LeftShiftNode.java index bbdb2f47ddae8..1d6c1af6dbbc3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/LeftShiftNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/LeftShiftNode.java @@ -40,10 +40,7 @@ import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.graal.compiler.vector.nodes.simd.SimdStamp; -import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.PrimitiveConstant; @NodeInfo(shortName = "<<") public final class LeftShiftNode extends ShiftNode { @@ -106,28 +103,17 @@ public boolean tryReplaceWithMulNode() { * @see #tryReplaceWithMulNode() */ public MulNode getEquivalentMulNode() { - if (this.getY().isConstant() && stamp(NodeView.DEFAULT) instanceof IntegerStamp selfStamp) { - Constant c = getY().asConstant(); - if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { - IntegerStamp xStamp = (IntegerStamp) getX().stamp(NodeView.DEFAULT); - if (xStamp.getBits() == selfStamp.getBits()) { - long shiftAmount = ((PrimitiveConstant) c).asLong(); - /* - * The shift below is done in long arithmetic, but if the underlying values are - * ints (or smaller), we must shift according to int semantics. So mask - * accordingly. - */ - if (selfStamp.getBits() <= Integer.SIZE) { - shiftAmount &= CodeUtil.mask(CodeUtil.log2(Integer.SIZE)); - } - /* - * If shiftAmount == 63, this will give Long.MIN_VALUE, which is negative but - * still correct as the multiplier. We have to do a shift here, computing this - * as (long) Math.pow(2, 63) would round to the wrong value. - */ - long multiplier = 1L << shiftAmount; - return new MulNode(getX(), ConstantNode.forIntegerStamp(xStamp, multiplier)); - } + if (getY().isJavaConstant() && stamp(NodeView.DEFAULT) instanceof IntegerStamp selfStamp) { + IntegerStamp xStamp = (IntegerStamp) getX().stamp(NodeView.DEFAULT); + if (xStamp.getBits() == selfStamp.getBits()) { + int shiftAmount = getConstantShiftAmount(); + /* + * If shiftAmount == 63, this will give Long.MIN_VALUE, which is negative but + * still correct as the multiplier. We have to do a shift here, computing this + * as (long) Math.pow(2, 63) would round to the wrong value. + */ + long multiplier = 1L << shiftAmount; + return new MulNode(getX(), ConstantNode.forIntegerStamp(xStamp, multiplier)); } } return null; @@ -150,7 +136,7 @@ private static ValueNode canonical(LeftShiftNode leftShiftNode, ArithmeticOpTabl if (forX instanceof ShiftNode) { ShiftNode other = (ShiftNode) forX; if (other.getY().isConstant()) { - int otherAmount = other.getY().asJavaConstant().asInt() & mask; + int otherAmount = other.getConstantShiftAmount(); if (other instanceof LeftShiftNode) { int total = amount + otherAmount; if (total != (total & mask)) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java index b0777866a8fe9..9b9fb4923728d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java @@ -104,7 +104,7 @@ protected static ValueNode findSynonym(ValueNode forValue, NodeView view) { RightShiftNode shift = (RightShiftNode) forValue; Stamp stamp = forValue.stamp(view); if (shift.getY().isConstant() && stamp instanceof IntegerStamp) { - int shiftAmount = shift.getY().asJavaConstant().asInt(); + int shiftAmount = shift.getConstantShiftAmount(); if (shiftAmount == ((IntegerStamp) stamp).getBits() - 1) { return UnsignedRightShiftNode.create(shift.getX(), shift.getY(), view); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/RightShiftNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/RightShiftNode.java index 8f58f4ef276e3..b292fa831104a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/RightShiftNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/RightShiftNode.java @@ -124,7 +124,7 @@ private static ValueNode canonical(RightShiftNode rightShiftNode, ArithmeticOpTa if (forX instanceof ShiftNode) { ShiftNode other = (ShiftNode) forX; if (other.getY().isConstant()) { - int otherAmount = other.getY().asJavaConstant().asInt() & mask; + int otherAmount = other.getConstantShiftAmount(); if (other instanceof RightShiftNode) { int total = amount + otherAmount; if (total != (total & mask)) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/ShiftNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/ShiftNode.java index f1c166c25813e..72e738aa91acd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/ShiftNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/ShiftNode.java @@ -130,6 +130,23 @@ public int getShiftAmountMask() { return getArithmeticOp().getShiftAmountMask(stamp(NodeView.DEFAULT)); } + /// Gets the constant shift distance with the implicit mask of this operation applied, as specified + /// in [JLS 15.19 (Shift Operators)](https://docs.oracle.com/javase/specs/jls/se25/html/jls-15.html#jls-15.19). + /// + /// A graph need not be fully canonicalized, so `getY()` can contain a negative or + /// oversized constant. Code that interprets that constant must use this method rather than + /// read its raw value. For example, an int shift by -1 has distance 31, and an int shift by + /// 33 has distance 1 even when the caller performs its calculation in long arithmetic. + /// For SIMD shifts by a scalar constant, this method masks the distance according to the width + /// of each vector element. + /// + /// @return the masked distance + /// @throws AssertionError if `getY()` is not a Java constant + public final int getConstantShiftAmount() { + assert getY().isJavaConstant() : getY(); + return getY().asJavaConstant().asInt() & getShiftAmountMask(); + } + @Override public boolean isNarrowable(int resultBits) { assert CodeUtil.isPowerOf2(resultBits); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/UnsignedRightShiftNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/UnsignedRightShiftNode.java index e1485176ec47e..d446525444bf4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/UnsignedRightShiftNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/UnsignedRightShiftNode.java @@ -125,7 +125,7 @@ private static ValueNode canonical(UnsignedRightShiftNode node, ArithmeticOpTabl if (bits >= Integer.SIZE && forX instanceof ShiftNode) { ShiftNode other = (ShiftNode) forX; if (other.getY().isConstant()) { - int otherAmount = other.getY().asJavaConstant().asInt() & mask; + int otherAmount = other.getConstantShiftAmount(); if (other instanceof UnsignedRightShiftNode) { int total = amount + otherAmount; if (total != (total & mask)) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/Loop.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/Loop.java index e7ad77568c191..791c18fb59e02 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/Loop.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/Loop.java @@ -761,7 +761,8 @@ private static ValueNode calcScaleTo(Loop loop, ValueNode op, ValueNode base) { if (op instanceof LeftShiftNode) { LeftShiftNode shift = (LeftShiftNode) op; if (shift.getX() == base && shift.getY().isConstant()) { - return ConstantNode.forIntegerStamp(base.stamp(NodeView.DEFAULT), 1L << shift.getY().asJavaConstant().asInt(), base.graph()); + int shiftAmount = shift.getConstantShiftAmount(); + return ConstantNode.forIntegerStamp(base.stamp(NodeView.DEFAULT), 1L << shiftAmount, base.graph()); } } return null; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/lir/amd64/AMD64VectorNodeMatchRules.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/lir/amd64/AMD64VectorNodeMatchRules.java index c321fcf907e92..9a1ce70dc56a1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/lir/amd64/AMD64VectorNodeMatchRules.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/lir/amd64/AMD64VectorNodeMatchRules.java @@ -464,12 +464,12 @@ private static boolean isRotateElementSizeSupported(SimdStamp simdStamp) { @Override public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) { if (lshift.stamp(NodeView.DEFAULT) instanceof SimdStamp simdStamp) { - JavaConstant lshiftConst = lshift.getY().asJavaConstant(); - JavaConstant rshiftConst = rshift.getY().asJavaConstant(); - if (supportsVectorRotate() && isRotateElementSizeSupported(simdStamp) && (lshift.getShiftAmountMask() & (lshiftConst.asInt() + rshiftConst.asInt())) == 0) { + int lshiftAmount = lshift.getConstantShiftAmount(); + int rshiftAmount = rshift.getConstantShiftAmount(); + if (supportsVectorRotate() && isRotateElementSizeSupported(simdStamp) && (lshift.getShiftAmountMask() & (lshiftAmount + rshiftAmount)) == 0) { return builder -> { Value input = operand(lshift.getX()); - Value rotateCount = new ConstantValue(LIRKind.value(AMD64Kind.DWORD), lshiftConst); + Value rotateCount = new ConstantValue(LIRKind.value(AMD64Kind.DWORD), JavaConstant.forInt(lshiftAmount)); return getArithmeticLIRGenerator().emitRol(input, rotateCount); }; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/nodes/op/VectorHashStepNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/nodes/op/VectorHashStepNode.java index 4492f5f373ec8..00736450541fe 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/nodes/op/VectorHashStepNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/nodes/op/VectorHashStepNode.java @@ -369,7 +369,12 @@ public static MultiplicationDescriptor find(AccumulatorNode accumulator) { long mulConst; if (mulCandidate instanceof LeftShiftNode || mulCandidate.getX() == accumulator) { if (mulCandidate.getY().isJavaConstant() && mulCandidate.getY().stamp(NodeView.DEFAULT).isIntegerStamp()) { - mulConst = mulCandidate.getY().asJavaConstant().asLong(); + if (mulCandidate instanceof LeftShiftNode shift) { + // The multiplier is computed in long arithmetic even for an int shift. + mulConst = shift.getConstantShiftAmount(); + } else { + mulConst = mulCandidate.getY().asJavaConstant().asLong(); + } } else { // other operand of multiplication or shift needs to be a constant return NO_HASH; @@ -413,7 +418,7 @@ public static MultiplicationDescriptor find(AccumulatorNode accumulator) { * \ / * Add */ - mulConst += 1L << ((LeftShiftNode) other).getY().asJavaConstant().asLong(); + mulConst += 1L << ((LeftShiftNode) other).getConstantShiftAmount(); } else { break; } @@ -439,9 +444,9 @@ public static MultiplicationDescriptor find(AccumulatorNode accumulator) { * Sub */ if (sub.getX().equals(mulCandidate)) { - mulConst = mulConst - (1L << shift.getY().asJavaConstant().asLong()); + mulConst = mulConst - (1L << shift.getConstantShiftAmount()); } else { - mulConst = (1L << shift.getY().asJavaConstant().asLong()) - mulConst; + mulConst = (1L << shift.getConstantShiftAmount()) - mulConst; } } else { break; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/phases/amd64/AMD64VectorLoweringPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/phases/amd64/AMD64VectorLoweringPhase.java index 167bbf77d570b..123e002652b4c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/phases/amd64/AMD64VectorLoweringPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/vector/phases/amd64/AMD64VectorLoweringPhase.java @@ -549,7 +549,7 @@ private static void lowerVectorShift(ShiftNode node, VectorAMD64 vectorArch) * vector simplifications and canonicalization turned into (x << 1). Legalize it. We * must use repeated addition because multiply on bytes isn't supported either. */ - int remainingShift = node.getY().asJavaConstant().asInt(); + int remainingShift = node.getConstantShiftAmount(); ValueNode replacement = node.getX(); while (remainingShift-- > 0) { replacement = graph.unique(new AddNode(replacement, replacement));