diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 38c322566..9f925bf2e 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -519,6 +519,35 @@ public: void name(const std::string& name) override { m_name = name; } bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } }; +class AstWith final : public AstNode { + // Similar to AstArg, but this is essentially a lambda passed to a call. + // Not an AstNodeExpr as there is no concept of function values in Verilator + // The dtypep() contains the with lambda's return dtype, not a function type. + // Parents: NodeFTaskRef, CMethodHard + // Children: LambdaArgRef that declares the item variable + // Children: LambdaArgRef that declares the item.index variable + // Children: expression (equation establishing the with) + // @astgen op1 := indexArgRefp : AstLambdaArgRef + // @astgen op2 := valueArgRefp : AstLambdaArgRef + // @astgen op3 := exprp : List[AstNode] // Pins, expression and constraints + // TODO: Separate expression and constraints +public: + AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, + AstNode* exprp) + : ASTGEN_SUPER_With(fl) { + this->indexArgRefp(indexArgRefp); + this->valueArgRefp(valueArgRefp); + addExprp(exprp); + } + ASTGEN_MEMBERS_AstWith; + bool hasDType() const override { return true; } + bool sameNode(const AstNode* /*samep*/) const override { return true; } + const char* broken() const override { + BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype + BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype + return nullptr; + } +}; // === AstNodeExpr === class AstAddrOfCFunc final : public AstNodeExpr { @@ -639,6 +668,7 @@ class AstCMethodHard final : public AstNodeExpr { // PARENTS: stmt/expr // @astgen op1 := fromp : AstNodeExpr // Subject of method call // @astgen op2 := pinsp : List[AstNodeExpr] // Arguments + // @astgen op3 := withp : Optional[AstWith] // With clause VCMethod m_method; // Which method to call bool m_pure = false; // Pure optimizable bool m_usePtr = false; // Use '->' not '.' @@ -2599,37 +2629,6 @@ public: bool cleanOut() const override { return true; } bool sameNode(const AstNode* /*samep*/) const override { return true; } }; -class AstWith final : public AstNodeExpr { - // Used as argument to method, then to AstCMethodHard - // dtypep() contains the with lambda's return dtype - // Parents: funcref (similar to AstArg) - // Children: LambdaArgRef that declares the item variable - // Children: LambdaArgRef that declares the item.index variable - // Children: expression (equation establishing the with) - // @astgen op1 := indexArgRefp : AstLambdaArgRef - // @astgen op2 := valueArgRefp : AstLambdaArgRef - // @astgen op3 := exprp : List[AstNode] // Pins, expression and constraints - // TODO: Separate expression and constraints -public: - AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, - AstNode* exprp) - : ASTGEN_SUPER_With(fl) { - this->indexArgRefp(indexArgRefp); - this->valueArgRefp(valueArgRefp); - addExprp(exprp); - } - ASTGEN_MEMBERS_AstWith; - bool sameNode(const AstNode* /*samep*/) const override { return true; } - const char* broken() const override { - BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype - BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype - return nullptr; - } - - string emitVerilog() override { V3ERROR_NA_RETURN(""); } - string emitC() override { V3ERROR_NA_RETURN(""); } - bool cleanOut() const override { V3ERROR_NA_RETURN(true); } -}; class AstWithParse final : public AstNodeExpr { // In early parse, FUNC(index) WITH equation-using-index // Replaced with AstWith diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 269ba2459..bdf198eb3 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -763,6 +763,10 @@ public: comma = true; argNum++; } + if (nodep->withp()) { + if (comma) puts(", "); + iterateConst(nodep->withp()); + } puts(")"); } void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 01f20063a..65d9f035f 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -618,6 +618,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { puts("." + nodep->name() + "("); iterateAndCommaConstNull(nodep->pinsp()); puts(")"); + iterateConstNull(nodep->withp()); } void visit(AstCMethodCall* nodep) override { iterateConst(nodep->fromp()); @@ -1025,7 +1026,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { } void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); } void visit(AstWith* nodep) override { - putfs(nodep, "with ("); + putfs(nodep, " with ("); iterateConstNull(nodep->exprp()); puts(") "); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ece34d0c4..43b244bd5 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3857,7 +3857,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod("r_" + nodep->name()), withp}; + VCMethod::arrayMethod("r_" + nodep->name())}; + newp->withp(withp); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique") { @@ -3875,7 +3876,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); newp->dtypep(queueDTypeIndexedBy(adtypep->subDTypep())); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "map") { @@ -3950,7 +3952,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod("r_" + nodep->name()), withp}; + VCMethod::arrayMethod("r_" + nodep->name())}; + newp->withp(withp); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" @@ -3960,7 +3963,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); if (nodep->name() == "unique_index") { newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep())); } else { @@ -3974,7 +3978,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); newp->dtypep(queueDTypeIndexedBy(adtypep->subDTypep())); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" @@ -3984,7 +3989,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep())); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "map") { @@ -4079,7 +4085,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { @@ -4088,7 +4095,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); if (nodep->name() == "unique_index") { newp->dtypep(newp->findQueueIndexDType()); } else { @@ -4103,7 +4111,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); newp->dtypep(queueDTypeIndexedBy(adtypep->subDTypep())); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" @@ -4114,7 +4123,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod(nodep->name()), withp}; + VCMethod::arrayMethod(nodep->name())}; + newp->withp(withp); newp->dtypep(newp->findQueueIndexDType()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "map") { @@ -4159,7 +4169,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod("r_" + nodep->name()), withp}; + VCMethod::arrayMethod("r_" + nodep->name())}; + newp->withp(withp); newp->dtypeFrom(adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if ((newp = methodCallArray(nodep, adtypep))) { @@ -4260,7 +4271,8 @@ class WidthVisitor final : public VNVisitor { methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod("r_" + nodep->name()), withp}; + VCMethod::arrayMethod("r_" + nodep->name())}; + newp->withp(withp); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if ((newp = methodCallArray(nodep, adtypep))) { @@ -4579,7 +4591,8 @@ class WidthVisitor final : public VNVisitor { methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - VCMethod::arrayMethod("r_" + nodep->name()), withp}; + VCMethod::arrayMethod("r_" + nodep->name())}; + newp->withp(withp); newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); newp->protect(false); diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index 744f7cc7d..e5f33d5f6 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -291,7 +291,7 @@ module Vt_debug_emitv_t; sum = $random('sha); sum = $urandom(); sum = $urandom('sha); - sum = array.r_sum(with ((item * 'sh2)) ); + sum = array.r_sum() with ((item * 'sh2)) ; if ((PKG_PARAM != 'sh1)) begin $stop; end