[llvm] 53b00b8 - [InstSimplify] Fold X {lshr,udiv} C <u X --> true for nonzero X, non-identity C
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 26 13:49:43 PST 2021
Author: Erik Desjardins
Date: 2021-11-26T16:48:33-05:00
New Revision: 53b00b821582a95c5186bd76e7e7d12d2697a630
URL: https://github.com/llvm/llvm-project/commit/53b00b821582a95c5186bd76e7e7d12d2697a630
DIFF: https://github.com/llvm/llvm-project/commit/53b00b821582a95c5186bd76e7e7d12d2697a630.diff
LOG: [InstSimplify] Fold X {lshr,udiv} C <u X --> true for nonzero X, non-identity C
This eliminates the bounds check in Rust code like
pub fn mid(data: &[i32]) -> i32 {
if data.is_empty() { return 0; }
return data[data.len()/2];
}
(from https://blog.sigplan.org/2021/11/18/undefined-behavior-deserves-a-better-reputation/)
Alive proofs:
lshr https://alive2.llvm.org/ce/z/nyTu8D
udiv https://alive2.llvm.org/ce/z/CNUZH7
Differential Revision: https://reviews.llvm.org/D114279
Added:
Modified:
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstSimplify/compare.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index a411c4338e235..cab3455b98197 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2960,8 +2960,10 @@ static Value *simplifyICmpWithBinOpOnLHS(
return getFalse(ITy);
}
- // x >> y <=u x
- // x udiv y <=u x.
+ // x >>u y <=u x --> true.
+ // x >>u y >u x --> false.
+ // x udiv y <=u x --> true.
+ // x udiv y >u x --> false.
if (match(LBO, m_LShr(m_Specific(RHS), m_Value())) ||
match(LBO, m_UDiv(m_Specific(RHS), m_Value()))) {
// icmp pred (X op Y), X
@@ -2971,6 +2973,37 @@ static Value *simplifyICmpWithBinOpOnLHS(
return getTrue(ITy);
}
+ // If x is nonzero:
+ // x >>u C <u x --> true for C != 0.
+ // x >>u C != x --> true for C != 0.
+ // x >>u C >=u x --> false for C != 0.
+ // x >>u C == x --> false for C != 0.
+ // x udiv C <u x --> true for C != 1.
+ // x udiv C != x --> true for C != 1.
+ // x udiv C >=u x --> false for C != 1.
+ // x udiv C == x --> false for C != 1.
+ // TODO: allow non-constant shift amount/divisor
+ const APInt *C;
+ if ((match(LBO, m_LShr(m_Specific(RHS), m_APInt(C))) && *C != 0) ||
+ (match(LBO, m_UDiv(m_Specific(RHS), m_APInt(C))) && *C != 1)) {
+ if (isKnownNonZero(RHS, Q.DL, 0, Q.AC, Q.CxtI, Q.DT)) {
+ switch (Pred) {
+ default:
+ break;
+ case ICmpInst::ICMP_EQ:
+ case ICmpInst::ICMP_UGE:
+ return getFalse(ITy);
+ case ICmpInst::ICMP_NE:
+ case ICmpInst::ICMP_ULT:
+ return getTrue(ITy);
+ case ICmpInst::ICMP_UGT:
+ case ICmpInst::ICMP_ULE:
+ // UGT/ULE are handled by the more general case just above
+ llvm_unreachable("Unexpected UGT/ULE, should have been handled");
+ }
+ }
+ }
+
// (x*C1)/C2 <= x for C1 <= C2.
// This holds even if the multiplication overflows: Assume that x != 0 and
// arithmetic is modulo M. For overflow to occur we must have C1 >= M/x and
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index 223ad6466fa40..dce8f95ef7f1d 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -582,9 +582,7 @@ define i1 @lshr_nonzero_eq(i32 %x) {
; CHECK-LABEL: @lshr_nonzero_eq(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
@@ -597,9 +595,7 @@ define i1 @lshr_nonzero_uge(i32 %x) {
; CHECK-LABEL: @lshr_nonzero_uge(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
@@ -612,9 +608,7 @@ define i1 @lshr_nonzero_ne(i32 %x) {
; CHECK-LABEL: @lshr_nonzero_ne(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
@@ -627,9 +621,7 @@ define i1 @lshr_nonzero_ult(i32 %x) {
; CHECK-LABEL: @lshr_nonzero_ult(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
@@ -998,9 +990,7 @@ define i1 @udiv_nonzero_eq(i32 %x) {
; CHECK-LABEL: @udiv_nonzero_eq(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
@@ -1013,9 +1003,7 @@ define i1 @udiv_nonzero_uge(i32 %x) {
; CHECK-LABEL: @udiv_nonzero_uge(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3
-; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
@@ -1028,9 +1016,7 @@ define i1 @udiv_nonzero_ne(i32 %x) {
; CHECK-LABEL: @udiv_nonzero_ne(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
@@ -1043,9 +1029,7 @@ define i1 @udiv_nonzero_ult(i32 %x) {
; CHECK-LABEL: @udiv_nonzero_ult(
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
-; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%x_ne_0 = icmp ne i32 %x, 0
call void @llvm.assume(i1 %x_ne_0)
More information about the llvm-commits
mailing list