Fix initializing static array in dynamic arrays and queues (#5287).

This commit is contained in:
Wilson Snyder 2024-07-24 06:06:57 -04:00
parent 1e3c7a5496
commit 0419ed0430
11 changed files with 264 additions and 72 deletions

View File

@ -42,6 +42,7 @@ Verilator 5.027 devel
* Fix randomization when used with inheritance (#5268). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix inline constraints creating class random generator (#5280). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix elaborating foreach loops (#5285). [Arkadiusz Kozdra, Antmicro Ltd.]
* Fix initializing static array in dynamic arrays and queues (#5287). [Baruch Sterin]
* Fix randomizing current object with `rand` class instance member (#5292). [Krzysztof Bieganski, Antmicro Ltd.]

View File

@ -512,28 +512,29 @@ public:
return *this;
}
static VlQueue cons(const T_Value& lhs) {
// Construct new object from _V_alue and/or _C_ontainer child objects
static VlQueue consV(const T_Value& lhs) {
VlQueue out;
out.push_back(lhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const T_Value& rhs) {
static VlQueue consVV(const T_Value& lhs, const T_Value& rhs) {
VlQueue out;
out.push_back(rhs);
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) {
static VlQueue consCV(const VlQueue& lhs, const T_Value& rhs) {
VlQueue out = lhs;
out.push_front(rhs);
return out;
}
static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) {
static VlQueue consVC(const T_Value& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
out.push_back(lhs);
return out;
}
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
static VlQueue consCC(const VlQueue& lhs, const VlQueue& rhs) {
VlQueue out = rhs;
for (const auto& i : lhs.m_deque) out.push_back(i);
return out;
@ -751,7 +752,7 @@ public:
// Can't use std::find_if as need index number
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) return VlQueue::cons(i);
if (with_func(index, i)) return VlQueue::consV(i);
++index;
}
return VlQueue{};
@ -760,7 +761,7 @@ public:
VlQueue<IData> find_first_index(Func with_func) const {
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) return VlQueue<IData>::cons(index);
if (with_func(index, i)) return VlQueue<IData>::consV(index);
++index;
}
return VlQueue<IData>{};
@ -769,7 +770,7 @@ public:
VlQueue find_last(Func with_func) const {
IData index = m_deque.size() - 1;
for (auto& item : vlstd::reverse_view(m_deque)) {
if (with_func(index, item)) return VlQueue::cons(item);
if (with_func(index, item)) return VlQueue::consV(item);
--index;
}
return VlQueue{};
@ -778,7 +779,7 @@ public:
VlQueue<IData> find_last_index(Func with_func) const {
IData index = m_deque.size() - 1;
for (auto& item : vlstd::reverse_view(m_deque)) {
if (with_func(index, item)) return VlQueue<IData>::cons(index);
if (with_func(index, item)) return VlQueue<IData>::consV(index);
--index;
}
return VlQueue<IData>{};
@ -788,7 +789,7 @@ public:
VlQueue min() const {
if (m_deque.empty()) return VlQueue{};
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend());
return VlQueue::cons(*it);
return VlQueue::consV(*it);
}
template <typename Func>
VlQueue min(Func with_func) const {
@ -797,12 +798,12 @@ public:
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue::cons(*it);
return VlQueue::consV(*it);
}
VlQueue max() const {
if (m_deque.empty()) return VlQueue{};
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend());
return VlQueue::cons(*it);
return VlQueue::consV(*it);
}
template <typename Func>
VlQueue max(Func with_func) const {
@ -811,7 +812,7 @@ public:
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue::cons(*it);
return VlQueue::consV(*it);
}
T_Value r_sum() const {
@ -1092,7 +1093,7 @@ public:
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
return VlQueue<T_Value>::consV(it->second);
}
template <typename Func>
VlQueue<T_Key> find_first_index(Func with_func) const {
@ -1101,7 +1102,7 @@ public:
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
return VlQueue<T_Key>::consV(it->first);
}
template <typename Func>
VlQueue<T_Value> find_last(Func with_func) const {
@ -1109,7 +1110,7 @@ public:
m_map.crbegin(), m_map.crend(),
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
return VlQueue<T_Value>::consV(it->second);
}
template <typename Func>
VlQueue<T_Key> find_last_index(Func with_func) const {
@ -1117,7 +1118,7 @@ public:
m_map.crbegin(), m_map.crend(),
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
return VlQueue<T_Key>::consV(it->first);
}
// Reduction operators
@ -1128,7 +1129,7 @@ public:
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
return VlQueue<T_Value>::consV(it->second);
}
template <typename Func>
VlQueue<T_Value> min(Func with_func) const {
@ -1138,7 +1139,7 @@ public:
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
return VlQueue<T_Value>::consV(it->second);
}
VlQueue<T_Value> max() const {
if (m_map.empty()) return VlQueue<T_Value>();
@ -1147,7 +1148,7 @@ public:
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return a.second < b.second;
});
return VlQueue<T_Value>::cons(it->second);
return VlQueue<T_Value>::consV(it->second);
}
template <typename Func>
VlQueue<T_Value> max(Func with_func) const {
@ -1157,7 +1158,7 @@ public:
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
return with_func(a.first, a.second) < with_func(b.first, b.second);
});
return VlQueue<T_Value>::cons(it->second);
return VlQueue<T_Value>::consV(it->second);
}
T_Value r_sum() const {
@ -1438,7 +1439,7 @@ public:
// Can't use std::find_if as need index number
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) return VlQueue<T_Value>::cons(i);
if (with_func(index, i)) return VlQueue<T_Value>::consV(i);
++index;
}
return VlQueue<T_Value>{};
@ -1447,7 +1448,7 @@ public:
VlQueue<T_Key> find_first_index(Func with_func) const {
IData index = 0;
for (const auto& i : m_storage) {
if (with_func(index, i)) return VlQueue<IData>::cons(index);
if (with_func(index, i)) return VlQueue<IData>::consV(index);
++index;
}
return VlQueue<T_Key>{};
@ -1455,14 +1456,14 @@ public:
template <typename Func>
VlQueue<T_Value> find_last(Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::cons(m_storage[i]);
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::consV(m_storage[i]);
}
return VlQueue<T_Value>{};
}
template <typename Func>
VlQueue<T_Key> find_last_index(Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<IData>::cons(i);
if (with_func(i, m_storage[i])) return VlQueue<IData>::consV(i);
}
return VlQueue<T_Key>{};
}
@ -1470,7 +1471,7 @@ public:
// Reduction operators
VlQueue<T_Value> min() const {
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::cons(*it);
return VlQueue<T_Value>::consV(*it);
}
template <typename Func>
VlQueue<T_Value> min(Func with_func) const {
@ -1478,11 +1479,11 @@ public:
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue<T_Value>::cons(*it);
return VlQueue<T_Value>::consV(*it);
}
VlQueue<T_Value> max() const {
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::cons(*it);
return VlQueue<T_Value>::consV(*it);
}
template <typename Func>
VlQueue<T_Value> max(Func with_func) const {
@ -1490,7 +1491,7 @@ public:
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue<T_Value>::cons(*it);
return VlQueue<T_Value>::consV(*it);
}
// Dumping. Verilog: str = $sformatf("%p", assoc)

View File

@ -1585,7 +1585,7 @@ VCastable AstNode::computeCastable(const AstNodeDType* toDtp, const AstNodeDType
const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp);
UINFO(9, " castable=" << castable << " for " << toDtp << endl);
UINFO(9, " =?= " << fromDtp << endl);
UINFO(9, " const= " << fromConstp << endl);
if (fromConstp) UINFO(9, " const= " << fromConstp << endl);
return castable;
}

View File

@ -1537,6 +1537,7 @@ public:
"ENUM_IMPLICIT", "DYNAMIC_CLASS", "INCOMPATIBLE"};
return names[m_e];
}
bool isAssignable() const { return m_e != UNSUPPORTED && m_e != INCOMPATIBLE; }
VCastable()
: m_e{UNSUPPORTED} {}
// cppcheck-suppress noExplicitConstructor

View File

@ -810,19 +810,38 @@ class AstConsDynArray final : public AstNodeExpr {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// @astgen op1 := lhsp : Optional[AstNode]
// @astgen op2 := rhsp : Optional[AstNode]
const bool m_lhsIsValue = false; // LHS constructs value inside the queue, not concat
const bool m_rhsIsValue = false; // RHS constructs value inside the queue, not concat
public:
explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
: ASTGEN_SUPER_ConsDynArray(fl) {
explicit AstConsDynArray(FileLine* fl)
: ASTGEN_SUPER_ConsDynArray(fl) {}
explicit AstConsDynArray(FileLine* fl, bool lhsIsValue, AstNode* lhsp)
: ASTGEN_SUPER_ConsDynArray(fl)
, m_lhsIsValue(lhsIsValue) {
this->lhsp(lhsp);
}
explicit AstConsDynArray(FileLine* fl, bool lhsIsValue, AstNode* lhsp, bool rhsIsValue,
AstNode* rhsp)
: ASTGEN_SUPER_ConsDynArray(fl)
, m_lhsIsValue(lhsIsValue)
, m_rhsIsValue(rhsIsValue) {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstConsDynArray;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string emitVerilog() override { return "'{%l, %r}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
bool same(const AstNode* samep) const override {
const AstConsDynArray* const sp = VN_DBG_AS(samep, ConsDynArray);
return m_lhsIsValue == sp->m_lhsIsValue && m_rhsIsValue == sp->m_rhsIsValue;
}
bool lhsIsValue() const { return m_lhsIsValue; }
bool rhsIsValue() const { return m_rhsIsValue; }
};
class AstConsPackMember final : public AstNodeExpr {
// Construct a packed array single emement [member1: value1]
@ -873,19 +892,38 @@ class AstConsQueue final : public AstNodeExpr {
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
// @astgen op1 := lhsp : Optional[AstNode]
// @astgen op2 := rhsp : Optional[AstNode]
const bool m_lhsIsValue = false; // LHS constructs value inside the queue, not concat
const bool m_rhsIsValue = false; // RHS constructs value inside the queue, not concat
public:
explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
: ASTGEN_SUPER_ConsQueue(fl) {
explicit AstConsQueue(FileLine* fl)
: ASTGEN_SUPER_ConsQueue(fl) {}
explicit AstConsQueue(FileLine* fl, bool lhsIsValue, AstNode* lhsp)
: ASTGEN_SUPER_ConsQueue(fl)
, m_lhsIsValue(lhsIsValue) {
this->lhsp(lhsp);
}
explicit AstConsQueue(FileLine* fl, bool lhsIsValue, AstNode* lhsp, bool rhsIsValue,
AstNode* rhsp)
: ASTGEN_SUPER_ConsQueue(fl)
, m_lhsIsValue(lhsIsValue)
, m_rhsIsValue(rhsIsValue) {
this->lhsp(lhsp);
this->rhsp(rhsp);
}
ASTGEN_MEMBERS_AstConsQueue;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
string emitVerilog() override { return "'{%l, %r}"; }
string emitC() override { V3ERROR_NA_RETURN(""); }
string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
bool cleanOut() const override { return true; }
int instrCount() const override { return widthInstrs(); }
bool same(const AstNode* /*samep*/) const override { return true; }
bool same(const AstNode* samep) const override {
const AstConsQueue* const sp = VN_DBG_AS(samep, ConsQueue);
return m_lhsIsValue == sp->m_lhsIsValue && m_rhsIsValue == sp->m_rhsIsValue;
}
bool lhsIsValue() const { return m_lhsIsValue; }
bool rhsIsValue() const { return m_rhsIsValue; }
};
class AstConsWildcard final : public AstNodeExpr {
// Construct a wildcard assoc array and return object, '{}

View File

@ -322,6 +322,28 @@ AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* l
return new AstLogAnd{fileline(), ap, bp};
}
void AstConsDynArray::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (lhsIsValue()) str << " [LVAL]";
if (rhsIsValue()) str << " [RVAL]";
}
void AstConsDynArray::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, lhsIsValue);
dumpJsonBoolFunc(str, rhsIsValue);
dumpJsonGen(str);
}
void AstConsQueue::dump(std::ostream& str) const {
this->AstNodeExpr::dump(str);
if (lhsIsValue()) str << " [LVAL]";
if (rhsIsValue()) str << " [RVAL]";
}
void AstConsQueue::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, lhsIsValue);
dumpJsonBoolFunc(str, rhsIsValue);
dumpJsonGen(str);
}
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
bool success = false;
if (literal[0] == '"') {

View File

@ -1420,9 +1420,12 @@ public:
void visit(AstConsDynArray* nodep) override {
putnbs(nodep, nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
putns(nodep, "()");
putns(nodep, "{}");
} else {
putns(nodep, "::cons(");
puts("::cons");
puts(nodep->lhsIsValue() ? "V" : "C");
if (nodep->rhsp()) puts(nodep->rhsIsValue() ? "V" : "C");
puts("(");
iterateAndNextConstNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");
@ -1451,9 +1454,12 @@ public:
void visit(AstConsQueue* nodep) override {
putnbs(nodep, nodep->dtypep()->cType("", false, false));
if (!nodep->lhsp()) {
puts("()");
puts("{}");
} else {
puts("::cons(");
puts("::cons");
puts(nodep->lhsIsValue() ? "V" : "C");
if (nodep->rhsp()) puts(nodep->rhsIsValue() ? "V" : "C");
puts("(");
iterateAndNextConstNull(nodep->lhsp());
if (nodep->rhsp()) {
puts(", ");

View File

@ -262,6 +262,16 @@ class SliceVisitor final : public VNVisitor {
m_okInitArray = true;
iterateChildren(nodep);
}
void visit(AstConsDynArray* nodep) override {
VL_RESTORER(m_okInitArray);
m_okInitArray = true;
iterateChildren(nodep);
}
void visit(AstConsQueue* nodep) override {
VL_RESTORER(m_okInitArray);
m_okInitArray = true;
iterateChildren(nodep);
}
void visit(AstInitArray* nodep) override {
UASSERT_OBJ(!m_assignp || m_okInitArray, nodep,
"Array initialization should have been removed earlier");

View File

@ -547,18 +547,37 @@ class WidthVisitor final : public VNVisitor {
AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp();
userIterate(vdtypep, WidthVP{SELF, BOTH}.p());
// Conversions
if (VN_IS(vdtypep, QueueDType)) {
if (const AstDynArrayDType* const adtypep = VN_CAST(vdtypep, DynArrayDType)) {
// IEEE 1800-2023 10.10 requires looking at argument data type
// to determine if value or push
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, PRELIM}.p());
userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, PRELIM}.p());
// Queue "element 0" is lhsp, so we need to swap arguments
auto* const newp = new AstConsQueue{nodep->fileline(), nodep->rhsp()->unlinkFrBack(),
nodep->lhsp()->unlinkFrBack()};
const bool lhsIsValue = AstNode::computeCastable(adtypep->subDTypep(),
nodep->lhsp()->dtypep(), nullptr).isAssignable();
const bool rhsIsValue = AstNode::computeCastable(adtypep->subDTypep(),
nodep->rhsp()->dtypep(), nullptr).isAssignable();
AstConsDynArray* const newp
= new AstConsDynArray{nodep->fileline(), rhsIsValue, nodep->rhsp()->unlinkFrBack(),
lhsIsValue, nodep->lhsp()->unlinkFrBack()};
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
userIterateChildren(newp, m_vup);
return;
}
if (VN_IS(vdtypep, DynArrayDType)) {
auto* const newp = new AstConsDynArray{
nodep->fileline(), nodep->rhsp()->unlinkFrBack(), nodep->lhsp()->unlinkFrBack()};
if (const AstQueueDType* const adtypep = VN_CAST(vdtypep, QueueDType)) {
// IEEE 1800-2023 10.10 requires looking at argument data type
// to determine if value or push
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, PRELIM}.p());
userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, PRELIM}.p());
// Queue "element 0" is lhsp, so we need to swap arguments
const bool lhsIsValue = AstNode::computeCastable(adtypep->subDTypep(),
nodep->lhsp()->dtypep(), nullptr).isAssignable();
const bool rhsIsValue = AstNode::computeCastable(adtypep->subDTypep(),
nodep->rhsp()->dtypep(), nullptr).isAssignable();
AstConsQueue* const newp
= new AstConsQueue{nodep->fileline(), rhsIsValue, nodep->rhsp()->unlinkFrBack(),
lhsIsValue, nodep->lhsp()->unlinkFrBack()};
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
userIterateChildren(newp, m_vup);
@ -2498,29 +2517,31 @@ class WidthVisitor final : public VNVisitor {
AstDynArrayDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), DynArrayDType);
UASSERT_OBJ(vdtypep, nodep, "ConsDynArray requires queue upper parent data type");
if (m_vup->prelim()) {
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, PRELIM}.p());
userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, PRELIM}.p());
if (nodep->didWidthAndSet()) return;
AstNodeDType* const lhsDtp = nodep->lhsIsValue() ? vdtypep->subDTypep() : vdtypep;
AstNodeDType* const rhsDtp = nodep->rhsIsValue() ? vdtypep->subDTypep() : vdtypep;
userIterateAndNext(nodep->lhsp(), WidthVP{lhsDtp, PRELIM}.p());
userIterateAndNext(nodep->rhsp(), WidthVP{rhsDtp, PRELIM}.p());
nodep->dtypeFrom(vdtypep);
}
if (m_vup->final()) {
if (nodep->didWidthAndSet()) return;
// Arguments can be either elements of the queue or a queue itself
// Concats (part of tree of concats) must always become ConsDynArray's
AstNodeDType* const lhsDtp = nodep->lhsIsValue() ? vdtypep->subDTypep() : vdtypep;
AstNodeDType* const rhsDtp = nodep->rhsIsValue() ? vdtypep->subDTypep() : vdtypep;
if (nodep->lhsp()) {
if (VN_IS(nodep->lhsp()->dtypep(), DynArrayDType)
|| VN_IS(nodep->lhsp(), ConsDynArray)) {
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, FINAL}.p());
} else {
if (nodep->lhsIsValue()) {
// Sub elements are not queues, but concats, must always pass concats down
iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL);
iterateCheckTyped(nodep, "LHS", nodep->lhsp(), lhsDtp, FINAL);
} else {
userIterateAndNext(nodep->lhsp(), WidthVP{lhsDtp, FINAL}.p());
}
}
if (nodep->rhsp()) {
if (VN_IS(nodep->rhsp()->dtypep(), DynArrayDType)
|| VN_IS(nodep->rhsp(), ConsDynArray)) {
userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, FINAL}.p());
if (nodep->rhsIsValue()) {
iterateCheckTyped(nodep, "RHS", nodep->rhsp(), rhsDtp, FINAL);
} else {
iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL);
userIterateAndNext(nodep->rhsp(), WidthVP{rhsDtp, FINAL}.p());
}
}
if (nodep->didWidthAndSet()) return;
@ -2532,28 +2553,31 @@ class WidthVisitor final : public VNVisitor {
AstQueueDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), QueueDType);
UASSERT_OBJ(vdtypep, nodep, "ConsQueue requires queue upper parent data type");
if (m_vup->prelim()) {
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, PRELIM}.p());
userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, PRELIM}.p());
AstNodeDType* const lhsDtp = nodep->lhsIsValue() ? vdtypep->subDTypep() : vdtypep;
AstNodeDType* const rhsDtp = nodep->rhsIsValue() ? vdtypep->subDTypep() : vdtypep;
userIterateAndNext(nodep->lhsp(), WidthVP{lhsDtp, PRELIM}.p());
userIterateAndNext(nodep->rhsp(), WidthVP{rhsDtp, PRELIM}.p());
nodep->dtypeFrom(vdtypep);
}
if (m_vup->final()) {
if (nodep->didWidthAndSet()) return;
// Arguments can be either elements of the queue or a queue itself
// Concats (part of tree of concats) must always become ConsQueue's
AstNodeDType* const lhsDtp = nodep->lhsIsValue() ? vdtypep->subDTypep() : vdtypep;
AstNodeDType* const rhsDtp = nodep->rhsIsValue() ? vdtypep->subDTypep() : vdtypep;
if (nodep->lhsp()) {
if (VN_IS(nodep->lhsp()->dtypep(), QueueDType)
|| VN_IS(nodep->lhsp(), ConsQueue)) {
userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, FINAL}.p());
} else {
if (nodep->lhsIsValue()) {
// Sub elements are not queues, but concats, must always pass concats down
iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL);
iterateCheckTyped(nodep, "LHS", nodep->lhsp(), lhsDtp, FINAL);
} else {
userIterateAndNext(nodep->lhsp(), WidthVP{lhsDtp, FINAL}.p());
}
}
if (nodep->rhsp()) {
if (VN_IS(nodep->rhsp()->dtypep(), QueueDType)
|| VN_IS(nodep->rhsp(), ConsQueue)) {
userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, FINAL}.p());
if (nodep->rhsIsValue()) {
iterateCheckTyped(nodep, "RHS", nodep->rhsp(), rhsDtp, FINAL);
} else {
iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL);
userIterateAndNext(nodep->rhsp(), WidthVP{rhsDtp, FINAL}.p());
}
}
nodep->dtypeFrom(vdtypep);
@ -2572,7 +2596,8 @@ class WidthVisitor final : public VNVisitor {
if (VN_IS(arrayp, NodeArrayDType) || VN_IS(arrayp, AssocArrayDType)) {
userIterateChildren(nodep, WidthVP{arrayp->subDTypep(), BOTH}.p());
} else {
UINFO(1, "dtype object " << vdtypep->skipRefp() << endl);
UINFO(1, "on " << nodep << endl);
UINFO(1, "dtype object " << arrayp << endl);
nodep->v3fatalSrc("InitArray on non-array");
}
}
@ -4503,7 +4528,8 @@ class WidthVisitor final : public VNVisitor {
patp = VN_AS(patp->nextp(), PatMember)) {
patp->dtypep(arrayp->subDTypep());
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
AstConsDynArray* const newap = new AstConsDynArray{nodep->fileline(), valuep, newp};
AstConsDynArray* const newap
= new AstConsDynArray{nodep->fileline(), true, valuep, false, newp};
newap->dtypeFrom(arrayp);
newp = newap;
}
@ -4518,7 +4544,8 @@ class WidthVisitor final : public VNVisitor {
patp = VN_AS(patp->nextp(), PatMember)) {
patp->dtypep(arrayp->subDTypep());
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
AstConsQueue* const newap = new AstConsQueue{nodep->fileline(), valuep, newp};
AstConsQueue* const newap
= new AstConsQueue{nodep->fileline(), true, valuep, false, newp};
newap->dtypeFrom(arrayp);
newp = newap;
}

View File

@ -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 2024 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,65 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`ifdef VERILATOR
`define stop $stop
`else
`define stop
`endif
`define checkp(gotv,expv_s) do begin string gotv_s; gotv_s = $sformatf("%p", gotv); if ((gotv_s) !== (expv_s)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv_s), (expv_s)); `stop; end end while(0);
module t(/*AUTOARG*/);
int da[][2] = '{};
int da2[][2] = '{'{1, 2}};
int dd[][] = '{};
int dd1[][] = '{'{1}};
int dd2[][] = '{'{1, 2}};
int dq[][$] = '{};
int dq1[][$] = '{'{1}};
int dq2[][$] = '{'{1, 2}};
int qa[$][2] = '{};
int qa2[$][2] = '{'{1, 2}};
int qd[$][] = '{};
int qd1[$][] = '{'{1}};
int qd2[$][] = '{'{1, 2}};
int qq[$][$] = '{};
int qq1[$][$] = '{'{1}};
int qq2[$][$] = '{'{1, 2}};
initial begin
`checkp(da, "'{}");
`checkp(da2, "'{'{'h1, 'h2} } ");
`checkp(dd, "'{}");
`checkp(dd1, "'{'{'h1} } ");
`checkp(dd2, "'{'{'h1, 'h2} } ");
`checkp(dq, "'{}");
`checkp(dq1, "'{'{'h1} } ");
`checkp(dq2, "'{'{'h1, 'h2} } ");
`checkp(qa, "'{}");
`checkp(qa2, "'{'{'h1, 'h2} } ");
`checkp(qd, "'{}");
`checkp(qd1, "'{'{'h1} } ");
`checkp(qd2, "'{'{'h1, 'h2} } ");
`checkp(qq, "'{}");
`checkp(qq1, "'{'{'h1} } ");
`checkp(qq2, "'{'{'h1, 'h2} } ");
$write("*-* All Finished *-*\n");
$finish;
end
endmodule