-
Notifications
You must be signed in to change notification settings - Fork 49
explicit_object_extensions provisional -- SIMICS-23313
#399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1169,6 +1169,41 @@ def log(self): | |
| DMLError.log(self) | ||
| self.print_site_message(self.other_site, "existing declaration") | ||
|
|
||
|
|
||
| class EEXTENSION(DMLError): | ||
| """When the `explict_object_extensions` provisional feature is enabled, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. link |
||
| any object definition made via `in` syntax is considered an extension such | ||
| that there must be some other non-extension declaration of the object, or | ||
| DMLC will reject the extension. | ||
| To declare and define a new object not already declared, omit the `in` | ||
| syntax. | ||
| """ | ||
| fmt = ("object '%s' not declared elsewhere." | ||
| " To declare and define a new object, omit 'in'.") | ||
|
|
||
| class EMULTIOBJDECL(DMLError): | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I struggled a bit with naming of these error tags, but ultimately it doesn't matter much. |
||
| """When the `explicit_object_extensions` provisional feature is enabled, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. link |
||
| any object declaration not made using `in` syntax is considered a | ||
| declaration of a novel object — because of that, DMLC will reject | ||
| it if there already is another non-`in` declaration across files enabling | ||
| `explicit_object_extensions`. | ||
| """ | ||
| fmt = ("object '%s' already declared." | ||
| " To extend upon the definition of an object, use 'in %s'") | ||
| def __init__(self, site, other_site, objtype, name): | ||
| super().__init__(site, name, f'{objtype} {name} ...') | ||
| self.other_site = other_site | ||
|
|
||
| def log(self): | ||
| from . import provisional | ||
| DMLError.log(self) | ||
| self.print_site_message(self.other_site, "existing declaration") | ||
| prov_site = self.site.provisional_enabled( | ||
| provisional.explicit_object_extensions) | ||
| self.print_site_message( | ||
| prov_site, | ||
| "enabled by the explicit_object_extensions provisional feature") | ||
|
|
||
| class EVARPARAM(DMLError): | ||
| """ | ||
| The value assigned to the parameter is not a well-defined constant. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -135,6 +135,34 @@ class simics_util_vect(ProvisionalFeature): | |
| stable = True | ||
| dml12 = True | ||
|
|
||
|
|
||
| @feature | ||
| class explicit_object_extensions(ProvisionalFeature): | ||
| '''<a id="explicit_object_extensions"/> | ||
| This feature extends the DML syntax for object declarations to distinguish | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. newline after
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wait-- you mean ? That's messed up, man...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wait i can't see that reflected for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... in fact I can't see a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, I meant to write: instead of: The first one is rendered like this:blah The second one is rendered like this:blah `blah`and don't ask me why everything is underlined now |
||
| between an intent to introduce a new object to the model structure, and an | ||
| intent to extend the definition of an existing object. | ||
|
|
||
| The following form is introduced to mark the intent to extend an object: | ||
| <pre> | ||
| in <em>object-type</em> <em>name</em> <em>...</em> { <em>...</em> } | ||
| </pre> | ||
| E.g. | ||
| <pre> | ||
| in bank some_bank { ... } | ||
| </pre> | ||
|
|
||
| If this form is used while there is no other non-extension declaration of | ||
| the named object, then DMLC will signal an error because the definition | ||
| was not intended to introduce the object to the model structure. | ||
|
|
||
| DMLC will also signal an error if there is more than one non-extension | ||
| declaration of the object among the files enabling | ||
| `explicit_object_extensions`. | ||
| ''' | ||
| short = "Require `in` syntax for additional declarations of an object" | ||
| stable = False | ||
|
|
||
| def parse_provisional( | ||
| provs: list[("Site", str)]) -> dict[ProvisionalFeature, "Site"]: | ||
| ret = {} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -503,9 +503,9 @@ def wrap_sites(spec, issite, tname): | |
| else: | ||
| raise ICE(issite, 'unknown node type %r %r' % (asttype, stmt)) | ||
| composite_wrapped = [ | ||
| (objtype, name, arrayinfo, | ||
| (objtype, name, arrayinfo, is_extension, | ||
| ObjectSpec(*wrap_sites(spec, issite, tname))) | ||
| for (objtype, name, arrayinfo, spec) in composite] | ||
| for (objtype, name, arrayinfo, is_extension, spec) in composite] | ||
| blocks.append((preconds, shallow_wrapped, composite_wrapped)) | ||
|
|
||
| return (TemplateSite(spec.site, issite, tname), spec.rank, | ||
|
|
@@ -833,8 +833,8 @@ def sort_method_implementations(implementations, obj_specs): | |
| return traits.sort_method_implementations(implementations) | ||
|
|
||
| def merge_subobj_defs(def1, def2, parent): | ||
| (objtype, name, arrayinfo, obj_specs1) = def1 | ||
| (objtype2, name2, arrayinfo2, obj_specs2) = def2 | ||
| (objtype, name, arrayinfo, extension_status1, obj_specs1) = def1 | ||
| (objtype2, name2, arrayinfo2, extension_status2, obj_specs2) = def2 | ||
| assert name == name2 | ||
|
|
||
| site1 = obj_specs1[0].site | ||
|
|
@@ -844,6 +844,26 @@ def merge_subobj_defs(def1, def2, parent): | |
| report(ENAMECOLL(site1, site2, name)) | ||
| return def1 | ||
|
|
||
| # extension status: | ||
| # None -> dual extension and decl | ||
| # True -> extension | ||
| # False -> explicit decl | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This ternary rep is pretty damn ugly. @mandolaerik does this deserve the use of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current rep is fine, but I also wouldn't object to enum. The question it poses to me is rather whether it makes sense to handle subobj merge in this incremental pairwise fashion -- I think this logic would be much easier to express if we just merged all object defs at once. IIRC the pairwise thing is there for a historical reason: before dml 1.4, templates would consist of pre-merged subobj defs, so a template used many times did not have to merge defs again. It would probably make sense to refactor all of merge_subobj_defs, but no need to do within this PR. |
||
| if extension_status1 is extension_status2 is False: | ||
| # Blame the one with higher rank if possible. Otherwise, blame the | ||
| # new def. | ||
| (decl_site_1, decl_site_2) = ( | ||
| (site1, site2) if ( | ||
| obj_specs2[0].rank in obj_specs1[0].rank.inferior) | ||
| else (site2, site1)) | ||
| report(EMULTIOBJDECL(decl_site_1, decl_site_2, objtype, name)) | ||
| # One is explicit decl: merged is explicit decl | ||
| elif extension_status1 is False or extension_status2 is False: | ||
| extension_status1 = False | ||
| # If either is dual, make dual | ||
| elif extension_status1 is None or extension_status2 is None: | ||
| extension_status1 = None | ||
| # Otherwise, both are explicit extensions. Keep explicit extension. | ||
|
|
||
| if len(arrayinfo) != len(arrayinfo2): | ||
| raise EAINCOMP(site1, site2, name, | ||
| "mixing declarations with different number " | ||
|
|
@@ -870,7 +890,8 @@ def merge_subobj_defs(def1, def2, parent): | |
| merged_arrayinfo.append((idxvar1, len1)) | ||
|
|
||
|
|
||
| return (objtype, name, merged_arrayinfo, obj_specs1 + obj_specs2) | ||
| return (objtype, name, merged_arrayinfo, extension_status1, | ||
| obj_specs1 + obj_specs2) | ||
|
|
||
| def method_is_std(node, methname): | ||
| """ | ||
|
|
@@ -1708,13 +1729,14 @@ def mkobj2(obj, obj_specs, params, each_stmts): | |
|
|
||
| for (stmts, obj_spec) in composite_subobjs: | ||
| for s in stmts: | ||
| (objtype, ident, arrayinfo, subobj_spec) = s | ||
| (objtype, ident, arrayinfo, is_extension, subobj_spec) = s | ||
|
|
||
| if ident is None: | ||
| assert (dml.globals.dml_version == (1, 2) | ||
| and objtype in {'bank', 'field'}) | ||
|
|
||
| subobj_def = (objtype, ident, arrayinfo, [subobj_spec]) | ||
| subobj_def = (objtype, ident, arrayinfo, is_extension, | ||
| [subobj_spec]) | ||
| if ident in subobj_defs: | ||
| subobj_defs[ident] = merge_subobj_defs(subobj_defs[ident], | ||
| subobj_def, obj) | ||
|
|
@@ -1724,7 +1746,10 @@ def mkobj2(obj, obj_specs, params, each_stmts): | |
| symbols[ident] = subobj_spec.site | ||
| subobj_defs[ident] = subobj_def | ||
|
|
||
| for (_, _, arrayinfo, specs) in subobj_defs.values(): | ||
| for (_, ident, arrayinfo, extension_status, specs) in subobj_defs.values(): | ||
| if extension_status is True: | ||
| for spec in specs: | ||
| report(EEXTENSION(spec.site, ident)) | ||
| for (i, (idx, dimsize_ast)) in enumerate(arrayinfo): | ||
| if dimsize_ast is None: | ||
| idxref = (f" (with index variable '{idx.args[0]}')" | ||
|
|
@@ -1814,7 +1839,7 @@ def mkobj2(obj, obj_specs, params, each_stmts): | |
| # the whole register. | ||
| if obj.objtype == 'register' and not any( | ||
| objtype == 'field' | ||
| for (objtype, _, _, _) in list(subobj_defs.values())): | ||
| for (objtype, _, _, _, _) in list(subobj_defs.values())): | ||
| # The implicit field instantiates the built-in field | ||
| # template and does nothing else. | ||
| subobjs.append(mkobj( | ||
|
|
@@ -1856,7 +1881,7 @@ def mkobj2(obj, obj_specs, params, each_stmts): | |
| subobj_name_defs = {} | ||
|
|
||
| for name in sorted(subobj_defs, key=lambda name: name or ''): | ||
| (objtype, ident, arrayinfo, subobj_specs) = subobj_defs[name] | ||
| (objtype, ident, arrayinfo, _, subobj_specs) = subobj_defs[name] | ||
| if (not obj.accepts_child_type(objtype) | ||
| # HACK: disallow non-toplevel banks in DML 1.2, see SIMICS-19009 | ||
| or (dml.globals.dml_version == (1, 2) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /* | ||
| © 2025 Intel Corporation | ||
| SPDX-License-Identifier: MPL-2.0 | ||
| */ | ||
|
|
||
| dml 1.4; | ||
|
|
||
| provisional explicit_object_extensions; | ||
|
|
||
| device test; | ||
|
|
||
| import "explicit_object_extensions_disabled.dml"; | ||
|
|
||
| template t { | ||
| group g1 { | ||
| group child; | ||
| } | ||
| in group g2 { | ||
| group child; | ||
| } | ||
| } | ||
|
|
||
| template u { | ||
| in group g1 { | ||
| in group child { | ||
| session int dummy; | ||
| } | ||
| } | ||
| group g2 { | ||
| in group child { | ||
| session int dummy; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| group common_1; | ||
| in group common_2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we really want to allow
in register x size 4 @ 4711 { }? all the special syntax is a clear declaration marker to me.I suggest
in KIND NAME [INDICES] { ... }as the only allowed form, analogous to the grammar forin each xyz { ... }BTW: should we forbid the
[_ < ...]index forms outside extensions when the provisional is active?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reference this in the JIRA issue. I intentionally made this feature as consistent as possible, and the questions of what we should or should not allow a separate issue -- because the answers are not obvious, (in particular, although I previously agreed with forbidding
[_ < ...]as a decl, upon reevaluation it's less obvious to me that such a decl would be nonsensical.)In other words: i don't care when it comes to this PR. To answer these questions, we need deeper discussion and analysis, and this PR has no need for that since this is an unstable provisional. Besides, the consistent design is a virtue in its own right, and answers about it vs. any ad-hoc restrictions we make could perhaps be enlightened by Gustav's use of it.