-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[InstCombine] Added optimisation for trunc (Negated Pow2 >> x) to i1 #157998
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
Conversation
@llvm/pr-subscribers-llvm-transforms Author: None (kper) ChangesFollow up of #157030
General proof Full diff: https://github.com/llvm/llvm-project/pull/157998.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index ccf918f0b6dbe..839286ca83ce9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -990,6 +990,15 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
return replaceInstUsesWith(Trunc, Icmp);
}
+ // OP = { lshr, ashr }
+ // trunc ( OP i8 C1, V1) to i1 -> icmp ugt V1, cttz(C1) - 1 iff (C1) is
+ // negative power of 2
+ if (DestWidth == 1 && match(Src, m_Shr(m_NegatedPower2(C1), m_Value(V1)))) {
+ Value *Right = ConstantInt::get(V1->getType(), C1->countr_zero() - 1);
+ Value *Icmp = Builder.CreateICmpUGT(V1, Right);
+ return replaceInstUsesWith(Trunc, Icmp);
+ }
+
return Changed ? &Trunc : nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/trunc-lshr.ll b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
index c443b35cb1c1e..0e996e5d017fe 100644
--- a/llvm/test/Transforms/InstCombine/trunc-lshr.ll
+++ b/llvm/test/Transforms/InstCombine/trunc-lshr.ll
@@ -219,3 +219,77 @@ define i1 @negative_test_fold_ashr(i8 %x) {
%trunc = trunc i8 %ashr to i1
ret i1 %trunc
}
+
+define i1 @fold_lshr_negated_power_of_2(i8 %x) {
+; CHECK-LABEL: define i1 @fold_lshr_negated_power_of_2(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT: [[TRUNC:%.*]] = icmp ugt i8 [[X]], 3
+; CHECK-NEXT: ret i1 [[TRUNC]]
+;
+ %lshr = lshr i8 -16, %x
+ %trunc = trunc i8 %lshr to i1
+ ret i1 %trunc
+}
+
+define i1 @fold_ashr_negated_power_of_2(i8 %x) {
+; CHECK-LABEL: define i1 @fold_ashr_negated_power_of_2(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT: [[TRUNC:%.*]] = icmp ugt i8 [[X]], 3
+; CHECK-NEXT: ret i1 [[TRUNC]]
+;
+ %ashr = ashr i8 -16, %x
+ %trunc = trunc i8 %ashr to i1
+ ret i1 %trunc
+}
+
+define i1 @fold_lshr_negated_power_of_2_multi_use(i8 %x) {
+; CHECK-LABEL: define i1 @fold_lshr_negated_power_of_2_multi_use(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i8 -16, [[X]]
+; CHECK-NEXT: call void @use(i8 [[LSHR]])
+; CHECK-NEXT: [[TRUNC:%.*]] = icmp ugt i8 [[X]], 3
+; CHECK-NEXT: ret i1 [[TRUNC]]
+;
+ %lshr = lshr i8 -16, %x
+ call void @use(i8 %lshr)
+ %trunc = trunc i8 %lshr to i1
+ ret i1 %trunc
+}
+
+define i1 @fold_ashr_negated_power_of_2_multi_use(i8 %x) {
+; CHECK-LABEL: define i1 @fold_ashr_negated_power_of_2_multi_use(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT: [[ASHR:%.*]] = ashr i8 -16, [[X]]
+; CHECK-NEXT: call void @use(i8 [[ASHR]])
+; CHECK-NEXT: [[TRUNC:%.*]] = icmp ugt i8 [[X]], 3
+; CHECK-NEXT: ret i1 [[TRUNC]]
+;
+ %ashr = ashr i8 -16, %x
+ call void @use(i8 %ashr)
+ %trunc = trunc i8 %ashr to i1
+ ret i1 %trunc
+}
+
+define i1 @negative_test_fold_lshr_negated_power_of_2(i8 %x) {
+; CHECK-LABEL: define i1 @negative_test_fold_lshr_negated_power_of_2(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i8 -17, [[X]]
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[LSHR]] to i1
+; CHECK-NEXT: ret i1 [[TRUNC]]
+;
+ %lshr = lshr i8 -17, %x
+ %trunc = trunc i8 %lshr to i1
+ ret i1 %trunc
+}
+
+define i1 @negative_test_fold_ashr_negated_power_of_2(i8 %x) {
+; CHECK-LABEL: define i1 @negative_test_fold_ashr_negated_power_of_2(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT: [[ASHR1:%.*]] = lshr i8 -17, [[X]]
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[ASHR1]] to i1
+; CHECK-NEXT: ret i1 [[TRUNC]]
+;
+ %ashr = ashr i8 -17, %x
+ %trunc = trunc i8 %ashr to i1
+ ret i1 %trunc
+}
|
@dtcxzyw can you run the benchmark to see whether it has some real world improvements? |
These proofs aren't correct: They check for a power of two which is a negative number, which is not the same as a negated power of two. Correct ones should be: https://alive2.llvm.org/ce/z/vVfaJc Note that these use |
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
@zyw-bot mfuzz |
Value *Icmp = Builder.CreateICmpUGE(V1, Right); | ||
return replaceInstUsesWith(Trunc, Icmp); |
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.
Value *Icmp = Builder.CreateICmpUGE(V1, Right); | |
return replaceInstUsesWith(Trunc, Icmp); | |
return new ICmpInst(ICmpInst::ICMP_UGE, Icmp, Right); |
See https://llvm.org/docs/InstCombineContributorGuide.html#instcombine-apis.
Can you also modify replaceInstUsesWith
above (introduced by #157030)?
Follow up of #157030
General proof
lshr: https://alive2.llvm.org/ce/z/vVfaJc
ashr: https://alive2.llvm.org/ce/z/8aAcgD