Add static assertions for unnecessary VN_IS/VN_AS/VN_CAST

Fail at compile time if the result of these macros can be statically
determined (i.e.: they aways succeed or always fail). Remove unnecessary
casts discovered. No functional change.
This commit is contained in:
Geza Lore 2021-10-22 17:36:58 +01:00
parent 7cb6dc664e
commit 70603bb752
18 changed files with 83 additions and 59 deletions

View File

@ -489,8 +489,7 @@ private:
// METHODS
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
// Move always to appropriate ACTIVE based on its sense list
if (oldsensesp && oldsensesp->sensesp() && VN_IS(oldsensesp->sensesp(), SenItem)
&& VN_AS(oldsensesp->sensesp(), SenItem)->isNever()) {
if (oldsensesp && oldsensesp->sensesp() && oldsensesp->sensesp()->isNever()) {
// Never executing. Kill it.
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");

View File

@ -70,8 +70,7 @@ private:
V3Const::constifyExpensiveEdit(nodep);
AstSenTree* sensesp = nodep->sensesp();
UASSERT_OBJ(sensesp, nodep, "nullptr");
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
&& VN_AS(sensesp->sensesp(), SenItem)->isNever()) {
if (sensesp->sensesp() && sensesp->sensesp()->isNever()) {
// Never executing. Kill it.
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");

View File

@ -62,17 +62,20 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
// (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<Ast##nodetypename>(nodep))
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename, decltype(nodep)>(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<Ast##nodetypename>(nodep))
#define VN_CAST_CONST(nodep, nodetypename) (AstNode::privateCastConst<Ast##nodetypename>(nodep))
#define VN_CAST(nodep, nodetypename) \
(AstNode::privateCast<Ast##nodetypename, decltype(nodep)>(nodep))
#define VN_CAST_CONST(nodep, nodetypename) \
(AstNode::privateCastConst<Ast##nodetypename, decltype(nodep)>(nodep))
// (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<Ast##nodetypename>(nodep))
#define VN_AS_CONST(nodep, nodetypename) (AstNode::privateAsConst<Ast##nodetypename>(nodep))
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
#define VN_AS_CONST(nodep, nodetypename) \
(AstNode::privateAsConst<Ast##nodetypename, decltype(nodep)>(nodep))
// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
#define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1)
@ -1847,28 +1850,58 @@ private:
// For internal use only.
template <typename T> inline static bool privateTypeTest(const AstNode* nodep);
template <typename TargetType, typename DeclType> constexpr static bool uselessCast() {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
return std::is_base_of<TargetType, NonCV>::value;
}
template <typename TargetType, typename DeclType> constexpr static bool impossibleCast() {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
return !std::is_base_of<NonCV, TargetType>::value;
}
public:
// For use via the VN_IS macro only
template <typename T> inline static bool privateIs(const AstNode* nodep) {
template <typename T, typename E> inline static bool privateIs(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_IS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_IS, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep);
}
// For use via the VN_CAST macro only
template <typename T> inline static T* privateCast(AstNode* nodep) {
return privateIs<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
template <typename T, typename E> inline static T* privateCast(AstNode* nodep) {
static_assert(!uselessCast<T, E>(),
"Unnecessary VN_CAST, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
}
// For use via the VN_CAST_CONST macro only
template <typename T> inline static const T* privateCastConst(const AstNode* nodep) {
return privateIs<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
template <typename T, typename E>
inline static const T* privateCastConst(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(),
"Unnecessary VN_CAST_CONST, node known to have target type.");
static_assert(!impossibleCast<T, E>(),
"Unnecessary VN_CAST_CONST, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
}
// For use via the VN_AS macro only
template <typename T> inline static T* privateAs(AstNode* nodep) {
template <typename T, typename E> inline static T* privateAs(AstNode* nodep) {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return reinterpret_cast<T*>(nodep);
}
// For use via the VN_AS_CONST macro only
template <typename T> inline static const T* privateAsConst(const AstNode* nodep) {
template <typename T, typename E> inline static const T* privateAsConst(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(),
"Unnecessary VN_AS_CONST, node known to have target type.");
static_assert(!impossibleCast<T, E>(),
"Unnecessary VN_AS_CONST, node cannot be this type.");
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");

View File

@ -1456,13 +1456,9 @@ public:
ASTNODE_NODE_FUNCS(EnumItemRef)
virtual void dump(std::ostream& str) const override;
virtual string name() const override { return itemp()->name(); }
virtual const char* broken() const override {
BROKEN_RTN(!VN_IS(itemp(), EnumItem));
return nullptr;
}
virtual int instrCount() const override { return 0; }
virtual void cloneRelink() override {
if (m_itemp->clonep()) m_itemp = VN_AS(m_itemp->clonep(), EnumItem);
if (m_itemp->clonep()) m_itemp = m_itemp->clonep();
}
virtual bool same(const AstNode* samep) const override {
const AstEnumItemRef* sp = static_cast<const AstEnumItemRef*>(samep);
@ -4976,7 +4972,7 @@ public:
virtual void dump(std::ostream& str) const override;
virtual const char* broken() const override {
for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
BROKEN_RTN(!VN_IS(it->second, InitItem));
BROKEN_RTN(!it->second);
BROKEN_RTN(!it->second->brokeExists());
}
return nullptr;

View File

@ -197,7 +197,7 @@ private:
if (nodep->dtypep()) {
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep,
UASSERT_OBJ(nodep->dtypep(), nodep,
"Non-dtype link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
}
if (v3Global.assertDTypesResolved()) {

View File

@ -2671,7 +2671,7 @@ private:
{
AstUser4InUse m_inuse4;
// Mark x in SENITEM(x)
for (AstSenItem* senp = VN_AS(nodep->sensesp(), SenItem); senp;
for (AstSenItem* senp = nodep->sensesp(); senp;
senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->varrefp() && senp->varrefp()->varScopep()) {
senp->varrefp()->varScopep()->user4(1);
@ -2682,7 +2682,7 @@ private:
// Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together.
// Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs
// Make things a little faster; check first if we need a sort
for (AstSenItem *nextp, *senp = VN_AS(nodep->sensesp(), SenItem); senp; senp = nextp) {
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
nextp = VN_AS(senp->nextp(), SenItem);
// cppcheck-suppress unassignedVariable // cppcheck bug
SenItemCmp cmp;
@ -2690,7 +2690,7 @@ private:
// Something's out of order, sort it
senp = nullptr;
std::vector<AstSenItem*> vec;
for (AstSenItem* senp = VN_AS(nodep->sensesp(), SenItem); senp;
for (AstSenItem* senp = nodep->sensesp(); senp;
senp = VN_AS(senp->nextp(), SenItem)) {
vec.push_back(senp);
}
@ -2702,7 +2702,7 @@ private:
}
// Pass2, remove dup edges
for (AstSenItem *nextp, *senp = VN_AS(nodep->sensesp(), SenItem); senp; senp = nextp) {
for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) {
nextp = VN_AS(senp->nextp(), SenItem);
AstSenItem* const litemp = senp;
AstSenItem* const ritemp = nextp;

View File

@ -533,13 +533,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(",");
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
} else {
if (!assigntop->selfPointer().empty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
for (int word = VL_WORDS_I(upWidth) - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning
@ -558,13 +556,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(",");
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
} else {
if (!assigntop->selfPointer().empty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
for (int word = EMITC_NUM_CONSTW - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning

View File

@ -898,7 +898,7 @@ public:
}
}
virtual void visit(AstTextBlock* nodep) override {
visit(VN_AS(nodep, NodeSimpleText));
visit(static_cast<AstNodeSimpleText*>(nodep));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp);
if (nodep->commas() && childp->nextp()) puts(", ");
@ -978,7 +978,7 @@ public:
}
virtual void visit(AstRedXor* nodep) override {
if (nodep->lhsp()->isWide()) {
visit(VN_AS(nodep, NodeUniop));
visit(static_cast<AstNodeUniop*>(nodep));
} else {
AstVarRef* const vrefp = VN_CAST(nodep->lhsp(), VarRef);
const int widthPow2 = vrefp ? vrefp->varp()->dtypep()->widthPow2()

View File

@ -382,7 +382,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
}
}
virtual void visit(AstTextBlock* nodep) override {
visit(VN_AS(nodep, NodeSimpleText));
visit(static_cast<AstNodeSimpleText*>(nodep));
{
VL_RESTORER(m_suppressSemi);
m_suppressVarSemi = nodep->commas();

View File

@ -843,10 +843,9 @@ private:
UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
"Can't replace lvalue assignments with const var");
AstNode* substp = m_replaceTreep->cloneTree(false);
UASSERT_OBJ(
!(VN_IS(nodep, NodeVarRef) && VN_IS(substp, NodeVarRef) && nodep->same(substp)),
// Prevent an infinite loop...
substp, "Replacing node with itself; perhaps circular logic?");
UASSERT_OBJ(!(VN_IS(substp, NodeVarRef) && nodep->same(substp)),
// Prevent an infinite loop...
substp, "Replacing node with itself; perhaps circular logic?");
// Which fileline() to use?
// If replacing with logic, an error/warning is likely to want to point to the logic
// IE what we're replacing with.

View File

@ -359,7 +359,7 @@ private:
// Each inlined cell that contain an interface variable need to
// copy the IfaceRefDType and point it to the newly cloned
// interface cell.
AstIfaceRefDType* newdp = VN_AS(ifacerefp->cloneTree(false), IfaceRefDType);
AstIfaceRefDType* newdp = ifacerefp->cloneTree(false);
nodep->dtypep(newdp);
ifacerefp->addNextHere(newdp);
// Relink to point to newly cloned cell

View File

@ -2093,7 +2093,7 @@ private:
nodep->v3error("'super' used on non-extended class (IEEE 1800-2017 8.15)");
m_ds.m_dotErr = true;
} else {
const auto cextp = VN_AS(classp->extendsp(), ClassExtends);
const auto cextp = classp->extendsp();
UASSERT_OBJ(cextp, nodep, "Bad super extends link");
const auto sclassp = cextp->classp();
UASSERT_OBJ(sclassp, nodep, "Bad superclass");
@ -2311,8 +2311,7 @@ private:
refp->dotted(dotted.substr(0, pos));
newp = refp;
} else {
newp = new AstUnlinkedRef(nodep->fileline(), VN_AS(refp, VarXRef),
refp->name(),
newp = new AstUnlinkedRef(nodep->fileline(), refp, refp->name(),
m_ds.m_unlinkedScopep->unlinkFrBack());
m_ds.m_unlinkedScopep = nullptr;
m_ds.m_unresolved = false;

View File

@ -1262,11 +1262,11 @@ static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top) {
const bool fromInitial = fromp->hasInitial() || fromp->hasSettle();
if (toInitial != fromInitial) return true;
const AstSenItem* fromSenListp = VN_AS(fromp->sensesp(), SenItem);
const AstSenItem* toSenListp = VN_AS(top->sensesp(), SenItem);
const AstSenItem* fromSenListp = fromp->sensesp();
const AstSenItem* toSenListp = top->sensesp();
UASSERT_OBJ(fromSenListp, fromp, "sensitivity list item is not an AstSenItem");
UASSERT_OBJ(toSenListp, top, "sensitivity list item is not an AstSenItem");
UASSERT_OBJ(fromSenListp, fromp, "sensitivity list empty");
UASSERT_OBJ(toSenListp, top, "sensitivity list empty");
if (fromSenListp->nextp()) return false;
if (toSenListp->nextp()) return false;

View File

@ -452,7 +452,7 @@ class ParamProcessor final {
<< " has hier_block metacomment, hierarchical verilation"
<< " supports only integer/floating point/string parameters");
}
} else if (VN_IS(pinp->modPTypep(), ParamTypeDType)) {
} else {
pinp->v3error(AstNode::prettyNameQ(modp->origName())
<< " has hier_block metacomment, but 'parameter type' is not supported");
}

View File

@ -966,11 +966,11 @@ private:
badNodeType(nodep);
return;
}
AstNodeFTask* funcp = VN_AS(nodep->taskp(), NodeFTask);
AstNodeFTask* funcp = nodep->taskp();
UASSERT_OBJ(funcp, nodep, "Not linked");
if (m_params) V3Width::widthParamsEdit(funcp);
VL_DANGLING(funcp); // Make sure we've sized the function
funcp = VN_AS(nodep->taskp(), NodeFTask);
funcp = nodep->taskp();
UASSERT_OBJ(funcp, nodep, "Not linked");
// Apply function call values to function
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());

View File

@ -145,7 +145,7 @@ private:
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) override {
AstCell* const cellp = VN_CAST(nodep->aboveCellp(), Cell);
AstCell* const cellp = nodep->aboveCellp();
if (cellp && VN_IS(cellp->modp(), Iface)) {
AstCFunc* const origSubFunc = m_initSubFuncp;
int origSubStmts = m_initSubStmts;

View File

@ -4365,7 +4365,7 @@ private:
}
virtual void visit(AstFuncRef* nodep) override {
visit(VN_AS(nodep, NodeFTaskRef));
visit(static_cast<AstNodeFTaskRef*>(nodep));
nodep->dtypeFrom(nodep->taskp());
// if (debug()) nodep->dumpTree(cout, " FuncOut: ");
}

View File

@ -333,12 +333,11 @@ class Cpt:
" iterateAndNextNull(nodep->lhsp());\n" +
"".join(out_for_type_sc))
if out_for_type[0]:
self.print(
" iterateAndNextNull(nodep->rhsp());\n" +
" AstNodeTriop *tnp = VN_CAST(nodep, NodeTriop);\n"
+
" if (tnp && tnp->thsp()) iterateAndNextNull(tnp->thsp());\n"
+ "".join(out_for_type) + " }\n")
self.print(" iterateAndNextNull(nodep->rhsp());\n")
if is_subclass_of(typen, "NodeTriop"):
self.print(
" iterateAndNextNull(nodep->thsp());\n")
self.print("".join(out_for_type) + " }\n")
elif len(out_for_type) > 0: # Other types with something to print
skip = typen in self.tree_skip_visit
gen = "Gen" if skip else ""
@ -450,6 +449,10 @@ def children_of(typen):
return cllist
def is_subclass_of(typen, what):
return typen == what or (typen in children_of(what))
# ---------------------------------------------------------------------