[llvm] [LVI] Handle icmp of ashr. (PR #68010)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 2 10:17:23 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
<details>
<summary>Changes</summary>
This handles the case where this combine:
icmp sgt (ashr X, ShAmtC), C --> icmp sgt X, ((C + 1) << ShAmtC) - 1
wasn't performed by instcombine.
Proof of the original combine: https://alive2.llvm.org/ce/z/SfpsvX
This is a port of the review in https://reviews.llvm.org/D151911 to GitHub.
---
Full diff: https://github.com/llvm/llvm-project/pull/68010.diff
2 Files Affected:
- (modified) llvm/lib/Analysis/LazyValueInfo.cpp (+52)
- (modified) llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll (+104)
``````````diff
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 0892aa9d75fb417..3a7b798178db278 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -26,6 +26,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
+#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
@@ -1148,6 +1149,57 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI,
CR.getUnsignedMin().zext(BitWidth), APInt(BitWidth, 0)));
}
+ // Recognize:
+ // icmp sgt (ashr X, ShAmtC), C --> icmp sgt X, ((C + 1) << ShAmtC) - 1
+ // and friends.
+ // Preconditions: (C != SIGNED_MAX) &&
+ // ((C+1) << ShAmtC != SIGNED_MIN) &&
+ // (((C+1) << ShAmtC) >> ShAmtC) == (C+1)
+ const APInt *ShAmtC;
+ if (CmpInst::isSigned(EdgePred) &&
+ match(LHS, m_AShr(m_Specific(Val), m_APInt(ShAmtC))) &&
+ match(RHS, m_APInt(C))) {
+ APInt New = ((*C + 1) << *ShAmtC) - 1;
+ APInt MaxSigned = APInt::getSignedMaxValue(New.getBitWidth());
+ APInt MinSigned = APInt::getSignedMinValue(New.getBitWidth());
+ auto CheckPreConds = [&]() {
+ if (*C == MaxSigned)
+ return false;
+ APInt Shifted = (*C + 1) << *ShAmtC;
+ if (Shifted == MinSigned)
+ return false;
+ if ((Shifted.ashr(*ShAmtC)) != (*C + 1))
+ return false;
+ return true;
+ };
+ if (!CheckPreConds())
+ return ValueLatticeElement::getOverdefined();
+ APInt Lower, Upper;
+ switch (EdgePred) {
+ default:
+ llvm_unreachable("Unknown signed predicate!");
+ case ICmpInst::ICMP_SGT:
+ Lower = New + 1;
+ Upper = MaxSigned;
+ break;
+ case ICmpInst::ICMP_SLE:
+ Lower = MinSigned;
+ Upper = New + 1;
+ break;
+ case ICmpInst::ICMP_SGE:
+ Lower = New;
+ Upper = MaxSigned;
+ break;
+ case ICmpInst::ICMP_SLT:
+ Lower = MinSigned;
+ Upper = New;
+ break;
+ }
+
+ return ValueLatticeElement::getRange(
+ ConstantRange::getNonEmpty(Lower, Upper));
+ }
+
return ValueLatticeElement::getOverdefined();
}
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
index c4f0ade39942a76..29225595281fb40 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
@@ -1240,6 +1240,110 @@ define <2 x i1> @non_const_range_minmax_vec(<2 x i8> %a, <2 x i8> %b) {
ret <2 x i1> %cmp1
}
+define void @ashr_sgt(i8 %x) {
+; CHECK-LABEL: @ashr_sgt(
+; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[S]], 0
+; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK: if:
+; CHECK-NEXT: call void @check1(i1 true)
+; CHECK-NEXT: [[C3:%.*]] = icmp ugt i8 [[X]], 4
+; CHECK-NEXT: call void @check1(i1 [[C3]])
+; CHECK-NEXT: ret void
+; CHECK: else:
+; CHECK-NEXT: ret void
+;
+ %s = ashr i8 %x, 2
+ %c = icmp sgt i8 %s, 0
+ br i1 %c, label %if, label %else
+if:
+ %c2 = icmp sgt i8 %x, 3
+ call void @check1(i1 %c2)
+ %c3 = icmp sgt i8 %x, 4
+ call void @check1(i1 %c3)
+ ret void
+else:
+ ret void
+}
+
+define void @ashr_sge(i8 %x) {
+; CHECK-LABEL: @ashr_sge(
+; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
+; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[S]], 0
+; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK: if:
+; CHECK-NEXT: call void @check1(i1 true)
+; CHECK-NEXT: [[C3:%.*]] = icmp uge i8 [[X]], 4
+; CHECK-NEXT: call void @check1(i1 [[C3]])
+; CHECK-NEXT: ret void
+; CHECK: else:
+; CHECK-NEXT: ret void
+;
+ %s = ashr i8 %x, 2
+ %c = icmp sge i8 %s, 0
+ br i1 %c, label %if, label %else
+if:
+ %c2 = icmp sge i8 %x, 3
+ call void @check1(i1 %c2)
+ %c3 = icmp sge i8 %x, 4
+ call void @check1(i1 %c3)
+ ret void
+else:
+ ret void
+}
+
+define void @ashr_slt(i8 %x) {
+; CHECK-LABEL: @ashr_slt(
+; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
+; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[S]], 0
+; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK: if:
+; CHECK-NEXT: call void @check1(i1 true)
+; CHECK-NEXT: [[C3:%.*]] = icmp slt i8 [[X]], 2
+; CHECK-NEXT: call void @check1(i1 [[C3]])
+; CHECK-NEXT: ret void
+; CHECK: else:
+; CHECK-NEXT: ret void
+;
+ %s = ashr i8 %x, 2
+ %c = icmp slt i8 %s, 0
+ br i1 %c, label %if, label %else
+if:
+ %c2 = icmp slt i8 %x, 3
+ call void @check1(i1 %c2)
+ %c3 = icmp slt i8 %x, 2
+ call void @check1(i1 %c3)
+ ret void
+else:
+ ret void
+}
+
+define void @ashr_sle(i8 %x) {
+; CHECK-LABEL: @ashr_sle(
+; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
+; CHECK-NEXT: [[C:%.*]] = icmp sle i8 [[S]], 0
+; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK: if:
+; CHECK-NEXT: call void @check1(i1 true)
+; CHECK-NEXT: [[C3:%.*]] = icmp sle i8 [[X]], 2
+; CHECK-NEXT: call void @check1(i1 [[C3]])
+; CHECK-NEXT: ret void
+; CHECK: else:
+; CHECK-NEXT: ret void
+;
+ %s = ashr i8 %x, 2
+ %c = icmp sle i8 %s, 0
+ br i1 %c, label %if, label %else
+if:
+ %c2 = icmp sle i8 %x, 3
+ call void @check1(i1 %c2)
+ %c3 = icmp sle i8 %x, 2
+ call void @check1(i1 %c3)
+ ret void
+else:
+ ret void
+}
+
declare i8 @llvm.umin.i8(i8, i8)
declare i8 @llvm.umax.i8(i8, i8)
declare <2 x i8> @llvm.umin.v2i8(<2 x i8>, <2 x i8>)
``````````
</details>
https://github.com/llvm/llvm-project/pull/68010
More information about the llvm-commits
mailing list