From 1a77030c9bddb4f28ddb3b89393c07e7581f234c Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Sat, 5 Aug 2023 07:24:00 +0000 Subject: [PATCH] Internals: Speedup to only typecheck node child getters in debug builds (#4394) --- src/V3Ast.h | 35 ++++++++++++++++++++++++++++------- src/astgen | 4 ++-- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 1be69f7cb..f763284ca 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -82,6 +82,17 @@ using MTaskIdSet = std::set; // Set of mtaskIds for Var sorting // Ast*' is returned. #define VN_AS(nodep, nodetypename) (AstNode::privateAs(nodep)) +// Same as VN_AS, but only checks the type in debug builds. Type checking is less critical in node +// child getters (the strongly-typed functions that wrap op*p pointers). This is because the op*p +// pointers are usually populated by code that already asserts the correct type. Having fewer type +// assertions yields better performance in release builds. +#ifdef VL_DEBUG +#define VN_DBG_AS(nodep, nodetypename) VN_AS(nodep, nodetypename) +#else +#define VN_DBG_AS(nodep, nodetypename) \ + (AstNode::unsafePrivateAs(nodep)) +#endif + // (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only) #define VN_DELETED(nodep) VL_UNLIKELY((uint64_t)(nodep) == 0x1) @@ -2067,24 +2078,34 @@ public: return nodep && privateTypeTest(nodep) ? reinterpret_cast(nodep) : nullptr; } - // For use via the VN_AS macro only + // For use via privateAs or the VN_DBG_AS macro only template - static T* privateAs(AstNode* nodep) VL_PURE { + static T* unsafePrivateAs(AstNode* nodep) VL_PURE { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); - UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, - "AstNode is not of expected type, but instead has type '" << nodep->typeName() - << "'"); return reinterpret_cast(nodep); } template - static const T* privateAs(const AstNode* nodep) VL_PURE { + static const T* unsafePrivateAs(const AstNode* nodep) VL_PURE { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); + return reinterpret_cast(nodep); + } + + // For use via the VN_AS macro only + template + static T* privateAs(AstNode* nodep) VL_PURE { UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, "AstNode is not of expected type, but instead has type '" << nodep->typeName() << "'"); - return reinterpret_cast(nodep); + return unsafePrivateAs(nodep); + } + template + static const T* privateAs(const AstNode* nodep) VL_PURE { + UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, + "AstNode is not of expected type, but instead has type '" << nodep->typeName() + << "'"); + return unsafePrivateAs(nodep); } // Predicate that returns true if the given 'nodep' might have a descendant of type 'T_Node'. diff --git a/src/astgen b/src/astgen index e567b4c21..a7f12ef14 100755 --- a/src/astgen +++ b/src/astgen @@ -948,8 +948,8 @@ def write_ast_macros(filename): if not op: continue name, monad, kind = op - retrieve = ("VN_AS(op{n}p(), {kind})" if kind != "Node" else - "op{n}p()").format(n=n, kind=kind) + retrieve = ("VN_DBG_AS(op{n}p(), {kind})" if kind != "Node" + else "op{n}p()").format(n=n, kind=kind) if monad == "List": emitBlock('''\ Ast{kind}* {name}() const VL_MT_STABLE {{ return {retrieve}; }}