Skip to content

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Dec 21, 2025

No description provided.

@arsenm arsenm added the floating-point Floating-point math label Dec 21, 2025 — with Graphite App
@arsenm arsenm added the llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes label Dec 21, 2025 — with Graphite App
@arsenm arsenm marked this pull request as ready for review December 21, 2025 13:21
@llvmbot
Copy link
Member

llvmbot commented Dec 21, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Matt Arsenault (arsenm)

Changes

Patch is 29.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/173188.diff

1 Files Affected:

  • (added) llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll (+609)
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll new file mode 100644 index 0000000000000..20de837d14367 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll @@ -0,0 +1,609 @@ +; 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 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 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 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: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[CANON]] +; + %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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[PSUB]] +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; 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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[NSUB]] +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; 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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SUB]] +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; CHECK-NEXT: ret float [[CANON]] +; + %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: [[CANON:%.*]] = call 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_nsub_ieee() { +; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_nsub_ieee() { +; CHECK-NEXT: [[NSUB:%.*]] = call float @returns_nsub() +; CHECK-NEXT: [[CANON:%.*]] = call 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_sub_ieee() { +; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_sub_ieee() { +; CHECK-NEXT: [[SUB:%.*]] = call float @returns_sub() +; CHECK-NEXT: [[CANON:%.*]] = call 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_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: [[CANON:%.*]] = call 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_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: [[CANON:%.*]] = call 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_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 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: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> [[X]], <2 x float> [[SUB]] +; CHECK-NEXT: [[CANON:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[SELECT]]) +; 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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[SUB_OR_ZERO]] +; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[SELECT]]) +; 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: [[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(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 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 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 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: [[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 +} + +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: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[X]]) +; CHECK-NEXT: ret float [[CANON]] +; + %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: [[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_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: [[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_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: [[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_daz(float nofpclass(sub) %x, i1 %cond) #0 { +; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_no_sub_src_daz( +; CHECK-SAME: fl... [truncated] 
@github-actions
Copy link

github-actions bot commented Dec 21, 2025

🐧 Linux x64 Test Results

  • 187750 tests passed
  • 4985 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link

github-actions bot commented Dec 21, 2025

🪟 Windows x64 Test Results

  • 128844 tests passed
  • 2838 tests skipped

✅ The build succeeded and all tests passed.

@arsenm arsenm force-pushed the users/arsenm/instcombine/add-baseline-test-simplify-demanded-fpclass-canonicalize branch from 06ef509 to fa6f411 Compare December 21, 2025 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

floating-point Floating-point math llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

3 participants