From ac622f9db8675cc2271aa1b08f2a3a7232c10b28 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 16 Oct 2021 19:29:38 +0100 Subject: [PATCH] Introduce VN_AS for downcasting to known AstNode subtype. VN_AS should be used over VN_CAST in code where the author knows up front (i.e.: statically) what the true type of the node is. This has multiple benefits over VN_CAST: - In the debug build: Asserts node type is as expected - In the optimized build: It is faster as no superfluous type test - And (I would argue most importantly) it documents intent in the code No current instances of VN_CAST changed in this patch --- src/V3Ast.h | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 9d7abd681..4fb190666 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -60,15 +60,21 @@ using MTaskIdSet = std::set; // Set of mtaskIds for Var sorting if (VL_UNCOVERABLE(reasonp)) return reasonp; \ } while (false) -// (V)erilator (N)ode is: True if AstNode is of a a given AstType +// (V)erilator (N)ode is: Returns true iff AstNode is of the given AstNode subtype, and not +// nullptr. #define VN_IS(nodep, nodetypename) (AstNode::privateIs(nodep)) -// (V)erilator (N)ode cast: Cast to given type if can; effectively -// dynamic_cast(nodep) +// (V)erilator (N)ode cast: More efficient but otherwise same as dynamic_cast, use this instead. +// Cast to given type if node is of such type, otherwise returns nullptr. #define VN_CAST(nodep, nodetypename) (AstNode::privateCast(nodep)) -#define VN_CAST_CONST(nodep, nodetypename) (AstNode::privateConstCast(nodep)) +#define VN_CAST_CONST(nodep, nodetypename) (AstNode::privateCastConst(nodep)) -// (V)erilator (N)ode deleted: Reference to deleted child (for assertions only) +// (V)erilator (N)ode as: Assert node is of given type then cast to that type. Node can be nullptr. +// Use this to downcast instead of VN_CAST when you know the true type of the node. +#define VN_AS(nodep, nodetypename) (AstNode::privateAs(nodep)) +#define VN_AS_CONST(nodep, nodetypename) (AstNode::privateAsConst(nodep)) + +// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only) #define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1) //###################################################################### @@ -1851,9 +1857,23 @@ public: return privateIs(nodep) ? reinterpret_cast(nodep) : nullptr; } // For use via the VN_CAST_CONST macro only - template inline static const T* privateConstCast(const AstNode* nodep) { + template inline static const T* privateCastConst(const AstNode* nodep) { return privateIs(nodep) ? reinterpret_cast(nodep) : nullptr; } + // For use via the VN_AS macro only + template inline static T* privateAs(AstNode* nodep) { + UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, + "AstNode is not of expected type, but instead has type '" << nodep->typeName() + << "'"); + return reinterpret_cast(nodep); + } + // For use via the VN_AS_CONST macro only + template inline static const T* privateAsConst(const AstNode* nodep) { + UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, + "AstNode is not of expected type, but instead has type '" << nodep->typeName() + << "'"); + return reinterpret_cast(nodep); + } }; // Specialisations of privateIs/privateCast