Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions RELEASENOTES-1.4.docu
Original file line number Diff line number Diff line change
Expand Up @@ -521,4 +521,20 @@
This fix is only enabled by default with Simics API version 7 or above.
With version 6 or below it must be explicitly enabled by passing
<tt>--no-compat=shared_logs_on_device</tt> to DMLC.</add-note></build-id>
<build-id value="next"><add-note> Added the <em>discard reference</em>
'<tt>_</tt>' &mdash; a non-value expression which may be used as an assign
target in order to explictly discard the result of an evaluated expression
or return value of a method call <bug number="SIMICS-21584"/>.
Example usage:
<pre>
_ = any_expression;
_ = throwing_method();
(_, x, _) = method_with_multiple_return_values();
</pre>
For backwards compatibility, declared variables and object members are
still allowed to be named '<tt>_</tt>' with Simics API version 6 or below.
Any such declaration will <em>shadow</em> the discard reference &mdash;
i.e. make it unavailable within the scope that the declaration is
accessible. This compatibility feature can be disabled by passing
<tt>--no-compat=discard_ref_shadowing</tt> to DMLC.</add-note></build-id>
</rn>
27 changes: 27 additions & 0 deletions doc/1.4/language.md
Original file line number Diff line number Diff line change
Expand Up @@ -3808,6 +3808,33 @@ independent method callback(int i, void *aux) {
}
```

### The Discard Reference (`_`)
```
_
```

The discard reference *`_`* is an expression without any run-time representation
that may be used as the target of an assignment in order to explicitly discard
the result of an evaluated expression or return value of a method call.

When the compatibility feature `discard_ref_shadowing` is enabled, `_` is not a
keyword, but instead behaves more closely as a global identifier.
What this means is that declared identifiers (e.g. local variables) are allowed
to shadow it by being named `_`.

Example usage:
```
// Evaluate an expression and explicitly discard its result.
// Can be relevant to e.g. suppress Coverity's CHECKED_RETURN checker
_ = nonthrowing_single_return_method();

// Calls to methods that throw or have multiple return values require a target
// for each return value. `_` can be used to discard return values not of
// interest.
_ = throwing_method();
(_, x, _) = method_with_multiple_return_values();
```

### New Expressions

<pre>
Expand Down
3 changes: 2 additions & 1 deletion grammar_to_md.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@
'BCONST' : '<i>binary-literal</i>',
'FCONST' : '<i>float-literal</i>',
'ELLIPSIS' : '<i>"..."</i>',
'<empty>' : '&lt;empty&gt;'
'<empty>' : '&lt;empty&gt;',
'_' : '<b>_</b>'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the token be named DISCARDREF.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disagree weakly. Other keyword-formed tokens are named as the keyword.

}

for k in (reserved_idents
Expand Down
1 change: 1 addition & 0 deletions lib/1.2/dml-builtins.dml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ template device {
parameter _compat_port_obj_param auto;
parameter _compat_io_memory auto;
parameter _compat_shared_logs_on_device auto;
parameter _compat_discard_ref_shadowing auto;
parameter _compat_dml12_inline auto;
parameter _compat_dml12_not auto;
parameter _compat_dml12_goto auto;
Expand Down
3 changes: 2 additions & 1 deletion lib/1.4/dml-builtins.dml
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ template device {
param _compat_port_obj_param auto;
param _compat_io_memory auto;
param _compat_shared_logs_on_device auto;
param _compat_discard_ref_shadowing auto;
param _compat_dml12_inline auto;
param _compat_dml12_not auto;
param _compat_dml12_goto auto;
Expand Down Expand Up @@ -1848,7 +1849,7 @@ template bank is (object, shown_desc) {
}

shared method _num_registers() -> (uint32) {
local (const register *_, uint64 table_size) = _reginfo_table();
local (const register *_table, uint64 table_size) = _reginfo_table();
return table_size;
}

Expand Down
62 changes: 27 additions & 35 deletions py/dml/c_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@ def generate_init_data_objs(device):
start_function_definition(
'void _init_data_objs(%s *_dev)' % (crep.structtype(device),))
out('{\n', postindent = 1)
with crep.DeviceInstanceContext():
with crep.DeviceInstanceContext(), allow_linemarks():
for node in device.initdata:
# Usually, the initializer is constant, but we permit that it
# depends on index. When the initializer is constant, we use a loop
Expand All @@ -1859,37 +1859,39 @@ def generate_init_data_objs(device):
# mainly meant to capture EIDXVAR; for other errors, the error will
# normally re-appear when evaluating per instance
except DMLError:
with allow_linemarks():
for indices in node.all_indices():
index_exprs = tuple(mkIntegerLiteral(node.site, i)
for i in indices)
nref = mkNodeRef(node.site, node, index_exprs)
try:
init = eval_initializer(
node.site, node._type, node.astinit,
Location(node.parent, index_exprs),
global_scope, True)
except DMLError as e:
report(e)
else:
markers = ([('store_writes_const_field', 'FALSE')]
if deep_const(node._type) else [])
coverity_markers(markers, init.site)
init.assign_to(nref, node._type)
for indices in node.all_indices():
index_exprs = tuple(mkIntegerLiteral(node.site, i)
for i in indices)
nref = mkNodeRef(node.site, node, index_exprs)
try:
init = eval_initializer(
node.site, node._type, node.astinit,
Location(node.parent, index_exprs),
global_scope, True)
except DMLError as e:
report(e)
else:
markers = ([('store_writes_const_field', 'FALSE')]
if deep_const(node._type) else [])
coverity_markers(markers, init.site)
out(init.assign_to(nref.read(), node._type) + ';\n')
else:
index_exprs = ()
if node.dimensions:
reset_line_directive()
for (i, sz) in enumerate(node.dimsizes):
var = 'i%d' % (i,)
out(('for (int %s = 0; %s < %s; ++%s) {\n'
% (var, var, sz, var)),
postindent=1)
index_exprs += (mkLit(node.site, var, TInt(64, True)),)
nref = mkNodeRef(node.site, node, index_exprs)
with allow_linemarks():
markers = ([('store_writes_const_field', 'FALSE')]
if deep_const(node._type) else [])
coverity_markers(markers, init.site)
init.assign_to(nref, node._type)
markers = ([('store_writes_const_field', 'FALSE')]
if deep_const(node._type) else [])
coverity_markers(markers, init.site)
out(init.assign_to(nref.read(), node._type) + ';\n')
if node.dimensions:
reset_line_directive()
for _ in range(node.dimensions):
out('}\n', postindent=-1)
out('}\n\n', preindent = -1)
Expand Down Expand Up @@ -3120,12 +3122,7 @@ def generate_startup_trait_calls(data, idxvars):
ref = ObjTraitRef(site, node, trait, indices)
out(f'_tref = {ref.read()};\n')
for method in trait_methods:
outargs = [mkLit(method.site,
('*((%s) {0})'
% ((TArray(t, mkIntegerLiteral(method.site, 1))
.declaration('')),)),
t)
for (_, t) in method.outp]
outargs = [mkDiscardRef(method.site) for _ in method.outp]

method_ref = TraitMethodDirect(
method.site, mkLit(method.site, '_tref', TTrait(trait)), method)
Expand All @@ -3137,12 +3134,7 @@ def generate_startup_trait_calls(data, idxvars):
def generate_startup_regular_call(method, idxvars):
site = method.site
indices = tuple(mkLit(site, idx, TInt(32, False)) for idx in idxvars)
outargs = [mkLit(site,
('*((%s) {0})'
% ((TArray(t, mkIntegerLiteral(site, 1))
.declaration('')),)),
t)
for (_, t) in method.outp]
outargs = [mkDiscardRef(method.site) for _ in method.outp]
# startup memoized methods can throw, which is ignored during startup.
# Memoization of the throw then allows for the user to check whether
# or not the method did throw during startup by calling the method
Expand Down
Loading