From 0c3cb0f020836609fc83489df0867903280b625e Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 27 Sep 2023 19:50:47 -0700 Subject: [PATCH] in divmod algorithm log regexes that match against expected register values --- .../decoder/isa/test_caller_svp64_powmod.py | 4 +- src/openpower/test/bigint/powmod.py | 87 ++++++++++++++++++- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/openpower/decoder/isa/test_caller_svp64_powmod.py b/src/openpower/decoder/isa/test_caller_svp64_powmod.py index 68afdf8f..c9675ee2 100644 --- a/src/openpower/decoder/isa/test_caller_svp64_powmod.py +++ b/src/openpower/decoder/isa/test_caller_svp64_powmod.py @@ -24,7 +24,9 @@ class TestPythonAlgorithms(unittest.TestCase): q, r = divmod(n, d) with self.subTest(n=f"{n:#_x}", d=f"{d:#_x}", q=f"{q:#_x}", r=f"{r:#_x}"): - out_q, out_r = python_divmod_algorithm(n, d) + log_regex = n == 2 ** 511 - 1 and d == 2 ** 256 - 1 + out_q, out_r = python_divmod_algorithm( + n, d, log_regex=log_regex) with self.subTest(out_q=f"{out_q:#_x}", out_r=f"{out_r:#_x}"): self.assertEqual(out_q, q) self.assertEqual(out_r, r) diff --git a/src/openpower/test/bigint/powmod.py b/src/openpower/test/bigint/powmod.py index 3e97eef2..cb6e0aca 100644 --- a/src/openpower/test/bigint/powmod.py +++ b/src/openpower/test/bigint/powmod.py @@ -18,6 +18,7 @@ from openpower.test.common import TestAccumulatorBase, skip_case from openpower.test.state import ExpectedState from openpower.test.util import assemble from nmutil.sim_util import hash_256 +from openpower.util import log MUL_256_X_256_TO_512_ASM = ( @@ -157,20 +158,102 @@ DIVMOD_512x256_TO_256x256_ASM = ( ) -def python_divmod_algorithm(n, d, width=256): +class _DivModRegsRegexLogger: + """ logger that logs a regex that matches the expected register dump for + the currently tracked `locals` -- quite useful for debugging + """ + + def __init__(self, enabled=True): + self.__tracked = {} + self.enabled = enabled + + def log(self, locals_, **changes): + """ use like so: + ``` + # create a variable `a`: + a = ... + + # we invoke `locals()` each time since python doesn't guarantee + # it's up-to-date otherwise + logger.log(locals(), a=(4, 6)) # `a` starts at r4 and uses 6 registers + + a += 3 + + logger.log(locals()) # keeps using `a` + + b = a + 5 + + logger.log(locals(), a=None, b=(4, 6)) # remove `a` and add `b` + ``` + """ + + for k, v in changes.items(): + if v is None: + del self.__tracked[k] + else: + self.__tracked[k] = v + + gprs = [None] * 128 + for name, (start_gpr, size) in self.__tracked.items(): + value = locals_[name] + for i in range(size): + assert gprs[start_gpr + i] is None, "overlapping values" + gprs[start_gpr + i] = (value >> 64 * i) % 2 ** 64 + + if not self.enabled: + # after building `gprs` so we catch any missing/invalid locals + return + + segments = [] + + for i in range(0, 128, 8): + segments.append(f"reg +{i}") + for value in gprs[i:i + 8]: + if value is None: + segments.append(" +[0-9a-f]+") + else: + segments.append(f" +{value:08x}") + segments.append("\\n") + log("DIVMOD REGEX:", "".join(segments)) + + +def python_divmod_algorithm(n, d, width=256, log_regex=False): assert n >= 0 and d > 0 and width > 0 and n < (d << width), "invalid input" + do_log = _DivModRegsRegexLogger(enabled=log_regex).log + + do_log(locals(), n=(4, 8), d=(32, 4)) + r = n + do_log(locals(), n=None, r=(40, 8)) + shifted_d = d << (width - 1) + do_log(locals(), d=None, shifted_d=(32, 8)) + q = 0 + do_log(locals(), q=(4, 4)) + for _ in range(width): diff = r - shifted_d borrowed = diff < 0 + do_log(locals(), diff=(48, 8)) + q <<= 1 + do_log(locals()) + if not borrowed: q |= 1 + do_log(locals()) + r = diff + do_log(locals()) + r <<= 1 - return q, r >> width + do_log(locals()) + + r >>= width + do_log(locals(), r=(8, 4)) + + return q, r class PowModCases(TestAccumulatorBase): -- 2.30.2