Skip to content

Commit 45cc515

Browse files
erifanXiaohong Gong
authored andcommitted
8354242: VectorAPI: combine vector not operation with compare
Reviewed-by: epeter, jbhateja, xgong
1 parent c2c44a0 commit 45cc515

File tree

7 files changed

+1635
-1
lines changed

7 files changed

+1635
-1
lines changed

src/hotspot/share/opto/node.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,9 @@ bool Node::has_special_unique_user() const {
12161216
} else if ((is_IfFalse() || is_IfTrue()) && n->is_If()) {
12171217
// See IfNode::fold_compares
12181218
return true;
1219+
} else if (n->Opcode() == Op_XorV || n->Opcode() == Op_XorVMask) {
1220+
// Condition for XorVMask(VectorMaskCmp(x,y,cond), MaskAll(true)) ==> VectorMaskCmp(x,y,ncond)
1221+
return true;
12191222
} else {
12201223
return false;
12211224
}

src/hotspot/share/opto/subnode.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,9 @@ struct BoolTest {
328328
// a simple char array where each element is the ASCII version of a 'mask'
329329
// enum from above.
330330
mask commute( ) const { return mask("032147658"[_test]-'0'); }
331-
mask negate( ) const { return mask(_test^4); }
331+
mask negate( ) const { return negate_mask(_test); }
332+
// Return the negative mask for the given mask, for both signed and unsigned comparison.
333+
static mask negate_mask(mask btm) { return mask(btm ^ 4); }
332334
bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le || _test == BoolTest::overflow); }
333335
bool is_less( ) const { return _test == BoolTest::lt || _test == BoolTest::le; }
334336
bool is_greater( ) const { return _test == BoolTest::gt || _test == BoolTest::ge; }

src/hotspot/share/opto/vectornode.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2268,6 +2268,99 @@ Node* OrVNode::Identity(PhaseGVN* phase) {
22682268
return redundant_logical_identity(this);
22692269
}
22702270

2271+
// Returns whether (XorV (VectorMaskCmp) -1) can be optimized by negating the
2272+
// comparison operation.
2273+
bool VectorMaskCmpNode::predicate_can_be_negated() {
2274+
switch (_predicate) {
2275+
case BoolTest::eq:
2276+
case BoolTest::ne:
2277+
// eq and ne also apply to floating-point special values like NaN and infinities.
2278+
return true;
2279+
case BoolTest::le:
2280+
case BoolTest::ge:
2281+
case BoolTest::lt:
2282+
case BoolTest::gt:
2283+
case BoolTest::ule:
2284+
case BoolTest::uge:
2285+
case BoolTest::ult:
2286+
case BoolTest::ugt: {
2287+
BasicType bt = vect_type()->element_basic_type();
2288+
// For float and double, we don't know if either comparison operand is a
2289+
// NaN, NaN {le|ge|lt|gt} anything is false, resulting in inconsistent
2290+
// results before and after negation.
2291+
return is_integral_type(bt);
2292+
}
2293+
default:
2294+
return false;
2295+
}
2296+
}
2297+
2298+
// This function transforms the following patterns:
2299+
//
2300+
// For integer types:
2301+
// (XorV (VectorMaskCmp src1 src2 cond) (Replicate -1))
2302+
// => (VectorMaskCmp src1 src2 ncond)
2303+
// (XorVMask (VectorMaskCmp src1 src2 cond) (MaskAll m1))
2304+
// => (VectorMaskCmp src1 src2 ncond)
2305+
// (XorV (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (Replicate -1))
2306+
// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond))
2307+
// (XorVMask (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (MaskAll m1))
2308+
// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond))
2309+
// cond can be eq, ne, le, ge, lt, gt, ule, uge, ult and ugt.
2310+
// ncond is the negative comparison of cond.
2311+
//
2312+
// For float and double types:
2313+
// (XorV (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (Replicate -1))
2314+
// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond))
2315+
// (XorVMask (VectorMaskCast (VectorMaskCmp src1 src2 cond)) (MaskAll m1))
2316+
// => (VectorMaskCast (VectorMaskCmp src1 src2 ncond))
2317+
// cond can be eq or ne.
2318+
Node* XorVNode::Ideal_XorV_VectorMaskCmp(PhaseGVN* phase, bool can_reshape) {
2319+
Node* in1 = in(1);
2320+
Node* in2 = in(2);
2321+
// Transformations for predicated vectors are not supported for now.
2322+
if (is_predicated_vector() ||
2323+
in1->is_predicated_vector() ||
2324+
in2->is_predicated_vector()) {
2325+
return nullptr;
2326+
}
2327+
2328+
// XorV/XorVMask is commutative, swap VectorMaskCmp/VectorMaskCast to in1.
2329+
if (VectorNode::is_all_ones_vector(in1)) {
2330+
swap(in1, in2);
2331+
}
2332+
2333+
bool with_vector_mask_cast = false;
2334+
// Required conditions:
2335+
// 1. VectorMaskCast and VectorMaskCmp should only have a single use,
2336+
// otherwise the optimization may be unprofitable.
2337+
// 2. The predicate of VectorMaskCmp should be negatable.
2338+
// 3. The second input should be an all true vector mask.
2339+
if (in1->Opcode() == Op_VectorMaskCast) {
2340+
if (in1->outcnt() != 1) {
2341+
return nullptr;
2342+
}
2343+
with_vector_mask_cast = true;
2344+
in1 = in1->in(1);
2345+
}
2346+
if (in1->Opcode() != Op_VectorMaskCmp ||
2347+
in1->outcnt() != 1 ||
2348+
!in1->as_VectorMaskCmp()->predicate_can_be_negated() ||
2349+
!VectorNode::is_all_ones_vector(in2)) {
2350+
return nullptr;
2351+
}
2352+
2353+
BoolTest::mask neg_cond = BoolTest::negate_mask((in1->as_VectorMaskCmp())->get_predicate());
2354+
ConINode* predicate_node = phase->intcon(neg_cond);
2355+
const TypeVect* vt = in1->as_Vector()->vect_type();
2356+
Node* res = new VectorMaskCmpNode(neg_cond, in1->in(1), in1->in(2), predicate_node, vt);
2357+
if (with_vector_mask_cast) {
2358+
// We optimized out a VectorMaskCast, regenerate one to ensure type correctness.
2359+
res = new VectorMaskCastNode(phase->transform(res), vect_type());
2360+
}
2361+
return res;
2362+
}
2363+
22712364
Node* XorVNode::Ideal(PhaseGVN* phase, bool can_reshape) {
22722365
// (XorV src src) => (Replicate zero)
22732366
// (XorVMask src src) => (MaskAll zero)
@@ -2281,6 +2374,11 @@ Node* XorVNode::Ideal(PhaseGVN* phase, bool can_reshape) {
22812374
Node* zero = phase->transform(phase->zerocon(bt));
22822375
return VectorNode::scalar2vector(zero, length(), bt, bottom_type()->isa_vectmask() != nullptr);
22832376
}
2377+
2378+
Node* res = Ideal_XorV_VectorMaskCmp(phase, can_reshape);
2379+
if (res != nullptr) {
2380+
return res;
2381+
}
22842382
return VectorNode::Ideal(phase, can_reshape);
22852383
}
22862384

src/hotspot/share/opto/vectornode.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ class XorVNode : public VectorNode {
10131013
XorVNode(Node* in1, Node* in2, const TypeVect* vt) : VectorNode(in1,in2,vt) {}
10141014
virtual int Opcode() const;
10151015
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
1016+
Node* Ideal_XorV_VectorMaskCmp(PhaseGVN* phase, bool can_reshape);
10161017
};
10171018

10181019
//------------------------------XorReductionVNode--------------------------------------
@@ -1676,6 +1677,7 @@ class VectorMaskCmpNode : public VectorNode {
16761677
virtual bool cmp( const Node &n ) const {
16771678
return VectorNode::cmp(n) && _predicate == ((VectorMaskCmpNode&)n)._predicate;
16781679
}
1680+
bool predicate_can_be_negated();
16791681
BoolTest::mask get_predicate() { return _predicate; }
16801682
#ifndef PRODUCT
16811683
virtual void dump_spec(outputStream *st) const;

test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,11 @@ public class IRNode {
22952295
vectorNode(VECTOR_MASK_CMP_D, "VectorMaskCmp", TYPE_DOUBLE);
22962296
}
22972297

2298+
public static final String VECTOR_MASK_CMP = PREFIX + "VECTOR_MASK_CMP" + POSTFIX;
2299+
static {
2300+
beforeMatchingNameRegex(VECTOR_MASK_CMP, "VectorMaskCmp");
2301+
}
2302+
22982303
public static final String VECTOR_CAST_B2S = VECTOR_PREFIX + "VECTOR_CAST_B2S" + POSTFIX;
22992304
static {
23002305
vectorNode(VECTOR_CAST_B2S, "VectorCastB2X", TYPE_SHORT);
@@ -2705,6 +2710,11 @@ public class IRNode {
27052710
vectorNode(XOR_VL, "XorV", TYPE_LONG);
27062711
}
27072712

2713+
public static final String XOR_V = PREFIX + "XOR_V" + POSTFIX;
2714+
static {
2715+
beforeMatchingNameRegex(XOR_V, "XorV");
2716+
}
2717+
27082718
public static final String XOR_V_MASK = PREFIX + "XOR_V_MASK" + POSTFIX;
27092719
static {
27102720
beforeMatchingNameRegex(XOR_V_MASK, "XorVMask");

0 commit comments

Comments
 (0)