Skip to content

Commit

Permalink
Internals: astgen: Detect bad node types after edits.
Browse files Browse the repository at this point in the history
Also add checks for nodes that can be multiple types with syntax
`AstNode<AstNodeExpr|AstNodeDType>`
  • Loading branch information
wsnyder committed Oct 1, 2024
1 parent 0547108 commit 03012da
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 19 deletions.
2 changes: 1 addition & 1 deletion src/V3AstNodeDType.h
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ class AstQueueDType final : public AstNodeDType {
bool isCompound() const override { return true; }
};
class AstRefDType final : public AstNodeDType {
// @astgen op1 := typeofp : Optional[AstNode]
// @astgen op1 := typeofp : Optional[AstNode<AstNodeExpr|AstNodeDType>]
// @astgen op2 := classOrPackageOpp : Optional[AstNodeExpr]
// @astgen op3 := paramsp : List[AstPin]
//
Expand Down
2 changes: 1 addition & 1 deletion src/V3AstNodeExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ class AstArg final : public AstNodeExpr {
};
class AstAttrOf final : public AstNodeExpr {
// Return a value of a attribute, for example a LSB or array LSB of a signal
// @astgen op1 := fromp : Optional[AstNode] // Expr or DType
// @astgen op1 := fromp : Optional[AstNode<AstNodeExpr|AstNodeDType>]
// @astgen op2 := dimp : Optional[AstNodeExpr]
VAttrType m_attrType; // What sort of extraction
public:
Expand Down
7 changes: 4 additions & 3 deletions src/V3AstNodeOther.h
Original file line number Diff line number Diff line change
Expand Up @@ -1407,7 +1407,7 @@ class AstPackageImport final : public AstNode {
};
class AstPin final : public AstNode {
// A port or parameter assignment on an instantiation
// @astgen op1 := exprp : Optional[AstNode] // NodeExpr or NodeDType (nullptr if unconnected)
// @astgen op1 := exprp : Optional[AstNode<AstNodeExpr|AstNodeDType>] // nullptr=unconnected
//
// @astgen ptr := m_modVarp : Optional[AstVar] // Input/output connects to on submodule
// @astgen ptr := m_modPTypep : Optional[AstParamTypeDType] // Param type connects to on sub
Expand Down Expand Up @@ -1781,7 +1781,8 @@ class AstVar final : public AstNode {
// @astgen op2 := delayp : Optional[AstDelay] // Net delay
// Initial value that never changes (static const), or constructor argument for
// MTASKSTATE variables
// @astgen op3 := valuep : Optional[AstNode] // May be a DType for type parameter defaults
// @astgen op3 := valuep : Optional[AstNode<AstNodeExpr|AstNodeDType>]
// Value is a DType for type parameter defaults
// @astgen op4 := attrsp : List[AstNode] // Attributes during early parse
// @astgen ptr := m_sensIfacep : Optional[AstIface] // Interface type to which reads from this
// var are sensitive
Expand Down Expand Up @@ -2559,7 +2560,7 @@ class AstInitialStatic final : public AstNodeProcedure {
class AstBracketRange final : public AstNodeRange {
// Parser only concept "[lhsp]", an AstUnknownRange, QueueRange or Range,
// unknown until lhsp type is determined
// @astgen op1 := elementsp : AstNode // Expr or DType
// @astgen op1 := elementsp : AstNode<AstNodeExpr|AstNodeDType>
public:
AstBracketRange(FileLine* fl, AstNode* elementsp)
: ASTGEN_SUPER_BracketRange(fl) {
Expand Down
64 changes: 50 additions & 14 deletions src/astgen
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ class Node:
assert not self.isCompleted
self._subClasses.append(subClass)

def addOp(self, n, name, monad, kind):
def addOp(self, n, name, monad, kind, legals):
assert 1 <= n <= 4
self._ops[n] = (name, monad, kind)
self._ops[n] = (name, monad, kind, legals)
self._arity = max(self._arity, n)

def getOp(self, n):
Expand All @@ -79,9 +79,9 @@ class Node:
return self.superClass.getOp(n)
return None

def addPtr(self, name, monad, kind):
def addPtr(self, name, monad, kind, legals):
name = re.sub(r'^m_', '', name)
self._ptrs.append({'name': name, 'monad': monad, 'kind': kind})
self._ptrs.append({'name': name, 'monad': monad, 'kind': kind, 'legals': legals})

# Computes derived properties over entire class hierarchy.
# No more changes to the hierarchy are allowed once this was called
Expand Down Expand Up @@ -519,17 +519,25 @@ def partitionAndStrip(string, separator):


def parseOpType(string):
match = re.match(r'^(\w+)\[(\w+)\]$', string)
# Return [Optional/List, AstNodeKind, LegalAstKinds]
match = re.match(r'^(\w+)\[(.*?)\]$', string)
if match:
monad, kind = match.groups()
if monad not in ("Optional", "List"):
return None
kind = parseOpType(kind)
if not kind or kind[0]:
return None
return monad, kind[1]
if re.match(r'^Ast(\w+)$', string):
return "", string[3:]
return monad, kind[1], kind[2]
match = re.match(r'^Ast(\w+)<(.*?)>$', string)
if match:
kind = match.group(1)
legals = match.group(2)
legals = re.sub(r'\bAst', '', legals)
return "", kind, legals
match = re.match(r'^Ast(\w+)$', string)
if match:
return "", match.group(1), match.group(1)
return None


Expand Down Expand Up @@ -889,7 +897,7 @@ def write_ast_type_info(filename):
opTypeList.append('OP_UNUSED')
opNameList.append('op{0}p'.format(n))
else:
name, monad, _ = op
name, monad, _, _ = op
if not monad:
opTypeList.append('OP_USED')
elif monad == "Optional":
Expand Down Expand Up @@ -930,6 +938,34 @@ def write_ast_impl(filename):
emitBlock(" BROKEN_RTN(!m_{name});\n" +
" BROKEN_RTN(!m_{name}->brokeExists());\n",
name=ptr['name'])
if ptr['legals'] != '':
emitBlock(" BROKEN_RTN(m_{name} && !(", name=ptr['name'])
eor = ""
for legal in ptr['legals'].split('|'):
# We use privateTypeTest, as VN_IS would assert that we know
# the type is correct, but we want to check regardless,
# to find errors after raw node edits/replacements
emitBlock("{eor}privateTypeTest<Ast{legal}>(m_{name})",
eor=eor,
name=ptr['name'],
legal=legal)
eor = " || "
emitBlock("));\n")
for i in range(1, 5):
op = node.getOp(i)
if op is None:
continue
name, _, _, legals = op
if legals != '':
emitBlock(" BROKEN_RTN({name}() && !(", name=name)
eor = ""
for legal in legals.split('|'):
emitBlock("{eor}privateTypeTest<Ast{legal}>({name}())",
eor=eor,
name=name,
legal=legal)
eor = " || "
emitBlock("));\n")
# Node's broken rules can be specialized by declaring broken()
emitBlock(" return Ast{t}::broken();\n", t=node.name)
emitBlock("}}\n", t=node.name)
Expand Down Expand Up @@ -959,7 +995,7 @@ def write_ast_impl(filename):
op = node.getOp(i)
if op is None:
continue
name, _, _ = op
name, _, _, _ = op
emitBlock(" dumpNodeListJson(str, {name}(), \"{name}\", indent);\n", name=name)
emitBlock("}}\n")

Expand Down Expand Up @@ -1025,7 +1061,7 @@ def write_ast_macros(filename):
op = node.getOp(n)
if not op:
continue
name, monad, kind = op
name, monad, kind, _ = op
retrieve = ("VN_DBG_AS(op{n}p(), {kind})"
if kind != "Node" else "op{n}p()").format(n=n, kind=kind)
superOp = node.superClass.getOp(n)
Expand Down Expand Up @@ -1113,7 +1149,7 @@ def write_dfg_macros(filename):
s=node.superClass.name)

for n in range(1, node.arity + 1):
name, _, _ = node.getOp(n)
name, _, _, _ = node.getOp(n)
emitBlock('''\
DfgVertex* {name}() const {{ return source<{n}>(); }}
void {name}(DfgVertex* vtxp) {{ relinkSource<{n}>(vtxp); }}
Expand Down Expand Up @@ -1300,9 +1336,9 @@ for node in AstNodeList:
for n in range(1, node.arity + 1):
op = node.getOp(n)
if op is not None:
name, monad, kind = op
name, monad, kind, legals = op
assert monad == "", "Cannot represent AstNode as DfgVertex"
vertex.addOp(n, name, "", "")
vertex.addOp(n, name, "", "", "")

# Compute derived properties over the whole DfgVertex hierarchy
DfgVertices["Vertex"].complete()
Expand Down

0 comments on commit 03012da

Please sign in to comment.