Skip to content

Commit 83af24d

Browse files
rez5427Yui5427RKSimon
authored
[DAG] Generalize fold (not (neg x)) -> (add X, -1) (#154348)
Generalize `fold (not (neg x)) -> (add X, -1)` to `fold (not (sub Y, X)) -> (add X, ~Y)` --------- Co-authored-by: Yui5427 <785369607@qq.com> Co-authored-by: Simon Pilgrim <llvm-dev@redking.me.uk>
1 parent dfbefe4 commit 83af24d

File tree

3 files changed

+49
-18
lines changed

3 files changed

+49
-18
lines changed

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10001,13 +10001,16 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
1000110001
}
1000210002
}
1000310003

10004-
// fold (not (neg x)) -> (add X, -1)
10005-
// FIXME: This can be generalized to (not (sub Y, X)) -> (add X, ~Y) if
10006-
// Y is a constant or the subtract has a single use.
10007-
if (isAllOnesConstant(N1) && N0.getOpcode() == ISD::SUB &&
10008-
isNullConstant(N0.getOperand(0))) {
10009-
return DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(1),
10010-
DAG.getAllOnesConstant(DL, VT));
10004+
// fold (not (sub Y, X)) -> (add X, ~Y) if Y is a constant
10005+
if (N0.getOpcode() == ISD::SUB && isAllOnesConstant(N1)) {
10006+
SDValue Y = N0.getOperand(0);
10007+
SDValue X = N0.getOperand(1);
10008+
10009+
if (auto *YConst = dyn_cast<ConstantSDNode>(Y)) {
10010+
APInt NotYValue = ~YConst->getAPIntValue();
10011+
SDValue NotY = DAG.getConstant(NotYValue, DL, VT);
10012+
return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
10013+
}
1001110014
}
1001210015

1001310016
// fold (not (add X, -1)) -> (neg X)

llvm/test/CodeGen/X86/shift-i128.ll

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -949,21 +949,20 @@ define i128 @shift_i128_limited_shamt(i128 noundef %a, i32 noundef %b) nounwind
949949
; i686-NEXT: pushl %esi
950950
; i686-NEXT: andl $-16, %esp
951951
; i686-NEXT: subl $16, %esp
952-
; i686-NEXT: movl 28(%ebp), %esi
953-
; i686-NEXT: movl 32(%ebp), %eax
952+
; i686-NEXT: movl 32(%ebp), %ebx
953+
; i686-NEXT: movl 28(%ebp), %edi
954+
; i686-NEXT: movzbl 40(%ebp), %ecx
954955
; i686-NEXT: movb $6, %dl
955-
; i686-NEXT: subb 40(%ebp), %dl
956+
; i686-NEXT: subb %cl, %dl
957+
; i686-NEXT: addb $-7, %cl
958+
; i686-NEXT: movl %edi, %eax
959+
; i686-NEXT: shrl %eax
960+
; i686-NEXT: shrl %cl, %eax
956961
; i686-NEXT: movl %edx, %ecx
957-
; i686-NEXT: shll %cl, %eax
958-
; i686-NEXT: movl %esi, %ebx
959-
; i686-NEXT: movl %esi, %edi
960-
; i686-NEXT: shrl %ebx
961-
; i686-NEXT: notb %cl
962-
; i686-NEXT: shrl %cl, %ebx
962+
; i686-NEXT: shll %cl, %ebx
963963
; i686-NEXT: orl %eax, %ebx
964964
; i686-NEXT: movl 24(%ebp), %esi
965965
; i686-NEXT: movl %esi, %eax
966-
; i686-NEXT: movl %edx, %ecx
967966
; i686-NEXT: shll %cl, %eax
968967
; i686-NEXT: shldl %cl, %esi, %edi
969968
; 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
972971
; i686-NEXT: movl 32(%ebp), %edx
973972
; i686-NEXT: shldl %cl, %edx, %esi
974973
; i686-NEXT: movl %esi, 12(%edi)
974+
; i686-NEXT: movl %ebx, 8(%edi)
975975
; i686-NEXT: movl {{[-0-9]+}}(%e{{[sb]}}p), %ecx # 4-byte Reload
976976
; i686-NEXT: movl %ecx, 4(%edi)
977977
; i686-NEXT: movl %eax, (%edi)
978-
; i686-NEXT: movl %ebx, 8(%edi)
979978
; i686-NEXT: movl %edi, %eax
980979
; i686-NEXT: leal -12(%ebp), %esp
981980
; i686-NEXT: popl %esi
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
3+
4+
; Test for DAG combine: fold (not (sub Y, X)) -> (add X, ~Y)
5+
; when Y is a constant.
6+
7+
; Test case 1: Y is a constant - should transform to (add X, ~Y)
8+
define i32 @test_not_sub_constant(i32 %x) {
9+
; CHECK-LABEL: test_not_sub_constant:
10+
; CHECK: # %bb.0:
11+
; CHECK: leal -101(%rdi), %eax
12+
; CHECK-NEXT: retq
13+
%sub = sub i32 100, %x
14+
%not = xor i32 %sub, -1
15+
ret i32 %not
16+
}
17+
18+
; Test case 2: Y is not a constant - should NOT optimize
19+
define i32 @test_not_sub_non_constant(i32 %x, i32 %y) {
20+
; CHECK-LABEL: test_not_sub_non_constant:
21+
; CHECK: # %bb.0:
22+
; CHECK-NEXT: movl %esi, %eax
23+
; CHECK-NEXT: subl %edi, %eax
24+
; CHECK-NEXT: notl %eax
25+
; CHECK-NEXT: retq
26+
%sub = sub i32 %y, %x
27+
%not = xor i32 %sub, -1
28+
ret i32 %not
29+
}

0 commit comments

Comments
 (0)