llvm-mirror/test/Transforms/InstSimplify/signed-div-rem.ll
Sanjay Patel 3e2b1fd515 [InstSimplify] fold sdiv/srem based on compare of dividend and divisor
This should bring signed div/rem analysis up to the same level as unsigned. 
We use icmp simplification to determine when the divisor is known greater than the dividend.

Each positive test is followed by a negative test to show that we're not overstepping the boundaries of the known bits.
There are extra tests for the signed-min-value special cases.

Alive proofs:
http://rise4fun.com/Alive/WI5

Differential Revision: https://reviews.llvm.org/D37713

llvm-svn: 313264
2017-09-14 14:59:07 +00:00

355 lines
9.7 KiB
LLVM

; RUN: opt < %s -instsimplify -S | FileCheck %s
define i32 @sdiv_sext_big_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_sext_big_divisor(
; CHECK-NEXT: ret i32 0
;
%conv = sext i8 %x to i32
%div = sdiv i32 %conv, 129
ret i32 %div
}
define i32 @not_sdiv_sext_big_divisor(i8 %x) {
; CHECK-LABEL: @not_sdiv_sext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], 128
; CHECK-NEXT: ret i32 [[DIV]]
;
%conv = sext i8 %x to i32
%div = sdiv i32 %conv, 128
ret i32 %div
}
define i32 @sdiv_sext_small_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_sext_small_divisor(
; CHECK-NEXT: ret i32 0
;
%conv = sext i8 %x to i32
%div = sdiv i32 %conv, -129
ret i32 %div
}
define i32 @not_sdiv_sext_small_divisor(i8 %x) {
; CHECK-LABEL: @not_sdiv_sext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], -128
; CHECK-NEXT: ret i32 [[DIV]]
;
%conv = sext i8 %x to i32
%div = sdiv i32 %conv, -128
ret i32 %div
}
define i32 @sdiv_zext_big_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_zext_big_divisor(
; CHECK-NEXT: ret i32 0
;
%conv = zext i8 %x to i32
%div = sdiv i32 %conv, 256
ret i32 %div
}
define i32 @not_sdiv_zext_big_divisor(i8 %x) {
; CHECK-LABEL: @not_sdiv_zext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], 255
; CHECK-NEXT: ret i32 [[DIV]]
;
%conv = zext i8 %x to i32
%div = sdiv i32 %conv, 255
ret i32 %div
}
define i32 @sdiv_zext_small_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_zext_small_divisor(
; CHECK-NEXT: ret i32 0
;
%conv = zext i8 %x to i32
%div = sdiv i32 %conv, -256
ret i32 %div
}
define i32 @not_sdiv_zext_small_divisor(i8 %x) {
; CHECK-LABEL: @not_sdiv_zext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[CONV]], -255
; CHECK-NEXT: ret i32 [[DIV]]
;
%conv = zext i8 %x to i32
%div = sdiv i32 %conv, -255
ret i32 %div
}
define i32 @sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(
; CHECK-NEXT: ret i32 0
;
%and = and i32 %x, 253
%div = sdiv i32 %and, 254
ret i32 %div
}
define i32 @not_sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_pos_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[AND]], 253
; CHECK-NEXT: ret i32 [[DIV]]
;
%and = and i32 %x, 253
%div = sdiv i32 %and, 253
ret i32 %div
}
define i32 @sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(
; CHECK-NEXT: ret i32 0
;
%and = and i32 %x, 253
%div = sdiv i32 %and, -254
ret i32 %div
}
define i32 @not_sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_neg_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[AND]], -253
; CHECK-NEXT: ret i32 [[DIV]]
;
%and = and i32 %x, 253
%div = sdiv i32 %and, -253
ret i32 %div
}
define i32 @sdiv_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_pos_divisor_set_bits(
; CHECK-NEXT: ret i32 0
;
%or = or i32 %x, -253
%div = sdiv i32 %or, 254
ret i32 %div
}
define i32 @not_sdiv_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_pos_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[OR]], 253
; CHECK-NEXT: ret i32 [[DIV]]
;
%or = or i32 %x, -253
%div = sdiv i32 %or, 253
ret i32 %div
}
define i32 @sdiv_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @sdiv_dividend_known_smaller_than_neg_divisor_set_bits(
; CHECK-NEXT: ret i32 0
;
%or = or i32 %x, -253
%div = sdiv i32 %or, -254
ret i32 %div
}
define i32 @not_sdiv_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @not_sdiv_dividend_known_smaller_than_neg_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[OR]], -253
; CHECK-NEXT: ret i32 [[DIV]]
;
%or = or i32 %x, -253
%div = sdiv i32 %or, -253
ret i32 %div
}
define i32 @srem_sext_big_divisor(i8 %x) {
; CHECK-LABEL: @srem_sext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = sext i8 %x to i32
%rem = srem i32 %conv, 129
ret i32 %rem
}
define i32 @not_srem_sext_big_divisor(i8 %x) {
; CHECK-LABEL: @not_srem_sext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], 128
; CHECK-NEXT: ret i32 [[REM]]
;
%conv = sext i8 %x to i32
%rem = srem i32 %conv, 128
ret i32 %rem
}
define i32 @srem_sext_small_divisor(i8 %x) {
; CHECK-LABEL: @srem_sext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = sext i8 %x to i32
%rem = srem i32 %conv, -129
ret i32 %rem
}
define i32 @not_srem_sext_small_divisor(i8 %x) {
; CHECK-LABEL: @not_srem_sext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = sext i8 %x to i32
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], -128
; CHECK-NEXT: ret i32 [[REM]]
;
%conv = sext i8 %x to i32
%rem = srem i32 %conv, -128
ret i32 %rem
}
define i32 @srem_zext_big_divisor(i8 %x) {
; CHECK-LABEL: @srem_zext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = zext i8 %x to i32
%rem = srem i32 %conv, 256
ret i32 %rem
}
define i32 @not_srem_zext_big_divisor(i8 %x) {
; CHECK-LABEL: @not_srem_zext_big_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], 255
; CHECK-NEXT: ret i32 [[REM]]
;
%conv = zext i8 %x to i32
%rem = srem i32 %conv, 255
ret i32 %rem
}
define i32 @srem_zext_small_divisor(i8 %x) {
; CHECK-LABEL: @srem_zext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
; CHECK-NEXT: ret i32 [[CONV]]
;
%conv = zext i8 %x to i32
%rem = srem i32 %conv, -256
ret i32 %rem
}
define i32 @not_srem_zext_small_divisor(i8 %x) {
; CHECK-LABEL: @not_srem_zext_small_divisor(
; CHECK-NEXT: [[CONV:%.*]] = zext i8 %x to i32
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[CONV]], -255
; CHECK-NEXT: ret i32 [[REM]]
;
%conv = zext i8 %x to i32
%rem = srem i32 %conv, -255
ret i32 %rem
}
define i32 @srem_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_pos_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
; CHECK-NEXT: ret i32 [[AND]]
;
%and = and i32 %x, 253
%rem = srem i32 %and, 254
ret i32 %rem
}
define i32 @not_srem_dividend_known_smaller_than_pos_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @not_srem_dividend_known_smaller_than_pos_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[AND]], 253
; CHECK-NEXT: ret i32 [[REM]]
;
%and = and i32 %x, 253
%rem = srem i32 %and, 253
ret i32 %rem
}
define i32 @srem_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_neg_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
; CHECK-NEXT: ret i32 [[AND]]
;
%and = and i32 %x, 253
%rem = srem i32 %and, -254
ret i32 %rem
}
define i32 @not_srem_dividend_known_smaller_than_neg_divisor_clear_bits(i32 %x) {
; CHECK-LABEL: @not_srem_dividend_known_smaller_than_neg_divisor_clear_bits(
; CHECK-NEXT: [[AND:%.*]] = and i32 %x, 253
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[AND]], -253
; CHECK-NEXT: ret i32 [[REM]]
;
%and = and i32 %x, 253
%rem = srem i32 %and, -253
ret i32 %rem
}
define i32 @srem_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_pos_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, -253
%rem = srem i32 %or, 254
ret i32 %rem
}
define i32 @not_srem_dividend_known_smaller_than_pos_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @not_srem_dividend_known_smaller_than_pos_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[OR]], 253
; CHECK-NEXT: ret i32 [[REM]]
;
%or = or i32 %x, -253
%rem = srem i32 %or, 253
ret i32 %rem
}
define i32 @srem_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @srem_dividend_known_smaller_than_neg_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
; CHECK-NEXT: ret i32 [[OR]]
;
%or = or i32 %x, -253
%rem = srem i32 %or, -254
ret i32 %rem
}
define i32 @not_srem_dividend_known_smaller_than_neg_divisor_set_bits(i32 %x) {
; CHECK-LABEL: @not_srem_dividend_known_smaller_than_neg_divisor_set_bits(
; CHECK-NEXT: [[OR:%.*]] = or i32 %x, -253
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[OR]], -253
; CHECK-NEXT: ret i32 [[REM]]
;
%or = or i32 %x, -253
%rem = srem i32 %or, -253
ret i32 %rem
}
; Make sure that we're handling the minimum signed constant correctly - can't fold this.
define i16 @sdiv_min_dividend(i8 %x) {
; CHECK-LABEL: @sdiv_min_dividend(
; CHECK-NEXT: [[Z:%.*]] = zext i8 %x to i16
; CHECK-NEXT: [[D:%.*]] = sdiv i16 -32768, [[Z]]
; CHECK-NEXT: ret i16 [[D]]
;
%z = zext i8 %x to i16
%d = sdiv i16 -32768, %z
ret i16 %d
}
; If the quotient is known to not be -32768, then this can fold.
define i16 @sdiv_min_divisor(i8 %x) {
; CHECK-LABEL: @sdiv_min_divisor(
; CHECK-NEXT: ret i16 0
;
%z = zext i8 %x to i16
%d = sdiv i16 %z, -32768
ret i16 %d
}