-
Notifications
You must be signed in to change notification settings - Fork 15k
[InstCombine] Add optimization to combine adds through zext nneg, and add testcase #157723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1910,6 +1910,32 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) { | |
| if (Instruction *Res = foldBinOpOfSelectAndCastOfSelectCondition(I)) | ||
| return Res; | ||
|
|
||
| { | ||
| Value *X; | ||
| const APInt *C1, *C2; | ||
| if (match(&I, | ||
| m_Add(m_NNegZExt(m_Add(m_Value(X), m_APInt(C1))), m_APInt(C2)))) { | ||
| // Check if inner constant C1 is negative C1 < 0 and outer constant C2 >= | ||
| // 0 | ||
| if (!C1->isNegative() || C2->isNegative()) | ||
| return nullptr; | ||
|
|
||
| APInt Sum = C1->sext(C2->getBitWidth()) + *C2; | ||
Aethezz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| APInt newSum = Sum.trunc(C1->getBitWidth()); | ||
|
|
||
| if (!Sum.isSignedIntN(C1->getBitWidth())) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per the alive proof in https://alive2.llvm.org/ce/z/pY63fh, you need to perform this check on C2, not on Sum. And if you do, then you don't need the additional check below. |
||
| return nullptr; | ||
|
|
||
| // X if sum is zero, else X + newSum | ||
| Value *Inner = | ||
| Sum.isZero() | ||
| ? X | ||
| : Builder.CreateAdd(X, ConstantInt::get(X->getType(), newSum)); | ||
Aethezz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| return new ZExtInst(Inner, I.getType()); | ||
| } | ||
| } | ||
|
|
||
| // Re-enqueue users of the induction variable of add recurrence if we infer | ||
| // new nuw/nsw flags. | ||
| if (Changed) { | ||
|
|
||
Aethezz marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -976,3 +976,85 @@ entry: | |
| %res = zext nneg i2 %x to i32 | ||
| ret i32 %res | ||
| } | ||
|
|
||
| define i32 @zext_nneg_add_cancel(i8 %arg) { | ||
| ; CHECK-LABEL: @zext_nneg_add_cancel( | ||
| ; CHECK-NEXT: [[ADD2:%.*]] = zext i8 [[ARG:%.*]] to i32 | ||
| ; CHECK-NEXT: ret i32 [[ADD2]] | ||
| ; | ||
| %add = add i8 %arg, -2 | ||
| %zext = zext nneg i8 %add to i32 | ||
| %add2 = add i32 %zext, 2 | ||
| ret i32 %add2 | ||
| } | ||
|
|
||
| define i32 @zext_nneg_add_cancel_multi_use(i8 %arg) { | ||
| ; CHECK-LABEL: @zext_nneg_add_cancel_multi_use( | ||
| ; CHECK-NEXT: [[ADD:%.*]] = add i8 [[ARG:%.*]], -2 | ||
| ; CHECK-NEXT: [[ZEXT:%.*]] = zext nneg i8 [[ADD]] to i32 | ||
| ; CHECK-NEXT: call void @use32(i32 [[ZEXT]]) | ||
| ; CHECK-NEXT: [[ADD2:%.*]] = zext i8 [[ARG]] to i32 | ||
| ; CHECK-NEXT: ret i32 [[ADD2]] | ||
| ; | ||
| %add = add i8 %arg, -2 | ||
| %zext = zext nneg i8 %add to i32 | ||
| call void @use32(i32 %zext) | ||
| %add2 = add i32 %zext, 2 | ||
| ret i32 %add2 | ||
| } | ||
|
|
||
| define i32 @zext_nneg_no_cancel(i8 %arg) { | ||
| ; CHECK-LABEL: @zext_nneg_no_cancel( | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[ARG:%.*]], -1 | ||
| ; CHECK-NEXT: [[ADD2:%.*]] = zext i8 [[TMP1]] to i32 | ||
| ; CHECK-NEXT: ret i32 [[ADD2]] | ||
| ; | ||
| %add = add i8 %arg, -2 | ||
| %zext = zext nneg i8 %add to i32 | ||
| %add2 = add i32 %zext, 1 | ||
| ret i32 %add2 | ||
| } | ||
|
|
||
| define i32 @zext_nneg_no_cancel_multi_use(i8 %arg) { | ||
| ; CHECK-LABEL: @zext_nneg_no_cancel_multi_use( | ||
| ; CHECK-NEXT: [[ADD:%.*]] = add i8 [[ARG:%.*]], -2 | ||
| ; CHECK-NEXT: [[ZEXT:%.*]] = zext nneg i8 [[ADD]] to i32 | ||
| ; CHECK-NEXT: call void @use32(i32 [[ZEXT]]) | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[ARG]], -1 | ||
| ; CHECK-NEXT: [[ADD2:%.*]] = zext i8 [[TMP1]] to i32 | ||
|
||
| ; CHECK-NEXT: ret i32 [[ADD2]] | ||
| ; | ||
| %add = add i8 %arg, -2 | ||
| %zext = zext nneg i8 %add to i32 | ||
| call void @use32(i32 %zext) | ||
| %add2 = add i32 %zext, 1 | ||
| ret i32 %add2 | ||
| } | ||
|
|
||
| define i32 @zext_nneg_overflow(i8 %arg) { | ||
| ; CHECK-LABEL: @zext_nneg_overflow( | ||
| ; CHECK-NEXT: [[ADD:%.*]] = add i8 [[ARG:%.*]], -2 | ||
| ; CHECK-NEXT: [[ZEXT:%.*]] = zext nneg i8 [[ADD]] to i32 | ||
| ; CHECK-NEXT: [[ADD2:%.*]] = add nuw nsw i32 [[ZEXT]], 299 | ||
| ; CHECK-NEXT: ret i32 [[ADD2]] | ||
| ; | ||
| %add = add i8 %arg, -2 | ||
| %zext = zext nneg i8 %add to i32 | ||
| %add2 = add i32 %zext, 299 | ||
| ret i32 %add2 | ||
| } | ||
|
|
||
| define i32 @zext_nneg_overflow_multi_use(i8 %arg) { | ||
Aethezz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ; CHECK-LABEL: @zext_nneg_overflow_multi_use( | ||
| ; CHECK-NEXT: [[ADD:%.*]] = add i8 [[ARG:%.*]], -2 | ||
| ; CHECK-NEXT: [[ZEXT:%.*]] = zext nneg i8 [[ADD]] to i32 | ||
| ; CHECK-NEXT: call void @use32(i32 [[ZEXT]]) | ||
| ; CHECK-NEXT: [[ADD2:%.*]] = add nuw nsw i32 [[ZEXT]], 299 | ||
| ; CHECK-NEXT: ret i32 [[ADD2]] | ||
| ; | ||
| %add = add i8 %arg, -2 | ||
| %zext = zext nneg i8 %add to i32 | ||
| call void @use32(i32 %zext) | ||
| %add2 = add i32 %zext, 299 | ||
| ret i32 %add2 | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you use early exits like this, the transform should be moved into a separate function. Otherwise there is a high risk of accidentally skipping transforms that get added after this point.