[llvm] [llubi] Upstream existing floating-point intrinsics (PR #196034)
Zhige Chen via llvm-commits
llvm-commits at lists.llvm.org
Thu May 7 23:20:33 PDT 2026
https://github.com/nofe1248 updated https://github.com/llvm/llvm-project/pull/196034
>From 4a5053621b086687fa87a7834ff6169019d61881 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhige_chen at outlook.com>
Date: Wed, 6 May 2026 17:23:46 +0800
Subject: [PATCH 1/6] [llubi] Floating-point intrinsics
---
llvm/test/tools/llubi/intr_fp_fma.ll | 30 ++
llvm/test/tools/llubi/intr_fp_fptoi_sat.ll | 32 ++
llvm/test/tools/llubi/intr_fp_is_fpclass.ll | 35 ++
llvm/test/tools/llubi/intr_fp_minmax.ll | 122 +++++++
llvm/test/tools/llubi/intr_fp_unary.ll | 28 ++
.../test/tools/llubi/intr_fp_vector_reduce.ll | 78 +++++
llvm/tools/llubi/lib/Context.h | 3 +
llvm/tools/llubi/lib/Interpreter.cpp | 310 +++++++++++++++++-
llvm/tools/llubi/llubi.cpp | 6 +
9 files changed, 636 insertions(+), 8 deletions(-)
create mode 100644 llvm/test/tools/llubi/intr_fp_fma.ll
create mode 100644 llvm/test/tools/llubi/intr_fp_fptoi_sat.ll
create mode 100644 llvm/test/tools/llubi/intr_fp_is_fpclass.ll
create mode 100644 llvm/test/tools/llubi/intr_fp_minmax.ll
create mode 100644 llvm/test/tools/llubi/intr_fp_unary.ll
create mode 100644 llvm/test/tools/llubi/intr_fp_vector_reduce.ll
diff --git a/llvm/test/tools/llubi/intr_fp_fma.ll b/llvm/test/tools/llubi/intr_fp_fma.ll
new file mode 100644
index 0000000000000..cd52f1ac7d0d4
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_fp_fma.ll
@@ -0,0 +1,30 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %fma = call float @llvm.fma.f32(float 2.0, float 3.0, float 4.0)
+ %fma_poison_lhs = call float @llvm.fma.f32(float poison, float 3.0, float 4.0)
+ %fma_poison_rhs = call float @llvm.fma.f32(float 2.0, float poison, float 4.0)
+ %fma_poison_addend = call float @llvm.fma.f32(float 2.0, float 3.0, float poison)
+ %fma_vec = call <4 x float> @llvm.fma.v4f32(<4 x float> <float 2.0, float poison, float 2.0, float 2.0>, <4 x float> <float 3.0, float 3.0, float 5.0, float 3.0>, <4 x float> <float 4.0, float 4.0, float 7.0, float poison>)
+
+ %fmuladd = call float @llvm.fmuladd.f32(float 2.0, float 3.0, float 4.0)
+ %fmuladd_poison_lhs = call float @llvm.fmuladd.f32(float poison, float 3.0, float 4.0)
+ %fmuladd_poison_rhs = call float @llvm.fmuladd.f32(float 2.0, float poison, float 4.0)
+ %fmuladd_poison_addend = call float @llvm.fmuladd.f32(float 2.0, float 3.0, float poison)
+ %fmuladd_vec = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> <float 2.0, float poison, float 2.0, float 2.0>, <4 x float> <float 3.0, float 3.0, float 5.0, float 3.0>, <4 x float> <float 4.0, float 4.0, float 7.0, float poison>)
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %fma = call float @llvm.fma.f32(float 2.000000e+00, float 3.000000e+00, float 4.000000e+00) => float 1.000000e+01
+; CHECK-NEXT: %fma_poison_lhs = call float @llvm.fma.f32(float poison, float 3.000000e+00, float 4.000000e+00) => poison
+; CHECK-NEXT: %fma_poison_rhs = call float @llvm.fma.f32(float 2.000000e+00, float poison, float 4.000000e+00) => poison
+; CHECK-NEXT: %fma_poison_addend = call float @llvm.fma.f32(float 2.000000e+00, float 3.000000e+00, float poison) => poison
+; CHECK-NEXT: %fma_vec = call <4 x float> @llvm.fma.v4f32(<4 x float> <float 2.000000e+00, float poison, float 2.000000e+00, float 2.000000e+00>, <4 x float> <float 3.000000e+00, float 3.000000e+00, float 5.000000e+00, float 3.000000e+00>, <4 x float> <float 4.000000e+00, float 4.000000e+00, float 7.000000e+00, float poison>) => { float 1.000000e+01, poison, float 1.700000e+01, poison }
+; CHECK-NEXT: %fmuladd = call float @llvm.fmuladd.f32(float 2.000000e+00, float 3.000000e+00, float 4.000000e+00) => float 1.000000e+01
+; CHECK-NEXT: %fmuladd_poison_lhs = call float @llvm.fmuladd.f32(float poison, float 3.000000e+00, float 4.000000e+00) => poison
+; CHECK-NEXT: %fmuladd_poison_rhs = call float @llvm.fmuladd.f32(float 2.000000e+00, float poison, float 4.000000e+00) => poison
+; CHECK-NEXT: %fmuladd_poison_addend = call float @llvm.fmuladd.f32(float 2.000000e+00, float 3.000000e+00, float poison) => poison
+; CHECK-NEXT: %fmuladd_vec = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> <float 2.000000e+00, float poison, float 2.000000e+00, float 2.000000e+00>, <4 x float> <float 3.000000e+00, float 3.000000e+00, float 5.000000e+00, float 3.000000e+00>, <4 x float> <float 4.000000e+00, float 4.000000e+00, float 7.000000e+00, float poison>) => { float 1.000000e+01, poison, float 1.700000e+01, poison }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_fptoi_sat.ll b/llvm/test/tools/llubi/intr_fp_fptoi_sat.ll
new file mode 100644
index 0000000000000..fa93a5b1338d4
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_fp_fptoi_sat.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %spos = call i8 @llvm.fptosi.sat.i8.f32(float 127.75)
+ %sneg = call i8 @llvm.fptosi.sat.i8.f32(float -128.75)
+ %slarge = call i8 @llvm.fptosi.sat.i8.f32(float 1.0e+10)
+ %slarge_neg = call i8 @llvm.fptosi.sat.i8.f32(float -1.0e+10)
+ %spoison = call i8 @llvm.fptosi.sat.i8.f32(float poison)
+ %svec = call <4 x i8> @llvm.fptosi.sat.v4i8.v4f32(<4 x float> <float 1.25, float poison, float 1.0e+10, float -1.0e+10>)
+
+ %upos = call i8 @llvm.fptoui.sat.i8.f32(float 255.75)
+ %uneg = call i8 @llvm.fptoui.sat.i8.f32(float -1.25)
+ %ularge = call i8 @llvm.fptoui.sat.i8.f32(float 1.0e+10)
+ %upoison = call i8 @llvm.fptoui.sat.i8.f32(float poison)
+ %uvec = call <4 x i8> @llvm.fptoui.sat.v4i8.v4f32(<4 x float> <float 1.25, float poison, float 1.0e+10, float -1.25>)
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %spos = call i8 @llvm.fptosi.sat.i8.f32(float 1.277500e+02) => i8 127
+; CHECK-NEXT: %sneg = call i8 @llvm.fptosi.sat.i8.f32(float -1.287500e+02) => i8 -128
+; CHECK-NEXT: %slarge = call i8 @llvm.fptosi.sat.i8.f32(float 1.000000e+10) => i8 127
+; CHECK-NEXT: %slarge_neg = call i8 @llvm.fptosi.sat.i8.f32(float -1.000000e+10) => i8 -128
+; CHECK-NEXT: %spoison = call i8 @llvm.fptosi.sat.i8.f32(float poison) => poison
+; CHECK-NEXT: %svec = call <4 x i8> @llvm.fptosi.sat.v4i8.v4f32(<4 x float> <float 1.250000e+00, float poison, float 1.000000e+10, float -1.000000e+10>) => { i8 1, poison, i8 127, i8 -128 }
+; CHECK-NEXT: %upos = call i8 @llvm.fptoui.sat.i8.f32(float 2.557500e+02) => i8 -1
+; CHECK-NEXT: %uneg = call i8 @llvm.fptoui.sat.i8.f32(float -1.250000e+00) => i8 0
+; CHECK-NEXT: %ularge = call i8 @llvm.fptoui.sat.i8.f32(float 1.000000e+10) => i8 -1
+; CHECK-NEXT: %upoison = call i8 @llvm.fptoui.sat.i8.f32(float poison) => poison
+; CHECK-NEXT: %uvec = call <4 x i8> @llvm.fptoui.sat.v4i8.v4f32(<4 x float> <float 1.250000e+00, float poison, float 1.000000e+10, float -1.250000e+00>) => { i8 1, poison, i8 -1, i8 0 }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_is_fpclass.ll b/llvm/test/tools/llubi/intr_fp_is_fpclass.ll
new file mode 100644
index 0000000000000..c781fbeae281e
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_fp_is_fpclass.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %is_snan = call i1 @llvm.is.fpclass.f32(float 0x7FF0000020000000, i32 1)
+ %is_qnan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 2)
+ %is_nan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 3)
+ %is_neg_inf = call i1 @llvm.is.fpclass.f32(float 0xFFF0000000000000, i32 4)
+ %is_neg_normal = call i1 @llvm.is.fpclass.f32(float -1.0, i32 8)
+ %is_neg_subnormal = call i1 @llvm.is.fpclass.f32(float -1.434929627468612680625899e-42, i32 16)
+ %is_neg_zero = call i1 @llvm.is.fpclass.f32(float -0.0, i32 32)
+ %is_pos_zero = call i1 @llvm.is.fpclass.f32(float 0.0, i32 64)
+ %is_pos_subnormal = call i1 @llvm.is.fpclass.f32(float 1.434929627468612680625899e-42, i32 128)
+ %is_pos_normal = call i1 @llvm.is.fpclass.f32(float 1.0, i32 256)
+ %is_pos_inf = call i1 @llvm.is.fpclass.f32(float 0x7FF0000000000000, i32 512)
+ %is_poison = call i1 @llvm.is.fpclass.f32(float poison, i32 256)
+ %is_vec = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> <float 0x7FF8000020000000, float poison, float 1.0, float -0.0>, i32 291)
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %is_snan = call i1 @llvm.is.fpclass.f32(float 0x7FF0000020000000, i32 1) => T
+; CHECK-NEXT: %is_qnan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 2) => T
+; CHECK-NEXT: %is_nan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 3) => T
+; CHECK-NEXT: %is_neg_inf = call i1 @llvm.is.fpclass.f32(float 0xFFF0000000000000, i32 4) => T
+; CHECK-NEXT: %is_neg_normal = call i1 @llvm.is.fpclass.f32(float -1.000000e+00, i32 8) => T
+; CHECK-NEXT: %is_neg_subnormal = call i1 @llvm.is.fpclass.f32(float 0xB740000000000000, i32 16) => T
+; CHECK-NEXT: %is_neg_zero = call i1 @llvm.is.fpclass.f32(float -0.000000e+00, i32 32) => T
+; CHECK-NEXT: %is_pos_zero = call i1 @llvm.is.fpclass.f32(float 0.000000e+00, i32 64) => T
+; CHECK-NEXT: %is_pos_subnormal = call i1 @llvm.is.fpclass.f32(float 0x3740000000000000, i32 128) => T
+; CHECK-NEXT: %is_pos_normal = call i1 @llvm.is.fpclass.f32(float 1.000000e+00, i32 256) => T
+; CHECK-NEXT: %is_pos_inf = call i1 @llvm.is.fpclass.f32(float 0x7FF0000000000000, i32 512) => T
+; CHECK-NEXT: %is_poison = call i1 @llvm.is.fpclass.f32(float poison, i32 256) => poison
+; CHECK-NEXT: %is_vec = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> <float 0x7FF8000020000000, float poison, float 1.000000e+00, float -0.000000e+00>, i32 291) => { T, poison, T, T }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_minmax.ll b/llvm/test/tools/llubi/intr_fp_minmax.ll
new file mode 100644
index 0000000000000..7195c5bc5ca67
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_fp_minmax.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %maxnum = call float @llvm.maxnum.f32(float 1.0, float 2.0)
+ %maxnum_neg_zero = call float @llvm.maxnum.f32(float -0.0, float 0.0)
+ %maxnum_qnan_lhs = call float @llvm.maxnum.f32(float 0x7FF8000020000000, float 2.0)
+ %maxnum_qnan_rhs = call float @llvm.maxnum.f32(float 2.0, float 0x7FF8000020000000)
+ %maxnum_snan_lhs = call float @llvm.maxnum.f32(float 0x7FF0000020000000, float 2.0)
+ %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.0, float 0x7FF0000020000000)
+ %maxnum_poison_lhs = call float @llvm.maxnum.f32(float poison, float 2.0)
+ %maxnum_poison_rhs = call float @llvm.maxnum.f32(float 1.0, float poison)
+ %maxnum_vec = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+
+ %minnum = call float @llvm.minnum.f32(float 1.0, float 2.0)
+ %minnum_neg_zero = call float @llvm.minnum.f32(float -0.0, float 0.0)
+ %minnum_qnan_lhs = call float @llvm.minnum.f32(float 0x7FF8000020000000, float 2.0)
+ %minnum_qnan_rhs = call float @llvm.minnum.f32(float 2.0, float 0x7FF8000020000000)
+ %minnum_snan_lhs = call float @llvm.minnum.f32(float 0x7FF0000020000000, float 2.0)
+ %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.0, float 0x7FF0000020000000)
+ %minnum_poison_lhs = call float @llvm.minnum.f32(float poison, float 2.0)
+ %minnum_poison_rhs = call float @llvm.minnum.f32(float 1.0, float poison)
+ %minnum_vec = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+
+ %maximum = call float @llvm.maximum.f32(float 1.0, float 2.0)
+ %maximum_neg_zero = call float @llvm.maximum.f32(float -0.0, float 0.0)
+ %maximum_qnan_lhs = call float @llvm.maximum.f32(float 0x7FF8000020000000, float 2.0)
+ %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.0, float 0x7FF8000020000000)
+ %maximum_snan_lhs = call float @llvm.maximum.f32(float 0x7FF0000020000000, float 2.0)
+ %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.0, float 0x7FF0000020000000)
+ %maximum_poison_lhs = call float @llvm.maximum.f32(float poison, float 2.0)
+ %maximum_poison_rhs = call float @llvm.maximum.f32(float 1.0, float poison)
+ %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+
+ %minimum = call float @llvm.minimum.f32(float 1.0, float 2.0)
+ %minimum_neg_zero = call float @llvm.minimum.f32(float -0.0, float 0.0)
+ %minimum_qnan_lhs = call float @llvm.minimum.f32(float 0x7FF8000020000000, float 2.0)
+ %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.0, float 0x7FF8000020000000)
+ %minimum_snan_lhs = call float @llvm.minimum.f32(float 0x7FF0000020000000, float 2.0)
+ %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.0, float 0x7FF0000020000000)
+ %minimum_poison_lhs = call float @llvm.minimum.f32(float poison, float 2.0)
+ %minimum_poison_rhs = call float @llvm.minimum.f32(float 1.0, float poison)
+ %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+
+ %maximumnum = call float @llvm.maximumnum.f32(float 1.0, float 2.0)
+ %maximumnum_neg_zero = call float @llvm.maximumnum.f32(float -0.0, float 0.0)
+ %maximumnum_qnan_lhs = call float @llvm.maximumnum.f32(float 0x7FF8000020000000, float 2.0)
+ %maximumnum_qnan_rhs = call float @llvm.maximumnum.f32(float 2.0, float 0x7FF8000020000000)
+ %maximumnum_snan_lhs = call float @llvm.maximumnum.f32(float 0x7FF0000020000000, float 2.0)
+ %maximumnum_snan_rhs = call float @llvm.maximumnum.f32(float 2.0, float 0x7FF0000020000000)
+ %maximumnum_poison_lhs = call float @llvm.maximumnum.f32(float poison, float 2.0)
+ %maximumnum_poison_rhs = call float @llvm.maximumnum.f32(float 1.0, float poison)
+ %maximumnum_vec = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+
+ %minimumnum = call float @llvm.minimumnum.f32(float 1.0, float 2.0)
+ %minimumnum_neg_zero = call float @llvm.minimumnum.f32(float -0.0, float 0.0)
+ %minimumnum_qnan_lhs = call float @llvm.minimumnum.f32(float 0x7FF8000020000000, float 2.0)
+ %minimumnum_qnan_rhs = call float @llvm.minimumnum.f32(float 2.0, float 0x7FF8000020000000)
+ %minimumnum_snan_lhs = call float @llvm.minimumnum.f32(float 0x7FF0000020000000, float 2.0)
+ %minimumnum_snan_rhs = call float @llvm.minimumnum.f32(float 2.0, float 0x7FF0000020000000)
+ %minimumnum_poison_lhs = call float @llvm.minimumnum.f32(float poison, float 2.0)
+ %minimumnum_poison_rhs = call float @llvm.minimumnum.f32(float 1.0, float poison)
+ %minimumnum_vec = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %maxnum = call float @llvm.maxnum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maxnum_neg_zero = call float @llvm.maxnum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
+; CHECK-NEXT: %maxnum_qnan_lhs = call float @llvm.maxnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maxnum_qnan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
+; CHECK-NEXT: %maxnum_snan_lhs = call float @llvm.maxnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
+; CHECK-NEXT: %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0xFFC00000
+; CHECK-NEXT: %maxnum_poison_lhs = call float @llvm.maxnum.f32(float poison, float 2.000000e+00) => poison
+; CHECK-NEXT: %maxnum_poison_rhs = call float @llvm.maxnum.f32(float 1.000000e+00, float poison) => poison
+; CHECK-NEXT: %maxnum_vec = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: %minnum = call float @llvm.minnum.f32(float 1.000000e+00, float 2.000000e+00) => float 1.000000e+00
+; CHECK-NEXT: %minnum_neg_zero = call float @llvm.minnum.f32(float -0.000000e+00, float 0.000000e+00) => float -0.000000e+00
+; CHECK-NEXT: %minnum_qnan_lhs = call float @llvm.minnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %minnum_qnan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
+; CHECK-NEXT: %minnum_snan_lhs = call float @llvm.minnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
+; CHECK-NEXT: %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0xFFC00000
+; CHECK-NEXT: %minnum_poison_lhs = call float @llvm.minnum.f32(float poison, float 2.000000e+00) => poison
+; CHECK-NEXT: %minnum_poison_rhs = call float @llvm.minnum.f32(float 1.000000e+00, float poison) => poison
+; CHECK-NEXT: %minnum_vec = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: %maximum = call float @llvm.maximum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maximum_neg_zero = call float @llvm.maximum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
+; CHECK-NEXT: %maximum_qnan_lhs = call float @llvm.maximum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 0x7FC00001
+; CHECK-NEXT: %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 0xFFC00000
+; CHECK-NEXT: %maximum_snan_lhs = call float @llvm.maximum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
+; CHECK-NEXT: %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0x7F800001
+; CHECK-NEXT: %maximum_poison_lhs = call float @llvm.maximum.f32(float poison, float 2.000000e+00) => poison
+; CHECK-NEXT: %maximum_poison_rhs = call float @llvm.maximum.f32(float 1.000000e+00, float poison) => poison
+; CHECK-NEXT: %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 0xFFC00001, poison }
+; CHECK-NEXT: %minimum = call float @llvm.minimum.f32(float 1.000000e+00, float 2.000000e+00) => float 1.000000e+00
+; CHECK-NEXT: %minimum_neg_zero = call float @llvm.minimum.f32(float -0.000000e+00, float 0.000000e+00) => float -0.000000e+00
+; CHECK-NEXT: %minimum_qnan_lhs = call float @llvm.minimum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 0xFFC00000
+; CHECK-NEXT: %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 0xFFC00001
+; CHECK-NEXT: %minimum_snan_lhs = call float @llvm.minimum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
+; CHECK-NEXT: %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0x7FC00001
+; CHECK-NEXT: %minimum_poison_lhs = call float @llvm.minimum.f32(float poison, float 2.000000e+00) => poison
+; CHECK-NEXT: %minimum_poison_rhs = call float @llvm.minimum.f32(float 1.000000e+00, float poison) => poison
+; CHECK-NEXT: %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float NaN, poison }
+; CHECK-NEXT: %maximumnum = call float @llvm.maximumnum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_neg_zero = call float @llvm.maximumnum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
+; CHECK-NEXT: %maximumnum_qnan_lhs = call float @llvm.maximumnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_qnan_rhs = call float @llvm.maximumnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_snan_lhs = call float @llvm.maximumnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_snan_rhs = call float @llvm.maximumnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_poison_lhs = call float @llvm.maximumnum.f32(float poison, float 2.000000e+00) => poison
+; CHECK-NEXT: %maximumnum_poison_rhs = call float @llvm.maximumnum.f32(float 1.000000e+00, float poison) => poison
+; CHECK-NEXT: %maximumnum_vec = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: %minimumnum = call float @llvm.minimumnum.f32(float 1.000000e+00, float 2.000000e+00) => float 1.000000e+00
+; CHECK-NEXT: %minimumnum_neg_zero = call float @llvm.minimumnum.f32(float -0.000000e+00, float 0.000000e+00) => float -0.000000e+00
+; CHECK-NEXT: %minimumnum_qnan_lhs = call float @llvm.minimumnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_qnan_rhs = call float @llvm.minimumnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_snan_lhs = call float @llvm.minimumnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_snan_rhs = call float @llvm.minimumnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_poison_lhs = call float @llvm.minimumnum.f32(float poison, float 2.000000e+00) => poison
+; CHECK-NEXT: %minimumnum_poison_rhs = call float @llvm.minimumnum.f32(float 1.000000e+00, float poison) => poison
+; CHECK-NEXT: %minimumnum_vec = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_unary.ll b/llvm/test/tools/llubi/intr_fp_unary.ll
new file mode 100644
index 0000000000000..269664bf14c34
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_fp_unary.ll
@@ -0,0 +1,28 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %fabs = call float @llvm.fabs.f32(float -1.5)
+ %fabs_neg_zero = call float @llvm.fabs.f32(float -0.0)
+ %fabs_poison = call float @llvm.fabs.f32(float poison)
+ %fabs_vec = call <4 x float> @llvm.fabs.v4f32(<4 x float> <float -1.0, float poison, float 2.0, float -0.0>)
+
+ %copysign = call float @llvm.copysign.f32(float 1.0, float -2.0)
+ %copysign_neg_zero = call float @llvm.copysign.f32(float 1.0, float -0.0)
+ %copysign_poison_mag = call float @llvm.copysign.f32(float poison, float -2.0)
+ %copysign_poison_sign = call float @llvm.copysign.f32(float 1.0, float poison)
+ %copysign_vec = call <4 x float> @llvm.copysign.v4f32(<4 x float> <float 1.0, float poison, float 3.0, float -0.0>, <4 x float> <float -2.0, float -2.0, float 2.0, float 2.0>)
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %fabs = call float @llvm.fabs.f32(float -1.500000e+00) => float 1.500000e+00
+; CHECK-NEXT: %fabs_neg_zero = call float @llvm.fabs.f32(float -0.000000e+00) => float 0.000000e+00
+; CHECK-NEXT: %fabs_poison = call float @llvm.fabs.f32(float poison) => poison
+; CHECK-NEXT: %fabs_vec = call <4 x float> @llvm.fabs.v4f32(<4 x float> <float -1.000000e+00, float poison, float 2.000000e+00, float -0.000000e+00>) => { float 1.000000e+00, poison, float 2.000000e+00, float 0.000000e+00 }
+; CHECK-NEXT: %copysign = call float @llvm.copysign.f32(float 1.000000e+00, float -2.000000e+00) => float -1.000000e+00
+; CHECK-NEXT: %copysign_neg_zero = call float @llvm.copysign.f32(float 1.000000e+00, float -0.000000e+00) => float -1.000000e+00
+; CHECK-NEXT: %copysign_poison_mag = call float @llvm.copysign.f32(float poison, float -2.000000e+00) => poison
+; CHECK-NEXT: %copysign_poison_sign = call float @llvm.copysign.f32(float 1.000000e+00, float poison) => poison
+; CHECK-NEXT: %copysign_vec = call <4 x float> @llvm.copysign.v4f32(<4 x float> <float 1.000000e+00, float poison, float 3.000000e+00, float -0.000000e+00>, <4 x float> <float -2.000000e+00, float -2.000000e+00, float 2.000000e+00, float 2.000000e+00>) => { float -1.000000e+00, poison, float 3.000000e+00, float 0.000000e+00 }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_vector_reduce.ll b/llvm/test/tools/llubi/intr_fp_vector_reduce.ll
new file mode 100644
index 0000000000000..57050438c0e2b
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_fp_vector_reduce.ll
@@ -0,0 +1,78 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --vscale=4 --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %fadd = call float @llvm.vector.reduce.fadd.v4f32(float 1.0, <4 x float> <float 2.0, float 3.0, float 4.0, float 5.0>)
+ %fadd_poison_acc = call float @llvm.vector.reduce.fadd.v4f32(float poison, <4 x float> <float 2.0, float 3.0, float 4.0, float 5.0>)
+ %fadd_poison_vec = call float @llvm.vector.reduce.fadd.v4f32(float 1.0, <4 x float> <float 2.0, float poison, float 4.0, float 5.0>)
+
+ %fmul = call float @llvm.vector.reduce.fmul.v4f32(float 2.0, <4 x float> <float 2.0, float 3.0, float 4.0, float 5.0>)
+ %fmul_poison_acc = call float @llvm.vector.reduce.fmul.v4f32(float poison, <4 x float> <float 2.0, float 3.0, float 4.0, float 5.0>)
+ %fmul_poison_vec = call float @llvm.vector.reduce.fmul.v4f32(float 2.0, <4 x float> <float 2.0, float poison, float 4.0, float 5.0>)
+
+ %fmax = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.0, float 2.0, float 4.0, float 5.0>)
+ %fmax_poison = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.0, float poison, float 4.0, float 5.0>)
+
+ %fmin = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.0, float 2.0, float 4.0, float 5.0>)
+ %fmin_poison = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.0, float poison, float 4.0, float 5.0>)
+
+ %fmaximum = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.0, float 2.0, float 4.0, float 5.0>)
+ %fmaximum_poison = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.0, float poison, float 4.0, float 5.0>)
+
+ %fminimum = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> <float 1.0, float 2.0, float 4.0, float 5.0>)
+ %fminimum_poison = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> <float 1.0, float poison, float 4.0, float 5.0>)
+
+ %sv_poison = insertelement <vscale x 4 x float> splat (float 2.0), float poison, i64 1
+ %sv_fadd = call float @llvm.vector.reduce.fadd.nxv4f32(float 1.0, <vscale x 4 x float> splat (float 2.0))
+ %sv_fadd_poison_acc = call float @llvm.vector.reduce.fadd.nxv4f32(float poison, <vscale x 4 x float> splat (float 2.0))
+ %sv_fadd_poison_vec = call float @llvm.vector.reduce.fadd.nxv4f32(float 1.0, <vscale x 4 x float> %sv_poison)
+
+ %sv_fmul = call float @llvm.vector.reduce.fmul.nxv4f32(float 2.0, <vscale x 4 x float> splat (float 2.0))
+ %sv_fmul_poison_acc = call float @llvm.vector.reduce.fmul.nxv4f32(float poison, <vscale x 4 x float> splat (float 2.0))
+ %sv_fmul_poison_vec = call float @llvm.vector.reduce.fmul.nxv4f32(float 2.0, <vscale x 4 x float> %sv_poison)
+
+ %sv_fmax = call float @llvm.vector.reduce.fmax.nxv4f32(<vscale x 4 x float> splat (float 2.0))
+ %sv_fmax_poison = call float @llvm.vector.reduce.fmax.nxv4f32(<vscale x 4 x float> %sv_poison)
+
+ %sv_fmin = call float @llvm.vector.reduce.fmin.nxv4f32(<vscale x 4 x float> splat (float 2.0))
+ %sv_fmin_poison = call float @llvm.vector.reduce.fmin.nxv4f32(<vscale x 4 x float> %sv_poison)
+
+ %sv_fmaximum = call float @llvm.vector.reduce.fmaximum.nxv4f32(<vscale x 4 x float> splat (float 2.0))
+ %sv_fmaximum_poison = call float @llvm.vector.reduce.fmaximum.nxv4f32(<vscale x 4 x float> %sv_poison)
+
+ %sv_fminimum = call float @llvm.vector.reduce.fminimum.nxv4f32(<vscale x 4 x float> splat (float 2.0))
+ %sv_fminimum_poison = call float @llvm.vector.reduce.fminimum.nxv4f32(<vscale x 4 x float> %sv_poison)
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %fadd = call float @llvm.vector.reduce.fadd.v4f32(float 1.000000e+00, <4 x float> <float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 1.500000e+01
+; CHECK-NEXT: %fadd_poison_acc = call float @llvm.vector.reduce.fadd.v4f32(float poison, <4 x float> <float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fadd_poison_vec = call float @llvm.vector.reduce.fadd.v4f32(float 1.000000e+00, <4 x float> <float 2.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fmul = call float @llvm.vector.reduce.fmul.v4f32(float 2.000000e+00, <4 x float> <float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 2.400000e+02
+; CHECK-NEXT: %fmul_poison_acc = call float @llvm.vector.reduce.fmul.v4f32(float poison, <4 x float> <float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fmul_poison_vec = call float @llvm.vector.reduce.fmul.v4f32(float 2.000000e+00, <4 x float> <float 2.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fmax = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 5.000000e+00
+; CHECK-NEXT: %fmax_poison = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fmin = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 1.000000e+00
+; CHECK-NEXT: %fmin_poison = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fmaximum = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 5.000000e+00
+; CHECK-NEXT: %fmaximum_poison = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fminimum = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 1.000000e+00
+; CHECK-NEXT: %fminimum_poison = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %sv_poison = insertelement <vscale x 4 x float> splat (float 2.000000e+00), float poison, i64 1 => { float 2.000000e+00, poison, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float 2.000000e+00 }
+; CHECK-NEXT: %sv_fadd = call float @llvm.vector.reduce.fadd.nxv4f32(float 1.000000e+00, <vscale x 4 x float> splat (float 2.000000e+00)) => float 3.300000e+01
+; CHECK-NEXT: %sv_fadd_poison_acc = call float @llvm.vector.reduce.fadd.nxv4f32(float poison, <vscale x 4 x float> splat (float 2.000000e+00)) => poison
+; CHECK-NEXT: %sv_fadd_poison_vec = call float @llvm.vector.reduce.fadd.nxv4f32(float 1.000000e+00, <vscale x 4 x float> %sv_poison) => poison
+; CHECK-NEXT: %sv_fmul = call float @llvm.vector.reduce.fmul.nxv4f32(float 2.000000e+00, <vscale x 4 x float> splat (float 2.000000e+00)) => float 1.310720e+05
+; CHECK-NEXT: %sv_fmul_poison_acc = call float @llvm.vector.reduce.fmul.nxv4f32(float poison, <vscale x 4 x float> splat (float 2.000000e+00)) => poison
+; CHECK-NEXT: %sv_fmul_poison_vec = call float @llvm.vector.reduce.fmul.nxv4f32(float 2.000000e+00, <vscale x 4 x float> %sv_poison) => poison
+; CHECK-NEXT: %sv_fmax = call float @llvm.vector.reduce.fmax.nxv4f32(<vscale x 4 x float> splat (float 2.000000e+00)) => float 2.000000e+00
+; CHECK-NEXT: %sv_fmax_poison = call float @llvm.vector.reduce.fmax.nxv4f32(<vscale x 4 x float> %sv_poison) => poison
+; CHECK-NEXT: %sv_fmin = call float @llvm.vector.reduce.fmin.nxv4f32(<vscale x 4 x float> splat (float 2.000000e+00)) => float 2.000000e+00
+; CHECK-NEXT: %sv_fmin_poison = call float @llvm.vector.reduce.fmin.nxv4f32(<vscale x 4 x float> %sv_poison) => poison
+; CHECK-NEXT: %sv_fmaximum = call float @llvm.vector.reduce.fmaximum.nxv4f32(<vscale x 4 x float> splat (float 2.000000e+00)) => float 2.000000e+00
+; CHECK-NEXT: %sv_fmaximum_poison = call float @llvm.vector.reduce.fmaximum.nxv4f32(<vscale x 4 x float> %sv_poison) => poison
+; CHECK-NEXT: %sv_fminimum = call float @llvm.vector.reduce.fminimum.nxv4f32(<vscale x 4 x float> splat (float 2.000000e+00)) => float 2.000000e+00
+; CHECK-NEXT: %sv_fminimum_poison = call float @llvm.vector.reduce.fminimum.nxv4f32(<vscale x 4 x float> %sv_poison) => poison
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index 177778aa1f691..af5849caeb8d6 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -208,6 +208,7 @@ class Context {
bool Deterministic = false;
UndefValueBehavior UndefBehavior = UndefValueBehavior::NonDeterministic;
NaNPropagationBehavior NaNBehavior = NaNPropagationBehavior::NonDeterministic;
+ bool fusedMultiplyAdd = false;
std::mt19937_64 Rng;
@@ -260,6 +261,7 @@ class Context {
void setVScale(uint32_t VS) { VScale = VS; }
void setMaxSteps(uint32_t MS) { MaxSteps = MS; }
void setMaxStackDepth(uint32_t Depth) { MaxStackDepth = Depth; }
+ void setFusedMultiplyAdd(bool F) { fusedMultiplyAdd = F; }
uint64_t getMemoryLimit() const { return MaxMem; }
uint32_t getVScale() const { return VScale; }
uint32_t getMaxSteps() const { return MaxSteps; }
@@ -269,6 +271,7 @@ class Context {
bool mayUseNonDeterminism() const { return !Deterministic; }
UndefValueBehavior getEffectiveUndefValueBehavior() const;
NaNPropagationBehavior getEffectiveNaNPropagationBehavior() const;
+ bool fuseMultiplyAdd() const { return fusedMultiplyAdd; }
void setUndefValueBehavior(UndefValueBehavior UB) { UndefBehavior = UB; }
void setNaNPropagationBehavior(NaNPropagationBehavior NaNBehav) {
NaNBehavior = NaNBehav;
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 212e1626c1b91..acde46b5b3c01 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -165,7 +165,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
APFloat handleDenormal(APFloat Val, DenormalMode::DenormalModeKind Mode,
- bool IsInput = false) {
+ bool IsInput) {
if (!Val.isDenormal())
return Val;
if (IsInput) {
@@ -394,6 +394,31 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
});
}
+ AnyValue
+ visitFPUnOpWithResult(Type *RetTy, const FastMathFlags &FMF,
+ const AnyValue &Operand,
+ function_ref<APFloat(const APFloat &)> ScalarFn) {
+ return computeUnOp(
+ RetTy, Operand, [&](const AnyValue &OperandInner) -> AnyValue {
+ if (OperandInner.isPoison())
+ return AnyValue::poison();
+
+ // We don't flush denormals here since the only
+ // floating-point unary operation is fneg. And fneg is
+ // specified as a bitwise operation which only flips
+ // the sign bit of the input.
+
+ AnyValue ValidatedOperand =
+ handleFMFFlags(OperandInner, FMF, /*IsInput=*/true);
+ if (ValidatedOperand.isPoison())
+ return ValidatedOperand;
+
+ APFloat Result = ScalarFn(ValidatedOperand.asFloat());
+
+ return handleFMFFlags(Result, FMF, /*IsInput=*/false);
+ });
+ }
+
AnyValue computeBinOp(
Type *Ty, const AnyValue &LHS, const AnyValue &RHS,
function_ref<AnyValue(const AnyValue &, const AnyValue &)> ScalarFn) {
@@ -448,14 +473,16 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
return ValidatedRHS;
// Flush input denormals
- APFloat FLHS = handleDenormal(ValidatedLHS.asFloat(), DenormMode.Input);
- APFloat FRHS = handleDenormal(ValidatedRHS.asFloat(), DenormMode.Input);
+ APFloat FLHS = handleDenormal(ValidatedLHS.asFloat(), DenormMode.Input,
+ /*IsInput=*/true);
+ APFloat FRHS = handleDenormal(ValidatedRHS.asFloat(), DenormMode.Input,
+ /*IsInput=*/true);
APFloat RawResult = ScalarFn(FLHS, FRHS);
// Flush output denormals and handle fast-math flags.
AnyValue FResult = handleFMFFlags(
- handleDenormal(RawResult, DenormMode.Output, /*IsInput=*/true), FMF,
+ handleDenormal(RawResult, DenormMode.Output, /*IsInput=*/false), FMF,
/*IsInput=*/false);
if (FResult.isPoison())
@@ -510,6 +537,53 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
AnyValue(std::move(OverflowVec))};
}
+ AnyValue visitFPBinOpWithResult(
+ Type *RetTy, const FastMathFlags &FMF, const AnyValue &LHS,
+ const AnyValue &RHS,
+ function_ref<APFloat(const APFloat &, const APFloat &)> ScalarFn) {
+ DenormalMode DenormMode = getCurrentDenormalMode(RetTy);
+
+ if (!Ctx.isDefaultFPEnv())
+ reportImmediateUB() << "Non-constrained floating-point operation assumes "
+ "default floating-point environment";
+
+ return computeBinOp(
+ RetTy, LHS, RHS,
+ [&](const AnyValue &LHSInner, const AnyValue &RHSInner) -> AnyValue {
+ if (LHSInner.isPoison() || RHSInner.isPoison())
+ return AnyValue::poison();
+
+ AnyValue ValidatedLHS =
+ handleFMFFlags(LHSInner, FMF, /*IsInput=*/true);
+ AnyValue ValidatedRHS =
+ handleFMFFlags(RHSInner, FMF, /*IsInput=*/true);
+ if (ValidatedLHS.isPoison())
+ return ValidatedLHS;
+ if (ValidatedRHS.isPoison())
+ return ValidatedRHS;
+
+ // Flush input denormals
+ APFloat FLHS = handleDenormal(ValidatedLHS.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
+ APFloat FRHS = handleDenormal(ValidatedRHS.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
+
+ APFloat RawResult = ScalarFn(FLHS, FRHS);
+
+ // Flush output denormals and handle fast-math flags.
+ AnyValue FResult = handleFMFFlags(
+ handleDenormal(RawResult, DenormMode.Output, /*IsInput=*/false),
+ FMF,
+ /*IsInput=*/false);
+
+ if (FResult.isPoison())
+ return FResult;
+
+ APFloat Result = FResult.asFloat();
+ return applyNaNPropagation(Result, {&FLHS, &FRHS});
+ });
+ }
+
AnyValue
computeTriOp(Type *Ty, const AnyValue &Op1, const AnyValue &Op2,
const AnyValue &Op3,
@@ -569,6 +643,61 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
});
}
+ AnyValue visitFPTriOpWithResult(
+ Type *RetTy, const FastMathFlags &FMF, const AnyValue &Op1,
+ const AnyValue &Op2, const AnyValue &Op3,
+ function_ref<APFloat(const APFloat &, const APFloat &, const APFloat &)>
+ ScalarFn) {
+ DenormalMode DenormMode = getCurrentDenormalMode(RetTy);
+
+ if (!Ctx.isDefaultFPEnv())
+ reportImmediateUB() << "Non-constrained floating-point operation assumes "
+ "default floating-point environment";
+
+ return computeTriOp(
+ RetTy, Op1, Op2, Op3,
+ [&](const AnyValue &Op1Inner, const AnyValue &Op2Inner,
+ const AnyValue &Op3Inner) -> AnyValue {
+ if (Op1Inner.isPoison() || Op2Inner.isPoison() || Op3Inner.isPoison())
+ return AnyValue::poison();
+
+ AnyValue ValidatedOp1 =
+ handleFMFFlags(Op1Inner, FMF, /*IsInput=*/true);
+ AnyValue ValidatedOp2 =
+ handleFMFFlags(Op2Inner, FMF, /*IsInput=*/true);
+ AnyValue ValidatedOp3 =
+ handleFMFFlags(Op3Inner, FMF, /*IsInput=*/true);
+ if (ValidatedOp1.isPoison())
+ return ValidatedOp1;
+ if (ValidatedOp2.isPoison())
+ return ValidatedOp2;
+ if (ValidatedOp3.isPoison())
+ return ValidatedOp3;
+
+ // Flush input denormals
+ APFloat FOp1 = handleDenormal(ValidatedOp1.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
+ APFloat FOp2 = handleDenormal(ValidatedOp2.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
+ APFloat FOp3 = handleDenormal(ValidatedOp3.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
+
+ APFloat RawResult = ScalarFn(FOp1, FOp2, FOp3);
+
+ // Flush output denormals and handle fast-math flags.
+ AnyValue FResult = handleFMFFlags(
+ handleDenormal(RawResult, DenormMode.Output, /*IsInput=*/false),
+ FMF,
+ /*IsInput=*/false);
+
+ if (FResult.isPoison())
+ return FResult;
+
+ APFloat Result = FResult.asFloat();
+ return applyNaNPropagation(Result, {&FOp1, &FOp2, &FOp3});
+ });
+ }
+
void jumpTo(Instruction &Terminator, BasicBlock *DestBB) {
if (!Handler.onBBJump(Terminator, *DestBB)) {
setFailed();
@@ -696,6 +825,14 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
I.getOperand(0)->getType()->getScalarType()->getFltSemantics());
}
+ DenormalMode getCurrentDenormalMode(Type *Ty) {
+ if (Ty->isFPOrFPVectorTy()) {
+ return CurrentFrame->Func.getDenormalMode(
+ Ty->getScalarType()->getFltSemantics());
+ }
+ return DenormalMode::getDefault();
+ }
+
// Helper function to convert BooleanKind to bool. Report an immediate UB if
// a poison is found.
bool getBooleanNonPoison(BooleanKind Boolean) {
@@ -816,6 +953,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
AnyValue callIntrinsic(CallBase &CB, ArrayRef<AnyValue> Args) {
Intrinsic::ID IID = CB.getIntrinsicID();
Type *RetTy = CB.getType();
+ const FastMathFlags FMF =
+ isa<FPMathOperator>(CB) ? CB.getFastMathFlags() : FastMathFlags();
switch (IID) {
case Intrinsic::assume:
@@ -1304,6 +1443,159 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
return std::move(Res);
}
+ case Intrinsic::vector_reduce_fadd:
+ case Intrinsic::vector_reduce_fmul:
+ case Intrinsic::vector_reduce_fmax:
+ case Intrinsic::vector_reduce_fmin:
+ case Intrinsic::vector_reduce_fmaximum:
+ case Intrinsic::vector_reduce_fminimum: {
+ const auto DenormMode = getCurrentDenormalMode(RetTy);
+ const bool HasStart =
+ IID == Intrinsic::vector_reduce_fadd ||
+ IID == Intrinsic::vector_reduce_fmul;
+ const AnyValue &Vector = HasStart ? Args[1] : Args[0];
+ std::optional<APFloat> Res;
+ if (HasStart) {
+ if (Args[0].isPoison())
+ return AnyValue::poison();
+ const AnyValue ValidatedStart =
+ handleFMFFlags(Args[0], FMF, /*IsInput=*/true);
+ if (ValidatedStart.isPoison())
+ return AnyValue::poison();
+ Res = handleDenormal(ValidatedStart.asFloat(), DenormMode.Input,
+ /*IsInput=*/true);
+ }
+ for (const auto &V : Vector.asAggregate()) {
+ if (V.isPoison()) {
+ Res.reset();
+ break;
+ }
+ const AnyValue ValidatedOp =
+ handleFMFFlags(V, FMF, /*IsInput=*/true);
+ if (ValidatedOp.isPoison()) {
+ Res.reset();
+ break;
+ }
+ APFloat Op = handleDenormal(ValidatedOp.asFloat(), DenormMode.Input,
+ /*IsInput=*/true);
+ if (!Res) {
+ Res = std::move(Op);
+ continue;
+ }
+ switch (IID) {
+ case Intrinsic::vector_reduce_fadd:
+ *Res = *Res + Op;
+ break;
+ case Intrinsic::vector_reduce_fmul:
+ *Res = *Res * Op;
+ break;
+ case Intrinsic::vector_reduce_fmax:
+ *Res = maxnum(*Res, Op);
+ break;
+ case Intrinsic::vector_reduce_fmin:
+ *Res = minnum(*Res, Op);
+ break;
+ case Intrinsic::vector_reduce_fmaximum:
+ *Res = maximum(*Res, Op);
+ break;
+ case Intrinsic::vector_reduce_fminimum:
+ *Res = minimum(*Res, Op);
+ break;
+ default:
+ llvm_unreachable("Unexpected intrinsic ID");
+ }
+ }
+ return Res.has_value()
+ ? handleDenormal(handleFMFFlags(std::move(*Res), FMF,
+ /*IsInput=*/false)
+ .asFloat(),
+ DenormMode.Output,
+ /*IsInput=*/false)
+ : AnyValue::poison();
+ }
+ case Intrinsic::fabs: {
+ return visitFPUnOpWithResult(
+ RetTy, FMF, Args[0],
+ [](const APFloat &Operand) -> APFloat { return abs(Operand); });
+ }
+ case Intrinsic::fma: {
+ return visitFPTriOpWithResult(
+ RetTy, FMF, Args[0], Args[1], Args[2],
+ [](const APFloat &Op1, const APFloat &Op2,
+ const APFloat &Op3) -> APFloat {
+ auto Res = Op1;
+ Res.fusedMultiplyAdd(Op2, Op3, RoundingMode::NearestTiesToEven);
+ return Res;
+ });
+ }
+ case Intrinsic::fmuladd: {
+ return visitFPTriOpWithResult(
+ RetTy, FMF, Args[0], Args[1], Args[2],
+ [&](const APFloat &Op1, const APFloat &Op2,
+ const APFloat &Op3) -> APFloat {
+ if (Ctx.fuseMultiplyAdd()) {
+ auto Res = Op1;
+ Res.fusedMultiplyAdd(Op2, Op3, RoundingMode::NearestTiesToEven);
+ return Res;
+ }
+ return Op1 * Op2 + Op3;
+ });
+ }
+ case Intrinsic::is_fpclass: {
+ if (Args[1].isPoison())
+ return AnyValue::poison();
+ const FPClassTest Mask =
+ static_cast<FPClassTest>(Args[1].asInteger().getZExtValue());
+ return computeUnOp(RetTy, Args[0], [&](const AnyValue &Op) -> AnyValue {
+ if (Op.isPoison())
+ return AnyValue::poison();
+ return AnyValue::boolean(
+ static_cast<bool>(Op.asFloat().classify() & Mask));
+ });
+ }
+ case Intrinsic::copysign:
+ case Intrinsic::maxnum:
+ case Intrinsic::minnum:
+ case Intrinsic::maximum:
+ case Intrinsic::minimum:
+ case Intrinsic::maximumnum:
+ case Intrinsic::minimumnum: {
+ return visitFPBinOpWithResult(
+ RetTy, FMF, Args[0], Args[1],
+ [IID](const APFloat &LHS, const APFloat &RHS) -> APFloat {
+ switch (IID) {
+ case Intrinsic::copysign:
+ return APFloat::copySign(LHS, RHS);
+ case Intrinsic::maxnum:
+ return maxnum(LHS, RHS);
+ case Intrinsic::minnum:
+ return minnum(LHS, RHS);
+ case Intrinsic::maximum:
+ return maximum(LHS, RHS);
+ case Intrinsic::minimum:
+ return minimum(LHS, RHS);
+ case Intrinsic::maximumnum:
+ return maximumnum(LHS, RHS);
+ case Intrinsic::minimumnum:
+ return minimumnum(LHS, RHS);
+ default:
+ llvm_unreachable("Unexpected intrinsic ID");
+ }
+ });
+ }
+ case Intrinsic::fptosi_sat:
+ case Intrinsic::fptoui_sat: {
+ const auto BitWidth = RetTy->getScalarSizeInBits();
+ return computeUnOp(RetTy, Args[0], [&](const AnyValue &Op) -> AnyValue {
+ if (Op.isPoison())
+ return AnyValue::poison();
+ const APFloat &Operand = Op.asFloat();
+ APSInt V(BitWidth, IID == Intrinsic::fptoui_sat);
+ [[maybe_unused]] bool IsExact;
+ Operand.convertToInteger(V, APFloat::rmTowardZero, &IsExact);
+ return V;
+ });
+ }
default:
Handler.onUnrecognizedInstruction(CB);
setFailed();
@@ -1776,8 +2068,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
if (ValidatedOperand.isPoison())
return ValidatedOperand;
- APFloat FOperand =
- handleDenormal(ValidatedOperand.asFloat(), DenormMode.Input);
+ APFloat FOperand = handleDenormal(ValidatedOperand.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
APFloat SourceNaN = FOperand;
bool LosesInfo;
@@ -1931,8 +2223,10 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
ValidateRes.isPoison())
return ValidateRes;
- APFloat FLHS = handleDenormal(LHS.asFloat(), DenormMode.Input);
- APFloat FRHS = handleDenormal(RHS.asFloat(), DenormMode.Input);
+ APFloat FLHS =
+ handleDenormal(LHS.asFloat(), DenormMode.Input, /*IsInput=*/true);
+ APFloat FRHS =
+ handleDenormal(RHS.asFloat(), DenormMode.Input, /*IsInput=*/true);
return AnyValue::boolean(FCmpInst::compare(FLHS, FRHS, I.getPredicate()));
});
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index 396ace887d0fc..d92e4de691e14 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -84,6 +84,11 @@ static cl::opt<bool>
cl::desc("Disable interpreter-introduced non-determinism."),
cl::init(false), cl::cat(InterpreterCategory));
+static cl::opt<bool>
+ FuseMultiplyAdd("fuse-multiply-add",
+ cl::desc("Fuse floating-point multiply add operation"),
+ cl::init(false), cl::cat(InterpreterCategory));
+
cl::opt<ubi::UndefValueBehavior> UndefBehavior(
"", cl::desc("Choose undef value behavior:"),
cl::values(clEnumVal(ubi::UndefValueBehavior::NonDeterministic,
@@ -234,6 +239,7 @@ int main(int argc, char **argv) {
Ctx.setVScale(VScale);
Ctx.setMaxSteps(MaxSteps);
Ctx.setMaxStackDepth(MaxStackDepth);
+ Ctx.setFusedMultiplyAdd(FuseMultiplyAdd);
Ctx.setDeterministic(Deterministic);
Ctx.setUndefValueBehavior(UndefBehavior);
Ctx.setNaNPropagationBehavior(NaNPropagationBehavior);
>From be86eca689b44a0e71a1fffb9628463cb6d9d0c2 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhige_chen at outlook.com>
Date: Wed, 6 May 2026 17:43:42 +0800
Subject: [PATCH 2/6] [llubi] Fix copysign and NaN propagation in FP vector
reduction
---
llvm/tools/llubi/lib/Interpreter.cpp | 54 ++++++++++++++++++++--------
1 file changed, 39 insertions(+), 15 deletions(-)
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index acde46b5b3c01..7df6ff9acd202 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -1450,9 +1450,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
case Intrinsic::vector_reduce_fmaximum:
case Intrinsic::vector_reduce_fminimum: {
const auto DenormMode = getCurrentDenormalMode(RetTy);
- const bool HasStart =
- IID == Intrinsic::vector_reduce_fadd ||
- IID == Intrinsic::vector_reduce_fmul;
+ const bool HasStart = IID == Intrinsic::vector_reduce_fadd ||
+ IID == Intrinsic::vector_reduce_fmul;
const AnyValue &Vector = HasStart ? Args[1] : Args[0];
std::optional<APFloat> Res;
if (HasStart) {
@@ -1470,8 +1469,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
Res.reset();
break;
}
- const AnyValue ValidatedOp =
- handleFMFFlags(V, FMF, /*IsInput=*/true);
+ const AnyValue ValidatedOp = handleFMFFlags(V, FMF, /*IsInput=*/true);
if (ValidatedOp.isPoison()) {
Res.reset();
break;
@@ -1505,13 +1503,24 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
llvm_unreachable("Unexpected intrinsic ID");
}
}
- return Res.has_value()
- ? handleDenormal(handleFMFFlags(std::move(*Res), FMF,
- /*IsInput=*/false)
- .asFloat(),
- DenormMode.Output,
- /*IsInput=*/false)
- : AnyValue::poison();
+ if (Res.has_value()) {
+ const AnyValue ValidatedRes =
+ handleFMFFlags(*Res, FMF, /*IsInput=*/false);
+ if (ValidatedRes.isPoison()) {
+ Res.reset();
+ }
+ const APFloat FRes =
+ handleDenormal(ValidatedRes.asFloat(), DenormMode.Output,
+ /*IsInput=*/false);
+ std::vector<AnyValue> RawInputVec = Vector.asAggregate();
+ std::vector<const APFloat *> InputVec;
+ InputVec.reserve(RawInputVec.size());
+ transform(
+ RawInputVec, std::back_inserter(InputVec),
+ [](const AnyValue &V) -> const APFloat * { return &V.asFloat(); });
+ return applyNaNPropagation(FRes, InputVec);
+ }
+ return AnyValue::poison();
}
case Intrinsic::fabs: {
return visitFPUnOpWithResult(
@@ -1553,7 +1562,24 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
static_cast<bool>(Op.asFloat().classify() & Mask));
});
}
- case Intrinsic::copysign:
+ case Intrinsic::copysign: {
+ return computeBinOp(
+ RetTy, Args[0], Args[1],
+ [&](const AnyValue &LHS, const AnyValue &RHS) -> AnyValue {
+ if (LHS.isPoison() || RHS.isPoison())
+ return AnyValue::poison();
+ const AnyValue ValidatedLHS =
+ handleFMFFlags(LHS, FMF, /*IsInput=*/true);
+ const AnyValue ValidatedRHS =
+ handleFMFFlags(RHS, FMF, /*IsInput=*/true);
+ if (ValidatedLHS.isPoison() || ValidatedRHS.isPoison())
+ return AnyValue::poison();
+
+ return handleFMFFlags(APFloat::copySign(ValidatedLHS.asFloat(),
+ ValidatedRHS.asFloat()),
+ FMF, /*IsInput=*/false);
+ });
+ }
case Intrinsic::maxnum:
case Intrinsic::minnum:
case Intrinsic::maximum:
@@ -1564,8 +1590,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
RetTy, FMF, Args[0], Args[1],
[IID](const APFloat &LHS, const APFloat &RHS) -> APFloat {
switch (IID) {
- case Intrinsic::copysign:
- return APFloat::copySign(LHS, RHS);
case Intrinsic::maxnum:
return maxnum(LHS, RHS);
case Intrinsic::minnum:
>From 5be460427202c3ae2aaad4e8f83c788d9be9d6dd Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhige_chen at outlook.com>
Date: Wed, 6 May 2026 17:47:29 +0800
Subject: [PATCH 3/6] [llubi] Format code
---
llvm/tools/llubi/llubi.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index d92e4de691e14..673eb0d26702b 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -86,8 +86,8 @@ static cl::opt<bool>
static cl::opt<bool>
FuseMultiplyAdd("fuse-multiply-add",
- cl::desc("Fuse floating-point multiply add operation"),
- cl::init(false), cl::cat(InterpreterCategory));
+ cl::desc("Fuse floating-point multiply add operation"),
+ cl::init(false), cl::cat(InterpreterCategory));
cl::opt<ubi::UndefValueBehavior> UndefBehavior(
"", cl::desc("Choose undef value behavior:"),
>From 93830e9018dabdacb4616b4e5574d391fae14cc6 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Wed, 6 May 2026 19:51:41 +0800
Subject: [PATCH 4/6] [llubi] Implement non-det sNaN behavior for minnum/maxnum
& update tests
---
llvm/test/tools/llubi/intr_fp_fptoi_sat.ll | 8 +
llvm/test/tools/llubi/intr_fp_is_fpclass.ll | 20 +-
llvm/test/tools/llubi/intr_fp_minmax.ll | 120 +++++------
llvm/tools/llubi/lib/Context.h | 6 +-
llvm/tools/llubi/lib/Interpreter.cpp | 208 +++++++++++++-------
llvm/tools/llubi/llubi.cpp | 9 +-
6 files changed, 224 insertions(+), 147 deletions(-)
diff --git a/llvm/test/tools/llubi/intr_fp_fptoi_sat.ll b/llvm/test/tools/llubi/intr_fp_fptoi_sat.ll
index fa93a5b1338d4..80c12ddd663ee 100644
--- a/llvm/test/tools/llubi/intr_fp_fptoi_sat.ll
+++ b/llvm/test/tools/llubi/intr_fp_fptoi_sat.ll
@@ -8,12 +8,16 @@ define void @main() {
%slarge_neg = call i8 @llvm.fptosi.sat.i8.f32(float -1.0e+10)
%spoison = call i8 @llvm.fptosi.sat.i8.f32(float poison)
%svec = call <4 x i8> @llvm.fptosi.sat.v4i8.v4f32(<4 x float> <float 1.25, float poison, float 1.0e+10, float -1.0e+10>)
+ %sqnan = call i8 @llvm.fptosi.sat.i8.f32(float +nan(0x42))
+ %ssnan = call i8 @llvm.fptosi.sat.i8.f32(float +snan(0x42))
%upos = call i8 @llvm.fptoui.sat.i8.f32(float 255.75)
%uneg = call i8 @llvm.fptoui.sat.i8.f32(float -1.25)
%ularge = call i8 @llvm.fptoui.sat.i8.f32(float 1.0e+10)
%upoison = call i8 @llvm.fptoui.sat.i8.f32(float poison)
%uvec = call <4 x i8> @llvm.fptoui.sat.v4i8.v4f32(<4 x float> <float 1.25, float poison, float 1.0e+10, float -1.25>)
+ %uqnan = call i8 @llvm.fptoui.sat.i8.f32(float +nan(0x42))
+ %usnan = call i8 @llvm.fptoui.sat.i8.f32(float +snan(0x42))
ret void
}
; CHECK: Entering function: main
@@ -23,10 +27,14 @@ define void @main() {
; CHECK-NEXT: %slarge_neg = call i8 @llvm.fptosi.sat.i8.f32(float -1.000000e+10) => i8 -128
; CHECK-NEXT: %spoison = call i8 @llvm.fptosi.sat.i8.f32(float poison) => poison
; CHECK-NEXT: %svec = call <4 x i8> @llvm.fptosi.sat.v4i8.v4f32(<4 x float> <float 1.250000e+00, float poison, float 1.000000e+10, float -1.000000e+10>) => { i8 1, poison, i8 127, i8 -128 }
+; CHECK-NEXT: %sqnan = call i8 @llvm.fptosi.sat.i8.f32(float 0x7FF8000840000000) => i8 0
+; CHECK-NEXT: %ssnan = call i8 @llvm.fptosi.sat.i8.f32(float 0x7FF0000840000000) => i8 0
; CHECK-NEXT: %upos = call i8 @llvm.fptoui.sat.i8.f32(float 2.557500e+02) => i8 -1
; CHECK-NEXT: %uneg = call i8 @llvm.fptoui.sat.i8.f32(float -1.250000e+00) => i8 0
; CHECK-NEXT: %ularge = call i8 @llvm.fptoui.sat.i8.f32(float 1.000000e+10) => i8 -1
; CHECK-NEXT: %upoison = call i8 @llvm.fptoui.sat.i8.f32(float poison) => poison
; CHECK-NEXT: %uvec = call <4 x i8> @llvm.fptoui.sat.v4i8.v4f32(<4 x float> <float 1.250000e+00, float poison, float 1.000000e+10, float -1.250000e+00>) => { i8 1, poison, i8 -1, i8 0 }
+; CHECK-NEXT: %uqnan = call i8 @llvm.fptoui.sat.i8.f32(float 0x7FF8000840000000) => i8 0
+; CHECK-NEXT: %usnan = call i8 @llvm.fptoui.sat.i8.f32(float 0x7FF0000840000000) => i8 0
; CHECK-NEXT: ret void
; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_is_fpclass.ll b/llvm/test/tools/llubi/intr_fp_is_fpclass.ll
index c781fbeae281e..7800a772cc1be 100644
--- a/llvm/test/tools/llubi/intr_fp_is_fpclass.ll
+++ b/llvm/test/tools/llubi/intr_fp_is_fpclass.ll
@@ -2,25 +2,25 @@
; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
define void @main() {
- %is_snan = call i1 @llvm.is.fpclass.f32(float 0x7FF0000020000000, i32 1)
- %is_qnan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 2)
- %is_nan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 3)
- %is_neg_inf = call i1 @llvm.is.fpclass.f32(float 0xFFF0000000000000, i32 4)
+ %is_snan = call i1 @llvm.is.fpclass.f32(float +snan(0x42), i32 1)
+ %is_qnan = call i1 @llvm.is.fpclass.f32(float +nan(0x42), i32 2)
+ %is_nan = call i1 @llvm.is.fpclass.f32(float -nan(0x42), i32 3)
+ %is_neg_inf = call i1 @llvm.is.fpclass.f32(float -inf, i32 4)
%is_neg_normal = call i1 @llvm.is.fpclass.f32(float -1.0, i32 8)
%is_neg_subnormal = call i1 @llvm.is.fpclass.f32(float -1.434929627468612680625899e-42, i32 16)
%is_neg_zero = call i1 @llvm.is.fpclass.f32(float -0.0, i32 32)
%is_pos_zero = call i1 @llvm.is.fpclass.f32(float 0.0, i32 64)
%is_pos_subnormal = call i1 @llvm.is.fpclass.f32(float 1.434929627468612680625899e-42, i32 128)
%is_pos_normal = call i1 @llvm.is.fpclass.f32(float 1.0, i32 256)
- %is_pos_inf = call i1 @llvm.is.fpclass.f32(float 0x7FF0000000000000, i32 512)
+ %is_pos_inf = call i1 @llvm.is.fpclass.f32(float +inf, i32 512)
%is_poison = call i1 @llvm.is.fpclass.f32(float poison, i32 256)
- %is_vec = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> <float 0x7FF8000020000000, float poison, float 1.0, float -0.0>, i32 291)
+ %is_vec = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> <float +snan(0x42), float poison, float 1.0, float -0.0>, i32 291)
ret void
}
; CHECK: Entering function: main
-; CHECK-NEXT: %is_snan = call i1 @llvm.is.fpclass.f32(float 0x7FF0000020000000, i32 1) => T
-; CHECK-NEXT: %is_qnan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 2) => T
-; CHECK-NEXT: %is_nan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000020000000, i32 3) => T
+; CHECK-NEXT: %is_snan = call i1 @llvm.is.fpclass.f32(float 0x7FF0000840000000, i32 1) => T
+; CHECK-NEXT: %is_qnan = call i1 @llvm.is.fpclass.f32(float 0x7FF8000840000000, i32 2) => T
+; CHECK-NEXT: %is_nan = call i1 @llvm.is.fpclass.f32(float 0xFFF8000840000000, i32 3) => T
; CHECK-NEXT: %is_neg_inf = call i1 @llvm.is.fpclass.f32(float 0xFFF0000000000000, i32 4) => T
; CHECK-NEXT: %is_neg_normal = call i1 @llvm.is.fpclass.f32(float -1.000000e+00, i32 8) => T
; CHECK-NEXT: %is_neg_subnormal = call i1 @llvm.is.fpclass.f32(float 0xB740000000000000, i32 16) => T
@@ -30,6 +30,6 @@ define void @main() {
; CHECK-NEXT: %is_pos_normal = call i1 @llvm.is.fpclass.f32(float 1.000000e+00, i32 256) => T
; CHECK-NEXT: %is_pos_inf = call i1 @llvm.is.fpclass.f32(float 0x7FF0000000000000, i32 512) => T
; CHECK-NEXT: %is_poison = call i1 @llvm.is.fpclass.f32(float poison, i32 256) => poison
-; CHECK-NEXT: %is_vec = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> <float 0x7FF8000020000000, float poison, float 1.000000e+00, float -0.000000e+00>, i32 291) => { T, poison, T, T }
+; CHECK-NEXT: %is_vec = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> <float 0x7FF0000840000000, float poison, float 1.000000e+00, float -0.000000e+00>, i32 291) => { T, poison, T, T }
; CHECK-NEXT: ret void
; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_minmax.ll b/llvm/test/tools/llubi/intr_fp_minmax.ll
index 7195c5bc5ca67..e33aff27a368e 100644
--- a/llvm/test/tools/llubi/intr_fp_minmax.ll
+++ b/llvm/test/tools/llubi/intr_fp_minmax.ll
@@ -4,119 +4,119 @@
define void @main() {
%maxnum = call float @llvm.maxnum.f32(float 1.0, float 2.0)
%maxnum_neg_zero = call float @llvm.maxnum.f32(float -0.0, float 0.0)
- %maxnum_qnan_lhs = call float @llvm.maxnum.f32(float 0x7FF8000020000000, float 2.0)
- %maxnum_qnan_rhs = call float @llvm.maxnum.f32(float 2.0, float 0x7FF8000020000000)
- %maxnum_snan_lhs = call float @llvm.maxnum.f32(float 0x7FF0000020000000, float 2.0)
- %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.0, float 0x7FF0000020000000)
+ %maxnum_qnan_lhs = call float @llvm.maxnum.f32(float +nan(0x42), float 2.0)
+ %maxnum_qnan_rhs = call float @llvm.maxnum.f32(float 2.0, float +nan(0x42))
+ %maxnum_snan_lhs = call float @llvm.maxnum.f32(float +snan(0x42), float 2.0)
+ %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.0, float +snan(0x42))
%maxnum_poison_lhs = call float @llvm.maxnum.f32(float poison, float 2.0)
%maxnum_poison_rhs = call float @llvm.maxnum.f32(float 1.0, float poison)
- %maxnum_vec = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+ %maxnum_vec = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.0, float poison, float +nan(0x42), float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
%minnum = call float @llvm.minnum.f32(float 1.0, float 2.0)
%minnum_neg_zero = call float @llvm.minnum.f32(float -0.0, float 0.0)
- %minnum_qnan_lhs = call float @llvm.minnum.f32(float 0x7FF8000020000000, float 2.0)
- %minnum_qnan_rhs = call float @llvm.minnum.f32(float 2.0, float 0x7FF8000020000000)
- %minnum_snan_lhs = call float @llvm.minnum.f32(float 0x7FF0000020000000, float 2.0)
- %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.0, float 0x7FF0000020000000)
+ %minnum_qnan_lhs = call float @llvm.minnum.f32(float +nan(0x42), float 2.0)
+ %minnum_qnan_rhs = call float @llvm.minnum.f32(float 2.0, float +nan(0x42))
+ %minnum_snan_lhs = call float @llvm.minnum.f32(float +snan(0x42), float 2.0)
+ %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.0, float +snan(0x42))
%minnum_poison_lhs = call float @llvm.minnum.f32(float poison, float 2.0)
%minnum_poison_rhs = call float @llvm.minnum.f32(float 1.0, float poison)
- %minnum_vec = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+ %minnum_vec = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.0, float poison, float +nan(0x42), float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
%maximum = call float @llvm.maximum.f32(float 1.0, float 2.0)
%maximum_neg_zero = call float @llvm.maximum.f32(float -0.0, float 0.0)
- %maximum_qnan_lhs = call float @llvm.maximum.f32(float 0x7FF8000020000000, float 2.0)
- %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.0, float 0x7FF8000020000000)
- %maximum_snan_lhs = call float @llvm.maximum.f32(float 0x7FF0000020000000, float 2.0)
- %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.0, float 0x7FF0000020000000)
+ %maximum_qnan_lhs = call float @llvm.maximum.f32(float +nan(0x42), float 2.0)
+ %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.0, float +nan(0x42))
+ %maximum_snan_lhs = call float @llvm.maximum.f32(float +snan(0x42), float 2.0)
+ %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.0, float +snan(0x42))
%maximum_poison_lhs = call float @llvm.maximum.f32(float poison, float 2.0)
%maximum_poison_rhs = call float @llvm.maximum.f32(float 1.0, float poison)
- %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+ %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.0, float poison, float +nan(0x42), float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
%minimum = call float @llvm.minimum.f32(float 1.0, float 2.0)
%minimum_neg_zero = call float @llvm.minimum.f32(float -0.0, float 0.0)
- %minimum_qnan_lhs = call float @llvm.minimum.f32(float 0x7FF8000020000000, float 2.0)
- %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.0, float 0x7FF8000020000000)
- %minimum_snan_lhs = call float @llvm.minimum.f32(float 0x7FF0000020000000, float 2.0)
- %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.0, float 0x7FF0000020000000)
+ %minimum_qnan_lhs = call float @llvm.minimum.f32(float +nan(0x42), float 2.0)
+ %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.0, float +nan(0x42))
+ %minimum_snan_lhs = call float @llvm.minimum.f32(float +snan(0x42), float 2.0)
+ %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.0, float +snan(0x42))
%minimum_poison_lhs = call float @llvm.minimum.f32(float poison, float 2.0)
%minimum_poison_rhs = call float @llvm.minimum.f32(float 1.0, float poison)
- %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+ %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.0, float poison, float +nan(0x42), float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
%maximumnum = call float @llvm.maximumnum.f32(float 1.0, float 2.0)
%maximumnum_neg_zero = call float @llvm.maximumnum.f32(float -0.0, float 0.0)
- %maximumnum_qnan_lhs = call float @llvm.maximumnum.f32(float 0x7FF8000020000000, float 2.0)
- %maximumnum_qnan_rhs = call float @llvm.maximumnum.f32(float 2.0, float 0x7FF8000020000000)
- %maximumnum_snan_lhs = call float @llvm.maximumnum.f32(float 0x7FF0000020000000, float 2.0)
- %maximumnum_snan_rhs = call float @llvm.maximumnum.f32(float 2.0, float 0x7FF0000020000000)
+ %maximumnum_qnan_lhs = call float @llvm.maximumnum.f32(float +nan(0x42), float 2.0)
+ %maximumnum_qnan_rhs = call float @llvm.maximumnum.f32(float 2.0, float +nan(0x42))
+ %maximumnum_snan_lhs = call float @llvm.maximumnum.f32(float +snan(0x42), float 2.0)
+ %maximumnum_snan_rhs = call float @llvm.maximumnum.f32(float 2.0, float +snan(0x42))
%maximumnum_poison_lhs = call float @llvm.maximumnum.f32(float poison, float 2.0)
%maximumnum_poison_rhs = call float @llvm.maximumnum.f32(float 1.0, float poison)
- %maximumnum_vec = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+ %maximumnum_vec = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 1.0, float poison, float +nan(0x42), float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
%minimumnum = call float @llvm.minimumnum.f32(float 1.0, float 2.0)
%minimumnum_neg_zero = call float @llvm.minimumnum.f32(float -0.0, float 0.0)
- %minimumnum_qnan_lhs = call float @llvm.minimumnum.f32(float 0x7FF8000020000000, float 2.0)
- %minimumnum_qnan_rhs = call float @llvm.minimumnum.f32(float 2.0, float 0x7FF8000020000000)
- %minimumnum_snan_lhs = call float @llvm.minimumnum.f32(float 0x7FF0000020000000, float 2.0)
- %minimumnum_snan_rhs = call float @llvm.minimumnum.f32(float 2.0, float 0x7FF0000020000000)
+ %minimumnum_qnan_lhs = call float @llvm.minimumnum.f32(float +nan(0x42), float 2.0)
+ %minimumnum_qnan_rhs = call float @llvm.minimumnum.f32(float 2.0, float +nan(0x42))
+ %minimumnum_snan_lhs = call float @llvm.minimumnum.f32(float +snan(0x42), float 2.0)
+ %minimumnum_snan_rhs = call float @llvm.minimumnum.f32(float 2.0, float +snan(0x42))
%minimumnum_poison_lhs = call float @llvm.minimumnum.f32(float poison, float 2.0)
%minimumnum_poison_rhs = call float @llvm.minimumnum.f32(float 1.0, float poison)
- %minimumnum_vec = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 1.0, float poison, float 0x7FF8000020000000, float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
+ %minimumnum_vec = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 1.0, float poison, float +nan(0x42), float 4.0>, <4 x float> <float 2.0, float 2.0, float 2.0, float poison>)
ret void
}
; CHECK: Entering function: main
; CHECK-NEXT: %maxnum = call float @llvm.maxnum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
; CHECK-NEXT: %maxnum_neg_zero = call float @llvm.maxnum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
-; CHECK-NEXT: %maxnum_qnan_lhs = call float @llvm.maxnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %maxnum_qnan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
-; CHECK-NEXT: %maxnum_snan_lhs = call float @llvm.maxnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
-; CHECK-NEXT: %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0xFFC00000
+; CHECK-NEXT: %maxnum_qnan_lhs = call float @llvm.maxnum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maxnum_qnan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 2.000000e+00
+; CHECK-NEXT: %maxnum_snan_lhs = call float @llvm.maxnum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0xFFC00000
; CHECK-NEXT: %maxnum_poison_lhs = call float @llvm.maxnum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %maxnum_poison_rhs = call float @llvm.maxnum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %maxnum_vec = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: %maxnum_vec = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 2.000000e+00, poison }
; CHECK-NEXT: %minnum = call float @llvm.minnum.f32(float 1.000000e+00, float 2.000000e+00) => float 1.000000e+00
; CHECK-NEXT: %minnum_neg_zero = call float @llvm.minnum.f32(float -0.000000e+00, float 0.000000e+00) => float -0.000000e+00
-; CHECK-NEXT: %minnum_qnan_lhs = call float @llvm.minnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %minnum_qnan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
-; CHECK-NEXT: %minnum_snan_lhs = call float @llvm.minnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
-; CHECK-NEXT: %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0xFFC00000
+; CHECK-NEXT: %minnum_qnan_lhs = call float @llvm.minnum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %minnum_qnan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 2.000000e+00
+; CHECK-NEXT: %minnum_snan_lhs = call float @llvm.minnum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 2.000000e+00
; CHECK-NEXT: %minnum_poison_lhs = call float @llvm.minnum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %minnum_poison_rhs = call float @llvm.minnum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %minnum_vec = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: %minnum_vec = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 2.000000e+00, poison }
; CHECK-NEXT: %maximum = call float @llvm.maximum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
; CHECK-NEXT: %maximum_neg_zero = call float @llvm.maximum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
-; CHECK-NEXT: %maximum_qnan_lhs = call float @llvm.maximum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 0x7FC00001
-; CHECK-NEXT: %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 0xFFC00000
-; CHECK-NEXT: %maximum_snan_lhs = call float @llvm.maximum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
-; CHECK-NEXT: %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0x7F800001
+; CHECK-NEXT: %maximum_qnan_lhs = call float @llvm.maximum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 0xFFC00000
+; CHECK-NEXT: %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 0x7FC00042
+; CHECK-NEXT: %maximum_snan_lhs = call float @llvm.maximum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 0xFFC00000
+; CHECK-NEXT: %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0x7F800042
; CHECK-NEXT: %maximum_poison_lhs = call float @llvm.maximum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %maximum_poison_rhs = call float @llvm.maximum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 0xFFC00001, poison }
+; CHECK-NEXT: %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 0x7FC00042, poison }
; CHECK-NEXT: %minimum = call float @llvm.minimum.f32(float 1.000000e+00, float 2.000000e+00) => float 1.000000e+00
; CHECK-NEXT: %minimum_neg_zero = call float @llvm.minimum.f32(float -0.000000e+00, float 0.000000e+00) => float -0.000000e+00
-; CHECK-NEXT: %minimum_qnan_lhs = call float @llvm.minimum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 0xFFC00000
-; CHECK-NEXT: %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 0xFFC00001
-; CHECK-NEXT: %minimum_snan_lhs = call float @llvm.minimum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 0x7F800001
-; CHECK-NEXT: %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 0x7FC00001
+; CHECK-NEXT: %minimum_qnan_lhs = call float @llvm.minimum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 0xFFC00042
+; CHECK-NEXT: %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 0xFFC00000
+; CHECK-NEXT: %minimum_snan_lhs = call float @llvm.minimum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 0xFFC00000
+; CHECK-NEXT: %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0x7F800042
; CHECK-NEXT: %minimum_poison_lhs = call float @llvm.minimum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %minimum_poison_rhs = call float @llvm.minimum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float NaN, poison }
+; CHECK-NEXT: %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 0x7FC00042, poison }
; CHECK-NEXT: %maximumnum = call float @llvm.maximumnum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
; CHECK-NEXT: %maximumnum_neg_zero = call float @llvm.maximumnum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
-; CHECK-NEXT: %maximumnum_qnan_lhs = call float @llvm.maximumnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %maximumnum_qnan_rhs = call float @llvm.maximumnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
-; CHECK-NEXT: %maximumnum_snan_lhs = call float @llvm.maximumnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %maximumnum_snan_rhs = call float @llvm.maximumnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_qnan_lhs = call float @llvm.maximumnum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_qnan_rhs = call float @llvm.maximumnum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_snan_lhs = call float @llvm.maximumnum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %maximumnum_snan_rhs = call float @llvm.maximumnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 2.000000e+00
; CHECK-NEXT: %maximumnum_poison_lhs = call float @llvm.maximumnum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %maximumnum_poison_rhs = call float @llvm.maximumnum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %maximumnum_vec = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: %maximumnum_vec = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 2.000000e+00, poison }
; CHECK-NEXT: %minimumnum = call float @llvm.minimumnum.f32(float 1.000000e+00, float 2.000000e+00) => float 1.000000e+00
; CHECK-NEXT: %minimumnum_neg_zero = call float @llvm.minimumnum.f32(float -0.000000e+00, float 0.000000e+00) => float -0.000000e+00
-; CHECK-NEXT: %minimumnum_qnan_lhs = call float @llvm.minimumnum.f32(float 0x7FF8000020000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %minimumnum_qnan_rhs = call float @llvm.minimumnum.f32(float 2.000000e+00, float 0x7FF8000020000000) => float 2.000000e+00
-; CHECK-NEXT: %minimumnum_snan_lhs = call float @llvm.minimumnum.f32(float 0x7FF0000020000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %minimumnum_snan_rhs = call float @llvm.minimumnum.f32(float 2.000000e+00, float 0x7FF0000020000000) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_qnan_lhs = call float @llvm.minimumnum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_qnan_rhs = call float @llvm.minimumnum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_snan_lhs = call float @llvm.minimumnum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 2.000000e+00
+; CHECK-NEXT: %minimumnum_snan_rhs = call float @llvm.minimumnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 2.000000e+00
; CHECK-NEXT: %minimumnum_poison_lhs = call float @llvm.minimumnum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %minimumnum_poison_rhs = call float @llvm.minimumnum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %minimumnum_vec = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000020000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 2.000000e+00, poison }
+; CHECK-NEXT: %minimumnum_vec = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 2.000000e+00, poison }
; CHECK-NEXT: ret void
; CHECK-NEXT: Exiting function: main
diff --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index af5849caeb8d6..12a9924c70633 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -208,7 +208,7 @@ class Context {
bool Deterministic = false;
UndefValueBehavior UndefBehavior = UndefValueBehavior::NonDeterministic;
NaNPropagationBehavior NaNBehavior = NaNPropagationBehavior::NonDeterministic;
- bool fusedMultiplyAdd = false;
+ bool FusedMultiplyAdd = false;
std::mt19937_64 Rng;
@@ -261,7 +261,7 @@ class Context {
void setVScale(uint32_t VS) { VScale = VS; }
void setMaxSteps(uint32_t MS) { MaxSteps = MS; }
void setMaxStackDepth(uint32_t Depth) { MaxStackDepth = Depth; }
- void setFusedMultiplyAdd(bool F) { fusedMultiplyAdd = F; }
+ void setFusedMultiplyAdd(bool F) { FusedMultiplyAdd = F; }
uint64_t getMemoryLimit() const { return MaxMem; }
uint32_t getVScale() const { return VScale; }
uint32_t getMaxSteps() const { return MaxSteps; }
@@ -271,7 +271,7 @@ class Context {
bool mayUseNonDeterminism() const { return !Deterministic; }
UndefValueBehavior getEffectiveUndefValueBehavior() const;
NaNPropagationBehavior getEffectiveNaNPropagationBehavior() const;
- bool fuseMultiplyAdd() const { return fusedMultiplyAdd; }
+ bool fuseMultiplyAdd() const { return FusedMultiplyAdd; }
void setUndefValueBehavior(UndefValueBehavior UB) { UndefBehavior = UB; }
void setNaNPropagationBehavior(NaNPropagationBehavior NaNBehav) {
NaNBehavior = NaNBehav;
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 7df6ff9acd202..a4f183d9b4896 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -394,17 +394,16 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
});
}
- AnyValue
- visitFPUnOpWithResult(Type *RetTy, const FastMathFlags &FMF,
- const AnyValue &Operand,
- function_ref<APFloat(const APFloat &)> ScalarFn) {
+ AnyValue visitBitwiseFPUnOpWithResult(
+ Type *RetTy, const FastMathFlags &FMF, const AnyValue &Operand,
+ function_ref<APFloat(const APFloat &)> ScalarFn) {
return computeUnOp(
RetTy, Operand, [&](const AnyValue &OperandInner) -> AnyValue {
if (OperandInner.isPoison())
return AnyValue::poison();
// We don't flush denormals here since the only
- // floating-point unary operation is fneg. And fneg is
+ // floating-point unary operation is llvm.fabs. And llvm.fabs is
// specified as a bitwise operation which only flips
// the sign bit of the input.
@@ -454,43 +453,10 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
void visitFPBinOp(
Instruction &I,
function_ref<APFloat(const APFloat &, const APFloat &)> ScalarFn) {
- FastMathFlags FMF = cast<FPMathOperator>(I).getFastMathFlags();
- DenormalMode DenormMode = getCurrentDenormalMode(I);
-
- if (!Ctx.isDefaultFPEnv())
- reportImmediateUB() << "Non-constrained floating-point operation assumes "
- "default floating-point environment";
-
- visitBinOp(I, [&](const AnyValue &LHS, const AnyValue &RHS) -> AnyValue {
- if (LHS.isPoison() || RHS.isPoison())
- return AnyValue::poison();
-
- AnyValue ValidatedLHS = handleFMFFlags(LHS, FMF, /*IsInput=*/true);
- AnyValue ValidatedRHS = handleFMFFlags(RHS, FMF, /*IsInput=*/true);
- if (ValidatedLHS.isPoison())
- return ValidatedLHS;
- if (ValidatedRHS.isPoison())
- return ValidatedRHS;
-
- // Flush input denormals
- APFloat FLHS = handleDenormal(ValidatedLHS.asFloat(), DenormMode.Input,
- /*IsInput=*/true);
- APFloat FRHS = handleDenormal(ValidatedRHS.asFloat(), DenormMode.Input,
- /*IsInput=*/true);
-
- APFloat RawResult = ScalarFn(FLHS, FRHS);
-
- // Flush output denormals and handle fast-math flags.
- AnyValue FResult = handleFMFFlags(
- handleDenormal(RawResult, DenormMode.Output, /*IsInput=*/false), FMF,
- /*IsInput=*/false);
-
- if (FResult.isPoison())
- return FResult;
-
- APFloat Result = FResult.asFloat();
- return applyNaNPropagation(Result, {&FLHS, &FRHS});
- });
+ setResult(I, visitFPBinOpWithResult(
+ I.getType(), cast<FPMathOperator>(I).getFastMathFlags(),
+ getValue(I.getOperand(0)), getValue(I.getOperand(1)),
+ ScalarFn));
}
AnyValue visitIntBinOpWithResult(
@@ -826,11 +792,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
DenormalMode getCurrentDenormalMode(Type *Ty) {
- if (Ty->isFPOrFPVectorTy()) {
- return CurrentFrame->Func.getDenormalMode(
- Ty->getScalarType()->getFltSemantics());
- }
- return DenormalMode::getDefault();
+ return CurrentFrame->Func.getDenormalMode(
+ Ty->getScalarType()->getFltSemantics());
}
// Helper function to convert BooleanKind to bool. Report an immediate UB if
@@ -1445,8 +1408,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
case Intrinsic::vector_reduce_fadd:
case Intrinsic::vector_reduce_fmul:
- case Intrinsic::vector_reduce_fmax:
- case Intrinsic::vector_reduce_fmin:
case Intrinsic::vector_reduce_fmaximum:
case Intrinsic::vector_reduce_fminimum: {
const auto DenormMode = getCurrentDenormalMode(RetTy);
@@ -1465,15 +1426,11 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
/*IsInput=*/true);
}
for (const auto &V : Vector.asAggregate()) {
- if (V.isPoison()) {
- Res.reset();
- break;
- }
+ if (V.isPoison())
+ return AnyValue::poison();
const AnyValue ValidatedOp = handleFMFFlags(V, FMF, /*IsInput=*/true);
- if (ValidatedOp.isPoison()) {
- Res.reset();
- break;
- }
+ if (ValidatedOp.isPoison())
+ return AnyValue::poison();
APFloat Op = handleDenormal(ValidatedOp.asFloat(), DenormMode.Input,
/*IsInput=*/true);
if (!Res) {
@@ -1487,12 +1444,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
case Intrinsic::vector_reduce_fmul:
*Res = *Res * Op;
break;
- case Intrinsic::vector_reduce_fmax:
- *Res = maxnum(*Res, Op);
- break;
- case Intrinsic::vector_reduce_fmin:
- *Res = minnum(*Res, Op);
- break;
case Intrinsic::vector_reduce_fmaximum:
*Res = maximum(*Res, Op);
break;
@@ -1522,8 +1473,75 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
return AnyValue::poison();
}
+ case Intrinsic::vector_reduce_fmax:
+ case Intrinsic::vector_reduce_fmin: {
+ const auto DenormMode = getCurrentDenormalMode(RetTy);
+ const auto &Vector = Args[0].asAggregate();
+ std::optional<APFloat> Res;
+ SmallVector<APFloat, 16> InputFloats;
+ std::vector<const APFloat *> InputVec;
+ InputFloats.reserve(Vector.size());
+ InputVec.reserve(Vector.size());
+ for (const auto &V : Vector) {
+ if (V.isPoison())
+ return AnyValue::poison();
+ const AnyValue ValidatedOp = handleFMFFlags(V, FMF, /*IsInput=*/true);
+ if (ValidatedOp.isPoison())
+ return AnyValue::poison();
+ InputFloats.push_back(handleDenormal(ValidatedOp.asFloat(),
+ DenormMode.Input,
+ /*IsInput=*/true));
+ InputVec.push_back(&InputFloats.back());
+ if (!Res) {
+ Res = InputFloats.back();
+ continue;
+ }
+ *Res = IID == Intrinsic::vector_reduce_fmax
+ ? maxnum(*Res, InputFloats.back())
+ : minnum(*Res, InputFloats.back());
+ }
+ if (!Res)
+ return AnyValue::poison();
+
+ AnyValue ValidatedRes = handleFMFFlags(*Res, FMF, /*IsInput=*/false);
+ if (ValidatedRes.isPoison())
+ return AnyValue::poison();
+ APFloat FRes = handleDenormal(ValidatedRes.asFloat(), DenormMode.Output,
+ /*IsInput=*/false);
+
+ if (!any_of(InputVec, [](const APFloat *V) { return V->isSignaling(); }))
+ return applyNaNPropagation(FRes, InputVec);
+
+ if (Ctx.mayUseNonDeterminism() && Ctx.getRandomBool())
+ return applyNaNPropagation(APFloat::getQNaN(FRes.getSemantics()),
+ InputVec);
+
+ SmallVector<APFloat, 16> QuietedInputFloats;
+ QuietedInputFloats.reserve(InputVec.size());
+ for (const APFloat *V : InputVec)
+ QuietedInputFloats.push_back(propagateInputNaN(*V, V->getSemantics(),
+ /*QuietingMode=*/true,
+ /*FlipSign=*/false));
+ APFloat QuietRes = QuietedInputFloats.front();
+ for (const APFloat &V :
+ ArrayRef<APFloat>(QuietedInputFloats).drop_front())
+ QuietRes = IID == Intrinsic::vector_reduce_fmax ? maxnum(QuietRes, V)
+ : minnum(QuietRes, V);
+ QuietRes = handleDenormal(QuietRes, DenormMode.Output,
+ /*IsInput=*/false);
+ AnyValue FinalRes = handleFMFFlags(QuietRes, FMF, /*IsInput=*/false);
+ if (FinalRes.isPoison())
+ return AnyValue::poison();
+ QuietRes = FinalRes.asFloat();
+
+ SmallVector<const APFloat *, 16> QuietedInputVec;
+ QuietedInputVec.reserve(QuietedInputFloats.size());
+ for (const APFloat &V : QuietedInputFloats)
+ QuietedInputVec.push_back(&V);
+ return applyNaNPropagation(QuietRes, QuietedInputVec);
+ }
case Intrinsic::fabs: {
- return visitFPUnOpWithResult(
+ return visitBitwiseFPUnOpWithResult(
RetTy, FMF, Args[0],
[](const APFloat &Operand) -> APFloat { return abs(Operand); });
}
@@ -1581,7 +1599,63 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
});
}
case Intrinsic::maxnum:
- case Intrinsic::minnum:
+ case Intrinsic::minnum: {
+ DenormalMode DenormMode = getCurrentDenormalMode(RetTy);
+
+ if (!Ctx.isDefaultFPEnv())
+ reportImmediateUB()
+ << "Non-constrained floating-point operation assumes default "
+ "floating-point environment";
+
+ return computeBinOp(
+ RetTy, Args[0], Args[1],
+ [&](const AnyValue &LHS, const AnyValue &RHS) -> AnyValue {
+ if (LHS.isPoison() || RHS.isPoison())
+ return AnyValue::poison();
+ AnyValue ValidatedLHS = handleFMFFlags(LHS, FMF, /*IsInput=*/true);
+ AnyValue ValidatedRHS = handleFMFFlags(RHS, FMF, /*IsInput=*/true);
+ if (ValidatedLHS.isPoison())
+ return ValidatedLHS;
+ if (ValidatedRHS.isPoison())
+ return ValidatedRHS;
+
+ APFloat FLHS = handleDenormal(ValidatedLHS.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
+ APFloat FRHS = handleDenormal(ValidatedRHS.asFloat(),
+ DenormMode.Input, /*IsInput=*/true);
+
+ APFloat RawResult = IID == Intrinsic::maxnum ? maxnum(FLHS, FRHS)
+ : minnum(FLHS, FRHS);
+ APFloat Result = handleDenormal(RawResult, DenormMode.Output,
+ /*IsInput=*/false);
+ AnyValue FResult = handleFMFFlags(Result, FMF, /*IsInput=*/false);
+ if (FResult.isPoison())
+ return FResult;
+ Result = FResult.asFloat();
+
+ if ((FLHS.isSignaling() || FRHS.isSignaling()) &&
+ (!Ctx.mayUseNonDeterminism() || !Ctx.getRandomBool())) {
+ APFloat QuietLHS = propagateInputNaN(FLHS, FLHS.getSemantics(),
+ /*QuietingMode=*/true,
+ /*FlipSign=*/false);
+ APFloat QuietRHS = propagateInputNaN(FRHS, FRHS.getSemantics(),
+ /*QuietingMode=*/true,
+ /*FlipSign=*/false);
+ APFloat QuietResult = IID == Intrinsic::maxnum
+ ? maxnum(QuietLHS, QuietRHS)
+ : minnum(QuietLHS, QuietRHS);
+ QuietResult = handleDenormal(QuietResult, DenormMode.Output,
+ /*IsInput=*/false);
+ AnyValue FinalResult =
+ handleFMFFlags(QuietResult, FMF, /*IsInput=*/false);
+ if (FinalResult.isPoison())
+ return FinalResult;
+ QuietResult = FinalResult.asFloat();
+ return applyNaNPropagation(QuietResult, {&QuietLHS, &QuietRHS});
+ }
+ return applyNaNPropagation(Result, {&FLHS, &FRHS});
+ });
+ }
case Intrinsic::maximum:
case Intrinsic::minimum:
case Intrinsic::maximumnum:
@@ -1590,10 +1664,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
RetTy, FMF, Args[0], Args[1],
[IID](const APFloat &LHS, const APFloat &RHS) -> APFloat {
switch (IID) {
- case Intrinsic::maxnum:
- return maxnum(LHS, RHS);
- case Intrinsic::minnum:
- return minnum(LHS, RHS);
case Intrinsic::maximum:
return maximum(LHS, RHS);
case Intrinsic::minimum:
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index 673eb0d26702b..53946b4cb08f8 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -84,10 +84,9 @@ static cl::opt<bool>
cl::desc("Disable interpreter-introduced non-determinism."),
cl::init(false), cl::cat(InterpreterCategory));
-static cl::opt<bool>
- FuseMultiplyAdd("fuse-multiply-add",
- cl::desc("Fuse floating-point multiply add operation"),
- cl::init(false), cl::cat(InterpreterCategory));
+static cl::opt<bool> FuseFMulAdd("fuse-fmuladd",
+ cl::desc("Fuse llvm.fmuladd.* intrinsic"),
+ cl::init(true), cl::cat(InterpreterCategory));
cl::opt<ubi::UndefValueBehavior> UndefBehavior(
"", cl::desc("Choose undef value behavior:"),
@@ -239,7 +238,7 @@ int main(int argc, char **argv) {
Ctx.setVScale(VScale);
Ctx.setMaxSteps(MaxSteps);
Ctx.setMaxStackDepth(MaxStackDepth);
- Ctx.setFusedMultiplyAdd(FuseMultiplyAdd);
+ Ctx.setFusedMultiplyAdd(FuseFMulAdd);
Ctx.setDeterministic(Deterministic);
Ctx.setUndefValueBehavior(UndefBehavior);
Ctx.setNaNPropagationBehavior(NaNPropagationBehavior);
>From 26872414c1d90bbcb0a9f12f7d15fcc89a6008ea Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Thu, 7 May 2026 14:08:42 +0800
Subject: [PATCH 5/6] [llubi] Small fix
---
llvm/test/tools/llubi/intr_fp_minmax.ll | 22 ++++++------
llvm/tools/llubi/lib/Interpreter.cpp | 45 +++++++------------------
2 files changed, 23 insertions(+), 44 deletions(-)
diff --git a/llvm/test/tools/llubi/intr_fp_minmax.ll b/llvm/test/tools/llubi/intr_fp_minmax.ll
index e33aff27a368e..0214741116b9a 100644
--- a/llvm/test/tools/llubi/intr_fp_minmax.ll
+++ b/llvm/test/tools/llubi/intr_fp_minmax.ll
@@ -68,8 +68,8 @@ define void @main() {
; CHECK-NEXT: %maxnum_neg_zero = call float @llvm.maxnum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
; CHECK-NEXT: %maxnum_qnan_lhs = call float @llvm.maxnum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 2.000000e+00
; CHECK-NEXT: %maxnum_qnan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 2.000000e+00
-; CHECK-NEXT: %maxnum_snan_lhs = call float @llvm.maxnum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0xFFC00000
+; CHECK-NEXT: %maxnum_snan_lhs = call float @llvm.maxnum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 0xFFC00042
+; CHECK-NEXT: %maxnum_snan_rhs = call float @llvm.maxnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0x7F800042
; CHECK-NEXT: %maxnum_poison_lhs = call float @llvm.maxnum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %maxnum_poison_rhs = call float @llvm.maxnum.f32(float 1.000000e+00, float poison) => poison
; CHECK-NEXT: %maxnum_vec = call <4 x float> @llvm.maxnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 2.000000e+00, poison }
@@ -78,28 +78,28 @@ define void @main() {
; CHECK-NEXT: %minnum_qnan_lhs = call float @llvm.minnum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 2.000000e+00
; CHECK-NEXT: %minnum_qnan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 2.000000e+00
; CHECK-NEXT: %minnum_snan_lhs = call float @llvm.minnum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 2.000000e+00
-; CHECK-NEXT: %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 2.000000e+00
+; CHECK-NEXT: %minnum_snan_rhs = call float @llvm.minnum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0x7F800042
; CHECK-NEXT: %minnum_poison_lhs = call float @llvm.minnum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %minnum_poison_rhs = call float @llvm.minnum.f32(float 1.000000e+00, float poison) => poison
; CHECK-NEXT: %minnum_vec = call <4 x float> @llvm.minnum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 2.000000e+00, poison }
; CHECK-NEXT: %maximum = call float @llvm.maximum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
; CHECK-NEXT: %maximum_neg_zero = call float @llvm.maximum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
; CHECK-NEXT: %maximum_qnan_lhs = call float @llvm.maximum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 0xFFC00000
-; CHECK-NEXT: %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 0x7FC00042
-; CHECK-NEXT: %maximum_snan_lhs = call float @llvm.maximum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 0xFFC00000
-; CHECK-NEXT: %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0x7F800042
+; CHECK-NEXT: %maximum_qnan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float NaN
+; CHECK-NEXT: %maximum_snan_lhs = call float @llvm.maximum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 0x7F800042
+; CHECK-NEXT: %maximum_snan_rhs = call float @llvm.maximum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0xFF800042
; CHECK-NEXT: %maximum_poison_lhs = call float @llvm.maximum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %maximum_poison_rhs = call float @llvm.maximum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 0x7FC00042, poison }
+; CHECK-NEXT: %maximum_vec = call <4 x float> @llvm.maximum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 2.000000e+00, poison, float 0xFFC00000, poison }
; CHECK-NEXT: %minimum = call float @llvm.minimum.f32(float 1.000000e+00, float 2.000000e+00) => float 1.000000e+00
; CHECK-NEXT: %minimum_neg_zero = call float @llvm.minimum.f32(float -0.000000e+00, float 0.000000e+00) => float -0.000000e+00
; CHECK-NEXT: %minimum_qnan_lhs = call float @llvm.minimum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 0xFFC00042
-; CHECK-NEXT: %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float 0xFFC00000
-; CHECK-NEXT: %minimum_snan_lhs = call float @llvm.minimum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 0xFFC00000
-; CHECK-NEXT: %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float 0x7F800042
+; CHECK-NEXT: %minimum_qnan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF8000840000000) => float NaN
+; CHECK-NEXT: %minimum_snan_lhs = call float @llvm.minimum.f32(float 0x7FF0000840000000, float 2.000000e+00) => float 0x7FC00042
+; CHECK-NEXT: %minimum_snan_rhs = call float @llvm.minimum.f32(float 2.000000e+00, float 0x7FF0000840000000) => float NaN
; CHECK-NEXT: %minimum_poison_lhs = call float @llvm.minimum.f32(float poison, float 2.000000e+00) => poison
; CHECK-NEXT: %minimum_poison_rhs = call float @llvm.minimum.f32(float 1.000000e+00, float poison) => poison
-; CHECK-NEXT: %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 0x7FC00042, poison }
+; CHECK-NEXT: %minimum_vec = call <4 x float> @llvm.minimum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 0x7FF8000840000000, float 4.000000e+00>, <4 x float> <float 2.000000e+00, float 2.000000e+00, float 2.000000e+00, float poison>) => { float 1.000000e+00, poison, float 0xFFC00042, poison }
; CHECK-NEXT: %maximumnum = call float @llvm.maximumnum.f32(float 1.000000e+00, float 2.000000e+00) => float 2.000000e+00
; CHECK-NEXT: %maximumnum_neg_zero = call float @llvm.maximumnum.f32(float -0.000000e+00, float 0.000000e+00) => float 0.000000e+00
; CHECK-NEXT: %maximumnum_qnan_lhs = call float @llvm.maximumnum.f32(float 0x7FF8000840000000, float 2.000000e+00) => float 2.000000e+00
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index a4f183d9b4896..05a76d19f978b 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -360,27 +360,11 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
});
}
- void visitFPUnOp(Instruction &I,
- function_ref<APFloat(const APFloat &)> ScalarFn) {
- FastMathFlags FMF = cast<FPMathOperator>(I).getFastMathFlags();
-
- visitUnOp(I, [&](const AnyValue &Operand) -> AnyValue {
- if (Operand.isPoison())
- return AnyValue::poison();
-
- // We don't flush denormals here since the only floating-point unary
- // operation is fneg. And fneg is specified as a bitwise operation which
- // only flips the sign bit of the input.
-
- AnyValue ValidatedOperand =
- handleFMFFlags(Operand, FMF, /*IsInput=*/true);
- if (ValidatedOperand.isPoison())
- return ValidatedOperand;
-
- APFloat Result = ScalarFn(ValidatedOperand.asFloat());
-
- return handleFMFFlags(Result, FMF, /*IsInput=*/false);
- });
+ void visitBitwiseFPUnOp(Instruction &I,
+ function_ref<APFloat(const APFloat &)> ScalarFn) {
+ setResult(I, visitBitwiseFPUnOpWithResult(
+ I.getType(), cast<FPMathOperator>(I).getFastMathFlags(),
+ getValue(I.getOperand(0)), ScalarFn));
}
AnyValue
@@ -402,10 +386,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
if (OperandInner.isPoison())
return AnyValue::poison();
- // We don't flush denormals here since the only
- // floating-point unary operation is llvm.fabs. And llvm.fabs is
- // specified as a bitwise operation which only flips
- // the sign bit of the input.
+ // We don't flush denormals here since bitwise floating-point
+ // operations only manipulate on certain bits of the operand.
AnyValue ValidatedOperand =
handleFMFFlags(OperandInner, FMF, /*IsInput=*/true);
@@ -1534,11 +1516,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
return AnyValue::poison();
QuietRes = FinalRes.asFloat();
- SmallVector<const APFloat *, 16> QuietedInputVec;
- QuietedInputVec.reserve(QuietedInputFloats.size());
- for (const APFloat &V : QuietedInputFloats)
- QuietedInputVec.push_back(&V);
- return applyNaNPropagation(QuietRes, QuietedInputVec);
+ return applyNaNPropagation(QuietRes, InputVec);
}
case Intrinsic::fabs: {
return visitBitwiseFPUnOpWithResult(
@@ -1634,7 +1612,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
Result = FResult.asFloat();
if ((FLHS.isSignaling() || FRHS.isSignaling()) &&
- (!Ctx.mayUseNonDeterminism() || !Ctx.getRandomBool())) {
+ Ctx.getRandomBool()) {
APFloat QuietLHS = propagateInputNaN(FLHS, FLHS.getSemantics(),
/*QuietingMode=*/true,
/*FlipSign=*/false);
@@ -1651,7 +1629,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
if (FinalResult.isPoison())
return FinalResult;
QuietResult = FinalResult.asFloat();
- return applyNaNPropagation(QuietResult, {&QuietLHS, &QuietRHS});
+ return applyNaNPropagation(QuietResult, {&FLHS, &FRHS});
}
return applyNaNPropagation(Result, {&FLHS, &FRHS});
});
@@ -2109,7 +2087,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
void visitFNeg(UnaryOperator &I) {
- visitFPUnOp(I, [](const APFloat &Operand) -> APFloat { return -Operand; });
+ visitBitwiseFPUnOp(
+ I, [](const APFloat &Operand) -> APFloat { return -Operand; });
}
void visitTruncInst(TruncInst &Trunc) {
>From d862a2f4a7140f1b057c12c7f919684dfb4e946f Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Fri, 8 May 2026 14:20:12 +0800
Subject: [PATCH 6/6] [llubi] llvm.vector.reduce.fmin/fmax update
---
llvm/test/tools/llubi/intr_fp_fmuladd.ll | 19 +++
.../test/tools/llubi/intr_fp_vector_reduce.ll | 4 +
llvm/tools/llubi/lib/Interpreter.cpp | 115 ++++++++----------
3 files changed, 71 insertions(+), 67 deletions(-)
create mode 100644 llvm/test/tools/llubi/intr_fp_fmuladd.ll
diff --git a/llvm/test/tools/llubi/intr_fp_fmuladd.ll b/llvm/test/tools/llubi/intr_fp_fmuladd.ll
new file mode 100644
index 0000000000000..dd504a3e71a97
--- /dev/null
+++ b/llvm/test/tools/llubi/intr_fp_fmuladd.ll
@@ -0,0 +1,19 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: llubi --verbose --fuse-fmuladd=false < %s 2>&1 | FileCheck %s
+
+define void @main() {
+ %fmuladd = call float @llvm.fmuladd.f32(float 2.0, float 3.0, float 4.0)
+ %fmuladd_poison_lhs = call float @llvm.fmuladd.f32(float poison, float 3.0, float 4.0)
+ %fmuladd_poison_rhs = call float @llvm.fmuladd.f32(float 2.0, float poison, float 4.0)
+ %fmuladd_poison_addend = call float @llvm.fmuladd.f32(float 2.0, float 3.0, float poison)
+ %fmuladd_vec = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> <float 2.0, float poison, float 2.0, float 2.0>, <4 x float> <float 3.0, float 3.0, float 5.0, float 3.0>, <4 x float> <float 4.0, float 4.0, float 7.0, float poison>)
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %fmuladd = call float @llvm.fmuladd.f32(float 2.000000e+00, float 3.000000e+00, float 4.000000e+00) => float 1.000000e+01
+; CHECK-NEXT: %fmuladd_poison_lhs = call float @llvm.fmuladd.f32(float poison, float 3.000000e+00, float 4.000000e+00) => poison
+; CHECK-NEXT: %fmuladd_poison_rhs = call float @llvm.fmuladd.f32(float 2.000000e+00, float poison, float 4.000000e+00) => poison
+; CHECK-NEXT: %fmuladd_poison_addend = call float @llvm.fmuladd.f32(float 2.000000e+00, float 3.000000e+00, float poison) => poison
+; CHECK-NEXT: %fmuladd_vec = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> <float 2.000000e+00, float poison, float 2.000000e+00, float 2.000000e+00>, <4 x float> <float 3.000000e+00, float 3.000000e+00, float 5.000000e+00, float 3.000000e+00>, <4 x float> <float 4.000000e+00, float 4.000000e+00, float 7.000000e+00, float poison>) => { float 1.000000e+01, poison, float 1.700000e+01, poison }
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/intr_fp_vector_reduce.ll b/llvm/test/tools/llubi/intr_fp_vector_reduce.ll
index 57050438c0e2b..c1364545f1cb8 100644
--- a/llvm/test/tools/llubi/intr_fp_vector_reduce.ll
+++ b/llvm/test/tools/llubi/intr_fp_vector_reduce.ll
@@ -12,9 +12,11 @@ define void @main() {
%fmax = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.0, float 2.0, float 4.0, float 5.0>)
%fmax_poison = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.0, float poison, float 4.0, float 5.0>)
+ %fmax_snan = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.0, float +snan(0x42), float 4.0, float 5.0>)
%fmin = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.0, float 2.0, float 4.0, float 5.0>)
%fmin_poison = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.0, float poison, float 4.0, float 5.0>)
+ %fmin_snan = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.0, float +snan(0x42), float 4.0, float 5.0>)
%fmaximum = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.0, float 2.0, float 4.0, float 5.0>)
%fmaximum_poison = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.0, float poison, float 4.0, float 5.0>)
@@ -53,8 +55,10 @@ define void @main() {
; CHECK-NEXT: %fmul_poison_vec = call float @llvm.vector.reduce.fmul.v4f32(float 2.000000e+00, <4 x float> <float 2.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
; CHECK-NEXT: %fmax = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 5.000000e+00
; CHECK-NEXT: %fmax_poison = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fmax_snan = call float @llvm.vector.reduce.fmax.v4f32(<4 x float> <float 1.000000e+00, float 0x7FF0000840000000, float 4.000000e+00, float 5.000000e+00>) => float 5.000000e+00
; CHECK-NEXT: %fmin = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 1.000000e+00
; CHECK-NEXT: %fmin_poison = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
+; CHECK-NEXT: %fmin_snan = call float @llvm.vector.reduce.fmin.v4f32(<4 x float> <float 1.000000e+00, float 0x7FF0000840000000, float 4.000000e+00, float 5.000000e+00>) => float 0x7F800042
; CHECK-NEXT: %fmaximum = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 5.000000e+00
; CHECK-NEXT: %fmaximum_poison = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> <float 1.000000e+00, float poison, float 4.000000e+00, float 5.000000e+00>) => poison
; CHECK-NEXT: %fminimum = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 4.000000e+00, float 5.000000e+00>) => float 1.000000e+00
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 05a76d19f978b..5800c66774adf 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -768,11 +768,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
return IdxInt.sext(IndexBitWidth);
}
- DenormalMode getCurrentDenormalMode(Instruction &I) {
- return CurrentFrame->Func.getDenormalMode(
- I.getOperand(0)->getType()->getScalarType()->getFltSemantics());
- }
-
DenormalMode getCurrentDenormalMode(Type *Ty) {
return CurrentFrame->Func.getDenormalMode(
Ty->getScalarType()->getFltSemantics());
@@ -1436,32 +1431,27 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
llvm_unreachable("Unexpected intrinsic ID");
}
}
- if (Res.has_value()) {
- const AnyValue ValidatedRes =
- handleFMFFlags(*Res, FMF, /*IsInput=*/false);
- if (ValidatedRes.isPoison()) {
- Res.reset();
- }
- const APFloat FRes =
- handleDenormal(ValidatedRes.asFloat(), DenormMode.Output,
- /*IsInput=*/false);
- std::vector<AnyValue> RawInputVec = Vector.asAggregate();
- std::vector<const APFloat *> InputVec;
- InputVec.reserve(RawInputVec.size());
- transform(
- RawInputVec, std::back_inserter(InputVec),
- [](const AnyValue &V) -> const APFloat * { return &V.asFloat(); });
- return applyNaNPropagation(FRes, InputVec);
- }
- return AnyValue::poison();
+ assert(Res.has_value());
+ const AnyValue ValidatedRes =
+ handleFMFFlags(*Res, FMF, /*IsInput=*/false);
+ if (ValidatedRes.isPoison())
+ return AnyValue::poison();
+ const APFloat FRes =
+ handleDenormal(ValidatedRes.asFloat(), DenormMode.Output,
+ /*IsInput=*/false);
+ SmallVector<const APFloat *, 8> InputVec;
+ InputVec.reserve(Vector.asAggregate().size());
+ transform(
+ Vector.asAggregate(), std::back_inserter(InputVec),
+ [](const AnyValue &V) -> const APFloat * { return &V.asFloat(); });
+ return applyNaNPropagation(FRes, InputVec);
}
case Intrinsic::vector_reduce_fmax:
case Intrinsic::vector_reduce_fmin: {
const auto DenormMode = getCurrentDenormalMode(RetTy);
const auto &Vector = Args[0].asAggregate();
- std::optional<APFloat> Res;
- SmallVector<APFloat, 16> InputFloats;
- std::vector<const APFloat *> InputVec;
+ SmallVector<APFloat, 8> InputFloats;
+ SmallVector<const APFloat *, 8> InputVec;
InputFloats.reserve(Vector.size());
InputVec.reserve(Vector.size());
for (const auto &V : Vector) {
@@ -1474,49 +1464,41 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
DenormMode.Input,
/*IsInput=*/true));
InputVec.push_back(&InputFloats.back());
- if (!Res) {
- Res = InputFloats.back();
- continue;
- }
- *Res = IID == Intrinsic::vector_reduce_fmax
- ? maxnum(*Res, InputFloats.back())
- : minnum(*Res, InputFloats.back());
}
- if (!Res)
+ if (InputVec.empty())
return AnyValue::poison();
- AnyValue ValidatedRes = handleFMFFlags(*Res, FMF, /*IsInput=*/false);
+ SmallVector<APFloat, 8> Worklist(InputFloats);
+ const bool HasSNaN =
+ any_of(InputVec, [](const APFloat *V) { return V->isSignaling(); });
+ while (Worklist.size() > 1) {
+ size_t LHSIdx = 0;
+ size_t RHSIdx = 1;
+ if (HasSNaN) {
+ LHSIdx = Ctx.getRandomUInt64() % Worklist.size();
+ RHSIdx = Ctx.getRandomUInt64() % (Worklist.size() - 1);
+ if (RHSIdx >= LHSIdx)
+ ++RHSIdx;
+ }
+
+ APFloat Res = IID == Intrinsic::vector_reduce_fmax
+ ? maxnum(Worklist[LHSIdx], Worklist[RHSIdx])
+ : minnum(Worklist[LHSIdx], Worklist[RHSIdx]);
+ if (LHSIdx < RHSIdx)
+ std::swap(LHSIdx, RHSIdx);
+ Worklist.erase(Worklist.begin() + LHSIdx);
+ Worklist.erase(Worklist.begin() + RHSIdx);
+ Worklist.push_back(std::move(Res));
+ }
+
+ AnyValue ValidatedRes =
+ handleFMFFlags(Worklist.front(), FMF, /*IsInput=*/false);
if (ValidatedRes.isPoison())
return AnyValue::poison();
APFloat FRes = handleDenormal(ValidatedRes.asFloat(), DenormMode.Output,
/*IsInput=*/false);
- if (!any_of(InputVec, [](const APFloat *V) { return V->isSignaling(); }))
- return applyNaNPropagation(FRes, InputVec);
-
- if (Ctx.mayUseNonDeterminism() && Ctx.getRandomBool())
- return applyNaNPropagation(APFloat::getQNaN(FRes.getSemantics()),
- InputVec);
-
- SmallVector<APFloat, 16> QuietedInputFloats;
- QuietedInputFloats.reserve(InputVec.size());
- for (const APFloat *V : InputVec)
- QuietedInputFloats.push_back(propagateInputNaN(*V, V->getSemantics(),
- /*QuietingMode=*/true,
- /*FlipSign=*/false));
- APFloat QuietRes = QuietedInputFloats.front();
- for (const APFloat &V :
- ArrayRef<APFloat>(QuietedInputFloats).drop_front())
- QuietRes = IID == Intrinsic::vector_reduce_fmax ? maxnum(QuietRes, V)
- : minnum(QuietRes, V);
- QuietRes = handleDenormal(QuietRes, DenormMode.Output,
- /*IsInput=*/false);
- AnyValue FinalRes = handleFMFFlags(QuietRes, FMF, /*IsInput=*/false);
- if (FinalRes.isPoison())
- return AnyValue::poison();
- QuietRes = FinalRes.asFloat();
-
- return applyNaNPropagation(QuietRes, InputVec);
+ return applyNaNPropagation(FRes, InputVec);
}
case Intrinsic::fabs: {
return visitBitwiseFPUnOpWithResult(
@@ -1547,8 +1529,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
});
}
case Intrinsic::is_fpclass: {
- if (Args[1].isPoison())
- return AnyValue::poison();
const FPClassTest Mask =
static_cast<FPClassTest>(Args[1].asInteger().getZExtValue());
return computeUnOp(RetTy, Args[0], [&](const AnyValue &Op) -> AnyValue {
@@ -1628,8 +1608,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
handleFMFFlags(QuietResult, FMF, /*IsInput=*/false);
if (FinalResult.isPoison())
return FinalResult;
- QuietResult = FinalResult.asFloat();
- return applyNaNPropagation(QuietResult, {&FLHS, &FRHS});
+ Result = FinalResult.asFloat();
}
return applyNaNPropagation(Result, {&FLHS, &FRHS});
});
@@ -2135,7 +2114,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
return AnyValue::poison();
FastMathFlags FMF = cast<FPMathOperator>(I).getFastMathFlags();
- DenormalMode DenormMode = getCurrentDenormalMode(I);
+ DenormalMode DenormMode =
+ getCurrentDenormalMode(I.getOperand(0)->getType());
auto ValidatedOperand = handleFMFFlags(Operand, FMF, /*IsInput=*/true);
if (ValidatedOperand.isPoison())
@@ -2282,7 +2262,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
}
void visitFCmpInst(FCmpInst &I) {
- DenormalMode DenormMode = getCurrentDenormalMode(I);
+ DenormalMode DenormMode =
+ getCurrentDenormalMode(I.getOperand(0)->getType());
FastMathFlags FMF = I.getFastMathFlags();
visitBinOp(I, [&](const AnyValue &LHS, const AnyValue &RHS) -> AnyValue {
More information about the llvm-commits
mailing list