Internals: Rename some non-nodes to avoid Ast prefix. No functional change.
This commit is contained in:
parent
340efe3a3a
commit
b7ad1e6d61
|
|
@ -441,12 +441,12 @@ void AstNode::addOp4p(AstNode* newp) {
|
||||||
void AstNode::replaceWith(AstNode* newp) {
|
void AstNode::replaceWith(AstNode* newp) {
|
||||||
// Replace oldp with this
|
// Replace oldp with this
|
||||||
// Unlike a unlink/relink, children are changed to point to the new node.
|
// Unlike a unlink/relink, children are changed to point to the new node.
|
||||||
AstNRelinker repHandle;
|
VNRelinker repHandle;
|
||||||
this->unlinkFrBack(&repHandle);
|
this->unlinkFrBack(&repHandle);
|
||||||
repHandle.relink(newp);
|
repHandle.relink(newp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNRelinker::dump(std::ostream& str) const {
|
void VNRelinker::dump(std::ostream& str) const {
|
||||||
str << " BK=" << reinterpret_cast<uint32_t*>(m_backp);
|
str << " BK=" << reinterpret_cast<uint32_t*>(m_backp);
|
||||||
str << " ITER=" << reinterpret_cast<uint32_t*>(m_iterpp);
|
str << " ITER=" << reinterpret_cast<uint32_t*>(m_iterpp);
|
||||||
str << " CHG=" << (m_chg == RELINK_NEXT ? "[NEXT] " : "");
|
str << " CHG=" << (m_chg == RELINK_NEXT ? "[NEXT] " : "");
|
||||||
|
|
@ -456,7 +456,7 @@ void AstNRelinker::dump(std::ostream& str) const {
|
||||||
str << (m_chg == RELINK_OP4 ? "[OP4] " : "");
|
str << (m_chg == RELINK_OP4 ? "[OP4] " : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
AstNode* AstNode::unlinkFrBackWithNext(VNRelinker* linkerp) {
|
||||||
debugTreeChange(this, "-unlinkWNextThs: ", __LINE__, true);
|
debugTreeChange(this, "-unlinkWNextThs: ", __LINE__, true);
|
||||||
AstNode* const oldp = this;
|
AstNode* const oldp = this;
|
||||||
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
|
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
|
||||||
|
|
@ -467,15 +467,15 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
||||||
linkerp->m_backp = backp;
|
linkerp->m_backp = backp;
|
||||||
linkerp->m_iterpp = oldp->m_iterpp;
|
linkerp->m_iterpp = oldp->m_iterpp;
|
||||||
if (backp->m_nextp == oldp) {
|
if (backp->m_nextp == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
linkerp->m_chg = VNRelinker::RELINK_NEXT;
|
||||||
} else if (backp->m_op1p == oldp) {
|
} else if (backp->m_op1p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
linkerp->m_chg = VNRelinker::RELINK_OP1;
|
||||||
} else if (backp->m_op2p == oldp) {
|
} else if (backp->m_op2p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
linkerp->m_chg = VNRelinker::RELINK_OP2;
|
||||||
} else if (backp->m_op3p == oldp) {
|
} else if (backp->m_op3p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
linkerp->m_chg = VNRelinker::RELINK_OP3;
|
||||||
} else if (backp->m_op4p == oldp) {
|
} else if (backp->m_op4p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
linkerp->m_chg = VNRelinker::RELINK_OP4;
|
||||||
} else {
|
} else {
|
||||||
oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
|
oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||||
}
|
}
|
||||||
|
|
@ -516,7 +516,7 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
||||||
return oldp;
|
return oldp;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) {
|
||||||
debugTreeChange(this, "-unlinkFrBkThs: ", __LINE__, true);
|
debugTreeChange(this, "-unlinkFrBkThs: ", __LINE__, true);
|
||||||
AstNode* const oldp = this;
|
AstNode* const oldp = this;
|
||||||
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
|
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
|
||||||
|
|
@ -527,15 +527,15 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
||||||
linkerp->m_backp = backp;
|
linkerp->m_backp = backp;
|
||||||
linkerp->m_iterpp = oldp->m_iterpp;
|
linkerp->m_iterpp = oldp->m_iterpp;
|
||||||
if (backp->m_nextp == oldp) {
|
if (backp->m_nextp == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
linkerp->m_chg = VNRelinker::RELINK_NEXT;
|
||||||
} else if (backp->m_op1p == oldp) {
|
} else if (backp->m_op1p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
linkerp->m_chg = VNRelinker::RELINK_OP1;
|
||||||
} else if (backp->m_op2p == oldp) {
|
} else if (backp->m_op2p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
linkerp->m_chg = VNRelinker::RELINK_OP2;
|
||||||
} else if (backp->m_op3p == oldp) {
|
} else if (backp->m_op3p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
linkerp->m_chg = VNRelinker::RELINK_OP3;
|
||||||
} else if (backp->m_op4p == oldp) {
|
} else if (backp->m_op4p == oldp) {
|
||||||
linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
linkerp->m_chg = VNRelinker::RELINK_OP4;
|
||||||
} else {
|
} else {
|
||||||
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||||
}
|
}
|
||||||
|
|
@ -580,7 +580,7 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
||||||
return oldp;
|
return oldp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::relink(AstNRelinker* linkerp) {
|
void AstNode::relink(VNRelinker* linkerp) {
|
||||||
if (debug() > 8) {
|
if (debug() > 8) {
|
||||||
UINFO(0, " EDIT: relink: ");
|
UINFO(0, " EDIT: relink: ");
|
||||||
dumpPtrs();
|
dumpPtrs();
|
||||||
|
|
@ -600,11 +600,11 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
||||||
debugTreeChange(backp, "-relinkTre: ", __LINE__, true);
|
debugTreeChange(backp, "-relinkTre: ", __LINE__, true);
|
||||||
|
|
||||||
switch (linkerp->m_chg) {
|
switch (linkerp->m_chg) {
|
||||||
case AstNRelinker::RELINK_NEXT: backp->addNextHere(newp); break;
|
case VNRelinker::RELINK_NEXT: backp->addNextHere(newp); break;
|
||||||
case AstNRelinker::RELINK_OP1: relinkOneLink(backp->m_op1p /*ref*/, newp); break;
|
case VNRelinker::RELINK_OP1: relinkOneLink(backp->m_op1p /*ref*/, newp); break;
|
||||||
case AstNRelinker::RELINK_OP2: relinkOneLink(backp->m_op2p /*ref*/, newp); break;
|
case VNRelinker::RELINK_OP2: relinkOneLink(backp->m_op2p /*ref*/, newp); break;
|
||||||
case AstNRelinker::RELINK_OP3: relinkOneLink(backp->m_op3p /*ref*/, newp); break;
|
case VNRelinker::RELINK_OP3: relinkOneLink(backp->m_op3p /*ref*/, newp); break;
|
||||||
case AstNRelinker::RELINK_OP4: relinkOneLink(backp->m_op4p /*ref*/, newp); break;
|
case VNRelinker::RELINK_OP4: relinkOneLink(backp->m_op4p /*ref*/, newp); break;
|
||||||
default: this->v3fatalSrc("Relink of node without any link to change."); break;
|
default: this->v3fatalSrc("Relink of node without any link to change."); break;
|
||||||
}
|
}
|
||||||
// Relink
|
// Relink
|
||||||
|
|
@ -654,15 +654,15 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
|
||||||
|
|
||||||
void AstNode::addHereThisAsNext(AstNode* newp) {
|
void AstNode::addHereThisAsNext(AstNode* newp) {
|
||||||
// {old}->this->{next} becomes {old}->new->this->{next}
|
// {old}->this->{next} becomes {old}->new->this->{next}
|
||||||
AstNRelinker handle;
|
VNRelinker handle;
|
||||||
this->unlinkFrBackWithNext(&handle);
|
this->unlinkFrBackWithNext(&handle);
|
||||||
newp->addNext(this);
|
newp->addNext(this);
|
||||||
handle.relink(newp);
|
handle.relink(newp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::swapWith(AstNode* bp) {
|
void AstNode::swapWith(AstNode* bp) {
|
||||||
AstNRelinker aHandle;
|
VNRelinker aHandle;
|
||||||
AstNRelinker bHandle;
|
VNRelinker bHandle;
|
||||||
this->unlinkFrBack(&aHandle);
|
this->unlinkFrBack(&aHandle);
|
||||||
bp->unlinkFrBack(&bHandle);
|
bp->unlinkFrBack(&bHandle);
|
||||||
aHandle.relink(bp);
|
aHandle.relink(bp);
|
||||||
|
|
@ -1279,9 +1279,9 @@ AstNodeDType* AstNode::findVoidDType() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// AstNDeleter
|
// VNDeleter
|
||||||
|
|
||||||
void AstNDeleter::doDeletes() {
|
void VNDeleter::doDeletes() {
|
||||||
for (AstNode* const nodep : m_deleteps) nodep->deleteTree();
|
for (AstNode* const nodep : m_deleteps) nodep->deleteTree();
|
||||||
m_deleteps.clear();
|
m_deleteps.clear();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
src/V3Ast.h
34
src/V3Ast.h
|
|
@ -1157,7 +1157,7 @@ public:
|
||||||
// user2. When the member goes out of scope it will be automagically
|
// user2. When the member goes out of scope it will be automagically
|
||||||
// freed up.
|
// freed up.
|
||||||
|
|
||||||
class AstUserInUseBase VL_NOT_FINAL {
|
class VNUserInUseBase VL_NOT_FINAL {
|
||||||
protected:
|
protected:
|
||||||
static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) {
|
static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) {
|
||||||
// Perhaps there's still a AstUserInUse in scope for this?
|
// Perhaps there's still a AstUserInUse in scope for this?
|
||||||
|
|
@ -1188,7 +1188,7 @@ protected:
|
||||||
// We let AstNode peek into here, because when under low optimization even
|
// We let AstNode peek into here, because when under low optimization even
|
||||||
// an accessor would be way too slow.
|
// an accessor would be way too slow.
|
||||||
// clang-format off
|
// clang-format off
|
||||||
class AstUser1InUse final : AstUserInUseBase {
|
class AstUser1InUse final : VNUserInUseBase {
|
||||||
protected:
|
protected:
|
||||||
friend class AstNode;
|
friend class AstNode;
|
||||||
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
||||||
|
|
@ -1199,7 +1199,7 @@ public:
|
||||||
static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
};
|
};
|
||||||
class AstUser2InUse final : AstUserInUseBase {
|
class AstUser2InUse final : VNUserInUseBase {
|
||||||
protected:
|
protected:
|
||||||
friend class AstNode;
|
friend class AstNode;
|
||||||
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
||||||
|
|
@ -1210,7 +1210,7 @@ public:
|
||||||
static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
};
|
};
|
||||||
class AstUser3InUse final : AstUserInUseBase {
|
class AstUser3InUse final : VNUserInUseBase {
|
||||||
protected:
|
protected:
|
||||||
friend class AstNode;
|
friend class AstNode;
|
||||||
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
||||||
|
|
@ -1221,7 +1221,7 @@ public:
|
||||||
static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
};
|
};
|
||||||
class AstUser4InUse final : AstUserInUseBase {
|
class AstUser4InUse final : VNUserInUseBase {
|
||||||
protected:
|
protected:
|
||||||
friend class AstNode;
|
friend class AstNode;
|
||||||
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
||||||
|
|
@ -1232,7 +1232,7 @@ public:
|
||||||
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||||
};
|
};
|
||||||
class AstUser5InUse final : AstUserInUseBase {
|
class AstUser5InUse final : VNUserInUseBase {
|
||||||
protected:
|
protected:
|
||||||
friend class AstNode;
|
friend class AstNode;
|
||||||
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
||||||
|
|
@ -1251,7 +1251,7 @@ public:
|
||||||
// nodes needs to be deferred to a later time, because pointers to the
|
// nodes needs to be deferred to a later time, because pointers to the
|
||||||
// removed nodes might still exist.
|
// removed nodes might still exist.
|
||||||
|
|
||||||
class AstNDeleter VL_NOT_FINAL {
|
class VNDeleter VL_NOT_FINAL {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
std::vector<AstNode*> m_deleteps; // Nodes to delete
|
std::vector<AstNode*> m_deleteps; // Nodes to delete
|
||||||
|
|
||||||
|
|
@ -1268,14 +1268,14 @@ public:
|
||||||
void doDeletes();
|
void doDeletes();
|
||||||
|
|
||||||
// Do the deletions on destruction
|
// Do the deletions on destruction
|
||||||
virtual ~AstNDeleter() { doDeletes(); }
|
virtual ~VNDeleter() { doDeletes(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// AstNVisitor -- Allows new functions to be called on each node
|
// AstNVisitor -- Allows new functions to be called on each node
|
||||||
// type without changing the base classes. See "Modern C++ Design".
|
// type without changing the base classes. See "Modern C++ Design".
|
||||||
|
|
||||||
class AstNVisitor VL_NOT_FINAL : public AstNDeleter {
|
class AstNVisitor VL_NOT_FINAL : public VNDeleter {
|
||||||
friend class AstNode;
|
friend class AstNode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -1303,10 +1303,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// AstNRelinker -- Holds the state of a unlink so a new node can be
|
// VNRelinker -- Holds the state of a unlink so a new node can be
|
||||||
// added at the same point.
|
// added at the same point.
|
||||||
|
|
||||||
class AstNRelinker final {
|
class VNRelinker final {
|
||||||
protected:
|
protected:
|
||||||
friend class AstNode;
|
friend class AstNode;
|
||||||
enum RelinkWhatEn : uint8_t {
|
enum RelinkWhatEn : uint8_t {
|
||||||
|
|
@ -1323,12 +1323,12 @@ protected:
|
||||||
AstNode** m_iterpp = nullptr;
|
AstNode** m_iterpp = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstNRelinker() = default;
|
VNRelinker() = default;
|
||||||
void relink(AstNode* newp);
|
void relink(AstNode* newp);
|
||||||
AstNode* oldp() const { return m_oldp; }
|
AstNode* oldp() const { return m_oldp; }
|
||||||
void dump(std::ostream& str = std::cout) const;
|
void dump(std::ostream& str = std::cout) const;
|
||||||
};
|
};
|
||||||
inline std::ostream& operator<<(std::ostream& os, const AstNRelinker& rhs) {
|
inline std::ostream& operator<<(std::ostream& os, const VNRelinker& rhs) {
|
||||||
rhs.dump(os);
|
rhs.dump(os);
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
@ -1771,12 +1771,12 @@ public:
|
||||||
}
|
}
|
||||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
||||||
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
||||||
AstNode* unlinkFrBack(AstNRelinker* linkerp
|
AstNode* unlinkFrBack(VNRelinker* linkerp
|
||||||
= nullptr); // Unlink this from whoever points to it.
|
= nullptr); // Unlink this from whoever points to it.
|
||||||
// Unlink this from whoever points to it, keep entire next list with unlinked node
|
// Unlink this from whoever points to it, keep entire next list with unlinked node
|
||||||
AstNode* unlinkFrBackWithNext(AstNRelinker* linkerp = nullptr);
|
AstNode* unlinkFrBackWithNext(VNRelinker* linkerp = nullptr);
|
||||||
void swapWith(AstNode* bp);
|
void swapWith(AstNode* bp);
|
||||||
void relink(AstNRelinker* linkerp); // Generally use linker->relink() instead
|
void relink(VNRelinker* linkerp); // Generally use linker->relink() instead
|
||||||
void cloneRelinkNode() { cloneRelink(); }
|
void cloneRelinkNode() { cloneRelink(); }
|
||||||
// Iterate and insert - assumes tree format
|
// Iterate and insert - assumes tree format
|
||||||
virtual void addNextStmt(AstNode* newp,
|
virtual void addNextStmt(AstNode* newp,
|
||||||
|
|
@ -1935,7 +1935,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
|
inline void VNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ private:
|
||||||
|
|
||||||
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
|
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
|
||||||
UINFO(4, " NeedCast " << nodep << endl);
|
UINFO(4, " NeedCast " << nodep << endl);
|
||||||
AstNRelinker relinkHandle;
|
VNRelinker relinkHandle;
|
||||||
nodep->unlinkFrBack(&relinkHandle);
|
nodep->unlinkFrBack(&relinkHandle);
|
||||||
//
|
//
|
||||||
AstCCast* const castp
|
AstCCast* const castp
|
||||||
|
|
@ -102,7 +102,7 @@ private:
|
||||||
void ensureNullChecked(AstNode* nodep) {
|
void ensureNullChecked(AstNode* nodep) {
|
||||||
// TODO optimize to track null checked values and avoid where possible
|
// TODO optimize to track null checked values and avoid where possible
|
||||||
if (!VN_IS(nodep->backp(), NullCheck)) {
|
if (!VN_IS(nodep->backp(), NullCheck)) {
|
||||||
AstNRelinker relinkHandle;
|
VNRelinker relinkHandle;
|
||||||
nodep->unlinkFrBack(&relinkHandle);
|
nodep->unlinkFrBack(&relinkHandle);
|
||||||
AstNode* const newp = new AstNullCheck{nodep->fileline(), nodep};
|
AstNode* const newp = new AstNullCheck{nodep->fileline(), nodep};
|
||||||
relinkHandle.relink(newp);
|
relinkHandle.relink(newp);
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ private:
|
||||||
// Operate on nodes
|
// Operate on nodes
|
||||||
void insertClean(AstNode* nodep) { // We'll insert ABOVE passed node
|
void insertClean(AstNode* nodep) { // We'll insert ABOVE passed node
|
||||||
UINFO(4, " NeedClean " << nodep << endl);
|
UINFO(4, " NeedClean " << nodep << endl);
|
||||||
AstNRelinker relinkHandle;
|
VNRelinker relinkHandle;
|
||||||
nodep->unlinkFrBack(&relinkHandle);
|
nodep->unlinkFrBack(&relinkHandle);
|
||||||
//
|
//
|
||||||
computeCppWidth(nodep);
|
computeCppWidth(nodep);
|
||||||
|
|
|
||||||
|
|
@ -1809,7 +1809,7 @@ private:
|
||||||
}
|
}
|
||||||
void replaceShiftOp(AstNodeBiop* nodep) {
|
void replaceShiftOp(AstNodeBiop* nodep) {
|
||||||
UINFO(5, "SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) " << nodep << endl);
|
UINFO(5, "SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) " << nodep << endl);
|
||||||
AstNRelinker handle;
|
VNRelinker handle;
|
||||||
nodep->unlinkFrBack(&handle);
|
nodep->unlinkFrBack(&handle);
|
||||||
AstNodeBiop* const lhsp = VN_AS(nodep->lhsp(), NodeBiop);
|
AstNodeBiop* const lhsp = VN_AS(nodep->lhsp(), NodeBiop);
|
||||||
lhsp->unlinkFrBack();
|
lhsp->unlinkFrBack();
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ private:
|
||||||
// Put assignment before the referencing statement
|
// Put assignment before the referencing statement
|
||||||
AstAssign* const assp = new AstAssign{
|
AstAssign* const assp = new AstAssign{
|
||||||
nodep->fileline(), new AstVarRef{nodep->fileline(), varp, VAccess::WRITE}, nodep};
|
nodep->fileline(), new AstVarRef{nodep->fileline(), varp, VAccess::WRITE}, nodep};
|
||||||
AstNRelinker linker2;
|
VNRelinker linker2;
|
||||||
m_stmtp->unlinkFrBack(&linker2);
|
m_stmtp->unlinkFrBack(&linker2);
|
||||||
assp->addNext(m_stmtp);
|
assp->addNext(m_stmtp);
|
||||||
linker2.relink(assp);
|
linker2.relink(assp);
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ private:
|
||||||
VL_DEBUG_FUNC; // Declare debug()
|
VL_DEBUG_FUNC; // Declare debug()
|
||||||
|
|
||||||
AstCFunc* createDeepFunc(AstNode* nodep) {
|
AstCFunc* createDeepFunc(AstNode* nodep) {
|
||||||
AstNRelinker relinkHandle;
|
VNRelinker relinkHandle;
|
||||||
nodep->unlinkFrBack(&relinkHandle);
|
nodep->unlinkFrBack(&relinkHandle);
|
||||||
// Create sub function
|
// Create sub function
|
||||||
AstScope* const scopep = m_cfuncp->scopep();
|
AstScope* const scopep = m_cfuncp->scopep();
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ private:
|
||||||
|
|
||||||
static void insertBefore(AstNode* placep, AstNode* newp) {
|
static void insertBefore(AstNode* placep, AstNode* newp) {
|
||||||
newp->user1(1); // Already processed, don't need to re-iterate
|
newp->user1(1); // Already processed, don't need to re-iterate
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
placep->unlinkFrBack(&linker);
|
placep->unlinkFrBack(&linker);
|
||||||
newp->addNext(placep);
|
newp->addNext(placep);
|
||||||
linker.relink(newp);
|
linker.relink(newp);
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ private:
|
||||||
AstJumpLabel* const labelp = new AstJumpLabel(nodep->fileline(), blockp);
|
AstJumpLabel* const labelp = new AstJumpLabel(nodep->fileline(), blockp);
|
||||||
blockp->labelp(labelp);
|
blockp->labelp(labelp);
|
||||||
|
|
||||||
AstNRelinker repHandle;
|
VNRelinker repHandle;
|
||||||
if (under_and_next) {
|
if (under_and_next) {
|
||||||
underp->unlinkFrBackWithNext(&repHandle);
|
underp->unlinkFrBackWithNext(&repHandle);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1034,7 +1034,7 @@ public:
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// OrderProcess class
|
// OrderProcess class
|
||||||
|
|
||||||
class OrderProcess final : AstNDeleter {
|
class OrderProcess final : VNDeleter {
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstNodeModule::user3 -> int: Number of AstCFuncs created under this module
|
// AstNodeModule::user3 -> int: Number of AstCFuncs created under this module
|
||||||
// AstNode::user4 -> Used by V3Const::constifyExpensiveEdit
|
// AstNode::user4 -> Used by V3Const::constifyExpensiveEdit
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ private:
|
||||||
} else if (m_inTracep) {
|
} else if (m_inTracep) {
|
||||||
m_inTracep->addPrecondsp(newp);
|
m_inTracep->addPrecondsp(newp);
|
||||||
} else if (m_stmtp) {
|
} else if (m_stmtp) {
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
m_stmtp->unlinkFrBack(&linker);
|
m_stmtp->unlinkFrBack(&linker);
|
||||||
newp->addNext(m_stmtp);
|
newp->addNext(m_stmtp);
|
||||||
linker.relink(newp);
|
linker.relink(newp);
|
||||||
|
|
@ -167,7 +167,7 @@ private:
|
||||||
void createDeepTemp(AstNode* nodep, bool noSubst) {
|
void createDeepTemp(AstNode* nodep, bool noSubst) {
|
||||||
if (nodep->user1SetOnce()) return; // Only add another assignment for this node
|
if (nodep->user1SetOnce()) return; // Only add another assignment for this node
|
||||||
|
|
||||||
AstNRelinker relinker;
|
VNRelinker relinker;
|
||||||
nodep->unlinkFrBack(&relinker);
|
nodep->unlinkFrBack(&relinker);
|
||||||
|
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
|
|
@ -276,7 +276,7 @@ private:
|
||||||
// C operator's width must be < maximum shift which is
|
// C operator's width must be < maximum shift which is
|
||||||
// based on Verilog width
|
// based on Verilog width
|
||||||
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
|
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
|
||||||
AstNRelinker replaceHandle;
|
VNRelinker replaceHandle;
|
||||||
nodep->unlinkFrBack(&replaceHandle);
|
nodep->unlinkFrBack(&replaceHandle);
|
||||||
AstNode* constzerop;
|
AstNode* constzerop;
|
||||||
const int m1value
|
const int m1value
|
||||||
|
|
|
||||||
|
|
@ -543,7 +543,7 @@ protected:
|
||||||
if (leaveAlone) {
|
if (leaveAlone) {
|
||||||
UINFO(6, " No changes\n");
|
UINFO(6, " No changes\n");
|
||||||
} else {
|
} else {
|
||||||
AstNRelinker replaceHandle; // Where to add the list
|
VNRelinker replaceHandle; // Where to add the list
|
||||||
AstNode* newListp = nullptr;
|
AstNode* newListp = nullptr;
|
||||||
for (auto it = rankMap.cbegin(); it != rankMap.cend(); ++it) {
|
for (auto it = rankMap.cbegin(); it != rankMap.cend(); ++it) {
|
||||||
AstNode* const nextp = it->second;
|
AstNode* const nextp = it->second;
|
||||||
|
|
|
||||||
|
|
@ -1010,7 +1010,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||||
AstVar* const envarp = getCreateEnVarp(varrefp->varp());
|
AstVar* const envarp = getCreateEnVarp(varrefp->varp());
|
||||||
// If any drops, we need to add in the count of Zs (from __en)
|
// If any drops, we need to add in the count of Zs (from __en)
|
||||||
UINFO(4, " COUNTBITS('z)-> " << nodep << endl);
|
UINFO(4, " COUNTBITS('z)-> " << nodep << endl);
|
||||||
AstNRelinker relinkHandle;
|
VNRelinker relinkHandle;
|
||||||
nodep->unlinkFrBack(&relinkHandle);
|
nodep->unlinkFrBack(&relinkHandle);
|
||||||
AstNode* newp = new AstCountOnes(
|
AstNode* newp = new AstCountOnes(
|
||||||
nodep->fileline(), new AstVarRef(nodep->fileline(), envarp, VAccess::READ));
|
nodep->fileline(), new AstVarRef(nodep->fileline(), envarp, VAccess::READ));
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ private:
|
||||||
// Saves us teaching V3Const how to optimize, and it won't be needed again.
|
// Saves us teaching V3Const how to optimize, and it won't be needed again.
|
||||||
if (const AstIf* const ifp = VN_AS(prep->user2p(), If)) {
|
if (const AstIf* const ifp = VN_AS(prep->user2p(), If)) {
|
||||||
UASSERT_OBJ(!needDly, prep, "Should have already converted to non-delay");
|
UASSERT_OBJ(!needDly, prep, "Should have already converted to non-delay");
|
||||||
AstNRelinker replaceHandle;
|
VNRelinker replaceHandle;
|
||||||
AstNode* const earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
|
AstNode* const earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
|
||||||
AstNode* const newp = new AstLogAnd(condp->fileline(), condp, earliercondp);
|
AstNode* const newp = new AstLogAnd(condp->fileline(), condp, earliercondp);
|
||||||
UINFO(4, "Edit BOUNDLVALUE " << newp << endl);
|
UINFO(4, "Edit BOUNDLVALUE " << newp << endl);
|
||||||
|
|
@ -330,7 +330,7 @@ private:
|
||||||
= new AstVar(nodep->fileline(), AstVarType::XTEMP, m_xrandNames.get(nodep),
|
= new AstVar(nodep->fileline(), AstVarType::XTEMP, m_xrandNames.get(nodep),
|
||||||
VFlagLogicPacked(), nodep->width());
|
VFlagLogicPacked(), nodep->width());
|
||||||
++m_statUnkVars;
|
++m_statUnkVars;
|
||||||
AstNRelinker replaceHandle;
|
VNRelinker replaceHandle;
|
||||||
nodep->unlinkFrBack(&replaceHandle);
|
nodep->unlinkFrBack(&replaceHandle);
|
||||||
AstNodeVarRef* const newref1p
|
AstNodeVarRef* const newref1p
|
||||||
= new AstVarRef(nodep->fileline(), newvarp, VAccess::READ);
|
= new AstVarRef(nodep->fileline(), newvarp, VAccess::READ);
|
||||||
|
|
@ -386,7 +386,7 @@ private:
|
||||||
VL_DO_DANGLING(condp->deleteTree(), condp);
|
VL_DO_DANGLING(condp->deleteTree(), condp);
|
||||||
} else if (!lvalue) {
|
} else if (!lvalue) {
|
||||||
// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
|
// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
|
||||||
AstNRelinker replaceHandle;
|
VNRelinker replaceHandle;
|
||||||
nodep->unlinkFrBack(&replaceHandle);
|
nodep->unlinkFrBack(&replaceHandle);
|
||||||
V3Number xnum(nodep, nodep->width());
|
V3Number xnum(nodep, nodep->width());
|
||||||
xnum.setAllBitsX();
|
xnum.setAllBitsX();
|
||||||
|
|
@ -445,7 +445,7 @@ private:
|
||||||
// Making a scalar would break if we're making an array
|
// Making a scalar would break if we're making an array
|
||||||
&& !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) {
|
&& !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||||
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
|
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
|
||||||
AstNRelinker replaceHandle;
|
VNRelinker replaceHandle;
|
||||||
nodep->unlinkFrBack(&replaceHandle);
|
nodep->unlinkFrBack(&replaceHandle);
|
||||||
V3Number xnum(nodep, nodep->width());
|
V3Number xnum(nodep, nodep->width());
|
||||||
if (nodep->isString()) {
|
if (nodep->isString()) {
|
||||||
|
|
@ -462,7 +462,7 @@ private:
|
||||||
iterate(newp);
|
iterate(newp);
|
||||||
} else if (!lvalue) { // Mid-multidimension read, just use zero
|
} else if (!lvalue) { // Mid-multidimension read, just use zero
|
||||||
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
|
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
|
||||||
AstNRelinker replaceHandle;
|
VNRelinker replaceHandle;
|
||||||
AstNode* const bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
|
AstNode* const bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
|
||||||
AstNode* const newp = new AstCondBound(
|
AstNode* const newp = new AstCondBound(
|
||||||
bitp->fileline(), condp, bitp,
|
bitp->fileline(), condp, bitp,
|
||||||
|
|
|
||||||
|
|
@ -3351,7 +3351,7 @@ private:
|
||||||
if (patp->lhssp()->nextp()) {
|
if (patp->lhssp()->nextp()) {
|
||||||
// Can't just addNext, as would add to end of all members.
|
// Can't just addNext, as would add to end of all members.
|
||||||
// So detach, add next and reattach
|
// So detach, add next and reattach
|
||||||
AstNRelinker relinkHandle;
|
VNRelinker relinkHandle;
|
||||||
patp->unlinkFrBack(&relinkHandle);
|
patp->unlinkFrBack(&relinkHandle);
|
||||||
while (AstNode* const movep = patp->lhssp()->nextp()) {
|
while (AstNode* const movep = patp->lhssp()->nextp()) {
|
||||||
movep->unlinkFrBack(); // Not unlinkFrBackWithNext, just one
|
movep->unlinkFrBack(); // Not unlinkFrBackWithNext, just one
|
||||||
|
|
@ -4078,7 +4078,7 @@ private:
|
||||||
|| VN_IS(dtypep, QueueDType)) {
|
|| VN_IS(dtypep, QueueDType)) {
|
||||||
added = true;
|
added = true;
|
||||||
newFormat += "%@";
|
newFormat += "%@";
|
||||||
AstNRelinker handle;
|
VNRelinker handle;
|
||||||
argp->unlinkFrBack(&handle);
|
argp->unlinkFrBack(&handle);
|
||||||
AstCMath* const newp
|
AstCMath* const newp
|
||||||
= new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true);
|
= new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true);
|
||||||
|
|
@ -4657,7 +4657,7 @@ private:
|
||||||
if (portp->attrSFormat()
|
if (portp->attrSFormat()
|
||||||
&& (!VN_IS(pinp, SFormatF) || pinp->nextp())) { // Not already done
|
&& (!VN_IS(pinp, SFormatF) || pinp->nextp())) { // Not already done
|
||||||
UINFO(4, " sformat via metacomment: " << nodep << endl);
|
UINFO(4, " sformat via metacomment: " << nodep << endl);
|
||||||
AstNRelinker handle;
|
VNRelinker handle;
|
||||||
argp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
|
argp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
|
||||||
AstNode* argsp = nullptr;
|
AstNode* argsp = nullptr;
|
||||||
while (AstArg* const nextargp = VN_AS(argp->nextp(), Arg)) {
|
while (AstArg* const nextargp = VN_AS(argp->nextp(), Arg)) {
|
||||||
|
|
@ -4691,7 +4691,7 @@ private:
|
||||||
&& VN_AS(pinp, VarRef)->varp()->basicp()->keyword()
|
&& VN_AS(pinp, VarRef)->varp()->basicp()->keyword()
|
||||||
== AstBasicDTypeKwd::STRING)) {
|
== AstBasicDTypeKwd::STRING)) {
|
||||||
UINFO(4, " Add CvtPackString: " << pinp << endl);
|
UINFO(4, " Add CvtPackString: " << pinp << endl);
|
||||||
AstNRelinker handle;
|
VNRelinker handle;
|
||||||
pinp->unlinkFrBack(&handle); // No next, that's the next pin
|
pinp->unlinkFrBack(&handle); // No next, that's the next pin
|
||||||
AstNode* const newp = new AstCvtPackString(pinp->fileline(), pinp);
|
AstNode* const newp = new AstCvtPackString(pinp->fileline(), pinp);
|
||||||
handle.relink(newp);
|
handle.relink(newp);
|
||||||
|
|
@ -5314,7 +5314,7 @@ private:
|
||||||
nodep = newp;
|
nodep = newp;
|
||||||
} else if (expWidth < nodep->width()) {
|
} else if (expWidth < nodep->width()) {
|
||||||
// Trunc - Extract
|
// Trunc - Extract
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
nodep->unlinkFrBack(&linker);
|
nodep->unlinkFrBack(&linker);
|
||||||
AstNode* const newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
|
AstNode* const newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
|
||||||
newp->didWidth(true); // Don't replace dtype with unsigned
|
newp->didWidth(true); // Don't replace dtype with unsigned
|
||||||
|
|
@ -5322,7 +5322,7 @@ private:
|
||||||
nodep = newp;
|
nodep = newp;
|
||||||
} else {
|
} else {
|
||||||
// Extend
|
// Extend
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
nodep->unlinkFrBack(&linker);
|
nodep->unlinkFrBack(&linker);
|
||||||
bool doSigned = false;
|
bool doSigned = false;
|
||||||
switch (extendRule) {
|
switch (extendRule) {
|
||||||
|
|
@ -5367,7 +5367,7 @@ private:
|
||||||
VL_DANGLING(nodep);
|
VL_DANGLING(nodep);
|
||||||
nodep = newp;
|
nodep = newp;
|
||||||
} else {
|
} else {
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
nodep->unlinkFrBack(&linker);
|
nodep->unlinkFrBack(&linker);
|
||||||
AstNode* const newp = new AstRedOr(nodep->fileline(), nodep);
|
AstNode* const newp = new AstRedOr(nodep->fileline(), nodep);
|
||||||
linker.relink(newp);
|
linker.relink(newp);
|
||||||
|
|
@ -5521,7 +5521,7 @@ private:
|
||||||
// For DOUBLE under a logical op, add implied test against zero, never a warning
|
// For DOUBLE under a logical op, add implied test against zero, never a warning
|
||||||
if (underp && underp->isDouble()) {
|
if (underp && underp->isDouble()) {
|
||||||
UINFO(6, " spliceCvtCmpD0: " << underp << endl);
|
UINFO(6, " spliceCvtCmpD0: " << underp << endl);
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
underp->unlinkFrBack(&linker);
|
underp->unlinkFrBack(&linker);
|
||||||
AstNode* const newp
|
AstNode* const newp
|
||||||
= new AstNeqD(nodep->fileline(), underp,
|
= new AstNeqD(nodep->fileline(), underp,
|
||||||
|
|
@ -5727,7 +5727,7 @@ private:
|
||||||
// We don't warn here, "2.0 * 2" is common and reasonable
|
// We don't warn here, "2.0 * 2" is common and reasonable
|
||||||
if (nodep && !nodep->dtypep()->skipRefp()->isDouble()) {
|
if (nodep && !nodep->dtypep()->skipRefp()->isDouble()) {
|
||||||
UINFO(6, " spliceCvtD: " << nodep << endl);
|
UINFO(6, " spliceCvtD: " << nodep << endl);
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
nodep->unlinkFrBack(&linker);
|
nodep->unlinkFrBack(&linker);
|
||||||
AstNode* newp;
|
AstNode* newp;
|
||||||
if (nodep->dtypep()->skipRefp()->isSigned()) {
|
if (nodep->dtypep()->skipRefp()->isSigned()) {
|
||||||
|
|
@ -5746,7 +5746,7 @@ private:
|
||||||
// 11.8.2: Argument to convert is self-determined
|
// 11.8.2: Argument to convert is self-determined
|
||||||
if (nodep && nodep->dtypep()->skipRefp()->isDouble()) {
|
if (nodep && nodep->dtypep()->skipRefp()->isDouble()) {
|
||||||
UINFO(6, " spliceCvtS: " << nodep << endl);
|
UINFO(6, " spliceCvtS: " << nodep << endl);
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
nodep->unlinkFrBack(&linker);
|
nodep->unlinkFrBack(&linker);
|
||||||
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
||||||
// We convert to/from vlsint32 rather than use floor() as want to make sure is
|
// We convert to/from vlsint32 rather than use floor() as want to make sure is
|
||||||
|
|
@ -5772,7 +5772,7 @@ private:
|
||||||
// 11.8.2: Argument to convert is self-determined
|
// 11.8.2: Argument to convert is self-determined
|
||||||
if (nodep && !(nodep->dtypep()->basicp() && nodep->dtypep()->basicp()->isString())) {
|
if (nodep && !(nodep->dtypep()->basicp() && nodep->dtypep()->basicp()->isString())) {
|
||||||
UINFO(6, " spliceCvtString: " << nodep << endl);
|
UINFO(6, " spliceCvtString: " << nodep << endl);
|
||||||
AstNRelinker linker;
|
VNRelinker linker;
|
||||||
nodep->unlinkFrBack(&linker);
|
nodep->unlinkFrBack(&linker);
|
||||||
AstNode* const newp = new AstCvtPackString(nodep->fileline(), nodep);
|
AstNode* const newp = new AstCvtPackString(nodep->fileline(), nodep);
|
||||||
linker.relink(newp);
|
linker.relink(newp);
|
||||||
|
|
|
||||||
|
|
@ -366,8 +366,6 @@ def read_types(filename):
|
||||||
supern = match.group(1) if match else ""
|
supern = match.group(1) if match else ""
|
||||||
assert classn != "AstNode" or supern == "", "AstNode can't have a superclass"
|
assert classn != "AstNode" or supern == "", "AstNode can't have a superclass"
|
||||||
if re.search(r'Ast', supern) or classn == "AstNode":
|
if re.search(r'Ast', supern) or classn == "AstNode":
|
||||||
if supern == "AstNDeleter":
|
|
||||||
continue
|
|
||||||
classn = re.sub(r'^Ast', '', classn)
|
classn = re.sub(r'^Ast', '', classn)
|
||||||
supern = re.sub(r'^Ast', '', supern)
|
supern = re.sub(r'^Ast', '', supern)
|
||||||
Classes[classn] = supern
|
Classes[classn] = supern
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue