Internal: Optimize program size by refactoring error reporting routines (#4446)

This commit is contained in:
Anthony Donlon 2023-08-30 04:54:32 +08:00 committed by GitHub
parent c3e19f2821
commit cf6566b9bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 99 additions and 100 deletions

View File

@ -1341,12 +1341,6 @@ bool AstNode::isTreePureRecurse() const {
return true;
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;
}
string AstNode::instanceStr() const {
// Max iterations before giving up on location search,
// in case we have some circular reference bug.
@ -1371,9 +1365,9 @@ string AstNode::instanceStr() const {
return "";
}
void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
void AstNode::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
if (!m_fileline) {
V3Error::s().v3errorEnd(str, instanceStr());
V3Error::v3errorEnd(str, instanceStr());
} else {
std::ostringstream nsstr;
nsstr << str.str();
@ -1390,6 +1384,11 @@ void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s()
nsstr, m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr());
}
}
void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;
}
//======================================================================
// Data type conversion

View File

@ -1916,9 +1916,9 @@ public:
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
// METHODS - dump and error
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex);
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
VL_REQUIRES(V3Error::s().m_mutex);
VL_RELEASE(V3Error::s().m_mutex);
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {
return fileline()->warnContextPrimary();
}

View File

@ -503,11 +503,11 @@ public:
inline bool inlined() const;
// Methods that allow DfgVertex to participate in error reporting/messaging
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
m_filelinep->v3errorEnd(str);
}
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
VL_REQUIRES(V3Error::s().m_mutex) {
VL_RELEASE(V3Error::s().m_mutex) {
m_filelinep->v3errorEndFatal(str);
}
string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) {

View File

@ -291,3 +291,35 @@ void V3Error::vlAbort() {
VL_GCOV_DUMP();
std::abort();
}
void V3Error::v3errorAcquireLock() VL_ACQUIRE(s().m_mutex) {
#ifndef V3ERROR_NO_GLOBAL_
V3Error::s().m_mutex.lockCheckStopRequest(
[]() -> void { V3ThreadPool::s().waitIfStopRequested(); });
#else
V3Error::s().m_mutex.lock();
#endif
}
std::ostringstream& V3Error::v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex) {
v3errorAcquireLock();
s().v3errorPrep(code);
return v3errorStr();
}
std::ostringstream& V3Error::v3errorPrepFileLine(V3ErrorCode code, const char* file, int line)
VL_ACQUIRE(s().m_mutex) {
v3errorPrep(code) << file << ":" << std::dec << line << ": ";
return v3errorStr();
}
std::ostringstream& V3Error::v3errorStr() VL_REQUIRES(s().m_mutex) { return s().v3errorStr(); }
void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) VL_RELEASE(s().m_mutex) {
s().v3errorEnd(sstr, extra);
V3Error::s().m_mutex.unlock();
}
void v3errorEnd(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) {
V3Error::v3errorEnd(sstr);
}
void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) {
V3Error::v3errorEnd(sstr);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;
}

View File

@ -286,9 +286,13 @@ inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) {
}
// ######################################################################
class V3Error;
class V3ErrorGuarded final {
// Should only be used by V3ErrorGuarded::m_mutex is already locked
// contains guarded members
friend class V3Error;
public:
using MessagesSet = std::set<std::string>;
using ErrorExitCb = void (*)(void);
@ -319,6 +323,16 @@ private:
= MAX_ERRORS; // Option: --error-limit Number of errors before exit
bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal
std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed
void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) {
m_errorStr.str("");
m_errorCode = code;
m_errorContexted = false;
m_errorSuppressed = false;
}
std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; }
void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex);
public:
V3RecursiveMutex m_mutex; // Make sure only single thread is in class
@ -361,13 +375,6 @@ public:
int errorLimit() VL_REQUIRES(m_mutex) { return m_errorLimit; }
void warnFatal(bool flag) VL_REQUIRES(m_mutex) { m_warnFatal = flag; }
bool warnFatal() VL_REQUIRES(m_mutex) { return m_warnFatal; }
void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) {
m_errorStr.str("");
m_errorCode = code;
m_errorContexted = false;
m_errorSuppressed = false;
}
std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; }
V3ErrorCode errorCode() VL_REQUIRES(m_mutex) { return m_errorCode; }
bool errorContexted() VL_REQUIRES(m_mutex) { return m_errorContexted; }
int warnCount() VL_REQUIRES(m_mutex) { return m_warnCount; }
@ -385,7 +392,6 @@ public:
void describedWarnings(bool flag) VL_REQUIRES(m_mutex) { m_describedWarnings = flag; }
int tellManual() VL_REQUIRES(m_mutex) { return m_tellManual; }
void tellManual(int level) VL_REQUIRES(m_mutex) { m_tellManual = level; }
void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex);
void suppressThisWarning() VL_REQUIRES(m_mutex);
string warnContextNone() VL_REQUIRES(m_mutex) {
errorContexted(true);
@ -512,66 +518,32 @@ public:
// Internals for v3error()/v3fatal() macros only
// Error end takes the string stream to output, be careful to seek() as needed
static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) {
const V3RecursiveLockGuard guard{s().m_mutex};
s().v3errorPrep(code);
}
static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) {
const V3RecursiveLockGuard guard{s().m_mutex};
return s().v3errorStr();
}
static void vlAbort();
static void v3errorAcquireLock() VL_ACQUIRE(s().m_mutex);
static std::ostringstream& v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex);
static std::ostringstream& v3errorPrepFileLine(V3ErrorCode code, const char* file, int line)
VL_ACQUIRE(s().m_mutex);
static std::ostringstream& v3errorStr() VL_REQUIRES(s().m_mutex);
// static, but often overridden in classes.
static void v3errorEnd(std::ostringstream& sstr, const string& extra = "")
VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE {
const V3RecursiveLockGuard guard{s().m_mutex};
s().v3errorEnd(sstr, extra);
}
// We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal',
// due to bug in GCC (tested on 11.3.0 version with --enable-m32)
// causing internal error when backtrace is printed.
// Instead use this wrapper.
static void v3errorEndGuardedCall(std::ostringstream& sstr, const string& extra = "")
VL_REQUIRES(s().m_mutex) VL_MT_SAFE {
s().v3errorEnd(sstr, extra);
}
VL_RELEASE(s().m_mutex);
static void vlAbort();
};
// Global versions, so that if the class doesn't define a operator, we get the functions anyways.
inline void v3errorEnd(std::ostringstream& sstr) VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE {
V3Error::v3errorEndGuardedCall(sstr);
}
inline void v3errorEndFatal(std::ostringstream& sstr)
VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE {
V3Error::v3errorEndGuardedCall(sstr);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;
}
#ifndef V3ERROR_NO_GLOBAL_
#define V3ErrorLockAndCheckStopRequested \
V3Error::s().m_mutex.lockCheckStopRequest( \
[]() -> void { V3ThreadPool::s().waitIfStopRequested(); })
#else
#define V3ErrorLockAndCheckStopRequested V3Error::s().m_mutex.lock()
#endif
// Global versions, so that if the class doesn't define an operator, we get the functions anyway.
void v3errorEnd(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex);
void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex);
// Theses allow errors using << operators: v3error("foo"<<"bar");
// Careful, you can't put () around msg, as you would in most macro definitions
// Note the commas are the comma operator, not separating arguments. These are needed to ensure
// evaluation order as otherwise we couldn't ensure v3errorPrep is called first.
// Note: due to limitations of clang thread-safety analysis, we can't use
// lock guard here, instead we are locking the mutex as first operation in temporary,
// but we are unlocking the mutex after function using comma operator.
// This way macros should also work when they are in 'if' stmt without '{}'.
#define v3warnCode(code, msg) \
v3errorEnd((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
V3Error::s().m_mutex.unlock()
// Careful, you can't put () around msg, as you would in most macro definitions.
// 'V3Error::v3errorPrep(code) << msg' could be more efficient but the order of function calls in a
// single statement can be arbitrary until C++17, thus make it possible to execute
// V3Error::v3errorPrep that acquires the lock after functions in the msg may require it. So we use
// the comma operator (,) to guarantee the execution order here.
#define v3errorBuildMessage(prep, msg) \
(prep, static_cast<std::ostringstream&>(V3Error::v3errorStr() << msg))
#define v3warnCode(code, msg) v3errorEnd(v3errorBuildMessage(V3Error::v3errorPrep(code), msg))
#define v3warnCodeFatal(code, msg) \
v3errorEndFatal((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
V3Error::s().m_mutex.unlock()
v3errorEndFatal(v3errorBuildMessage(V3Error::v3errorPrep(code), msg))
#define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg)
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
@ -580,14 +552,11 @@ inline void v3errorEndFatal(std::ostringstream& sstr)
#define v3fatalExit(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALEXIT, msg)
// Use this instead of fatal() to mention the source code line.
#define v3fatalSrc(msg) \
v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, \
__FILE__ << ":" << std::dec << __LINE__ << ": " << msg)
v3errorEndFatal(v3errorBuildMessage( \
V3Error::v3errorPrepFileLine(V3ErrorCode::EC_FATALSRC, __FILE__, __LINE__), msg))
// Use this when normal v3fatal is called in static method that overrides fileline.
#define v3fatalStatic(msg) \
(::v3errorEndFatal((V3ErrorLockAndCheckStopRequested, \
V3Error::s().v3errorPrep(V3ErrorCode::EC_FATAL), \
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr()))), \
V3Error::s().m_mutex.unlock()
::v3errorEndFatal(v3errorBuildMessage(V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), msg))
#define UINFO(level, stmsg) \
do { \

View File

@ -379,7 +379,7 @@ bool FileLine::warnIsOff(V3ErrorCode code) const {
// cppverilator-suppress constParameter
void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra)
VL_REQUIRES(V3Error::s().m_mutex) {
VL_RELEASE(V3Error::s().m_mutex) {
std::ostringstream nsstr;
if (lastLineno()) nsstr << this;
nsstr << sstr.str();
@ -396,7 +396,7 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra)
nsstr << warnContextPrimary();
}
if (!m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str());
V3Error::s().v3errorEnd(nsstr, lstr.str());
V3Error::v3errorEnd(nsstr, lstr.str());
}
string FileLine::warnMore() const VL_REQUIRES(V3Error::s().m_mutex) {

View File

@ -318,9 +318,9 @@ public:
// OPERATORS
void v3errorEnd(std::ostringstream& str, const string& extra = "")
VL_REQUIRES(V3Error::s().m_mutex);
VL_RELEASE(V3Error::s().m_mutex);
void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN
VL_REQUIRES(V3Error::s().m_mutex) {
VL_RELEASE(V3Error::s().m_mutex) {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;

View File

@ -129,7 +129,7 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVerte
}
// cppcheck-has-bug-suppress constParameter
void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
std::ostringstream nsstr;
nsstr << str.str();
if (debug()) {
@ -139,11 +139,11 @@ void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Erro
if (FileLine* const flp = fileline()) {
flp->v3errorEnd(nsstr);
} else {
V3Error::s().v3errorEnd(nsstr);
V3Error::v3errorEnd(nsstr);
}
}
void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const
VL_REQUIRES(V3Error::s().m_mutex) {
VL_RELEASE(V3Error::s().m_mutex) {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;

View File

@ -248,8 +248,8 @@ public:
V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); }
// METHODS
/// Error reporting
void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
void v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex);
void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex);
void v3errorEndFatal(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex);
/// Edges are routed around this vertex to point from "from" directly to "to"
void rerouteEdges(V3Graph* graphp);
/// Find the edge connecting ap and bp, where bp is wayward from ap.

View File

@ -76,7 +76,7 @@ constexpr int MAX_SPRINTF_DOUBLE_SIZE
//======================================================================
// Errors
void V3Number::v3errorEnd(const std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) {
void V3Number::v3errorEnd(const std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
std::ostringstream nsstr;
nsstr << str.str();
if (m_nodep) {
@ -84,12 +84,12 @@ void V3Number::v3errorEnd(const std::ostringstream& str) const VL_REQUIRES(V3Err
} else if (m_fileline) {
m_fileline->v3errorEnd(nsstr);
} else {
V3Error::s().v3errorEnd(nsstr);
V3Error::v3errorEnd(nsstr);
}
}
void V3Number::v3errorEndFatal(const std::ostringstream& str) const
VL_REQUIRES(V3Error::s().m_mutex) {
VL_RELEASE(V3Error::s().m_mutex) {
v3errorEnd(str);
assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE;

View File

@ -566,9 +566,9 @@ private:
}
public:
void v3errorEnd(const std::ostringstream& sstr) const VL_REQUIRES(V3Error::s().m_mutex);
void v3errorEnd(const std::ostringstream& sstr) const VL_RELEASE(V3Error::s().m_mutex);
void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN
VL_REQUIRES(V3Error::s().m_mutex);
VL_RELEASE(V3Error::s().m_mutex);
void width(int width, bool sized = true) {
m_data.m_sized = sized;
m_data.resize(width);

View File

@ -185,7 +185,7 @@ public:
// For getline()
string m_lineChars; ///< Characters left for next line
void v3errorEnd(std::ostringstream& str) VL_REQUIRES(V3Error::s().m_mutex) {
void v3errorEnd(std::ostringstream& str) VL_RELEASE(V3Error::s().m_mutex) {
fileline()->v3errorEnd(str);
}

View File

@ -121,12 +121,11 @@ std::ostream& operator<<(std::ostream& str, const Castable& rhs) {
}
#define v3widthWarn(lhs, rhs, msg) \
v3errorEnd((V3Error::s().m_mutex.lock(), \
V3Error::s().v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
: (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \
: V3ErrorCode::WIDTH), \
(V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \
V3Error::s().m_mutex.unlock()
v3errorEnd( \
v3errorBuildMessage(V3Error::v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
: (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \
: V3ErrorCode::WIDTH), \
msg))
//######################################################################
// Width state, as a visitor of each AstNode