[llvm] InstCombine: Add baseline tests for fmul SimplifyDemandedFPClass handling (PR #173871)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 30 10:41:06 PST 2025


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/173871

>From 5b8b491f977943f77cc3c3f61cb4219a28b5f1e4 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 21 Dec 2025 15:52:33 +0100
Subject: [PATCH] InstCombine: Add baseline tests for fmul
 SimplifyDemandedFPClass handling

---
 .../simplify-demanded-fpclass-fmul.ll         | 918 ++++++++++++++++++
 1 file changed, 918 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll

diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
new file mode 100644
index 0000000000000..22119dc714881
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-fmul.ll
@@ -0,0 +1,918 @@
+; 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(inf nan norm sub) float @returns_zero()
+declare nofpclass(inf nan norm sub nzero) float @returns_pzero()
+declare nofpclass(inf nan norm sub pzero) float @returns_nzero()
+
+; No inf result implies no inf inputs.
+;
+; Does not require special handling of fmul.
+define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_unknown_or_pinf(i1 %cond, float %x, float %y) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__fmul_unknown_or_pinf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000
+  %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000
+  %mul = fmul float %x.or.pinf, %y.or.pinf
+  ret float %mul
+}
+
+; Does not require special handling of fmul.
+define nofpclass(ninf) float @ret_nofpclass_pinf__fmul_unknown_or_ninf(i1 %cond, float %x, float %y) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_pinf__fmul_unknown_or_ninf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    [[MUL:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.or.ninf = select i1 %cond, float %x, float 0xFFF0000000000000
+  %y.or.ninf = select i1 %cond, float %y, float 0xFFF0000000000000
+  %mul = fmul float %x.or.ninf, %y.or.ninf
+  ret float %mul
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__fmul_unknown_or_pinf(i1 %cond, float %x, float %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fmul_unknown_or_pinf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[TMP1]]
+;
+  %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000
+  %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000
+  %mul = fmul float %x.or.pinf, %y.or.pinf
+  ret float %mul
+}
+
+; -> Only propagate nan %x
+define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_results_or_nan_square(float %x) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_results_or_nan_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+; -> poison
+define nofpclass(pinf pnorm psub pzero nan) float @ret_only_negative_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    ret float poison
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf norm sub) float @ret_only_zero_or_nan_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_only_zero_or_nan_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf norm sub nan) float @ret_only_zero_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(nan inf sub norm) float @ret_only_zero_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf norm sub zero) float @ret_only_nan_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf norm sub zero snan) float @ret_only_qnan_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_only_qnan_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf norm sub zero qnan) float @ret_only_snan_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(qnan inf zero sub norm) float @ret_only_snan_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(norm sub zero) float @ret_only_inf_or_nan_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(zero sub norm) float @ret_only_inf_or_nan_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(norm sub zero nan) float @ret_only_inf_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(nan zero sub norm) float @ret_only_inf_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(ninf norm sub zero) float @ret_only_pinf_or_nan_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(ninf zero sub norm) float @ret_only_pinf_or_nan_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(ninf norm sub zero nan) float @ret_only_pinf_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(nan ninf zero sub norm) float @ret_only_pinf_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+; -> poison
+define nofpclass(pinf norm sub zero nan) float @ret_only_ninf_results_square(float %x) {
+; CHECK-LABEL: define nofpclass(nan pinf zero sub norm) float @ret_only_ninf_results_square(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    ret float poison
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf) float @ret_src_must_be_zero_square(float nofpclass(nan inf norm sub) %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_square(
+; CHECK-SAME: float nofpclass(nan inf sub norm) [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf) float @ret_src_must_be_pzero(float nofpclass(nan inf norm sub nzero) %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_pzero(
+; CHECK-SAME: float nofpclass(nan inf nzero sub norm) [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf) float @ret_src_must_be_nzero(float nofpclass(nan inf norm sub pzero) %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_nzero(
+; CHECK-SAME: float nofpclass(nan inf pzero sub norm) [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square(float nofpclass(inf norm sub) %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_src_must_be_zero_or_nan_square(
+; CHECK-SAME: float nofpclass(inf sub norm) [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+; -> qnan
+define nofpclass(nzero) float @ret_src_must_be_nan_square(float nofpclass(inf norm sub zero) %x) {
+; CHECK-LABEL: define nofpclass(nzero) float @ret_src_must_be_nan_square(
+; CHECK-SAME: float nofpclass(inf zero sub norm) [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[X]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %x
+  ret float %mul
+}
+
+; -> qnan
+define nofpclass(pinf pnorm psub pzero) float @ret_only_negative_results_or_nan_fabs_xy(float %x, float nofpclass(ninf nnorm nsub nzero) %y.pos.or.nan) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_only_negative_results_or_nan_fabs_xy(
+; CHECK-SAME: float [[X:%.*]], float nofpclass(ninf nzero nsub nnorm) [[Y_POS_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X_FABS]], [[Y_POS_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %mul = fmul float %x.fabs, %y.pos.or.nan
+  ret float %mul
+}
+
+; -> poison
+define nofpclass(pinf pnorm psub pzero nan) float @ret_only_negative_results_fabs_xy(float %x,float nofpclass(ninf nnorm nsub nzero) %y.pos.or.nan) {
+; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_only_negative_results_fabs_xy(
+; CHECK-SAME: float [[X:%.*]], float nofpclass(ninf nzero nsub nnorm) [[Y_POS_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X_FABS]], [[Y_POS_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.fabs = call float @llvm.fabs.f32(float %x)
+  %mul = fmul float %x.fabs, %y.pos.or.nan
+  ret float %mul
+}
+
+define nofpclass(zero) float @ret_only_zero_results__rhs_non0_const(float %x) {
+; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__rhs_non0_const(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], 2.000000e+00
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, 2.0
+  ret float %mul
+}
+
+define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub(float nofpclass(zero sub) %x, float %y) {
+; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub(
+; CHECK-SAME: float nofpclass(zero sub) [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_daz(float nofpclass(zero sub) %x, float %y) #0 {
+; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_daz(
+; CHECK-SAME: float nofpclass(zero sub) [[X:%.*]], float [[Y:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_dynamic(float nofpclass(zero sub) %x, float %y) #1 {
+; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_nonsub_dynamic(
+; CHECK-SAME: float nofpclass(zero sub) [[X:%.*]], float [[Y:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero(float nofpclass(zero) %x, float %y) {
+; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero(
+; CHECK-SAME: float nofpclass(zero) [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_daz(float nofpclass(zero) %x, float %y) #1 {
+; CHECK-LABEL: define nofpclass(zero) float @ret_only_zero_results__lhs_known_nonzero_daz(
+; CHECK-SAME: float nofpclass(zero) [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(inf) float @ret_only_inf_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_only_inf_results__lhs_known_non_inf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
+; CHECK-NEXT:    [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000
+  %mul = fmul float %x.or.pinf, %y
+  ret float %mul
+}
+
+define nofpclass(inf) float @ret_no_inf_results__rhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_no_inf_results__rhs_known_non_inf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
+; CHECK-NEXT:    [[Y_OR_PINF:%.*]] = select i1 [[COND]], float [[Y]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y_OR_PINF]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000
+  %mul = fmul float %x, %y.or.pinf
+  ret float %mul
+}
+
+; Do nothing, this could still be -inf
+define nofpclass(ninf nan) float @ret_no_ninf_or_nan_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
+; CHECK-LABEL: define nofpclass(nan ninf) float @ret_no_ninf_or_nan_results__lhs_known_non_inf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
+; CHECK-NEXT:    [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000
+  %mul = fmul float %x.or.pinf, %y
+  ret float %mul
+}
+
+; Do nothing, this could still be -inf
+define nofpclass(pinf nan) float @ret_no_pinf_or_nan_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
+; CHECK-LABEL: define nofpclass(nan pinf) float @ret_no_pinf_or_nan_results__lhs_known_non_inf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
+; CHECK-NEXT:    [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000
+  %mul = fmul float %x.or.pinf, %y
+  ret float %mul
+}
+
+; fold to fmul
+define nofpclass(inf nan) float @ret_no_inf_or_nan_results__lhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_or_nan_results__lhs_known_non_inf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
+; CHECK-NEXT:    [[X_OR_PINF:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X_OR_PINF]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %x.or.pinf = select i1 %cond, float %x, float 0x7FF0000000000000
+  %mul = fmul float %x.or.pinf, %y
+  ret float %mul
+}
+
+; fold to fmul
+define nofpclass(inf nan) float @ret_no_inf_or_nan_results__rhs_known_non_inf(i1 %cond, float %x, float nofpclass(inf) %y) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_inf_or_nan_results__rhs_known_non_inf(
+; CHECK-SAME: i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(inf) [[Y:%.*]]) {
+; CHECK-NEXT:    [[Y_OR_PINF:%.*]] = select i1 [[COND]], float [[Y]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y_OR_PINF]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %y.or.pinf = select i1 %cond, float %y, float 0x7FF0000000000000
+  %mul = fmul float %x, %y.or.pinf
+  ret float %mul
+}
+
+; -> nan
+define nofpclass(ninf nnorm nsub nzero) float @ret_only_positive_results_or_nan_known_negative_fmul(float nofpclass(ninf nnorm nsub nzero) %only.positive.or.nan, float nofpclass(pinf pnorm psub pzero) %only.negative.or.nan) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_only_positive_results_or_nan_known_negative_fmul(
+; CHECK-SAME: float nofpclass(ninf nzero nsub nnorm) [[ONLY_POSITIVE_OR_NAN:%.*]], float nofpclass(pinf pzero psub pnorm) [[ONLY_NEGATIVE_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ONLY_NEGATIVE_OR_NAN]], [[ONLY_POSITIVE_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %only.negative.or.nan, %only.positive.or.nan
+  ret float %mul
+}
+
+; -> poison
+define nofpclass(ninf nnorm nsub nzero nan) float @ret_only_positive_results_known_negative_fmul(float nofpclass(ninf nnorm nsub nzero) %only.positive.or.nan, float nofpclass(pinf pnorm psub pzero) %only.negative.or.nan) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_only_positive_results_known_negative_fmul(
+; CHECK-SAME: float nofpclass(ninf nzero nsub nnorm) [[ONLY_POSITIVE_OR_NAN:%.*]], float nofpclass(pinf pzero psub pnorm) [[ONLY_NEGATIVE_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ONLY_NEGATIVE_OR_NAN]], [[ONLY_POSITIVE_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %only.negative.or.nan, %only.positive.or.nan
+  ret float %mul
+}
+
+; missing nnan rhs
+define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf(float nofpclass(inf sub norm) %zero.or.nan, float nofpclass(inf) %not.inf) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf(
+; CHECK-SAME: float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]], float nofpclass(inf) [[NOT_INF:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ZERO_OR_NAN]], [[NOT_INF]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %zero.or.nan, %not.inf
+  ret float %mul
+}
+
+; Needs to be pzero to replace with copysign
+define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm) %zero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_zero_or_nan__fmul__not_inf_or_nan(
+; CHECK-SAME: float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %zero.or.nan, %not.inf.or.nan
+  ret float %mul
+}
+
+; Needs to be pzero to replace with copysign
+define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_zero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm) %zero.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_zero_or_nan(
+; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf sub norm) [[ZERO_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_INF_OR_NAN]], [[ZERO_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.inf.or.nan, %zero.or.nan
+  ret float %mul
+}
+
+; -> copysign
+define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_pzero_or_nan__fmul__not_inf_or_nan(
+; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %pzero.or.nan, %not.inf.or.nan
+  ret float %mul
+}
+
+; missing nnan lhs
+define nofpclass(nsub) float @ret__not_inf__fmul__known_pzero_or_nan(float nofpclass(inf) %not.inf, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf__fmul__known_pzero_or_nan(
+; CHECK-SAME: float nofpclass(inf) [[NOT_INF:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_INF]], [[PZERO_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.inf, %pzero.or.nan
+  ret float %mul
+}
+
+; -> copysign
+define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf nan) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__not_inf_or_nan__fmul__known_pzero_or_nan(
+; CHECK-SAME: float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_INF_OR_NAN]], [[PZERO_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.inf.or.nan, %pzero.or.nan
+  ret float %mul
+}
+
+; Missing no-nan on RHS to turn into fneg
+define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0_or_nan(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(zero pinf pnorm psub) %negative.non0.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0_or_nan(
+; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %inf.or.nan, %negative.non0.or.nan
+  ret float %mul
+}
+
+; Missing no-nan on LHS to turn into fneg
+define nofpclass(nsub) float @ret__known_negative_non0_or_nan__fmul__known_inf_or_nan(float nofpclass(zero pinf pnorm psub) %negative.non0.or.nan, float nofpclass(zero sub norm) %inf.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0_or_nan__fmul__known_inf_or_nan(
+; CHECK-SAME: float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0_OR_NAN:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NEGATIVE_NON0_OR_NAN]], [[INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %negative.non0.or.nan, %inf.or.nan
+  ret float %mul
+}
+
+; -> fneg
+define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm psub) %negative.non0) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0(
+; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %inf.or.nan, %negative.non0
+  ret float %mul
+}
+
+; -> fneg
+define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan(float nofpclass(nan zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan(
+; CHECK-SAME: float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NEGATIVE_NON0]], [[INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %negative.non0, %inf.or.nan
+  ret float %mul
+}
+
+; Cannot fold to fneg due to possible nsub input
+define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0__daz(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm psub) %negative.non0) #1 {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_non0__daz(
+; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %inf.or.nan, %negative.non0
+  ret float %mul
+}
+
+; Cannot fold to fneg due to possible nsub input
+define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan__daz(float nofpclass(nan zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) #1 {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_non0__fmul__known_inf_or_nan__daz(
+; CHECK-SAME: float nofpclass(nan pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NEGATIVE_NON0]], [[INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %negative.non0, %inf.or.nan
+  ret float %mul
+}
+
+; -> fneg
+define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_nonlogical0__daz(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(nan zero pinf pnorm sub) %negative.nonlogical0) #1 {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_inf_or_nan__fmul__known_negative_nonlogical0__daz(
+; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(nan pinf zero sub pnorm) [[NEGATIVE_NONLOGICAL0:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NONLOGICAL0]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %inf.or.nan, %negative.nonlogical0
+  ret float %mul
+}
+
+; -> fneg
+define nofpclass(nsub) float @ret__known_negative_nonlogical0__fmul__known_inf_or_nan__daz(float nofpclass(nan zero pinf pnorm sub) %negative.nonlogical0, float nofpclass(zero sub norm) %inf.or.nan) #1 {
+; CHECK-LABEL: define nofpclass(nsub) float @ret__known_negative_nonlogical0__fmul__known_inf_or_nan__daz(
+; CHECK-SAME: float nofpclass(nan pinf zero sub pnorm) [[NEGATIVE_NONLOGICAL0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NEGATIVE_NONLOGICAL0]], [[INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %negative.nonlogical0, %inf.or.nan
+  ret float %mul
+}
+
+; Should be able to fold to copysign, helped by the lack of nan results.
+define nofpclass(nan) float @ret_no_nan_result__known_pzero__fmul__not_inf(float nofpclass(inf sub norm nzero) %pzero.or.nan, float nofpclass(inf nan) %not.inf.or.nan) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_pzero__fmul__not_inf(
+; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float nofpclass(nan inf) [[NOT_INF_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[NOT_INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %pzero.or.nan, %not.inf.or.nan
+  ret float %mul
+}
+
+; Should be able to fold to copysign, helped by the lack of nan results.
+define nofpclass(nan) float @ret_no_nan_result__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf) %not.inf.or.nan, float nofpclass(inf sub norm nzero) %pzero.or.nan) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__not_inf_or_nan__fmul__known_pzero_or_nan(
+; CHECK-SAME: float nofpclass(inf) [[NOT_INF_OR_NAN:%.*]], float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_INF_OR_NAN]], [[PZERO_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.inf.or.nan, %pzero.or.nan
+  ret float %mul
+}
+
+; -> fneg, with help of no nan results
+define nofpclass(nan) float @ret_no_nan_result__known_inf_or_nan__fmul__known_negative_non0(float nofpclass(zero sub norm) %inf.or.nan, float nofpclass(zero pinf pnorm psub) %negative.non0) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_inf_or_nan__fmul__known_negative_non0(
+; CHECK-SAME: float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]], float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[INF_OR_NAN]], [[NEGATIVE_NON0]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %inf.or.nan, %negative.non0
+  ret float %mul
+}
+
+; -> fneg, with help of no nan results
+define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known_inf_or_nan(float nofpclass(zero pinf pnorm psub) %negative.non0, float nofpclass(zero sub norm) %inf.or.nan) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan_result__known_negative_non0__fmul__known_inf_or_nan(
+; CHECK-SAME: float nofpclass(pinf zero psub pnorm) [[NEGATIVE_NON0:%.*]], float nofpclass(zero sub norm) [[INF_OR_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NEGATIVE_NON0]], [[INF_OR_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %negative.non0, %inf.or.nan
+  ret float %mul
+}
+
+; -> copysign, take no-infs-no-nans from invalid return
+define nofpclass(inf nan) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__known_pzero_or_nan__fmul__not_inf_or_nan(
+; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[UNKNOWN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %pzero.or.nan, %unknown
+  ret float %mul
+}
+
+; -> copysign, take no-infs-no-nans from invalid return, commuted
+define nofpclass(inf nan) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(float nofpclass(inf sub norm nzero) %pzero.or.nan, float %unknown) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_noinf_nonan__not_inf_or_nan__fmul__known_pzero_or_nan(
+; CHECK-SAME: float nofpclass(inf nzero sub norm) [[PZERO_OR_NAN:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[PZERO_OR_NAN]], [[UNKNOWN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %pzero.or.nan, %unknown
+  ret float %mul
+}
+
+; -> copysign, take no-infs from invalid return
+define nofpclass(inf) float @ret_noinf__known_zero_or_nan__fmul__not_nan(float nofpclass(nan sub norm nzero) %pzero.or.inf, float nofpclass(nan) %not.nan) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__known_zero_or_nan__fmul__not_nan(
+; CHECK-SAME: float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[PZERO_OR_INF]], [[NOT_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %pzero.or.inf, %not.nan
+  ret float %mul
+}
+
+; -> copysign, take no-infs from invalid return, commuted
+define nofpclass(inf) float @ret_noinf__noinf_or_nan__fmul__known_pzero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(nan sub norm nzero) %pzero.or.inf) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_noinf__noinf_or_nan__fmul__known_pzero_or_nan(
+; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_NAN]], [[PZERO_OR_INF]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.nan, %pzero.or.inf
+  ret float %mul
+}
+
+define nofpclass(pinf) float @ret_nopinf__known_pzero_or_nan__fmul__not_nan(float nofpclass(nan sub norm nzero) %pzero.or.inf, float nofpclass(nan) %not.nan) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__known_pzero_or_nan__fmul__not_nan(
+; CHECK-SAME: float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[PZERO_OR_INF]], [[NOT_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %pzero.or.inf, %not.nan
+  ret float %mul
+}
+
+define nofpclass(pinf) float @ret_nopinf__not_nan__fmul__known_zero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(nan sub norm nzero) %pzero.or.inf) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__not_nan__fmul__known_zero_or_nan(
+; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_NAN]], [[PZERO_OR_INF]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.nan, %pzero.or.inf
+  ret float %mul
+}
+
+define nofpclass(ninf) float @ret_noninf__known_pzero_or_nan__fmul__not_nan(float nofpclass(nan sub norm nzero) %pzero.or.inf, float nofpclass(nan) %not.nan) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__known_pzero_or_nan__fmul__not_nan(
+; CHECK-SAME: float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]], float nofpclass(nan) [[NOT_NAN:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[PZERO_OR_INF]], [[NOT_NAN]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %pzero.or.inf, %not.nan
+  ret float %mul
+}
+
+define nofpclass(ninf) float @ret_noninf__not_nan__fmul__known_zero_or_nan(float nofpclass(nan) %not.nan, float nofpclass(nan sub norm nzero) %pzero.or.inf) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__not_nan__fmul__known_zero_or_nan(
+; CHECK-SAME: float nofpclass(nan) [[NOT_NAN:%.*]], float nofpclass(nan nzero sub norm) [[PZERO_OR_INF:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_NAN]], [[PZERO_OR_INF]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.nan, %pzero.or.inf
+  ret float %mul
+}
+
+; no pinf result implies no infs if the signs of each operand are the same, must be +0
+define nofpclass(pinf) float @ret_nopinf__known_zero_or_pos_nan__fmul__not_nan_pos(float nofpclass(nan ninf sub norm) %zero.or.not.neg, float nofpclass(nan ninf nzero nsub nnorm) %not.nan.not.neg) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__known_zero_or_pos_nan__fmul__not_nan_pos(
+; CHECK-SAME: float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_NEG]], [[NOT_NAN_NOT_NEG]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %zero.or.not.neg, %not.nan.not.neg
+  ret float %mul
+}
+
+define nofpclass(pinf) float @ret_nopinf__not_nan_pos__fmul__known_zero_or_pos_nan(float nofpclass(nan ninf nsub nnorm) %not.nan.not.neg, float nofpclass(nan ninf nzero sub norm) %zero.or.not.neg) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__not_nan_pos__fmul__known_zero_or_pos_nan(
+; CHECK-SAME: float nofpclass(nan ninf nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]], float nofpclass(nan ninf nzero sub norm) [[ZERO_OR_NOT_NEG:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_NEG]], [[ZERO_OR_NOT_NEG]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.nan.not.neg, %zero.or.not.neg
+  ret float %mul
+}
+
+define nofpclass(pinf) float @ret_nopinf__known_zero_or_neg_nan__fmul__not_nan_neg(float nofpclass(nan pinf sub norm) %zero.or.not.pos, float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__known_zero_or_neg_nan__fmul__not_nan_neg(
+; CHECK-SAME: float nofpclass(nan pinf sub norm) [[ZERO_OR_NOT_POS:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_POS]], [[NOT_NAN_NOT_POS]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %zero.or.not.pos, %not.nan.not.pos
+  ret float %mul
+}
+
+define nofpclass(pinf) float @ret_nopinf__not_nan_neg__fmul__known_zero_or_neg_nan(float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos, float nofpclass(nan pinf sub norm) %zero.or.not.pos) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nopinf__not_nan_neg__fmul__known_zero_or_neg_nan(
+; CHECK-SAME: float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]], float nofpclass(nan pinf sub norm) [[ZERO_OR_NOT_POS:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_POS]], [[ZERO_OR_NOT_POS]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.nan.not.pos, %zero.or.not.pos
+  ret float %mul
+}
+
+define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_pos(float nofpclass(nan ninf sub norm) %zero.or.not.neg, float nofpclass(nan ninf nzero nsub nnorm) %not.nan.not.neg) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_pos(
+; CHECK-SAME: float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]], float nofpclass(nan ninf nzero nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_NEG]], [[NOT_NAN_NOT_NEG]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %zero.or.not.neg, %not.nan.not.neg
+  ret float %mul
+}
+
+define nofpclass(ninf) float @ret_noninf__not_nan_pos__fmul__known_zero_or_pos_nan(float nofpclass(nan ninf nzero nsub nnorm) %not.nan.not.neg, float nofpclass(nan ninf sub norm) %zero.or.not.neg) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__not_nan_pos__fmul__known_zero_or_pos_nan(
+; CHECK-SAME: float nofpclass(nan ninf nzero nsub nnorm) [[NOT_NAN_NOT_NEG:%.*]], float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_NEG]], [[ZERO_OR_NOT_NEG]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.nan.not.neg, %zero.or.not.neg
+  ret float %mul
+}
+
+define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_neg(float nofpclass(nan ninf sub norm) %zero.or.not.neg, float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__known_zero_or_pos_nan__fmul__not_nan_neg(
+; CHECK-SAME: float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]], float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[ZERO_OR_NOT_NEG]], [[NOT_NAN_NOT_POS]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %zero.or.not.neg, %not.nan.not.pos
+  ret float %mul
+}
+
+define nofpclass(ninf) float @ret_noninf__not_nan_neg__fmul__known_zero_or_pos_nan(float nofpclass(nan pinf pzero psub pnorm) %not.nan.not.pos, float nofpclass(nan ninf sub norm) %zero.or.not.neg) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_noninf__not_nan_neg__fmul__known_zero_or_pos_nan(
+; CHECK-SAME: float nofpclass(nan pinf pzero psub pnorm) [[NOT_NAN_NOT_POS:%.*]], float nofpclass(nan ninf sub norm) [[ZERO_OR_NOT_NEG:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[NOT_NAN_NOT_POS]], [[ZERO_OR_NOT_NEG]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %not.nan.not.pos, %zero.or.not.neg
+  ret float %mul
+}
+
+define nofpclass(inf norm sub zero) float @ret_only_nan_results_fmul(float %x, float %y) {
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_only_nan_results_fmul(
+; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(inf norm sub zero snan) float @ret_only_qnan_results_fmul(float %x, float %y) {
+; CHECK-LABEL: define nofpclass(snan inf zero sub norm) float @ret_only_qnan_results_fmul(
+; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(inf norm sub zero qnan) float @ret_only_snan_results_fmul(float %x, float %y) {
+; CHECK-LABEL: define nofpclass(qnan inf zero sub norm) float @ret_only_snan_results_fmul(
+; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[MUL]]
+;
+  %mul = fmul float %x, %y
+  ret float %mul
+}
+
+define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_nonan_noinf__nonan_noinf(float nofpclass(inf nan) %x, float nofpclass(inf nan) %y) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_nonan_noinf__nonan_noinf(
+; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]], float nofpclass(nan inf) [[Y:%.*]]) {
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %fmul = fmul float %x, %y
+  ret float %fmul
+}
+
+define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_no_nan__normal_constant(float nofpclass(inf nan) %x) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_no_nan_no_inf__fmul_no_nan__normal_constant(
+; CHECK-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[X]], 4.000000e+00
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %fmul = fmul float %x, 4.0
+  ret float %fmul
+}
+
+define nofpclass(nan) float @ret_no_nan__fmul_zero__unknown(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_zero__unknown(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[ZERO:%.*]] = call float @returns_zero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[ZERO]], [[UNKNOWN]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %zero = call float @returns_zero()
+  %fmul = fmul float %zero, %unknown
+  ret float %fmul
+}
+
+define nofpclass(nan) float @ret_no_nan__fmul_unknown__zero(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__zero(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[ZERO:%.*]] = call float @returns_zero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[UNKNOWN]], [[ZERO]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %zero = call float @returns_zero()
+  %fmul = fmul float %unknown, %zero
+  ret float %fmul
+}
+
+define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_pzero__unknown(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[PZERO:%.*]] = call float @returns_pzero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[PZERO]], [[UNKNOWN]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %pzero = call float @returns_pzero()
+  %fmul = fmul float %pzero, %unknown
+  ret float %fmul
+}
+
+define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__pzero(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[PZERO:%.*]] = call float @returns_pzero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[UNKNOWN]], [[PZERO]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %pzero = call float @returns_pzero()
+  %fmul = fmul float %unknown, %pzero
+  ret float %fmul
+}
+
+define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_nzero__unknown(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[NZERO:%.*]] = call float @returns_nzero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[NZERO]], [[UNKNOWN]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %nzero = call float @returns_nzero()
+  %fmul = fmul float %nzero, %unknown
+  ret float %fmul
+}
+
+define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(float %unknown) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_no_nan__fmul_unknown__nzero(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[NZERO:%.*]] = call float @returns_nzero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[UNKNOWN]], [[NZERO]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %nzero = call float @returns_nzero()
+  %fmul = fmul float %unknown, %nzero
+  ret float %fmul
+}
+
+define nofpclass(ninf) float @ret_ninf__fmul_nnan_zero__unknown(float %unknown) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_ninf__fmul_nnan_zero__unknown(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[ZERO:%.*]] = call float @returns_zero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul nnan float [[ZERO]], [[UNKNOWN]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %zero = call float @returns_zero()
+  %fmul = fmul nnan float %zero, %unknown
+  ret float %fmul
+}
+
+define nofpclass(ninf) float @ret_ninf__fmul_nnan_unknown__zero(float %unknown) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_ninf__fmul_nnan_unknown__zero(
+; CHECK-SAME: float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:    [[ZERO:%.*]] = call float @returns_zero()
+; CHECK-NEXT:    [[FMUL:%.*]] = fmul nnan float [[UNKNOWN]], [[ZERO]]
+; CHECK-NEXT:    ret float [[FMUL]]
+;
+  %zero = call float @returns_zero()
+  %fmul = fmul nnan float %unknown, %zero
+  ret float %fmul
+}
+
+attributes #0 = { "denormal-fp-math"="preserve-sign,preserve-sign" }
+attributes #1 = { "denormal-fp-math"="dynamic,dynamic" }
+
+
+
+
+
+



More information about the llvm-commits mailing list