[CodeGen] Support folds of not(cmp(cc, ...)) -> cmp(!cc, ...) for scalable vectors

I have updated TargetLowering::isConstTrueVal to also consider
SPLAT_VECTOR nodes with constant integer operands. This allows the
optimisation to also work for targets that support scalable vectors.

Differential Revision: https://reviews.llvm.org/D117210
This commit is contained in:
David Sherwood 2022-01-13 11:07:54 +00:00
parent a24cc48bc6
commit daa80339df
6 changed files with 130 additions and 26 deletions

View File

@ -3682,11 +3682,11 @@ public:
/// Return if the N is a constant or constant vector equal to the true value /// Return if the N is a constant or constant vector equal to the true value
/// from getBooleanContents(). /// from getBooleanContents().
bool isConstTrueVal(const SDNode *N) const; bool isConstTrueVal(SDValue N) const;
/// Return if the N is a constant or constant vector equal to the false value /// Return if the N is a constant or constant vector equal to the false value
/// from getBooleanContents(). /// from getBooleanContents().
bool isConstFalseVal(const SDNode *N) const; bool isConstFalseVal(SDValue N) const;
/// Return if \p N is a True value when extended to \p VT. /// Return if \p N is a True value when extended to \p VT.
bool isExtendedTrueVal(const ConstantSDNode *N, EVT VT, bool SExt) const; bool isExtendedTrueVal(const ConstantSDNode *N, EVT VT, bool SExt) const;

View File

@ -906,9 +906,8 @@ bool DAGCombiner::isSetCCEquivalent(SDValue N, SDValue &LHS, SDValue &RHS,
return true; return true;
} }
if (N.getOpcode() != ISD::SELECT_CC || if (N.getOpcode() != ISD::SELECT_CC || !TLI.isConstTrueVal(N.getOperand(2)) ||
!TLI.isConstTrueVal(N.getOperand(2).getNode()) || !TLI.isConstFalseVal(N.getOperand(3)))
!TLI.isConstFalseVal(N.getOperand(3).getNode()))
return false; return false;
if (TLI.getBooleanContents(N.getValueType()) == if (TLI.getBooleanContents(N.getValueType()) ==
@ -8035,8 +8034,8 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
// fold !(x cc y) -> (x !cc y) // fold !(x cc y) -> (x !cc y)
unsigned N0Opcode = N0.getOpcode(); unsigned N0Opcode = N0.getOpcode();
SDValue LHS, RHS, CC; SDValue LHS, RHS, CC;
if (TLI.isConstTrueVal(N1.getNode()) && if (TLI.isConstTrueVal(N1) &&
isSetCCEquivalent(N0, LHS, RHS, CC, /*MatchStrict*/true)) { isSetCCEquivalent(N0, LHS, RHS, CC, /*MatchStrict*/ true)) {
ISD::CondCode NotCC = ISD::getSetCCInverse(cast<CondCodeSDNode>(CC)->get(), ISD::CondCode NotCC = ISD::getSetCCInverse(cast<CondCodeSDNode>(CC)->get(),
LHS.getValueType()); LHS.getValueType());
if (!LegalOperations || if (!LegalOperations ||

View File

@ -3194,29 +3194,25 @@ bool TargetLowering::isSplatValueForTargetNode(SDValue Op,
// FIXME: Ideally, this would use ISD::isConstantSplatVector(), but that must // FIXME: Ideally, this would use ISD::isConstantSplatVector(), but that must
// work with truncating build vectors and vectors with elements of less than // work with truncating build vectors and vectors with elements of less than
// 8 bits. // 8 bits.
bool TargetLowering::isConstTrueVal(const SDNode *N) const { bool TargetLowering::isConstTrueVal(SDValue N) const {
if (!N) if (!N)
return false; return false;
unsigned EltWidth;
APInt CVal; APInt CVal;
if (auto *CN = dyn_cast<ConstantSDNode>(N)) { if (ConstantSDNode *CN = isConstOrConstSplat(N, /*AllowUndefs=*/false,
/*AllowTruncation=*/true)) {
CVal = CN->getAPIntValue(); CVal = CN->getAPIntValue();
} else if (auto *BV = dyn_cast<BuildVectorSDNode>(N)) { EltWidth = N.getValueType().getScalarSizeInBits();
auto *CN = BV->getConstantSplatNode(); } else
if (!CN)
return false;
// If this is a truncating build vector, truncate the splat value.
// Otherwise, we may fail to match the expected values below.
unsigned BVEltWidth = BV->getValueType(0).getScalarSizeInBits();
CVal = CN->getAPIntValue();
if (BVEltWidth < CVal.getBitWidth())
CVal = CVal.trunc(BVEltWidth);
} else {
return false; return false;
}
switch (getBooleanContents(N->getValueType(0))) { // If this is a truncating splat, truncate the splat value.
// Otherwise, we may fail to match the expected values below.
if (EltWidth < CVal.getBitWidth())
CVal = CVal.trunc(EltWidth);
switch (getBooleanContents(N.getValueType())) {
case UndefinedBooleanContent: case UndefinedBooleanContent:
return CVal[0]; return CVal[0];
case ZeroOrOneBooleanContent: case ZeroOrOneBooleanContent:
@ -3228,7 +3224,7 @@ bool TargetLowering::isConstTrueVal(const SDNode *N) const {
llvm_unreachable("Invalid boolean contents"); llvm_unreachable("Invalid boolean contents");
} }
bool TargetLowering::isConstFalseVal(const SDNode *N) const { bool TargetLowering::isConstFalseVal(SDValue N) const {
if (!N) if (!N)
return false; return false;
@ -3763,7 +3759,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
if (TopSetCC.getValueType() == MVT::i1 && VT == MVT::i1 && if (TopSetCC.getValueType() == MVT::i1 && VT == MVT::i1 &&
TopSetCC.getOpcode() == ISD::SETCC && TopSetCC.getOpcode() == ISD::SETCC &&
(N0Opc == ISD::ZERO_EXTEND || N0Opc == ISD::SIGN_EXTEND) && (N0Opc == ISD::ZERO_EXTEND || N0Opc == ISD::SIGN_EXTEND) &&
(isConstFalseVal(N1C) || (isConstFalseVal(N1) ||
isExtendedTrueVal(N1C, N0->getValueType(0), SExt))) { isExtendedTrueVal(N1C, N0->getValueType(0), SExt))) {
bool Inverse = (N1C->isZero() && Cond == ISD::SETEQ) || bool Inverse = (N1C->isZero() && Cond == ISD::SETEQ) ||

View File

@ -14527,7 +14527,7 @@ static SDValue PerformXORCombine(SDNode *N,
SDValue N0 = N->getOperand(0); SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1); SDValue N1 = N->getOperand(1);
const TargetLowering *TLI = Subtarget->getTargetLowering(); const TargetLowering *TLI = Subtarget->getTargetLowering();
if (TLI->isConstTrueVal(N1.getNode()) && if (TLI->isConstTrueVal(N1) &&
(N0->getOpcode() == ARMISD::VCMP || N0->getOpcode() == ARMISD::VCMPZ)) { (N0->getOpcode() == ARMISD::VCMP || N0->getOpcode() == ARMISD::VCMPZ)) {
if (CanInvertMVEVCMP(N0)) { if (CanInvertMVEVCMP(N0)) {
SDLoc DL(N0); SDLoc DL(N0);

View File

@ -0,0 +1,54 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=aarch64-linux-unknown -mattr=+sve -o - < %s | FileCheck %s
define <vscale x 8 x i1> @not_icmp_sle_nxv8i16(<vscale x 8 x i16> %a, <vscale x 8 x i16> %b) {
; CHECK-LABEL: not_icmp_sle_nxv8i16:
; CHECK: // %bb.0:
; CHECK-NEXT: ptrue p0.h
; CHECK-NEXT: cmpgt p0.h, p0/z, z0.h, z1.h
; CHECK-NEXT: ret
%icmp = icmp sle <vscale x 8 x i16> %a, %b
%tmp = insertelement <vscale x 8 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 8 x i1> %tmp, <vscale x 8 x i1> undef, <vscale x 8 x i32> zeroinitializer
%not = xor <vscale x 8 x i1> %ones, %icmp
ret <vscale x 8 x i1> %not
}
define <vscale x 4 x i1> @not_icmp_sgt_nxv4i32(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) {
; CHECK-LABEL: not_icmp_sgt_nxv4i32:
; CHECK: // %bb.0:
; CHECK-NEXT: ptrue p0.s
; CHECK-NEXT: cmpge p0.s, p0/z, z1.s, z0.s
; CHECK-NEXT: ret
%icmp = icmp sgt <vscale x 4 x i32> %a, %b
%tmp = insertelement <vscale x 4 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 4 x i1> %tmp, <vscale x 4 x i1> undef, <vscale x 4 x i32> zeroinitializer
%not = xor <vscale x 4 x i1> %icmp, %ones
ret <vscale x 4 x i1> %not
}
define <vscale x 2 x i1> @not_fcmp_une_nxv2f64(<vscale x 2 x double> %a, <vscale x 2 x double> %b) {
; CHECK-LABEL: not_fcmp_une_nxv2f64:
; CHECK: // %bb.0:
; CHECK-NEXT: ptrue p0.d
; CHECK-NEXT: fcmeq p0.d, p0/z, z0.d, z1.d
; CHECK-NEXT: ret
%icmp = fcmp une <vscale x 2 x double> %a, %b
%tmp = insertelement <vscale x 2 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 2 x i1> %tmp, <vscale x 2 x i1> undef, <vscale x 2 x i32> zeroinitializer
%not = xor <vscale x 2 x i1> %icmp, %ones
ret <vscale x 2 x i1> %not
}
define <vscale x 4 x i1> @not_fcmp_uge_nxv4f32(<vscale x 4 x float> %a, <vscale x 4 x float> %b) {
; CHECK-LABEL: not_fcmp_uge_nxv4f32:
; CHECK: // %bb.0:
; CHECK-NEXT: ptrue p0.s
; CHECK-NEXT: fcmgt p0.s, p0/z, z1.s, z0.s
; CHECK-NEXT: ret
%icmp = fcmp uge <vscale x 4 x float> %a, %b
%tmp = insertelement <vscale x 4 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 4 x i1> %tmp, <vscale x 4 x i1> undef, <vscale x 4 x i32> zeroinitializer
%not = xor <vscale x 4 x i1> %icmp, %ones
ret <vscale x 4 x i1> %not
}

View File

@ -0,0 +1,55 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+m,+d,+zfh,+v -verify-machineinstrs < %s | FileCheck %s
; RUN: llc -mtriple=riscv64 -mattr=+m,+d,+zfh,+v -verify-machineinstrs < %s | FileCheck %s
define <vscale x 8 x i1> @not_icmp_sle_nxv8i16(<vscale x 8 x i16> %a, <vscale x 8 x i16> %b) {
; CHECK-LABEL: not_icmp_sle_nxv8i16:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e16, m2, ta, mu
; CHECK-NEXT: vmslt.vv v0, v10, v8
; CHECK-NEXT: ret
%icmp = icmp sle <vscale x 8 x i16> %a, %b
%tmp = insertelement <vscale x 8 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 8 x i1> %tmp, <vscale x 8 x i1> undef, <vscale x 8 x i32> zeroinitializer
%not = xor <vscale x 8 x i1> %ones, %icmp
ret <vscale x 8 x i1> %not
}
define <vscale x 4 x i1> @not_icmp_sgt_nxv4i32(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) {
; CHECK-LABEL: not_icmp_sgt_nxv4i32:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e32, m2, ta, mu
; CHECK-NEXT: vmsle.vv v0, v8, v10
; CHECK-NEXT: ret
%icmp = icmp sgt <vscale x 4 x i32> %a, %b
%tmp = insertelement <vscale x 4 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 4 x i1> %tmp, <vscale x 4 x i1> undef, <vscale x 4 x i32> zeroinitializer
%not = xor <vscale x 4 x i1> %icmp, %ones
ret <vscale x 4 x i1> %not
}
define <vscale x 2 x i1> @not_fcmp_une_nxv2f64(<vscale x 2 x double> %a, <vscale x 2 x double> %b) {
; CHECK-LABEL: not_fcmp_une_nxv2f64:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e64, m2, ta, mu
; CHECK-NEXT: vmfeq.vv v0, v8, v10
; CHECK-NEXT: ret
%icmp = fcmp une <vscale x 2 x double> %a, %b
%tmp = insertelement <vscale x 2 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 2 x i1> %tmp, <vscale x 2 x i1> undef, <vscale x 2 x i32> zeroinitializer
%not = xor <vscale x 2 x i1> %icmp, %ones
ret <vscale x 2 x i1> %not
}
define <vscale x 4 x i1> @not_fcmp_uge_nxv4f32(<vscale x 4 x float> %a, <vscale x 4 x float> %b) {
; CHECK-LABEL: not_fcmp_uge_nxv4f32:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e32, m2, ta, mu
; CHECK-NEXT: vmflt.vv v0, v8, v10
; CHECK-NEXT: ret
%icmp = fcmp uge <vscale x 4 x float> %a, %b
%tmp = insertelement <vscale x 4 x i1> undef, i1 true, i32 0
%ones = shufflevector <vscale x 4 x i1> %tmp, <vscale x 4 x i1> undef, <vscale x 4 x i32> zeroinitializer
%not = xor <vscale x 4 x i1> %icmp, %ones
ret <vscale x 4 x i1> %not
}