forked from OSchip/llvm-project
[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
This commit is contained in:
parent
06f1d63cb1
commit
53b00b8215
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue