diff --git a/include/verilated.cpp b/include/verilated.cpp index 63affb724..dc23517cc 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -693,7 +693,7 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE { } template -std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) { +std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) VL_MT_SAFE { const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp(); const std::string suffix = ctxImpp->timeFormatSuffix(); const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15 diff --git a/include/verilated_imp.h b/include/verilated_imp.h index e357ddcc8..dfc1cdf92 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -148,7 +148,7 @@ public: private: VL_UNCOPYABLE(VerilatedThreadMsgQueue); // METHODS - static VerilatedThreadMsgQueue& threadton() { + static VerilatedThreadMsgQueue& threadton() VL_MT_SAFE { static thread_local VerilatedThreadMsgQueue t_s; return t_s; } diff --git a/include/verilatedos.h b/include/verilatedos.h index da40b1edd..625552d4f 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -603,8 +603,12 @@ reverse_wrapper reverse_view(const T& v) { } // C++17's std::as_const +// `VL_MT_SAFE` annotation only applies to this function. +// Object that is returned by this function is not considered +// as MT_SAFE and any function call on this object still +// needs to be `VL_MT_SAFE`. template -T const& as_const(T& v) { +T const& as_const(T& v) VL_MT_SAFE { return v; } diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index dba884b49..0cea38289 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -49,14 +49,16 @@ class VlAnnotations: release: bool = False def is_mt_safe_context(self): - return (not (self.mt_unsafe or self.mt_unsafe_one) - and (self.mt_safe or self.mt_start)) + return (not (self.mt_unsafe or self.mt_unsafe_one) and self.mt_safe) def is_pure_context(self): return self.pure def is_stabe_tree_context(self): - return self.stable_tree + # stable tree context requires calls to be marked + # as MT_SAFE or MT_STABLE + # Functions in MT_START needs to be MT_SAFE or MT_STABLE + return self.stable_tree or self.mt_start def is_mt_unsafe_call(self): return self.mt_unsafe or self.mt_unsafe_one @@ -389,7 +391,8 @@ class CallAnnotationsValidator: # stable tree context if ctx.is_stabe_tree_context(): - if not (annotations.is_stabe_tree_call() + if annotations.is_mt_unsafe_call() or not ( + annotations.is_stabe_tree_call() or annotations.is_pure_call() or self.check_mt_safe_call(node, refd, annotations)): self.emit_diagnostic( @@ -417,7 +420,8 @@ class CallAnnotationsValidator: # stable tree context if ctx.is_stabe_tree_context(): - if not (annotations.is_pure_call() + if annotations.is_mt_unsafe_call() or not ( + annotations.is_pure_call() or annotations.is_mt_safe_call() or annotations.is_stabe_tree_call()): self.emit_diagnostic( @@ -465,11 +469,19 @@ class CallAnnotationsValidator: if not supported: self.iterate_children(node.get_children(), self.dispatch_node_inside_definition) - return + return True assert refd is not None if self._is_ignored_call(refd): - return + return True + + if "std::function" in refd.displayname: + # Workaroud for missing support for lambda annotations + # in c++11. + # If function takes std::function as argument, + # assume, that this std::function will be called inside it. + self.process_function_definition(node) + return False assert self._call_location is not None node_file = os.path.abspath(node.location.file.name) @@ -481,47 +493,40 @@ class CallAnnotationsValidator: or refd.kind == CursorKind.CXX_METHOD and refd.is_static_method()): self.process_function_call(refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Function pointer - if refd.kind in [ + elif refd.kind in [ CursorKind.VAR_DECL, CursorKind.FIELD_DECL, CursorKind.PARM_DECL ]: self.process_function_call(refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Non-static class methods - if refd.kind == CursorKind.CXX_METHOD: + elif refd.kind == CursorKind.CXX_METHOD: self.process_method_call(node, refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Conversion method (e.g. `operator int()`) - if refd.kind == CursorKind.CONVERSION_FUNCTION: + elif refd.kind == CursorKind.CONVERSION_FUNCTION: self.process_method_call(node, refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Constructors - if refd.kind == CursorKind.CONSTRUCTOR: + elif refd.kind == CursorKind.CONSTRUCTOR: self.process_constructor_call(refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return - - # Ignore other callables - print(f"{refd.location.file.name}:{refd.location.line}: " - f"{refd.displayname} {refd.kind}\n" - f" from: {node.location.file.name}:{node.location.line}") + else: + # Ignore other callables, but report them + print("Unknown callable: " + f"{refd.location.file.name}:{refd.location.line}: " + f"{refd.displayname} {refd.kind}\n" + f" from: {node.location.file.name}:{node.location.line}") + return True # Definition handling def dispatch_node_inside_definition(self, node: clang.cindex.Cursor): if node.kind == CursorKind.CALL_EXPR: - self.dispatch_call_node(node) + if self.dispatch_call_node(node) is False: + return None + elif node.is_definition() and node.kind in [ + CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, + CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION + ]: + self.process_function_definition(node) return None return self.iterate_children(node.get_children(), @@ -556,12 +561,14 @@ class CallAnnotationsValidator: # for callees validation. self._caller = FunctionInfo.from_node(node, refd, def_annotations | annotations) + prev_call_location = self._call_location self._call_location = self._caller self.iterate_children(node_children, self.dispatch_node_inside_definition) - self._call_location = None + self._call_location = prev_call_location + self._caller = prev_call_location return None @@ -826,7 +833,7 @@ class TopDownSummaryPrinter(): elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX: name += "is pure but calls non-pure function(s)" elif func.reason == DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX: - name += "calls stable_tree function(s) but isn't annotated as stable_tree" + name += "is stable_tree but calls non-stable_tree or non-mtsafe" else: name += "for unknown reason (please add description)" diff --git a/src/V3Active.cpp b/src/V3Active.cpp index a333f65f7..87194907f 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -54,7 +54,7 @@ private: const string m_name; // Only used for .dot file generation const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT) - string typestr() const { // " + string typestr() const VL_MT_SAFE { // " switch (m_type) { case VT_BLOCK: return "(||)"; // basic block node case VT_BRANCH: return "(&&)"; // if/else branch mode diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index e19729116..dcc43148c 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -285,7 +285,7 @@ string AstNode::vpiName(const string& namein) { return pretty; } -string AstNode::prettyTypeName() const { +string AstNode::prettyTypeName() const VL_MT_STABLE { if (name() == "") return typeName(); return std::string{typeName()} + " '" + prettyName() + "'"; } diff --git a/src/V3Ast.h b/src/V3Ast.h index ea3c1bb61..6a286bde8 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -470,7 +470,7 @@ public: _ENUM_MAX }; enum en m_e; - const char* ascii() const { + const char* ascii() const VL_MT_SAFE { static const char* const names[] = {"%E-unk", "bit", "byte", @@ -1693,13 +1693,14 @@ public: static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors) return std::string{"'"} + prettyName(namein) + "'"; } - static string - encodeName(const string& namein); // Encode user name into internal C representation + // Encode user name into internal C representation + static string encodeName(const string& namein); static string encodeNumber(int64_t num); // Encode number into internal C representation static string vcdName(const string& namein); // Name for printing out to vcd files string prettyName() const VL_MT_STABLE { return prettyName(name()); } string prettyNameQ() const { return prettyNameQ(name()); } - string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name) + // "VARREF" for error messages (NOT dtype's pretty name) + string prettyTypeName() const VL_MT_STABLE; virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); } FileLine* fileline() const VL_MT_SAFE { return m_fileline; } void fileline(FileLine* fl) { m_fileline = fl; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index e923385d3..cff2cfdbe 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1151,7 +1151,7 @@ public: void cloneRelink() override { V3ERROR_NA; } string name() const override VL_MT_STABLE { return "$root"; } void dump(std::ostream& str) const override; - AstNodeModule* topModulep() const { // Top module in hierarchy + AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy return modulesp(); // First one in the list, for now } AstTypeTable* typeTablep() { return m_typeTablep; } @@ -1789,7 +1789,7 @@ public: string dpiTmpVarType(const string& varName) const; // Return Verilator internal type for argument: CData, SData, IData, WData string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "", - bool asRef = false) const VL_MT_SAFE; + bool asRef = false) const VL_MT_STABLE; string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration @@ -2001,8 +2001,8 @@ public: string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); } void dump(std::ostream& str) const override; bool hasDType() const override { return true; } - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under + AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable + AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under void scopep(AstScope* nodep) { m_scopep = nodep; } bool isTrace() const { return m_trace; } void trace(bool flag) { m_trace = flag; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a88ef0a06..3ebd67499 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -397,7 +397,7 @@ string AstVar::verilogKwd() const { } string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc, - bool asRef) const VL_MT_SAFE { + bool asRef) const VL_MT_STABLE { UASSERT_OBJ(!forReturn, this, "Internal data is never passed as return, but as first argument"); string ostatic; diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index e3c001be9..5ae0074c4 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -55,14 +55,14 @@ public: return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className + "*>(voidSelf);\n"; } - static string symClassName() { + static string symClassName() VL_MT_STABLE { return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms"); } static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; } static string symClassAssign() { return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; } - static string prefixNameProtect(const AstNode* nodep) VL_MT_SAFE { // C++ name with prefix + static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { // C++ name with prefix return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name()); } static bool isAnonOk(const AstVar* varp) { diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 0bf14ae3f..8f1cf140b 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -165,7 +165,7 @@ private: static FileLineSingleton s; return s; } - static FileLine& defaultFileLine() { + static FileLine& defaultFileLine() VL_MT_SAFE { static FileLine s; return s; } @@ -364,7 +364,7 @@ public: private: string warnContext() const; string warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex); - const MsgEnBitSet& msgEn() const { return singleton().msgEn(m_msgEnIdx); } + const MsgEnBitSet& msgEn() const VL_MT_SAFE { return singleton().msgEn(m_msgEnIdx); } }; std::ostream& operator<<(std::ostream& os, FileLine* fileline); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 2929916bc..640cade21 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -76,7 +76,7 @@ public: ~GateEitherVertex() override = default; // ACCESSORS string dotStyle() const override { return m_consumed ? "" : "dotted"; } - AstScope* scopep() const { return m_scopep; } + AstScope* scopep() const VL_MT_STABLE { return m_scopep; } bool reducible() const { return m_reducible; } bool dedupable() const { return m_dedupable; } void setConsumed(const char* /*consumedReason*/) { @@ -133,7 +133,7 @@ public: , m_varScp{varScp} {} ~GateVarVertex() override = default; // ACCESSORS - AstVarScope* varScp() const { return m_varScp; } + AstVarScope* varScp() const VL_MT_STABLE { return m_varScp; } string name() const override VL_MT_STABLE { return (cvtToHex(m_varScp) + " " + varScp()->name()); } diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 3a80da8c2..9e5e295c5 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -385,7 +385,7 @@ void V3Number::create(const char* sourcep) { // m_value[0]); } -void V3Number::nodep(AstNode* nodep) { +void V3Number::nodep(AstNode* nodep) VL_MT_STABLE { m_nodep = nodep; if (!nodep) return; m_fileline = nodep->fileline(); @@ -498,7 +498,7 @@ V3Number& V3Number::setMask(int nbits) { //====================================================================== // ACCESSORS - as strings -string V3Number::ascii(bool prefixed, bool cleanVerilog) const VL_MT_SAFE { +string V3Number::ascii(bool prefixed, bool cleanVerilog) const VL_MT_STABLE { std::ostringstream out; if (is1Step()) { @@ -604,11 +604,11 @@ string V3Number::displayPad(size_t fmtsize, char pad, bool left, const string& i return left ? (in + padding) : (padding + in); } -string V3Number::displayed(AstNode* nodep, const string& vformat) const VL_MT_SAFE { +string V3Number::displayed(AstNode* nodep, const string& vformat) const VL_MT_STABLE { return displayed(nodep->fileline(), vformat); } -string V3Number::displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE { +string V3Number::displayed(FileLine* fl, const string& vformat) const VL_MT_STABLE { auto pos = vformat.cbegin(); UASSERT(pos != vformat.cend() && pos[0] == '%', "$display-like function with non format argument " << *this); @@ -847,7 +847,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE } } -string V3Number::toDecimalS() const { +string V3Number::toDecimalS() const VL_MT_STABLE { if (isNegative()) { V3Number lhsNoSign = *this; lhsNoSign.opNegate(*this); @@ -857,7 +857,7 @@ string V3Number::toDecimalS() const { } } -string V3Number::toDecimalU() const { +string V3Number::toDecimalU() const VL_MT_STABLE { const int maxdecwidth = (width() + 3) * 4 / 3; // Or (maxdecwidth+7)/8], but can't have more than 4 BCD bits per word @@ -1013,7 +1013,7 @@ bool V3Number::isAllX() const VL_MT_SAFE { } return true; } -bool V3Number::isEqZero() const { +bool V3Number::isEqZero() const VL_MT_SAFE { if (isString()) return m_data.str().empty(); for (int i = 0; i < words(); i++) { const ValueAndX v = m_data.num()[i]; diff --git a/src/V3Number.h b/src/V3Number.h index b94a212fb..46ba16094 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -52,7 +52,7 @@ public: uint32_t m_value; // Each bit is true if it's X or Z, 10=z, 11=x uint32_t m_valueX; - bool operator==(const ValueAndX& other) const { + bool operator==(const ValueAndX& other) const VL_MT_SAFE { return m_value == other.m_value && m_valueX == other.m_valueX; } }; @@ -210,7 +210,7 @@ public: UASSERT(isString(), "`str` member accessed when data type is " << m_type); return m_string; } - const std::string& str() const { + const std::string& str() const VL_MT_SAFE { UASSERT(isString(), "`str` member accessed when data type is " << m_type); return m_string; } @@ -356,7 +356,7 @@ class V3Number final { void opCleanThis(bool warnOnTruncation = false); public: - void nodep(AstNode* nodep); + void nodep(AstNode* nodep) VL_MT_STABLE; FileLine* fileline() const VL_MT_SAFE { return m_fileline; } V3Number& setZero(); V3Number& setQuad(uint64_t value); @@ -560,8 +560,8 @@ private: } } static string displayPad(size_t fmtsize, char pad, bool left, const string& in) VL_PURE; - string displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE; - string displayed(const string& vformat) const VL_MT_SAFE { + string displayed(FileLine* fl, const string& vformat) const VL_MT_STABLE; + string displayed(const string& vformat) const VL_MT_STABLE { return displayed(m_fileline, vformat); } @@ -583,8 +583,8 @@ public: V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc // ACCESSORS - string ascii(bool prefixed = true, bool cleanVerilog = false) const VL_MT_SAFE; - string displayed(AstNode* nodep, const string& vformat) const VL_MT_SAFE; + string ascii(bool prefixed = true, bool cleanVerilog = false) const VL_MT_STABLE; + string displayed(AstNode* nodep, const string& vformat) const VL_MT_STABLE; static bool displayedFmtLegal(char format, bool isScan); // Is this a valid format letter? int width() const VL_MT_SAFE { return m_data.width(); } int widthMin() const; // Minimum width that can represent this number (~== log2(num)+1) @@ -612,7 +612,7 @@ public: return m_data.type() == V3NumberDataType::LOGIC || m_data.type() == V3NumberDataType::DOUBLE; } - bool isNegative() const { return !isString() && bitIs1(width() - 1); } + bool isNegative() const VL_MT_SAFE { return !isString() && bitIs1(width() - 1); } bool is1Step() const VL_MT_SAFE { return m_data.m_is1Step; } bool isNull() const VL_MT_SAFE { return m_data.m_isNull; } bool isFourState() const VL_MT_SAFE; @@ -626,7 +626,7 @@ public: } bool isAllZ() const VL_MT_SAFE; bool isAllX() const VL_MT_SAFE; - bool isEqZero() const; + bool isEqZero() const VL_MT_SAFE; bool isNeqZero() const; bool isBitsZero(int msb, int lsb) const; bool isEqOne() const; @@ -642,8 +642,8 @@ public: uint64_t toUQuad() const VL_MT_SAFE; int64_t toSQuad() const VL_MT_SAFE; string toString() const VL_MT_SAFE; - string toDecimalS() const; // return ASCII signed decimal number - string toDecimalU() const; // return ASCII unsigned decimal number + string toDecimalS() const VL_MT_STABLE; // return ASCII signed decimal number + string toDecimalU() const VL_MT_STABLE; // return ASCII unsigned decimal number double toDouble() const VL_MT_SAFE; V3Hash toHash() const; uint32_t edataWord(int eword) const; diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index c1e3f2a91..d51a540a0 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -123,7 +123,7 @@ public: virtual bool domainMatters() = 0; // ACCESSORS - AstSenTree* domainp() const { return m_domainp; } + AstSenTree* domainp() const VL_MT_STABLE { return m_domainp; } void domainp(AstSenTree* domainp) { #if VL_DEBUG UASSERT(!m_domainp, "Domain should only be set once"); @@ -154,8 +154,8 @@ public: bool domainMatters() override { return true; } // ACCESSORS - AstNode* nodep() const { return m_nodep; } - AstScope* scopep() const { return m_scopep; } + AstNode* nodep() const VL_MT_STABLE { return m_nodep; } + AstScope* scopep() const VL_MT_STABLE { return m_scopep; } AstSenTree* hybridp() const { return m_hybridp; } // LCOV_EXCL_START // Debug code @@ -181,7 +181,7 @@ public: // LCOV_EXCL_START // Debug code string dotShape() const override final { return "ellipse"; } - virtual string nameSuffix() const = 0; + virtual string nameSuffix() const VL_MT_SAFE = 0; string name() const override final VL_MT_STABLE { return cvtToHex(m_vscp) + " " + nameSuffix() + "\\n " + m_vscp->name(); } @@ -199,7 +199,7 @@ public: bool domainMatters() override { return true; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return ""; } + string nameSuffix() const override VL_MT_SAFE { return ""; } string dotColor() const override { return "grey"; } // LCOV_EXCL_STOP }; @@ -215,7 +215,7 @@ public: bool domainMatters() override { return false; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return "PRE"; } + string nameSuffix() const override VL_MT_SAFE { return "PRE"; } string dotColor() const override { return "green"; } // LCOV_EXCL_STOP }; @@ -231,7 +231,7 @@ public: bool domainMatters() override { return false; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return "POST"; } + string nameSuffix() const override VL_MT_SAFE { return "POST"; } string dotColor() const override { return "red"; } // LCOV_EXCL_STOP }; @@ -247,7 +247,7 @@ public: bool domainMatters() override { return false; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return "PORD"; } + string nameSuffix() const override VL_MT_SAFE { return "PORD"; } string dotColor() const override { return "blue"; } // LCOV_EXCL_STOP }; diff --git a/src/V3OrderMoveGraph.h b/src/V3OrderMoveGraph.h index 426b410ff..fb54ac7a0 100644 --- a/src/V3OrderMoveGraph.h +++ b/src/V3OrderMoveGraph.h @@ -75,7 +75,7 @@ public: } return nm; } - OrderLogicVertex* logicp() const { return m_logicp; } + OrderLogicVertex* logicp() const VL_MT_STABLE { return m_logicp; } bool isWait() const { return m_state == POM_WAIT; } void setReady() { UASSERT(m_state == POM_WAIT, "Wait->Ready on node not in proper state"); diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 04d34e842..a10ffec1c 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -268,7 +268,7 @@ public: uint32_t id() const override { return m_serialId; } void id(uint32_t id) { m_serialId = id; } // Abstract cost of every logic mtask - uint32_t cost() const override { return m_cost; } + uint32_t cost() const override VL_MT_SAFE { return m_cost; } void setCost(uint32_t cost) { m_cost = cost; } // For tests only uint32_t stepCost() const { return stepCost(m_cost); } static uint32_t stepCost(uint32_t cost) { diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index b83679a06..0827ca381 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -72,7 +72,7 @@ public: , m_bodyp{bodyp} , m_id{id} {} AstMTaskBody* bodyp() const { return m_bodyp; } - uint32_t id() const override { return m_id; } + uint32_t id() const override VL_MT_SAFE { return m_id; } uint32_t priority() const { return m_priority; } void priority(uint32_t pri) { m_priority = pri; } uint32_t cost() const override { return m_cost; } diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index c7f92195a..69e093fcc 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -85,8 +85,14 @@ public: void resize(unsigned n) VL_MT_UNSAFE; // Enqueue a job for asynchronous execution + // Due to missing support for lambda annotations in c++11, + // `clang_check_attributes` script assumes that if + // function takes `std::function` as argument, it + // will call it. `VL_MT_START` here indicates that + // every function call inside this `std::function` requires + // annotations. template - std::future enqueue(std::function&& f) VL_MT_SAFE; + std::future enqueue(std::function&& f) VL_MT_START; // Request exclusive access to processing. // It sends request to stop all other threads and waits for them to stop. @@ -190,7 +196,7 @@ T V3ThreadPool::waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mute } template -std::future V3ThreadPool::enqueue(std::function&& f) VL_MT_SAFE { +std::future V3ThreadPool::enqueue(std::function&& f) VL_MT_START { std::shared_ptr> prom = std::make_shared>(); std::future result = prom->get_future(); pushJob(prom, std::move(f)); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index afbba68f5..a71ad592e 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -81,7 +81,7 @@ private: ~DependencyVertex() override = default; // ACCESSORS - virtual AstNode* nodep() const { return m_nodep; } + virtual AstNode* nodep() const VL_MT_STABLE { return m_nodep; } }; // NODE STATE diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 0028d2bc8..61720c2a4 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -152,7 +152,7 @@ public: , m_nodep{nodep} {} ~TristateVertex() override = default; // ACCESSORS - AstNode* nodep() const { return m_nodep; } + AstNode* nodep() const VL_MT_STABLE { return m_nodep; } const AstVar* varp() const { return VN_CAST(nodep(), Var); } string name() const override VL_MT_STABLE { return ((isTristate() ? "tri\\n" @@ -170,9 +170,9 @@ public: } FileLine* fileline() const override { return nodep()->fileline(); } void isTristate(bool flag) { m_isTristate = flag; } - bool isTristate() const { return m_isTristate; } + bool isTristate() const VL_MT_SAFE { return m_isTristate; } void feedsTri(bool flag) { m_feedsTri = flag; } - bool feedsTri() const { return m_feedsTri; } + bool feedsTri() const VL_MT_SAFE { return m_feedsTri; } void processed(bool flag) { m_processed = flag; } bool processed() const { return m_processed; } }; diff --git a/test_regress/t/t_dist_attributes_bad.out b/test_regress/t/t_dist_attributes_bad.out index e7649a02f..fea14b7b0 100644 --- a/test_regress/t/t_dist_attributes_bad.out +++ b/test_regress/t/t_dist_attributes_bad.out @@ -65,7 +65,7 @@ t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:155: [mt_start] TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -143,7 +143,7 @@ t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:212: [mt_start] TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -273,7 +273,7 @@ t/t_dist_attributes_bad.cpp:175: [mt_safe] TestClass t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:175: [mt_start] TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -299,7 +299,7 @@ t/t_dist_attributes_bad.h:238: [mt_safe] TestClass t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:238: [mt_start] TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -327,7 +327,7 @@ t/t_dist_attributes_bad.h:170: [mt_start] TestCla t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:119: [mt_start] TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) @@ -357,7 +357,7 @@ t/t_dist_attributes_bad.h:170: [mt_start] TestCla t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:173: [mt_start] TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) @@ -467,7 +467,7 @@ t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:93: [mt_start] TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) @@ -585,7 +585,7 @@ t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:141: [mt_start] TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) @@ -759,7 +759,7 @@ t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_ t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "ifh_test_caller_func_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "ifh_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:53: [mt_start] ifh_test_caller_func_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) @@ -789,7 +789,7 @@ t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_ t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:97: [mt_start] ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) @@ -899,7 +899,7 @@ t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_ t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "nsf_test_caller_func_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "nsf_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:42: [mt_start] nsf_test_caller_func_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) @@ -1017,7 +1017,7 @@ t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_ t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:83: [mt_start] nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) @@ -1163,7 +1163,7 @@ t/t_dist_attributes_bad.cpp:60: [mt_start] sfc_VL_ t/t_dist_attributes_bad.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "sfc_test_caller_func_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "sfc_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:63: [mt_start] sfc_test_caller_func_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &)