DFG: Make implementation more similar to AST
Use the same style, and reuse the bulk of astgen to generate DfgVertex related code. In particular allow for easier definition of custom DfgVertex sub-types that do not directly correspond to an AstNode sub-type. Also introduces specific names for the fixed arity vertices. No functional change intended.
This commit is contained in:
parent
56ac054fb2
commit
965d99f1bc
|
|
@ -1047,9 +1047,9 @@ Generating ``AstNode`` members
|
|||
Some of the member s of ``AstNode`` sub-classes are generated by ``astgen``.
|
||||
These are emitted as pre-processor macro definitions, which then need to be
|
||||
added to the ``AstNode`` sub-classes they correspond to. Specifically ``class
|
||||
AstFoo`` should contain an instance of ``ASTGEN_MEMBERS_Foo;`` at class scope.
|
||||
The ``astgen`` script checks and errors if this is not present. The method
|
||||
generated depends on whether the class is a concrete final class, or an
|
||||
AstFoo`` should contain an instance of ``ASTGEN_MEMBERS_AstFoo;`` at class
|
||||
scope. The ``astgen`` script checks and errors if this is not present. The
|
||||
method generated depends on whether the class is a concrete final class, or an
|
||||
abstract ``AstNode*`` base-class, and on ``@astgen`` directives present in
|
||||
comment sections in the body of the ``AstNode`` sub-class definitions.
|
||||
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ NON_STANDALONE_HEADERS = \
|
|||
V3AstNodeDType.h \
|
||||
V3AstNodeMath.h \
|
||||
V3AstNodeOther.h \
|
||||
V3DfgVertices.h \
|
||||
V3WidthCommit.h \
|
||||
|
||||
AST_DEFS := \
|
||||
|
|
@ -296,10 +297,19 @@ AST_DEFS := \
|
|||
V3AstNodeMath.h \
|
||||
V3AstNodeOther.h \
|
||||
|
||||
DFG_DEFS := \
|
||||
V3DfgVertices.h
|
||||
|
||||
#### astgen common flags
|
||||
|
||||
ASTGENFLAGS = -I $(srcdir)
|
||||
ASTGENFLAGS += $(foreach f,$(AST_DEFS),--astdef $f)
|
||||
ASTGENFLAGS += $(foreach f,$(DFG_DEFS),--dfgdef $f)
|
||||
|
||||
#### Linking
|
||||
|
||||
ifeq ($(VL_VLCOV),)
|
||||
PREDEP_H = V3Ast__gen_classes.h
|
||||
PREDEP_H = V3Ast__gen_forward_class_decls.h
|
||||
OBJS += $(RAW_OBJS) $(NC_OBJS)
|
||||
else
|
||||
PREDEP_H =
|
||||
|
|
@ -318,8 +328,8 @@ V3Number_test: V3Number_test.o
|
|||
|
||||
#### Modules
|
||||
|
||||
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS)
|
||||
$(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) $*.cpp
|
||||
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
|
||||
$(PYTHON3) $(ASTGEN) $(ASTGENFLAGS) $*.cpp
|
||||
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
|
|
@ -341,7 +351,7 @@ V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
|||
#### Generated files
|
||||
|
||||
# Target rule called before parallel build to make generated files
|
||||
serial:: V3Ast__gen_classes.h V3ParseBison.c
|
||||
serial:: V3Ast__gen_forward_class_decls.h V3ParseBison.c
|
||||
|
||||
serial_vlcov:: vlcovgen.d
|
||||
|
||||
|
|
@ -349,8 +359,8 @@ vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h
|
|||
$(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir)
|
||||
touch $@
|
||||
|
||||
V3Ast__gen_classes.h : $(ASTGEN) $(AST_DEFS)
|
||||
$(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) --classes
|
||||
V3Ast__gen_forward_class_decls.h: $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
|
||||
$(PYTHON3) $(ASTGEN) $(ASTGENFLAGS) --classes
|
||||
|
||||
V3ParseBison.h: V3ParseBison.c
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include "V3Global.h"
|
||||
#include "V3Number.h"
|
||||
|
||||
#include "V3Ast__gen_classes.h" // From ./astgen
|
||||
#include "V3Ast__gen_forward_class_decls.h" // From ./astgen
|
||||
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
|
|
@ -87,7 +87,7 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
|
|||
|
||||
class VNType final {
|
||||
public:
|
||||
#include "V3Ast__gen_types.h" // From ./astgen
|
||||
#include "V3Ast__gen_type_enum.h" // From ./astgen
|
||||
// Above include has:
|
||||
// enum en {...};
|
||||
// const char* ascii() const {...};
|
||||
|
|
@ -2179,7 +2179,7 @@ void AstNode::addPrev(AstNode* newp) {
|
|||
}
|
||||
|
||||
// Specialisations of privateTypeTest
|
||||
#include "V3Ast__gen_impl.h" // From ./astgen
|
||||
#include "V3Ast__gen_type_tests.h" // From ./astgen
|
||||
|
||||
// Specializations of AstNode::mayBeUnder
|
||||
template <>
|
||||
|
|
@ -2478,7 +2478,7 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
|
|||
return nodep->iterateSubtreeReturnEdits(*this);
|
||||
}
|
||||
|
||||
// Include macros generated by 'astgen'. These include ASTGEN_MEMBERS_<Node>
|
||||
// Include macros generated by 'astgen'. These include ASTGEN_MEMBERS_Ast<Node>
|
||||
// for each AstNode sub-type, and ASTGEN_SUPER_<Node> for concrete final
|
||||
// AstNode sub-types. The generated members include boilerplate methods related
|
||||
// to cloning, visitor dispatch, and other functionality. ASTGEN_SUPER_<Node>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ protected:
|
|||
: AstNode{t, fl} {}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_NodeDType;
|
||||
ASTGEN_MEMBERS_AstNodeDType;
|
||||
// ACCESSORS
|
||||
void dump(std::ostream& str) const override;
|
||||
virtual void dumpSmall(std::ostream& str) const;
|
||||
|
|
@ -144,7 +144,7 @@ protected:
|
|||
: AstNodeDType{t, fl} {}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_NodeArrayDType;
|
||||
ASTGEN_MEMBERS_AstNodeArrayDType;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
const char* broken() const override {
|
||||
|
|
@ -212,7 +212,7 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_NodeUOrStructDType;
|
||||
ASTGEN_MEMBERS_AstNodeUOrStructDType;
|
||||
int uniqueNum() const { return m_uniqueNum; }
|
||||
const char* broken() const override;
|
||||
void dump(std::ostream& str) const override;
|
||||
|
|
@ -270,7 +270,7 @@ public:
|
|||
this->rangep(rangep);
|
||||
this->valuep(valuep);
|
||||
}
|
||||
ASTGEN_MEMBERS_EnumItem;
|
||||
ASTGEN_MEMBERS_AstEnumItem;
|
||||
string name() const override { return m_name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
bool hasDType() const override { return true; }
|
||||
|
|
@ -300,7 +300,7 @@ public:
|
|||
keyDTypep(keyDtp);
|
||||
dtypep(dtp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AssocArrayDType;
|
||||
ASTGEN_MEMBERS_AstAssocArrayDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
|
|
@ -385,7 +385,7 @@ private:
|
|||
AstRange* rangep);
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_BasicDType;
|
||||
ASTGEN_MEMBERS_AstBasicDType;
|
||||
void dump(std::ostream& str) const override;
|
||||
// width/widthMin/numeric compared elsewhere
|
||||
bool same(const AstNode* samep) const override {
|
||||
|
|
@ -467,7 +467,7 @@ public:
|
|||
this->childDTypep(childDTypep);
|
||||
this->elementsp(elementsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_BracketArrayDType;
|
||||
ASTGEN_MEMBERS_AstBracketArrayDType;
|
||||
bool similarDType(AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); }
|
||||
AstNodeDType* subDTypep() const override { return childDTypep(); }
|
||||
// METHODS
|
||||
|
|
@ -495,7 +495,7 @@ public:
|
|||
this->dtypep(this);
|
||||
this->addParamsp(paramsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_ClassRefDType;
|
||||
ASTGEN_MEMBERS_AstClassRefDType;
|
||||
// METHODS
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
|
|
@ -539,7 +539,7 @@ public:
|
|||
dtypep(nullptr); // V3Width will resolve
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTGEN_MEMBERS_ConstDType;
|
||||
ASTGEN_MEMBERS_AstConstDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
|
|
@ -593,7 +593,7 @@ public:
|
|||
childDTypep(dtp); // Only for parser
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_DefImplicitDType;
|
||||
ASTGEN_MEMBERS_AstDefImplicitDType;
|
||||
int uniqueNum() const { return m_uniqueNum; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstDefImplicitDType* const sp = static_cast<const AstDefImplicitDType*>(samep);
|
||||
|
|
@ -635,7 +635,7 @@ public:
|
|||
refDTypep(dtp);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_DynArrayDType;
|
||||
ASTGEN_MEMBERS_AstDynArrayDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
|
|
@ -677,7 +677,7 @@ public:
|
|||
: ASTGEN_SUPER_EmptyQueueDType(fl) {
|
||||
dtypep(this);
|
||||
}
|
||||
ASTGEN_MEMBERS_EmptyQueueDType;
|
||||
ASTGEN_MEMBERS_AstEmptyQueueDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
|
|
@ -716,7 +716,7 @@ public:
|
|||
dtypep(nullptr); // V3Width will resolve
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTGEN_MEMBERS_EnumDType;
|
||||
ASTGEN_MEMBERS_AstEnumDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
|
|
@ -777,7 +777,7 @@ public:
|
|||
, m_cellName{cellName}
|
||||
, m_ifaceName{ifaceName}
|
||||
, m_modportName{modport} {}
|
||||
ASTGEN_MEMBERS_IfaceRefDType;
|
||||
ASTGEN_MEMBERS_AstIfaceRefDType;
|
||||
// METHODS
|
||||
const char* broken() const override;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
|
|
@ -832,7 +832,7 @@ public:
|
|||
dtypep(this);
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTGEN_MEMBERS_MemberDType;
|
||||
ASTGEN_MEMBERS_AstMemberDType;
|
||||
string name() const override { return m_name; } // * = Var name
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
|
|
@ -889,7 +889,7 @@ public:
|
|||
childDTypep(dtp); // Only for parser
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_ParamTypeDType;
|
||||
ASTGEN_MEMBERS_AstParamTypeDType;
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); }
|
||||
AstBasicDType* basicp() const override { return subDTypep()->basicp(); }
|
||||
|
|
@ -923,7 +923,7 @@ class AstParseTypeDType final : public AstNodeDType {
|
|||
public:
|
||||
explicit AstParseTypeDType(FileLine* fl)
|
||||
: ASTGEN_SUPER_ParseTypeDType(fl) {}
|
||||
ASTGEN_MEMBERS_ParseTypeDType;
|
||||
ASTGEN_MEMBERS_AstParseTypeDType;
|
||||
AstNodeDType* dtypep() const { return nullptr; }
|
||||
// METHODS
|
||||
bool similarDType(AstNodeDType* samep) const override { return this == samep; }
|
||||
|
|
@ -960,7 +960,7 @@ public:
|
|||
refDTypep(dtp);
|
||||
dtypep(dtp);
|
||||
}
|
||||
ASTGEN_MEMBERS_QueueDType;
|
||||
ASTGEN_MEMBERS_AstQueueDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
|
|
@ -1026,7 +1026,7 @@ public:
|
|||
: ASTGEN_SUPER_RefDType(fl) {
|
||||
this->typeofp(typeofp);
|
||||
}
|
||||
ASTGEN_MEMBERS_RefDType;
|
||||
ASTGEN_MEMBERS_AstRefDType;
|
||||
// METHODS
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
|
|
@ -1101,7 +1101,7 @@ public:
|
|||
refDTypep(nullptr);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_UnsizedArrayDType;
|
||||
ASTGEN_MEMBERS_AstUnsizedArrayDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
|
|
@ -1134,7 +1134,7 @@ public:
|
|||
: ASTGEN_SUPER_VoidDType(fl) {
|
||||
dtypep(this);
|
||||
}
|
||||
ASTGEN_MEMBERS_VoidDType;
|
||||
ASTGEN_MEMBERS_AstVoidDType;
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
bool hasDType() const override { return true; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
|
|
@ -1166,7 +1166,7 @@ public:
|
|||
refDTypep(nullptr);
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
}
|
||||
ASTGEN_MEMBERS_WildcardArrayDType;
|
||||
ASTGEN_MEMBERS_AstWildcardArrayDType;
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
|
|
@ -1199,7 +1199,7 @@ class AstPackArrayDType final : public AstNodeArrayDType {
|
|||
public:
|
||||
inline AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep);
|
||||
inline AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep);
|
||||
ASTGEN_MEMBERS_PackArrayDType;
|
||||
ASTGEN_MEMBERS_AstPackArrayDType;
|
||||
string prettyDTypeName() const override;
|
||||
bool isCompound() const override { return false; }
|
||||
};
|
||||
|
|
@ -1226,7 +1226,7 @@ public:
|
|||
// width and signing from the subDType/base type
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTGEN_MEMBERS_UnpackArrayDType;
|
||||
ASTGEN_MEMBERS_AstUnpackArrayDType;
|
||||
string prettyDTypeName() const override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstUnpackArrayDType* const sp = static_cast<const AstUnpackArrayDType*>(samep);
|
||||
|
|
@ -1244,7 +1244,7 @@ public:
|
|||
// VSigning below is mispurposed to indicate if packed or not
|
||||
AstStructDType(FileLine* fl, VSigning numericUnpack)
|
||||
: ASTGEN_SUPER_StructDType(fl, numericUnpack) {}
|
||||
ASTGEN_MEMBERS_StructDType;
|
||||
ASTGEN_MEMBERS_AstStructDType;
|
||||
string verilogKwd() const override { return "struct"; }
|
||||
};
|
||||
class AstUnionDType final : public AstNodeUOrStructDType {
|
||||
|
|
@ -1253,7 +1253,7 @@ public:
|
|||
// VSigning below is mispurposed to indicate if packed or not
|
||||
AstUnionDType(FileLine* fl, VSigning numericUnpack)
|
||||
: ASTGEN_SUPER_UnionDType(fl, numericUnpack) {}
|
||||
ASTGEN_MEMBERS_UnionDType;
|
||||
ASTGEN_MEMBERS_AstUnionDType;
|
||||
string verilogKwd() const override { return "union"; }
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -208,8 +208,7 @@ class ExtractCyclicComponents final {
|
|||
// The extracted cyclic components
|
||||
std::vector<std::unique_ptr<DfgGraph>> m_components;
|
||||
// Map from 'variable vertex' -> 'component index' -> 'clone in that component'
|
||||
std::unordered_map<const DfgVertexLValue*, std::unordered_map<size_t, DfgVertexLValue*>>
|
||||
m_clones;
|
||||
std::unordered_map<const DfgVertexVar*, std::unordered_map<size_t, DfgVertexVar*>> m_clones;
|
||||
|
||||
// METHODS
|
||||
|
||||
|
|
@ -285,7 +284,7 @@ class ExtractCyclicComponents final {
|
|||
|
||||
void visitMergeSCCs(const DfgVertex& vtx, size_t targetComponent) {
|
||||
// We stop at variable boundaries, which is where we will split the graphs
|
||||
if (vtx.is<DfgVarPacked>() || vtx.is<DfgVarArray>()) return;
|
||||
if (vtx.is<DfgVertexVar>()) return;
|
||||
|
||||
// Mark visited/move on if already visited
|
||||
if (!m_merged.insert(&vtx).second) return;
|
||||
|
|
@ -312,9 +311,9 @@ class ExtractCyclicComponents final {
|
|||
// Methods for extraction
|
||||
|
||||
// Retrieve clone of vertex in the given component
|
||||
DfgVertexLValue& getClone(DfgVertexLValue& vtx, size_t component) {
|
||||
DfgVertexVar& getClone(DfgVertexVar& vtx, size_t component) {
|
||||
UASSERT_OBJ(m_state.at(&vtx).component != component, &vtx, "Vertex is in that component");
|
||||
DfgVertexLValue*& clonep = m_clones[&vtx][component];
|
||||
DfgVertexVar*& clonep = m_clones[&vtx][component];
|
||||
if (!clonep) {
|
||||
DfgGraph& dfg = component == 0 ? m_dfg : *m_components[component - 1];
|
||||
if (DfgVarPacked* const pVtxp = vtx.cast<DfgVarPacked>()) {
|
||||
|
|
@ -322,7 +321,7 @@ class ExtractCyclicComponents final {
|
|||
} else if (DfgVarArray* const aVtxp = vtx.cast<DfgVarArray>()) {
|
||||
clonep = new DfgVarArray{dfg, aVtxp->varp()};
|
||||
}
|
||||
UASSERT_OBJ(clonep, &vtx, "Unhandled 'DfgVertexLValue' sub-type");
|
||||
UASSERT_OBJ(clonep, &vtx, "Unhandled 'DfgVertexVar' sub-type");
|
||||
if (VL_UNLIKELY(m_doExpensiveChecks)) {
|
||||
// Assign component number of clone for later checks
|
||||
m_state
|
||||
|
|
@ -338,30 +337,30 @@ class ExtractCyclicComponents final {
|
|||
return *clonep;
|
||||
}
|
||||
|
||||
// Fix up non-variable sources of a DfgVertexLValue that are in a different component,
|
||||
// Fix up non-variable sources of a DfgVertexVar that are in a different component,
|
||||
// using the provided 'relink' callback
|
||||
template <typename T_Vertex>
|
||||
void fixSources(T_Vertex& vtx, std::function<void(T_Vertex&, DfgVertex&, size_t)> relink) {
|
||||
static_assert(std::is_base_of<DfgVertexLValue, T_Vertex>::value,
|
||||
"'Vertex' must be a 'DfgVertexLValue'");
|
||||
static_assert(std::is_base_of<DfgVertexVar, T_Vertex>::value,
|
||||
"'Vertex' must be a 'DfgVertexVar'");
|
||||
const size_t component = m_state.at(&vtx).component;
|
||||
vtx.forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
DfgVertex& source = *edge.sourcep();
|
||||
// DfgVertexLValue sources are fixed up by `fixSinks` on those sources
|
||||
if (source.is<DfgVarPacked>() || source.is<DfgVarArray>()) return;
|
||||
// DfgVertexVar sources are fixed up by `fixSinks` on those sources
|
||||
if (source.is<DfgVertexVar>()) return;
|
||||
const size_t sourceComponent = m_state.at(&source).component;
|
||||
// Same component is OK
|
||||
if (sourceComponent == component) return;
|
||||
// Unlink the source edge (source is reconnected by 'relink'
|
||||
edge.unlinkSource();
|
||||
// Apply the fixup
|
||||
DfgVertexLValue& clone = getClone(vtx, sourceComponent);
|
||||
DfgVertexVar& clone = getClone(vtx, sourceComponent);
|
||||
relink(*(clone.as<T_Vertex>()), source, idx);
|
||||
});
|
||||
}
|
||||
|
||||
// Fix up sinks of given variable vertex that are in a different component
|
||||
void fixSinks(DfgVertexLValue& vtx) {
|
||||
void fixSinks(DfgVertexVar& vtx) {
|
||||
const size_t component = m_state.at(&vtx).component;
|
||||
vtx.forEachSinkEdge([&](DfgEdge& edge) {
|
||||
const size_t sinkComponent = m_state.at(edge.sinkp()).component;
|
||||
|
|
@ -400,7 +399,7 @@ class ExtractCyclicComponents final {
|
|||
vtx.forEachSourceEdge([&](DfgEdge& edge, size_t) {
|
||||
DfgVertex& source = *edge.sourcep();
|
||||
// OK to cross at variables
|
||||
if (source.is<DfgVarPacked>() || source.is<DfgVarArray>()) return;
|
||||
if (source.is<DfgVertexVar>()) return;
|
||||
UASSERT_OBJ(component == m_state.at(&source).component, &vtx,
|
||||
"Component crossing edge without variable involvement");
|
||||
});
|
||||
|
|
@ -670,9 +669,7 @@ static void dumpDotVertexAndSourceEdges(std::ostream& os, const DfgVertex& vtx)
|
|||
vtx.forEachSourceEdge([&](const DfgEdge& edge, size_t idx) { //
|
||||
if (edge.sourcep()) {
|
||||
string headLabel;
|
||||
if (vtx.arity() > 1 || vtx.is<DfgVarPacked>() || vtx.is<DfgVarArray>()) {
|
||||
headLabel = vtx.srcName(idx);
|
||||
}
|
||||
if (vtx.arity() > 1 || vtx.is<DfgVertexVar>()) headLabel = vtx.srcName(idx);
|
||||
dumpDotEdge(os, edge, headLabel);
|
||||
}
|
||||
});
|
||||
|
|
@ -843,7 +840,7 @@ void DfgEdge::relinkSource(DfgVertex* newSourcep) {
|
|||
// DfgVertex
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DfgVertex::DfgVertex(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, DfgType type)
|
||||
DfgVertex::DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
|
||||
: m_filelinep{flp}
|
||||
, m_dtypep{dtypep}
|
||||
, m_type{type} {
|
||||
|
|
@ -897,7 +894,7 @@ V3Hash DfgVertex::hash(HashCache& cache) const {
|
|||
result += selfHash();
|
||||
// Variables are defined by themselves, so there is no need to hash the sources. This
|
||||
// enables sound hashing of graphs circular only through variables, which we rely on.
|
||||
if (!is<DfgVarPacked>() && !is<DfgVarArray>()) {
|
||||
if (!is<DfgVertexVar>()) {
|
||||
forEachSource([&result, &cache](const DfgVertex& src) { result += src.hash(cache); });
|
||||
}
|
||||
}
|
||||
|
|
@ -930,7 +927,6 @@ void DfgVertex::replaceWith(DfgVertex* newSorucep) {
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
// DfgVarPacked ----------
|
||||
void DfgVarPacked::accept(DfgVisitor& visitor) { visitor.visit(this); }
|
||||
|
||||
bool DfgVarPacked::selfEquals(const DfgVertex& that) const {
|
||||
if (const DfgVarPacked* otherp = that.cast<DfgVarPacked>()) {
|
||||
|
|
@ -943,7 +939,6 @@ bool DfgVarPacked::selfEquals(const DfgVertex& that) const {
|
|||
V3Hash DfgVarPacked::selfHash() const { return V3Hasher::uncachedHash(varp()); }
|
||||
|
||||
// DfgVarPacked ----------
|
||||
void DfgVarArray::accept(DfgVisitor& visitor) { visitor.visit(this); }
|
||||
|
||||
bool DfgVarArray::selfEquals(const DfgVertex& that) const {
|
||||
if (const DfgVarArray* otherp = that.cast<DfgVarArray>()) {
|
||||
|
|
@ -956,7 +951,6 @@ bool DfgVarArray::selfEquals(const DfgVertex& that) const {
|
|||
V3Hash DfgVarArray::selfHash() const { return V3Hasher::uncachedHash(varp()); }
|
||||
|
||||
// DfgConst ----------
|
||||
void DfgConst::accept(DfgVisitor& visitor) { visitor.visit(this); }
|
||||
|
||||
bool DfgConst::selfEquals(const DfgVertex& that) const {
|
||||
if (const DfgConst* otherp = that.cast<DfgConst>()) {
|
||||
|
|
@ -971,12 +965,4 @@ V3Hash DfgConst::selfHash() const { return V3Hasher::uncachedHash(m_constp); }
|
|||
// DfgVisitor
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void DfgVisitor::visit(DfgVarPacked* vtxp) { visit(static_cast<DfgVertex*>(vtxp)); }
|
||||
void DfgVisitor::visit(DfgVarArray* vtxp) { visit(static_cast<DfgVertex*>(vtxp)); }
|
||||
void DfgVisitor::visit(DfgConst* vtxp) { visit(static_cast<DfgVertex*>(vtxp)); }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 'astgen' generated definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "V3Dfg__gen_definitions.h"
|
||||
#include "V3Dfg__gen_visitor_defns.h" // From ./astgen
|
||||
|
|
|
|||
589
src/V3Dfg.h
589
src/V3Dfg.h
|
|
@ -21,7 +21,7 @@
|
|||
// than the linked list based structures used by V3Graph.
|
||||
//
|
||||
// A bulk of the DfgVertex sub-types are generated by astgen, and are
|
||||
// analogous to the correspondign AstNode sub-types.
|
||||
// analogous to the corresponding AstNode sub-types.
|
||||
//
|
||||
// See also the internals documentation docs/internals.rst
|
||||
//
|
||||
|
|
@ -39,6 +39,8 @@
|
|||
#include "V3Hasher.h"
|
||||
#include "V3List.h"
|
||||
|
||||
#include "V3Dfg__gen_forward_class_decls.h" // From ./astgen
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
|
|
@ -46,7 +48,10 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class DfgVertex;
|
||||
#ifndef VL_NOT_FINAL
|
||||
#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE
|
||||
#endif
|
||||
|
||||
class DfgEdge;
|
||||
class DfgVisitor;
|
||||
|
||||
|
|
@ -63,6 +68,25 @@ struct std::hash<std::pair<const DfgVertex*, const DfgVertex*>> final {
|
|||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Dataflow vertex type enum
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class VDfgType final {
|
||||
public:
|
||||
#include "V3Dfg__gen_type_enum.h" // From ./astgen
|
||||
enum en m_e;
|
||||
VDfgType() = default;
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VDfgType(en _e)
|
||||
: m_e{_e} {}
|
||||
constexpr operator en() const { return m_e; }
|
||||
};
|
||||
constexpr bool operator==(VDfgType lhs, VDfgType rhs) { return lhs.m_e == rhs.m_e; }
|
||||
constexpr bool operator==(VDfgType lhs, VDfgType::en rhs) { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VDfgType::en lhs, VDfgType rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VDfgType& t) { return os << t.ascii(); }
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Dataflow graph
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -191,9 +215,6 @@ public:
|
|||
// Dataflow graph vertex
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Reuse the generated type constants
|
||||
using DfgType = VNType;
|
||||
|
||||
// Base data flow graph vertex
|
||||
class DfgVertex VL_NOT_FINAL {
|
||||
friend class DfgGraph;
|
||||
|
|
@ -206,10 +227,10 @@ protected:
|
|||
DfgEdge* m_sinksp = nullptr; // List of sinks of this vertex
|
||||
FileLine* const m_filelinep; // Source location
|
||||
AstNodeDType* m_dtypep = nullptr; // Data type of the result of this vertex
|
||||
const DfgType m_type;
|
||||
const VDfgType m_type;
|
||||
|
||||
// CONSTRUCTOR
|
||||
DfgVertex(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, DfgType type);
|
||||
DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep);
|
||||
|
||||
public:
|
||||
virtual ~DfgVertex();
|
||||
|
|
@ -277,7 +298,7 @@ public:
|
|||
// The data type of the result of the nodes
|
||||
AstNodeDType* dtypep() const { return m_dtypep; }
|
||||
// The type of this vertex
|
||||
DfgType type() const { return m_type; }
|
||||
VDfgType type() const { return m_type; }
|
||||
|
||||
// Width of result
|
||||
uint32_t width() const {
|
||||
|
|
@ -396,11 +417,18 @@ public:
|
|||
string warnMore() const { return fileline()->warnMore(); }
|
||||
string warnOther() const { return fileline()->warnOther(); }
|
||||
|
||||
private:
|
||||
// For internal use only.
|
||||
// Note: specializations for particular vertex types are provided by 'astgen'
|
||||
template <typename T>
|
||||
inline static bool privateTypeTest(const DfgVertex* nodep);
|
||||
|
||||
public:
|
||||
// Subtype test
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
static_assert(std::is_base_of<DfgVertex, T>::value, "'T' must be a subtype of DfgVertex");
|
||||
return m_type == T::dfgType();
|
||||
return privateTypeTest<typename std::remove_cv<T>::type>(this);
|
||||
}
|
||||
|
||||
// Ensure subtype, then cast to that type
|
||||
|
|
@ -436,367 +464,8 @@ public:
|
|||
virtual const string srcName(size_t idx) const = 0;
|
||||
};
|
||||
|
||||
// DfgVertices are, well ... DfgVertices
|
||||
template <>
|
||||
constexpr bool DfgVertex::is<DfgVertex>() const {
|
||||
return true;
|
||||
}
|
||||
template <>
|
||||
constexpr DfgVertex* DfgVertex::as<DfgVertex>() {
|
||||
return this;
|
||||
}
|
||||
template <>
|
||||
constexpr const DfgVertex* DfgVertex::as<DfgVertex>() const {
|
||||
return this;
|
||||
}
|
||||
template <>
|
||||
constexpr DfgVertex* DfgVertex::cast<DfgVertex>() {
|
||||
return this;
|
||||
}
|
||||
template <>
|
||||
constexpr const DfgVertex* DfgVertex::cast<DfgVertex>() const {
|
||||
return this;
|
||||
}
|
||||
|
||||
template <size_t Arity>
|
||||
class DfgVertexWithArity VL_NOT_FINAL : public DfgVertex {
|
||||
static_assert(1 <= Arity && Arity <= 4, "Arity must be between 1 and 4 inclusive");
|
||||
|
||||
std::array<DfgEdge, Arity> m_srcs; // Source edges
|
||||
|
||||
protected:
|
||||
DfgVertexWithArity<Arity>(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, DfgType type)
|
||||
: DfgVertex{dfg, flp, dtypep, type} {
|
||||
// Initialize source edges
|
||||
for (size_t i = 0; i < Arity; ++i) m_srcs[i].init(this);
|
||||
}
|
||||
|
||||
~DfgVertexWithArity<Arity>() override = default;
|
||||
|
||||
public:
|
||||
std::pair<DfgEdge*, size_t> sourceEdges() override { //
|
||||
return {m_srcs.data(), Arity};
|
||||
}
|
||||
std::pair<const DfgEdge*, size_t> sourceEdges() const override {
|
||||
return {m_srcs.data(), Arity};
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
DfgEdge* sourceEdge() {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return &m_srcs[Index];
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
const DfgEdge* sourceEdge() const {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return &m_srcs[Index];
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
DfgVertex* source() const {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return m_srcs[Index].sourcep();
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
void relinkSource(DfgVertex* newSourcep) {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
UASSERT_OBJ(m_srcs[Index].sinkp() == this, this, "Inconsistent");
|
||||
m_srcs[Index].relinkSource(newSourcep);
|
||||
}
|
||||
|
||||
// Named source getter/setter for unary vertices
|
||||
template <size_t A = Arity>
|
||||
typename std::enable_if<A == 1, DfgVertex*>::type srcp() const {
|
||||
static_assert(A == Arity, "Should not be changed");
|
||||
return source<0>();
|
||||
}
|
||||
template <size_t A = Arity>
|
||||
typename std::enable_if<A == 1, void>::type srcp(DfgVertex* vtxp) {
|
||||
static_assert(A == Arity, "Should not be changed");
|
||||
relinkSource<0>(vtxp);
|
||||
}
|
||||
|
||||
// Named source getter/setter for binary vertices
|
||||
template <size_t A = Arity>
|
||||
typename std::enable_if<A == 2, DfgVertex*>::type lhsp() const {
|
||||
static_assert(A == Arity, "Should not be changed");
|
||||
return source<0>();
|
||||
}
|
||||
template <size_t A = Arity>
|
||||
typename std::enable_if<A == 2, void>::type lhsp(DfgVertex* vtxp) {
|
||||
static_assert(A == Arity, "Should not be changed");
|
||||
relinkSource<0>(vtxp);
|
||||
}
|
||||
|
||||
template <size_t A = Arity>
|
||||
typename std::enable_if<A == 2, DfgVertex*>::type rhsp() const {
|
||||
static_assert(A == Arity, "Should not be changed");
|
||||
return source<1>();
|
||||
}
|
||||
template <size_t A = Arity>
|
||||
typename std::enable_if<A == 2, void>::type rhsp(DfgVertex* vtxp) {
|
||||
static_assert(A == Arity, "Should not be changed");
|
||||
relinkSource<1>(vtxp);
|
||||
}
|
||||
};
|
||||
|
||||
class DfgVertexVariadic VL_NOT_FINAL : public DfgVertex {
|
||||
DfgEdge* m_srcsp; // The source edges
|
||||
uint32_t m_srcCnt = 0; // Number of sources used
|
||||
uint32_t m_srcCap; // Number of sources allocated
|
||||
|
||||
// Allocate a new source edge array
|
||||
DfgEdge* allocSources(size_t n) {
|
||||
DfgEdge* const srcsp = new DfgEdge[n];
|
||||
for (size_t i = 0; i < n; ++i) srcsp[i].init(this);
|
||||
return srcsp;
|
||||
}
|
||||
|
||||
// Double the capacity of m_srcsp
|
||||
void growSources() {
|
||||
m_srcCap *= 2;
|
||||
DfgEdge* const newsp = allocSources(m_srcCap);
|
||||
for (size_t i = 0; i < m_srcCnt; ++i) {
|
||||
DfgEdge* const oldp = m_srcsp + i;
|
||||
// Skip over unlinked source edge
|
||||
if (!oldp->sourcep()) continue;
|
||||
// New edge driven from the same vertex as the old edge
|
||||
newsp[i].relinkSource(oldp->sourcep());
|
||||
// Unlink the old edge, it will be deleted
|
||||
oldp->unlinkSource();
|
||||
}
|
||||
// Delete old source edges
|
||||
delete[] m_srcsp;
|
||||
// Keep hold of new source edges
|
||||
m_srcsp = newsp;
|
||||
}
|
||||
|
||||
protected:
|
||||
DfgVertexVariadic(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, DfgType type,
|
||||
uint32_t initialCapacity = 1)
|
||||
: DfgVertex{dfg, flp, dtypep, type}
|
||||
, m_srcsp{allocSources(initialCapacity)}
|
||||
, m_srcCap{initialCapacity} {}
|
||||
|
||||
~DfgVertexVariadic() override { delete[] m_srcsp; };
|
||||
|
||||
DfgEdge* addSource() {
|
||||
if (m_srcCnt == m_srcCap) growSources();
|
||||
return m_srcsp + m_srcCnt++;
|
||||
}
|
||||
|
||||
void resetSources() {
|
||||
// #ifdef VL_DEBUG TODO: DEBUG ONLY
|
||||
for (uint32_t i = 0; i < m_srcCnt; ++i) {
|
||||
UASSERT_OBJ(!m_srcsp[i].sourcep(), m_srcsp[i].sourcep(), "Connected source");
|
||||
}
|
||||
// #endif
|
||||
m_srcCnt = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
DfgEdge* sourceEdge(size_t idx) const { return &m_srcsp[idx]; }
|
||||
DfgVertex* source(size_t idx) const { return m_srcsp[idx].sourcep(); }
|
||||
|
||||
std::pair<DfgEdge*, size_t> sourceEdges() override { return {m_srcsp, m_srcCnt}; }
|
||||
std::pair<const DfgEdge*, size_t> sourceEdges() const override { return {m_srcsp, m_srcCnt}; }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Vertex classes
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class DfgVertexLValue VL_NOT_FINAL : public DfgVertexVariadic {
|
||||
AstVar* const m_varp; // The AstVar associated with this vertex (not owned by this vertex)
|
||||
bool m_hasModRefs = false; // This AstVar is referenced outside the DFG, but in the module
|
||||
bool m_hasExtRefs = false; // This AstVar is referenced from outside the module
|
||||
|
||||
public:
|
||||
DfgVertexLValue(DfgGraph& dfg, DfgType type, AstVar* varp, uint32_t initialCapacity)
|
||||
: DfgVertexVariadic{dfg, varp->fileline(), dtypeFor(varp), type, initialCapacity}
|
||||
, m_varp{varp} {}
|
||||
|
||||
AstVar* varp() const { return m_varp; }
|
||||
bool hasModRefs() const { return m_hasModRefs; }
|
||||
void setHasModRefs() { m_hasModRefs = true; }
|
||||
bool hasExtRefs() const { return m_hasExtRefs; }
|
||||
void setHasExtRefs() { m_hasExtRefs = true; }
|
||||
bool hasRefs() const { return m_hasModRefs || m_hasExtRefs; }
|
||||
|
||||
// Variable cannot be removed, even if redundant in the DfgGraph (might be used externally)
|
||||
bool keep() const {
|
||||
// Keep if referenced outside this module
|
||||
if (hasExtRefs()) return true;
|
||||
// Keep if traced
|
||||
if (v3Global.opt.trace() && varp()->isTrace()) return true;
|
||||
// Keep if public
|
||||
if (varp()->isSigPublic()) return true;
|
||||
// Otherwise it can be removed
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class DfgVarPacked final : public DfgVertexLValue {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
using DriverData = std::pair<FileLine*, uint32_t>;
|
||||
|
||||
std::vector<DriverData> m_driverData; // Additional data associate with each driver
|
||||
|
||||
void accept(DfgVisitor& visitor) override;
|
||||
bool selfEquals(const DfgVertex& that) const override;
|
||||
V3Hash selfHash() const override;
|
||||
static constexpr DfgType dfgType() { return DfgType::atVar; };
|
||||
|
||||
public:
|
||||
DfgVarPacked(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexLValue{dfg, dfgType(), varp, 1u} {}
|
||||
|
||||
bool isDrivenByDfg() const { return arity() > 0; }
|
||||
bool isDrivenFullyByDfg() const { return arity() == 1 && source(0)->dtypep() == dtypep(); }
|
||||
|
||||
void addDriver(FileLine* flp, uint32_t lsb, DfgVertex* vtxp) {
|
||||
m_driverData.emplace_back(flp, lsb);
|
||||
DfgVertexVariadic::addSource()->relinkSource(vtxp);
|
||||
}
|
||||
|
||||
void resetSources() {
|
||||
m_driverData.clear();
|
||||
DfgVertexVariadic::resetSources();
|
||||
}
|
||||
|
||||
// Remove undriven sources
|
||||
void packSources() {
|
||||
// Grab and reset the driver data
|
||||
std::vector<DriverData> driverData{std::move(m_driverData)};
|
||||
|
||||
// Grab and unlink the sources
|
||||
std::vector<DfgVertex*> sources{arity()};
|
||||
forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
sources[idx] = edge.sourcep();
|
||||
edge.unlinkSource();
|
||||
});
|
||||
DfgVertexVariadic::resetSources();
|
||||
|
||||
// Add back the driven sources
|
||||
for (size_t i = 0; i < sources.size(); ++i) {
|
||||
if (!sources[i]) continue;
|
||||
addDriver(driverData[i].first, driverData[i].second, sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FileLine* driverFileLine(size_t idx) const { return m_driverData[idx].first; }
|
||||
uint32_t driverLsb(size_t idx) const { return m_driverData[idx].second; }
|
||||
|
||||
const string srcName(size_t idx) const override {
|
||||
return isDrivenFullyByDfg() ? "" : cvtToStr(driverLsb(idx));
|
||||
}
|
||||
};
|
||||
|
||||
class DfgVarArray final : public DfgVertexLValue {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
using DriverData = std::pair<FileLine*, uint32_t>;
|
||||
|
||||
std::vector<DriverData> m_driverData; // Additional data associate with each driver
|
||||
|
||||
void accept(DfgVisitor& visitor) override;
|
||||
bool selfEquals(const DfgVertex& that) const override;
|
||||
V3Hash selfHash() const override;
|
||||
static constexpr DfgType dfgType() { return DfgType::atUnpackArrayDType; }; // TODO: gross
|
||||
|
||||
public:
|
||||
DfgVarArray(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexLValue{dfg, dfgType(), varp, 4u} {
|
||||
UASSERT_OBJ(VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType), varp, "Non array DfgVarArray");
|
||||
}
|
||||
|
||||
bool isDrivenByDfg() const { return arity() > 0; }
|
||||
|
||||
void addDriver(FileLine* flp, uint32_t index, DfgVertex* vtxp) {
|
||||
m_driverData.emplace_back(flp, index);
|
||||
DfgVertexVariadic::addSource()->relinkSource(vtxp);
|
||||
}
|
||||
|
||||
void resetSources() {
|
||||
m_driverData.clear();
|
||||
DfgVertexVariadic::resetSources();
|
||||
}
|
||||
|
||||
// Remove undriven sources
|
||||
void packSources() {
|
||||
// Grab and reset the driver data
|
||||
std::vector<DriverData> driverData{std::move(m_driverData)};
|
||||
|
||||
// Grab and unlink the sources
|
||||
std::vector<DfgVertex*> sources{arity()};
|
||||
forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
sources[idx] = edge.sourcep();
|
||||
edge.unlinkSource();
|
||||
});
|
||||
DfgVertexVariadic::resetSources();
|
||||
|
||||
// Add back the driven sources
|
||||
for (size_t i = 0; i < sources.size(); ++i) {
|
||||
if (!sources[i]) continue;
|
||||
addDriver(driverData[i].first, driverData[i].second, sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FileLine* driverFileLine(size_t idx) const { return m_driverData[idx].first; }
|
||||
uint32_t driverIndex(size_t idx) const { return m_driverData[idx].second; }
|
||||
|
||||
DfgVertex* driverAt(size_t idx) const {
|
||||
const DfgEdge* const edgep = findSourceEdge([=](const DfgEdge&, size_t i) { //
|
||||
return driverIndex(i) == idx;
|
||||
});
|
||||
return edgep ? edgep->sourcep() : nullptr;
|
||||
}
|
||||
|
||||
const string srcName(size_t idx) const override { return cvtToStr(driverIndex(idx)); }
|
||||
};
|
||||
|
||||
class DfgConst final : public DfgVertex {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
AstConst* const m_constp; // The AstConst associated with this vertex (owned by this vertex)
|
||||
|
||||
void accept(DfgVisitor& visitor) override;
|
||||
bool selfEquals(const DfgVertex& that) const override;
|
||||
V3Hash selfHash() const override;
|
||||
static constexpr DfgType dfgType() { return DfgType::atConst; };
|
||||
|
||||
public:
|
||||
DfgConst(DfgGraph& dfg, AstConst* constp)
|
||||
: DfgVertex{dfg, constp->fileline(), dtypeFor(constp), dfgType()}
|
||||
, m_constp{constp} {}
|
||||
|
||||
~DfgConst() override { VL_DO_DANGLING(m_constp->deleteTree(), m_constp); }
|
||||
|
||||
AstConst* constp() const { return m_constp; }
|
||||
V3Number& num() const { return m_constp->num(); }
|
||||
|
||||
uint32_t toU32() const { return num().toUInt(); }
|
||||
int32_t toI32() const { return num().toSInt(); }
|
||||
|
||||
bool isZero() const { return num().isEqZero(); }
|
||||
bool isOnes() const { return num().isEqAllOnes(width()); }
|
||||
|
||||
std::pair<DfgEdge*, size_t> sourceEdges() override { return {nullptr, 0}; }
|
||||
std::pair<const DfgEdge*, size_t> sourceEdges() const override { return {nullptr, 0}; }
|
||||
const string srcName(size_t) const override { // LCOV_EXCL_START
|
||||
VL_UNREACHABLE;
|
||||
return "";
|
||||
} // LCOV_EXCL_STOP
|
||||
};
|
||||
|
||||
// The rest of the DfgVertex subclasses are generated by 'astgen' from AstNodeMath nodes
|
||||
#include "V3Dfg__gen_vertex_classes.h"
|
||||
// Specialisations of privateTypeTest
|
||||
#include "V3Dfg__gen_type_tests.h" // From ./astgen
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Dfg vertex visitor
|
||||
|
|
@ -807,10 +476,8 @@ public:
|
|||
// Dispatch to most specific 'visit' method on 'vtxp'
|
||||
void iterate(DfgVertex* vtxp) { vtxp->accept(*this); }
|
||||
|
||||
virtual void visit(DfgVarPacked* vtxp);
|
||||
virtual void visit(DfgVarArray* vtxp);
|
||||
virtual void visit(DfgConst* vtxp);
|
||||
#include "V3Dfg__gen_visitor_decls.h"
|
||||
virtual void visit(DfgVertex* nodep) = 0;
|
||||
#include "V3Dfg__gen_visitor_decls.h" // From ./astgen
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -937,6 +604,180 @@ Vertex* DfgVertex::findSink() const {
|
|||
return findSink<Vertex>([](const Vertex&) { return true; });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// DfgVertex sub-types follow
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Include macros generated by 'astgen'. These include DFGGEN_MEMBERS_<Node>
|
||||
// for each DfgVertex sub-type. The generated members include boilerplate
|
||||
// methods related to cloning, visitor dispatch, and other functionality.
|
||||
// For precise details please read the generated macros.
|
||||
#include "V3Dfg__gen_macros.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation of dataflow graph vertices with a fixed number of sources
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <size_t Arity>
|
||||
class DfgVertexWithArity VL_NOT_FINAL : public DfgVertex {
|
||||
static_assert(1 <= Arity && Arity <= 4, "Arity must be between 1 and 4 inclusive");
|
||||
|
||||
std::array<DfgEdge, Arity> m_srcs; // Source edges
|
||||
|
||||
protected:
|
||||
DfgVertexWithArity<Arity>(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertex{dfg, type, flp, dtypep} {
|
||||
// Initialize source edges
|
||||
for (size_t i = 0; i < Arity; ++i) m_srcs[i].init(this);
|
||||
}
|
||||
|
||||
~DfgVertexWithArity<Arity>() override = default;
|
||||
|
||||
public:
|
||||
std::pair<DfgEdge*, size_t> sourceEdges() final override { //
|
||||
return {m_srcs.data(), Arity};
|
||||
}
|
||||
std::pair<const DfgEdge*, size_t> sourceEdges() const final override {
|
||||
return {m_srcs.data(), Arity};
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
DfgEdge* sourceEdge() {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return &m_srcs[Index];
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
const DfgEdge* sourceEdge() const {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return &m_srcs[Index];
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
DfgVertex* source() const {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return m_srcs[Index].sourcep();
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
void relinkSource(DfgVertex* newSourcep) {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
UASSERT_OBJ(m_srcs[Index].sinkp() == this, this, "Inconsistent");
|
||||
m_srcs[Index].relinkSource(newSourcep);
|
||||
}
|
||||
};
|
||||
|
||||
class DfgVertexUnary VL_NOT_FINAL : public DfgVertexWithArity<1> {
|
||||
protected:
|
||||
DfgVertexUnary(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertexWithArity<1>{dfg, type, flp, dtypep} {}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_DfgVertexUnary;
|
||||
|
||||
// Named getter/setter for sources
|
||||
DfgVertex* srcp() const { return source<0>(); }
|
||||
void srcp(DfgVertex* vtxp) { relinkSource<0>(vtxp); }
|
||||
};
|
||||
|
||||
class DfgVertexBinary VL_NOT_FINAL : public DfgVertexWithArity<2> {
|
||||
protected:
|
||||
DfgVertexBinary(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertexWithArity<2>{dfg, type, flp, dtypep} {}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_DfgVertexBinary;
|
||||
|
||||
// Named getter/setter for sources
|
||||
DfgVertex* lhsp() const { return source<0>(); }
|
||||
void lhsp(DfgVertex* vtxp) { relinkSource<0>(vtxp); }
|
||||
DfgVertex* rhsp() const { return source<1>(); }
|
||||
void rhsp(DfgVertex* vtxp) { relinkSource<1>(vtxp); }
|
||||
};
|
||||
|
||||
class DfgVertexTernary VL_NOT_FINAL : public DfgVertexWithArity<3> {
|
||||
protected:
|
||||
DfgVertexTernary(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertexWithArity<3>{dfg, type, flp, dtypep} {}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_DfgVertexTernary;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation of dataflow graph vertices with a variable number of sources
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class DfgVertexVariadic VL_NOT_FINAL : public DfgVertex {
|
||||
DfgEdge* m_srcsp; // The source edges
|
||||
uint32_t m_srcCnt = 0; // Number of sources used
|
||||
uint32_t m_srcCap; // Number of sources allocated
|
||||
|
||||
// Allocate a new source edge array
|
||||
DfgEdge* allocSources(size_t n) {
|
||||
DfgEdge* const srcsp = new DfgEdge[n];
|
||||
for (size_t i = 0; i < n; ++i) srcsp[i].init(this);
|
||||
return srcsp;
|
||||
}
|
||||
|
||||
// Double the capacity of m_srcsp
|
||||
void growSources() {
|
||||
m_srcCap *= 2;
|
||||
DfgEdge* const newsp = allocSources(m_srcCap);
|
||||
for (size_t i = 0; i < m_srcCnt; ++i) {
|
||||
DfgEdge* const oldp = m_srcsp + i;
|
||||
// Skip over unlinked source edge
|
||||
if (!oldp->sourcep()) continue;
|
||||
// New edge driven from the same vertex as the old edge
|
||||
newsp[i].relinkSource(oldp->sourcep());
|
||||
// Unlink the old edge, it will be deleted
|
||||
oldp->unlinkSource();
|
||||
}
|
||||
// Delete old source edges
|
||||
delete[] m_srcsp;
|
||||
// Keep hold of new source edges
|
||||
m_srcsp = newsp;
|
||||
}
|
||||
|
||||
protected:
|
||||
DfgVertexVariadic(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep,
|
||||
uint32_t initialCapacity = 1)
|
||||
: DfgVertex{dfg, type, flp, dtypep}
|
||||
, m_srcsp{allocSources(initialCapacity)}
|
||||
, m_srcCap{initialCapacity} {}
|
||||
|
||||
~DfgVertexVariadic() override { delete[] m_srcsp; };
|
||||
|
||||
DfgEdge* addSource() {
|
||||
if (m_srcCnt == m_srcCap) growSources();
|
||||
return m_srcsp + m_srcCnt++;
|
||||
}
|
||||
|
||||
void resetSources() {
|
||||
// #ifdef VL_DEBUG TODO: DEBUG ONLY
|
||||
for (uint32_t i = 0; i < m_srcCnt; ++i) {
|
||||
UASSERT_OBJ(!m_srcsp[i].sourcep(), m_srcsp[i].sourcep(), "Connected source");
|
||||
}
|
||||
// #endif
|
||||
m_srcCnt = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_DfgVertexVariadic;
|
||||
|
||||
DfgEdge* sourceEdge(size_t idx) const { return &m_srcsp[idx]; }
|
||||
DfgVertex* source(size_t idx) const { return m_srcsp[idx].sourcep(); }
|
||||
|
||||
std::pair<DfgEdge*, size_t> sourceEdges() override { return {m_srcsp, m_srcCnt}; }
|
||||
std::pair<const DfgEdge*, size_t> sourceEdges() const override { return {m_srcsp, m_srcCnt}; }
|
||||
};
|
||||
|
||||
// DfgVertex subclasses
|
||||
#include "V3DfgVertices.h"
|
||||
|
||||
// The rest of the DfgVertex subclasses are generated by 'astgen' from AstNodeMath nodes
|
||||
#include "V3Dfg__gen_auto_classes.h"
|
||||
|
||||
bool DfgVertex::isZero() const {
|
||||
if (const DfgConst* const constp = cast<DfgConst>()) return constp->isZero();
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ namespace {
|
|||
|
||||
// Create a DfgVertex out of a AstNodeMath. For most AstNodeMath subtypes, this can be done
|
||||
// automatically. For the few special cases, we provide specializations below
|
||||
template <typename Vertex>
|
||||
Vertex* makeVertex(const AstForDfg<Vertex>* nodep, DfgGraph& dfg) {
|
||||
template <typename Vertex, typename Node>
|
||||
Vertex* makeVertex(const Node* nodep, DfgGraph& dfg) {
|
||||
return new Vertex{dfg, nodep->fileline(), DfgVertex::dtypeFor(nodep)};
|
||||
}
|
||||
|
||||
|
|
@ -51,22 +51,22 @@ Vertex* makeVertex(const AstForDfg<Vertex>* nodep, DfgGraph& dfg) {
|
|||
// LCOV_EXCL_START
|
||||
// AstCCast changes width, but should not exists where DFG optimization is currently invoked
|
||||
template <>
|
||||
DfgCCast* makeVertex<DfgCCast>(const AstCCast*, DfgGraph&) {
|
||||
DfgCCast* makeVertex<DfgCCast, AstCCast>(const AstCCast*, DfgGraph&) {
|
||||
return nullptr;
|
||||
}
|
||||
// Unhandled in DfgToAst, but also operates on strings which we don't optimize anyway
|
||||
template <>
|
||||
DfgAtoN* makeVertex<DfgAtoN>(const AstAtoN*, DfgGraph&) {
|
||||
DfgAtoN* makeVertex<DfgAtoN, AstAtoN>(const AstAtoN*, DfgGraph&) {
|
||||
return nullptr;
|
||||
}
|
||||
// Unhandled in DfgToAst, but also operates on strings which we don't optimize anyway
|
||||
template <>
|
||||
DfgCompareNN* makeVertex<DfgCompareNN>(const AstCompareNN*, DfgGraph&) {
|
||||
DfgCompareNN* makeVertex<DfgCompareNN, AstCompareNN>(const AstCompareNN*, DfgGraph&) {
|
||||
return nullptr;
|
||||
}
|
||||
// Unhandled in DfgToAst, but also operates on unpacked arrays which we don't optimize anyway
|
||||
template <>
|
||||
DfgSliceSel* makeVertex<DfgSliceSel>(const AstSliceSel*, DfgGraph&) {
|
||||
DfgSliceSel* makeVertex<DfgSliceSel, AstSliceSel>(const AstSliceSel*, DfgGraph&) {
|
||||
return nullptr;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
|
@ -105,11 +105,11 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
m_uncommittedVertices.clear();
|
||||
}
|
||||
|
||||
DfgVertexLValue* getNet(AstVar* varp) {
|
||||
DfgVertexVar* getNet(AstVar* varp) {
|
||||
if (!varp->user1p()) {
|
||||
// Note DfgVertexLValue vertices are not added to m_uncommittedVertices, because we
|
||||
// Note DfgVertexVar vertices are not added to m_uncommittedVertices, because we
|
||||
// want to hold onto them via AstVar::user1p, and the AstVar might be referenced via
|
||||
// multiple AstVarRef instances, so we will never revert a DfgVertexLValue once
|
||||
// multiple AstVarRef instances, so we will never revert a DfgVertexVar once
|
||||
// created. We will delete unconnected variable vertices at the end.
|
||||
if (VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
DfgVarArray* const vtxp = new DfgVarArray{*m_dfgp, varp};
|
||||
|
|
@ -122,7 +122,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
varp->user1p(vtxp);
|
||||
}
|
||||
}
|
||||
return varp->user1u().to<DfgVertexLValue*>();
|
||||
return varp->user1u().to<DfgVertexVar*>();
|
||||
}
|
||||
|
||||
DfgVertex* getVertex(AstNode* nodep) {
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ namespace {
|
|||
|
||||
// Create an AstNodeMath out of a DfgVertex. For most AstNodeMath subtypes, this can be done
|
||||
// automatically. For the few special cases, we provide specializations below
|
||||
template <typename Node, typename... Ops>
|
||||
Node* makeNode(const DfgForAst<Node>* vtxp, Ops... ops) {
|
||||
template <typename Node, typename Vertex, typename... Ops>
|
||||
Node* makeNode(const Vertex* vtxp, Ops... ops) {
|
||||
Node* const nodep = new Node{vtxp->fileline(), ops...};
|
||||
UASSERT_OBJ(nodep->width() == static_cast<int>(vtxp->width()), vtxp,
|
||||
"Incorrect width in AstNode created from DfgVertex "
|
||||
|
|
@ -55,31 +55,31 @@ Node* makeNode(const DfgForAst<Node>* vtxp, Ops... ops) {
|
|||
// Vertices needing special conversion
|
||||
|
||||
template <>
|
||||
AstExtend* makeNode<AstExtend, AstNodeMath*>( //
|
||||
AstExtend* makeNode<AstExtend, DfgExtend, AstNodeMath*>( //
|
||||
const DfgExtend* vtxp, AstNodeMath* op1) {
|
||||
return new AstExtend{vtxp->fileline(), op1, static_cast<int>(vtxp->width())};
|
||||
}
|
||||
|
||||
template <>
|
||||
AstExtendS* makeNode<AstExtendS, AstNodeMath*>( //
|
||||
AstExtendS* makeNode<AstExtendS, DfgExtendS, AstNodeMath*>( //
|
||||
const DfgExtendS* vtxp, AstNodeMath* op1) {
|
||||
return new AstExtendS{vtxp->fileline(), op1, static_cast<int>(vtxp->width())};
|
||||
}
|
||||
|
||||
template <>
|
||||
AstShiftL* makeNode<AstShiftL, AstNodeMath*, AstNodeMath*>( //
|
||||
AstShiftL* makeNode<AstShiftL, DfgShiftL, AstNodeMath*, AstNodeMath*>( //
|
||||
const DfgShiftL* vtxp, AstNodeMath* op1, AstNodeMath* op2) {
|
||||
return new AstShiftL{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())};
|
||||
}
|
||||
|
||||
template <>
|
||||
AstShiftR* makeNode<AstShiftR, AstNodeMath*, AstNodeMath*>( //
|
||||
AstShiftR* makeNode<AstShiftR, DfgShiftR, AstNodeMath*, AstNodeMath*>( //
|
||||
const DfgShiftR* vtxp, AstNodeMath* op1, AstNodeMath* op2) {
|
||||
return new AstShiftR{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())};
|
||||
}
|
||||
|
||||
template <>
|
||||
AstShiftRS* makeNode<AstShiftRS, AstNodeMath*, AstNodeMath*>( //
|
||||
AstShiftRS* makeNode<AstShiftRS, DfgShiftRS, AstNodeMath*, AstNodeMath*>( //
|
||||
const DfgShiftRS* vtxp, AstNodeMath* op1, AstNodeMath* op2) {
|
||||
return new AstShiftRS{vtxp->fileline(), op1, op2, static_cast<int>(vtxp->width())};
|
||||
}
|
||||
|
|
@ -88,20 +88,21 @@ AstShiftRS* makeNode<AstShiftRS, AstNodeMath*, AstNodeMath*>( //
|
|||
// Currently unhandled nodes - see corresponding AstToDfg functions
|
||||
// LCOV_EXCL_START
|
||||
template <>
|
||||
AstCCast* makeNode<AstCCast, AstNodeMath*>(const DfgCCast* vtxp, AstNodeMath*) {
|
||||
AstCCast* makeNode<AstCCast, DfgCCast, AstNodeMath*>(const DfgCCast* vtxp, AstNodeMath*) {
|
||||
vtxp->v3fatalSrc("not implemented");
|
||||
}
|
||||
template <>
|
||||
AstAtoN* makeNode<AstAtoN, AstNodeMath*>(const DfgAtoN* vtxp, AstNodeMath*) {
|
||||
AstAtoN* makeNode<AstAtoN, DfgAtoN, AstNodeMath*>(const DfgAtoN* vtxp, AstNodeMath*) {
|
||||
vtxp->v3fatalSrc("not implemented");
|
||||
}
|
||||
template <>
|
||||
AstCompareNN* makeNode<AstCompareNN, AstNodeMath*, AstNodeMath*>(const DfgCompareNN* vtxp,
|
||||
AstCompareNN*
|
||||
makeNode<AstCompareNN, DfgCompareNN, AstNodeMath*, AstNodeMath*>(const DfgCompareNN* vtxp,
|
||||
AstNodeMath*, AstNodeMath*) {
|
||||
vtxp->v3fatalSrc("not implemented");
|
||||
}
|
||||
template <>
|
||||
AstSliceSel* makeNode<AstSliceSel, AstNodeMath*, AstNodeMath*, AstNodeMath*>(
|
||||
AstSliceSel* makeNode<AstSliceSel, DfgSliceSel, AstNodeMath*, AstNodeMath*, AstNodeMath*>(
|
||||
const DfgSliceSel* vtxp, AstNodeMath*, AstNodeMath*, AstNodeMath*) {
|
||||
vtxp->v3fatalSrc("not implemented");
|
||||
}
|
||||
|
|
@ -215,8 +216,7 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
// Inline vertices that drive only a single node, or are special
|
||||
if (!vtx.hasMultipleSinks()) return true;
|
||||
if (vtx.is<DfgConst>()) return true;
|
||||
if (vtx.is<DfgVarPacked>()) return true;
|
||||
if (vtx.is<DfgVarArray>()) return true;
|
||||
if (vtx.is<DfgVertexVar>()) return true;
|
||||
if (const DfgArraySel* const selp = vtx.cast<DfgArraySel>()) {
|
||||
return selp->bitp()->is<DfgConst>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ void V3DfgPasses::removeVars(DfgGraph& dfg, DfgRemoveVarsContext& ctx) {
|
|||
void V3DfgPasses::removeUnused(DfgGraph& dfg) {
|
||||
const auto processVertex = [&](DfgVertex& vtx) {
|
||||
// Keep variables
|
||||
if (vtx.is<DfgVarPacked>() || vtx.is<DfgVarArray>()) return false;
|
||||
if (vtx.is<DfgVertexVar>()) return false;
|
||||
// Keep if it has sinks
|
||||
if (vtx.hasSinks()) return false;
|
||||
// Unlink and delete vertex
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
DfgConst* makeZero(FileLine* flp, uint32_t width) { return makeConst(flp, width, 0); }
|
||||
|
||||
// Transformations that apply to all commutative binary vertices
|
||||
void commutativeBinary(DfgVertexWithArity<2>* vtxp) {
|
||||
void commutativeBinary(DfgVertexBinary* vtxp) {
|
||||
DfgVertex* const lhsp = vtxp->source<0>();
|
||||
DfgVertex* const rhsp = vtxp->source<1>();
|
||||
// Ensure Const is on left-hand side to simplify other patterns
|
||||
|
|
@ -138,9 +138,9 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
// If both sides are variable references, order the side in some defined way. This allows
|
||||
// CSE to later merge 'a op b' with 'b op a'.
|
||||
if (lhsp->is<DfgVarPacked>() && rhsp->is<DfgVarPacked>()) {
|
||||
AstVar* const lVarp = lhsp->as<DfgVarPacked>()->varp();
|
||||
AstVar* const rVarp = rhsp->as<DfgVarPacked>()->varp();
|
||||
if (lhsp->is<DfgVertexVar>() && rhsp->is<DfgVertexVar>()) {
|
||||
AstVar* const lVarp = lhsp->as<DfgVertexVar>()->varp();
|
||||
AstVar* const rVarp = rhsp->as<DfgVertexVar>()->varp();
|
||||
if (lVarp->name() > rVarp->name()) {
|
||||
APPLYING(SWAP_VAR_IN_COMMUTATIVE_BINARY) {
|
||||
vtxp->lhsp(rhsp);
|
||||
|
|
@ -152,12 +152,12 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
|
||||
// Transformations that apply to all associative binary vertices
|
||||
void associativeBinary(DfgVertexWithArity<2>* vtxp) {
|
||||
void associativeBinary(DfgVertexBinary* vtxp) {
|
||||
DfgVertex* const lhsp = vtxp->lhsp();
|
||||
|
||||
// Make associative trees right leaning (for better CSE opportunities)
|
||||
if (lhsp->type() == vtxp->type() && !lhsp->hasMultipleSinks()) {
|
||||
DfgVertexWithArity<2>* const lBinp = static_cast<DfgVertexWithArity<2>*>(lhsp);
|
||||
DfgVertexBinary* const lBinp = lhsp->as<DfgVertexBinary>();
|
||||
APPLYING(RIGHT_LEANING_ASSOC) {
|
||||
vtxp->replaceWith(lBinp);
|
||||
vtxp->lhsp(lBinp->rhsp());
|
||||
|
|
@ -242,7 +242,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
newRhsp->rhsp(concatp->rhsp());
|
||||
|
||||
// The replacement Vertex
|
||||
DfgVertexWithArity<2>* const replacementp
|
||||
DfgVertexBinary* const replacementp
|
||||
= std::is_same<Vertex, DfgEq>::value
|
||||
? new DfgAnd{m_dfg, concatp->fileline(), m_bitDType}
|
||||
: nullptr;
|
||||
|
|
@ -334,7 +334,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
rReducep->srcp(concatp->rhsp());
|
||||
|
||||
// Bitwise reduce the results
|
||||
DfgVertexWithArity<2>* const replacementp = new Bitwise{m_dfg, flp, m_bitDType};
|
||||
Bitwise* const replacementp = new Bitwise{m_dfg, flp, m_bitDType};
|
||||
replacementp->lhsp(lReducep);
|
||||
replacementp->rhsp(rReducep);
|
||||
vtxp->replaceWith(replacementp);
|
||||
|
|
@ -362,7 +362,7 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void optimizeShiftRHS(DfgVertexWithArity<2>* vtxp) {
|
||||
void optimizeShiftRHS(DfgVertexBinary* vtxp) {
|
||||
if (const DfgConcat* const concatp = vtxp->rhsp()->cast<DfgConcat>()) {
|
||||
if (concatp->lhsp()->isZero()) { // Drop redundant zero extension
|
||||
APPLYING(REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT) { //
|
||||
|
|
@ -1330,12 +1330,12 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
|
||||
// Process one vertex. Return true if graph changed
|
||||
bool processVertex(DfgVertex& vtx) {
|
||||
// Keep DfgVertexLValue vertices in this pass. We will remove them later if they become
|
||||
// Keep DfgVertexVar vertices in this pass. We will remove them later if they become
|
||||
// redundant. We want to keep the original variables for non-var vertices that drive
|
||||
// multiple sinks (otherwise we would need to introduce a temporary, but it is better for
|
||||
// debugging to keep the original variable name, if one is available), so we can't remove
|
||||
// redundant variables here.
|
||||
const bool keep = vtx.is<DfgVarPacked>() || vtx.is<DfgVarArray>();
|
||||
const bool keep = vtx.is<DfgVertexVar>();
|
||||
|
||||
// If it has no sinks (unused), we can remove it
|
||||
if (!keep && !vtx.hasSinks()) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,229 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: DfgVertex sub-classes
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2022 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// This is a data-flow graph based representation of combinational logic,
|
||||
// the main difference from a V3Graph is that DfgVertex owns the storage
|
||||
// of it's input edges (operands/sources/arguments), and can access each
|
||||
// input edge directly by indexing, making modifications more efficient
|
||||
// than the linked list based structures used by V3Graph.
|
||||
//
|
||||
// A bulk of the DfgVertex sub-types are generated by astgen, and are
|
||||
// analogous to the corresponding AstNode sub-types.
|
||||
//
|
||||
// See also the internals documentation docs/internals.rst
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3DFGVERTICES_H_
|
||||
#define VERILATOR_V3DFGVERTICES_H_
|
||||
|
||||
#ifndef VERILATOR_V3DFG_H_
|
||||
#error "Use V3Dfg.h as the include"
|
||||
#include "V3Dfg.h" // This helps code analysis tools pick up symbols in V3Dfg.h
|
||||
#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE
|
||||
#endif
|
||||
|
||||
// === Abstract base node types (DfgVertex*) ===================================
|
||||
|
||||
class DfgVertexVar VL_NOT_FINAL : public DfgVertexVariadic {
|
||||
AstVar* const m_varp; // The AstVar associated with this vertex (not owned by this vertex)
|
||||
bool m_hasModRefs = false; // This AstVar is referenced outside the DFG, but in the module
|
||||
bool m_hasExtRefs = false; // This AstVar is referenced from outside the module
|
||||
|
||||
public:
|
||||
DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, uint32_t initialCapacity)
|
||||
: DfgVertexVariadic{dfg, type, varp->fileline(), dtypeFor(varp), initialCapacity}
|
||||
, m_varp{varp} {}
|
||||
ASTGEN_MEMBERS_DfgVertexVar;
|
||||
|
||||
AstVar* varp() const { return m_varp; }
|
||||
bool hasModRefs() const { return m_hasModRefs; }
|
||||
void setHasModRefs() { m_hasModRefs = true; }
|
||||
bool hasExtRefs() const { return m_hasExtRefs; }
|
||||
void setHasExtRefs() { m_hasExtRefs = true; }
|
||||
bool hasRefs() const { return m_hasModRefs || m_hasExtRefs; }
|
||||
|
||||
// Variable cannot be removed, even if redundant in the DfgGraph (might be used externally)
|
||||
bool keep() const {
|
||||
// Keep if referenced outside this module
|
||||
if (hasExtRefs()) return true;
|
||||
// Keep if traced
|
||||
if (v3Global.opt.trace() && varp()->isTrace()) return true;
|
||||
// Keep if public
|
||||
if (varp()->isSigPublic()) return true;
|
||||
// Otherwise it can be removed
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
|
||||
// === DfgVertex ===
|
||||
class DfgConst final : public DfgVertex {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
AstConst* const m_constp; // The AstConst associated with this vertex (owned by this vertex)
|
||||
|
||||
bool selfEquals(const DfgVertex& that) const override;
|
||||
V3Hash selfHash() const override;
|
||||
|
||||
public:
|
||||
DfgConst(DfgGraph& dfg, AstConst* constp)
|
||||
: DfgVertex{dfg, dfgType(), constp->fileline(), dtypeFor(constp)}
|
||||
, m_constp{constp} {}
|
||||
ASTGEN_MEMBERS_DfgConst;
|
||||
|
||||
~DfgConst() override { VL_DO_DANGLING(m_constp->deleteTree(), m_constp); }
|
||||
|
||||
AstConst* constp() const { return m_constp; }
|
||||
V3Number& num() const { return m_constp->num(); }
|
||||
|
||||
uint32_t toU32() const { return num().toUInt(); }
|
||||
int32_t toI32() const { return num().toSInt(); }
|
||||
|
||||
bool isZero() const { return num().isEqZero(); }
|
||||
bool isOnes() const { return num().isEqAllOnes(width()); }
|
||||
|
||||
std::pair<DfgEdge*, size_t> sourceEdges() override { return {nullptr, 0}; }
|
||||
std::pair<const DfgEdge*, size_t> sourceEdges() const override { return {nullptr, 0}; }
|
||||
const string srcName(size_t) const override { // LCOV_EXCL_START
|
||||
VL_UNREACHABLE;
|
||||
return "";
|
||||
} // LCOV_EXCL_STOP
|
||||
};
|
||||
|
||||
// === DfgVertexVar ===
|
||||
class DfgVarArray final : public DfgVertexVar {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
using DriverData = std::pair<FileLine*, uint32_t>;
|
||||
|
||||
std::vector<DriverData> m_driverData; // Additional data associate with each driver
|
||||
|
||||
bool selfEquals(const DfgVertex& that) const override;
|
||||
V3Hash selfHash() const override;
|
||||
|
||||
public:
|
||||
DfgVarArray(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexVar{dfg, dfgType(), varp, 4u} {
|
||||
UASSERT_OBJ(VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType), varp, "Non array DfgVarArray");
|
||||
}
|
||||
ASTGEN_MEMBERS_DfgVarArray;
|
||||
|
||||
bool isDrivenByDfg() const { return arity() > 0; }
|
||||
|
||||
void addDriver(FileLine* flp, uint32_t index, DfgVertex* vtxp) {
|
||||
m_driverData.emplace_back(flp, index);
|
||||
DfgVertexVariadic::addSource()->relinkSource(vtxp);
|
||||
}
|
||||
|
||||
void resetSources() {
|
||||
m_driverData.clear();
|
||||
DfgVertexVariadic::resetSources();
|
||||
}
|
||||
|
||||
// Remove undriven sources
|
||||
void packSources() {
|
||||
// Grab and reset the driver data
|
||||
std::vector<DriverData> driverData{std::move(m_driverData)};
|
||||
|
||||
// Grab and unlink the sources
|
||||
std::vector<DfgVertex*> sources{arity()};
|
||||
forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
sources[idx] = edge.sourcep();
|
||||
edge.unlinkSource();
|
||||
});
|
||||
DfgVertexVariadic::resetSources();
|
||||
|
||||
// Add back the driven sources
|
||||
for (size_t i = 0; i < sources.size(); ++i) {
|
||||
if (!sources[i]) continue;
|
||||
addDriver(driverData[i].first, driverData[i].second, sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FileLine* driverFileLine(size_t idx) const { return m_driverData[idx].first; }
|
||||
uint32_t driverIndex(size_t idx) const { return m_driverData[idx].second; }
|
||||
|
||||
DfgVertex* driverAt(size_t idx) const {
|
||||
const DfgEdge* const edgep = findSourceEdge([=](const DfgEdge&, size_t i) { //
|
||||
return driverIndex(i) == idx;
|
||||
});
|
||||
return edgep ? edgep->sourcep() : nullptr;
|
||||
}
|
||||
|
||||
const string srcName(size_t idx) const override { return cvtToStr(driverIndex(idx)); }
|
||||
};
|
||||
class DfgVarPacked final : public DfgVertexVar {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
using DriverData = std::pair<FileLine*, uint32_t>;
|
||||
|
||||
std::vector<DriverData> m_driverData; // Additional data associate with each driver
|
||||
|
||||
bool selfEquals(const DfgVertex& that) const override;
|
||||
V3Hash selfHash() const override;
|
||||
|
||||
public:
|
||||
DfgVarPacked(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexVar{dfg, dfgType(), varp, 1u} {}
|
||||
ASTGEN_MEMBERS_DfgVarPacked;
|
||||
|
||||
bool isDrivenByDfg() const { return arity() > 0; }
|
||||
bool isDrivenFullyByDfg() const { return arity() == 1 && source(0)->dtypep() == dtypep(); }
|
||||
|
||||
void addDriver(FileLine* flp, uint32_t lsb, DfgVertex* vtxp) {
|
||||
m_driverData.emplace_back(flp, lsb);
|
||||
DfgVertexVariadic::addSource()->relinkSource(vtxp);
|
||||
}
|
||||
|
||||
void resetSources() {
|
||||
m_driverData.clear();
|
||||
DfgVertexVariadic::resetSources();
|
||||
}
|
||||
|
||||
// Remove undriven sources
|
||||
void packSources() {
|
||||
// Grab and reset the driver data
|
||||
std::vector<DriverData> driverData{std::move(m_driverData)};
|
||||
|
||||
// Grab and unlink the sources
|
||||
std::vector<DfgVertex*> sources{arity()};
|
||||
forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
sources[idx] = edge.sourcep();
|
||||
edge.unlinkSource();
|
||||
});
|
||||
DfgVertexVariadic::resetSources();
|
||||
|
||||
// Add back the driven sources
|
||||
for (size_t i = 0; i < sources.size(); ++i) {
|
||||
if (!sources[i]) continue;
|
||||
addDriver(driverData[i].first, driverData[i].second, sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FileLine* driverFileLine(size_t idx) const { return m_driverData[idx].first; }
|
||||
uint32_t driverLsb(size_t idx) const { return m_driverData[idx].second; }
|
||||
|
||||
const string srcName(size_t idx) const override {
|
||||
return isDrivenFullyByDfg() ? "" : cvtToStr(driverLsb(idx));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
562
src/astgen
562
src/astgen
|
|
@ -8,12 +8,14 @@ import os
|
|||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
# from pprint import pprint, pformat
|
||||
|
||||
|
||||
# This class is used to represents both AstNode and DfgVertex sub-types
|
||||
class Node:
|
||||
|
||||
def __init__(self, name, superClass, file, lineno):
|
||||
def __init__(self, name, superClass, file=None, lineno=None):
|
||||
self._name = name
|
||||
self._superClass = superClass
|
||||
self._subClasses = [] # Initially list, but tuple after completion
|
||||
|
|
@ -173,9 +175,11 @@ class Node:
|
|||
return self in other.allSubClasses
|
||||
|
||||
|
||||
Nodes = {}
|
||||
SortedNodes = None
|
||||
DfgVertices = None
|
||||
AstNodes = {}
|
||||
AstNodeList = None
|
||||
|
||||
DfgVertices = {}
|
||||
DfgVertexList = None
|
||||
|
||||
ClassRefs = {}
|
||||
Stages = {}
|
||||
|
|
@ -278,7 +282,7 @@ class Cpt:
|
|||
self.error("Can't parse from function: " + func)
|
||||
typen = match.group(1)
|
||||
subnodes = match.group(2)
|
||||
if Nodes[typen].isRoot:
|
||||
if AstNodes[typen].isRoot:
|
||||
self.error("Unknown AstNode typen: " + typen + ": in " + func)
|
||||
|
||||
mif = ""
|
||||
|
|
@ -333,7 +337,7 @@ class Cpt:
|
|||
elif match_skip:
|
||||
typen = match_skip.group(1)
|
||||
self.tree_skip_visit[typen] = 1
|
||||
if typen not in Nodes:
|
||||
if typen not in AstNodes:
|
||||
self.error("Unknown node type: " + typen)
|
||||
|
||||
else:
|
||||
|
|
@ -463,7 +467,7 @@ class Cpt:
|
|||
self.print(
|
||||
" // Bottom class up, as more simple transforms are generally better\n"
|
||||
)
|
||||
for node in SortedNodes:
|
||||
for node in AstNodeList:
|
||||
out_for_type_sc = []
|
||||
out_for_type = []
|
||||
classes = list(node.allSuperClasses)
|
||||
|
|
@ -502,7 +506,7 @@ class Cpt:
|
|||
"".join(out_for_type_sc))
|
||||
if out_for_type[0]:
|
||||
self.print(" iterateAndNextNull(nodep->rhsp());\n")
|
||||
if node.isSubClassOf(Nodes["NodeTriop"]):
|
||||
if node.isSubClassOf(AstNodes["NodeTriop"]):
|
||||
self.print(
|
||||
" iterateAndNextNull(nodep->thsp());\n")
|
||||
self.print("".join(out_for_type) + " }\n")
|
||||
|
|
@ -542,7 +546,7 @@ def parseOpType(string):
|
|||
return None
|
||||
|
||||
|
||||
def read_types(filename):
|
||||
def read_types(filename, Nodes, prefix):
|
||||
hasErrors = False
|
||||
|
||||
def error(lineno, message):
|
||||
|
|
@ -560,8 +564,9 @@ def read_types(filename):
|
|||
return
|
||||
if not hasAstgenMembers:
|
||||
error(
|
||||
node.lineno, "'Ast" + node.name +
|
||||
"' does not contain 'ASTGEN_MEMBERS_" + node.name + ";'")
|
||||
node.lineno,
|
||||
"'{p}{n}' does not contain 'ASTGEN_MEMBERS_{p}{n};'".format(
|
||||
p=prefix, n=node.name))
|
||||
hasAstgenMembers = False
|
||||
|
||||
with open(filename) as fh:
|
||||
|
|
@ -575,12 +580,12 @@ def read_types(filename):
|
|||
classn = match.group(2)
|
||||
match = re.search(r':\s*public\s+(\S+)', line)
|
||||
supern = match.group(1) if match else ""
|
||||
if re.search(r'Ast', supern):
|
||||
classn = re.sub(r'^Ast', '', classn)
|
||||
supern = re.sub(r'^Ast', '', supern)
|
||||
if re.search(prefix, supern):
|
||||
classn = re.sub(r'^' + prefix, '', classn)
|
||||
supern = re.sub(r'^' + prefix, '', supern)
|
||||
if not supern:
|
||||
sys.exit("%Error: 'Ast{}' has no super-class".format(
|
||||
classn))
|
||||
sys.exit("%Error: '{p}{c}' has no super-class".format(
|
||||
p=prefix, c=classn))
|
||||
checkFinishedNode(node)
|
||||
superClass = Nodes[supern]
|
||||
node = Node(classn, superClass, filename, lineno)
|
||||
|
|
@ -589,8 +594,13 @@ def read_types(filename):
|
|||
if not node:
|
||||
continue
|
||||
|
||||
if re.match(r'^\s*ASTGEN_MEMBERS_' + node.name + ';', line):
|
||||
if re.match(r'^\s*ASTGEN_MEMBERS_' + prefix + node.name + ';',
|
||||
line):
|
||||
hasAstgenMembers = True
|
||||
|
||||
if prefix != "Ast":
|
||||
continue
|
||||
|
||||
match = re.match(r'^\s*//\s*@astgen\s+(.*)$', line)
|
||||
if match:
|
||||
decl = re.sub(r'//.*$', '', match.group(1))
|
||||
|
|
@ -650,6 +660,59 @@ def read_types(filename):
|
|||
sys.exit("%Error: Stopping due to errors reported above")
|
||||
|
||||
|
||||
def check_types(sortedTypes, prefix, abstractPrefix):
|
||||
baseClass = prefix + abstractPrefix
|
||||
|
||||
# Check all leaf types are not AstNode* and non-leaves are AstNode*
|
||||
for node in sortedTypes:
|
||||
if re.match(r'^' + abstractPrefix, node.name):
|
||||
if node.isLeaf:
|
||||
sys.exit(
|
||||
"%Error: Final {b} subclasses must not be named {b}*: {p}{n}"
|
||||
.format(b=baseClass, p=prefix, n=node.name))
|
||||
else:
|
||||
if not node.isLeaf:
|
||||
sys.exit(
|
||||
"%Error: Non-final {b} subclasses must be named {b}*: {p}{n}"
|
||||
.format(b=baseClass, p=prefix, n=node.name))
|
||||
|
||||
# Check ordering of node definitions
|
||||
hasOrderingError = False
|
||||
|
||||
files = tuple(
|
||||
sorted(set(_.file for _ in sortedTypes if _.file is not None)))
|
||||
|
||||
for file in files:
|
||||
nodes = tuple(filter(lambda _, f=file: _.file == f, sortedTypes))
|
||||
expectOrder = tuple(sorted(nodes, key=lambda _: (_.isLeaf, _.ordIdx)))
|
||||
actualOrder = tuple(sorted(nodes, key=lambda _: _.lineno))
|
||||
expect = {
|
||||
node: pred
|
||||
for pred, node in zip((None, ) + expectOrder[:-1], expectOrder)
|
||||
}
|
||||
actual = {
|
||||
node: pred
|
||||
for pred, node in zip((None, ) + actualOrder[:-1], actualOrder)
|
||||
}
|
||||
for node in nodes:
|
||||
if expect[node] != actual[node]:
|
||||
hasOrderingError = True
|
||||
pred = expect[node]
|
||||
print(
|
||||
"{file}:{lineno}: %Error: Definition of '{p}{n}' is out of order. Shold be {where}."
|
||||
.format(file=file,
|
||||
lineno=node.lineno,
|
||||
p=prefix,
|
||||
n=node.name,
|
||||
where=("right after '" + prefix + pred.name +
|
||||
"'" if pred else "first in file")),
|
||||
file=sys.stderr)
|
||||
|
||||
if hasOrderingError:
|
||||
sys.exit(
|
||||
"%Error: Stopping due to out of order definitions listed above")
|
||||
|
||||
|
||||
def read_stages(filename):
|
||||
with open(filename) as fh:
|
||||
n = 100
|
||||
|
|
@ -712,7 +775,7 @@ def write_report(filename):
|
|||
fh.write(" " + classn + "\n")
|
||||
|
||||
fh.write("\nClasses:\n")
|
||||
for node in SortedNodes:
|
||||
for node in AstNodeList:
|
||||
fh.write(" class Ast%-17s\n" % node.name)
|
||||
fh.write(" arity: {}\n".format(node.arity))
|
||||
fh.write(" parent: ")
|
||||
|
|
@ -741,97 +804,110 @@ def write_report(filename):
|
|||
fh.write("\n")
|
||||
|
||||
|
||||
def write_classes(filename):
|
||||
with open_file(filename) as fh:
|
||||
fh.write("class AstNode;\n")
|
||||
for node in SortedNodes:
|
||||
fh.write("class Ast%-17s // " % (node.name + ";"))
|
||||
################################################################################
|
||||
# Common code genaration
|
||||
################################################################################
|
||||
|
||||
|
||||
def write_forward_class_decls(prefix, nodeList):
|
||||
with open_file("V3{p}__gen_forward_class_decls.h".format(p=prefix)) as fh:
|
||||
for node in nodeList:
|
||||
fh.write("class {p}{n:<17} // ".format(p=prefix,
|
||||
n=node.name + ";"))
|
||||
for superClass in node.allSuperClasses:
|
||||
fh.write("Ast%-12s " % superClass.name)
|
||||
fh.write("{p}{n:<12} ".format(p=prefix, n=superClass.name))
|
||||
fh.write("\n")
|
||||
|
||||
|
||||
def write_visitor_decls(filename):
|
||||
with open_file(filename) as fh:
|
||||
for node in SortedNodes:
|
||||
def write_visitor_decls(prefix, nodeList):
|
||||
with open_file("V3{p}__gen_visitor_decls.h".format(p=prefix)) as fh:
|
||||
for node in nodeList:
|
||||
if not node.isRoot:
|
||||
fh.write("virtual void visit(Ast" + node.name + "*);\n")
|
||||
fh.write("virtual void visit({p}{n}*);\n".format(p=prefix,
|
||||
n=node.name))
|
||||
|
||||
|
||||
def write_visitor_defns(filename):
|
||||
with open_file(filename) as fh:
|
||||
for node in SortedNodes:
|
||||
def write_visitor_defns(prefix, nodeList, visitor):
|
||||
with open_file("V3{p}__gen_visitor_defns.h".format(p=prefix)) as fh:
|
||||
variable = "nodep" if prefix == "Ast" else "vtxp"
|
||||
for node in nodeList:
|
||||
base = node.superClass
|
||||
if base is not None:
|
||||
fh.write("void VNVisitor::visit(Ast" + node.name +
|
||||
"* nodep) { visit(static_cast<Ast" + base.name +
|
||||
"*>(nodep)); }\n")
|
||||
fh.write(
|
||||
"void {c}::visit({p}{n}* {v}) {{ visit(static_cast<{p}{b}*>({v})); }}\n"
|
||||
.format(c=visitor,
|
||||
p=prefix,
|
||||
n=node.name,
|
||||
b=base.name,
|
||||
v=variable))
|
||||
|
||||
|
||||
def write_impl(filename):
|
||||
with open_file(filename) as fh:
|
||||
fh.write("\n")
|
||||
fh.write("// For internal use. They assume argument is not nullptr.\n")
|
||||
for node in SortedNodes:
|
||||
fh.write("template<> inline bool AstNode::privateTypeTest<Ast" +
|
||||
node.name + ">(const AstNode* nodep) { ")
|
||||
if node.isRoot:
|
||||
fh.write("return true; ")
|
||||
else:
|
||||
fh.write("return ")
|
||||
if not node.isLeaf:
|
||||
fh.write(
|
||||
"static_cast<int>(nodep->type()) >= static_cast<int>(VNType::first"
|
||||
+ node.name + ") && ")
|
||||
fh.write(
|
||||
"static_cast<int>(nodep->type()) <= static_cast<int>(VNType::last"
|
||||
+ node.name + "); ")
|
||||
else:
|
||||
fh.write("nodep->type() == VNType::at" + node.name + "; ")
|
||||
fh.write("}\n")
|
||||
def write_type_enum(prefix, nodeList):
|
||||
root = next(_ for _ in nodeList if _.isRoot)
|
||||
with open_file("V3{p}__gen_type_enum.h".format(p=prefix)) as fh:
|
||||
|
||||
|
||||
def write_types(filename):
|
||||
with open_file(filename) as fh:
|
||||
fh.write(" enum en : uint16_t {\n")
|
||||
for node in sorted(filter(lambda _: _.isLeaf, SortedNodes),
|
||||
for node in sorted(filter(lambda _: _.isLeaf, nodeList),
|
||||
key=lambda _: _.typeId):
|
||||
fh.write(" at" + node.name + " = " + str(node.typeId) +
|
||||
",\n")
|
||||
fh.write(" _ENUM_END = " + str(Nodes["Node"].typeIdMax + 1) +
|
||||
"\n")
|
||||
fh.write(" at{t} = {n},\n".format(t=node.name,
|
||||
n=node.typeId))
|
||||
fh.write(" _ENUM_END = {n}\n".format(n=root.typeIdMax + 1))
|
||||
fh.write(" };\n")
|
||||
|
||||
fh.write(" enum bounds : uint16_t {\n")
|
||||
for node in sorted(filter(lambda _: not _.isLeaf, SortedNodes),
|
||||
for node in sorted(filter(lambda _: not _.isLeaf, nodeList),
|
||||
key=lambda _: _.typeIdMin):
|
||||
fh.write(" first" + node.name + " = " +
|
||||
str(node.typeIdMin) + ",\n")
|
||||
fh.write(" last" + node.name + " = " + str(node.typeIdMax) +
|
||||
",\n")
|
||||
fh.write(" first{t} = {n},\n".format(t=node.name,
|
||||
n=node.typeIdMin))
|
||||
fh.write(" last{t} = {n},\n".format(t=node.name,
|
||||
n=node.typeIdMax))
|
||||
fh.write(" _BOUNDS_END\n")
|
||||
fh.write(" };\n")
|
||||
|
||||
fh.write(" const char* ascii() const {\n")
|
||||
fh.write(" static const char* const names[_ENUM_END + 1] = {\n")
|
||||
for node in sorted(filter(lambda _: _.isLeaf, SortedNodes),
|
||||
for node in sorted(filter(lambda _: _.isLeaf, nodeList),
|
||||
key=lambda _: _.typeId):
|
||||
fh.write(" \"" + node.name.upper() + "\",\n")
|
||||
fh.write(' "{T}",\n'.format(T=node.name.upper()))
|
||||
fh.write(" \"_ENUM_END\"\n")
|
||||
fh.write(" };\n")
|
||||
fh.write(" return names[m_e];\n")
|
||||
fh.write(" }\n")
|
||||
|
||||
|
||||
def write_yystype(filename):
|
||||
with open_file(filename) as fh:
|
||||
for node in SortedNodes:
|
||||
fh.write("Ast{t}* {m}p;\n".format(t=node.name,
|
||||
m=node.name[0].lower() +
|
||||
node.name[1:]))
|
||||
def write_type_tests(prefix, nodeList):
|
||||
with open_file("V3{p}__gen_type_tests.h".format(p=prefix)) as fh:
|
||||
fh.write("// For internal use. They assume argument is not nullptr.\n")
|
||||
if prefix == "Ast":
|
||||
base = "AstNode"
|
||||
variable = "nodep"
|
||||
enum = "VNType"
|
||||
elif prefix == "Dfg":
|
||||
base = "DfgVertex"
|
||||
variable = "vtxp"
|
||||
enum = "VDfgType"
|
||||
for node in nodeList:
|
||||
fh.write(
|
||||
"template<> inline bool {b}::privateTypeTest<{p}{n}>(const {b}* {v}) {{ "
|
||||
.format(b=base, p=prefix, n=node.name, v=variable))
|
||||
if node.isRoot:
|
||||
fh.write("return true;")
|
||||
elif not node.isLeaf:
|
||||
fh.write(
|
||||
"return static_cast<int>({v}->type()) >= static_cast<int>({e}::first{t}) && static_cast<int>({v}->type()) <= static_cast<int>({e}::last{t});"
|
||||
.format(v=variable, e=enum, t=node.name))
|
||||
else:
|
||||
fh.write("return {v}->type() == {e}::at{t};".format(
|
||||
v=variable, e=enum, t=node.name))
|
||||
fh.write(" }\n")
|
||||
|
||||
|
||||
def write_macros(filename):
|
||||
################################################################################
|
||||
# Ast code genaration
|
||||
################################################################################
|
||||
|
||||
|
||||
def write_ast_macros(filename):
|
||||
with open_file(filename) as fh:
|
||||
|
||||
def emitBlock(pattern, **fmt):
|
||||
|
|
@ -839,8 +915,8 @@ def write_macros(filename):
|
|||
textwrap.indent(textwrap.dedent(pattern),
|
||||
" ").format(**fmt).replace("\n", " \\\n"))
|
||||
|
||||
for node in SortedNodes:
|
||||
fh.write("#define ASTGEN_MEMBERS_{t} \\\n".format(t=node.name))
|
||||
for node in AstNodeList:
|
||||
fh.write("#define ASTGEN_MEMBERS_Ast{t} \\\n".format(t=node.name))
|
||||
emitBlock('''\
|
||||
static Ast{t}* cloneTreeNull(Ast{t}* nodep, bool cloneNextLink) {{
|
||||
return nodep ? nodep->cloneTree(cloneNextLink) : nullptr;
|
||||
|
|
@ -860,7 +936,7 @@ def write_macros(filename):
|
|||
''',
|
||||
t=node.name)
|
||||
|
||||
for n in (1, 2, 3, 4):
|
||||
for n in range(1, 5):
|
||||
op = node.getOp(n)
|
||||
if not op:
|
||||
continue
|
||||
|
|
@ -907,7 +983,15 @@ def write_macros(filename):
|
|||
fh.write("\n")
|
||||
|
||||
|
||||
def write_op_checks(filename):
|
||||
def write_ast_yystype(filename):
|
||||
with open_file(filename) as fh:
|
||||
for node in AstNodeList:
|
||||
fh.write("Ast{t}* {m}p;\n".format(t=node.name,
|
||||
m=node.name[0].lower() +
|
||||
node.name[1:]))
|
||||
|
||||
|
||||
def write_ast_op_checks(filename):
|
||||
with open_file(filename) as fh:
|
||||
|
||||
indent = ""
|
||||
|
|
@ -917,7 +1001,7 @@ def write_op_checks(filename):
|
|||
textwrap.indent(textwrap.dedent(pattern),
|
||||
indent).format(**fmt))
|
||||
|
||||
for node in SortedNodes:
|
||||
for node in AstNodeList:
|
||||
if not node.isLeaf:
|
||||
continue
|
||||
|
||||
|
|
@ -991,102 +1075,98 @@ def write_op_checks(filename):
|
|||
''')
|
||||
|
||||
|
||||
def write_dfg_vertex_classes(filename):
|
||||
################################################################################
|
||||
# DFG code genaration
|
||||
################################################################################
|
||||
|
||||
|
||||
def write_dfg_macros(filename):
|
||||
with open_file(filename) as fh:
|
||||
fh.write("\n")
|
||||
for node in DfgVertices:
|
||||
fh.write("class Dfg{} final : public DfgVertexWithArity<{}> {{\n".
|
||||
format(node.name, node.arity))
|
||||
fh.write(" friend class DfgVertex;\n")
|
||||
fh.write(" friend class DfgVisitor;\n")
|
||||
fh.write(" void accept(DfgVisitor& visitor) override;\n")
|
||||
|
||||
def emitBlock(pattern, **fmt):
|
||||
fh.write(
|
||||
" static constexpr DfgType dfgType() {{ return DfgType::at{t}; }};\n"
|
||||
.format(t=node.name))
|
||||
fh.write("public:\n")
|
||||
fh.write(
|
||||
" Dfg{t}(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep) : DfgVertexWithArity<{a}>{{dfg, flp, dtypep, dfgType()}} {{}}\n"
|
||||
.format(t=node.name, a=node.arity))
|
||||
# Accessors
|
||||
textwrap.indent(textwrap.dedent(pattern),
|
||||
" ").format(**fmt).replace("\n", " \\\n"))
|
||||
|
||||
for node in DfgVertexList:
|
||||
fh.write("#define ASTGEN_MEMBERS_Dfg{t} \\\n".format(t=node.name))
|
||||
|
||||
if node.isLeaf:
|
||||
emitBlock('''\
|
||||
static constexpr VDfgType dfgType() {{ return VDfgType::at{t}; }};
|
||||
void accept(DfgVisitor& v) override {{ v.visit(this); }}
|
||||
''',
|
||||
t=node.name)
|
||||
|
||||
for n in range(1, node.arity + 1):
|
||||
name, _, _ = node.getOp(n)
|
||||
emitBlock('''\
|
||||
DfgVertex* {name}() const {{ return source<{n}>(); }}
|
||||
void {name}(DfgVertex* vtxp) {{ relinkSource<{n}>(vtxp); }}
|
||||
''',
|
||||
name=name,
|
||||
n=n - 1)
|
||||
|
||||
operandNames = tuple(
|
||||
node.getOp(n)[0] for n in range(1, node.arity + 1))
|
||||
assert not operandNames or len(operandNames) == node.arity
|
||||
for i, n in enumerate(operandNames):
|
||||
fh.write(
|
||||
" DfgVertex* {n}() const {{ return source<{i}>(); }}\n".
|
||||
format(n=n, i=i))
|
||||
for i, n in enumerate(operandNames):
|
||||
fh.write(
|
||||
" void {n}(DfgVertex* vtxp) {{ relinkSource<{i}>(vtxp); }}\n"
|
||||
.format(n=n, i=i))
|
||||
if operandNames:
|
||||
names = ", ".join(map(lambda _: '"' + _ + '"', operandNames))
|
||||
fh.write(
|
||||
" const string srcName(size_t idx) const override {\n")
|
||||
fh.write(
|
||||
" static const char* names[{a}] = {{ {ns} }};\n".
|
||||
format(a=node.arity, ns=names))
|
||||
fh.write(" return names[idx];\n")
|
||||
fh.write(" }\n")
|
||||
fh.write("};\n")
|
||||
fh.write("\n")
|
||||
fh.write("\n")
|
||||
|
||||
fh.write("\n\ntemplate<typename Node>\n")
|
||||
fh.write("struct DfgForAstImpl;\n\n")
|
||||
for node in DfgVertices:
|
||||
fh.write("template <>\n")
|
||||
emitBlock('''\
|
||||
const std::string srcName(size_t idx) const override {{
|
||||
static const char* names[{a}] = {{ {ns} }};
|
||||
return names[idx];
|
||||
}}
|
||||
''',
|
||||
a=node.arity,
|
||||
ns=", ".join(
|
||||
map(lambda _: '"' + _ + '"', operandNames)))
|
||||
fh.write(
|
||||
"struct DfgForAstImpl<Ast{name}> {{\n".format(name=node.name))
|
||||
fh.write(" using type = Dfg{name};\n".format(name=node.name))
|
||||
fh.write("};\n")
|
||||
fh.write("\ntemplate<typename Node>\n")
|
||||
fh.write("using DfgForAst = typename DfgForAstImpl<Node>::type;\n")
|
||||
|
||||
fh.write("\n\ntemplate<typename Vertex>\n")
|
||||
fh.write("struct AstForDfgImpl;\n\n")
|
||||
for node in DfgVertices:
|
||||
fh.write("template <>\n")
|
||||
fh.write(
|
||||
"struct AstForDfgImpl<Dfg{name}> {{\n".format(name=node.name))
|
||||
fh.write(" using type = Ast{name};\n".format(name=node.name))
|
||||
fh.write("};\n")
|
||||
fh.write("\ntemplate<typename Vertex>\n")
|
||||
fh.write("using AstForDfg = typename AstForDfgImpl<Vertex>::type;\n")
|
||||
" static_assert(true, \"\")\n") # Swallowing the semicolon
|
||||
|
||||
|
||||
def write_dfg_visitor_decls(filename):
|
||||
def write_dfg_auto_classes(filename):
|
||||
with open_file(filename) as fh:
|
||||
fh.write("\n")
|
||||
fh.write("virtual void visit(DfgVertex*) = 0;\n")
|
||||
for node in DfgVertices:
|
||||
fh.write("virtual void visit(Dfg{}*);\n".format(node.name))
|
||||
|
||||
def emitBlock(pattern, **fmt):
|
||||
fh.write(textwrap.dedent(pattern).format(**fmt))
|
||||
|
||||
def write_dfg_definitions(filename):
|
||||
with open_file(filename) as fh:
|
||||
for node in DfgVertexList:
|
||||
# Only generate code for automatically derieved leaf nodes
|
||||
if (node.file is not None) or not node.isLeaf:
|
||||
continue
|
||||
|
||||
emitBlock('''\
|
||||
class Dfg{t} final : public Dfg{s} {{
|
||||
public:
|
||||
Dfg{t}(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep)
|
||||
: Dfg{s}{{dfg, dfgType(), flp, dtypep}} {{}}
|
||||
ASTGEN_MEMBERS_Dfg{t};
|
||||
}};
|
||||
''',
|
||||
t=node.name,
|
||||
s=node.superClass.name)
|
||||
fh.write("\n")
|
||||
for node in DfgVertices:
|
||||
fh.write(
|
||||
"void Dfg{}::accept(DfgVisitor& visitor) {{ visitor.visit(this); }}\n"
|
||||
.format(node.name))
|
||||
fh.write("\n")
|
||||
for node in DfgVertices:
|
||||
fh.write(
|
||||
"void DfgVisitor::visit(Dfg{}* vtxp) {{ visit(static_cast<DfgVertex*>(vtxp)); }}\n"
|
||||
.format(node.name))
|
||||
|
||||
|
||||
def write_dfg_ast_to_dfg(filename):
|
||||
with open_file(filename) as fh:
|
||||
fh.write("\n")
|
||||
for node in DfgVertices:
|
||||
for node in DfgVertexList:
|
||||
# Only generate code for automatically derieved leaf nodes
|
||||
if (node.file is not None) or (not node.isLeaf):
|
||||
continue
|
||||
|
||||
fh.write(
|
||||
"void visit(Ast{t}* nodep) override {{\n".format(t=node.name))
|
||||
fh.write(
|
||||
' UASSERT_OBJ(!nodep->user1p(), nodep, "Already has Dfg vertex");\n'
|
||||
' UASSERT_OBJ(!nodep->user1p(), nodep, "Already has Dfg vertex");\n\n'
|
||||
)
|
||||
fh.write(" if (unhandled(nodep)) return;\n")
|
||||
fh.write(" if (unhandled(nodep)) return;\n\n")
|
||||
for i in range(node.arity):
|
||||
fh.write(" iterate(nodep->op{j}p());\n".format(j=i + 1))
|
||||
fh.write(" if (m_foundUnhandled) return;\n")
|
||||
fh.write(
|
||||
' UASSERT_OBJ(nodep->op{j}p()->user1p(), nodep, "Child {j} missing Dfg vertex");\n'
|
||||
.format(j=i + 1))
|
||||
fh.write("\n")
|
||||
fh.write(
|
||||
" Dfg{t}* const vtxp = makeVertex<Dfg{t}>(nodep, *m_dfgp);\n"
|
||||
.format(t=node.name))
|
||||
|
|
@ -1095,24 +1175,23 @@ def write_dfg_ast_to_dfg(filename):
|
|||
fh.write(" ++m_ctx.m_nonRepNode;\n")
|
||||
fh.write(" return;\n")
|
||||
fh.write(" }\n\n")
|
||||
fh.write(" m_uncommittedVertices.push_back(vtxp);\n")
|
||||
for i in range(node.arity):
|
||||
fh.write(" iterate(nodep->op{j}p());\n".format(j=i + 1))
|
||||
fh.write(" if (m_foundUnhandled) return;\n")
|
||||
fh.write(
|
||||
' UASSERT_OBJ(nodep->op{j}p()->user1p(), nodep, "Child {j} missing Dfg vertex");\n'
|
||||
.format(j=i + 1))
|
||||
fh.write(
|
||||
" vtxp->relinkSource<{i}>(nodep->op{j}p()->user1u().to<DfgVertex*>());\n\n"
|
||||
" vtxp->relinkSource<{i}>(nodep->op{j}p()->user1u().to<DfgVertex*>());\n"
|
||||
.format(i=i, j=i + 1))
|
||||
fh.write("\n")
|
||||
fh.write(" m_uncommittedVertices.push_back(vtxp);\n")
|
||||
fh.write(" nodep->user1p(vtxp);\n")
|
||||
fh.write("}\n")
|
||||
|
||||
|
||||
def write_dfg_dfg_to_ast(filename):
|
||||
with open_file(filename) as fh:
|
||||
fh.write("\n")
|
||||
for node in DfgVertices:
|
||||
for node in DfgVertexList:
|
||||
# Only generate code for automatically derieved leaf nodes
|
||||
if (node.file is not None) or (not node.isLeaf):
|
||||
continue
|
||||
|
||||
fh.write(
|
||||
"void visit(Dfg{t}* vtxp) override {{\n".format(t=node.name))
|
||||
for i in range(node.arity):
|
||||
|
|
@ -1146,6 +1225,9 @@ parser.add_argument('-I', action='store', help='source code include directory')
|
|||
parser.add_argument('--astdef',
|
||||
action='append',
|
||||
help='add AST definition file (relative to -I)')
|
||||
parser.add_argument('--dfgdef',
|
||||
action='append',
|
||||
help='add DFG definition file (relative to -I)')
|
||||
parser.add_argument('--classes',
|
||||
action='store_true',
|
||||
help='makes class declaration files')
|
||||
|
|
@ -1155,66 +1237,86 @@ parser.add_argument('infiles', nargs='*', help='list of input .cpp filenames')
|
|||
|
||||
Args = parser.parse_args()
|
||||
|
||||
###############################################################################
|
||||
# Read AstNode definitions
|
||||
###############################################################################
|
||||
|
||||
# Set up the root AstNode type. It is standalone so we don't need to parse the
|
||||
# sources for this.
|
||||
Nodes["Node"] = Node("Node", None, "AstNode", 1)
|
||||
AstNodes["Node"] = Node("Node", None)
|
||||
|
||||
# Read Ast node definitions
|
||||
# Read AstNode definitions
|
||||
for filename in Args.astdef:
|
||||
read_types(os.path.join(Args.I, filename))
|
||||
read_types(os.path.join(Args.I, filename), AstNodes, "Ast")
|
||||
|
||||
# Compute derived properties over the whole AstNode hierarchy
|
||||
Nodes["Node"].complete()
|
||||
AstNodes["Node"].complete()
|
||||
|
||||
SortedNodes = tuple(map(lambda _: Nodes[_], sorted(Nodes.keys())))
|
||||
AstNodeList = tuple(map(lambda _: AstNodes[_], sorted(AstNodes.keys())))
|
||||
|
||||
for node in SortedNodes:
|
||||
# Check all leaves are not AstNode* and non-leaves are AstNode*
|
||||
if re.match(r'^Node', node.name):
|
||||
if node.isLeaf:
|
||||
sys.exit(
|
||||
"%Error: Final AstNode subclasses must not be named AstNode*: Ast"
|
||||
+ node.name)
|
||||
check_types(AstNodeList, "Ast", "Node")
|
||||
|
||||
###############################################################################
|
||||
# Read and generate DfgVertex definitions
|
||||
###############################################################################
|
||||
|
||||
# Set up the root DfgVertex type and some other hand-written base types.
|
||||
# These are standalone so we don't need to parse the sources for this.
|
||||
DfgVertices["Vertex"] = Node("Vertex", None)
|
||||
DfgVertices["VertexUnary"] = Node("VertexUnary", DfgVertices["Vertex"])
|
||||
DfgVertices["Vertex"].addSubClass(DfgVertices["VertexUnary"])
|
||||
DfgVertices["VertexBinary"] = Node("VertexBinary", DfgVertices["Vertex"])
|
||||
DfgVertices["Vertex"].addSubClass(DfgVertices["VertexBinary"])
|
||||
DfgVertices["VertexTernary"] = Node("VertexTernary", DfgVertices["Vertex"])
|
||||
DfgVertices["Vertex"].addSubClass(DfgVertices["VertexTernary"])
|
||||
DfgVertices["VertexVariadic"] = Node("VertexVariadic", DfgVertices["Vertex"])
|
||||
DfgVertices["Vertex"].addSubClass(DfgVertices["VertexVariadic"])
|
||||
|
||||
# Read DfgVertex definitions
|
||||
for filename in Args.dfgdef:
|
||||
read_types(os.path.join(Args.I, filename), DfgVertices, "Dfg")
|
||||
|
||||
# Add the DfgVertex sub-types automatically derived from AstNode sub-types
|
||||
for node in AstNodeList:
|
||||
# Ignore the hierarchy for now
|
||||
if not node.isLeaf:
|
||||
continue
|
||||
|
||||
# Ignore any explicitly defined vertex
|
||||
if node.name in DfgVertices:
|
||||
continue
|
||||
|
||||
if node.isSubClassOf(AstNodes["NodeUniop"]):
|
||||
base = DfgVertices["VertexUnary"]
|
||||
elif node.isSubClassOf(AstNodes["NodeBiop"]):
|
||||
base = DfgVertices["VertexBinary"]
|
||||
elif node.isSubClassOf(AstNodes["NodeTriop"]):
|
||||
base = DfgVertices["VertexTernary"]
|
||||
else:
|
||||
if not node.isLeaf:
|
||||
sys.exit(
|
||||
"%Error: Non-final AstNode subclasses must be named AstNode*: Ast"
|
||||
+ node.name)
|
||||
continue
|
||||
|
||||
DfgBases = (Nodes["NodeUniop"], Nodes["NodeBiop"], Nodes["NodeTriop"])
|
||||
DfgVertices = tuple(
|
||||
node for node in SortedNodes
|
||||
if node.isLeaf and any(node.isSubClassOf(base) for base in DfgBases))
|
||||
vertex = Node(node.name, base)
|
||||
DfgVertices[node.name] = vertex
|
||||
base.addSubClass(vertex)
|
||||
|
||||
# Check ordering of node definitions
|
||||
files = tuple(sorted(set(_.file for _ in SortedNodes)))
|
||||
for n in range(1, node.arity + 1):
|
||||
op = node.getOp(n)
|
||||
if op is not None:
|
||||
name, monad, kind = op
|
||||
assert monad == "", "Cannot represnt AstNode as DfgVertex"
|
||||
vertex.addOp(n, name, "", "")
|
||||
|
||||
hasOrderingError = False
|
||||
for file in files:
|
||||
nodes = tuple(filter(lambda _, f=file: _.file == f, SortedNodes))
|
||||
expectOrder = tuple(sorted(nodes, key=lambda _: (_.isLeaf, _.ordIdx)))
|
||||
actualOrder = tuple(sorted(nodes, key=lambda _: _.lineno))
|
||||
expect = {
|
||||
node: pred
|
||||
for pred, node in zip((None, ) + expectOrder[:-1], expectOrder)
|
||||
}
|
||||
actual = {
|
||||
node: pred
|
||||
for pred, node in zip((None, ) + actualOrder[:-1], actualOrder)
|
||||
}
|
||||
for node in nodes:
|
||||
if expect[node] != actual[node]:
|
||||
hasOrderingError = True
|
||||
pred = expect[node]
|
||||
print(file + ":" + str(node.lineno) +
|
||||
": %Error: Definition of 'Ast" + node.name +
|
||||
"' is out of order. Should be " +
|
||||
("right after 'Ast" + pred.name +
|
||||
"'" if pred else "first in file") + ".",
|
||||
file=sys.stderr)
|
||||
# Compute derived properties over the whole DfgVertex hierarchy
|
||||
DfgVertices["Vertex"].complete()
|
||||
|
||||
if hasOrderingError:
|
||||
sys.exit("%Error: Stopping due to out of order definitions listed above")
|
||||
DfgVertexList = tuple(map(lambda _: DfgVertices[_],
|
||||
sorted(DfgVertices.keys())))
|
||||
|
||||
check_types(DfgVertexList, "Dfg", "Vertex")
|
||||
|
||||
###############################################################################
|
||||
# Read additional files
|
||||
###############################################################################
|
||||
|
||||
read_stages(Args.I + "/Verilator.cpp")
|
||||
|
||||
|
|
@ -1224,19 +1326,29 @@ source_files.extend(glob.glob(Args.I + "/*.cpp"))
|
|||
for filename in source_files:
|
||||
read_refs(filename)
|
||||
|
||||
###############################################################################
|
||||
# Generate output
|
||||
###############################################################################
|
||||
|
||||
if Args.classes:
|
||||
write_report("V3Ast__gen_report.txt")
|
||||
write_classes("V3Ast__gen_classes.h")
|
||||
write_visitor_decls("V3Ast__gen_visitor_decls.h")
|
||||
write_visitor_defns("V3Ast__gen_visitor_defns.h")
|
||||
write_impl("V3Ast__gen_impl.h")
|
||||
write_types("V3Ast__gen_types.h")
|
||||
write_yystype("V3Ast__gen_yystype.h")
|
||||
write_macros("V3Ast__gen_macros.h")
|
||||
write_op_checks("V3Ast__gen_op_checks.h")
|
||||
write_dfg_vertex_classes("V3Dfg__gen_vertex_classes.h")
|
||||
write_dfg_visitor_decls("V3Dfg__gen_visitor_decls.h")
|
||||
write_dfg_definitions("V3Dfg__gen_definitions.h")
|
||||
# Write Ast code
|
||||
write_forward_class_decls("Ast", AstNodeList)
|
||||
write_visitor_decls("Ast", AstNodeList)
|
||||
write_visitor_defns("Ast", AstNodeList, "VNVisitor")
|
||||
write_type_enum("Ast", AstNodeList)
|
||||
write_type_tests("Ast", AstNodeList)
|
||||
write_ast_macros("V3Ast__gen_macros.h")
|
||||
write_ast_yystype("V3Ast__gen_yystype.h")
|
||||
write_ast_op_checks("V3Ast__gen_op_checks.h")
|
||||
# Write Dfg code
|
||||
write_forward_class_decls("Dfg", DfgVertexList)
|
||||
write_visitor_decls("Dfg", DfgVertexList)
|
||||
write_visitor_defns("Dfg", DfgVertexList, "DfgVisitor")
|
||||
write_type_enum("Dfg", DfgVertexList)
|
||||
write_type_tests("Dfg", DfgVertexList)
|
||||
write_dfg_macros("V3Dfg__gen_macros.h")
|
||||
write_dfg_auto_classes("V3Dfg__gen_auto_classes.h")
|
||||
write_dfg_ast_to_dfg("V3Dfg__gen_ast_to_dfg.h")
|
||||
write_dfg_dfg_to_ast("V3Dfg__gen_dfg_to_ast.h")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue