; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 ; RUN: opt -S -p=instcombine < %s | FileCheck %s ; Test a special pattern wrapping llvm.canonicalize which has weaker ; requirements for nan behavior. ; Base pattern with no denormal flushing, should fold to direct use of ; %x define float @canonicalize_ieee_0(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Commuted pattern, should fold to direct use of %x define float @canonicalize_ieee_1(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_1( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %uno = fcmp uno float %x, 0.0 %x.canon = select i1 %uno, float %soft.canonical, float %hard.canonical ret float %x.canon } ; Would be OK, but instcombine will delete the no-op fmul before ; reaching the select. define float @canonicalize_ieee_0_fmul(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0_fmul( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fmul float %x, 1.0 %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Commuted fdiv would be OK, but instcombine will delete the no-op ; fmul before reaching the select. define float @canonicalize_ieee_0_fdiv_commute(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0_fdiv_commute( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float %x, 1.0 %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Base pattern with denormal flushing, should fold to single ; canonicalize call. define float @canonicalize_daz_0(float %x) #1 { ; CHECK-LABEL: define float @canonicalize_daz_0( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[HARD_CANONICAL]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Commuted pattern with denormal flushing, should fold to single ; canonicalize call. define float @canonicalize_daz_1(float %x) #1 { ; CHECK-LABEL: define float @canonicalize_daz_1( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: ret float [[HARD_CANONICAL]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %uno = fcmp uno float %x, 0.0 %x.canon = select i1 %uno, float %soft.canonical, float %hard.canonical ret float %x.canon } ; Unknown denormal mode can fold to canonicalize call define float @canonicalize_dynamic_0(float %x) #2 { ; CHECK-LABEL: define float @canonicalize_dynamic_0( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Unknown denormal mode can fold to canonicalize call define float @canonicalize_dynamic_1(float %x) #2 { ; CHECK-LABEL: define float @canonicalize_dynamic_1( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR2]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], float [[SOFT_CANONICAL]], float [[HARD_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %uno = fcmp uno float %x, 0.0 %x.canon = select i1 %uno, float %soft.canonical, float %hard.canonical ret float %x.canon } define <2 x float> @canonicalize_ieee_0_vec(<2 x float> %x) #0 { ; CHECK-LABEL: define <2 x float> @canonicalize_ieee_0_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret <2 x float> [[X]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x %ord = fcmp ord <2 x float> %x, zeroinitializer %x.canon = select <2 x i1> %ord, <2 x float> %hard.canonical, <2 x float> %soft.canonical ret <2 x float> %x.canon } define <2 x float> @canonicalize_ieee_1_vec(<2 x float> %x) #0 { ; CHECK-LABEL: define <2 x float> @canonicalize_ieee_1_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret <2 x float> [[X]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x %uno = fcmp uno <2 x float> %x, zeroinitializer %x.canon = select <2 x i1> %uno, <2 x float> %soft.canonical, <2 x float> %hard.canonical ret <2 x float> %x.canon } define <2 x float> @canonicalize_ieee_0_vec_poison_elt(<2 x float> %x) #0 { ; CHECK-LABEL: define <2 x float> @canonicalize_ieee_0_vec_poison_elt( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> , [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord <2 x float> [[X]], zeroinitializer ; CHECK-NEXT: [[X_CANON:%.*]] = select <2 x i1> [[ORD]], <2 x float> [[X]], <2 x float> [[SOFT_CANONICAL]] ; CHECK-NEXT: ret <2 x float> [[X_CANON]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> , %x %ord = fcmp ord <2 x float> %x, zeroinitializer %x.canon = select <2 x i1> %ord, <2 x float> %hard.canonical, <2 x float> %soft.canonical ret <2 x float> %x.canon } define <2 x float> @canonicalize_daz_0_vec(<2 x float> %x) #1 { ; CHECK-LABEL: define <2 x float> @canonicalize_daz_0_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) ; CHECK-NEXT: ret <2 x float> [[HARD_CANONICAL]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x %ord = fcmp ord <2 x float> %x, zeroinitializer %x.canon = select <2 x i1> %ord, <2 x float> %hard.canonical, <2 x float> %soft.canonical ret <2 x float> %x.canon } define <2 x float> @canonicalize_daz_1_vec(<2 x float> %x) #1 { ; CHECK-LABEL: define <2 x float> @canonicalize_daz_1_vec( ; CHECK-SAME: <2 x float> [[X:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]]) ; CHECK-NEXT: ret <2 x float> [[HARD_CANONICAL]] ; %hard.canonical = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x) %soft.canonical = fdiv <2 x float> splat (float 1.0), %x %uno = fcmp uno <2 x float> %x, zeroinitializer %x.canon = select <2 x i1> %uno, <2 x float> %soft.canonical, <2 x float> %hard.canonical ret <2 x float> %x.canon } define bfloat @canonicalize_ieee_bf16(bfloat %x) #0 { ; CHECK-LABEL: define bfloat @canonicalize_ieee_bf16( ; CHECK-SAME: bfloat [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret bfloat [[X]] ; %hard.canonical = call bfloat @llvm.canonicalize.bf16(bfloat %x) %soft.canonical = fdiv bfloat 1.0, %x %ord = fcmp ord bfloat %x, 0.0 %x.canon = select i1 %ord, bfloat %hard.canonical, bfloat %soft.canonical ret bfloat %x.canon } define half @canonicalize_ieee_f16(half %x) #0 { ; CHECK-LABEL: define half @canonicalize_ieee_f16( ; CHECK-SAME: half [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret half [[X]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %soft.canonical = fdiv half 1.0, %x %ord = fcmp ord half %x, 0.0 %x.canon = select i1 %ord, half %hard.canonical, half %soft.canonical ret half %x.canon } define double @canonicalize_ieee_f64(double %x) #0 { ; CHECK-LABEL: define double @canonicalize_ieee_f64( ; CHECK-SAME: double [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret double [[X]] ; %hard.canonical = call double @llvm.canonicalize.f64(double %x) %soft.canonical = fdiv double 1.0, %x %ord = fcmp ord double %x, 0.0 %x.canon = select i1 %ord, double %hard.canonical, double %soft.canonical ret double %x.canon } define fp128 @canonicalize_ieee_f128(fp128 %x) #0 { ; CHECK-LABEL: define fp128 @canonicalize_ieee_f128( ; CHECK-SAME: fp128 [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret fp128 [[X]] ; %hard.canonical = call fp128 @llvm.canonicalize.f128(fp128 %x) %ord = fcmp ord fp128 %x, 0xL00000000000000000000000000000000 %x.canon = select i1 %ord, fp128 %hard.canonical, fp128 %x ret fp128 %x.canon } ; Negative test define float @div_not_one(float %x) #0 { ; CHECK-LABEL: define float @div_not_one( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 2.000000e+00, [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[X]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 2.0, %x %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Negative test define float @not_fdiv(float %x) #0 { ; CHECK-LABEL: define float @not_fdiv( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fadd float [[X]], 1.000000e+00 ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[X]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fadd float %x, 1.0 %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Negative test define float @fcmp_not_ord(float %x) #0 { ; CHECK-LABEL: define float @fcmp_not_ord( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp olt float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp olt float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } declare float @func(float) ; Negative test define float @not_canonicalize(float %x) #0 { ; CHECK-LABEL: define float @not_canonicalize( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[X_FR:%.*]] = freeze float [[X]] ; CHECK-NEXT: [[NOT_CANONICAL:%.*]] = call noundef float @func(float [[X_FR]]) ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X_FR]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[NOT_CANONICAL]], float [[X_FR]] ; CHECK-NEXT: ret float [[X_CANON]] ; %not.canonical = call noundef float @func(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %not.canonical, float %soft.canonical ret float %x.canon } ; Negative test define float @compared_value_different(float %x, float %y) #0 { ; CHECK-LABEL: define float @compared_value_different( ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[Y]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %y, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Negative test define float @fdiv_value_different_ieee(float %x, float %y) #0 { ; CHECK-LABEL: define float @fdiv_value_different_ieee( ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[Y]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[X]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %y %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Negative test define float @fdiv_value_different_ieee_commute(float %x, float %y) #0 { ; CHECK-LABEL: define float @fdiv_value_different_ieee_commute( ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[Y]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp uno float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[SOFT_CANONICAL]], float [[X]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %y %ord = fcmp uno float %x, 0.0 %x.canon = select i1 %ord, float %soft.canonical, float %hard.canonical ret float %x.canon } ; Negative test define float @fdiv_value_different_daz(float %x, float %y) #1 { ; CHECK-LABEL: define float @fdiv_value_different_daz( ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[Y]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %y %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Negative test define float @fdiv_value_different_daz_commute(float %x, float %y) #1 { ; CHECK-LABEL: define float @fdiv_value_different_daz_commute( ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[Y]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp uno float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[SOFT_CANONICAL]], float [[HARD_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %y %ord = fcmp uno float %x, 0.0 %x.canon = select i1 %ord, float %soft.canonical, float %hard.canonical ret float %x.canon } ; Negative test define float @fcmp_ord_not_constant(float %x, float %y) #0 { ; CHECK-LABEL: define float @fcmp_ord_not_constant( ; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], [[Y]] ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[SOFT_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, %y %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Negative test define float @fcmp_ord_nan_constant(float %x) #0 { ; CHECK-LABEL: define float @fcmp_ord_nan_constant( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[SOFT_CANONICAL:%.*]] = fdiv float 1.000000e+00, [[X]] ; CHECK-NEXT: ret float [[SOFT_CANONICAL]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, 0x7FF8000000000000 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } define x86_fp80 @ignore_x86_fp80(x86_fp80 %x) #0 { ; CHECK-LABEL: define x86_fp80 @ignore_x86_fp80( ; CHECK-SAME: x86_fp80 [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call x86_fp80 @llvm.canonicalize.f80(x86_fp80 [[X]]) ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord x86_fp80 [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], x86_fp80 [[HARD_CANONICAL]], x86_fp80 [[X]] ; CHECK-NEXT: ret x86_fp80 [[X_CANON]] ; %hard.canonical = call x86_fp80 @llvm.canonicalize.f80(x86_fp80 %x) %ord = fcmp ord x86_fp80 %x, 0xK00000000000000000000 %x.canon = select i1 %ord, x86_fp80 %hard.canonical, x86_fp80 %x ret x86_fp80 %x.canon } define ppc_fp128 @ignore_ppc_fp128(ppc_fp128 %x) #0 { ; CHECK-LABEL: define ppc_fp128 @ignore_ppc_fp128( ; CHECK-SAME: ppc_fp128 [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call ppc_fp128 @llvm.canonicalize.ppcf128(ppc_fp128 [[X]]) ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord ppc_fp128 [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], ppc_fp128 [[HARD_CANONICAL]], ppc_fp128 [[X]] ; CHECK-NEXT: ret ppc_fp128 [[X_CANON]] ; %hard.canonical = call ppc_fp128 @llvm.canonicalize.ppcf128(ppc_fp128 %x) %ord = fcmp ord ppc_fp128 %x, 0xM00000000000000000000000000000000 %x.canon = select i1 %ord, ppc_fp128 %hard.canonical, ppc_fp128 %x ret ppc_fp128 %x.canon } ; In IEEE mode there are no non-canonical values, we can drop the canonicalize. define float @canonicalize_ieee_0_missing_noop(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_0_missing_noop( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %x ret float %x.canon } ; In IEEE mode there are no non-canonical values, we can drop the ; canonicalize. define float @canonicalize_ieee_1_missing_noop(float %x) #0 { ; CHECK-LABEL: define float @canonicalize_ieee_1_missing_noop( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %uno = fcmp uno float %x, 0.0 %x.canon = select i1 %uno, float %x, float %hard.canonical ret float %x.canon } ; Negative test. This cannot fold to the canonicalize call, as it may ; change the payload and sign bit of %x in the nan case. define float @canonicalize_da_0_missing_noop(float %x) #1 { ; CHECK-LABEL: define float @canonicalize_da_0_missing_noop( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], float [[HARD_CANONICAL]], float [[X]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %x ret float %x.canon } ; Negative test. This cannot fold to the canonicalize call, as it may ; change the payload and sign bit of %x in the nan case. define float @canonicalize_daz_1_missing_noop(float %x) #1 { ; CHECK-LABEL: define float @canonicalize_daz_1_missing_noop( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], float [[X]], float [[HARD_CANONICAL]] ; CHECK-NEXT: ret float [[X_CANON]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %uno = fcmp uno float %x, 0.0 %x.canon = select i1 %uno, float %x, float %hard.canonical ret float %x.canon } ; Either input or output is sufficient to require canonicalize define float @canonicalize_only_ftz(float %x) "denormal-fp-math"="preserve-sign,ieee" { ; CHECK-LABEL: define float @canonicalize_only_ftz( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR3:[0-9]+]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Either input or output is sufficient to require canonicalize define float @canonicalize_only_daz(float %x) "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: define float @canonicalize_only_daz( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR4:[0-9]+]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %soft.canonical = fdiv float 1.0, %x %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %soft.canonical ret float %x.canon } ; Both components must be IEEE to fully drop the canonicalize define float @canonicalize_missing_noop_only_ftz(float %x) "denormal-fp-math"="preserve-sign,ieee" { ; CHECK-LABEL: define float @canonicalize_missing_noop_only_ftz( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR3]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %x ret float %x.canon } ; Both components must be IEEE to fully drop the canonicalize define float @canonicalize_missing_noop_only_daz(float %x) "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: define float @canonicalize_missing_noop_only_daz( ; CHECK-SAME: float [[X:%.*]]) #[[ATTR4]] { ; CHECK-NEXT: ret float [[X]] ; %hard.canonical = call float @llvm.canonicalize.f32(float %x) %ord = fcmp ord float %x, 0.0 %x.canon = select i1 %ord, float %hard.canonical, float %x ret float %x.canon } define half @independent_hands_canonicalize_ieee_0(half noundef %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_canonicalize_ieee_0( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], half [[X]], half [[Y]] ; CHECK-NEXT: ret half [[X_CANON]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %ord = fcmp ord half %x, 0.0 %x.canon = select i1 %ord, half %hard.canonical, half %y ret half %x.canon } define half @independent_hands_canonicalize_ieee_1(half noundef %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_canonicalize_ieee_1( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], half [[Y]], half [[X]] ; CHECK-NEXT: ret half [[X_CANON]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %uno = fcmp uno half %x, 0.0 %x.canon = select i1 %uno, half %y, half %hard.canonical ret half %x.canon } define half @independent_hands_fdiv_ieee_0(half noundef %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_fdiv_ieee_0( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0.000000e+00 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ORD]], half [[Y]], half [[X]] ; CHECK-NEXT: ret half [[SEL]] ; %rcp = fdiv half 1.0, %x %ord = fcmp ord half %x, 0.0 %sel = select i1 %ord, half %y, half %rcp ret half %sel } define half @independent_hands_fdiv_ieee_1(half noundef %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_fdiv_ieee_1( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[UNO]], half [[X]], half [[Y]] ; CHECK-NEXT: ret half [[SEL]] ; %rcp = fdiv half 1.0, %x %uno = fcmp uno half %x, 0.0 %sel = select i1 %uno, half %rcp, half %y ret half %sel } define half @independent_hands_canonicalize_daz_0(half noundef %x, half %y) #1 { ; CHECK-LABEL: define half @independent_hands_canonicalize_daz_0( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]]) ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], half [[HARD_CANONICAL]], half [[Y]] ; CHECK-NEXT: ret half [[X_CANON]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %ord = fcmp ord half %x, 0.0 %x.canon = select i1 %ord, half %hard.canonical, half %y ret half %x.canon } define half @independent_hands_canonicalize_daz_1(half noundef %x, half %y) #1 { ; CHECK-LABEL: define half @independent_hands_canonicalize_daz_1( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]]) ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], half [[Y]], half [[HARD_CANONICAL]] ; CHECK-NEXT: ret half [[X_CANON]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %uno = fcmp uno half %x, 0.0 %x.canon = select i1 %uno, half %y, half %hard.canonical ret half %x.canon } define half @independent_hands_fdiv_daz_0(half noundef %x, half %y) #1 { ; CHECK-LABEL: define half @independent_hands_fdiv_daz_0( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[RCP:%.*]] = fdiv half 1.000000e+00, [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0.000000e+00 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ORD]], half [[Y]], half [[RCP]] ; CHECK-NEXT: ret half [[SEL]] ; %rcp = fdiv half 1.0, %x %ord = fcmp ord half %x, 0.0 %sel = select i1 %ord, half %y, half %rcp ret half %sel } define half @independent_hands_fdiv_daz_1(half noundef %x, half %y) #1 { ; CHECK-LABEL: define half @independent_hands_fdiv_daz_1( ; CHECK-SAME: half noundef [[X:%.*]], half [[Y:%.*]]) #[[ATTR1]] { ; CHECK-NEXT: [[RCP:%.*]] = fdiv half 1.000000e+00, [[X]] ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[UNO]], half [[RCP]], half [[Y]] ; CHECK-NEXT: ret half [[SEL]] ; %rcp = fdiv half 1.0, %x %uno = fcmp uno half %x, 0.0 %sel = select i1 %uno, half %rcp, half %y ret half %sel } define x86_fp80 @independent_hands_canonicalize_ieee_0_x86_fp80(x86_fp80 noundef %x, x86_fp80 %y) #0 { ; CHECK-LABEL: define x86_fp80 @independent_hands_canonicalize_ieee_0_x86_fp80( ; CHECK-SAME: x86_fp80 noundef [[X:%.*]], x86_fp80 [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[HARD_CANONICAL:%.*]] = call x86_fp80 @llvm.canonicalize.f80(x86_fp80 [[X]]) ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord x86_fp80 [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], x86_fp80 [[HARD_CANONICAL]], x86_fp80 [[Y]] ; CHECK-NEXT: ret x86_fp80 [[X_CANON]] ; %hard.canonical = call x86_fp80 @llvm.canonicalize.f80(x86_fp80 %x) %ord = fcmp ord x86_fp80 %x, 0xK00000000000000000000 %x.canon = select i1 %ord, x86_fp80 %hard.canonical, x86_fp80 %y ret x86_fp80 %x.canon } define x86_fp80 @independent_hands_fdiv_ieee_0_x86_fp80(x86_fp80 noundef %x, x86_fp80 %y) #0 { ; CHECK-LABEL: define x86_fp80 @independent_hands_fdiv_ieee_0_x86_fp80( ; CHECK-SAME: x86_fp80 noundef [[X:%.*]], x86_fp80 [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[RCP:%.*]] = fdiv x86_fp80 1.000000e+00, [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord x86_fp80 [[X]], 0.000000e+00 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ORD]], x86_fp80 [[Y]], x86_fp80 [[RCP]] ; CHECK-NEXT: ret x86_fp80 [[SEL]] ; %rcp = fdiv x86_fp80 0xK3FFF8000000000000000, %x %ord = fcmp ord x86_fp80 %x, 0xK00000000000000000000 %sel = select i1 %ord, x86_fp80 %y, x86_fp80 %rcp ret x86_fp80 %sel } ; Negative test, needs noundef define half @independent_hands_canonicalize_ieee_0_maybe_undef(half %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_canonicalize_ieee_0_maybe_undef( ; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[ORD]], half [[X]], half [[Y]] ; CHECK-NEXT: ret half [[X_CANON]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %ord = fcmp ord half %x, 0.0 %x.canon = select i1 %ord, half %hard.canonical, half %y ret half %x.canon } ; Negative test, needs noundef define half @independent_hands_canonicalize_ieee_1_maybe_undef(half %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_canonicalize_ieee_1_maybe_undef( ; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00 ; CHECK-NEXT: [[X_CANON:%.*]] = select i1 [[UNO]], half [[Y]], half [[X]] ; CHECK-NEXT: ret half [[X_CANON]] ; %hard.canonical = call half @llvm.canonicalize.f16(half %x) %uno = fcmp uno half %x, 0.0 %x.canon = select i1 %uno, half %y, half %hard.canonical ret half %x.canon } ; Negative test, needs noundef define half @independent_hands_fdiv_ieee_0_maybe_undef(half %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_fdiv_ieee_0_maybe_undef( ; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[X_FR:%.*]] = freeze half [[X]] ; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X_FR]], 0.000000e+00 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[ORD]], half [[Y]], half [[X_FR]] ; CHECK-NEXT: ret half [[SEL]] ; %rcp = fdiv half 1.0, %x %ord = fcmp ord half %x, 0.0 %sel = select i1 %ord, half %y, half %rcp ret half %sel } ; Negative test, needs noundef define half @independent_hands_fdiv_ieee_1_maybe_undef(half %x, half %y) #0 { ; CHECK-LABEL: define half @independent_hands_fdiv_ieee_1_maybe_undef( ; CHECK-SAME: half [[X:%.*]], half [[Y:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[X_FR:%.*]] = freeze half [[X]] ; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X_FR]], 0.000000e+00 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[UNO]], half [[X_FR]], half [[Y]] ; CHECK-NEXT: ret half [[SEL]] ; %rcp = fdiv half 1.0, %x %uno = fcmp uno half %x, 0.0 %sel = select i1 %uno, half %rcp, half %y ret half %sel } attributes #0 = { denormal_fpenv(ieee) } attributes #1 = { denormal_fpenv(preservesign) } attributes #2 = { denormal_fpenv(dynamic) }