[llvm] r289738 - [DAG] allow more select folding for targets that have 'and not' (PR31175)

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 14 14:59:15 PST 2016


Author: spatel
Date: Wed Dec 14 16:59:14 2016
New Revision: 289738

URL: http://llvm.org/viewvc/llvm-project?rev=289738&view=rev
Log:
[DAG] allow more select folding for targets that have 'and not' (PR31175)

The original motivation for this patch comes from wanting to canonicalize 
more IR to selects and also canonicalizing min/max.

If we're going to do that, we need more backend fixups to undo select codegen 
when simpler ops will do. I chose AArch64 for the tests because that shows the
difference in the simplest way. This should fix:
https://llvm.org/bugs/show_bug.cgi?id=31175

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

Modified:
    llvm/trunk/include/llvm/Target/TargetLowering.h
    llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
    llvm/trunk/test/CodeGen/AArch64/arm64-icmp-opt.ll
    llvm/trunk/test/CodeGen/AArch64/selectcc-to-shiftand.ll

Modified: llvm/trunk/include/llvm/Target/TargetLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=289738&r1=289737&r2=289738&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/TargetLowering.h (original)
+++ llvm/trunk/include/llvm/Target/TargetLowering.h Wed Dec 14 16:59:14 2016
@@ -407,6 +407,15 @@ public:
     return false;
   }
 
+  /// Return true if the target has a bitwise and-not operation:
+  /// X = ~A & B
+  /// This can be used to simplify select or other instructions.
+  virtual bool hasAndNot(SDValue X) const {
+    // If the target has the more complex version of this operation, assume that
+    // it has this operation too.
+    return hasAndNotCompare(X);
+  }
+
   /// \brief Return true if the target wants to use the optimization that
   /// turns ext(promotableInst1(...(promotableInstN(load)))) into
   /// promotedInst1(...(promotedInstN(ext(load)))).

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp?rev=289738&r1=289737&r2=289738&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/DAGCombiner.cpp Wed Dec 14 16:59:14 2016
@@ -14879,17 +14879,31 @@ bool DAGCombiner::SimplifySelectOps(SDNo
 SDValue DAGCombiner::foldSelectCCToShiftAnd(const SDLoc &DL, SDValue N0,
                                             SDValue N1, SDValue N2, SDValue N3,
                                             ISD::CondCode CC) {
-  // Check to see if we can perform the "gzip trick", transforming
-  // (select_cc setlt X, 0, A, 0) -> (and (sra X, size(X)-1), A)
+  // If this is a select where the false operand is zero and the compare is a
+  // check of the sign bit, see if we can perform the "gzip trick":
+  // select_cc setlt X, 0, A, 0 -> and (sra X, size(X)-1), A
+  // select_cc setgt X, 0, A, 0 -> and (not (sra X, size(X)-1)), A
   EVT XType = N0.getValueType();
   EVT AType = N2.getValueType();
-  if (!isNullConstant(N3) || CC != ISD::SETLT || !XType.bitsGE(AType))
+  if (!isNullConstant(N3) || !XType.bitsGE(AType))
     return SDValue();
 
-  // (a < 0) ? b : 0
-  // (a < 1) ? a : 0
-  if (!(isNullConstant(N1) || (isOneConstant(N1) && N0 == N2)))
+  // If the comparison is testing for a positive value, we have to invert
+  // the sign bit mask, so only do that transform if the target has a bitwise
+  // 'and not' instruction (the invert is free).
+  if (CC == ISD::SETGT && TLI.hasAndNot(N2)) {
+    // (X > -1) ? A : 0
+    // (X >  0) ? X : 0 <-- This is canonical signed max.
+    if (!(isAllOnesConstant(N1) || (isNullConstant(N1) && N0 == N2)))
+      return SDValue();
+  } else if (CC == ISD::SETLT) {
+    // (X <  0) ? A : 0
+    // (X <  1) ? X : 0 <-- This is un-canonicalized signed min.
+    if (!(isNullConstant(N1) || (isOneConstant(N1) && N0 == N2)))
+      return SDValue();
+  } else {
     return SDValue();
+  }
 
   // and (sra X, size(X)-1), A -> "and (srl X, C2), A" iff A is a single-bit
   // constant.
@@ -14906,6 +14920,9 @@ SDValue DAGCombiner::foldSelectCCToShift
       AddToWorklist(Shift.getNode());
     }
 
+    if (CC == ISD::SETGT)
+      Shift = DAG.getNOT(DL, Shift, AType);
+
     return DAG.getNode(ISD::AND, DL, AType, Shift, N2);
   }
 
@@ -14918,6 +14935,9 @@ SDValue DAGCombiner::foldSelectCCToShift
     AddToWorklist(Shift.getNode());
   }
 
+  if (CC == ISD::SETGT)
+    Shift = DAG.getNOT(DL, Shift, AType);
+
   return DAG.getNode(ISD::AND, DL, AType, Shift, N2);
 }
 

Modified: llvm/trunk/test/CodeGen/AArch64/arm64-icmp-opt.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/arm64-icmp-opt.ll?rev=289738&r1=289737&r2=289738&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/arm64-icmp-opt.ll (original)
+++ llvm/trunk/test/CodeGen/AArch64/arm64-icmp-opt.ll Wed Dec 14 16:59:14 2016
@@ -8,8 +8,8 @@
 define i32 @t1(i64 %a) {
 ; CHECK-LABEL: t1:
 ; CHECK:       // BB#0:
-; CHECK-NEXT:    cmp x0, #0
-; CHECK-NEXT:    cset w0, ge
+; CHECK-NEXT:    lsr x8, x0, #63
+; CHECK-NEXT:    eor w0, w8, #0x1
 ; CHECK-NEXT:    ret
 ;
   %cmp = icmp sgt i64 %a, -1

Modified: llvm/trunk/test/CodeGen/AArch64/selectcc-to-shiftand.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/selectcc-to-shiftand.ll?rev=289738&r1=289737&r2=289738&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/selectcc-to-shiftand.ll (original)
+++ llvm/trunk/test/CodeGen/AArch64/selectcc-to-shiftand.ll Wed Dec 14 16:59:14 2016
@@ -54,16 +54,15 @@ define i32 @not_pos_sel_same_variable(i3
   ret i32 %min
 }
 
-; FIXME: Flipping the comparison condition can be handled by getting the bitwise not of the sign mask.
+; Flipping the comparison condition can be handled by getting the bitwise not of the sign mask.
 
 ; Compare if positive and select of constants where one constant is zero.
 
 define i32 @pos_sel_constants(i32 %a) {
 ; CHECK-LABEL: pos_sel_constants:
 ; CHECK:       // BB#0:
-; CHECK-NEXT:    cmp w0, #0
 ; CHECK-NEXT:    mov w8, #5
-; CHECK-NEXT:    csel w0, w8, wzr, ge
+; CHECK-NEXT:    bic w0, w8, w0, asr #31
 ; CHECK-NEXT:    ret
 ;
   %tmp.1 = icmp sgt i32 %a, -1
@@ -76,9 +75,8 @@ define i32 @pos_sel_constants(i32 %a) {
 define i32 @pos_sel_special_constant(i32 %a) {
 ; CHECK-LABEL: pos_sel_special_constant:
 ; CHECK:       // BB#0:
-; CHECK-NEXT:    cmp w0, #0
-; CHECK-NEXT:    cset w8, ge
-; CHECK-NEXT:    lsl w0, w8, #9
+; CHECK-NEXT:    orr w8, wzr, #0x200
+; CHECK-NEXT:    bic w0, w8, w0, lsr #22
 ; CHECK-NEXT:    ret
 ;
   %tmp.1 = icmp sgt i32 %a, -1
@@ -91,8 +89,7 @@ define i32 @pos_sel_special_constant(i32
 define i32 @pos_sel_variable_and_zero(i32 %a, i32 %b) {
 ; CHECK-LABEL: pos_sel_variable_and_zero:
 ; CHECK:       // BB#0:
-; CHECK-NEXT:    cmp w0, #0
-; CHECK-NEXT:    csel w0, w1, wzr, ge
+; CHECK-NEXT:    bic w0, w1, w0, asr #31
 ; CHECK-NEXT:    ret
 ;
   %tmp.1 = icmp sgt i32 %a, -1
@@ -105,8 +102,7 @@ define i32 @pos_sel_variable_and_zero(i3
 define i32 @not_neg_sel_same_variable(i32 %a) {
 ; CHECK-LABEL: not_neg_sel_same_variable:
 ; CHECK:       // BB#0:
-; CHECK-NEXT:    cmp w0, #0
-; CHECK-NEXT:    csel w0, w0, wzr, gt
+; CHECK-NEXT:    bic w0, w0, w0, asr #31
 ; CHECK-NEXT:    ret
 ;
   %tmp = icmp sgt i32 %a, 0
@@ -121,8 +117,7 @@ define i32 @PR31175(i32 %x, i32 %y) {
 ; CHECK-LABEL: PR31175:
 ; CHECK:       // BB#0:
 ; CHECK-NEXT:    sub w8, w0, w1
-; CHECK-NEXT:    cmp w8, #0
-; CHECK-NEXT:    csel w0, w8, wzr, gt
+; CHECK-NEXT:    bic w0, w8, w8, asr #31
 ; CHECK-NEXT:    ret
 ;
   %sub = sub nsw i32 %x, %y




More information about the llvm-commits mailing list