Skip to content

Commit a6edcea

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 Closes #105866
1 parent 155e3aa commit a6edcea

File tree

4 files changed

+76
-10
lines changed

4 files changed

+76
-10
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,24 @@ static Instruction *foldAddToAshr(BinaryOperator &Add) {
13041304
X, ConstantInt::get(Add.getType(), DivC->exactLogBase2()));
13051305
}
13061306

1307+
Instruction *InstCombinerImpl::foldAddLikeCommutative(Value *LHS, Value *RHS,
1308+
bool NSW, bool NUW) {
1309+
Value *A, *B, *C;
1310+
if (match(LHS, m_Sub(m_Value(A), m_Value(B))) &&
1311+
match(RHS, m_Sub(m_Value(C), m_Specific(A)))) {
1312+
Instruction *R = BinaryOperator::CreateSub(C, B);
1313+
bool NSWOut = NSW && match(LHS, m_NSWSub(m_Value(), m_Value())) &&
1314+
match(RHS, m_NSWSub(m_Value(), m_Value()));
1315+
1316+
bool NUWOut = match(LHS, m_NUWSub(m_Value(), m_Value())) &&
1317+
match(RHS, m_NUWSub(m_Value(), m_Value()));
1318+
R->setHasNoSignedWrap(NSWOut);
1319+
R->setHasNoUnsignedWrap(NUWOut);
1320+
return R;
1321+
}
1322+
return nullptr;
1323+
}
1324+
13071325
Instruction *InstCombinerImpl::
13081326
canonicalizeCondSignextOfHighBitExtractToSignextHighBitExtract(
13091327
BinaryOperator &I) {
@@ -1521,6 +1539,12 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
15211539
return R;
15221540

15231541
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
1542+
if (Instruction *R = foldAddLikeCommutative(LHS, RHS, I.hasNoSignedWrap(),
1543+
I.hasNoUnsignedWrap()))
1544+
return R;
1545+
if (Instruction *R = foldAddLikeCommutative(RHS, LHS, I.hasNoSignedWrap(),
1546+
I.hasNoUnsignedWrap()))
1547+
return R;
15241548
Type *Ty = I.getType();
15251549
if (Ty->isIntOrIntVectorTy(1))
15261550
return BinaryOperator::CreateXor(LHS, RHS);
@@ -2286,6 +2310,33 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
22862310
}
22872311
}
22882312

2313+
{
2314+
Value *W, *Z;
2315+
if (match(Op0, m_AddLike(m_Value(W), m_Value(X))) &&
2316+
match(Op1, m_AddLike(m_Value(Y), m_Value(Z)))) {
2317+
Instruction *R = nullptr;
2318+
if (W == Y)
2319+
R = BinaryOperator::CreateSub(X, Z);
2320+
else if (W == Z)
2321+
R = BinaryOperator::CreateSub(X, Y);
2322+
else if (X == Y)
2323+
R = BinaryOperator::CreateSub(W, Z);
2324+
else if (X == Z)
2325+
R = BinaryOperator::CreateSub(W, Y);
2326+
if (R) {
2327+
bool NSW = I.hasNoSignedWrap() &&
2328+
match(Op0, m_NSWAddLike(m_Value(), m_Value())) &&
2329+
match(Op1, m_NSWAddLike(m_Value(), m_Value()));
2330+
2331+
bool NUW = I.hasNoUnsignedWrap() &&
2332+
match(Op1, m_NUWAddLike(m_Value(), m_Value()));
2333+
R->setHasNoSignedWrap(NSW);
2334+
R->setHasNoUnsignedWrap(NUW);
2335+
return R;
2336+
}
2337+
}
2338+
}
2339+
22892340
// (~X) - (~Y) --> Y - X
22902341
{
22912342
// Need to ensure we can consume at least one of the `not` instructions,

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3580,6 +3580,17 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
35803580
if (Instruction *R = tryFoldInstWithCtpopWithNot(&I))
35813581
return R;
35823582

3583+
if (cast<PossiblyDisjointInst>(I).isDisjoint()) {
3584+
if (Instruction *R =
3585+
foldAddLikeCommutative(I.getOperand(0), I.getOperand(1),
3586+
/*NSW=*/true, /*NUW=*/true))
3587+
return R;
3588+
if (Instruction *R =
3589+
foldAddLikeCommutative(I.getOperand(1), I.getOperand(0),
3590+
/*NSW=*/true, /*NUW=*/true))
3591+
return R;
3592+
}
3593+
35833594
Value *X, *Y;
35843595
const APInt *CV;
35853596
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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,10 @@ 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 *foldAddLikeCommutative(Value *LHS, Value *RHS, bool NSW,
590+
bool NUW);
591+
588592
/// Canonicalize the position of binops relative to shufflevector.
589593
Instruction *foldVectorBinop(BinaryOperator &Inst);
590594
Instruction *foldVectorSelect(SelectInst &Sel);

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)