[DAGCombiner] form 'not' ops ahead of shifts (PR39657)

We fail to canonicalize IR this way (prefer 'not' ops to arbitrary 'xor'),
but that would not matter without this patch because DAGCombiner was 
reversing that transform. I think we need this transform in the backend 
regardless of what happens in IR to catch cases where the shift-xor 
is formed late from GEP or other ops.

https://rise4fun.com/Alive/NC1

  Name: shl
  Pre: (-1 << C2) == C1
  %shl = shl i8 %x, C2
  %r = xor i8 %shl, C1
  =>
  %not = xor i8 %x, -1
  %r = shl i8 %not, C2
  
  Name: shr
  Pre: (-1 u>> C2) == C1
  %sh = lshr i8 %x, C2
  %r = xor i8 %sh, C1
  =>
  %not = xor i8 %x, -1
  %r = lshr i8 %not, C2

https://bugs.llvm.org/show_bug.cgi?id=39657

llvm-svn: 347478
This commit is contained in:
Sanjay Patel 2018-11-22 19:24:10 +00:00
parent 0ab2a92a40
commit f60a29f8fa
20 changed files with 96 additions and 81 deletions

View File

@ -6133,6 +6133,23 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
return DAG.getNode(ISD::AND, DL, VT, NotX, N1);
}
if ((N0Opcode == ISD::SRL || N0Opcode == ISD::SHL) && N0.hasOneUse()) {
ConstantSDNode *XorC = isConstOrConstSplat(N1);
ConstantSDNode *ShiftC = isConstOrConstSplat(N0.getOperand(1));
if (XorC && ShiftC) {
APInt Ones = APInt::getAllOnesValue(VT.getScalarSizeInBits());
Ones = N0Opcode == ISD::SHL ? Ones.shl(ShiftC->getZExtValue())
: Ones.lshr(ShiftC->getZExtValue());
if (XorC->getAPIntValue() == Ones) {
// If the xor constant is a shifted -1, do a 'not' before the shift:
// xor (X << ShiftC), XorC --> (not X) << ShiftC
// xor (X >> ShiftC), XorC --> (not X) >> ShiftC
SDValue Not = DAG.getNOT(DL, N0.getOperand(0), VT);
return DAG.getNode(N0Opcode, DL, VT, Not, N0.getOperand(1));
}
}
}
// fold Y = sra (X, size(X)-1); xor (add (X, Y), Y) -> (abs X)
if (TLI.isOperationLegalOrCustom(ISD::ABS, VT)) {
SDValue A = N0Opcode == ISD::ADD ? N0 : N1;
@ -6196,6 +6213,10 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
/// Handle transforms common to the three shifts, when the shift amount is a
/// constant.
SDValue DAGCombiner::visitShiftByConstant(SDNode *N, ConstantSDNode *Amt) {
// Do not turn a 'not' into a regular xor.
if (isBitwiseNot(N->getOperand(0)))
return SDValue();
SDNode *LHS = N->getOperand(0).getNode();
if (!LHS->hasOneUse()) return SDValue();

View File

@ -4,9 +4,8 @@
define i32 @PR39657(i8* %p, i64 %x) {
; CHECK-LABEL: PR39657:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl x8, x1, #2
; CHECK-NEXT: eor x8, x8, #0xfffffffffffffffc
; CHECK-NEXT: ldr w0, [x0, x8]
; CHECK-NEXT: mvn x8, x1
; CHECK-NEXT: ldr w0, [x0, x8, lsl #2]
; CHECK-NEXT: ret
%sh = shl i64 %x, 2
%mul = xor i64 %sh, -4

View File

@ -9,12 +9,11 @@
; CHECK-LABEL: pr36577
; CHECK: ldrh r0, [r0]
; CHECK: bic r0, r1, r0, lsr #5
; CHECK: mvn r1, #7
; CHECK: orr r0, r0, r1
; CHECK: mvn r0, r0, lsr #7
; CHECK: orr r0, r1, r0, lsl #2
; CHECK-T2: ldrh r0, [r0]
; CHECK-T2: bic.w r0, r1, r0, lsr #5
; CHECK-T2: orn r0, r0, #7
; CHECK-T2: mvn.w r0, r0, lsr #7
; CHECK-T2: orr.w r0, r1, r0, lsl #2
define dso_local arm_aapcscc i32** @pr36577() {
entry:
%0 = load i16, i16* @a, align 2

View File

@ -147,9 +147,8 @@ define signext i32 @zeroEqualityTest05() {
; CHECK-NEXT: li 4, -1
; CHECK-NEXT: isel 5, 4, 3, 0
; CHECK-NEXT: .LBB4_3: # %endblock
; CHECK-NEXT: srwi 3, 5, 31
; CHECK-NEXT: xori 3, 3, 1
; CHECK-NEXT: clrldi 3, 3, 32
; CHECK-NEXT: nor 3, 5, 5
; CHECK-NEXT: rlwinm 3, 3, 1, 31, 31
; CHECK-NEXT: blr
%call = tail call signext i32 @memcmp(i8* bitcast ([4 x i32]* @zeroEqualityTest03.buffer1 to i8*), i8* bitcast ([4 x i32]* @zeroEqualityTest03.buffer2 to i8*), i64 16)
%call.lobit = lshr i32 %call, 31

View File

@ -36,8 +36,8 @@ define zeroext i1 @test2(%class.PB2* %s_a, %class.PB2* %s_b) local_unnamed_addr
; CHECK-NEXT: rlwinm 3, 3, 0, 28, 28
; CHECK-NEXT: rlwinm 4, 4, 0, 28, 28
; CHECK-NEXT: sub 3, 4, 3
; CHECK-NEXT: not 3, 3
; CHECK-NEXT: rldicl 3, 3, 1, 63
; CHECK-NEXT: xori 3, 3, 1
; CHECK-NEXT: blr
entry:
%arrayidx.i6 = bitcast %class.PB2* %s_a to i32*
@ -81,8 +81,8 @@ define zeroext i1 @test4(%class.PB2* %s_a, %class.PB2* %s_b) local_unnamed_addr
; CHECK-NEXT: rlwinm 3, 3, 0, 28, 28
; CHECK-NEXT: rlwinm 4, 4, 0, 28, 28
; CHECK-NEXT: sub 3, 3, 4
; CHECK-NEXT: not 3, 3
; CHECK-NEXT: rldicl 3, 3, 1, 63
; CHECK-NEXT: xori 3, 3, 1
; CHECK-NEXT: blr
entry:
%arrayidx.i6 = bitcast %class.PB2* %s_a to i32*

View File

@ -39,8 +39,8 @@ entry:
define signext i32 @test_igesll_z(i64 %a) {
; CHECK-LABEL: test_igesll_z:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: not r3, r3
; CHECK-NEXT: rldicl r3, r3, 1, 63
; CHECK-NEXT: xori r3, r3, 1
; CHECK-NEXT: blr
entry:
%cmp = icmp sgt i64 %a, -1

View File

@ -15,8 +15,8 @@ entry:
ret i32 %conv2
; CHECK-LABEL: test_igeuc:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -65,8 +65,8 @@ entry:
ret void
; CHECK_LABEL: test_igeuc_store:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i32 %conv
; CHECK-LABEL: test_igeui:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -64,8 +64,8 @@ entry:
ret void
; CHECK_LABEL: test_igeuc_store:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i32 %conv2
; CHECK-LABEL: test_igeus:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -64,8 +64,8 @@ entry:
ret void
; CHECK_LABEL: test_igeus_store:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i32 %conv2
; CHECK-LABEL: test_ileuc:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -67,8 +67,8 @@ entry:
ret void
; CHECK-LABEL: test_ileuc_store:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i32 %sub
; CHECK-LABEL: test_ileui:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -67,8 +67,8 @@ entry:
ret void
; CHECK-LABEL: test_ileui_store:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i32 %conv2
; CHECK-LABEL: test_ileus:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK-NEXT: blr
}
@ -67,8 +67,8 @@ entry:
ret void
; CHECK-LABEL: test_ileus_store:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i64 %conv3
; CHECK-LABEL: test_llgeuc:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -64,8 +64,8 @@ entry:
ret void
; CHECK_LABEL: test_llgeuc_store:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i64 %conv1
; CHECK-LABEL: test_llgeui:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -64,8 +64,8 @@ entry:
ret void
; CHECK_LABEL: test_igeuc_store:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i64 %conv3
; CHECK-LABEL: test_llgeus:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -64,8 +64,8 @@ entry:
ret void
; CHECK_LABEL: test_llgeus_store:
; CHECK: sub [[REG1:r[0-9]+]], r3, r4
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG2]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i64 %conv3
; CHECK-LABEL: test_llleuc:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK-NEXT: blr
}
@ -67,8 +67,8 @@ entry:
ret void
; CHECK-LABEL: test_llleuc_store:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i64 %conv1
; CHECK-LABEL: test_llleui:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -67,8 +67,8 @@ entry:
ret void
; CHECK-LABEL: test_llleui_store:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -15,8 +15,8 @@ entry:
ret i64 %conv3
; CHECK-LABEL: test_llleus:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK-NEXT: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK-NEXT: xori r3, [[REG2]], 1
; CHECK-NEXT: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}
@ -67,8 +67,8 @@ entry:
ret void
; CHECK-LABEL: test_llleus_store:
; CHECK: sub [[REG1:r[0-9]+]], r4, r3
; CHECK: rldicl [[REG2:r[0-9]+]], [[REG1]], 1, 63
; CHECK: xori {{r[0-9]+}}, [[REG2]], 1
; CHECK: not [[REG2:r[0-9]+]], [[REG1]]
; CHECK-NEXT: rldicl r3, [[REG2]], 1, 63
; CHECK: blr
}

View File

@ -8,8 +8,8 @@ define i32 @shrink_xor_constant1(i32 %x) {
; ALL-LABEL: shrink_xor_constant1:
; ALL: # %bb.0:
; ALL-NEXT: movl %edi, %eax
; ALL-NEXT: notl %eax
; ALL-NEXT: shrl $31, %eax
; ALL-NEXT: xorl $1, %eax
; ALL-NEXT: retq
%sh = lshr i32 %x, 31
%not = xor i32 %sh, -1
@ -35,8 +35,8 @@ define i8 @shrink_xor_constant2(i8 %x) {
; ALL-LABEL: shrink_xor_constant2:
; ALL: # %bb.0:
; ALL-NEXT: movl %edi, %eax
; ALL-NEXT: notb %al
; ALL-NEXT: shlb $5, %al
; ALL-NEXT: xorb $-32, %al
; ALL-NEXT: # kill: def $al killed $al killed $eax
; ALL-NEXT: retq
%sh = shl i8 %x, 5

View File

@ -493,18 +493,18 @@ define %struct.ref_s* @test12(%struct.ref_s* %op, i64 %osbot, i64 %intval) {
;
; X64-LIN-LABEL: test12:
; X64-LIN: # %bb.0:
; X64-LIN-NEXT: xorq $-1, %rdx
; X64-LIN-NEXT: shlq $32, %rdx
; X64-LIN-NEXT: sarq $28, %rdx
; X64-LIN-NEXT: leaq (%rdx,%rdi), %rax
; X64-LIN-NEXT: notl %edx
; X64-LIN-NEXT: movslq %edx, %rax
; X64-LIN-NEXT: shlq $4, %rax
; X64-LIN-NEXT: addq %rdi, %rax
; X64-LIN-NEXT: retq
;
; X64-WIN-LABEL: test12:
; X64-WIN: # %bb.0:
; X64-WIN-NEXT: xorq $-1, %r8
; X64-WIN-NEXT: shlq $32, %r8
; X64-WIN-NEXT: sarq $28, %r8
; X64-WIN-NEXT: leaq (%r8,%rcx), %rax
; X64-WIN-NEXT: notl %r8d
; X64-WIN-NEXT: movslq %r8d, %rax
; X64-WIN-NEXT: shlq $4, %rax
; X64-WIN-NEXT: addq %rcx, %rax
; X64-WIN-NEXT: retq
%neg = shl i64 %intval, 32
%sext = xor i64 %neg, -4294967296
@ -518,23 +518,20 @@ define i32 @PR39657(i8* %p, i64 %x) {
; X32: # %bb.0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: shll $2, %ecx
; X32-NEXT: xorl $-4, %ecx
; X32-NEXT: movl (%eax,%ecx), %eax
; X32-NEXT: notl %ecx
; X32-NEXT: movl (%eax,%ecx,4), %eax
; X32-NEXT: retl
;
; X64-LIN-LABEL: PR39657:
; X64-LIN: # %bb.0:
; X64-LIN-NEXT: shlq $2, %rsi
; X64-LIN-NEXT: xorq $-4, %rsi
; X64-LIN-NEXT: movl (%rdi,%rsi), %eax
; X64-LIN-NEXT: notq %rsi
; X64-LIN-NEXT: movl (%rdi,%rsi,4), %eax
; X64-LIN-NEXT: retq
;
; X64-WIN-LABEL: PR39657:
; X64-WIN: # %bb.0:
; X64-WIN-NEXT: shlq $2, %rdx
; X64-WIN-NEXT: xorq $-4, %rdx
; X64-WIN-NEXT: movl (%rcx,%rdx), %eax
; X64-WIN-NEXT: notq %rdx
; X64-WIN-NEXT: movl (%rcx,%rdx,4), %eax
; X64-WIN-NEXT: retq
%sh = shl i64 %x, 2
%mul = xor i64 %sh, -4