Skip to content

Commit f5ee61a

Browse files
committed
[InstCombine] Simplify (add/sub (sub/add) (sub/add)) irrelivant of use-count
Added folds: - `(add (sub X, Y), (sub Z, X))` -> `(sub Z, Y)` - `(sub (add X, Y), (add X, Z))` -> `(sub Y, Z)` The fold typically is handled in the `Reassosiate` pass, but it fails if the inner `sub`/`add` are multi-use. Less importantly, Reassosiate doesn't propagate flags correctly. This patch adds the fold explicitly the InstCombine Proofs: https://alive2.llvm.org/ce/z/p6JyRP
1 parent 5385726 commit f5ee61a

File tree

5 files changed

+72
-10
lines changed

5 files changed

+72
-10
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,9 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
15201520
if (Instruction *R = combineAddSubWithShlAddSub(Builder, I))
15211521
return R;
15221522

1523+
if (Instruction *R = foldAddLike(I))
1524+
return R;
1525+
15231526
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
15241527
Type *Ty = I.getType();
15251528
if (Ty->isIntOrIntVectorTy(1))
@@ -2286,6 +2289,33 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
22862289
}
22872290
}
22882291

2292+
{
2293+
Value *W, *Z;
2294+
if (match(Op0, m_AddLike(m_Value(W), m_Value(X))) &&
2295+
match(Op1, m_AddLike(m_Value(Y), m_Value(Z)))) {
2296+
Instruction *R = nullptr;
2297+
if (W == Y)
2298+
R = BinaryOperator::CreateSub(X, Z);
2299+
if (W == Z)
2300+
R = BinaryOperator::CreateSub(X, Y);
2301+
if (X == Y)
2302+
R = BinaryOperator::CreateSub(W, Z);
2303+
if (X == Z)
2304+
R = BinaryOperator::CreateSub(W, Y);
2305+
if (R) {
2306+
bool NSW = I.hasNoSignedWrap() &&
2307+
match(Op0, m_NSWAddLike(m_Value(), m_Value())) &&
2308+
match(Op1, m_NSWAddLike(m_Value(), m_Value()));
2309+
2310+
bool NUW = I.hasNoUnsignedWrap() &&
2311+
match(Op1, m_NUWAddLike(m_Value(), m_Value()));
2312+
R->setHasNoSignedWrap(NSW);
2313+
R->setHasNoUnsignedWrap(NUW);
2314+
return R;
2315+
}
2316+
}
2317+
}
2318+
22892319
// (~X) - (~Y) --> Y - X
22902320
{
22912321
// Need to ensure we can consume at least one of the `not` instructions,

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3576,6 +3576,9 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
35763576
if (Instruction *R = tryFoldInstWithCtpopWithNot(&I))
35773577
return R;
35783578

3579+
if (Instruction *R = foldAddLike(I))
3580+
return R;
3581+
35793582
Value *X, *Y;
35803583
const APInt *CV;
35813584
if (match(&I, m_c_Or(m_OneUse(m_Xor(m_Value(X), m_APInt(CV))), m_Value(Y))) &&

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,9 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
585585
FPClassTest DemandedMask, KnownFPClass &Known,
586586
unsigned Depth = 0);
587587

588+
/// Common transforms for add / disjoint or
589+
Instruction *foldAddLike(BinaryOperator &I);
590+
588591
/// Canonicalize the position of binops relative to shufflevector.
589592
Instruction *foldVectorBinop(BinaryOperator &Inst);
590593
Instruction *foldVectorSelect(SelectInst &Sel);

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,6 +2008,32 @@ static bool shouldMergeGEPs(GEPOperator &GEP, GEPOperator &Src) {
20082008
return true;
20092009
}
20102010

2011+
Instruction *InstCombinerImpl::foldAddLike(BinaryOperator &I) {
2012+
Value *LHS = I.getOperand(0);
2013+
Value *RHS = I.getOperand(1);
2014+
Value *A, *B, *C, *D;
2015+
if (match(LHS, m_Sub(m_Value(A), m_Value(B))) &&
2016+
match(RHS, m_Sub(m_Value(C), m_Value(D)))) {
2017+
Instruction *R = nullptr;
2018+
if (A == D)
2019+
R = BinaryOperator::CreateSub(C, B);
2020+
if (C == B)
2021+
R = BinaryOperator::CreateSub(A, D);
2022+
if (R) {
2023+
bool NSW = match(&I, m_NSWAddLike(m_Value(), m_Value())) &&
2024+
match(LHS, m_NSWSub(m_Value(), m_Value())) &&
2025+
match(RHS, m_NSWSub(m_Value(), m_Value()));
2026+
2027+
bool NUW = match(LHS, m_NUWSub(m_Value(), m_Value())) &&
2028+
match(RHS, m_NUWSub(m_Value(), m_Value()));
2029+
R->setHasNoSignedWrap(NSW);
2030+
R->setHasNoUnsignedWrap(NUW);
2031+
return R;
2032+
}
2033+
}
2034+
return nullptr;
2035+
}
2036+
20112037
Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) {
20122038
if (!isa<VectorType>(Inst.getType()))
20132039
return nullptr;

llvm/test/Transforms/InstCombine/fold-add-sub.ll

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ define i8 @test_add_nsw(i8 %x, i8 %y, i8 %z) {
88
; CHECK-NEXT: [[RHS:%.*]] = add nsw i8 [[X]], [[Z:%.*]]
99
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
1010
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
11-
; CHECK-NEXT: [[R:%.*]] = sub nsw i8 [[LHS]], [[RHS]]
11+
; CHECK-NEXT: [[R:%.*]] = sub nsw i8 [[Y]], [[Z]]
1212
; CHECK-NEXT: ret i8 [[R]]
1313
;
1414
%lhs = add nsw i8 %x, %y
@@ -25,7 +25,7 @@ define i8 @test_add_nsw_no_prop(i8 %x, i8 %y, i8 %z) {
2525
; CHECK-NEXT: [[RHS:%.*]] = add nuw i8 [[X]], [[Z:%.*]]
2626
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
2727
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
28-
; CHECK-NEXT: [[R:%.*]] = sub nsw i8 [[LHS]], [[RHS]]
28+
; CHECK-NEXT: [[R:%.*]] = sub i8 [[Y]], [[Z]]
2929
; CHECK-NEXT: ret i8 [[R]]
3030
;
3131
%lhs = add nsw i8 %x, %y
@@ -42,7 +42,7 @@ define i8 @test_add(i8 %x, i8 %y, i8 %z) {
4242
; CHECK-NEXT: [[RHS:%.*]] = add i8 [[X]], [[Z:%.*]]
4343
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
4444
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
45-
; CHECK-NEXT: [[R:%.*]] = sub i8 [[LHS]], [[RHS]]
45+
; CHECK-NEXT: [[R:%.*]] = sub i8 [[Y]], [[Z]]
4646
; CHECK-NEXT: ret i8 [[R]]
4747
;
4848
%lhs = add i8 %x, %y
@@ -76,7 +76,7 @@ define i8 @test_add_nuw(i8 %x, i8 %y, i8 %z) {
7676
; CHECK-NEXT: [[RHS:%.*]] = or disjoint i8 [[X]], [[Z:%.*]]
7777
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
7878
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
79-
; CHECK-NEXT: [[R:%.*]] = sub nuw i8 [[LHS]], [[RHS]]
79+
; CHECK-NEXT: [[R:%.*]] = sub nuw i8 [[Y]], [[Z]]
8080
; CHECK-NEXT: ret i8 [[R]]
8181
;
8282
%lhs = add i8 %x, %y
@@ -93,7 +93,7 @@ define i8 @test_add_nuw_no_prop(i8 %x, i8 %y, i8 %z) {
9393
; CHECK-NEXT: [[RHS:%.*]] = or disjoint i8 [[X]], [[Z:%.*]]
9494
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
9595
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
96-
; CHECK-NEXT: [[R:%.*]] = sub i8 [[LHS]], [[RHS]]
96+
; CHECK-NEXT: [[R:%.*]] = sub i8 [[Y]], [[Z]]
9797
; CHECK-NEXT: ret i8 [[R]]
9898
;
9999
%lhs = add i8 %x, %y
@@ -110,7 +110,7 @@ define i8 @test_sub_nuw(i8 %x, i8 %y, i8 %z) {
110110
; CHECK-NEXT: [[RHS:%.*]] = sub nuw i8 [[Y]], [[Z:%.*]]
111111
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
112112
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
113-
; CHECK-NEXT: [[R:%.*]] = add i8 [[LHS]], [[RHS]]
113+
; CHECK-NEXT: [[R:%.*]] = sub nuw i8 [[X]], [[Z]]
114114
; CHECK-NEXT: ret i8 [[R]]
115115
;
116116
%lhs = sub nuw i8 %x, %y
@@ -127,7 +127,7 @@ define i8 @test_sub_nuw_no_prop(i8 %x, i8 %y, i8 %z) {
127127
; CHECK-NEXT: [[RHS:%.*]] = sub i8 [[Y]], [[Z:%.*]]
128128
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
129129
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
130-
; CHECK-NEXT: [[R:%.*]] = add nuw i8 [[LHS]], [[RHS]]
130+
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X]], [[Z]]
131131
; CHECK-NEXT: ret i8 [[R]]
132132
;
133133
%lhs = sub nuw i8 %x, %y
@@ -144,7 +144,7 @@ define i8 @test_sub_nsw(i8 %x, i8 %y, i8 %z) {
144144
; CHECK-NEXT: [[RHS:%.*]] = sub nsw i8 [[Y]], [[Z:%.*]]
145145
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
146146
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
147-
; CHECK-NEXT: [[R:%.*]] = or disjoint i8 [[LHS]], [[RHS]]
147+
; CHECK-NEXT: [[R:%.*]] = sub nsw i8 [[X]], [[Z]]
148148
; CHECK-NEXT: ret i8 [[R]]
149149
;
150150
%lhs = sub nsw i8 %x, %y
@@ -161,7 +161,7 @@ define i8 @test_sub_nsw_no_prop(i8 %x, i8 %y, i8 %z) {
161161
; CHECK-NEXT: [[RHS:%.*]] = sub nsw i8 [[Y]], [[Z:%.*]]
162162
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
163163
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
164-
; CHECK-NEXT: [[R:%.*]] = or disjoint i8 [[LHS]], [[RHS]]
164+
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X]], [[Z]]
165165
; CHECK-NEXT: ret i8 [[R]]
166166
;
167167
%lhs = sub i8 %x, %y
@@ -178,7 +178,7 @@ define i8 @test_sub_none(i8 %x, i8 %y, i8 %z) {
178178
; CHECK-NEXT: [[RHS:%.*]] = sub i8 [[Y]], [[Z:%.*]]
179179
; CHECK-NEXT: call void @use.i8(i8 [[LHS]])
180180
; CHECK-NEXT: call void @use.i8(i8 [[RHS]])
181-
; CHECK-NEXT: [[R:%.*]] = add i8 [[LHS]], [[RHS]]
181+
; CHECK-NEXT: [[R:%.*]] = sub i8 [[X]], [[Z]]
182182
; CHECK-NEXT: ret i8 [[R]]
183183
;
184184
%lhs = sub i8 %x, %y

0 commit comments

Comments
 (0)