aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2024-12-11 15:30:53 +0000
committerPeter Maydell <peter.maydell@linaro.org>2024-12-11 15:30:53 +0000
commit4080eebd7357261dce0993e17ec6b6e9efa29581 (patch)
tree9e3d698359faaf236394205f438f35a48b68ba82 /include
parented885e306900e54a618ac9cc11ab68683db472b1 (diff)
downloadqemu-4080eebd7357261dce0993e17ec6b6e9efa29581.zip
qemu-4080eebd7357261dce0993e17ec6b6e9efa29581.tar.gz
qemu-4080eebd7357261dce0993e17ec6b6e9efa29581.tar.bz2
softfloat: Allow runtime choice of inf * 0 + NaN result
IEEE 758 does not define a fixed rule for what NaN to return in the case of a fused multiply-add of inf * 0 + NaN. Different architectures thus do different things: * some return the default NaN * some return the input NaN * Arm returns the default NaN if the input NaN is quiet, and the input NaN if it is signalling We want to make this logic be runtime selected rather than hardcoded into the binary, because: * this will let us have multiple targets in one QEMU binary * the Arm FEAT_AFP architectural feature includes letting the guest select a NaN propagation rule at runtime In this commit we add an enum for the propagation rule, the field in float_status, and the corresponding getters and setters. We change pickNaNMulAdd to honour this, but because all targets still leave this field at its default 0 value, the fallback logic will pick the rule type with the old ifdef ladder. Note that four architectures both use the muladd softfloat functions and did not have a branch of the ifdef ladder to specify their behaviour (and so were ending up with the "default" case, probably wrongly): i386, HPPA, SH4 and Tricore. SH4 and Tricore both set default_nan_mode, and so will never get into pickNaNMulAdd(). For HPPA and i386 we retain the same behaviour as the old default-case, which is to not ever return the default NaN. This might not be correct but it is not a behaviour change. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20241202131347.498124-4-peter.maydell@linaro.org
Diffstat (limited to 'include')
-rw-r--r--include/fpu/softfloat-helpers.h11
-rw-r--r--include/fpu/softfloat-types.h23
2 files changed, 34 insertions, 0 deletions
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
index 453188d..0bf44dc 100644
--- a/include/fpu/softfloat-helpers.h
+++ b/include/fpu/softfloat-helpers.h
@@ -81,6 +81,12 @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
status->float_2nan_prop_rule = rule;
}
+static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
+ float_status *status)
+{
+ status->float_infzeronan_rule = rule;
+}
+
static inline void set_flush_to_zero(bool val, float_status *status)
{
status->flush_to_zero = val;
@@ -137,6 +143,11 @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
return status->float_2nan_prop_rule;
}
+static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status)
+{
+ return status->float_infzeronan_rule;
+}
+
static inline bool get_flush_to_zero(float_status *status)
{
return status->flush_to_zero;
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
index 8f39691..47bb22c 100644
--- a/include/fpu/softfloat-types.h
+++ b/include/fpu/softfloat-types.h
@@ -208,6 +208,28 @@ typedef enum __attribute__((__packed__)) {
} Float2NaNPropRule;
/*
+ * Rule for result of fused multiply-add 0 * Inf + NaN.
+ * This must be a NaN, but implementations differ on whether this
+ * is the input NaN or the default NaN.
+ *
+ * You don't need to set this if default_nan_mode is enabled.
+ * When not in default-NaN mode, it is an error for the target
+ * not to set the rule in float_status if it uses muladd, and we
+ * will assert if we need to handle an input NaN and no rule was
+ * selected.
+ */
+typedef enum __attribute__((__packed__)) {
+ /* No propagation rule specified */
+ float_infzeronan_none = 0,
+ /* Result is never the default NaN (so always the input NaN) */
+ float_infzeronan_dnan_never,
+ /* Result is always the default NaN */
+ float_infzeronan_dnan_always,
+ /* Result is the default NaN if the input NaN is quiet */
+ float_infzeronan_dnan_if_qnan,
+} FloatInfZeroNaNRule;
+
+/*
* Floating Point Status. Individual architectures may maintain
* several versions of float_status for different functions. The
* correct status for the operation is then passed by reference to
@@ -219,6 +241,7 @@ typedef struct float_status {
FloatRoundMode float_rounding_mode;
FloatX80RoundPrec floatx80_rounding_precision;
Float2NaNPropRule float_2nan_prop_rule;
+ FloatInfZeroNaNRule float_infzeronan_rule;
bool tininess_before_rounding;
/* should denormalised results go to zero and set the inexact flag? */
bool flush_to_zero;