diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c813f88b5..319c83a7a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -251,3 +251,11 @@ like before. - `release 7 7134` - `release 6 6449` +- `note 6` DMLC no longer emits warnings saying + `top-level '#if' body with unsupported statements`. These warnings were + often triggered in common code, causing excessive polution in build logs unless `--no-warn=WEXPERIMENTAL` was passed to DMLC. + The same rules as before apply to `#if` statements: Statements such as + `param` and `template` are forbidden inside `#if`, but a special exception + allows forbidden statements to appear specifically inside an `#if (dml_1_2)` + block. The warning message was meant to highlight this irregularity, but + caused more harm than good; error messages surrounding the special case have been improved instead. diff --git a/doc/1.4/language.md b/doc/1.4/language.md index fb4ac5034..2b7a2528c 100644 --- a/doc/1.4/language.md +++ b/doc/1.4/language.md @@ -2488,8 +2488,8 @@ The *object declarations* are any number of declarations of objects, session variables, saved variables, methods, `in each` statements, or other `#if` statements, but not parameters or `is` statements. When the conditional is `true` (or if it's the else branch of a false conditional), the object -declarations are treated as if they had appeared without any surrounding *#if*. -So the two following declarations are equivalent: +declarations are treated as if they had appeared without any surrounding `#if`. +Thus, the two following snippets are equivalent: ``` #if (true) { @@ -2499,12 +2499,36 @@ So the two following declarations are equivalent: } ``` -is equivalent to - ``` register R size 4; ``` +As a special exception, an `#if` statement that appears on top level is allowed +to contain any type of statement, as long as the condition doesn't reference +any identifiers other than `dml_1_2`, `true` and `false`. +This is often useful while migrating the devices of a system from DML 1.2 +to DML 1.4, as it allows conditional definitions of templates in common +code used from both DML 1.2 and DML 1.4. +For example, let's say an existing template `reset_to_seven` +is used in DML 1.2 code to set the reset value of a field to 7 in DML 1.2. +The parameters that control reset values have changed from DML 1.2 to DML 1.4, +and one way to handle this is to provide separate template definitions +depending on whether the device uses DML 1.2 or DML 1.4: +``` +#if (dml_1_2) { + template seven is field { + param hard_reset_value = 7; + param soft_reset_value = 7; + } +} #else { + template seven is field { + param init_val = 7; + } +} +``` +Later, when all related devices have been ported to DML 1.4, +the `dml_1_2` clause can be removed. + ## In Each Declarations In Each declarations are a convenient mechanism to apply a diff --git a/py/dml/dmlparse.py b/py/dml/dmlparse.py index 70a966252..ac19524ed 100644 --- a/py/dml/dmlparse.py +++ b/py/dml/dmlparse.py @@ -272,12 +272,12 @@ def toplevel_param(t): def toplevel_if(t): '''toplevel_if : hashif LPAREN expression RPAREN \ LBRACE device_statements RBRACE toplevel_else''' - if all(stmt.kind in allowed_in_hashif for stmt in t[6] + t[8]): - t[0] = ast.hashif(site(t), t[3], t[6], t[8]) + bad_stmts = [stmt for stmt in t[6] + t[8] + if stmt.kind not in allowed_in_hashif] + if bad_stmts: + t[0] = ast.toplevel_if(site(t), t[3], t[6], t[8], bad_stmts) else: - report(WEXPERIMENTAL(site(t), ("top-level 'if' body with unsupported " - + "statements"))) - t[0] = ast.toplevel_if(site(t), t[3], t[6], t[8]) + t[0] = ast.hashif(site(t), t[3], t[6], t[8]) @prod_dml14 def toplevel_else_no(t): @@ -1023,12 +1023,9 @@ def validate_if_body(stmts): for stmt in stmts: if stmt.kind in allowed_in_hashif: result.append(stmt) - elif stmt.kind == 'param': - report(ECONDP(stmt.site)) - elif stmt.kind == 'is': - report(ECONDT(stmt.site)) else: - raise ICE(stmt.site, 'unknown kind %r' % (stmt.kind,)) + assert stmt.kind in {'param', 'is'} + report(EBADCONDSTMT(stmt.site, stmt.kind)) return result @prod_dml12 diff --git a/py/dml/messages.py b/py/dml/messages.py index 1ab6200bb..ff980a3c5 100644 --- a/py/dml/messages.py +++ b/py/dml/messages.py @@ -810,19 +810,17 @@ class EUNINITIALIZED(DMLError): """ fmt = "value of parameter %s is not yet initialized" -class ECONDP(DMLError): +class EBADCONDSTMT(DMLError): """ - It is not permitted to declare a parameter directly inside an - `if` conditional. - """ - fmt = "conditional parameters are not allowed" + `#if` statements in object scope are only allowed to contain + certain kinds of declarations: objects, `method`, `session`, + `saved`, `#if`, `in each`, or `error`. -class ECONDT(DMLError): - """ - It is not permitted to use a template directly inside an - `if` conditional. + A special exception is that a `#if` on top scope may contain any + kind of statement as long as the `#if` condition doesn't reference + any identifiers other than `dml_1_2`, `true`, and `false`. """ - fmt = "conditional templates are not allowed" + fmt = "'%s' declaration not allowed inside `#if`" # TODO: Consider re-wording the semantics of this error, allocate_type is only # relevant in 1.4 when imported from 1.2, and as per SIMICS-9393 this diff --git a/py/dml/toplevel.py b/py/dml/toplevel.py index 775596b8c..526d6cefa 100644 --- a/py/dml/toplevel.py +++ b/py/dml/toplevel.py @@ -148,25 +148,29 @@ def scan_statements(filename, site, stmts): [text] = s.args footers.append(ctree.mkCText(s.site, text)) elif s.kind == 'toplevel_if': - [cond, tbranch, fbranch] = s.args + [cond, tbranch, fbranch, bad_stmts] = s.args scope = symtab.Symtab() bsite = SimpleSite('', dml_version=dml.globals.dml_version) # HACK Add constants to scope typically defined by dml-builtins, # which is not accessible here - def add_constant(name, expr): + constants = { + 'dml_1_2': ctree.BoolConstant( + bsite, dml.globals.dml_version == (1, 2)), + 'true': ctree.BoolConstant(bsite, True), + 'false': ctree.BoolConstant(bsite, False), + } + for (name, expr) in constants.items(): scope.add(ctree.ExpressionSymbol(name, expr, bsite)) - add_constant( - 'dml_1_2', - ctree.BoolConstant(bsite, dml.globals.dml_version == (1, 2))) - add_constant('true', ctree.BoolConstant(bsite, True)) - add_constant('false', ctree.BoolConstant(bsite, False)) try: expr = ctree.as_bool(codegen.codegen_expression( cond, None, scope)) if not expr.constant: raise ENCONST(expr.site, expr) + except EIDENT: + for stmt in bad_stmts: + report(EBADCONDSTMT(stmt.site, stmt.kind)) except DMLError as e: report(e) else: diff --git a/test/1.2/errors/T_ECONDP.dml b/test/1.2/errors/T_ECONDP.dml deleted file mode 100644 index ca951bbd9..000000000 --- a/test/1.2/errors/T_ECONDP.dml +++ /dev/null @@ -1,12 +0,0 @@ -/* - © 2021 Intel Corporation - SPDX-License-Identifier: MPL-2.0 -*/ -dml 1.2; -device test; -import "testing.dml"; - -if (true) { - /// ERROR ECONDP - parameter foo = 1; -} diff --git a/test/1.2/errors/T_ECONDT.dml b/test/1.2/errors/T_ECONDT.dml deleted file mode 100644 index f4a84a29c..000000000 --- a/test/1.2/errors/T_ECONDT.dml +++ /dev/null @@ -1,19 +0,0 @@ -/* - © 2021 Intel Corporation - SPDX-License-Identifier: MPL-2.0 -*/ -dml 1.2; -device test; -import "testing.dml"; - -template t { - method init() { - error "error"; - } -} - -parameter p = true; -if ($p) { - /// ERROR ECONDT - is t; -} diff --git a/test/1.2/misc/T_import_dml14.dml b/test/1.2/misc/T_import_dml14.dml index 93051cde6..3cb98c337 100644 --- a/test/1.2/misc/T_import_dml14.dml +++ b/test/1.2/misc/T_import_dml14.dml @@ -12,7 +12,7 @@ constant x = 0; parameter is_dml_12 = true; -/// WARNING WEXPERIMENTAL dml14.dml +/// WARNING WEXPERIMENTAL dml12-compatibility.dml /// SCAN-FOR-TAGS dml14.dml import "dml14.dml"; diff --git a/test/1.2/misc/dml14.dml b/test/1.2/misc/dml14.dml index 392cfe7a3..5011a5d87 100644 --- a/test/1.2/misc/dml14.dml +++ b/test/1.2/misc/dml14.dml @@ -401,7 +401,6 @@ bank testbank is (miss_pattern_bank, function_mapped_bank) { bank overridden_bank is (unified_hard_reset, unified_soft_reset); -/// WARNING WEXPERIMENTAL #if (dml_1_2) { import "io-memory.dml"; } #else { @@ -515,10 +514,8 @@ attribute woa is (write_only_attr) { param global_sym = 14; -/// WARNING WEXPERIMENTAL #if (!dml_1_2) { param cond = false; -/// WARNING WEXPERIMENTAL } #else #if (!dml_1_2) { error; } #else { diff --git a/test/1.4/errors/T_EBADCONDSTMT.dml b/test/1.4/errors/T_EBADCONDSTMT.dml new file mode 100644 index 000000000..1a020f32c --- /dev/null +++ b/test/1.4/errors/T_EBADCONDSTMT.dml @@ -0,0 +1,52 @@ +/* + © 2024 Intel Corporation + SPDX-License-Identifier: MPL-2.0 +*/ +dml 1.4; + +device test; + +template empty {} + +param yes = true; +#if (yes) { + /// ERROR EBADCONDSTMT + param p = 3; + /// ERROR EBADCONDSTMT + typedef int i_t; +} #else { + /// ERROR EBADCONDSTMT + template t { + } + + /// ERROR EBADCONDSTMT + extern typedef int i_t; + + /// ERROR EBADCONDSTMT + is empty; +} + +#if (true) { + // no error + param p = 3; + extern typedef int i2_t; +} +#if (false) { + // no error + is empty; + param p = 3; +} +#if (dml_1_2) { + // no error + is empty; + param p = 3; +} + +group g { + #if (true) { + /// ERROR EBADCONDSTMT + param p = 5; + // ERROR EBADCONDSTMT + is empty; + } +} diff --git a/test/1.4/structure/T_top_hashif.dml b/test/1.4/structure/T_top_hashif.dml new file mode 100644 index 000000000..72ff9e021 --- /dev/null +++ b/test/1.4/structure/T_top_hashif.dml @@ -0,0 +1,51 @@ +/* + © 2024 Intel Corporation + SPDX-License-Identifier: MPL-2.0 +*/ +dml 1.4; + +device test; + +/// COMPILE-ONLY + +#if (true) { +extern typedef int a_t; +typedef int b_t; +param p = 1; +} #else { +extern void *x; +import "nonexisting.dml"; +param p = 2; +error; +} + +#if (p != 1) { error; } + +#if (false) { +typedef void *a_t; +extern typedef void *b_t; +error; +template t { error; } +} #else { +extern int x; +import "imported.dml"; +template t { param from_t = true; } +} + +#if (!imported) { error; } + +is t; +#if (!from_t) { error; } + +#if (dml_1_2 || false) { +error; +} #else { + #if (true) { + #if (!false) { + // nested top-level #ifs are permitted + param foo = true; + } + } +} + +#if (!foo) { error; } diff --git a/test/1.4/structure/imported.dml b/test/1.4/structure/imported.dml new file mode 100644 index 000000000..638c54585 --- /dev/null +++ b/test/1.4/structure/imported.dml @@ -0,0 +1,7 @@ +/* + © 2024 Intel Corporation + SPDX-License-Identifier: MPL-2.0 +*/ +dml 1.4; + +param imported = true;