[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