[DAG] Allow XOR(X,MIN_SIGNED_VALUE) to perform AddLike folds

As raised on PR52267, XOR(X,MIN_SIGNED_VALUE) can be treated as ADD(X,MIN_SIGNED_VALUE), so let these cases use the 'AddLike' folds, similar to how we perform no-common-bits OR(X,Y) cases.

define i8 @src(i8 %x) {
  %r = xor i8 %x, 128
  ret i8 %r
}
=>
define i8 @tgt(i8 %x) {
  %r = add i8 %x, 128
  ret i8 %r
}
Transformation seems to be correct!

https://alive2.llvm.org/ce/z/qV46E2

Differential Revision: https://reviews.llvm.org/D122754
This commit is contained in:
Simon Pilgrim 2022-04-06 10:37:07 +01:00
parent 7a50560354
commit 3369e474bb
5 changed files with 49 additions and 39 deletions

View file

@ -2348,6 +2348,15 @@ static SDValue foldAddSubOfSignBit(SDNode *N, SelectionDAG &DAG) {
return SDValue();
}
static bool isADDLike(SDValue V, const SelectionDAG &DAG) {
unsigned Opcode = V.getOpcode();
if (Opcode == ISD::OR)
return DAG.haveNoCommonBitsSet(V.getOperand(0), V.getOperand(1));
if (Opcode == ISD::XOR)
return isMinSignedConstant(V.getOperand(1));
return false;
}
/// Try to fold a node that behaves like an ADD (note that N isn't necessarily
/// an ISD::ADD here, it could for example be an ISD::OR if we know that there
/// are no common bits set in the operands).
@ -2423,9 +2432,10 @@ SDValue DAGCombiner::visitADDLike(SDNode *N) {
// Fold (add (or x, c0), c1) -> (add x, (c0 + c1)) if (or x, c0) is
// equivalent to (add x, c0).
if (N0.getOpcode() == ISD::OR &&
isConstantOrConstantVector(N0.getOperand(1), /* NoOpaque */ true) &&
DAG.haveNoCommonBitsSet(N0.getOperand(0), N0.getOperand(1))) {
// Fold (add (xor x, c0), c1) -> (add x, (c0 + c1)) if (xor x, c0) is
// equivalent to (add x, c0).
if (isADDLike(N0, DAG) &&
isConstantOrConstantVector(N0.getOperand(1), /* NoOpaque */ true)) {
if (SDValue Add0 = DAG.FoldConstantArithmetic(ISD::ADD, DL, VT,
{N1, N0.getOperand(1)}))
return DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(0), Add0);
@ -2442,10 +2452,11 @@ SDValue DAGCombiner::visitADDLike(SDNode *N) {
// Reassociate (add (or x, c), y) -> (add add(x, y), c)) if (or x, c) is
// equivalent to (add x, c).
// Reassociate (add (xor x, c), y) -> (add add(x, y), c)) if (xor x, c) is
// equivalent to (add x, c).
auto ReassociateAddOr = [&](SDValue N0, SDValue N1) {
if (N0.getOpcode() == ISD::OR && N0.hasOneUse() &&
isConstantOrConstantVector(N0.getOperand(1), /* NoOpaque */ true) &&
DAG.haveNoCommonBitsSet(N0.getOperand(0), N0.getOperand(1))) {
if (isADDLike(N0, DAG) && N0.hasOneUse() &&
isConstantOrConstantVector(N0.getOperand(1), /* NoOpaque */ true)) {
return DAG.getNode(ISD::ADD, DL, VT,
DAG.getNode(ISD::ADD, DL, VT, N1, N0.getOperand(0)),
N0.getOperand(1));
@ -8297,6 +8308,13 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
if (SDValue RXOR = reassociateOps(ISD::XOR, DL, N0, N1, N->getFlags()))
return RXOR;
// look for 'add-like' folds:
// XOR(N0,MIN_SIGNED_VALUE) == ADD(N0,MIN_SIGNED_VALUE)
if ((!LegalOperations || TLI.isOperationLegal(ISD::ADD, VT)) &&
isMinSignedConstant(N1))
if (SDValue Combined = visitADDLike(N))
return Combined;
// fold !(x cc y) -> (x !cc y)
unsigned N0Opcode = N0.getOpcode();
SDValue LHS, RHS, CC;

View file

@ -5058,6 +5058,8 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
break;
case ISD::FREEZE:
assert(VT == Operand.getValueType() && "Unexpected VT!");
if (isGuaranteedNotToBeUndefOrPoison(Operand))
return Operand;
break;
case ISD::TokenFactor:
case ISD::MERGE_VALUES:

View file

@ -272,23 +272,21 @@ entry:
define hidden i32 @NOT_SMMLA(i32 %a, i32 %b, i32 %c) local_unnamed_addr {
; DSP-LABEL: NOT_SMMLA:
; DSP: @ %bb.0: @ %entry
; DSP-NEXT: smmul r1, r2, r1
; DSP-NEXT: eor r1, r1, #-2147483648
; DSP-NEXT: add r0, r1
; DSP-NEXT: smmla r0, r1, r2, r0
; DSP-NEXT: add.w r0, r0, #-2147483648
; DSP-NEXT: bx lr
;
; ARM7-LABEL: NOT_SMMLA:
; ARM7: @ %bb.0: @ %entry
; ARM7-NEXT: smmul r1, r2, r1
; ARM7-NEXT: eor r1, r1, #-2147483648
; ARM7-NEXT: add r0, r1, r0
; ARM7-NEXT: smmla r0, r2, r1, r0
; ARM7-NEXT: add r0, r0, #-2147483648
; ARM7-NEXT: bx lr
;
; NODSP-LABEL: NOT_SMMLA:
; NODSP: @ %bb.0: @ %entry
; NODSP-NEXT: smull r1, r2, r2, r1
; NODSP-NEXT: eor r1, r2, #-2147483648
; NODSP-NEXT: add r0, r1
; NODSP-NEXT: add r0, r2
; NODSP-NEXT: add.w r0, r0, #-2147483648
; NODSP-NEXT: bx lr
entry:
%conv = sext i32 %b to i64

View file

@ -267,9 +267,9 @@ define void @test_i1_uge(i1 *%A2) {
define i64 @PR40657(i8 %var2, i8 %var9) {
; CHECK-LABEL: PR40657:
; CHECK: # %bb.0:
; CHECK-NEXT: notb %sil
; CHECK-NEXT: addb %dil, %sil
; CHECK-NEXT: movzbl %sil, %eax
; CHECK-NEXT: addb %sil, %dil
; CHECK-NEXT: incb %dil
; CHECK-NEXT: movzbl %dil, %eax
; CHECK-NEXT: andl $1, %eax
; CHECK-NEXT: retq
%var6 = trunc i8 %var9 to i1

View file

@ -143,17 +143,15 @@ define i8 @xor_add_sminval_i8(i8 %x, i8 %y) {
define i16 @xor_sub_sminval_i16(i16 %x) {
; X86-LABEL: xor_sub_sminval_i16:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: addl $-2, %eax
; X86-NEXT: xorl $32768, %eax # imm = 0x8000
; X86-NEXT: movl $32766, %eax # imm = 0x7FFE
; X86-NEXT: addl {{[0-9]+}}(%esp), %eax
; X86-NEXT: # kill: def $ax killed $ax killed $eax
; X86-NEXT: retl
;
; X64-LABEL: xor_sub_sminval_i16:
; X64: # %bb.0:
; X64-NEXT: # kill: def $edi killed $edi def $rdi
; X64-NEXT: leal -2(%rdi), %eax
; X64-NEXT: xorl $32768, %eax # imm = 0x8000
; X64-NEXT: leal 32766(%rdi), %eax
; X64-NEXT: # kill: def $ax killed $ax killed $eax
; X64-NEXT: retq
%s = sub i16 %x, 2
@ -164,16 +162,14 @@ define i16 @xor_sub_sminval_i16(i16 %x) {
define i32 @xor_add_sminval_i32(i32 %x) {
; X86-LABEL: xor_add_sminval_i32:
; X86: # %bb.0:
; X86-NEXT: movl $512, %eax # imm = 0x200
; X86-NEXT: movl $-2147483136, %eax # imm = 0x80000200
; X86-NEXT: addl {{[0-9]+}}(%esp), %eax
; X86-NEXT: addl $-2147483648, %eax # imm = 0x80000000
; X86-NEXT: retl
;
; X64-LABEL: xor_add_sminval_i32:
; X64: # %bb.0:
; X64-NEXT: # kill: def $edi killed $edi def $rdi
; X64-NEXT: leal 512(%rdi), %eax
; X64-NEXT: addl $-2147483648, %eax # imm = 0x80000000
; X64-NEXT: leal -2147483136(%rdi), %eax
; X64-NEXT: retq
%s = add i32 %x, 512
%r = xor i32 %s, 2147483648
@ -228,17 +224,15 @@ define i8 @sub_xor_sminval_i8(i8 %x, i8 %y) {
define i16 @add_xor_sminval_i16(i16 %x) {
; X86-LABEL: add_xor_sminval_i16:
; X86: # %bb.0:
; X86-NEXT: movl $-32768, %eax # imm = 0x8000
; X86-NEXT: xorl {{[0-9]+}}(%esp), %eax
; X86-NEXT: addl $2, %eax
; X86-NEXT: movl $-32766, %eax # imm = 0x8002
; X86-NEXT: addl {{[0-9]+}}(%esp), %eax
; X86-NEXT: # kill: def $ax killed $ax killed $eax
; X86-NEXT: retl
;
; X64-LABEL: add_xor_sminval_i16:
; X64: # %bb.0:
; X64-NEXT: # kill: def $edi killed $edi def $rdi
; X64-NEXT: xorl $-32768, %edi # imm = 0x8000
; X64-NEXT: leal 2(%rdi), %eax
; X64-NEXT: leal -32766(%rdi), %eax
; X64-NEXT: # kill: def $ax killed $ax killed $eax
; X64-NEXT: retq
%r = xor i16 %x, 32768
@ -249,16 +243,14 @@ define i16 @add_xor_sminval_i16(i16 %x) {
define i32 @sub_xor_sminval_i32(i32 %x) {
; X86-LABEL: sub_xor_sminval_i32:
; X86: # %bb.0:
; X86-NEXT: movl $-2147483648, %eax # imm = 0x80000000
; X86-NEXT: xorl {{[0-9]+}}(%esp), %eax
; X86-NEXT: addl $-512, %eax # imm = 0xFE00
; X86-NEXT: movl $2147483136, %eax # imm = 0x7FFFFE00
; X86-NEXT: addl {{[0-9]+}}(%esp), %eax
; X86-NEXT: retl
;
; X64-LABEL: sub_xor_sminval_i32:
; X64: # %bb.0:
; X64-NEXT: # kill: def $edi killed $edi def $rdi
; X64-NEXT: movl $-512, %eax # imm = 0xFE00
; X64-NEXT: leal -2147483648(%rdi,%rax), %eax
; X64-NEXT: leal 2147483136(%rdi), %eax
; X64-NEXT: retq
%r = xor i32 %x, 2147483648
%s = sub i32 %r, 512
@ -269,16 +261,16 @@ define i64 @add_xor_sminval_i64(i64 %x, i64 %y) {
; X86-LABEL: add_xor_sminval_i64:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl $-2147483648, %edx # imm = 0x80000000
; X86-NEXT: xorl {{[0-9]+}}(%esp), %edx
; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
; X86-NEXT: addl {{[0-9]+}}(%esp), %eax
; X86-NEXT: adcl {{[0-9]+}}(%esp), %edx
; X86-NEXT: addl $-2147483648, %edx # imm = 0x80000000
; X86-NEXT: retl
;
; X64-LABEL: add_xor_sminval_i64:
; X64: # %bb.0:
; X64-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000
; X64-NEXT: xorq %rdi, %rax
; X64-NEXT: addq %rdi, %rax
; X64-NEXT: addq %rsi, %rax
; X64-NEXT: retq
%r = xor i64 %x, -9223372036854775808