-
Notifications
You must be signed in to change notification settings - Fork 11.3k
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
[InstCombine] Fold (zext (X +nuw C)) + -C --> zext(X) when zext has additional use. #98533
Conversation
…, C1). NFC Add test where the zext has an additional use, but the entire expression can be replaced with (zext X). Folding even though there is an additional use would not increase the number of instructions.
…dditional use. We have a general fold for (zext (X +nuw C2)) + C1 --> zext (X + (C2 + trunc(C1))) but this fold is disabled if the zext has an additional use. If the two constants cancel, we can fold the whole expression to zext(X) without increasing the number of instructions. Though we will have 2 zexts which might be not be cheap. So another option could be to move the original narrow add after the zext for the other uses. That would allow sharing of the zext(x).
@llvm/pr-subscribers-llvm-transforms Author: Craig Topper (topperc) ChangesWe have a general fold for (zext (X +nuw C2)) + C1 --> zext (X + (C2 + trunc(C1))) If the two constants cancel, we can fold the whole expression to Though we will have 2 zexts which might be not be cheap. So Full diff: https://github.com/llvm/llvm-project/pull/98533.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 0a73c58c07409..0a55f4762fdf0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -819,11 +819,16 @@ static Instruction *foldNoWrapAdd(BinaryOperator &Add,
Value *X;
const APInt *C1, *C2;
if (match(Op1, m_APInt(C1)) &&
- match(Op0, m_OneUse(m_ZExt(m_NUWAddLike(m_Value(X), m_APInt(C2))))) &&
+ match(Op0, m_ZExt(m_NUWAddLike(m_Value(X), m_APInt(C2)))) &&
C1->isNegative() && C1->sge(-C2->sext(C1->getBitWidth()))) {
- Constant *NewC =
- ConstantInt::get(X->getType(), *C2 + C1->trunc(C2->getBitWidth()));
- return new ZExtInst(Builder.CreateNUWAdd(X, NewC), Ty);
+ APInt NewC = *C2 + C1->trunc(C2->getBitWidth());
+ // If the smaller add will fold to zero, we don't need to check one use.
+ if (NewC.isZero())
+ return new ZExtInst(X, Ty);
+ // Otherwise only do this if the existing zero extend will be removed.
+ if (Op0->hasOneUse())
+ return new ZExtInst(
+ Builder.CreateNUWAdd(X, ConstantInt::get(X->getType(), NewC)), Ty);
}
// More general combining of constants in the wide type.
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 8b3ecaf25cd9d..adb61cd4b9692 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -951,6 +951,21 @@ define i64 @test41(i32 %a) {
ret i64 %sub
}
+define i64 @test41_multiuse_constants_cancel(i32 %a) {
+; CHECK-LABEL: @test41_multiuse_constants_cancel(
+; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[A:%.*]], 1
+; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[ADD]] to i64
+; CHECK-NEXT: [[SUB:%.*]] = zext i32 [[A]] to i64
+; CHECK-NEXT: [[EXTRAUSE:%.*]] = add nuw nsw i64 [[ZEXT]], [[SUB]]
+; CHECK-NEXT: ret i64 [[EXTRAUSE]]
+;
+ %add = add nuw i32 %a, 1
+ %zext = zext i32 %add to i64
+ %sub = add i64 %zext, -1
+ %extrause = add i64 %zext, %sub
+ ret i64 %extrause
+}
+
; (add (zext (add nuw X, C2)), C) --> (zext (add nuw X, C2 + C))
define <2 x i64> @test41vec(<2 x i32> %a) {
|
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.
LGTM. Thank you!
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.
Sounds reasonable.
…dditional use. (llvm#98533) We have a general fold for (zext (X +nuw C2)) + C1 --> zext (X + (C2 + trunc(C1))) but this fold is disabled if the zext has an additional use. If the two constants cancel, we can fold the whole expression to zext(X) without increasing the number of instructions.
We have a general fold for (zext (X +nuw C2)) + C1 --> zext (X + (C2 + trunc(C1)))
but this fold is disabled if the zext has an additional use.
If the two constants cancel, we can fold the whole expression to
zext(X) without increasing the number of instructions.
Though we will have 2 zexts which might be not be cheap. So
another option could be to move the original narrow add after the zext
for the other uses. That would allow sharing of the zext(x).