Internals: Convert foreach loops in V3Begin as well as V3Width (#5283)
This commit is contained in:
parent
2f5c58b345
commit
a61178bd89
150
src/V3Begin.cpp
150
src/V3Begin.cpp
|
|
@ -134,6 +134,9 @@ class BeginVisitor final : public VNVisitor {
|
|||
dotNames(nodep, "__FORK__");
|
||||
nodep->name("");
|
||||
}
|
||||
void visit(AstForeach* nodep) override {
|
||||
VL_DO_DANGLING(V3Begin::convertToWhile(nodep), nodep);
|
||||
}
|
||||
void visit(AstNodeAssign* nodep) override {
|
||||
// Keep begin under assignment (in nodep->timingControlp())
|
||||
VL_RESTORER(m_keepBegins);
|
||||
|
|
@ -369,3 +372,150 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
|
|||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
||||
static AstNode* createForeachLoop(AstNodeForeach* nodep, AstNode* bodysp, AstVar* varp,
|
||||
AstNodeExpr* leftp, AstNodeExpr* rightp, VNType nodeType) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
AstNodeExpr* varRefp = new AstVarRef{fl, varp, VAccess::READ};
|
||||
AstNodeExpr* condp;
|
||||
bool inc = true;
|
||||
switch (nodeType) {
|
||||
case VNType::atLteS: condp = new AstLteS{fl, varRefp, rightp}; break;
|
||||
case VNType::atLt: condp = new AstLt{fl, varRefp, rightp}; break;
|
||||
case VNType::atGteS:
|
||||
condp = new AstGteS{fl, varRefp, rightp};
|
||||
inc = false;
|
||||
break;
|
||||
default: UASSERT_OBJ(0, varp, "Missing comparison handling"); break;
|
||||
}
|
||||
AstNodeExpr* incp;
|
||||
if (inc)
|
||||
incp = new AstAdd{fl, varRefp->cloneTree(false), new AstConst{fl, 1}};
|
||||
else
|
||||
incp = new AstSub{fl, varRefp->cloneTree(false), new AstConst{fl, 1}};
|
||||
|
||||
AstWhile* const whilep = new AstWhile{
|
||||
fl, condp, bodysp, new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, incp}};
|
||||
AstNode* const stmtsp = varp; // New statements for outer loop
|
||||
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, leftp});
|
||||
stmtsp->addNext(whilep);
|
||||
return stmtsp;
|
||||
}
|
||||
static AstNode* createForeachLoopRanged(AstNodeForeach* nodep, AstNode* bodysp, AstVar* varp,
|
||||
const VNumRange& declRange) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
V3Number left{nodep, 32}, right{nodep, 32};
|
||||
left.isSigned(true);
|
||||
right.isSigned(true);
|
||||
left.setLongS(declRange.left());
|
||||
right.setLongS(declRange.right());
|
||||
AstNodeExpr* const leftp = new AstConst{fl, left};
|
||||
AstNodeExpr* const rightp = new AstConst{fl, right};
|
||||
return createForeachLoop(nodep, bodysp, varp, leftp, rightp,
|
||||
declRange.left() <= declRange.right() ? VNType::atLteS
|
||||
: VNType::atGteS);
|
||||
}
|
||||
AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
||||
// if (debug()) dumpTree(cout, "- foreach-old: ");
|
||||
const AstSelLoopVars* const loopsp = VN_CAST(nodep->arrayp(), SelLoopVars);
|
||||
UASSERT_OBJ(loopsp, nodep, "No loop variables under foreach");
|
||||
AstNodeExpr* const fromp = loopsp->fromp();
|
||||
UASSERT_OBJ(fromp->dtypep(), fromp, "Missing data type");
|
||||
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
|
||||
// Split into for loop
|
||||
// We record where the body needs to eventually go with bodyPointp
|
||||
AstNode* bodyPointp = new AstBegin{nodep->fileline(), "[EditWrapper]", nullptr};
|
||||
AstNode* newp = nullptr;
|
||||
AstNode* lastp = nodep;
|
||||
|
||||
// Major dimension first
|
||||
for (AstNode *argsp = loopsp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
|
||||
next_argsp = argsp->nextp();
|
||||
const bool empty = VN_IS(argsp, Empty);
|
||||
AstVar* const varp = VN_CAST(argsp, Var);
|
||||
UASSERT_OBJ(varp || empty, argsp, "Missing foreach loop variable");
|
||||
if (varp) varp->unlinkFrBack()->usedLoopIdx(true);
|
||||
UASSERT_OBJ(fromDtp, argsp, "more loop vars than dimensions");
|
||||
fromDtp = fromDtp->skipRefp();
|
||||
|
||||
FileLine* const fl = argsp->fileline();
|
||||
if (varp) {
|
||||
AstNode* loopp = nullptr;
|
||||
VNRelinker handle;
|
||||
lastp->unlinkFrBack(&handle);
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(fromDtp, NodeArrayDType)) {
|
||||
loopp = createForeachLoopRanged(nodep, bodyPointp, varp, adtypep->declRange());
|
||||
} else if (AstBasicDType* const adtypep = VN_CAST(fromDtp, BasicDType)) {
|
||||
if (adtypep->isString()) {
|
||||
AstConst* const leftp = new AstConst{fl, 0};
|
||||
AstNodeExpr* const rightp = new AstLenN{fl, fromp->cloneTreePure(false)};
|
||||
loopp
|
||||
= createForeachLoop(nodep, bodyPointp, varp, leftp, rightp, VNType::atLt);
|
||||
} else {
|
||||
UASSERT_OBJ(adtypep->isRanged(), varp, "foreach on basic " << adtypep);
|
||||
loopp = createForeachLoopRanged(nodep, bodyPointp, varp, adtypep->declRange());
|
||||
}
|
||||
} else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) {
|
||||
AstConst* const leftp = new AstConst{fl, 0};
|
||||
AstNodeExpr* const rightp
|
||||
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "size"};
|
||||
rightp->dtypeSetSigned32();
|
||||
rightp->protect(false);
|
||||
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, rightp, VNType::atLt);
|
||||
} else if (const AstAssocArrayDType* const adtypep
|
||||
= VN_CAST(fromDtp, AssocArrayDType)) {
|
||||
// Make this: var KEY_TYPE index;
|
||||
// bit index__Vfirst;
|
||||
// index__Vfirst = 0;
|
||||
// if (0 != array.first(index))
|
||||
// do body while (index__Vfirst || 0 != array.next(index))
|
||||
AstVar* const first_varp = new AstVar{
|
||||
fl, VVarType::BLOCKTEMP, varp->name() + "__Vfirst", VFlagBitPacked{}, 1};
|
||||
first_varp->usedLoopIdx(true);
|
||||
first_varp->lifetime(VLifetime::AUTOMATIC);
|
||||
AstNodeExpr* const firstp
|
||||
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "first",
|
||||
new AstVarRef{fl, varp, VAccess::READWRITE}};
|
||||
firstp->dtypeSetSigned32();
|
||||
AstNodeExpr* const nextp
|
||||
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "next",
|
||||
new AstVarRef{fl, varp, VAccess::READWRITE}};
|
||||
nextp->dtypeSetSigned32();
|
||||
AstNode* const first_clearp
|
||||
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitFalse{}}};
|
||||
auto* const orp = new AstLogOr{fl, new AstVarRef{fl, first_varp, VAccess::READ},
|
||||
new AstNeq{fl, new AstConst{fl, 0}, nextp}};
|
||||
AstNode* const whilep = new AstWhile{fl, orp, first_clearp};
|
||||
first_clearp->addNext(bodyPointp);
|
||||
AstNode* const ifbodyp
|
||||
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitTrue{}}};
|
||||
ifbodyp->addNext(whilep);
|
||||
loopp = varp;
|
||||
loopp->addNext(first_varp);
|
||||
loopp->addNext(
|
||||
new AstIf{fl, new AstNeq{fl, new AstConst{fl, 0}, firstp}, ifbodyp});
|
||||
}
|
||||
UASSERT_OBJ(loopp, argsp, "unable to foreach " << fromDtp);
|
||||
// New loop goes UNDER previous loop
|
||||
handle.relink(loopp);
|
||||
lastp = bodyPointp;
|
||||
if (!newp) newp = loopp;
|
||||
}
|
||||
// Prep for next
|
||||
fromDtp = fromDtp->subDTypep();
|
||||
}
|
||||
// The parser validates we don't have "foreach (array[,,,])"
|
||||
AstNode* const bodyp = nodep->stmtsp();
|
||||
UASSERT_OBJ(newp, nodep, "foreach has no non-empty loop variable");
|
||||
if (bodyp) {
|
||||
bodyPointp->replaceWith(bodyp->unlinkFrBackWithNext());
|
||||
} else {
|
||||
bodyPointp->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(bodyPointp->deleteTree(), bodyPointp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
// if (debug()) newp->dumpTreeAndNext(cout, "- foreach-new: ");
|
||||
return newp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,15 @@
|
|||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
class AstNode;
|
||||
class AstForeach;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Begin final {
|
||||
public:
|
||||
static void debeginAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
static AstNode* convertToWhile(AstForeach* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
|
|
@ -1563,6 +1563,10 @@ class TaskVisitor final : public VNVisitor {
|
|||
// Done the loop
|
||||
m_insStmtp = nullptr; // Next thing should be new statement
|
||||
}
|
||||
void visit(AstNodeForeach* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc(
|
||||
"Foreach statements should have been converted to while statements in V3Begin.cpp");
|
||||
}
|
||||
void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc(
|
||||
"For statements should have been converted to while statements in V3Begin.cpp");
|
||||
|
|
|
|||
176
src/V3Width.cpp
176
src/V3Width.cpp
|
|
@ -68,6 +68,7 @@
|
|||
#include "V3Width.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Begin.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Global.h"
|
||||
|
|
@ -4869,10 +4870,6 @@ class WidthVisitor final : public VNVisitor {
|
|||
AstNodeExpr* const fromp = loopsp->fromp();
|
||||
UASSERT_OBJ(fromp->dtypep(), fromp, "Missing data type");
|
||||
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
|
||||
// Split into for loop
|
||||
// We record where the body needs to eventually go with bodyPointp
|
||||
AstNode* lastBodyPointp = nullptr;
|
||||
AstNode* newp = nullptr;
|
||||
// Major dimension first
|
||||
for (AstNode *argsp = loopsp->elementsp(), *next_argsp; argsp; argsp = next_argsp) {
|
||||
next_argsp = argsp->nextp();
|
||||
|
|
@ -4890,166 +4887,35 @@ class WidthVisitor final : public VNVisitor {
|
|||
UINFO(9, "- from on " << fromp << endl);
|
||||
UINFO(9, "- from dtp " << fromDtp << endl);
|
||||
|
||||
if (VN_IS(nodep, ConstraintForeach)) {
|
||||
// For now unsupported
|
||||
userIterate(varp, nullptr);
|
||||
// Prep for next
|
||||
fromDtp = nullptr;
|
||||
} else {
|
||||
argsp->unlinkFrBack();
|
||||
|
||||
FileLine* const fl = argsp->fileline();
|
||||
AstNode* bodyPointp = new AstBegin{fl, "[EditWrapper]", nullptr};
|
||||
AstNode* loopp = nullptr;
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(fromDtp, NodeArrayDType)) {
|
||||
if (varp) {
|
||||
loopp = createForeachLoopRanged(nodep, bodyPointp, varp,
|
||||
adtypep->declRange());
|
||||
}
|
||||
// Prep for next
|
||||
fromDtp = fromDtp->subDTypep();
|
||||
} else if (AstBasicDType* const adtypep = VN_CAST(fromDtp, BasicDType)) {
|
||||
if (adtypep->isString()) {
|
||||
if (varp) {
|
||||
AstConst* const leftp = new AstConst{fl, AstConst::Signed32{}, 0};
|
||||
AstLt* const condp
|
||||
= new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ},
|
||||
new AstLenN{fl, fromp->cloneTreePure(false)}};
|
||||
AstAdd* const incp
|
||||
= new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
|
||||
new AstVarRef{fl, varp, VAccess::READ}};
|
||||
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, condp, incp);
|
||||
}
|
||||
} else if (!adtypep->isRanged()) {
|
||||
argsp->v3error("Illegal to foreach loop on basic '"
|
||||
+ fromDtp->prettyTypeName() + "'");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(bodyPointp->deleteTree(), bodyPointp);
|
||||
return;
|
||||
} else {
|
||||
if (varp) {
|
||||
loopp = createForeachLoopRanged(nodep, bodyPointp, varp,
|
||||
adtypep->declRange());
|
||||
}
|
||||
}
|
||||
// Prep for next
|
||||
fromDtp = nullptr;
|
||||
} else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) {
|
||||
if (varp) {
|
||||
auto* const leftp = new AstConst{fl, AstConst::Signed32{}, 0};
|
||||
auto* const sizep
|
||||
= new AstCMethodHard{fl, fromp->cloneTreePure(false), "size"};
|
||||
sizep->dtypeSetSigned32();
|
||||
sizep->didWidth(true);
|
||||
sizep->protect(false);
|
||||
AstNodeExpr* const condp
|
||||
= new AstLt{fl, new AstVarRef{fl, varp, VAccess::READ}, sizep};
|
||||
AstNodeExpr* const incp
|
||||
= new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
|
||||
new AstVarRef{fl, varp, VAccess::READ}};
|
||||
loopp = createForeachLoop(nodep, bodyPointp, varp, leftp, condp, incp);
|
||||
}
|
||||
// Prep for next
|
||||
fromDtp = fromDtp->subDTypep();
|
||||
} else if (const AstAssocArrayDType* const adtypep
|
||||
= VN_CAST(fromDtp, AssocArrayDType)) {
|
||||
// Make this: var KEY_TYPE index;
|
||||
// bit index__Vfirst;
|
||||
// index__Vfirst = 0;
|
||||
// if (0 != array.first(index))
|
||||
// do body while (index__Vfirst || 0 != array.next(index))
|
||||
varp->dtypeFrom(adtypep->keyDTypep());
|
||||
AstVar* const first_varp = new AstVar{
|
||||
fl, VVarType::BLOCKTEMP, varp->name() + "__Vfirst", VFlagBitPacked{}, 1};
|
||||
first_varp->usedLoopIdx(true);
|
||||
first_varp->lifetime(VLifetime::AUTOMATIC);
|
||||
AstNodeExpr* const firstp = new AstMethodCall{
|
||||
fl, fromp->cloneTreePure(false), "first",
|
||||
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
|
||||
AstNodeExpr* const nextp = new AstMethodCall{
|
||||
fl, fromp->cloneTreePure(false), "next",
|
||||
new AstArg{fl, "", new AstVarRef{fl, varp, VAccess::READWRITE}}};
|
||||
AstNode* const first_clearp
|
||||
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitFalse{}}};
|
||||
auto* const orp
|
||||
= new AstLogOr{fl, new AstVarRef{fl, first_varp, VAccess::READ},
|
||||
new AstNeq{fl, new AstConst{fl, 0}, nextp}};
|
||||
AstNode* const whilep = new AstWhile{fl, orp, first_clearp};
|
||||
first_clearp->addNext(bodyPointp);
|
||||
AstNode* const ifbodyp
|
||||
= new AstAssign{fl, new AstVarRef{fl, first_varp, VAccess::WRITE},
|
||||
new AstConst{fl, AstConst::BitTrue{}}};
|
||||
ifbodyp->addNext(whilep);
|
||||
AstNode* const stmtsp = varp; // New statements for under new Begin
|
||||
stmtsp->addNext(first_varp);
|
||||
stmtsp->addNext(
|
||||
new AstIf{fl, new AstNeq{fl, new AstConst{fl, 0}, firstp}, ifbodyp});
|
||||
loopp = stmtsp;
|
||||
// Prep for next
|
||||
fromDtp = fromDtp->subDTypep();
|
||||
} else {
|
||||
argsp->v3error("Illegal to foreach loop on '" + fromDtp->prettyTypeName()
|
||||
+ "'");
|
||||
if (VN_IS(fromDtp, NodeArrayDType) || VN_IS(fromDtp, DynArrayDType)
|
||||
|| VN_IS(fromDtp, QueueDType)) {
|
||||
// Nothing special here
|
||||
} else if (AstBasicDType* const adtypep = VN_CAST(fromDtp, BasicDType)) {
|
||||
if (!adtypep->isString() && !adtypep->isRanged()) {
|
||||
argsp->v3error("Illegal 'foreach' loop on " << fromDtp->prettyTypeName()
|
||||
<< " data type");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
// New loop goes UNDER previous loop
|
||||
if (varp) {
|
||||
if (!newp) {
|
||||
newp = loopp;
|
||||
} else {
|
||||
lastBodyPointp->replaceWith(loopp);
|
||||
}
|
||||
lastBodyPointp = bodyPointp;
|
||||
}
|
||||
} else if (const AstAssocArrayDType* const adtypep
|
||||
= VN_CAST(fromDtp, AssocArrayDType)) {
|
||||
varp->dtypeFrom(adtypep->keyDTypep());
|
||||
} else {
|
||||
argsp->v3error("Illegal 'foreach' loop on " << fromDtp->prettyTypeName()
|
||||
<< " data type");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
fromDtp = fromDtp->subDTypep();
|
||||
}
|
||||
// The parser validates we don't have "foreach (array[,,,])"
|
||||
AstNode* const bodyp = nodep->stmtsp();
|
||||
if (VN_IS(nodep, ConstraintForeach)) {
|
||||
userIterateAndNext(bodyp, nullptr);
|
||||
} else {
|
||||
UASSERT_OBJ(newp, nodep, "foreach has no non-empty loop variable");
|
||||
if (bodyp) {
|
||||
lastBodyPointp->replaceWith(bodyp->unlinkFrBackWithNext());
|
||||
} else {
|
||||
lastBodyPointp->unlinkFrBack();
|
||||
}
|
||||
// if (debug()) newp->dumpTreeAndNext(cout, "- foreach-new: ");
|
||||
nodep->replaceWith(newp);
|
||||
if (lastBodyPointp) VL_DO_DANGLING(lastBodyPointp->deleteTree(), lastBodyPointp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
userIterateAndNext(bodyp, nullptr);
|
||||
if (AstForeach* const loopp = VN_CAST(nodep, Foreach)) {
|
||||
VL_DO_DANGLING(V3Begin::convertToWhile(loopp), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
AstNode* createForeachLoopRanged(AstNodeForeach* nodep, AstNode* bodysp, AstVar* varp,
|
||||
const VNumRange& declRange) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
AstNodeExpr* const leftp = new AstConst{fl, AstConst::Signed32{}, declRange.left()};
|
||||
AstNodeExpr* const rightp = new AstConst{fl, AstConst::Signed32{}, declRange.right()};
|
||||
AstNodeExpr* condp;
|
||||
AstNodeExpr* incp;
|
||||
if (declRange.left() < declRange.right()) {
|
||||
condp = new AstLte{fl, new AstVarRef{fl, varp, VAccess::READ}, rightp};
|
||||
incp = new AstAdd{fl, new AstConst{fl, AstConst::Signed32{}, 1},
|
||||
new AstVarRef{fl, varp, VAccess::READ}};
|
||||
} else {
|
||||
condp = new AstGte{fl, new AstVarRef{fl, varp, VAccess::READ}, rightp};
|
||||
incp = new AstSub{fl, new AstVarRef{fl, varp, VAccess::READ},
|
||||
new AstConst{fl, AstConst::Signed32{}, 1}};
|
||||
}
|
||||
return createForeachLoop(nodep, bodysp, varp, leftp, condp, incp);
|
||||
}
|
||||
AstNode* createForeachLoop(AstNodeForeach* nodep, AstNode* bodysp, AstVar* varp,
|
||||
AstNodeExpr* leftp, AstNodeExpr* condp, AstNodeExpr* incp) {
|
||||
FileLine* const fl = varp->fileline();
|
||||
auto* const whilep = new AstWhile{
|
||||
fl, condp, bodysp, new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, incp}};
|
||||
AstNode* const stmtsp = varp; // New statements for under new Begin
|
||||
stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, leftp});
|
||||
stmtsp->addNext(whilep);
|
||||
return stmtsp;
|
||||
}
|
||||
|
||||
void visit(AstNodeAssign* nodep) override {
|
||||
// IEEE-2012 10.7, 11.8.2, 11.8.3, 11.5: (Careful of 11.8.1 which is
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
%Error: t/t_foreach_type_bad.v:19:18: Illegal to foreach loop on 'CLASSREFDTYPE 'Cls''
|
||||
%Error: t/t_foreach_type_bad.v:19:18: Illegal 'foreach' loop on CLASSREFDTYPE 'Cls' data type
|
||||
: ... note: In instance 't'
|
||||
19 | foreach (c[i]);
|
||||
| ^
|
||||
%Error: t/t_foreach_type_bad.v:21:18: Illegal to foreach loop on basic 'BASICDTYPE 'real''
|
||||
%Error: t/t_foreach_type_bad.v:21:18: Illegal 'foreach' loop on BASICDTYPE 'real' data type
|
||||
: ... note: In instance 't'
|
||||
21 | foreach (r[i]);
|
||||
| ^
|
||||
%Error: t/t_foreach_type_bad.v:23:21: Illegal to foreach loop on basic 'BASICDTYPE 'bit''
|
||||
%Error: t/t_foreach_type_bad.v:23:21: Illegal 'foreach' loop on BASICDTYPE 'bit' data type
|
||||
: ... note: In instance 't'
|
||||
23 | foreach (b[i, j, k]);
|
||||
| ^
|
||||
%Error: t/t_foreach_type_bad.v:25:18: Illegal to foreach loop on basic 'BASICDTYPE 'real''
|
||||
%Error: t/t_foreach_type_bad.v:25:18: Illegal 'foreach' loop on BASICDTYPE 'real' data type
|
||||
: ... note: In instance 't'
|
||||
25 | foreach (r[, i]);
|
||||
| ^
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
Loading…
Reference in New Issue