diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 1ef2b35952833..d130efe96b56b 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -10001,13 +10001,16 @@ SDValue DAGCombiner::visitXOR(SDNode *N) { } } - // fold (not (neg x)) -> (add X, -1) - // FIXME: This can be generalized to (not (sub Y, X)) -> (add X, ~Y) if - // Y is a constant or the subtract has a single use. - if (isAllOnesConstant(N1) && N0.getOpcode() == ISD::SUB && - isNullConstant(N0.getOperand(0))) { - return DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(1), - DAG.getAllOnesConstant(DL, VT)); + // fold (not (sub Y, X)) -> (add X, ~Y) if Y is a constant + if (N0.getOpcode() == ISD::SUB && isAllOnesConstant(N1)) { + SDValue Y = N0.getOperand(0); + SDValue X = N0.getOperand(1); + + if (auto *YConst = dyn_cast(Y)) { + APInt NotYValue = ~YConst->getAPIntValue(); + SDValue NotY = DAG.getConstant(NotYValue, DL, VT); + return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags()); + } } // fold (not (add X, -1)) -> (neg X) diff --git a/llvm/test/CodeGen/X86/shift-i128.ll b/llvm/test/CodeGen/X86/shift-i128.ll index a82656e4b7147..7462c77482827 100644 --- a/llvm/test/CodeGen/X86/shift-i128.ll +++ b/llvm/test/CodeGen/X86/shift-i128.ll @@ -949,21 +949,20 @@ define i128 @shift_i128_limited_shamt(i128 noundef %a, i32 noundef %b) nounwind ; i686-NEXT: pushl %esi ; i686-NEXT: andl $-16, %esp ; i686-NEXT: subl $16, %esp -; i686-NEXT: movl 28(%ebp), %esi -; i686-NEXT: movl 32(%ebp), %eax +; i686-NEXT: movl 32(%ebp), %ebx +; i686-NEXT: movl 28(%ebp), %edi +; i686-NEXT: movzbl 40(%ebp), %ecx ; i686-NEXT: movb $6, %dl -; i686-NEXT: subb 40(%ebp), %dl +; i686-NEXT: subb %cl, %dl +; i686-NEXT: addb $-7, %cl +; i686-NEXT: movl %edi, %eax +; i686-NEXT: shrl %eax +; i686-NEXT: shrl %cl, %eax ; i686-NEXT: movl %edx, %ecx -; i686-NEXT: shll %cl, %eax -; i686-NEXT: movl %esi, %ebx -; i686-NEXT: movl %esi, %edi -; i686-NEXT: shrl %ebx -; i686-NEXT: notb %cl -; i686-NEXT: shrl %cl, %ebx +; i686-NEXT: shll %cl, %ebx ; i686-NEXT: orl %eax, %ebx ; i686-NEXT: movl 24(%ebp), %esi ; i686-NEXT: movl %esi, %eax -; i686-NEXT: movl %edx, %ecx ; i686-NEXT: shll %cl, %eax ; i686-NEXT: shldl %cl, %esi, %edi ; i686-NEXT: movl %edi, {{[-0-9]+}}(%e{{[sb]}}p) # 4-byte Spill @@ -972,10 +971,10 @@ define i128 @shift_i128_limited_shamt(i128 noundef %a, i32 noundef %b) nounwind ; i686-NEXT: movl 32(%ebp), %edx ; i686-NEXT: shldl %cl, %edx, %esi ; i686-NEXT: movl %esi, 12(%edi) +; i686-NEXT: movl %ebx, 8(%edi) ; i686-NEXT: movl {{[-0-9]+}}(%e{{[sb]}}p), %ecx # 4-byte Reload ; i686-NEXT: movl %ecx, 4(%edi) ; i686-NEXT: movl %eax, (%edi) -; i686-NEXT: movl %ebx, 8(%edi) ; i686-NEXT: movl %edi, %eax ; i686-NEXT: leal -12(%ebp), %esp ; i686-NEXT: popl %esi diff --git a/llvm/test/CodeGen/X86/xor-not-combine.ll b/llvm/test/CodeGen/X86/xor-not-combine.ll new file mode 100644 index 0000000000000..af65ade35ce8d --- /dev/null +++ b/llvm/test/CodeGen/X86/xor-not-combine.ll @@ -0,0 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s + +; Test for DAG combine: fold (not (sub Y, X)) -> (add X, ~Y) +; when Y is a constant. + +; Test case 1: Y is a constant - should transform to (add X, ~Y) +define i32 @test_not_sub_constant(i32 %x) { +; CHECK-LABEL: test_not_sub_constant: +; CHECK: # %bb.0: +; CHECK: leal -101(%rdi), %eax +; CHECK-NEXT: retq + %sub = sub i32 100, %x + %not = xor i32 %sub, -1 + ret i32 %not +} + +; Test case 2: Y is not a constant - should NOT optimize +define i32 @test_not_sub_non_constant(i32 %x, i32 %y) { +; CHECK-LABEL: test_not_sub_non_constant: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: subl %edi, %eax +; CHECK-NEXT: notl %eax +; CHECK-NEXT: retq + %sub = sub i32 %y, %x + %not = xor i32 %sub, -1 + ret i32 %not +}