Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions src/hotspot/share/opto/vectornode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,25 @@ Node* VectorNode::Ideal(PhaseGVN* phase, bool can_reshape) {
return nullptr;
}

// Traverses a chain of VectorMaskCast and returns the first non VectorMaskCast node.
//
// Due to the unique nature of vector masks, for specific IR patterns,
// VectorMaskCast does not affect the output results. For example:
// (VectorStoreMask (VectorMaskCast ... (VectorLoadMask x))) => (x)
// x remains to be a bool vector with no changes.
// This function can be used to eliminate the VectorMaskCast in such patterns.
Node* VectorNode::uncast_mask(Node* n) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be a static method instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's already a static method. See https://github.com/openjdk/jdk/pull/28313/files#diff-ba9e2d10a50a01316946660ec9f68321eb864fd9c815616c10abbec39360efe5R141

Or you mean a static method limited to this file ? If so, I prefer not, it may be used at other places. Thanks~

while (n->Opcode() == Op_VectorMaskCast) {
Node* in1 = n->in(1);
if (!in1->isa_Vector()) {
break;
}
assert(n->as_Vector()->length() == in1->as_Vector()->length(), "vector length must match");
n = in1;
}
return n;
}

// Return initial Pack node. Additional operands added with add_opd() calls.
PackNode* PackNode::make(Node* s, uint vlen, BasicType bt) {
const TypeVect* vt = TypeVect::make(bt, vlen);
Expand Down Expand Up @@ -1468,10 +1487,11 @@ Node* VectorLoadMaskNode::Identity(PhaseGVN* phase) {

Node* VectorStoreMaskNode::Identity(PhaseGVN* phase) {
// Identity transformation on boolean vectors.
// VectorStoreMask (VectorLoadMask bv) elem_size ==> bv
// VectorStoreMask (VectorMaskCast ... VectorLoadMask bv) elem_size ==> bv
// vector[n]{bool} => vector[n]{t} => vector[n]{bool}
if (in(1)->Opcode() == Op_VectorLoadMask) {
return in(1)->in(1);
Node* in1 = VectorNode::uncast_mask(in(1));
if (in1->Opcode() == Op_VectorLoadMask && length() == in1->as_Vector()->length()) {
return in1->in(1);
}
return this;
}
Expand Down Expand Up @@ -1901,11 +1921,12 @@ Node* VectorMaskOpNode::Ideal(PhaseGVN* phase, bool can_reshape) {
}

Node* VectorMaskCastNode::Identity(PhaseGVN* phase) {
Node* in1 = in(1);
// VectorMaskCast (VectorMaskCast x) => x
if (in1->Opcode() == Op_VectorMaskCast &&
vect_type()->eq(in1->in(1)->bottom_type())) {
return in1->in(1);
// (VectorMaskCast (VectorMaskCast ... x)) => (x)
// If the types of the input and output nodes in a VectorMaskCast chain are
// exactly the same, the intermediate VectorMaskCast nodes can be eliminated.
Node* n = VectorNode::uncast_mask(this);
if (vect_type()->eq(n->bottom_type())) {
return n;
}
return this;
}
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/opto/vectornode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class VectorNode : public TypeNode {
static bool is_scalar_op_that_returns_int_but_vector_op_returns_long(int opc);
static bool is_reinterpret_opcode(int opc);

static Node* uncast_mask(Node* n);

static void trace_new_vector(Node* n, const char* context) {
#ifdef ASSERT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@

/*
* @test
* @bug 8356760
* @bug 8356760 8370863
* @library /test/lib /
* @summary Optimize VectorMask.fromLong for all-true/all-false cases
* @summary test VectorMaskCast Identity() optimizations
* @modules jdk.incubator.vector
*
* @run driver compiler.vectorapi.VectorMaskCastIdentityTest
Expand All @@ -48,71 +48,82 @@ public class VectorMaskCastIdentityTest {
}
}

@Test
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 2" }, applyIfCPUFeatureOr = {"asimd", "true"})
public static int testTwoCastToDifferentType() {
// The types before and after the two casts are not the same, so the cast cannot be eliminated.
VectorMask<Float> mFloat64 = VectorMask.fromArray(FloatVector.SPECIES_64, mr, 0);
VectorMask<Double> mDouble128 = mFloat64.cast(DoubleVector.SPECIES_128);
VectorMask<Integer> mInt64 = mDouble128.cast(IntVector.SPECIES_64);
return mInt64.trueCount();
}

@Run(test = "testTwoCastToDifferentType")
public static void testTwoCastToDifferentType_runner() {
int count = testTwoCastToDifferentType();
VectorMask<Float> mFloat64 = VectorMask.fromArray(FloatVector.SPECIES_64, mr, 0);
Asserts.assertEquals(count, mFloat64.trueCount());
}
// The types before and after the cast sequence are the same,
// so the casts will be eliminated.

@Test
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 2" }, applyIfCPUFeatureOr = {"avx2", "true"})
public static int testTwoCastToDifferentType2() {
// The types before and after the two casts are not the same, so the cast cannot be eliminated.
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 0" },
applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true" },
applyIf = { "MaxVectorSize", ">= 16" })
public static int testOneCastToSameType() {
VectorMask<Integer> mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
VectorMask<Double> mDouble256 = mInt128.cast(DoubleVector.SPECIES_256);
VectorMask<Short> mShort64 = mDouble256.cast(ShortVector.SPECIES_64);
return mShort64.trueCount();
mInt128 = mInt128.cast(IntVector.SPECIES_128);
// Insert a not() to prevent the casts being optimized by the optimization:
// (VectorStoreMask (VectorMaskCast ... (VectorLoadMask x))) => x
return mInt128.not().trueCount();
}

@Run(test = "testTwoCastToDifferentType2")
public static void testTwoCastToDifferentType2_runner() {
int count = testTwoCastToDifferentType2();
@Run(test = "testOneCastToSameType")
public static void testOneCastToSameType_runner() {
int count = testOneCastToSameType();
VectorMask<Integer> mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
Asserts.assertEquals(count, mInt128.trueCount());
Asserts.assertEquals(count, mInt128.not().trueCount());
}

@Test
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 0" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"})
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 0" },
applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true" },
applyIf = { "MaxVectorSize", ">= 16" })
public static int testTwoCastToSameType() {
// The types before and after the two casts are the same, so the cast will be eliminated.
VectorMask<Integer> mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
VectorMask<Float> mFloat128 = mInt128.cast(FloatVector.SPECIES_128);
VectorMask<Integer> mInt128_2 = mFloat128.cast(IntVector.SPECIES_128);
return mInt128_2.trueCount();
return mInt128_2.not().trueCount();
}

@Run(test = "testTwoCastToSameType")
public static void testTwoCastToSameType_runner() {
int count = testTwoCastToSameType();
VectorMask<Integer> mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
Asserts.assertEquals(count, mInt128.trueCount());
Asserts.assertEquals(count, mInt128.not().trueCount());
}

// The types before and after the cast sequence are different,
// so the casts will not be eliminated.

@Test
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"})
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 1" },
applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true" },
applyIf = { "MaxVectorSize", ">= 16" })
public static int testOneCastToDifferentType() {
// The types before and after the only cast are different, the cast will not be eliminated.
VectorMask<Float> mFloat128 = VectorMask.fromArray(FloatVector.SPECIES_128, mr, 0).not();
VectorMask<Integer> mInt128 = mFloat128.cast(IntVector.SPECIES_128);
return mInt128.trueCount();
VectorMask<Integer> mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
VectorMask<Short> mShort64 = mInt128.cast(ShortVector.SPECIES_64);
return mShort64.not().trueCount();
}

@Run(test = "testOneCastToDifferentType")
public static void testOneCastToDifferentType_runner() {
int count = testOneCastToDifferentType();
VectorMask<Float> mInt128 = VectorMask.fromArray(FloatVector.SPECIES_128, mr, 0).not();
Asserts.assertEquals(count, mInt128.trueCount());
VectorMask<Integer> mInt128 = VectorMask.fromArray(IntVector.SPECIES_128, mr, 0);
Asserts.assertEquals(count, mInt128.not().trueCount());
}

@Test
@IR(counts = { IRNode.VECTOR_MASK_CAST, "= 2" },
applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true" },
applyIf = { "MaxVectorSize", ">= 16" })
public static int testTwoCastToDifferentType() {
VectorMask<Short> mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mr, 0);
VectorMask<Float> mFloat128 = mShort64.cast(FloatVector.SPECIES_128);
VectorMask<Integer> mInt128 = mFloat128.cast(IntVector.SPECIES_128);
return mInt128.not().trueCount();
}

@Run(test = "testTwoCastToDifferentType")
public static void testTwoCastToDifferentType_runner() {
int count = testTwoCastToDifferentType();
VectorMask<Short> mShort64 = VectorMask.fromArray(ShortVector.SPECIES_64, mr, 0);
Asserts.assertEquals(count, mShort64.not().trueCount());
}

public static void main(String[] args) {
Expand Down
Loading