Replace the virtual type() method on AstNode with a non-virtual, inlined
accessor to a const member variable m_type. This means that in order to be
able to use this for type testing, it needs to be initialized based on the
final type of the node. This is achieved by passing the relevant AstType
value back through the constructor call chain. Most of the boilerplate
involved is auto generated by first feeding V3AstNodes.h through astgen to
get V3AstNodes__gen.h, which is then included in V3Ast.h. No client code
needs to be aware and there is no functional change intended.
Eliminating the virtual function call to fetch the node type identifier
results in measured compilation speed improvement of 5-10% as it
eliminates up to 20% of all mispredicted branches from the execution.
dynamic_cast can have large run-time cost, so here we implement type
tests for AstNode instances by checking the unique type() property, which
in turn is a constant generated by astgen. For leaf types in the AstNode
type hierarchy, this is a simple equality check. To handle intermediate
types, we generate the type ids of leaf types in a pre-order traversal of
the type hierarchy. This yields contiguous ranges of ids for sub-type
trees, which means we can check membership of a non-leaf type via 2
comparisons against a low and high id. This single patch makes Verilator
itself 6-13% faster (depending on which optimizations are enabled) on a
large design of over 250k lines of Verilog.
The intention was that all subclasses of AstNode which are
intermediate must be abstract as well and called AstNode*. This was
violated recently by 28b9db1903. This
patch restores that property by:
- Renaming AstFile to AstNodeFile
- Introducing AstNodeSimpleText as the common base of AstText and
AstTextBlock, rather than AstTextBlock deriving from AstText.