2012-04-13 03:08:20 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2010-01-19 16:52:11 +01:00
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Parse module/signal name references
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2010-01-19 16:52:11 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2024-01-01 09:19:59 +01:00
|
|
|
// Copyright 2003-2024 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
|
2010-01-19 16:52:11 +01: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
|
2010-01-19 16:52:11 +01:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// Slice TRANSFORMATIONS:
|
2019-05-19 22:13:13 +02:00
|
|
|
// Top-down traversal (SliceVisitor):
|
|
|
|
|
// NODEASSIGN
|
|
|
|
|
// ARRAYSEL
|
|
|
|
|
// Compare the dimensions to the Var to check for implicit slices.
|
|
|
|
|
// Using ->length() calculate the number of clones needed.
|
|
|
|
|
// VARREF
|
|
|
|
|
// Check the dimensions of the Var for an implicit slice.
|
|
|
|
|
// Replace with ArraySel nodes if needed.
|
|
|
|
|
// SEL, EXTEND
|
|
|
|
|
// We might be assigning a 1-D packed array to a 2-D packed array,
|
|
|
|
|
// this is unsupported.
|
|
|
|
|
// SliceCloneVisitor (called if this node is a slice):
|
|
|
|
|
// NODEASSIGN
|
|
|
|
|
// Clone and iterate the clone:
|
|
|
|
|
// ARRAYSEL
|
|
|
|
|
// Modify bitp() for the new value and set ->length(1)
|
2017-11-23 20:55:32 +01:00
|
|
|
//
|
|
|
|
|
// TODO: This code was written before SLICESEL was a type it might be
|
|
|
|
|
// simplified to look primarily for SLICESELs.
|
2010-01-19 16:52:11 +01:00
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2023-10-18 04:50:27 +02:00
|
|
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
|
|
|
|
|
2023-10-18 12:37:46 +02:00
|
|
|
#include "V3Slice.h"
|
|
|
|
|
|
2022-09-18 21:53:42 +02:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
2010-01-19 16:52:11 +01:00
|
|
|
//*************************************************************************
|
|
|
|
|
|
2022-01-02 19:56:40 +01:00
|
|
|
class SliceVisitor final : public VNVisitor {
|
2010-01-19 16:52:11 +01:00
|
|
|
// NODE STATE
|
|
|
|
|
// Cleared on netlist
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstNodeAssign::user1() -> bool. True if find is complete
|
2018-06-22 12:35:27 +02:00
|
|
|
// AstNodeUniop::user1() -> bool. True if find is complete
|
2019-05-19 22:13:13 +02:00
|
|
|
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
2022-01-02 19:56:40 +01:00
|
|
|
const VNUser1InUse m_inuser1;
|
2023-10-15 18:53:35 +02:00
|
|
|
// AstInitArray::user2() -> Previously accessed itemIdx
|
|
|
|
|
// AstInitItem::user2() -> Corresponding first elemIdx
|
|
|
|
|
const VNUser2InUse m_inuser2;
|
2010-04-10 03:05:46 +02:00
|
|
|
|
2010-01-19 16:52:11 +01:00
|
|
|
// STATE
|
2020-08-16 15:55:36 +02:00
|
|
|
AstNode* m_assignp = nullptr; // Assignment we are under
|
|
|
|
|
bool m_assignError = false; // True if the current assign already has an error
|
2023-02-13 13:47:35 +01:00
|
|
|
bool m_okInitArray = false; // Allow InitArray children
|
2010-01-19 16:52:11 +01:00
|
|
|
|
|
|
|
|
// METHODS
|
2023-10-15 18:53:35 +02:00
|
|
|
|
|
|
|
|
AstNodeExpr* cloneAndSel(AstNode* nodep, int elements, int elemIdx) {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Insert an ArraySel, except for a few special cases
|
2021-11-13 19:50:44 +01:00
|
|
|
const AstUnpackArrayDType* const arrayp
|
|
|
|
|
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!arrayp) { // V3Width should have complained, but...
|
2018-03-10 22:32:04 +01:00
|
|
|
if (!m_assignError) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->v3error(
|
|
|
|
|
nodep->prettyTypeName()
|
|
|
|
|
<< " is not an unpacked array, but is in an unpacked array context");
|
2021-03-13 19:39:29 +01:00
|
|
|
} else {
|
|
|
|
|
V3Error::incErrors(); // Otherwise might infinite loop
|
2018-03-10 22:32:04 +01:00
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignError = true;
|
2022-11-13 21:33:11 +01:00
|
|
|
// Likely will cause downstream errors
|
|
|
|
|
return VN_AS(nodep, NodeExpr)->cloneTree(false);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
if (arrayp->rangep()->elementsConst() != elements) {
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!m_assignError) {
|
|
|
|
|
nodep->v3error(
|
|
|
|
|
"Slices of arrays in assignments have different unpacked dimensions, "
|
|
|
|
|
<< elements << " versus " << arrayp->rangep()->elementsConst());
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignError = true;
|
2020-04-15 13:58:34 +02:00
|
|
|
elements = 1;
|
2023-10-15 18:53:35 +02:00
|
|
|
elemIdx = 0;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2022-11-13 21:33:11 +01:00
|
|
|
AstNodeExpr* newp;
|
2023-10-15 18:53:35 +02:00
|
|
|
if (AstInitArray* const initp = VN_CAST(nodep, InitArray)) {
|
|
|
|
|
UINFO(9, " cloneInitArray(" << elements << "," << elemIdx << ") " << nodep << endl);
|
|
|
|
|
|
|
|
|
|
auto considerOrder = [](const auto* nodep, int idxFromLeft) -> int {
|
|
|
|
|
return !nodep->rangep()->ascending()
|
|
|
|
|
? nodep->rangep()->elementsConst() - 1 - idxFromLeft
|
|
|
|
|
: idxFromLeft;
|
|
|
|
|
};
|
|
|
|
|
newp = nullptr;
|
|
|
|
|
int itemIdx = 0;
|
|
|
|
|
int i = 0;
|
|
|
|
|
if (const int prevItemIdx = initp->user2()) {
|
|
|
|
|
const AstInitArray::KeyItemMap& itemMap = initp->map();
|
|
|
|
|
const auto it = itemMap.find(considerOrder(arrayp, prevItemIdx));
|
|
|
|
|
if (it != itemMap.end()) {
|
|
|
|
|
const AstInitItem* itemp = it->second;
|
|
|
|
|
if (itemp->user2() && itemp->user2() < elemIdx) {
|
|
|
|
|
// Let's resume traversal from the previous position
|
|
|
|
|
itemIdx = prevItemIdx;
|
|
|
|
|
i = itemp->user2();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const AstNodeDType* const expectedItemDTypep = arrayp->subDTypep()->skipRefp();
|
|
|
|
|
while (i <= elemIdx) {
|
|
|
|
|
AstNodeExpr* const itemp
|
|
|
|
|
= initp->getIndexDefaultedValuep(considerOrder(arrayp, itemIdx));
|
|
|
|
|
if (!itemp && !m_assignError) {
|
|
|
|
|
nodep->v3error("Array initialization has too few elements, need element "
|
|
|
|
|
<< elemIdx);
|
|
|
|
|
m_assignError = true;
|
|
|
|
|
}
|
|
|
|
|
const AstNodeDType* itemRawDTypep = itemp->dtypep()->skipRefp();
|
|
|
|
|
const VCastable castable
|
|
|
|
|
= AstNode::computeCastable(expectedItemDTypep, itemRawDTypep, itemp);
|
|
|
|
|
if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) {
|
|
|
|
|
if (i == elemIdx) {
|
|
|
|
|
newp = itemp->cloneTreePure(false);
|
|
|
|
|
break;
|
|
|
|
|
} else { // Check the next item
|
|
|
|
|
++i;
|
|
|
|
|
++itemIdx;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const AstUnpackArrayDType* const itemDTypep
|
|
|
|
|
= VN_CAST(itemRawDTypep, UnpackArrayDType);
|
|
|
|
|
if (!itemDTypep
|
2023-10-18 23:36:09 +02:00
|
|
|
|| !expectedItemDTypep->isSame(itemDTypep->subDTypep()->skipRefp())) {
|
2023-10-15 18:53:35 +02:00
|
|
|
if (!m_assignError) {
|
|
|
|
|
itemp->v3error("Item is incompatible with the array type.");
|
|
|
|
|
}
|
|
|
|
|
m_assignError = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (i + itemDTypep->elementsConst()
|
|
|
|
|
> elemIdx) { // This item contains the element
|
|
|
|
|
int offset = considerOrder(itemDTypep, elemIdx - i);
|
|
|
|
|
if (AstSliceSel* const slicep = VN_CAST(itemp, SliceSel)) {
|
|
|
|
|
offset += slicep->declRange().lo();
|
|
|
|
|
newp = new AstArraySel{nodep->fileline(),
|
2023-11-12 19:30:48 +01:00
|
|
|
slicep->fromp()->cloneTreePure(false), offset};
|
2023-10-15 18:53:35 +02:00
|
|
|
} else {
|
|
|
|
|
newp = new AstArraySel{nodep->fileline(), itemp->cloneTreePure(false),
|
|
|
|
|
offset};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_assignError && elemIdx + 1 == elements
|
|
|
|
|
&& i + itemDTypep->elementsConst() > elements) {
|
|
|
|
|
nodep->v3error("Array initialization has too many elements. "
|
|
|
|
|
<< elements << " elements are expected, but at least "
|
|
|
|
|
<< i + itemDTypep->elementsConst()
|
|
|
|
|
<< " elements exist.");
|
|
|
|
|
m_assignError = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
} else { // Check the next item
|
|
|
|
|
i += itemDTypep->elementsConst();
|
|
|
|
|
++itemIdx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (elemIdx + 1 == elements && static_cast<size_t>(itemIdx) + 1 < initp->map().size()
|
|
|
|
|
&& !m_assignError) {
|
|
|
|
|
nodep->v3error("Array initialization has too many elements. "
|
|
|
|
|
<< elements << " elements are expected, but at least "
|
|
|
|
|
<< i + initp->map().size() - itemIdx << " elements exist.");
|
|
|
|
|
m_assignError = true;
|
|
|
|
|
}
|
|
|
|
|
if (newp) {
|
|
|
|
|
const AstInitArray::KeyItemMap& itemMap = initp->map();
|
|
|
|
|
const auto it = itemMap.find(considerOrder(arrayp, itemIdx));
|
|
|
|
|
if (it != itemMap.end()) { // Remember current position for the next invocation.
|
|
|
|
|
initp->user2(itemIdx);
|
|
|
|
|
it->second->user2(i);
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2023-10-15 18:53:35 +02:00
|
|
|
if (!newp) newp = new AstConst{nodep->fileline(), 0};
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) {
|
2023-10-15 18:53:35 +02:00
|
|
|
UINFO(9, " cloneCond(" << elements << "," << elemIdx << ") " << nodep << endl);
|
2023-09-17 04:50:54 +02:00
|
|
|
return snodep->cloneType(snodep->condp()->cloneTreePure(false),
|
2023-10-15 18:53:35 +02:00
|
|
|
cloneAndSel(snodep->thenp(), elements, elemIdx),
|
|
|
|
|
cloneAndSel(snodep->elsep(), elements, elemIdx));
|
2021-11-26 23:55:36 +01:00
|
|
|
} else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) {
|
2023-10-15 18:53:35 +02:00
|
|
|
UINFO(9, " cloneSliceSel(" << elements << "," << elemIdx << ") " << nodep << endl);
|
2021-06-21 00:32:57 +02:00
|
|
|
const int leOffset = (snodep->declRange().lo()
|
2023-03-21 01:44:11 +01:00
|
|
|
+ (!snodep->declRange().ascending()
|
2023-10-15 18:53:35 +02:00
|
|
|
? snodep->declRange().elements() - 1 - elemIdx
|
|
|
|
|
: elemIdx));
|
2023-09-17 04:50:54 +02:00
|
|
|
newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTreePure(false),
|
|
|
|
|
leOffset};
|
2020-12-13 01:19:16 +01:00
|
|
|
} else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel)
|
2023-05-27 18:43:40 +02:00
|
|
|
|| VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel)
|
2024-06-12 18:07:33 +02:00
|
|
|
|| VN_IS(nodep, ExprStmt) || VN_IS(nodep, StructSel)) {
|
2023-10-15 18:53:35 +02:00
|
|
|
UINFO(9, " cloneSel(" << elements << "," << elemIdx << ") " << nodep << endl);
|
2023-03-21 01:44:11 +01:00
|
|
|
const int leOffset = !arrayp->rangep()->ascending()
|
2023-10-15 18:53:35 +02:00
|
|
|
? arrayp->rangep()->elementsConst() - 1 - elemIdx
|
|
|
|
|
: elemIdx;
|
2023-09-17 04:50:54 +02:00
|
|
|
newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTreePure(false),
|
2022-11-13 21:33:11 +01:00
|
|
|
leOffset};
|
2020-04-15 13:58:34 +02:00
|
|
|
} else {
|
|
|
|
|
if (!m_assignError) {
|
|
|
|
|
nodep->v3error(nodep->prettyTypeName()
|
|
|
|
|
<< " unexpected in assignment to unpacked array");
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignError = true;
|
2022-11-13 21:33:11 +01:00
|
|
|
// Likely will cause downstream errors
|
|
|
|
|
newp = VN_AS(nodep, NodeExpr)->cloneTree(false);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
return newp;
|
2010-01-19 16:52:11 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNodeAssign* nodep) override {
|
2019-05-19 22:13:13 +02:00
|
|
|
// Called recursively on newly created assignments
|
2020-04-15 13:58:34 +02:00
|
|
|
if (!nodep->user1() && !VN_IS(nodep, AssignAlias)) {
|
2019-05-19 22:13:13 +02:00
|
|
|
nodep->user1(true);
|
|
|
|
|
m_assignError = false;
|
2022-11-27 14:31:22 +01:00
|
|
|
if (debug() >= 9) nodep->dumpTree("- Deslice-In: ");
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const dtp = nodep->lhsp()->dtypep()->skipRefp();
|
2024-03-21 23:26:42 +01:00
|
|
|
AstNode* stp = nodep->rhsp();
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstUnpackArrayDType* const arrayp = VN_CAST(dtp, UnpackArrayDType)) {
|
2024-03-21 23:26:42 +01:00
|
|
|
if (!VN_IS(stp, CvtPackedToUnpackArray)) {
|
|
|
|
|
// Left and right could have different ascending/descending range,
|
|
|
|
|
// but #elements is common and all variables are realigned to start at zero
|
|
|
|
|
// Assign of an ascending range slice to a descending range one must reverse
|
|
|
|
|
// the elements
|
|
|
|
|
AstNodeAssign* newlistp = nullptr;
|
|
|
|
|
const int elements = arrayp->rangep()->elementsConst();
|
|
|
|
|
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
|
|
|
|
|
AstNodeAssign* const newp
|
|
|
|
|
= nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx),
|
|
|
|
|
cloneAndSel(nodep->rhsp(), elements, elemIdx));
|
|
|
|
|
if (debug() >= 9) newp->dumpTree("- new: ");
|
|
|
|
|
newlistp = AstNode::addNext(newlistp, newp);
|
|
|
|
|
}
|
|
|
|
|
if (debug() >= 9) nodep->dumpTree("- Deslice-Dn: ");
|
|
|
|
|
nodep->replaceWith(newlistp);
|
|
|
|
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
|
|
|
|
// Normal edit iterator will now iterate on all of the expansion assignments
|
|
|
|
|
// This will potentially call this function again to resolve next level of
|
|
|
|
|
// slicing
|
|
|
|
|
return;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-19 21:23:37 +01:00
|
|
|
VL_RESTORER(m_assignp);
|
2019-05-19 22:13:13 +02:00
|
|
|
m_assignp = nodep;
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2010-01-19 16:52:11 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-13 13:47:35 +01:00
|
|
|
void visit(AstConsPackUOrStruct* nodep) override {
|
|
|
|
|
VL_RESTORER(m_okInitArray);
|
|
|
|
|
m_okInitArray = true;
|
|
|
|
|
iterateChildren(nodep);
|
|
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstInitArray* nodep) override {
|
2023-02-13 13:47:35 +01:00
|
|
|
UASSERT_OBJ(!m_assignp || m_okInitArray, nodep,
|
|
|
|
|
"Array initialization should have been removed earlier");
|
2010-04-10 03:05:46 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-23 22:58:30 +02:00
|
|
|
void expandBiOp(AstNodeBiop* nodep) {
|
2019-05-19 22:13:13 +02:00
|
|
|
if (!nodep->user1()) {
|
|
|
|
|
nodep->user1(true);
|
|
|
|
|
// If it's an unpacked array, blow it up into comparing each element
|
2021-11-13 19:50:44 +01:00
|
|
|
AstNodeDType* const fromDtp = nodep->lhsp()->dtypep()->skipRefp();
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(9, " Bi-Eq/Neq expansion " << nodep << endl);
|
2021-11-13 19:50:44 +01:00
|
|
|
if (const AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
|
2020-08-15 16:12:55 +02:00
|
|
|
AstNodeBiop* logp = nullptr;
|
2019-11-05 03:51:20 +01:00
|
|
|
if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
2020-04-15 13:58:34 +02:00
|
|
|
nodep->lhsp()->v3error(
|
|
|
|
|
"Slice operator "
|
|
|
|
|
<< nodep->lhsp()->prettyTypeName()
|
|
|
|
|
<< " on non-slicable (e.g. non-vector) left-hand-side operand");
|
|
|
|
|
} else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
|
|
|
|
nodep->rhsp()->v3error(
|
|
|
|
|
"Slice operator "
|
|
|
|
|
<< nodep->rhsp()->prettyTypeName()
|
|
|
|
|
<< " on non-slicable (e.g. non-vector) right-hand-side operand");
|
|
|
|
|
} else {
|
2022-11-12 00:01:30 +01:00
|
|
|
const int elements = adtypep->rangep()->elementsConst();
|
2023-10-15 18:53:35 +02:00
|
|
|
for (int elemIdx = 0; elemIdx < elements; ++elemIdx) {
|
2019-11-05 03:51:20 +01:00
|
|
|
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
|
2023-10-15 18:53:35 +02:00
|
|
|
AstNodeBiop* const clonep = VN_AS(
|
|
|
|
|
nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, elemIdx),
|
|
|
|
|
cloneAndSel(nodep->rhsp(), elements, elemIdx)),
|
|
|
|
|
NodeBiop);
|
2020-08-16 20:55:46 +02:00
|
|
|
if (!logp) {
|
2020-04-15 13:58:34 +02:00
|
|
|
logp = clonep;
|
2020-08-16 20:55:46 +02:00
|
|
|
} else {
|
2019-11-05 03:51:20 +01:00
|
|
|
switch (nodep->type()) {
|
2022-01-02 19:56:40 +01:00
|
|
|
case VNType::atEq: // FALLTHRU
|
|
|
|
|
case VNType::atEqCase:
|
2022-11-11 04:58:27 +01:00
|
|
|
logp = new AstLogAnd{nodep->fileline(), logp, clonep};
|
2019-11-05 03:51:20 +01:00
|
|
|
break;
|
2022-01-02 19:56:40 +01:00
|
|
|
case VNType::atNeq: // FALLTHRU
|
|
|
|
|
case VNType::atNeqCase:
|
2022-11-11 04:58:27 +01:00
|
|
|
logp = new AstLogOr{nodep->fileline(), logp, clonep};
|
2019-11-05 03:51:20 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
nodep->v3fatalSrc("Unknown node type processing array slice");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-11-05 03:51:20 +01:00
|
|
|
UASSERT_OBJ(logp, nodep, "Unpacked array with empty indices range");
|
|
|
|
|
nodep->replaceWith(logp);
|
2020-01-17 02:17:11 +01:00
|
|
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
2019-11-05 03:51:20 +01:00
|
|
|
nodep = logp;
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-05-11 02:55:37 +02:00
|
|
|
iterateChildren(nodep);
|
2019-05-19 22:13:13 +02:00
|
|
|
}
|
2016-07-23 22:58:30 +02:00
|
|
|
}
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstEq* nodep) override { expandBiOp(nodep); }
|
|
|
|
|
void visit(AstNeq* nodep) override { expandBiOp(nodep); }
|
|
|
|
|
void visit(AstEqCase* nodep) override { expandBiOp(nodep); }
|
|
|
|
|
void visit(AstNeqCase* nodep) override { expandBiOp(nodep); }
|
2016-07-23 22:58:30 +02:00
|
|
|
|
2022-09-16 12:22:11 +02:00
|
|
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
2010-01-19 16:52:11 +01:00
|
|
|
|
|
|
|
|
public:
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-16 15:55:36 +02:00
|
|
|
explicit SliceVisitor(AstNetlist* nodep) { iterate(nodep); }
|
2022-09-16 12:22:11 +02:00
|
|
|
~SliceVisitor() override = default;
|
2010-01-19 16:52:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Link class functions
|
|
|
|
|
|
2018-10-15 00:39:33 +02:00
|
|
|
void V3Slice::sliceAll(AstNetlist* nodep) {
|
2020-04-15 13:58:34 +02:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2021-11-26 16:52:36 +01:00
|
|
|
{ SliceVisitor{nodep}; } // Destruct before checking
|
2024-01-09 16:35:13 +01:00
|
|
|
V3Global::dumpCheckGlobalTree("slice", 0, dumpTreeEitherLevel() >= 3);
|
2010-01-19 16:52:11 +01:00
|
|
|
}
|