From f458951b17e75283cb72da75687142e832bac8c4 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 1 Nov 2024 14:10:44 +0000 Subject: [PATCH] Fix slow unsized number parsing (#5577) Try to avoid allocating and deallocating a full --max-num-width buffer on parsing every single unsized number literal. --- src/V3Number.cpp | 7 ++++- .../t/t_const_number_unsized_parse.py | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_const_number_unsized_parse.py diff --git a/src/V3Number.cpp b/src/V3Number.cpp index c446947aa..7f02d7b1e 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -198,7 +198,12 @@ void V3Number::create(const char* sourcep) { } // Otherwise... else if (!sized()) { - width(v3Global.opt.maxNumWidth(), false); // Will change width below + // We don't use v3Global.opt.maxNumWidth() here, as it can be arbitrarily large, + // and cause extremely slow parsing. We will resize the value at the end anyway. + // We just need a width big enough to fit the constant, so we use a conservative + // upper bound to start from. Should never need more than 4 bits per digit. + const int widthBound = std::max(32, std::strlen(value_startp) * 4); + width(widthBound, false); // Will change width below if (unbased) isSigned(true); // Also says the spec. } diff --git a/test_regress/t/t_const_number_unsized_parse.py b/test_regress/t/t_const_number_unsized_parse.py new file mode 100755 index 000000000..c33ca7d69 --- /dev/null +++ b/test_regress/t/t_const_number_unsized_parse.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import signal +import vltest_bootstrap + +test.scenarios('vlt') + +test.top_filename = f"{test.obj_dir}/in.v" + +with open(test.top_filename, "w", encoding="utf8") as f: + f.write("module top;\n") + for i in range(100000): + f.write(f" int x{i} = 'd{i};\n") + f.write("endmodule\n") + +signal.alarm(20) # 20s timeout + +test.lint(verilator_flags2=[f"--max-num-width {2**30}"]) + +test.passes()