2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 13:35:28 +02:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Add temporaries, such as for clean nodes
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2025-01-01 14:30:25 +01:00
|
|
|
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 23:07:57 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// V3Clean's Transformations:
|
2008-06-10 03:25:10 +02:00
|
|
|
//
|
2006-08-26 13:35:28 +02:00
|
|
|
// Each module:
|
2022-10-12 11:19:21 +02:00
|
|
|
// For each expression, if it requires a clean operand,
|
2019-05-19 22:13:13 +02:00
|
|
|
// and the operand is dirty, insert a CLEAN node.
|
|
|
|
|
// Resize operands to C++ 32/64/wide types.
|
|
|
|
|
// Copy all width() values to widthMin() so RANGE, etc can still see orig widths
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-10-18 04:50:27 +02:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
2023-10-18 12:37:46 +02:00
|
|
|
#include "V3Clean.h"
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// Clean state, as a visitor of each AstNode
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class CleanVisitor final : public VNVisitor {
|
2006-08-26 13:35:28 +02:00
|
|
|
// NODE STATE
|
|
|
|
|
// Entire netlist:
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstNode::user() -> CleanState. For this node, 0==UNKNOWN
|
|
|
|
|
// AstNode::user2() -> bool. True indicates widthMin has been propagated
|
|
|
|
|
// AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser1InUse m_inuser1;
|
|
|
|
|
const VNUser2InUse m_inuser2;
|
|
|
|
|
const VNUser3InUse m_inuser3;
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2009-01-21 22:56:50 +01:00
|
|
|
// TYPES
|
2020-08-16 18:05:35 +02:00
|
|
|
enum CleanState : uint8_t { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
|
2009-01-21 22:56:50 +01:00
|
|
|
|
2025-04-27 20:17:24 +02:00
|
|
|
// STATE - for current visit position (use VL_RESTORER)
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNodeModule* m_modp = nullptr;
|
2008-06-10 03:25:10 +02:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// METHODS
|
2009-01-21 22:56:50 +01:00
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
// Width resetting
|
2025-08-19 23:02:10 +02:00
|
|
|
int cppWidth(const AstNode* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->width() <= VL_IDATASIZE) {
|
|
|
|
|
return VL_IDATASIZE;
|
|
|
|
|
} else if (nodep->width() <= VL_QUADSIZE) {
|
|
|
|
|
return VL_QUADSIZE;
|
|
|
|
|
} else {
|
|
|
|
|
return nodep->widthWords() * VL_EDATASIZE;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2018-08-25 15:52:45 +02:00
|
|
|
void setCppWidth(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user2(true); // Don't resize it again
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const old_dtypep = nodep->dtypep();
|
2021-06-21 00:32:57 +02:00
|
|
|
const int width = cppWidth(nodep); // widthMin is unchanged
|
2019-05-19 22:13:13 +02:00
|
|
|
if (old_dtypep->width() != width) {
|
|
|
|
|
// Since any given dtype's cppWidth() is the same, we can just
|
2019-09-09 13:50:21 +02:00
|
|
|
// remember one conversion for each, and reuse it
|
2021-11-13 19:50:44 +01:00
|
|
|
if (AstNodeDType* const new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->dtypep(new_dtypep);
|
|
|
|
|
} else {
|
|
|
|
|
nodep->dtypeChgWidth(width, nodep->widthMin());
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const new_dtypep2 = nodep->dtypep();
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(new_dtypep2 != old_dtypep, nodep,
|
|
|
|
|
"Dtype didn't change when width changed");
|
2019-05-19 22:13:13 +02:00
|
|
|
old_dtypep->user3p(new_dtypep2); // Remember for next time
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2018-08-25 15:52:45 +02:00
|
|
|
void computeCppWidth(AstNode* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!nodep->user2() && nodep->hasDType()) {
|
2023-01-29 22:50:10 +01:00
|
|
|
if (VN_IS(nodep, Var) //
|
|
|
|
|
|| VN_IS(nodep, ConsPackMember) //
|
2020-04-15 13:58:34 +02:00
|
|
|
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|
2019-12-01 17:52:48 +01:00
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|
2022-07-20 15:01:36 +02:00
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), WildcardArrayDType)
|
2020-03-07 16:24:27 +01:00
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType)
|
2019-12-24 18:47:27 +01:00
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
|
2019-12-01 18:35:49 +01:00
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), QueueDType)
|
2023-06-14 04:46:42 +02:00
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), StreamDType)
|
2019-12-01 17:52:48 +01:00
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
|
|
|
|
|
|| VN_IS(nodep->dtypep()->skipRefp(), VoidDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
} else {
|
2023-01-28 04:41:12 +01:00
|
|
|
const AstNodeUOrStructDType* const dtypep
|
|
|
|
|
= VN_CAST(nodep->dtypep()->skipRefp(), NodeUOrStructDType);
|
|
|
|
|
if (!dtypep || dtypep->packed()) setCppWidth(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store the clean state in the userp on each node
|
2020-04-15 13:58:34 +02:00
|
|
|
void setCleanState(AstNode* nodep, CleanState clean) { nodep->user1(clean); }
|
2025-08-19 23:02:10 +02:00
|
|
|
CleanState getCleanState(const AstNode* nodep) {
|
|
|
|
|
return static_cast<CleanState>(nodep->user1());
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
bool isClean(AstNode* nodep) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const CleanState clstate = getCleanState(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (clstate == CS_CLEAN) return true;
|
|
|
|
|
if (clstate == CS_DIRTY) return false;
|
|
|
|
|
nodep->v3fatalSrc("Unknown clean state on node: " + nodep->prettyTypeName());
|
2019-05-19 22:13:13 +02:00
|
|
|
return false;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
void setClean(AstNode* nodep, bool isClean) {
|
2018-08-25 15:52:45 +02:00
|
|
|
computeCppWidth(nodep); // Just to be sure it's in widthMin
|
2021-06-21 00:32:57 +02:00
|
|
|
const bool wholeUint
|
|
|
|
|
= (nodep->widthMin() == VL_IDATASIZE || nodep->widthMin() == VL_QUADSIZE
|
|
|
|
|
|| (nodep->widthMin() % VL_EDATASIZE) == 0);
|
2019-12-09 03:36:38 +01:00
|
|
|
setCleanState(nodep, ((isClean || wholeUint) ? CS_CLEAN : CS_DIRTY));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Operate on nodes
|
2022-11-13 21:33:11 +01:00
|
|
|
void insertClean(AstNodeExpr* nodep) { // We'll insert ABOVE passed node
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(4, " NeedClean " << nodep);
|
2022-01-02 16:32:35 +01:00
|
|
|
VNRelinker relinkHandle;
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->unlinkFrBack(&relinkHandle);
|
|
|
|
|
//
|
2019-05-10 02:03:19 +02:00
|
|
|
computeCppWidth(nodep);
|
2022-11-20 21:06:49 +01:00
|
|
|
V3Number mask{nodep, cppWidth(nodep)};
|
2019-05-10 02:03:19 +02:00
|
|
|
mask.setMask(nodep->widthMin());
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNode* const cleanp
|
2022-11-20 21:06:49 +01:00
|
|
|
= new AstAnd{nodep->fileline(), new AstConst{nodep->fileline(), mask}, nodep};
|
2019-05-19 22:13:13 +02:00
|
|
|
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
|
|
|
|
|
relinkHandle.relink(cleanp);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
void ensureClean(AstNodeExpr* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
|
|
|
|
if (!isClean(nodep)) insertClean(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
void ensureCleanAndNext(AstNodeExpr* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Editing list, careful looping!
|
2022-11-13 21:33:11 +01:00
|
|
|
for (AstNodeExpr* exprp = nodep; exprp;) {
|
|
|
|
|
AstNodeExpr* const nextp = VN_AS(exprp->nextp(), NodeExpr);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureClean(exprp);
|
2019-05-19 22:13:13 +02:00
|
|
|
exprp = nextp;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Base type handling methods
|
|
|
|
|
void operandBiop(AstNodeBiop* nodep) {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
|
|
|
|
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
|
|
|
|
// no setClean.. must do it in each user routine.
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
void operandTriop(AstNodeTriop* nodep) {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
|
|
|
|
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
|
|
|
|
if (nodep->cleanThs()) ensureClean(nodep->thsp());
|
|
|
|
|
// no setClean.. must do it in each user routine.
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-05-10 20:27:22 +02:00
|
|
|
void operandQuadop(AstNodeQuadop* nodep) {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
computeCppWidth(nodep);
|
2021-02-22 03:25:21 +01:00
|
|
|
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
|
|
|
|
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
|
|
|
|
if (nodep->cleanThs()) ensureClean(nodep->thsp());
|
|
|
|
|
if (nodep->cleanFhs()) ensureClean(nodep->fhsp());
|
2020-05-10 20:27:22 +02:00
|
|
|
// no setClean.. must do it in each user routine.
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// VISITORS
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeModule* nodep) override {
|
2020-08-25 03:10:43 +02:00
|
|
|
VL_RESTORER(m_modp);
|
2024-11-10 16:51:48 +01:00
|
|
|
m_modp = nodep;
|
|
|
|
|
iterateChildren(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeUniop* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, nodep->cleanOut());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeBiop* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
operandBiop(nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, nodep->cleanOut());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstAnd* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
operandBiop(nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp()));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstXor* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
operandBiop(nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstOr* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
operandBiop(nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeQuadop* nodep) override {
|
2020-05-10 20:27:22 +02:00
|
|
|
operandQuadop(nodep);
|
|
|
|
|
setClean(nodep, nodep->cleanOut());
|
|
|
|
|
}
|
2025-05-19 15:35:35 +02:00
|
|
|
void visit(AstExprStmt* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
computeCppWidth(nodep);
|
|
|
|
|
setClean(nodep, isClean(nodep->resultp()));
|
|
|
|
|
}
|
2022-10-12 11:19:21 +02:00
|
|
|
void visit(AstNodeExpr* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, nodep->cleanOut());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeAssign* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstScopeName* nodep) override { //
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, true);
|
2007-06-14 18:41:32 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCNew* nodep) override {
|
2020-04-13 00:57:12 +02:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
setClean(nodep, true);
|
|
|
|
|
}
|
2024-03-16 02:56:24 +01:00
|
|
|
void visit(AstConsPackMember* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
ensureClean(nodep->rhsp());
|
|
|
|
|
setClean(nodep, true);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSel* nodep) override {
|
2025-06-24 17:59:09 +02:00
|
|
|
operandBiop(nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, nodep->cleanOut());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
void visit(AstCExprUser* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, false);
|
2019-05-19 22:13:13 +02:00
|
|
|
// We always clean, as we don't trust those pesky users.
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
for (AstNode* argp = nodep->nodesp(); argp; argp = argp->nextp()) {
|
2022-11-13 21:33:11 +01:00
|
|
|
if (AstNodeExpr* const exprp = VN_CAST(argp, NodeExpr)) ensureClean(exprp);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2023-12-12 20:30:18 +01:00
|
|
|
void visit(AstTraceDecl* nodep) override {} // Nothing to do here
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTraceInc* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureCleanAndNext(nodep->valuep());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstTypedef* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// No cleaning, or would loose pointer to enum
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2014-11-07 13:50:11 +01:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstParamTypeDType* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// No cleaning, or would loose pointer to enum
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2016-03-15 02:51:31 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
// Control flow operators
|
2025-08-16 00:49:06 +02:00
|
|
|
void visit(AstCond* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureClean(nodep->condp());
|
2022-09-15 20:43:56 +02:00
|
|
|
setClean(nodep, isClean(nodep->thenp()) && isClean(nodep->elsep()));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2025-09-29 16:25:25 +02:00
|
|
|
void visit(AstLoop* nodep) override { iterateChildren(nodep); }
|
|
|
|
|
void visit(AstLoopTest* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureClean(nodep->condp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeIf* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureClean(nodep->condp());
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstSFormatF* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureCleanAndNext(nodep->exprsp());
|
2019-05-19 22:13:13 +02:00
|
|
|
setClean(nodep, true); // generates a string, so not relevant
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
void visit(AstCStmtUser* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
Internals: Refactor text based Ast constructs (#6280) (#6571)
Remove the large variety of ways raw "text" is represented in the Ast.
Particularly, the only thing that represents a string to be emitted in
the output is AstText.
There are 5 AstNodes that can contain AstText, and V3Emit will throw an
error if an AstText is encountered anywhere else:
- AstCStmt: Internally generated procedural statements involving raw
text.
- AstCStmtUser: This is the old AstUCStmt, renamed so it sorts next to
AstCStmt, as it's largely equivalent. We should never create this
internally unless used to represent user input. It is used for $c,
statements in the input, and for some 'systemc_* blocks.
- AstCExpr: Internally generaged expression involving raw text.
- AstCExprUser: This is the old AstUCFunc, renamed so it sorts next to
AstCExpr. It is largely equivalent, but also has more optimizations
disabled. This should never be created internally, it is only used for
$c expressions in the input.
- AstTextBlock: Use by V3ProtectLib only, to generate the hierarchical
wrappers.
Text "tracking" for indentation is always on for AstCStmt, AstCExpr, and
AstTextBlock, as these are always generated by us, and should always be
well formed.
Tracking is always off for AstCStmtUser and AstCExprUser, as these
contain arbitrary user input that might not be safe to parse for
indentation.
Remove subsequently redundant AstNodeSimpleText and AstNodeText types.
This patch also fixes incorrect indentation in emitted waveform tracing
functions, and makes the output more readable for hier block SV stubs.
With that, all raw text nodes are handled as a proper AstNodeStmt or
AstNodeExpr as required for #6280.
2025-10-21 13:41:29 +02:00
|
|
|
for (AstNode* argp = nodep->nodesp(); argp; argp = argp->nextp()) {
|
2022-11-13 21:33:11 +01:00
|
|
|
if (AstNodeExpr* const exprp = VN_CAST(argp, NodeExpr)) ensureClean(exprp);
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeCCall* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureCleanAndNext(nodep->argsp());
|
2018-08-25 15:52:45 +02:00
|
|
|
setClean(nodep, true);
|
2006-10-11 17:41:42 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstCMethodHard* nodep) override {
|
2019-12-01 17:52:48 +01:00
|
|
|
iterateChildren(nodep);
|
2020-01-25 02:10:44 +01:00
|
|
|
ensureCleanAndNext(nodep->pinsp());
|
2019-12-01 17:52:48 +01:00
|
|
|
setClean(nodep, true);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstWith* nodep) override {
|
2020-11-01 16:56:07 +01:00
|
|
|
iterateChildren(nodep);
|
2023-05-30 15:02:59 +02:00
|
|
|
setClean(nodep, true);
|
|
|
|
|
}
|
|
|
|
|
void visit(AstCReturn* nodep) override {
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
ensureClean(nodep->lhsp());
|
2020-11-01 16:56:07 +01:00
|
|
|
setClean(nodep, true);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstIntfRef* nodep) override {
|
2019-12-07 15:42:09 +01:00
|
|
|
iterateChildren(nodep);
|
|
|
|
|
setClean(nodep, true); // generates a string, so not relevant
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
//--------------------
|
|
|
|
|
// Default: Just iterate
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override {
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
computeCppWidth(nodep);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-16 15:55:36 +02:00
|
|
|
explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2022-09-16 12:22:11 +02:00
|
|
|
~CleanVisitor() override = default;
|
2006-08-26 13:35:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Clean class functions
|
|
|
|
|
|
|
|
|
|
void V3Clean::cleanAll(AstNetlist* nodep) {
|
2025-05-23 02:29:32 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ":");
|
2021-11-26 16:52:36 +01:00
|
|
|
{ CleanVisitor{nodep}; } // Destruct before checking
|
2024-01-09 16:35:13 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("clean", 0, dumpTreeEitherLevel() >= 3);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|