From 7d1341d34311460ac9e5810cccb4df162f0fb9f3 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 16 Apr 2025 16:15:18 -0400 Subject: [PATCH 01/49] more work on interfaces --- act/defs.m4 | 152 +++++++++++++++++++++++++++--- act/expr2.cc | 6 ++ act/macros.cc | 6 +- act/namespaces.cc | 3 +- act/process.cc | 24 +++++ act/test/types/65.act | 32 +++++++ act/test/types/66.act | 32 +++++++ act/test/types/runs/65.act.stderr | 0 act/test/types/runs/65.act.stdout | 0 act/test/types/runs/66.act.stderr | 0 act/test/types/runs/66.act.stdout | 0 act/types.cc | 138 +++++++++++++++++++++++++++ act/types.h | 49 +++++++++- 13 files changed, 426 insertions(+), 16 deletions(-) create mode 100644 act/test/types/65.act create mode 100644 act/test/types/66.act create mode 100644 act/test/types/runs/65.act.stderr create mode 100644 act/test/types/runs/65.act.stdout create mode 100644 act/test/types/runs/66.act.stderr create mode 100644 act/test/types/runs/66.act.stdout diff --git a/act/defs.m4 b/act/defs.m4 index efe07176..43561333 100644 --- a/act/defs.m4 +++ b/act/defs.m4 @@ -389,6 +389,12 @@ proc_body: } } } + + const char *r = $0->u_p->validateInterfaces (); + if (r) { + $E("%s: inconsistent/missing method", r); + } + return NULL; }} ; @@ -420,7 +426,10 @@ interface_one_spec: iface_inst_type } $A(iface); - $A($0->u_p); + if (!$0->u_p && !$0->u_d) { + $E("Interfaces can only be exported by processes and data types"); + } + $A($0->u_p || $0->u_d); for (li = list_first (ret); li; li = list_next (li)) { if (!iface->isPort ((char *)list_value (li))) { $E("``%s'' is not a port in interface ``%s''", @@ -428,12 +437,25 @@ interface_one_spec: iface_inst_type } li = list_next (li); $A(li); - if (!$0->u_p->isPort ((char *)list_value (li))) { - $E("``%s'' is not a port in process ``%s''", - (char *)list_value (li), $0->u_p->getName()); + if ($0->u_p) { + if (!$0->u_p->isPort ((char *)list_value (li))) { + $E("``%s'' is not a port in process ``%s''", + (char *)list_value (li), $0->u_p->getName()); + } + } + else { + if (!$0->u_d->isPort ((char *)list_value (li))) { + $E("``%s'' is not a port in data type ``%s''", + (char *)list_value (li), $0->u_d->getName()); + } } } - $0->u_p->addIface ($1, ret); + if ($0->u_p) { + $0->u_p->addIface ($1, ret); + } + else { + $0->u_d->addIface ($1, ret); + } return NULL; }} ; @@ -918,6 +940,9 @@ single_macro_port_item: physical_inst_type id_list else if ($0->u_d) { u = $0->u_d; } + else if ($0->u_i) { + u = $0->u_i; + } else { $A(0); } @@ -1150,7 +1175,9 @@ data_chan_body: ";" {{X: return NULL; }} -| [ "+{" override_spec "}" ] +| +[ ":>" interface_spec ] +[ "+{" override_spec "}" ] {{X: if ($0->u_c) { if ($0->u_c->isDefined ()) { @@ -1166,6 +1193,7 @@ data_chan_body: ";" $A(0); } OPT_FREE ($1); + OPT_FREE ($2); }} "{" base_body [ methods_body ] "}" {{X: @@ -1173,18 +1201,18 @@ data_chan_body: ";" UserDef *me; if ($0->u_c) { $0->u_c->MkDefined (); - $0->u_c->AppendBody ($3); + $0->u_c->AppendBody ($4); me = $0->u_c; } else if ($0->u_d) { $0->u_d->MkDefined(); - $0->u_d->AppendBody ($3); + $0->u_d->AppendBody ($4); me = $0->u_d; } else { $A(0); } - OPT_FREE ($4); + OPT_FREE ($5); parent = me->getParent (); if (parent && TypeFactory::isUserType (parent)) { @@ -1198,6 +1226,12 @@ data_chan_body: ";" } } } + if ($0->u_d) { + const char *r = $0->u_d->validateInterfaces (); + if (r) { + $E("%s: inconsistent/missing method", r); + } + } return NULL; }} ; @@ -2873,8 +2907,8 @@ defiface: [ template_spec ] /*printf ("Orig scope: %x\n", $0->scope);*/ $0->scope = $0->u_i->CurScope (); }} - "(" [ port_formal_list ] ")" ";" -{{X: + "(" [ port_formal_list ] ")" +{{X: /* Create type here */ UserDef *u; @@ -2892,14 +2926,108 @@ defiface: [ template_spec ] else { $A($0->curns->CreateType ($3, $0->u_i)); } - OPT_FREE ($5); $0->strict_checking = 0; +}} +interface_methods +{{X: $0->scope =$0->curns->CurScope(); + $0->u_i->MkDefined (); return NULL; }} ; +interface_methods: "{" "methods" "{" method_decl_list "}" "}" +{{X: + return NULL; +}} +| ";" +{{X: + return NULL; +}} +; + +method_decl_list: one_method_decl method_decl_list +| one_method_decl +; + +one_method_decl: "macro" ID +{{X: + $A($0->u_i); + if (strcmp ($2, "int") == 0) { + $E("``int'' cannot be used as a macro name; it is built-in!"); + } + else if (strcmp ($2, $0->u_i->getName()) == 0) { + $E("``%s'' cannot be used as a macro name; it is built-in!", + $0->u_i->getName()); + } + $0->um = $0->u_i->newMacro ($2); + if (!$0->um) { + $E("Duplicate macro name: ``%s''", $2); + } + $0->scope = new Scope ($0->scope, 0); +}} +"(" [ macro_formal_list ] ")" ";" +{{X: + OPT_FREE ($4); + $0->um = NULL; + + Scope *tmp = $0->scope; + $0->scope = tmp->Parent (); + delete tmp; + + return NULL; +}} +| "function" ID +{{X: + $A($0->u_i); + if (strcmp ($2, "int") == 0) { + $E("``int'' cannot be used as a macro name; it is built-in!"); + } + else if (strcmp ($2, $0->u_i->getName()) == 0) { + $E("``%s'' cannot be used as a macro name; it is built-in!", + $0->u_i->getName()); + } + $0->um = $0->u_i->newMacro ($2); + if (!$0->um) { + $E("Duplicate macro name: ``%s''", $2); + } + $0->scope = new Scope ($0->scope, 0); +}} +"(" macro_fn_formal ")" ":" func_ret_type ";" +{{X: + if ($0->um->getNumPorts() > 0) { + if (TypeFactory::isParamType ($0->um->getPortType (0))) { + if (!TypeFactory::isParamType ($7)) { + $E("Macro function with parameter types: return type must be a parameter!"); + } + } + else { + if (TypeFactory::isParamType ($7)) { + $E("Macro function with non-parameter types: return type cannot be a parameter!"); + } + } + } + if (TypeFactory::isParamType ($7)) { + for (int i=0; i < $0->u_i->getNumParams (); i++) { + if ($0->um->addPort ($0->u_i->getPortType (-(i+1)), + $0->u_i->getPortName (-(i+1))) != 1) { + $E("Macro function `%s': duplicate port name for parameter type `%s'.", + $0->um->getName(), $0->u_i->getPortName (-(i+1))); + } + } + } + $0->um->setRetType ($7); + $0->um = NULL; + + Scope *tmp = $0->scope; + $0->scope = tmp->Parent (); + delete tmp; + + return NULL; +}} +; + /*------------------------------------------------------------------------ * * Parameter structure diff --git a/act/expr2.cc b/act/expr2.cc index aebaacd6..2084af57 100644 --- a/act/expr2.cc +++ b/act/expr2.cc @@ -1790,6 +1790,9 @@ static Expr *_expr_expand (int *width, Expr *e, else if (ret->u.e.l->type == E_REAL) { fprintf (stderr, "preal"); } + else if (ret->u.e.l->type == E_TRUE || ret->u.e.l->type == E_FALSE) { + fprintf (stderr, "pbool"); + } else { fprintf (stderr, "other"); } @@ -1800,6 +1803,9 @@ static Expr *_expr_expand (int *width, Expr *e, else if (ret->u.e.r->type == E_REAL) { fprintf (stderr, "preal"); } + else if (ret->u.e.r->type == E_TRUE || ret->u.e.r->type == E_FALSE) { + fprintf (stderr, "pbool"); + } else { fprintf (stderr, "other"); } diff --git a/act/macros.cc b/act/macros.cc index 0f02ef96..11f0f4c0 100644 --- a/act/macros.cc +++ b/act/macros.cc @@ -73,7 +73,7 @@ UserMacro::~UserMacro () } -void UserMacro::Print (FILE *fp) +void UserMacro::Print (FILE *fp, bool header_only) { int templ = 0; int meta = 0; @@ -100,6 +100,10 @@ void UserMacro::Print (FILE *fp) fprintf (fp, " : "); rettype->Print (fp); } + if (header_only) { + fprintf (fp, ";\n"); + return; + } fprintf (fp, " {\n"); if (_exf && _exf->isExpanded()) { diff --git a/act/namespaces.cc b/act/namespaces.cc index 87b549eb..2c2cbe6a 100644 --- a/act/namespaces.cc +++ b/act/namespaces.cc @@ -590,8 +590,7 @@ void ActNamespace::Print (FILE *fp) fprintf (fp, ";\n"); } else if (TypeFactory::isInterfaceType (t)) { - u->PrintHeader (fp, "interface"); - fprintf (fp, ";\n"); + u->Print (fp); } else if (TypeFactory::isFuncType (t)) { Function *f = dynamic_cast (t); diff --git a/act/process.cc b/act/process.cc index 94dc4199..168ac6bc 100644 --- a/act/process.cc +++ b/act/process.cc @@ -742,3 +742,27 @@ void Process::recordGlobal (ActId *id) if (findGlobal (id)) return; list_append (used_globals, id->Clone()); } + + +const char *Process::validateInterfaces () +{ + static char buf[1024]; + if (!ifaces) return NULL; + listitem_t *li; + for (li = list_first (ifaces); li; li = list_next (li)) { + InstType *x = (InstType *) list_value (li); + Interface *ix = dynamic_cast (x->BaseType()); + Assert (ix, "What?!"); + + // now typecheck macros + const char *ret = ix->validateMacros (this, um, A_LEN (um)); + if (ret) { + snprintf (buf, 1024, "Method `%s' from interface `%s'", ret, + ix->getName()); + return buf; + } + + li = list_next (li); + } + return NULL; +} diff --git a/act/test/types/65.act b/act/test/types/65.act new file mode 100644 index 00000000..920863cd --- /dev/null +++ b/act/test/types/65.act @@ -0,0 +1,32 @@ +template +interface linear(bool in[N], out[N]) +{ + methods { + macro sum(int x, y); + } +} + +template) p> +defproc foo () +{ + bool w[N]; + int a, b; + p y; + + y.in = w; + chp { + y.sum(a, b) + } +} + +defproc bar (bool in[4], out[4]) :> linear<4> { in -> in, out -> out } +{ + bool q[4]; + methods { + macro sum(int a, b) { + a := a + b + } + } +} + +foo<4, @bar> x; diff --git a/act/test/types/66.act b/act/test/types/66.act new file mode 100644 index 00000000..73f84c8a --- /dev/null +++ b/act/test/types/66.act @@ -0,0 +1,32 @@ +template +interface linear(bool in[N], out[N]) +{ + methods { + macro sum(int x, y); + } +} + +template) p> +defproc foo () +{ + bool w[N]; + int a, b; + p y; + + y.in = w; + chp { + y.sum(a, b) + } +} + +defproc bar (bool in[4], out[4]) :> linear<4> { in -> in, out -> out } +{ + bool q[4]; + methods { + macro sum(int a, b) { + a := a + b + } + } +} + +foo<4, @bar> x; diff --git a/act/test/types/runs/65.act.stderr b/act/test/types/runs/65.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/65.act.stdout b/act/test/types/runs/65.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/66.act.stderr b/act/test/types/runs/66.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/66.act.stdout b/act/test/types/runs/66.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/types.cc b/act/types.cc index 3c1cc6b6..67112522 100644 --- a/act/types.cc +++ b/act/types.cc @@ -634,6 +634,7 @@ Data::Data (UserDef *u) : UserDef (u) is_eint = 0; b = NULL; enum_vals = NULL; + ifaces = NULL; for (i=0; i < ACT_NUM_STD_METHODS; i++) { methods[i] = NULL; @@ -1303,6 +1304,22 @@ Data *Data::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) xd->enum_vals = list_dup (enum_vals); } + if (ifaces) { + listitem_t *li; + xd->ifaces = list_new (); + for (li = list_first (ifaces); li; li = list_next (li)) { + InstType *iface = (InstType *)list_value (li); + Assert (list_next (li), "What?"); + list_t *lmap = (list_t *)list_value (list_next (li)); + li = list_next (li); + list_append (xd->ifaces, iface->Expand (ns, xd->I)); + list_append (xd->ifaces, lmap); + } + } + else { + xd->ifaces = NULL; + } + /*-- expand macros --*/ /*-- do this in two phases: first, the built-in ones! --*/ @@ -2917,3 +2934,124 @@ void UserDef::updateClonedTypes (ActNamespace */*root*/, { Assert (0, "This should not be called!"); } + + +void Data::addIface (InstType *iface, list_t *lmap) +{ + if (!ifaces) { + ifaces = list_new (); + } + list_append (ifaces, iface); + list_append (ifaces, lmap); +} + +int Data::hasIface (InstType *x, int weak) +{ + listitem_t *li; + if (!ifaces) return 0; + for (li = list_first (ifaces); li; li = list_next (li)) { + InstType *itmp = (InstType *)list_value (li); + Assert (itmp, "What?"); + Interface *tmp = dynamic_cast (itmp->BaseType()); + Assert (tmp, "What?"); + if (itmp->isEqual (x, weak)) { + return 1; + } + li = list_next (li); + } + return 0; +} + +list_t *Data::findMap (InstType *x) +{ + listitem_t *li; + + if (!ifaces) return NULL; + + Array *xtmp = x->arrayInfo(); + x->clrArray(); + + for (li = list_first (ifaces); li; li = list_next (li)) { + InstType *itmp = (InstType *)list_value (li); + Assert (itmp, "What?"); + Interface *tmp = dynamic_cast (itmp->BaseType()); + Assert (tmp, "What?"); + + if (itmp->isEqual (x)) { + x->MkArray (xtmp); + return (list_t *)list_value (list_next (li)); + } + li = list_next (li); + } + x->MkArray (xtmp); + return NULL; +} + +const char *Data::validateInterfaces () +{ + static char buf[1024]; + if (!ifaces) return NULL; + listitem_t *li; + for (li = list_first (ifaces); li; li = list_next (li)) { + InstType *x = (InstType *) list_value (li); + Interface *ix = dynamic_cast (x->BaseType()); + Assert (ix, "What?!"); + + // now typecheck macros + const char *ret = ix->validateMacros (this, um, A_LEN (um)); + if (ret) { + snprintf (buf, 1024, "Method `%s' from interface `%s'", ret, + ix->getName()); + return buf; + } + + li = list_next (li); + } + return NULL; +} + +void Interface::Print (FILE *fp) +{ + PrintHeader (fp, "interface"); + if (A_LEN (um) > 0) { + fprintf (fp, "\n{ methods {\n"); + for (int i=0; i < A_LEN (um); i++) { + um[i]->Print (fp, true); + } + fprintf (fp, " }\n}\n"); + } + else { + fprintf (fp, ";\n"); + } +} + +const char *Interface::validateMacros (UserDef *u, UserMacro **macros, int count) +{ + // we have to try type substitutions for the interface name with the + // specified type name! + for (int i=0; i < A_LEN (um); i++) { + const char *err = um[i]->getName(); + int idx; + for (idx=0; idx < count; idx++) { + if (strcmp (macros[idx]->getName(), err) == 0) { + break; + } + } + if (idx == count) return err; + + /* now check that um[i] and macros[idx] match up! */ + if (um[i]->getNumPorts() != macros[idx]->getNumPorts()) return err; + + if (um[i]->getRetType()) { + if (!macros[idx]->getRetType()) return err; + } + else { + if (macros[idx]->getRetType()) return err; + } + + /* now match the types for each of the arguments as well as the + return value */ + + } + return NULL; +} diff --git a/act/types.h b/act/types.h index 03b4d980..b66632b7 100644 --- a/act/types.h +++ b/act/types.h @@ -852,6 +852,10 @@ class Interface : public UserDef { ActNamespace *newroot, UserDef *orig); Interface *Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u); + + const char *validateMacros (UserDef *u, UserMacro **um, int n); + + void Print (FILE *fp); }; /** @@ -972,6 +976,15 @@ class Process : public UserDef { */ int hasIface (InstType *x, int weak); + /** + * Validate interfaces exported to make sure any macros/methods are + * defined. + * + * @return macro name that caused the error, if any. NULL return + * value means success. + */ + const char *validateInterfaces (); + /** * @return the port name map for the interface exported by this * process @@ -1404,7 +1417,41 @@ class Data : public UserDef { */ void synthStructMacro (); + /** + * Add an interface specification that this process exports. Note + * that a process can export multiple interfaces. + * + * @param iface is the interface exported + * @param imap is the name mapping from the process ports to the + * interface ports + */ + void addIface (InstType *iface, list_t *imap); + + /** + * Weak check for interface equality + */ + int hasIface (InstType *x, int weak); + + /** + * Validate interfaces exported to make sure any macros/methods are + * defined. + * + * @return macro name that caused the error, if any. NULL return + * value means success. + */ + const char *validateInterfaces (); + + /** + * @return the port name map for the interface exported by this + * type + */ + list_t *findMap (InstType *iface); + private: + list_t *ifaces; ///< a mixed list of interface, map + ///pairs. The map is also a list of + ///oldname, newname pairs + void _get_struct_count (int *nbools, int *nints); void _get_struct_fields (ActId **a, int *types, int *pos, ActId *prefix); @@ -1554,7 +1601,7 @@ class UserMacro { UserMacro (UserDef *u, const char *name); ~UserMacro (); - void Print (FILE *fp); + void Print (FILE *fp, bool header_only = false); /** * Expand a user-defined macro. The is_proc flag is used because From 8a76b20a8fc92be505be0732b8a27366df11649f Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Fri, 18 Apr 2025 10:10:08 -0400 Subject: [PATCH 02/49] more work on parameter array args to functions --- act/defs.m4 | 15 ++++ act/expr2.cc | 12 +-- act/func.cc | 131 ++++++++++++++++++------------- act/inline.h | 4 +- act/inst.cc | 4 +- act/test/func/53.act | 16 ++++ act/test/func/54.act | 19 +++++ act/test/func/55.act | 19 +++++ act/test/func/56.act | 17 ++++ act/test/func/runs/53.act.stderr | 5 ++ act/test/func/runs/53.act.stdout | 0 act/test/func/runs/54.act.stderr | 6 ++ act/test/func/runs/54.act.stdout | 0 act/test/func/runs/55.act.stderr | 5 ++ act/test/func/runs/55.act.stdout | 0 act/test/func/runs/56.act.stderr | 6 ++ act/test/func/runs/56.act.stdout | 0 act/test/meta/runs/20.act.stderr | 2 +- act/types.cc | 32 ++++---- act/types.h | 7 ++ 20 files changed, 219 insertions(+), 81 deletions(-) create mode 100644 act/test/func/53.act create mode 100644 act/test/func/54.act create mode 100644 act/test/func/55.act create mode 100644 act/test/func/56.act create mode 100644 act/test/func/runs/53.act.stderr create mode 100644 act/test/func/runs/53.act.stdout create mode 100644 act/test/func/runs/54.act.stderr create mode 100644 act/test/func/runs/54.act.stdout create mode 100644 act/test/func/runs/55.act.stderr create mode 100644 act/test/func/runs/55.act.stdout create mode 100644 act/test/func/runs/56.act.stderr create mode 100644 act/test/func/runs/56.act.stdout diff --git a/act/defs.m4 b/act/defs.m4 index 43561333..69e3801b 100644 --- a/act/defs.m4 +++ b/act/defs.m4 @@ -1857,6 +1857,21 @@ ID else { $A($0->curns->CreateType($3, $0->u_f)); } + if ($0->u_f->getNumPorts() > 0) { + // we have a situation where this could be PURELY pstruct ports! + // In this case, we need to move them over to parameter types + bool convert = true; + for (int i=0; convert && i < $0->u_f->getNumPorts(); i++) { + InstType *it = $0->u_f->getPortType (i); + if (!TypeFactory::isParamType (it)) { + convert = false; + } + } + if (convert) { + $0->u_f->convPortsToParams(); + } + } + if ($0->u_f->getNumPorts() > 0 && TypeFactory::isParamType ($8)) { $E("Function ``%s'': return type incompatible with arguments", $3); } diff --git a/act/expr2.cc b/act/expr2.cc index 2084af57..e3d4c0da 100644 --- a/act/expr2.cc +++ b/act/expr2.cc @@ -502,15 +502,9 @@ static void _eval_function (ActNamespace *ns, Scope *s, Expr *fn, Expr **ret, } } for (int i=0; i < nargs; i++) { - if (!expr_is_a_const (args[i])) { - if (args[i]->type == E_ARRAY) { - act_error_ctxt (stderr); - fatal_error ("Arrays are not supported as function arguments."); - } - else { - act_error_ctxt (stderr); - Assert (expr_is_a_const (args[i]), "Argument is not a constant?"); - } + if (!expr_is_a_const (args[i]) && args[i]->type != E_ARRAY) { + act_error_ctxt (stderr); + Assert (expr_is_a_const (args[i]), "Argument is not a constant?"); } } e = x->eval (ns, nargs, args); diff --git a/act/func.cc b/act/func.cc index aac7482e..b2caf2fe 100644 --- a/act/func.cc +++ b/act/func.cc @@ -552,7 +552,8 @@ Expr *Function::eval (ActNamespace *ns, int nargs, Expr **args) Assert (nargs == getNumParams(), "What?"); for (int i=0; i < nargs; i++) { - Assert (expr_is_a_const (args[i]), "Argument is not a constant?"); + Assert (args[i]->type == E_ARRAY || + expr_is_a_const (args[i]), "Argument is not a constant?"); } /* @@ -576,25 +577,48 @@ Expr *Function::eval (ActNamespace *ns, int nargs, Expr **args) expanded = 1; ValueIdx *vx; - + bool ext_err = false; + for (int i=0; i < getNumParams(); i++) { InstType *it; const char *name; + int count; it = getPortType (-(i+1)); name = getPortName (-(i+1)); - - I->Add (name, it); + + if (it->arrayInfo()) { + if (!it->arrayInfo()->isExpanded()) { + Array *xa = it->arrayInfo()->Expand (ns, ns->CurScope()); + count = xa->size(); + delete xa; + } + else { + count = it->arrayInfo()->size(); + } + ext_err = true; + } + else { + count = 1; + } + + if (it->isExpanded()) { + I->Add (name, it); + } + else { + InstType *xit = it->Expand (ns, ns->CurScope()); + xit->MkCached (); + I->Add (name, xit); + } vx = I->LookupVal (name); + Assert (vx, "Hmm"); - vx->init = 1; - if (TypeFactory::isPIntType (it)) { - vx->u.idx = I->AllocPInt(); + if (TypeFactory::isPIntType (it) || + TypeFactory::isPBoolType (it) || + TypeFactory::isPRealType (it)) { + // okay } - else if (TypeFactory::isPBoolType (it)) { - vx->u.idx = I->AllocPBool(); - } - else if (TypeFactory::isPRealType (it)) { - vx->u.idx = I->AllocPReal(); + else if (TypeFactory::isPStructType (it)) { + ext_err = true; } else { fatal_error ("Invalid type in function signature"); @@ -607,21 +631,26 @@ Expr *Function::eval (ActNamespace *ns, int nargs, Expr **args) I->Add ("self", getRetType ()->Expand (ns, I)); vx = I->LookupVal ("self"); Assert (vx, "Hmm"); - vx->init = 1; - if (TypeFactory::isPIntType (getRetType())) { - vx->u.idx = I->AllocPInt(); + int count; + if (vx->t->arrayInfo()) { + count = vx->t->arrayInfo()->size(); + ext_err = true; + } + else { + count = 1; } - else if (TypeFactory::isPBoolType (getRetType())) { - vx->u.idx = I->AllocPBool(); + if (TypeFactory::isPIntType (getRetType()) || + TypeFactory::isPBoolType (getRetType()) || + TypeFactory::isPRealType (getRetType())) { + // okay } - else if (TypeFactory::isPRealType (getRetType())) { - vx->u.idx = I->AllocPReal(); + else if (TypeFactory::isPStructType (getRetType())) { + ext_err = true; } else { fatal_error ("Invalid return type in function signature"); } - /* now run the chp body */ act_chp *c = NULL; @@ -655,6 +684,10 @@ Expr *Function::eval (ActNamespace *ns, int nargs, Expr **args) fatal_error ("Function `%s': no chp body, and no external definition", getName()); } + if (ext_err) { + act_error_ctxt (stderr); + fatal_error ("Function `%s': external functions can only have simple arguments and return types", getName()); + } long *eargs = NULL; if (nargs != 0) { MALLOC (eargs, long, nargs); @@ -693,51 +726,41 @@ Expr *Function::eval (ActNamespace *ns, int nargs, Expr **args) Expr *ret = NULL; - if (TypeFactory::isPIntType (getRetType())) { - if (ext_found) { + if (ext_found) { + if (TypeFactory::isPIntType (getRetType())) { ret = const_expr (nargs); } - else { - if (I->issetPInt (vx->u.idx)) { - ret = const_expr (I->getPInt (vx->u.idx)); - } - else { - act_error_ctxt (stderr); - fatal_error ("self is not assigned!"); - } - } - } - else if (TypeFactory::isPBoolType (getRetType())) { - if (ext_found) { + else if (TypeFactory::isPBoolType (getRetType())) { ret = const_expr_bool (nargs == 0 ? 0 : 1); } - else { - if (I->issetPBool (vx->u.idx)) { - ret = const_expr_bool (I->getPBool (vx->u.idx)); - } - else { - act_error_ctxt (stderr); - fatal_error ("self is not assigned!"); - } - } - } - else if (TypeFactory::isPRealType (getRetType())) { - if (ext_found) { + else if (TypeFactory::isPRealType (getRetType())) { ret = const_expr_real (nargs); } else { - if (I->issetPReal (vx->u.idx)) { - ret = const_expr_real (I->getPReal (vx->u.idx)); - } - else { - act_error_ctxt (stderr); - fatal_error ("self is not assigned!"); - } + fatal_error ("Invalid return type in function signature"); } } else { - fatal_error ("Invalid return type in function signature"); + ActId *res = new ActId (string_cache ("self")); + ret = res->Eval (ns, I); } return ret; } + +void Function::convPortsToParams () +{ + Assert (!isExpanded(), "Must be only called on unexpanded functions!"); + + Assert (nt == 0 && nports > 0, "What?"); + Assert (pt == NULL && port_t != NULL, "What?"); + Assert (pn == NULL && port_n != NULL, "What?"); + + pt = port_t; + port_t = NULL; + pn = port_n; + port_n = NULL; + nt = nports; + nports = 0; +} + diff --git a/act/inline.h b/act/inline.h index 749084c1..296e126d 100644 --- a/act/inline.h +++ b/act/inline.h @@ -32,6 +32,7 @@ struct act_inline_value { is_struct = 0; is_struct_id = 0; struct_count = 0; + is_top_arr = 0; u.val = NULL; } @@ -82,7 +83,8 @@ struct act_inline_value { unsigned int is_struct:1; /* is this a structure? */ unsigned int is_struct_id:1; /* special case structure, ID map */ - unsigned int struct_count:30; /* size of array for sanity checking */ + unsigned int is_top_arr:1; /* is this an array? */ + unsigned int struct_count:29; /* size of array for sanity checking */ union { Expr *val; /* single value */ Expr **arr; /* flattened array of values */ diff --git a/act/inst.cc b/act/inst.cc index cbec8f2f..e7c6ab92 100644 --- a/act/inst.cc +++ b/act/inst.cc @@ -917,8 +917,8 @@ InstType *InstType::Expand (ActNamespace *ns, Scope *s) } #if 0 - printf ("[%x] Name: %s\n", t, t->getName()); - printf ("[%x] Expanded: %s\n", xt, xt->getName()); + printf ("[%p] Name: %s\n", t, t->getName()); + printf ("[%p] Expanded: %s\n", xt, xt->getName()); #endif /* If parent is user-defined, we need to make sure we have the diff --git a/act/test/func/53.act b/act/test/func/53.act new file mode 100644 index 00000000..bd8f015a --- /dev/null +++ b/act/test/func/53.act @@ -0,0 +1,16 @@ +function pfunc (pint a[4]) : pint +{ + chp { + self := a[0] + a[1] + a[2] + a[3] + } +} + +pint w[3]; + +w[0] = 5; +w[1] = 3; +w[2] = 17; + +pint res = pfunc (w); + +{ res = 10 : "What?" }; diff --git a/act/test/func/54.act b/act/test/func/54.act new file mode 100644 index 00000000..b3352f87 --- /dev/null +++ b/act/test/func/54.act @@ -0,0 +1,19 @@ +function pfunc (pint a[4]) : pint +{ + chp { + self := a[0] + a[1] + a[2] + a[3] + } +} + +pint w[4]; + +w[0] = 5; +w[1] = 3; +w[2] = 17; +w[3] = 2; + +pint res = pfunc (w); + +{ res = 27 : "Should match!" }; + +{ res = 10 : "What?" }; diff --git a/act/test/func/55.act b/act/test/func/55.act new file mode 100644 index 00000000..508aaed3 --- /dev/null +++ b/act/test/func/55.act @@ -0,0 +1,19 @@ +function pfunc (pint a[4]) : pint +{ + chp { + a[0] := a[0] + a[1] + a[2] + a[3] + } +} + +pint w[4]; + +w[0] = 5; +w[1] = 3; +w[2] = 17; +w[3] = 2; + +pint res = pfunc (w); + +{ res = 27 : "Should match!" }; + +{ res = 10 : "What?" }; diff --git a/act/test/func/56.act b/act/test/func/56.act new file mode 100644 index 00000000..ef22bc35 --- /dev/null +++ b/act/test/func/56.act @@ -0,0 +1,17 @@ +defptype foo (pint a; pbool b); + +function testme (foo x) : pint +{ + chp { + [ x.b -> self := x.a + 4 + [] else -> self := x.a - 1 + ] + } +} + +foo x; +x = foo (5, true); + +{ testme (x) = 9 : "Should pass!" }; + +{ testme (x) = 8 : "Should fail!" }; diff --git a/act/test/func/runs/53.act.stderr b/act/test/func/runs/53.act.stderr new file mode 100644 index 00000000..82f6d81f --- /dev/null +++ b/act/test/func/runs/53.act.stderr @@ -0,0 +1,5 @@ +In expanding pfunc (53.act:1) +In expanding :: +Error on or near line number 14. +Typechecking failed, pint[4] v/s pint[3] + Types `pint[4]' and `pint[3]' are not compatible diff --git a/act/test/func/runs/53.act.stdout b/act/test/func/runs/53.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/func/runs/54.act.stderr b/act/test/func/runs/54.act.stderr new file mode 100644 index 00000000..d68e35e1 --- /dev/null +++ b/act/test/func/runs/54.act.stderr @@ -0,0 +1,6 @@ +In expanding :: +Error on or near line number 19. +*** Assertion failed *** + assertion: res=10 + message: What? +FATAL: Aborted execution on failed assertion diff --git a/act/test/func/runs/54.act.stdout b/act/test/func/runs/54.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/func/runs/55.act.stderr b/act/test/func/runs/55.act.stderr new file mode 100644 index 00000000..74e15005 --- /dev/null +++ b/act/test/func/runs/55.act.stderr @@ -0,0 +1,5 @@ +In expanding pfunc (55.act:1) +In expanding :: +Error on or near line number 15. + id: self +FATAL: Uninitialized identifier diff --git a/act/test/func/runs/55.act.stdout b/act/test/func/runs/55.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/func/runs/56.act.stderr b/act/test/func/runs/56.act.stderr new file mode 100644 index 00000000..f6aa5c79 --- /dev/null +++ b/act/test/func/runs/56.act.stderr @@ -0,0 +1,6 @@ +In expanding :: +Error on or near line number 17. +*** Assertion failed *** + assertion: testme(x)=8 + message: Should fail! +FATAL: Aborted execution on failed assertion diff --git a/act/test/func/runs/56.act.stdout b/act/test/func/runs/56.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/meta/runs/20.act.stderr b/act/test/meta/runs/20.act.stderr index 8dc06031..c65d4c1b 100644 --- a/act/test/meta/runs/20.act.stderr +++ b/act/test/meta/runs/20.act.stderr @@ -1,3 +1,3 @@ In expanding :: Error on or near line number 7. -FATAL: Argument to parameter structure constructor `mytype<>' is not a constant +FATAL: Argument to parameter structure constructor `mytype' is not a constant diff --git a/act/types.cc b/act/types.cc index 67112522..d966047a 100644 --- a/act/types.cc +++ b/act/types.cc @@ -786,7 +786,7 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, int ii = 0; for (i=0; i < nt; i++) { - p = getPortType (-(i+1)); + p = getPortType (-(i+1)); Assert (p, "What?"); x = p->Expand (ns, ux->I); // this is the real type of the // parameter @@ -1467,7 +1467,6 @@ const char *PType::getName () return name; } - PStruct *PStruct::Expand (ActNamespace *ns, Scope *s, int _nt, inst_param *u) { if (nt < _nt) { @@ -1475,25 +1474,30 @@ PStruct *PStruct::Expand (ActNamespace *ns, Scope *s, int _nt, inst_param *u) fatal_error ("PStruct being expanded; too many parameters (%d v/s %d).", nt, _nt); } - PStruct *xd; - UserDef *ux; - int cache_hit; - if (isExpanded() && _nt == 0) { return this; } - ux = UserDef::Expand (ns, s, _nt, u, &cache_hit); + recursion_depth++; - if (cache_hit) { - return dynamic_cast(ux); + if (recursion_depth >= Act::max_recurse_depth) { + act_error_ctxt (stderr); + fatal_error ("Exceeded maximum recursion depth of %d\n", Act::max_recurse_depth); + } + + // in place expansion + I->FlushExpand (); + pending = 1; + expanded = 1; + for (int i =0; i < nt; i++) { + pt[i] = pt[i]->Expand (ns, s); + pt[i]->MkCached (); + I->Add (pn[i], pt[i]); } - xd = new PStruct (ux); - delete ux; - - Assert (_ns->EditType (xd->name, xd) == 1, "What?"); - return xd; + pending = 0; + recursion_depth--; + return this; } diff --git a/act/types.h b/act/types.h index b66632b7..ce93d6e8 100644 --- a/act/types.h +++ b/act/types.h @@ -1176,6 +1176,13 @@ class Function : public UserDef { } return false; } + + /** + * The user-defined types in the function argument list are all + * template parameters; convert them from the port list to the + * template list. + */ + void convPortsToParams (); private: InstType *ret_type; ///< holds return type From b8ac4be875047af06930706d2f17de245b5fcb40 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Sun, 20 Apr 2025 11:45:58 -0400 Subject: [PATCH 03/49] missing type-checking case --- act/check.cc | 22 +++++++++++++++++++++- act/lang_chp.cc | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/act/check.cc b/act/check.cc index b9f533cf..18cafd55 100644 --- a/act/check.cc +++ b/act/check.cc @@ -714,11 +714,13 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) typecheck_err ("Bitfield range is empty {%d..%d}", hi, lo); return T_ERR; } +#if 0 if ((TypeFactory::bitWidth (xit) >= 0 && hi+1 > TypeFactory::bitWidth (xit)) || lo < 0) { typecheck_err ("Bitfield range {%d..%d} is wider than operand (%d)", hi, lo, TypeFactory::bitWidth (xit)); return T_ERR; } +#endif if (width) { *width = hi - lo + 1; } @@ -757,11 +759,13 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) typecheck_err ("Bitfield range is empty {%d..%d}", hi, lo); return T_ERR; } +#if 0 if ((TypeFactory::bitWidth (xit) >= 0 && hi+1 > TypeFactory::bitWidth (xit)) || lo < 0) { typecheck_err ("Bitfield range {%d..%d} is wider than operand (%d)", hi, lo, TypeFactory::bitWidth (xit)); return T_ERR; } +#endif if (width) { *width = hi - lo + 1; } @@ -907,7 +911,7 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) } if (!x->isConnectable (y, 1)) { - if ((TypeFactory::isIntType (x) && + if (((TypeFactory::isIntType (x) || TypeFactory::isEnum (x)) && (TypeFactory::isPIntType (y) || TypeFactory::isIntType (y))) || (TypeFactory::isBoolType (x) && TypeFactory::isPBoolType (y))) { @@ -919,6 +923,22 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) return T_ERR; } } + + if ((x->arrayInfo() && !y->arrayInfo()) || + (y->arrayInfo() && !x->arrayInfo())) { + typecheck_err ("Function `%s': arg #%d has an incompatible type", + fn->getName(), i); + return T_ERR; + } + else if (x->arrayInfo() && + y->arrayInfo() && x->arrayInfo()->isExpanded()) { + if (!x->arrayInfo()->isEqual (y->arrayInfo(), 0)) { + typecheck_err ("Function `%s': arg #%d has an incompatible type", + fn->getName(), i); + return T_ERR; + } + } + tmp = tmp->u.e.r; } diff --git a/act/lang_chp.cc b/act/lang_chp.cc index e5e73b9a..1bf419d5 100644 --- a/act/lang_chp.cc +++ b/act/lang_chp.cc @@ -1929,9 +1929,24 @@ static act_chp_lang_t *chp_expand_1 (act_chp_lang_t *c, ActNamespace *ns, Scope // also be fixed like STRUCT_REF Expr *te = chp_expr_expand (c->u.assign.e, ns, s); + list_t *xassign = chp_expr_unstruct (s, te); ret->u.assign.e = te; + + if (_chp_expanding_macro == 0) { + int tr = act_type_expr (s, te, NULL, 2); + if (tr == T_ERR) { + fprintf (stderr, "Typechecking failed on CHP assignment\n"); + fprintf (stderr, " stmt: "); + ret->u.assign.id->Print (stderr, NULL); + fprintf (stderr, " := "); + print_uexpr (stderr, c->u.assign.e); + fprintf (stderr, "\n\t%s\n", act_type_errmsg ()); + exit (1); + } + } + if (xassign) { ret->label = NULL; list_append (xassign, ret); From 2f660fbe13778a69a7fd5f13db272882a407bc5c Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 21 Apr 2025 09:14:12 -0400 Subject: [PATCH 04/49] more array inlining fixes --- act/act_array.h | 8 + act/array.cc | 7 + act/expr2.cc | 8 +- act/func.cc | 28 +- act/inline.cc | 333 ++++++++++++++---- act/inline.h | 33 +- passes/finline/finline.cc | 111 ++++-- transform/testing/inline/test/40.act | 22 ++ transform/testing/inline/test/41.act | 25 ++ transform/testing/inline/test/42.act | 20 ++ .../testing/inline/test/runs/40.act.stderr | 0 .../testing/inline/test/runs/40.act.stdout | 37 ++ .../testing/inline/test/runs/41.act.stderr | 0 .../testing/inline/test/runs/41.act.stdout | 42 +++ .../testing/inline/test/runs/42.act.stderr | 0 .../testing/inline/test/runs/42.act.stdout | 32 ++ 16 files changed, 599 insertions(+), 107 deletions(-) create mode 100644 transform/testing/inline/test/40.act create mode 100644 transform/testing/inline/test/41.act create mode 100644 transform/testing/inline/test/42.act create mode 100644 transform/testing/inline/test/runs/40.act.stderr create mode 100644 transform/testing/inline/test/runs/40.act.stdout create mode 100644 transform/testing/inline/test/runs/41.act.stderr create mode 100644 transform/testing/inline/test/runs/41.act.stdout create mode 100644 transform/testing/inline/test/runs/42.act.stderr create mode 100644 transform/testing/inline/test/runs/42.act.stdout diff --git a/act/act_array.h b/act/act_array.h index a85914a2..58a60270 100644 --- a/act/act_array.h +++ b/act/act_array.h @@ -350,6 +350,14 @@ class Array { */ Expr *getDeref (int idx); + /** + * Must be called on an expanded array that is in fact an array + * dereference, and where the de-reference is non-const + * @param idx is the dimension of the array of interest + * @param e is the updated expression for the de-reference + */ + void setDeref (int idx, Expr *e); + /** * Given an array deference or subrange, returns the offset for the * first element of the sub-range/dereference in the standard linear diff --git a/act/array.cc b/act/array.cc index bfa8e25d..dc9c04cd 100644 --- a/act/array.cc +++ b/act/array.cc @@ -1036,6 +1036,13 @@ Expr *Array::getDeref (int idx) } } +void Array::setDeref (int idx, Expr *e) +{ + Assert (0 <= idx && idx < dims, "Invalid dimension"); + Assert (r[idx].u.ex.isrange == 2, "Updating only for non-const derefs"); + r[idx].u.ex.deref = e; +} + /*------------------------------------------------------------------------ * * Array::stepper -- diff --git a/act/expr2.cc b/act/expr2.cc index e3d4c0da..20bd9738 100644 --- a/act/expr2.cc +++ b/act/expr2.cc @@ -2815,7 +2815,13 @@ static int _expr_bw_calc(struct pHashtable *H, Expr *e, Scope *s) { InstType *xit; lw = act_type_var (s, (ActId *)e->u.e.l, &xit); - width = TypeFactory::bitWidth (xit); + if (xit->arrayInfo() && !((ActId *)e->u.e.l)->arrayInfo()) { + // not a de-reference + width = -1; + } + else { + width = TypeFactory::bitWidth (xit); + } } break; diff --git a/act/func.cc b/act/func.cc index b2caf2fe..610c98f0 100644 --- a/act/func.cc +++ b/act/func.cc @@ -129,12 +129,14 @@ act_inline_value Function::toInline (int nargs, act_inline_value *args) for (it = it.begin(); it != it.end(); it++) { ValueIdx *vx = (*it); if (TypeFactory::isParamType (vx->t)) continue; +#if 0 if (vx->t->arrayInfo()) { act_error_ctxt (stderr); warning ("Inlining failed; array declarations!"); act_error_pop (); return ret; } +#endif } /* @@ -169,9 +171,9 @@ act_inline_value Function::toInline (int nargs, act_inline_value *args) act_error_ctxt (stderr); fatal_error ("toInline(): arg #%d is a non-structure argument to structure field?", i); } - if (!args[i].is_struct_id && (nb + ni != args[i].numElems())) { + if (!args[i].is_just_id && (nb + ni != args[i].numStructElems())) { act_error_ctxt (stderr); - fatal_error ("toInline(): arg #%d structure count mismatch (%d vs %d)", i, nb + ni, args[i].numElems()); + fatal_error ("toInline(): arg #%d structure count mismatch (%d vs %d)", i, nb + ni, args[i].numStructElems()); } } else { @@ -180,6 +182,17 @@ act_inline_value Function::toInline (int nargs, act_inline_value *args) fatal_error ("toInline(): arg #%d is a structure argument to a non-struct field?", i); } } + if (getPortType (i)->arrayInfo()) { + if (!args[i].is_array) { + act_error_ctxt (stderr); + fatal_error ("toInline(): arg #%d is a non-array argument to array field?", i); + } + if (!args[i].is_just_id && getPortType(i)->arrayInfo()->size () != + args[i].numArrayElems()) { + act_error_ctxt (stderr); + fatal_error ("toInline(): arg #%d array count mismatch (%d vs %d)", i, getPortType (i)->arrayInfo()->size(), args[i].numArrayElems()); + } + } Assert (i < getNumPorts(), "Hmm..."); @@ -194,7 +207,7 @@ act_inline_value Function::toInline (int nargs, act_inline_value *args) printf (" > %p", args[i].u.val); } printf ("\n"); -#endif +#endif delete tmp; } @@ -312,9 +325,18 @@ void Function::_chk_inline (Expr *e) case E_TRUE: case E_FALSE: case E_REAL: + break; + case E_VAR: case E_PROBE: case E_BITFIELD: + { + ActId *id = (ActId *)e->u.e.l; + if (id->isDynamicDeref ()) { + is_simple_inline = 0; + return; + } + } break; case E_FUNCTION: diff --git a/act/inline.cc b/act/inline.cc index 60702d6f..b92829b5 100644 --- a/act/inline.cc +++ b/act/inline.cc @@ -123,16 +123,19 @@ void act_dump_table (act_inline_table *tab) static act_inline_value _lookup_binding (act_inline_table *Hs, - const char *name, ActId *rest, int err = 1) + const char *name, + Array *deref, + ActId *rest, int err = 1) { hash_bucket_t *b; act_inline_table *origHs = Hs; act_inline_value rv; + while (Hs) { b = hash_lookup (Hs->state, name); if (b) { int ni, nb; - int sz = 1; + int sz, array_sz; InstType *it = Hs->sc->Lookup (name); Data *d = NULL; @@ -146,6 +149,18 @@ _lookup_binding (act_inline_table *Hs, d->getStructCount (&nb, &ni); sz = nb + ni; } + else { + sz = -1; + } + + if (it->arrayInfo()) { + // XXX: deal with deref + array_sz = it->arrayInfo()->size(); + } + else { + array_sz = -1; + } + /* return a copy */ act_inline_value bval; bval = *((act_inline_value *)b->v); @@ -160,16 +175,29 @@ _lookup_binding (act_inline_table *Hs, Assert (off + sz2 <= sz, "What?"); Assert (sz2 > 0, "Hmm"); + int array_off = 0; + + if (array_sz != -1) { + Assert (deref, "Array var without deref?"); + array_off = it->arrayInfo()->Offset (deref); + act_error_ctxt (stderr); + fatal_error ("Access to index that is out of bounds in _lookup!"); + } + Assert (bval.is_struct, "What?"); - if (sz2 == 1) { - /* XXX: FIXME. This may or may not be a structure */ + // get type of the "rest" + InstType *rit; + act_type_var (d->CurScope(), rest, &rit); + Assert (rit, "Hmm"); + + if (sz2 == 1 && !TypeFactory::isStructure (rit)) { rv.is_struct = 0; } else { rv.is_struct = 1; } - rv.is_struct_id = 0; + rv.is_just_id = 0; if (rv.is_struct) { MALLOC (rv.u.arr, Expr *, sz2); rv.struct_count = sz2; @@ -192,6 +220,9 @@ _lookup_binding (act_inline_table *Hs, } Assert (bval.getVal()->type == E_VAR, "Hmm"); xnew = ((ActId *)bval.getVal()->u.e.l)->Clone (); + if (deref) { + xnew->Tail()->setArray (deref->Clone()); + } xnew->Tail()->Append (fields[i+off]->Clone()); NEW (bind_val, Expr); bind_val->type = E_VAR; @@ -199,7 +230,7 @@ _lookup_binding (act_inline_table *Hs, bind_val->u.e.l = (Expr *)xnew; } else { - bind_val = bval.u.arr[i+off]; + bind_val = bval.u.arr[array_off*sz+i+off]; } if (rv.is_struct) { rv.u.arr[i] = bind_val; @@ -222,11 +253,44 @@ _lookup_binding (act_inline_table *Hs, FREE (fields); } } + else if (deref) { + if (bval.isSimple()) { + ActId *xnew; + if (bval.getVal()->type != E_VAR) { + fprintf (stderr, " PTR is %p\n", bval.getVal()); + bval.Print (stderr); + fprintf (stderr, "\n"); + } + Assert (bval.getVal()->type == E_VAR, "Hmm"); + xnew = ((ActId *)bval.getVal()->u.e.l)->Clone (); + xnew->Tail()->setArray (deref->Clone()); + + Expr *bind_val; + NEW (bind_val, Expr); + bind_val->type = E_VAR; + bind_val->u.e.r = NULL; + bind_val->u.e.l = (Expr *)xnew; + rv.u.val = bind_val; + rv.is_just_id = 1; + } + else { + int array_off = it->arrayInfo()->Offset (deref); + Assert (array_off != -1, "Out of bounds?"); + rv.u.val = bval.u.arr[array_off]; + if (rv.u.val->type == E_VAR) { + rv.is_just_id = 1; + } + } + } else { + // either simple ID access or structure access rv = bval; if (!bval.isSimple()) { - Assert (bval.struct_count == sz, "What?"); - MALLOC (rv.u.arr, Expr *, bval.struct_count); + Assert (sz == -1 || bval.struct_count == sz, "What?"); + Assert (array_sz == -1 || bval.array_sz == array_sz, "What?!"); + MALLOC (rv.u.arr, Expr *, + (sz == -1 ? 1 : bval.struct_count)* + (array_sz == -1 ? 1 : bval.array_sz)); for (int i=0; i < sz; i++) { rv.u.arr[i] = bval.u.arr[i]; if (err) { @@ -318,6 +382,7 @@ static void _update_binding (act_inline_table *Hs, ActId *id, int sz = 1; Data *xd; int *widths; + Array *deref = id->arrayInfo(); #if 0 printf ("update binding for: "); @@ -363,7 +428,7 @@ static void _update_binding (act_inline_table *Hs, ActId *id, b = hash_lookup (Hs->state, id->getName()); if (!b) { act_inline_value lv, bindv; - lv = _lookup_binding (Hs, id->getName(), NULL, 0); + lv = _lookup_binding (Hs, id->getName(), id->arrayInfo(), NULL, 0); #if 0 printf ("I'm here, lv = "); lv.Print (stdout); @@ -372,13 +437,13 @@ static void _update_binding (act_inline_table *Hs, ActId *id, if (lv.isValid()) { // found a valid binding bindv = lv; - if (bindv.isSimple() && xd) { -#if 0 + if (bindv.isSimple() && (xd || xit->arrayInfo())) { +#if 0 printf ("| populate and elaborate binding\n"); #endif // structure, elaborate the binding - bindv.elaborateStructId (xd); -#if 0 + bindv.elaborateStructId (xd, xit->arrayInfo()); +#if 0 printf ("| "); bindv.Print (stdout); printf ("\n"); @@ -387,38 +452,67 @@ static void _update_binding (act_inline_table *Hs, ActId *id, } else { // create a dummy NULL binding - if (xd) { - bindv.is_struct = 1; - bindv.struct_count = sz; - MALLOC (bindv.u.arr, Expr *, sz); - for (int i=0; i < sz; i++) { + if (xd || xit->arrayInfo()) { + if (xd) { + bindv.is_struct = 1; + bindv.struct_count = sz; + } + + if (xit->arrayInfo()) { + bindv.is_array = 1; + bindv.array_sz = xit->arrayInfo()->size(); + } + + MALLOC (bindv.u.arr, Expr *, sz*(bindv.is_array ? bindv.array_sz : 1)); + + for (int i=0; i < sz*(bindv.is_array ? bindv.array_sz : 1); i++) { bindv.u.arr[i] = NULL; } + +#if 0 + printf ("| "); + bindv.Print (stdout); + printf ("\n"); +#endif } } b = hash_add (Hs->state, id->getName()); /* add int(.) wrapper if needed */ - if (xd) { - for (int i=0; i < sz; i++) { - if (!Hs->macro_mode && bindv.u.arr[i] && widths[i] > 0) { - bindv.u.arr[i] = _wrap_width (bindv.u.arr[i], widths[i]); + if (xd || xit->arrayInfo()) { + int tot = sz * (bindv.is_array ? bindv.array_sz : 1); + for (int i=0; i < tot; i++) { + if (!Hs->macro_mode && bindv.u.arr[i]) { + if (xd) { + if (widths[i % sz] > 0) { + bindv.u.arr[i] = _wrap_width (bindv.u.arr[i], widths[i]); + } + } + else { + if (widths[0] > 0) { + bindv.u.arr[i] = _wrap_width (bindv.u.arr[i], widths[0]); + } + } } } } else { if (!Hs->macro_mode && bindv.u.val && widths[0] > 0) { bindv.u.val = _wrap_width (bindv.u.val, widths[0]); + bindv.is_just_id = 0; } } b->v = new act_inline_value(); *((act_inline_value *)b->v) = bindv; - } - act_inline_value resv = _lookup_binding (Hs, id->getName(), NULL, 0); - if (id->Rest()) { - Assert (xd, "What?!"); - int sz2; +#if 0 + printf ("F| "); + bindv.Print (stdout); + printf ("\n"); +#endif + } + act_inline_value resv = _lookup_binding (Hs, id->getName(), + id->arrayInfo(), NULL, 0); #if 0 printf (" >> update scenario:\n "); @@ -429,12 +523,21 @@ static void _update_binding (act_inline_table *Hs, ActId *id, printf ("\n"); #endif + if (id->Rest()) { + Assert (xd, "What?!"); + int sz2; + int off = xd->getStructOffset (id->Rest(), &sz2); + int array_off = 0; + if (deref) { + array_off = xit->arrayInfo()->Offset (deref); + Assert (array_off != -1, "Invalid array index?"); + } Assert (off >= 0 && off < sz, "What?"); Assert (off + sz2 <= sz, "What?"); Assert (!update.isSimple() || sz2 == 1, "Hmm"); if (resv.isSimple()) { - resv.elaborateStructId (xd); + resv.elaborateStructId (xd, xit->arrayInfo()); } Assert (!resv.isSimple(), "Hmm"); for (int i=0; i < sz2; i++) { @@ -446,10 +549,10 @@ static void _update_binding (act_inline_table *Hs, ActId *id, updatev = update.u.arr[i]; } if (!Hs->macro_mode && updatev && widths[off+i] > 0) { - resv.u.arr[off+i] = _wrap_width (updatev, widths[off+i]); + resv.u.arr[array_off*sz + off+i] = _wrap_width (updatev, widths[off+i]); } else { - resv.u.arr[off+i] = updatev; + resv.u.arr[array_off*sz + off+i] = updatev; } #if 0 printf ("set offset %d to ", off+i); @@ -476,31 +579,64 @@ static void _update_binding (act_inline_table *Hs, ActId *id, #endif } else { - if (xd) { - if (update.isSimple()) { + if (xd || deref) { + if (update.isSimple() && !deref) { resv = update; } else { if (resv.isSimple()) { - resv.elaborateStructId (xd); + resv.elaborateStructId (xd, xit->arrayInfo()); + } + int array_off = 0; + if (deref) { + array_off = xit->arrayInfo()->Offset (deref); + Assert (array_off != -1, "Out of bounds"); } - for (int i=0; i < sz; i++) { - if (!Hs->macro_mode && update.u.arr[i] && widths[i] > 0) { - resv.u.arr[i] = _wrap_width (update.u.arr[i], widths[i]); + if (xd) { + for (int i=0; i < sz; i++) { + if (!Hs->macro_mode && update.u.arr[i] && widths[i] > 0) { + resv.u.arr[array_off*sz + i] = _wrap_width (update.u.arr[i], widths[i]); + } + else { + resv.u.arr[array_off*sz + i] = update.u.arr[i]; + } + } + } + else { + if (!Hs->macro_mode && update.u.val && widths[0] > 0) { + resv.u.arr[array_off] = _wrap_width (update.u.val, widths[0]); } else { - resv.u.arr[i] = update.u.arr[i]; + resv.u.arr[array_off] = update.u.val; } } } } else { Assert (update.isSimple(), "Hmm"); - if (!Hs->macro_mode && update.u.val && widths[0] > 0) { - resv.u.val = _wrap_width (update.u.val, widths[0]); + + if (resv.isValid()) { + if (resv.isSimple()) { + resv.u.val = update.u.val; + resv.is_just_id = update.is_just_id; + } + else { + if (resv.u.arr) { + FREE (resv.u.arr); + } + resv.u.val = update.u.val; + resv.is_just_id = update.is_just_id; + } } else { - resv.u.val = update.u.val; + resv = update; + } + + if (!Hs->macro_mode && update.u.val && widths[0] > 0) { + if (!xit->arrayInfo()) { + resv.u.val = _wrap_width (resv.u.val, widths[0]); + resv.is_just_id = 0; + } } } } @@ -580,6 +716,7 @@ static act_inline_value _expand_inline (act_inline_table *Hs, Expr *e, int recur only */ { lv = _lookup_binding (Hs, ((ActId *)e->u.e.l)->getName(), + ((ActId *)e->u.e.l)->arrayInfo(), ((ActId *)e->u.e.l)->Rest()); Assert (lv.isSimple(), "What?"); Expr *r = lv.getVal(); @@ -738,7 +875,7 @@ static act_inline_value _expand_inline (act_inline_table *Hs, Expr *e, int recur break; case E_SELF: - retv = _lookup_binding (Hs, "self", NULL); + retv = _lookup_binding (Hs, "self", NULL, NULL); break; case E_SELF_ACK: @@ -748,7 +885,8 @@ static act_inline_value _expand_inline (act_inline_table *Hs, Expr *e, int recur case E_VAR: { ActId *tid = (ActId *)e->u.e.l; - retv = _lookup_binding (Hs, tid->getName(), tid->Rest()); + retv = _lookup_binding (Hs, tid->getName(), + tid->arrayInfo(), tid->Rest()); } break; @@ -806,7 +944,7 @@ act_inline_table *act_inline_merge_tables (int nT, act_inline_table **T, act_inline_value vl; /* vl is the value before the merge, in the parent context */ - vl = _lookup_binding (Tret, b->key, NULL, 0); + vl = _lookup_binding (Tret, b->key, NULL, NULL, 0); InstType *et = sc->Lookup (b->key); Assert (et, "What?"); @@ -969,7 +1107,7 @@ void act_inline_setval (act_inline_table *Hs, ActId *id, act_inline_value act_inline_getval (act_inline_table *Hs, const char *s) { - return _lookup_binding (Hs, s, NULL); + return _lookup_binding (Hs, s, NULL, NULL); } @@ -979,17 +1117,41 @@ void act_inline_value::Print (FILE *fp) fprintf (fp, "@invalid@"); return; } + if (is_array && !is_just_id) { + fprintf (fp, "@arr[%d]", array_sz); + } fprintf (fp, "@%s", is_struct ? "struct" : "elem"); if (is_struct) { - if (is_struct_id) { + if (is_just_id) { fprintf (fp, " id: "); print_uexpr (fp, u.val); } else { fprintf (fp, "%d ", struct_count); - for (int i=0; i < struct_count; i++) { + for (int j=0; j < (array_sz == 0 ? 1 : array_sz); j++) { + if (j != 0) { + fprintf(fp, " | "); + } + for (int i=0; i < struct_count; i++) { + if (i != 0) { + fprintf (fp, " ; "); + } + if (u.arr[i+j*struct_count]) { + print_uexpr (fp, u.arr[i+j*struct_count]); + } + else { + fprintf (fp, "nul"); + } + } + } + } + } + else { + fprintf (fp, " "); + if (is_array && !is_just_id) { + for (int i=0; i < array_sz; i++) { if (i != 0) { - fprintf (fp, " ; "); + fprintf (fp, " | "); } if (u.arr[i]) { print_uexpr (fp, u.arr[i]); @@ -999,44 +1161,77 @@ void act_inline_value::Print (FILE *fp) } } } - } - else { - fprintf (fp, " "); - print_uexpr (fp, u.val); + else { + print_uexpr (fp, u.val); + } } fprintf (fp, "@"); } -void act_inline_value::elaborateStructId (Data *d) +void act_inline_value::elaborateStructId (Data *d, Array *a) { Assert (isSimple(), "hmm"); Assert (is_struct, "What?"); ActId **fields; - int *types; ActId *baseid; int ni, nb; - d->getStructCount (&nb, &ni); - int sz = ni + nb; - fields = d->getStructFields (&types); - FREE (types); + int sz; + + if (d) { + int *types; + d->getStructCount (&nb, &ni); + sz = ni + nb; + fields = d->getStructFields (&types); + FREE (types); + } + else { + sz = 1; + fields = NULL; + } Assert (getVal()->type == E_VAR, "Hmm"); baseid = (ActId *)getVal()->u.e.l; - MALLOC (u.arr, Expr *, sz); + + if (a) { + is_array = 1; + array_sz = a->size(); + MALLOC (u.arr, Expr *, sz*array_sz); + } + else { + is_array = 0; + array_sz = 0; + MALLOC (u.arr, Expr *, sz); + } struct_count = sz; - is_struct_id = 0; - - for (int i=0; i < sz; i++) { - ActId *varnew; - NEW (u.arr[i], Expr); - u.arr[i]->type = E_VAR; - u.arr[i]->u.e.r = NULL; - varnew = baseid->Clone(); - varnew->Append (fields[i]); - u.arr[i]->u.e.l = (Expr *) varnew; + is_just_id = 0; + + for (int arr=0; arr < (array_sz == 0 ? 1 : array_sz); arr++) { + Array *newa; + + if (a) { + newa = a->unOffset (arr); + } + else { + newa = NULL; + } + + for (int i=0; i < sz; i++) { + ActId *varnew; + NEW (u.arr[arr*sz + i], Expr); + u.arr[arr*sz + i]->type = E_VAR; + u.arr[arr*sz + i]->u.e.r = NULL; + varnew = baseid->Clone(); + if (fields) { + varnew->Append (fields[i]); + } + varnew->setArray (newa); + u.arr[arr*sz + i]->u.e.l = (Expr *) varnew; + } + } + if (fields) { + FREE (fields); } - FREE (fields); Assert (!isSimple(), "Hmm{"); Assert (isValid(), "Check"); } diff --git a/act/inline.h b/act/inline.h index 296e126d..de785878 100644 --- a/act/inline.h +++ b/act/inline.h @@ -1,6 +1,6 @@ /************************************************************************* * - * Copyright (c) 2021 Rajit Manohar + * Copyright (c) 2021, 2025 Rajit Manohar * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -29,10 +29,11 @@ class Data; struct act_inline_table; struct act_inline_value { act_inline_value() { + is_just_id = 0; is_struct = 0; - is_struct_id = 0; struct_count = 0; - is_top_arr = 0; + is_array = 0; + array_sz = 0; u.val = NULL; } @@ -46,24 +47,26 @@ struct act_inline_value { Expr *getVal() { return u.val; } bool isSimple() { - if (is_struct == 0 || is_struct_id) return true; + if ((is_struct == 0 && is_array == 0) || is_just_id) return true; return false; } - void elaborateStructId (Data *d); + void elaborateStructId (Data *d, Array *a = NULL); - int numElems() { return struct_count; } + int numStructElems() { return struct_count; } + int numArrayElems() { return array_sz; } // check if there is some legitimate binding stored here bool isValid() { if (isSimple()) { + // the binding is stored in u.val if (u.val == NULL) return false; - if (is_struct) { + if (is_just_id) { if (u.val->type != E_VAR) return false; } return true; } - if (struct_count == 0) return false; + if (struct_count == 0 && array_sz == 0) return false; if (u.arr == NULL) return false; return true; } @@ -71,8 +74,10 @@ struct act_inline_value { // check if everthing is valid bool isValidFull() { if (!isValid()) return false; - if (is_struct && !is_struct_id) { - for (int i=0; i < struct_count; i++) { + if (!is_just_id) { + int tot = (struct_count == 0 ? 1 : struct_count) * + (array_sz == 0 ? 1 : array_sz); + for (int i=0; i < tot; i++) { if (u.arr[i] == NULL) return false; } } @@ -82,9 +87,11 @@ struct act_inline_value { void Print (FILE *fp); unsigned int is_struct:1; /* is this a structure? */ - unsigned int is_struct_id:1; /* special case structure, ID map */ - unsigned int is_top_arr:1; /* is this an array? */ - unsigned int struct_count:29; /* size of array for sanity checking */ + unsigned int is_array:1; /* this is an array */ + unsigned int is_just_id:1; /* special case, ID */ + unsigned int struct_count:30; /* size of flattened struct for sanity checking */ + unsigned int array_sz:30; /* array size, if any */ + union { Expr *val; /* single value */ Expr **arr; /* flattened array of values */ diff --git a/passes/finline/finline.cc b/passes/finline/finline.cc index aa449c4d..20c30852 100644 --- a/passes/finline/finline.cc +++ b/passes/finline/finline.cc @@ -215,7 +215,10 @@ act_inline_value ActCHPFuncInline::_inline_funcs (list_t *l, Expr *e) case E_SELF: case E_SELF_ACK: case E_PROBE: + break; + case E_VAR: + retv.is_just_id = 1; break; default: @@ -268,10 +271,14 @@ act_inline_value ActCHPFuncInline::_inline_funcs_general (list_t *l, Expr *e) ACT_EXPR_EXFLAG_DUPONLY|ACT_EXPR_EXFLAG_CHPEX); arglist[args++] = _inline_funcs (l, ex); + // this computes a pure inlined expression value + // now we need to set various flags if (TypeFactory::isStructure (fx->getPortType (args-1))) { - arglist[args-1].is_struct_id = 1; arglist[args-1].is_struct = 1; } + if (fx->getPortType (args-1)->arrayInfo()) { + arglist[args-1].is_array = 1; + } Assert (arglist[args-1].isValid(), "What?"); tmp = tmp->u.e.r; } @@ -1343,6 +1350,8 @@ void ActCHPFuncInline::_apply_complex_inlines (list_t *l, Expr *e) return; } +static Expr *_expr_clone_subst (struct fn_inline_args *fn, Expr *e); + static ActId *_find_subst (struct fn_inline_args *fn, ActId *id) { ActId *repl; @@ -1371,6 +1380,20 @@ static ActId *_find_subst (struct fn_inline_args *fn, ActId *id) if (id && id->Rest()) { repl->Append (id->Rest()->Clone()); } + + /*-- there might be arrays here, so include them --*/ + if (id && id->arrayInfo()) { + Array *c = id->arrayInfo()->Clone (); + + /* substitute any array derefs here as well */ + for (int i=0; i < c->nDims(); i++) { + Expr *e = c->getDeref (i); + if (e->type != E_INT) { + c->setDeref (i, _expr_clone_subst (fn, e)); + } + } + repl->setArray (c); + } return repl; } @@ -1607,36 +1630,82 @@ act_chp_lang_t *ActCHPFuncInline::_do_inline (struct pHashtable *H, /* -- inline this function -- */ for (int i=0; i < fn->fx->getNumPorts(); i++) { - NEW (tmpc, act_chp_lang_t); - tmpc->label = NULL; - tmpc->space = NULL; - tmpc->type = ACT_CHP_ASSIGN; - tmpc->u.assign.id = fn->args[i]->Clone(); - tmpc->u.assign.e = req->args[i]; - list_append (c->u.semi_comma.cmd, tmpc); + + if (fn->fx->getPortType (i)->arrayInfo()) { + // array assignment! + Array *xa = fn->fx->getPortType (i)->arrayInfo(); + for (int j=0; j < xa->size(); j++) { + Array *a = xa->unOffset (j); + NEW (tmpc, act_chp_lang_t); + tmpc->label = NULL; + tmpc->space = NULL; + tmpc->type = ACT_CHP_ASSIGN; + tmpc->u.assign.id = fn->args[i]->Clone (); + tmpc->u.assign.id->setArray (a); + if (req->args[i]->type != E_VAR) { + act_error_ctxt (stderr); + fatal_error ("Failed in complex inline in the presence of arrays?"); + } + tmpc->u.assign.e = expr_dup (req->args[i]); + Assert (((ActId *)tmpc->u.assign.e->u.e.l)->arrayInfo() == NULL, + "Hmm..."); + ((ActId *)tmpc->u.assign.e->u.e.l)->setArray (a->Clone ()); + list_append (c->u.semi_comma.cmd, tmpc); + } + } + else { + NEW (tmpc, act_chp_lang_t); + tmpc->label = NULL; + tmpc->space = NULL; + tmpc->type = ACT_CHP_ASSIGN; + tmpc->u.assign.id = fn->args[i]->Clone(); + tmpc->u.assign.e = req->args[i]; + list_append (c->u.semi_comma.cmd, tmpc); + } } list_append (c->u.semi_comma.cmd, _chp_clone_subst (fn, fn->fx->getlang()->getchp()->c)); - NEW (tmpc, act_chp_lang_t); - tmpc->label = NULL; - tmpc->space = NULL; - tmpc->type = ACT_CHP_ASSIGN; - NEW (tmpc->u.assign.e, Expr); - tmpc->u.assign.e->type = E_VAR; - tmpc->u.assign.e->u.e.r = NULL; - tmpc->u.assign.e->u.e.l = (Expr *) fn->ret->Clone(); - + // return value int idx = _get_fresh_idx ("fuse", &_useidx); char buf[1024]; snprintf (buf, 1024, "fuse_%d", idx); Assert (_cursc->Add (buf, fn->fx->getRetType()) == 1, "Hmm"); - tmpc->u.assign.id = new ActId (buf); - list_append (l, new ActId (buf)); - list_append (c->u.semi_comma.cmd, tmpc); - + if (fn->fx->getRetType()->arrayInfo()) { + Array *xa = fn->fx->getRetType()->arrayInfo(); + for (int j=0; j < xa->size(); j++) { + Array *a = xa->unOffset (j); + NEW (tmpc, act_chp_lang_t); + tmpc->label = NULL; + tmpc->space = NULL; + tmpc->type = ACT_CHP_ASSIGN; + NEW (tmpc->u.assign.e, Expr); + tmpc->u.assign.e->type = E_VAR; + tmpc->u.assign.e->u.e.r = NULL; + tmpc->u.assign.e->u.e.l = (Expr *) fn->ret->Clone(); + Assert (tmpc->u.assign.e->u.e.l->type == E_VAR, "What?"); + Assert (((ActId*)tmpc->u.assign.e->u.e.l->u.e.l)->arrayInfo() == NULL, "Huh?"); + ((ActId*)tmpc->u.assign.e->u.e.l->u.e.l)->setArray (a); + tmpc->u.assign.id = new ActId (buf); + tmpc->u.assign.id->setArray (a->Clone ()); + list_append (c->u.semi_comma.cmd, tmpc); + } + } + else { + NEW (tmpc, act_chp_lang_t); + tmpc->label = NULL; + tmpc->space = NULL; + tmpc->type = ACT_CHP_ASSIGN; + NEW (tmpc->u.assign.e, Expr); + tmpc->u.assign.e->type = E_VAR; + tmpc->u.assign.e->u.e.r = NULL; + tmpc->u.assign.e->u.e.l = (Expr *) fn->ret->Clone(); + tmpc->u.assign.id = new ActId (buf); + list_append (c->u.semi_comma.cmd, tmpc); + } + list_append (l, new ActId (buf)); } len--; } diff --git a/transform/testing/inline/test/40.act b/transform/testing/inline/test/40.act new file mode 100644 index 00000000..8526dc6b --- /dev/null +++ b/transform/testing/inline/test/40.act @@ -0,0 +1,22 @@ +function testme (int x[4]) : int +{ + int a; + chp { + a := 3; + self := x[a] + } +} + + + +defproc test() +{ + int w[4]; + int a; + + chp { + a := testme (w) + } +} + +test t; diff --git a/transform/testing/inline/test/41.act b/transform/testing/inline/test/41.act new file mode 100644 index 00000000..c15de54c --- /dev/null +++ b/transform/testing/inline/test/41.act @@ -0,0 +1,25 @@ +deftype mystruct(int<4> a, b) +{ } + +function swap(mystruct m) : mystruct +{ + chp { + self.a := m.b; + self.b := m.a + } +} + +defproc test() +{ + mystruct m; + int y; + + chp { + m.a := 0x1; + m.b := 0x2; + m := swap(swap(m)); + skip + } +} + +test t; diff --git a/transform/testing/inline/test/42.act b/transform/testing/inline/test/42.act new file mode 100644 index 00000000..95698833 --- /dev/null +++ b/transform/testing/inline/test/42.act @@ -0,0 +1,20 @@ +function testme (int x[4]) : int +{ + chp { + self := x[3] + } +} + + + +defproc test() +{ + int w[4]; + int a; + + chp { + a := testme (w) + } +} + +test t; diff --git a/transform/testing/inline/test/runs/40.act.stderr b/transform/testing/inline/test/runs/40.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/testing/inline/test/runs/40.act.stdout b/transform/testing/inline/test/runs/40.act.stdout new file mode 100644 index 00000000..f5a15af5 --- /dev/null +++ b/transform/testing/inline/test/runs/40.act.stdout @@ -0,0 +1,37 @@ +defproc test (); +function testme (int<32> x[4]) : int<32>; + +defproc test () +{ + +/* instances */ +int<32> fuse_0; +int<32> farg_0[4]; +int<32> a; +int<32> w[4]; +int<32> floc_0; +int<32> fret_0; + +/* connections */ +chp { +farg_0[0]:=w[0];farg_0[1]:=w[1];farg_0[2]:=w[2];farg_0[3]:=w[3];floc_0:=0x3;fret_0:=farg_0[floc_0];fuse_0:=fret_0;a:=fuse_0 +} +} + +function testme (int<32> x[4]) : int<32> +{ + +/* instances */ +int<32> a; + +/* connections */ +chp { +a:=0x3;self:=x[a] +} +} + + +/* instances */ +test t; + +/* connections */ diff --git a/transform/testing/inline/test/runs/41.act.stderr b/transform/testing/inline/test/runs/41.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/testing/inline/test/runs/41.act.stdout b/transform/testing/inline/test/runs/41.act.stdout new file mode 100644 index 00000000..da9d1511 --- /dev/null +++ b/transform/testing/inline/test/runs/41.act.stdout @@ -0,0 +1,42 @@ +defproc test (); +function swap (mystruct m) : mystruct; +deftype mystruct (int<4> a; int<4> b); + +defproc test () +{ + +/* instances */ +mystruct _us_0; +int<32> y; +mystruct m; + +/* connections */ +chp { +m.a:=0x1;m.b:=0x2;_us_0.a:=int(m.a,4);_us_0.b:=int(m.b,4);m.a:=_us_0.a;m.b:=_us_0.b;skip +} +} + +function swap (mystruct m) : mystruct +{ + +/* instances */ + +/* connections */ +chp { +self.a:=m.b;self.b:=m.a +} +} + +deftype mystruct (int<4> a; int<4> b) +{ + +/* instances */ + +/* connections */ +} + + +/* instances */ +test t; + +/* connections */ diff --git a/transform/testing/inline/test/runs/42.act.stderr b/transform/testing/inline/test/runs/42.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/testing/inline/test/runs/42.act.stdout b/transform/testing/inline/test/runs/42.act.stdout new file mode 100644 index 00000000..e9bb77a4 --- /dev/null +++ b/transform/testing/inline/test/runs/42.act.stdout @@ -0,0 +1,32 @@ +defproc test (); +function testme (int<32> x[4]) : int<32>; + +defproc test () +{ + +/* instances */ +int<32> a; +int<32> w[4]; + +/* connections */ +chp { +a:=int(w[3],32) +} +} + +function testme (int<32> x[4]) : int<32> +{ + +/* instances */ + +/* connections */ +chp { +self:=x[3] +} +} + + +/* instances */ +test t; + +/* connections */ From 027bbd8f236584016df7042585b4aa4f611af4a0 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 21 Apr 2025 13:44:23 -0400 Subject: [PATCH 05/49] empty userdef2 can happen --- act/expr_extra.c | 1 + act/test/func/57.act | 29 +++++++++++++++++++++++++++++ act/test/func/runs/57.act.stderr | 0 act/test/func/runs/57.act.stdout | 0 4 files changed, 30 insertions(+) create mode 100644 act/test/func/57.act create mode 100644 act/test/func/runs/57.act.stderr create mode 100644 act/test/func/runs/57.act.stdout diff --git a/act/expr_extra.c b/act/expr_extra.c index a35bfc41..f359d46e 100644 --- a/act/expr_extra.c +++ b/act/expr_extra.c @@ -1091,6 +1091,7 @@ int act_expr_parse_newtokens (LFILE *l) int act_expr_free_default (Expr *e) { + if (!e) return 0; if (e->type == E_ENUM_CONST) { FREE (e->u.fn.s); return 1; diff --git a/act/test/func/57.act b/act/test/func/57.act new file mode 100644 index 00000000..96535273 --- /dev/null +++ b/act/test/func/57.act @@ -0,0 +1,29 @@ +deftype mystruct (int a, b) +{ + methods { + function getsum() : int + { + chp { + self := a + b + } + } + function addone() : mystruct + { + chp { + self.a := a + 1; + self.b := b + 1 + } + } + } +} + +defproc test() +{ + mystruct s; + int a; + chp { + s := s.addone(); + a := s.getsum(); + a := s.addone().getsum() + } +} diff --git a/act/test/func/runs/57.act.stderr b/act/test/func/runs/57.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/func/runs/57.act.stdout b/act/test/func/runs/57.act.stdout new file mode 100644 index 00000000..e69de29b From d54e46bddae9e5bdc29fddd1c54abd590d7011a0 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 21 Apr 2025 15:39:50 -0400 Subject: [PATCH 06/49] zero-length arrays are stripped out --- act/body.cc | 4 ++ act/test/expand/10.act | 2 +- act/test/expand/18.act | 10 ++++ act/test/expand/19.act | 12 ++++ act/test/expand/runs/10.act.stderr | 7 --- act/test/expand/runs/18.act.stderr | 5 ++ act/test/expand/runs/18.act.stdout | 0 act/test/expand/runs/19.act.stderr | 5 ++ act/test/expand/runs/19.act.stdout | 0 act/test/other/runs/14.act.stderr | 5 +- act/types.cc | 15 ++++- passes/cells/cells.cc | 53 +++++++++++++----- transform/prs2net/test/all.cells | 14 +++++ transform/prs2net/test/runs/20.act.fstderr | 4 -- transform/prs2net/test/runs/20.act.fstdout | 64 ++++++++++++++++++++++ transform/prs2net/test/runs/21.act.fstderr | 4 -- transform/prs2net/test/runs/21.act.fstdout | 64 ++++++++++++++++++++++ 17 files changed, 233 insertions(+), 35 deletions(-) create mode 100644 act/test/expand/18.act create mode 100644 act/test/expand/19.act create mode 100644 act/test/expand/runs/18.act.stderr create mode 100644 act/test/expand/runs/18.act.stdout create mode 100644 act/test/expand/runs/19.act.stderr create mode 100644 act/test/expand/runs/19.act.stdout diff --git a/act/body.cc b/act/body.cc index 5f7640b8..370abdcd 100644 --- a/act/body.cc +++ b/act/body.cc @@ -143,6 +143,10 @@ void ActBody_Inst::Expand (ActNamespace *ns, Scope *s) it = t->Expand (ns, s); act_error_setline (getLine()); + if (it->arrayInfo() && it->arrayInfo()->size() == 0) { + return; + } + if (it->arrayInfo() && it->arrayInfo()->size() == 0) { act_error_ctxt (stderr); fatal_error ("Instance `%s': zero-length array creation not permitted", id); diff --git a/act/test/expand/10.act b/act/test/expand/10.act index 5a6d6c59..bbd81704 100644 --- a/act/test/expand/10.act +++ b/act/test/expand/10.act @@ -6,7 +6,7 @@ defproc foo (bool x[i]; bool y[i]) prs { (k:i: x[k] => y[k]-) } - foo f; + [ i > 0 -> foo f; ] } diff --git a/act/test/expand/18.act b/act/test/expand/18.act new file mode 100644 index 00000000..b6e9bca9 --- /dev/null +++ b/act/test/expand/18.act @@ -0,0 +1,10 @@ +template +defproc test(int a, b[N]) +{ + (i:N: a=b[i];) + a=b[0]; +} + +test<3> x; + +test<0> y; diff --git a/act/test/expand/19.act b/act/test/expand/19.act new file mode 100644 index 00000000..b264854c --- /dev/null +++ b/act/test/expand/19.act @@ -0,0 +1,12 @@ +defproc test() +{ + int a[0]; + int b; + + chp { + b := 0; + b := a[b] + } +} + +test t; diff --git a/act/test/expand/runs/10.act.stderr b/act/test/expand/runs/10.act.stderr index b420d3e3..e69de29b 100644 --- a/act/test/expand/runs/10.act.stderr +++ b/act/test/expand/runs/10.act.stderr @@ -1,7 +0,0 @@ -In expanding foo<0> (10.act:3) -In expanding foo<1> (10.act:3) -In expanding foo<2> (10.act:3) -In expanding foo<3> (10.act:3) -In expanding :: -Error on or near line number 9. -FATAL: Port `x': zero-length array creation not permitted diff --git a/act/test/expand/runs/18.act.stderr b/act/test/expand/runs/18.act.stderr new file mode 100644 index 00000000..2796ffce --- /dev/null +++ b/act/test/expand/runs/18.act.stderr @@ -0,0 +1,5 @@ +In expanding test<0> (18.act:1) +In expanding :: +Error on or near line number 5. + id: b[0] +FATAL: Identifer conditionally created, but used when it does not exist diff --git a/act/test/expand/runs/18.act.stdout b/act/test/expand/runs/18.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/expand/runs/19.act.stderr b/act/test/expand/runs/19.act.stderr new file mode 100644 index 00000000..8addfcdb --- /dev/null +++ b/act/test/expand/runs/19.act.stderr @@ -0,0 +1,5 @@ +In expanding test (19.act:1) +In expanding :: +Error on or near line number 6. + id: a[b] +FATAL: Identifer conditionally created, but used when it does not exist diff --git a/act/test/expand/runs/19.act.stdout b/act/test/expand/runs/19.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/other/runs/14.act.stderr b/act/test/other/runs/14.act.stderr index a1b4a95e..49343b40 100644 --- a/act/test/other/runs/14.act.stderr +++ b/act/test/other/runs/14.act.stderr @@ -1,3 +1,4 @@ In expanding :: -Error on or near line number 1. -FATAL: Instance `x': zero-length array creation not permitted +Error on or near line number 3. + id: x +FATAL: Identifer conditionally created, but used when it does not exist diff --git a/act/types.cc b/act/types.cc index d966047a..18aafbc3 100644 --- a/act/types.cc +++ b/act/types.cc @@ -791,6 +791,11 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, x = p->Expand (ns, ux->I); // this is the real type of the // parameter + if (x->arrayInfo() && x->arrayInfo()->size() == 0) { + // we just skip this one! + continue; + } + if (x->arrayInfo() && x->arrayInfo()->size() == 0) { act_error_ctxt (stderr); fatal_error ("Template parameter `%s': zero-length array creation not permitted", getPortName (-(i+1))); @@ -1201,8 +1206,14 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, /*-- create ports --*/ for (int i=0; i < nports; i++) { InstType *chk; - Assert (ux->AddPort ((chk = getPortType(i)->Expand (ns, ux->I)), - getPortName (i)), "What?"); + chk = getPortType(i)->Expand (ns, ux->I); + + if (chk->arrayInfo() && chk->arrayInfo()->size() == 0) { + // skip the port! + continue; + } + + Assert (ux->AddPort (chk, getPortName (i)), "What?"); if (chk->arrayInfo() && chk->arrayInfo()->size() == 0) { act_error_ctxt (stderr); diff --git a/passes/cells/cells.cc b/passes/cells/cells.cc index 4ca43565..fe135724 100644 --- a/passes/cells/cells.cc +++ b/passes/cells/cells.cc @@ -2299,6 +2299,11 @@ ActBody_Conn *ActCellPass::_build_connections (const char *name, Expr *idexpr; i = pi->nout + pi->nat; + + if (i == pi->nvars) { + // no inputs, so nothing to connect to + return NULL; + } Assert (i < pi->nvars, "No inputs?"); idexpr = _idexpr (i, pi); @@ -2515,11 +2520,12 @@ void ActCellPass::_collect_one_prs (Scope *sc, act_prs_lang_t *prs) //ac->Next()->Print (stdout); //printf (" --- \n"); - - int oval = Act::double_expand; - Act::double_expand = 0; - ac->Expandlist (NULL, sc); - Act::double_expand = oval; + if (ac) { + int oval = Act::double_expand; + Act::double_expand = 0; + ac->Expandlist (NULL, sc); + Act::double_expand = oval; + } if (pi->match_perm) { FREE (pi->match_perm); @@ -3011,18 +3017,33 @@ int ActCellPass::_collect_cells (ActNamespace *cells) fatal_error ("Unexpected cell `%s' in cell namespace (has parameters?)", p->getName()); } - if (p->getNumPorts() != 2) { + if (p->getNumPorts() != 2 && p->getNumPorts() != 1) { fatal_error ("Cell `%s::%s': More than two ports", cell_ns->getName(), p->getName()); } - if ((strcmp (p->getPortName (0), _inport_name) != 0) || - (strcmp (p->getPortName (1), _outport_name) != 0)) { - fatal_error ("Cell `%s::%s': Ports should be in/out", - cell_ns->getName(), p->getName()); + if (p->getNumPorts() == 2) { + if ((strcmp (p->getPortName (0), _inport_name) != 0) || + (strcmp (p->getPortName (1), _outport_name) != 0)) { + fatal_error ("Cell `%s::%s': Ports should be in/out", + cell_ns->getName(), p->getName()); + } + } + else if (p->getNumPorts() == 1) { + if (strcmp (p->getPortName (0), _outport_name) != 0) { + fatal_error ("Cell `%s::%s': Ports should be in/out", + cell_ns->getName(), p->getName()); + } } InstType *in_t, *out_t; - in_t = p->getPortType (0); - out_t = p->getPortType (1); + + if (p->getNumPorts() == 2) { + in_t = p->getPortType (0); + out_t = p->getPortType (1); + } + else { + in_t = NULL; + out_t = p->getPortType (0); + } #if 0 int id, version; @@ -3036,7 +3057,7 @@ int ActCellPass::_collect_cells (ActNamespace *cells) /* in_t must be a bool array or bool out_t must be a bool array or bool */ - if (!TypeFactory::isBoolType (in_t) || !TypeFactory::isBoolType (out_t)) { + if ((in_t && !TypeFactory::isBoolType (in_t)) || !TypeFactory::isBoolType (out_t)) { fatal_error ("Cell `%s::%s': Port base types must `bool'", cell_ns->getName(), p->getName()); } @@ -3082,8 +3103,10 @@ int ActCellPass::_collect_cells (ActNamespace *cells) } /* fine. now dump into celldb */ - pi = _gen_prs_attributes (l, in_t->arrayInfo() ? - in_t->arrayInfo()->size() : 1, + pi = _gen_prs_attributes (l, + in_t ? + (in_t->arrayInfo() ? + in_t->arrayInfo()->size() : 1) : 0, out_t->arrayInfo() ? out_t->arrayInfo()->size() : 1); pi->leak_adjust = prs->leak_adjust; diff --git a/transform/prs2net/test/all.cells b/transform/prs2net/test/all.cells index 753d9899..eb48af89 100644 --- a/transform/prs2net/test/all.cells +++ b/transform/prs2net/test/all.cells @@ -202,6 +202,20 @@ export defcell g_0x5 (bool? in[1]; bool! out) } } +export defcell g_i0x0 (bool? in[0]; bool! out) +{ + prs { + false -> out- + } +} + +export defcell g_i1x0 (bool? in[0]; bool! out) +{ + prs { + true -> out- + } +} + export defcell g_vl0n3ax1 (bool? in[3]; bool! out) { prs { diff --git a/transform/prs2net/test/runs/20.act.fstderr b/transform/prs2net/test/runs/20.act.fstderr index 5273dda6..e69de29b 100644 --- a/transform/prs2net/test/runs/20.act.fstderr +++ b/transform/prs2net/test/runs/20.act.fstderr @@ -1,4 +0,0 @@ -In expanding g_i1x0 -In expanding foo<> (inst: f) (20.act:1) -In expanding -toplevel- -FATAL: Port `in': zero-length array creation not permitted diff --git a/transform/prs2net/test/runs/20.act.fstdout b/transform/prs2net/test/runs/20.act.fstdout index e69de29b..efb95ae2 100644 --- a/transform/prs2net/test/runs/20.act.fstdout +++ b/transform/prs2net/test/runs/20.act.fstdout @@ -0,0 +1,64 @@ +* +*---- act defproc: cell::g_i1x0<> ----- +* raw ports: out +* +.subckt _8_8cell_8_8g_i1x0 out +*.PININFO out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +M0_ out Vdd GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: g_i1x0<> ----- +* +*---- act defproc: cell::g_i0x0<> ----- +* raw ports: out +* +.subckt _8_8cell_8_8g_i0x0 out +*.PININFO out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +.ends +*---- end of process: g_i0x0<> ----- +* +*---- act defproc: cell::g_0x4<> ----- +* raw ports: in[0] out +* +.subckt _8_8cell_8_8g_0x4 in_20_3 out +*.PININFO in_20_3:I out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +M0_ out in_20_3 GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: g_0x4<> ----- +.subckt foo +xcpx1 cpx1_4out _8_8cell_8_8g_i1x0 +xcpx2 cpx2_4out _8_8cell_8_8g_i0x0 +xcpx0 a b _8_8cell_8_8g_0x4 +.ends diff --git a/transform/prs2net/test/runs/21.act.fstderr b/transform/prs2net/test/runs/21.act.fstderr index 24c3f350..e69de29b 100644 --- a/transform/prs2net/test/runs/21.act.fstderr +++ b/transform/prs2net/test/runs/21.act.fstderr @@ -1,4 +0,0 @@ -In expanding g_i1x0 -In expanding foo<> (inst: f) (21.act:1) -In expanding -toplevel- -FATAL: Port `in': zero-length array creation not permitted diff --git a/transform/prs2net/test/runs/21.act.fstdout b/transform/prs2net/test/runs/21.act.fstdout index e69de29b..efb95ae2 100644 --- a/transform/prs2net/test/runs/21.act.fstdout +++ b/transform/prs2net/test/runs/21.act.fstdout @@ -0,0 +1,64 @@ +* +*---- act defproc: cell::g_i1x0<> ----- +* raw ports: out +* +.subckt _8_8cell_8_8g_i1x0 out +*.PININFO out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +M0_ out Vdd GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: g_i1x0<> ----- +* +*---- act defproc: cell::g_i0x0<> ----- +* raw ports: out +* +.subckt _8_8cell_8_8g_i0x0 out +*.PININFO out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +.ends +*---- end of process: g_i0x0<> ----- +* +*---- act defproc: cell::g_0x4<> ----- +* raw ports: in[0] out +* +.subckt _8_8cell_8_8g_0x4 in_20_3 out +*.PININFO in_20_3:I out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +M0_ out in_20_3 GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: g_0x4<> ----- +.subckt foo +xcpx1 cpx1_4out _8_8cell_8_8g_i1x0 +xcpx2 cpx2_4out _8_8cell_8_8g_i0x0 +xcpx0 a b _8_8cell_8_8g_0x4 +.ends From b07696d3f3639e0895e7566988db59e3eea3c2c1 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 21 Apr 2025 15:46:53 -0400 Subject: [PATCH 07/49] more places to check empty input connections --- passes/cells/cells.cc | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/passes/cells/cells.cc b/passes/cells/cells.cc index fe135724..5d744d6c 100644 --- a/passes/cells/cells.cc +++ b/passes/cells/cells.cc @@ -996,10 +996,12 @@ void ActCellPass::flush_pending (Scope *sc) //ac->Next()->Print (stdout); //printf (" --- \n"); - int oval = Act::double_expand; - Act::double_expand = 0; - ac->Expandlist (NULL, sc); - Act::double_expand = oval; + if (ac) { + int oval = Act::double_expand; + Act::double_expand = 0; + ac->Expandlist (NULL, sc); + Act::double_expand = oval; + } //printf ("---\n"); } A_FREE (groupprs); @@ -2627,11 +2629,12 @@ void ActCellPass::_collect_one_passgate (Scope *sc, act_prs_lang_t *prs) //ac->Next()->Print (stdout); //printf (" --- \n"); - - int oval = Act::double_expand; - Act::double_expand = 0; - ac->Expandlist (NULL, sc); - Act::double_expand = oval; + if (ac) { + int oval = Act::double_expand; + Act::double_expand = 0; + ac->Expandlist (NULL, sc); + Act::double_expand = oval; + } } void ActCellPass::_collect_one_cap (Scope *sc, act_prs_lang_t *prs) @@ -2713,11 +2716,12 @@ void ActCellPass::_collect_one_cap (Scope *sc, act_prs_lang_t *prs) //ac->Next()->Print (stdout); //printf (" --- \n"); - - int oval = Act::double_expand; - Act::double_expand = 0; - ac->Expandlist (NULL, sc); - Act::double_expand = oval; + if (ac) { + int oval = Act::double_expand; + Act::double_expand = 0; + ac->Expandlist (NULL, sc); + Act::double_expand = oval; + } } From 66376fc2710bfc2ede760b7cb46454ee792e0c21 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 21 Apr 2025 19:47:25 -0400 Subject: [PATCH 08/49] user enums in channels --- act/check.cc | 35 +++++++++++++++++++++++++++++- act/test/intchan/runs/1.act.stderr | 2 +- act/test/types/67.act | 18 +++++++++++++++ act/test/types/runs/46.act.stderr | 2 +- act/test/types/runs/67.act.stderr | 0 act/test/types/runs/67.act.stdout | 0 act/typefactory.cc | 3 +++ act/types.m4 | 2 +- 8 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 act/test/types/67.act create mode 100644 act/test/types/runs/67.act.stderr create mode 100644 act/test/types/runs/67.act.stdout diff --git a/act/check.cc b/act/check.cc index 18cafd55..06aa85b3 100644 --- a/act/check.cc +++ b/act/check.cc @@ -2324,6 +2324,7 @@ int act_type_chan (Scope *sc, Chan *ch, int is_send, Expr *e, ActId *id, } ret = 0; if (!TypeFactory::isDataType (it1) && !TypeFactory::isStructure (it1) && + !TypeFactory::isEnum (it1) && !TypeFactory::isPIntType (it1) && !TypeFactory::isPBoolType (it1)) { typecheck_err ("Channels require data types!"); } @@ -2350,11 +2351,27 @@ int act_type_chan (Scope *sc, Chan *ch, int is_send, Expr *e, ActId *id, if (type_connectivity_check (it1, ch->datatype(), 0)) { ret = 1; } + else { + typecheck_err ("Incompatible structures"); + } } else { typecheck_err ("Structure/non-structure types are incompatible."); } } + else if (TypeFactory::isEnum (ch->datatype())) { + if (TypeFactory::isEnum (it1)) { + if (type_connectivity_check (it1, ch->datatype(), 0)) { + ret = 1; + } + else { + typecheck_err ("Incompatible enumerations"); + } + } + else { + typecheck_err ("Enum/non-enum types are incompatible."); + } + } } } if (!ret) { @@ -2374,7 +2391,7 @@ int act_type_chan (Scope *sc, Chan *ch, int is_send, Expr *e, ActId *id, } ret = 0; if (!TypeFactory::isDataType (it2) && !TypeFactory::isStructure (it2) && - !TypeFactory::isPIntType (it2) && + !TypeFactory::isPIntType (it2) && !TypeFactory::isEnum (it2) && !TypeFactory::isPBoolType (it2)) { typecheck_err ("Channels require data types!"); } @@ -2402,11 +2419,27 @@ int act_type_chan (Scope *sc, Chan *ch, int is_send, Expr *e, ActId *id, if (type_connectivity_check (it2, ch->acktype(), 0)) { ret = 1; } + else { + typecheck_err ("Incompatible structures"); + } } else { typecheck_err ("Structure/non-structure types are incompatible."); } } + else if (TypeFactory::isEnum (ch->acktype())) { + if (TypeFactory::isEnum (it2)) { + if (type_connectivity_check (it2, ch->acktype(), 0)) { + ret = 1; + } + else { + typecheck_err ("Incompatible enumerations"); + } + } + else { + typecheck_err ("Enumeration/non-enumeration types are incompatible."); + } + } } } if (it1) { delete it1; } diff --git a/act/test/intchan/runs/1.act.stderr b/act/test/intchan/runs/1.act.stderr index 4e7522d2..e383979a 100644 --- a/act/test/intchan/runs/1.act.stderr +++ b/act/test/intchan/runs/1.act.stderr @@ -1,3 +1,3 @@ ERROR: File `1.act', line 6, col 5 - User-defined channel data type must be a structure with pure data. + User-defined channel data type must be a structure with pure data or enumeration. Type: dualrail diff --git a/act/test/types/67.act b/act/test/types/67.act new file mode 100644 index 00000000..8293bf22 --- /dev/null +++ b/act/test/types/67.act @@ -0,0 +1,18 @@ +defenum alu_ctrl { + ADD, SUB, AND, OR +}; + +defproc alu (chan?(int) A, B; chan?(alu_ctrl) ctrl; chan!(int) O) +{ + int a, b; + alu_ctrl c; + + chp { + *[ A?a, B?b, ctrl?c; + [ c = alu_ctrl.ADD -> O!(a+b) + [] c = alu_ctrl.SUB -> O!(a-b) + [] c = alu_ctrl.AND -> O!(a&b) + [] c = alu_ctrl.OR -> O!(a|b) + ] ] + } +} diff --git a/act/test/types/runs/46.act.stderr b/act/test/types/runs/46.act.stderr index de8ce208..ee9eca45 100644 --- a/act/test/types/runs/46.act.stderr +++ b/act/test/types/runs/46.act.stderr @@ -1,3 +1,3 @@ ERROR: File `46.act', line 6, col 5 - User-defined channel data type must be a structure with pure data. + User-defined channel data type must be a structure with pure data or enumeration. Type: dualrail diff --git a/act/test/types/runs/67.act.stderr b/act/test/types/runs/67.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/67.act.stdout b/act/test/types/runs/67.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/typefactory.cc b/act/typefactory.cc index 67e705b8..b8de1aee 100644 --- a/act/typefactory.cc +++ b/act/typefactory.cc @@ -465,6 +465,9 @@ int TypeFactory::isValidChannelDataType (const Type *t) /* is an int/enum/bool */ return 1; } + if (isEnum (t)) { + return 1; + } if (!isStructure (t)) { return 0; } diff --git a/act/types.m4 b/act/types.m4 index d10c176b..8a7a0224 100644 --- a/act/types.m4 +++ b/act/types.m4 @@ -182,7 +182,7 @@ chan_type[InstType *]: "chan" [ chan_dir ] "(" physical_inst_type [ "," physical } if (!TypeFactory::isValidChannelDataType (t) || (ack && !TypeFactory::isValidChannelDataType (ack))) { - $e("User-defined channel data type must be a structure with pure data.\n"); + $e("User-defined channel data type must be a structure with pure data or enumeration.\n"); fprintf ($f, "\tType%s: ", ack ? "s" : ""); t->Print ($f); if (ack) { From 4c5aaab7249119a659f0efdbc673f85168393728 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 22 Apr 2025 07:12:33 -0400 Subject: [PATCH 09/49] more interface tests and error messages --- act/defs.m4 | 53 ++++++++++++++++++++----------- act/global_generic.conf | 2 +- act/inst.cc | 42 +++++++++++++++++------- act/test/types/68.act | 31 ++++++++++++++++++ act/test/types/runs/68.act.stderr | 0 act/test/types/runs/68.act.stdout | 0 6 files changed, 97 insertions(+), 31 deletions(-) create mode 100644 act/test/types/68.act create mode 100644 act/test/types/runs/68.act.stderr create mode 100644 act/test/types/runs/68.act.stdout diff --git a/act/defs.m4 b/act/defs.m4 index 69e3801b..4278f3b0 100644 --- a/act/defs.m4 +++ b/act/defs.m4 @@ -407,21 +407,26 @@ interface_spec: { interface_one_spec "," }* ; interface_one_spec: iface_inst_type -"{" { idmap "," }* "}" +"{" opt_idmap "}" {{X: listitem_t *li; list_t *ret; Interface *iface = dynamic_cast ($1->BaseType()); - ret = NULL; - for (li = list_first ($3); li; li = list_next (li)) { - list_t *tlist = (list_t *) list_value (li); - if (!ret) { - ret = tlist; - } - else { - list_concat (ret, tlist); - list_free (tlist); + if ($3 == NULL) { + ret = list_new (); + } + else { + ret = NULL; + for (li = list_first ($3); li; li = list_next (li)) { + list_t *tlist = (list_t *) list_value (li); + if (!ret) { + ret = tlist; + } + else { + list_concat (ret, tlist); + list_free (tlist); + } } } @@ -429,6 +434,9 @@ interface_one_spec: iface_inst_type if (!$0->u_p && !$0->u_d) { $E("Interfaces can only be exported by processes and data types"); } + if ($0->u_d && !TypeFactory::isStructure ($0->u_d)) { + $E("Interfaces can only be exported by structures"); + } $A($0->u_p || $0->u_d); for (li = list_first (ret); li; li = list_next (li)) { if (!iface->isPort ((char *)list_value (li))) { @@ -467,7 +475,14 @@ idmap[list_t *]: ID "->" ID list_append (ret, $3); return ret; }} -; +; + +opt_idmap[list_t *]: { idmap "," }* +{{X: + return $1; +}} +| /* empty */ +; override_spec: override_one_spec override_spec {{X: return NULL; }} @@ -1871,7 +1886,7 @@ ID $0->u_f->convPortsToParams(); } } - + if ($0->u_f->getNumPorts() > 0 && TypeFactory::isParamType ($8)) { $E("Function ``%s'': return type incompatible with arguments", $3); } @@ -2923,7 +2938,7 @@ defiface: [ template_spec ] $0->scope = $0->u_i->CurScope (); }} "(" [ port_formal_list ] ")" -{{X: + {{X: /* Create type here */ UserDef *u; @@ -2941,12 +2956,14 @@ defiface: [ template_spec ] else { $A($0->curns->CreateType ($3, $0->u_i)); } + OPT_FREE ($5); $0->strict_checking = 0; }} interface_methods {{X: - $0->scope =$0->curns->CurScope(); $0->u_i->MkDefined (); + $0->u_i = NULL; + $0->scope =$0->curns->CurScope(); return NULL; }} ; @@ -2962,11 +2979,11 @@ interface_methods: "{" "methods" "{" method_decl_list "}" "}" }} ; -method_decl_list: one_method_decl method_decl_list +method_decl_list: one_method_decl method_decl_list | one_method_decl ; -one_method_decl: "macro" ID +one_method_decl: "macro" ID {{X: $A($0->u_i); if (strcmp ($2, "int") == 0) { @@ -2993,7 +3010,7 @@ one_method_decl: "macro" ID return NULL; }} -| "function" ID +| "function" ID {{X: $A($0->u_i); if (strcmp ($2, "int") == 0) { @@ -3038,7 +3055,7 @@ one_method_decl: "macro" ID Scope *tmp = $0->scope; $0->scope = tmp->Parent (); delete tmp; - + return NULL; }} ; diff --git a/act/global_generic.conf b/act/global_generic.conf index d6fe6448..462f713d 100644 --- a/act/global_generic.conf +++ b/act/global_generic.conf @@ -47,7 +47,7 @@ string_table instance_attr "i:s:pos_x" "i:s:pos_y" "i:s:size_x" "i:s:size_y" "i: # # Special characters that should be mangled during printing # -string mangle_chars ":()<>[],{}."$\" +string mangle_chars ":()<>[],{}."$\@" string mangle_letter "_" end diff --git a/act/inst.cc b/act/inst.cc index e7c6ab92..6fd5f0be 100644 --- a/act/inst.cc +++ b/act/inst.cc @@ -450,10 +450,11 @@ Type *InstType::isConnectable (InstType *it, int weak) /* other valid case: ptype(x) to connect to y, where y exports interface x */ - if (TypeFactory::isPTypeType (t) && TypeFactory::isProcessType (it)) { + if (TypeFactory::isPTypeType (t) && + (TypeFactory::isProcessType (it) || TypeFactory::isStructure (it))) { /* ok there is hope - extract interface from ptype - - check that process exports this interface + - check that process/data type exports this interface */ if ((arrayInfo() && !arrayInfo()->isDeref()) || (it->arrayInfo() && !it->arrayInfo()->isDeref())) { @@ -463,18 +464,35 @@ Type *InstType::isConnectable (InstType *it, int weak) } PType *pt = dynamic_cast (t); InstType *iface = pt->getType(); - Process *rhs = dynamic_cast (it->BaseType()); - Assert (rhs, "What?"); - if (!iface) { - iface = this->getTypeParam (0); + if (TypeFactory::isProcessType (it)) { + Process *rhs = dynamic_cast (it->BaseType()); + Assert (rhs, "What?"); + if (!iface) { + iface = this->getTypeParam (0); + } + Assert (iface, "What?"); + if (!rhs->hasIface (iface, weak)) { + typecheck_err ("Process `%s' does not export interface `%s'\n", + rhs->getName(), iface->BaseType()->getName()); + return NULL; + } + return t; } - Assert (iface, "What?"); - if (!rhs->hasIface (iface, weak)) { - typecheck_err ("Process `%s' does not export interface `%s'\n", - rhs->getName(), iface->BaseType()->getName()); - return NULL; + else { + Assert (TypeFactory::isStructure (it), "I should not be here"); + Data *rhs = dynamic_cast (it->BaseType()); + Assert (rhs, "What?"); + if (!iface) { + iface = this->getTypeParam (0); + } + Assert (iface, "What?"); + if (!rhs->hasIface (iface, weak)) { + typecheck_err ("Data type `%s' does not export interface `%s'\n", + rhs->getName(), iface->BaseType()->getName()); + return NULL; + } + return t; } - return t; } return NULL; } diff --git a/act/test/types/68.act b/act/test/types/68.act new file mode 100644 index 00000000..44b8c123 --- /dev/null +++ b/act/test/types/68.act @@ -0,0 +1,31 @@ +interface me() { + methods { + function sum (int x) : int; + } +} + +deftype myint (int xa) :> me { } +{ + methods { + function sum (int w) : int + { + chp { + self := w + xa + } + } + } +} + +template defproc test() +{ + x a; + int y; + + chp { + + y := 0; + y := a.sum(y) + } +} + +test<@myint> t; diff --git a/act/test/types/runs/68.act.stderr b/act/test/types/runs/68.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/68.act.stdout b/act/test/types/runs/68.act.stdout new file mode 100644 index 00000000..e69de29b From 2cd847cca60d7f69cce19732aadcfcfd1aa11dc6 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 22 Apr 2025 09:05:57 -0400 Subject: [PATCH 10/49] additional check for macro expansion --- act/process.cc | 12 ++++++++++++ act/types.cc | 22 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/act/process.cc b/act/process.cc index 168ac6bc..fa0adfc5 100644 --- a/act/process.cc +++ b/act/process.cc @@ -23,8 +23,11 @@ #include #include #include +#include #include +int _act_inc_rec_depth (); +void _act_dec_rec_depth(); /*------------------------------------------------------------------------ * @@ -99,6 +102,13 @@ Process *Process::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) xp->ifaces = NULL; } + int recval = _act_inc_rec_depth (); + + if (recval >= Act::max_recurse_depth) { + act_error_ctxt (stderr); + fatal_error ("Exceeded maximum recursion depth of %d\n", Act::max_recurse_depth); + } + /*-- expand macros --*/ for (int i=0; i < A_LEN (um); i++) { A_NEW (xp->um, UserMacro *); @@ -106,6 +116,8 @@ Process *Process::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) A_INC (xp->um); } + _act_dec_rec_depth (); + return xp; } diff --git a/act/types.cc b/act/types.cc index 18aafbc3..b760fbc6 100644 --- a/act/types.cc +++ b/act/types.cc @@ -712,6 +712,9 @@ int UserDef::isEqual (const UserDef *u) const static int recursion_depth = 0; +int _act_inc_rec_depth () { recursion_depth++; return recursion_depth; } +void _act_dec_rec_depth() { recursion_depth--; } + /*------------------------------------------------------------------------ * * Expand user-defined type! @@ -727,9 +730,9 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, InstType *x, *p; Array *xa; - recursion_depth++; + int recval = _act_inc_rec_depth(); - if (recursion_depth >= Act::max_recurse_depth) { + if (recval >= Act::max_recurse_depth) { act_error_ctxt (stderr); fatal_error ("Exceeded maximum recursion depth of %d\n", Act::max_recurse_depth); } @@ -1172,7 +1175,7 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, FREE (buf); /* we found one! */ delete ux; - recursion_depth--; + _act_dec_rec_depth (); *cache_hit = 1; return uy; } @@ -1278,7 +1281,9 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, } ux->pending = 0; - recursion_depth--; + + _act_dec_rec_depth (); + return ux; } @@ -1333,6 +1338,13 @@ Data *Data::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) /*-- expand macros --*/ + int recval = _act_inc_rec_depth (); + + if (recval >= Act::max_recurse_depth) { + act_error_ctxt (stderr); + fatal_error ("Exceeded maximum recursion depth of %d\n", Act::max_recurse_depth); + } + /*-- do this in two phases: first, the built-in ones! --*/ for (int i=0; i < A_LEN (um); i++) { if (um[i]->isBuiltinMacro()) { @@ -1356,6 +1368,8 @@ Data *Data::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) } } + _act_dec_rec_depth (); + return xd; } From dada6be360e5f240b7bd4c40c082d64d90ca5121 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 22 Apr 2025 21:03:58 -0400 Subject: [PATCH 11/49] more work on interfaces --- act/defs.m4 | 9 ++++++--- act/inst.cc | 4 ++++ act/test/types/69.act | 30 ++++++++++++++++++++++++++++++ act/test/types/runs/69.act.stderr | 0 act/test/types/runs/69.act.stdout | 0 act/types.m4 | 8 +++++++- 6 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 act/test/types/69.act create mode 100644 act/test/types/runs/69.act.stderr create mode 100644 act/test/types/runs/69.act.stdout diff --git a/act/defs.m4 b/act/defs.m4 index 4278f3b0..27349e83 100644 --- a/act/defs.m4 +++ b/act/defs.m4 @@ -941,9 +941,12 @@ single_macro_port_item: physical_inst_type id_list UserDef *u; if (!TypeFactory::isDataType ($1) && !TypeFactory::isStructure($1)) { - r = (ActRet *) list_value (list_first ($2)); - $A(r->type == R_STRING); - $E("Parameter ``%s'': port parameter for a macro must be a data type", r->u.str); + if (!TypeFactory::isInterfaceType ($1)) { + /* allow F-bounded polymorphism */ + r = (ActRet *) list_value (list_first ($2)); + $A(r->type == R_STRING); + $E("Parameter ``%s'': port parameter for a macro must be a data type", r->u.str); + } } if ($0->u_p) { diff --git a/act/inst.cc b/act/inst.cc index 6fd5f0be..28472578 100644 --- a/act/inst.cc +++ b/act/inst.cc @@ -430,6 +430,10 @@ Type *InstType::isConnectable (InstType *it, int weak) /* Even if the base types are not the same, they might be connectable because they have a common root */ + if (TypeFactory::isInterfaceType (t) && t == it->t) { + return t; + } + /* EVENTUALLY insttype pointers will be unique, and so this will work! */ if (TypeFactory::isInterfaceType (t)) { diff --git a/act/test/types/69.act b/act/test/types/69.act new file mode 100644 index 00000000..1773e926 --- /dev/null +++ b/act/test/types/69.act @@ -0,0 +1,30 @@ +/* F-bounded polymorphism */ +interface foo() { +methods { + function test (foo x) : bool; +} +} + +deftype mytype (int x) :> foo { } +{ + methods { + function test (mytype y) : bool + { + chp { + self := y.x > x ? true : false + } + } + } +} + +template +defproc test() +{ + t x; + bool w; + chp { + w := x.test(x) + } +} + +test<@mytype> x; diff --git a/act/test/types/runs/69.act.stderr b/act/test/types/runs/69.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/69.act.stdout b/act/test/types/runs/69.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/types.m4 b/act/types.m4 index 8a7a0224..52e2a65b 100644 --- a/act/types.m4 +++ b/act/types.m4 @@ -230,7 +230,13 @@ physical_inst_type[InstType *]: data_type | user_type {{X: if (TypeFactory::isInterfaceType ($1) && !$0->ptype_expand) { - $E("An interface type cannot be used in this context"); + if (TypeFactory::isInterfaceType ($1) && + $0->u_i && $0->u_i->isEqual ($1->BaseType())) { + /* F-bounded polymorphism! */ + } + else { + $E("An interface type cannot be used in this context"); + } } $0->ptype_expand = 0; return $1; From b50f05eec9a78cac46ae558a5d955104f0f846d4 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 23 Apr 2025 09:21:02 -0400 Subject: [PATCH 12/49] more interface types --- act/body.cc | 1 + act/check.cc | 21 +++++- act/process.cc | 11 ++-- act/test/types/70.act | 30 +++++++++ act/test/types/71.act | 32 +++++++++ act/test/types/runs/29.act.stderr | 7 +- act/test/types/runs/70.act.stderr | 6 ++ act/test/types/runs/70.act.stdout | 0 act/test/types/runs/71.act.stderr | 0 act/test/types/runs/71.act.stdout | 0 act/typecheck.h | 1 + act/types.cc | 105 +++++++++++++++++++++++++----- 12 files changed, 189 insertions(+), 25 deletions(-) create mode 100644 act/test/types/70.act create mode 100644 act/test/types/71.act create mode 100644 act/test/types/runs/70.act.stderr create mode 100644 act/test/types/runs/70.act.stdout create mode 100644 act/test/types/runs/71.act.stderr create mode 100644 act/test/types/runs/71.act.stdout diff --git a/act/body.cc b/act/body.cc index 370abdcd..cb790aff 100644 --- a/act/body.cc +++ b/act/body.cc @@ -409,6 +409,7 @@ void ActBody_Inst::Expand (ActNamespace *ns, Scope *s) } InstType *x = new InstType (s->getPType (vx->u.idx)); + x->MkCached (); x->setIfaceType (it); if (it->arrayInfo()) { x->MkArray (it->arrayInfo()); diff --git a/act/check.cc b/act/check.cc index 06aa85b3..3ce90ed2 100644 --- a/act/check.cc +++ b/act/check.cc @@ -124,7 +124,7 @@ static InstType *_act_get_var_type (Scope *s, ActId *id, ActId **retid, Assert (it, "This should have been caught during parsing!"); /* pstruct can be strict even if there is an id de-reference */ - if (TypeFactory::isPStructType (it) && id->Rest()) { + if (id->Rest() && TypeFactory::isPStructType (it)) { u = s->getUserDef (); if (u && u->isStrictPort (id->getName())) { is_strict = 1; @@ -205,6 +205,8 @@ static int _act_type_id_to_flags (InstType *it, ActId *id, int is_strict) return T_PROC|arr; } if (TypeFactory::isInterfaceType (t)) { + return T_IFACE|arr; + char *tmpbuf; MALLOC (tmpbuf, char, 10240); id->sPrint (tmpbuf, 10240); @@ -1230,6 +1232,12 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) *width = TypeFactory::bitWidth (rtype); } } + else if (TypeFactory::isInterfaceType (rtype)) { + ret |= T_IFACE; + if (width) { + *width = -1; + } + } else { Assert (0, "Unknown return type"); } @@ -2200,8 +2208,15 @@ int type_chp_check_assignable (InstType *lhs, InstType *rhs) if (!TypeFactory::isDataType (lhs) && !TypeFactory::isPureStruct (lhs) && !TypeFactory::isPBoolType (lhs) && !TypeFactory::isPIntType (lhs)) { - typecheck_err ("Assignable variable requires data types!"); - return 0; + if (TypeFactory::isInterfaceType (lhs) && + TypeFactory::isInterfaceType (rhs) && + lhs->BaseType()->isEqual (rhs->BaseType())) { + return 1; + } + else { + typecheck_err ("Assignable variable requires data types!"); + return 0; + } } if (TypeFactory::isPBoolType (lhs)) { if (TypeFactory::isPBoolType (rhs)) { diff --git a/act/process.cc b/act/process.cc index fa0adfc5..fa10141a 100644 --- a/act/process.cc +++ b/act/process.cc @@ -116,6 +116,12 @@ Process *Process::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) A_INC (xp->um); } + const char *ret = xp->validateInterfaces (); + if (ret) { + act_error_ctxt (stderr); + fatal_error ("Inconsistent/missing method\n\t%s", ret); + } + _act_dec_rec_depth (); return xp; @@ -758,7 +764,6 @@ void Process::recordGlobal (ActId *id) const char *Process::validateInterfaces () { - static char buf[1024]; if (!ifaces) return NULL; listitem_t *li; for (li = list_first (ifaces); li; li = list_next (li)) { @@ -769,9 +774,7 @@ const char *Process::validateInterfaces () // now typecheck macros const char *ret = ix->validateMacros (this, um, A_LEN (um)); if (ret) { - snprintf (buf, 1024, "Method `%s' from interface `%s'", ret, - ix->getName()); - return buf; + return ret; } li = list_next (li); diff --git a/act/test/types/70.act b/act/test/types/70.act new file mode 100644 index 00000000..8ef82893 --- /dev/null +++ b/act/test/types/70.act @@ -0,0 +1,30 @@ +/* F-bounded polymorphism */ +interface foo() { +methods { + function test (int x) : bool; +} +} + +deftype mytype (int x) :> foo { } +{ + methods { + function test (int<4> y) : bool + { + chp { + self := x > x ? true : false + } + } + } +} + +template +defproc test() +{ + t x; + bool w; + chp { + w := x.test(3) + } +} + +test<@mytype> x; diff --git a/act/test/types/71.act b/act/test/types/71.act new file mode 100644 index 00000000..7c60a351 --- /dev/null +++ b/act/test/types/71.act @@ -0,0 +1,32 @@ +/* F-bounded polymorphism */ +interface foo() { +methods { + function test (int x) : foo; +} +} + +deftype mytype (int x) :> foo { } +{ + methods { + function test (int y) : mytype + { + mytype ret; + chp { + ret.x := y; + self := ret + } + } + } +} + +template +defproc test() +{ + t x; + bool w; + chp { + x := x.test(3) + } +} + +test<@mytype> x; diff --git a/act/test/types/runs/29.act.stderr b/act/test/types/runs/29.act.stderr index ce7d12e2..d80aa3b5 100644 --- a/act/test/types/runs/29.act.stderr +++ b/act/test/types/runs/29.act.stderr @@ -1,3 +1,4 @@ -ERROR: File `29.act', line 17, col 4 - Typechecking failed on expression! - Identifier `y' is an interface type +ERROR: File `29.act', line 25, col 8 + Typechecking failed for template parameter #1 + Process `bitinv' does not export interface `linear' +Types `ptype' and `bitinv' are not compatible diff --git a/act/test/types/runs/70.act.stderr b/act/test/types/runs/70.act.stderr new file mode 100644 index 00000000..aa69db42 --- /dev/null +++ b/act/test/types/runs/70.act.stderr @@ -0,0 +1,6 @@ +In expanding mytype (70.act:8) +In expanding test (70.act:20) +In expanding :: +Error on or near line number 30. +FATAL: Inconsistent/missing method + Method `test', interface `foo<>': arg #0 type mismatch diff --git a/act/test/types/runs/70.act.stdout b/act/test/types/runs/70.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/71.act.stderr b/act/test/types/runs/71.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/71.act.stdout b/act/test/types/runs/71.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/typecheck.h b/act/typecheck.h index 2397e59e..53dfb4c1 100644 --- a/act/typecheck.h +++ b/act/typecheck.h @@ -60,6 +60,7 @@ #define T_DATA_ENUM 0xb ///< an enum that is not an int #define T_PTYPE 0x10 ///< used when the expression is a type #define T_PSTRUCT 0x11 ///< used when the expression is a pstruct +#define T_IFACE 0x12 ///< used for interfaces #define T_MASK 0x1f ///< mask for the list of options diff --git a/act/types.cc b/act/types.cc index b760fbc6..68e1fcb9 100644 --- a/act/types.cc +++ b/act/types.cc @@ -1368,6 +1368,12 @@ Data *Data::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) } } + const char *ret = xd->validateInterfaces (); + if (ret) { + act_error_ctxt (stderr); + fatal_error ("Inconsistent/missing method\n\t%s", ret); + } + _act_dec_rec_depth (); return xd; @@ -1466,7 +1472,24 @@ Interface *Interface::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) xd = new Interface (ux); delete ux; + int recval = _act_inc_rec_depth (); + + if (recval >= Act::max_recurse_depth) { + act_error_ctxt (stderr); + fatal_error ("Exceeded maximum recursion depth of %d\n", Act::max_recurse_depth); + } + Assert (_ns->EditType (xd->name, xd) == 1, "What?"); + + /*-- expand macros --*/ + for (int i=0; i < A_LEN (um); i++) { + A_NEW (xd->um, UserMacro *); + A_NEXT (xd->um) = um[i]->Expand (xd, ns, xd->I, 1); + A_INC (xd->um); + } + + _act_dec_rec_depth (); + return xd; } @@ -3018,7 +3041,6 @@ list_t *Data::findMap (InstType *x) const char *Data::validateInterfaces () { - static char buf[1024]; if (!ifaces) return NULL; listitem_t *li; for (li = list_first (ifaces); li; li = list_next (li)) { @@ -3029,9 +3051,7 @@ const char *Data::validateInterfaces () // now typecheck macros const char *ret = ix->validateMacros (this, um, A_LEN (um)); if (ret) { - snprintf (buf, 1024, "Method `%s' from interface `%s'", ret, - ix->getName()); - return buf; + return ret; } li = list_next (li); @@ -3056,31 +3076,86 @@ void Interface::Print (FILE *fp) const char *Interface::validateMacros (UserDef *u, UserMacro **macros, int count) { + static char buf[1024]; + int len; // we have to try type substitutions for the interface name with the // specified type name! for (int i=0; i < A_LEN (um); i++) { - const char *err = um[i]->getName(); int idx; + int err; for (idx=0; idx < count; idx++) { - if (strcmp (macros[idx]->getName(), err) == 0) { + if (strcmp (macros[idx]->getName(), um[i]->getName()) == 0) { break; } } - if (idx == count) return err; - /* now check that um[i] and macros[idx] match up! */ - if (um[i]->getNumPorts() != macros[idx]->getNumPorts()) return err; + if (idx == count) { + snprintf (buf, 1024, "Method `%s' from interface '%s' is missing.", + um[i]->getName(), getName()); + return buf; + } + /* now check that um[i] and macros[idx] match up! */ + if (um[i]->getNumPorts() != macros[idx]->getNumPorts()) { + snprintf (buf, 1024, "Method `%s', interface `%s': mismatch in port count (%d vs %d)", + um[i]->getName (), getName(), + um[i]->getNumPorts(), macros[idx]->getNumPorts()); + return buf; + } + + + /* match the types for each of the arguments as well as the return value */ + err = 0; + for (int j=0; j < um[i]->getNumPorts(); j++) { + /* 1. normal test for typechecking connections, and + 2. stricter check: the interface must be the same as the type + */ +#define _TYPEMATCH(t1,t2) \ + do { \ + if (TypeFactory::isInterfaceType (t1)) { \ + InstType *tmp = new InstType (u->CurScope(), u); \ + if (!type_connectivity_check ((t2), tmp) || \ + (!u->isEqual ((t2)->BaseType()))) { \ + delete tmp; \ + err = 1; \ + } \ + delete tmp; \ + } \ + else { \ + if (!type_connectivity_check (t1, t2)) { \ + err = 1; \ + } \ + } \ + } while (0) + _TYPEMATCH(um[i]->getPortType (j), macros[idx]->getPortType (j)); + if (err) { + snprintf (buf, 1024, "Method `%s', interface `%s': arg #%d type mismatch", + um[i]->getName (), getName(), j); + return buf; + } + } + if (um[i]->getRetType()) { - if (!macros[idx]->getRetType()) return err; + if (!macros[idx]->getRetType()) { + snprintf (buf, 1024, "Method `%s', interface `%s': macro/function inconsistency", + um[i]->getName(), getName()); + return buf; + } + _TYPEMATCH (um[i]->getRetType(), macros[idx]->getRetType()); + if (err) { + snprintf (buf, 1024, "Method `%s', interface `%s': return type mismatch", + um[i]->getName (), getName()); + return buf; + } } else { - if (macros[idx]->getRetType()) return err; + if (macros[idx]->getRetType()) { + snprintf (buf, 1024, "Method `%s', interface `%s': macro/function inconsistency", + um[i]->getName(), getName()); + return buf; + } } - - /* now match the types for each of the arguments as well as the - return value */ - +#undef _TYPEMATCH } return NULL; } From 062b6dd7a4d086df71f93ab160c62374c57b64e2 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Thu, 24 Apr 2025 07:23:52 -0400 Subject: [PATCH 13/49] namespace cloning tests --- act/body.h | 4 ++ act/namespaces.cc | 45 +++++++++++++++++- transform/prs2net/test/57.act | 8 ++++ transform/prs2net/test/58.act | 10 ++++ transform/prs2net/test/runs/57.act.fstderr | 0 transform/prs2net/test/runs/57.act.fstdout | 24 ++++++++++ transform/prs2net/test/runs/57.act.stderr | 0 transform/prs2net/test/runs/57.act.stdout | 33 +++++++++++++ transform/prs2net/test/runs/58.act.fstderr | 0 transform/prs2net/test/runs/58.act.fstdout | 25 ++++++++++ transform/prs2net/test/runs/58.act.stderr | 0 transform/prs2net/test/runs/58.act.stdout | 55 ++++++++++++++++++++++ transform/prs2net/test/xfoo.act | 12 +++++ 13 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 transform/prs2net/test/57.act create mode 100644 transform/prs2net/test/58.act create mode 100644 transform/prs2net/test/runs/57.act.fstderr create mode 100644 transform/prs2net/test/runs/57.act.fstdout create mode 100644 transform/prs2net/test/runs/57.act.stderr create mode 100644 transform/prs2net/test/runs/57.act.stdout create mode 100644 transform/prs2net/test/runs/58.act.fstderr create mode 100644 transform/prs2net/test/runs/58.act.fstdout create mode 100644 transform/prs2net/test/runs/58.act.stderr create mode 100644 transform/prs2net/test/runs/58.act.stdout create mode 100644 transform/prs2net/test/xfoo.act diff --git a/act/body.h b/act/body.h index 165a85e9..e2ae8a9a 100644 --- a/act/body.h +++ b/act/body.h @@ -80,6 +80,10 @@ class ActBody { */ ActBody *Next () { return next; } + /** clear next pointer */ + void clrNext() { next = NULL; } + void setNext(ActBody *b) { next = b; } + /** * In cases when we are cloning a * body into a new namespace hierarchy, the "replace" pointer is diff --git a/act/namespaces.cc b/act/namespaces.cc index 2c2cbe6a..4dd7ba6d 100644 --- a/act/namespaces.cc +++ b/act/namespaces.cc @@ -1020,8 +1020,51 @@ void ActNamespace::_updateClonedTypes (ActNamespace *root, hash_bucket_t *b, *bnew; // update the body type info, and re-construct scopes! + if (ActNamespace::Global()->B) { + ActBody *tmp; + ActBody *update = NULL; + ActBody *utail = NULL; + bool found = false; + + for (tmp = ActNamespace::Global()->B; tmp; tmp = tmp->Next()) { + if (dynamic_cast(tmp)) { + ActNamespace *tns = (dynamic_cast(tmp))->getNS(); + if (tns == this) { + found = true; + } + else { + found = false; + } + } + if (found) { + ActBody *tnext = tmp->Next(); + tmp->clrNext (); + ActBody *cpy = tmp->Clone (root, newroot); + tmp->setNext (tnext); + if (!update) { + update = cpy; + utail = update; + } + else { + utail->Append (cpy); + utail = cpy; + } + } + } + if (update) { + ActBody *tmp = new ActBody_Namespace (newns); + tmp->Append (update); + utail->Append (new ActBody_Namespace (ActNamespace::Global())); + ActNamespace::Global()->B->Append (tmp); + } + } if (B) { - newns->B = B->Clone (root, newroot); + if (newns->B) { + newns->B->Append (B->Clone (root, newroot)); + } + else { + newns->B = B->Clone (root, newroot); + } } hash_iter_init (N, &it); diff --git a/transform/prs2net/test/57.act b/transform/prs2net/test/57.act new file mode 100644 index 00000000..e88409e4 --- /dev/null +++ b/transform/prs2net/test/57.act @@ -0,0 +1,8 @@ +import xfoo; + +defproc foo() +{ +xfoo::test t; +} + +foo f; diff --git a/transform/prs2net/test/58.act b/transform/prs2net/test/58.act new file mode 100644 index 00000000..f6f70089 --- /dev/null +++ b/transform/prs2net/test/58.act @@ -0,0 +1,10 @@ +import xfoo; +open xfoo => xbar; + +defproc foo() +{ +xfoo::test t; +xbar::test t2; +} + +foo f; diff --git a/transform/prs2net/test/runs/57.act.fstderr b/transform/prs2net/test/runs/57.act.fstderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/prs2net/test/runs/57.act.fstdout b/transform/prs2net/test/runs/57.act.fstdout new file mode 100644 index 00000000..326b37b3 --- /dev/null +++ b/transform/prs2net/test/runs/57.act.fstdout @@ -0,0 +1,24 @@ +* +*---- act defproc: cell::g0n_0x0<> ----- +* raw ports: in[0] out +* +.subckt _8_8cell_8_8g0n_0x0 in_20_3 out +*.PININFO in_20_3:I out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +M0_ out in_20_3 Vdd Vdd pch W=0.3U L=0.06U +M1_ out in_20_3 GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: g0n_0x0<> ----- +.subckt foo +xt_4cx0 t_4a t_4b _8_8cell_8_8g0n_0x0 +.ends diff --git a/transform/prs2net/test/runs/57.act.stderr b/transform/prs2net/test/runs/57.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/prs2net/test/runs/57.act.stdout b/transform/prs2net/test/runs/57.act.stdout new file mode 100644 index 00000000..0036bdd9 --- /dev/null +++ b/transform/prs2net/test/runs/57.act.stdout @@ -0,0 +1,33 @@ +* +*---- act defproc: xfoo::test<> ----- +* raw ports: a b +* +.subckt _8_8xfoo_8_8test a b +*.PININFO a:I b:O +*.POWER VDD _8_8xfoo_8_8VddN +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB _8_8xfoo_8_8VddN +* +* --- node flags --- +* +* b (combinational) +* +* --- end node flags --- +* +M0_ b a _8_8xfoo_8_8VddN _8_8xfoo_8_8VddN pch W=0.3U L=0.06U +M1_ b a GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: test<> ----- +* +*---- act defproc: foo<> ----- +* raw ports: +* +.subckt foo +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +xt t_4a t_4b _8_8xfoo_8_8test +.ends +*---- end of process: foo<> ----- diff --git a/transform/prs2net/test/runs/58.act.fstderr b/transform/prs2net/test/runs/58.act.fstderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/prs2net/test/runs/58.act.fstdout b/transform/prs2net/test/runs/58.act.fstdout new file mode 100644 index 00000000..3d51084c --- /dev/null +++ b/transform/prs2net/test/runs/58.act.fstdout @@ -0,0 +1,25 @@ +* +*---- act defproc: cell::g0n_0x0<> ----- +* raw ports: in[0] out +* +.subckt _8_8cell_8_8g0n_0x0 in_20_3 out +*.PININFO in_20_3:I out:O +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +* +* --- node flags --- +* +* out (combinational) +* +* --- end node flags --- +* +M0_ out in_20_3 Vdd Vdd pch W=0.3U L=0.06U +M1_ out in_20_3 GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: g0n_0x0<> ----- +.subckt foo +xt2_4cx0 t2_4a t2_4b _8_8cell_8_8g0n_0x0 +xt_4cx0 t_4a t_4b _8_8cell_8_8g0n_0x0 +.ends diff --git a/transform/prs2net/test/runs/58.act.stderr b/transform/prs2net/test/runs/58.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/prs2net/test/runs/58.act.stdout b/transform/prs2net/test/runs/58.act.stdout new file mode 100644 index 00000000..4dae6c6c --- /dev/null +++ b/transform/prs2net/test/runs/58.act.stdout @@ -0,0 +1,55 @@ +* +*---- act defproc: xbar::test<> ----- +* raw ports: a b +* +.subckt _8_8xbar_8_8test a b +*.PININFO a:I b:O +*.POWER VDD _8_8xbar_8_8VddN +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB _8_8xbar_8_8VddN +* +* --- node flags --- +* +* b (combinational) +* +* --- end node flags --- +* +M0_ b a _8_8xbar_8_8VddN _8_8xbar_8_8VddN pch W=0.3U L=0.06U +M1_ b a GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: test<> ----- +* +*---- act defproc: xfoo::test<> ----- +* raw ports: a b +* +.subckt _8_8xfoo_8_8test a b +*.PININFO a:I b:O +*.POWER VDD _8_8xfoo_8_8VddN +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB _8_8xfoo_8_8VddN +* +* --- node flags --- +* +* b (combinational) +* +* --- end node flags --- +* +M0_ b a _8_8xfoo_8_8VddN _8_8xfoo_8_8VddN pch W=0.3U L=0.06U +M1_ b a GND GND nch W=0.15U L=0.06U +.ends +*---- end of process: test<> ----- +* +*---- act defproc: foo<> ----- +* raw ports: +* +.subckt foo +*.POWER VDD Vdd +*.POWER GND GND +*.POWER NSUB GND +*.POWER PSUB Vdd +xt2 t2_4a t2_4b _8_8xbar_8_8test +xt t_4a t_4b _8_8xfoo_8_8test +.ends +*---- end of process: foo<> ----- diff --git a/transform/prs2net/test/xfoo.act b/transform/prs2net/test/xfoo.act new file mode 100644 index 00000000..b6a73aa6 --- /dev/null +++ b/transform/prs2net/test/xfoo.act @@ -0,0 +1,12 @@ +namespace xfoo { + +bool VddN; + +export defproc test(bool a, b) +{ + prs { + a => b- + } +} + +} From 458330962e6fa10fc39c091c27bee8454365c36e Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 28 Apr 2025 05:28:33 -0400 Subject: [PATCH 14/49] interface check for overloads --- act/test/types/72.act | 30 ++++++++++++++++++++++++++++++ act/test/types/runs/72.act.stderr | 0 act/test/types/runs/72.act.stdout | 0 act/wrap.cc | 6 ++++-- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 act/test/types/72.act create mode 100644 act/test/types/runs/72.act.stderr create mode 100644 act/test/types/runs/72.act.stdout diff --git a/act/test/types/72.act b/act/test/types/72.act new file mode 100644 index 00000000..3eef001f --- /dev/null +++ b/act/test/types/72.act @@ -0,0 +1,30 @@ +interface foo() { +methods { + function plus (foo x) : foo; +} +} + +deftype mytype (int x) :> foo { } +{ + methods { + function plus (mytype y) : mytype + { + mytype ret; + chp { + ret.x := y.x; + self := ret + } + } + } +} + +template +defproc test() +{ + t x1, x2; + chp { + x1 := x1 + x2 + } +} + +test<@mytype> x; diff --git a/act/test/types/runs/72.act.stderr b/act/test/types/runs/72.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/types/runs/72.act.stdout b/act/test/types/runs/72.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/wrap.cc b/act/wrap.cc index f1b8057b..c599d0f2 100644 --- a/act/wrap.cc +++ b/act/wrap.cc @@ -286,7 +286,8 @@ static Expr *_check_overload (ActTree *cookie, Expr *e, const char *nm) if (!e) return e; if (act_expr_could_be_struct (e->u.e.l)) { InstType *it = act_expr_insttype (cookie->scope, e->u.e.l, NULL, 2); - if (it && TypeFactory::isPureStruct (it)) { + if (it && + (TypeFactory::isPureStruct (it) || TypeFactory::isInterfaceType (it))) { struct act_position p; p.l = cookie->line; p.c = cookie->column; @@ -336,7 +337,8 @@ static Expr *_check_overload_bool (ActTree *cookie, Expr *e, const char *nm) if (!e) return e; if (act_expr_could_be_struct (e->u.e.l)) { InstType *it = act_expr_insttype (cookie->scope, e->u.e.l, NULL, 2); - if (it && TypeFactory::isPureStruct (it)) { + if (it && + (TypeFactory::isPureStruct (it) || TypeFactory::isInterfaceType (it))) { struct act_position p; p.l = cookie->line; p.c = cookie->column; From d14e864cd1d66ee534b3754cc6133b9ef6970aa0 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 29 Apr 2025 05:38:32 -0400 Subject: [PATCH 15/49] eliminate old reliance on top-level instances --- transform/prs2net/main.cc | 22 +++++++++++----------- transform/prs2net/test/runs/22.act.fstderr | 3 +-- transform/prs2net/test/runs/37.act.fstderr | 3 +-- transform/prs2net/test/runs/39.act.fstderr | 3 +-- transform/prs2net/test/runs/40.act.fstderr | 6 ++---- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/transform/prs2net/main.cc b/transform/prs2net/main.cc index 88e7831d..bdbf3098 100644 --- a/transform/prs2net/main.cc +++ b/transform/prs2net/main.cc @@ -214,9 +214,19 @@ int main (int argc, char **argv) a->Expand (); + Process *p = a->findProcess (proc); + + if (!p) { + fatal_error ("Could not find process `%s' in file `%s'", proc, argv[1]); + } + + if (!p->isExpanded()) { + p = p->Expand (ActNamespace::Global(), p->CurScope(), 0, NULL); + } + if (cell_file) { ActCellPass *cp = new ActCellPass (a); - cp->run(); + cp->run(p); FILE *oc = fopen (cell_file, "w"); if (!oc) { @@ -230,16 +240,6 @@ int main (int argc, char **argv) a->mangle (config_get_string ("net.mangle_chars")); } - Process *p = a->findProcess (proc); - - if (!p) { - fatal_error ("Could not find process `%s' in file `%s'", proc, argv[1]); - } - - if (!p->isExpanded()) { - p = p->Expand (ActNamespace::Global(), p->CurScope(), 0, NULL); - } - ActNetlistPass *np = new ActNetlistPass (a); if (enable_shared_stat) { np->enableSharedStat(); diff --git a/transform/prs2net/test/runs/22.act.fstderr b/transform/prs2net/test/runs/22.act.fstderr index 89ed061d..520cc133 100644 --- a/transform/prs2net/test/runs/22.act.fstderr +++ b/transform/prs2net/test/runs/22.act.fstderr @@ -1,4 +1,3 @@ -In expanding foo<> (inst: f) (22.act:1) -In expanding -toplevel- +In expanding foo<> (22.act:1) WARNING: Sizing directive {+20,-15} specified for already sized rule skipped signal: `b' diff --git a/transform/prs2net/test/runs/37.act.fstderr b/transform/prs2net/test/runs/37.act.fstderr index 1e836368..998496b1 100644 --- a/transform/prs2net/test/runs/37.act.fstderr +++ b/transform/prs2net/test/runs/37.act.fstderr @@ -1,5 +1,4 @@ -In expanding foo<> (inst: ct) (37.act:3) -In expanding -toplevel- +In expanding foo<> (37.act:3) WARNING: Local dynamic arrays cannot have other partial connections ID: x FATAL: Cannot proceed. Dynamic arrays used in unsupported ways. diff --git a/transform/prs2net/test/runs/39.act.fstderr b/transform/prs2net/test/runs/39.act.fstderr index 6777075f..e187d7e4 100644 --- a/transform/prs2net/test/runs/39.act.fstderr +++ b/transform/prs2net/test/runs/39.act.fstderr @@ -1,4 +1,3 @@ -In expanding foo<> (inst: ct) (39.act:1) -In expanding -toplevel- +In expanding foo<> (39.act:1) Channel: a FATAL: Receive action in multiple concurrent blocks! diff --git a/transform/prs2net/test/runs/40.act.fstderr b/transform/prs2net/test/runs/40.act.fstderr index 8d99d5bd..bdd4246c 100644 --- a/transform/prs2net/test/runs/40.act.fstderr +++ b/transform/prs2net/test/runs/40.act.fstderr @@ -1,6 +1,4 @@ -In expanding foo<> (inst: ct) (40.act:1) -In expanding -toplevel- +In expanding foo<> (40.act:1) WARNING: Probe, send, and receive in different processes? -In expanding foo<> (inst: ct) (40.act:1) -In expanding -toplevel- +In expanding foo<> (40.act:1) WARNING: Probe, send, and receive in different processes? From 6cbd97faec20a838013cc5da2bf6513d1a4118b0 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 30 Apr 2025 10:34:45 -0400 Subject: [PATCH 16/49] fixed module name limit in verilog netlist --- transform/v2act/v2act.cy | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/transform/v2act/v2act.cy b/transform/v2act/v2act.cy index 033f99b5..55b7c47a 100644 --- a/transform/v2act/v2act.cy +++ b/transform/v2act/v2act.cy @@ -13,17 +13,27 @@ module: "module" ID {{X: module_t *m; int off = 0; - char buf[10240]; + char *buf; + + int len = strlen ($2); + if (len < 10) { + len = 10; + } if ($2[0] == '\\') { char *tmp; - MALLOC (tmp, char, strlen ($2)); + MALLOC (tmp, char, len); strcpy (tmp, $2+1); - $0->a->mangle_string (tmp, buf, 10240); + + MALLOC (buf, char, 2*len); + buf[0] = '\0'; + $0->a->mangle_string (tmp, buf, 2*len); FREE (tmp); } else { - snprintf (buf, 10240, "%s", $2); + MALLOC (buf, char, len+1); + buf[0] = '\0'; + snprintf (buf, len+1, "%s", $2); } NEW (m, module_t); @@ -66,6 +76,7 @@ module: "module" ID /* now that we've found it, it should no longer be missing! */ hash_delete ($0->missing, buf); } + FREE (buf); }} "(" port_list ")" ";" module_body ; From 5a354d1fed6659a47361d272749f2c319f43390f Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 30 Apr 2025 12:10:17 -0400 Subject: [PATCH 17/49] only check elements for non-simple inlining --- act/inline.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/act/inline.h b/act/inline.h index de785878..00245e52 100644 --- a/act/inline.h +++ b/act/inline.h @@ -77,8 +77,11 @@ struct act_inline_value { if (!is_just_id) { int tot = (struct_count == 0 ? 1 : struct_count) * (array_sz == 0 ? 1 : array_sz); - for (int i=0; i < tot; i++) { - if (u.arr[i] == NULL) return false; + + if (!isSimple()) { + for (int i=0; i < tot; i++) { + if (u.arr[i] == NULL) return false; + } } } return true; From 07ae8ae9063d5cc80ae9ef6c1d3195d30e640c99 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 7 May 2025 05:59:43 -0400 Subject: [PATCH 18/49] added standard pr template --- .github/PULL_REQUEST_TEMPLATE/standard.md | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/standard.md diff --git a/.github/PULL_REQUEST_TEMPLATE/standard.md b/.github/PULL_REQUEST_TEMPLATE/standard.md new file mode 100644 index 00000000..30bbb1d8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/standard.md @@ -0,0 +1,33 @@ + + +## Description + + +## Purpose of this change + + + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New API (non-breaking change, adds functionality) +- [ ] Modified API (breaking change) +- [ ] New language feature (non-breaking change which adds functionality; note: this is unlikely to be accepted without prior discussions with core developers.) + +For any changes, please ensure that existing test cases pass. For any +API changes, please ensure that the [actflow](https://github.com/asyncvlsi/actflow) repo builds and test cases pass with the proposed changes. + +For bug fixes, please provide additional test cases that would break without +the fix, and that pass with the proposed fixes. + +## How has this been tested? + + +## Checklist: + + +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. +- [ ] The [actflow](https://github.com/asyncvlsi/actflow) repository builds with the changes, and test cases pass. From f0693b454eba3875c9a37e5ce5cbc2d314f03b04 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 7 May 2025 06:16:21 -0400 Subject: [PATCH 19/49] more templates --- .github/PULL_REQUEST_TEMPLATE/api.md | 28 +++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE/bug.md | 23 +++++++++++++++ .../{standard.md => generic.md} | 0 .github/pull_request_template.md | 5 ++++ 4 files changed, 56 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/api.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/bug.md rename .github/PULL_REQUEST_TEMPLATE/{standard.md => generic.md} (100%) create mode 100644 .github/pull_request_template.md diff --git a/.github/PULL_REQUEST_TEMPLATE/api.md b/.github/PULL_REQUEST_TEMPLATE/api.md new file mode 100644 index 00000000..5fa05cbd --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/api.md @@ -0,0 +1,28 @@ + + +## Description + + +## Purpose of this API change + + + +## Types of changes + +- [ ] New API (non-breaking change, adds functionality) +- [ ] Modified API (breaking change) + +For any changes, please ensure that existing test cases pass. For any +API changes, please ensure that the [actflow](https://github.com/asyncvlsi/actflow) repo builds and test cases pass with the proposed changes. + +## How has this been tested? + + +## Checklist: + + +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. +- [ ] The [actflow](https://github.com/asyncvlsi/actflow) repository builds with the changes, and test cases pass. diff --git a/.github/PULL_REQUEST_TEMPLATE/bug.md b/.github/PULL_REQUEST_TEMPLATE/bug.md new file mode 100644 index 00000000..e13945e8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/bug.md @@ -0,0 +1,23 @@ + + +## Description of change + + +## Purpose of this change + + + +Please provide additional test cases that trigger this bug, i.e. which +break without the fix, and that pass with the proposed fix. + +## How has this been tested? + + +## Checklist: + + +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. +- [ ] The [actflow](https://github.com/asyncvlsi/actflow) repository builds with the changes, and test cases pass. diff --git a/.github/PULL_REQUEST_TEMPLATE/standard.md b/.github/PULL_REQUEST_TEMPLATE/generic.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/standard.md rename to .github/PULL_REQUEST_TEMPLATE/generic.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..92c86dab --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ +Please go to the `Preview` tab and select the appropriate sub-template: + +* [Bug fix](?expand=1&template=bug.md) : this request fixes a bug +* [API changes](?expand=1&template=api.md) : this request changes the ACT library API +* [Generic](?expand=1&template=generic.md) : a combination of the two or other change From 195c12b07a7bceb7ce882554191bbab2a8106dc1 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Thu, 8 May 2025 05:25:13 -0400 Subject: [PATCH 20/49] replaced placeholder comment with correct chp expansion --- act/expr2.cc | 11 +++++++++-- act/test/print/34.act | 12 ++++++++++++ act/test/print/35.act | 11 +++++++++++ act/test/print/runs/31.act.stdout | 2 +- act/test/print/runs/34.act.stderr | 0 act/test/print/runs/34.act.stdout | 19 +++++++++++++++++++ act/test/print/runs/35.act.stderr | 0 act/test/print/runs/35.act.stdout | 18 ++++++++++++++++++ 8 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 act/test/print/34.act create mode 100644 act/test/print/35.act create mode 100644 act/test/print/runs/34.act.stderr create mode 100644 act/test/print/runs/34.act.stdout create mode 100644 act/test/print/runs/35.act.stderr create mode 100644 act/test/print/runs/35.act.stdout diff --git a/act/expr2.cc b/act/expr2.cc index 20bd9738..475c2274 100644 --- a/act/expr2.cc +++ b/act/expr2.cc @@ -2441,10 +2441,17 @@ static Expr *_expr_expand (int *width, Expr *e, *width = TypeFactory::bitWidth (it); } else if (te->type == E_INT) { + *width = act_expr_intwidth (te->u.ival.v); if (te->u.ival.v_extra == NULL) { - /* XXX: add stuff here */ + BigInt *btmp; + Expr *nte; + NEW (nte, Expr); + *nte = *te; + btmp = new BigInt(*width, 0, 1); + btmp->setVal (0, nte->u.ival.v); + nte->u.ival.v_extra = btmp; + te = nte; } - *width = act_expr_intwidth (te->u.ival.v); } else { *width = -1; diff --git a/act/test/print/34.act b/act/test/print/34.act new file mode 100644 index 00000000..026a3561 --- /dev/null +++ b/act/test/print/34.act @@ -0,0 +1,12 @@ +defproc test() +{ + pint W = 65; + int<128> q; + + chp { + q := 1 << (65 - 1); + q := 1 << (W - 1) + } +} + +test t; diff --git a/act/test/print/35.act b/act/test/print/35.act new file mode 100644 index 00000000..c43c0161 --- /dev/null +++ b/act/test/print/35.act @@ -0,0 +1,11 @@ +defproc test() +{ + pint W = 65; + + chp { + log(1 << (65 - 1)); + log(1 << (W - 1)) + } +} + +test t; diff --git a/act/test/print/runs/31.act.stdout b/act/test/print/runs/31.act.stdout index c6c988c7..06d811b8 100644 --- a/act/test/print/runs/31.act.stdout +++ b/act/test/print/runs/31.act.stdout @@ -9,7 +9,7 @@ int<4> x[4]; /* connections */ chp { -x[0]:=0x1;x[1]:=0x2;x[2]:=0x3;x[3]:=0x4;y:=x[0]*0+x[1]*1+x[2]*2+x[3]*3 +x[0]:=0x1;x[1]:=0x2;x[2]:=0x3;x[3]:=0x4;y:=x[0]*0x0+x[1]*0x1+x[2]*0x2+x[3]*0x3 } } diff --git a/act/test/print/runs/34.act.stderr b/act/test/print/runs/34.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/print/runs/34.act.stdout b/act/test/print/runs/34.act.stdout new file mode 100644 index 00000000..b61b7136 --- /dev/null +++ b/act/test/print/runs/34.act.stdout @@ -0,0 +1,19 @@ +defproc test (); + +defproc test () +{ + +/* instances */ +int<128> q; + +/* connections */ +chp { +q:=0x0000000000000000000000000000000010000000000000000;q:=0x0000000000000000000000000000000010000000000000000 +} +} + + +/* instances */ +test t; + +/* connections */ diff --git a/act/test/print/runs/35.act.stderr b/act/test/print/runs/35.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/print/runs/35.act.stdout b/act/test/print/runs/35.act.stdout new file mode 100644 index 00000000..8891b214 --- /dev/null +++ b/act/test/print/runs/35.act.stdout @@ -0,0 +1,18 @@ +defproc test (); + +defproc test () +{ + +/* instances */ + +/* connections */ +chp { +log(0x0000000000000000000000000000000010000000000000000);log(0x0000000000000000000000000000000010000000000000000) +} +} + + +/* instances */ +test t; + +/* connections */ From b4cf7fa89723bb20cd7cafa5104b9f4ada7fd1ff Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Thu, 8 May 2025 06:31:04 -0400 Subject: [PATCH 21/49] fix --- act/connect.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/act/connect.cc b/act/connect.cc index 8f62ece2..37f5f0ce 100644 --- a/act/connect.cc +++ b/act/connect.cc @@ -541,6 +541,7 @@ static void _verify_subconn_canonical (UserDef *ux, act_connection *c); static void mk_raw_skip_connection (UserDef *ux, act_connection *c1, act_connection *c2) { + act_connection *c2arg = c2; act_connection *c2p; act_connection *tmp = c2; /* c1 is the root, not c2 */ @@ -658,7 +659,9 @@ static void mk_raw_skip_connection (UserDef *ux, if (!c2->a) { /* no subconnections. done. */ - delete c2; + /* XXX: check this change: + delete c2; + */ #ifdef DEBUG_SKIP_CONN printf ("[raw-skip/3b] return value...\n"); From 4ca209f6e51ad7410f32c78bab530c15c43ed02f Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Sun, 11 May 2025 11:56:48 -0400 Subject: [PATCH 22/49] added support for inlining structure functions in communication --- passes/finline/finline.cc | 74 ++++++++++++++++++- transform/testing/inline/test/43.act | 23 ++++++ transform/testing/inline/test/44.act | 24 ++++++ .../testing/inline/test/runs/43.act.stderr | 0 .../testing/inline/test/runs/43.act.stdout | 40 ++++++++++ .../testing/inline/test/runs/44.act.stderr | 0 .../testing/inline/test/runs/44.act.stdout | 41 ++++++++++ 7 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 transform/testing/inline/test/43.act create mode 100644 transform/testing/inline/test/44.act create mode 100644 transform/testing/inline/test/runs/43.act.stderr create mode 100644 transform/testing/inline/test/runs/43.act.stdout create mode 100644 transform/testing/inline/test/runs/44.act.stderr create mode 100644 transform/testing/inline/test/runs/44.act.stdout diff --git a/passes/finline/finline.cc b/passes/finline/finline.cc index 20c30852..3f0e0349 100644 --- a/passes/finline/finline.cc +++ b/passes/finline/finline.cc @@ -562,10 +562,76 @@ void ActCHPFuncInline::_inline_funcs (list_t *l, act_chp_lang_t *c) c->u.comm.e = val.getVal(); } else { - if (c->type == ACT_CHP_SEND && c->u.comm.e && - c->u.comm.e->type != E_VAR) { - /* XXX: check special case of function that returns a structure */ - warning ("Structure return value inlining for send data not currently supported!"); + if (c->u.comm.e && c->u.comm.e->type != E_VAR) { + /* unstructure this if needed */ + + act_inline_value vals = _inline_funcs_general (l, c->u.comm.e); + Data *d; + int *types; + int nb, ni; + + if (vals.isValid()) { + /* simple inline */ + char buf[1024]; + int idx = _get_fresh_idx ("_us", &_inline_idx); + snprintf (buf, 1024, "_us_%d", idx); + _cursc->Add (buf, cx->datatype()); + ActId *myid = new ActId (buf); + + d = dynamic_cast (cx->datatype()->BaseType()); + Assert (d, "Hmm"); + ActId **fields = d->getStructFields (&types); + FREE (types); + d->getStructCount (&nb, &ni); + int sz = nb + ni; + list_t *l = list_new (); + + Assert (!vals.isSimple(), "Hmm"); + + for (int i=0; i < sz; i++) { + act_chp_lang_t *tc; + + if (vals.u.arr[i]) { + NEW (tc, act_chp_lang_t); + tc->type = ACT_CHP_ASSIGN; + tc->label = NULL; + tc->space = NULL; + tc->u.assign.id = myid->Clone(); + tc->u.assign.id->Tail()->Append (fields[i]); + tc->u.assign.e = vals.u.arr[i]; + list_append (l, tc); + } + else { + delete fields[i]; + } + } + FREE (fields); + { + act_chp_lang_t *tc; + NEW (tc, act_chp_lang_t); + tc->type = c->type; + tc->label = NULL; + tc->space = NULL; + tc->u.comm.chan = c->u.comm.chan; + tc->u.comm.var = c->u.comm.var; + tc->u.comm.flavor = c->u.comm.flavor; + tc->u.comm.convert = c->u.comm.convert; + + // replace orig + c->type = ACT_CHP_SEMI; + c->u.semi_comma.cmd = l; + + NEW (tc->u.comm.e, Expr); + tc->u.comm.e->type = E_VAR; + tc->u.comm.e->u.e.r = NULL; + tc->u.comm.e->u.e.l = (Expr *)myid; + list_append (l, tc); + } + } + else { + act_inline_value vx = _inline_funcs_general (l, c->u.comm.e); + Assert (!vx.isValid(), "What?"); + } } } } diff --git a/transform/testing/inline/test/43.act b/transform/testing/inline/test/43.act new file mode 100644 index 00000000..0e21f4f1 --- /dev/null +++ b/transform/testing/inline/test/43.act @@ -0,0 +1,23 @@ +deftype data (int a, b) +{ + methods { + function plus (data d) : data + { + chp { + self.a := d.a + a; + self.b := d.b + b + } + } + } +} + +defproc test() +{ + data d1, d2; + + chp { + d1 := d1 + d2 + } +} + +test t; diff --git a/transform/testing/inline/test/44.act b/transform/testing/inline/test/44.act new file mode 100644 index 00000000..7a586667 --- /dev/null +++ b/transform/testing/inline/test/44.act @@ -0,0 +1,24 @@ +deftype data (int a, b) +{ + methods { + function plus (data d) : data + { + chp { + self.a := d.a + a; + self.b := d.b + b + } + } + } +} + +defproc test() +{ + data d1, d2; + chan(data) O; + + chp { + O!(d1 + d2) + } +} + +test t; diff --git a/transform/testing/inline/test/runs/43.act.stderr b/transform/testing/inline/test/runs/43.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/testing/inline/test/runs/43.act.stdout b/transform/testing/inline/test/runs/43.act.stdout new file mode 100644 index 00000000..3a6ca847 --- /dev/null +++ b/transform/testing/inline/test/runs/43.act.stdout @@ -0,0 +1,40 @@ +defproc test (); +deftype data (int<32> a; int<32> b); + +defproc test () +{ + +/* instances */ +data _us_0; +data d2; +data d1; + +/* connections */ +chp { +_us_0.a:=int(d2.a+d1.a,32);_us_0.b:=int(d2.b+d1.b,32);d1.a:=_us_0.a;d1.b:=_us_0.b +} +} + +deftype data (int<32> a; int<32> b) +{ + +/* instances */ + +/* connections */ + methods { + function plus (data d) : data { + +/* instances */ + +/* connections */ + chp { self.a:=d.a+a;self.b:=d.b+b } + } + + } +} + + +/* instances */ +test t; + +/* connections */ diff --git a/transform/testing/inline/test/runs/44.act.stderr b/transform/testing/inline/test/runs/44.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/testing/inline/test/runs/44.act.stdout b/transform/testing/inline/test/runs/44.act.stdout new file mode 100644 index 00000000..a0bec022 --- /dev/null +++ b/transform/testing/inline/test/runs/44.act.stdout @@ -0,0 +1,41 @@ +defproc test (); +deftype data (int<32> a; int<32> b); + +defproc test () +{ + +/* instances */ +data _us_0; +chan(data) O; +data d2; +data d1; + +/* connections */ +chp { +_us_0.a:=int(d2.a+d1.a,32);_us_0.b:=int(d2.b+d1.b,32);O!_us_0 +} +} + +deftype data (int<32> a; int<32> b) +{ + +/* instances */ + +/* connections */ + methods { + function plus (data d) : data { + +/* instances */ + +/* connections */ + chp { self.a:=d.a+a;self.b:=d.b+b } + } + + } +} + + +/* instances */ +test t; + +/* connections */ From 20df51a771732c326940b19c24e16fa5f210dbe5 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Fri, 16 May 2025 14:11:32 -0400 Subject: [PATCH 23/49] fix memory issue --- act/connect.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/act/connect.cc b/act/connect.cc index 37f5f0ce..9ee6bc76 100644 --- a/act/connect.cc +++ b/act/connect.cc @@ -541,15 +541,19 @@ static void _verify_subconn_canonical (UserDef *ux, act_connection *c); static void mk_raw_skip_connection (UserDef *ux, act_connection *c1, act_connection *c2) { - act_connection *c2arg = c2; act_connection *c2p; act_connection *tmp = c2; + bool skip_delete = false; /* c1 is the root, not c2 */ if (c1 == c2) return; c2p = c2->primary (); + if (c2p == c1->primary()) { + skip_delete = true; + } + #ifdef DEBUG_SKIP_CONN printf ("\n[raw-skip] entry *****\n"); dump_conn_rec (c1); @@ -659,9 +663,9 @@ static void mk_raw_skip_connection (UserDef *ux, if (!c2->a) { /* no subconnections. done. */ - /* XXX: check this change: - delete c2; - */ + if (!skip_delete) { + delete c2; + } #ifdef DEBUG_SKIP_CONN printf ("[raw-skip/3b] return value...\n"); @@ -797,6 +801,7 @@ static void _merge_subtrees (UserDef *ux, #endif mk_raw_skip_connection (ux, c1->a[i], c2->a[i]); _verify_subconn_canonical (ux, c1->a[i]); + c2->a[i] = NULL; #ifdef DEBUG_MERGE_SUBTREE printf (" %d: end-skip\n", i); #endif From 311925f4cbf652598925607214f6e422a4ca86e8 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Sat, 24 May 2025 08:09:41 -0400 Subject: [PATCH 24/49] config file options to change names for transistor parameters --- act/prs2net_opts.conf | 10 ++++++++++ passes/netgen/emit.cc | 17 ++++++++++------- passes/netgen/netlist.cc | 16 ++++++++++++++++ passes/netgen/netlist.h | 9 +++++++++ 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/act/prs2net_opts.conf b/act/prs2net_opts.conf index c80b0c92..870e7eb9 100644 --- a/act/prs2net_opts.conf +++ b/act/prs2net_opts.conf @@ -35,6 +35,16 @@ int emit_parasitics 0 # string_table device "C" +begin fet_params + string width "W" + string length "L" + string fin "NFIN" + string area_src "AS" + string area_drain "AD" + string perim_src "PS" + string perim_drain "PD" +end + end # diff --git a/passes/netgen/emit.cc b/passes/netgen/emit.cc index dc32a458..73e8f4e9 100644 --- a/passes/netgen/emit.cc +++ b/passes/netgen/emit.cc @@ -410,9 +410,9 @@ netlist_t *ActNetlistPass::emitNetlist (Process *p) fatal_error ("Device mapping for `%s' not defined in technology file.", devname); } fprintf (fp, " %s", config_get_string (devname)); - fprintf (fp, " W="); + fprintf (fp, " %s=", param_names.w); print_number (fp, w*manufacturing_grid*output_scale_factor); - fprintf (fp, " L="); + fprintf (fp, " %s=", param_names.l); if (len_repeat > 1 && discrete_len == 0 && il == len_repeat-1) { print_number (fp, (find_length_fit (e->l - (e->nlen-1)*l)* @@ -426,7 +426,10 @@ netlist_t *ActNetlistPass::emitNetlist (Process *p) if (_fin_width > 0) { Assert ((w % _fin_width) == 0, "Internal inconsistency in fin width value"); - fprintf (fp, " NFIN=%d", w/_fin_width); + if (!param_names.fin) { + fatal_error ("fin_width specified without fin name in fet parameters!"); + } + fprintf (fp, " %s=%d", param_names.fin, w/_fin_width); } /* print extra fet string */ @@ -459,9 +462,9 @@ netlist_t *ActNetlistPass::emitNetlist (Process *p) else { gap = fet_spacing_diffonly; } - fprintf (fp, "+ AS="); + fprintf (fp, "+ %s=", param_names.as); print_number (fp, (e->w/getGridsPerLambda()*gap)*(lambda2*oscale2)); - fprintf (fp, " PS="); + fprintf (fp, " %s=", param_names.ps); print_number (fp, 2*(e->w/getGridsPerLambda() + gap)* lambda*output_scale_factor); @@ -481,9 +484,9 @@ netlist_t *ActNetlistPass::emitNetlist (Process *p) else { gap = fet_spacing_diffonly; } - fprintf (fp, " AD="); + fprintf (fp, " %s=", param_names.ad); print_number (fp, (e->w/getGridsPerLambda()*gap)*(lambda2*oscale2)); - fprintf (fp, " PD="); + fprintf (fp, " %s=", param_names.pd); print_number (fp, 2*(e->w/getGridsPerLambda() + gap)* lambda*output_scale_factor); fprintf (fp, "\n"); diff --git a/passes/netgen/netlist.cc b/passes/netgen/netlist.cc index 79b222c7..37323b30 100644 --- a/passes/netgen/netlist.cc +++ b/passes/netgen/netlist.cc @@ -2629,6 +2629,14 @@ ActNetlistPass::ActNetlistPass (Act *a) : ActPass (a, "prs2net") weak_share_min = 1; weak_share_max = 1; + config_set_default_string ("net.fet_params.width", "W"); + config_set_default_string ("net.fet_params.length", "L"); + config_set_default_string ("net.fet_params.area_src", "AS"); + config_set_default_string ("net.fet_params.perim_src", "PS"); + config_set_default_string ("net.fet_params.area_drain", "AD"); + config_set_default_string ("net.fet_params.perim_drain", "PD"); + config_set_default_string ("net.fet_params.fin", "NFIN"); + default_load_cap = config_get_real ("net.default_load_cap"); p_n_ratio = config_get_real ("net.p_n_ratio"); weak_to_strong_ratio = config_get_real ("net.weak_to_strong_ratio"); @@ -2773,6 +2781,14 @@ ActNetlistPass::ActNetlistPass (Act *a) : ActPass (a, "prs2net") else { mangled_ports_actflat = true; } + + param_names.w = config_get_string ("net.fet_params.width"); + param_names.l = config_get_string ("net.fet_params.length"); + param_names.as = config_get_string ("net.fet_params.area_src"); + param_names.ps = config_get_string ("net.fet_params.perim_src"); + param_names.ad = config_get_string ("net.fet_params.area_drain"); + param_names.pd = config_get_string ("net.fet_params.perim_drain"); + param_names.fin = config_get_string ("net.fet_params.fin"); } ActNetlistPass::~ActNetlistPass() diff --git a/passes/netgen/netlist.h b/passes/netgen/netlist.h index dd3b427a..f2fea690 100644 --- a/passes/netgen/netlist.h +++ b/passes/netgen/netlist.h @@ -300,6 +300,15 @@ class ActNetlistPass : public ActPass { /* mangled cells for flat act output? */ bool mangled_ports_actflat; + /* strings for fet parameters */ + struct fet_param { + const char *w; + const char *l; + const char *fin; + const char *as, *ad; + const char *ps, *pd; + } param_names; + netlist_t *generate_netlist (Process *p); void generate_netgraph (netlist_t *N, int num_vdd_share, From 9ced40dc0115f1d954f91328a0b592811cbfc54d Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Sat, 24 May 2025 12:52:20 -0400 Subject: [PATCH 25/49] macro expansions needs to duplicate id --- act/macros.cc | 8 ++++++++ act/test/userdef/82.act | 21 +++++++++++++++++++++ act/test/userdef/runs/82.act.stderr | 0 act/test/userdef/runs/82.act.stdout | 0 4 files changed, 29 insertions(+) create mode 100644 act/test/userdef/82.act create mode 100644 act/test/userdef/runs/82.act.stderr create mode 100644 act/test/userdef/runs/82.act.stdout diff --git a/act/macros.cc b/act/macros.cc index 11f0f4c0..cb3f5da7 100644 --- a/act/macros.cc +++ b/act/macros.cc @@ -581,6 +581,14 @@ static void _replace_ids (ActId *id, act_inline_table *tab, Expr *e) if (e->type == E_INT && e->u.ival.v_extra) { e->u.ival.v_extra = (Expr *) new BigInt (*((BigInt *)e->u.ival.v_extra)); } + else if (e->type == E_VAR) { + e->u.e.l = (Expr *) ((ActId *)e->u.e.l)->Clone (); + } + else { + Expr *f = expr_dup (e); + *e = *f; + FREE (f); + } } else { ActId *ret = id->Clone (); diff --git a/act/test/userdef/82.act b/act/test/userdef/82.act new file mode 100644 index 00000000..ff2601a0 --- /dev/null +++ b/act/test/userdef/82.act @@ -0,0 +1,21 @@ +export deftype blah (int w) +{ + methods { + macro delay(int x) { + *[ x > 0 -> x := x - 1 ] + } + } +} + +defproc test() +{ + blah b; + int w; + + chp { + w := 100; + b.delay (w) + } +} + +test t; diff --git a/act/test/userdef/runs/82.act.stderr b/act/test/userdef/runs/82.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/userdef/runs/82.act.stdout b/act/test/userdef/runs/82.act.stdout new file mode 100644 index 00000000..e69de29b From 487460bd927910891aec584150068cd6caae3d45 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 26 May 2025 16:51:56 -0400 Subject: [PATCH 26/49] don't traverse pstructs... --- act/pass.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/act/pass.cc b/act/pass.cc index 2af1e710..19a88a57 100644 --- a/act/pass.cc +++ b/act/pass.cc @@ -283,7 +283,7 @@ void ActPass::recursive_op (UserDef *p, int mode) FREE (tmp); } } - else { + else if (TypeFactory::isDataType (vx->t)) { Data *x = dynamic_cast (vx->t->BaseType()); Assert (x, "what?"); if (x->isExpanded()) { @@ -298,6 +298,10 @@ void ActPass::recursive_op (UserDef *p, int mode) FREE (tmp); } } + else if (TypeFactory::isPStructType (vx->t)) { + /* nothing to do */ + } + // could be a pstruct! } } From 3444d780116d5ffa27c8ffa814436340866d1fb8 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 26 May 2025 16:57:44 -0400 Subject: [PATCH 27/49] traverse structures as well --- act/pass.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/act/pass.cc b/act/pass.cc index 19a88a57..6d58b770 100644 --- a/act/pass.cc +++ b/act/pass.cc @@ -283,7 +283,8 @@ void ActPass::recursive_op (UserDef *p, int mode) FREE (tmp); } } - else if (TypeFactory::isDataType (vx->t)) { + else if (TypeFactory::isDataType (vx->t) || + TypeFactory::isStructure (vx->t)) { Data *x = dynamic_cast (vx->t->BaseType()); Assert (x, "what?"); if (x->isExpanded()) { From 8ebd8cb7f3f69c7bf146f62e4afe77ae625adddf Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Fri, 6 Jun 2025 06:43:34 -0400 Subject: [PATCH 28/49] support for int conv of parameterized structs --- act/check.cc | 4 ++++ act/test/userdef/83.act | 24 ++++++++++++++++++++++++ act/test/userdef/runs/83.act.stderr | 0 act/test/userdef/runs/83.act.stdout | 0 4 files changed, 28 insertions(+) create mode 100644 act/test/userdef/83.act create mode 100644 act/test/userdef/runs/83.act.stderr create mode 100644 act/test/userdef/runs/83.act.stdout diff --git a/act/check.cc b/act/check.cc index 3ce90ed2..763a65df 100644 --- a/act/check.cc +++ b/act/check.cc @@ -1078,6 +1078,10 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) InstType *x; if (strcmp (um->getName(), "int") == 0) { x = new InstType (s, um->Parent(), 0); + // get struct arguments, if any! + if (y->getNumParams() > 0) { + x->appendParams (y->getNumParams(), y->allParams()); + } } else { x = TypeFactory::Factory()->NewInt (s, Type::direction::NONE, 0, diff --git a/act/test/userdef/83.act b/act/test/userdef/83.act new file mode 100644 index 00000000..a347eb0e --- /dev/null +++ b/act/test/userdef/83.act @@ -0,0 +1,24 @@ +pint w=3; + +template deftype struct ( + int a; + int b; + int c +){} + +defproc test(){ + +int flat0; +struct str; + + chp{ + log("running"); + str.a:=1; + str.b:=int(2,1); + str.c:=1; + log("str.a: ",str.a,"%b str.b: ",str.b," str.c: ",str.c); + + flat0:=int(str); + log("%bflat0: ",flat0) + } +} diff --git a/act/test/userdef/runs/83.act.stderr b/act/test/userdef/runs/83.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/userdef/runs/83.act.stdout b/act/test/userdef/runs/83.act.stdout new file mode 100644 index 00000000..e69de29b From 1ec1d59459c916985110cda5829125186020c149 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 18 Jun 2025 11:08:07 -0400 Subject: [PATCH 29/49] after inline expansion, check cached exprs --- act/expr_api.h | 5 +++++ act/expr_print.cc | 13 ++++++++++--- act/macros.cc | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/act/expr_api.h b/act/expr_api.h index 8ef714a9..14d004b0 100644 --- a/act/expr_api.h +++ b/act/expr_api.h @@ -314,6 +314,11 @@ Expr *expr_dag (Expr *e); */ void expr_dag_free (Expr *); +/** + * Return 1 if the expression is cached, 0 otherwise + */ +int expr_ex_is_cached (Expr *); + class UserMacro; /* diff --git a/act/expr_print.cc b/act/expr_print.cc index 967b2127..5e7e1db5 100644 --- a/act/expr_print.cc +++ b/act/expr_print.cc @@ -1132,7 +1132,15 @@ AExprstep *AExpr::stepper() } - +int expr_ex_is_cached (Expr *e) +{ + if (!e) return 1; + if (e->type == E_TRUE || e->type == E_FALSE || + (e->type == E_INT && !e->u.ival.v_extra)) { + return 1; + } + return 0; +} static void efree_ex (Expr *e) @@ -1189,8 +1197,7 @@ static void efree_ex (Expr *e) if (e->u.e.r) efree_ex (e->u.e.r); break; } - if (e->type == E_TRUE || e->type == E_FALSE || - (e->type == E_INT && !e->u.ival.v_extra)) { + if (expr_ex_is_cached (e)) { /* cached */ } else { diff --git a/act/macros.cc b/act/macros.cc index cb3f5da7..1a87f806 100644 --- a/act/macros.cc +++ b/act/macros.cc @@ -584,7 +584,7 @@ static void _replace_ids (ActId *id, act_inline_table *tab, Expr *e) else if (e->type == E_VAR) { e->u.e.l = (Expr *) ((ActId *)e->u.e.l)->Clone (); } - else { + else if (!expr_ex_is_cached (e)) { Expr *f = expr_dup (e); *e = *f; FREE (f); From d9e328201fc2513e8306703f5a435e801661cd12 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 24 Jun 2025 11:37:48 -0400 Subject: [PATCH 30/49] started on dataflow structure support --- act/act.cc | 2 ++ act/check.cc | 25 +++++++++++++++++++------ act/expr.m4 | 5 +++++ act/expr2.cc | 11 ++++++++--- act/id.cc | 5 +++++ act/lang.m4 | 3 +++ act/test/lang/137.act | 13 +++++++++++++ act/test/lang/138.act | 22 ++++++++++++++++++++++ act/treetypes.h | 3 +++ act/typecheck.h | 17 +++++++++++++++-- act/wrap.cc | 9 +++++++-- 11 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 act/test/lang/137.act create mode 100644 act/test/lang/138.act diff --git a/act/act.cc b/act/act.cc index 90c44ff8..49e5b726 100644 --- a/act/act.cc +++ b/act/act.cc @@ -576,6 +576,8 @@ static void _init_tr (ActTree *tr, TypeFactory *tf, ActNamespace *G) tr->special_id = 0; tr->special_id_sc = NULL; + + tr->allow_chan = false; } static void _free_tr (ActTree *tr) diff --git a/act/check.cc b/act/check.cc index 763a65df..aa718022 100644 --- a/act/check.cc +++ b/act/check.cc @@ -97,7 +97,7 @@ static void dumpflags(int f) #endif static InstType *_act_get_var_type (Scope *s, ActId *id, ActId **retid, - int *strict) + int *strict, bool subchan) { InstType *it; UserDef *u; @@ -131,8 +131,14 @@ static InstType *_act_get_var_type (Scope *s, ActId *id, ActId **retid, } } + bool subchan_conv = false; + if (id->Rest ()) { while (id->Rest()) { + if (subchan && TypeFactory::isChanType (it->BaseType())) { + it = TypeFactory::getChanDataType (it); + subchan_conv = true; + } u = dynamic_cast(it->BaseType ()); Assert (u, "This should have been caught during parsing!"); id = id->Rest(); @@ -154,6 +160,10 @@ static InstType *_act_get_var_type (Scope *s, ActId *id, ActId **retid, *strict = is_strict; } *retid = id; + + if (subchan_conv) { + it = new InstType (s, TypeFactory::Factory()->NewChan (it, NULL)); + } return it; } @@ -241,12 +251,12 @@ static int _act_type_id_to_flags (InstType *it, ActId *id, int is_strict) } } -int act_type_var (Scope *s, ActId *id, InstType **xit) +int act_type_var_gen (Scope *s, ActId *id, InstType **xit, bool subchan) { InstType *it; int is_strict; - it = _act_get_var_type (s, id, &id, &is_strict); + it = _act_get_var_type (s, id, &id, &is_strict, subchan); if (!it->arrayInfo() && id->arrayInfo()) { char *tmpbuf; @@ -669,7 +679,7 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) InstType *xit; long lo, hi; theid = (ActId *)e->u.e.l; - lt = act_type_var (s, theid, &xit); + lt = act_type_var_gen (s, theid, &xit, (only_chan == 0 ? false : true)); if (lt == T_ERR) return T_ERR; if (only_chan == 1 || (only_chan == 2 && !(T_BASETYPE_INT (lt)))) { if (TypeFactory::isChanType (xit)) { @@ -1254,13 +1264,16 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) case E_VAR: { InstType *xit; - lt = act_type_var (s, (ActId *)e->u.e.l, &xit); + + lt = act_type_var_gen (s, (ActId *)e->u.e.l, &xit, + (only_chan == 0 ? false : true)); + if (lt == T_ERR) return T_ERR; if (only_chan) { if (lt == T_CHAN) { ActId *tmp, *theid; theid = (ActId *) e->u.e.l; - InstType *it = _act_get_var_type (s, theid, &tmp, NULL); + InstType *it = _act_get_var_type (s, theid, &tmp, NULL, true); if (it->getDir() == Type::OUT) { InstType *it2 = s->FullLookup (theid->getName()); diff --git a/act/expr.m4 b/act/expr.m4 index 0b074ccf..e1de22e9 100644 --- a/act/expr.m4 +++ b/act/expr.m4 @@ -268,6 +268,11 @@ expr_id[ActId *]: { base_id "." }* } } + if (list_next (li) && $0->allow_chan && TypeFactory::isExactChanType (it)) { + it = TypeFactory::getChanDataType (it); + $A(it); + } + ud = NULL; for (li = list_next (li); li; li = list_next (li)) { /* it = the inst type of where we are so far; li has the next diff --git a/act/expr2.cc b/act/expr2.cc index 475c2274..351223d8 100644 --- a/act/expr2.cc +++ b/act/expr2.cc @@ -848,6 +848,11 @@ static Expr *_expr_expand (int *width, Expr *e, UserDef *id_ux = NULL; if (id_it) { id_ux = dynamic_cast (id_it->BaseType()); + if (!id_ux && (flags & ACT_EXPR_EXFLAG_CHPEX)) { + Assert (TypeFactory::isChanType (id_it), "Should have been caught earlier"); + id_ux = dynamic_cast + (TypeFactory::getChanDataType (id_it)->BaseType()); + } Assert (id_ux, "What?"); um = id_ux->getMacro (um->getName()); if (!_idstack) { @@ -997,7 +1002,7 @@ static Expr *_expr_expand (int *width, Expr *e, } act_chp_macro_check (s, (ActId *)te->u.e.l); InstType *it; - act_type_var (s, (ActId *)te->u.e.l, &it); + act_type_var_gen (s, (ActId *)te->u.e.l, &it, true); *width = TypeFactory::bitWidth (it); // now we have the bit-width! // now we convert the rest of the expression!!! @@ -2437,7 +2442,7 @@ static Expr *_expr_expand (int *width, Expr *e, if (te->type == E_VAR) { act_chp_macro_check (s, (ActId *)te->u.e.l); InstType *it; - act_type_var (s, (ActId *)te->u.e.l, &it); + act_type_var_gen (s, (ActId *)te->u.e.l, &it, true); *width = TypeFactory::bitWidth (it); } else if (te->type == E_INT) { @@ -2821,7 +2826,7 @@ static int _expr_bw_calc(struct pHashtable *H, Expr *e, Scope *s) case E_VAR: { InstType *xit; - lw = act_type_var (s, (ActId *)e->u.e.l, &xit); + lw = act_type_var_gen (s, (ActId *)e->u.e.l, &xit, true); if (xit->arrayInfo() && !((ActId *)e->u.e.l)->arrayInfo()) { // not a de-reference width = -1; diff --git a/act/id.cc b/act/id.cc index 3a02337b..a2aca2cf 100644 --- a/act/id.cc +++ b/act/id.cc @@ -350,6 +350,11 @@ Expr *ActId::Eval (ActNamespace *ns, Scope *s, int is_lval, int is_chp) Assert (it->isExpanded(), "This should be expanded"); u = dynamic_cast(it->BaseType ()); + if (!u && is_chp) { + if (TypeFactory::isChanType (it)) { + u = dynamic_cast (TypeFactory::getChanDataType (it)->BaseType()); + } + } Assert (u, "This should have been caught earlier!"); if (TypeFactory::isPStructType (u)) { diff --git a/act/lang.m4 b/act/lang.m4 index 785f8954..18109c9d 100644 --- a/act/lang.m4 +++ b/act/lang.m4 @@ -3099,6 +3099,7 @@ lang_dataflow[ActBody *]: "dataflow" "{" [ dataflow_ordering ] $0->line = $l; $0->column = $c; $0->file = $n; + $0->allow_chan = true; }} { dataflow_items ";" }* "}" {{X: @@ -3118,6 +3119,8 @@ lang_dataflow[ActBody *]: "dataflow" "{" [ dataflow_ordering ] } OPT_FREE ($3); + $0->allow_chan = false; + return new ActBody_Lang ($l, dflow); }} ; diff --git a/act/test/lang/137.act b/act/test/lang/137.act new file mode 100644 index 00000000..4af7a343 --- /dev/null +++ b/act/test/lang/137.act @@ -0,0 +1,13 @@ +deftype rec (int a, b) { } + +defproc test() +{ + chan(rec) a; + chan(int) x; + + dataflow { + a.a -> x + } +} + +test t; diff --git a/act/test/lang/138.act b/act/test/lang/138.act new file mode 100644 index 00000000..50d9a9eb --- /dev/null +++ b/act/test/lang/138.act @@ -0,0 +1,22 @@ +deftype rec (int a, b) { + methods { + function geta() : int + { + chp { + self := a + } + } + } +} + +defproc test() +{ + chan(rec) a; + chan(int) x; + + dataflow { + a.geta() -> x + } +} + +test t; diff --git a/act/treetypes.h b/act/treetypes.h index 5d987534..2acc9e77 100644 --- a/act/treetypes.h +++ b/act/treetypes.h @@ -201,6 +201,9 @@ typedef struct { int special_id; /* special ID! for user macros */ Scope *special_id_sc; /* scope (if any) */ + + /* set this to true if a chan ID is in the expression */ + bool allow_chan; } ActTree; diff --git a/act/typecheck.h b/act/typecheck.h index 53dfb4c1..04bd8fa3 100644 --- a/act/typecheck.h +++ b/act/typecheck.h @@ -123,15 +123,28 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan = 0); /** - * Used to type-check a variable + * Used to type-check a variable. If the subchan flag is set to true, + * this permits A. to pass typechecking when A is a channel + * whose data type is a structure, and is a valid field + * reference. In this case, the type of the variable is going to be a + * channel of type , where is the type of . * * @param s is the scope in which to peform the type-checking * @param id is the variable to be checked * @param xit is used to return the actual InstType * for the * identifier, if xit is non-NULL + * @param subchan if this is true, then chan.sub is permitted for + * structure channels, and returns chan(foo) where foo is the type of + * the sub field. * @return a T_... flag that describes the result of the checking */ -int act_type_var (Scope *s, ActId *id, InstType **xit); +int act_type_var_gen (Scope *s, ActId *id, InstType **xit, bool subchan); + +/** + * This definition wraps the general act_type_var call setting subchan + * to false. + */ +#define act_type_var(a,b,c) act_type_var_gen((a),(b),(c),false) /** * Used to type-check a channel operation. The channel operation is of diff --git a/act/wrap.cc b/act/wrap.cc index c599d0f2..a86686ee 100644 --- a/act/wrap.cc +++ b/act/wrap.cc @@ -895,8 +895,13 @@ Expr *act_walk_X_expr (ActTree *cookie, Expr *e) } u = dynamic_cast (it->BaseType()); if (!u) { - act_parse_err (&p, "Field `%s' isn't a user-defined type", - tmp->getName()); + if (cookie->allow_chan && TypeFactory::isChanType (it->BaseType())) { + u = dynamic_cast (TypeFactory::getChanDataType (it)->BaseType()); + } + if (!u) { + act_parse_err (&p, "Field `%s' isn't a user-defined type", + tmp->getName()); + } } sc = u->CurScope(); prev = tmp; From 67fc02a493903c40ac024992752bdb3d1ee21d78 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 24 Jun 2025 11:38:17 -0400 Subject: [PATCH 31/49] new test cases --- act/test/lang/runs/137.act.stderr | 0 act/test/lang/runs/137.act.stdout | 0 act/test/lang/runs/138.act.stderr | 0 act/test/lang/runs/138.act.stdout | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 act/test/lang/runs/137.act.stderr create mode 100644 act/test/lang/runs/137.act.stdout create mode 100644 act/test/lang/runs/138.act.stderr create mode 100644 act/test/lang/runs/138.act.stdout diff --git a/act/test/lang/runs/137.act.stderr b/act/test/lang/runs/137.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/137.act.stdout b/act/test/lang/runs/137.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/138.act.stderr b/act/test/lang/runs/138.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/138.act.stdout b/act/test/lang/runs/138.act.stdout new file mode 100644 index 00000000..e69de29b From 1fc4b905782389f12a00adbcddd674d0c891ccfa Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Fri, 27 Jun 2025 14:37:51 -0400 Subject: [PATCH 32/49] more updates to support dataflow with structs --- act/check.cc | 27 +++++++++++++++++++++++---- act/lang.m4 | 6 ++++++ act/scope.cc | 2 +- act/test/lang/139.act | 13 +++++++++++++ act/test/lang/140.act | 13 +++++++++++++ act/test/lang/runs/139.act.stderr | 3 +++ act/test/lang/runs/139.act.stdout | 0 act/test/lang/runs/140.act.stderr | 0 act/test/lang/runs/140.act.stdout | 0 act/typecheck.h | 3 ++- 10 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 act/test/lang/139.act create mode 100644 act/test/lang/140.act create mode 100644 act/test/lang/runs/139.act.stderr create mode 100644 act/test/lang/runs/139.act.stdout create mode 100644 act/test/lang/runs/140.act.stderr create mode 100644 act/test/lang/runs/140.act.stdout diff --git a/act/check.cc b/act/check.cc index aa718022..8d297955 100644 --- a/act/check.cc +++ b/act/check.cc @@ -132,6 +132,7 @@ static InstType *_act_get_var_type (Scope *s, ActId *id, ActId **retid, } bool subchan_conv = false; + ActId *orig_id = id; if (id->Rest ()) { while (id->Rest()) { @@ -140,6 +141,14 @@ static InstType *_act_get_var_type (Scope *s, ActId *id, ActId **retid, subchan_conv = true; } u = dynamic_cast(it->BaseType ()); + if (!u && !subchan) { + char *tmpbuf; + MALLOC (tmpbuf, char, 10240); + orig_id->sPrint (tmpbuf, 10240); + typecheck_err ("Identifier `%s' has an illegal use of `.' in this context.", tmpbuf); + FREE (tmpbuf); + return NULL; + } Assert (u, "This should have been caught during parsing!"); id = id->Rest(); it = u->Lookup (id); @@ -257,6 +266,9 @@ int act_type_var_gen (Scope *s, ActId *id, InstType **xit, bool subchan) int is_strict; it = _act_get_var_type (s, id, &id, &is_strict, subchan); + if (!it) { + return T_ERR; + } if (!it->arrayInfo() && id->arrayInfo()) { char *tmpbuf; @@ -299,7 +311,8 @@ static InstType *_act_special_expr_insttype (Scope *s, Expr *e, int *islocal, if (e->type == E_VAR) { /* special case #1 */ - it = act_actual_insttype (s, (ActId *)e->u.e.l, islocal); + it = act_actual_insttype (s, (ActId *)e->u.e.l, islocal, + only_chan == 0 ? false : true); return it; } else if (e->type == E_FUNCTION) { @@ -349,7 +362,8 @@ static InstType *_act_special_expr_insttype (Scope *s, Expr *e, int *islocal, Assert (e->u.e.r->type == E_VAR, "What?"); it = act_actual_insttype (u->CurScope(), (ActId *) e->u.e.r->u.e.l, - islocal); + islocal, + only_chan == 0 ? false : true); return it; } else if (e->type == E_PSTRUCT) { @@ -1274,6 +1288,7 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) ActId *tmp, *theid; theid = (ActId *) e->u.e.l; InstType *it = _act_get_var_type (s, theid, &tmp, NULL, true); + Assert (it, "This should not happen"); if (it->getDir() == Type::OUT) { InstType *it2 = s->FullLookup (theid->getName()); @@ -1510,7 +1525,7 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) Returns the insttype for the ID. If islocal != NULL, set to 1 if this is a local id within the scope */ -InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal) +InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal, bool subchan) { InstType *it; @@ -1572,6 +1587,10 @@ InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal) } UserDef *u; u = dynamic_cast(it->BaseType ()); + if (!u && subchan && TypeFactory::isChanType (it)) { + u = dynamic_cast + (TypeFactory::getChanDataType (it)->BaseType()); + } Assert (u, "This should have been caught during parsing!"); /* HERE: APPLY MAP! */ @@ -2166,7 +2185,7 @@ int act_type_conn (Scope *s, ActId *id, AExpr *rae) */ int lhslocal; - InstType *lhs = act_actual_insttype (s, id, &lhslocal); + InstType *lhs = act_actual_insttype (s, id, &lhslocal, false); if (!lhs) return T_ERR; diff --git a/act/lang.m4 b/act/lang.m4 index 18109c9d..8fd5c281 100644 --- a/act/lang.m4 +++ b/act/lang.m4 @@ -3165,6 +3165,9 @@ w_chan_int_expr "->" [ "[" wpint_expr [ "," wpint_expr ] "]" ] expr_id if (_act_id_is_true_false ($4)) { $E("Dataflow RHS can't be true/false!"); } + if (_act_id_is_enum_const ($0->os, $0->curns, $4)) { + $E("Can't use an enumeration constant in this context!"); + } InstType *it; if (act_type_var ($0->scope, $4, &it) != T_CHAN) { $e("Identifier on the RHS of a dataflow expression must be of channel type"); @@ -3456,6 +3459,9 @@ expr_id_or_star[ActId *]: expr_id if (_act_id_is_true_false ($1)) { $E("Can't use true/false in this context!"); } + if (_act_id_is_enum_const ($0->os, $0->curns, $1)) { + $E("Can't use an enumeration constant in this context!"); + } return $1; }} | "*" diff --git a/act/scope.cc b/act/scope.cc index 9a85cc00..c1cacb78 100644 --- a/act/scope.cc +++ b/act/scope.cc @@ -1255,7 +1255,7 @@ void Scope::BindParam (ActId *id, AExpr *ae) AExprstep *aes = NULL; if (subrange_info) { - actual = act_actual_insttype (this, id, NULL); + actual = act_actual_insttype (this, id, NULL, false); } else { actual = vx->t; diff --git a/act/test/lang/139.act b/act/test/lang/139.act new file mode 100644 index 00000000..9630fe12 --- /dev/null +++ b/act/test/lang/139.act @@ -0,0 +1,13 @@ +deftype rec (int a, b) { } + +defproc test() +{ + chan(rec) a; + chan(int) x; + + dataflow { + x -> a.a + } +} + +test t; diff --git a/act/test/lang/140.act b/act/test/lang/140.act new file mode 100644 index 00000000..ace1adb1 --- /dev/null +++ b/act/test/lang/140.act @@ -0,0 +1,13 @@ +deftype rec (int a, b) { } + +defproc test() +{ + chan(rec) a; + chan(int) x; + + dataflow { + a.a + a.b -> x + } +} + +test t; diff --git a/act/test/lang/runs/139.act.stderr b/act/test/lang/runs/139.act.stderr new file mode 100644 index 00000000..ca62da36 --- /dev/null +++ b/act/test/lang/runs/139.act.stderr @@ -0,0 +1,3 @@ +ERROR: File `139.act', line 9, col 6 + Identifier on the RHS of a dataflow expression must be of channel type + ID: a.a diff --git a/act/test/lang/runs/139.act.stdout b/act/test/lang/runs/139.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/140.act.stderr b/act/test/lang/runs/140.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/140.act.stdout b/act/test/lang/runs/140.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/typecheck.h b/act/typecheck.h index 04bd8fa3..32dcda5c 100644 --- a/act/typecheck.h +++ b/act/typecheck.h @@ -237,9 +237,10 @@ InstType *act_expr_insttype (Scope *s, Expr *e, int *islocal, int only_chan); * @param id is the identifier * @param islocal is used to return 1 if the identifier is only * accessible within the local scope specified, 0 otherwise + * @param subchan has the same meaning as act_type_var_gen * @return the type of the identifier (NULL if not found) */ -InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal); +InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal, bool subchan); /** * Used to record the line, column, and file for error reporting From d88865698da100de52e948153c38f07ca56d6d7f Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 2 Jul 2025 13:51:54 -0400 Subject: [PATCH 33/49] update for newer versions of gcc --- miniscm/lispA-Z.h | 122 ++++++++++++++++++++------------------------- miniscm/lispEval.c | 4 +- 2 files changed, 57 insertions(+), 69 deletions(-) diff --git a/miniscm/lispA-Z.h b/miniscm/lispA-Z.h index e560a07d..d436e755 100644 --- a/miniscm/lispA-Z.h +++ b/miniscm/lispA-Z.h @@ -37,106 +37,94 @@ /* * predicates */ -extern LispObj *LispIsBool (); -extern LispObj *LispIsSym (); -extern LispObj *LispIsList (); -extern LispObj *LispIsPair (); -extern LispObj *LispIsNumber (); -extern LispObj *LispIsString (); -extern LispObj *LispIsProc (); -extern LispObj *LispEqv (); +extern LispObj *LispIsBool (char *, Sexp *, Sexp *); +extern LispObj *LispIsSym (char *, Sexp *, Sexp *); +extern LispObj *LispIsList (char *, Sexp *, Sexp *); +extern LispObj *LispIsPair (char *, Sexp *, Sexp *); +extern LispObj *LispIsNumber (char *, Sexp *, Sexp *); +extern LispObj *LispIsString (char *, Sexp *, Sexp *); +extern LispObj *LispIsProc (char *, Sexp *, Sexp *); +extern LispObj *LispEqv (char *, Sexp *, Sexp *); /* * lists */ -extern LispObj *LispCar (); -extern LispObj *LispCdr (); -extern LispObj *LispCons (); -extern LispObj *LispNull (); -extern LispObj *LispList (); -extern LispObj *LispLength (); +extern LispObj *LispCar (char *, Sexp *, Sexp *); +extern LispObj *LispCdr (char *, Sexp *, Sexp *); +extern LispObj *LispCons (char *, Sexp *, Sexp *); +extern LispObj *LispNull (char *, Sexp *, Sexp *); +extern LispObj *LispList (char *, Sexp *, Sexp *); +extern LispObj *LispLength (char *, Sexp *, Sexp *); /* * controlling evaluation */ -extern LispObj *LispQuote (); -extern LispObj *Lispeval (); -extern LispObj *LispLambda (); -extern LispObj *Lispapply (); +extern LispObj *LispQuote (char *, Sexp *, Sexp *); +extern LispObj *Lispeval (char *, Sexp *, Sexp *); +extern LispObj *LispLambda (char *, Sexp *, Sexp *); +extern LispObj *Lispapply (char *, Sexp *, Sexp *); /* * definitions and side-effects */ -extern LispObj *LispDefine (); -extern LispObj *LispSetBang (); -extern LispObj *LispLet (); -extern LispObj *LispLetRec (); -extern LispObj *LispLetStar (); -extern LispObj *LispSetCarBang (); -extern LispObj *LispSetCdrBang (); +extern LispObj *LispDefine (char *, Sexp *, Sexp *); +extern LispObj *LispSetBang (char *, Sexp *, Sexp *); +extern LispObj *LispLet (char *, Sexp *, Sexp *); +extern LispObj *LispLetRec (char *, Sexp *, Sexp *); +extern LispObj *LispLetStar (char *, Sexp *, Sexp *); +extern LispObj *LispSetCarBang (char *, Sexp *, Sexp *); +extern LispObj *LispSetCdrBang (char *, Sexp *, Sexp *); /* * arithmetic */ -extern LispObj *LispAdd (); -extern LispObj *LispSub (); -extern LispObj *LispMult (); -extern LispObj *LispDiv (); -extern LispObj *LispTruncate (); -extern LispObj *LispZeroQ (); -extern LispObj *LispPositiveQ (); -extern LispObj *LispNegativeQ (); +extern LispObj *LispAdd (char *, Sexp *, Sexp *); +extern LispObj *LispSub (char *, Sexp *, Sexp *); +extern LispObj *LispMult (char *, Sexp *, Sexp *); +extern LispObj *LispDiv (char *, Sexp *, Sexp *); +extern LispObj *LispTruncate (char *, Sexp *, Sexp *); +extern LispObj *LispZeroQ (char *, Sexp *, Sexp *); +extern LispObj *LispPositiveQ (char *, Sexp *, Sexp *); +extern LispObj *LispNegativeQ (char *, Sexp *, Sexp *); /* * control flow */ -extern LispObj *LispBegin (); -extern LispObj *LispIf (); -extern LispObj *LispCond (); +extern LispObj *LispBegin (char *, Sexp *, Sexp *); +extern LispObj *LispIf (char *, Sexp *, Sexp *); +extern LispObj *LispCond (char *, Sexp *, Sexp *); /* * debugging */ -extern LispObj *LispShowFrame (); -extern LispObj *LispDisplayObj (); -extern LispObj *LispPrintObj (); -extern LispObj *LispError (); +extern LispObj *LispShowFrame (char *, Sexp *, Sexp *); +extern LispObj *LispDisplayObj (char *, Sexp *, Sexp *); +extern LispObj *LispPrintObj (char *, Sexp *, Sexp *); +extern LispObj *LispError (char *, Sexp *, Sexp *); /* * I/O */ -extern LispObj *LispLoad (); -extern LispObj *LispWrite (); -extern LispObj *LispSpawn (); -extern LispObj *LispWait (); +extern LispObj *LispLoad (char *, Sexp *, Sexp *); +extern LispObj *LispWrite (char *, Sexp *, Sexp *); +extern LispObj *LispSpawn (char *, Sexp *, Sexp *); +extern LispObj *LispWait (char *, Sexp *, Sexp *); /* * utilities */ -extern LispObj *LispCollectGarbage (); +extern LispObj *LispCollectGarbage (char *, Sexp *, Sexp *); /* * String functions */ -extern LispObj *LispStrCat (); -extern LispObj *LispSymbolToString (); -extern LispObj *LispStringToSymbol (); -extern LispObj *LispNumberToString (); -extern LispObj *LispStringToNumber (); -extern LispObj *LispStringLength (); -extern LispObj *LispStringCompare (); -extern LispObj *LispStringRef (); -extern LispObj *LispStringSet (); -extern LispObj *LispSubString (); - -/* - * magic interaction - */ -extern LispObj *LispGetPaint (); -extern LispObj *LispGetSelPaint (); -extern LispObj *LispGetbox (); -extern LispObj *LispGetPoint (); -extern LispObj *LispGetLabel (); -extern LispObj *LispGetSelLabel (); -extern LispObj *LispGetCellNames (); -extern LispObj *LispEvalMagic (); +extern LispObj *LispStrCat (char *, Sexp *, Sexp *); +extern LispObj *LispSymbolToString (char *, Sexp *, Sexp *); +extern LispObj *LispStringToSymbol (char *, Sexp *, Sexp *); +extern LispObj *LispNumberToString (char *, Sexp *, Sexp *); +extern LispObj *LispStringToNumber (char *, Sexp *, Sexp *); +extern LispObj *LispStringLength (char *, Sexp *, Sexp *); +extern LispObj *LispStringCompare (char *, Sexp *, Sexp *); +extern LispObj *LispStringRef (char *, Sexp *, Sexp *); +extern LispObj *LispStringSet (char *, Sexp *, Sexp *); +extern LispObj *LispSubString (char *, Sexp *, Sexp *); diff --git a/miniscm/lispEval.c b/miniscm/lispEval.c index 3570fa6a..d4e2f4b9 100644 --- a/miniscm/lispEval.c +++ b/miniscm/lispEval.c @@ -212,7 +212,7 @@ LispAddDynamicFunc (char *name, void *f) } for (i=0; i < DyTableNum; i++) { if (DyTable[i].id == id) { - DyTable[i].f = (LispObj *(*)())f; + DyTable[i].f = (LispObj *(*)(char *, Sexp *))f; return 1; } } @@ -228,7 +228,7 @@ LispAddDynamicFunc (char *name, void *f) } DyTable[DyTableNum].name = Strdup (name); DyTable[DyTableNum].id = id; - DyTable[DyTableNum].f = (LispObj *(*)()) f; + DyTable[DyTableNum].f = (LispObj *(*)(char *, Sexp *)) f; DyTableNum++; return 1; } From 16f3f713776ad4970ea0987bd7b569321f38aa94 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Thu, 3 Jul 2025 21:36:15 -0400 Subject: [PATCH 34/49] need a full lookup in this context --- act/test/userdef/84.act | 30 +++++++++++++++++++++++++++++ act/test/userdef/85.act | 30 +++++++++++++++++++++++++++++ act/test/userdef/runs/84.act.stderr | 3 +++ act/test/userdef/runs/84.act.stdout | 0 act/test/userdef/runs/85.act.stderr | 0 act/test/userdef/runs/85.act.stdout | 0 act/wrap.cc | 2 +- 7 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 act/test/userdef/84.act create mode 100644 act/test/userdef/85.act create mode 100644 act/test/userdef/runs/84.act.stderr create mode 100644 act/test/userdef/runs/84.act.stdout create mode 100644 act/test/userdef/runs/85.act.stderr create mode 100644 act/test/userdef/runs/85.act.stdout diff --git a/act/test/userdef/84.act b/act/test/userdef/84.act new file mode 100644 index 00000000..d94181e4 --- /dev/null +++ b/act/test/userdef/84.act @@ -0,0 +1,30 @@ +deftype MyInnerType(int<16> a, b) { + methods { + function serialize() : int<32> { + chp { + self := a << 16 | b + } + } + } +} + +deftype MyOuterType(MyInnerType inner) { + methods { + function serialize() : int<32> { + chp { + self := inner.serialize() + } + } + } +} + +defproc test() { + MyInnerType ti; + MyOuterType to; + chp { + ti := MyInnerType(0x23 << 16 | 0x18); + to := MyOuterType(ti); + log("%x", ti.serialize()); + log("%x", to.serialize()) + } +} diff --git a/act/test/userdef/85.act b/act/test/userdef/85.act new file mode 100644 index 00000000..bf89af18 --- /dev/null +++ b/act/test/userdef/85.act @@ -0,0 +1,30 @@ +deftype MyInnerType(int<16> a, b) { + methods { + function serialize() : int<32> { + chp { + self := a << 16 | b + } + } + } +} + +deftype MyOuterType(MyInnerType inner) { + methods { + function serialize() : int<32> { + chp { + self := inner.serialize() + } + } + } +} + +defproc test() { + MyInnerType ti; + MyOuterType to; + chp { + ti := MyInnerType(0x23 << 16 | 0x18); + to.inner := ti; + log("%x", ti.serialize()); + log("%x", to.serialize()) + } +} diff --git a/act/test/userdef/runs/84.act.stderr b/act/test/userdef/runs/84.act.stderr new file mode 100644 index 00000000..5f645f3b --- /dev/null +++ b/act/test/userdef/runs/84.act.stderr @@ -0,0 +1,3 @@ +ERROR: File `84.act', line 26, col 27 + Typechecking failed on expression! + Built-in macro `MyOuterType': argument has an incompatible type diff --git a/act/test/userdef/runs/84.act.stdout b/act/test/userdef/runs/84.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/userdef/runs/85.act.stderr b/act/test/userdef/runs/85.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/userdef/runs/85.act.stdout b/act/test/userdef/runs/85.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/wrap.cc b/act/wrap.cc index a86686ee..3aedd4b6 100644 --- a/act/wrap.cc +++ b/act/wrap.cc @@ -889,7 +889,7 @@ Expr *act_walk_X_expr (ActTree *cookie, Expr *e) u = NULL; prev = NULL; while (tmp->Rest()) { - it = sc->Lookup (tmp->getName()); + it = sc->FullLookup (tmp->getName()); if (!it) { act_parse_err (&p, "Field `%s' not found!", tmp->getName()); } From d3554feeb8ec546db8b3a9a01a2325d581a08daa Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Fri, 4 Jul 2025 17:07:24 -0400 Subject: [PATCH 35/49] user macro / array interaction fixed --- act/expr.m4 | 49 +++++++++++++++++- act/expr2.cc | 3 ++ act/expr_extra.c | 5 +- act/fexpr.cc | 86 +++++++++++++++++-------------- act/prs.cc | 5 ++ act/test/lang/141.act | 29 +++++++++++ act/test/lang/142.act | 29 +++++++++++ act/test/lang/143.act | 28 ++++++++++ act/test/lang/runs/141.act.stderr | 0 act/test/lang/runs/141.act.stdout | 0 act/test/lang/runs/142.act.stderr | 2 + act/test/lang/runs/142.act.stdout | 0 act/test/lang/runs/143.act.stderr | 0 act/test/lang/runs/143.act.stdout | 0 14 files changed, 194 insertions(+), 42 deletions(-) create mode 100644 act/test/lang/141.act create mode 100644 act/test/lang/142.act create mode 100644 act/test/lang/143.act create mode 100644 act/test/lang/runs/141.act.stderr create mode 100644 act/test/lang/runs/141.act.stdout create mode 100644 act/test/lang/runs/142.act.stderr create mode 100644 act/test/lang/runs/142.act.stdout create mode 100644 act/test/lang/runs/143.act.stderr create mode 100644 act/test/lang/runs/143.act.stdout diff --git a/act/expr.m4 b/act/expr.m4 index e1de22e9..e37e008d 100644 --- a/act/expr.m4 +++ b/act/expr.m4 @@ -425,6 +425,9 @@ w_c_expr[Expr *]: expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -450,6 +453,9 @@ w_expr[Expr *]: expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -465,6 +471,7 @@ w_expr[Expr *]: expr if ($0->strict_checking && ((tc & T_STRICT) == 0)) { $E("Expressions in port parameter list can only use strict template parameters"); } + $0->special_id = oldval; return e; }} ; @@ -475,6 +482,9 @@ w_expr_chp[Expr *]: EXTERN[fexpr] {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; e = (Expr *) $1; $A($0->scope); @@ -487,6 +497,7 @@ w_expr_chp[Expr *]: EXTERN[fexpr] if ($0->strict_checking && ((tc & T_STRICT) == 0)) { $E("Expressions in port parameter list can only use strict template parameters"); } + $0->special_id = oldval; return e; }} ; @@ -495,6 +506,9 @@ w_exprchp[Expr *]: expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -510,6 +524,7 @@ w_exprchp[Expr *]: expr if ($0->strict_checking && ((tc & T_STRICT) == 0)) { $E("Expressions in port parameter list can only use strict template parameters"); } + $0->special_id = oldval; return e; }} ; @@ -520,6 +535,9 @@ w_chan_int_expr[Expr *]: EXTERN[fexpr] {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; e = (Expr *) $1; @@ -533,6 +551,7 @@ w_chan_int_expr[Expr *]: EXTERN[fexpr] if ($0->strict_checking && ((tc & T_STRICT) == 0)) { $E("Expressions in port parameter list can only use strict template parameters"); } + $0->special_id = oldval; return e; }} ; @@ -542,6 +561,9 @@ wnumber_expr[Expr *]: expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -563,6 +585,7 @@ wnumber_expr[Expr *]: expr if (!(tc & T_PARAM)) { $E("Expression must be of type pint or preal"); } + $0->special_id = oldval; return e; }} ; @@ -571,6 +594,9 @@ wnumber_flav_expr[Expr *]: expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -581,6 +607,7 @@ wnumber_flav_expr[Expr *]: expr e = act_walk_X_expr ($0, $1); if ($0->skip_id_check == 2) { $0->skip_id_check = 0; + $0->special_id = oldval; return e; } $0->skip_id_check = 0; @@ -600,6 +627,7 @@ wnumber_flav_expr[Expr *]: expr if (!(tc & T_PARAM)) { $E("Expression must be of type pint or preal"); } + $0->special_id = oldval; return e; }} ; @@ -609,6 +637,9 @@ wint_or_bool_expr[Expr *]: expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -634,18 +665,22 @@ wint_or_bool_expr[Expr *]: expr fprintf ($f, "''\n"); exit (1); } + $0->special_id = oldval; return e; }} ; /* - CONSISTENCY: _wint_expr in prs.c + CONSISTENCY: _wint_expr in prs.cc */ wint_expr[Expr *]: int_expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -673,6 +708,7 @@ wint_expr[Expr *]: int_expr fprintf ($f, "''\n"); exit (1); } + $0->special_id = oldval; return e; }} ; @@ -681,6 +717,8 @@ wpint_expr[Expr *]: int_expr {{X: Expr *e; int tc; + int oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -711,6 +749,7 @@ wpint_expr[Expr *]: int_expr fprintf ($f, "''\n"); exit (1); } + $0->special_id = oldval; return e; }} ; @@ -720,6 +759,9 @@ wbool_expr[Expr *]: bool_expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -745,6 +787,7 @@ wbool_expr[Expr *]: bool_expr fprintf ($f, "''\n"); exit (1); } + $0->special_id = oldval; return e; }} ; @@ -753,6 +796,9 @@ wbool_allow_chan_expr[Expr *]: bool_expr {{X: Expr *e; int tc; + int oldval; + oldval = $0->special_id; + $0->special_id = 0; $0->line = $l; $0->column = $c; @@ -778,6 +824,7 @@ wbool_allow_chan_expr[Expr *]: bool_expr fprintf ($f, "''\n"); exit (1); } + $0->special_id = oldval; return e; }} ; diff --git a/act/expr2.cc b/act/expr2.cc index 351223d8..652e0b86 100644 --- a/act/expr2.cc +++ b/act/expr2.cc @@ -2437,7 +2437,10 @@ static Expr *_expr_expand (int *width, Expr *e, else { if (flags & ACT_EXPR_EXFLAG_CHPEX) { /* chp mode expansion */ + int tmpex = Act::double_expand; + Act::double_expand = 0; xid = ((ActId *)e->u.e.l)->ExpandCHP (ns, s); + Act::double_expand = tmpex; te = xid->EvalCHP (ns, s, 0); if (te->type == E_VAR) { act_chp_macro_check (s, (ActId *)te->u.e.l); diff --git a/act/expr_extra.c b/act/expr_extra.c index f359d46e..95c6a3e6 100644 --- a/act/expr_extra.c +++ b/act/expr_extra.c @@ -33,7 +33,7 @@ static int tokxor, tokplus, tokmult; static int double_colon, comma; static int inttok, booltok; static int langle, rangle; -static int dot; +static int dot, lbrack; static void do_init (LFILE *l) { @@ -55,6 +55,7 @@ static void do_init (LFILE *l) inttok = file_addtoken (l, "int"); booltok = file_addtoken (l, "bool"); dot = file_addtoken (l, "."); + lbrack = file_addtoken (l, "["); init = 1; } } @@ -203,7 +204,7 @@ static Expr *_parse_expr_func2 (LFILE *l, int first_fn) return e; } } - else if (!found_dcolon && file_have (l, dot)) { + else if (!found_dcolon && (file_have (l, dot) || file_sym(l) == lbrack)) { if (pushed) { file_set_position (l); file_pop_position (l); diff --git a/act/fexpr.cc b/act/fexpr.cc index 3e49e23c..5efceda0 100644 --- a/act/fexpr.cc +++ b/act/fexpr.cc @@ -331,58 +331,66 @@ static Expr *expr_basecase (void) } } else { - if (v && expr_free_id) { - (*expr_free_id) (v); +#if 0 + printf (" -- got here, looking-at %s!\n", file_tokenstring (Tl)); +#endif + if (!file_have (Tl, T[E_LPAR])) { + if (v && expr_free_id) { + (*expr_free_id) (v); + } + SET (Tl); + POP (Tl); + return NULL; } - SET (Tl); -#if 1 - POP (Tl); - return NULL; -#else - /* - XXX: This is duplicate parsing code that is replicated in - expr_extra.c; so leave it in one place rather than having - multiple function call parsers. - */ - if (file_have (Tl, f_id) && file_sym (Tl) == T[E_LPAR]) { - e = newexpr (); - e->type = E_FUNCTION; - e->u.fn.s = Strdup (file_prev (Tl)); - e->u.fn.r = NULL; - f = e; - file_mustbe (Tl, T[E_LPAR]); - if (file_sym (Tl) != T[E_RPAR]) { - do { - f->u.e.r = newexpr (); /* wow! rely that this is the same - space as u.fn.r */ + expr_inc_parens (); + e = newexpr (); + e->type = E_USERMACRO; + NEW (e->u.e.l, Expr); + e->u.e.l->type = E_VAR; + e->u.e.l->u.e.l = (Expr *)v; + e->u.e.l->u.e.r = NULL; + e->u.e.r = NULL; + f = e; + if (file_sym (Tl) != T[E_RPAR]) { + do { + if (f == e) { + NEW (e->u.e.r, Expr); + f = e->u.e.r; + } + else { + NEW (f->u.e.r, Expr); f = f->u.e.r; - f->type = E_LT; - f->u.e.r = NULL; - f->u.e.l = expr_parse (); - if (!f->u.e.l) { - expr_free (e); - SET (Tl); - POP (Tl); - return NULL; - } - } while (file_have (Tl, T[E_COMMA])); - if (file_sym (Tl) != T[E_RPAR]) { + } + f->type = E_LT; + f->u.e.r = NULL; + f->u.e.l = expr_parse_any (Tl); + if (!f->u.e.l) { expr_free (e); + expr_dec_parens (); SET (Tl); POP (Tl); return NULL; } + } while (file_have (Tl, T[E_COMMA])); + if (file_sym (Tl) != T[E_RPAR]) { + expr_free (e); + expr_dec_parens (); + SET (Tl); + POP (Tl); + return NULL; } /* success! */ - POP (Tl); file_getsym (Tl); + expr_dec_parens (); + POP (Tl); + return e; } else { - SET (Tl); - POP (Tl); - return NULL; + /* eat the token */ + file_getsym (Tl); } -#endif + POP (Tl); + return e; } } } diff --git a/act/prs.cc b/act/prs.cc index 7896cc91..30d50e4b 100644 --- a/act/prs.cc +++ b/act/prs.cc @@ -522,6 +522,10 @@ static Expr *_wint_expr (ActTree *a, Expr *e) if (!e) return NULL; + int oldval; + oldval = a->special_id; + a->special_id = 0; + p.l = a->line; p.c = a->column; p.f = a->file; @@ -542,6 +546,7 @@ static Expr *_wint_expr (ActTree *a, Expr *e) if (!(tc & T_PARAM)) { act_parse_err (&p, "Expression must be of type pint"); } + a->special_id = oldval; return e; } diff --git a/act/test/lang/141.act b/act/test/lang/141.act new file mode 100644 index 00000000..fd5492f5 --- /dev/null +++ b/act/test/lang/141.act @@ -0,0 +1,29 @@ +deftype rec (int a, b) { + methods { + function geta() : int + { + chp { + self := a + } + } + } +} + +deftype foo(rec b) { } + +defproc test() +{ + rec a[2]; + int x; + + foo b; + + chp { + x := b.b.geta(); + log ("got x: ", x); + x := a[0].geta(); + log ("got x: ", x) + } +} + +test t; diff --git a/act/test/lang/142.act b/act/test/lang/142.act new file mode 100644 index 00000000..5e13094c --- /dev/null +++ b/act/test/lang/142.act @@ -0,0 +1,29 @@ +deftype rec (int a, b) { + methods { + function geta() : int + { + chp { + self := a + } + } + } +} + +deftype foo(rec b) { } + +defproc test() +{ + rec a[2]; + int x; + + foo b; + + chp { + x := b.b.geta(); + log ("got x: ", x); + x := a[0].geta[2](); + log ("got x: ", x) + } +} + +test t; diff --git a/act/test/lang/143.act b/act/test/lang/143.act new file mode 100644 index 00000000..45f2ad40 --- /dev/null +++ b/act/test/lang/143.act @@ -0,0 +1,28 @@ +deftype rec (int a, b) { + methods { + function geta() : int + { + chp { + self := a + } + } + } +} + +deftype foo(rec b) { } + +defproc test() +{ + rec a[2]; + int x; + + foo b; + + chp { + x := b.b.geta(); + log ("got x: ", x); + [ a[0].geta() = 0 -> log ("equal zero") [] else -> skip ] + } +} + +test t; diff --git a/act/test/lang/runs/141.act.stderr b/act/test/lang/runs/141.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/141.act.stdout b/act/test/lang/runs/141.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/142.act.stderr b/act/test/lang/runs/142.act.stderr new file mode 100644 index 00000000..f1479c7c --- /dev/null +++ b/act/test/lang/runs/142.act.stderr @@ -0,0 +1,2 @@ +ERROR: File `142.act', line 24, col 11 + Array de-reference for user macro: a[0].geta[2] diff --git a/act/test/lang/runs/142.act.stdout b/act/test/lang/runs/142.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/143.act.stderr b/act/test/lang/runs/143.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/143.act.stdout b/act/test/lang/runs/143.act.stdout new file mode 100644 index 00000000..e69de29b From 0cc9d10857794f288c6c2890cbf05d77de6af0ce Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Sun, 6 Jul 2025 08:52:10 -0400 Subject: [PATCH 36/49] allow conditionals in function --- act/defs.m4 | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/act/defs.m4 b/act/defs.m4 index 27349e83..6ef2b655 100644 --- a/act/defs.m4 +++ b/act/defs.m4 @@ -1945,7 +1945,7 @@ func_body[ActBody *]: ";" }} ; -func_body_items[ActBody *]: alias_or_inst_list lang_chp +func_body_items[ActBody *]: alias_or_inst_list gen_lang_chp {{X: ActBody *b; @@ -1960,6 +1960,55 @@ func_body_items[ActBody *]: alias_or_inst_list lang_chp }} ; + +gen_lang_chp[ActBody *]: lang_chp +{{X: + return $1; +}} +| "*[" +{{X: $0->in_cond++; }} +{ gc_1_v2 "[]" }* "]" [";"] +{{X: + return apply_X_loop_opt1 ($0, $2, $4); +}} +| "[" +{{X: $0->in_cond++; }} + guarded_cmds_v2 "]" [";"] +{{X: + $0->in_cond--; + OPT_FREE ($4); + return $2; +}} +| assertion +{{X: return $1; }} +| debug_output +{{X: return $1; }} +; + +gc_1_v2[ActBody_Select_gc *]: wbool_expr "->" func_body_items +{{X: + return apply_X_gc_1_opt0 ($0, $1, $3); +}} +| "(" "[]" ID +{{X: + lapply_X_gc_1_1_2 ($0, $3); +}} +":" !noreal wpint_expr [ ".." wpint_expr ] ":" wbool_expr "->" func_body_items ")" +{{X: + return apply_X_gc_1_opt1 ($0, $3, $5, $6, $8, $10); +}} +| "else" "->" func_body_items +{{X: + return apply_X_gc_1_opt2 ($0, $3); +}} +; + +guarded_cmds_v2[ActBody *]: { gc_1_v2 "[]" }* +{{X: + return apply_X_guarded_cmds_opt0 ($0, $1); +}} +; + alias_or_inst_list[ActBody *]: al_item alias_or_inst_list {{X: $1->Append ($2); From 082d1290211f6c59103161dff838317116689e41 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Sun, 6 Jul 2025 19:55:28 -0400 Subject: [PATCH 37/49] save scope as well as flag --- act/expr.m4 | 38 ++++++++++++++++++++++++++++++++++++++ act/prs.cc | 3 +++ 2 files changed, 41 insertions(+) diff --git a/act/expr.m4 b/act/expr.m4 index e37e008d..e8340641 100644 --- a/act/expr.m4 +++ b/act/expr.m4 @@ -426,7 +426,9 @@ w_c_expr[Expr *]: expr Expr *e; int tc; int oldval; + Scope *oldsc; oldval = $0->special_id; + oldsc = $0->special_id_sc; $0->special_id = 0; $0->line = $l; @@ -445,6 +447,8 @@ w_c_expr[Expr *]: expr if ($0->strict_checking && ((tc & T_STRICT) == 0)) { $E("Expressions in port parameter list can only use strict template parameters"); } + $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -454,6 +458,8 @@ w_expr[Expr *]: expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -472,6 +478,7 @@ w_expr[Expr *]: expr $E("Expressions in port parameter list can only use strict template parameters"); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -483,6 +490,8 @@ w_expr_chp[Expr *]: EXTERN[fexpr] Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -498,6 +507,7 @@ w_expr_chp[Expr *]: EXTERN[fexpr] $E("Expressions in port parameter list can only use strict template parameters"); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -507,6 +517,8 @@ w_exprchp[Expr *]: expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -525,6 +537,7 @@ w_exprchp[Expr *]: expr $E("Expressions in port parameter list can only use strict template parameters"); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -536,6 +549,8 @@ w_chan_int_expr[Expr *]: EXTERN[fexpr] Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -552,6 +567,7 @@ w_chan_int_expr[Expr *]: EXTERN[fexpr] $E("Expressions in port parameter list can only use strict template parameters"); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -562,6 +578,8 @@ wnumber_expr[Expr *]: expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -586,6 +604,7 @@ wnumber_expr[Expr *]: expr $E("Expression must be of type pint or preal"); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -595,6 +614,8 @@ wnumber_flav_expr[Expr *]: expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -608,6 +629,7 @@ wnumber_flav_expr[Expr *]: expr if ($0->skip_id_check == 2) { $0->skip_id_check = 0; $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; } $0->skip_id_check = 0; @@ -628,6 +650,7 @@ wnumber_flav_expr[Expr *]: expr $E("Expression must be of type pint or preal"); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -638,6 +661,8 @@ wint_or_bool_expr[Expr *]: expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -666,6 +691,7 @@ wint_or_bool_expr[Expr *]: expr exit (1); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -679,6 +705,8 @@ wint_expr[Expr *]: int_expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -709,6 +737,7 @@ wint_expr[Expr *]: int_expr exit (1); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -718,6 +747,8 @@ wpint_expr[Expr *]: int_expr Expr *e; int tc; int oldval = $0->special_id; + Scope *oldsc; + oldsc = $0->special_id_sc; $0->special_id = 0; $0->line = $l; @@ -750,6 +781,7 @@ wpint_expr[Expr *]: int_expr exit (1); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -760,6 +792,8 @@ wbool_expr[Expr *]: bool_expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -788,6 +822,7 @@ wbool_expr[Expr *]: bool_expr exit (1); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; @@ -797,6 +832,8 @@ wbool_allow_chan_expr[Expr *]: bool_expr Expr *e; int tc; int oldval; + Scope *oldsc; + oldsc = $0->special_id_sc; oldval = $0->special_id; $0->special_id = 0; @@ -825,6 +862,7 @@ wbool_allow_chan_expr[Expr *]: bool_expr exit (1); } $0->special_id = oldval; + $0->special_id_sc = oldsc; return e; }} ; diff --git a/act/prs.cc b/act/prs.cc index 30d50e4b..0cb58628 100644 --- a/act/prs.cc +++ b/act/prs.cc @@ -522,6 +522,8 @@ static Expr *_wint_expr (ActTree *a, Expr *e) if (!e) return NULL; + Scope *oldsc; + oldsc = a->special_id_sc; int oldval; oldval = a->special_id; a->special_id = 0; @@ -547,6 +549,7 @@ static Expr *_wint_expr (ActTree *a, Expr *e) act_parse_err (&p, "Expression must be of type pint"); } a->special_id = oldval; + a->special_id_sc = oldsc; return e; } From 4812746bacd22e9a073309ccfc8cc11770eeb1b8 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 8 Jul 2025 18:56:28 -0400 Subject: [PATCH 38/49] more complex macro cases --- act/act_array.h | 10 ++++++++++ act/array.cc | 43 +++++++++++++++++++++++++++++++++++++++++++ act/check.cc | 3 ++- act/lang_chp.cc | 2 +- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/act/act_array.h b/act/act_array.h index 58a60270..31483317 100644 --- a/act/act_array.h +++ b/act/act_array.h @@ -334,6 +334,16 @@ class Array { */ int Validate (Array *a); + /** + * Validate that the array indices specified in the argument are + * valid indicies for the array. This must be called on an expanded + * array. Skip any dynamic references. + * + * @param a is the Array that contains the indices of interest + * @return 1 if the de-reference is valid, 0 otherwise + */ + int weakValidate (Array *a); + /** * Checks to see if this array includes a dynamic de-reference * diff --git a/act/array.cc b/act/array.cc index dc9c04cd..fb0579ef 100644 --- a/act/array.cc +++ b/act/array.cc @@ -636,6 +636,49 @@ int Array::Validate (Array *a) return 1; } +/*------------------------------------------------------------------------ + * "a" is an ExpandRef'ed array + * Returns 1 if "a" is a valid de-reference or subrange reference for + * the array, 0 otherwise. + *------------------------------------------------------------------------ + */ +int Array::weakValidate (Array *a) +{ + if (!expanded || !a->isExpanded()) { + fatal_error ("Array::weakValidate() should only be called for expanded arrays"); + } + Assert (dims == a->nDims(), "dimensions don't match!"); + + int i, d; + + for (i=0; i < dims; i++) { + /* a is going to be from an ID */ + if (a->r[i].u.ex.isrange == 2) continue; + d = a->r[i].u.ex.idx.hi; + if (r[i].u.ex.idx.lo > d || r[i].u.ex.idx.hi < d) { + if (next) { + return next->Validate (a); + } + else { + return 0; + } + } + if (a->r[i].u.ex.idx.lo != a->r[i].u.ex.idx.hi) { + /* subrange, check the extreme ends */ + d = a->r[i].u.ex.idx.lo; + if (r[i].u.ex.idx.lo > d || r[i].u.ex.idx.hi < d) { + if (next) { + return next->Validate (a); + } + else { + return 0; + } + } + } + } + return 1; +} + /*------------------------------------------------------------------------ * "a" is an ExpandRef'ed array diff --git a/act/check.cc b/act/check.cc index 8d297955..e70645d6 100644 --- a/act/check.cc +++ b/act/check.cc @@ -1573,7 +1573,8 @@ InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal, bool subchan) Assert (it->isExpanded(), "What on earth?"); Assert (id->arrayInfo()->isExpanded(), "What on earth2?"); - if (!it->arrayInfo()->Validate (id->arrayInfo())) { + /* weak validate, because this can come from a CHP body */ + if (!it->arrayInfo()->weakValidate (id->arrayInfo())) { typecheck_err ("Array dereference out of range"); return NULL; } diff --git a/act/lang_chp.cc b/act/lang_chp.cc index 1bf419d5..bef2b732 100644 --- a/act/lang_chp.cc +++ b/act/lang_chp.cc @@ -2159,7 +2159,7 @@ static act_chp_lang_t *chp_expand_1 (act_chp_lang_t *c, ActNamespace *ns, Scope case ACT_CHP_MACRO: { - ActId *x = expand_var_read (c->u.macro.id, ns, s); + ActId *x = expand_var_write (c->u.macro.id, ns, s); if (x->isNamespace()) { act_error_ctxt (stderr); fatal_error ("CHP macro and namespace globals don't mix"); From 8291470a5207f373f34ef8711c3b3c0fc84407d3 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Fri, 18 Jul 2025 10:50:06 -0400 Subject: [PATCH 39/49] consolidated fresh var gen; added generated fresh vars to decomp list --- act/act.cc | 77 +++++++++++++ act/act.h | 13 +++ act/id.cc | 2 +- act/lang_chp.cc | 1 + act/process.cc | 1 + passes/finline/finline.cc | 106 ++++++++++++------ passes/finline/finline.h | 1 - transform/testing/inline/test/45.act | 26 +++++ .../testing/inline/test/runs/45.act.stderr | 0 .../testing/inline/test/runs/45.act.stdout | 41 +++++++ 10 files changed, 229 insertions(+), 39 deletions(-) create mode 100644 transform/testing/inline/test/45.act create mode 100644 transform/testing/inline/test/runs/45.act.stderr create mode 100644 transform/testing/inline/test/runs/45.act.stdout diff --git a/act/act.cc b/act/act.cc index 49e5b726..71843bb7 100644 --- a/act/act.cc +++ b/act/act.cc @@ -607,6 +607,9 @@ Act::Act (const char *s) num_inst_levels[i] = 0; } + /* empty genvars */ + _genVars = NULL; + /* initialize act library */ Act::Init (&argc, &argv); FREE (argv[0]); @@ -1225,6 +1228,27 @@ list_t *Act::getDecomp (Process *p) } } } + + if (_genVars) { + phash_bucket_t *pb; + phash_iter_t pit; + list_t *l = NULL; + phash_iter_init (_genVars, &pit); + while ((pb = phash_iter_next (_genVars, &pit))) { + if (p == (Process *)pb->v) { + if (!l) { + l = list_new (); + list_append (l, (ValueIdx *)(pb->key)); + } + } + } + if (l) { + if (!ret) { + ret = list_new (); + } + list_append (ret, l); + } + } return ret; } @@ -1325,3 +1349,56 @@ bool Act::LocalizeGlobal (const char *s) } return true; } + + + +/*------------------------------------------------------------------------ + * Expanding a process might result in a re-write that includes a + * freshly generated variable. These generated variables are not + * declared in the original ACT; during logic synthesis, these + * variables have to be declared, not overridden. + *------------------------------------------------------------------------ + */ +void Act::addGeneratedVar (Scope *sc, ValueIdx *vx) +{ + Assert (vx->t->isExpanded(), "Must be called only with expanded ValueIdx!"); + + if (!_genVars) { + _genVars = phash_new (4); + } + phash_bucket_t *b; + b = phash_add (_genVars, vx); + + while (sc && sc->getUserDef() == NULL) { + sc = sc->Parent (); + } + if (!sc) { + fatal_error ("Act::addGenerateVar(): Scope doesn't lead to a user-defined type."); + } + b->v = sc->getUserDef (); +} + +void Act::updateType (UserDef *from, UserDef *to) +{ + if (!_genVars) return; + phash_bucket_t *pb; + phash_iter_t pit; + + phash_iter_init (_genVars, &pit); + while ((pb = phash_iter_next (_genVars, &pit))) { + if (pb->v == from) { + pb->v = to; + } + } +} + +bool Act::isGeneratedVar (ValueIdx *vx) +{ + if (!_genVars) { + return false; + } + if (phash_lookup (_genVars, vx)) { + return true; + } + return false; +} diff --git a/act/act.h b/act/act.h index 22c75de5..1948f004 100644 --- a/act/act.h +++ b/act/act.h @@ -702,6 +702,13 @@ class Act { void incRefSteps(int nsteps = 1) { refine_steps += nsteps; } ///< increment the number of ///remaining refinement steps + + + void addGeneratedVar (Scope *sc, ValueIdx *vx); ///< add generated variable + void updateType (UserDef *from, UserDef *to); ///< update generated + ///type + bool isGeneratedVar (ValueIdx *vx); ///< check if variable was generated + private: TypeFactory *tf; ///< type factory for the Act instance ActNamespace *gns; ///< the global namespace pointer @@ -749,6 +756,12 @@ class Act { bool _finished_init; ///< set to true after the first file ///has been read + struct pHashtable *_genVars; ///< table that includes ValueIdx + ///pointers that were generated. Since + ///these pointers are unique per + ///process, we don't need to save the + ///process info. + static char *_getopt_string; ///< the string used for getopt /** diff --git a/act/id.cc b/act/id.cc index a2aca2cf..0e0b7f62 100644 --- a/act/id.cc +++ b/act/id.cc @@ -1515,7 +1515,7 @@ act_connection *ActId::Canonical (Scope *s) #if 0 printf ("Type: %s, port %s\n", ux->getName(), idrest->getName()); -#endif +#endif portid = ux->FindPort (idrest->getName()); Assert (portid > 0, "What?"); diff --git a/act/lang_chp.cc b/act/lang_chp.cc index bef2b732..315d1122 100644 --- a/act/lang_chp.cc +++ b/act/lang_chp.cc @@ -57,6 +57,7 @@ static void _chp_expr_unstruct (list_t *l, Scope *s, Expr *e) char buf[1024]; snprintf (buf, 1024, "_us%d", _chp_freshvar_count); s->Add (buf, it); + ActNamespace::Act()->addGeneratedVar (s, s->LookupVal (buf)); NEW (c, act_chp_lang_t); c->space = NULL; c->label = NULL; diff --git a/act/process.cc b/act/process.cc index fa10141a..06363ed5 100644 --- a/act/process.cc +++ b/act/process.cc @@ -81,6 +81,7 @@ Process *Process::Expand (ActNamespace *ns, Scope *s, int nt, inst_param *u) } xp = new Process (ux); + ActNamespace::Act()->updateType (ux, xp); delete ux; Assert (_ns->EditType (xp->name, xp) == 1, "What?"); diff --git a/passes/finline/finline.cc b/passes/finline/finline.cc index 3f0e0349..3dec9852 100644 --- a/passes/finline/finline.cc +++ b/passes/finline/finline.cc @@ -573,9 +573,11 @@ void ActCHPFuncInline::_inline_funcs (list_t *l, act_chp_lang_t *c) if (vals.isValid()) { /* simple inline */ char buf[1024]; - int idx = _get_fresh_idx ("_us", &_inline_idx); - snprintf (buf, 1024, "_us_%d", idx); + _cursc->findFresh ("_us_", &_inline_idx); + snprintf (buf, 1024, "_us_%d", _inline_idx); + _inline_idx++; _cursc->Add (buf, cx->datatype()); + ActNamespace::Act()->addGeneratedVar (_cursc, _cursc->LookupVal (buf)); ActId *myid = new ActId (buf); d = dynamic_cast (cx->datatype()->BaseType()); @@ -586,23 +588,43 @@ void ActCHPFuncInline::_inline_funcs (list_t *l, act_chp_lang_t *c) int sz = nb + ni; list_t *l = list_new (); - Assert (!vals.isSimple(), "Hmm"); + //Assert (!vals.isSimple(), "Hmm"); for (int i=0; i < sz; i++) { act_chp_lang_t *tc; - if (vals.u.arr[i]) { + if (vals.isSimple()) { NEW (tc, act_chp_lang_t); tc->type = ACT_CHP_ASSIGN; tc->label = NULL; tc->space = NULL; tc->u.assign.id = myid->Clone(); tc->u.assign.id->Tail()->Append (fields[i]); - tc->u.assign.e = vals.u.arr[i]; + NEW (tc->u.assign.e, Expr); + tc->u.assign.e->u.e.r = NULL; + tc->u.assign.e->type = E_VAR; + // structure expression can only be an actual + // structure variable + Assert (vals.getVal()->type == E_VAR, "What?"); + ActId *tmp = ((ActId *)vals.getVal()->u.e.l)->Clone (); + tmp->Tail()->Append (fields[i]->Clone()); + tc->u.assign.e->u.e.l = (Expr *) tmp; list_append (l, tc); } else { - delete fields[i]; + if (vals.u.arr[i]) { + NEW (tc, act_chp_lang_t); + tc->type = ACT_CHP_ASSIGN; + tc->label = NULL; + tc->space = NULL; + tc->u.assign.id = myid->Clone(); + tc->u.assign.id->Tail()->Append (fields[i]); + tc->u.assign.e = vals.u.arr[i]; + list_append (l, tc); + } + else { + delete fields[i]; + } } } FREE (fields); @@ -659,9 +681,10 @@ void ActCHPFuncInline::_inline_funcs (list_t *l, act_chp_lang_t *c) ActId *origid = c->u.assign.id; if (unstruct_me) { char buf[1024]; - int idx = _get_fresh_idx ("_us", &_inline_idx); - snprintf (buf, 1024, "_us_%d", idx); + _cursc->findFresh ("_us_", &_inline_idx); + snprintf (buf, 1024, "_us_%d", _inline_idx++); _cursc->Add (buf, it); + ActNamespace::Act()->addGeneratedVar (_cursc, _cursc->LookupVal (buf)); myid = new ActId (buf); } @@ -673,23 +696,43 @@ void ActCHPFuncInline::_inline_funcs (list_t *l, act_chp_lang_t *c) int sz = nb + ni; list_t *l = list_new (); - Assert (!vals.isSimple(), "Hmm"); - + //Assert (!vals.isSimple(), "Hmm"); + for (int i=0; i < sz; i++) { act_chp_lang_t *tc; - if (vals.u.arr[i]) { + if (vals.isSimple()) { NEW (tc, act_chp_lang_t); tc->type = ACT_CHP_ASSIGN; tc->label = NULL; tc->space = NULL; tc->u.assign.id = myid->Clone(); tc->u.assign.id->Tail()->Append (fields[i]); - tc->u.assign.e = vals.u.arr[i]; + NEW (tc->u.assign.e, Expr); + tc->u.assign.e->u.e.r = NULL; + tc->u.assign.e->type = E_VAR; + // structure expression can only be an actual + // structure variable + Assert (vals.getVal()->type == E_VAR, "What?"); + ActId *tmp = ((ActId *)vals.getVal()->u.e.l)->Clone (); + tmp->Tail()->Append (fields[i]->Clone()); + tc->u.assign.e->u.e.l = (Expr *) tmp; list_append (l, tc); } else { - delete fields[i]; + if (vals.u.arr[i]) { + NEW (tc, act_chp_lang_t); + tc->type = ACT_CHP_ASSIGN; + tc->label = NULL; + tc->space = NULL; + tc->u.assign.id = myid->Clone(); + tc->u.assign.id->Tail()->Append (fields[i]); + tc->u.assign.e = vals.u.arr[i]; + list_append (l, tc); + } + else { + delete fields[i]; + } } } FREE (fields); @@ -760,20 +803,6 @@ void ActCHPFuncInline::_inline_funcs (list_t *l, act_chp_lang_t *c) } } - -int ActCHPFuncInline::_get_fresh_idx (const char *prefix, int *idx) -{ - char tmpnm[1024]; - int i = *idx; - - do { - snprintf (tmpnm, 1024, "%s_%d", prefix, i++); - } while (_cursc->Lookup (tmpnm)); - *idx = i; - - return i-1; -} - /*------------------------------------------------------------------------ * * Complex inlines: functions with loops @@ -811,14 +840,14 @@ void ActCHPFuncInline::_do_complex_inline (struct pHashtable *Hargs, list_t *l, if (!b) { struct fn_inline_args *args; NEW (args, struct fn_inline_args); - int idx; args->fx = fx; - idx = _get_fresh_idx ("fret", &ret_idx); - snprintf (tmpnm, 1024, "fret_%d", idx); + _cursc->findFresh ("fret_", &ret_idx); + snprintf (tmpnm, 1024, "fret_%d", ret_idx++); args->ret = new ActId (tmpnm); Assert (_cursc->Add (tmpnm, fx->getRetType()), "What?"); - + ActNamespace::Act()->addGeneratedVar (_cursc, _cursc->LookupVal (tmpnm)); + if (fx->getNumPorts() > 0) { MALLOC (args->args, ActId *, fx->getNumPorts()); } @@ -826,10 +855,11 @@ void ActCHPFuncInline::_do_complex_inline (struct pHashtable *Hargs, list_t *l, args->args = NULL; } for (int i=0; i < fx->getNumPorts(); i++) { - idx = _get_fresh_idx ("farg", &arg_idx); - snprintf (tmpnm, 1024, "farg_%d", idx); + _cursc->findFresh ("farg_", &arg_idx); + snprintf (tmpnm, 1024, "farg_%d", arg_idx++); args->args[i] = new ActId (tmpnm); Assert (_cursc->Add (tmpnm, fx->getPortType (i)), "What?"); + ActNamespace::Act()->addGeneratedVar (_cursc, _cursc->LookupVal (tmpnm)); } b = phash_add (Hargs, fx); b->v = args; @@ -864,9 +894,10 @@ void ActCHPFuncInline::_do_complex_inline (struct pHashtable *Hargs, list_t *l, if (!args->local_vars) { args->local_vars = hash_new (4); } - idx = _get_fresh_idx ("floc", &local_idx); - snprintf (tmpnm, 1024, "floc_%d", idx); + _cursc->findFresh ("floc_", &local_idx); + snprintf (tmpnm, 1024, "floc_%d", local_idx++); Assert (_cursc->Add (tmpnm, vx->t), "What?"); + ActNamespace::Act()->addGeneratedVar (_cursc, _cursc->LookupVal (tmpnm)); ab = hash_add (args->local_vars, vx->getName()); ab->v = new ActId (tmpnm); } @@ -1734,10 +1765,11 @@ act_chp_lang_t *ActCHPFuncInline::_do_inline (struct pHashtable *H, _chp_clone_subst (fn, fn->fx->getlang()->getchp()->c)); // return value - int idx = _get_fresh_idx ("fuse", &_useidx); + _cursc->findFresh ("fuse_", &_useidx); char buf[1024]; - snprintf (buf, 1024, "fuse_%d", idx); + snprintf (buf, 1024, "fuse_%d", _useidx++); Assert (_cursc->Add (buf, fn->fx->getRetType()) == 1, "Hmm"); + ActNamespace::Act()->addGeneratedVar (_cursc, _cursc->LookupVal (buf)); if (fn->fx->getRetType()->arrayInfo()) { Array *xa = fn->fx->getRetType()->arrayInfo(); diff --git a/passes/finline/finline.h b/passes/finline/finline.h index c5b31237..e40ce683 100644 --- a/passes/finline/finline.h +++ b/passes/finline/finline.h @@ -52,7 +52,6 @@ class ActCHPFuncInline : public ActPass { void _structure_assign (act_chp_lang_t *c); - int _get_fresh_idx (const char *prefix, int *idx); int _useidx; }; diff --git a/transform/testing/inline/test/45.act b/transform/testing/inline/test/45.act new file mode 100644 index 00000000..bfa4bfa6 --- /dev/null +++ b/transform/testing/inline/test/45.act @@ -0,0 +1,26 @@ +deftype pair(int x, y) {} + +function testme (pair p) : pair +{ + chp { + self := p + } +} + +defproc test(chan?(int) X, Y; chan!(int) O) { + pair p; + + chp { + *[ + X?p.x, + Y?p.y; + p.x := testme(p).x; + *[ p.x > p.y -> p.x := p.x - p.y + [] p.y > p.x -> p.y := p.y - p.x + ]; + O!p.x + ] + } +} + +test t; diff --git a/transform/testing/inline/test/runs/45.act.stderr b/transform/testing/inline/test/runs/45.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/transform/testing/inline/test/runs/45.act.stdout b/transform/testing/inline/test/runs/45.act.stdout new file mode 100644 index 00000000..77c167a0 --- /dev/null +++ b/transform/testing/inline/test/runs/45.act.stdout @@ -0,0 +1,41 @@ +defproc test (chan(int<32>)? X; chan(int<32>)? Y; chan(int<32>)! O); +function testme (pair p) : pair; +deftype pair (int<32> x; int<32> y); + +defproc test (chan(int<32>)? X; chan(int<32>)? Y; chan(int<32>)! O) +{ + +/* instances */ +pair _us0; +pair p; + +/* connections */ +chp { +*[true -> X?p.x,Y?p.y;_us0.x:=p.x;_us0.y:=p.y;p.x:=_us0.x;*[p.x>p.y -> p.x:=p.x-p.y [] p.y>p.x -> p.y:=p.y-p.x];O!p.x] +} +} + +function testme (pair p) : pair +{ + +/* instances */ + +/* connections */ +chp { +self:=p +} +} + +deftype pair (int<32> x; int<32> y) +{ + +/* instances */ + +/* connections */ +} + + +/* instances */ +test t; + +/* connections */ From 368005c358f9ebd7e85c7ad51274572a0ba8df1f Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 21 Jul 2025 15:49:42 -0400 Subject: [PATCH 40/49] updated refine --- act/test/lang/144.act | 29 +++++++++++++++++++ act/test/lang/runs/144.act.stderr | 0 act/test/lang/runs/144.act.stdout | 0 act/types.cc | 47 +++++++++++++++++++++++++++---- act/types.h | 4 +++ 5 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 act/test/lang/144.act create mode 100644 act/test/lang/runs/144.act.stderr create mode 100644 act/test/lang/runs/144.act.stdout diff --git a/act/test/lang/144.act b/act/test/lang/144.act new file mode 100644 index 00000000..aada56bf --- /dev/null +++ b/act/test/lang/144.act @@ -0,0 +1,29 @@ +defproc bar(bool a, b) +{ + prs { + a => b- + } +} + +deftype myfoo <: bool (bool t, f) { } + + +deftype morefoo <: myfoo (bool q) { q = f; } + +defproc test() +{ + bool x, y, z; + prs { + + x => y- + } + + refine +{ myfoo x; } + { + bar q(x.t,y); + } + refine<2> +{ myfoo z; morefoo x; } + { bar q2(y,z.t); } +} + +test t; diff --git a/act/test/lang/runs/144.act.stderr b/act/test/lang/runs/144.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/144.act.stdout b/act/test/lang/runs/144.act.stdout new file mode 100644 index 00000000..e69de29b diff --git a/act/types.cc b/act/types.cc index 68e1fcb9..29e0b7ae 100644 --- a/act/types.cc +++ b/act/types.cc @@ -2793,6 +2793,7 @@ void Data::synthStructMacro () void UserDef::_apply_ref_overrides (ActBody *b, ActBody *srch) { + list_t *ol = NULL; while (srch) { ActBody_Lang *l = dynamic_cast (srch); if (l) { @@ -2800,17 +2801,51 @@ void UserDef::_apply_ref_overrides (ActBody *b, ActBody *srch) act_refine *r = (act_refine *) l->getlang(); if (acceptRefine (ActNamespace::Act()->getRefSteps(), r->nsteps) && r->overrides) { - refine_override *rl = r->overrides; - /* apply overrides! */ - while (rl) { - b->updateInstType (rl->ids, rl->it); - rl = rl->next; - } + listitem_t *oi, *oprev; + if (!ol) { + ol = list_new (); + } + oi = list_first (ol); + oprev = NULL; + while (oi) { + act_refine *rl = (act_refine *) list_value (oi); + if (r->nsteps < rl->nsteps) { + if (!oprev) { + list_append_head (ol, r); + break; + } + else { + listitem_t *xtl = list_tail (ol); + list_append (ol, r); + list_tail (ol)->next = oi; + oprev->next = list_tail (ol); + list_tail (ol) = xtl; + xtl->next = NULL; + break; + } + } + oprev = oi; + oi = list_next (oi); + } + if (!oi) { + list_append (ol, r); + } } } } srch = srch->Next(); } + /* apply overrides in refinement order */ + if (ol) { + for (listitem_t *oi = list_first (ol); oi; oi = list_next (oi)) { + act_refine *ri = (act_refine *) list_value (oi); + refine_override *rl = ri->overrides; + while (rl) { + b->updateInstType (rl->ids, rl->it); + rl = rl->next; + } + } + } } Interface::Interface(ActNamespace *ns) : UserDef (ns) diff --git a/act/types.h b/act/types.h index ce93d6e8..4f69d9fe 100644 --- a/act/types.h +++ b/act/types.h @@ -735,12 +735,16 @@ class UserDef : public Type { if (!has_refinement) { return false; } + if (refsteps >= mysteps) return true; +#if 0 + /* old refinement rule */ li = list_first (has_refinement); while (li && list_ivalue (li) <= refsteps) { k = list_ivalue (li); li = list_next (li); } if (k == mysteps) return true; +#endif return false; } From 48cf7c1f32d0ff4d51020b068812efc72540c9cd Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 21 Jul 2025 15:55:19 -0400 Subject: [PATCH 41/49] removed unused vars --- act/types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/act/types.h b/act/types.h index 4f69d9fe..31b965b6 100644 --- a/act/types.h +++ b/act/types.h @@ -729,8 +729,10 @@ class UserDef : public Type { void setRefineList(list_t *l) { has_refinement = l; } bool acceptRefine (int refsteps, int mysteps) { +#if 0 listitem_t *li; int k = 0; +#endif if (!has_refinement) { return false; From 2040f232cb9e4f68d013ef6faec069d8915d5535 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Tue, 22 Jul 2025 07:48:27 -0400 Subject: [PATCH 42/49] need to track parent refines --- act/body.cc | 15 +++++++++++---- act/types.cc | 6 +++++- act/types.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/act/body.cc b/act/body.cc index cb790aff..9d6b8a6f 100644 --- a/act/body.cc +++ b/act/body.cc @@ -1246,10 +1246,15 @@ void ActBody_Lang::Expand (ActNamespace *ns, Scope *s) all_lang = ux->getlang(); } - if (ux && (ux->getRefineList() != NULL) && - ActNamespace::Act()->getRefSteps() >= - list_ivalue (list_first (ux->getRefineList()))) { - in_refinement = 1; + if (ux) { + /* check if there are nested refines that will override language + bodies, OR if there are pending refines that do the same */ + if ((ux->getRefineList() != NULL && + ActNamespace::Act()->getRefSteps() >= + list_ivalue (list_first (ux->getRefineList()))) || + ux->moreRefinesExist (ActNamespace::Act()->getRefSteps())) { + in_refinement = 1; + } } #if 0 @@ -1364,6 +1369,7 @@ void ActBody_Lang::Expand (ActNamespace *ns, Scope *s) if (ux->acceptRefine (ActNamespace::Act()->getRefSteps(), r->nsteps)) { list_t *old = ux->getRefineList (); + ux->pushRefine (r->nsteps, old); ux->setRefineList (r->refsublist); ActNamespace::Act()->decRefSteps(r->nsteps); @@ -1371,6 +1377,7 @@ void ActBody_Lang::Expand (ActNamespace *ns, Scope *s) r->b->Expandlist (ns, s); } ux->setRefineList (old); + ux->popRefine (); ActNamespace::Act()->incRefSteps(r->nsteps); } } diff --git a/act/types.cc b/act/types.cc index 29e0b7ae..34a75f53 100644 --- a/act/types.cc +++ b/act/types.cc @@ -329,7 +329,8 @@ UserDef::UserDef (ActNamespace *ns) file = NULL; lineno = 0; - has_refinement = 0; + has_refinement = NULL; + parent_refinement = NULL; inherited_templ = 0; inherited_param = NULL; @@ -425,6 +426,7 @@ void UserDef::MkCopy (UserDef *u) file = u->file; lineno = u->lineno; has_refinement = u->has_refinement; + parent_refinement = u->parent_refinement; inherited_templ = u->inherited_templ; inherited_param = u->inherited_param; @@ -493,6 +495,7 @@ void UserDef::Clone (UserDef *u) file = string_cache (u->file); lineno = u->lineno; has_refinement = list_dup (u->has_refinement); + parent_refinement = list_dup (u->parent_refinement); inherited_templ = u->inherited_templ; @@ -759,6 +762,7 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, ux->file = file; ux->lineno = lineno; ux->has_refinement = has_refinement; + ux->parent_refinement = parent_refinement; if (defined) { ux->MkDefined(); diff --git a/act/types.h b/act/types.h index 31b965b6..8cb57383 100644 --- a/act/types.h +++ b/act/types.h @@ -750,6 +750,48 @@ class UserDef : public Type { return false; } + + /** + * Parent list, used to check for additional refinements + */ + void pushRefine (int steps, list_t *reflist) { + if (!parent_refinement) { + parent_refinement = list_new (); + } + list_append_head (parent_refinement, reflist); + list_iappend_head (parent_refinement, steps); + } + + void popRefine () { + list_delete_head (parent_refinement); + list_delete_head (parent_refinement); + } + + /** + * Check parent list to see if futher refinements are possible + */ + bool moreRefinesExist (int steps) { + listitem_t *li; + + if (!parent_refinement) return false; + + for (li = list_first (parent_refinement); li; li = list_next (li)) { + int v = list_ivalue (li); + li = list_next (li); + list_t *rlist = (list_t *) list_value (li); + steps += v; + + for (listitem_t *mi = list_first (rlist); mi; mi = list_next (mi)) { + // the refinement would be accepted, and this is a higher + // level of refinement than the current one. + if (steps >= list_ivalue (mi) && v < list_ivalue (mi)) { + return true; + } + } + } + return false; + } + /** * Create a new user-defined macro * @param name is the name of the macro @@ -820,6 +862,7 @@ class UserDef : public Type { const char *file; ///< file name (if known) where this was defined int lineno; ///< line number (if known) where this was defined + list_t *parent_refinement; ///< stack of (refinement#, reflist) taken so far list_t *has_refinement; ///< list of refinement levels in this type int inherited_templ; ///< number of inherited template parameters From 457b354ac018204a4a8841a5369811bd78faf058 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 23 Jul 2025 08:06:59 -0400 Subject: [PATCH 43/49] playbody needs to also re-play refinements --- act/scope.cc | 39 ++++++++++++++++++------------- act/test/lang/145.act | 29 +++++++++++++++++++++++ act/test/lang/runs/145.act.stderr | 0 act/test/lang/runs/145.act.stdout | 0 4 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 act/test/lang/145.act create mode 100644 act/test/lang/runs/145.act.stderr create mode 100644 act/test/lang/runs/145.act.stdout diff --git a/act/scope.cc b/act/scope.cc index c1cacb78..90a3e88e 100644 --- a/act/scope.cc +++ b/act/scope.cc @@ -1820,26 +1820,33 @@ void Scope::playBody (ActBody *b) Add (inst->getName(), inst->getType()); } } - else { - if (dynamic_cast(b)) { + else if (dynamic_cast(b)) { + ActBody_Lang *l = dynamic_cast(b); + if (l->gettype() == ActBody_Lang::LANG_REFINE) { + act_refine *r = (act_refine *) l->getlang(); + if (r->b) { + playBody (r->b); + } + } + } + else if (dynamic_cast(b)) { ActBody_Loop *l = dynamic_cast(b); playBody (l->getBody()); + } + else { + ActBody_Select_gc *sel; + if (dynamic_cast(b)) { + sel = dynamic_cast(b)->getGC(); + } + else if (dynamic_cast(b)) { + sel = dynamic_cast(b)->getGC(); } else { - ActBody_Select_gc *sel; - if (dynamic_cast(b)) { - sel = dynamic_cast(b)->getGC(); - } - else if (dynamic_cast(b)) { - sel = dynamic_cast(b)->getGC(); - } - else { - sel = NULL; - } - while (sel) { - playBody (sel->getBody()); - sel = sel->getNext(); - } + sel = NULL; + } + while (sel) { + playBody (sel->getBody()); + sel = sel->getNext(); } } } diff --git a/act/test/lang/145.act b/act/test/lang/145.act new file mode 100644 index 00000000..0a3dbf96 --- /dev/null +++ b/act/test/lang/145.act @@ -0,0 +1,29 @@ +deftype myint <: int () { } + +defproc p () +{ + int x; + chp { + *[ x:=0 ] + } + refine { + int y; + chp { + *[ y:=1 ] + } + } +} + +defproc p1 <: p () +{ + refine<2> + +{ + myint y; + } + { + chp { + *[ y:=2 ] + } + } +} + diff --git a/act/test/lang/runs/145.act.stderr b/act/test/lang/runs/145.act.stderr new file mode 100644 index 00000000..e69de29b diff --git a/act/test/lang/runs/145.act.stdout b/act/test/lang/runs/145.act.stdout new file mode 100644 index 00000000..e69de29b From 6be97c3335055f441191a00871e63a01d7a61f7b Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 30 Jul 2025 09:18:38 -0400 Subject: [PATCH 44/49] fixes for interface macros --- act/check.cc | 52 ++++++++++++++++++++++++++++++++---- act/id.cc | 71 ++++++++++++++++++++++++++++++++++++++++++------- act/lang.h | 8 +++++- act/lang_chp.cc | 10 ++++++- act/types.cc | 33 +++++++++++++++++++++-- 5 files changed, 156 insertions(+), 18 deletions(-) diff --git a/act/check.cc b/act/check.cc index e70645d6..1ec8acfe 100644 --- a/act/check.cc +++ b/act/check.cc @@ -1599,12 +1599,21 @@ InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal, bool subchan) /* extract the real type */ InstType *itmp = it->getIfaceType(); Assert (itmp, "What?"); - Process *proc = dynamic_cast (it->BaseType()); - Assert (proc, "What?"); - list_t *map = proc->findMap (itmp); + list_t *map = NULL; + if (TypeFactory::isProcessType (it)) { + Process *proc = dynamic_cast (it->BaseType()); + Assert (proc, "What?"); + map = proc->findMap (itmp); + } + else { + Data *idat = dynamic_cast (it->BaseType()); + Assert (idat, "What?"); + map = idat->findMap (itmp); + } if (!map) { - fatal_error ("Missing interface `%s' from process `%s'?", - itmp->BaseType()->getName(), proc->getName()); + act_error_ctxt (stderr); + fatal_error ("Missing interface `%s' from type `%s'?", + itmp->BaseType()->getName(), it->BaseType()->getName()); } listitem_t *li; #if 0 @@ -1628,6 +1637,39 @@ InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal, bool subchan) li = list_next (li); } if (!li) { +#if 0 + bool extra_check_passed = false; + if (chp_processing_macro() != 0) { + // it may not be in the interface, but it may be in the + // actual type! we allow this for macros. + Scope *srch = s; + const char *pt = itmp->getPTypeID (); + if (pt) { + ValueIdx *vx = s->LookupVal (pt); + if (!vx && s->Parent()) { + vx = s->Parent()->LookupVal (pt); + srch = s->Parent (); + } + if (vx) { + if (vx->init && srch->issetPType (vx->u.idx)) { + InstType *px = srch->getPType (vx->u.idx); + u = dynamic_cast(px->BaseType()); + if (u) { + if (u->FindPort (id->Rest()->getName()) != 0) { + extra_check_passed = true; + id = id->Rest (); + } + } + } + } + } + } + if (!extra_check_passed) { + fatal_error ("Map for interface `%s' doesn't contain `%s'", + itmp->BaseType()->getName(), id->Rest()->getName()); + } +#endif + act_error_ctxt (stderr); fatal_error ("Map for interface `%s' doesn't contain `%s'", itmp->BaseType()->getName(), id->Rest()->getName()); } diff --git a/act/id.cc b/act/id.cc index 0e0b7f62..3d37dc8b 100644 --- a/act/id.cc +++ b/act/id.cc @@ -27,6 +27,7 @@ #include #include #include +#include //#define DEBUG_CONNECTIONS @@ -372,12 +373,25 @@ Expr *ActId::Eval (ActNamespace *ns, Scope *s, int is_lval, int is_chp) /* extract the real type */ InstType *itmp = it->getIfaceType(); Assert (itmp, "What?"); - Process *proc = dynamic_cast (it->BaseType()); - Assert (proc, "What?"); - list_t *map = proc->findMap (itmp); + list_t *map = NULL; + if (TypeFactory::isProcessType (it)) { + Process *proc = dynamic_cast (it->BaseType()); + Assert (proc, "What?"); + map = proc->findMap (itmp); + } + else if (TypeFactory::isDataType (it) || TypeFactory::isStructure (it)) { + Data *dat = dynamic_cast (it->BaseType()); + Assert (dat, "What?"); + map = dat->findMap (itmp); + } + else { + act_error_ctxt (stderr); + fatal_error ("Interfaces are only supported for process and data types; got `%s'?", it->BaseType()->getName()); + } if (!map) { - fatal_error ("Missing interface `%s' from process `%s'?", - itmp->BaseType()->getName(), proc->getName()); + act_error_ctxt (stderr); + fatal_error ("Missing interface `%s' from type `%s'?", + itmp->BaseType()->getName(), it->BaseType()->getName()); } listitem_t *li; #if 0 @@ -402,14 +416,52 @@ Expr *ActId::Eval (ActNamespace *ns, Scope *s, int is_lval, int is_chp) li = list_next (li); } if (!li) { - fatal_error ("Map for interface `%s' doesn't contain `%s'", - itmp->BaseType()->getName(), id->Rest()->getName()); + bool extra_check_passed = false; + if (is_chp && chp_processing_macro() != 0) { + // it may not be in the interface, but it may be in the + // actual type! we allow this for macros. + Scope *srch = s; + const char *pt = itmp->getPTypeID (); + if (pt) { + ValueIdx *vx = s->LookupVal (pt); + // XXX: this isn't really right... we need to find the + // correct scope here! + if (!vx && s->Parent()) { + vx = s->Parent()->LookupVal (pt); + srch = s->Parent (); + } + if (vx) { + if (vx->init && srch->issetPType (vx->u.idx)) { + InstType *px = srch->getPType (vx->u.idx); + u = dynamic_cast(px->BaseType()); + if (u) { + // XXX: edit type in "s" for expanded scopes + if (s->isExpanded()) { + Assert (s->Lookup (id->getName()) == it, "What?"); + InstType *xtmp = new InstType (srch, u, 1); + s->refineBaseType (id->getName(), xtmp); + delete xtmp; + } + if (u->FindPort (id->Rest()->getName()) != 0) { + extra_check_passed = true; + id = id->Rest (); + } + } + } + } + } + } + if (!extra_check_passed) { + act_error_ctxt (stderr); + fatal_error ("Map for interface `%s' doesn't contain `%s'", + itmp->BaseType()->getName(), id->Rest()->getName()); + } } -#if 0 +#if 0 printf ("NEW ID rest: "); id->Print(stdout); printf ("\n"); -#endif +#endif } else { id = id->Rest (); @@ -1450,6 +1502,7 @@ act_connection *ActId::Canonical (Scope *s) li = list_next (li); } if (!li) { + act_error_ctxt (stderr); fatal_error ("Map for interface `%s' doesn't contain `%s'", itmp->BaseType()->getName(), id->Rest()->getName()); } diff --git a/act/lang.h b/act/lang.h index 8db0af54..2da58f4b 100644 --- a/act/lang.h +++ b/act/lang.h @@ -885,10 +885,16 @@ act_dataflow *dflow_dup (act_dataflow *, ActNamespace *, ActNamespace *); act_chp *chp_expand (act_chp *, ActNamespace *, Scope *); /** - * Set the CHP expansion mode (1 if in macro, 0 otherwise) + * Set the CHP expansion mode (1/2 if in macro, 0 otherwise) + * 2 = macro in a process, 1 = other macro */ void chp_expand_macromode (int mode); +/** + * Get the CHP expansion mode: is it handling a macro? + */ +int chp_processing_macro (void); + /** * chp_expand helper for the items within the language block */ diff --git a/act/lang_chp.cc b/act/lang_chp.cc index 315d1122..e56ae286 100644 --- a/act/lang_chp.cc +++ b/act/lang_chp.cc @@ -265,12 +265,18 @@ void act_chp_free (act_chp_lang_t *c) } static int _chp_expanding_macro = 0; +static int _chp_still_in_macro = 0; void chp_expand_macromode (int v) { _chp_expanding_macro = v; } +int chp_processing_macro (void) +{ + return _chp_expanding_macro ? 1 : (_chp_still_in_macro ? 1 : 0); +} + void act_chp_macro_check (Scope *s, ActId *id) { if (_chp_expanding_macro) { @@ -1935,7 +1941,7 @@ static act_chp_lang_t *chp_expand_1 (act_chp_lang_t *c, ActNamespace *ns, Scope ret->u.assign.e = te; - if (_chp_expanding_macro == 0) { + if (chp_processing_macro() == 0) { int tr = act_type_expr (s, te, NULL, 2); if (tr == T_ERR) { fprintf (stderr, "Typechecking failed on CHP assignment\n"); @@ -2237,12 +2243,14 @@ static act_chp_lang_t *chp_expand_1 (act_chp_lang_t *c, ActNamespace *ns, Scope /*-- re-expand, do all the checks --*/ { + _chp_still_in_macro++; int tmp = Act::double_expand; act_chp_lang_t *oret = ret; Act::double_expand = 0; ret = chp_expand_1 (oret, ns, s); Act::double_expand = tmp; act_chp_free (oret); + _chp_still_in_macro--; } delete tsc; diff --git a/act/types.cc b/act/types.cc index 34a75f53..d8ce27ee 100644 --- a/act/types.cc +++ b/act/types.cc @@ -1219,8 +1219,37 @@ UserDef *UserDef::Expand (ActNamespace *ns, Scope *s, // skip the port! continue; } - - Assert (ux->AddPort (chk, getPortName (i)), "What?"); + + + /* + * XXX: This really needs to be "if this is a real type rather + * than part of an interface". Examples of "part of an interface" + * are interfaces themselves or functions within interfaces. + */ + if (is_proc != 2 && TypeFactory::isInterfaceType (chk)) { + /* this means that this was a ptype... we need to do more work */ + const char *pt = chk->getPTypeID(); + Assert (pt, "PType ID missing!"); + ValueIdx *vx = ux->CurScope()->LookupVal (pt); + Assert (vx, "PType ID not found?"); + if (!vx->init || !ux->CurScope()->issetPType (vx->u.idx)) { + act_error_ctxt (stderr); + fatal_error ("Ptype `%s' used to instantiate `%s' is not set", pt, + getPortName (i)); + } + + InstType *x = new InstType (ux->CurScope()->getPType (vx->u.idx)); + x->MkCached (); + x->setIfaceType (chk); + if (chk->arrayInfo()) { + x->MkArray (chk->arrayInfo()); + } + Assert (ux->AddPort (x, getPortName (i)), "Should succeed!"); + chk = x; + } + else { + Assert (ux->AddPort (chk, getPortName (i)), "Should succeed; what happened?!"); + } if (chk->arrayInfo() && chk->arrayInfo()->size() == 0) { act_error_ctxt (stderr); From c59f15705eba9b54b887628440bef1bbd37bf58e Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Thu, 31 Jul 2025 08:24:21 -0400 Subject: [PATCH 45/49] slightly more general fix --- act/check.cc | 32 -------------------------------- act/id.cc | 10 ++++------ 2 files changed, 4 insertions(+), 38 deletions(-) diff --git a/act/check.cc b/act/check.cc index 1ec8acfe..1967b48f 100644 --- a/act/check.cc +++ b/act/check.cc @@ -1637,38 +1637,6 @@ InstType *act_actual_insttype (Scope *s, ActId *id, int *islocal, bool subchan) li = list_next (li); } if (!li) { -#if 0 - bool extra_check_passed = false; - if (chp_processing_macro() != 0) { - // it may not be in the interface, but it may be in the - // actual type! we allow this for macros. - Scope *srch = s; - const char *pt = itmp->getPTypeID (); - if (pt) { - ValueIdx *vx = s->LookupVal (pt); - if (!vx && s->Parent()) { - vx = s->Parent()->LookupVal (pt); - srch = s->Parent (); - } - if (vx) { - if (vx->init && srch->issetPType (vx->u.idx)) { - InstType *px = srch->getPType (vx->u.idx); - u = dynamic_cast(px->BaseType()); - if (u) { - if (u->FindPort (id->Rest()->getName()) != 0) { - extra_check_passed = true; - id = id->Rest (); - } - } - } - } - } - } - if (!extra_check_passed) { - fatal_error ("Map for interface `%s' doesn't contain `%s'", - itmp->BaseType()->getName(), id->Rest()->getName()); - } -#endif act_error_ctxt (stderr); fatal_error ("Map for interface `%s' doesn't contain `%s'", itmp->BaseType()->getName(), id->Rest()->getName()); diff --git a/act/id.cc b/act/id.cc index 3d37dc8b..1279dfe7 100644 --- a/act/id.cc +++ b/act/id.cc @@ -423,12 +423,10 @@ Expr *ActId::Eval (ActNamespace *ns, Scope *s, int is_lval, int is_chp) Scope *srch = s; const char *pt = itmp->getPTypeID (); if (pt) { - ValueIdx *vx = s->LookupVal (pt); - // XXX: this isn't really right... we need to find the - // correct scope here! - if (!vx && s->Parent()) { - vx = s->Parent()->LookupVal (pt); - srch = s->Parent (); + ValueIdx *vx = srch->LookupVal (pt); + while (!vx && srch && srch->Parent()) { + vx = srch->Parent()->LookupVal (pt); + srch = srch->Parent (); } if (vx) { if (vx->init && srch->issetPType (vx->u.idx)) { From 81cf17ac366aef797bd968415b6fa0bfccfbed58 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Wed, 6 Aug 2025 13:23:12 -0400 Subject: [PATCH 46/49] fix for mask bits v/s non-mask bits --- act/check.cc | 29 +++++++++++++++++++++-------- act/types.h | 1 - 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/act/check.cc b/act/check.cc index 1967b48f..edfcd731 100644 --- a/act/check.cc +++ b/act/check.cc @@ -422,7 +422,7 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) WIDTH_UPDATE(mode); \ return (((f) != (g) ? (g) : T_BOOL) & ~(T_PARAM|T_STRICT))|flgs; \ } \ - if ((f & T_REAL) && T_BASETYPE_ISNUM(lt) && T_BASETYPE_ISNUM(rt)) { \ + if ((T_BASETYPE (f) == T_REAL) && T_BASETYPE_ISNUM(lt) && T_BASETYPE_ISNUM(rt)) { \ if (T_BASETYPE(lt) == T_REAL || T_BASETYPE(rt) == T_REAL) { \ return (((f) != (g) ? (g) : T_REAL) & ~(T_PARAM|T_STRICT))|flgs; \ } \ @@ -816,8 +816,8 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) typecheck_err ("bool(.) requires an integer argument"); return T_ERR; } - if (lt & T_INT) { - return (lt & ~T_INT) | T_BOOL; + if (T_FIXBASETYPE(lt) == T_INT) { + return (lt & ~T_MASK) | T_BOOL; } typecheck_err ("Invalid use of bool(.)"); return T_ERR; @@ -842,9 +842,9 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) if (width) { *width = 1; } - return (lt & ~(T_BOOL|T_DATA_BOOL))|T_INT; + return (lt & ~T_MASK)|T_INT; } - if (lt & T_REAL) { + if (T_BASETYPE (lt) == T_REAL) { if (width) { *width = 64; } @@ -873,7 +873,12 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) } return lt; } - typecheck_err ("int(.) takes only an int or bool argument"); + if (e->u.e.r) { + typecheck_err ("int(.,) takes only an int argument"); + } + else { + typecheck_err ("int(.) takes only an int or bool argument"); + } return T_ERR; break; @@ -1290,6 +1295,10 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) InstType *it = _act_get_var_type (s, theid, &tmp, NULL, true); Assert (it, "This should not happen"); + Assert (TypeFactory::isChanType (it), "T_CHAN without channel type?"); + InstType *dit = TypeFactory::getChanDataType (it); + Assert (dit, "Hmm"); + if (it->getDir() == Type::OUT) { InstType *it2 = s->FullLookup (theid->getName()); if (!(theid->Rest() && TypeFactory::isProcessType (it2))) { @@ -1308,13 +1317,13 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) return T_ERR; } - if (TypeFactory::boolType (it) == 1) { + if (TypeFactory::boolType (dit) == 1) { if (width) { *width = 1; } return T_BOOL; } - else { + else if (TypeFactory::isDataType (dit)) { if (width) { if (xit->isExpanded()) { *width = TypeFactory::bitWidth (xit); @@ -1325,6 +1334,10 @@ int act_type_expr (Scope *s, Expr *e, int *width, int only_chan) } return T_INT; } + else { + Assert (TypeFactory::isStructure (dit), "Hmm"); + return T_DATA; + } } if (!(lt & T_ARRAYOF) && (lt & T_PARAM) && T_BASETYPE_ISINTBOOL (lt)) { if (width) { diff --git a/act/types.h b/act/types.h index 8cb57383..e10be934 100644 --- a/act/types.h +++ b/act/types.h @@ -2320,7 +2320,6 @@ class TypeFactory { /** * A UserDef that is a Data type can hold a structure. A data type * is a structure when it does not implement a built-in data type. - * Note that currently structures cannot contain arrays. * @return 1 if this is a structure, 0 otherwise */ static int isStructure (const Type *t); From 2c3aa6843b01cbdc185340b80570dc93728877a8 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 11 Aug 2025 10:17:00 -0400 Subject: [PATCH 47/49] slightly more information in error output --- act/check.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/act/check.cc b/act/check.cc index edfcd731..e9268912 100644 --- a/act/check.cc +++ b/act/check.cc @@ -1787,13 +1787,13 @@ InstType *act_expr_insttype (Scope *s, Expr *e, int *islocal, int only_chan) if (ret == (T_INT|T_PARAM)) { return TypeFactory::Factory()->NewPInt(); } - else if (ret == T_INT) { + else if (ret == T_INT || ret == T_DATA_INT) { return TypeFactory::Factory()->NewInt (s, Type::NONE, 0, const_expr (32)); } else if (ret == (T_BOOL|T_PARAM)) { return TypeFactory::Factory()->NewPBool (); } - else if (ret == T_BOOL) { + else if (ret == T_BOOL || ret == T_DATA_BOOL) { return TypeFactory::Factory()->NewBool (Type::NONE); } else if (ret == (T_REAL|T_PARAM)) { @@ -1825,7 +1825,7 @@ InstType *act_expr_insttype (Scope *s, Expr *e, int *islocal, int only_chan) } } else { - fatal_error ("Not sure what to do now"); + fatal_error ("Unexpected return code in typechecking: %x", ret); } return NULL; } From 4dee7053436b31f0ca0764ecb5c35681367e4fa1 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Mon, 11 Aug 2025 12:33:07 -0400 Subject: [PATCH 48/49] update expr to string to support dags --- act/expr_print.cc | 54 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/act/expr_print.cc b/act/expr_print.cc index 5e7e1db5..abe77f73 100644 --- a/act/expr_print.cc +++ b/act/expr_print.cc @@ -1424,10 +1424,26 @@ static void _expr_to_var (char **buf, int *len, int *sz, } static void _expr_to_string (char **buf, int *len, int *sz, + struct pHashtable *H, int *uid, list_t *ids, Expr *e, int *isassoc) { int iszero = 0; int tmp; + phash_bucket_t *b; + + b = phash_lookup (H, e); + if (b) { + _expr_expand_sz (buf, len, sz, 32); + (*buf)[*len] = 'w'; + *len = *len + 1; + snprintf (*buf + *len, *sz - *len, "%lu", (unsigned long)b->i); + *len += strlen (*buf + *len); + return; + } + b = phash_add (H, e); + b->i = *uid; + *uid = *uid + 1; + switch (e->type) { case E_PLUS: case E_MULT: @@ -1437,14 +1453,14 @@ static void _expr_to_string (char **buf, int *len, int *sz, } if (e->u.e.l->type == e->type) { (*isassoc) = (*isassoc) + 1; - _expr_to_string (buf, len, sz, ids, e->u.e.l, isassoc); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.l, isassoc); } else { tmp = 0; - _expr_to_string (buf, len, sz, ids, e->u.e.l, &tmp); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.l, &tmp); } tmp = 0; - _expr_to_string (buf, len, sz, ids, e->u.e.r, &tmp); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.r, &tmp); if (iszero) { _expr_append_char (buf, len, sz, _expr_type_char (e->type)); while (*isassoc) { @@ -1460,22 +1476,22 @@ static void _expr_to_string (char **buf, int *len, int *sz, case E_LT: case E_GT: case E_LE: case E_GE: case E_EQ: case E_NE: - _expr_to_string (buf, len, sz, ids, e->u.e.l, &iszero); - _expr_to_string (buf, len, sz, ids, e->u.e.r, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.r, &iszero); _expr_append_char (buf, len, sz, _expr_type_char (e->type)); break; case E_NOT: case E_UMINUS: case E_COMPLEMENT: - _expr_to_string (buf, len, sz, ids, e->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.l, &iszero); _expr_append_char (buf, len, sz, _expr_type_char (e->type)); break; case E_QUERY: - _expr_to_string (buf, len, sz, ids, e->u.e.l, &iszero); - _expr_to_string (buf, len, sz, ids, e->u.e.r->u.e.l, &iszero); - _expr_to_string (buf, len, sz, ids, e->u.e.r->u.e.r, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.r->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.r->u.e.r, &iszero); _expr_append_char (buf, len, sz, _expr_type_char (e->type)); break; @@ -1508,7 +1524,7 @@ static void _expr_to_string (char **buf, int *len, int *sz, { Expr *f = e; while (f) { - _expr_to_string (buf, len, sz, ids, f->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, f->u.e.l, &iszero); f = f->u.e.r; } _expr_append_char (buf, len, sz, _expr_type_char (e->type)); @@ -1520,21 +1536,21 @@ static void _expr_to_string (char **buf, int *len, int *sz, _expr_to_var (buf, len, sz, ids, (ActId *)e->u.e.l); _expr_append_char (buf, len, sz, _expr_type_char (e->type)); if (e->u.e.r->u.e.l) { - _expr_to_string (buf, len, sz, ids, e->u.e.r->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.r->u.e.l, &iszero); } - _expr_to_string (buf, len, sz, ids, e->u.e.r->u.e.r, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.r->u.e.r, &iszero); _expr_append_char (buf, len, sz, _expr_type_char (e->type)); break; case E_BUILTIN_BOOL: - _expr_to_string (buf, len, sz, ids, e->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.l, &iszero); _expr_append_char (buf, len, sz, _expr_type_char (e->type)); break; case E_BUILTIN_INT: - _expr_to_string (buf, len, sz, ids, e->u.e.l, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.l, &iszero); if (e->u.e.r) { - _expr_to_string (buf, len, sz, ids, e->u.e.r, &iszero); + _expr_to_string (buf, len, sz, H, uid, ids, e->u.e.r, &iszero); } _expr_append_char (buf, len, sz, _expr_type_char (e->type)); if (e->u.e.r) { @@ -1569,7 +1585,13 @@ char *act_expr_to_string (list_t *id_list, Expr *e) buf[0] = '\0'; len = 0; - _expr_to_string (&buf, &len, &sz, id_list, e, &iszero); + struct pHashtable *H = phash_new (8); + + int unique_id = 0; + + _expr_to_string (&buf, &len, &sz, H, &unique_id, id_list, e, &iszero); + + phash_free (H); char *ret = Strdup (buf); FREE (buf); From d7bc142731b3f6aa9ccb239fe4851f11a980f6b1 Mon Sep 17 00:00:00 2001 From: Rajit Manohar Date: Thu, 21 Aug 2025 11:38:36 -0400 Subject: [PATCH 49/49] fully propagate refines --- act/body.cc | 18 +++++++++++++++--- act/body.h | 8 ++++++-- act/defs.m4 | 2 +- act/types.cc | 39 ++++++++++++++++++++++++++++++--------- 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/act/body.cc b/act/body.cc index 9d6b8a6f..88ef9eda 100644 --- a/act/body.cc +++ b/act/body.cc @@ -1881,7 +1881,7 @@ ActBody *ActBody_Print::Clone(ActNamespace *replace, ActNamespace *newns) } -void ActBody::updateInstType (list_t *namelist, InstType *it) +void ActBody::updateInstType (list_t *namelist, InstType *it, bool handle_subref) { ActBody *b = this; listitem_t *li; @@ -1908,7 +1908,7 @@ void ActBody::updateInstType (list_t *namelist, InstType *it) else if (dynamic_cast (b)) { ActBody_Loop *bl = dynamic_cast (b); if (bl->getBody()) { - bl->getBody()->updateInstType (namelist, it); + bl->getBody()->updateInstType (namelist, it, handle_subref); } } else { @@ -1919,12 +1919,24 @@ void ActBody::updateInstType (list_t *namelist, InstType *it) else if (dynamic_cast (b)) { sel = dynamic_cast (b)->getGC(); } + else if (dynamic_cast (b) && handle_subref) { + ActBody_Lang *l = dynamic_cast (b); + if (l->gettype() == ActBody_Lang::LANG_REFINE) { + act_refine *r = (act_refine *) l->getlang(); + if (r->b && r->nsteps <= ActNamespace::Act()->getRefSteps ()) { + ActNamespace::Act()->decRefSteps (r->nsteps); + r->b->updateInstType (namelist, it, true); + ActNamespace::Act()->incRefSteps (r->nsteps); + } + } + sel = NULL; + } else { sel = NULL; } while (sel) { if (sel->getBody()) { - sel->getBody()->updateInstType (namelist, it); + sel->getBody()->updateInstType (namelist, it, handle_subref); } sel = sel->getNext(); } diff --git a/act/body.h b/act/body.h index e2ae8a9a..aecd9ee0 100644 --- a/act/body.h +++ b/act/body.h @@ -119,9 +119,13 @@ class ActBody { * instance type to the new one specified. This is used to support * overrides. * @param namelist is a list of names (char * list) - * @param it is the updated instance type for the specified identifiers + * @param it is the updated instance type for the specified + * identifiers + * @param handle_subref is a flag. If it is true, then the update + * method also handles a nested refine within the body; otherwise + * those are ignored. */ - void updateInstType (list_t *namelist, InstType *it); + void updateInstType (list_t *namelist, InstType *it, bool handle_subref); /** * @return the saved away line number associated with a body diff --git a/act/defs.m4 b/act/defs.m4 index 6ef2b655..d4c8d0d3 100644 --- a/act/defs.m4 +++ b/act/defs.m4 @@ -648,7 +648,7 @@ override_one_spec: user_type [ "+" ] bare_id_list ";" } /* walk through the body, editing instances */ if (b) { - b->updateInstType ($3, $1); + b->updateInstType ($3, $1, false); if (port_override_asserts) { b->Tail()->Append (port_override_asserts); } diff --git a/act/types.cc b/act/types.cc index d8ce27ee..16071412 100644 --- a/act/types.cc +++ b/act/types.cc @@ -2827,17 +2827,19 @@ void Data::synthStructMacro () void UserDef::_apply_ref_overrides (ActBody *b, ActBody *srch) { list_t *ol = NULL; + while (srch) { ActBody_Lang *l = dynamic_cast (srch); if (l) { if (l->gettype() == ActBody_Lang::LANG_REFINE) { act_refine *r = (act_refine *) l->getlang(); - if (acceptRefine (ActNamespace::Act()->getRefSteps(), r->nsteps) && - r->overrides) { + if (acceptRefine (ActNamespace::Act()->getRefSteps(), r->nsteps)) { listitem_t *oi, *oprev; if (!ol) { ol = list_new (); } + + /* insert the override into a sorted list of refinement levels */ oi = list_first (ol); oprev = NULL; while (oi) { @@ -2870,14 +2872,33 @@ void UserDef::_apply_ref_overrides (ActBody *b, ActBody *srch) } /* apply overrides in refinement order */ if (ol) { - for (listitem_t *oi = list_first (ol); oi; oi = list_next (oi)) { - act_refine *ri = (act_refine *) list_value (oi); - refine_override *rl = ri->overrides; + for (listitem_t *oi = list_first (ol); oi; oi = list_next (oi)) { + act_refine *ri = (act_refine *) list_value (oi); + refine_override *rl = ri->overrides; + while (rl) { - b->updateInstType (rl->ids, rl->it); - rl = rl->next; - } - } + b->updateInstType (rl->ids, rl->it, false); + rl = rl->next; + } + + /* also propagate the refinement to the bodies of the earlier + refinement bodies! */ + + /** XXX: this doesn't correctly handle nested refinement blocks **/ + if (ri->overrides) { + for (listitem_t *op = list_first (ol); op != oi; op = list_next (op)) { + act_refine *rp = (act_refine *) list_value (op); + rl = ri->overrides; + Assert (rp->nsteps <= ActNamespace::Act()->getRefSteps(), "What?"); + ActNamespace::Act()->decRefSteps (rp->nsteps); + while (rl) { + rp->b->updateInstType (rl->ids, rl->it, true); + rl = rl->next; + } + ActNamespace::Act()->incRefSteps (rp->nsteps); + } + } + } } }