diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -795,6 +795,12 @@ return true; } + // By default prefer folding (abs (sub nsw x, y)) -> abds(x, y). Some targets + // may want to avoid this to prevent loss of sub_nsw pattern. + virtual bool preferABDSToABSWithNSW(EVT VT) const { + return true; + } + // Return true if the target wants to transform Op(Splat(X)) -> Splat(Op(X)) virtual bool preferScalarizeSplat(unsigned Opc) const { return true; } diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -10520,9 +10520,8 @@ if (Opc0 != Op1.getOpcode() || (Opc0 != ISD::ZERO_EXTEND && Opc0 != ISD::SIGN_EXTEND)) { // fold (abs (sub nsw x, y)) -> abds(x, y) - // Limit this to legal ops to prevent loss of sub_nsw pattern. - if (AbsOp1->getFlags().hasNoSignedWrap() && - TLI.isOperationLegal(ISD::ABDS, VT)) { + if (AbsOp1->getFlags().hasNoSignedWrap() && hasOperation(ISD::ABDS, VT) && + TLI.preferABDSToABSWithNSW(VT)) { SDValue ABD = DAG.getNode(ISD::ABDS, DL, VT, Op0, Op1); return DAG.getZExtOrTrunc(ABD, DL, SrcVT); } diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h --- a/llvm/lib/Target/X86/X86ISelLowering.h +++ b/llvm/lib/Target/X86/X86ISelLowering.h @@ -1046,6 +1046,8 @@ SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + bool preferABDSToABSWithNSW(EVT VT) const override; + /// Return true if the target has native support for /// the specified value type and it is 'desirable' to use the type for the /// given node type. e.g. On x86 i16 is legal, but undesirable since i16 diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -57116,6 +57116,10 @@ return SDValue(); } +bool X86TargetLowering::preferABDSToABSWithNSW(EVT VT) const { + return false; +} + bool X86TargetLowering::isTypeDesirableForOp(unsigned Opc, EVT VT) const { if (!isTypeLegal(VT)) return false; diff --git a/llvm/test/CodeGen/AArch64/sve-saba.ll b/llvm/test/CodeGen/AArch64/sve-saba.ll --- a/llvm/test/CodeGen/AArch64/sve-saba.ll +++ b/llvm/test/CodeGen/AArch64/sve-saba.ll @@ -6,10 +6,7 @@ define @saba_abs_d( %a, %b, %c) #0 { ; CHECK-LABEL: saba_abs_d: ; CHECK: // %bb.0: -; CHECK-NEXT: ptrue p0.d -; CHECK-NEXT: sub z1.d, z1.d, z2.d -; CHECK-NEXT: abs z1.d, p0/m, z1.d -; CHECK-NEXT: add z0.d, z0.d, z1.d +; CHECK-NEXT: saba z0.d, z1.d, z2.d ; CHECK-NEXT: ret %sub = sub nsw %b, %c %abs = call @llvm.abs.nxv2i64( %sub, i1 true) @@ -20,10 +17,7 @@ define @saba_abs_s( %a, %b, %c) #0 { ; CHECK-LABEL: saba_abs_s: ; CHECK: // %bb.0: -; CHECK-NEXT: ptrue p0.s -; CHECK-NEXT: sub z1.s, z1.s, z2.s -; CHECK-NEXT: abs z1.s, p0/m, z1.s -; CHECK-NEXT: add z0.s, z0.s, z1.s +; CHECK-NEXT: saba z0.s, z1.s, z2.s ; CHECK-NEXT: ret %sub = sub nsw %b, %c %abs = call @llvm.abs.nxv4i32( %sub, i1 true) @@ -34,10 +28,7 @@ define @saba_abs_h( %a, %b, %c) #0 { ; CHECK-LABEL: saba_abs_h: ; CHECK: // %bb.0: -; CHECK-NEXT: ptrue p0.h -; CHECK-NEXT: sub z1.h, z1.h, z2.h -; CHECK-NEXT: abs z1.h, p0/m, z1.h -; CHECK-NEXT: add z0.h, z0.h, z1.h +; CHECK-NEXT: saba z0.h, z1.h, z2.h ; CHECK-NEXT: ret %sub = sub nsw %b, %c %abs = call @llvm.abs.nxv8i16( %sub, i1 true) @@ -48,10 +39,7 @@ define @saba_abs_b( %a, %b, %c) #0 { ; CHECK-LABEL: saba_abs_b: ; CHECK: // %bb.0: -; CHECK-NEXT: ptrue p0.b -; CHECK-NEXT: sub z1.b, z1.b, z2.b -; CHECK-NEXT: abs z1.b, p0/m, z1.b -; CHECK-NEXT: add z0.b, z0.b, z1.b +; CHECK-NEXT: saba z0.b, z1.b, z2.b ; CHECK-NEXT: ret %sub = sub nsw %b, %c %abs = call @llvm.abs.nxv16i8( %sub, i1 true)