Yingwei Zheng cab09e76e0
[InstCombine] Propagate FMF from fptrunc when folding fptrunc fabs(X) -> fabs(fptrunc X) (#143352)
Alive2: https://alive2.llvm.org/ce/z/DWV3G3
fptrunc yields infinity when the input cannot fit in the target type. So
ninf should be propagated from fptrunc. For other intrinsics, the
previous check ensures that the result is never an infinity:

5d3899d293/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp (L1910-L1917)

Closes https://github.com/llvm/llvm-project/issues/143122.
2025-06-16 12:07:47 +08:00

1785 lines
66 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -mtriple=x86_64-unknown-linux-gnu < %s -passes=instcombine -S | FileCheck %s
; Make sure libcalls are replaced with intrinsic calls.
declare float @llvm.fabs.f32(float)
declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
declare double @llvm.fabs.f64(double)
declare fp128 @llvm.fabs.f128(fp128)
declare float @fabsf(float)
declare double @fabs(double)
declare fp128 @fabsl(fp128)
declare float @llvm.fma.f32(float, float, float)
declare float @llvm.fmuladd.f32(float, float, float)
declare void @use(float)
declare void @usebool(i1)
define float @replace_fabs_call_f32(float %x) {
; CHECK-LABEL: @replace_fabs_call_f32(
; CHECK-NEXT: [[FABSF:%.*]] = tail call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: ret float [[FABSF]]
;
%fabsf = tail call float @fabsf(float %x)
ret float %fabsf
}
define double @replace_fabs_call_f64(double %x) {
; CHECK-LABEL: @replace_fabs_call_f64(
; CHECK-NEXT: [[FABS:%.*]] = tail call double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%fabs = tail call double @fabs(double %x)
ret double %fabs
}
define fp128 @replace_fabs_call_f128(fp128 %x) {
; CHECK-LABEL: @replace_fabs_call_f128(
; CHECK-NEXT: [[FABSL:%.*]] = tail call fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
; CHECK-NEXT: ret fp128 [[FABSL]]
;
%fabsl = tail call fp128 @fabsl(fp128 %x)
ret fp128 %fabsl
}
; Make sure fast math flags are preserved when replacing the libcall.
define float @fmf_replace_fabs_call_f32(float %x) {
; CHECK-LABEL: @fmf_replace_fabs_call_f32(
; CHECK-NEXT: [[FABSF:%.*]] = tail call nnan float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: ret float [[FABSF]]
;
%fabsf = tail call nnan float @fabsf(float %x)
ret float %fabsf
}
; Make sure all intrinsic calls are eliminated when the input is known
; positive.
; The fabs cannot be eliminated because %x may be a NaN
define float @square_fabs_intrinsic_f32(float %x) {
; CHECK-LABEL: @square_fabs_intrinsic_f32(
; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X:%.*]], [[X]]
; CHECK-NEXT: [[FABSF:%.*]] = tail call float @llvm.fabs.f32(float [[MUL]])
; CHECK-NEXT: ret float [[FABSF]]
;
%mul = fmul float %x, %x
%fabsf = tail call float @llvm.fabs.f32(float %mul)
ret float %fabsf
}
define double @square_fabs_intrinsic_f64(double %x) {
; CHECK-LABEL: @square_fabs_intrinsic_f64(
; CHECK-NEXT: [[MUL:%.*]] = fmul double [[X:%.*]], [[X]]
; CHECK-NEXT: [[FABS:%.*]] = tail call double @llvm.fabs.f64(double [[MUL]])
; CHECK-NEXT: ret double [[FABS]]
;
%mul = fmul double %x, %x
%fabs = tail call double @llvm.fabs.f64(double %mul)
ret double %fabs
}
define fp128 @square_fabs_intrinsic_f128(fp128 %x) {
; CHECK-LABEL: @square_fabs_intrinsic_f128(
; CHECK-NEXT: [[MUL:%.*]] = fmul fp128 [[X:%.*]], [[X]]
; CHECK-NEXT: [[FABSL:%.*]] = tail call fp128 @llvm.fabs.f128(fp128 [[MUL]])
; CHECK-NEXT: ret fp128 [[FABSL]]
;
%mul = fmul fp128 %x, %x
%fabsl = tail call fp128 @llvm.fabs.f128(fp128 %mul)
ret fp128 %fabsl
}
define float @square_nnan_fabs_intrinsic_f32(float %x) {
; CHECK-LABEL: @square_nnan_fabs_intrinsic_f32(
; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[X:%.*]], [[X]]
; CHECK-NEXT: ret float [[MUL]]
;
%mul = fmul nnan float %x, %x
%fabsf = call float @llvm.fabs.f32(float %mul)
ret float %fabsf
}
; Shrinking a library call to a smaller type should not be inhibited by nor inhibit the square optimization.
define float @square_fabs_shrink_call1(float %x) {
; CHECK-LABEL: @square_fabs_shrink_call1(
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[X]]
; CHECK-NEXT: [[TRUNC:%.*]] = call float @llvm.fabs.f32(float [[TMP1]])
; CHECK-NEXT: ret float [[TRUNC]]
;
%ext = fpext float %x to double
%sq = fmul double %ext, %ext
%fabs = call double @fabs(double %sq)
%trunc = fptrunc double %fabs to float
ret float %trunc
}
define float @square_fabs_shrink_call2(float %x) {
; CHECK-LABEL: @square_fabs_shrink_call2(
; CHECK-NEXT: [[SQ:%.*]] = fmul float [[X:%.*]], [[X]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[SQ]])
; CHECK-NEXT: ret float [[TMP1]]
;
%sq = fmul float %x, %x
%ext = fpext float %sq to double
%fabs = call double @fabs(double %ext)
%trunc = fptrunc double %fabs to float
ret float %trunc
}
define float @fabs_select_constant_negative_positive(i32 %c) {
; CHECK-LABEL: @fabs_select_constant_negative_positive(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
; CHECK-NEXT: ret float [[FABS]]
;
%cmp = icmp eq i32 %c, 0
%select = select i1 %cmp, float -1.0, float 2.0
%fabs = call float @llvm.fabs.f32(float %select)
ret float %fabs
}
define float @fabs_select_constant_positive_negative(i32 %c) {
; CHECK-LABEL: @fabs_select_constant_positive_negative(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
; CHECK-NEXT: ret float [[FABS]]
;
%cmp = icmp eq i32 %c, 0
%select = select i1 %cmp, float 1.0, float -2.0
%fabs = call float @llvm.fabs.f32(float %select)
ret float %fabs
}
define float @fabs_select_constant_negative_negative(i32 %c) {
; CHECK-LABEL: @fabs_select_constant_negative_negative(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[CMP]], float 1.000000e+00, float 2.000000e+00
; CHECK-NEXT: ret float [[FABS]]
;
%cmp = icmp eq i32 %c, 0
%select = select i1 %cmp, float -1.0, float -2.0
%fabs = call float @llvm.fabs.f32(float %select)
ret float %fabs
}
define float @fabs_select_constant_neg0(i32 %c) {
; CHECK-LABEL: @fabs_select_constant_neg0(
; CHECK-NEXT: ret float 0.000000e+00
;
%cmp = icmp eq i32 %c, 0
%select = select i1 %cmp, float -0.0, float 0.0
%fabs = call float @llvm.fabs.f32(float %select)
ret float %fabs
}
define float @fabs_select_var_constant_negative(i32 %c, float %x) {
; CHECK-LABEL: @fabs_select_var_constant_negative(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT:%.*]])
; CHECK-NEXT: [[FABS1:%.*]] = select i1 [[CMP]], float [[FABS]], float 1.000000e+00
; CHECK-NEXT: ret float [[FABS1]]
;
%cmp = icmp eq i32 %c, 0
%select = select i1 %cmp, float %x, float -1.0
%fabs = call float @llvm.fabs.f32(float %select)
ret float %fabs
}
; The fabs cannot be eliminated because %x may be a NaN
define float @square_fma_fabs_intrinsic_f32(float %x) {
; CHECK-LABEL: @square_fma_fabs_intrinsic_f32(
; CHECK-NEXT: [[FMA:%.*]] = call float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
; CHECK-NEXT: [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMA]])
; CHECK-NEXT: ret float [[FABSF]]
;
%fma = call float @llvm.fma.f32(float %x, float %x, float 1.0)
%fabsf = call float @llvm.fabs.f32(float %fma)
ret float %fabsf
}
; The fabs cannot be eliminated because %x may be a NaN
define float @square_nnan_fma_fabs_intrinsic_f32(float %x) {
; CHECK-LABEL: @square_nnan_fma_fabs_intrinsic_f32(
; CHECK-NEXT: [[FMA:%.*]] = call nnan float @llvm.fma.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
; CHECK-NEXT: ret float [[FMA]]
;
%fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.0)
%fabsf = call float @llvm.fabs.f32(float %fma)
ret float %fabsf
}
define float @square_fmuladd_fabs_intrinsic_f32(float %x) {
; CHECK-LABEL: @square_fmuladd_fabs_intrinsic_f32(
; CHECK-NEXT: [[FMULADD:%.*]] = call float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
; CHECK-NEXT: [[FABSF:%.*]] = call float @llvm.fabs.f32(float [[FMULADD]])
; CHECK-NEXT: ret float [[FABSF]]
;
%fmuladd = call float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
%fabsf = call float @llvm.fabs.f32(float %fmuladd)
ret float %fabsf
}
define float @square_nnan_fmuladd_fabs_intrinsic_f32(float %x) {
; CHECK-LABEL: @square_nnan_fmuladd_fabs_intrinsic_f32(
; CHECK-NEXT: [[FMULADD:%.*]] = call nnan float @llvm.fmuladd.f32(float [[X:%.*]], float [[X]], float 1.000000e+00)
; CHECK-NEXT: ret float [[FMULADD]]
;
%fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.0)
%fabsf = call float @llvm.fabs.f32(float %fmuladd)
ret float %fabsf
}
; Don't introduce a second fpext
define double @multi_use_fabs_fpext(float %x) {
; CHECK-LABEL: @multi_use_fabs_fpext(
; CHECK-NEXT: [[FPEXT:%.*]] = fpext float [[X:%.*]] to double
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[FPEXT]])
; CHECK-NEXT: store volatile double [[FPEXT]], ptr undef, align 8
; CHECK-NEXT: ret double [[FABS]]
;
%fpext = fpext float %x to double
%fabs = call double @llvm.fabs.f64(double %fpext)
store volatile double %fpext, ptr undef
ret double %fabs
}
; X <= 0.0 ? (0.0 - X) : X --> fabs(X)
define double @select_fcmp_ole_zero(double %x) {
; CHECK-LABEL: @select_fcmp_ole_zero(
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp nnan ole double %x, 0.0
%negx = fsub double 0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
define double @select_fcmp_ole_zero_no_nnan(double %x) {
; CHECK-LABEL: @select_fcmp_ole_zero_no_nnan(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fsub double 0.000000e+00, [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ole double %x, 0.0
%negx = fsub double 0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
define double @select_fcmp_ole_zero_no_nnan_input_nofpclass_nan(double nofpclass(nan) %x) {
; CHECK-LABEL: @select_fcmp_ole_zero_no_nnan_input_nofpclass_nan(
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ole double %x, 0.0
%negx = fsub double 0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
define double @select_fcmp_ole_zero_select_nnan(double %x) {
; CHECK-LABEL: @select_fcmp_ole_zero_select_nnan(
; CHECK-NEXT: [[FABS:%.*]] = call nnan double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ole double %x, 0.0
%negx = fsub double 0.0, %x
%fabs = select nnan i1 %lezero, double %negx, double %x
ret double %fabs
}
define double @select_fcmp_nnan_ole_zero(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_ole_zero(
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp nnan ole double %x, 0.0
%negx = fsub nnan double 0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
define double @select_nnan_fcmp_nnan_ole_zero(double %x) {
; CHECK-LABEL: @select_nnan_fcmp_nnan_ole_zero(
; CHECK-NEXT: [[FABS:%.*]] = call nnan double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp nnan ole double %x, 0.0
%negx = fsub nnan double 0.0, %x
%fabs = select nnan i1 %lezero, double %negx, double %x
ret double %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define double @select_fcmp_nnan_ule_zero(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_ule_zero(
; CHECK-NEXT: [[FABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp nnan ule double %x, 0.0
%negx = fsub nnan double 0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
; Negative test - wrong predicate.
define double @select_fcmp_nnan_olt_zero(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_olt_zero(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fsub nnan double 0.000000e+00, [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp olt double %x, 0.0
%negx = fsub nnan double 0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
; X <= -0.0 ? (0.0 - X) : X --> fabs(X)
define <2 x float> @select_fcmp_nnan_ole_negzero(<2 x float> %x) {
; CHECK-LABEL: @select_fcmp_nnan_ole_negzero(
; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%lezero = fcmp nnan ole <2 x float> %x, <float -0.0, float -0.0>
%negx = fsub nnan <2 x float> <float 0.0, float poison>, %x
%fabs = select <2 x i1> %lezero, <2 x float> %negx, <2 x float> %x
ret <2 x float> %fabs
}
define <2 x float> @select_nnan_fcmp_nnan_ole_negzero(<2 x float> %x) {
; CHECK-LABEL: @select_nnan_fcmp_nnan_ole_negzero(
; CHECK-NEXT: [[FABS:%.*]] = call nnan <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%lezero = fcmp nnan ole <2 x float> %x, <float -0.0, float -0.0>
%negx = fsub nnan <2 x float> <float 0.0, float poison>, %x
%fabs = select nnan <2 x i1> %lezero, <2 x float> %negx, <2 x float> %x
ret <2 x float> %fabs
}
; X > 0.0 ? X : (0.0 - X) --> fabs(X)
define fp128 @select_fcmp_ogt_zero(fp128 %x) {
; CHECK-LABEL: @select_fcmp_ogt_zero(
; CHECK-NEXT: [[FABS:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
; CHECK-NEXT: ret fp128 [[FABS]]
;
%gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
%negx = fsub fp128 zeroinitializer, %x
%fabs = select i1 %gtzero, fp128 %x, fp128 %negx
ret fp128 %fabs
}
; This is not fabs because that could produce a different signbit for a NAN input.
; PR59279
define float @select_nsz_fcmp_ogt_fneg(float %a) {
; CHECK-LABEL: @select_nsz_fcmp_ogt_fneg(
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[A:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt float [[A]], 0.000000e+00
; CHECK-NEXT: [[R:%.*]] = select nsz i1 [[CMP]], float [[A]], float [[FNEG]]
; CHECK-NEXT: ret float [[R]]
;
%fneg = fneg float %a
%cmp = fcmp ogt float %a, %fneg
%r = select nsz i1 %cmp, float %a, float %fneg
ret float %r
}
define float @select_nsz_nnan_fcmp_ogt_fneg(float %a) {
; CHECK-LABEL: @select_nsz_nnan_fcmp_ogt_fneg(
; CHECK-NEXT: [[R:%.*]] = call nnan nsz float @llvm.fabs.f32(float [[A:%.*]])
; CHECK-NEXT: ret float [[R]]
;
%fneg = fneg float %a
%cmp = fcmp ogt float %a, %fneg
%r = select nsz nnan i1 %cmp, float %a, float %fneg
ret float %r
}
define fp128 @select_fcmp_nnan_ogt_zero(fp128 %x) {
; CHECK-LABEL: @select_fcmp_nnan_ogt_zero(
; CHECK-NEXT: [[FABS:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
; CHECK-NEXT: ret fp128 [[FABS]]
;
%gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
%negx = fsub nnan fp128 zeroinitializer, %x
%fabs = select i1 %gtzero, fp128 %x, fp128 %negx
ret fp128 %fabs
}
define fp128 @select_nnan_fcmp_nnan_ogt_zero(fp128 %x) {
; CHECK-LABEL: @select_nnan_fcmp_nnan_ogt_zero(
; CHECK-NEXT: [[FABS:%.*]] = call nnan fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
; CHECK-NEXT: ret fp128 [[FABS]]
;
%gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
%negx = fsub nnan fp128 zeroinitializer, %x
%fabs = select nnan i1 %gtzero, fp128 %x, fp128 %negx
ret fp128 %fabs
}
; X > -0.0 ? X : (0.0 - X) --> fabs(X)
define half @select_fcmp_nnan_ogt_negzero(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_ogt_negzero(
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: ret half [[FABS]]
;
%gtzero = fcmp nnan ogt half %x, -0.0
%negx = fsub nnan half 0.0, %x
%fabs = select i1 %gtzero, half %x, half %negx
ret half %fabs
}
define half @select_nnan_fcmp_nnan_ogt_negzero(half %x) {
; CHECK-LABEL: @select_nnan_fcmp_nnan_ogt_negzero(
; CHECK-NEXT: [[FABS:%.*]] = call nnan half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: ret half [[FABS]]
;
%gtzero = fcmp nnan ogt half %x, -0.0
%negx = fsub nnan half 0.0, %x
%fabs = select nnan i1 %gtzero, half %x, half %negx
ret half %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define half @select_fcmp_nnan_ugt_negzero(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_ugt_negzero(
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: ret half [[FABS]]
;
%gtzero = fcmp nnan ugt half %x, -0.0
%negx = fsub nnan half 0.0, %x
%fabs = select i1 %gtzero, half %x, half %negx
ret half %fabs
}
; Negative test - wrong predicate.
define half @select_fcmp_nnan_oge_negzero(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_oge_negzero(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp oge half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[NEGX:%.*]] = fsub nnan half 0xH0000, [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GTZERO]], half [[X]], half [[NEGX]]
; CHECK-NEXT: ret half [[FABS]]
;
%gtzero = fcmp oge half %x, -0.0
%negx = fsub nnan half 0.0, %x
%fabs = select i1 %gtzero, half %x, half %negx
ret half %fabs
}
; This is not fabs because that could produce a different signbit for a NAN input.
; PR59279
define double @select_nsz_fcmp_olt_zero_unary_fneg(double %x) {
; CHECK-LABEL: @select_nsz_fcmp_olt_zero_unary_fneg(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nsz i1 [[LTZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%ltzero = fcmp olt double %x, 0.0
%negx = fneg double %x
%fabs = select nsz i1 %ltzero, double %negx, double %x
ret double %fabs
}
; X < 0.0 ? -X : X --> fabs(X)
define double @select_nsz_nnan_fcmp_olt_zero_unary_fneg(double %x) {
; CHECK-LABEL: @select_nsz_nnan_fcmp_olt_zero_unary_fneg(
; CHECK-NEXT: [[FABS:%.*]] = call nnan nsz double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%ltzero = fcmp olt double %x, 0.0
%negx = fneg double %x
%fabs = select nsz nnan i1 %ltzero, double %negx, double %x
ret double %fabs
}
define double @select_fcmp_nnan_nsz_olt_zero(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_zero(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LTZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%ltzero = fcmp olt double %x, 0.0
%negx = fsub nnan nsz double -0.0, %x
%fabs = select i1 %ltzero, double %negx, double %x
ret double %fabs
}
define double @select_nnan_nsz_fcmp_nnan_nsz_olt_zero(double %x) {
; CHECK-LABEL: @select_nnan_nsz_fcmp_nnan_nsz_olt_zero(
; CHECK-NEXT: [[FABS:%.*]] = call nnan nsz double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%ltzero = fcmp olt double %x, 0.0
%negx = fsub nnan nsz double -0.0, %x
%fabs = select nnan nsz i1 %ltzero, double %negx, double %x
ret double %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define double @select_fcmp_nnan_nsz_ult_zero(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ult_zero(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp ult double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LTZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%ltzero = fcmp ult double %x, 0.0
%negx = fsub nnan nsz double -0.0, %x
%fabs = select i1 %ltzero, double %negx, double %x
ret double %fabs
}
define double @select_fcmp_nnan_nsz_olt_zero_unary_fneg(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_zero_unary_fneg(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LTZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%ltzero = fcmp olt double %x, 0.0
%negx = fneg nnan nsz double %x
%fabs = select i1 %ltzero, double %negx, double %x
ret double %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define double @select_fcmp_nnan_nsz_ult_zero_unary_fneg(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ult_zero_unary_fneg(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp ult double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LTZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%ltzero = fcmp ult double %x, 0.0
%negx = fneg nnan nsz double %x
%fabs = select i1 %ltzero, double %negx, double %x
ret double %fabs
}
; X < -0.0 ? -X : X --> fabs(X)
define float @select_fcmp_nnan_nsz_olt_negzero(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_negzero(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan ninf nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LTZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%ltzero = fcmp olt float %x, -0.0
%negx = fsub nnan ninf nsz float -0.0, %x
%fabs = select i1 %ltzero, float %negx, float %x
ret float %fabs
}
define float @select_nnan_ninf_nsz_fcmp_nnan_nsz_olt_negzero(float %x) {
; CHECK-LABEL: @select_nnan_ninf_nsz_fcmp_nnan_nsz_olt_negzero(
; CHECK-NEXT: [[FABS:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: ret float [[FABS]]
;
%ltzero = fcmp olt float %x, -0.0
%negx = fsub nnan nsz float -0.0, %x
%fabs = select nnan ninf nsz i1 %ltzero, float %negx, float %x
ret float %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define float @select_fcmp_nnan_nsz_ult_negzero(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ult_negzero(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp ult float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan ninf nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LTZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%ltzero = fcmp ult float %x, -0.0
%negx = fsub nnan ninf nsz float -0.0, %x
%fabs = select i1 %ltzero, float %negx, float %x
ret float %fabs
}
define float @select_fcmp_nnan_nsz_olt_negzero_unary_fneg(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_negzero_unary_fneg(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan ninf nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LTZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%ltzero = fcmp olt float %x, -0.0
%negx = fneg nnan ninf nsz float %x
%fabs = select i1 %ltzero, float %negx, float %x
ret float %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define float @select_fcmp_nnan_nsz_ult_negzero_unary_fneg(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ult_negzero_unary_fneg(
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp ult float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan ninf nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LTZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%ltzero = fcmp ult float %x, -0.0
%negx = fneg nnan ninf nsz float %x
%fabs = select i1 %ltzero, float %negx, float %x
ret float %fabs
}
; X <= 0.0 ? -X : X --> fabs(X)
define double @select_fcmp_nnan_nsz_ole_zero(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_zero(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg fast double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ole double %x, 0.0
%negx = fsub fast double -0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
define double @select_fast_fcmp_nnan_nsz_ole_zero(double %x) {
; CHECK-LABEL: @select_fast_fcmp_nnan_nsz_ole_zero(
; CHECK-NEXT: [[FABS:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ole double %x, 0.0
%negx = fsub nnan nsz double -0.0, %x
%fabs = select fast i1 %lezero, double %negx, double %x
ret double %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define double @select_fcmp_nnan_nsz_ule_zero(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ule_zero(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ule double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg fast double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LEZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ule double %x, 0.0
%negx = fsub fast double -0.0, %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
define double @select_fcmp_nnan_nsz_ole_zero_unary_fneg(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_zero_unary_fneg(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg fast double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ole double %x, 0.0
%negx = fneg fast double %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define double @select_fcmp_nnan_nsz_ule_zero_unary_fneg(double %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ule_zero_unary_fneg(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ule double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg fast double [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LEZERO]], double [[NEGX]], double [[X]]
; CHECK-NEXT: ret double [[FABS]]
;
%lezero = fcmp ule double %x, 0.0
%negx = fneg fast double %x
%fabs = select i1 %lezero, double %negx, double %x
ret double %fabs
}
; X <= -0.0 ? -X : X --> fabs(X)
define float @select_fcmp_nnan_nsz_ole_negzero(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_negzero(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ole float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%lezero = fcmp ole float %x, -0.0
%negx = fsub nnan nsz float -0.0, %x
%fabs = select i1 %lezero, float %negx, float %x
ret float %fabs
}
define float @select_nnan_nsz_fcmp_nnan_nsz_ole_negzero(float %x) {
; CHECK-LABEL: @select_nnan_nsz_fcmp_nnan_nsz_ole_negzero(
; CHECK-NEXT: [[FABS:%.*]] = call nnan nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: ret float [[FABS]]
;
%lezero = fcmp ole float %x, -0.0
%negx = fsub nnan nsz float -0.0, %x
%fabs = select nnan nsz i1 %lezero, float %negx, float %x
ret float %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define float @select_fcmp_nnan_nsz_ule_negzero(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ule_negzero(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ule float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LEZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%lezero = fcmp ule float %x, -0.0
%negx = fsub nnan nsz float -0.0, %x
%fabs = select i1 %lezero, float %negx, float %x
ret float %fabs
}
define float @select_fcmp_nnan_nsz_ole_negzero_unary_fneg(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_negzero_unary_fneg(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ole float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%lezero = fcmp ole float %x, -0.0
%negx = fneg nnan nsz float %x
%fabs = select i1 %lezero, float %negx, float %x
ret float %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define float @select_fcmp_nnan_nsz_ule_negzero_unary_fneg(float %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ule_negzero_unary_fneg(
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ule float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz float [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[LEZERO]], float [[NEGX]], float [[X]]
; CHECK-NEXT: ret float [[FABS]]
;
%lezero = fcmp ule float %x, -0.0
%negx = fneg nnan nsz float %x
%fabs = select i1 %lezero, float %negx, float %x
ret float %fabs
}
; This is not fabs because that could produce a different signbit for a NAN input.
; PR59279
define <2 x float> @select_nsz_fcmp_ogt_zero_unary_fneg(<2 x float> %x) {
; CHECK-LABEL: @select_nsz_fcmp_ogt_zero_unary_fneg(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ogt <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg <2 x float> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nsz <2 x i1> [[GTZERO]], <2 x float> [[X]], <2 x float> [[NEGX]]
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%gtzero = fcmp ogt <2 x float> %x, zeroinitializer
%negx = fneg <2 x float> %x
%fabs = select nsz <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
ret <2 x float> %fabs
}
; X > 0.0 ? X : (-X) --> fabs(X)
define <2 x float> @select_nsz_nnan_fcmp_ogt_zero_unary_fneg(<2 x float> %x) {
; CHECK-LABEL: @select_nsz_nnan_fcmp_ogt_zero_unary_fneg(
; CHECK-NEXT: [[FABS:%.*]] = call nnan nsz <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%gtzero = fcmp ogt <2 x float> %x, zeroinitializer
%negx = fneg <2 x float> %x
%fabs = select nsz nnan <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
ret <2 x float> %fabs
}
define <2 x float> @select_fcmp_nnan_nsz_ogt_zero(<2 x float> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_zero(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ogt <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz arcp <2 x float> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan <2 x i1> [[GTZERO]], <2 x float> [[X]], <2 x float> [[NEGX]]
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%gtzero = fcmp ogt <2 x float> %x, zeroinitializer
%negx = fsub nnan nsz arcp <2 x float> <float -0.0, float -0.0>, %x
%fabs = select <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
ret <2 x float> %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define <2 x float> @select_fcmp_nnan_nsz_ugt_zero(<2 x float> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ugt_zero(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ugt <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz arcp <2 x float> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select <2 x i1> [[GTZERO]], <2 x float> [[X]], <2 x float> [[NEGX]]
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%gtzero = fcmp ugt <2 x float> %x, zeroinitializer
%negx = fsub nnan nsz arcp <2 x float> <float -0.0, float -0.0>, %x
%fabs = select <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
ret <2 x float> %fabs
}
define <2 x float> @select_fcmp_nnan_nsz_ogt_zero_unary_fneg(<2 x float> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_zero_unary_fneg(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ogt <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz arcp <2 x float> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan <2 x i1> [[GTZERO]], <2 x float> [[X]], <2 x float> [[NEGX]]
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%gtzero = fcmp ogt <2 x float> %x, zeroinitializer
%negx = fneg nnan nsz arcp <2 x float> %x
%fabs = select <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
ret <2 x float> %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define <2 x float> @select_fcmp_nnan_nsz_ugt_zero_unary_fneg(<2 x float> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ugt_zero_unary_fneg(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ugt <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz arcp <2 x float> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select <2 x i1> [[GTZERO]], <2 x float> [[X]], <2 x float> [[NEGX]]
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%gtzero = fcmp ugt <2 x float> %x, zeroinitializer
%negx = fneg nnan nsz arcp <2 x float> %x
%fabs = select <2 x i1> %gtzero, <2 x float> %x, <2 x float> %negx
ret <2 x float> %fabs
}
; X > -0.0 ? X : (0.0 - X) --> fabs(X)
define half @select_fcmp_nnan_nsz_ogt_negzero(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_negzero(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ogt half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[NEGX:%.*]] = fneg fast half [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[GTZERO]], half [[X]], half [[NEGX]]
; CHECK-NEXT: ret half [[FABS]]
;
%gtzero = fcmp ogt half %x, -0.0
%negx = fsub fast half 0.0, %x
%fabs = select i1 %gtzero, half %x, half %negx
ret half %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define half @select_fcmp_nnan_nsz_ugt_negzero(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_ugt_negzero(
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp ugt half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[NEGX:%.*]] = fneg fast half [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GTZERO]], half [[X]], half [[NEGX]]
; CHECK-NEXT: ret half [[FABS]]
;
%gtzero = fcmp ugt half %x, -0.0
%negx = fsub fast half 0.0, %x
%fabs = select i1 %gtzero, half %x, half %negx
ret half %fabs
}
; X > 0.0 ? X : (0.0 - X) --> fabs(X)
define <2 x double> @select_fcmp_nnan_nsz_oge_zero(<2 x double> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_zero(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp oge <2 x double> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg reassoc nnan nsz <2 x double> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan <2 x i1> [[GEZERO]], <2 x double> [[X]], <2 x double> [[NEGX]]
; CHECK-NEXT: ret <2 x double> [[FABS]]
;
%gezero = fcmp oge <2 x double> %x, zeroinitializer
%negx = fsub nnan nsz reassoc <2 x double> <double -0.0, double -0.0>, %x
%fabs = select <2 x i1> %gezero, <2 x double> %x, <2 x double> %negx
ret <2 x double> %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define <2 x double> @select_fcmp_nnan_nsz_uge_zero(<2 x double> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_uge_zero(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp uge <2 x double> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg reassoc nnan nsz <2 x double> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select <2 x i1> [[GEZERO]], <2 x double> [[X]], <2 x double> [[NEGX]]
; CHECK-NEXT: ret <2 x double> [[FABS]]
;
%gezero = fcmp uge <2 x double> %x, zeroinitializer
%negx = fsub nnan nsz reassoc <2 x double> <double -0.0, double -0.0>, %x
%fabs = select <2 x i1> %gezero, <2 x double> %x, <2 x double> %negx
ret <2 x double> %fabs
}
define <2 x double> @select_fcmp_nnan_nsz_oge_zero_unary_fneg(<2 x double> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_zero_unary_fneg(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp oge <2 x double> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg reassoc nnan nsz <2 x double> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan <2 x i1> [[GEZERO]], <2 x double> [[X]], <2 x double> [[NEGX]]
; CHECK-NEXT: ret <2 x double> [[FABS]]
;
%gezero = fcmp oge <2 x double> %x, zeroinitializer
%negx = fneg nnan nsz reassoc <2 x double> %x
%fabs = select <2 x i1> %gezero, <2 x double> %x, <2 x double> %negx
ret <2 x double> %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define <2 x double> @select_fcmp_nnan_nsz_uge_zero_unary_fneg(<2 x double> %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_uge_zero_unary_fneg(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp uge <2 x double> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[NEGX:%.*]] = fneg reassoc nnan nsz <2 x double> [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select <2 x i1> [[GEZERO]], <2 x double> [[X]], <2 x double> [[NEGX]]
; CHECK-NEXT: ret <2 x double> [[FABS]]
;
%gezero = fcmp uge <2 x double> %x, zeroinitializer
%negx = fneg nnan nsz reassoc <2 x double> %x
%fabs = select <2 x i1> %gezero, <2 x double> %x, <2 x double> %negx
ret <2 x double> %fabs
}
; X > -0.0 ? X : (0.0 - X) --> fabs(X)
define half @select_fcmp_nnan_nsz_oge_negzero(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_negzero(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp oge half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz half [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[GEZERO]], half [[X]], half [[NEGX]]
; CHECK-NEXT: ret half [[FABS]]
;
%gezero = fcmp oge half %x, -0.0
%negx = fsub nnan nsz half -0.0, %x
%fabs = select i1 %gezero, half %x, half %negx
ret half %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define half @select_fcmp_nnan_nsz_uge_negzero(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_uge_negzero(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp uge half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz half [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GEZERO]], half [[X]], half [[NEGX]]
; CHECK-NEXT: ret half [[FABS]]
;
%gezero = fcmp uge half %x, -0.0
%negx = fsub nnan nsz half -0.0, %x
%fabs = select i1 %gezero, half %x, half %negx
ret half %fabs
}
define half @select_fcmp_nnan_nsz_oge_negzero_unary_fneg(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_negzero_unary_fneg(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp oge half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz half [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select nnan i1 [[GEZERO]], half [[X]], half [[NEGX]]
; CHECK-NEXT: ret half [[FABS]]
;
%gezero = fcmp oge half %x, -0.0
%negx = fneg nnan nsz half %x
%fabs = select i1 %gezero, half %x, half %negx
ret half %fabs
}
; Repeat with unordered predicate - nnan allows us to treat ordered/unordered identically.
define half @select_fcmp_nnan_nsz_uge_negzero_unary_fneg(half %x) {
; CHECK-LABEL: @select_fcmp_nnan_nsz_uge_negzero_unary_fneg(
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp uge half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[NEGX:%.*]] = fneg nnan nsz half [[X]]
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GEZERO]], half [[X]], half [[NEGX]]
; CHECK-NEXT: ret half [[FABS]]
;
%gezero = fcmp uge half %x, -0.0
%negx = fneg nnan nsz half %x
%fabs = select i1 %gezero, half %x, half %negx
ret half %fabs
}
define float @select_fneg(i1 %c, float %x) {
; CHECK-LABEL: @select_fneg(
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: ret float [[FABS]]
;
%n = fneg float %x
%s = select i1 %c, float %n, float %x
%fabs = call float @llvm.fabs.f32(float %s)
ret float %fabs
}
define float @select_fneg_use1(i1 %c, float %x) {
; CHECK-LABEL: @select_fneg_use1(
; CHECK-NEXT: [[N:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: call void @use(float [[N]])
; CHECK-NEXT: [[FABS:%.*]] = call fast float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[FABS]]
;
%n = fneg float %x
call void @use(float %n)
%s = select i1 %c, float %x, float %n
%fabs = call fast float @llvm.fabs.f32(float %s)
ret float %fabs
}
define float @select_fneg_use2(i1 %c, float %x) {
; CHECK-LABEL: @select_fneg_use2(
; CHECK-NEXT: [[N:%.*]] = fneg arcp float [[X:%.*]]
; CHECK-NEXT: [[S:%.*]] = select i1 [[C:%.*]], float [[N]], float [[X]]
; CHECK-NEXT: call void @use(float [[S]])
; CHECK-NEXT: [[FABS:%.*]] = call nnan nsz float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[FABS]]
;
%n = fneg arcp float %x
%s = select i1 %c, float %n, float %x
call void @use(float %s)
%fabs = call nnan nsz float @llvm.fabs.f32(float %s)
ret float %fabs
}
define <2 x float> @select_fneg_vec(<2 x i1> %c, <2 x float> %x) {
; CHECK-LABEL: @select_fneg_vec(
; CHECK-NEXT: [[FABS:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
; CHECK-NEXT: ret <2 x float> [[FABS]]
;
%n = fneg <2 x float> %x
%s = select fast <2 x i1> %c, <2 x float> %x, <2 x float> %n
%fabs = call <2 x float> @llvm.fabs.v2f32(<2 x float> %s)
ret <2 x float> %fabs
}
define float @test_select_neg_negx_x(float %value) {
; CHECK-LABEL: @test_select_neg_negx_x(
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = call float @llvm.fabs.f32(float [[VALUE:%.*]])
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
%fneg.i = fneg float %value
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_nneg_negx_x(float %value) {
; CHECK-LABEL: @test_select_nneg_negx_x(
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VALUE:%.*]])
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp sgt i32 %a0, -1
%fneg.i = fneg float %value
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_neg_x_negx(float %value) {
; CHECK-LABEL: @test_select_neg_x_negx(
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VALUE:%.*]])
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
%fneg.i = fneg float %value
%value.addr.0.i = select i1 %a1, float %value, float %fneg.i
ret float %value.addr.0.i
}
define float @test_select_nneg_x_negx(float %value) {
; CHECK-LABEL: @test_select_nneg_x_negx(
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = call float @llvm.fabs.f32(float [[VALUE:%.*]])
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp sgt i32 %a0, -1
%fneg.i = fneg float %value
%value.addr.0.i = select i1 %a1, float %value, float %fneg.i
ret float %value.addr.0.i
}
define float @test_select_neg_negx_x_multiuse1(float %value) {
; CHECK-LABEL: @test_select_neg_negx_x_multiuse1(
; CHECK-NEXT: [[A0:%.*]] = bitcast float [[VALUE:%.*]] to i32
; CHECK-NEXT: [[A1:%.*]] = icmp slt i32 [[A0]], 0
; CHECK-NEXT: call void @usebool(i1 [[A1]])
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
call void @usebool(i1 %a1)
%fneg.i = fneg float %value
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_neg_negx_x_multiuse2(float %value) {
; CHECK-LABEL: @test_select_neg_negx_x_multiuse2(
; CHECK-NEXT: [[FNEG_I:%.*]] = fneg float [[VALUE:%.*]]
; CHECK-NEXT: call void @use(float [[FNEG_I]])
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
%fneg.i = fneg float %value
call void @use(float %fneg.i)
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_neg_negx_x_multiuse3(float %value) {
; CHECK-LABEL: @test_select_neg_negx_x_multiuse3(
; CHECK-NEXT: [[A0:%.*]] = bitcast float [[VALUE:%.*]] to i32
; CHECK-NEXT: [[A1:%.*]] = icmp slt i32 [[A0]], 0
; CHECK-NEXT: call void @usebool(i1 [[A1]])
; CHECK-NEXT: [[FNEG_I:%.*]] = fneg float [[VALUE]]
; CHECK-NEXT: call void @use(float [[FNEG_I]])
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
call void @usebool(i1 %a1)
%fneg.i = fneg float %value
call void @use(float %fneg.i)
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_neg_negx_x_fmf(float %value) {
; CHECK-LABEL: @test_select_neg_negx_x_fmf(
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[VALUE:%.*]])
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
%fneg.i = fneg float %value
%value.addr.0.i = select nsz nnan ninf i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_nneg_negx_x_fmf(float %value) {
; CHECK-LABEL: @test_select_nneg_negx_x_fmf(
; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[VALUE:%.*]])
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = fneg nnan ninf nsz float [[TMP1]]
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp sgt i32 %a0, -1
%fneg.i = fneg float %value
%value.addr.0.i = select nsz nnan ninf i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
; Negative tests
define float @test_select_nneg_negx_x_multiuse4(float %value) {
; CHECK-LABEL: @test_select_nneg_negx_x_multiuse4(
; CHECK-NEXT: [[A0:%.*]] = bitcast float [[VALUE:%.*]] to i32
; CHECK-NEXT: [[A1:%.*]] = icmp sgt i32 [[A0]], -1
; CHECK-NEXT: call void @usebool(i1 [[A1]])
; CHECK-NEXT: [[FNEG_I:%.*]] = fneg float [[VALUE]]
; CHECK-NEXT: call void @use(float [[FNEG_I]])
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = select i1 [[A1]], float [[FNEG_I]], float [[VALUE]]
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp sgt i32 %a0, -1
call void @usebool(i1 %a1)
%fneg.i = fneg float %value
call void @use(float %fneg.i)
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_neg_negx_x_mismatched1(float %value, float %y) {
; CHECK-LABEL: @test_select_neg_negx_x_mismatched1(
; CHECK-NEXT: [[A0:%.*]] = bitcast float [[Y:%.*]] to i32
; CHECK-NEXT: [[A1:%.*]] = icmp slt i32 [[A0]], 0
; CHECK-NEXT: [[FNEG_I:%.*]] = fneg float [[VALUE:%.*]]
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = select i1 [[A1]], float [[FNEG_I]], float [[VALUE]]
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %y to i32
%a1 = icmp slt i32 %a0, 0
%fneg.i = fneg float %value
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_neg_negx_x_mismatched2(float %value, float %y) {
; CHECK-LABEL: @test_select_neg_negx_x_mismatched2(
; CHECK-NEXT: [[A0:%.*]] = bitcast float [[VALUE:%.*]] to i32
; CHECK-NEXT: [[A1:%.*]] = icmp slt i32 [[A0]], 0
; CHECK-NEXT: [[FNEG_I:%.*]] = fneg float [[Y:%.*]]
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = select i1 [[A1]], float [[FNEG_I]], float [[VALUE]]
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
%fneg.i = fneg float %y
%value.addr.0.i = select i1 %a1, float %fneg.i, float %value
ret float %value.addr.0.i
}
define float @test_select_neg_negx_x_mismatched3(float %value, float %y) {
; CHECK-LABEL: @test_select_neg_negx_x_mismatched3(
; CHECK-NEXT: [[A0:%.*]] = bitcast float [[VALUE:%.*]] to i32
; CHECK-NEXT: [[A1:%.*]] = icmp slt i32 [[A0]], 0
; CHECK-NEXT: [[FNEG_I:%.*]] = fneg float [[VALUE]]
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = select i1 [[A1]], float [[FNEG_I]], float [[Y:%.*]]
; CHECK-NEXT: ret float [[VALUE_ADDR_0_I]]
;
%a0 = bitcast float %value to i32
%a1 = icmp slt i32 %a0, 0
%fneg.i = fneg float %value
%value.addr.0.i = select i1 %a1, float %fneg.i, float %y
ret float %value.addr.0.i
}
define <2 x float> @test_select_neg_negx_x_wrong_type(<2 x float> %value) {
; CHECK-LABEL: @test_select_neg_negx_x_wrong_type(
; CHECK-NEXT: [[A0:%.*]] = bitcast <2 x float> [[VALUE:%.*]] to i64
; CHECK-NEXT: [[A1:%.*]] = icmp slt i64 [[A0]], 0
; CHECK-NEXT: [[FNEG_I:%.*]] = fneg <2 x float> [[VALUE]]
; CHECK-NEXT: [[VALUE_ADDR_0_I:%.*]] = select i1 [[A1]], <2 x float> [[FNEG_I]], <2 x float> [[VALUE]]
; CHECK-NEXT: ret <2 x float> [[VALUE_ADDR_0_I]]
;
%a0 = bitcast <2 x float> %value to i64
%a1 = icmp slt i64 %a0, 0
%fneg.i = fneg <2 x float> %value
%value.addr.0.i = select i1 %a1, <2 x float> %fneg.i, <2 x float> %value
ret <2 x float> %value.addr.0.i
}
define i1 @test_fabs_used_by_fcmp(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fcmp(
; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%cmp2 = fcmp olt float %sel, %y
ret i1 %cmp2
}
define float @test_fabs_used_by_fpop_nnan_nsz(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fpop_nnan_nsz(
; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[ADD:%.*]] = fadd nnan nsz float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%add = fadd nnan nsz float %sel, %y
ret float %add
}
define i1 @test_fabs_fsub_used_by_fcmp(float %x, float %y) {
; CHECK-LABEL: @test_fabs_fsub_used_by_fcmp(
; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = fcmp ogt float %x, 0.000000e+00
%neg = fsub float 0.000000e+00, %x
%sel = select i1 %cmp, float %x, float %neg
%cmp2 = fcmp olt float %sel, %y
ret i1 %cmp2
}
define float @test_fabs_fsub_used_by_fpop_nnan(float %x, float %y) {
; CHECK-LABEL: @test_fabs_fsub_used_by_fpop_nnan(
; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[ADD:%.*]] = fadd nnan float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
%cmp = fcmp ogt float %x, 0.000000e+00
%neg = fsub float 0.000000e+00, %x
%sel = select i1 %cmp, float %x, float %neg
%add = fadd nnan float %sel, %y
ret float %add
}
define float @test_fabs_used_by_fpop_nsz(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fpop_nsz(
; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[ADD:%.*]] = fadd nsz float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%add = fadd nsz float %sel, %y
ret float %add
}
define float @test_fabs_used_by_fcopysign_mag(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fcopysign_mag(
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X:%.*]], float [[Y:%.*]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%copysign = call float @llvm.copysign.f32(float %sel, float %y)
ret float %copysign
}
define float @test_fabs_nsz_used_by_canonicalize(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_canonicalize(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SEL]])
; CHECK-NEXT: ret float [[CANON]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%canon = call float @llvm.canonicalize.f32(float %sel)
ret float %canon
}
define void @test_fabs_used_by_nofpclass_nan(float %x) {
; CHECK-LABEL: @test_fabs_used_by_nofpclass_nan(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: call void @use(float nofpclass(nan) [[SEL]])
; CHECK-NEXT: ret void
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
call void @use(float nofpclass(nan) %sel)
ret void
}
define nofpclass(nan) float @test_fabs_used_by_ret_nofpclass_nan(float %x) {
; CHECK-LABEL: @test_fabs_used_by_ret_nofpclass_nan(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: ret float [[SEL]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
ret float %sel
}
define i32 @test_fabs_used_fptosi(float %x) {
; CHECK-LABEL: @test_fabs_used_fptosi(
; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[FPTOSI:%.*]] = fptosi float [[SEL]] to i32
; CHECK-NEXT: ret i32 [[FPTOSI]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%fptosi = fptosi float %sel to i32
ret i32 %fptosi
}
define i32 @test_fabs_used_fptoui(float %x) {
; CHECK-LABEL: @test_fabs_used_fptoui(
; CHECK-NEXT: [[SEL:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[FPTOSI:%.*]] = fptoui float [[SEL]] to i32
; CHECK-NEXT: ret i32 [[FPTOSI]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%fptosi = fptoui float %sel to i32
ret i32 %fptosi
}
define float @test_fabs_nsz_used_by_maxnum(float %x, float %y) {
; CHECK-LABEL: @test_fabs_nsz_used_by_maxnum(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[Y:%.*]], float [[SEL]])
; CHECK-NEXT: ret float [[MAX]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%max = call float @llvm.maxnum.f32(float %y, float %sel)
ret float %max
}
define i1 @test_fabs_used_is_fpclass_pnorm_or_nan(float %x) {
; CHECK-LABEL: @test_fabs_used_is_fpclass_pnorm_or_nan(
; CHECK-NEXT: [[IS_FPCLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 267)
; CHECK-NEXT: ret i1 [[IS_FPCLASS]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%is_fpclass = call i1 @llvm.is.fpclass.f32(float %sel, i32 259)
ret i1 %is_fpclass
}
define i1 @test_fabs_used_is_fpclass_zero_or_pinf(float %x) {
; CHECK-LABEL: @test_fabs_used_is_fpclass_zero_or_pinf(
; CHECK-NEXT: [[IS_FPCLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 612)
; CHECK-NEXT: ret i1 [[IS_FPCLASS]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%is_fpclass = call i1 @llvm.is.fpclass.f32(float %sel, i32 608)
ret i1 %is_fpclass
}
define float @test_fabs_nsz_used_by_fadd(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fadd(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = fadd float [[SEL]], 1.000000e+00
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = fadd float %sel, 1.000000e+00
ret float %op
}
define float @test_fabs_nsz_used_by_fsub(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fsub(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = fsub float 1.000000e+00, [[SEL]]
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = fsub float 1.000000e+00, %sel
ret float %op
}
define float @test_fabs_nsz_used_by_fmul(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fmul(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = fmul float [[SEL]], 3.000000e+00
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = fmul float %sel, 3.000000e+00
ret float %op
}
define float @test_fabs_nsz_used_by_fdiv(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fdiv(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = fdiv float [[SEL]], 3.000000e+00
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = fdiv float %sel, 3.000000e+00
ret float %op
}
define float @test_fabs_nsz_used_by_frem(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_frem(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = fdiv float [[SEL]], 3.000000e+00
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = fdiv float %sel, 3.000000e+00
ret float %op
}
define half @test_fabs_nsz_used_by_fptrunc(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fptrunc(
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[X:%.*]] to half
; CHECK-NEXT: [[OP:%.*]] = call half @llvm.fabs.f16(half [[TMP1]])
; CHECK-NEXT: ret half [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = fptrunc float %sel to half
ret half %op
}
define float @test_fabs_nsz_used_by_fpext(half %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fpext(
; CHECK-NEXT: [[SEL:%.*]] = call nsz half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = fpext half [[SEL]] to float
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge half %x, 0.000000e+00
%neg = fneg half %x
%sel = select nsz i1 %cmp, half %x, half %neg
%op = fpext half %sel to float
ret float %op
}
define float @test_fabs_nsz_used_by_maximum(float %x, float %y) {
; CHECK-LABEL: @test_fabs_nsz_used_by_maximum(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[Y:%.*]], float [[SEL]])
; CHECK-NEXT: ret float [[MAX]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%max = call float @llvm.maximum.f32(float %y, float %sel)
ret float %max
}
define float @test_fabs_nsz_used_by_maximumnum(float %x, float %y) {
; CHECK-LABEL: @test_fabs_nsz_used_by_maximumnum(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximumnum.f32(float [[Y:%.*]], float [[SEL]])
; CHECK-NEXT: ret float [[MAX]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%max = call float @llvm.maximumnum.f32(float %y, float %sel)
ret float %max
}
define float @test_fabs_nsz_used_by_fma(float %x, float %y, float %z) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fma(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.fma.f32(float [[SEL]], float [[Z:%.*]], float [[Z]])
; CHECK-NEXT: ret float [[MAX]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%max = call float @llvm.fma.f32(float %sel, float %z, float %z)
ret float %max
}
define float @test_fabs_nsz_used_by_sqrt(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_sqrt(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = call float @llvm.sqrt.f32(float [[SEL]])
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = call float @llvm.sqrt.f32(float %sel)
ret float %op
}
define float @test_fabs_nsz_used_by_pow(float %x, float %y) {
; CHECK-LABEL: @test_fabs_nsz_used_by_pow(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = call float @llvm.pow.f32(float [[SEL]], float [[Y:%.*]])
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = call float @llvm.pow.f32(float %sel, float %y)
ret float %op
}
define float @test_fabs_nsz_used_by_powi(float %x, i32 %y) {
; CHECK-LABEL: @test_fabs_nsz_used_by_powi(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = call float @llvm.powi.f32.i32(float [[SEL]], i32 [[Y:%.*]])
; CHECK-NEXT: ret float [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = call float @llvm.powi.f32(float %sel, i32 %y)
ret float %op
}
define i32 @test_fabs_nsz_used_by_fptoui_sat(float %x) {
; CHECK-LABEL: @test_fabs_nsz_used_by_fptoui_sat(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[OP:%.*]] = call i32 @llvm.fptoui.sat.i32.f32(float [[SEL]])
; CHECK-NEXT: ret i32 [[OP]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
%op = call i32 @llvm.fptoui.sat.i32.f32(float %sel)
ret i32 %op
}
define <2 x i1> @test_fabs_used_vp_is_fpclass_zero_or_pinf(<2 x float> %x, <2 x i1> %mask, i32 %evl) {
; CHECK-LABEL: @test_fabs_used_vp_is_fpclass_zero_or_pinf(
; CHECK-NEXT: [[SEL:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
; CHECK-NEXT: [[IS_FPCLASS:%.*]] = call <2 x i1> @llvm.vp.is.fpclass.v2f32(<2 x float> [[SEL]], i32 608, <2 x i1> [[MASK:%.*]], i32 [[EVL:%.*]])
; CHECK-NEXT: ret <2 x i1> [[IS_FPCLASS]]
;
%cmp = fcmp oge <2 x float> %x, zeroinitializer
%neg = fneg <2 x float> %x
%sel = select <2 x i1> %cmp, <2 x float> %x, <2 x float> %neg
%is_fpclass = call <2 x i1> @llvm.vp.is.fpclass.v2f32(<2 x float> %sel, i32 608, <2 x i1> %mask, i32 %evl)
ret <2 x i1> %is_fpclass
}
define void @test_fabs_nsz_used_by_invoke(float %x) personality ptr null {
; CHECK-LABEL: @test_fabs_nsz_used_by_invoke(
; CHECK-NEXT: [[SEL:%.*]] = call nsz float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: invoke void @use(float nofpclass(nan) [[SEL]])
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[UNWIND:%.*]]
; CHECK: normal:
; CHECK-NEXT: ret void
; CHECK: unwind:
; CHECK-NEXT: [[TMP1:%.*]] = landingpad ptr
; CHECK-NEXT: cleanup
; CHECK-NEXT: resume ptr null
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select nsz i1 %cmp, float %x, float %neg
invoke void @use(float nofpclass(nan) %sel) to label %normal unwind label %unwind
normal:
ret void
unwind:
landingpad ptr cleanup
resume ptr null
}
; Negative tests
define float @test_fabs_used_by_fpop_nnan(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fpop_nnan(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
; CHECK-NEXT: [[ADD:%.*]] = fadd nnan float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: ret float [[ADD]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%add = fadd nnan float %sel, %y
ret float %add
}
define i1 @test_fabs_used_by_fcmp_multiuse(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fcmp_multiuse(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[SEL]], [[Y:%.*]]
; CHECK-NEXT: call void @use(float [[SEL]])
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%cmp2 = fcmp olt float %sel, %y
call void @use(float %sel)
ret i1 %cmp2
}
define float @test_fabs_used_by_fcopysign_sign(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_fcopysign_sign(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[Y:%.*]], float [[SEL]])
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%copysign = call float @llvm.copysign.f32(float %y, float %sel)
ret float %copysign
}
define float @test_fabs_used_by_maxnum(float %x, float %y) {
; CHECK-LABEL: @test_fabs_used_by_maxnum(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[Y:%.*]], float [[SEL]])
; CHECK-NEXT: ret float [[MAX]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%max = call float @llvm.maxnum.f32(float %y, float %sel)
ret float %max
}
define float @test_fabs_used_by_canonicalize(float %x) {
; CHECK-LABEL: @test_fabs_used_by_canonicalize(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SEL]])
; CHECK-NEXT: ret float [[CANON]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%canon = call float @llvm.canonicalize.f32(float %sel)
ret float %canon
}
define float @test_fabs_used_by_select(float %x, i1 %cond) {
; CHECK-LABEL: @test_fabs_used_by_select(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND:%.*]], float [[SEL]], float 0.000000e+00
; CHECK-NEXT: ret float [[SEL2]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%sel2 = select i1 %cond, float %sel, float 0.000000e+00
ret float %sel2
}
define i1 @test_fabs_used_is_fpclass_pzero(float %x) {
; CHECK-LABEL: @test_fabs_used_is_fpclass_pzero(
; CHECK-NEXT: [[CMP:%.*]] = fcmp oge float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float [[X]], float [[NEG]]
; CHECK-NEXT: [[IS_FPCLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[SEL]], i32 64)
; CHECK-NEXT: ret i1 [[IS_FPCLASS]]
;
%cmp = fcmp oge float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %cmp, float %x, float %neg
%is_fpclass = call i1 @llvm.is.fpclass.f32(float %sel, i32 64)
ret i1 %is_fpclass
}