The div/rem constant expressions are going away in D129148. Convert some tests to use InstSimplify instead, to show that the constant folding still happens.
338 lines
8.3 KiB
LLVM
338 lines
8.3 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
|
|
|
|
define i32 @zero_dividend(i32 %A) {
|
|
; CHECK-LABEL: @zero_dividend(
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%B = sdiv i32 0, %A
|
|
ret i32 %B
|
|
}
|
|
|
|
define <2 x i32> @zero_dividend_vector(<2 x i32> %A) {
|
|
; CHECK-LABEL: @zero_dividend_vector(
|
|
; CHECK-NEXT: ret <2 x i32> zeroinitializer
|
|
;
|
|
%B = udiv <2 x i32> zeroinitializer, %A
|
|
ret <2 x i32> %B
|
|
}
|
|
|
|
define <2 x i32> @zero_dividend_vector_undef_elt(<2 x i32> %A) {
|
|
; CHECK-LABEL: @zero_dividend_vector_undef_elt(
|
|
; CHECK-NEXT: ret <2 x i32> zeroinitializer
|
|
;
|
|
%B = sdiv <2 x i32> <i32 0, i32 undef>, %A
|
|
ret <2 x i32> %B
|
|
}
|
|
|
|
; Division-by-zero is poison. UB in any vector lane means the whole op is poison.
|
|
|
|
define <2 x i8> @sdiv_zero_elt_vec_constfold(<2 x i8> %x) {
|
|
; CHECK-LABEL: @sdiv_zero_elt_vec_constfold(
|
|
; CHECK-NEXT: ret <2 x i8> poison
|
|
;
|
|
%div = sdiv <2 x i8> <i8 1, i8 2>, <i8 0, i8 -42>
|
|
ret <2 x i8> %div
|
|
}
|
|
|
|
define <2 x i8> @udiv_zero_elt_vec_constfold(<2 x i8> %x) {
|
|
; CHECK-LABEL: @udiv_zero_elt_vec_constfold(
|
|
; CHECK-NEXT: ret <2 x i8> poison
|
|
;
|
|
%div = udiv <2 x i8> <i8 1, i8 2>, <i8 42, i8 0>
|
|
ret <2 x i8> %div
|
|
}
|
|
|
|
define <2 x i8> @sdiv_zero_elt_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @sdiv_zero_elt_vec(
|
|
; CHECK-NEXT: ret <2 x i8> poison
|
|
;
|
|
%div = sdiv <2 x i8> %x, <i8 -42, i8 0>
|
|
ret <2 x i8> %div
|
|
}
|
|
|
|
define <2 x i8> @udiv_zero_elt_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @udiv_zero_elt_vec(
|
|
; CHECK-NEXT: ret <2 x i8> poison
|
|
;
|
|
%div = udiv <2 x i8> %x, <i8 0, i8 42>
|
|
ret <2 x i8> %div
|
|
}
|
|
|
|
define <2 x i8> @sdiv_undef_elt_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @sdiv_undef_elt_vec(
|
|
; CHECK-NEXT: ret <2 x i8> poison
|
|
;
|
|
%div = sdiv <2 x i8> %x, <i8 -42, i8 undef>
|
|
ret <2 x i8> %div
|
|
}
|
|
|
|
define <2 x i8> @udiv_undef_elt_vec(<2 x i8> %x) {
|
|
; CHECK-LABEL: @udiv_undef_elt_vec(
|
|
; CHECK-NEXT: ret <2 x i8> poison
|
|
;
|
|
%div = udiv <2 x i8> %x, <i8 undef, i8 42>
|
|
ret <2 x i8> %div
|
|
}
|
|
|
|
; Division-by-zero is undef. UB in any vector lane means the whole op is undef.
|
|
; Thus, we can simplify this: if any element of 'y' is 0, we can do anything.
|
|
; Therefore, assume that all elements of 'y' must be 1.
|
|
|
|
define <2 x i1> @sdiv_bool_vec(<2 x i1> %x, <2 x i1> %y) {
|
|
; CHECK-LABEL: @sdiv_bool_vec(
|
|
; CHECK-NEXT: ret <2 x i1> [[X:%.*]]
|
|
;
|
|
%div = sdiv <2 x i1> %x, %y
|
|
ret <2 x i1> %div
|
|
}
|
|
|
|
define <2 x i1> @udiv_bool_vec(<2 x i1> %x, <2 x i1> %y) {
|
|
; CHECK-LABEL: @udiv_bool_vec(
|
|
; CHECK-NEXT: ret <2 x i1> [[X:%.*]]
|
|
;
|
|
%div = udiv <2 x i1> %x, %y
|
|
ret <2 x i1> %div
|
|
}
|
|
|
|
define i32 @zext_bool_udiv_divisor(i1 %x, i32 %y) {
|
|
; CHECK-LABEL: @zext_bool_udiv_divisor(
|
|
; CHECK-NEXT: ret i32 [[Y:%.*]]
|
|
;
|
|
%ext = zext i1 %x to i32
|
|
%r = udiv i32 %y, %ext
|
|
ret i32 %r
|
|
}
|
|
|
|
define <2 x i32> @zext_bool_sdiv_divisor_vec(<2 x i1> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @zext_bool_sdiv_divisor_vec(
|
|
; CHECK-NEXT: ret <2 x i32> [[Y:%.*]]
|
|
;
|
|
%ext = zext <2 x i1> %x to <2 x i32>
|
|
%r = sdiv <2 x i32> %y, %ext
|
|
ret <2 x i32> %r
|
|
}
|
|
|
|
define i32 @udiv_dividend_known_smaller_than_constant_divisor(i32 %x) {
|
|
; CHECK-LABEL: @udiv_dividend_known_smaller_than_constant_divisor(
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%and = and i32 %x, 250
|
|
%div = udiv i32 %and, 251
|
|
ret i32 %div
|
|
}
|
|
|
|
define i32 @not_udiv_dividend_known_smaller_than_constant_divisor(i32 %x) {
|
|
; CHECK-LABEL: @not_udiv_dividend_known_smaller_than_constant_divisor(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 251
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AND]], 251
|
|
; CHECK-NEXT: ret i32 [[DIV]]
|
|
;
|
|
%and = and i32 %x, 251
|
|
%div = udiv i32 %and, 251
|
|
ret i32 %div
|
|
}
|
|
|
|
define i32 @udiv_constant_dividend_known_smaller_than_divisor(i32 %x) {
|
|
; CHECK-LABEL: @udiv_constant_dividend_known_smaller_than_divisor(
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%or = or i32 %x, 251
|
|
%div = udiv i32 250, %or
|
|
ret i32 %div
|
|
}
|
|
|
|
define i32 @not_udiv_constant_dividend_known_smaller_than_divisor(i32 %x) {
|
|
; CHECK-LABEL: @not_udiv_constant_dividend_known_smaller_than_divisor(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 251
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 251, [[OR]]
|
|
; CHECK-NEXT: ret i32 [[DIV]]
|
|
;
|
|
%or = or i32 %x, 251
|
|
%div = udiv i32 251, %or
|
|
ret i32 %div
|
|
}
|
|
|
|
define i8 @udiv_dividend_known_smaller_than_constant_divisor2(i1 %b) {
|
|
; CHECK-LABEL: @udiv_dividend_known_smaller_than_constant_divisor2(
|
|
; CHECK-NEXT: ret i8 0
|
|
;
|
|
%t0 = zext i1 %b to i8
|
|
%xor = xor i8 %t0, 12
|
|
%r = udiv i8 %xor, 14
|
|
ret i8 %r
|
|
}
|
|
|
|
; negative test - dividend can equal 13
|
|
|
|
define i8 @not_udiv_dividend_known_smaller_than_constant_divisor2(i1 %b) {
|
|
; CHECK-LABEL: @not_udiv_dividend_known_smaller_than_constant_divisor2(
|
|
; CHECK-NEXT: [[T0:%.*]] = zext i1 [[B:%.*]] to i8
|
|
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[T0]], 12
|
|
; CHECK-NEXT: [[R:%.*]] = udiv i8 [[XOR]], 13
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
;
|
|
%t0 = zext i1 %b to i8
|
|
%xor = xor i8 %t0, 12
|
|
%r = udiv i8 %xor, 13
|
|
ret i8 %r
|
|
}
|
|
|
|
; This would require computing known bits on both x and y. Is it worth doing?
|
|
|
|
define i32 @udiv_dividend_known_smaller_than_divisor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @udiv_dividend_known_smaller_than_divisor(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 250
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 251
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AND]], [[OR]]
|
|
; CHECK-NEXT: ret i32 [[DIV]]
|
|
;
|
|
%and = and i32 %x, 250
|
|
%or = or i32 %y, 251
|
|
%div = udiv i32 %and, %or
|
|
ret i32 %div
|
|
}
|
|
|
|
define i32 @not_udiv_dividend_known_smaller_than_divisor(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @not_udiv_dividend_known_smaller_than_divisor(
|
|
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 251
|
|
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 251
|
|
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[AND]], [[OR]]
|
|
; CHECK-NEXT: ret i32 [[DIV]]
|
|
;
|
|
%and = and i32 %x, 251
|
|
%or = or i32 %y, 251
|
|
%div = udiv i32 %and, %or
|
|
ret i32 %div
|
|
}
|
|
|
|
declare i32 @external()
|
|
|
|
define i32 @div1() {
|
|
; CHECK-LABEL: @div1(
|
|
; CHECK-NEXT: [[CALL:%.*]] = call i32 @external(), !range [[RNG0:![0-9]+]]
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%call = call i32 @external(), !range !0
|
|
%urem = udiv i32 %call, 3
|
|
ret i32 %urem
|
|
}
|
|
|
|
define i8 @sdiv_minusone_divisor() {
|
|
; CHECK-LABEL: @sdiv_minusone_divisor(
|
|
; CHECK-NEXT: ret i8 poison
|
|
;
|
|
%v = sdiv i8 -128, -1
|
|
ret i8 %v
|
|
}
|
|
|
|
@g = external global i64
|
|
@g2 = external global i64
|
|
|
|
define i64 @const_sdiv_one() {
|
|
; CHECK-LABEL: @const_sdiv_one(
|
|
; CHECK-NEXT: ret i64 ptrtoint (ptr @g to i64)
|
|
;
|
|
%div = sdiv i64 ptrtoint (ptr @g to i64), 1
|
|
ret i64 %div
|
|
}
|
|
|
|
define i64 @const_srem_one() {
|
|
; CHECK-LABEL: @const_srem_one(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%rem = srem i64 ptrtoint (ptr @g to i64), 1
|
|
ret i64 %rem
|
|
}
|
|
|
|
define i64 @const_udiv_one() {
|
|
; CHECK-LABEL: @const_udiv_one(
|
|
; CHECK-NEXT: ret i64 ptrtoint (ptr @g to i64)
|
|
;
|
|
%div = udiv i64 ptrtoint (ptr @g to i64), 1
|
|
ret i64 %div
|
|
}
|
|
|
|
define i64 @const_urem_one() {
|
|
; CHECK-LABEL: @const_urem_one(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%rem = urem i64 ptrtoint (ptr @g to i64), 1
|
|
ret i64 %rem
|
|
}
|
|
|
|
define i64 @const_sdiv_zero() {
|
|
; CHECK-LABEL: @const_sdiv_zero(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%div = sdiv i64 0, ptrtoint (ptr @g to i64)
|
|
ret i64 %div
|
|
}
|
|
|
|
define i64 @const_srem_zero() {
|
|
; CHECK-LABEL: @const_srem_zero(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%rem = srem i64 0, ptrtoint (ptr @g to i64)
|
|
ret i64 %rem
|
|
}
|
|
|
|
define i64 @const_udiv_zero() {
|
|
; CHECK-LABEL: @const_udiv_zero(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%div = udiv i64 0, ptrtoint (ptr @g to i64)
|
|
ret i64 %div
|
|
}
|
|
|
|
define i64 @const_urem_zero() {
|
|
; CHECK-LABEL: @const_urem_zero(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%rem = urem i64 0, ptrtoint (ptr @g to i64)
|
|
ret i64 %rem
|
|
}
|
|
|
|
define i64 @const_sdiv_zero_negone() {
|
|
; CHECK-LABEL: @const_sdiv_zero_negone(
|
|
; CHECK-NEXT: ret i64 0
|
|
;
|
|
%div = sdiv i64 0, -1
|
|
ret i64 %div
|
|
}
|
|
|
|
define i1 @const_sdiv_i1() {
|
|
; CHECK-LABEL: @const_sdiv_i1(
|
|
; CHECK-NEXT: ret i1 ptrtoint (ptr @g to i1)
|
|
;
|
|
%div = sdiv i1 ptrtoint (ptr @g to i1), ptrtoint (ptr @g2 to i1)
|
|
ret i1 %div
|
|
}
|
|
|
|
define i1 @const_srem_1() {
|
|
; CHECK-LABEL: @const_srem_1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%rem = srem i1 ptrtoint (ptr @g to i1), ptrtoint (ptr @g2 to i1)
|
|
ret i1 %rem
|
|
}
|
|
|
|
define i1 @const_udiv_i1() {
|
|
; CHECK-LABEL: @const_udiv_i1(
|
|
; CHECK-NEXT: ret i1 ptrtoint (ptr @g to i1)
|
|
;
|
|
%div = udiv i1 ptrtoint (ptr @g to i1), ptrtoint (ptr @g2 to i1)
|
|
ret i1 %div
|
|
}
|
|
|
|
define i1 @const_urem_1() {
|
|
; CHECK-LABEL: @const_urem_1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%rem = urem i1 ptrtoint (ptr @g to i1), ptrtoint (ptr @g2 to i1)
|
|
ret i1 %rem
|
|
}
|
|
|
|
|
|
!0 = !{i32 0, i32 3}
|