Skip to content

Commit

Permalink
[DAG] allow more select folding for targets that have 'and not' (PR31…
Browse files Browse the repository at this point in the history
…175)

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

llvm-svn: 289738
  • Loading branch information
rotateright committed Dec 14, 2016
1 parent 1ebbd17 commit afee21a
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 20 deletions.
9 changes: 9 additions & 0 deletions llvm/include/llvm/Target/TargetLowering.h
Expand Up @@ -407,6 +407,15 @@ class TargetLoweringBase {
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)))).
Expand Down
32 changes: 26 additions & 6 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Expand Up @@ -14879,17 +14879,31 @@ bool DAGCombiner::SimplifySelectOps(SDNode *TheSelect, SDValue LHS,
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.
Expand All @@ -14906,6 +14920,9 @@ SDValue DAGCombiner::foldSelectCCToShiftAnd(const SDLoc &DL, SDValue N0,
AddToWorklist(Shift.getNode());
}

if (CC == ISD::SETGT)
Shift = DAG.getNOT(DL, Shift, AType);

return DAG.getNode(ISD::AND, DL, AType, Shift, N2);
}

Expand All @@ -14918,6 +14935,9 @@ SDValue DAGCombiner::foldSelectCCToShiftAnd(const SDLoc &DL, SDValue N0,
AddToWorklist(Shift.getNode());
}

if (CC == ISD::SETGT)
Shift = DAG.getNOT(DL, Shift, AType);

return DAG.getNode(ISD::AND, DL, AType, Shift, N2);
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/AArch64/arm64-icmp-opt.ll
Expand Up @@ -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
Expand Down
19 changes: 7 additions & 12 deletions llvm/test/CodeGen/AArch64/selectcc-to-shiftand.ll
Expand Up @@ -54,16 +54,15 @@ define i32 @not_pos_sel_same_variable(i32 %a) {
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
Expand All @@ -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
Expand All @@ -91,8 +89,7 @@ define i32 @pos_sel_special_constant(i32 %a) {
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
Expand All @@ -105,8 +102,7 @@ define i32 @pos_sel_variable_and_zero(i32 %a, i32 %b) {
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
Expand All @@ -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
Expand Down

0 comments on commit afee21a

Please sign in to comment.