Support pattern assignments in function calls, bug617.

This commit is contained in:
Wilson Snyder 2013-02-13 20:32:25 -05:00
parent a80fce5ac1
commit 49dbfd2131
3 changed files with 37 additions and 25 deletions

View File

@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
**** Support pattern assignments to const variables, bug616. [Ed Lander]
**** Support pattern assignments in function calls, bug617. [Ed Lander]
**** Fix DETECTARRAY on packed structures, bug610. [Jeremy Bennett]
**** Fix LITENDIAN on unpacked structures, bug614. [Wai Sum Mong]

View File

@ -95,7 +95,9 @@ public:
WidthVP(int width, int widthMin, Stage stage)
: m_width(width), m_widthMin(widthMin), m_dtypep(NULL), m_stage(stage) {}
WidthVP(AstNodeDType* dtypep, Stage stage)
: m_width(0), m_widthMin(0), m_dtypep(dtypep), m_stage(stage) {}
: m_width(dtypep->width()), m_widthMin(dtypep->widthMin()), m_dtypep(dtypep), m_stage(stage) {}
WidthVP(AstNodeDType* dtypep, int width, int widthMin, Stage stage)
: m_width(width), m_widthMin(widthMin), m_dtypep(dtypep), m_stage(stage) {}
int width() const { return m_width; }
int widthMin() const { return m_widthMin?m_widthMin:m_width; }
AstNodeDType* dtypep() const { return m_dtypep; }
@ -118,7 +120,6 @@ private:
AstFunc* m_funcp; // Current function
AstInitial* m_initialp; // Current initial block
AstAttrOf* m_attrp; // Current attribute
AstNodeDType* m_assDTypep; // Assign LHS data type for assignment pattern
bool m_doGenerate; // Do errors later inside generate statement
int m_dtTables; // Number of created data type tables
@ -970,6 +971,7 @@ private:
virtual void visit(AstEnumItem* nodep, AstNUser* vup) {
UINFO(5," ENUMITEM "<<nodep<<endl);
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("ENUMITEM not under ENUM");
nodep->dtypep(vdtypep);
if (nodep->valuep()) { // else the value will be assigned sequentially
int width = vdtypep->width(); // Always from parent type
@ -1128,12 +1130,13 @@ private:
virtual void visit(AstPattern* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return;
UINFO(9,"PATTERN "<<nodep<<endl);
AstNodeDType* oldAssDTypep = m_assDTypep;
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath a supported construct: "<<nodep->backp()->prettyTypeName());
{
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern not underneath an assignment");
m_assDTypep = m_assDTypep->skipRefp();
UINFO(9," adtypep "<<m_assDTypep<<endl);
nodep->dtypep(m_assDTypep);
vdtypep = vdtypep->skipRefp();
nodep->dtypep(vdtypep);
UINFO(9," adtypep "<<vdtypep<<endl);
nodep->dtypep(vdtypep);
for (AstPatMember* patp = nodep->itemsp()->castPatMember(); patp; patp = patp->nextp()->castPatMember()) {
// Determine replication count, and replicate initial value as widths need to be individually determined
int times = visitPatMemberRep(patp);
@ -1151,10 +1154,10 @@ private:
patp->unlinkFrBack();
}
}
while (AstConstDType* classp = m_assDTypep->castConstDType()) {
m_assDTypep = classp->subDTypep()->skipRefp();
while (AstConstDType* classp = vdtypep->castConstDType()) {
vdtypep = classp->subDTypep()->skipRefp();
}
if (AstNodeClassDType* classp = m_assDTypep->castNodeClassDType()) {
if (AstNodeClassDType* classp = vdtypep->castNodeClassDType()) {
// Due to "default" and tagged patterns, we need to determine
// which member each AstPatMember corresponds to before we can
// determine the dtypep for that PatMember's value, and then
@ -1208,9 +1211,9 @@ private:
patp = it->second;
}
// Determine initial values
m_assDTypep = memp;
vdtypep = memp;
patp->dtypep(memp);
patp->accept(*this,WidthVP(patp->width(),patp->width(),BOTH).p());
patp->accept(*this,WidthVP(memp,BOTH).p());
// Convert to concat for now
if (!newp) newp = patp->lhsp()->unlinkFrBack();
else {
@ -1226,16 +1229,16 @@ private:
else nodep->v3error("Assignment pattern with no members");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
} else {
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<m_assDTypep->prettyTypeName());
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<vdtypep->prettyTypeName());
}
}
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstPatMember* nodep, AstNUser* vup) {
if (!nodep->dtypep()) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath an assignment");
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
nodep->dtypep(vdtypep);
nodep->lhsp()->dtypeFrom(nodep);
nodep->iterateChildren(*this,WidthVP(nodep->dtypep()->width(),nodep->dtypep()->width(),BOTH).p());
nodep->iterateChildren(*this,WidthVP(nodep->dtypep(),BOTH).p());
widthCheck(nodep,"LHS",nodep->lhsp(),nodep->width(),nodep->width());
}
int visitPatMemberRep(AstPatMember* nodep) {
@ -1332,14 +1335,12 @@ private:
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// TOP LEVEL NODE
//if (debug()) nodep->dumpTree(cout," AssignPre: ");
AstNodeDType* oldAssDTypep = m_assDTypep;
{
//if (debug()) nodep->dumpTree(cout,"- assin: ");
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (!nodep->lhsp()->dtypep()) nodep->v3fatalSrc("How can LHS be untyped?");
if (!nodep->lhsp()->dtypep()->widthSized()) nodep->v3fatalSrc("How can LHS be unsized?");
m_assDTypep = nodep->lhsp()->dtypep();
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(nodep->lhsp()->dtypep(),ANYSIZE,0,PRELIM).p());
//if (debug()) nodep->dumpTree(cout,"- assign: ");
if (!nodep->lhsp()->isDouble() && nodep->rhsp()->isDouble()) {
spliceCvtS(nodep->rhsp(), false); // Round RHS
@ -1350,7 +1351,7 @@ private:
if (awidth==0) {
awidth = nodep->rhsp()->width(); // Parameters can propagate by unsized assignment
}
nodep->rhsp()->iterateAndNext(*this,WidthVP(awidth,awidth,FINAL).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(nodep->lhsp()->dtypep(),awidth,awidth,FINAL).p());
nodep->dtypeFrom(nodep->lhsp());
nodep->dtypeChgWidth(awidth,awidth); // We know the assign will truncate, so rather
// than using "width" and have the optimizer truncate the result, we do
@ -1359,7 +1360,6 @@ private:
widthCheck(nodep,"Assign RHS",nodep->rhsp(),awidth,awidth);
//if (debug()) nodep->dumpTree(cout," AssignOut: ");
}
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstSFormatF* nodep, AstNUser*) {
// Excludes NodeDisplay, see below
@ -1684,7 +1684,7 @@ private:
handle.relink(newp);
pinp = newp;
}
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
pinp->accept(*this,WidthVP(portp->dtypep(),PRELIM).p()); pinp=NULL;
} else if (accept_mode==1) {
// Change data types based on above accept completion
if (portp->isDouble()) {
@ -1692,7 +1692,7 @@ private:
}
} else if (accept_mode==2) {
// Do PRELIM again, because above accept may have exited early due to node replacement
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
pinp->accept(*this,WidthVP(portp->dtypep(),BOTH).p());
if ((portp->isOutput() || portp->isInout())
&& pinp->width() != portp->width()) {
pinp->v3error("Unsupported: Function output argument '"<<portp->prettyName()<<"'"
@ -2588,7 +2588,6 @@ public:
m_funcp = NULL;
m_initialp = NULL;
m_attrp = NULL;
m_assDTypep = NULL;
m_doGenerate = doGenerate;
m_dtTables = 0;
}

View File

@ -41,6 +41,9 @@ module t;
const b4_t b4_const_a = '{1'b1, 1'b0, 1'b0, 1'b1};
wire b4_t b4_wire;
assign b4_wire = '{1'b1, 1'b0, 1'b1, 1'b0};
pack2_t arr[2];
initial begin
@ -97,9 +100,17 @@ module t;
end
if (b4_const_a != 4'b1001) $stop;
if (b4_wire != 4'b1010) $stop;
if (pat(4'b1100, 4'b1100)) $stop;
if (pat('{1'b1, 1'b0, 1'b1, 1'b1}, 4'b1011)) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
function pat(b4_t in, logic [3:0] cmp);
if (in !== cmp) $stop;
pat = 1'b0;
endfunction
endmodule