Internals: Add --debug-width option for developers to check width consistency (#4923)
This commit is contained in:
parent
af51107587
commit
da9521a351
|
|
@ -1171,6 +1171,31 @@ void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE {
|
|||
default: this->v3fatalSrc("Bad case"); break;
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.debugWidth() && v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH) {
|
||||
if (const AstNodeExpr* const exprp = VN_CAST(this, NodeExpr)) {
|
||||
const char* const whyp = exprp->widthMismatch();
|
||||
if (whyp) {
|
||||
auto dtypeStr = [](const AstNodeExpr* exprp) VL_MT_STABLE {
|
||||
std::ostringstream ss;
|
||||
exprp->dtypep()->dumpSmall(ss);
|
||||
return ss.str();
|
||||
};
|
||||
if (const AstNodeUniop* const uniopp = VN_CAST(exprp, NodeUniop)) {
|
||||
UASSERT_OBJ(!whyp, uniopp,
|
||||
"widthMismatch detected " << whyp << "OUT:" << dtypeStr(uniopp)
|
||||
<< " LHS:" << dtypeStr(uniopp->lhsp()));
|
||||
} else if (const AstNodeBiop* const biopp = VN_CAST(exprp, NodeBiop)) {
|
||||
UASSERT_OBJ(!whyp, biopp,
|
||||
"widthMismatch detected " << whyp << "OUT:" << dtypeStr(biopp)
|
||||
<< " LHS:" << dtypeStr(biopp->lhsp())
|
||||
<< " RHS:" << dtypeStr(biopp->rhsp()));
|
||||
} else {
|
||||
UASSERT_OBJ(false, exprp,
|
||||
"widthMismatch detected " << whyp << " in an unexpected type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
|
|
|
|||
|
|
@ -2002,7 +2002,7 @@ public:
|
|||
|
||||
// TODO stomp these width functions out, and call via dtypep() instead
|
||||
inline int width() const VL_MT_STABLE;
|
||||
inline int widthMin() const;
|
||||
inline int widthMin() const VL_MT_STABLE;
|
||||
int widthMinV() const {
|
||||
return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
// Inline METHODS
|
||||
|
||||
int AstNode::width() const VL_MT_STABLE { return dtypep() ? dtypep()->width() : 0; }
|
||||
int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; }
|
||||
int AstNode::widthMin() const VL_MT_STABLE { return dtypep() ? dtypep()->widthMin() : 0; }
|
||||
bool AstNode::width1() const { // V3Const uses to know it can optimize
|
||||
return dtypep() && dtypep()->width() == 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public:
|
|||
// ACCESSORS
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
virtual void dumpSmall(std::ostream& str) const;
|
||||
virtual void dumpSmall(std::ostream& str) const VL_MT_STABLE;
|
||||
bool hasDType() const override { return true; }
|
||||
/// Require VlUnpacked, instead of [] for POD elements.
|
||||
/// A non-POD object is always compound, but some POD elements
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ public:
|
|||
|
||||
// Wrap This expression into an AstStmtExpr to denote it occurs in statement position
|
||||
inline AstStmtExpr* makeStmt();
|
||||
// Returns an error message if widthMin() is not correct otherwise returns nullptr like
|
||||
// broken()
|
||||
virtual const char* widthMismatch() const VL_MT_STABLE { return nullptr; }
|
||||
};
|
||||
class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
|
||||
// Binary expression
|
||||
|
|
@ -3830,6 +3833,7 @@ public:
|
|||
bool cleanRhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
const char* widthMismatch() const override VL_MT_STABLE;
|
||||
};
|
||||
class AstMul final : public AstNodeBiComAsv {
|
||||
public:
|
||||
|
|
@ -3924,6 +3928,7 @@ public:
|
|||
bool cleanRhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
const char* widthMismatch() const override VL_MT_STABLE;
|
||||
};
|
||||
class AstXor final : public AstNodeBiComAsv {
|
||||
public:
|
||||
|
|
@ -3946,6 +3951,7 @@ public:
|
|||
bool cleanRhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
const char* widthMismatch() const override VL_MT_STABLE;
|
||||
};
|
||||
|
||||
// === AstNodeDistBiop ===
|
||||
|
|
@ -5082,6 +5088,7 @@ public:
|
|||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool sizeMattersLhs() const override { return true; }
|
||||
const char* widthMismatch() const override VL_MT_STABLE;
|
||||
};
|
||||
class AstNullCheck final : public AstNodeUniop {
|
||||
// Return LHS after checking that LHS is non-null
|
||||
|
|
|
|||
|
|
@ -1916,7 +1916,7 @@ void AstNodeDType::dumpJson(std::ostream& str) const {
|
|||
dumpJsonBoolFunc(str, generic);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstNodeDType::dumpSmall(std::ostream& str) const {
|
||||
void AstNodeDType::dumpSmall(std::ostream& str) const VL_MT_STABLE {
|
||||
str << "(" << (generic() ? "G/" : "") << ((isSigned() && !isDouble()) ? "s" : "")
|
||||
<< (isNosign() ? "n" : "") << (isDouble() ? "d" : "") << (isString() ? "str" : "");
|
||||
if (!isDouble() && !isString()) str << "w" << (widthSized() ? "" : "u") << width();
|
||||
|
|
@ -2757,3 +2757,22 @@ void AstDelay::dumpJson(std::ostream& str) const {
|
|||
dumpJsonBoolFunc(str, isCycleDelay);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
const char* AstAnd::widthMismatch() const VL_MT_STABLE {
|
||||
BROKEN_RTN(lhsp()->widthMin() != rhsp()->widthMin());
|
||||
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
||||
return nullptr;
|
||||
}
|
||||
const char* AstOr::widthMismatch() const VL_MT_STABLE {
|
||||
BROKEN_RTN(lhsp()->widthMin() != rhsp()->widthMin());
|
||||
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
||||
return nullptr;
|
||||
}
|
||||
const char* AstXor::widthMismatch() const VL_MT_STABLE {
|
||||
BROKEN_RTN(lhsp()->widthMin() != rhsp()->widthMin());
|
||||
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
||||
return nullptr;
|
||||
}
|
||||
const char* AstNot::widthMismatch() const VL_MT_STABLE {
|
||||
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,16 +75,17 @@ public:
|
|||
VWidthMinUsage()
|
||||
: m_e{LINT_WIDTH} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VWidthMinUsage(en _e)
|
||||
: m_e{_e} {}
|
||||
constexpr VWidthMinUsage(en _e) VL_PURE : m_e{_e} {}
|
||||
constexpr VWidthMinUsage(const VWidthMinUsage& _e) VL_PURE = default;
|
||||
explicit VWidthMinUsage(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
constexpr VWidthMinUsage& operator=(const VWidthMinUsage& _e) VL_PURE = default;
|
||||
};
|
||||
constexpr bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VWidthMinUsage& lhs, VWidthMinUsage::en rhs) {
|
||||
constexpr bool operator==(const VWidthMinUsage& lhs, VWidthMinUsage::en rhs) VL_PURE {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
constexpr bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) {
|
||||
|
|
@ -140,7 +141,7 @@ public:
|
|||
|
||||
// ACCESSORS (general)
|
||||
AstNetlist* rootp() const VL_MT_SAFE { return m_rootp; }
|
||||
VWidthMinUsage widthMinUsage() const { return m_widthMinUsage; }
|
||||
VWidthMinUsage widthMinUsage() const VL_PURE { return m_widthMinUsage; }
|
||||
bool assertDTypesResolved() const { return m_assertDTypesResolved; }
|
||||
bool assertScoped() const { return m_assertScoped; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1197,6 +1197,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented();
|
||||
DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort
|
||||
DECL_OPTION("-debug-stack-check", OnOff, &m_debugStackCheck).undocumented();
|
||||
DECL_OPTION("-debug-width", OnOff, &m_debugWidth).undocumented();
|
||||
DECL_OPTION("-decoration", CbCall, [this, fl]() { decorations(fl, "medium"); });
|
||||
DECL_OPTION("-decorations", CbVal, [this, fl](const char* optp) { decorations(fl, optp); });
|
||||
DECL_OPTION("-no-decoration", CbCall, [this, fl]() { decorations(fl, "none"); });
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ private:
|
|||
bool m_debugProtect = false; // main switch: --debug-protect
|
||||
bool m_debugSelfTest = false; // main switch: --debug-self-test
|
||||
bool m_debugStackCheck = false; // main switch: --debug-stack-check
|
||||
bool m_debugWidth = false; // main switch: --debug-width
|
||||
bool m_decoration = true; // main switch: --decoration
|
||||
bool m_decorationNodes = false; // main switch: --decoration=nodes
|
||||
bool m_dpiHdrOnly = false; // main switch: --dpi-hdr-only
|
||||
|
|
@ -483,6 +484,7 @@ public:
|
|||
bool debugProtect() const VL_MT_SAFE { return m_debugProtect; }
|
||||
bool debugSelfTest() const { return m_debugSelfTest; }
|
||||
bool debugStackCheck() const { return m_debugStackCheck; }
|
||||
bool debugWidth() const VL_PURE { return m_debugWidth; }
|
||||
bool decoration() const VL_MT_SAFE { return m_decoration; }
|
||||
bool decorationNodes() const VL_MT_SAFE { return m_decorationNodes; }
|
||||
bool dpiHdrOnly() const { return m_dpiHdrOnly; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
%Error: Internal Error: t/t_const_opt.v:531:34: ../V3Ast.cpp:#: widthMismatch detected 'lhsp()->widthMin() != rhsp()->widthMin()' @ ../V3AstNodes.cpp:#OUT:(G/wu32/1) LHS:(G/w32) RHS:(G/wu32/1)
|
||||
531 | always_ff @(posedge clkin_data[0], posedge myfirst, posedge mysecond)
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html for more assistance.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
top_filename("t/t_const_opt.v");
|
||||
scenarios(simulator => 1);
|
||||
|
||||
lint(
|
||||
verilator_flags2 => ["--lint-only", "--debug-width"],
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
Loading…
Reference in New Issue