diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 3c1bf40d0..be535e86d 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -5534,6 +5534,20 @@ public: bool cleanLhs() const override { return true; } bool sizeMattersLhs() const override { return false; } }; +class AstToStringN final : public AstNodeUniop { +public: + AstToStringN(FileLine* fl, AstNodeExpr* lhsp) + : ASTGEN_SUPER_ToStringN(fl, lhsp) { + dtypeSetString(); + } + ASTGEN_MEMBERS_AstToStringN; + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + string emitVerilog() override { return "$sformatf(\"%p\", %l)"; } + string emitC() override { return isWide() ? "VL_TO_STRING_W(%nw, %li)" : "VL_TO_STRING(%li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; class AstToUpperN final : public AstNodeUniop { // string.toupper() public: diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 65b58cf7b..30e3468d9 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -1260,6 +1260,13 @@ private: } } } + void visit(AstToStringN* nodep) override { + if (jumpingOver()) return; + if (!optimizable()) return; // Accelerate + checkNodeInfo(nodep); + iterateChildrenConst(nodep); + clearOptimizable(nodep, "Cannot convert to string"); // LCOV_EXCL_LINE + } void visit(AstCoverInc* nodep) override { m_isCoverage = true; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7ce8d1477..22ce31ba7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5525,6 +5525,11 @@ class WidthVisitor final : public VNVisitor { userIterateAndNext(nodep->fmtp(), WidthVP{SELF, BOTH}.p()); userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p()); } + void visit(AstToStringN* nodep) override { + // Inserted by V3Width only so we know has been resolved + nodep->dtypeSetString(); + userIterateAndNext(nodep->lhsp(), WidthVP{nodep->lhsp()->dtypep(), BOTH}.p()); + } void visit(AstSFormatF* nodep) override { // Excludes NodeDisplay, see below if (m_vup && !m_vup->prelim()) return; // Can be called as statement or function @@ -5611,13 +5616,7 @@ class WidthVisitor final : public VNVisitor { VNRelinker handle; argp->unlinkFrBack(&handle); FileLine* const flp = nodep->fileline(); - AstCExpr* const newp = new AstCExpr{flp, nullptr}; - newp->addExprsp(new AstText{flp, "VL_TO_STRING(", true}); - newp->addExprsp(argp); - newp->addExprsp(new AstText{flp, ")", true}); - newp->dtypeSetString(); - newp->pure(true); - newp->protect(false); + AstNodeExpr* const newp = new AstToStringN{flp, argp}; handle.relink(newp); // Set argp to what we replaced it with, as we will keep processing the // next argument.