softfloat: Allow runtime choice of NaN propagation for muladd

IEEE 758 does not define a fixed rule for which NaN to pick as the
result if both operands of a 3-operand fused multiply-add operation
are NaNs.  As a result different architectures have ended up with
different rules for propagating NaNs.

QEMU currently hardcodes the NaN propagation logic into the binary
because pickNaNMulAdd() has an ifdef ladder for different targets.
We want to make the propagation rule instead be selectable at
runtime, 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.

It's valid not to set a propagation rule if default_nan_mode is
enabled, because in that case there's no need to pick a NaN; all the
callers of pickNaNMulAdd() catch this case and skip calling it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20241202131347.498124-16-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2024-12-11 15:30:57 +00:00
parent d62c734d52
commit 7a944c30f7
3 changed files with 107 additions and 126 deletions

View file

@ -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_3nan_prop_rule(Float3NaNPropRule rule,
float_status *status)
{
status->float_3nan_prop_rule = rule;
}
static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
float_status *status)
{
@ -143,6 +149,11 @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
return status->float_2nan_prop_rule;
}
static inline Float3NaNPropRule get_float_3nan_prop_rule(float_status *status)
{
return status->float_3nan_prop_rule;
}
static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status)
{
return status->float_infzeronan_rule;