From patchwork Mon Dec 2 13:12:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 846597 Delivered-To: patch@linaro.org Received: by 2002:a5d:4cd0:0:b0:385:e875:8a9e with SMTP id c16csp1195815wrt; Mon, 2 Dec 2024 05:15:16 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCVsBt3KYvXoBJTJRf5NOFt8oaU3bvdZMnGoIagm4ss8zhGislG69mO/pUaXolSnkVR0YsI/Eg==@linaro.org X-Google-Smtp-Source: AGHT+IH1m93qs+4Ei8S0mWGZkFRoXU2ubYZVLdFoe8JhBPT2rqBJl/riHBIe2UMawKIMUqJBk7cp X-Received: by 2002:a05:6808:2f0a:b0:3e7:b9be:52cc with SMTP id 5614622812f47-3ea6db61ff7mr20003540b6e.6.1733145315937; Mon, 02 Dec 2024 05:15:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1733145315; cv=none; d=google.com; s=arc-20240605; b=eXRDWgypWEXOsU94zw//ZgKOwi+4gq4JCAtB+vHX4tRcZYrXBA5S9tFizhviljjuLi SJkrHPTWEg9rt2qi5+0FRUKVMT8cJmM9wk3bzz0UVhtkFFPoVYCZqW7HveGlTLMi7FKM vRs+BEF8ooJ2Pp7a1BRaaEfrPpg3ftfa3pb6TXsDbkvzVOY0N/kDZFIn4Y3iMRhJ1iAW V9rFegWs0HyK+ikp1WShc8/t2Ohg50yQ8PiUUU4m4Mrqw1ciE/n4DDeq5RxhHbPUUOIn l4Qa6Cs3nzu0hgJ3PS2MyeCUH3E9Sh9tnK62TBNfGyWiMVtay1VBiqWfvVPyMupWLpvi lMDA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=v4zzS01bYybKsGEAJxbtpX4MUEAVNVSp3HeO2uhMqBQ=; fh=QgE9QYJDVj//6C0QJWGeEM+qaFVaxwMel1ZWqkEy6K0=; b=FZ2ZULNdIrNJ1scPoHxPdnPllIRS6CNXlZ+jsXhZAEoaGH1Oz4wU7iNyxkdf+zNQEt oAHAv9m3NdRjBgyzKVIcDenGCRMhxuF7K89i6xBqCK+Yq/XIZSGxf/kXCkZBsvrj9WyF Ujg2tEHNeICjCLCbhYjuk47LPQV3QsJP0xqE88PxW+ReQEDufahvXdApu4qmLfH175sk eDMS3q6Hh++soC7MfML8qyp3MEMh/hCDKQOGofpRWZgzFsP7kn5aGaWO5IGAj2E6X85j NsKxCXkTYBqdL/CL53qx3HizvecIETZ6pyq7LQvWADAM3auZTMhuwB0+Iaxom1CRWlvh ytIw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=QqxYOHpG; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id 71dfb90a1353d-5156d0d9e84si3618258e0c.162.2024.12.02.05.15.15 for (version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256); Mon, 02 Dec 2024 05:15:15 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=QqxYOHpG; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org; dara=neutral header.i=@linaro.org Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tI6GL-00024H-Br; Mon, 02 Dec 2024 08:14:53 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tI6Fs-0001nb-Ke for qemu-devel@nongnu.org; Mon, 02 Dec 2024 08:14:25 -0500 Received: from mail-wm1-x32f.google.com ([2a00:1450:4864:20::32f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tI6FP-00036m-VO for qemu-devel@nongnu.org; Mon, 02 Dec 2024 08:13:58 -0500 Received: by mail-wm1-x32f.google.com with SMTP id 5b1f17b1804b1-434b3e32e9dso35650545e9.2 for ; Mon, 02 Dec 2024 05:13:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1733145234; x=1733750034; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=v4zzS01bYybKsGEAJxbtpX4MUEAVNVSp3HeO2uhMqBQ=; b=QqxYOHpGUDccBcbCsrl5Z0GjPZELFKX5j4HZ7km+Mb6EtRELz/dipxd+M2HQ9hO/Lf B5j+PfJH+v+nNbnF+de9SkmNwvB41wNLiFyGEZB+KtLwJcOZ/SMtl3cIXX6mYXIziAv8 3fvI4rGr0x8oRrGTyo3eIXxhTWZyyl3c4qOg5MRctFirpNk0R/b9Blju6LDMo7hsKuOH j1X3gtPFiSfHJXExVN0kwQbG/0G1Nn3NbWX/IWxTSWLWE6MRTf4tdxx7LcCas3UE7zC/ HNTV5bnSFSwkxq5Pqyg/WCuyD1wT571sE9MBb+2eYSv42nkX3fEkUrdr7EXFX2qYRyQU LDlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733145234; x=1733750034; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=v4zzS01bYybKsGEAJxbtpX4MUEAVNVSp3HeO2uhMqBQ=; b=ctrCJY67zi2DllYqiUFmcZnvxB3GBTi6H/SDjUk/SvPVliUCJyXWJjGGZcTHjhLdoG Y5xpX0Yn8QWCsakKBp1rAlGsL1KJbewBCSFIDMbQeRFCUbAGavYBtOAxO2rBjWDlDWSe oqL342+XwXJqL7gXjeQoDZWQtYp5h4Dkna0DzjlokpUT7MAWrlhwQNq/agDEY6Hpguwf k6bUtJZrN0sRQTBYj7fB8S4+2oZihq0a0pw5St/dxBMplZitaKF9PU6fSZHHC3UCtzjm uRnJ4a9JNImBtShLRV9baIf1MG9vSP5nPHYfmlEiKefvFl7qpQl7Akx9+vOHPMUC753u /d+Q== X-Gm-Message-State: AOJu0YzCANU3uC6OG7CiPk9tDSLef5+KJ3NR6eR4cUJVDq/uZsLLjQDx vB+KnBXxpEYfYTPX0LZr3t6uWXIyKSCTg8LHCkCiXh2jPLNg4ennaa5dxNmp4unR73aHnoCwAvX h X-Gm-Gg: ASbGnctBN2u265bWNSjnFrDg2VdHqepHppgOXytVuxYlJf2H/G+l2i++SFKQREn8sXj HiA2eYQ3TjY/DsG/LvOraQ/Oi070nnmQyh77VooOmuu/q0fRzZmYkSeY++efVAK7nScBDIt2G7i BouzrVJ/9Y2tewjrPC58OZ5e+9ChCU+5KNnY5x2GBZCcKiAOpeo1dhIaXIUcn1CEw2Q1UtBhITF zlrQnzBptW6NyU/kPhb1g5TYRSaLSHacfwgSQbNj1RPkljhCDksCG4= X-Received: by 2002:a05:600c:5106:b0:434:9df4:5472 with SMTP id 5b1f17b1804b1-434a9df09b4mr220815605e9.31.1733145233371; Mon, 02 Dec 2024 05:13:53 -0800 (PST) Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385dea1e4ebsm10160157f8f.1.2024.12.02.05.13.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 05:13:52 -0800 (PST) From: Peter Maydell To: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org, qemu-ppc@nongnu.org, qemu-s390x@nongnu.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Richard Henderson , Paolo Bonzini , Eduardo Habkost , Song Gao , =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= , Jiaxun Yang , Aleksandar Rikalo , Nicholas Piggin , Daniel Henrique Barboza , David Hildenbrand , Ilya Leoshkevich , Thomas Huth , Mark Cave-Ayland , Artyom Tarasenko , Max Filippov Subject: [PATCH v2 for-10.0 03/54] softfloat: Allow runtime choice of inf * 0 + NaN result Date: Mon, 2 Dec 2024 13:12:56 +0000 Message-Id: <20241202131347.498124-4-peter.maydell@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241202131347.498124-1-peter.maydell@linaro.org> References: <20241202131347.498124-1-peter.maydell@linaro.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::32f; envelope-from=peter.maydell@linaro.org; helo=mail-wm1-x32f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org 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 Reviewed-by: Richard Henderson --- v1->v2: float_infzeronan_dnan_never shouldn't be the same value as float_infzeronan_none --- include/fpu/softfloat-helpers.h | 11 ++++ include/fpu/softfloat-types.h | 23 +++++++++ fpu/softfloat-specialize.c.inc | 91 ++++++++++++++++++++++----------- 3 files changed, 95 insertions(+), 30 deletions(-) diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index 453188de70b..0bf44dc6087 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 8f39691dfd0..47bb22c4e25 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -207,6 +207,28 @@ typedef enum __attribute__((__packed__)) { float_2nan_prop_x87, } 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 @@ -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; diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 81a67eb67b5..f5b422e07b5 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -475,6 +475,8 @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls, static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, bool infzero, float_status *status) { + FloatInfZeroNaNRule rule = status->float_infzeronan_rule; + /* * We guarantee not to require the target to tell us how to * pick a NaN if we're always returning the default NaN. @@ -482,14 +484,68 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, * specify. */ assert(!status->default_nan_mode); + + if (rule == float_infzeronan_none) { + /* + * Temporarily fall back to ifdef ladder + */ #if defined(TARGET_ARM) - /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns - * the default NaN - */ - if (infzero && is_qnan(c_cls)) { - return 3; + /* + * For ARM, the (inf,zero,qnan) case returns the default NaN, + * but (inf,zero,snan) returns the input NaN. + */ + rule = float_infzeronan_dnan_if_qnan; +#elif defined(TARGET_MIPS) + if (snan_bit_is_one(status)) { + /* + * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) + * case sets InvalidOp and returns the default NaN + */ + rule = float_infzeronan_dnan_always; + } else { + /* + * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan) + * case sets InvalidOp and returns the input value 'c' + */ + rule = float_infzeronan_dnan_never; + } +#elif defined(TARGET_PPC) || defined(TARGET_SPARC) || \ + defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \ + defined(TARGET_I386) || defined(TARGET_LOONGARCH) + /* + * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) + * case sets InvalidOp and returns the input value 'c' + */ + /* + * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer + * to return an input NaN if we have one (ie c) rather than generating + * a default NaN + */ + rule = float_infzeronan_dnan_never; +#elif defined(TARGET_S390X) + rule = float_infzeronan_dnan_always; +#endif } + if (infzero) { + /* + * Inf * 0 + NaN -- some implementations return the default NaN here, + * and some return the input NaN. + */ + switch (rule) { + case float_infzeronan_dnan_never: + return 2; + case float_infzeronan_dnan_always: + return 3; + case float_infzeronan_dnan_if_qnan: + return is_qnan(c_cls) ? 3 : 2; + default: + g_assert_not_reached(); + } + } + +#if defined(TARGET_ARM) + /* This looks different from the ARM ARM pseudocode, because the ARM ARM * puts the operands to a fused mac operation (a*b)+c in the order c,a,b. */ @@ -508,13 +564,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, } #elif defined(TARGET_MIPS) if (snan_bit_is_one(status)) { - /* - * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan) - * case sets InvalidOp and returns the default NaN - */ - if (infzero) { - return 3; - } /* Prefer sNaN over qNaN, in the a, b, c order. */ if (is_snan(a_cls)) { return 0; @@ -530,10 +579,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, return 2; } } else { - /* - * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan) - * case sets InvalidOp and returns the input value 'c' - */ /* Prefer sNaN over qNaN, in the c, a, b order. */ if (is_snan(c_cls)) { return 2; @@ -550,11 +595,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, } } #elif defined(TARGET_LOONGARCH64) - /* - * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan) - * case sets InvalidOp and returns the input value 'c' - */ - /* Prefer sNaN over qNaN, in the c, a, b order. */ if (is_snan(c_cls)) { return 2; @@ -570,11 +610,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, return 1; } #elif defined(TARGET_PPC) - /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer - * to return an input NaN if we have one (ie c) rather than generating - * a default NaN - */ - /* If fRA is a NaN return it; otherwise if fRB is a NaN return it; * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB */ @@ -586,10 +621,6 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, return 1; } #elif defined(TARGET_S390X) - if (infzero) { - return 3; - } - if (is_snan(a_cls)) { return 0; } else if (is_snan(b_cls)) {