[llvm] InstCombine: Add baseline test for nanless canonicalize combine (PR #172997)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Sat Feb 21 11:09:43 PST 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/172997
>From 2f43a1e2b3c7d2e957522fced55083cff184d286 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 19 Dec 2025 10:53:13 +0100
Subject: [PATCH] InstCombine: Add baseline test for nanless canonicalize
combine
---
.../nanless-canonicalize-combine.ll | 832 ++++++++++++++++++
1 file changed, 832 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll
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..56e0808c650ff
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/nanless-canonicalize-combine.ll
@@ -0,0 +1,832 @@
+; 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 noundef 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 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: [[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
+}
+
+; 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]], 0xK00000000000000000000
+; 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]], 0xM00000000000000000000000000000000
+; 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: [[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
+}
+
+; 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: [[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
+}
+
+; 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: [[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
+}
+
+; 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: [[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
+}
+
+; 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: [[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
+}
+
+; 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: [[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
+}
+
+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: [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]])
+; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; 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_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: [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]])
+; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; 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_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: [[RCP:%.*]] = fdiv half 0xH3C00, [[X]]
+; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; 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_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: [[RCP:%.*]] = fdiv half 0xH3C00, [[X]]
+; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; 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 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]], 0xH0000
+; 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]], 0xH0000
+; 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 0xH3C00, [[X]]
+; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; 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 0xH3C00, [[X]]
+; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; 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]], 0xK00000000000000000000
+; 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 0xK3FFF8000000000000000, [[X]]
+; CHECK-NEXT: [[ORD:%.*]] = fcmp ord x86_fp80 [[X]], 0xK00000000000000000000
+; 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: [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]])
+; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; 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
+}
+
+; 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: [[HARD_CANONICAL:%.*]] = call half @llvm.canonicalize.f16(half [[X]])
+; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; 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
+}
+
+; 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: [[RCP:%.*]] = fdiv half 0xH3C00, [[X]]
+; CHECK-NEXT: [[ORD:%.*]] = fcmp ord half [[X]], 0xH0000
+; 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
+}
+
+; 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: [[RCP:%.*]] = fdiv half 0xH3C00, [[X]]
+; CHECK-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0xH0000
+; 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
+}
+
+attributes #0 = { "denormal-fp-math"="ieee,ieee" }
+attributes #1 = { "denormal-fp-math"="preserve-sign,preserve-sign" }
+attributes #2 = { "denormal-fp-math"="dynamic,dynamic" }
More information about the llvm-commits
mailing list