llvm/llvm/test/Transforms/Attributor/nofpclass.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --version 2
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC

declare nofpclass(nan) float @ret_nofpclass_nan()
declare [2 x [3 x float]] @ret_array()
declare float @extern()
declare float @extern.f32(float)
declare void @extern.use(float)
declare void @extern.use.array([2 x [3 x float]])
declare void @llvm.assume(i1 noundef)
declare void @unknown()
declare half @llvm.fabs.f16(half)
declare float @llvm.fabs.f32(float)
declare void @extern.use.f16(half)
declare i1 @llvm.is.fpclass.f32(float, i32 immarg)
declare float @llvm.experimental.constrained.sitofp.f32.i32(i32, metadata, metadata)
declare float @llvm.experimental.constrained.uitofp.f32.i32(i32, metadata, metadata)
declare float @llvm.arithmetic.fence.f32(float)

define float @returned_0() {
; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @returned_0() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret float 0.000000e+00
;
  call void @unknown()
  ret float 0.0
}

define float @returned_neg0() {
; CHECK-LABEL: define noundef nofpclass(nan inf pzero sub norm) float @returned_neg0() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret float -0.000000e+00
;
  call void @unknown()
  ret float -0.0
}

define float @returned_undef() {
; CHECK-LABEL: define nofpclass(all) float @returned_undef() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret float undef
;
  call void @unknown()
  ret float undef
}

define float @returned_poison() {
; CHECK-LABEL: define nofpclass(all) float @returned_poison() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret float poison
;
  call void @unknown()
  ret float poison
}

; Know nothing
define float @returned_freeze_poison() {
; CHECK-LABEL: define noundef float @returned_freeze_poison() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    [[FREEZE_POISON:%.*]] = freeze float poison
; CHECK-NEXT:    ret float [[FREEZE_POISON]]
;
  call void @unknown()
  %freeze.poison = freeze float poison
  ret float %freeze.poison
}

define double @returned_snan() {
; CHECK-LABEL: define noundef nofpclass(qnan inf zero sub norm) double @returned_snan() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret double 0x7FF0000000000001
;
  call void @unknown()
  ret double 0x7FF0000000000001
}

define double @returned_qnan() {
; CHECK-LABEL: define noundef nofpclass(snan inf zero sub norm) double @returned_qnan() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret double 0x7FF8000000000000
;
  call void @unknown()
  ret double 0x7FF8000000000000
}

define <2 x double> @returned_zero_vector() {
; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) <2 x double> @returned_zero_vector() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret <2 x double> zeroinitializer
;
  call void @unknown()
  ret <2 x double> zeroinitializer
}

define <2 x double> @returned_negzero_vector() {
; CHECK-LABEL: define noundef nofpclass(nan inf pzero sub norm) <2 x double> @returned_negzero_vector() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
;
  call void @unknown()
  ret <2 x double> <double -0.0, double -0.0>
}

; Test a vector element that's a constant but not ConstantFP.
define <2 x double> @returned_strange_constant_vector_elt() {
; CHECK-LABEL: define <2 x double> @returned_strange_constant_vector_elt() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double bitcast (i64 ptrtoint (ptr @unknown to i64) to double)>
;
  call void @unknown()
  ret <2 x double> <double -0.0, double bitcast (i64 ptrtoint (ptr @unknown to i64) to double)>
}

; Test a vector element that's undef
define <3 x double> @returned_undef_constant_vector_elt() {
; CHECK-LABEL: define <3 x double> @returned_undef_constant_vector_elt() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret <3 x double> <double -0.000000e+00, double 0.000000e+00, double undef>
;
  call void @unknown()
  ret <3 x double> <double -0.0, double 0.0, double undef>
}

; Test a vector element that's poison
define <3 x double> @returned_poison_constant_vector_elt() {
; CHECK-LABEL: define nofpclass(nan inf sub norm) <3 x double> @returned_poison_constant_vector_elt() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret <3 x double> <double -0.000000e+00, double 0.000000e+00, double poison>
;
  call void @unknown()
  ret <3 x double> <double -0.0, double 0.0, double poison>
}

define <2 x double> @returned_qnan_zero_vector() {
; CHECK-LABEL: define noundef nofpclass(snan inf nzero sub norm) <2 x double> @returned_qnan_zero_vector() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret <2 x double> <double 0x7FF8000000000000, double 0.000000e+00>
;
  call void @unknown()
  ret <2 x double> <double 0x7FF8000000000000, double 0.0>
}

; Return a float trivially nofpclass(nan) (call return attribute)
define float @return_nofpclass_nan_decl_return() {
; CHECK-LABEL: define nofpclass(nan) float @return_nofpclass_nan_decl_return() {
; CHECK-NEXT:    [[RET:%.*]] = call nofpclass(nan) float @ret_nofpclass_nan()
; CHECK-NEXT:    ret float [[RET]]
;
  %ret = call float @ret_nofpclass_nan()
  ret float %ret
}

; Return a float trivially nofpclass(nan) (argument attribute)
define float @return_nofpclass_nan_arg(float returned nofpclass(nan) %p) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @return_nofpclass_nan_arg
; CHECK-SAME: (float returned nofpclass(nan) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
; CHECK-NEXT:    ret float [[P]]
;
  ret float %p
}

define [2 x [3 x float]] @return_nofpclass_inf_ret_array() {
; CHECK-LABEL: define nofpclass(inf) [2 x [3 x float]] @return_nofpclass_inf_ret_array() {
; CHECK-NEXT:    [[RET:%.*]] = call nofpclass(inf) [2 x [3 x float]] @ret_array()
; CHECK-NEXT:    ret [2 x [3 x float]] [[RET]]
;
  %ret = call nofpclass(inf) [2 x [3 x float]]  @ret_array()
  ret [2 x [3 x float]] %ret
}

define float @returned_nnan_fadd(float %arg0, float %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @returned_nnan_fadd
; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FADD:%.*]] = fadd nnan float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[FADD]]
;
  %fadd = fadd nnan float %arg0, %arg1
  ret float %fadd
}

define float @return_nofpclass_nan_callsite() {
; CHECK-LABEL: define nofpclass(nan) float @return_nofpclass_nan_callsite() {
; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @extern()
; CHECK-NEXT:    ret float [[CALL]]
;
  %call = call nofpclass(nan) float @extern()
  ret float %call
}

; Can union the return classes
define nofpclass(inf) float @return_ninf_nofpclass_nan_callsite() {
; CHECK-LABEL: define nofpclass(nan inf) float @return_ninf_nofpclass_nan_callsite() {
; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @extern()
; CHECK-NEXT:    ret float [[CALL]]
;
  %call = call nofpclass(nan) float @extern()
  ret float %call
}

define void @arg_used_by_nofpclass_nan_callsite(float %arg) {
; CHECK-LABEL: define void @arg_used_by_nofpclass_nan_callsite
; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) {
; CHECK-NEXT:    call void @extern.use(float nofpclass(nan) [[ARG]])
; CHECK-NEXT:    ret void
;
  call void @extern.use(float nofpclass(nan) %arg)
  ret void
}

; Callsite can union the incoming and outgoing
define void @ninf_arg_used_by_nofpclass_nan_callsite(float nofpclass(inf) %arg) {
; CHECK-LABEL: define void @ninf_arg_used_by_nofpclass_nan_callsite
; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) {
; CHECK-NEXT:    call void @extern.use(float nofpclass(nan inf) [[ARG]])
; CHECK-NEXT:    ret void
;
  call void @extern.use(float nofpclass(nan) %arg)
  ret void
}

define void @ninf_arg_used_by_callsite_array([2 x [3 x float]] nofpclass(inf) %arg) {
; CHECK-LABEL: define void @ninf_arg_used_by_callsite_array
; CHECK-SAME: ([2 x [3 x float]] nofpclass(inf) [[ARG:%.*]]) {
; CHECK-NEXT:    call void @extern.use.array([2 x [3 x float]] nofpclass(inf) [[ARG]])
; CHECK-NEXT:    ret void
;
  call void @extern.use.array([2 x [3 x float]]  %arg)
  ret void
}

define void @nofpclass_call_use_after_unannotated_use(float %arg) {
; CHECK-LABEL: define void @nofpclass_call_use_after_unannotated_use
; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) {
; CHECK-NEXT:    call void @extern(float nofpclass(nan inf) [[ARG]]) #[[ATTR17:[0-9]+]]
; CHECK-NEXT:    call void @extern(float nofpclass(nan inf) [[ARG]])
; CHECK-NEXT:    ret void
;
  call void @extern(float %arg) willreturn nounwind ; < annotate this use
  call void @extern(float nofpclass(nan inf) %arg)
  ret void
}

define float @mutually_recursive0(float %arg) {
; TUNIT: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(all) float @mutually_recursive0
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
; TUNIT-NEXT:    ret float undef
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(all) float @mutually_recursive0
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    ret float undef
;
  %call = call float @mutually_recursive1(float %arg)
  ret float %call
}

define float @mutually_recursive1(float %arg) {
; TUNIT: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(all) float @mutually_recursive1
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR4]] {
; TUNIT-NEXT:    ret float undef
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(all) float @mutually_recursive1
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    ret float undef
;
  %call = call float @mutually_recursive0(float %arg)
  ret float %call
}

define float @recursive_phi(ptr %ptr) {
; CHECK-LABEL: define nofpclass(nan) float @recursive_phi
; CHECK-SAME: (ptr nofree [[PTR:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[RET:%.*]] = call nofpclass(nan) float @ret_nofpclass_nan()
; CHECK-NEXT:    br label [[LOOP:%.*]]
; CHECK:       loop:
; CHECK-NEXT:    [[PHI:%.*]] = phi float [ [[RET]], [[ENTRY:%.*]] ], [ [[RET]], [[LOOP]] ]
; CHECK-NEXT:    [[COND:%.*]] = load volatile i1, ptr [[PTR]], align 1
; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK:       exit:
; CHECK-NEXT:    ret float [[RET]]
;
entry:
  %ret = call float @ret_nofpclass_nan()
  br label %loop

loop:
  %phi = phi float [%ret, %entry], [%phi, %loop]
  %cond = load volatile i1, ptr %ptr
  br i1 %cond, label %loop, label %exit

exit:
  ret float %phi
}

; Should be able to infer nofpclass(nan) return
define float @fcmp_uno_check(float %arg) local_unnamed_addr {
; CHECK-LABEL: define float @fcmp_uno_check
; CHECK-SAME: (float [[ARG:%.*]]) local_unnamed_addr {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[ISNAN:%.*]] = fcmp uno float [[ARG]], 0.000000e+00
; CHECK-NEXT:    br i1 [[ISNAN]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK:       bb0:
; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @ret_nofpclass_nan()
; CHECK-NEXT:    br label [[BB1]]
; CHECK:       bb1:
; CHECK-NEXT:    [[PHI:%.*]] = phi float [ [[CALL]], [[BB0]] ], [ [[ARG]], [[ENTRY:%.*]] ]
; CHECK-NEXT:    ret float [[PHI]]
;
entry:
  %isnan = fcmp uno float %arg, 0.0
  br i1 %isnan, label %bb0, label %bb1

bb0:
  %call = call float @ret_nofpclass_nan()
  br label %bb1

bb1:
  %phi = phi float [ %call, %bb0 ], [ %arg, %entry ]
  ret float %phi
}

; Should be able to infer nofpclass(nan) on %arg use
define void @fcmp_ord_guard_callsite_arg(float %arg) {
; CHECK-LABEL: define void @fcmp_ord_guard_callsite_arg
; CHECK-SAME: (float [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[IS_NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
; CHECK-NEXT:    br i1 [[IS_NOT_NAN]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK:       bb0:
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    br label [[BB1]]
; CHECK:       bb1:
; CHECK-NEXT:    ret void
;
entry:
  %is.not.nan = fcmp ord float %arg, 0.0
  br i1 %is.not.nan, label %bb0, label %bb1

bb0:
  call void @extern.use(float %arg)
  br label %bb1

bb1:
  ret void
}

; Should be able to infer nofpclass on both %arg uses
define float @fcmp_ord_assume_callsite_arg_return(float %arg) {
; CHECK-LABEL: define float @fcmp_ord_assume_callsite_arg_return
; CHECK-SAME: (float returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[IS_NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NOT_NAN]]) #[[ATTR18:[0-9]+]]
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    ret float [[ARG]]
;
entry:
  %is.not.nan = fcmp ord float %arg, 0.0
  call void @llvm.assume(i1 %is.not.nan)
  call void @extern.use(float %arg)
  ret float %arg
}

define internal float @returned_dead() {
; CHECK-LABEL: define internal nofpclass(nan inf nzero sub norm) float @returned_dead() {
; CHECK-NEXT:    call void @unknown()
; CHECK-NEXT:    ret float undef
;
  call void @unknown()
  ret float 0.0
}

define void @returned_dead_caller() {
; CHECK-LABEL: define void @returned_dead_caller() {
; CHECK-NEXT:    [[TMP1:%.*]] = call float @returned_dead()
; CHECK-NEXT:    ret void
;
  call float @returned_dead()
  ret void
}

define internal float @only_nofpclass_inf_callers(float %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define internal float @only_nofpclass_inf_callers
; CHECK-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg, %arg
  ret float %add
}

define float @call_noinf_0(float nofpclass(inf) %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define float @call_noinf_0
; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR19:[0-9]+]]
; TUNIT-NEXT:    ret float [[RESULT]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define float @call_noinf_0
; CGSCC-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
; CGSCC-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR19:[0-9]+]]
; CGSCC-NEXT:    ret float [[RESULT]]
;
  %result = call float @only_nofpclass_inf_callers(float %arg)
  ret float %result
}

define float @call_noinf_1(float %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define float @call_noinf_1
; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR19]]
; TUNIT-NEXT:    ret float [[RESULT]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define float @call_noinf_1
; CGSCC-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[RESULT]]
;
  %result = call float @only_nofpclass_inf_callers(float nofpclass(inf) %arg)
  ret float %result
}

; TODO: Should be able to infer nofpclass(inf) on return
define internal float @only_nofpclass_inf_return_users(float %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define internal float @only_nofpclass_inf_return_users
; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg, %arg
  ret float %add
}

define float @call_noinf_return_0(float %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(inf) float @call_noinf_return_0
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR19]]
; TUNIT-NEXT:    ret float [[RESULT]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(inf) float @call_noinf_return_0
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[RESULT]]
;
  %result = call nofpclass(inf) float @only_nofpclass_inf_return_users(float %arg)
  ret float %result
}

define float @call_noinf_return_1(float %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(inf) float @call_noinf_return_1
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR19]]
; TUNIT-NEXT:    ret float [[RESULT]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(inf) float @call_noinf_return_1
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[RESULT]]
;
  %result = call nofpclass(inf) float @only_nofpclass_inf_return_users(float %arg)
  ret float %result
}

define float @fcmp_olt_assume_one_0_callsite_arg_return(float %arg) {
; CHECK-LABEL: define float @fcmp_olt_assume_one_0_callsite_arg_return
; CHECK-SAME: (float returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp one float [[ARG]], 0.000000e+00
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    ret float [[ARG]]
;
entry:
  %is.not.zero.or.nan = fcmp one float %arg, 0.0
  call void @llvm.assume(i1 %is.not.zero.or.nan)
  call void @extern.use(float %arg)
  ret float %arg
}

define float @fcmp_olt_assume_une_0_callsite_arg_return(float %arg) {
; CHECK-LABEL: define float @fcmp_olt_assume_une_0_callsite_arg_return
; CHECK-SAME: (float returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp une float [[ARG]], 0.000000e+00
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    ret float [[ARG]]
;
entry:
  %is.not.zero.or.nan = fcmp une float %arg, 0.0
  call void @llvm.assume(i1 %is.not.zero.or.nan)
  call void @extern.use(float %arg)
  ret float %arg
}

define half @fcmp_assume_issubnormal_callsite_arg_return(half %arg) {
; CHECK-LABEL: define half @fcmp_assume_issubnormal_callsite_arg_return
; CHECK-SAME: (half returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fabs.f16(half [[ARG]]) #[[ATTR20:[0-9]+]]
; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
; CHECK-NEXT:    ret half [[ARG]]
;
entry:
  %fabs = call half @llvm.fabs.f16(half %arg)
  %is.subnormal = fcmp olt half %fabs, 0xH0400
  call void @llvm.assume(i1 %is.subnormal)
  call void @extern.use.f16(half %arg)
  ret half %arg
}

; Assume is after the call, shouldn't mark callsite.
define half @fcmp_assume_not_inf_after_call(half %arg) {
; CHECK-LABEL: define half @fcmp_assume_not_inf_after_call
; CHECK-SAME: (half returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
; CHECK-NEXT:    [[NOT_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[NOT_INF]])
; CHECK-NEXT:    ret half [[ARG]]
;
entry:
  call void @extern.use.f16(half %arg)
  %not.inf = fcmp oeq half %arg, 0xH7C00
  call void @llvm.assume(i1 %not.inf)
  ret half %arg
}

; Assume not subnormal or zero, and not infinity
define half @fcmp_assume2_callsite_arg_return(half %arg) {
; CHECK-LABEL: define half @fcmp_assume2_callsite_arg_return
; CHECK-SAME: (half returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fabs.f16(half [[ARG]]) #[[ATTR20]]
; CHECK-NEXT:    [[NOT_SUBNORMAL_OR_ZERO:%.*]] = fcmp oge half [[FABS]], 0xH0400
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[NOT_SUBNORMAL_OR_ZERO]]) #[[ATTR18]]
; CHECK-NEXT:    [[NOT_INF:%.*]] = fcmp one half [[ARG]], 0xH7C00
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[NOT_INF]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
; CHECK-NEXT:    ret half [[ARG]]
;
entry:
  %fabs = call half @llvm.fabs.f16(half %arg)
  %not.subnormal.or.zero = fcmp oge half %fabs, 0xH0400
  call void @llvm.assume(i1 %not.subnormal.or.zero)

  %not.inf = fcmp one half %arg, 0xH7C00
  call void @llvm.assume(i1 %not.inf)

  call void @extern.use.f16(half %arg)
  ret half %arg
}

define float @is_fpclass_assume_arg_return(float %arg) {
; CHECK-LABEL: define float @is_fpclass_assume_arg_return
; CHECK-SAME: (float returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CLASS_TEST:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 292) #[[ATTR20]]
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[CLASS_TEST]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    ret float [[ARG]]
;
entry:
  %class.test = call i1 @llvm.is.fpclass.f32(float %arg, i32 292)
  call void @llvm.assume(i1 %class.test)
  call void @extern.use(float %arg)
  ret float %arg
}

; Make sure we don't get confused by looking at an unrelated assume
; based on the fabs of the value.
define half @assume_fcmp_fabs_with_other_fabs_assume(half %arg) {
; CHECK-LABEL: define half @assume_fcmp_fabs_with_other_fabs_assume
; CHECK-SAME: (half returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fabs.f16(half [[ARG]]) #[[ATTR20]]
; CHECK-NEXT:    [[UNRELATED_FABS:%.*]] = fcmp one half [[FABS]], 0xH0000
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR18]]
; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
; CHECK-NEXT:    call void @extern.use.f16(half nofpclass(ninf nzero nsub nnorm) [[FABS]])
; CHECK-NEXT:    ret half [[ARG]]
;
entry:

  %fabs = call half @llvm.fabs.f16(half %arg)
  %unrelated.fabs = fcmp one half %fabs, 0.0
  call void @llvm.assume(i1 %unrelated.fabs)
  %is.subnormal = fcmp olt half %fabs, 0xH0400
  call void @llvm.assume(i1 %is.subnormal)
  call void @extern.use.f16(half %arg)
  call void @extern.use.f16(half %fabs)
  ret half %arg
}

; Make sure if looking through the fabs finds a different source
; value, we still identify a test mask by ignoring the fabs
define half @assume_fcmp_fabs_with_other_fabs_assume_fallback(half %arg) {
; CHECK-LABEL: define half @assume_fcmp_fabs_with_other_fabs_assume_fallback
; CHECK-SAME: (half returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) half @llvm.fabs.f16(half [[ARG]]) #[[ATTR20]]
; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) #[[ATTR18]]
; CHECK-NEXT:    [[UNRELATED_FABS:%.*]] = fcmp oeq half [[FABS]], 0xH0000
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR18]]
; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
; CHECK-NEXT:    call void @extern.use.f16(half nofpclass(ninf nzero nsub nnorm) [[FABS]])
; CHECK-NEXT:    ret half [[ARG]]
;
entry:

  %fabs = call half @llvm.fabs.f16(half %arg)

  %one.inf = fcmp one half %arg, 0xH7C00
  call void @llvm.assume(i1 %one.inf)

  %unrelated.fabs = fcmp oeq half %fabs, 0.0
  call void @llvm.assume(i1 %unrelated.fabs)

  %is.subnormal = fcmp olt half %fabs, 0xH0400
  call void @llvm.assume(i1 %is.subnormal)
  call void @extern.use.f16(half %arg)
  call void @extern.use.f16(half %fabs)
  ret half %arg
}

define float @assume_bundles(i1 %c, float %ret) {
; CHECK-LABEL: define float @assume_bundles
; CHECK-SAME: (i1 noundef [[C:%.*]], float returned [[RET:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
; CHECK:       A:
; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) #[[ATTR18]] [ "nofpclass"(float [[RET]], i32 3) ]
; CHECK-NEXT:    call void @extern.use(float nofpclass(nan) [[RET]])
; CHECK-NEXT:    ret float [[RET]]
; CHECK:       B:
; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofpclass"(float [[RET]], i32 12) ]
; CHECK-NEXT:    call void @extern.use(float nofpclass(ninf nnorm) [[RET]])
; CHECK-NEXT:    ret float [[RET]]
;
entry:
  br i1 %c, label %A, label %B

A:
  call void @llvm.assume(i1 true) [ "nofpclass"(float %ret, i32 3) ]
  call void @extern.use(float %ret)
  ret float %ret

B:
  call void @llvm.assume(i1 true) [ "nofpclass"(float %ret, i32 12) ]
  call void @extern.use(float %ret)
  ret float %ret
}

define float @returned_load(ptr %ptr) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: define float @returned_load
; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[PTR:%.*]]) #[[ATTR5:[0-9]+]] {
; CHECK-NEXT:    [[LOAD:%.*]] = load float, ptr [[PTR]], align 4
; CHECK-NEXT:    ret float [[LOAD]]
;
  %load = load float, ptr %ptr
  ret float %load
}

define float @pass_nofpclass_inf_through_memory(float nofpclass(inf) %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define float @pass_nofpclass_inf_through_memory
; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; TUNIT-NEXT:    store float [[ARG]], ptr [[ALLOCA]], align 4
; TUNIT-NEXT:    [[RET:%.*]] = call float @returned_load(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ALLOCA]]) #[[ATTR21:[0-9]+]]
; TUNIT-NEXT:    ret float [[RET]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define float @pass_nofpclass_inf_through_memory
; CGSCC-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; CGSCC-NEXT:    store float [[ARG]], ptr [[ALLOCA]], align 4
; CGSCC-NEXT:    [[RET:%.*]] = call float @returned_load(ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ALLOCA]]) #[[ATTR21:[0-9]+]]
; CGSCC-NEXT:    ret float [[RET]]
;
  %alloca = alloca float
  store float %arg, ptr %alloca
  %ret = call float @returned_load(ptr %alloca)
  ret float %ret
}

define float @returned_fabs(float %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs
; TUNIT-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR22:[0-9]+]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs
; CGSCC-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nosnan(float nofpclass(snan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(snan ninf nzero nsub nnorm) float @returned_fabs_nosnan
; TUNIT-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(snan ninf nzero nsub nnorm) float @returned_fabs_nosnan
; CGSCC-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_noqnan(float nofpclass(qnan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(qnan ninf nzero nsub nnorm) float @returned_fabs_noqnan
; TUNIT-SAME: (float nofpclass(qnan) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(qnan ninf nzero nsub nnorm) float @returned_fabs_noqnan
; CGSCC-SAME: (float nofpclass(qnan) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nonan(float nofpclass(nan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @returned_fabs_nonan
; TUNIT-SAME: (float nofpclass(nan) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @returned_fabs_nonan
; CGSCC-SAME: (float nofpclass(nan) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_noinf(float nofpclass(inf) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(inf nzero nsub nnorm) float @returned_fabs_noinf
; TUNIT-SAME: (float nofpclass(inf) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(inf) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(inf nzero nsub nnorm) float @returned_fabs_noinf
; CGSCC-SAME: (float nofpclass(inf) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(inf) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nopos(float nofpclass(psub pnorm pinf) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nopos
; TUNIT-SAME: (float nofpclass(pinf psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf psub pnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nopos
; CGSCC-SAME: (float nofpclass(pinf psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf psub pnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nopos_nopzero(float nofpclass(psub pnorm pinf pzero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nopos_nopzero
; TUNIT-SAME: (float nofpclass(pinf pzero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf pzero psub pnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nopos_nopzero
; CGSCC-SAME: (float nofpclass(pinf pzero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf pzero psub pnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nopos_nozero(float nofpclass(psub pnorm pinf zero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf zero nsub nnorm) float @returned_fabs_nopos_nozero
; TUNIT-SAME: (float nofpclass(pinf zero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf zero psub pnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf zero nsub nnorm) float @returned_fabs_nopos_nozero
; CGSCC-SAME: (float nofpclass(pinf zero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf zero psub pnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nopos_nonan(float nofpclass(psub pnorm pinf nan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @returned_fabs_nopos_nonan
; TUNIT-SAME: (float nofpclass(nan pinf psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan pinf psub pnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @returned_fabs_nopos_nonan
; CGSCC-SAME: (float nofpclass(nan pinf psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan pinf psub pnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_noneg(float nofpclass(nsub nnorm ninf) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_noneg
; TUNIT-SAME: (float nofpclass(ninf nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nsub nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_noneg
; CGSCC-SAME: (float nofpclass(ninf nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nsub nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_noneg_nonzero(float nofpclass(nsub nnorm ninf nzero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_noneg_nonzero
; TUNIT-SAME: (float nofpclass(ninf nzero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nzero nsub nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_noneg_nonzero
; CGSCC-SAME: (float nofpclass(ninf nzero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nzero nsub nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_noneg_nozero(float nofpclass(nsub nnorm ninf zero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf zero nsub nnorm) float @returned_fabs_noneg_nozero
; TUNIT-SAME: (float nofpclass(ninf zero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf zero nsub nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf zero nsub nnorm) float @returned_fabs_noneg_nozero
; CGSCC-SAME: (float nofpclass(ninf zero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf zero nsub nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_noneg_nonan(float nofpclass(nsub nnorm ninf nan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @returned_fabs_noneg_nonan
; TUNIT-SAME: (float nofpclass(nan ninf nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan ninf nsub nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @returned_fabs_noneg_nonan
; CGSCC-SAME: (float nofpclass(nan ninf nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan ninf nsub nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nonsub_nopnorm_nonzero(float nofpclass(nsub pnorm nzero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nonsub_nopnorm_nonzero
; TUNIT-SAME: (float nofpclass(nzero nsub pnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nzero nsub pnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nonsub_nopnorm_nonzero
; CGSCC-SAME: (float nofpclass(nzero nsub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nzero nsub pnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nopsub_nonnorm_nopzero(float nofpclass(psub nnorm pzero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nopsub_nonnorm_nopzero
; TUNIT-SAME: (float nofpclass(pzero psub nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pzero psub nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nopsub_nonnorm_nopzero
; CGSCC-SAME: (float nofpclass(pzero psub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pzero psub nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fabs_nonnorm_nozero(float nofpclass(nnorm nzero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nonnorm_nozero
; TUNIT-SAME: (float nofpclass(nzero nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nzero nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fabs_nonnorm_nozero
; CGSCC-SAME: (float nofpclass(nzero nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nzero nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  ret float %fabs
}

define float @returned_fneg(float %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @returned_fneg
; CHECK-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_nosnan(float nofpclass(snan) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(snan) float @returned_fneg_nosnan
; CHECK-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_noqnan(float nofpclass(qnan) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(qnan) float @returned_fneg_noqnan
; CHECK-SAME: (float nofpclass(qnan) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_nosnan_ninf_flag(float nofpclass(snan) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(snan inf) float @returned_fneg_nosnan_ninf_flag
; CHECK-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg ninf float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg ninf float %x
  ret float %fneg
}

define float @returned_fneg_nonan(float nofpclass(nan) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @returned_fneg_nonan
; CHECK-SAME: (float nofpclass(nan) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_noinf(float nofpclass(inf) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(inf) float @returned_fneg_noinf
; CHECK-SAME: (float nofpclass(inf) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_noneg(float nofpclass(ninf nsub nnorm nzero) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_noneg
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_noneg_nnan_flag(float nofpclass(ninf nsub nnorm nzero) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @returned_fneg_noneg_nnan_flag
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg nnan float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg nnan float %x
  ret float %fneg
}

define float @returned_fneg_nonsubnnorm(float nofpclass(nsub nnorm) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(psub pnorm) float @returned_fneg_nonsubnnorm
; CHECK-SAME: (float nofpclass(nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_nopos(float nofpclass(pinf psub pnorm pzero) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @returned_fneg_nopos
; CHECK-SAME: (float nofpclass(pinf pzero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_nopnormpsub(float nofpclass(psub pnorm) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nsub nnorm) float @returned_fneg_nopnormpsub
; CHECK-SAME: (float nofpclass(psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_mixed(float nofpclass(psub nnorm nzero qnan ninf) %x) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(qnan pinf pzero nsub pnorm) float @returned_fneg_mixed
; CHECK-SAME: (float nofpclass(qnan ninf nzero psub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT:    ret float [[FNEG]]
;
  %fneg = fneg float %x
  ret float %fneg
}

define float @returned_fneg_fabs(float %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs
; TUNIT-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs
; CGSCC-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_nosnan(float nofpclass(snan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(snan pinf pzero psub pnorm) float @returned_fneg_fabs_nosnan
; TUNIT-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(snan pinf pzero psub pnorm) float @returned_fneg_fabs_nosnan
; CGSCC-SAME: (float nofpclass(snan) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(snan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(snan) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_noqnan(float nofpclass(qnan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(qnan pinf pzero psub pnorm) float @returned_fneg_fabs_noqnan
; TUNIT-SAME: (float nofpclass(qnan) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(qnan pinf pzero psub pnorm) float @returned_fneg_fabs_noqnan
; CGSCC-SAME: (float nofpclass(qnan) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_nonan(float nofpclass(nan) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @returned_fneg_fabs_nonan
; TUNIT-SAME: (float nofpclass(nan) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @returned_fneg_fabs_nonan
; CGSCC-SAME: (float nofpclass(nan) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(nan) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_noneg(float nofpclass(ninf nsub nnorm nzero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs_noneg
; TUNIT-SAME: (float nofpclass(ninf nzero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nzero nsub nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs_noneg
; CGSCC-SAME: (float nofpclass(ninf nzero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(ninf nzero nsub nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_nopos(float nofpclass(pinf psub pnorm pzero) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs_nopos
; TUNIT-SAME: (float nofpclass(pinf pzero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf pzero psub pnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(pinf pzero psub pnorm) float @returned_fneg_fabs_nopos
; CGSCC-SAME: (float nofpclass(pinf pzero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(pinf pzero psub pnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_mixed(float nofpclass(psub nnorm nzero qnan ninf) %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(qnan pinf pzero psub pnorm) float @returned_fneg_fabs_mixed
; TUNIT-SAME: (float nofpclass(qnan ninf nzero psub nnorm) [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan ninf nzero psub nnorm) [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(qnan pinf pzero psub pnorm) float @returned_fneg_fabs_mixed
; CGSCC-SAME: (float nofpclass(qnan ninf nzero psub nnorm) [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(qnan ninf nzero nsub nnorm) float @llvm.fabs.f32(float nofpclass(qnan ninf nzero psub nnorm) [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_ninf_flag_fabs(float %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(inf pzero psub pnorm) float @returned_fneg_fabs_ninf_flag_fabs
; TUNIT-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call ninf nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(inf pzero psub pnorm) float @returned_fneg_fabs_ninf_flag_fabs
; CGSCC-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call ninf nofpclass(inf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call ninf float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg float %fabs
  ret float %fneg.fabs
}

define float @returned_fneg_fabs_ninf_flag_fneg(float %x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(inf pzero psub pnorm) float @returned_fneg_fabs_ninf_flag_fneg
; TUNIT-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR22]]
; TUNIT-NEXT:    [[FNEG_FABS:%.*]] = fneg ninf float [[FABS]]
; TUNIT-NEXT:    ret float [[FNEG_FABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define nofpclass(inf pzero psub pnorm) float @returned_fneg_fabs_ninf_flag_fneg
; CGSCC-SAME: (float [[X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[FABS:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float [[X]]) #[[ATTR19]]
; CGSCC-NEXT:    [[FNEG_FABS:%.*]] = fneg ninf float [[FABS]]
; CGSCC-NEXT:    ret float [[FNEG_FABS]]
;
  %fabs = call float @llvm.fabs.f32(float %x)
  %fneg.fabs = fneg ninf float %fabs
  ret float %fneg.fabs
}

define float @uitofp_i32_to_f32(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub nnorm) float @uitofp_i32_to_f32
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = uitofp i32 [[ARG]] to float
; CHECK-NEXT:    ret float [[CVT]]
;
  %cvt = uitofp i32 %arg to float
  ret float %cvt
}

define float @sitofp_i32_to_f32(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub) float @sitofp_i32_to_f32
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = sitofp i32 [[ARG]] to float
; CHECK-NEXT:    ret float [[CVT]]
;
  %cvt = sitofp i32 %arg to float
  ret float %cvt
}

define <2 x float> @uitofp_v2i32_to_v2f32(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub nnorm) <2 x float> @uitofp_v2i32_to_v2f32
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = uitofp <2 x i32> [[ARG]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CVT]]
;
  %cvt = uitofp <2 x i32> %arg to <2 x float>
  ret <2 x float> %cvt
}

define <2 x float> @sitofp_v2i32_to_v2i32(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub) <2 x float> @sitofp_v2i32_to_v2i32
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = sitofp <2 x i32> [[ARG]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CVT]]
;
  %cvt = sitofp <2 x i32> %arg to <2 x float>
  ret <2 x float> %cvt
}

define half @uitofp_i17_to_f16(i17 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) half @uitofp_i17_to_f16
; CHECK-SAME: (i17 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = uitofp i17 [[ARG]] to half
; CHECK-NEXT:    ret half [[CVT]]
;
  %cvt = uitofp i17 %arg to half
  ret half %cvt
}

define half @sitofp_i17_to_f16(i17 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan nzero sub) half @sitofp_i17_to_f16
; CHECK-SAME: (i17 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = sitofp i17 [[ARG]] to half
; CHECK-NEXT:    ret half [[CVT]]
;
  %cvt = sitofp i17 %arg to half
  ret half %cvt
}

define <2 x half> @uitofp_v2i17_to_v2f16(<2 x i17> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) <2 x half> @uitofp_v2i17_to_v2f16
; CHECK-SAME: (<2 x i17> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = uitofp <2 x i17> [[ARG]] to <2 x half>
; CHECK-NEXT:    ret <2 x half> [[CVT]]
;
  %cvt = uitofp <2 x i17> %arg to <2 x half>
  ret <2 x half> %cvt
}

define <2 x half> @sitofp_v2i17_to_v2i17(<2 x i17> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan nzero sub) <2 x half> @sitofp_v2i17_to_v2i17
; CHECK-SAME: (<2 x i17> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CVT:%.*]] = sitofp <2 x i17> [[ARG]] to <2 x half>
; CHECK-NEXT:    ret <2 x half> [[CVT]]
;
  %cvt = sitofp <2 x i17> %arg to <2 x half>
  ret <2 x half> %cvt
}

define float @assume_intersection_not_zero_and_not_nan(float %arg) {
; CHECK-LABEL: define float @assume_intersection_not_zero_and_not_nan
; CHECK-SAME: (float returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp une float [[ARG]], 0.000000e+00
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR18]]
; CHECK-NEXT:    [[IS_ORD:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_ORD]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    ret float [[ARG]]
;
entry:
  %is.not.zero.or.nan = fcmp une float %arg, 0.0
  call void @llvm.assume(i1 %is.not.zero.or.nan)
  %is.ord = fcmp ord float %arg, 0.0
  call void @llvm.assume(i1 %is.ord)
  call void @extern.use(float %arg)
  ret float %arg
}

define float @assume_intersection_class(float %arg) {
; CHECK-LABEL: define float @assume_intersection_class
; CHECK-SAME: (float returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[POS_NORMAL_OR_POS_SUBNORMAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 384) #[[ATTR20]]
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[POS_NORMAL_OR_POS_SUBNORMAL]]) #[[ATTR18]]
; CHECK-NEXT:    [[IS_NORMAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 264) #[[ATTR20]]
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NORMAL]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    ret float [[ARG]]
;
entry:
  %pos.normal.or.pos.subnormal = call i1 @llvm.is.fpclass.f32(float %arg, i32 384)
  call void @llvm.assume(i1 %pos.normal.or.pos.subnormal)
  %is.normal = call i1 @llvm.is.fpclass.f32(float %arg, i32 264)
  call void @llvm.assume(i1 %is.normal)

  call void @extern.use(float %arg)
  ret float %arg
}

define float @assume_intersection_none(float %arg) {
; CHECK-LABEL: define float @assume_intersection_none
; CHECK-SAME: (float returned [[ARG:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CLASS1:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 682) #[[ATTR20]]
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[CLASS1]]) #[[ATTR18]]
; CHECK-NEXT:    [[CLASS2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 341) #[[ATTR20]]
; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[CLASS2]]) #[[ATTR18]]
; CHECK-NEXT:    call void @extern.use(float [[ARG]])
; CHECK-NEXT:    ret float [[ARG]]
;
entry:
  %class1 = call i1 @llvm.is.fpclass.f32(float %arg, i32 682)
  call void @llvm.assume(i1 %class1)
  %class2 = call i1 @llvm.is.fpclass.f32(float %arg, i32 341)
  call void @llvm.assume(i1 %class2)
  call void @extern.use(float %arg)
  ret float %arg
}

define float @returned_extractelement_dynamic_index(<4 x float> nofpclass(nan) %vec, i32 %idx) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @returned_extractelement_dynamic_index
; CHECK-SAME: (<4 x float> nofpclass(nan) [[VEC:%.*]], i32 [[IDX:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[VEC]], i32 [[IDX]]
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %extract = extractelement <4 x float> %vec, i32 %idx
  ret float %extract
}

define float @returned_extractelement_index0(<4 x float> nofpclass(nan) %vec) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @returned_extractelement_index0
; CHECK-SAME: (<4 x float> nofpclass(nan) [[VEC:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[VEC]], i32 0
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %extract = extractelement <4 x float> %vec, i32 0
  ret float %extract
}

define float @returned_extractelement_index_oob(<4 x float> nofpclass(nan) %vec) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @returned_extractelement_index_oob
; CHECK-SAME: (<4 x float> nofpclass(nan) [[VEC:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[VEC]], i32 5
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %extract = extractelement <4 x float> %vec, i32 5
  ret float %extract
}

define float @returned_extractelement_scalable(<vscale x 4 x float> nofpclass(nan) %vec) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @returned_extractelement_scalable
; CHECK-SAME: (<vscale x 4 x float> nofpclass(nan) [[VEC:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <vscale x 4 x float> [[VEC]], i32 0
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %extract = extractelement <vscale x 4 x float> %vec, i32 0
  ret float %extract
}

define float @returned_extractvalue([4 x float] nofpclass(nan) %array) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan) float @returned_extractvalue
; CHECK-SAME: ([4 x float] nofpclass(nan) [[ARRAY:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractvalue [4 x float] [[ARRAY]], 0
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %extract = extractvalue [4 x float] %array, 0
  ret float %extract
}

define float @return_nofpclass_freeze_nan_arg(float nofpclass(nan) %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define noundef float @return_nofpclass_freeze_nan_arg
; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FREEZE:%.*]] = freeze float [[ARG]]
; CHECK-NEXT:    ret float [[FREEZE]]
;
  %freeze = freeze float %arg
  ret float %freeze
}

define float @return_nofpclass_extractelement_freeze_pinf_arg(<2 x float> nofpclass(pinf) %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define noundef float @return_nofpclass_extractelement_freeze_pinf_arg
; CHECK-SAME: (<2 x float> nofpclass(pinf) [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FREEZE:%.*]] = freeze <2 x float> [[ARG]]
; CHECK-NEXT:    [[ELT:%.*]] = extractelement <2 x float> [[FREEZE]], i32 0
; CHECK-NEXT:    ret float [[ELT]]
;
  %freeze = freeze <2 x float> %arg
  %elt = extractelement <2 x float> %freeze, i32 0
  ret float %elt
}

define <4 x float> @insertelement_constant_chain() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan ninf nzero sub) <4 x float> @insertelement_constant_chain
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    [[INS_0:%.*]] = insertelement <4 x float> poison, float 1.000000e+00, i32 0
; CHECK-NEXT:    [[INS_1:%.*]] = insertelement <4 x float> [[INS_0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    [[INS_2:%.*]] = insertelement <4 x float> [[INS_1]], float -9.000000e+00, i32 2
; CHECK-NEXT:    [[INS_3:%.*]] = insertelement <4 x float> [[INS_2]], float 0x7FF0000000000000, i32 3
; CHECK-NEXT:    ret <4 x float> [[INS_3]]
;
  %ins.0 = insertelement <4 x float> poison, float 1.0, i32 0
  %ins.1 = insertelement <4 x float> %ins.0, float 0.0, i32 1
  %ins.2 = insertelement <4 x float> %ins.1, float -9.0, i32 2
  %ins.3 = insertelement <4 x float> %ins.2, float 0x7FF0000000000000, i32 3
  ret <4 x float> %ins.3
}

define <4 x float> @insertelement_non_constant_chain(i32 %idx) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub) <4 x float> @insertelement_non_constant_chain
; CHECK-SAME: (i32 [[IDX:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[INS_0:%.*]] = insertelement <4 x float> poison, float 1.000000e+00, i32 0
; CHECK-NEXT:    [[INS_1:%.*]] = insertelement <4 x float> [[INS_0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    [[INS_2:%.*]] = insertelement <4 x float> [[INS_1]], float -9.000000e+00, i32 2
; CHECK-NEXT:    [[INS_3:%.*]] = insertelement <4 x float> [[INS_2]], float 3.000000e+00, i32 3
; CHECK-NEXT:    [[INS_4:%.*]] = insertelement <4 x float> [[INS_2]], float 4.000000e+00, i32 [[IDX]]
; CHECK-NEXT:    ret <4 x float> [[INS_4]]
;
  %ins.0 = insertelement <4 x float> poison, float 1.0, i32 0
  %ins.1 = insertelement <4 x float> %ins.0, float 0.0, i32 1
  %ins.2 = insertelement <4 x float> %ins.1, float -9.0, i32 2
  %ins.3 = insertelement <4 x float> %ins.2, float 3.0, i32 3
  %ins.4 = insertelement <4 x float> %ins.2, float 4.0, i32 %idx
  ret <4 x float> %ins.4
}

define <vscale x 4 x float> @insertelement_scalable_constant_chain() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <vscale x 4 x float> @insertelement_scalable_constant_chain
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    [[INS_0:%.*]] = insertelement <vscale x 4 x float> poison, float 1.000000e+00, i32 0
; CHECK-NEXT:    [[INS_1:%.*]] = insertelement <vscale x 4 x float> [[INS_0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    [[INS_2:%.*]] = insertelement <vscale x 4 x float> [[INS_1]], float -9.000000e+00, i32 2
; CHECK-NEXT:    [[INS_3:%.*]] = insertelement <vscale x 4 x float> [[INS_2]], float 0x7FF0000000000000, i32 3
; CHECK-NEXT:    ret <vscale x 4 x float> [[INS_3]]
;
  %ins.0 = insertelement <vscale x 4 x float> poison, float 1.0, i32 0
  %ins.1 = insertelement <vscale x 4 x float> %ins.0, float 0.0, i32 1
  %ins.2 = insertelement <vscale x 4 x float> %ins.1, float -9.0, i32 2
  %ins.3 = insertelement <vscale x 4 x float> %ins.2, float 0x7FF0000000000000, i32 3
  ret <vscale x 4 x float> %ins.3
}

define <4 x float> @insertelement_unknown_base(<4 x float> %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @insertelement_unknown_base
; CHECK-SAME: (<4 x float> [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[INSERT:%.*]] = insertelement <4 x float> [[ARG0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    ret <4 x float> [[INSERT]]
;
  %insert = insertelement <4 x float> %arg0, float 0.0, i32 1
  ret <4 x float> %insert
}

define float @insertelement_extractelement_same(<4 x float> %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @insertelement_extractelement_same
; CHECK-SAME: (<4 x float> [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[INSERT:%.*]] = insertelement <4 x float> [[ARG0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[INSERT]], i32 1
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %insert = insertelement <4 x float> %arg0, float 0.0, i32 1
  %extract = extractelement <4 x float> %insert, i32 1
  ret float %extract
}

define float @insertelement_extractelement_different(<4 x float> nofpclass(zero) %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(zero) float @insertelement_extractelement_different
; CHECK-SAME: (<4 x float> nofpclass(zero) [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[INSERT:%.*]] = insertelement <4 x float> [[ARG0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[INSERT]], i32 2
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %insert = insertelement <4 x float> %arg0, float 0.0, i32 1
  %extract = extractelement <4 x float> %insert, i32 2
  ret float %extract
}

define float @insertelement_extractelement_unknown(<4 x float> nofpclass(zero) %arg0, i32 %idx) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @insertelement_extractelement_unknown
; CHECK-SAME: (<4 x float> nofpclass(zero) [[ARG0:%.*]], i32 [[IDX:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[INSERT:%.*]] = insertelement <4 x float> [[ARG0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[INSERT]], i32 [[IDX]]
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %insert = insertelement <4 x float> %arg0, float 0.0, i32 1
  %extract = extractelement <4 x float> %insert, i32 %idx
  ret float %extract
}

define <4 x float> @insertelement_index_oob_chain() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan ninf nzero sub norm) <4 x float> @insertelement_index_oob_chain
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    [[INSERT:%.*]] = insertelement <4 x float> zeroinitializer, float 0x7FF0000000000000, i32 4
; CHECK-NEXT:    ret <4 x float> [[INSERT]]
;
  %insert = insertelement <4 x float> zeroinitializer, float 0x7FF0000000000000, i32 4
  ret <4 x float> %insert
}

define <2 x float> @multiple_extractelement(<4 x float> nofpclass(zero) %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(zero) <2 x float> @multiple_extractelement
; CHECK-SAME: (<4 x float> nofpclass(zero) [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[INSERT:%.*]] = insertelement <4 x float> [[ARG0]], float 0.000000e+00, i32 1
; CHECK-NEXT:    [[EXTRACT2:%.*]] = extractelement <4 x float> [[INSERT]], i32 2
; CHECK-NEXT:    [[EXTRACT3:%.*]] = extractelement <4 x float> [[INSERT]], i32 3
; CHECK-NEXT:    [[INS_0:%.*]] = insertelement <2 x float> poison, float [[EXTRACT3]], i32 0
; CHECK-NEXT:    [[INS_1:%.*]] = insertelement <2 x float> [[INS_0]], float [[EXTRACT2]], i32 1
; CHECK-NEXT:    ret <2 x float> [[INS_1]]
;
  %insert = insertelement <4 x float> %arg0, float 0.0, i32 1
  %extract2 = extractelement <4 x float> %insert, i32 2
  %extract3 = extractelement <4 x float> %insert, i32 3
  %ins.0 = insertelement <2 x float> poison, float %extract3, i32 0
  %ins.1 = insertelement <2 x float> %ins.0, float %extract2, i32 1
  ret <2 x float> %ins.1
}

; FIXME: Doesn't actually reach computeKnownFPClass
define <4 x float> @shufflevector_constexpr() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @shufflevector_constexpr
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    ret <4 x float> <float 1.000000e+00, float bitcast (i32 ptrtoint (ptr @shufflevector_constexpr to i32) to float), float 4.000000e+00, float 0.000000e+00>
;
  ret <4 x float> shufflevector (<2 x float> <float 1.0, float bitcast (i32 ptrtoint (ptr @shufflevector_constexpr to i32) to float)>, <2 x float> <float 4.0, float 0.0>, <4 x i32> <i32 0, i32 1, i32 2, i32 3>)
}

define <4 x float> @shufflevector_concat_disjoint(<2 x float> nofpclass(nan) %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @shufflevector_concat_disjoint
; CHECK-SAME: (<2 x float> nofpclass(nan) [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_concat_overlap(<2 x float> nofpclass(nan norm psub) %arg0, <2 x float> nofpclass(inf nan sub) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan psub) <4 x float> @shufflevector_concat_overlap
; CHECK-SAME: (<2 x float> nofpclass(nan psub norm) [[ARG0:%.*]], <2 x float> nofpclass(nan inf sub) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_unknown_lhs(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @shufflevector_unknown_lhs
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 3, i32 2, i32 1, i32 0>
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_unknown_rhs(<2 x float> nofpclass(inf) %arg0, <2 x float> %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @shufflevector_unknown_rhs
; CHECK-SAME: (<2 x float> nofpclass(inf) [[ARG0:%.*]], <2 x float> [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 3, i32 2, i32 1, i32 0>
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_unknown_all(<2 x float> %arg0, <2 x float> %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @shufflevector_unknown_all
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 3, i32 2, i32 1, i32 0>
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_only_demand_lhs(<2 x float> nofpclass(inf) %arg0, <2 x float> %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(inf) <4 x float> @shufflevector_only_demand_lhs
; CHECK-SAME: (<2 x float> nofpclass(inf) [[ARG0:%.*]], <2 x float> [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 0, i32 1, i32 1, i32 0>
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_only_demand_rhs(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(inf) <4 x float> @shufflevector_only_demand_rhs
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 2, i32 3, i32 3, i32 2>
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 2, i32 3, i32 3, i32 2>
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_undef_demanded(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @shufflevector_undef_demanded
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> poison
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> undef
  ret <4 x float> %shuffle
}

define <4 x float> @shufflevector_zeroinit_demanded(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <4 x float> @shufflevector_zeroinit_demanded
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> zeroinitializer
; CHECK-NEXT:    ret <4 x float> [[SHUFFLE]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> zeroinitializer
  ret <4 x float> %shuffle
}

define float @shufflevector_extractelt0(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @shufflevector_extractelt0
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 1, i32 3, i32 0, i32 1>
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[SHUFFLE]], i32 0
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 1, i32 3, i32 0, i32 1>
  %extract = extractelement <4 x float> %shuffle, i32 0
  ret float %extract
}

define float @shufflevector_extractelt1(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(inf) float @shufflevector_extractelt1
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 1, i32 3, i32 0, i32 1>
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[SHUFFLE]], i32 1
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 1, i32 3, i32 0, i32 1>
  %extract = extractelement <4 x float> %shuffle, i32 1
  ret float %extract
}

define float @shufflevector_extractelt2(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @shufflevector_extractelt2
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 1, i32 3, i32 0, i32 1>
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[SHUFFLE]], i32 2
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 1, i32 3, i32 0, i32 1>
  %extract = extractelement <4 x float> %shuffle, i32 2
  ret float %extract
}

define float @shufflevector_extractelt3(<2 x float> %arg0, <2 x float> nofpclass(inf) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @shufflevector_extractelt3
; CHECK-SAME: (<2 x float> [[ARG0:%.*]], <2 x float> nofpclass(inf) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <2 x float> [[ARG0]], <2 x float> [[ARG1]], <4 x i32> <i32 1, i32 3, i32 0, i32 1>
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <4 x float> [[SHUFFLE]], i32 3
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %shuffle = shufflevector <2 x float> %arg0, <2 x float> %arg1, <4 x i32> <i32 1, i32 3, i32 0, i32 1>
  %extract = extractelement <4 x float> %shuffle, i32 3
  ret float %extract
}

define float @shufflevector_constantdatavector_demanded0() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @shufflevector_constantdatavector_demanded0
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <3 x float> <float 1.000000e+00, float 0x7FF8000000000000, float 0.000000e+00>, <3 x float> poison, <2 x i32> <i32 0, i32 2>
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <2 x float> [[SHUFFLE]], i32 0
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %shuffle = shufflevector <3 x float> <float 1.0, float 0x7FF8000000000000, float 0.0>, <3 x float> poison, <2 x i32> <i32 0, i32 2>
  %extract = extractelement <2 x float> %shuffle, i32 0
  ret float %extract
}

define float @shufflevector_constantdatavector_demanded1() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) float @shufflevector_constantdatavector_demanded1
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE:%.*]] = shufflevector <3 x float> <float 1.000000e+00, float 0x7FF8000000000000, float 0.000000e+00>, <3 x float> poison, <2 x i32> <i32 0, i32 2>
; CHECK-NEXT:    [[EXTRACT:%.*]] = extractelement <2 x float> [[SHUFFLE]], i32 1
; CHECK-NEXT:    ret float [[EXTRACT]]
;
  %shuffle = shufflevector <3 x float> <float 1.0, float 0x7FF8000000000000, float 0.0>, <3 x float> poison, <2 x i32> <i32 0, i32 2>
  %extract = extractelement <2 x float> %shuffle, i32 1
  ret float %extract
}

define i32 @fptosi(float nofpclass(inf nan) %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define i32 @fptosi
; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[FPTOSI:%.*]] = fptosi float [[ARG]] to i32
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[FPTOSI]], 1
; CHECK-NEXT:    ret i32 [[ADD]]
;
  %fptosi = fptosi float %arg to i32
  %add = add i32 %fptosi, 1
  ret i32 %add
}

define float @fptrunc(double nofpclass(inf nan) %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fptrunc
; CHECK-SAME: (double nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CAST:%.*]] = fptrunc double [[ARG]] to float
; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[CAST]], [[CAST]]
; CHECK-NEXT:    ret float [[MUL]]
;
  %cast = fptrunc double %arg to float
  %mul = fmul float %cast, %cast
  ret float %mul
}

define double @fpext(float nofpclass(inf nan) %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) double @fpext
; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[CAST:%.*]] = fpext float [[ARG]] to double
; CHECK-NEXT:    [[MUL:%.*]] = fmul double [[CAST]], [[CAST]]
; CHECK-NEXT:    ret double [[MUL]]
;
  %cast = fpext float %arg to double
  %mul = fmul double %cast, %cast
  ret double %mul
}

define float @atomicrmw_fadd(ptr %ptr, float nofpclass(inf nan) %val) {
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define float @atomicrmw_fadd
; CHECK-SAME: (ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[PTR:%.*]], float nofpclass(nan inf) [[VAL:%.*]]) #[[ATTR6:[0-9]+]] {
; CHECK-NEXT:    [[RESULT:%.*]] = atomicrmw fadd ptr [[PTR]], float [[VAL]] seq_cst, align 4
; CHECK-NEXT:    ret float [[RESULT]]
;
  %result = atomicrmw fadd ptr %ptr, float %val seq_cst
  ret float %result
}

define float @load(ptr %ptr, float nofpclass(nan inf) %val) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @load
; CHECK-SAME: (ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[PTR:%.*]], float nofpclass(nan inf) [[VAL:%.*]]) #[[ATTR7:[0-9]+]] {
; CHECK-NEXT:    store float [[VAL]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[LOAD:%.*]] = load float, ptr [[PTR]], align 4
; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[LOAD]], [[LOAD]]
; CHECK-NEXT:    ret float [[MUL]]
;
  store float %val, ptr %ptr
  %load = load float, ptr %ptr
  %mul = fmul float %load, %load
  ret float %mul
}

define float @load_atomic(ptr %ptr, float nofpclass(nan inf) %val) {
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @load_atomic
; CHECK-SAME: (ptr nocapture nofree noundef nonnull align 4 dereferenceable(4) [[PTR:%.*]], float nofpclass(nan inf) [[VAL:%.*]]) #[[ATTR6]] {
; CHECK-NEXT:    store atomic float [[VAL]], ptr [[PTR]] seq_cst, align 4
; CHECK-NEXT:    [[LOAD:%.*]] = load atomic float, ptr [[PTR]] seq_cst, align 4
; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[LOAD]], [[LOAD]]
; CHECK-NEXT:    ret float [[MUL]]
;
  store atomic float %val, ptr %ptr seq_cst, align 4
  %load = load atomic float, ptr %ptr seq_cst, align 4
  %mul = fmul float %load, %load
  ret float %mul
}

define <8 x float> @shufflevector_shufflevector(<4 x float> nofpclass(inf nan) %arg0, <4 x float> nofpclass(inf nan zero) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf) <8 x float> @shufflevector_shufflevector
; CHECK-SAME: (<4 x float> nofpclass(nan inf) [[ARG0:%.*]], <4 x float> nofpclass(nan inf zero) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHUFFLE0:%.*]] = shufflevector <4 x float> [[ARG0]], <4 x float> [[ARG0]], <4 x i32> <i32 3, i32 2, i32 1, i32 0>
; CHECK-NEXT:    [[SHUFFLE1:%.*]] = shufflevector <4 x float> [[ARG1]], <4 x float> [[ARG1]], <4 x i32> <i32 0, i32 1, i32 2, i32 3>
; CHECK-NEXT:    [[SHUFFLE2:%.*]] = shufflevector <4 x float> [[SHUFFLE0]], <4 x float> [[SHUFFLE1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
; CHECK-NEXT:    ret <8 x float> [[SHUFFLE2]]
;
  %shuffle0 = shufflevector <4 x float> %arg0, <4 x float> %arg0, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
  %shuffle1 = shufflevector <4 x float> %arg1, <4 x float> %arg1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
  %shuffle2 = shufflevector <4 x float> %shuffle0, <4 x float> %shuffle1, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
  ret <8 x float> %shuffle2
}

define float @constrained_sitofp(i32 %arg) strictfp {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind strictfp willreturn memory(inaccessiblemem: readwrite)
; CHECK-LABEL: define nofpclass(nan nzero sub) float @constrained_sitofp
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR8:[0-9]+]] {
; CHECK-NEXT:    [[VAL:%.*]] = call nofpclass(nan nzero sub) float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR20]]
; CHECK-NEXT:    ret float [[VAL]]
;
  %val = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %arg, metadata !"round.dynamic", metadata !"fpexcept.strict")
  ret float %val
}

define float @constrained_uitofp(i32 %arg) strictfp {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind strictfp willreturn memory(inaccessiblemem: readwrite)
; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) float @constrained_uitofp
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR8]] {
; CHECK-NEXT:    [[VAL:%.*]] = call nofpclass(nan ninf nzero sub nnorm) float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR20]]
; CHECK-NEXT:    ret float [[VAL]]
;
  %val = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %arg, metadata !"round.dynamic", metadata !"fpexcept.strict")
  ret float %val
}

define float @fadd_p0(float %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, 0.0
  ret float %add
}

define float @fadd_n0(float %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_n0
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], -0.000000e+00
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, -0.0
  ret float %add
}

define float @fsub_p0(float %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_p0
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[ARG0]], 0.000000e+00
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float %arg0, 0.0
  ret float %sub
}

define float @fsub_n0(float %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fsub_n0
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[ARG0]], -0.000000e+00
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float %arg0, -0.0
  ret float %sub
}

define float @fsub_p0_commute(float %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fsub_p0_commute
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float 0.000000e+00, [[ARG0]]
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float 0.0, %arg0
  ret float %sub
}

define float @fsub_n0_commute(float %arg0) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_n0_commute
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float -0.000000e+00, [[ARG0]]
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float -0.0, %arg0
  ret float %sub
}

define float @fadd_p0_ftz_daz(float %arg0) #3 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0_ftz_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR9:[0-9]+]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, 0.0
  ret float %add
}

define float @fadd_n0_ftz_daz(float %arg0) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_n0_ftz_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR10:[0-9]+]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], -0.000000e+00
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, -0.0
  ret float %add
}

define float @fsub_p0_ftz_daz(float %arg0) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_p0_ftz_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[ARG0]], 0.000000e+00
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float %arg0, 0.0
  ret float %sub
}

define float @fsub_n0_ftz_daz(float %arg0) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_n0_ftz_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[ARG0]], -0.000000e+00
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float %arg0, -0.0
  ret float %sub
}

define float @fsub_p0_commute_ftz_daz(float %arg0) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_p0_commute_ftz_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float 0.000000e+00, [[ARG0]]
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float 0.0, %arg0
  ret float %sub
}

define float @fsub_n0_commute_ftz_daz(float %arg0) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_n0_commute_ftz_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float -0.000000e+00, [[ARG0]]
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float -0.0, %arg0
  ret float %sub
}

define float @fadd_p0_ieee_daz(float %arg0) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0_ieee_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR11:[0-9]+]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, 0.0
  ret float %add
}

define float @fadd_p0_dapz_ieee(float %arg0) #4 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_p0_dapz_ieee
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR12:[0-9]+]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], 0.000000e+00
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, 0.0
  ret float %add
}

define float @fadd_n0_ieee_daz(float %arg0) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_n0_ieee_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], -0.000000e+00
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, -0.0
  ret float %add
}

define float @fsub_p0_ieee_daz(float %arg0) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_p0_ieee_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[ARG0]], 0.000000e+00
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float %arg0, 0.0
  ret float %sub
}

define float @fsub_n0_ieee_daz(float %arg0) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fsub_n0_ieee_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float [[ARG0]], -0.000000e+00
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float %arg0, -0.0
  ret float %sub
}

define float @fsub_p0_commute_ieee_daz(float %arg0) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fsub_p0_commute_ieee_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float 0.000000e+00, [[ARG0]]
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float 0.0, %arg0
  ret float %sub
}

define float @fsub_n0_commute_ieee_daz(float %arg0) #1 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fsub_n0_commute_ieee_daz
; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR13:[0-9]+]] {
; CHECK-NEXT:    [[SUB:%.*]] = fsub float -0.000000e+00, [[ARG0]]
; CHECK-NEXT:    ret float [[SUB]]
;
  %sub = fsub float -0.0, %arg0
  ret float %sub
}

define float @fadd_never_negzero_or_negsub(float nofpclass(nzero nsub) %a, float nofpclass(nzero nsub) %b) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_negsub
; CHECK-SAME: (float nofpclass(nzero nsub) [[A:%.*]], float nofpclass(nzero nsub) [[B:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_never_negzero_or_negsub_daz(float nofpclass(nzero nsub) %a, float nofpclass(nzero nsub) %b) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_negsub_daz
; CHECK-SAME: (float nofpclass(nzero nsub) [[A:%.*]], float nofpclass(nzero nsub) [[B:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_never_negzero_or_negsub_dapz(float nofpclass(nzero nsub) %a, float nofpclass(nzero nsub) %b) #5 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_negsub_dapz
; CHECK-SAME: (float nofpclass(nzero nsub) [[A:%.*]], float nofpclass(nzero nsub) [[B:%.*]]) #[[ATTR14:[0-9]+]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_never_negzero_or_possub(float nofpclass(nzero psub) %a, float nofpclass(nzero psub) %b) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_possub
; CHECK-SAME: (float nofpclass(nzero psub) [[A:%.*]], float nofpclass(nzero psub) [[B:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_never_negzero_or_possub_daz(float nofpclass(nzero psub) %a, float nofpclass(nzero psub) %b) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_never_negzero_or_possub_daz
; CHECK-SAME: (float nofpclass(nzero psub) [[A:%.*]], float nofpclass(nzero psub) [[B:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_never_negzero_or_possub_dapz(float nofpclass(nzero psub) %a, float nofpclass(nzero psub) %b) #5 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_possub_dapz
; CHECK-SAME: (float nofpclass(nzero psub) [[A:%.*]], float nofpclass(nzero psub) [[B:%.*]]) #[[ATTR14]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_never_negzero_or_sub_daz(float nofpclass(nzero sub) %a, float nofpclass(nzero sub) %b) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_sub_daz
; CHECK-SAME: (float nofpclass(nzero sub) [[A:%.*]], float nofpclass(nzero sub) [[B:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_never_negzero_or_sub_dapz(float nofpclass(nzero sub) %a, float nofpclass(nzero sub) %b) #5 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_never_negzero_or_sub_dapz
; CHECK-SAME: (float nofpclass(nzero sub) [[A:%.*]], float nofpclass(nzero sub) [[B:%.*]]) #[[ATTR14]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[A]], [[B]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %a, %b
  ret float %add
}

define float @fadd_known_positive_lhs(float nofpclass(ninf nsub nnorm) %arg0, float %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_known_positive_lhs
; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_rhs(float %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_known_positive_rhs
; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_known_positive
; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_daz(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm) %arg1) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_known_positive_daz
; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_nzero_lhs(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_known_positive_nzero_lhs
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_nzero_rhs(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_known_positive_nzero_rhs
; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_nzero(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_known_positive_nzero
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_nzero_ftz_daz(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_known_positive_nzero_ftz_daz
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_nzero_ftz(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #1 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nsub nnorm) float @fadd_known_positive_nzero_ftz
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR13]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_nzero_daz(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #2 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @fadd_known_positive_nzero_daz
; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR11]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_normal(float nofpclass(ninf nnorm nzero) %arg0, float nofpclass(ninf nnorm nzero) %arg1) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_known_positive_normal
; CHECK-SAME: (float nofpclass(ninf nzero nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_normal_daz(float nofpclass(ninf nnorm nzero) %arg0, float nofpclass(ninf nnorm nzero) %arg1) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_known_positive_normal_daz
; CHECK-SAME: (float nofpclass(ninf nzero nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nnorm) [[ARG1:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_normal_except0_daz(float nofpclass(ninf nnorm) %arg0, float nofpclass(ninf nnorm) %arg1) #0 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define float @fadd_known_positive_normal_except0_daz
; CHECK-SAME: (float nofpclass(ninf nnorm) [[ARG0:%.*]], float nofpclass(ninf nnorm) [[ARG1:%.*]]) #[[ATTR10]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define float @fadd_known_positive_normal_dapz(float nofpclass(ninf nnorm nzero) %arg0, float nofpclass(ninf nnorm nzero) %arg1) #3 {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nzero) float @fadd_known_positive_normal_dapz
; CHECK-SAME: (float nofpclass(ninf nzero nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nnorm) [[ARG1:%.*]]) #[[ATTR9]] {
; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG0]], [[ARG1]]
; CHECK-NEXT:    ret float [[ADD]]
;
  %add = fadd float %arg0, %arg1
  ret float %add
}

define internal float @returns_fence(float %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define internal float @returns_fence
; TUNIT-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[RET:%.*]] = call float @llvm.arithmetic.fence.f32(float nofpclass(inf) [[ARG]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[RET]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define internal float @returns_fence
; CGSCC-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[RET:%.*]] = call float @llvm.arithmetic.fence.f32(float nofpclass(nan inf) [[ARG]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[RET]]
;
  %ret = call float @llvm.arithmetic.fence.f32(float %arg)
  ret float %ret
}

; Check that the func0 callsite is marked with both no inf and no nan
define internal float @refine_callsite_attribute(float nofpclass(inf) %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define internal float @refine_callsite_attribute
; TUNIT-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FUNC0:%.*]] = call float @returns_fence(float nofpclass(nan inf) [[ARG]]) #[[ATTR19]]
; TUNIT-NEXT:    [[RET:%.*]] = call float @llvm.arithmetic.fence.f32(float [[FUNC0]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[RET]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define internal float @refine_callsite_attribute
; CGSCC-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[FUNC0:%.*]] = call float @returns_fence(float nofpclass(nan inf) [[ARG]]) #[[ATTR19]]
; CGSCC-NEXT:    [[RET:%.*]] = call float @llvm.arithmetic.fence.f32(float [[FUNC0]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[RET]]
;
  %func0 = call float @returns_fence(float nofpclass(nan) %arg)
  %ret = call float @llvm.arithmetic.fence.f32(float %func0)
  ret float %ret
}

define float @user(float %arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define float @user
; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[FUNC1:%.*]] = call float @refine_callsite_attribute(float nofpclass(inf) [[ARG]]) #[[ATTR19]]
; TUNIT-NEXT:    ret float [[FUNC1]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define float @user
; CGSCC-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[FUNC1:%.*]] = call float @refine_callsite_attribute(float nofpclass(nan inf) [[ARG]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[FUNC1]]
;
  %func1 = call float @refine_callsite_attribute(float %arg)
  ret float %func1
}

; value is passed through memory
define internal float @through_memory0(ptr %ptr.arg) {
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define internal float @through_memory0
; CGSCC-SAME: (float [[TMP0:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[PTR_ARG_PRIV:%.*]] = alloca float, align 4
; CGSCC-NEXT:    store float [[TMP0]], ptr [[PTR_ARG_PRIV]], align 4
; CGSCC-NEXT:    [[LOAD:%.*]] = load float, ptr [[PTR_ARG_PRIV]], align 4
; CGSCC-NEXT:    ret float [[LOAD]]
;
  %load = load float, ptr %ptr.arg
  ret float %load
}

; value is passed through memory and goes through an inferrable FP user
define internal float @through_memory1(ptr %ptr.arg) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define internal float @through_memory1
; TUNIT-SAME: (float [[TMP0:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[PTR_ARG_PRIV:%.*]] = alloca float, align 4
; TUNIT-NEXT:    store float [[TMP0]], ptr [[PTR_ARG_PRIV]], align 4
; TUNIT-NEXT:    [[LOAD:%.*]] = load float, ptr [[PTR_ARG_PRIV]], align 4
; TUNIT-NEXT:    [[CALL:%.*]] = call float @llvm.arithmetic.fence.f32(float [[LOAD]]) #[[ATTR22]]
; TUNIT-NEXT:    ret float [[CALL]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define internal float @through_memory1
; CGSCC-SAME: (float [[TMP0:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:    [[PTR_ARG_PRIV:%.*]] = alloca float, align 4
; CGSCC-NEXT:    store float [[TMP0]], ptr [[PTR_ARG_PRIV]], align 4
; CGSCC-NEXT:    [[LOAD:%.*]] = load float, ptr [[PTR_ARG_PRIV]], align 4
; CGSCC-NEXT:    [[CALL:%.*]] = call float @llvm.arithmetic.fence.f32(float [[LOAD]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[CALL]]
;
  %load = load float, ptr %ptr.arg
  %call = call float @llvm.arithmetic.fence.f32(float %load)
  ret float %call
}

; value is passed through memory and goes through an uninferrable FP user
define internal float @through_memory2(ptr %ptr.arg) {
; CHECK: Function Attrs: memory(readwrite, argmem: none)
; CHECK-LABEL: define internal float @through_memory2
; CHECK-SAME: (float [[TMP0:%.*]]) #[[ATTR15:[0-9]+]] {
; CHECK-NEXT:    [[PTR_ARG_PRIV:%.*]] = alloca float, align 4
; CHECK-NEXT:    store float [[TMP0]], ptr [[PTR_ARG_PRIV]], align 4
; CHECK-NEXT:    [[LOAD:%.*]] = load float, ptr [[PTR_ARG_PRIV]], align 4
; CHECK-NEXT:    [[CALL:%.*]] = call float @extern.f32(float [[LOAD]])
; CHECK-NEXT:    ret float [[CALL]]
;
  %load = load float, ptr %ptr.arg
  %call = call float @extern.f32(float %load)
  ret float %call
}

define float @call_through_memory0(float nofpclass(nan) %val) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define nofpclass(nan) float @call_through_memory0
; TUNIT-SAME: (float returned nofpclass(nan) [[VAL:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; TUNIT-NEXT:    store float [[VAL]], ptr [[ALLOCA]], align 4
; TUNIT-NEXT:    ret float [[VAL]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define float @call_through_memory0
; CGSCC-SAME: (float nofpclass(nan) [[VAL:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; CGSCC-NEXT:    store float [[VAL]], ptr [[ALLOCA]], align 4
; CGSCC-NEXT:    [[THROUGH_MEMORY:%.*]] = call float @through_memory0(float nofpclass(nan) [[VAL]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[THROUGH_MEMORY]]
;
  %alloca = alloca float
  store float %val, ptr %alloca
  %through_memory = call float @through_memory0(ptr %alloca)
  ret float %through_memory
}

define float @call_through_memory1(float nofpclass(nan) %val) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define float @call_through_memory1
; TUNIT-SAME: (float nofpclass(nan) [[VAL:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; TUNIT-NEXT:    store float [[VAL]], ptr [[ALLOCA]], align 4
; TUNIT-NEXT:    [[TMP1:%.*]] = load float, ptr [[ALLOCA]], align 4
; TUNIT-NEXT:    [[THROUGH_MEMORY:%.*]] = call float @through_memory1(float [[TMP1]]) #[[ATTR21]]
; TUNIT-NEXT:    ret float [[THROUGH_MEMORY]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define float @call_through_memory1
; CGSCC-SAME: (float nofpclass(nan) [[VAL:%.*]]) #[[ATTR4]] {
; CGSCC-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; CGSCC-NEXT:    store float [[VAL]], ptr [[ALLOCA]], align 4
; CGSCC-NEXT:    [[THROUGH_MEMORY:%.*]] = call float @through_memory1(float nofpclass(nan) [[VAL]]) #[[ATTR19]]
; CGSCC-NEXT:    ret float [[THROUGH_MEMORY]]
;
  %alloca = alloca float
  store float %val, ptr %alloca
  %through_memory = call float @through_memory1(ptr %alloca)
  ret float %through_memory
}

define float @call_through_memory2(float nofpclass(nan) %val) {
; TUNIT-LABEL: define float @call_through_memory2
; TUNIT-SAME: (float nofpclass(nan) [[VAL:%.*]]) {
; TUNIT-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; TUNIT-NEXT:    store float [[VAL]], ptr [[ALLOCA]], align 4
; TUNIT-NEXT:    [[TMP1:%.*]] = load float, ptr [[ALLOCA]], align 4
; TUNIT-NEXT:    [[THROUGH_MEMORY:%.*]] = call float @through_memory2(float [[TMP1]])
; TUNIT-NEXT:    ret float [[THROUGH_MEMORY]]
;
; CGSCC-LABEL: define float @call_through_memory2
; CGSCC-SAME: (float nofpclass(nan) [[VAL:%.*]]) {
; CGSCC-NEXT:    [[ALLOCA:%.*]] = alloca float, align 4
; CGSCC-NEXT:    store float [[VAL]], ptr [[ALLOCA]], align 4
; CGSCC-NEXT:    [[THROUGH_MEMORY:%.*]] = call float @through_memory2(float nofpclass(nan) [[VAL]])
; CGSCC-NEXT:    ret float [[THROUGH_MEMORY]]
;
  %alloca = alloca float
  store float %val, ptr %alloca
  %through_memory = call float @through_memory2(ptr %alloca)
  ret float %through_memory
}

define amdgpu_kernel void @fast_pow_kernel(ptr addrspace(1) nocapture noundef writeonly align 4 %out, ptr addrspace(1) nocapture noundef readonly align 4 %in1, ptr addrspace(1) nocapture noundef readonly align 4 %in2)  {
; CHECK-LABEL: define amdgpu_kernel void @fast_pow_kernel
; CHECK-SAME: (ptr addrspace(1) nocapture nofree noundef writeonly align 4 [[OUT:%.*]], ptr addrspace(1) nocapture nofree noundef readonly align 4 [[IN1:%.*]], ptr addrspace(1) nocapture nofree noundef readonly align 4 [[IN2:%.*]]) {
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[CALL:%.*]] = tail call i64 @_Z13get_global_idj(i32 noundef 0)
; CHECK-NEXT:    [[SEXT:%.*]] = shl i64 [[CALL]], 32
; CHECK-NEXT:    [[IDXPROM:%.*]] = ashr exact i64 [[SEXT]], 32
; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[IN1]], i64 [[IDXPROM]]
; CHECK-NEXT:    [[I:%.*]] = load float, ptr addrspace(1) [[ARRAYIDX]], align 4
; CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[IN2]], i64 [[IDXPROM]]
; CHECK-NEXT:    [[I1:%.*]] = load float, ptr addrspace(1) [[ARRAYIDX2]], align 4
; CHECK-NEXT:    [[CALL3:%.*]] = tail call reassoc nnan ninf nsz arcp afn nofpclass(nan inf) float @pow_wrapper(float noundef nofpclass(nan inf) [[I]], float noundef nofpclass(nan inf) [[I1]])
; CHECK-NEXT:    [[ARRAYIDX5:%.*]] = getelementptr inbounds float, ptr addrspace(1) [[OUT]], i64 [[IDXPROM]]
; CHECK-NEXT:    store float [[CALL3]], ptr addrspace(1) [[ARRAYIDX5]], align 4
; CHECK-NEXT:    ret void
;
entry:
  %call = tail call i64 @_Z13get_global_idj(i32 noundef 0)
  %sext = shl i64 %call, 32
  %idxprom = ashr exact i64 %sext, 32
  %arrayidx = getelementptr inbounds float, ptr addrspace(1) %in1, i64 %idxprom
  %i = load float, ptr addrspace(1) %arrayidx, align 4
  %arrayidx2 = getelementptr inbounds float, ptr addrspace(1) %in2, i64 %idxprom
  %i1 = load float, ptr addrspace(1) %arrayidx2, align 4
  %call3 = tail call reassoc nnan ninf nsz arcp afn nofpclass(nan inf) float @pow_wrapper(float noundef nofpclass(nan inf) %i, float noundef nofpclass(nan inf) %i1)
  %arrayidx5 = getelementptr inbounds float, ptr addrspace(1) %out, i64 %idxprom
  store float %call3, ptr addrspace(1) %arrayidx5, align 4
  ret void
}

define internal float @pow_wrapper(float %arg, float %arg1) {
; TUNIT: Function Attrs: norecurse
; TUNIT-LABEL: define internal float @pow_wrapper
; TUNIT-SAME: (float noundef nofpclass(nan inf) [[ARG:%.*]], float noundef nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR16:[0-9]+]] {
; TUNIT-NEXT:  bb:
; TUNIT-NEXT:    [[I:%.*]] = tail call float @pow_impl(float noundef nofpclass(nan inf) [[ARG]], float noundef nofpclass(nan inf) [[ARG1]])
; TUNIT-NEXT:    ret float [[I]]
;
; CGSCC-LABEL: define internal float @pow_wrapper
; CGSCC-SAME: (float noundef nofpclass(nan inf) [[ARG:%.*]], float noundef nofpclass(nan inf) [[ARG1:%.*]]) {
; CGSCC-NEXT:  bb:
; CGSCC-NEXT:    [[I:%.*]] = tail call float @pow_impl(float noundef nofpclass(nan inf) [[ARG]], float noundef nofpclass(nan inf) [[ARG1]])
; CGSCC-NEXT:    ret float [[I]]
;
bb:
  %i = tail call float @pow_impl(float %arg, float %arg1)
  ret float %i
}

; nofpclass(nan inf) should reach here through pow_wrapper
define internal float @pow_impl(float %arg, float %arg1) {
; TUNIT: Function Attrs: norecurse
; TUNIT-LABEL: define internal float @pow_impl
; TUNIT-SAME: (float noundef nofpclass(nan inf) [[ARG:%.*]], float noundef nofpclass(nan inf) [[ARG1:%.*]]) #[[ATTR16]] {
; TUNIT-NEXT:  bb:
; TUNIT-NEXT:    [[IMPLEMENT_POW:%.*]] = call float asm "
; TUNIT-NEXT:    ret float [[IMPLEMENT_POW]]
;
; CGSCC: Function Attrs: norecurse
; CGSCC-LABEL: define internal float @pow_impl
; CGSCC-SAME: (float [[ARG:%.*]], float [[ARG1:%.*]]) #[[ATTR16:[0-9]+]] {
; CGSCC-NEXT:  bb:
; CGSCC-NEXT:    [[IMPLEMENT_POW:%.*]] = call float asm "
; CGSCC-NEXT:    ret float [[IMPLEMENT_POW]]
;
bb:
  %implement.pow = call float asm " ; do pow $0, $1, $2", "=v,v,v"(float %arg, float %arg1)
  ret float %implement.pow
}

define [4 x float] @constant_aggregate_zero() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero sub norm) [4 x float] @constant_aggregate_zero
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    ret [4 x float] zeroinitializer
;
  ret [4 x float] zeroinitializer
}

define <vscale x 4 x float> @scalable_splat_pnorm() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <vscale x 4 x float> @scalable_splat_pnorm
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    ret <vscale x 4 x float> shufflevector (<vscale x 4 x float> insertelement (<vscale x 4 x float> poison, float 1.000000e+00, i64 0), <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer)
;
  ret <vscale x 4 x float> splat (float 1.0)
}

define <vscale x 4 x float> @scalable_splat_zero() {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) <vscale x 4 x float> @scalable_splat_zero
; CHECK-SAME: () #[[ATTR3]] {
; CHECK-NEXT:    ret <vscale x 4 x float> zeroinitializer
;
  ret <vscale x 4 x float> zeroinitializer
}

; Verify we do not derive 'nofpclass(inf zero sub norm)' for the argument __x.
; See https://github.com/llvm/llvm-project/issues/78507

define double @call_abs(double noundef %__x) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define noundef nofpclass(ninf nzero nsub nnorm) double @call_abs
; TUNIT-SAME: (double noundef [[__X:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT:  entry:
; TUNIT-NEXT:    [[ABS:%.*]] = tail call noundef nofpclass(ninf nzero nsub nnorm) double @llvm.fabs.f64(double noundef [[__X]]) #[[ATTR22]]
; TUNIT-NEXT:    ret double [[ABS]]
;
; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define noundef nofpclass(ninf nzero nsub nnorm) double @call_abs
; CGSCC-SAME: (double noundef [[__X:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT:  entry:
; CGSCC-NEXT:    [[ABS:%.*]] = tail call noundef nofpclass(ninf nzero nsub nnorm) double @llvm.fabs.f64(double noundef [[__X]]) #[[ATTR19]]
; CGSCC-NEXT:    ret double [[ABS]]
;
entry:
  %abs = tail call double @llvm.fabs.f64(double %__x)
  ret double %abs
}

define float @bitcast_to_float_sign_0(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @bitcast_to_float_sign_0
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[ARG]], 1
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i32 [[SHR]] to float
; CHECK-NEXT:    ret float [[CAST]]
;
  %shr = lshr i32 %arg, 1
  %cast = bitcast i32 %shr to float
  ret float %cast
}

define float @bitcast_to_float_nnan(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @bitcast_to_float_nnan
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = lshr i32 [[ARG]], 2
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i32 [[SHR]] to float
; CHECK-NEXT:    ret float [[CAST]]
;
  %shr = lshr i32 %arg, 2
  %cast = bitcast i32 %shr to float
  ret float %cast
}

define float @bitcast_to_float_sign_1(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @bitcast_to_float_sign_1
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[ARG]], -2147483648
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i32 [[OR]] to float
; CHECK-NEXT:    ret float [[CAST]]
;
  %or = or i32 %arg, -2147483648
  %cast = bitcast i32 %or to float
  ret float %cast
}

define float @bitcast_to_float_nan(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(inf zero sub norm) float @bitcast_to_float_nan
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[ARG]], 2139095041
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i32 [[OR]] to float
; CHECK-NEXT:    ret float [[CAST]]
;
  %or = or i32 %arg, 2139095041
  %cast = bitcast i32 %or to float
  ret float %cast
}

define float @bitcast_to_float_zero(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf sub norm) float @bitcast_to_float_zero
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[ARG]], 31
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i32 [[SHL]] to float
; CHECK-NEXT:    ret float [[CAST]]
;
  %shl = shl i32 %arg, 31
  %cast = bitcast i32 %shl to float
  ret float %cast
}

define float @bitcast_to_float_nzero(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(zero) float @bitcast_to_float_nzero
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[ARG]], 134217728
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i32 [[OR]] to float
; CHECK-NEXT:    ret float [[CAST]]
;
  %or = or i32 %arg, 134217728
  %cast = bitcast i32 %or to float
  ret float %cast
}

define float @bitcast_to_float_inf(i32 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan zero sub norm) float @bitcast_to_float_inf
; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = shl i32 [[ARG]], 31
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[SHR]], 2139095040
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i32 [[OR]] to float
; CHECK-NEXT:    ret float [[CAST]]
;
  %shr = shl i32 %arg, 31
  %or = or i32 %shr, 2139095040
  %cast = bitcast i32 %or to float
  ret float %cast
}

define double @bitcast_to_double_sign_0(i64 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) double @bitcast_to_double_sign_0
; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = lshr i64 [[ARG]], 1
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i64 [[SHR]] to double
; CHECK-NEXT:    ret double [[CAST]]
;
  %shr = lshr i64 %arg, 1
  %cast = bitcast i64 %shr to double
  ret double %cast
}

define double @bitcast_to_double_nnan(i64 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) double @bitcast_to_double_nnan
; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = lshr i64 [[ARG]], 2
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i64 [[SHR]] to double
; CHECK-NEXT:    ret double [[CAST]]
;
  %shr = lshr i64 %arg, 2
  %cast = bitcast i64 %shr to double
  ret double %cast
}

define double @bitcast_to_double_sign_1(i64 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) double @bitcast_to_double_sign_1
; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[ARG]], -9223372036854775808
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i64 [[OR]] to double
; CHECK-NEXT:    ret double [[CAST]]
;
  %or = or i64 %arg, -9223372036854775808
  %cast = bitcast i64 %or to double
  ret double %cast
}

define double @bitcast_to_double_nan(i64 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(inf zero sub norm) double @bitcast_to_double_nan
; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[ARG]], -4503599627370495
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i64 [[OR]] to double
; CHECK-NEXT:    ret double [[CAST]]
;
  %or = or i64 %arg, -4503599627370495
  %cast = bitcast i64 %or to double
  ret double %cast
}


define double @bitcast_to_double_zero(i64 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf sub norm) double @bitcast_to_double_zero
; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHL:%.*]] = shl i64 [[ARG]], 63
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i64 [[SHL]] to double
; CHECK-NEXT:    ret double [[CAST]]
;
  %shl = shl i64 %arg, 63
  %cast = bitcast i64 %shl to double
  ret double %cast
}

define double @bitcast_to_double_nzero(i64 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(zero) double @bitcast_to_double_nzero
; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[ARG]], 1152921504606846976
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i64 [[OR]] to double
; CHECK-NEXT:    ret double [[CAST]]
;
  %or = or i64 %arg, 1152921504606846976
  %cast = bitcast i64 %or to double
  ret double %cast
}

define double @bitcast_to_double_inf(i64 %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan zero sub norm) double @bitcast_to_double_inf
; CHECK-SAME: (i64 [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = shl i64 [[ARG]], 63
; CHECK-NEXT:    [[OR:%.*]] = or i64 [[SHR]], 9218868437227405312
; CHECK-NEXT:    [[CAST:%.*]] = bitcast i64 [[OR]] to double
; CHECK-NEXT:    ret double [[CAST]]
;
  %shr = shl i64 %arg, 63
  %or = or i64 %shr, 9218868437227405312
  %cast = bitcast i64 %or to double
  ret double %cast
}


define <2 x float> @bitcast_to_float_vect_sign_0(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) <2 x float> @bitcast_to_float_vect_sign_0
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = lshr <2 x i32> [[ARG]], <i32 1, i32 2>
; CHECK-NEXT:    [[CAST:%.*]] = bitcast <2 x i32> [[SHR]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CAST]]
;
  %shr = lshr <2 x i32> %arg, <i32 1, i32 2>
  %cast = bitcast <2 x i32> %shr to <2 x float>
  ret <2 x float> %cast
}

define <2 x float> @bitcast_to_float_vect_nnan(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) <2 x float> @bitcast_to_float_vect_nnan
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[SHR:%.*]] = lshr <2 x i32> [[ARG]], <i32 4, i32 4>
; CHECK-NEXT:    [[CAST:%.*]] = bitcast <2 x i32> [[SHR]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CAST]]
;
  %shr = lshr <2 x i32> %arg, <i32 4, i32 4>
  %cast = bitcast <2 x i32> %shr to <2 x float>
  ret <2 x float> %cast
}

define <2 x float> @bitcast_to_float_vect_sign_1(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) <2 x float> @bitcast_to_float_vect_sign_1
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[ARG]], <i32 -2147483648, i32 -2147483648>
; CHECK-NEXT:    [[CAST:%.*]] = bitcast <2 x i32> [[OR]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CAST]]
;
  %or = or <2 x i32> %arg, <i32 -2147483648, i32 -2147483648>
  %cast = bitcast <2 x i32> %or to <2 x float>
  ret <2 x float> %cast
}

define <2 x float> @bitcast_to_float_vect_nan(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define nofpclass(inf zero sub norm) <2 x float> @bitcast_to_float_vect_nan
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[ARG]], <i32 2139095041, i32 2139095041>
; CHECK-NEXT:    [[CAST:%.*]] = bitcast <2 x i32> [[OR]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CAST]]
;
  %or = or <2 x i32> %arg, <i32 2139095041, i32 2139095041>
  %cast = bitcast <2 x i32> %or to <2 x float>
  ret <2 x float> %cast
}

define <2 x float> @bitcast_to_float_vect_conservative_1(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <2 x float> @bitcast_to_float_vect_conservative_1
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[ARG]], <i32 -2147483648, i32 0>
; CHECK-NEXT:    [[CAST:%.*]] = bitcast <2 x i32> [[OR]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CAST]]
;
  %or = or <2 x i32> %arg, <i32 -2147483648, i32 0>
  %cast = bitcast <2 x i32> %or to <2 x float>
  ret <2 x float> %cast
}

define <2 x float> @bitcast_to_float_vect_conservative_2(<2 x i32> %arg) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define <2 x float> @bitcast_to_float_vect_conservative_2
; CHECK-SAME: (<2 x i32> [[ARG:%.*]]) #[[ATTR3]] {
; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[ARG]], <i32 0, i32 2139095041>
; CHECK-NEXT:    [[CAST:%.*]] = bitcast <2 x i32> [[OR]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[CAST]]
;
  %or = or <2 x i32> %arg, <i32 0, i32 2139095041>
  %cast = bitcast <2 x i32> %or to <2 x float>
  ret <2 x float> %cast
}

declare i64 @_Z13get_global_idj(i32 noundef)

attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" }
attributes #1 = { "denormal-fp-math"="preserve-sign,ieee" }
attributes #2 = { "denormal-fp-math"="ieee,preserve-sign" }
attributes #3 = { "denormal-fp-math"="positive-zero,positive-zero" }
attributes #4 = { "denormal-fp-math"="positive-zero,ieee" }
attributes #5 = { "denormal-fp-math"="ieee,positive-zero" }