mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 12:17:35 +00:00
Fix initializing static array in dynamic arrays and queues (#5287).
This commit is contained in:
parent
1e3c7a5496
commit
0419ed0430
1
Changes
1
Changes
@ -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.]
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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, '{}
|
||||
|
@ -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] == '"') {
|
||||
|
@ -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(", ");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
21
test_regress/t/t_dynarray_concat.pl
Executable file
21
test_regress/t/t_dynarray_concat.pl
Executable 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;
|
65
test_regress/t/t_dynarray_concat.v
Normal file
65
test_regress/t/t_dynarray_concat.v
Normal 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
|
Loading…
Reference in New Issue
Block a user