[llvm] 1879b25 - InstCombine: Add baseline test for SimplifyDemandedFPClass

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 4 15:41:27 PDT 2023


Author: Matt Arsenault
Date: 2023-10-04T15:41:02-07:00
New Revision: 1879b2570adc7e9f0c02be8d234960b1f68e2f32

URL: https://github.com/llvm/llvm-project/commit/1879b2570adc7e9f0c02be8d234960b1f68e2f32
DIFF: https://github.com/llvm/llvm-project/commit/1879b2570adc7e9f0c02be8d234960b1f68e2f32.diff

LOG: InstCombine: Add baseline test for SimplifyDemandedFPClass

Added: 
    llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
new file mode 100644
index 000000000000000..9817b6e13ca8ae9
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
@@ -0,0 +1,1263 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+declare float @llvm.fabs.f32(float)
+declare float @llvm.copysign.f32(float, float)
+declare void @llvm.assume(i1 noundef)
+declare float @llvm.log2.f32(float)
+declare float @llvm.exp2.f32(float)
+declare float @llvm.trunc.f32(float)
+declare float @llvm.arithmetic.fence.f32(float)
+declare float @llvm.minnum.f32(float, float)
+declare float @llvm.maxnum.f32(float, float)
+
+
+define float @ninf_user_select_inf(i1 %cond, float %x, float %y) {
+; CHECK-LABEL: define float @ninf_user_select_inf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[NINF_USER:%.*]] = fmul ninf float [[SELECT]], [[Y]]
+; CHECK-NEXT:    ret float [[NINF_USER]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %ninf.user = fmul ninf float %y, %select
+  ret float %ninf.user
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf_poison() {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf_poison() {
+; CHECK-NEXT:    ret float poison
+;
+  ret float poison
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf_undef() {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf_undef() {
+; CHECK-NEXT:    ret float undef
+;
+  ret float undef
+}
+
+; Make sure there's no infinite loop
+define nofpclass(all) float @ret_nofpclass_all_var(float %arg) {
+; CHECK-LABEL: define nofpclass(all) float @ret_nofpclass_all_var
+; CHECK-SAME: (float [[ARG:%.*]]) {
+; CHECK-NEXT:    ret float [[ARG]]
+;
+  ret float %arg
+}
+
+; Make sure there's no infinite loop
+define nofpclass(all) <2 x float> @ret_nofpclass_all_var_vector(<2 x float> %arg) {
+; CHECK-LABEL: define nofpclass(all) <2 x float> @ret_nofpclass_all_var_vector
+; CHECK-SAME: (<2 x float> [[ARG:%.*]]) {
+; CHECK-NEXT:    ret <2 x float> [[ARG]]
+;
+  ret <2 x float> %arg
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__0() {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__0() {
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  ret float 0.0
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__pinf() {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__pinf() {
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  ret float 0x7FF0000000000000
+}
+
+define nofpclass(pinf) float @ret_nofpclass_pinf__pinf() {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__pinf() {
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  ret float 0x7FF0000000000000
+}
+
+define nofpclass(pinf) float @ret_nofpclass_pinf__ninf() {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__ninf() {
+; CHECK-NEXT:    ret float 0xFFF0000000000000
+;
+  ret float 0xFFF0000000000000
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__ninf() {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__ninf() {
+; CHECK-NEXT:    ret float 0xFFF0000000000000
+;
+  ret float 0xFFF0000000000000
+}
+
+; Negative test, do nothing
+define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_inf_lhs(i1 %cond, float nofpclass(inf) %x, float %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_inf_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float nofpclass(inf) [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[Y]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float %x, float %y
+  ret float %select
+}
+
+; Make sure nofpclass from source argument is used, fold to %y
+define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_lhs(i1 %cond, float nofpclass(nan norm zero sub) %x, float %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float nofpclass(nan zero sub norm) [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[Y]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float %x, float %y
+  ret float %select
+}
+
+; Make sure nofpclass from source argument is used, fold to %x
+define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_rhs(i1 %cond, float %x, float nofpclass(nan norm zero sub) %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_arg_only_inf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float nofpclass(nan zero sub norm) [[Y:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[Y]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float %x, float %y
+  ret float %select
+}
+
+; Fold to ret %y
+define nofpclass(inf) [3 x [2 x float]] @ret_float_array(i1 %cond, [3 x [2 x float]] nofpclass(nan norm zero sub) %x, [3 x [2 x float]] %y) {
+; CHECK-LABEL: define nofpclass(inf) [3 x [2 x float]] @ret_float_array
+; CHECK-SAME: (i1 [[COND:%.*]], [3 x [2 x float]] nofpclass(nan zero sub norm) [[X:%.*]], [3 x [2 x float]] [[Y:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], [3 x [2 x float]] [[X]], [3 x [2 x float]] [[Y]]
+; CHECK-NEXT:    ret [3 x [2 x float]] [[SELECT]]
+;
+  %select = select i1 %cond, [3 x [2 x float]] %x, [3 x [2 x float]] %y
+  ret [3 x [2 x float ]] %select
+}
+
+; Fold to ret %x
+define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_lhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0x7FF0000000000000, float %x
+  ret float %select
+}
+
+; Fold to ret %x
+define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  ret float %select
+}
+
+; Fold to poison
+define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_or_ninf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_pinf_or_ninf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float 0xFFF0000000000000
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0x7FF0000000000000, float 0xFFF0000000000000
+  ret float %select
+}
+
+; Fold to poison
+define nofpclass(inf) float @ret_nofpclass_inf__select_ninf_or_pinf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_ninf_or_pinf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0xFFF0000000000000, float 0x7FF0000000000000
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0xFFF0000000000000, float 0x7FF0000000000000
+  ret float %select
+}
+
+; Fold to pos inf
+define nofpclass(ninf) float @ret_nofpclass_ninf__select_ninf_or_pinf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__select_ninf_or_pinf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0xFFF0000000000000, float 0x7FF0000000000000
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0xFFF0000000000000, float 0x7FF0000000000000
+  ret float %select
+}
+
+; Fold to neg inf
+define nofpclass(pinf) float @ret_nofpclass_pinf__select_ninf_or_pinf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__select_ninf_or_pinf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0xFFF0000000000000, float 0x7FF0000000000000
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0xFFF0000000000000, float 0x7FF0000000000000
+  ret float %select
+}
+
+; Fold to poison
+define nofpclass(zero) float @ret_nofpclass_zero__select_pzero_or_nzero(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(zero) float @ret_nofpclass_zero__select_pzero_or_nzero
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0.000000e+00, float -0.000000e+00
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0.0, float -0.0
+  ret float %select
+}
+
+; Fold to +0
+define nofpclass(nzero) float @ret_nofpclass_nzero__select_pzero_or_nzero(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nzero) float @ret_nofpclass_nzero__select_pzero_or_nzero
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0.000000e+00, float -0.000000e+00
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0.0, float -0.0
+  ret float %select
+}
+
+; Fold to -0
+define nofpclass(pzero) float @ret_nofpclass_pzero__select_pzero_or_nzero(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(pzero) float @ret_nofpclass_pzero__select_pzero_or_nzero
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0.000000e+00, float -0.000000e+00
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0.0, float -0.0
+  ret float %select
+}
+
+; Fold to ret %x
+define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector(<2 x i1> %cond, <2 x float> %x) {
+; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector
+; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>, <2 x float> [[X]]
+; CHECK-NEXT:    ret <2 x float> [[SELECT]]
+;
+  %select = select <2 x i1> %cond, <2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>, <2 x float> %x
+  ret <2 x float> %select
+}
+
+; Fold to ret %x
+define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector_undef(<2 x i1> %cond, <2 x float> %x) {
+; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_pinf_lhs_vector_undef
+; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> <float 0x7FF0000000000000, float poison>, <2 x float> [[X]]
+; CHECK-NEXT:    ret <2 x float> [[SELECT]]
+;
+  %select = select <2 x i1> %cond, <2 x float> <float 0x7FF0000000000000, float poison>, <2 x float> %x
+  ret <2 x float> %select
+}
+
+; Fold to ret %x
+define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_mixed_inf_lhs_vector(<2 x i1> %cond, <2 x float> %x) {
+; CHECK-LABEL: define nofpclass(inf) <2 x float> @ret_nofpclass_inf__select_mixed_inf_lhs_vector
+; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> <float 0x7FF0000000000000, float 0xFFF0000000000000>, <2 x float> [[X]]
+; CHECK-NEXT:    ret <2 x float> [[SELECT]]
+;
+  %select = select <2 x i1> %cond, <2 x float> <float 0x7FF0000000000000, float 0xFFF0000000000000>, <2 x float> %x
+  ret <2 x float> %select
+}
+
+; Can't delete the select
+define nofpclass(inf) float @ret_nofpclass_inf__select_multi_use_pinf_lhs(i1 %cond, float %x, ptr %ptr) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_multi_use_pinf_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], ptr [[PTR:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
+; CHECK-NEXT:    store float [[SELECT]], ptr [[PTR]], align 4
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0x7FF0000000000000, float %x
+  store float %select, ptr %ptr
+  ret float %select
+}
+
+; Can't do anything
+define nofpclass(inf) float @ret_nofpclass_inf__select_p0_lhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_p0_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0.000000e+00, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0.0, float %x
+  ret float %select
+}
+
+; Can't do anything
+define nofpclass(inf) float @ret_nofpclass_inf__select_p0_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_p0_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0.000000e+00
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float %x, float 0.0
+  ret float %select
+}
+
+; Can't do anything
+define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_lhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float 0x7FF0000000000000, float %x
+  ret float %select
+}
+
+; Can't do anything
+define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  ret float %select
+}
+
+define nofpclass(inf nan) float @ret_nofpclass_inf_nan__select_chain_inf_nan_0(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_nofpclass_inf_nan__select_chain_inf_nan_0
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT1:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT1]]
+;
+  %select0 = select i1 %cond, float 0x7FF8000000000000, float %x
+  %select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
+  ret float %select1
+}
+
+define nofpclass(inf nan) float @ret_nofpclass_inf_nan__select_chain_inf_nan_1(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_nofpclass_inf_nan__select_chain_inf_nan_1
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT1:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float 0x7FF8000000000000
+; CHECK-NEXT:    ret float [[SELECT1]]
+;
+  %select0 = select i1 %cond, float %x, float 0x7FF8000000000000
+  %select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
+  ret float %select1
+}
+
+define nofpclass(nan) float @ret_nofpclass_nan__select_chain_inf_nan(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__select_chain_inf_nan
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT1:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT1]]
+;
+  %select0 = select i1 %cond, float 0x7FF8000000000000, float %x
+  %select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
+  ret float %select1
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_0(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_0
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT1:%.*]] = select i1 [[COND]], float 0x7FF0000000000000, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT1]]
+;
+  %select0 = select i1 %cond, float 0x7FF8000000000000, float %x
+  %select1 = select i1 %cond, float 0x7FF0000000000000, float %select0
+  ret float %select1
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_1(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_1
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT1:%.*]] = select i1 [[COND]], float 0x7FF8000000000000, float 0x7FF0000000000000
+; CHECK-NEXT:    ret float [[SELECT1]]
+;
+  %select0 = select i1 %cond, float 0x7FF8000000000000, float %x
+  %select1 = select i1 %cond, float %select0, float 0x7FF0000000000000
+  ret float %select1
+}
+
+; Simplify to fabs %x
+define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_ninf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_ninf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0xFFF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %select = select i1 %cond, float %x, float 0xFFF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+; Simplify to fabs %x
+define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives__fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+; Fold to fabs(%x), preserving a possible nan's payload bits
+define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives__fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives_nan__fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives_nan__fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+; Can fold to poison
+define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_no_positives_nan__fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_no_positives_nan__fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FABS]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  ret float %fabs
+}
+
+; Simplify to fneg %x
+define nofpclass(inf) float @ret_nofpclass_inf__fneg_select_ninf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fneg_select_ninf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0xFFF0000000000000
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[SELECT]]
+; CHECK-NEXT:    ret float [[FNEG]]
+;
+  %select = select i1 %cond, float %x, float 0xFFF0000000000000
+  %fneg = fneg float %select
+  ret float %fneg
+}
+
+; Simplify to fneg %x
+define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___fneg_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_nonegatives_noinf___fneg_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[SELECT]]
+; CHECK-NEXT:    ret float [[FNEG]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fneg = fneg float %select
+  ret float %fneg
+}
+
+; Simplify to fneg %x
+define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___fneg_select_ninf_lhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_nonegatives_noinf___fneg_select_ninf_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float 0xFFF0000000000000, float [[X]]
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[SELECT]]
+; CHECK-NEXT:    ret float [[FNEG]]
+;
+  %select = select i1 %cond, float 0xFFF0000000000000, float %x
+  %fneg = fneg float %select
+  ret float %fneg
+}
+
+define nofpclass(pzero psub pnorm pinf) float @ret_nofpclass_nopositives___fneg_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives___fneg_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[SELECT]]
+; CHECK-NEXT:    ret float [[FNEG]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fneg = fneg float %select
+  ret float %fneg
+}
+
+; Fold to fneg fabs
+define nofpclass(inf) float @ret_nofpclass_inf__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fneg_fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[FABS]]
+; CHECK-NEXT:    ret float [[FNEG]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  %fneg = fneg float %fabs
+  ret float %fneg
+}
+
+; Fold to fneg fabs, may need to preserve a nan payload
+define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives__fneg_fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[FABS]]
+; CHECK-NEXT:    ret float [[FNEG]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  %fneg = fneg float %fabs
+  ret float %fneg
+}
+
+
+; Fold to poison
+define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_nonan__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_nonan__fneg_fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[FABS]]
+; CHECK-NEXT:    ret float [[FNEG]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs = call float @llvm.fabs.f32(float %select)
+  %fneg = fneg float %fabs
+  ret float %fneg
+}
+
+; should fold to ret copysign(%x)
+define nofpclass(inf) float @ret_nofpclass_inf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_unknown_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
+  ret float %copysign
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__copysign_positive_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_positive_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float 1.0)
+  ret float %copysign
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = fneg float [[TMP1]]
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float -1.0)
+  ret float %copysign
+}
+
+; can fold to fneg(fabs(x))
+define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign(float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign
+; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
+  ret float %copysign
+}
+
+; can fold to fneg(fabs(x))
+define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives_copysign_nnan_flag(float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives_copysign_nnan_flag
+; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
+  ret float %copysign
+}
+
+; can fold to fneg(fabs(x))
+define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_nopositives_nonan_copysign(float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_nopositives_nonan_copysign
+; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
+  ret float %copysign
+}
+
+; can fold to fabs(x)
+define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign(float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign
+; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
+  ret float %copysign
+}
+
+; can fold to fabs(x)
+define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_copysign_nnan_flag(float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_copysign_nnan_flag
+; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call nnan float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %copysign = call nnan float @llvm.copysign.f32(float %x, float %unknown.sign)
+  ret float %copysign
+}
+
+; can fold to fabs(x)
+define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_nonan_copysign(float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives_nonan_copysign
+; CHECK-SAME: (float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[X]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %copysign = call float @llvm.copysign.f32(float %x, float %unknown.sign)
+  ret float %copysign
+}
+
+define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives__copysign_fabs_select_pinf_rhs(i1 %cond, float %x, float %sign) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives__copysign_fabs_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fabs.sign = call float @llvm.fabs.f32(float %sign)
+  %copysign = call float @llvm.copysign.f32(float %select, float %fabs.sign)
+  ret float %copysign
+}
+
+; Can fold to copysign %x
+define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_no_negatives_noinf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_no_negatives_noinf__copysign_unknown_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
+  ret float %copysign
+}
+
+; Can fold to copysign %x
+define nofpclass(inf pnorm psub pzero) float @ret_nofpclass_no_positives_noinf__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_nofpclass_no_positives_noinf__copysign_unknown_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
+  ret float %copysign
+}
+
+; Can't fold because it could have nan payload bits
+define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
+  ret float %copysign
+}
+
+; Can't fold because it could be nan
+define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
+  ret float %copysign
+}
+
+; Could fold to copysign with constant
+define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives_nonan__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives_nonan__copysign_unknown_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
+  ret float %copysign
+}
+
+; Could fold to copysign %x with constant
+define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_no_positives_nonan__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
+; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_no_positives_nonan__copysign_unknown_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float [[SELECT]], float [[UNKNOWN_SIGN]])
+; CHECK-NEXT:    ret float [[COPYSIGN]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %copysign = call float @llvm.copysign.f32(float %select, float %unknown.sign)
+  ret float %copysign
+}
+
+; Do nothing
+define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_negatives__select_clamp_neg_to_zero(float %x) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_negatives__select_clamp_neg_to_zero
+; CHECK-SAME: (float [[X:%.*]]) {
+; CHECK-NEXT:    [[IS_LT_ZERO:%.*]] = fcmp olt float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[IS_LT_ZERO]], float 0.000000e+00, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %is.lt.zero = fcmp olt float %x, 0.0
+  %select = select i1 %is.lt.zero, float 0.0, float %x
+  ret float %select
+}
+
+; Can fold to ret %x, assumed to be nan
+define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_negatives__select_clamp_pos_to_zero(float %x) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_negatives__select_clamp_pos_to_zero
+; CHECK-SAME: (float [[X:%.*]]) {
+; CHECK-NEXT:    [[IS_GT_ZERO:%.*]] = fcmp ogt float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[IS_GT_ZERO]], float 0.000000e+00, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %is.gt.zero = fcmp ogt float %x, 0.0
+  %select = select i1 %is.gt.zero, float 0.0, float %x
+  ret float %select
+}
+
+; Can fold to ret +0
+define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nan_negatives__select_clamp_pos_to_zero(float %x) {
+; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_nan_negatives__select_clamp_pos_to_zero
+; CHECK-SAME: (float [[X:%.*]]) {
+; CHECK-NEXT:    [[IS_GT_ZERO:%.*]] = fcmp ogt float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[IS_GT_ZERO]], float 0.000000e+00, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %is.gt.zero = fcmp ogt float %x, 0.0
+  %select = select i1 %is.gt.zero, float 0.0, float %x
+  ret float %select
+}
+
+; Can fold to ret poison
+define nofpclass(nan ninf nnorm nsub zero) float @ret_nofpclass_nan_negatives_zero__select_clamp_pos_to_zero(float %x) {
+; CHECK-LABEL: define nofpclass(nan ninf zero nsub nnorm) float @ret_nofpclass_nan_negatives_zero__select_clamp_pos_to_zero
+; CHECK-SAME: (float [[X:%.*]]) {
+; CHECK-NEXT:    [[IS_GT_ZERO:%.*]] = fcmp ogt float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[IS_GT_ZERO]], float 0.000000e+00, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %is.gt.zero = fcmp ogt float %x, 0.0
+  %select = select i1 %is.gt.zero, float 0.0, float %x
+  ret float %select
+}
+
+; Can fold to ret %x, assumed to be nan
+define nofpclass(ninf nnorm nsub zero) float @ret_nofpclass_negatives_zero__select_clamp_pos_to_zero(float %x) {
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_nofpclass_negatives_zero__select_clamp_pos_to_zero
+; CHECK-SAME: (float [[X:%.*]]) {
+; CHECK-NEXT:    [[IS_GT_ZERO:%.*]] = fcmp ogt float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[IS_GT_ZERO]], float 0.000000e+00, float [[X]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %is.gt.zero = fcmp ogt float %x, 0.0
+  %select = select i1 %is.gt.zero, float 0.0, float %x
+  ret float %select
+}
+
+; Assume should allow folding ret %y
+define nofpclass(inf) float @ret_nofpclass_noinfs__assumed_isinf__select_pinf_lhs(i1 %cond, float %x, float %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_noinfs__assumed_isinf__select_pinf_lhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[FABS_X:%.*]] = call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[X_IS_INF:%.*]] = fcmp oeq float [[FABS_X]], 0x7FF0000000000000
+; CHECK-NEXT:    call void @llvm.assume(i1 [[X_IS_INF]])
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float [[Y]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %fabs.x = call float @llvm.fabs.f32(float %x)
+  %x.is.inf = fcmp oeq float %fabs.x, 0x7FF0000000000000
+  call void @llvm.assume(i1 %x.is.inf)
+  %select = select i1 %cond, float %x, float %y
+  ret float %select
+}
+
+; Ideally should be able to fold out everything after the exp2 call.
+define nofpclass(nan inf nzero nsub nnorm) float @powr_issue64870(float nofpclass(nan inf) %x, float nofpclass(nan inf) %y) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @powr_issue64870
+; CHECK-SAME: (float nofpclass(nan inf) [[X:%.*]], float nofpclass(nan inf) [[Y:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[I:%.*]] = tail call float @llvm.fabs.f32(float [[X]])
+; CHECK-NEXT:    [[I1:%.*]] = tail call float @llvm.log2.f32(float [[I]])
+; CHECK-NEXT:    [[I2:%.*]] = fmul float [[I1]], [[Y]]
+; CHECK-NEXT:    [[I3:%.*]] = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float [[I2]])
+; CHECK-NEXT:    [[I4:%.*]] = fcmp olt float [[Y]], 0.000000e+00
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], float 0x7FF0000000000000, float 0.000000e+00
+; CHECK-NEXT:    [[I6:%.*]] = fcmp oeq float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[I7:%.*]] = select i1 [[I6]], float [[I5]], float [[I3]]
+; CHECK-NEXT:    [[I8:%.*]] = fcmp oeq float [[Y]], 0.000000e+00
+; CHECK-NEXT:    [[I9:%.*]] = select i1 [[I6]], float 0x7FF8000000000000, float 1.000000e+00
+; CHECK-NEXT:    [[I10:%.*]] = select i1 [[I8]], float [[I9]], float [[I7]]
+; CHECK-NEXT:    [[I11:%.*]] = fcmp oeq float [[X]], 1.000000e+00
+; CHECK-NEXT:    [[I12:%.*]] = select i1 [[I11]], float 1.000000e+00, float [[I10]]
+; CHECK-NEXT:    [[I13:%.*]] = fcmp olt float [[X]], 0.000000e+00
+; CHECK-NEXT:    [[I14:%.*]] = select i1 [[I13]], float 0x7FF8000000000000, float [[I12]]
+; CHECK-NEXT:    ret float [[I14]]
+;
+entry:
+  %i = tail call float @llvm.fabs.f32(float %x)
+  %i1 = tail call float @llvm.log2.f32(float %i)
+  %i2 = fmul float %i1, %y
+  %i3 = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float %i2)
+  %i4 = fcmp olt float %y, 0.000000e+00
+  %i5 = select i1 %i4, float 0x7FF0000000000000, float 0.000000e+00
+  %i6 = fcmp oeq float %x, 0.000000e+00
+  %i7 = select i1 %i6, float %i5, float %i3
+  %i8 = fcmp oeq float %y, 0.000000e+00
+  %i9 = select i1 %i6, float 0x7FF8000000000000, float 1.000000e+00
+  %i10 = select i1 %i8, float %i9, float %i7
+  %i11 = fcmp oeq float %x, 1.000000e+00
+  %i12 = select i1 %i11, float 1.000000e+00, float %i10
+  %i13 = fcmp olt float %x, 0.000000e+00
+  %i14 = select i1 %i13, float 0x7FF8000000000000, float %i12
+  ret float %i14
+}
+
+; Different implementation of powr
+define nofpclass(nan inf nzero nsub nnorm) float @test_powr_issue64870_2(float nofpclass(nan inf) %arg, float nofpclass(nan inf) %arg1) #0 {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @test_powr_issue64870_2
+; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) {
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    [[I:%.*]] = fcmp olt float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I]], float 0x7FF8000000000000, float [[ARG]]
+; CHECK-NEXT:    [[I3:%.*]] = tail call float @llvm.log2.f32(float noundef [[I2]])
+; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I]], float 0x7FF8000000000000, float [[ARG1]]
+; CHECK-NEXT:    [[I5:%.*]] = fmul float [[I4]], [[I3]]
+; CHECK-NEXT:    [[I6:%.*]] = tail call noundef nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float noundef [[I5]])
+; CHECK-NEXT:    [[I7:%.*]] = fcmp olt float [[I4]], 0.000000e+00
+; CHECK-NEXT:    [[I8:%.*]] = select i1 [[I7]], float 0x7FF0000000000000, float 0.000000e+00
+; CHECK-NEXT:    [[I9:%.*]] = fcmp ueq float [[I4]], 0.000000e+00
+; CHECK-NEXT:    [[I10:%.*]] = fcmp oeq float [[I2]], 0.000000e+00
+; CHECK-NEXT:    [[I11:%.*]] = select i1 [[I9]], float 0x7FF8000000000000, float [[I8]]
+; CHECK-NEXT:    [[I12:%.*]] = select i1 [[I10]], float [[I11]], float [[I6]]
+; CHECK-NEXT:    ret float [[I12]]
+;
+bb:
+  %i = fcmp olt float %arg, 0.000000e+00
+  %i2 = select i1 %i, float 0x7FF8000000000000, float %arg
+  %i3 = tail call float @llvm.log2.f32(float noundef %i2) #2
+  %i4 = select i1 %i, float 0x7FF8000000000000, float %arg1
+  %i5 = fmul float %i4, %i3
+  %i6 = tail call noundef nofpclass(ninf nzero nsub nnorm) float @llvm.exp2.f32(float noundef %i5)
+  %i7 = fcmp olt float %i4, 0.000000e+00
+  %i8 = select i1 %i7, float 0x7FF0000000000000, float 0.000000e+00
+  %i9 = fcmp ueq float %i4, 0.000000e+00
+  %i10 = fcmp oeq float %i2, 0.000000e+00
+  %i11 = select i1 %i9, float 0x7FF8000000000000, float %i8
+  %i12 = select i1 %i10, float %i11, float %i6
+  ret float %i12
+}
+
+; implementation of pow with some prunable cases
+define nofpclass(nan inf) float @pow_f32(float nofpclass(nan inf) %arg, float nofpclass(nan inf) %arg1) #0 {
+; CHECK-LABEL: define nofpclass(nan inf) float @pow_f32
+; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]], float nofpclass(nan inf) [[ARG1:%.*]]) {
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    [[I:%.*]] = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef [[ARG]])
+; CHECK-NEXT:    [[I2:%.*]] = tail call float @llvm.log2.f32(float noundef [[I]])
+; CHECK-NEXT:    [[I3:%.*]] = fmul float [[I2]], [[ARG1]]
+; CHECK-NEXT:    [[I4:%.*]] = tail call noundef float @llvm.exp2.f32(float noundef [[I3]])
+; CHECK-NEXT:    [[I5:%.*]] = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef [[ARG1]])
+; CHECK-NEXT:    [[I6:%.*]] = tail call float @llvm.trunc.f32(float noundef [[I5]])
+; CHECK-NEXT:    [[I7:%.*]] = fcmp oeq float [[I6]], [[I5]]
+; CHECK-NEXT:    [[I8:%.*]] = fmul float [[I5]], 5.000000e-01
+; CHECK-NEXT:    [[I9:%.*]] = tail call float @llvm.trunc.f32(float noundef [[I8]])
+; CHECK-NEXT:    [[I10:%.*]] = fcmp une float [[I9]], [[I8]]
+; CHECK-NEXT:    [[I11:%.*]] = and i1 [[I7]], [[I10]]
+; CHECK-NEXT:    [[I12:%.*]] = select i1 [[I11]], float [[ARG]], float 1.000000e+00
+; CHECK-NEXT:    [[I13:%.*]] = tail call noundef float @llvm.copysign.f32(float noundef [[I4]], float noundef [[I12]])
+; CHECK-NEXT:    [[I14:%.*]] = fcmp olt float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    [[I15:%.*]] = select i1 [[I7]], float [[I13]], float 0x7FF8000000000000
+; CHECK-NEXT:    [[I16:%.*]] = select i1 [[I14]], float [[I15]], float [[I13]]
+; CHECK-NEXT:    [[I17:%.*]] = fcmp oeq float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    [[I18:%.*]] = fcmp olt float [[ARG1]], 0.000000e+00
+; CHECK-NEXT:    [[I19:%.*]] = xor i1 [[I17]], [[I18]]
+; CHECK-NEXT:    [[I20:%.*]] = select i1 [[I19]], float 0.000000e+00, float 0x7FF0000000000000
+; CHECK-NEXT:    [[I21:%.*]] = select i1 [[I11]], float [[ARG]], float 0.000000e+00
+; CHECK-NEXT:    [[I22:%.*]] = tail call noundef nofpclass(nan sub norm) float @llvm.copysign.f32(float noundef [[I20]], float noundef [[I21]])
+; CHECK-NEXT:    [[I23:%.*]] = select i1 [[I17]], float [[I22]], float [[I16]]
+; CHECK-NEXT:    [[I24:%.*]] = fcmp oeq float [[ARG]], 1.000000e+00
+; CHECK-NEXT:    [[I25:%.*]] = fcmp oeq float [[ARG1]], 0.000000e+00
+; CHECK-NEXT:    [[I26:%.*]] = or i1 [[I24]], [[I25]]
+; CHECK-NEXT:    [[I27:%.*]] = select i1 [[I26]], float 1.000000e+00, float [[I23]]
+; CHECK-NEXT:    ret float [[I27]]
+;
+bb:
+  %i = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef %arg)
+  %i2 = tail call float @llvm.log2.f32(float noundef %i)
+  %i3 = fmul float %i2, %arg1
+  %i4 = tail call noundef float @llvm.exp2.f32(float noundef %i3)
+  %i5 = tail call nofpclass(ninf nzero nsub nnorm) float @llvm.fabs.f32(float noundef %arg1)
+  %i6 = tail call float @llvm.trunc.f32(float noundef %i5)
+  %i7 = fcmp oeq float %i6, %i5
+  %i8 = fmul float %i5, 5.000000e-01
+  %i9 = tail call float @llvm.trunc.f32(float noundef %i8)
+  %i10 = fcmp une float %i9, %i8
+  %i11 = and i1 %i7, %i10
+  %i12 = select i1 %i11, float %arg, float 1.000000e+00
+  %i13 = tail call noundef float @llvm.copysign.f32(float noundef %i4, float noundef %i12)
+  %i14 = fcmp olt float %arg, 0.000000e+00
+  %i15 = select i1 %i7, float %i13, float 0x7FF8000000000000
+  %i16 = select i1 %i14, float %i15, float %i13
+  %i17 = fcmp oeq float %arg, 0.000000e+00
+  %i18 = fcmp olt float %arg1, 0.000000e+00
+  %i19 = xor i1 %i17, %i18
+  %i20 = select i1 %i19, float 0.000000e+00, float 0x7FF0000000000000
+  %i21 = select i1 %i11, float %arg, float 0.000000e+00
+  %i22 = tail call noundef nofpclass(nan sub norm) float @llvm.copysign.f32(float noundef %i20, float noundef %i21)
+  %i23 = select i1 %i17, float %i22, float %i16
+  %i24 = fcmp oeq float %arg, 1.000000e+00
+  %i25 = fcmp oeq float %arg1, 0.000000e+00
+  %i26 = or i1 %i24, %i25
+  %i27 = select i1 %i26, float 1.000000e+00, float %i23
+  ret float %i27
+}
+
+declare float @extern()
+
+; Make sure nofpclass from arbitrary callsite is used, fold to %y
+define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_call_only_inf(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_nofpclass_call_only_inf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_INF:%.*]] = call nofpclass(nan zero sub norm) float @extern()
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_INF]], float [[Y]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %must.be.inf = call nofpclass(nan norm zero sub) float @extern()
+  %select = select i1 %cond, float %must.be.inf, float %y
+  ret float %select
+}
+
+define nofpclass(pinf) float @ret_nofpclass_pinf__nofpclass_call_only_inf(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__nofpclass_call_only_inf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_INF:%.*]] = call nofpclass(nan zero sub norm) float @extern()
+; CHECK-NEXT:    ret float [[MUST_BE_INF]]
+;
+  %must.be.inf = call nofpclass(nan norm zero sub) float @extern()
+  ret float %must.be.inf
+}
+
+define nofpclass(ninf) float @ret_nofpclass_ninf__nofpclass_call_only_inf(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__nofpclass_call_only_inf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_INF:%.*]] = call nofpclass(nan zero sub norm) float @extern()
+; CHECK-NEXT:    ret float [[MUST_BE_INF]]
+;
+  %must.be.inf = call nofpclass(nan norm zero sub) float @extern()
+  ret float %must.be.inf
+}
+
+define nofpclass(nzero) float @ret_nofpclass_nzero__nofpclass_call_only_zero(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(nzero) float @ret_nofpclass_nzero__nofpclass_call_only_zero
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_ZERO:%.*]] = call nofpclass(nan inf sub norm) float @extern()
+; CHECK-NEXT:    ret float [[MUST_BE_ZERO]]
+;
+  %must.be.zero = call nofpclass(nan sub norm inf) float @extern()
+  ret float %must.be.zero
+}
+
+define nofpclass(pzero) float @ret_nofpclass_pzero__nofpclass_call_only_zero(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(pzero) float @ret_nofpclass_pzero__nofpclass_call_only_zero
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_ZERO:%.*]] = call nofpclass(nan inf sub norm) float @extern()
+; CHECK-NEXT:    ret float [[MUST_BE_ZERO]]
+;
+  %must.be.zero = call nofpclass(nan sub norm inf) float @extern()
+  ret float %must.be.zero
+}
+
+; Should not fold this, should not assume payload/sign bits are canonical
+define nofpclass(qnan) float @ret_nofpclass_qnan__nofpclass_call_only_nan(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(qnan) float @ret_nofpclass_qnan__nofpclass_call_only_nan
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_NAN:%.*]] = call nofpclass(inf zero sub norm) float @extern()
+; CHECK-NEXT:    ret float [[MUST_BE_NAN]]
+;
+  %must.be.nan = call nofpclass(inf norm zero sub) float @extern()
+  ret float %must.be.nan
+}
+
+; Should not fold this, should not assume payload/sign bits are canonical
+define nofpclass(snan) float @ret_nofpclass_snan__nofpclass_call_only_nan(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(snan) float @ret_nofpclass_snan__nofpclass_call_only_nan
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_NAN:%.*]] = call nofpclass(inf zero sub norm) float @extern()
+; CHECK-NEXT:    ret float [[MUST_BE_NAN]]
+;
+  %must.be.nan = call nofpclass(inf norm zero sub) float @extern()
+  ret float %must.be.nan
+}
+
+; Assume call should allow folding this to %y
+; TODO: Not working, multiple user problem.
+define nofpclass(inf) float @ret_nofpclass_inf__select_assumed_call_result_only_inf(i1 %cond, float %y) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__select_assumed_call_result_only_inf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[Y:%.*]]) {
+; CHECK-NEXT:    [[MUST_BE_INF:%.*]] = call float @extern()
+; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MUST_BE_INF]])
+; CHECK-NEXT:    [[IS_INF:%.*]] = fcmp oeq float [[FABS]], 0x7FF0000000000000
+; CHECK-NEXT:    call void @llvm.assume(i1 [[IS_INF]])
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[MUST_BE_INF]], float [[Y]]
+; CHECK-NEXT:    ret float [[SELECT]]
+;
+  %must.be.inf = call float @extern()
+  %fabs = call float @llvm.fabs.f32(float %must.be.inf)
+  %is.inf = fcmp oeq float %fabs, 0x7FF0000000000000
+  call void @llvm.assume(i1 %is.inf)
+  %select = select i1 %cond, float %must.be.inf, float %y
+  ret float %select
+}
+
+define nofpclass(inf) float @ret_nofpclass_inf__simple_phi_inf_or_unknown(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__simple_phi_inf_or_unknown
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND]], label [[BB0:%.*]], label [[RET:%.*]]
+; CHECK:       bb0:
+; CHECK-NEXT:    br label [[RET]]
+; CHECK:       ret:
+; CHECK-NEXT:    [[PHI:%.*]] = phi float [ 0x7FF0000000000000, [[ENTRY:%.*]] ], [ [[X]], [[BB0]] ]
+; CHECK-NEXT:    ret float [[PHI]]
+;
+entry:
+  br i1 %cond, label %bb0, label %ret
+
+bb0:
+  br label %ret
+
+ret:
+  %phi = phi float [ 0x7FF0000000000000, %entry ], [ %x, %bb0 ]
+  ret float %phi
+}
+
+declare i1 @loop.cond()
+
+declare float @loop.func()
+
+
+; Should be able to fold inf initial value to poison
+define nofpclass(inf) float @ret_nofpclass_inf__phi_0(i1 %cond0, float %unknown) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__phi_0
+; CHECK-SAME: (i1 [[COND0:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND0]], label [[LOOP:%.*]], label [[RET:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[PHI_LOOP:%.*]] = phi float [ 0x7FF0000000000000, [[ENTRY:%.*]] ], [ [[LOOP_FUNC:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[LOOP_FUNC]] = call nofpclass(nan) float @loop.func()
+; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @loop.cond()
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
+; CHECK:       ret:
+; CHECK-NEXT:    [[PHI_RET:%.*]] = phi float [ 0.000000e+00, [[ENTRY]] ], [ [[PHI_LOOP]], [[LOOP]] ]
+; CHECK-NEXT:    ret float [[PHI_RET]]
+;
+entry:
+  br i1 %cond0, label %loop, label %ret
+
+loop:
+  %phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ %loop.func, %loop ]
+  %loop.func = call nofpclass(nan) float @loop.func()
+  %loop.cond = call i1 @loop.cond()
+  br i1 %loop.cond, label %ret, label %loop
+
+ret:
+  %phi.ret = phi float [ 0.0, %entry ], [ %phi.loop, %loop ]
+  ret float %phi.ret
+}
+
+; fold to ret 0
+define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_0(i1 %cond0, float %unknown) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_0
+; CHECK-SAME: (i1 [[COND0:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND0]], label [[LOOP:%.*]], label [[RET:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @loop.cond()
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
+; CHECK:       ret:
+; CHECK-NEXT:    [[PHI_RET:%.*]] = phi float [ 0.000000e+00, [[ENTRY:%.*]] ], [ 0x7FF0000000000000, [[LOOP]] ]
+; CHECK-NEXT:    ret float [[PHI_RET]]
+;
+entry:
+  br i1 %cond0, label %loop, label %ret
+
+loop:
+  %phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ %phi.loop, %loop ]
+  %loop.cond = call i1 @loop.cond()
+  br i1 %loop.cond, label %ret, label %loop
+
+ret:
+  %phi.ret = phi float [ 0.0, %entry ], [ %phi.loop, %loop ]
+  ret float %phi.ret
+}
+
+; fold to ret poison
+define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_1(i1 %cond0, float %unknown) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__recursive_phi_1
+; CHECK-SAME: (i1 [[COND0:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[COND0]], label [[LOOP:%.*]], label [[RET:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @loop.cond()
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
+; CHECK:       ret:
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+entry:
+  br i1 %cond0, label %loop, label %ret
+
+loop:
+  %phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ %phi.loop, %loop ]
+  %loop.cond = call i1 @loop.cond()
+  br i1 %loop.cond, label %ret, label %loop
+
+ret:
+  %phi.ret = phi float [ 0x7FF0000000000000, %entry ], [ %phi.loop, %loop ]
+  ret float %phi.ret
+}
+
+; Should be able to fold inf initial values to poison
+define nofpclass(inf) float @ret_nofpclass_inf__phi_switch_repeated_predecessor(i32 %switch, float %unknown) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__phi_switch_repeated_predecessor
+; CHECK-SAME: (i32 [[SWITCH:%.*]], float [[UNKNOWN:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[SWITCH]], label [[RET:%.*]] [
+; CHECK-NEXT:    i32 0, label [[LOOP:%.*]]
+; CHECK-NEXT:    i32 1, label [[LOOP]]
+; CHECK-NEXT:    ]
+; CHECK:       loop:
+; CHECK-NEXT:    [[PHI_LOOP:%.*]] = phi float [ 0x7FF0000000000000, [[ENTRY:%.*]] ], [ 0x7FF0000000000000, [[ENTRY]] ], [ [[UNKNOWN]], [[LOOP]] ]
+; CHECK-NEXT:    [[LOOP_COND:%.*]] = call i1 @loop.cond()
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[RET]], label [[LOOP]]
+; CHECK:       ret:
+; CHECK-NEXT:    [[PHI_RET:%.*]] = phi float [ 0.000000e+00, [[ENTRY]] ], [ [[PHI_LOOP]], [[LOOP]] ]
+; CHECK-NEXT:    ret float [[PHI_RET]]
+;
+entry:
+  switch i32 %switch, label %ret [
+  i32 0, label %loop
+  i32 1, label %loop
+  ]
+
+loop:
+  %phi.loop = phi float [ 0x7FF0000000000000, %entry ], [ 0x7FF0000000000000, %entry ], [ %unknown, %loop ]
+  %loop.cond = call i1 @loop.cond()
+  br i1 %loop.cond, label %ret, label %loop
+
+ret:
+  %phi.ret = phi float [ 0.0, %entry ], [ %phi.loop, %loop ]
+  ret float %phi.ret
+}
+
+; Simplify to arithmetic.fence %x
+define nofpclass(inf) float @ret_nofpclass_inf__arithmetic_fence_select_pinf_rhs(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__arithmetic_fence_select_pinf_rhs
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
+; CHECK-NEXT:    [[FENCE:%.*]] = call float @llvm.arithmetic.fence.f32(float [[SELECT]])
+; CHECK-NEXT:    ret float [[FENCE]]
+;
+  %select = select i1 %cond, float %x, float 0x7FF0000000000000
+  %fence = call float @llvm.arithmetic.fence.f32(float %select)
+  ret float %fence
+}
+
+; Can simplify to %x
+define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_pinf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_pinf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[MIN:%.*]] = call float @llvm.minnum.f32(float [[X]], float 0x7FF0000000000000)
+; CHECK-NEXT:    ret float [[MIN]]
+;
+  %min = call float @llvm.minnum.f32(float %x, float 0x7FF0000000000000)
+  ret float %min
+}
+
+; Can fold to -inf
+define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_ninf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_ninf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    ret float 0xFFF0000000000000
+;
+  %min = call float @llvm.minnum.f32(float %x, float 0xFFF0000000000000)
+  ret float %min
+}
+
+; Can simplify to %x
+define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_ninf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_ninf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[X]], float 0xFFF0000000000000)
+; CHECK-NEXT:    ret float [[MAX]]
+;
+  %max = call float @llvm.maxnum.f32(float %x, float 0xFFF0000000000000)
+  ret float %max
+}
+
+; Can fold to +inf
+define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_pinf(i1 %cond, float %x) {
+; CHECK-LABEL: define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_pinf
+; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  %max = call float @llvm.maxnum.f32(float %x, float 0x7FF0000000000000)
+  ret float %max
+}


        


More information about the llvm-commits mailing list