From: Matheus Ferst <matheus.fe...@eldorado.org.br> The non-signalling versions of VSX scalar convert to shorter/longer precision insns doesn't silence SNaNs in the hardware. To better match this behavior, use the non-arithmetic conversion of helper_todouble instead of float32_to_float64. A test is added to prevent future regressions.
Signed-off-by: Matheus Ferst <matheus.fe...@eldorado.org.br> Reviewed-by: Philippe Mathieu-Daudé <f4...@amsat.org> [ clg: Fixed spelling in commit log ] Message-Id: <20211214144459.1086343-1-matheus.fe...@eldorado.org.br> Signed-off-by: Cédric Le Goater <c...@kaod.org> --- target/ppc/fpu_helper.c | 5 +--- tests/tcg/ppc64le/non_signalling_xscv.c | 36 +++++++++++++++++++++++++ tests/tcg/ppc64/Makefile.target | 4 +-- tests/tcg/ppc64le/Makefile.target | 4 +-- 4 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 tests/tcg/ppc64le/non_signalling_xscv.c diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 700c79156b06..e5c29b53b8b5 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -2816,10 +2816,7 @@ uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) { - float_status tstat = env->fp_status; - set_float_exception_flags(0, &tstat); - - return float32_to_float64(xb >> 32, &tstat); + return helper_todouble(xb >> 32); } /* diff --git a/tests/tcg/ppc64le/non_signalling_xscv.c b/tests/tcg/ppc64le/non_signalling_xscv.c new file mode 100644 index 000000000000..77f07033335d --- /dev/null +++ b/tests/tcg/ppc64le/non_signalling_xscv.c @@ -0,0 +1,36 @@ +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> +#include <assert.h> + +#define TEST(INSN, B_HI, B_LO, T_HI, T_LO) \ + do { \ + __uint128_t t, b = B_HI; \ + b <<= 64; \ + b |= B_LO; \ + asm(INSN " %x0, %x1\n\t" \ + : "=wa" (t) \ + : "wa" (b)); \ + printf(INSN "(0x%016" PRIx64 "%016" PRIx64 ") = 0x%016" PRIx64 \ + "%016" PRIx64 "\n", (uint64_t)(b >> 64), (uint64_t)b, \ + (uint64_t)(t >> 64), (uint64_t)t); \ + assert((uint64_t)(t >> 64) == T_HI && (uint64_t)t == T_LO); \ + } while (0) + +int main(void) +{ +#ifndef __SIZEOF_INT128__ + puts("__uint128_t not available, skipping...\n"); +#else + /* SNaN shouldn't be silenced */ + TEST("xscvspdpn", 0x7fbfffff00000000ULL, 0x0, 0x7ff7ffffe0000000ULL, 0x0); + TEST("xscvdpspn", 0x7ff7ffffffffffffULL, 0x0, 0x7fbfffff7fbfffffULL, 0x0); + + /* + * SNaN inputs having no significant bits in the upper 23 bits of the + * signifcand will return Infinity as the result. + */ + TEST("xscvdpspn", 0x7ff000001fffffffULL, 0x0, 0x7f8000007f800000ULL, 0x0); +#endif + return 0; +} diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target index 8f4c7ac4ed7d..0368007028c9 100644 --- a/tests/tcg/ppc64/Makefile.target +++ b/tests/tcg/ppc64/Makefile.target @@ -6,9 +6,9 @@ VPATH += $(SRC_PATH)/tests/tcg/ppc64 VPATH += $(SRC_PATH)/tests/tcg/ppc64le ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),) -PPC64_TESTS=bcdsub +PPC64_TESTS=bcdsub non_signalling_xscv endif -bcdsub: CFLAGS += -mpower8-vector +$(PPC64_TESTS): CFLAGS += -mpower8-vector PPC64_TESTS += byte_reverse PPC64_TESTS += mtfsf diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target index e031f65adcb3..480ff0898d7e 100644 --- a/tests/tcg/ppc64le/Makefile.target +++ b/tests/tcg/ppc64le/Makefile.target @@ -5,9 +5,9 @@ VPATH += $(SRC_PATH)/tests/tcg/ppc64le ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),) -PPC64LE_TESTS=bcdsub +PPC64LE_TESTS=bcdsub non_signalling_xscv endif -bcdsub: CFLAGS += -mpower8-vector +$(PPC64LE_TESTS): CFLAGS += -mpower8-vector ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),) PPC64LE_TESTS += byte_reverse -- 2.31.1