[DAGCombiner] Fold (sext (not i1 x)) -> (add (zext i1 x), -1)

Move fold of (sext (not i1 x)) -> (add (zext i1 x), -1) from X86 to DAGCombiner to improve codegen on other targets.

Differential Revision: https://reviews.llvm.org/D91589
This commit is contained in:
Layton Kifer 2020-12-06 11:50:42 -05:00 committed by Sanjay Patel
parent 0b3e393d6c
commit ac522f8700
8 changed files with 41 additions and 52 deletions

View File

@ -10663,6 +10663,19 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
return DAG.getNode(ISD::ADD, DL, VT, Zext, DAG.getAllOnesConstant(DL, VT));
}
// fold sext (not i1 X) -> add (zext i1 X), -1
// TODO: This could be extended to handle bool vectors.
if (N0.getValueType() == MVT::i1 && isBitwiseNot(N0) && N0.hasOneUse() &&
(!LegalOperations || (TLI.isOperationLegal(ISD::ZERO_EXTEND, VT) &&
TLI.isOperationLegal(ISD::ADD, VT)))) {
// If we can eliminate the 'not', the sext form should be better
if (SDValue NewXor = visitXOR(N0.getNode()))
return DAG.getNode(ISD::SIGN_EXTEND, DL, VT, NewXor);
SDValue Zext = DAG.getNode(ISD::ZERO_EXTEND, DL, VT, N0.getOperand(0));
return DAG.getNode(ISD::ADD, DL, VT, Zext, DAG.getAllOnesConstant(DL, VT));
}
return SDValue();
}

View File

@ -46882,7 +46882,6 @@ static SDValue combineSext(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
SDValue N0 = N->getOperand(0);
EVT VT = N->getValueType(0);
EVT InVT = N0.getValueType();
SDLoc DL(N);
// (i32 (sext (i8 (x86isd::setcc_carry)))) -> (i32 (x86isd::setcc_carry))
@ -46911,16 +46910,6 @@ static SDValue combineSext(SDNode *N, SelectionDAG &DAG,
if (SDValue V = combineExtSetcc(N, DAG, Subtarget))
return V;
if (InVT == MVT::i1 && N0.getOpcode() == ISD::XOR &&
isAllOnesConstant(N0.getOperand(1)) && N0.hasOneUse()) {
// Invert and sign-extend a boolean is the same as zero-extend and subtract
// 1 because 0 becomes -1 and 1 becomes 0. The subtract is efficiently
// lowered with an LEA or a DEC. This is the same as: select Bool, 0, -1.
// sext (xor Bool, -1) --> sub (zext Bool), 1
SDValue Zext = DAG.getNode(ISD::ZERO_EXTEND, DL, VT, N0.getOperand(0));
return DAG.getNode(ISD::SUB, DL, VT, Zext, DAG.getConstant(1, DL, VT));
}
if (SDValue V = combineToExtendBoolVectorInReg(N, DAG, DCI, Subtarget))
return V;

View File

@ -68,8 +68,8 @@ define i32 @select_1_or_0_signext(i1 signext %cond) {
define i32 @select_0_or_neg1(i1 %cond) {
; CHECK-LABEL: select_0_or_neg1:
; CHECK: // %bb.0:
; CHECK-NEXT: mvn w8, w0
; CHECK-NEXT: sbfx w0, w8, #0, #1
; CHECK-NEXT: and w8, w0, #0x1
; CHECK-NEXT: sub w0, w8, #1 // =1
; CHECK-NEXT: ret
%sel = select i1 %cond, i32 0, i32 -1
ret i32 %sel
@ -78,8 +78,7 @@ define i32 @select_0_or_neg1(i1 %cond) {
define i32 @select_0_or_neg1_zeroext(i1 zeroext %cond) {
; CHECK-LABEL: select_0_or_neg1_zeroext:
; CHECK: // %bb.0:
; CHECK-NEXT: mvn w8, w0
; CHECK-NEXT: sbfx w0, w8, #0, #1
; CHECK-NEXT: sub w0, w0, #1 // =1
; CHECK-NEXT: ret
%sel = select i1 %cond, i32 0, i32 -1
ret i32 %sel

View File

@ -137,23 +137,21 @@ define i32 @select_1_or_0_signext(i1 signext %cond) {
define i32 @select_0_or_neg1(i1 %cond) {
; ARM-LABEL: select_0_or_neg1:
; ARM: @ %bb.0:
; ARM-NEXT: mov r1, #1
; ARM-NEXT: bic r0, r1, r0
; ARM-NEXT: rsb r0, r0, #0
; ARM-NEXT: and r0, r0, #1
; ARM-NEXT: sub r0, r0, #1
; ARM-NEXT: mov pc, lr
;
; THUMB2-LABEL: select_0_or_neg1:
; THUMB2: @ %bb.0:
; THUMB2-NEXT: movs r1, #1
; THUMB2-NEXT: bic.w r0, r1, r0
; THUMB2-NEXT: rsbs r0, r0, #0
; THUMB2-NEXT: and r0, r0, #1
; THUMB2-NEXT: subs r0, #1
; THUMB2-NEXT: bx lr
;
; THUMB-LABEL: select_0_or_neg1:
; THUMB: @ %bb.0:
; THUMB-NEXT: movs r1, #1
; THUMB-NEXT: bics r1, r0
; THUMB-NEXT: rsbs r0, r1, #0
; THUMB-NEXT: ands r1, r0
; THUMB-NEXT: subs r0, r1, #1
; THUMB-NEXT: bx lr
%sel = select i1 %cond, i32 0, i32 -1
ret i32 %sel
@ -162,21 +160,17 @@ define i32 @select_0_or_neg1(i1 %cond) {
define i32 @select_0_or_neg1_zeroext(i1 zeroext %cond) {
; ARM-LABEL: select_0_or_neg1_zeroext:
; ARM: @ %bb.0:
; ARM-NEXT: eor r0, r0, #1
; ARM-NEXT: rsb r0, r0, #0
; ARM-NEXT: sub r0, r0, #1
; ARM-NEXT: mov pc, lr
;
; THUMB2-LABEL: select_0_or_neg1_zeroext:
; THUMB2: @ %bb.0:
; THUMB2-NEXT: eor r0, r0, #1
; THUMB2-NEXT: rsbs r0, r0, #0
; THUMB2-NEXT: subs r0, #1
; THUMB2-NEXT: bx lr
;
; THUMB-LABEL: select_0_or_neg1_zeroext:
; THUMB: @ %bb.0:
; THUMB-NEXT: movs r1, #1
; THUMB-NEXT: eors r1, r0
; THUMB-NEXT: rsbs r0, r1, #0
; THUMB-NEXT: subs r0, r0, #1
; THUMB-NEXT: bx lr
%sel = select i1 %cond, i32 0, i32 -1
ret i32 %sel

View File

@ -69,9 +69,8 @@ define i32 @select_1_or_0_signext(i1 signext %cond) {
define i32 @select_0_or_neg1(i1 %cond) {
; ALL-LABEL: select_0_or_neg1:
; ALL: # %bb.0:
; ALL-NEXT: not 3, 3
; ALL-NEXT: clrldi 3, 3, 63
; ALL-NEXT: neg 3, 3
; ALL-NEXT: addi 3, 3, -1
; ALL-NEXT: blr
%sel = select i1 %cond, i32 0, i32 -1
ret i32 %sel
@ -80,8 +79,7 @@ define i32 @select_0_or_neg1(i1 %cond) {
define i32 @select_0_or_neg1_zeroext(i1 zeroext %cond) {
; ALL-LABEL: select_0_or_neg1_zeroext:
; ALL: # %bb.0:
; ALL-NEXT: xori 3, 3, 1
; ALL-NEXT: neg 3, 3
; ALL-NEXT: addi 3, 3, -1
; ALL-NEXT: blr
%sel = select i1 %cond, i32 0, i32 -1
ret i32 %sel

View File

@ -437,20 +437,18 @@ define i32 @trunc_i64_to_i32(i64 %a) nounwind {
ret i32 %1
}
;; TODO: fold (sext (not x)) -> (add (zext x) -1)
;; fold (sext (not x)) -> (add (zext x) -1)
define i32 @sext_of_not_i32(i1 %x) {
; RV32I-LABEL: sext_of_not_i32:
; RV32I: # %bb.0:
; RV32I-NEXT: not a0, a0
; RV32I-NEXT: andi a0, a0, 1
; RV32I-NEXT: neg a0, a0
; RV32I-NEXT: addi a0, a0, -1
; RV32I-NEXT: ret
;
; RV64I-LABEL: sext_of_not_i32:
; RV64I: # %bb.0:
; RV64I-NEXT: not a0, a0
; RV64I-NEXT: andi a0, a0, 1
; RV64I-NEXT: neg a0, a0
; RV64I-NEXT: addi a0, a0, -1
; RV64I-NEXT: ret
%xor = xor i1 %x, 1
%sext = sext i1 %xor to i32
@ -460,24 +458,23 @@ define i32 @sext_of_not_i32(i1 %x) {
define i64 @sext_of_not_i64(i1 %x) {
; RV32I-LABEL: sext_of_not_i64:
; RV32I: # %bb.0:
; RV32I-NEXT: not a0, a0
; RV32I-NEXT: andi a0, a0, 1
; RV32I-NEXT: neg a0, a0
; RV32I-NEXT: mv a1, a0
; RV32I-NEXT: andi a1, a0, 1
; RV32I-NEXT: addi a0, a1, -1
; RV32I-NEXT: sltu a1, a0, a1
; RV32I-NEXT: addi a1, a1, -1
; RV32I-NEXT: ret
;
; RV64I-LABEL: sext_of_not_i64:
; RV64I: # %bb.0:
; RV64I-NEXT: not a0, a0
; RV64I-NEXT: andi a0, a0, 1
; RV64I-NEXT: neg a0, a0
; RV64I-NEXT: addi a0, a0, -1
; RV64I-NEXT: ret
%xor = xor i1 %x, 1
%sext = sext i1 %xor to i64
ret i64 %sext
}
;; TODO: fold (sext (not (setcc a, b, cc))) -> (sext (setcc a, b, !cc))
;; fold (sext (not (setcc a, b, cc))) -> (sext (setcc a, b, !cc))
define i32 @sext_of_not_cmp_i32(i32 %x) {
; RV32I-LABEL: sext_of_not_cmp_i32:
; RV32I: # %bb.0:

View File

@ -1,20 +1,19 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
;; TODO: fold (sext (not x)) -> (add (zext x) -1)
;; fold (sext (not x)) -> (add (zext x) -1)
define i32 @sext_of_not(i1 %x) {
; CHECK-LABEL: sext_of_not:
; CHECK: # %bb.0:
; CHECK-NEXT: xilf %r2, 4294967295
; CHECK-NEXT: nilf %r2, 1
; CHECK-NEXT: lcr %r2, %r2
; CHECK-NEXT: ahi %r2, -1
; CHECK-NEXT: br %r14
%xor = xor i1 %x, 1
%sext = sext i1 %xor to i32
ret i32 %sext
}
;; TODO: fold (sext (not (setcc a, b, cc))) -> (sext (setcc a, b, !cc))
;; fold (sext (not (setcc a, b, cc))) -> (sext (setcc a, b, !cc))
define i32 @sext_of_not_cmp(i32 %x) {
; CHECK-LABEL: sext_of_not_cmp:
; CHECK: # %bb.0:

View File

@ -49,8 +49,8 @@ define i32 @main() {
; CHECK-NEXT: movabsq $1010101010101010101, %rcx # imm = 0xE04998456557EB5
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpq %rcx, {{[0-9]+}}(%rsp)
; CHECK-NEXT: sete %al
; CHECK-NEXT: decl %eax
; CHECK-NEXT: setne %al
; CHECK-NEXT: negl %eax
; CHECK-NEXT: addq $584, %rsp # imm = 0x248
; CHECK-NEXT: .cfi_def_cfa_offset 8
; CHECK-NEXT: retq