mirror of
https://github.com/verilator/verilator.git
synced 2025-01-10 00:27:35 +00:00
Internals: Split large method function. No functional change.
This commit is contained in:
parent
c36d9a68f5
commit
ce5a70fbca
276
src/V3Width.cpp
276
src/V3Width.cpp
@ -1632,147 +1632,13 @@ private:
|
||||
AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : NULL;
|
||||
UINFO(9," from dt "<<fromDtp<<endl);
|
||||
if (AstEnumDType* adtypep = VN_CAST(fromDtp, EnumDType)) {
|
||||
// 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());
|
||||
}
|
||||
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 "<<nodep->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 "<<nodep->prettyNameQ());
|
||||
}
|
||||
methodCallString(nodep, basicp);
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Unsupported: Member call on non-enum object '"
|
||||
@ -1780,6 +1646,140 @@ private:
|
||||
<<"' which is a '"<<nodep->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 "<<nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPattern* nodep) {
|
||||
if (nodep->didWidthAndSet()) return;
|
||||
|
Loading…
Reference in New Issue
Block a user