diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index ebacde2f5d6..d1b8b89b0b3 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -1344,6 +1344,14 @@ Node* VectorNode::reassociate_vector_operation(PhaseGVN* phase) { return nullptr; } + // Reassociation is beneficial if transformed node with replicate inputs can + // subsequently be collapsed by push_through_replicate into Replicate(ScalarOp(..)). + // That folding needs a scalar opcode for this operation/element type. + // Safety check to ensure we skip useless/redundant reassociations. + if (scalar_opcode(Opcode(), vect_type()->element_basic_type()) == 0) { + return nullptr; + } + Node* in1 = in(1); Node* in2 = in(2); if (in2->Opcode() == Op_Replicate && in1->Opcode() == Opcode()) { diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorReassociations.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorReassociations.java index c6a11627215..1fc1c6ff799 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorReassociations.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorReassociations.java @@ -23,7 +23,8 @@ /* * @test - * @bug 8358521 + * @bug 8358521 8385833 + * @key randomness * @summary Test reassociation of broadcasted inputs across vector operations * @modules jdk.incubator.vector * @library /test/lib / @@ -32,7 +33,10 @@ package compiler.vectorapi; +import compiler.lib.generators.Generator; +import compiler.lib.generators.Generators; import compiler.lib.ir_framework.*; +import compiler.lib.verify.*; import jdk.incubator.vector.*; import java.util.stream.IntStream; @@ -602,4 +606,56 @@ public class TestVectorReassociations { ByteVector.broadcast(BSP, bb)) .intoArray(byteOut, 0); } + + private static final Generators RD = Generators.G; + + static int uA, uB, uC; + + static { + Generator ig = RD.ints(); + uA = ig.next(); uB = ig.next(); uC = ig.next(); + } + + static int[] umaxIntOut = new int[ISP.length()]; + static int[] uminIntOut = new int[ISP.length()]; + + // UMAX(UMAX(bcast(uA), bcast(uB)), bcast(uC)). + @Test + @IR(counts = { IRNode.UMAX_VI, " >0 " }, + applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"}) + @Warmup(value = 10000) + static void test_int_umax_all_broadcast() { + IntVector.broadcast(ISP, uA) + .lanewise(VectorOperators.UMAX, uB) + .lanewise(VectorOperators.UMAX, uC) + .intoArray(umaxIntOut, 0); + } + + @Check(test = "test_int_umax_all_broadcast") + static void check_int_umax_all_broadcast() { + int e = VectorMath.maxUnsigned(VectorMath.maxUnsigned(uA, uB), uC); + for (int v : umaxIntOut) { + Verify.checkEQ(v, e); + } + } + + // UMIN(UMIN(bcast(uA), bcast(uB)), bcast(uC)). + @Test + @IR(counts = { IRNode.UMIN_VI, " >0 " }, + applyIfCPUFeatureOr = {"avx", "true", "rvv", "true"}) + @Warmup(value = 10000) + static void test_int_umin_all_broadcast() { + IntVector.broadcast(ISP, uA) + .lanewise(VectorOperators.UMIN, uB) + .lanewise(VectorOperators.UMIN, uC) + .intoArray(uminIntOut, 0); + } + + @Check(test = "test_int_umin_all_broadcast") + static void check_int_umin_all_broadcast() { + int e = VectorMath.minUnsigned(VectorMath.minUnsigned(uA, uB), uC); + for (int v : uminIntOut) { + Verify.checkEQ(v, e); + } + } }