From 0658af90f541955a724589da960d853deda6307a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 14 Jul 2024 13:57:16 -0400 Subject: [PATCH] Fix classes/modules of case-similar names (#5109). --- Changes | 1 + src/V3EmitCBase.cpp | 36 +++++++++++++ src/V3EmitCBase.h | 5 +- test_regress/t/t_class_capitalization.pl | 21 ++++++++ test_regress/t/t_class_capitalization.v | 64 ++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_class_capitalization.pl create mode 100644 test_regress/t/t_class_capitalization.v diff --git a/Changes b/Changes index 6d3271a55..bf631cdd0 100644 --- a/Changes +++ b/Changes @@ -22,6 +22,7 @@ Verilator 5.027 devel * Add `--compiler-include` for additional C++ includes (#5139) (#5202). [Bartłomiej Chmiel, Antmicro Ltd.] * Add `--emit-accessors` (#5182) (#5227). [Ryan Ziegler] * Fix fusing macro arguments to not ignore whitespace (#5061). [Tudor Timi] +* Fix classes/modules of case-similar names (#5109). [Arkadiusz Kozdra] * Fix mis-removing $value$plusargs calls (#5127) (#5137). [Seth Pellegrino] * Fix splitting if statements with impure conditions (#5219). [Bartłomiej Chmiel, Antmicro Ltd.] * Fix unknown conversion on queues (#5220). [Alex Solomatnikov] diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 8a4967112..7f9d33cea 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -35,6 +35,42 @@ EmitCParentModule::EmitCParentModule() { setAll(v3Global.rootp()->constPoolp()->modp()); } +//###################################################################### +// EmitCBase implementation + +string EmitCBase::prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { + const string prefix = v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name()); + // If all-uppercase prefix conflicts with a previous usage of the + // prefix with different capitalization, rename to avoid conflict. + // This is to support OSes where filename compares are non-case significant. + // STATIC: + static V3Mutex s_mutex; + const V3LockGuard lock{s_mutex}; // Otherwise map access is unsafe + static std::map s_memoized; + static std::map s_ucToPrefix; + // Memoize results + const auto mit = s_memoized.find(prefix); + if (mit != s_memoized.end()) return mit->second; + // + // Check capitalization + const string prefixUpper = VString::upcase(prefix); + string result; + { + const auto it = s_ucToPrefix.find(prefixUpper); + if (it == s_ucToPrefix.end()) { + s_ucToPrefix.emplace(prefixUpper, prefix); + result = prefix; + } else if (it->second == prefix) { + result = prefix; // Same capitialization as last time + } else { + VHashSha256 hash{prefix}; + result = prefix + "__Vphsh" + hash.digestSymbol(); + } + } + s_memoized.emplace(prefix, result); + return result; +} + //###################################################################### // EmitCBaseVisitor implementation diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 8cb5581e4..0f6dca34b 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -66,9 +66,8 @@ public: static string topClassName() VL_MT_SAFE { // Return name of top wrapper module return v3Global.opt.prefix(); } - static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { // C++ name with prefix - return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name()); - } + // Return C++ class name for a module/class object + static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE; static bool isAnonOk(const AstVar* varp) { AstNodeDType* const dtp = varp->dtypep()->skipRefp(); return v3Global.opt.compLimitMembers() != 0 // Enabled diff --git a/test_regress/t/t_class_capitalization.pl b/test_regress/t/t_class_capitalization.pl new file mode 100755 index 000000000..e64ab41be --- /dev/null +++ b/test_regress/t/t_class_capitalization.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# 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 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_capitalization.v b/test_regress/t/t_class_capitalization.v new file mode 100644 index 000000000..8f93cf689 --- /dev/null +++ b/test_regress/t/t_class_capitalization.v @@ -0,0 +1,64 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Test different uppercase/lowercase capitalization cases +class ClsMixed; + int m; + int M; +endclass + +class Clsmixed; + int m; + int M; +endclass + +module ModMixed; + // verilator no_inline_module + int m; + int M; +endmodule + +module Modmixed; + // verilator no_inline_module + int m; + int M; +endmodule + +module t(/*AUTOARG*/); + // verilator no_inline_module + + ModMixed modMixed(); + Modmixed modmixed(); + + initial begin + ClsMixed clsMixed; + Clsmixed clsmixed; + + clsMixed = new; + clsMixed.m = 1; + clsMixed.M = 2; + clsmixed = new; + clsmixed.m = 3; + clsmixed.M = 4; + if (clsMixed.m != 1) $stop; + if (clsMixed.M != 2) $stop; + if (clsmixed.m != 3) $stop; + if (clsmixed.M != 4) $stop; + + modMixed.m = 1; + modMixed.M = 2; + modmixed.m = 3; + modmixed.M = 4; + if (modMixed.m != 1) $stop; + if (modMixed.M != 2) $stop; + if (modmixed.m != 3) $stop; + if (modmixed.M != 4) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule