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:
parent
7cb6dc664e
commit
70603bb752
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
57
src/V3Ast.h
57
src/V3Ast.h
|
|
@ -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()
|
||||
<< "'");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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: ");
|
||||
}
|
||||
|
|
|
|||
15
src/astgen
15
src/astgen
|
|
@ -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))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue