Skip to content

Commit

Permalink
[InstSimplify] Peephole optimization for icmp (urem X, Y), X
Browse files Browse the repository at this point in the history
This revision adds the following peephole optimization
and it's negation:

    %a = urem i64 %x, %y
    %b = icmp ule i64 %a, %x
    ====>
    %b = true

With John Regehr's help this optimization was checked with Alive2
which suggests it should be valid.

This pattern occurs in the bound checks of Rust code, the program

    const N: usize = 3;
    const T = u8;

    pub fn split_mutiple(slice: &[T]) -> (&[T], &[T]) {
        let len = slice.len() / N;
        slice.split_at(len * N)
    }

the method call slice.split_at will check that len * N is within
the bounds of slice, this bounds check is after some transformations
turned into the urem seen above and then LLVM fails to optimize it
any further. Adding this optimization would cause this bounds check
to be fully optimized away.

ref: rust-lang/rust#74938

Differential Revision: https://reviews.llvm.org/D85092
  • Loading branch information
xldenis authored and nikic committed Aug 4, 2020
1 parent b778b04 commit 29fe3fe
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 12 deletions.
8 changes: 8 additions & 0 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2814,6 +2814,14 @@ static Value *simplifyICmpWithBinOpOnLHS(
}
}

// icmp pred (urem X, Y), X
if (match(LBO, m_URem(m_Specific(RHS), m_Value()))) {
if (Pred == ICmpInst::ICMP_ULE)
return getTrue(ITy);
if (Pred == ICmpInst::ICMP_UGT)
return getFalse(ITy);
}

// x >> y <=u x
// x udiv y <=u x.
if (match(LBO, m_LShr(m_Specific(RHS), m_Value())) ||
Expand Down
16 changes: 4 additions & 12 deletions llvm/test/Transforms/InstSimplify/compare.ll
Original file line number Diff line number Diff line change
Expand Up @@ -725,9 +725,7 @@ define i1 @urem7(i32 %X) {

define i1 @urem8(i8 %X, i8 %Y) {
; CHECK-LABEL: @urem8(
; CHECK-NEXT: [[A:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[B:%.*]] = icmp ule i8 [[A]], [[X]]
; CHECK-NEXT: ret i1 [[B]]
; CHECK-NEXT: ret i1 true
;
%A = urem i8 %X, %Y
%B = icmp ule i8 %A, %X
Expand All @@ -736,9 +734,7 @@ define i1 @urem8(i8 %X, i8 %Y) {

define i1 @urem9(i8 %X, i8 %Y) {
; CHECK-LABEL: @urem9(
; CHECK-NEXT: [[A:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 [[A]], [[X]]
; CHECK-NEXT: ret i1 [[B]]
; CHECK-NEXT: ret i1 false
;
%A = urem i8 %X, %Y
%B = icmp ugt i8 %A, %X
Expand All @@ -747,9 +743,7 @@ define i1 @urem9(i8 %X, i8 %Y) {

define i1 @urem10(i8 %X, i8 %Y) {
; CHECK-LABEL: @urem10(
; CHECK-NEXT: [[A:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[B:%.*]] = icmp uge i8 [[X]], [[A]]
; CHECK-NEXT: ret i1 [[B]]
; CHECK-NEXT: ret i1 true
;
%A = urem i8 %X, %Y
%B = icmp uge i8 %X, %A
Expand All @@ -758,9 +752,7 @@ define i1 @urem10(i8 %X, i8 %Y) {

define i1 @urem11(i8 %X, i8 %Y) {
; CHECK-LABEL: @urem11(
; CHECK-NEXT: [[A:%.*]] = urem i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[B:%.*]] = icmp ult i8 [[X]], [[A]]
; CHECK-NEXT: ret i1 [[B]]
; CHECK-NEXT: ret i1 false
;
%A = urem i8 %X, %Y
%B = icmp ult i8 %X, %A
Expand Down

0 comments on commit 29fe3fe

Please sign in to comment.