From f9ac76bd4a8d9f3753610f6d828b9a9ecd6f6044 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 18 May 2023 23:40:45 -0700 Subject: [PATCH] add WIP fcvtfg unit tests --- src/openpower/test/fmv_fcvt/fmv_fcvt.py | 133 +++++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/src/openpower/test/fmv_fcvt/fmv_fcvt.py b/src/openpower/test/fmv_fcvt/fmv_fcvt.py index d47f35cc..652fc2e9 100644 --- a/src/openpower/test/fmv_fcvt/fmv_fcvt.py +++ b/src/openpower/test/fmv_fcvt/fmv_fcvt.py @@ -14,13 +14,23 @@ def _cached_program(*instrs): return Program(list(SVP64Asm(list(instrs))), bigendian=False) -def fp_bits_add(fp, amount): - """add `amount` to the IEEE 754 bits representing `fp`""" - bits = struct.unpack("> (inp_width - 1): + # negative + inp_value -= 2 ** inp_width + # cast to nearby f32/f64 + inp_fp = fp_bits_add(inp_value, 0, bfp32=bfp32) + if inp_fp == inp_value: # exact conversion -- no rounding necessary + expected_fp = inp_fp + expected_bits = bitcast_fp_to_int(expected_fp, bfp32=False) + else: + # get the fp value on either side of the exact value. + # we need to get several values and select 2 because int -> fp + # conversion in fp_bits_add could be off by a bit due to + # rounding/double-rounding. + # we can ignore weirdness around infinity because input values + # can't get big enough to convert to infinity for bfp32/64. + # we can ignore weirdness around zero because small integers + # always convert exactly, and therefore don't reach this + # `else` block. + fp_values = sorted( + fp_bits_add(inp_value, i, bfp32=bfp32) for i in range(-2, 3)) + while fp_values[-2] > inp_value: + fp_values.pop() + prev_fp = fp_values[-2] + next_fp = fp_values[-1] + # if fp values are big enough to not be exact, they are always + # integers. + prev_int = int(prev_fp) + next_int = int(next_fp) + prev_fp_is_even = bitcast_fp_to_int(prev_fp, bfp32=bfp32) & 1 == 0 + halfway = 2 * inp_value == prev_int + next_int + next_is_closer = 2 * inp_value > prev_int + next_int + if RN == 0: + # round to nearest + use_prev = (halfway and prev_fp_is_even) or not next_is_closer + elif RN == 1: + # trunc + use_prev = abs(prev_int) < abs(next_int) + elif RN == 2: + # ceil + use_prev = False + else: + assert RN == 3, "invalid RN" + # floor + use_prev = True + if use_prev: + expected_fp = prev_fp + else: + expected_fp = next_fp + expected_bits = bitcast_fp_to_int(expected_fp, bfp32=False) + initial_fpscr = FPSCRState() + initial_fpscr.RN = RN + fpscr = FPSCRState(initial_fpscr) + if expected_fp != inp_value: + fpscr.XX = 1 + fpscr.FX = 1 + fpscr.FI = 1 + fpscr.FR = abs(expected_fp) > abs(inp_value) + if expected_fp < 0: + fpscr.FPRF = "- Normal Number" + elif expected_fp > 0: + fpscr.FPRF = "+ Normal Number" + else: + # integer conversion never gives -0.0 + fpscr.FPRF = "+ Zero" + if inp_width == 32 and not bfp32: + # defined to not modify FPSCR since the conversion is always exact + fpscr = FPSCRState(initial_fpscr) + cr1 = int(fpscr.FX) << 3 + cr1 |= int(fpscr.FEX) << 2 + cr1 |= int(fpscr.VX) << 1 + cr1 |= int(fpscr.OX) + with self.subTest( + inp=hex(inp), bfp32=bfp32, IT=IT, Rc=Rc, RN=RN, + expected_fp=expected_fp.hex(), expected_bits=hex(expected_bits), + XX=fpscr.XX, FR=fpscr.FR, FPRF=bin(int(fpscr.FPRF)), CR1=bin(cr1), + ): + rc_str = "." if Rc else "" + lst = [f"fcvtfg{rc_str} 0,3,{IT}"] + gprs = [0] * 32 + fprs = [0] * 32 + gprs[3] = inp + e = ExpectedState(pc=4, int_regs=gprs, fp_regs=fprs) + e.crregs[1] = cr1 + e.fpregs[0] = expected_bits + e.fpscr = int(fpscr) + self.add_case( + _cached_program(*lst), gprs, fpregs=fprs, expected=e, + initial_fpscr=int(initial_fpscr)) + + def fcvtfg(self, inp): + for bfp32 in (False, True): + for IT in range(4): + for Rc in (False, True): + for RN in range(4): + self.fcvtfg_one(inp, bfp32, IT, Rc, RN) + + def case_fcvtfg(self): + inp_values = {0} + for sh in (0, 22, 23, 24, 31, 52, 53, 54, 63): + for offset in range(-2, 3): + for offset_sh in range(64): + v = 1 << sh + v += offset << offset_sh + v %= 2 ** 64 + inp_values.add(v) + for i in sorted(inp_values): + self.fcvtfg(i) + class SVP64FMvFCvtCases(TestAccumulatorBase): @skip_case("FIXME: rewrite to fmv/fcvt tests") -- 2.30.2