; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 ; RUN: opt -S -passes=instcombine < %s | FileCheck %s declare nofpclass(norm inf nan nzero nsub) float @returns_pzero_psub() declare nofpclass(norm inf nan zero nsub) float @returns_psub() declare nofpclass(norm inf nan zero psub) float @returns_nsub() declare nofpclass(norm inf nan zero) float @returns_sub() declare nofpclass(norm inf nan zero) <2 x float> @returns_sub_vec() declare nofpclass(norm inf nan) float @returns_sub_zero() declare nofpclass(qnan) float @returns_maybe_snan() declare nofpclass(qnan zero norm sub inf) float @returns_snan() declare nofpclass(inf nan zero) float @returns_sub_norm() declare nofpclass(nnorm inf nan zero nsub) float @returns_psub_pnorm() declare nofpclass(pnorm inf nan zero psub) float @returns_nsub_nnorm() ; Does not require special handling of canonicalize. define nofpclass(inf) float @ret_nofpclass_inf__canonicalize_select_pinf_rhs(i1 %cond, float %x) { ; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__canonicalize_select_pinf_rhs( ; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call ninf float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[TMP1]] ; %select = select i1 %cond, float %x, float 0x7FF0000000000000 %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_psub_pnorm_daz(float %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_psub_pnorm_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub_pnorm() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[PSUB]] ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[CANON]] ; %psub = call float @returns_psub_pnorm() %select = select i1 %cond, float %x, float %psub %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_nsub_nnorm_daz(float %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_nsub_nnorm_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub_nnorm() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[NSUB]] ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[CANON]] ; %nsub = call float @returns_nsub_nnorm() %select = select i1 %cond, float %x, float %nsub %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_sub_norm_daz(float %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_sub_norm_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub_norm() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SUB]] ; CHECK-NEXT: ret float [[SELECT]] ; %sub = call float @returns_sub_norm() %select = select i1 %cond, float %x, float %sub %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_psub_daz(float %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan pzero) float @ret_nofpclass_nan_pzero__canonicalize_select_psub_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub() ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %psub = call float @returns_psub() %select = select i1 %cond, float %x, float %psub %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_nsub_daz(float %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan nzero) float @ret_nofpclass_nan_nzero__canonicalize_select_nsub_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %nsub = call float @returns_nsub() %select = select i1 %cond, float %x, float %nsub %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_sub_daz(float %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan zero) float @ret_nofpclass_nan_zero__canonicalize_select_sub_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() ; CHECK-NEXT: ret float [[X]] ; %sub = call float @returns_sub() %select = select i1 %cond, float %x, float %sub %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_ieee() { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub() ; CHECK-NEXT: ret float [[PSUB]] ; %psub = call float @returns_psub() %canon = call float @llvm.canonicalize.f32(float %psub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() ; CHECK-NEXT: ret float [[NSUB]] ; %nsub = call float @returns_nsub() %canon = call float @llvm.canonicalize.f32(float %nsub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_ieee() { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_ieee() { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() ; CHECK-NEXT: ret float [[SUB]] ; %sub = call float @returns_sub() %canon = call float @llvm.canonicalize.f32(float %sub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_daz() #0 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_daz( ; CHECK-SAME: ) #[[ATTR0]] { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub() ; CHECK-NEXT: ret float 0.000000e+00 ; %psub = call float @returns_psub() %canon = call float @llvm.canonicalize.f32(float %psub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_daz() #0 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_daz( ; CHECK-SAME: ) #[[ATTR0]] { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() ; CHECK-NEXT: ret float -0.000000e+00 ; %nsub = call float @returns_nsub() %canon = call float @llvm.canonicalize.f32(float %nsub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_daz() #0 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_daz( ; CHECK-SAME: ) #[[ATTR0]] { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() ; CHECK-NEXT: [[CANON:%.*]] = call nnan ninf float @llvm.canonicalize.f32(float [[SUB]]) ; CHECK-NEXT: ret float [[CANON]] ; %sub = call float @returns_sub() %canon = call float @llvm.canonicalize.f32(float %sub) ret float %canon } define nofpclass(zero) <2 x float> @ret_nofpclass_zero__canonicalize_daz_vec(<2 x float> %x, <2 x i1> %cond) #0 { ; CHECK-LABEL: define nofpclass(zero) <2 x float> @ret_nofpclass_zero__canonicalize_daz_vec( ; CHECK-SAME: <2 x float> [[X:%.*]], <2 x i1> [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SUB:%.*]] = call <2 x float> @returns_sub_vec() ; CHECK-NEXT: [[CANON:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) ; CHECK-NEXT: ret <2 x float> [[CANON]] ; %sub = call <2 x float> @returns_sub_vec() %select = select <2 x i1> %cond, <2 x float> %x, <2 x float> %sub %canon = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %select) ret <2 x float> %canon } define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz(float %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(zero sub) float @ret_nofpclass_sub_zero__canonicalize_daz( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SUB_OR_ZERO:%.*]] = call float @returns_sub_zero() ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %sub_or_zero = call float @returns_sub_zero() %select = select i1 %cond, float %x, float %sub_or_zero %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_ieee(float %unknown) { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_ieee( ; CHECK-SAME: float [[UNKNOWN:%.*]]) { ; CHECK-NEXT: ret float [[UNKNOWN]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon } define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_ieee(float %unknown) { ; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_ieee( ; CHECK-SAME: float [[UNKNOWN:%.*]]) { ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[UNKNOWN]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_daz(float %unknown) #0 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_daz( ; CHECK-SAME: float [[UNKNOWN:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[UNKNOWN]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_dynamic(float %unknown) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_dynamic( ; CHECK-SAME: float [[UNKNOWN:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[UNKNOWN]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon } ; Only snan not sufficent to strip canonicalize define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_ieee(float %unknown) { ; CHECK-LABEL: define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_ieee( ; CHECK-SAME: float [[UNKNOWN:%.*]]) { ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[UNKNOWN]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon } ; Only qnan not sufficent to strip canonicalize define nofpclass(qnan) float @ret_nofpclass_anan__canonicalize_ieee(float %unknown) { ; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_anan__canonicalize_ieee( ; CHECK-SAME: float [[UNKNOWN:%.*]]) { ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[UNKNOWN]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon } ; Ignore fp80, leave canonicalize. define nofpclass(nan) x86_fp80 @ret_nofpclass_zero_sub_canonicalize_fp80_daz(x86_fp80 %unknown) { ; CHECK-LABEL: define nofpclass(nan) x86_fp80 @ret_nofpclass_zero_sub_canonicalize_fp80_daz( ; CHECK-SAME: x86_fp80 [[UNKNOWN:%.*]]) { ; CHECK-NEXT: [[CANON:%.*]] = call x86_fp80 @llvm.canonicalize.f80(x86_fp80 [[UNKNOWN]]) ; CHECK-NEXT: ret x86_fp80 [[CANON]] ; %canon = call x86_fp80 @llvm.canonicalize.f80(x86_fp80 %unknown) ret x86_fp80 %canon } define nofpclass(nan sub) float @ret_nofpclass_nan_sub__canonicalize_dynamic(float %unknown) #1 { ; CHECK-LABEL: define nofpclass(nan sub) float @ret_nofpclass_nan_sub__canonicalize_dynamic( ; CHECK-SAME: float [[UNKNOWN:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[UNKNOWN]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %unknown) ret float %canon } ; Cannot do anything. No signaling nan result doesn't tell us anything. define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_select_unknown_or_snan(float %x, i1 %cond) { ; CHECK-LABEL: define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_select_unknown_or_snan( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]] ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[CANON]] ; %snan = call float @returns_snan() %select = select i1 %cond, float %x, float %snan %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } ; Fold to canonicalize of %x. The result cannot be a qnan, so it ; cannot be the signaling nan select result. define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_select_unknown_or_snan(float %x, i1 %cond) { ; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_select_unknown_or_snan( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]] ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[CANON]] ; %snan = call float @returns_snan() %select = select i1 %cond, float %x, float %snan %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } ; Can fold to direct use of %x define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_select_unknown_or_snan(float %x, i1 %cond) { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_select_unknown_or_snan( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() ; CHECK-NEXT: ret float [[X]] ; %snan = call float @returns_snan() %select = select i1 %cond, float %x, float %snan %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_unknown_or_snan(float %x, i1 %cond) { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero_nnan_flag__canonicalize_select_unknown_or_snan( ; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SNAN]] ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[CANON]] ; %snan = call float @returns_snan() %select = select i1 %cond, float %x, float %snan %canon = call float @llvm.canonicalize.f32(float %select) ret float %canon } ; With IEEE handling the canonicalize can be dropped. ; ; FIXME: This doesn't really require the nofpclass on the return, but ; we don't attempt SimplifyDemandedFPClass without it. define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_ieee(float nofpclass(nan) %x, i1 %cond) { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_ieee( ; CHECK-SAME: float nofpclass(nan) [[X:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } ; Must preserve canonicalize with DAZ define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_daz(float nofpclass(nan) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_nnan_src_daz( ; CHECK-SAME: float nofpclass(nan) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_src_daz(float nofpclass(sub) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_src_daz( ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_daz(float nofpclass(nan sub) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_daz( ; CHECK-SAME: float nofpclass(nan sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_dynamic(float nofpclass(nan sub) %x, i1 %cond) #1 { ; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__canonicalize_no_sub_no_nan_src_dynamic( ; CHECK-SAME: float nofpclass(nan sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } ; Input cannot be subnormal and result cannot be nan, so canonicalize is droppable define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_daz(float nofpclass(sub) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_daz( ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } ; No qnan result is sufficient. define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_no_sub_src_daz(float nofpclass(sub) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_qnan__canonicalize_no_sub_src_daz( ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_no_sub_src_daz(float nofpclass(sub) %x, i1 %cond) #0 { ; CHECK-LABEL: define nofpclass(snan) float @ret_nofpclass_snan__canonicalize_no_sub_src_daz( ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } ; Input cannot be subnormal and result cannot be nan, so canonicalize is droppable define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_dynamic(float nofpclass(sub) %x, i1 %cond) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_dynamic( ; CHECK-SAME: float nofpclass(sub) [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float [[X]] ; %canon = call float @llvm.canonicalize.f32(float %x) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_dapz() #2 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_dapz( ; CHECK-SAME: ) #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() ; CHECK-NEXT: ret float 0.000000e+00 ; %nsub = call float @returns_nsub() %canon = call float @llvm.canonicalize.f32(float %nsub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_dapz() #2 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_dapz( ; CHECK-SAME: ) #[[ATTR2]] { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub() ; CHECK-NEXT: ret float 0.000000e+00 ; %psub = call float @returns_psub() %canon = call float @llvm.canonicalize.f32(float %psub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_dapz() #2 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_dapz( ; CHECK-SAME: ) #[[ATTR2]] { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() ; CHECK-NEXT: ret float 0.000000e+00 ; %sub = call float @returns_sub() %canon = call float @llvm.canonicalize.f32(float %sub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_dynamic() #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_dynamic( ; CHECK-SAME: ) #[[ATTR1]] { ; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() ; CHECK-NEXT: [[CANON:%.*]] = call nnan ninf float @llvm.canonicalize.f32(float [[NSUB]]) ; CHECK-NEXT: ret float [[CANON]] ; %nsub = call float @returns_nsub() %canon = call float @llvm.canonicalize.f32(float %nsub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_dynamic() #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_psub_dynamic( ; CHECK-SAME: ) #[[ATTR1]] { ; CHECK-NEXT: [[PSUB:%.*]] = call float @returns_psub() ; CHECK-NEXT: [[CANON:%.*]] = call nnan ninf float @llvm.canonicalize.f32(float [[PSUB]]) ; CHECK-NEXT: ret float [[CANON]] ; %psub = call float @returns_psub() %canon = call float @llvm.canonicalize.f32(float %psub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_dynamic() #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_dynamic( ; CHECK-SAME: ) #[[ATTR1]] { ; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() ; CHECK-NEXT: [[CANON:%.*]] = call nnan ninf float @llvm.canonicalize.f32(float [[SUB]]) ; CHECK-NEXT: ret float [[CANON]] ; %sub = call float @returns_sub() %canon = call float @llvm.canonicalize.f32(float %sub) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_ninf__dynamic(i1 %cond, float nofpclass(sub norm zero pinf) %must.be.ninf.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_ninf__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(pinf zero sub norm) [[MUST_BE_NINF_OR_NAN:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float -inf ; %canon = call float @llvm.canonicalize.f32(float %must.be.ninf.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pinf__dynamic(i1 %cond, float nofpclass(sub norm zero pinf) %must.be.pinf.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pinf__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(pinf zero sub norm) [[MUST_BE_PINF_OR_NAN:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float -inf ; %canon = call float @llvm.canonicalize.f32(float %must.be.pinf.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_inf__dynamic(i1 %cond, float nofpclass(sub norm zero) %must.be.inf.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_inf__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(zero sub norm) [[MUST_BE_INF_OR_NAN:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float [[MUST_BE_INF_OR_NAN]] ; %canon = call float @llvm.canonicalize.f32(float %must.be.inf.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pzero__dynamic(i1 %cond, float nofpclass(sub norm nzero inf) %must.be.pzero.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_pzero__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf nzero sub norm) [[MUST_BE_PZERO_OR_NAN:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %canon = call float @llvm.canonicalize.f32(float %must.be.pzero.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nzero__dynamic(i1 %cond, float nofpclass(sub norm pzero inf) %must.be.nzero.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nzero__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf pzero sub norm) [[MUST_BE_NZERO_OR_NAN:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float -0.000000e+00 ; %canon = call float @llvm.canonicalize.f32(float %must.be.nzero.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__ieee(i1 %cond, float nofpclass(sub norm inf) %must.be.zero.or.nan) { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__ieee( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) { ; CHECK-NEXT: ret float [[MUST_BE_ZERO_OR_NAN]] ; %canon = call float @llvm.canonicalize.f32(float %must.be.zero.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dynamic(i1 %cond, float nofpclass(sub norm inf) %must.be.zero.or.nan) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dynamic( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: ret float [[MUST_BE_ZERO_OR_NAN]] ; %canon = call float @llvm.canonicalize.f32(float %must.be.zero.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dapz(i1 %cond, float nofpclass(sub norm inf) %must.be.zero.or.nan) #2 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dapz( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %canon = call float @llvm.canonicalize.f32(float %must.be.zero.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub__dapz(i1 %cond, float nofpclass(zero norm inf) %must.be.sub.or.nan) #2 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub__dapz( ; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf zero norm) [[MUST_BE_SUB_OR_NAN:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: ret float 0.000000e+00 ; %canon = call float @llvm.canonicalize.f32(float %must.be.sub.or.nan) ret float %canon } define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_drop_noundef(float %x) #1 { ; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_drop_noundef( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[CANON:%.*]] = call nnan float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[CANON]] ; %canon = call noundef float @llvm.canonicalize.f32(float %x), !unknown.md !{} ret float %canon } define nofpclass(snan) float @qnan_result_demands_snan_src(i1 %cond, float %unknown) { ; CHECK-LABEL: define nofpclass(snan) float @qnan_result_demands_snan_src( ; CHECK-SAME: i1 [[COND:%.*]], float [[UNKNOWN:%.*]]) { ; CHECK-NEXT: [[SNAN:%.*]] = call float @returns_snan() ; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[SNAN]], float [[UNKNOWN]] ; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) ; CHECK-NEXT: ret float [[RESULT]] ; %snan = call float @returns_snan() %select = select i1 %cond, float %snan, float %unknown %result = call float @llvm.canonicalize.f32(float %select) ret float %result } attributes #0 = { denormal_fpenv(preservesign) } attributes #1 = { denormal_fpenv(dynamic) } attributes #2 = { denormal_fpenv(positivezero|positivezero) }