[DAGCombine][PowerPC] Simplify nabs by using legal `smin` operation
authorKai Luo <lkail@cn.ibm.com>
Tue, 8 Dec 2020 03:22:32 +0000 (03:22 +0000)
committerKai Luo <lkail@cn.ibm.com>
Tue, 8 Dec 2020 03:24:07 +0000 (03:24 +0000)
Convert `0 - abs(x)` to `smin (x, -x)` if `smin` is a legal operation.

Verification: https://alive2.llvm.org/ce/z/vpquFR

Reviewed By: RKSimon

Differential Revision: https://reviews.llvm.org/D92637

llvm/include/llvm/CodeGen/TargetLowering.h
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
llvm/test/CodeGen/PowerPC/neg-abs.ll

index 4aeefd9..3dce96d 100644 (file)
@@ -4393,8 +4393,10 @@ public:
   /// (ABS x) -> (XOR (ADD x, (SRA x, type_size)), (SRA x, type_size))
   /// \param N Node to expand
   /// \param Result output after conversion
+  /// \param IsNegative indicate negated abs
   /// \returns True, if the expansion was successful, false otherwise
-  bool expandABS(SDNode *N, SDValue &Result, SelectionDAG &DAG) const;
+  bool expandABS(SDNode *N, SDValue &Result, SelectionDAG &DAG,
+                 bool IsNegative = false) const;
 
   /// Turn load of vector type into a load of the individual elements.
   /// \param LD load to expand
index 51de545..6d5a541 100644 (file)
@@ -3193,18 +3193,12 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
       return N1;
     }
 
-    // Convert 0 - abs(x) -> Y = sra (X, size(X)-1); sub (Y, xor (X, Y)).
+    // Convert 0 - abs(x).
+    SDValue Result;
     if (N1->getOpcode() == ISD::ABS &&
-        !TLI.isOperationLegalOrCustom(ISD::ABS, VT)) {
-      SDValue X = N1->getOperand(0);
-      SDValue Shift =
-          DAG.getNode(ISD::SRA, DL, VT, X,
-                      DAG.getConstant(BitWidth - 1, DL, getShiftAmountTy(VT)));
-      SDValue Xor = DAG.getNode(ISD::XOR, DL, VT, X, Shift);
-      AddToWorklist(Shift.getNode());
-      AddToWorklist(Xor.getNode());
-      return DAG.getNode(ISD::SUB, DL, VT, Shift, Xor);
-    }
+        !TLI.isOperationLegalOrCustom(ISD::ABS, VT) &&
+        TLI.expandABS(N1.getNode(), Result, DAG, true))
+      return Result;
   }
 
   // Canonicalize (sub -1, x) -> ~x, i.e. (xor x, -1)
index d27ada4..3897dce 100644 (file)
@@ -6816,14 +6816,15 @@ bool TargetLowering::expandCTTZ(SDNode *Node, SDValue &Result,
 }
 
 bool TargetLowering::expandABS(SDNode *N, SDValue &Result,
-                               SelectionDAG &DAG) const {
+                               SelectionDAG &DAG, bool IsNegative) const {
   SDLoc dl(N);
   EVT VT = N->getValueType(0);
   EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout());
   SDValue Op = N->getOperand(0);
 
   // abs(x) -> smax(x,sub(0,x))
-  if (isOperationLegal(ISD::SUB, VT) && isOperationLegal(ISD::SMAX, VT)) {
+  if (!IsNegative && isOperationLegal(ISD::SUB, VT) &&
+      isOperationLegal(ISD::SMAX, VT)) {
     SDValue Zero = DAG.getConstant(0, dl, VT);
     Result = DAG.getNode(ISD::SMAX, dl, VT, Op,
                          DAG.getNode(ISD::SUB, dl, VT, Zero, Op));
@@ -6831,24 +6832,42 @@ bool TargetLowering::expandABS(SDNode *N, SDValue &Result,
   }
 
   // abs(x) -> umin(x,sub(0,x))
-  if (isOperationLegal(ISD::SUB, VT) && isOperationLegal(ISD::UMIN, VT)) {
+  if (!IsNegative && isOperationLegal(ISD::SUB, VT) &&
+      isOperationLegal(ISD::UMIN, VT)) {
     SDValue Zero = DAG.getConstant(0, dl, VT);
     Result = DAG.getNode(ISD::UMIN, dl, VT, Op,
                          DAG.getNode(ISD::SUB, dl, VT, Zero, Op));
     return true;
   }
 
+  // 0 - abs(x) -> smin(x, sub(0,x))
+  if (IsNegative && isOperationLegal(ISD::SUB, VT) &&
+      isOperationLegal(ISD::SMIN, VT)) {
+    SDValue Zero = DAG.getConstant(0, dl, VT);
+    Result = DAG.getNode(ISD::SMIN, dl, VT, Op,
+                         DAG.getNode(ISD::SUB, dl, VT, Zero, Op));
+    return true;
+  }
+
   // Only expand vector types if we have the appropriate vector operations.
-  if (VT.isVector() && (!isOperationLegalOrCustom(ISD::SRA, VT) ||
-                        !isOperationLegalOrCustom(ISD::ADD, VT) ||
-                        !isOperationLegalOrCustomOrPromote(ISD::XOR, VT)))
+  if (VT.isVector() &&
+      (!isOperationLegalOrCustom(ISD::SRA, VT) ||
+       (!IsNegative && !isOperationLegalOrCustom(ISD::ADD, VT)) ||
+       (IsNegative && !isOperationLegalOrCustom(ISD::SUB, VT)) ||
+       !isOperationLegalOrCustomOrPromote(ISD::XOR, VT)))
     return false;
 
   SDValue Shift =
       DAG.getNode(ISD::SRA, dl, VT, Op,
                   DAG.getConstant(VT.getScalarSizeInBits() - 1, dl, ShVT));
-  SDValue Add = DAG.getNode(ISD::ADD, dl, VT, Op, Shift);
-  Result = DAG.getNode(ISD::XOR, dl, VT, Add, Shift);
+  if (!IsNegative) {
+    SDValue Add = DAG.getNode(ISD::ADD, dl, VT, Op, Shift);
+    Result = DAG.getNode(ISD::XOR, dl, VT, Add, Shift);
+  } else {
+    // 0 - abs(x) -> Y = sra (X, size(X)-1); sub (Y, xor (X, Y))
+    SDValue Xor = DAG.getNode(ISD::XOR, dl, VT, Op, Shift);
+    Result = DAG.getNode(ISD::SUB, dl, VT, Shift, Xor);
+  }
   return true;
 }
 
index c23423a..a4fc9f0 100644 (file)
@@ -24,13 +24,9 @@ define i64@neg_abs(i64 %x) {
 define <2 x i64> @neg_abs_v2i64(<2 x i64> %0) {
 ; CHECK-LE-LABEL: neg_abs_v2i64:
 ; CHECK-LE:       # %bb.0:
-; CHECK-LE-NEXT:    addis r3, r2, .LCPI1_0@toc@ha
-; CHECK-LE-NEXT:    addi r3, r3, .LCPI1_0@toc@l
-; CHECK-LE-NEXT:    lxvd2x vs0, 0, r3
-; CHECK-LE-NEXT:    xxswapd vs35, vs0
-; CHECK-LE-NEXT:    vsrad v3, v2, v3
-; CHECK-LE-NEXT:    xxlxor vs34, vs34, vs35
-; CHECK-LE-NEXT:    vsubudm v2, v3, v2
+; CHECK-LE-NEXT:    xxlxor vs35, vs35, vs35
+; CHECK-LE-NEXT:    vsubudm v3, v3, v2
+; CHECK-LE-NEXT:    vminsd v2, v2, v3
 ; CHECK-LE-NEXT:    blr
   %abs = call <2 x i64> @llvm.abs.v2i64(<2 x i64> %0, i1 true)
   %neg.abs = sub <2 x i64> zeroinitializer, %abs
@@ -40,12 +36,9 @@ define <2 x i64> @neg_abs_v2i64(<2 x i64> %0) {
 define <4 x i32> @neg_abs_v4i32(<4 x i32> %0) {
 ; CHECK-LE-LABEL: neg_abs_v4i32:
 ; CHECK-LE:       # %bb.0:
-; CHECK-LE-NEXT:    vspltisw v3, -16
-; CHECK-LE-NEXT:    vspltisw v4, 15
-; CHECK-LE-NEXT:    vsubuwm v3, v4, v3
-; CHECK-LE-NEXT:    vsraw v3, v2, v3
-; CHECK-LE-NEXT:    xxlxor vs34, vs34, vs35
-; CHECK-LE-NEXT:    vsubuwm v2, v3, v2
+; CHECK-LE-NEXT:    xxlxor vs35, vs35, vs35
+; CHECK-LE-NEXT:    vsubuwm v3, v3, v2
+; CHECK-LE-NEXT:    vminsw v2, v2, v3
 ; CHECK-LE-NEXT:    blr
   %abs = call <4 x i32> @llvm.abs.v4i32(<4 x i32> %0, i1 true)
   %neg.abs = sub <4 x i32> zeroinitializer, %abs
@@ -55,10 +48,9 @@ define <4 x i32> @neg_abs_v4i32(<4 x i32> %0) {
 define <8 x i16> @neg_abs_v8i16(<8 x i16> %0) {
 ; CHECK-LE-LABEL: neg_abs_v8i16:
 ; CHECK-LE:       # %bb.0:
-; CHECK-LE-NEXT:    vspltish v3, 15
-; CHECK-LE-NEXT:    vsrah v3, v2, v3
-; CHECK-LE-NEXT:    xxlxor vs34, vs34, vs35
-; CHECK-LE-NEXT:    vsubuhm v2, v3, v2
+; CHECK-LE-NEXT:    xxlxor vs35, vs35, vs35
+; CHECK-LE-NEXT:    vsubuhm v3, v3, v2
+; CHECK-LE-NEXT:    vminsh v2, v2, v3
 ; CHECK-LE-NEXT:    blr
   %abs = call <8 x i16> @llvm.abs.v8i16(<8 x i16> %0, i1 true)
   %neg.abs = sub <8 x i16> zeroinitializer, %abs
@@ -68,10 +60,9 @@ define <8 x i16> @neg_abs_v8i16(<8 x i16> %0) {
 define <16 x i8> @neg_abs_v16i8(<16 x i8> %0) {
 ; CHECK-LE-LABEL: neg_abs_v16i8:
 ; CHECK-LE:       # %bb.0:
-; CHECK-LE-NEXT:    vspltisb v3, 7
-; CHECK-LE-NEXT:    vsrab v3, v2, v3
-; CHECK-LE-NEXT:    xxlxor vs34, vs34, vs35
-; CHECK-LE-NEXT:    vsububm v2, v3, v2
+; CHECK-LE-NEXT:    xxlxor vs35, vs35, vs35
+; CHECK-LE-NEXT:    vsububm v3, v3, v2
+; CHECK-LE-NEXT:    vminsb v2, v2, v3
 ; CHECK-LE-NEXT:    blr
   %abs = call <16 x i8> @llvm.abs.v16i8(<16 x i8> %0, i1 true)
   %neg.abs = sub <16 x i8> zeroinitializer, %abs