Skip to content

Commit e8b1bbf

Browse files
committed
Add compatibility feature and releasenotes
1 parent bc95e8d commit e8b1bbf

File tree

10 files changed

+122
-8
lines changed

10 files changed

+122
-8
lines changed

RELEASENOTES.docu

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,4 +1776,12 @@ extern typedef struct { } my_type_t;</pre> </add-note></build-id>
17761776
the <tt>dead_dml_methods</tt> library, which caused it to never
17771777
detect methods as dead if they occur directly after
17781778
a <tt>footer</tt> block.</add-note></build-id>
1779+
<build-id _6="next" _7="next"><add-note>Typechecking has been reworked
1780+
to be more strict, and more accurately reject type mismatch that would
1781+
result in invalid C. To avoid breakage in corners where DMLC is entirely
1782+
responsible for proper typechecking, such as uses of <tt>extern</tt>
1783+
macros or method overrides, the legacy lenient typechecking is still used
1784+
by default with Simics API version 7 or below. The strict typechecking can
1785+
be enabled by passing <tt>--no-compat=lenient_typechecking</tt> to
1786+
DMLC.</add-note></build-id>
17791787
</rn>

lib/1.2/dml-builtins.dml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ template device {
215215
parameter _compat_io_memory auto;
216216
parameter _compat_shared_logs_on_device auto;
217217
parameter _compat_suppress_WLOGMIXUP auto;
218+
parameter _compat_lenient_typechecking auto;
218219
parameter _compat_dml12_inline auto;
219220
parameter _compat_dml12_not auto;
220221
parameter _compat_dml12_goto auto;

lib/1.4/dml-builtins.dml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ template device {
561561
param _compat_io_memory auto;
562562
param _compat_shared_logs_on_device auto;
563563
param _compat_suppress_WLOGMIXUP auto;
564+
param _compat_lenient_typechecking auto;
564565
param _compat_dml12_inline auto;
565566
param _compat_dml12_not auto;
566567
param _compat_dml12_goto auto;

py/dml/compat.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,23 @@ class suppress_WLOGMIXUP(CompatFeature):
199199
last_api_version = api_6
200200

201201

202+
@feature
203+
class lenient_typechecking(CompatFeature):
204+
'''This compatibility feature makes DMLC's type checking very inexact and
205+
lenient in multiple respects when compared to GCC's type checking of the
206+
generated C.
207+
This discrepency mostly affects method overrides or uses of `extern`:d C
208+
macros, because in those scenarios DMLC can become wholly responsible for
209+
proper type checking.
210+
211+
While migrating from this feature, novel type errors due to uses of
212+
`extern`:d macros can often be resolved by changing the signature of
213+
the `extern` declaration to more accurately reflect the macro's effective
214+
type.
215+
'''
216+
short = "Make type checking inexact and lenient"
217+
last_api_version = api_7
218+
202219
@feature
203220
class dml12_inline(CompatFeature):
204221
'''When using `inline` to inline a method in a DML 1.2 device,

py/dml/structure.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -737,8 +737,13 @@ def typecheck_method_override(m1, m2, location):
737737
# TODO move to caller
738738
(_, type1) = eval_type(t1, a1.site, location, global_scope)
739739
(_, type2) = eval_type(t2, a2.site, location, global_scope)
740-
if safe_realtype_unconst(type1).cmp(
741-
safe_realtype_unconst(type2)) != 0:
740+
type1 = safe_realtype_unconst(type1)
741+
type2 = safe_realtype_unconst(type2)
742+
743+
ok = (type1.cmp_fuzzy(type2)
744+
if compat.lenient_typechecking in dml.globals.enabled_compat
745+
else type1.cmp(type2)) == 0
746+
if not ok:
742747
raise EMETH(a1.site, a2.site,
743748
f"mismatching types in input argument {n1}")
744749

@@ -747,8 +752,12 @@ def typecheck_method_override(m1, m2, location):
747752
((n1, t1), (n2, t2)) = (a1.args, a2.args)
748753
(_, type1) = eval_type(t1, a1.site, location, global_scope)
749754
(_, type2) = eval_type(t2, a2.site, location, global_scope)
750-
if safe_realtype_unconst(type1).cmp(
751-
safe_realtype_unconst(type2)) != 0:
755+
type1 = safe_realtype_unconst(type1)
756+
type2 = safe_realtype_unconst(type2)
757+
ok = (type1.cmp_fuzzy(type2)
758+
if compat.lenient_typechecking in dml.globals.enabled_compat
759+
else type1.cmp(type2)) == 0
760+
if not ok:
752761
msg = "mismatching types in return value"
753762
if len(outp1) > 1:
754763
msg += f" {i + 1}"

py/dml/traits.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import contextlib
99
import abc
1010
import os
11-
from . import objects, logging, crep, codegen, toplevel, topsort
11+
from . import objects, logging, crep, codegen, toplevel, topsort, compat
1212
from .logging import *
1313
from .codegen import *
1414
from .symtab import *
@@ -401,11 +401,21 @@ def typecheck_method_override(left, right):
401401
if throws0 != throws1:
402402
raise EMETH(site0, site1, "different nothrow annotations")
403403
for ((n, t0), (_, t1)) in zip(inp0, inp1):
404-
if safe_realtype_unconst(t0).cmp(safe_realtype_unconst(t1)) != 0:
404+
t0 = safe_realtype_unconst(t0)
405+
t1 = safe_realtype_unconst(t1)
406+
ok = (t0.cmp_fuzzy(t1)
407+
if compat.lenient_typechecking in dml.globals.enabled_compat
408+
else t0.cmp(t1)) == 0
409+
if not ok:
405410
raise EMETH(site0, site1,
406411
"mismatching types in input argument %s" % (n,))
407412
for (i, ((_, t0), (_, t1))) in enumerate(zip(outp0, outp1)):
408-
if safe_realtype_unconst(t0).cmp(safe_realtype_unconst(t1)) != 0:
413+
t0 = safe_realtype_unconst(t0)
414+
t1 = safe_realtype_unconst(t1)
415+
ok = (t0.cmp_fuzzy(t1)
416+
if compat.lenient_typechecking in dml.globals.enabled_compat
417+
else t0.cmp(t1)) == 0
418+
if not ok:
409419
raise EMETH(site0, site1,
410420
"mismatching types in output argument %d" % (i + 1,))
411421

py/dml/types.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,8 @@ def canstore(self, other):
936936
and shallow_const(other.base))
937937
if self.base.void or other.base.void:
938938
ok = True
939+
if compat.lenient_typechecking in dml.globals.enabled_compat:
940+
constviol = False
939941
else:
940942
unconst_self_base = safe_realtype_unconst(self.base)
941943
unconst_other_base = safe_realtype_unconst(other.base)
@@ -945,7 +947,8 @@ def canstore(self, other):
945947
else unconst_self_base.cmp)(unconst_other_base)
946948
== 0)
947949
elif isinstance(other, TFunction):
948-
ok = safe_realtype_unconst(self.base).cmp(other) == 0
950+
ok = (compat.lenient_typechecking in dml.globals.enabled_compat
951+
or safe_realtype_unconst(self.base).cmp(other) == 0)
949952
# TODO gate this behind dml.globals.dml_version == (1, 2) or
950953
# dml12_misc?
951954
if self.base.void and isinstance(other, TDevice):
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
© 2024 Intel Corporation
3+
SPDX-License-Identifier: MPL-2.0
4+
*/
5+
dml 1.4;
6+
7+
device test;
8+
9+
/// COMPILE-ONLY
10+
/// DMLC-FLAG --no-compat=lenient_typechecking
11+
/// SCAN-FOR-TAGS lenient_typechecking.dml
12+
import "lenient_typechecking.dml";
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
© 2024 Intel Corporation
3+
SPDX-License-Identifier: MPL-2.0
4+
*/
5+
dml 1.4;
6+
7+
device test;
8+
9+
/// COMPILE-ONLY
10+
/// DMLC-FLAG --simics-api=7
11+
import "lenient_typechecking.dml";
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
© 2024 Intel Corporation
3+
SPDX-License-Identifier: MPL-2.0
4+
*/
5+
6+
dml 1.4;
7+
8+
template t {
9+
shared method sm(const int *p) -> (const int *) default { return p; }
10+
shared method m(const int *p) -> (const int *);
11+
method n(const int *p) -> (const int *) default { return p; }
12+
}
13+
14+
template u is t {
15+
/// ERROR EMETH
16+
shared method sm(int *p) -> (int *) { return p; }
17+
}
18+
19+
group g is u {
20+
/// ERROR EMETH
21+
method m(int *p) -> (int *) { return p; }
22+
23+
/// ERROR EMETH
24+
method n(int *p) -> (int *) { return p; }
25+
}
26+
27+
header %{
28+
#define MACRO(a,b,c) ((void)0)
29+
%}
30+
31+
extern void MACRO(void *a, int *b, void (*c)(void));
32+
33+
method init() {
34+
// no error
35+
MACRO(NULL, NULL, NULL);
36+
/// ERROR ECONSTP
37+
MACRO(cast(NULL, const int *), NULL, NULL);
38+
/// ERROR ECONSTP
39+
MACRO(NULL, cast(NULL, const void *), NULL);
40+
/// ERROR EPTYPE
41+
MACRO(NULL, NULL, MACRO);
42+
}

0 commit comments

Comments
 (0)