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: Ast node structures
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2006-08-26 13:35:28 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2022-01-01 14:26:40 +01:00
|
|
|
// Copyright 2003-2022 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
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2006-12-18 20:20:45 +01:00
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
#include "V3Ast.h"
|
2021-06-13 16:05:55 +02:00
|
|
|
#include "V3EmitCBase.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
#include "V3File.h"
|
|
|
|
|
#include "V3Global.h"
|
2018-07-23 02:54:28 +02:00
|
|
|
#include "V3Graph.h"
|
2021-06-13 16:05:55 +02:00
|
|
|
#include "V3Hasher.h"
|
2018-07-23 02:54:28 +02:00
|
|
|
#include "V3PartitionGraph.h" // Just for mtask dumping
|
2020-08-15 15:43:53 +02:00
|
|
|
#include "V3String.h"
|
2006-08-26 13:35:28 +02:00
|
|
|
|
2021-05-22 12:13:02 +02:00
|
|
|
#include "V3AstNodes__gen_macros.h" // Generated by 'astgen'
|
|
|
|
|
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <iomanip>
|
2021-06-13 16:05:55 +02:00
|
|
|
#include <iterator>
|
2018-10-14 19:43:24 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//======================================================================
|
|
|
|
|
// Special methods
|
|
|
|
|
|
|
|
|
|
// We need these here, because the classes they point to aren't defined when we declare the class
|
2013-05-28 03:39:19 +02:00
|
|
|
const char* AstIfaceRefDType::broken() const {
|
|
|
|
|
BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
|
2021-10-22 14:56:48 +02:00
|
|
|
return ((m_cellp && m_cellp->modp()) ? VN_AS(m_cellp->modp(), Iface) : m_ifacep);
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-13 00:10:52 +01:00
|
|
|
const char* AstNodeFTaskRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_taskp && !m_taskp->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstNodeFTaskRef::cloneRelink() {
|
|
|
|
|
if (m_taskp && m_taskp->clonep()) m_taskp = m_taskp->clonep();
|
|
|
|
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
|
|
|
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-25 23:05:22 +02:00
|
|
|
const char* AstNodeVarRef::broken() const {
|
|
|
|
|
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
2021-12-13 00:10:52 +01:00
|
|
|
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2013-05-19 01:45:40 +02:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
|
|
|
|
|
void AstNodeVarRef::cloneRelink() {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
2021-12-13 00:10:52 +01:00
|
|
|
if (m_varScopep && m_varScopep->clonep()) m_varScopep = m_varScopep->clonep();
|
|
|
|
|
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
|
|
|
|
m_classOrPackagep = m_classOrPackagep->clonep();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 15:33:11 +02:00
|
|
|
string AstNodeVarRef::selfPointerProtect(bool useSelfForThis) const {
|
|
|
|
|
const string& sp
|
|
|
|
|
= useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer();
|
|
|
|
|
return VIdProtect::protectWordsIf(sp, protect());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstAddrOfCFunc::cloneRelink() {
|
|
|
|
|
if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* AstAddrOfCFunc::broken() const {
|
|
|
|
|
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
|
|
|
|
|
return nullptr;
|
2019-10-06 19:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
int AstNodeSel::bitConst() const {
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstConst* const constp = VN_AS(bitp(), Const);
|
2018-02-02 03:32:58 +01:00
|
|
|
return (constp ? constp->toSInt() : 0);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
void AstNodeUOrStructDType::repairMemberCache() {
|
2012-07-29 16:16:20 +02:00
|
|
|
clearCache();
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (m_members.find(itemp->name()) != m_members.end()) {
|
|
|
|
|
itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ());
|
|
|
|
|
} else {
|
2020-12-19 00:24:47 +01:00
|
|
|
m_members.emplace(itemp->name(), itemp);
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
const char* AstNodeUOrStructDType::broken() const {
|
2020-08-15 16:03:34 +02:00
|
|
|
std::unordered_set<AstMemberDType*> exists;
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
exists.insert(itemp);
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) {
|
2019-07-01 04:37:03 +02:00
|
|
|
if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) {
|
2020-04-15 13:58:34 +02:00
|
|
|
this->v3error("Internal: Structure member broken: " << it->first);
|
2019-05-19 22:13:13 +02:00
|
|
|
return "member broken";
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
|
2020-03-07 18:52:11 +01:00
|
|
|
void AstNodeCCall::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-03-07 18:52:11 +01:00
|
|
|
if (funcp()) {
|
|
|
|
|
str << " " << funcp()->name() << " => ";
|
|
|
|
|
funcp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " " << name();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void AstNodeCCall::cloneRelink() {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep();
|
2020-03-07 18:52:11 +01:00
|
|
|
}
|
|
|
|
|
const char* AstNodeCCall::broken() const {
|
|
|
|
|
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-03-07 18:52:11 +01:00
|
|
|
}
|
|
|
|
|
bool AstNodeCCall::isPure() const { return funcp()->pure(); }
|
2021-07-13 18:42:17 +02:00
|
|
|
|
|
|
|
|
string AstCCall::selfPointerProtect(bool useSelfForThis) const {
|
2021-06-13 15:33:11 +02:00
|
|
|
const string& sp
|
|
|
|
|
= useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer();
|
|
|
|
|
return VIdProtect::protectWordsIf(sp, protect());
|
|
|
|
|
}
|
2020-03-07 18:52:11 +01:00
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
|
|
|
|
|
const V3Number& ths) {
|
2020-04-16 03:47:37 +02:00
|
|
|
if (lhs.isNeqZero()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
out.opAssign(rhs);
|
2020-04-16 03:47:37 +02:00
|
|
|
} else {
|
2020-04-15 13:58:34 +02:00
|
|
|
out.opAssign(ths);
|
2020-04-16 03:47:37 +02:00
|
|
|
}
|
2019-05-10 02:03:19 +02:00
|
|
|
}
|
|
|
|
|
|
2009-11-05 04:31:53 +01:00
|
|
|
int AstBasicDType::widthAlignBytes() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (isQuad()) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else {
|
|
|
|
|
return 4;
|
|
|
|
|
}
|
2009-11-05 04:31:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int AstBasicDType::widthTotalBytes() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (isQuad()) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else {
|
|
|
|
|
return widthWords() * (VL_EDATASIZE / 8);
|
|
|
|
|
}
|
2009-11-05 04:31:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
int AstNodeUOrStructDType::widthTotalBytes() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (isQuad()) {
|
|
|
|
|
return 8;
|
|
|
|
|
} else {
|
|
|
|
|
return widthWords() * (VL_EDATASIZE / 8);
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 04:46:09 +01:00
|
|
|
int AstNodeUOrStructDType::widthAlignBytes() const {
|
2012-07-29 16:16:20 +02:00
|
|
|
// Could do max across members but that would be slow,
|
|
|
|
|
// instead intuit based on total structure size
|
2020-04-15 13:58:34 +02:00
|
|
|
if (width() <= 8) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else if (width() <= 16) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else if (width() <= 32) {
|
|
|
|
|
return 4;
|
|
|
|
|
} else {
|
|
|
|
|
return 8;
|
|
|
|
|
}
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
|
|
|
|
|
2014-01-21 03:59:53 +01:00
|
|
|
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
|
|
|
|
return new AstEqN(fl, lhsp, rhsp);
|
|
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEqD(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEq(fl, lhsp, rhsp);
|
2014-01-21 03:59:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-18 02:15:40 +02:00
|
|
|
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
2019-10-05 01:13:39 +02:00
|
|
|
if (lhsp->isString() && rhsp->isString()) {
|
|
|
|
|
return new AstEqN(fl, lhsp, rhsp);
|
|
|
|
|
} else if (lhsp->isDouble() && rhsp->isDouble()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEqD(fl, lhsp, rhsp);
|
2017-05-18 02:15:40 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
return new AstEqWild(fl, lhsp, rhsp);
|
2017-05-18 02:15:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-21 03:59:53 +01:00
|
|
|
|
2022-04-10 12:37:41 +02:00
|
|
|
AstExecGraph::AstExecGraph(FileLine* fileline, const string& name)
|
2021-06-16 13:18:56 +02:00
|
|
|
: ASTGEN_SUPER_ExecGraph(fileline)
|
2022-04-10 12:37:41 +02:00
|
|
|
, m_depGraphp{new V3Graph}
|
|
|
|
|
, m_name{name} {}
|
2018-07-23 02:54:28 +02:00
|
|
|
|
2021-06-16 13:18:56 +02:00
|
|
|
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
|
2021-06-13 15:33:11 +02:00
|
|
|
|
2020-03-31 00:12:50 +02:00
|
|
|
AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) {
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNode* const ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
|
|
|
|
|
AstNode* const bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
|
2020-03-31 00:12:50 +02:00
|
|
|
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
|
|
|
|
|
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNode* const newp = new AstAnd(fileline(), ap, bp);
|
2020-03-31 00:12:50 +02:00
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-02 13:29:52 +02:00
|
|
|
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
|
|
|
|
bool success = false;
|
|
|
|
|
if (literal[0] == '"') {
|
|
|
|
|
// This is a string
|
2021-11-26 23:55:36 +01:00
|
|
|
const string v = literal.substr(1, literal.find('"', 1) - 1);
|
2020-07-02 13:29:52 +02:00
|
|
|
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
|
|
|
|
|
} else if (literal.find_first_of(".eEpP") != string::npos) {
|
|
|
|
|
// This may be a real
|
2021-11-26 23:55:36 +01:00
|
|
|
const double v = VString::parseDouble(literal, &success);
|
2020-07-02 13:29:52 +02:00
|
|
|
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
|
|
|
|
|
}
|
|
|
|
|
if (!success) {
|
|
|
|
|
// This is either an integer or an error
|
|
|
|
|
// We first try to convert it as C literal. If strtol returns
|
|
|
|
|
// 0 this is either an error or 0 was parsed. But in any case
|
|
|
|
|
// we will try to parse it as a verilog literal, hence having
|
|
|
|
|
// the false negative for 0 is okay. If anything remains in
|
|
|
|
|
// the string after the number, this is invalid C and we try
|
|
|
|
|
// the Verilog literal parser.
|
|
|
|
|
char* endp;
|
2021-11-26 23:55:36 +01:00
|
|
|
const int v = strtol(literal.c_str(), &endp, 0);
|
2020-07-02 13:29:52 +02:00
|
|
|
if ((v != 0) && (endp[0] == 0)) { // C literal
|
2021-07-08 14:42:25 +02:00
|
|
|
return new AstConst(fl, AstConst::Signed32(), v);
|
2020-07-02 13:29:52 +02:00
|
|
|
} else { // Try a Verilog literal (fatals if not)
|
|
|
|
|
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-07-02 13:29:52 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
AstNetlist::AstNetlist()
|
|
|
|
|
: ASTGEN_SUPER_Netlist(new FileLine(FileLine::builtInFilename()))
|
|
|
|
|
, m_typeTablep{new AstTypeTable(fileline())}
|
|
|
|
|
, m_constPoolp{new AstConstPool(fileline())} {
|
|
|
|
|
addMiscsp(m_typeTablep);
|
|
|
|
|
addMiscsp(m_constPoolp);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) {
|
2021-06-21 00:32:57 +02:00
|
|
|
const VTimescale prec = v3Global.opt.timeComputePrec(value);
|
2020-04-16 01:39:03 +02:00
|
|
|
if (prec.isNone() || prec == m_timeprecision) {
|
|
|
|
|
} else if (m_timeprecision.isNone()) {
|
|
|
|
|
m_timeprecision = prec;
|
|
|
|
|
} else if (prec < m_timeprecision) {
|
|
|
|
|
m_timeprecision = prec;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
bool AstVar::isSigPublic() const {
|
2008-09-30 14:58:07 +02:00
|
|
|
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
bool AstVar::isScQuad() const { return (isSc() && isQuad() && !isScBv() && !isScBigUint()); }
|
2009-03-13 19:17:30 +01:00
|
|
|
bool AstVar::isScBv() const {
|
2011-10-26 14:57:27 +02:00
|
|
|
return ((isSc() && width() >= v3Global.opt.pinsBv()) || m_attrScBv);
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2013-04-27 03:02:32 +02:00
|
|
|
bool AstVar::isScUint() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return ((isSc() && v3Global.opt.pinsScUint() && width() >= 2 && width() <= 64) && !isScBv());
|
2013-04-27 03:02:32 +02:00
|
|
|
}
|
|
|
|
|
bool AstVar::isScBigUint() const {
|
2020-04-15 13:58:34 +02:00
|
|
|
return ((isSc() && v3Global.opt.pinsScBigUint() && width() >= 65 && width() <= 512)
|
|
|
|
|
&& !isScBv());
|
2013-04-27 03:02:32 +02:00
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
void AstVar::combineType(VVarType type) {
|
2012-04-24 13:45:02 +02:00
|
|
|
// These flags get combined with the existing settings of the flags.
|
|
|
|
|
// We don't test varType for certain types, instead set flags since
|
|
|
|
|
// when we combine wires cross-hierarchy we need a union of all characteristics.
|
2018-10-27 23:29:00 +02:00
|
|
|
m_varType = type;
|
2006-08-26 13:35:28 +02:00
|
|
|
// These flags get combined with the existing settings of the flags.
|
2022-01-02 19:56:40 +01:00
|
|
|
if (type == VVarType::TRIWIRE || type == VVarType::TRI0 || type == VVarType::TRI1) {
|
2018-10-27 23:29:00 +02:00
|
|
|
m_tristate = true;
|
2018-10-04 01:51:05 +02:00
|
|
|
}
|
2022-01-02 19:56:40 +01:00
|
|
|
if (type == VVarType::TRI0) m_isPulldown = true;
|
|
|
|
|
if (type == VVarType::TRI1) m_isPullup = true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string AstVar::verilogKwd() const {
|
2018-10-27 23:29:00 +02:00
|
|
|
if (isIO()) {
|
|
|
|
|
return direction().verilogKwd();
|
2006-09-25 22:40:52 +02:00
|
|
|
} else if (isTristate()) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "tri";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (varType() == VVarType::WIRE) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "wire";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (varType() == VVarType::WREAL) {
|
2018-10-27 23:29:00 +02:00
|
|
|
return "wreal";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (varType() == VVarType::IFACEREF) {
|
2018-12-06 13:12:39 +01:00
|
|
|
return "ifaceref";
|
2006-08-26 13:35:28 +02:00
|
|
|
} else {
|
2018-10-27 23:29:00 +02:00
|
|
|
return dtypep()->name();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc,
|
|
|
|
|
bool asRef) const {
|
2019-07-07 15:01:36 +02:00
|
|
|
UASSERT_OBJ(!forReturn, this,
|
|
|
|
|
"Internal data is never passed as return, but as first argument");
|
2019-11-13 03:52:25 +01:00
|
|
|
string ostatic;
|
2019-12-01 12:09:58 +01:00
|
|
|
if (isStatic() && namespc.empty()) ostatic = "static ";
|
|
|
|
|
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
const bool isRef = isDpiOpenArray()
|
|
|
|
|
|| (forFunc && (isWritable() || direction().isRefOrConstRef())) || asRef;
|
2020-10-17 22:04:29 +02:00
|
|
|
|
|
|
|
|
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
|
2019-12-01 12:09:58 +01:00
|
|
|
|
|
|
|
|
string oname;
|
|
|
|
|
if (named) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!namespc.empty()) oname += namespc + "::";
|
2019-12-01 12:09:58 +01:00
|
|
|
oname += VIdProtect::protectIf(name(), protect());
|
|
|
|
|
}
|
2020-10-17 22:48:11 +02:00
|
|
|
return ostatic + dtypep()->cType(oname, forFunc, isRef);
|
2009-12-03 12:55:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-17 13:22:49 +01:00
|
|
|
string AstVar::vlEnumType() const {
|
|
|
|
|
string arg;
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstBasicDType* const bdtypep = basicp();
|
2022-01-02 19:56:40 +01:00
|
|
|
const bool strtype = bdtypep && bdtypep->keyword() == VBasicDTypeKwd::STRING;
|
|
|
|
|
if (bdtypep && bdtypep->keyword() == VBasicDTypeKwd::CHARPTR) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "VLVT_PTR";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (bdtypep && bdtypep->keyword() == VBasicDTypeKwd::SCOPEPTR) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "VLVT_PTR";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (strtype) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_STRING";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (widthMin() <= 8) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT8";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (widthMin() <= 16) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT16";
|
2019-12-09 03:36:38 +01:00
|
|
|
} else if (widthMin() <= VL_IDATASIZE) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT32";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (isQuad()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_UINT64";
|
2010-03-17 13:22:49 +01:00
|
|
|
} else if (isWide()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
arg += "VLVT_WDATA";
|
2010-03-17 13:22:49 +01:00
|
|
|
}
|
|
|
|
|
// else return "VLVT_UNKNOWN"
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-06 02:01:17 +02:00
|
|
|
string AstVar::vlEnumDir() const {
|
2017-12-16 16:07:15 +01:00
|
|
|
string out;
|
2018-10-27 23:29:00 +02:00
|
|
|
if (isInoutish()) {
|
2017-12-16 16:07:15 +01:00
|
|
|
out = "VLVD_INOUT";
|
2018-10-27 23:29:00 +02:00
|
|
|
} else if (isWritable()) {
|
2017-12-16 16:07:15 +01:00
|
|
|
out = "VLVD_OUT";
|
2018-10-27 23:29:00 +02:00
|
|
|
} else if (isNonOutput()) {
|
|
|
|
|
out = "VLVD_IN";
|
2010-04-06 02:01:17 +02:00
|
|
|
} else {
|
2017-12-16 16:07:15 +01:00
|
|
|
out = "VLVD_NODIR";
|
2010-04-06 02:01:17 +02:00
|
|
|
}
|
2017-12-16 16:07:15 +01:00
|
|
|
//
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isSigUserRWPublic()) {
|
|
|
|
|
out += "|VLVF_PUB_RW";
|
|
|
|
|
} else if (isSigUserRdPublic()) {
|
|
|
|
|
out += "|VLVF_PUB_RD";
|
|
|
|
|
}
|
2017-12-17 22:28:58 +01:00
|
|
|
//
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstBasicDType* const bdtypep = basicp()) {
|
2017-12-17 22:28:58 +01:00
|
|
|
if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY";
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 20:55:46 +02:00
|
|
|
string AstVar::vlPropDecl(const string& propName) const {
|
2017-12-17 22:28:58 +01:00
|
|
|
string out;
|
2020-05-08 19:22:44 +02:00
|
|
|
|
|
|
|
|
std::vector<int> ulims; // Unpacked dimension limits
|
|
|
|
|
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
2017-12-17 22:28:58 +01:00
|
|
|
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
2021-10-22 16:15:42 +02:00
|
|
|
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
2020-05-08 19:22:44 +02:00
|
|
|
ulims.push_back(adtypep->declRange().left());
|
|
|
|
|
ulims.push_back(adtypep->declRange().right());
|
2017-12-17 22:28:58 +01:00
|
|
|
dtp = adtypep->subDTypep();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
break; // AstBasicDType - nothing below
|
2017-12-17 22:28:58 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-08 19:22:44 +02:00
|
|
|
|
|
|
|
|
if (!ulims.empty()) {
|
|
|
|
|
out += "static const int " + propName + "__ulims[";
|
|
|
|
|
out += cvtToStr(ulims.size());
|
|
|
|
|
out += "] = {";
|
2020-08-16 17:43:49 +02:00
|
|
|
auto it = ulims.cbegin();
|
2020-05-08 19:22:44 +02:00
|
|
|
out += cvtToStr(*it);
|
2020-08-16 17:43:49 +02:00
|
|
|
while (++it != ulims.cend()) {
|
2020-05-08 19:22:44 +02:00
|
|
|
out += ", ";
|
|
|
|
|
out += cvtToStr(*it);
|
|
|
|
|
}
|
|
|
|
|
out += "};\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out += "static const VerilatedVarProps ";
|
|
|
|
|
out += propName;
|
|
|
|
|
out += "(";
|
|
|
|
|
out += vlEnumType(); // VLVT_UINT32 etc
|
|
|
|
|
out += ", " + vlEnumDir(); // VLVD_IN etc
|
|
|
|
|
if (const AstBasicDType* const bdtypep = basicp()) {
|
|
|
|
|
out += ", VerilatedVarProps::Packed()";
|
|
|
|
|
out += ", " + cvtToStr(bdtypep->left());
|
|
|
|
|
out += ", " + cvtToStr(bdtypep->right());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ulims.empty()) {
|
|
|
|
|
out += ", VerilatedVarProps::Unpacked()";
|
|
|
|
|
out += ", " + cvtToStr(ulims.size() / 2);
|
|
|
|
|
out += ", " + propName + "__ulims";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out += ");\n";
|
2017-12-16 16:07:15 +01:00
|
|
|
return out;
|
2010-04-06 02:01:17 +02:00
|
|
|
}
|
|
|
|
|
|
2009-12-09 03:35:15 +01:00
|
|
|
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (forReturn) named = false;
|
2009-12-03 12:55:29 +01:00
|
|
|
string arg;
|
2018-10-27 23:29:00 +02:00
|
|
|
if (isWide() && isReadOnly()) arg += "const ";
|
2022-03-05 22:19:53 +01:00
|
|
|
const bool isRef = !forReturn && (isWritable() || direction().isRefOrConstRef());
|
|
|
|
|
if (VN_IS(dtypeSkipRefp(), BasicDType) && !dtypeSkipRefp()->isDouble()
|
|
|
|
|
&& !dtypeSkipRefp()->isString()) {
|
|
|
|
|
// Backward compatible type declaration
|
|
|
|
|
if (widthMin() == 1) {
|
|
|
|
|
arg += "bool";
|
|
|
|
|
} else if (widthMin() <= VL_IDATASIZE) {
|
|
|
|
|
arg += "uint32_t";
|
|
|
|
|
} else if (widthMin() <= VL_QUADSIZE) {
|
2022-03-27 21:27:40 +02:00
|
|
|
arg += "uint64_t";
|
2022-03-05 22:19:53 +01:00
|
|
|
} else {
|
|
|
|
|
arg += "uint32_t"; // []'s added later
|
|
|
|
|
}
|
|
|
|
|
if (isWide()) {
|
|
|
|
|
if (forReturn) {
|
|
|
|
|
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
|
|
|
|
|
"make an output of a public task instead");
|
|
|
|
|
}
|
|
|
|
|
arg += " (& " + name();
|
|
|
|
|
arg += ")[" + cvtToStr(widthWords()) + "]";
|
|
|
|
|
} else {
|
|
|
|
|
if (isRef) arg += "&";
|
|
|
|
|
if (named) arg += " " + name();
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2009-12-03 12:55:29 +01:00
|
|
|
} else {
|
2022-03-05 22:19:53 +01:00
|
|
|
// Newer internal-compatible types
|
2022-08-30 05:50:32 +02:00
|
|
|
arg += dtypep()->cType((named ? name() : std::string{}), true, isRef);
|
2009-12-03 12:55:29 +01:00
|
|
|
}
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 14:22:02 +01:00
|
|
|
class dpiTypesToStringConverter VL_NOT_FINAL {
|
2020-11-19 14:02:58 +01:00
|
|
|
public:
|
|
|
|
|
virtual string openArray(const AstVar*) const { return "const svOpenArrayHandle"; }
|
2022-07-30 16:01:25 +02:00
|
|
|
virtual string bitLogicVector(const AstVar* /*varp*/, bool isBit) const {
|
2020-11-19 14:02:58 +01:00
|
|
|
return isBit ? "svBitVecVal" : "svLogicVecVal";
|
|
|
|
|
}
|
|
|
|
|
virtual string primitive(const AstVar* varp) const {
|
|
|
|
|
string type;
|
2022-01-02 19:56:40 +01:00
|
|
|
const VBasicDTypeKwd keyword = varp->basicp()->keyword();
|
2020-12-13 08:05:06 +01:00
|
|
|
if (keyword.isDpiUnsignable() && !varp->basicp()->isSigned()) type = "unsigned ";
|
|
|
|
|
type += keyword.dpiType();
|
2020-11-19 14:02:58 +01:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
string convert(const AstVar* varp) const {
|
|
|
|
|
if (varp->isDpiOpenArray()) {
|
|
|
|
|
return openArray(varp);
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstBasicDType* const basicp = varp->basicp()) {
|
2020-12-13 08:05:06 +01:00
|
|
|
if (basicp->isDpiBitVec() || basicp->isDpiLogicVec()) {
|
|
|
|
|
return bitLogicVector(varp, basicp->isDpiBitVec());
|
|
|
|
|
} else {
|
|
|
|
|
return primitive(varp);
|
|
|
|
|
}
|
2017-12-10 02:17:37 +01:00
|
|
|
} else {
|
2020-12-13 08:05:06 +01:00
|
|
|
return "UNKNOWN";
|
2017-12-10 02:17:37 +01:00
|
|
|
}
|
2020-11-19 14:02:58 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
|
|
|
|
if (forReturn) {
|
|
|
|
|
return dpiTypesToStringConverter{}.convert(this);
|
2009-12-03 12:55:29 +01:00
|
|
|
} else {
|
2020-11-19 14:22:02 +01:00
|
|
|
class converter final : public dpiTypesToStringConverter {
|
2020-11-19 14:02:58 +01:00
|
|
|
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
|
|
|
|
return string(varp->isReadOnly() ? "const " : "")
|
|
|
|
|
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
|
|
|
|
|
}
|
|
|
|
|
virtual string primitive(const AstVar* varp) const override {
|
|
|
|
|
string type = dpiTypesToStringConverter::primitive(varp);
|
|
|
|
|
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
2022-01-02 19:56:40 +01:00
|
|
|
if (!varp->isWritable() && varp->basicp()->keyword() != VBasicDTypeKwd::STRING)
|
2020-11-19 14:02:58 +01:00
|
|
|
type = "const " + type;
|
|
|
|
|
type += "*";
|
|
|
|
|
}
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
string arg = converter{}.convert(this);
|
|
|
|
|
if (named) arg += " " + name();
|
|
|
|
|
return arg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string AstVar::dpiTmpVarType(const string& varName) const {
|
2020-11-19 14:22:02 +01:00
|
|
|
class converter final : public dpiTypesToStringConverter {
|
2021-11-26 23:55:36 +01:00
|
|
|
const string m_name;
|
2020-11-19 14:02:58 +01:00
|
|
|
string arraySuffix(const AstVar* varp, size_t n) const {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstUnpackArrayDType* const unpackp
|
2020-11-19 14:02:58 +01:00
|
|
|
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
|
|
|
|
// Convert multi dimensional unpacked array to 1D array
|
|
|
|
|
if (n == 0) n = 1;
|
|
|
|
|
n *= unpackp->arrayUnpackedElements();
|
|
|
|
|
return '[' + cvtToStr(n) + ']';
|
|
|
|
|
} else if (n > 0) {
|
|
|
|
|
return '[' + cvtToStr(n) + ']';
|
|
|
|
|
} else {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2018-10-27 23:29:00 +02:00
|
|
|
}
|
2020-11-19 14:02:58 +01:00
|
|
|
virtual string openArray(const AstVar* varp) const override {
|
|
|
|
|
return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name
|
|
|
|
|
+ arraySuffix(varp, 0);
|
|
|
|
|
}
|
|
|
|
|
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
|
|
|
|
string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit);
|
|
|
|
|
type += ' ' + m_name + arraySuffix(varp, varp->widthWords());
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
virtual string primitive(const AstVar* varp) const override {
|
|
|
|
|
string type = dpiTypesToStringConverter::primitive(varp);
|
|
|
|
|
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
2022-01-02 19:56:40 +01:00
|
|
|
if (!varp->isWritable() && varp->basicp()->keyword() == VBasicDTypeKwd::CHANDLE)
|
2020-11-19 14:02:58 +01:00
|
|
|
type = "const " + type;
|
|
|
|
|
}
|
|
|
|
|
type += ' ' + m_name + arraySuffix(varp, 0);
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit converter(const string& name)
|
|
|
|
|
: m_name(name) {}
|
|
|
|
|
};
|
|
|
|
|
return converter{varName}.convert(this);
|
2006-10-05 16:53:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string AstVar::scType() const {
|
2013-04-27 03:02:32 +02:00
|
|
|
if (isScBigUint()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (string("sc_biguint<") + cvtToStr(widthMin())
|
|
|
|
|
+ "> "); // Keep the space so don't get >>
|
2013-04-27 03:02:32 +02:00
|
|
|
} else if (isScUint()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (string("sc_uint<") + cvtToStr(widthMin())
|
|
|
|
|
+ "> "); // Keep the space so don't get >>
|
2013-04-27 03:02:32 +02:00
|
|
|
} else if (isScBv()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
return (string("sc_bv<") + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
|
2009-03-13 19:17:30 +01:00
|
|
|
} else if (widthMin() == 1) {
|
2019-05-19 22:13:13 +02:00
|
|
|
return "bool";
|
2019-12-09 03:36:38 +01:00
|
|
|
} else if (widthMin() <= VL_IDATASIZE) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (widthMin() <= 8 && v3Global.opt.pinsUint8()) {
|
|
|
|
|
return "uint8_t";
|
|
|
|
|
} else if (widthMin() <= 16 && v3Global.opt.pinsUint8()) {
|
|
|
|
|
return "uint16_t";
|
|
|
|
|
} else {
|
|
|
|
|
return "uint32_t";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
} else {
|
2022-03-27 21:27:40 +02:00
|
|
|
return "uint64_t";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 03:09:55 +01:00
|
|
|
AstVar* AstVar::scVarRecurse(AstNode* nodep) {
|
|
|
|
|
// See if this is a SC assignment; if so return that type
|
|
|
|
|
// Historically sc variables are identified by a variable
|
|
|
|
|
// attribute. TODO it would better be a data type attribute.
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstVar* const anodep = VN_CAST(nodep, Var)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (anodep->isSc()) {
|
|
|
|
|
return anodep;
|
|
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
} else if (VN_IS(nodep, VarRef)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
if (VN_AS(nodep, VarRef)->varp()->isSc()) {
|
|
|
|
|
return VN_AS(nodep, VarRef)->varp();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
} else if (VN_IS(nodep, ArraySel)) {
|
|
|
|
|
if (nodep->op1p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op1p())) return p;
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op2p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op2p())) return p;
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op3p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op3p())) return p;
|
|
|
|
|
}
|
|
|
|
|
if (nodep->op4p()) {
|
|
|
|
|
if (AstVar* p = scVarRecurse(nodep->op4p())) return p;
|
|
|
|
|
}
|
2015-02-26 03:09:55 +01:00
|
|
|
}
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2015-02-26 03:09:55 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class AstNodeDType::CTypeRecursed final {
|
2020-10-17 22:48:11 +02:00
|
|
|
public:
|
|
|
|
|
string m_type; // The base type, e.g.: "Foo_t"s
|
|
|
|
|
string m_dims; // Array dimensions, e.g.: "[3][2][1]"
|
|
|
|
|
string render(const string& name, bool isRef) const {
|
|
|
|
|
string out;
|
|
|
|
|
out += m_type;
|
Introduce model interface class, make $root part or Syms (#3036)
This patch implements #3032. Verilator creates a module representing the
SystemVerilog $root scope (V3LinkLevel::wrapTop). Until now, this was
called the "TOP" module, which also acted as the user instantiated model
class. Syms used to hold a pointer to this root module, but hold
instances of any submodule. This patch renames this root scope module
from "TOP" to "$root", and introduces a separate model class which is
now an interface class. As the root module is no longer the user
interface class, it can now be made an instance of Syms, just like any
other submodule. This allows absolute references into the root module to
avoid an additional pointer indirection resulting in a potential speedup
(about 1.5% on OpenTitan). The model class now also contains all non
design specific generated code (e.g.: eval loops, trace config, etc),
which additionally simplifies Verilator internals.
Please see the updated documentation for the model interface changes.
2021-06-21 16:30:20 +02:00
|
|
|
if (!name.empty()) out += " ";
|
|
|
|
|
if (isRef) {
|
|
|
|
|
if (!m_dims.empty()) out += "(";
|
|
|
|
|
out += "&";
|
|
|
|
|
out += name;
|
|
|
|
|
if (!m_dims.empty()) out += ")";
|
|
|
|
|
} else {
|
|
|
|
|
out += name;
|
|
|
|
|
}
|
2020-10-17 22:48:11 +02:00
|
|
|
out += m_dims;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-30 16:01:25 +02:00
|
|
|
string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const {
|
2021-06-21 00:32:57 +02:00
|
|
|
const CTypeRecursed info = cTypeRecurse(false);
|
2020-10-17 22:48:11 +02:00
|
|
|
return info.render(name, isRef);
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 03:40:14 +01:00
|
|
|
AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
2021-03-13 18:32:35 +01:00
|
|
|
// Legacy compound argument currently just passed through and unused
|
2020-10-17 22:48:11 +02:00
|
|
|
CTypeRecursed info;
|
|
|
|
|
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNodeDType* const dtypep = this->skipRefp();
|
|
|
|
|
if (const auto* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
|
2020-11-11 03:40:14 +01:00
|
|
|
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
|
|
|
|
|
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
2022-07-20 15:01:36 +02:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
|
|
|
|
info.m_type = "VlAssocArray<std::string, " + sub.m_type + ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
|
2020-11-11 03:40:14 +01:00
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlQueue<" + sub.m_type + ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, QueueDType)) {
|
2020-11-11 03:40:14 +01:00
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlQueue<" + sub.m_type;
|
|
|
|
|
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
|
|
|
|
|
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
|
|
|
|
|
info.m_type += ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
2020-12-13 01:19:16 +01:00
|
|
|
if (adtypep->isCompound()) compound = true;
|
|
|
|
|
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
|
2021-03-13 18:32:35 +01:00
|
|
|
info.m_type = "VlUnpacked<" + sub.m_type;
|
|
|
|
|
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
|
|
|
|
|
info.m_type += ">";
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstBasicDType* const bdtypep = dtypep->basicp()) {
|
2020-10-17 22:48:11 +02:00
|
|
|
// We don't print msb()/lsb() as multidim packed would require recursion,
|
|
|
|
|
// and may confuse users as C++ data is stored always with bit 0 used
|
|
|
|
|
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
|
|
|
|
|
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
|
|
|
|
|
: "";
|
2022-01-02 19:56:40 +01:00
|
|
|
if (bdtypep->keyword() == VBasicDTypeKwd::CHARPTR) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "const char*";
|
2022-01-02 19:56:40 +01:00
|
|
|
} else if (bdtypep->keyword() == VBasicDTypeKwd::SCOPEPTR) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "const VerilatedScope*";
|
2021-06-16 13:18:56 +02:00
|
|
|
} else if (bdtypep->keyword().isDouble()) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "double";
|
2021-06-16 13:18:56 +02:00
|
|
|
} else if (bdtypep->keyword().isString()) {
|
2020-10-17 22:48:11 +02:00
|
|
|
info.m_type = "std::string";
|
2021-06-16 13:18:56 +02:00
|
|
|
} else if (bdtypep->keyword().isMTaskState()) {
|
|
|
|
|
info.m_type = "VlMTaskVertex";
|
2020-10-17 22:48:11 +02:00
|
|
|
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
|
|
|
|
info.m_type = "CData" + bitvec;
|
|
|
|
|
} else if (dtypep->widthMin() <= 16) {
|
|
|
|
|
info.m_type = "SData" + bitvec;
|
|
|
|
|
} else if (dtypep->widthMin() <= VL_IDATASIZE) {
|
|
|
|
|
info.m_type = "IData" + bitvec;
|
|
|
|
|
} else if (dtypep->isQuad()) {
|
|
|
|
|
info.m_type = "QData" + bitvec;
|
|
|
|
|
} else if (dtypep->isWide()) {
|
2021-03-13 18:32:35 +01:00
|
|
|
info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + ">" + bitvec;
|
2020-10-17 22:48:11 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-15 03:49:22 +01:00
|
|
|
uint32_t AstNodeDType::arrayUnpackedElements() {
|
2019-05-19 22:13:13 +02:00
|
|
|
uint32_t entries = 1;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNodeDType* dtypep = this; dtypep;) {
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
entries *= adtypep->elementsConst();
|
|
|
|
|
dtypep = adtypep->subDTypep();
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstBasicDType - nothing below, 1
|
|
|
|
|
break;
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return entries;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
|
2010-04-10 02:43:25 +02:00
|
|
|
// How many array dimensions (packed,unpacked) does this Var have?
|
|
|
|
|
uint32_t packed = 0;
|
|
|
|
|
uint32_t unpacked = 0;
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNodeDType* dtypep = this; dtypep;) {
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (VN_IS(adtypep, PackArrayDType)) {
|
|
|
|
|
++packed;
|
|
|
|
|
} else {
|
|
|
|
|
++unpacked;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep = adtypep->subDTypep();
|
|
|
|
|
continue;
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstQueueDType* const qdtypep = VN_CAST(dtypep, QueueDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
unpacked++;
|
|
|
|
|
dtypep = qdtypep->subDTypep();
|
|
|
|
|
continue;
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstBasicDType* const adtypep = VN_CAST(dtypep, BasicDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else if (VN_IS(dtypep, StructDType)) {
|
2019-12-19 00:17:18 +01:00
|
|
|
packed++;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2010-01-19 16:52:11 +01:00
|
|
|
}
|
2021-03-13 00:17:49 +01:00
|
|
|
return std::make_pair(packed, unpacked);
|
2010-01-19 16:52:11 +01:00
|
|
|
}
|
2012-04-29 17:34:25 +02:00
|
|
|
|
|
|
|
|
int AstNodeDType::widthPow2() const {
|
|
|
|
|
// I.e. width 30 returns 32, width 32 returns 32.
|
2021-11-26 23:55:36 +01:00
|
|
|
const uint32_t width = this->width();
|
2020-04-15 13:58:34 +02:00
|
|
|
for (int p2 = 30; p2 >= 0; p2--) {
|
|
|
|
|
if (width > (1UL << p2)) return (1UL << (p2 + 1));
|
2012-04-29 17:34:25 +02:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2010-01-19 16:52:11 +01:00
|
|
|
|
2021-07-22 19:59:03 +02:00
|
|
|
bool AstNodeDType::isLiteralType() const {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
|
2021-07-22 19:59:03 +02:00
|
|
|
return dtypep->keyword().isLiteralType();
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
|
2021-07-22 19:59:03 +02:00
|
|
|
return dtypep->basicp()->isLiteralType();
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const auto* const dtypep = VN_CAST(skipRefp(), StructDType)) {
|
2021-07-22 19:59:03 +02:00
|
|
|
// Currently all structs are packed, later this can be expanded to
|
|
|
|
|
// 'forall members _.isLiteralType()'
|
|
|
|
|
return dtypep->packed();
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-15 13:58:34 +02:00
|
|
|
/// What is the base variable (or const) this dereferences?
|
2021-03-13 19:04:13 +01:00
|
|
|
AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
|
2009-10-25 21:53:55 +01:00
|
|
|
// Else AstArraySel etc; search for the base
|
|
|
|
|
while (nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (VN_IS(nodep, ArraySel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, ArraySel)->fromp();
|
2020-04-15 13:58:34 +02:00
|
|
|
continue;
|
|
|
|
|
} else if (VN_IS(nodep, Sel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, Sel)->fromp();
|
2020-04-15 13:58:34 +02:00
|
|
|
continue;
|
2021-03-13 19:04:13 +01:00
|
|
|
} else if (overMembers && VN_IS(nodep, MemberSel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, MemberSel)->fromp();
|
2021-03-13 19:04:13 +01:00
|
|
|
continue;
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
2019-03-14 00:47:36 +01:00
|
|
|
// AstNodeSelPre stashes the associated variable under an ATTROF
|
2022-01-02 19:56:40 +01:00
|
|
|
// of VAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
|
2020-04-15 13:58:34 +02:00
|
|
|
else if (VN_IS(nodep, AttrOf)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, AttrOf)->fromp();
|
2020-04-15 13:58:34 +02:00
|
|
|
continue;
|
|
|
|
|
} else if (VN_IS(nodep, NodePreSel)) {
|
2021-10-22 14:56:48 +02:00
|
|
|
if (VN_AS(nodep, NodePreSel)->attrp()) {
|
|
|
|
|
nodep = VN_AS(nodep, NodePreSel)->attrp();
|
2019-03-14 00:47:36 +01:00
|
|
|
} else {
|
2021-10-22 14:56:48 +02:00
|
|
|
nodep = VN_AS(nodep, NodePreSel)->fromp();
|
2019-03-14 00:47:36 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
continue;
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
break;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-07 03:33:05 +02:00
|
|
|
const char* AstJumpBlock::broken() const {
|
|
|
|
|
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-05-07 03:33:05 +02:00
|
|
|
}
|
|
|
|
|
void AstJumpBlock::cloneRelink() {
|
|
|
|
|
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-25 23:05:22 +02:00
|
|
|
const char* AstScope::broken() const {
|
|
|
|
|
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
|
|
|
|
|
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
|
|
|
|
|
BROKEN_RTN(!m_modp);
|
|
|
|
|
BROKEN_RTN(m_modp && !m_modp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
void AstScope::cloneRelink() {
|
2016-11-09 03:16:22 +01:00
|
|
|
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
|
|
|
|
|
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep();
|
2018-10-15 00:39:33 +02:00
|
|
|
if (m_modp && static_cast<AstNode*>(m_modp)->clonep()) {
|
|
|
|
|
static_cast<AstNode*>(m_modp)->clonep();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
string AstScope::nameDotless() const {
|
2009-12-05 16:38:49 +01:00
|
|
|
string out = shortName();
|
2006-08-26 13:35:28 +02:00
|
|
|
string::size_type pos;
|
2020-04-15 13:58:34 +02:00
|
|
|
while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__");
|
2009-12-05 16:38:49 +01:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-17 01:27:18 +02:00
|
|
|
string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
|
2009-12-05 16:38:49 +01:00
|
|
|
string out;
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
out += textp->text();
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
|
|
|
|
// TOP will be replaced by top->name()
|
2019-05-19 22:13:13 +02:00
|
|
|
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
|
|
|
|
|
if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, "");
|
|
|
|
|
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
|
2009-12-05 16:38:49 +01:00
|
|
|
return AstNode::prettyName(out);
|
|
|
|
|
}
|
2015-06-17 01:27:18 +02:00
|
|
|
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
|
2009-12-05 16:38:49 +01:00
|
|
|
string out;
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
out += textp->text();
|
2014-07-22 02:55:52 +02:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
|
|
|
|
|
if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, "");
|
|
|
|
|
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
|
2014-07-22 02:55:52 +02:00
|
|
|
string::size_type pos;
|
2020-04-15 13:58:34 +02:00
|
|
|
while ((pos = out.find('.')) != string::npos) out.replace(pos, 1, "__");
|
|
|
|
|
while ((pos = out.find("__DOT__")) != string::npos) out.replace(pos, 7, "__");
|
2014-07-22 02:55:52 +02:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasClocked() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isClocked()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasSettle() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isSettle()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasInitial() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isInitial()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-11-02 23:02:11 +01:00
|
|
|
bool AstSenTree::hasCombo() const {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
|
2021-10-22 14:56:48 +02:00
|
|
|
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (senp->isCombo()) return true;
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
AstTypeTable::AstTypeTable(FileLine* fl)
|
|
|
|
|
: ASTGEN_SUPER_TypeTable(fl) {
|
2022-01-02 19:56:40 +01:00
|
|
|
for (int i = 0; i < VBasicDTypeKwd::_ENUM_MAX; ++i) m_basicps[i] = nullptr;
|
2021-06-13 16:05:55 +02:00
|
|
|
}
|
|
|
|
|
|
2012-04-29 16:14:13 +02:00
|
|
|
void AstTypeTable::clearCache() {
|
|
|
|
|
// When we mass-change widthMin in V3WidthCommit, we need to correct the table.
|
|
|
|
|
// Just clear out the maps; the search functions will be used to rebuild the map
|
2020-11-11 04:10:38 +01:00
|
|
|
for (auto& itr : m_basicps) itr = nullptr;
|
2012-04-29 16:14:13 +02:00
|
|
|
m_detailedMap.clear();
|
|
|
|
|
// Clear generic()'s so dead detection will work
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstTypeTable::repairCache() {
|
|
|
|
|
// After we mass-change widthMin in V3WidthCommit, we need to correct the table.
|
|
|
|
|
clearCache();
|
2020-04-15 13:58:34 +02:00
|
|
|
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
(void)findInsertSameDType(bdtypep);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 23:23:35 +02:00
|
|
|
AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_emptyQueuep)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstEmptyQueueDType* const newp = new AstEmptyQueueDType{fl};
|
2021-08-28 23:23:35 +02:00
|
|
|
addTypesp(newp);
|
|
|
|
|
m_emptyQueuep = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_emptyQueuep;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-01 17:52:48 +01:00
|
|
|
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_voidp)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstVoidDType* const newp = new AstVoidDType{fl};
|
2019-12-01 17:52:48 +01:00
|
|
|
addTypesp(newp);
|
|
|
|
|
m_voidp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_voidp;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-01 16:56:07 +01:00
|
|
|
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
|
|
|
|
|
if (VL_UNLIKELY(!m_queueIndexp)) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstQueueDType* const newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
|
2020-11-01 16:56:07 +01:00
|
|
|
addTypesp(newp);
|
|
|
|
|
m_queueIndexp = newp;
|
|
|
|
|
}
|
|
|
|
|
return m_queueIndexp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, VBasicDTypeKwd kwd) {
|
2012-04-29 16:14:13 +02:00
|
|
|
if (m_basicps[kwd]) return m_basicps[kwd];
|
|
|
|
|
//
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const new1p = new AstBasicDType(fl, kwd);
|
2012-04-29 16:14:13 +02:00
|
|
|
// Because the detailed map doesn't update this map,
|
|
|
|
|
// check the detailed map for this same node
|
|
|
|
|
// Also adds this new node to the detailed map
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const newp = findInsertSameDType(new1p);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (newp != new1p) {
|
|
|
|
|
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
|
|
|
|
} else {
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
//
|
|
|
|
|
m_basicps[kwd] = newp;
|
|
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width,
|
2020-04-20 03:19:09 +02:00
|
|
|
int widthMin, VSigning numeric) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
|
|
|
|
|
AstBasicDType* const newp = findInsertSameDType(new1p);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (newp != new1p) {
|
|
|
|
|
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
|
|
|
|
} else {
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
|
2020-08-16 20:55:46 +02:00
|
|
|
const VNumRange& range, int widthMin,
|
|
|
|
|
VSigning numeric) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
|
|
|
|
|
AstBasicDType* const newp = findInsertSameDType(new1p);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (newp != new1p) {
|
|
|
|
|
VL_DO_DANGLING(new1p->deleteTree(), new1p);
|
|
|
|
|
} else {
|
|
|
|
|
addTypesp(newp);
|
|
|
|
|
}
|
2013-01-17 02:58:48 +01:00
|
|
|
return newp;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-29 16:14:13 +02:00
|
|
|
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
|
|
|
|
|
nodep->nrange());
|
2012-04-29 16:14:13 +02:00
|
|
|
DetailedMap& mapr = m_detailedMap;
|
2020-08-16 17:43:49 +02:00
|
|
|
const auto it = mapr.find(key);
|
2012-04-29 16:14:13 +02:00
|
|
|
if (it != mapr.end()) return it->second;
|
2020-12-19 00:24:47 +01:00
|
|
|
mapr.emplace(key, nodep);
|
2012-04-29 16:14:13 +02:00
|
|
|
nodep->generic(true);
|
|
|
|
|
// No addTypesp; the upper function that called new() is responsible for adding
|
|
|
|
|
return nodep;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
AstConstPool::AstConstPool(FileLine* fl)
|
|
|
|
|
: ASTGEN_SUPER_ConstPool(fl)
|
|
|
|
|
, m_modp{new AstModule(fl, "@CONST-POOL@")}
|
|
|
|
|
, m_scopep{new AstScope(fl, m_modp, "@CONST-POOL@", nullptr, nullptr)} {
|
|
|
|
|
addOp1p(m_modp);
|
|
|
|
|
m_modp->addStmtp(m_scopep);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
|
|
|
|
|
FileLine* const fl = initp->fileline();
|
2022-01-02 19:56:40 +01:00
|
|
|
AstVar* const varp = new AstVar(fl, VVarType::MODULETEMP, name, initp->dtypep());
|
2021-06-13 16:05:55 +02:00
|
|
|
varp->isConst(true);
|
|
|
|
|
varp->isStatic(true);
|
|
|
|
|
varp->valuep(initp->cloneTree(false));
|
|
|
|
|
m_modp->addStmtp(varp);
|
|
|
|
|
AstVarScope* const varScopep = new AstVarScope(fl, m_scopep, varp);
|
|
|
|
|
m_scopep->addVarp(varScopep);
|
|
|
|
|
return varScopep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
|
|
|
|
|
// Unpacked array initializers must have equivalent values
|
|
|
|
|
// Note, sadly we can't just call ap->sameTree(pb), because both:
|
|
|
|
|
// - the dtypes might be different instances
|
|
|
|
|
// - the default/inititem children might be in different order yet still yield the same table
|
|
|
|
|
// See note in AstInitArray::same about the same. This function instead compares by initializer
|
|
|
|
|
// value, rather than by tree structure.
|
2021-12-11 17:29:01 +01:00
|
|
|
if (const AstAssocArrayDType* const aDTypep = VN_CAST(ap->dtypep(), AssocArrayDType)) {
|
|
|
|
|
const AstAssocArrayDType* const bDTypep = VN_CAST(bp->dtypep(), AssocArrayDType);
|
|
|
|
|
if (!bDTypep) return false;
|
|
|
|
|
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) return false;
|
|
|
|
|
if (!aDTypep->keyDTypep()->sameTree(bDTypep->keyDTypep())) return false;
|
|
|
|
|
UASSERT_OBJ(ap->defaultp(), ap, "Assoc InitArray should have a default");
|
|
|
|
|
UASSERT_OBJ(bp->defaultp(), bp, "Assoc InitArray should have a default");
|
|
|
|
|
if (!ap->defaultp()->sameTree(bp->defaultp())) return false;
|
|
|
|
|
// Compare initializer arrays by value. Note this is only called when they hash the same,
|
|
|
|
|
// so they likely run at most once per call to 'AstConstPool::findTable'.
|
|
|
|
|
// This assumes that the defaults are used in the same way.
|
|
|
|
|
// TODO when buinding the AstInitArray, remove any values matching the default
|
|
|
|
|
const auto& amapr = ap->map();
|
|
|
|
|
const auto& bmapr = bp->map();
|
|
|
|
|
const auto ait = amapr.cbegin();
|
|
|
|
|
const auto bit = bmapr.cbegin();
|
|
|
|
|
while (ait != amapr.cend() || bit != bmapr.cend()) {
|
|
|
|
|
if (ait == amapr.cend() || bit == bmapr.cend()) return false; // Different size
|
|
|
|
|
if (ait->first != bit->first) return false; // Different key
|
|
|
|
|
if (ait->second->sameTree(bit->second)) return false; // Different value
|
|
|
|
|
}
|
|
|
|
|
} else if (const AstUnpackArrayDType* const aDTypep
|
|
|
|
|
= VN_CAST(ap->dtypep(), UnpackArrayDType)) {
|
|
|
|
|
const AstUnpackArrayDType* const bDTypep = VN_CAST(bp->dtypep(), UnpackArrayDType);
|
|
|
|
|
if (!bDTypep) return false;
|
|
|
|
|
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) return false;
|
|
|
|
|
if (!aDTypep->rangep()->sameTree(bDTypep->rangep())) return false;
|
|
|
|
|
// Compare initializer arrays by value. Note this is only called when they hash the same,
|
|
|
|
|
// so they likely run at most once per call to 'AstConstPool::findTable'.
|
2022-03-27 21:27:40 +02:00
|
|
|
const uint64_t size = aDTypep->elementsConst();
|
|
|
|
|
for (uint64_t n = 0; n < size; ++n) {
|
2021-12-11 17:29:01 +01:00
|
|
|
const AstNode* const valAp = ap->getIndexDefaultedValuep(n);
|
|
|
|
|
const AstNode* const valBp = bp->getIndexDefaultedValuep(n);
|
|
|
|
|
if (!valAp->sameTree(valBp)) return false;
|
|
|
|
|
}
|
2021-06-13 16:05:55 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNode* const defaultp = initp->defaultp();
|
2021-06-13 16:05:55 +02:00
|
|
|
// Verify initializer is well formed
|
2021-12-11 17:29:01 +01:00
|
|
|
UASSERT_OBJ(VN_IS(initp->dtypep(), AssocArrayDType)
|
|
|
|
|
|| VN_IS(initp->dtypep(), UnpackArrayDType),
|
|
|
|
|
initp, "Const pool table must have array dtype");
|
2021-06-13 16:05:55 +02:00
|
|
|
UASSERT_OBJ(!defaultp || VN_IS(defaultp, Const), initp,
|
|
|
|
|
"Const pool table default must be Const");
|
|
|
|
|
for (AstNode* nodep = initp->initsp(); nodep; nodep = nodep->nextp()) {
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstNode* const valuep = VN_AS(nodep, InitItem)->valuep();
|
2021-06-13 16:05:55 +02:00
|
|
|
UASSERT_OBJ(VN_IS(valuep, Const), valuep, "Const pool table entry must be Const");
|
|
|
|
|
}
|
|
|
|
|
// Try to find an existing table with the same content
|
2021-08-11 17:22:52 +02:00
|
|
|
const V3Hash hash = V3Hasher::uncachedHash(initp);
|
|
|
|
|
const auto& er = m_tables.equal_range(hash.value());
|
2021-06-13 16:05:55 +02:00
|
|
|
for (auto it = er.first; it != er.second; ++it) {
|
|
|
|
|
AstVarScope* const varScopep = it->second;
|
2021-10-22 14:56:48 +02:00
|
|
|
const AstInitArray* const init2p = VN_AS(varScopep->varp()->valuep(), InitArray);
|
2021-06-13 16:05:55 +02:00
|
|
|
if (sameInit(initp, init2p)) {
|
|
|
|
|
return varScopep; // Found identical table
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// No such table yet, create it.
|
|
|
|
|
string name = "TABLE_";
|
2021-08-11 17:22:52 +02:00
|
|
|
name += hash.toString();
|
2021-06-13 16:05:55 +02:00
|
|
|
name += "_";
|
|
|
|
|
name += cvtToStr(std::distance(er.first, er.second));
|
|
|
|
|
AstVarScope* const varScopep = createNewEntry(name, initp);
|
2021-08-11 17:22:52 +02:00
|
|
|
m_tables.emplace(hash.value(), varScopep);
|
2021-06-13 16:05:55 +02:00
|
|
|
return varScopep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool sameInit(const AstConst* ap, const AstConst* bp) {
|
|
|
|
|
// Similarly to the AstInitArray comparison, we ignore the dtype instance, so long as they
|
|
|
|
|
// are compatible. For now, we assume the dtype is not relevant, as we only call this from
|
|
|
|
|
// V3Prelim which is a late pass.
|
|
|
|
|
// Compare initializers by value. This checks widths as well.
|
|
|
|
|
return ap->num().isCaseEq(bp->num());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
|
|
|
|
|
// Try to find an existing constant with the same value
|
2021-08-11 17:22:52 +02:00
|
|
|
const V3Hash hash = initp->num().toHash();
|
|
|
|
|
const auto& er = m_consts.equal_range(hash.value());
|
2021-06-13 16:05:55 +02:00
|
|
|
for (auto it = er.first; it != er.second; ++it) {
|
|
|
|
|
AstVarScope* const varScopep = it->second;
|
2021-10-22 14:56:48 +02:00
|
|
|
const AstConst* const init2p = VN_AS(varScopep->varp()->valuep(), Const);
|
2021-06-13 16:05:55 +02:00
|
|
|
if (sameInit(initp, init2p)
|
|
|
|
|
&& (mergeDType || varScopep->dtypep()->sameTree(initp->dtypep()))) {
|
|
|
|
|
return varScopep; // Found identical constant
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// No such constant yet, create it.
|
|
|
|
|
string name = "CONST_";
|
2021-08-11 17:22:52 +02:00
|
|
|
name += hash.toString();
|
2021-06-13 16:05:55 +02:00
|
|
|
name += "_";
|
|
|
|
|
name += cvtToStr(std::distance(er.first, er.second));
|
|
|
|
|
AstVarScope* const varScopep = createNewEntry(name, initp);
|
2021-08-11 17:22:52 +02:00
|
|
|
m_consts.emplace(hash.value(), varScopep);
|
2021-06-13 16:05:55 +02:00
|
|
|
return varScopep;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-09 02:42:45 +02:00
|
|
|
//======================================================================
|
|
|
|
|
// Special walking tree inserters
|
|
|
|
|
|
|
|
|
|
void AstNode::addBeforeStmt(AstNode* newp, AstNode*) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(backp(), newp, "Can't find current statement to addBeforeStmt");
|
2009-10-09 02:42:45 +02:00
|
|
|
// Look up; virtual call will find where to put it
|
|
|
|
|
this->backp()->addBeforeStmt(newp, this);
|
|
|
|
|
}
|
|
|
|
|
void AstNode::addNextStmt(AstNode* newp, AstNode*) {
|
2019-07-06 18:57:50 +02:00
|
|
|
UASSERT_OBJ(backp(), newp, "Can't find current statement to addNextStmt");
|
2009-10-09 02:42:45 +02:00
|
|
|
// Look up; virtual call will find where to put it
|
|
|
|
|
this->backp()->addNextStmt(newp, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstNodeStmt::addBeforeStmt(AstNode* newp, AstNode*) {
|
|
|
|
|
// Insert newp before current node
|
|
|
|
|
this->addHereThisAsNext(newp);
|
|
|
|
|
}
|
|
|
|
|
void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) {
|
|
|
|
|
// Insert newp after current node
|
|
|
|
|
this->addNextHere(newp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) {
|
|
|
|
|
// Special, as statements need to be put in different places
|
|
|
|
|
// Belowp is how we came to recurse up to this point
|
2019-05-19 22:13:13 +02:00
|
|
|
// Preconditions insert first just before themselves (the normal rule
|
|
|
|
|
// for other statement types)
|
2009-10-09 02:42:45 +02:00
|
|
|
if (belowp == precondsp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Must have been first statement in precondsp list, so newp is new first statement
|
|
|
|
|
belowp->addHereThisAsNext(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == condp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Goes before condition, IE in preconditions
|
|
|
|
|
addPrecondsp(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == bodysp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Was first statement in body, so new front
|
|
|
|
|
belowp->addHereThisAsNext(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
belowp->v3fatalSrc("Doesn't look like this was really under the while");
|
2009-10-09 02:42:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
|
|
|
|
|
// Special, as statements need to be put in different places
|
|
|
|
|
// Belowp is how we came to recurse up to this point
|
2019-05-19 22:13:13 +02:00
|
|
|
// Preconditions insert first just before themselves (the normal rule
|
|
|
|
|
// for other statement types)
|
2009-10-09 02:42:45 +02:00
|
|
|
if (belowp == precondsp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Next in precond list
|
|
|
|
|
belowp->addNextHere(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == condp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Becomes first statement in body, body may have been empty
|
|
|
|
|
if (bodysp()) {
|
|
|
|
|
bodysp()->addHereThisAsNext(newp);
|
|
|
|
|
} else {
|
|
|
|
|
addBodysp(newp);
|
|
|
|
|
}
|
2009-10-09 02:42:45 +02:00
|
|
|
} else if (belowp == bodysp()) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Next statement in body
|
|
|
|
|
belowp->addNextHere(newp);
|
2009-10-09 02:42:45 +02:00
|
|
|
} else {
|
2019-05-19 22:13:13 +02:00
|
|
|
belowp->v3fatalSrc("Doesn't look like this was really under the while");
|
2009-10-09 02:42:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 13:35:28 +02:00
|
|
|
//======================================================================
|
|
|
|
|
// Per-type Debugging
|
|
|
|
|
|
2020-05-23 19:31:30 +02:00
|
|
|
// Render node address for dumps. By default this is just the address
|
|
|
|
|
// printed as hex, but with --dump-tree-addrids we map addresses to short
|
|
|
|
|
// strings with a bijection to aid human readability. Observe that this might
|
|
|
|
|
// not actually be a unique identifier as the address can get reused after a
|
|
|
|
|
// node has been freed.
|
|
|
|
|
static std::string nodeAddr(const AstNode* nodep) {
|
|
|
|
|
return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep);
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNode::dump(std::ostream& str) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << typeName() << " "
|
2020-05-23 19:31:30 +02:00
|
|
|
<< nodeAddr(this)
|
|
|
|
|
//<< " " << nodeAddr(m_backp)
|
2020-04-15 13:58:34 +02:00
|
|
|
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
|
2020-05-30 16:08:30 +02:00
|
|
|
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
|
|
|
|
|
<< fileline()->firstColumnLetters() << "}";
|
2020-05-23 19:31:30 +02:00
|
|
|
if (user1p()) str << " u1=" << nodeAddr(user1p());
|
|
|
|
|
if (user2p()) str << " u2=" << nodeAddr(user2p());
|
|
|
|
|
if (user3p()) str << " u3=" << nodeAddr(user3p());
|
|
|
|
|
if (user4p()) str << " u4=" << nodeAddr(user4p());
|
|
|
|
|
if (user5p()) str << " u5=" << nodeAddr(user5p());
|
2012-04-29 16:14:13 +02:00
|
|
|
if (hasDType()) {
|
2018-10-14 22:25:36 +02:00
|
|
|
// Final @ so less likely to by accident read it as a nodep
|
2020-04-15 13:58:34 +02:00
|
|
|
if (dtypep() == this) {
|
|
|
|
|
str << " @dt=this@";
|
|
|
|
|
} else {
|
2020-05-23 19:31:30 +02:00
|
|
|
str << " @dt=" << nodeAddr(dtypep()) << "@";
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstNodeDType* const dtp = dtypep()) dtp->dumpSmall(str);
|
2019-05-19 22:13:13 +02:00
|
|
|
} else { // V3Broken will throw an error
|
2020-05-23 19:31:30 +02:00
|
|
|
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
if (name() != "") {
|
|
|
|
|
if (VN_IS(this, Const)) {
|
|
|
|
|
str << " " << name(); // Already quoted
|
|
|
|
|
} else {
|
|
|
|
|
str << " " << V3OutFormatter::quoteNameControls(name());
|
|
|
|
|
}
|
2014-11-28 21:01:50 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2009-05-08 00:28:05 +02:00
|
|
|
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstAlways::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeProcedure::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]";
|
2013-05-01 04:55:28 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstAttrOf::dump(std::ostream& str) const {
|
2009-05-08 00:28:05 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " [" << attrType().ascii() << "]";
|
2009-05-08 00:28:05 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstBasicDType::dump(std::ostream& str) const {
|
2012-02-20 15:55:20 +01:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " kwd=" << keyword().ascii();
|
|
|
|
|
if (isRanged() && !rangep()) str << " range=[" << left() << ":" << right() << "]";
|
2009-11-02 14:06:04 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstBasicDType::prettyDTypeName() const {
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << keyword().ascii();
|
|
|
|
|
if (isRanged() && !rangep() && keyword().width() <= 1) {
|
|
|
|
|
os << "[" << left() << ":" << right() << "]";
|
|
|
|
|
}
|
|
|
|
|
return os.str();
|
|
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
|
|
|
|
|
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
|
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCCast::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeUniop::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " sz" << size();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCell::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (recursive()) str << " [RECURSIVE]";
|
|
|
|
|
if (modp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
modp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED:" << modName();
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCellInline::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> " << origModName();
|
2020-11-12 01:00:10 +01:00
|
|
|
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
const char* AstClassPackage::broken() const {
|
|
|
|
|
BROKEN_BASE_RTN(AstNodeModule::broken());
|
|
|
|
|
BROKEN_RTN(m_classp && !m_classp->brokeExists());
|
2020-08-15 16:12:55 +02:00
|
|
|
return nullptr;
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
2021-12-13 00:10:52 +01:00
|
|
|
void AstClassPackage::cloneRelink() {
|
|
|
|
|
if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep();
|
|
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
void AstClass::insertCache(AstNode* nodep) {
|
2021-10-22 14:56:48 +02:00
|
|
|
const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|
2022-05-17 15:22:43 +02:00
|
|
|
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())
|
|
|
|
|
|| VN_IS(nodep, CFunc));
|
2020-08-23 01:46:21 +02:00
|
|
|
if (doit) {
|
2020-04-05 15:30:23 +02:00
|
|
|
if (m_members.find(nodep->name()) != m_members.end()) {
|
|
|
|
|
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
|
|
|
|
|
} else {
|
2020-12-19 00:24:47 +01:00
|
|
|
m_members.emplace(nodep->name(), nodep);
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void AstClass::repairCache() {
|
|
|
|
|
clearCache();
|
2022-05-17 15:22:43 +02:00
|
|
|
for (auto* itemp = membersp(); itemp; itemp = itemp->nextp()) {
|
|
|
|
|
if (const auto* const scopep = VN_CAST(itemp, Scope)) {
|
2022-07-30 16:01:25 +02:00
|
|
|
for (auto* blockp = scopep->blocksp(); blockp; blockp = blockp->nextp()) {
|
|
|
|
|
insertCache(blockp);
|
|
|
|
|
}
|
2022-05-17 15:22:43 +02:00
|
|
|
} else {
|
|
|
|
|
insertCache(itemp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
2020-11-29 04:01:11 +01:00
|
|
|
bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) {
|
|
|
|
|
// TAIL RECURSIVE
|
|
|
|
|
if (!refClassp || !baseClassp) return false;
|
|
|
|
|
if (refClassp == baseClassp) return true;
|
2020-11-30 00:26:06 +01:00
|
|
|
if (!refClassp->extendsp()) return false;
|
2020-11-29 04:01:11 +01:00
|
|
|
return isClassExtendedFrom(refClassp->extendsp()->classp(), baseClassp);
|
|
|
|
|
}
|
2020-08-24 02:00:39 +02:00
|
|
|
void AstClass::dump(std::ostream& str) const {
|
2021-12-23 02:06:04 +01:00
|
|
|
this->AstNodeModule::dump(str);
|
2020-08-24 02:00:39 +02:00
|
|
|
if (isExtended()) str << " [EXT]";
|
|
|
|
|
if (isVirtual()) str << " [VIRT]";
|
|
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
AstClass* AstClassExtends::classp() const {
|
2021-11-26 23:55:36 +01:00
|
|
|
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
|
2020-11-26 17:06:59 +01:00
|
|
|
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
|
2021-10-22 14:56:48 +02:00
|
|
|
refp = VN_AS(childDTypep(), ClassRefDType);
|
2020-11-26 17:06:59 +01:00
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
UASSERT_OBJ(refp, this, "class extends non-ref");
|
|
|
|
|
return refp->classp();
|
|
|
|
|
}
|
|
|
|
|
void AstClassRefDType::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeDType::dump(str);
|
2021-12-23 02:06:04 +01:00
|
|
|
if (classOrPackagep()) str << " cpkg=" << nodeAddr(classOrPackagep());
|
2020-04-15 13:58:34 +02:00
|
|
|
if (classp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
classp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
|
|
|
|
void AstClassRefDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "class:" << name();
|
2020-04-05 15:30:23 +02:00
|
|
|
}
|
2019-12-17 03:43:52 +01:00
|
|
|
void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (immediate()) str << " [IMMEDIATE]";
|
2019-12-17 03:43:52 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstDisplay::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2021-09-09 01:31:26 +02:00
|
|
|
// str << " " << displayType().ascii();
|
2008-03-26 15:58:30 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstEnumItemRef::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeMath::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (itemp()) {
|
|
|
|
|
itemp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2009-12-27 14:29:55 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstIfaceRefDType::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeDType::dump(str);
|
2021-02-22 03:25:21 +01:00
|
|
|
if (cellName() != "") str << " cell=" << cellName();
|
|
|
|
|
if (ifaceName() != "") str << " if=" << ifaceName();
|
|
|
|
|
if (modportName() != "") str << " mp=" << modportName();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (cellp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
cellp()->dump(str);
|
|
|
|
|
} else if (ifacep()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
ifacep()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstIfaceRefDType::dumpSmall(std::ostream& str) const {
|
2013-05-28 03:39:19 +02:00
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "iface";
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2019-11-09 21:34:41 +01:00
|
|
|
void AstInitArray::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
int n = 0;
|
2021-12-11 17:22:04 +01:00
|
|
|
const auto& mapr = map();
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& itr : mapr) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (n++ > 5) {
|
|
|
|
|
str << " ...";
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-11-12 01:00:10 +01:00
|
|
|
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
|
2019-11-09 21:34:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstJumpGo::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (labelp()) {
|
|
|
|
|
labelp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2013-02-18 18:15:50 +01:00
|
|
|
}
|
2020-05-07 03:33:05 +02:00
|
|
|
void AstJumpLabel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-05-07 03:33:05 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (blockp()) {
|
|
|
|
|
blockp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-12 00:38:23 +01:00
|
|
|
void AstLogOr::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeMath::dump(str);
|
2021-12-12 00:38:23 +01:00
|
|
|
if (sideEffect()) str << " [SIDE]";
|
|
|
|
|
}
|
2020-01-16 02:18:12 +01:00
|
|
|
void AstMemberSel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeMath::dump(str);
|
2020-01-16 02:18:12 +01:00
|
|
|
str << " -> ";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (varp()) {
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2020-01-16 02:18:12 +01:00
|
|
|
}
|
2020-03-07 18:52:11 +01:00
|
|
|
void AstMethodCall::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeFTaskRef::dump(str);
|
2020-03-07 18:52:11 +01:00
|
|
|
if (isStatement()) str << " [STMT]";
|
|
|
|
|
str << " -> ";
|
|
|
|
|
if (taskp()) {
|
|
|
|
|
taskp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstModportFTaskRef::dump(std::ostream& str) const {
|
2013-12-21 12:51:15 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isExport()) str << " EXPORT";
|
|
|
|
|
if (isImport()) str << " IMPORT";
|
|
|
|
|
if (ftaskp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
ftaskp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2013-12-21 12:51:15 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstModportVarRef::dump(std::ostream& str) const {
|
2013-05-28 03:39:19 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (direction().isAny()) str << " " << direction();
|
|
|
|
|
if (varp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
|
|
|
|
}
|
2013-05-28 03:39:19 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstPin::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (modVarp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
modVarp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED";
|
|
|
|
|
}
|
|
|
|
|
if (svImplicit()) str << " [.SV]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstPrintTimeScale::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
|
|
|
|
|
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstTime::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTermop::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
|
|
|
|
void AstTimeD::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTermop::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
|
|
|
|
void AstTimeImport::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeUniop::dump(str);
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " " << timeunit();
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstTypedef::dump(std::ostream& str) const {
|
2014-11-07 13:50:11 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (attrPublic()) str << " [PUBLIC]";
|
2014-11-07 13:50:11 +01:00
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstRange::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeRange::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (littleEndian()) str << " [LITTLE]";
|
2009-10-25 21:53:55 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstRefDType::dump(std::ostream& str) const {
|
2012-02-20 15:55:20 +01:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-05-24 20:22:06 +02:00
|
|
|
if (typedefp() || subDTypep()) {
|
2019-10-06 14:20:02 +02:00
|
|
|
static bool s_recursing = false;
|
2019-01-12 15:33:57 +01:00
|
|
|
if (!s_recursing) { // Prevent infinite dump if circular typedefs
|
|
|
|
|
s_recursing = true;
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2021-07-08 01:42:49 +02:00
|
|
|
if (const auto subp = typedefp()) {
|
|
|
|
|
subp->dump(str);
|
|
|
|
|
} else if (const auto subp = subDTypep()) {
|
|
|
|
|
subp->dump(str);
|
2020-05-24 20:22:06 +02:00
|
|
|
}
|
2019-01-12 15:33:57 +01:00
|
|
|
s_recursing = false;
|
|
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
str << " -> UNLINKED";
|
2019-01-12 15:33:57 +01:00
|
|
|
}
|
2009-11-07 05:16:06 +01:00
|
|
|
}
|
2019-12-17 04:46:09 +01:00
|
|
|
void AstNodeUOrStructDType::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (packed()) str << " [PACKED]";
|
|
|
|
|
if (isFourstate()) str << " [4STATE]";
|
2012-07-29 16:16:20 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeDType::dump(std::ostream& str) const {
|
2012-02-20 15:55:20 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (generic()) str << " [GENERIC]";
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstNodeDType* const dtp = virtRefDTypep()) {
|
2020-05-23 19:31:30 +02:00
|
|
|
str << " refdt=" << nodeAddr(dtp);
|
2019-05-19 22:13:13 +02:00
|
|
|
dtp->dumpSmall(str);
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeDType::dumpSmall(std::ostream& str) const {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "(" << (generic() ? "G/" : "") << ((isSigned() && !isDouble()) ? "s" : "")
|
|
|
|
|
<< (isNosign() ? "n" : "") << (isDouble() ? "d" : "") << (isString() ? "str" : "");
|
2021-02-22 03:25:21 +01:00
|
|
|
if (!isDouble() && !isString()) str << "w" << (widthSized() ? "" : "u") << width();
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!widthSized()) str << "/" << widthMin();
|
|
|
|
|
str << ")";
|
2012-02-20 15:55:20 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeArrayDType::dumpSmall(std::ostream& str) const {
|
2013-01-13 20:30:56 +01:00
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2021-11-26 23:55:36 +01:00
|
|
|
if (auto* const adtypep = VN_CAST(this, UnpackArrayDType)) {
|
2020-12-13 01:19:16 +01:00
|
|
|
// uc = packed compound object, u = unpacked POD
|
|
|
|
|
str << (adtypep->isCompound() ? "uc" : "u");
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
2020-12-13 01:19:16 +01:00
|
|
|
str << "p";
|
2020-04-15 13:58:34 +02:00
|
|
|
}
|
|
|
|
|
str << declRange();
|
2013-01-13 20:30:56 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeArrayDType::dump(std::ostream& str) const {
|
2013-01-13 20:30:56 +01:00
|
|
|
this->AstNodeDType::dump(str);
|
2020-12-13 01:19:16 +01:00
|
|
|
if (isCompound()) str << " [COMPOUND]";
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " " << declRange();
|
2013-01-13 20:30:56 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstPackArrayDType::prettyDTypeName() const {
|
|
|
|
|
std::ostringstream os;
|
2021-07-08 01:42:49 +02:00
|
|
|
if (const auto subp = subDTypep()) os << subp->prettyDTypeName();
|
|
|
|
|
os << declRange();
|
2020-01-26 19:21:25 +01:00
|
|
|
return os.str();
|
|
|
|
|
}
|
|
|
|
|
string AstUnpackArrayDType::prettyDTypeName() const {
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
string ranges = cvtToStr(declRange());
|
|
|
|
|
// Unfortunately we need a single $ for the first unpacked, and all
|
|
|
|
|
// dimensions shown in "reverse" order
|
|
|
|
|
AstNodeDType* subp = subDTypep()->skipRefp();
|
|
|
|
|
while (AstUnpackArrayDType* adtypep = VN_CAST(subp, UnpackArrayDType)) {
|
|
|
|
|
ranges += cvtToStr(adtypep->declRange());
|
|
|
|
|
subp = adtypep->subDTypep()->skipRefp();
|
|
|
|
|
}
|
|
|
|
|
os << subp->prettyDTypeName() << "$" << ranges;
|
|
|
|
|
return os.str();
|
|
|
|
|
}
|
2020-11-19 14:02:58 +01:00
|
|
|
std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
|
|
|
|
|
std::vector<AstUnpackArrayDType*> dims;
|
|
|
|
|
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
|
|
|
|
|
dims.push_back(unpackp);
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstNodeDType* const subp = unpackp->subDTypep()) {
|
2020-11-19 14:02:58 +01:00
|
|
|
unpackp = VN_CAST(subp, UnpackArrayDType);
|
|
|
|
|
} else {
|
|
|
|
|
unpackp = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dims;
|
|
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
void AstNetlist::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeModule::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " L" << level();
|
|
|
|
|
if (modPublic()) str << " [P]";
|
|
|
|
|
if (inLibrary()) str << " [LIB]";
|
|
|
|
|
if (dead()) str << " [DEAD]";
|
|
|
|
|
if (recursiveClone()) {
|
|
|
|
|
str << " [RECURSIVE-CLONE]";
|
|
|
|
|
} else if (recursive()) {
|
|
|
|
|
str << " [RECURSIVE]";
|
|
|
|
|
}
|
2020-04-16 01:39:03 +02:00
|
|
|
str << " [" << timeunit() << "]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstPackageExport::dump(std::ostream& str) const {
|
2017-09-21 03:04:59 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> " << packagep();
|
2017-09-21 03:04:59 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstPackageImport::dump(std::ostream& str) const {
|
2009-11-10 01:07:59 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> " << packagep();
|
2009-11-10 01:07:59 +01:00
|
|
|
}
|
2020-11-07 17:56:24 +01:00
|
|
|
void AstPatMember::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeMath::dump(str);
|
2020-11-07 17:56:24 +01:00
|
|
|
if (isDefault()) str << " [DEFAULT]";
|
|
|
|
|
}
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTriop::dump(str);
|
2013-01-15 03:49:22 +01:00
|
|
|
if (declRange().ranged()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " decl" << declRange() << "]";
|
|
|
|
|
if (declElWidth() != 1) str << "/" << declElWidth();
|
2013-01-15 03:49:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSliceSel::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeTriop::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (declRange().ranged()) str << " decl" << declRange();
|
2017-11-23 20:55:32 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstMTaskBody::dump(std::ostream& str) const {
|
2018-07-23 02:54:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " ";
|
2018-07-23 02:54:28 +02:00
|
|
|
m_execMTaskp->dump(str);
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstTypeTable::dump(std::ostream& str) const {
|
2012-04-29 16:14:13 +02:00
|
|
|
this->AstNode::dump(str);
|
2022-01-02 19:56:40 +01:00
|
|
|
for (int i = 0; i < static_cast<int>(VBasicDTypeKwd::_ENUM_MAX); ++i) {
|
2021-11-26 23:55:36 +01:00
|
|
|
if (AstBasicDType* const subnodep = m_basicps[i]) {
|
2020-11-19 03:03:23 +01:00
|
|
|
str << '\n'; // Newline from caller, so newline first
|
2022-01-02 19:56:40 +01:00
|
|
|
str << "\t\t" << std::setw(8) << VBasicDTypeKwd(i).ascii();
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2019-05-19 22:13:13 +02:00
|
|
|
subnodep->dump(str);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
{
|
2019-10-20 17:49:41 +02:00
|
|
|
const DetailedMap& mapr = m_detailedMap;
|
2020-11-11 04:10:38 +01:00
|
|
|
for (const auto& itr : mapr) {
|
2021-11-26 23:55:36 +01:00
|
|
|
AstBasicDType* const dtypep = itr.second;
|
2020-11-19 03:03:23 +01:00
|
|
|
str << '\n'; // Newline from caller, so newline first
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "\t\tdetailed -> ";
|
2019-05-19 22:13:13 +02:00
|
|
|
dtypep->dump(str);
|
|
|
|
|
}
|
2012-04-29 16:14:13 +02:00
|
|
|
}
|
|
|
|
|
// Note get newline from caller too.
|
|
|
|
|
}
|
2019-12-01 17:52:48 +01:00
|
|
|
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-11-12 01:00:10 +01:00
|
|
|
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
|
2019-12-01 17:52:48 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstAssocArrayDType::prettyDTypeName() const {
|
|
|
|
|
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
|
|
|
|
|
}
|
2020-03-07 16:24:27 +01:00
|
|
|
void AstDynArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "[]";
|
2020-03-07 16:24:27 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
string AstDynArrayDType::prettyDTypeName() const { return subDTypep()->prettyDTypeName() + "[]"; }
|
2019-12-01 18:35:49 +01:00
|
|
|
void AstQueueDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "[queue]";
|
2019-12-01 18:35:49 +01:00
|
|
|
}
|
2020-01-26 19:21:25 +01:00
|
|
|
string AstQueueDType::prettyDTypeName() const {
|
|
|
|
|
string str = subDTypep()->prettyDTypeName() + "[$";
|
|
|
|
|
if (boundConst()) str += ":" + cvtToStr(boundConst());
|
|
|
|
|
return str + "]";
|
|
|
|
|
}
|
2022-07-20 15:01:36 +02:00
|
|
|
void AstWildcardArrayDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "[*]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
|
2017-12-17 22:28:58 +01:00
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "[]";
|
2017-12-17 22:28:58 +01:00
|
|
|
}
|
2021-08-28 23:23:35 +02:00
|
|
|
void AstEmptyQueueDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
|
|
|
|
str << "emptyq";
|
|
|
|
|
}
|
2019-12-01 17:52:48 +01:00
|
|
|
void AstVoidDType::dumpSmall(std::ostream& str) const {
|
|
|
|
|
this->AstNodeDType::dumpSmall(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << "void";
|
2019-12-01 17:52:48 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstVarScope::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isCircular()) str << " [CIRC]";
|
2022-01-02 21:03:57 +01:00
|
|
|
if (isTrace()) str << " [T]";
|
|
|
|
|
if (scopep()) str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (varp()) {
|
|
|
|
|
str << " -> ";
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << " ->UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-11-25 03:28:04 +01:00
|
|
|
void AstNodeVarRef::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeMath::dump(str);
|
2020-11-25 03:56:03 +01:00
|
|
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
2020-11-01 22:59:23 +01:00
|
|
|
str << " " << access().arrow() << " ";
|
2020-11-25 03:28:04 +01:00
|
|
|
}
|
|
|
|
|
void AstVarXRef::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeVarRef::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << ".=" << dotted() << " ";
|
|
|
|
|
if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - ";
|
|
|
|
|
if (varScopep()) {
|
|
|
|
|
varScopep()->dump(str);
|
|
|
|
|
} else if (varp()) {
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2012-07-20 03:18:39 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstVarRef::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeVarRef::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (varScopep()) {
|
|
|
|
|
varScopep()->dump(str);
|
|
|
|
|
} else if (varp()) {
|
|
|
|
|
varp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstVar::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isSc()) str << " [SC]";
|
|
|
|
|
if (isPrimaryIO()) str << (isInoutish() ? " [PIO]" : (isWritable() ? " [PO]" : " [PI]"));
|
|
|
|
|
if (isIO()) str << " " << direction().ascii();
|
|
|
|
|
if (isConst()) str << " [CONST]";
|
|
|
|
|
if (isPullup()) str << " [PULLUP]";
|
|
|
|
|
if (isPulldown()) str << " [PULLDOWN]";
|
|
|
|
|
if (isUsedClock()) str << " [CLK]";
|
|
|
|
|
if (isSigPublic()) str << " [P]";
|
2021-01-05 20:26:01 +01:00
|
|
|
if (isLatched()) str << " [LATCHED]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isUsedLoopIdx()) str << " [LOOP]";
|
|
|
|
|
if (attrClockEn()) str << " [aCLKEN]";
|
|
|
|
|
if (attrIsolateAssign()) str << " [aISO]";
|
|
|
|
|
if (attrFileDescr()) str << " [aFD]";
|
|
|
|
|
if (isFuncReturn()) {
|
|
|
|
|
str << " [FUNCRTN]";
|
|
|
|
|
} else if (isFuncLocal()) {
|
|
|
|
|
str << " [FUNC]";
|
|
|
|
|
}
|
|
|
|
|
if (isDpiOpenArray()) str << " [DPIOPENA]";
|
|
|
|
|
if (!attrClocker().unknown()) str << " [" << attrClocker().ascii() << "] ";
|
2020-04-26 18:45:06 +02:00
|
|
|
if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] ";
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " " << varType();
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-11-12 01:00:10 +01:00
|
|
|
void AstScope::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
|
|
|
|
|
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
|
|
|
|
|
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
|
|
|
|
|
}
|
2021-11-27 02:38:48 +01:00
|
|
|
void AstScopeName::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeMath::dump(str);
|
2021-11-27 02:38:48 +01:00
|
|
|
if (dpiExport()) str << " [DPIEX]";
|
|
|
|
|
if (forFormat()) str << " [FMT]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSenTree::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isMulti()) str << " [MULTI]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstSenItem::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " [" << edgeType().ascii() << "]";
|
2006-12-21 22:53:51 +01:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstParseRef::dump(std::ostream& str) const {
|
2006-12-21 22:53:51 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " [" << expect().ascii() << "]";
|
2012-12-31 23:05:13 +01:00
|
|
|
}
|
2020-07-11 16:29:15 +02:00
|
|
|
void AstClassOrPackageRef::dump(std::ostream& str) const {
|
2012-12-31 23:05:13 +01:00
|
|
|
this->AstNode::dump(str);
|
2020-12-05 22:23:20 +01:00
|
|
|
if (classOrPackageNodep()) str << " cpkg=" << nodeAddr(classOrPackageNodep());
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2020-12-05 22:23:20 +01:00
|
|
|
if (classOrPackageNodep()) {
|
|
|
|
|
classOrPackageNodep()->dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-05-23 18:44:15 +02:00
|
|
|
void AstDot::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
2020-07-12 02:32:27 +02:00
|
|
|
if (colon()) str << " [::]";
|
2020-05-23 18:44:15 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstActive::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " => ";
|
|
|
|
|
if (sensesp()) {
|
|
|
|
|
sensesp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-11-25 03:56:03 +01:00
|
|
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2021-02-22 03:25:21 +01:00
|
|
|
if (dotted() != "") str << ".=" << dotted() << " ";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (taskp()) {
|
|
|
|
|
taskp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeFTask::dump(std::ostream& str) const {
|
2006-08-26 13:35:28 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (classMethod()) str << " [METHOD]";
|
|
|
|
|
if (dpiExport()) str << " [DPIX]";
|
2022-01-04 00:50:41 +01:00
|
|
|
if (dpiImport()) str << " [DPII]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (dpiOpenChild()) str << " [DPIOPENCHILD]";
|
|
|
|
|
if (dpiOpenParent()) str << " [DPIOPENPARENT]";
|
2022-01-04 00:50:41 +01:00
|
|
|
if (prototype()) str << " [PROTOTYPE]";
|
|
|
|
|
if (recursive()) str << " [RECURSIVE]";
|
|
|
|
|
if (taskPublic()) str << " [PUBLIC]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-23 03:31:40 +02:00
|
|
|
void AstNodeBlock::dump(std::ostream& str) const {
|
2009-10-12 02:50:31 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (unnamed()) str << " [UNNAMED]";
|
2020-04-23 03:31:40 +02:00
|
|
|
}
|
|
|
|
|
void AstBegin::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeBlock::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (generate()) str << " [GEN]";
|
|
|
|
|
if (genforp()) str << " [GENFOR]";
|
|
|
|
|
if (implied()) str << " [IMPLIED]";
|
2009-10-12 02:50:31 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCoverDecl::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-06-01 15:08:50 +02:00
|
|
|
if (!page().empty()) str << " page=" << page();
|
|
|
|
|
if (!linescov().empty()) str << " lc=" << linescov();
|
2008-12-12 21:34:02 +01:00
|
|
|
if (this->dataDeclNullp()) {
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
2019-05-19 22:13:13 +02:00
|
|
|
this->dataDeclNullp()->dump(str);
|
2008-12-12 21:34:02 +01:00
|
|
|
} else {
|
2021-02-22 03:25:21 +01:00
|
|
|
if (binNum()) str << " bin" << std::dec << binNum();
|
2008-12-12 21:34:02 +01:00
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCoverInc::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (declp()) {
|
|
|
|
|
declp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2020-04-23 03:31:40 +02:00
|
|
|
void AstFork::dump(std::ostream& str) const {
|
2022-07-30 16:01:25 +02:00
|
|
|
this->AstNodeBlock::dump(str);
|
2020-04-23 03:31:40 +02:00
|
|
|
if (!joinType().join()) str << " [" << joinType() << "]";
|
|
|
|
|
}
|
2022-04-11 01:40:27 +02:00
|
|
|
void AstTraceDecl::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNodeStmt::dump(str);
|
|
|
|
|
if (code()) str << " [code=" << code() << "]";
|
|
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstTraceInc::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeStmt::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " -> ";
|
|
|
|
|
if (declp()) {
|
|
|
|
|
declp()->dump(str);
|
|
|
|
|
} else {
|
|
|
|
|
str << "%Error:UNLINKED";
|
|
|
|
|
}
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstNodeText::dump(std::ostream& str) const {
|
2009-12-05 16:38:49 +01:00
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
string out = text();
|
|
|
|
|
string::size_type pos;
|
2018-10-14 04:28:59 +02:00
|
|
|
if ((pos = out.find('\n')) != string::npos) {
|
2020-04-15 13:58:34 +02:00
|
|
|
out.erase(pos, out.length() - pos);
|
2019-05-19 22:13:13 +02:00
|
|
|
out += "...";
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
2020-04-15 13:58:34 +02:00
|
|
|
str << " \"" << out << "\"";
|
2009-12-05 16:38:49 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-17 03:52:24 +02:00
|
|
|
void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
|
|
|
|
void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); }
|
2019-09-27 09:44:23 +02:00
|
|
|
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCFile::dump(std::ostream& str) const {
|
2020-09-17 03:52:24 +02:00
|
|
|
this->AstNodeFile::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (source()) str << " [SRC]";
|
|
|
|
|
if (slow()) str << " [SLOW]";
|
2006-08-26 13:35:28 +02:00
|
|
|
}
|
2019-10-20 17:49:41 +02:00
|
|
|
void AstCFunc::dump(std::ostream& str) const {
|
2008-08-06 23:09:33 +02:00
|
|
|
this->AstNode::dump(str);
|
2020-04-15 13:58:34 +02:00
|
|
|
if (slow()) str << " [SLOW]";
|
|
|
|
|
if (pure()) str << " [PURE]";
|
2021-06-16 14:52:37 +02:00
|
|
|
if (isStatic()) str << " [STATIC]";
|
2021-06-10 23:41:33 +02:00
|
|
|
if (dpiExportDispatcher()) str << " [DPIED]";
|
|
|
|
|
if (dpiExportImpl()) str << " [DPIEI]";
|
|
|
|
|
if (dpiImportPrototype()) str << " [DPIIP]";
|
|
|
|
|
if (dpiImportWrapper()) str << " [DPIIW]";
|
2021-08-12 22:43:32 +02:00
|
|
|
if (dpiContext()) str << " [DPICTX]";
|
2020-04-15 13:58:34 +02:00
|
|
|
if (isConstructor()) str << " [CTOR]";
|
|
|
|
|
if (isDestructor()) str << " [DTOR]";
|
|
|
|
|
if (isVirtual()) str << " [VIRT]";
|
2008-08-06 23:09:33 +02:00
|
|
|
}
|
2020-02-01 22:45:11 +01:00
|
|
|
void AstCUse::dump(std::ostream& str) const {
|
|
|
|
|
this->AstNode::dump(str);
|
|
|
|
|
str << " [" << useType() << "]";
|
|
|
|
|
}
|