On 11/28/24 04:42, Peter Maydell wrote:
+/* + * 3-input NaN propagation rule, for fused multiply-add. Individual + * architectures have different rules for which input NaN is + * propagated to the output when there is more than one NaN on the + * input. + * + * If default_nan_mode is enabled then it is valid not to set a NaN + * propagation rule, because the softfloat code guarantees not to try + * to pick a NaN to propagate in default NaN mode. When not in + * default-NaN mode, it is an error for the target not to set the rule + * in float_status if it uses a muladd, and we will assert if we need + * to handle an input NaN and no rule was selected. + * + * For QEMU, the multiply-add operation is A * B + C. + * + * NB: we don't list all 12 possibilities here or implement them + * in pickNaNMulAdd; if your architecture needs one of the missing + * combinations you should add it. + */ +typedef enum __attribute__((__packed__)) { + /* No propagation rule specified */ + float_3nan_prop_none = 0, + /* Prefer SNaN over QNaN, then operand A over B over C */ + float_3nan_prop_s_abc, + /* Prefer SNaN over QNaN, then operand C over A over B */ + float_3nan_prop_s_cab, + /* Prefer SNaN over QNaN, then operand C over B over A */ + float_3nan_prop_s_cba, + /* Prefer A over B over C regardless of SNaN vs QNaN */ + float_3nan_prop_abc, + /* Prefer A over C over B regardless of SNaN vs QNaN */ + float_3nan_prop_acb, + /* Prefer C over B over A regardless of SNaN vs QNaN */ + float_3nan_prop_cba, +} Float3NaNPropRule;
Oof. I was imagining a bit more data driven solution, rather than explicitly enumerating. For instance: FIELD(3NAN, 1ST, 0, 2) FIELD(3NAN, 2ND, 2, 2) FIELD(3NAN, 3RD, 4, 2) FIELD(3NAN, SNAN, 6, 1) float_3nan_prop_abc = (0 << R_3NAN_1ST_SHIFT) | (1 << R_3NAN_2ND_SHIFT) | (2 << R_3NAN_3RD_SHIFT), float_3nan_prop_s_abc = float_3nan_prop_abc | R_3NAN_SNAN_MASK, FloatClass cls[3] = { a_cls, b_cls, c_cls }; if (rule & R_3NAN_SNAN_MASK && abc_mask & float_cmask_snan) { do { which = rule & R_3NAN_1ST_MASK; rule >>= R_3NAN_1ST_LENGTH; } while (!is_snan(cls[which])); } else { do { which = rule & R_3NAN_1ST_MASK; rule >>= R_3NAN_1ST_LENGTH; } while (!is_nan(cls[which])); } return which; r~