Skip to content

Commit 402e495

Browse files
committed
Make bitfields compatible only with identically specified bitfields
1 parent 20150c0 commit 402e495

File tree

4 files changed

+83
-38
lines changed

4 files changed

+83
-38
lines changed

py/dml/types.py

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
from . import output
6464
import dml .globals
6565
import abc
66+
import zlib
6667

6768
class DMLTypeError(Exception): pass
6869

@@ -510,6 +511,27 @@ def __init__(self, bits, signed, members = None, const = False):
510511
def is_bitfields(self):
511512
return self.members is not None
512513

514+
def describe_backing_type(self):
515+
raise Exception("%s.describe_backing_type not implemented"
516+
% (self.__class__.__name__,))
517+
518+
def describe(self):
519+
return (f'bitfields (backing type: {self.describe_backing_type()})'
520+
if self.is_bitfields else self.describe_backing_type())
521+
522+
def key(self):
523+
if not self.is_bitfields:
524+
return DMLType.key(self)
525+
526+
backing = self.describe_backing_type()
527+
528+
# using adler32 as a quick, dirty, short, implementation-consistent
529+
# hash that doesn't pull in any dependencies
530+
hsh = zlib.adler32(';'.join(
531+
f'{name}:{t.key()}@{msb}-{lsb}'
532+
for (name, (t, msb, lsb)) in self.members.items()).encode('utf-8'))
533+
return f'{self.const_str}bitfields({backing}, {hsh})'
534+
513535
@property
514536
def bytes(self):
515537
return (self.bits - 1) // 8 + 1
@@ -543,8 +565,29 @@ def cmp(self, other):
543565
return NotImplemented
544566
elif other.is_endian:
545567
return NotImplemented
546-
return (0 if (self.bits, self.signed) == (other.bits, other.signed)
547-
else NotImplemented)
568+
if (self.bits, self.signed) != (other.bits, other.signed):
569+
return NotImplemented
570+
if self.members is not other.members:
571+
if self.members is None or other.members is None:
572+
return NotImplemented
573+
574+
# Slow path, when the two bitfields types have different origins
575+
576+
# The specifications have to be completely equivalent.
577+
# We don't normalize reps via any sorting, as the order matters for
578+
# compound initializers; we are not lenient on names, as that
579+
# affects mkSubRef and designated initializers; we are not lenient
580+
# on types because they SHOULD affect mkSubRef even though they
581+
# don't today (see SIMICS-8857 and SIMICS-18394)
582+
if (len(self.members) != len(other.members)
583+
or any((name0, msb0, lsb0) != (name1, msb1, lsb1)
584+
or t0.cmp(t1) != 0
585+
for ((name0, (t0, msb0, lsb0)),
586+
(name1, (t1, msb1, lsb1)))
587+
in zip(self.members.items(), other.members.items()))):
588+
return NotImplemented
589+
590+
return 0
548591

549592
def cmp_fuzzy(self, other):
550593
if not other.is_int:
@@ -570,7 +613,11 @@ def cmp_fuzzy(self, other):
570613
def hashed(self):
571614
cls = type(self) if self.is_arch_dependent else IntegerType
572615
byte_order = self.byte_order if self.is_endian else None
573-
return hash((cls, self.const, self.bits, self.signed, byte_order))
616+
members = (tuple((name, typ.hashed(), lsb, msb)
617+
for (name, (typ, lsb, msb)) in self.members.items())
618+
if self.is_bitfields else None)
619+
return hash((cls, self.const, self.bits, self.signed, members,
620+
byte_order))
574621

575622
# This is the most restrictive canstore definition for
576623
# IntegerTypes, if this is overridden then it should be
@@ -600,12 +647,8 @@ class TInt(IntegerType):
600647
def __init__(self, bits, signed, members = None, const = False):
601648
IntegerType.__init__(self, bits, signed, members, const)
602649

603-
def describe(self):
604-
s = 'int%d' % self.bits
605-
if self.signed:
606-
return s
607-
else:
608-
return 'u' + s
650+
def describe_backing_type(self):
651+
return f'{"u"*(not self.signed)}int{self.bits}'
609652
def __repr__(self):
610653
return 'TInt(%r,%r,%r,%r)' % (self.bits, self.signed,
611654
self.members, self.const)
@@ -671,7 +714,7 @@ def __init__(self, signed, const=False):
671714
def c_name(self):
672715
return self.const_str + ('long' if self.signed else 'unsigned long')
673716

674-
def describe(self):
717+
def describe_backing_type(self):
675718
return self.c_name()
676719

677720
def __repr__(self):
@@ -692,7 +735,7 @@ def __init__(self, signed, const=False):
692735
def c_name(self):
693736
return self.const_str + ('ssize_t' if self.signed else 'size_t')
694737

695-
def describe(self):
738+
def describe_backing_type(self):
696739
return self.c_name()
697740

698741
def __repr__(self):
@@ -719,7 +762,7 @@ def c_name(self):
719762
name = 'int64_t' if self.signed else 'uint64_t'
720763
return f'const {name}' if self.const else name
721764

722-
def describe(self):
765+
def describe_backing_type(self):
723766
return self.c_name()
724767

725768
def __repr__(self):
@@ -755,7 +798,7 @@ def c_name(self):
755798
self.const_str, "" if self.signed else "u", self.bits,
756799
"be" if self.big_endian else "le")
757800

758-
def describe(self):
801+
def describe_backing_type(self):
759802
return self.c_name()
760803

761804
def __repr__(self):

test/1.4/hooks/T_basic.dml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ template hookset_test is hookset {
3636
assert h0.suspended == 0 && resumed == 2 && count == 2 && storage == 7;
3737
count = storage = 0;
3838

39-
local int i = 5;
39+
local bf_t i = 5;
4040
after h1 -> p: one_param(p);
4141
assert h1.suspended == 1 && i == 5;
4242
resumed = h1.send_now(&i);
4343
assert h1.suspended == 0 && resumed == 1 && i == 6;
44-
after h1 -> p: one_serializable_param(-5);
44+
after h1 -> p: one_serializable_param(11);
4545
assert h1.suspended == 1 && storage == 0 && i == 6;
4646
resumed = h1.send_now(&i);
47-
assert h1.suspended == 0 && resumed == 1 && storage == -5 && i == 6;
47+
assert h1.suspended == 0 && resumed == 1 && storage == 11 && i == 6;
4848
storage = i = 0;
4949

5050
after h2 -> (p, i): two_params(p, i);
@@ -85,11 +85,11 @@ template hookset_test is hookset {
8585
resumed = h1.send_now(&i);
8686
assert h1.suspended == 0 && resumed == 1 && i == 3 * 7 + 5;
8787
i = 0;
88-
after h1 -> p: indexed[3][5].one_serializable_param(-5);
88+
after h1 -> p: indexed[3][5].one_serializable_param(11);
8989
assert h1.suspended == 1 && storage_indexed == 0 && i == 0;
9090
resumed = h1.send_now(&i);
9191
assert h1.suspended == 0 && resumed == 1
92-
&& storage_indexed == -5 * (3 * 7 + 5) && i == 0;
92+
&& storage_indexed == 11 * (3 * 7 + 5) && i == 0;
9393
storage_indexed = 0;
9494

9595
after h2 -> (p, i): indexed[3][5].two_params(p, i);

test/1.4/hooks/T_checkpointing.dml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ attribute test_state is write_only_attr {
6363
count = storage = storage_indexed = 0;
6464
last_i_indexed = last_j_indexed = -1;
6565

66-
local int x = 4;
66+
local bf_t x = 4;
6767
resumed = obj.h1.send_now(&x);
6868
assert resumed == 2 && x == 5 && storage == 9;
6969
storage = 0;

test/1.4/hooks/common.dml

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,50 @@
44
*/
55
dml 1.4;
66

7-
session int count;
7+
typedef bitfields 16 { uint6 a @[12:7]; } bf_t;
8+
9+
session bf_t count;
810
method no_params() {
911
++count;
1012
}
11-
method one_param(int *x) {
13+
method one_param(bf_t *x) {
1214
++*x;
1315
}
14-
method two_params(int *x, int i) {
16+
method two_params(bf_t *x, bf_t i) {
1517
*x = i;
1618
}
17-
session int storage;
18-
method one_serializable_param(int i) {
19+
session bf_t storage;
20+
method one_serializable_param(bf_t i) {
1921
storage = i;
2022
}
2123

22-
session int storage_indexed;
24+
session bf_t storage_indexed;
2325
session (int last_i_indexed, int last_j_indexed) = (-1, -1);
2426
group indexed[i < 5][j < 7] {
2527
method no_params() {
2628
(last_i_indexed, last_j_indexed) = (i, j);
2729
}
28-
method one_param(int *x) {
30+
method one_param(bf_t *x) {
2931
*x = i*7 + j;
3032
}
31-
method two_params(int *x, int coeff) {
33+
method two_params(bf_t *x, bf_t coeff) {
3234
*x = coeff * (i*7 + j);
3335
}
34-
method one_serializable_param(int coeff) {
36+
method one_serializable_param(bf_t coeff) {
3537
storage_indexed = coeff * (i*7 + j);
3638
}
3739
}
3840

3941
template hookset {
4042
hook() _h0;
41-
hook(int *) _h1;
42-
hook(int *, int) _h2;
43+
hook(bf_t *) _h1;
44+
hook(bf_t *, bf_t) _h2;
4345

4446
hook() _h3[6][8];
45-
hook(int *) _h4[6][8];
46-
hook(int *, int) _h5[6][8];
47+
hook(bf_t *) _h4[6][8];
48+
hook(bf_t *, bf_t) _h5[6][8];
4749

48-
hook(int) _h6;
50+
hook(bf_t) _h6;
4951

5052
param h0 default _h0;
5153
param h1 default _h1;
@@ -73,24 +75,24 @@ method enforce_h0_ref(hook() h) -> (hook()) {
7375
return h;
7476
}
7577

76-
method enforce_h1_ref(hook(int *) h) -> (hook(int *)) {
78+
method enforce_h1_ref(hook(bf_t *) h) -> (hook(bf_t *)) {
7779
return h;
7880
}
7981

80-
method enforce_h2_ref(hook(int *, int) h) -> (hook(int *, int)) {
82+
method enforce_h2_ref(hook(bf_t *, bf_t) h) -> (hook(bf_t *, bf_t)) {
8183
return h;
8284
}
8385

84-
method enforce_h6_ref(hook(int) h) -> (hook(int)) {
86+
method enforce_h6_ref(hook(bf_t) h) -> (hook(bf_t)) {
8587
return h;
8688
}
8789

8890
group via_hookref is hookset_set {
8991
in each hookset {
9092
is init;
9193
session hook() h3_arr[6][8];
92-
session hook(int *) h4_arr[6][8];
93-
session hook(int *, int) h5_arr[6][8];
94+
session hook(bf_t *) h4_arr[6][8];
95+
session hook(bf_t *, bf_t) h5_arr[6][8];
9496
method init() {
9597
for (local int idx_0 = 0; idx_0 < 6; ++idx_0) {
9698
for (local int idx_1 = 0; idx_1 < 8; ++idx_1) {

0 commit comments

Comments
 (0)