@@ -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+
22712364Node* 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
0 commit comments