From ce5a70fbca30fbf7daaec04b50060e68ed1e33ee Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Nov 2019 14:40:45 -0500 Subject: [PATCH] Internals: Split large method function. No functional change. --- src/V3Width.cpp | 276 ++++++++++++++++++++++++------------------------ 1 file changed, 138 insertions(+), 138 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6e340360a..d55511229 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1632,147 +1632,13 @@ private: AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : NULL; UINFO(9," from dt "<name() == "num" - || nodep->name() == "first" - || nodep->name() == "last") { - // Constant value - AstConst* newp = NULL; - if (nodep->pinsp()) nodep->v3error("Arguments passed to enum.num method, but it does not take arguments"); - if (nodep->name() == "num") { - int items = 0; - for (AstNode* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()) ++items; - newp = new AstConst(nodep->fileline(), AstConst::Signed32(), items); - } else if (nodep->name() == "first") { - AstEnumItem* itemp = adtypep->itemsp(); - if (!itemp) newp = new AstConst( - nodep->fileline(), AstConst::Signed32(), 0); // Spec doesn't say what to do - else newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const - } else if (nodep->name() == "last") { - AstEnumItem* itemp = adtypep->itemsp(); - while (itemp && itemp->nextp()) itemp = VN_CAST(itemp->nextp(), EnumItem); - if (!itemp) newp = new AstConst( - nodep->fileline(), AstConst::Signed32(), 0); // Spec doesn't say what to do - else newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const - } - UASSERT_OBJ(newp, nodep, "Enum method (perhaps enum item) not const"); - newp->fileline(nodep->fileline()); // Use method's filename/line number to be clearer; may have warning disables - nodep->replaceWith(newp); - pushDeletep(nodep); VL_DANGLING(nodep); - } - else if (nodep->name() == "name" - || nodep->name() == "next" - || nodep->name() == "prev") { - AstAttrType attrType; - if (nodep->name() == "name") attrType = AstAttrType::ENUM_NAME; - else if (nodep->name() == "next") attrType = AstAttrType::ENUM_NEXT; - else if (nodep->name() == "prev") attrType = AstAttrType::ENUM_PREV; - else nodep->v3fatalSrc("Bad case"); - - if (nodep->pinsp() && nodep->name() == "name") { - nodep->v3error("Arguments passed to enum.name method, but it does not take arguments"); - } else if (nodep->pinsp() - && !(VN_IS(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const) - && VN_CAST(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const)->toUInt()==1 - && !nodep->pinsp()->nextp())) { - nodep->v3error("Unsupported: Arguments passed to enum.next method"); - } - // Need a runtime lookup table. Yuk. - // Most enums unless overridden are 32 bits, so we size array - // based on max enum value used. - // Ideally we would have a fast algorithm when a number is - // of small width and complete and so can use an array, and - // a map for when the value is many bits and sparse. - uint64_t msbdim = 0; - { - for (AstEnumItem* itemp = adtypep->itemsp(); - itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { - const AstConst* vconstp = VN_CAST(itemp->valuep(), Const); - UASSERT_OBJ(vconstp, nodep, "Enum item without constified value"); - if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad(); - } - if (adtypep->itemsp()->width() > 64 || msbdim >= (1<<16)) { - nodep->v3error("Unsupported; enum next/prev method on enum with > 10 bits"); - return; - } - } - int selwidth = V3Number::log2b(msbdim)+1; // Width to address a bit - AstVar* varp = enumVarp(adtypep, attrType, (VL_ULL(1)<fileline(), varp, false); - varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); - AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, - // Select in case widths are - // off due to msblen!=width - new AstSel(nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - 0, selwidth)); - nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); - } else { - nodep->v3error("Unknown built-in enum method "<prettyNameQ()); - } + methodCallEnum(nodep, adtypep); } - else if (AstUnpackArrayDType* arrayType = VN_CAST(fromDtp, UnpackArrayDType)) { - enum { - UNKNOWN = 0, - ARRAY_OR, - ARRAY_AND, - ARRAY_XOR - } methodId; - - methodId = UNKNOWN; - if (nodep->name() == "or") methodId = ARRAY_OR; - else if (nodep->name() == "and") methodId = ARRAY_AND; - else if (nodep->name() == "xor") methodId = ARRAY_XOR; - - if (methodId) { - if (nodep->pinsp()) nodep->v3error("Arguments passed to array method, but it does not take arguments"); - - FileLine* fl = nodep->fileline(); - AstNode* newp = NULL; - for (int i = 0; i < arrayType->elementsConst(); ++i) { - AstNode* arrayRef = nodep->fromp()->cloneTree(false); - AstNode* selector = new AstArraySel(fl, arrayRef, i); - if (!newp) { - newp = selector; - } else { - switch (methodId) { - case ARRAY_OR: newp = new AstOr(fl, newp, selector); break; - case ARRAY_AND: newp = new AstAnd(fl, newp, selector); break; - case ARRAY_XOR: newp = new AstXor(fl, newp, selector); break; - default: nodep->v3fatalSrc("bad case"); - } - } - } - nodep->replaceWith(newp); - nodep->deleteTree(); VL_DANGLING(nodep); - } - else { - nodep->v3error("Unknown built-in array method "<prettyNameQ()); - } + else if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) { + methodCallUnpack(nodep, adtypep); } else if (basicp && basicp->isString()) { - // Method call on string - if (nodep->name() == "len") { - // Constant value - if (nodep->pinsp()) nodep->v3error("Arguments passed to string.len method, but it does not take arguments"); - AstNode* newp = new AstLenN(nodep->fileline(), nodep->fromp()->unlinkFrBack()); - nodep->replaceWith(newp); - pushDeletep(nodep); VL_DANGLING(nodep); - } else if (nodep->name() == "itoa") { - replaceWithSFormat(nodep, "%0d"); VL_DANGLING(nodep); - } else if (nodep->name() == "hextoa") { - replaceWithSFormat(nodep, "%0x"); VL_DANGLING(nodep); - } else if (nodep->name() == "octtoa") { - replaceWithSFormat(nodep, "%0o"); VL_DANGLING(nodep); - } else if (nodep->name() == "bintoa") { - replaceWithSFormat(nodep, "%0b"); VL_DANGLING(nodep); - } else if (nodep->name() == "realtoa") { - replaceWithSFormat(nodep, "%g"); VL_DANGLING(nodep); - } else { - nodep->v3error("Unsupported: built-in string method "<prettyNameQ()); - } + methodCallString(nodep, basicp); } else { nodep->v3error("Unsupported: Member call on non-enum object '" @@ -1780,6 +1646,140 @@ private: <<"' which is a '"<fromp()->dtypep()->prettyTypeName()<<"'"); } } + void methodCallEnum(AstMethodSel* nodep, AstEnumDType* adtypep) { + // Method call on enum without following parenthesis, e.g. "ENUM.next" + // Convert this into a method call, and let that visitor figure out what to do next + if (adtypep) {} + if (nodep->name() == "num" + || nodep->name() == "first" + || nodep->name() == "last") { + // Constant value + AstConst* newp = NULL; + if (nodep->pinsp()) nodep->v3error("Arguments passed to enum.num method, but it does not take arguments"); + if (nodep->name() == "num") { + int items = 0; + for (AstNode* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()) ++items; + newp = new AstConst(nodep->fileline(), AstConst::Signed32(), items); + } else if (nodep->name() == "first") { + AstEnumItem* itemp = adtypep->itemsp(); + if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), + 0); // Spec doesn't say what to do + else newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const + } else if (nodep->name() == "last") { + AstEnumItem* itemp = adtypep->itemsp(); + while (itemp && itemp->nextp()) itemp = VN_CAST(itemp->nextp(), EnumItem); + if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), + 0); // Spec doesn't say what to do + else newp = VN_CAST(itemp->valuep()->cloneTree(false), Const); // A const + } + UASSERT_OBJ(newp, nodep, "Enum method (perhaps enum item) not const"); + newp->fileline(nodep->fileline()); // Use method's filename/line number to be clearer; + // may have warning disables + nodep->replaceWith(newp); pushDeletep(nodep); VL_DANGLING(nodep); + } else if (nodep->name() == "name" + || nodep->name() == "next" + || nodep->name() == "prev") { + AstAttrType attrType; + if (nodep->name() == "name") attrType = AstAttrType::ENUM_NAME; + else if (nodep->name() == "next") attrType = AstAttrType::ENUM_NEXT; + else if (nodep->name() == "prev") attrType = AstAttrType::ENUM_PREV; + else nodep->v3fatalSrc("Bad case"); + + if (nodep->pinsp() && nodep->name() == "name") { + nodep->v3error("Arguments passed to enum.name method, but it does not take arguments"); + } else if (nodep->pinsp() + && !(VN_IS(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const) + && VN_CAST(VN_CAST(nodep->pinsp(), Arg)->exprp(), Const)->toUInt() == 1 + && !nodep->pinsp()->nextp())) { + nodep->v3error("Unsupported: Arguments passed to enum.next method"); + } + // Need a runtime lookup table. Yuk. + // Most enums unless overridden are 32 bits, so we size array + // based on max enum value used. + // Ideally we would have a fast algorithm when a number is + // of small width and complete and so can use an array, and + // a map for when the value is many bits and sparse. + uint64_t msbdim = 0; + { + for (AstEnumItem* itemp = adtypep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), EnumItem)) { + const AstConst* vconstp = VN_CAST(itemp->valuep(), Const); + UASSERT_OBJ(vconstp, nodep, "Enum item without constified value"); + if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad(); + } + if (adtypep->itemsp()->width() > 64 || msbdim >= (1 << 16)) { + nodep->v3error("Unsupported; enum next/prev method on enum with > 10 bits"); + return; + } + } + int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit + AstVar* varp = enumVarp(adtypep, attrType, (VL_ULL(1) << selwidth) - 1); + AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false); + varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); + AstNode* newp = new AstArraySel( + nodep->fileline(), varrefp, + // Select in case widths are + // off due to msblen!=width + new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), 0, selwidth)); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } else { + nodep->v3error("Unknown built-in enum method " << nodep->prettyNameQ()); + } + } + void methodCallUnpack(AstMethodSel* nodep, AstUnpackArrayDType* adtypep) { + enum { UNKNOWN = 0, ARRAY_OR, ARRAY_AND, ARRAY_XOR } methodId; + + methodId = UNKNOWN; + if (nodep->name() == "or") methodId = ARRAY_OR; + else if (nodep->name() == "and") methodId = ARRAY_AND; + else if (nodep->name() == "xor") methodId = ARRAY_XOR; + + if (methodId) { + if (nodep->pinsp()) nodep->v3error("Arguments passed to array method, but it does not take arguments"); + FileLine* fl = nodep->fileline(); + AstNode* newp = NULL; + for (int i = 0; i < adtypep->elementsConst(); ++i) { + AstNode* arrayRef = nodep->fromp()->cloneTree(false); + AstNode* selector = new AstArraySel(fl, arrayRef, i); + if (!newp) { + newp = selector; + } else { + switch (methodId) { + case ARRAY_OR: newp = new AstOr(fl, newp, selector); break; + case ARRAY_AND: newp = new AstAnd(fl, newp, selector); break; + case ARRAY_XOR: newp = new AstXor(fl, newp, selector); break; + default: nodep->v3fatalSrc("bad case"); + } + } + } + nodep->replaceWith(newp); + nodep->deleteTree(); VL_DANGLING(nodep); + } else { + nodep->v3error("Unknown built-in array method " << nodep->prettyNameQ()); + } + } + void methodCallString(AstMethodSel* nodep, AstBasicDType* adtypep) { + // Method call on string + if (nodep->name() == "len") { + // Constant value + if (nodep->pinsp()) nodep->v3error("Arguments passed to string.len method, but it does not take arguments"); + AstNode* newp = new AstLenN(nodep->fileline(), nodep->fromp()->unlinkFrBack()); + nodep->replaceWith(newp); + pushDeletep(nodep); VL_DANGLING(nodep); + } else if (nodep->name() == "itoa") { + replaceWithSFormat(nodep, "%0d"); VL_DANGLING(nodep); + } else if (nodep->name() == "hextoa") { + replaceWithSFormat(nodep, "%0x"); VL_DANGLING(nodep); + } else if (nodep->name() == "octtoa") { + replaceWithSFormat(nodep, "%0o"); VL_DANGLING(nodep); + } else if (nodep->name() == "bintoa") { + replaceWithSFormat(nodep, "%0b"); VL_DANGLING(nodep); + } else if (nodep->name() == "realtoa") { + replaceWithSFormat(nodep, "%g"); VL_DANGLING(nodep); + } else { + nodep->v3error("Unsupported: built-in string method "<prettyNameQ()); + } + } virtual void visit(AstPattern* nodep) { if (nodep->didWidthAndSet()) return;