Files
clang-p2996/llvm/test/Transforms/InstSimplify/floating-point-compare.ll
Bjorn Pettersson 4c7f820b2b Update @llvm.powi to handle different int sizes for the exponent
This can be seen as a follow up to commit 0ee439b705,
that changed the second argument of __powidf2, __powisf2 and
__powitf2 in compiler-rt from si_int to int. That was to align with
how those runtimes are defined in libgcc.
One thing that seem to have been missing in that patch was to make
sure that the rest of LLVM also handle that the argument now depends
on the size of int (not using the si_int machine mode for 32-bit).
When using __builtin_powi for a target with 16-bit int clang crashed.
And when emitting libcalls to those rtlib functions, typically when
lowering @llvm.powi), the backend would always prepare the exponent
argument as an i32 which caused miscompiles when the rtlib was
compiled with 16-bit int.

The solution used here is to use an overloaded type for the second
argument in @llvm.powi. This way clang can use the "correct" type
when lowering __builtin_powi, and then later when emitting the libcall
it is assumed that the type used in @llvm.powi matches the rtlib
function.

One thing that needed some extra attention was that when vectorizing
calls several passes did not support that several arguments could
be overloaded in the intrinsics. This patch allows overload of a
scalar operand by adding hasVectorInstrinsicOverloadedScalarOpd, with
an entry for powi.

Differential Revision: https://reviews.llvm.org/D99439
2021-06-17 09:38:28 +02:00

1233 lines
33 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -instsimplify -S | FileCheck %s
; Infinity
define i1 @inf0(double %arg) {
; CHECK-LABEL: @inf0(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp ogt double %arg, 0x7FF0000000000000
ret i1 %tmp
}
define i1 @inf1(double %arg) {
; CHECK-LABEL: @inf1(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp ule double %arg, 0x7FF0000000000000
ret i1 %tmp
}
; Negative infinity
define i1 @ninf0(double %arg) {
; CHECK-LABEL: @ninf0(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp olt double %arg, 0xFFF0000000000000
ret i1 %tmp
}
define i1 @ninf1(double %arg) {
; CHECK-LABEL: @ninf1(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp uge double %arg, 0xFFF0000000000000
ret i1 %tmp
}
; NaNs
define i1 @nan0(double %arg) {
; CHECK-LABEL: @nan0(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp ord double %arg, 0x7FF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nan1(double %arg) {
; CHECK-LABEL: @nan1(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp oeq double %arg, 0x7FF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nan2(double %arg) {
; CHECK-LABEL: @nan2(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp olt double %arg, 0x7FF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nan3(double %arg) {
; CHECK-LABEL: @nan3(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp uno double %arg, 0x7FF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nan4(double %arg) {
; CHECK-LABEL: @nan4(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp une double %arg, 0x7FF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nan5(double %arg) {
; CHECK-LABEL: @nan5(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp ult double %arg, 0x7FF00000FFFFFFFF
ret i1 %tmp
}
; Negative NaN.
define i1 @nnan0(double %arg) {
; CHECK-LABEL: @nnan0(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp ord double %arg, 0xFFF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nnan1(double %arg) {
; CHECK-LABEL: @nnan1(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp oeq double %arg, 0xFFF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nnan2(double %arg) {
; CHECK-LABEL: @nnan2(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp olt double %arg, 0xFFF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nnan3(double %arg) {
; CHECK-LABEL: @nnan3(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp uno double %arg, 0xFFF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nnan4(double %arg) {
; CHECK-LABEL: @nnan4(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp une double %arg, 0xFFF00000FFFFFFFF
ret i1 %tmp
}
define i1 @nnan5(double %arg) {
; CHECK-LABEL: @nnan5(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp ult double %arg, 0xFFF00000FFFFFFFF
ret i1 %tmp
}
; Negative zero.
define i1 @nzero0() {
; CHECK-LABEL: @nzero0(
; CHECK-NEXT: ret i1 true
;
%tmp = fcmp oeq double 0.0, -0.0
ret i1 %tmp
}
define i1 @nzero1() {
; CHECK-LABEL: @nzero1(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp ogt double 0.0, -0.0
ret i1 %tmp
}
; No enlightenment here.
define i1 @one_with_self(double %arg) {
; CHECK-LABEL: @one_with_self(
; CHECK-NEXT: ret i1 false
;
%tmp = fcmp one double %arg, %arg
ret i1 %tmp
}
; These tests choose arbitrarily between float and double,
; and between uge and olt, to give reasonble coverage
; without combinatorial explosion.
declare half @llvm.fabs.f16(half)
declare float @llvm.fabs.f32(float)
declare double @llvm.fabs.f64(double)
declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
declare <3 x float> @llvm.fabs.v3f32(<3 x float>)
declare <2 x double> @llvm.fabs.v2f64(<2 x double>)
declare float @llvm.sqrt.f32(float)
declare double @llvm.powi.f64.i32(double,i32)
declare float @llvm.exp.f32(float)
declare float @llvm.minnum.f32(float, float)
declare <2 x float> @llvm.minnum.v2f32(<2 x float>, <2 x float>)
declare float @llvm.maxnum.f32(float, float)
declare <2 x float> @llvm.maxnum.v2f32(<2 x float>, <2 x float>)
declare float @llvm.maximum.f32(float, float)
declare double @llvm.exp2.f64(double)
declare float @llvm.fma.f32(float,float,float)
declare void @expect_equal(i1,i1)
define i1 @orderedLessZeroTree(float,float,float,float) {
; CHECK-LABEL: @orderedLessZeroTree(
; CHECK-NEXT: ret i1 true
;
%square = fmul float %0, %0
%abs = call float @llvm.fabs.f32(float %1)
%sqrt = call float @llvm.sqrt.f32(float %2)
%fma = call float @llvm.fma.f32(float %3, float %3, float %sqrt)
%div = fdiv float %square, %abs
%rem = frem float %sqrt, %fma
%add = fadd float %div, %rem
%uge = fcmp uge float %add, 0.000000e+00
ret i1 %uge
}
define i1 @orderedLessZero_fdiv(float %x) {
; CHECK-LABEL: @orderedLessZero_fdiv(
; CHECK-NEXT: ret i1 true
;
%d = fdiv float %x, %x
%uge = fcmp uge float %d, 0.0
ret i1 %uge
}
; If x == -0.0, maxnum can return -0.0, but that still compares equal to 0.0.
define i1 @orderedLessZero_maxnum(float %x) {
; CHECK-LABEL: @orderedLessZero_maxnum(
; CHECK-NEXT: ret i1 true
;
%d = call float @llvm.maxnum.f32(float %x, float 0.0)
%uge = fcmp uge float %d, 0.0
ret i1 %uge
}
define i1 @orderedLessZeroExpExt(float) {
; CHECK-LABEL: @orderedLessZeroExpExt(
; CHECK-NEXT: ret i1 true
;
%a = call float @llvm.exp.f32(float %0)
%b = fpext float %a to double
%uge = fcmp uge double %b, 0.000000e+00
ret i1 %uge
}
define i1 @orderedLessZeroExp2Trunc(double) {
; CHECK-LABEL: @orderedLessZeroExp2Trunc(
; CHECK-NEXT: ret i1 false
;
%a = call double @llvm.exp2.f64(double %0)
%b = fptrunc double %a to float
%olt = fcmp olt float %b, 0.000000e+00
ret i1 %olt
}
define i1 @orderedLessZeroPowi(double,double) {
; CHECK-LABEL: @orderedLessZeroPowi(
; CHECK-NEXT: ret i1 false
;
; Even constant exponent
%a = call double @llvm.powi.f64.i32(double %0, i32 2)
%square = fmul double %1, %1
; Odd constant exponent with provably non-negative base
%b = call double @llvm.powi.f64.i32(double %square, i32 3)
%c = fadd double %a, %b
%olt = fcmp olt double %b, 0.000000e+00
ret i1 %olt
}
define i1 @UIToFP_is_nan_or_positive_or_zero(i32 %x) {
; CHECK-LABEL: @UIToFP_is_nan_or_positive_or_zero(
; CHECK-NEXT: ret i1 true
;
%a = uitofp i32 %x to float
%r = fcmp uge float %a, 0.000000e+00
ret i1 %r
}
define <2 x i1> @UIToFP_is_nan_or_positive_or_zero_vec(<2 x i32> %x) {
; CHECK-LABEL: @UIToFP_is_nan_or_positive_or_zero_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%a = uitofp <2 x i32> %x to <2 x float>
%r = fcmp uge <2 x float> %a, zeroinitializer
ret <2 x i1> %r
}
define i1 @UIToFP_is_positive_or_zero(i32 %x) {
; CHECK-LABEL: @UIToFP_is_positive_or_zero(
; CHECK-NEXT: ret i1 true
;
%a = uitofp i32 %x to float
%r = fcmp oge float %a, 0.000000e+00
ret i1 %r
}
define <2 x i1> @UIToFP_is_positive_or_zero_vec(<2 x i32> %x) {
; CHECK-LABEL: @UIToFP_is_positive_or_zero_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%a = uitofp <2 x i32> %x to <2 x float>
%r = fcmp oge <2 x float> %a, zeroinitializer
ret <2 x i1> %r
}
define i1 @UIToFP_nnan_is_positive_or_zero(i32 %x) {
; CHECK-LABEL: @UIToFP_nnan_is_positive_or_zero(
; CHECK-NEXT: ret i1 true
;
%a = uitofp i32 %x to float
%r = fcmp nnan oge float %a, 0.000000e+00
ret i1 %r
}
define <2 x i1> @UIToFP_nnan_is_positive_or_zero_vec(<2 x i32> %x) {
; CHECK-LABEL: @UIToFP_nnan_is_positive_or_zero_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%a = uitofp <2 x i32> %x to <2 x float>
%r = fcmp nnan oge <2 x float> %a, zeroinitializer
ret <2 x i1> %r
}
define i1 @UIToFP_is_not_negative(i32 %x) {
; CHECK-LABEL: @UIToFP_is_not_negative(
; CHECK-NEXT: ret i1 false
;
%a = uitofp i32 %x to float
%r = fcmp olt float %a, 0.000000e+00
ret i1 %r
}
define <2 x i1> @UIToFP_is_not_negative_vec(<2 x i32> %x) {
; CHECK-LABEL: @UIToFP_is_not_negative_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%a = uitofp <2 x i32> %x to <2 x float>
%r = fcmp olt <2 x float> %a, zeroinitializer
ret <2 x i1> %r
}
; No FMF are required for this transform.
define i1 @UIToFP_is_not_negative_or_nan(i32 %x) {
; CHECK-LABEL: @UIToFP_is_not_negative_or_nan(
; CHECK-NEXT: ret i1 false
;
%a = uitofp i32 %x to float
%r = fcmp ult float %a, 0.000000e+00
ret i1 %r
}
define <2 x i1> @UIToFP_is_not_negative_or_nan_vec(<2 x i32> %x) {
; CHECK-LABEL: @UIToFP_is_not_negative_or_nan_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%a = uitofp <2 x i32> %x to <2 x float>
%r = fcmp ult <2 x float> %a, zeroinitializer
ret <2 x i1> %r
}
define i1 @UIToFP_nnan_is_not_negative(i32 %x) {
; CHECK-LABEL: @UIToFP_nnan_is_not_negative(
; CHECK-NEXT: ret i1 false
;
%a = uitofp i32 %x to float
%r = fcmp nnan ult float %a, 0.000000e+00
ret i1 %r
}
define <2 x i1> @UIToFP_nnan_is_not_negative_vec(<2 x i32> %x) {
; CHECK-LABEL: @UIToFP_nnan_is_not_negative_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%a = uitofp <2 x i32> %x to <2 x float>
%r = fcmp nnan ult <2 x float> %a, zeroinitializer
ret <2 x i1> %r
}
define i1 @fabs_is_nan_or_positive_or_zero(double %x) {
; CHECK-LABEL: @fabs_is_nan_or_positive_or_zero(
; CHECK-NEXT: ret i1 true
;
%fabs = tail call double @llvm.fabs.f64(double %x)
%cmp = fcmp uge double %fabs, 0.0
ret i1 %cmp
}
define <2 x i1> @fabs_is_nan_or_positive_or_zero_vec(<2 x double> %x) {
; CHECK-LABEL: @fabs_is_nan_or_positive_or_zero_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x)
%cmp = fcmp uge <2 x double> %fabs, zeroinitializer
ret <2 x i1> %cmp
}
define i1 @fabs_nnan_is_positive_or_zero(double %x) {
; CHECK-LABEL: @fabs_nnan_is_positive_or_zero(
; CHECK-NEXT: ret i1 true
;
%fabs = tail call nnan double @llvm.fabs.f64(double %x)
%cmp = fcmp oge double %fabs, 0.0
ret i1 %cmp
}
define <2 x i1> @fabs_nnan_is_positive_or_zero_vec(<2 x double> %x) {
; CHECK-LABEL: @fabs_nnan_is_positive_or_zero_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%fabs = tail call nnan <2 x double> @llvm.fabs.v2f64(<2 x double> %x)
%cmp = fcmp oge <2 x double> %fabs, zeroinitializer
ret <2 x i1> %cmp
}
define i1 @fabs_fcmp-nnan_is_positive_or_zero(double %x) {
; CHECK-LABEL: @fabs_fcmp-nnan_is_positive_or_zero(
; CHECK-NEXT: ret i1 true
;
%fabs = tail call double @llvm.fabs.f64(double %x)
%cmp = fcmp nnan oge double %fabs, 0.0
ret i1 %cmp
}
define <2 x i1> @fabs_fcmp-nnan_is_positive_or_zero_vec(<2 x double> %x) {
; CHECK-LABEL: @fabs_fcmp-nnan_is_positive_or_zero_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x)
%cmp = fcmp nnan oge <2 x double> %fabs, zeroinitializer
ret <2 x i1> %cmp
}
define i1 @fabs_is_not_negative(double %x) {
; CHECK-LABEL: @fabs_is_not_negative(
; CHECK-NEXT: ret i1 false
;
%fabs = tail call double @llvm.fabs.f64(double %x)
%cmp = fcmp olt double %fabs, 0.0
ret i1 %cmp
}
define <2 x i1> @fabs_is_not_negative_vec(<2 x double> %x) {
; CHECK-LABEL: @fabs_is_not_negative_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x)
%cmp = fcmp olt <2 x double> %fabs, zeroinitializer
ret <2 x i1> %cmp
}
define i1 @fabs_nnan_is_not_negative(double %x) {
; CHECK-LABEL: @fabs_nnan_is_not_negative(
; CHECK-NEXT: ret i1 false
;
%fabs = tail call nnan double @llvm.fabs.f64(double %x)
%cmp = fcmp ult double %fabs, 0.0
ret i1 %cmp
}
define <2 x i1> @fabs_nnan_is_not_negative_vec(<2 x double> %x) {
; CHECK-LABEL: @fabs_nnan_is_not_negative_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%fabs = tail call nnan <2 x double> @llvm.fabs.v2f64(<2 x double> %x)
%cmp = fcmp ult <2 x double> %fabs, zeroinitializer
ret <2 x i1> %cmp
}
define i1 @fabs_fcmp-nnan_is_not_negative(double %x) {
; CHECK-LABEL: @fabs_fcmp-nnan_is_not_negative(
; CHECK-NEXT: ret i1 false
;
%fabs = tail call double @llvm.fabs.f64(double %x)
%cmp = fcmp nnan ult double %fabs, 0.0
ret i1 %cmp
}
define <2 x i1> @fabs_fcmp-nnan_is_not_negative_vec(<2 x double> %x) {
; CHECK-LABEL: @fabs_fcmp-nnan_is_not_negative_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%fabs = tail call <2 x double> @llvm.fabs.v2f64(<2 x double> %x)
%cmp = fcmp nnan ult <2 x double> %fabs, zeroinitializer
ret <2 x i1> %cmp
}
define <2 x i1> @fabs_is_not_negative_negzero(<2 x float> %V) {
; CHECK-LABEL: @fabs_is_not_negative_negzero(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%abs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %V)
%cmp = fcmp olt <2 x float> %abs, <float -0.0, float -0.0>
ret <2 x i1> %cmp
}
define <2 x i1> @fabs_is_not_negative_poszero(<2 x float> %V) {
; CHECK-LABEL: @fabs_is_not_negative_poszero(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%abs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %V)
%cmp = fcmp olt <2 x float> %abs, <float 0.0, float 0.0>
ret <2 x i1> %cmp
}
define <2 x i1> @fabs_is_not_negative_anyzero(<2 x float> %V) {
; CHECK-LABEL: @fabs_is_not_negative_anyzero(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%abs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %V)
%cmp = fcmp olt <2 x float> %abs, <float 0.0, float -0.0>
ret <2 x i1> %cmp
}
define <3 x i1> @fabs_is_not_negative_negzero_undef(<3 x float> %V) {
; CHECK-LABEL: @fabs_is_not_negative_negzero_undef(
; CHECK-NEXT: ret <3 x i1> zeroinitializer
;
%abs = call <3 x float> @llvm.fabs.v3f32(<3 x float> %V)
%cmp = fcmp olt <3 x float> %abs, <float -0.0, float -0.0, float undef>
ret <3 x i1> %cmp
}
define <3 x i1> @fabs_is_not_negative_poszero_undef(<3 x float> %V) {
; CHECK-LABEL: @fabs_is_not_negative_poszero_undef(
; CHECK-NEXT: ret <3 x i1> zeroinitializer
;
%abs = call <3 x float> @llvm.fabs.v3f32(<3 x float> %V)
%cmp = fcmp olt <3 x float> %abs, <float 0.0, float 0.0, float undef>
ret <3 x i1> %cmp
}
define <3 x i1> @fabs_is_not_negative_anyzero_undef(<3 x float> %V) {
; CHECK-LABEL: @fabs_is_not_negative_anyzero_undef(
; CHECK-NEXT: ret <3 x i1> zeroinitializer
;
%abs = call <3 x float> @llvm.fabs.v3f32(<3 x float> %V)
%cmp = fcmp olt <3 x float> %abs, <float 0.0, float -0.0, float undef>
ret <3 x i1> %cmp
}
define i1 @orderedLessZeroSelect(float, float) {
; CHECK-LABEL: @orderedLessZeroSelect(
; CHECK-NEXT: ret i1 true
;
%a = call float @llvm.exp.f32(float %0)
%b = call float @llvm.fabs.f32(float %1)
%c = fcmp olt float %0, %1
%d = select i1 %c, float %a, float %b
%e = fadd float %d, 1.0
%uge = fcmp uge float %e, 0.000000e+00
ret i1 %uge
}
define i1 @orderedLessZeroMinNum(float, float) {
; CHECK-LABEL: @orderedLessZeroMinNum(
; CHECK-NEXT: ret i1 true
;
%a = call float @llvm.exp.f32(float %0)
%b = call float @llvm.fabs.f32(float %1)
%c = call float @llvm.minnum.f32(float %a, float %b)
%uge = fcmp uge float %c, 0.000000e+00
ret i1 %uge
}
; PR37776: https://bugs.llvm.org/show_bug.cgi?id=37776
; exp() may return nan, leaving %1 as the unknown result, so we can't simplify.
define i1 @orderedLessZeroMaxNum(float, float) {
; CHECK-LABEL: @orderedLessZeroMaxNum(
; CHECK-NEXT: [[A:%.*]] = call float @llvm.exp.f32(float [[TMP0:%.*]])
; CHECK-NEXT: [[B:%.*]] = call float @llvm.maxnum.f32(float [[A]], float [[TMP1:%.*]])
; CHECK-NEXT: [[UGE:%.*]] = fcmp uge float [[B]], 0.000000e+00
; CHECK-NEXT: ret i1 [[UGE]]
;
%a = call float @llvm.exp.f32(float %0)
%b = call float @llvm.maxnum.f32(float %a, float %1)
%uge = fcmp uge float %b, 0.000000e+00
ret i1 %uge
}
; But using maximum, we can simplify, since the NaN would be propagated
define i1 @orderedLessZeroMaximum(float, float) {
; CHECK-LABEL: @orderedLessZeroMaximum(
; CHECK-NEXT: ret i1 true
;
%a = call float @llvm.exp.f32(float %0)
%b = call float @llvm.maximum.f32(float %a, float %1)
%uge = fcmp uge float %b, 0.000000e+00
ret i1 %uge
}
define i1 @minnum_non_nan(float %x) {
; CHECK-LABEL: @minnum_non_nan(
; CHECK-NEXT: ret i1 true
;
%min = call float @llvm.minnum.f32(float 0.5, float %x)
%cmp = fcmp ord float %min, 1.0
ret i1 %cmp
}
define i1 @maxnum_non_nan(float %x) {
; CHECK-LABEL: @maxnum_non_nan(
; CHECK-NEXT: ret i1 false
;
%min = call float @llvm.maxnum.f32(float %x, float 42.0)
%cmp = fcmp uno float %min, 12.0
ret i1 %cmp
}
; min(x, 0.5) == 1.0 --> false
define i1 @minnum_oeq_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_oeq_small_min_constant(
; CHECK-NEXT: ret i1 false
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp oeq float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) > 1.0 --> false
define i1 @minnum_ogt_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_ogt_small_min_constant(
; CHECK-NEXT: ret i1 false
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp ogt float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) >= 1.0 --> false
define i1 @minnum_oge_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_oge_small_min_constant(
; CHECK-NEXT: ret i1 false
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp oge float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) == 1.0 --> false
define i1 @minnum_ueq_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_ueq_small_min_constant(
; CHECK-NEXT: ret i1 false
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp ueq float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) > 1.0 --> false
define i1 @minnum_ugt_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_ugt_small_min_constant(
; CHECK-NEXT: ret i1 false
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp ugt float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) >= 1.0 --> false
define <2 x i1> @minnum_uge_small_min_constant(<2 x float> %x) {
; CHECK-LABEL: @minnum_uge_small_min_constant(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%min = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> <float 0.5, float 0.5>)
%cmp = fcmp uge <2 x float> %min, <float 1.0, float 1.0>
ret <2 x i1> %cmp
}
; min(x, 0.5) < 1.0 --> true
define <2 x i1> @minnum_olt_small_min_constant(<2 x float> %x) {
; CHECK-LABEL: @minnum_olt_small_min_constant(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%min = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> <float 0.5, float 0.5>)
%cmp = fcmp olt <2 x float> %min, <float 1.0, float 1.0>
ret <2 x i1> %cmp
}
; min(x, 0.5) <= 1.0 --> true
define i1 @minnum_ole_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_ole_small_min_constant(
; CHECK-NEXT: ret i1 true
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp ole float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) != 1.0 --> true
define i1 @minnum_one_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_one_small_min_constant(
; CHECK-NEXT: ret i1 true
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp one float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) < 1.0 --> true
define i1 @minnum_ult_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_ult_small_min_constant(
; CHECK-NEXT: ret i1 true
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp ult float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) <= 1.0 --> true
define i1 @minnum_ule_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_ule_small_min_constant(
; CHECK-NEXT: ret i1 true
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp ule float %min, 1.0
ret i1 %cmp
}
; min(x, 0.5) != 1.0 --> true
define i1 @minnum_une_small_min_constant(float %x) {
; CHECK-LABEL: @minnum_une_small_min_constant(
; CHECK-NEXT: ret i1 true
;
%min = call float @llvm.minnum.f32(float %x, float 0.5)
%cmp = fcmp une float %min, 1.0
ret i1 %cmp
}
; Negative test:
; min(x, 1.0) != 1.0 --> ?
define i1 @minnum_une_equal_min_constant(float %x) {
; CHECK-LABEL: @minnum_une_equal_min_constant(
; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 1.000000e+00)
; CHECK-NEXT: [[CMP:%.*]] = fcmp une float [[MIN]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%min = call float @llvm.minnum.f32(float %x, float 1.0)
%cmp = fcmp une float %min, 1.0
ret i1 %cmp
}
; Negative test:
; min(x, 2.0) != 1.0 --> ?
define i1 @minnum_une_large_min_constant(float %x) {
; CHECK-LABEL: @minnum_une_large_min_constant(
; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 2.000000e+00)
; CHECK-NEXT: [[CMP:%.*]] = fcmp une float [[MIN]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%min = call float @llvm.minnum.f32(float %x, float 2.0)
%cmp = fcmp une float %min, 1.0
ret i1 %cmp
}
; Partial negative test (the minnum simplifies):
; min(x, NaN) != 1.0 --> x != 1.0
define i1 @minnum_une_nan_min_constant(float %x) {
; CHECK-LABEL: @minnum_une_nan_min_constant(
; CHECK-NEXT: [[CMP:%.*]] = fcmp une float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%min = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000)
%cmp = fcmp une float %min, 1.0
ret i1 %cmp
}
; max(x, 1.5) == 1.0 --> false
define i1 @maxnum_oeq_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_oeq_large_max_constant(
; CHECK-NEXT: ret i1 false
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp oeq float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) < 1.0 --> false
define i1 @maxnum_olt_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_olt_large_max_constant(
; CHECK-NEXT: ret i1 false
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp olt float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) <= 1.0 --> false
define i1 @maxnum_ole_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_ole_large_max_constant(
; CHECK-NEXT: ret i1 false
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp ole float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) == 1.0 --> false
define i1 @maxnum_ueq_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_ueq_large_max_constant(
; CHECK-NEXT: ret i1 false
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp ueq float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) < 1.0 --> false
define i1 @maxnum_ult_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_ult_large_max_constant(
; CHECK-NEXT: ret i1 false
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp ult float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) <= 1.0 --> false
define <2 x i1> @maxnum_ule_large_max_constant(<2 x float> %x) {
; CHECK-LABEL: @maxnum_ule_large_max_constant(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%max = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> <float 1.5, float 1.5>)
%cmp = fcmp ule <2 x float> %max, <float 1.0, float 1.0>
ret <2 x i1> %cmp
}
; max(x, 1.5) > 1.0 --> true
define <2 x i1> @maxnum_ogt_large_max_constant(<2 x float> %x) {
; CHECK-LABEL: @maxnum_ogt_large_max_constant(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%max = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> <float 1.5, float 1.5>)
%cmp = fcmp ogt <2 x float> %max, <float 1.0, float 1.0>
ret <2 x i1> %cmp
}
; max(x, 1.5) >= 1.0 --> true
define i1 @maxnum_oge_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_oge_large_max_constant(
; CHECK-NEXT: ret i1 true
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp oge float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) != 1.0 --> true
define i1 @maxnum_one_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_one_large_max_constant(
; CHECK-NEXT: ret i1 true
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp one float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) > 1.0 --> true
define i1 @maxnum_ugt_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_ugt_large_max_constant(
; CHECK-NEXT: ret i1 true
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp ugt float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) >= 1.0 --> true
define i1 @maxnum_uge_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_uge_large_max_constant(
; CHECK-NEXT: ret i1 true
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp uge float %max, 1.0
ret i1 %cmp
}
; max(x, 1.5) != 1.0 --> true
define i1 @maxnum_une_large_max_constant(float %x) {
; CHECK-LABEL: @maxnum_une_large_max_constant(
; CHECK-NEXT: ret i1 true
;
%max = call float @llvm.maxnum.f32(float %x, float 1.5)
%cmp = fcmp une float %max, 1.0
ret i1 %cmp
}
; Negative test:
; max(x, 1.0) != 1.0 --> ?
define i1 @maxnum_une_equal_max_constant(float %x) {
; CHECK-LABEL: @maxnum_une_equal_max_constant(
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00)
; CHECK-NEXT: [[CMP:%.*]] = fcmp une float [[MAX]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%max = call float @llvm.maxnum.f32(float %x, float 1.0)
%cmp = fcmp une float %max, 1.0
ret i1 %cmp
}
; Negative test:
; max(x, 0.5) != 1.0 --> ?
define i1 @maxnum_une_small_max_constant(float %x) {
; CHECK-LABEL: @maxnum_une_small_max_constant(
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float 5.000000e-01)
; CHECK-NEXT: [[CMP:%.*]] = fcmp une float [[MAX]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%max = call float @llvm.maxnum.f32(float %x, float 0.5)
%cmp = fcmp une float %max, 1.0
ret i1 %cmp
}
; Partial negative test (the maxnum simplifies):
; max(x, NaN) != 1.0 --> x != 1.0
define i1 @maxnum_une_nan_max_constant(float %x) {
; CHECK-LABEL: @maxnum_une_nan_max_constant(
; CHECK-NEXT: [[CMP:%.*]] = fcmp une float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%max = call float @llvm.maxnum.f32(float %x, float 0x7FF8000000000000)
%cmp = fcmp une float %max, 1.0
ret i1 %cmp
}
define i1 @known_positive_olt_with_negative_constant(double %a) {
; CHECK-LABEL: @known_positive_olt_with_negative_constant(
; CHECK-NEXT: ret i1 false
;
%call = call double @llvm.fabs.f64(double %a)
%cmp = fcmp olt double %call, -1.0
ret i1 %cmp
}
define <2 x i1> @known_positive_ole_with_negative_constant_splat_vec(<2 x i32> %a) {
; CHECK-LABEL: @known_positive_ole_with_negative_constant_splat_vec(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%call = uitofp <2 x i32> %a to <2 x double>
%cmp = fcmp ole <2 x double> %call, <double -2.0, double -2.0>
ret <2 x i1> %cmp
}
define i1 @known_positive_ugt_with_negative_constant(i32 %a) {
; CHECK-LABEL: @known_positive_ugt_with_negative_constant(
; CHECK-NEXT: ret i1 true
;
%call = uitofp i32 %a to float
%cmp = fcmp ugt float %call, -3.0
ret i1 %cmp
}
define <2 x i1> @known_positive_uge_with_negative_constant_splat_vec(<2 x float> %a) {
; CHECK-LABEL: @known_positive_uge_with_negative_constant_splat_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%call = call <2 x float> @llvm.fabs.v2f32(<2 x float> %a)
%cmp = fcmp uge <2 x float> %call, <float -4.0, float -4.0>
ret <2 x i1> %cmp
}
define i1 @known_positive_oeq_with_negative_constant(half %a) {
; CHECK-LABEL: @known_positive_oeq_with_negative_constant(
; CHECK-NEXT: ret i1 false
;
%call = call half @llvm.fabs.f16(half %a)
%cmp = fcmp oeq half %call, -5.0
ret i1 %cmp
}
define <2 x i1> @known_positive_une_with_negative_constant_splat_vec(<2 x i32> %a) {
; CHECK-LABEL: @known_positive_une_with_negative_constant_splat_vec(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%call = uitofp <2 x i32> %a to <2 x half>
%cmp = fcmp une <2 x half> %call, <half -6.0, half -6.0>
ret <2 x i1> %cmp
}
define i1 @nonans1(double %in1, double %in2) {
; CHECK-LABEL: @nonans1(
; CHECK-NEXT: ret i1 false
;
%cmp = fcmp nnan uno double %in1, %in2
ret i1 %cmp
}
define i1 @nonans2(double %in1, double %in2) {
; CHECK-LABEL: @nonans2(
; CHECK-NEXT: ret i1 true
;
%cmp = fcmp nnan ord double %in1, %in2
ret i1 %cmp
}
define <2 x i1> @orderedCompareWithNaNVector(<2 x double> %A) {
; CHECK-LABEL: @orderedCompareWithNaNVector(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%cmp = fcmp olt <2 x double> %A, <double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF>
ret <2 x i1> %cmp
}
define <2 x i1> @orderedCompareWithNaNVector_undef_elt(<2 x double> %A) {
; CHECK-LABEL: @orderedCompareWithNaNVector_undef_elt(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%cmp = fcmp olt <2 x double> %A, <double 0xFFFFFFFFFFFFFFFF, double undef>
ret <2 x i1> %cmp
}
define <2 x i1> @unorderedCompareWithNaNVector_undef_elt(<2 x double> %A) {
; CHECK-LABEL: @unorderedCompareWithNaNVector_undef_elt(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%cmp = fcmp ult <2 x double> %A, <double undef, double 0xFFFFFFFFFFFFFFFF>
ret <2 x i1> %cmp
}
define i1 @is_infinite(float %x) {
; CHECK-LABEL: @is_infinite(
; CHECK-NEXT: ret i1 false
;
%xabs = call ninf float @llvm.fabs.f32(float %x)
%r = fcmp oeq float %xabs, 0x7FF0000000000000
ret i1 %r
}
define <2 x i1> @is_infinite_neg(<2 x float> %x) {
; CHECK-LABEL: @is_infinite_neg(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%x42 = fadd ninf <2 x float> %x, <float 42.0, float 42.0>
%r = fcmp oeq <2 x float> %x42, <float 0xFFF0000000000000, float 0xFFF0000000000000>
ret <2 x i1> %r
}
; Negative test - but this could be reduced to 'uno' outside of instsimplify.
define i1 @is_infinite_or_nan(float %x) {
; CHECK-LABEL: @is_infinite_or_nan(
; CHECK-NEXT: [[X42:%.*]] = fadd ninf float [[X:%.*]], 4.200000e+01
; CHECK-NEXT: [[R:%.*]] = fcmp ueq float [[X42]], 0xFFF0000000000000
; CHECK-NEXT: ret i1 [[R]]
;
%x42 = fadd ninf float %x, 42.0
%r = fcmp ueq float %x42, 0xFFF0000000000000
ret i1 %r
}
define i1 @is_infinite_or_nan2(float %x) {
; CHECK-LABEL: @is_infinite_or_nan2(
; CHECK-NEXT: ret i1 false
;
%xabs = call nnan ninf float @llvm.fabs.f32(float %x)
%r = fcmp ueq float %xabs, 0x7FF0000000000000
ret i1 %r
}
define <2 x i1> @is_infinite_neg_or_nan(<2 x float> %x) {
; CHECK-LABEL: @is_infinite_neg_or_nan(
; CHECK-NEXT: ret <2 x i1> zeroinitializer
;
%x42 = fadd nnan ninf <2 x float> %x, <float 42.0, float 42.0>
%r = fcmp ueq <2 x float> %x42, <float 0xFFF0000000000000, float 0xFFF0000000000000>
ret <2 x i1> %r
}
define i1 @is_finite_or_nan(i1 %c, double %x) {
; CHECK-LABEL: @is_finite_or_nan(
; CHECK-NEXT: ret i1 true
;
%xx = fmul ninf double %x, %x
%s = select i1 %c, double 42.0, double %xx
%r = fcmp une double %s, 0x7FF0000000000000
ret i1 %r
}
define <2 x i1> @is_finite_or_nan_commute(<2 x i8> %x) {
; CHECK-LABEL: @is_finite_or_nan_commute(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%cast = uitofp <2 x i8> %x to <2 x float>
%r = fcmp une <2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>, %cast
ret <2 x i1> %r
}
; Negative test - but this could be reduced to 'ord' outside of instsimplify.
define i1 @is_finite_and_ordered(double %x) {
; CHECK-LABEL: @is_finite_and_ordered(
; CHECK-NEXT: [[XX:%.*]] = fmul ninf double [[X:%.*]], [[X]]
; CHECK-NEXT: [[R:%.*]] = fcmp one double [[XX]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[R]]
;
%xx = fmul ninf double %x, %x
%r = fcmp one double %xx, 0x7FF0000000000000
ret i1 %r
}
define i1 @is_finite(i1 %c, double %x) {
; CHECK-LABEL: @is_finite(
; CHECK-NEXT: ret i1 true
;
%xx = fmul nnan ninf double %x, %x
%s = select i1 %c, double 42.0, double %xx
%r = fcmp one double %s, 0x7FF0000000000000
ret i1 %r
}
define <2 x i1> @is_finite_commute(<2 x i8> %x) {
; CHECK-LABEL: @is_finite_commute(
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
;
%cast = uitofp <2 x i8> %x to <2 x float>
%r = fcmp one <2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>, %cast
ret <2 x i1> %r
}
; largest unsigned i15 = 2^15 - 1 = 32767
; largest half (max exponent = 15 -> 2^15 * (1 + 1023/1024) = 65504
define i1 @isKnownNeverInfinity_uitofp(i15 %x) {
; CHECK-LABEL: @isKnownNeverInfinity_uitofp(
; CHECK-NEXT: ret i1 true
;
%f = uitofp i15 %x to half
%r = fcmp une half %f, 0xH7c00
ret i1 %r
}
; negative test
define i1 @isNotKnownNeverInfinity_uitofp(i16 %x) {
; CHECK-LABEL: @isNotKnownNeverInfinity_uitofp(
; CHECK-NEXT: [[F:%.*]] = uitofp i16 [[X:%.*]] to half
; CHECK-NEXT: [[R:%.*]] = fcmp une half [[F]], 0xH7C00
; CHECK-NEXT: ret i1 [[R]]
;
%f = uitofp i16 %x to half
%r = fcmp une half %f, 0xH7c00
ret i1 %r
}
define i1 @isKnownNeverNegativeInfinity_uitofp(i15 %x) {
; CHECK-LABEL: @isKnownNeverNegativeInfinity_uitofp(
; CHECK-NEXT: ret i1 false
;
%f = uitofp i15 %x to half
%r = fcmp oeq half %f, 0xHfc00
ret i1 %r
}
; uitofp can't be negative, so this still works.
define i1 @isNotKnownNeverNegativeInfinity_uitofp(i16 %x) {
; CHECK-LABEL: @isNotKnownNeverNegativeInfinity_uitofp(
; CHECK-NEXT: ret i1 false
;
%f = uitofp i16 %x to half
%r = fcmp oeq half %f, 0xHfc00
ret i1 %r
}
; largest magnitude signed i16 = 2^15 - 1 = 32767 --> -32768
; largest half (max exponent = 15 -> 2^15 * (1 + 1023/1024) = 65504
define i1 @isKnownNeverInfinity_sitofp(i16 %x) {
; CHECK-LABEL: @isKnownNeverInfinity_sitofp(
; CHECK-NEXT: ret i1 true
;
%f = sitofp i16 %x to half
%r = fcmp une half %f, 0xH7c00
ret i1 %r
}
; negative test
define i1 @isNotKnownNeverInfinity_sitofp(i17 %x) {
; CHECK-LABEL: @isNotKnownNeverInfinity_sitofp(
; CHECK-NEXT: [[F:%.*]] = sitofp i17 [[X:%.*]] to half
; CHECK-NEXT: [[R:%.*]] = fcmp une half [[F]], 0xH7C00
; CHECK-NEXT: ret i1 [[R]]
;
%f = sitofp i17 %x to half
%r = fcmp une half %f, 0xH7c00
ret i1 %r
}
define i1 @isKnownNeverNegativeInfinity_sitofp(i16 %x) {
; CHECK-LABEL: @isKnownNeverNegativeInfinity_sitofp(
; CHECK-NEXT: ret i1 false
;
%f = sitofp i16 %x to half
%r = fcmp oeq half %f, 0xHfc00
ret i1 %r
}
; negative test
define i1 @isNotKnownNeverNegativeInfinity_sitofp(i17 %x) {
; CHECK-LABEL: @isNotKnownNeverNegativeInfinity_sitofp(
; CHECK-NEXT: [[F:%.*]] = sitofp i17 [[X:%.*]] to half
; CHECK-NEXT: [[R:%.*]] = fcmp oeq half [[F]], 0xHFC00
; CHECK-NEXT: ret i1 [[R]]
;
%f = sitofp i17 %x to half
%r = fcmp oeq half %f, 0xHfc00
ret i1 %r
}