Skip to content

InstCombine: Add baseline test for nanless canonicalize combine#172997

Open
arsenm wants to merge 1 commit intomainfrom
users/arsenm/instcombine/add-baseline-test-nanless-canonicalize
Open

InstCombine: Add baseline test for nanless canonicalize combine#172997
arsenm wants to merge 1 commit intomainfrom
users/arsenm/instcombine/add-baseline-test-nanless-canonicalize

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Dec 19, 2025

No description provided.

Copy link
Contributor Author

arsenm commented Dec 19, 2025

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

llvmbot commented Dec 19, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Matt Arsenault (arsenm)

Changes

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

1 Files Affected:

  • (added) llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll (+631)
diff --git a/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll b/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll
new file mode 100644
index 0000000000000..5aa156753e860
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll
@@ -0,0 +1,631 @@
+; 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:    [[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
+}
+
+; 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:    [[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
+}
+
+; 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:    [[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)
+  %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:    [[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)
+  %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:    [[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
+}
+
+; 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:    [[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
+}
+
+; 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:    [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]])
+; CHECK-NEXT:    [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]]
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord <2 x float> [[X]], zeroinitializer
+; CHECK-NEXT:    [[X_CANON:%.*]] = select <2 x i1> [[ORD]], <2 x float> [[HARD_CANONICAL]], <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> 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:    [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]])
+; CHECK-NEXT:    [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]]
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno <2 x float> [[X]], zeroinitializer
+; CHECK-NEXT:    [[X_CANON:%.*]] = select <2 x i1> [[UNO]], <2 x float> [[SOFT_CANONICAL]], <2 x float> [[HARD_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> 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:    [[HARD_CANONICAL:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> [[X]])
+; CHECK-NEXT:    [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> <float 1.000000e+00, float poison>, [[X]]
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord <2 x float> [[X]], zeroinitializer
+; CHECK-NEXT:    [[X_CANON:%.*]] = select <2 x i1> [[ORD]], <2 x float> [[HARD_CANONICAL]], <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> <float 1.0, float poison>, %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:    [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]]
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord <2 x float> [[X]], zeroinitializer
+; CHECK-NEXT:    [[X_CANON:%.*]] = select <2 x i1> [[ORD]], <2 x float> [[HARD_CANONICAL]], <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> 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:    [[SOFT_CANONICAL:%.*]] = fdiv <2 x float> splat (float 1.000000e+00), [[X]]
+; CHECK-NEXT:    [[UNO:%.*]] = fcmp uno <2 x float> [[X]], zeroinitializer
+; CHECK-NEXT:    [[X_CANON:%.*]] = select <2 x i1> [[UNO]], <2 x float> [[SOFT_CANONICAL]], <2 x float> [[HARD_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> 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:    [[HARD_CANONICAL:%.*]] = call bfloat @llvm.canonicalize.bf16(bfloat [[X]])
+; CHECK-NEXT:    [[SOFT_CANONICAL:%.*]] = fdiv bfloat 0xR3F80, [[X]]
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord bfloat [[X]], 0xR0000
+; CHECK-NEXT:    [[X_CANON:%.*]] = select i1 [[ORD]], bfloat [[HARD_CANONICAL]], bfloat [[SOFT_CANONICAL]]
+; CHECK-NEXT:    ret bfloat [[X_CANON]]
+;
+  %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:    [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]])
+; CHECK-NEXT:    [[SOFT_CANONICAL:%.*]] = fdiv half 0xH3C00, [[X]]
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; CHECK-NEXT:    [[X_CANON:%.*]] = select i1 [[ORD]], half [[HARD_CANONICAL]], half [[SOFT_CANONICAL]]
+; CHECK-NEXT:    ret half [[X_CANON]]
+;
+  %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:    [[HARD_CANONICAL:%.*]] = call double @llvm.canonicalize.f64(double [[X]])
+; CHECK-NEXT:    [[SOFT_CANONICAL:%.*]] = fdiv double 1.000000e+00, [[X]]
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord double [[X]], 0.000000e+00
+; CHECK-NEXT:    [[X_CANON:%.*]] = select i1 [[ORD]], double [[HARD_CANONICAL]], double [[SOFT_CANONICAL]]
+; CHECK-NEXT:    ret double [[X_CANON]]
+;
+  %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:    [[HARD_CANONICAL:%.*]] = call fp128 @llvm.canonicalize.f128(fp128 [[X]])
+; CHECK-NEXT:    [[ORD:%.*]] = fcmp ord fp128 [[X]], 0xL00000000000000000000000000000000
+; CHECK-NEXT:    [[X_CANON:%.*]] = select i1 [[ORD]], fp128 [[HARD_CANONICAL]], fp128 [[X]]
+; CHECK-NEXT:    ret fp128 [[X_CANON]]
+;
+  %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:    [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
+; 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 [[HARD_CANONICAL]], 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:    [[HARD_CANONICAL:%.*]] = call float @llvm.canonicalize.f32(float [[X]])
+; 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 [[HARD_CANONICAL]], 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:    [[NOT_CANONICAL:%.*]] = call float @func(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 [[NOT_CANONICAL]], float [[SOFT_CANONICAL]]
+; CHECK-NEXT:    ret float [[X_CANON]]
+;
+  %not.canonical = call 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:    [[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_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:    [[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
+}
+
+; Negati...
[truncated]

@arsenm arsenm force-pushed the users/arsenm/instcombine/add-baseline-test-nanless-canonicalize branch from 340f7e9 to 7c77545 Compare December 20, 2025 13:43
@arsenm arsenm force-pushed the users/arsenm/instcombine/add-baseline-test-nanless-canonicalize branch from 7c77545 to f793b21 Compare January 22, 2026 21:27
@arsenm arsenm force-pushed the users/arsenm/instcombine/add-baseline-test-nanless-canonicalize branch from f793b21 to 2f43a1e Compare February 21, 2026 19:09
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants