Skip to content

Commit 8551d9e

Browse files
committed
Merge remote-tracking branch 'origin/master' into release
2 parents a058e00 + 3363f4e commit 8551d9e

File tree

5 files changed

+288
-28
lines changed

5 files changed

+288
-28
lines changed

kmir/src/kmir/kdist/mir-semantics/rt/data.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,12 +2075,18 @@ Since our arithmetic operations signal undefined behaviour on overflow independe
20752075

20762076
#### "Nullary" operations reifying type information
20772077

2078-
`nullOpSizeOf`
2079-
`nullOpAlignOf`
2080-
`nullOpOffsetOf(VariantAndFieldIndices)`
2078+
Operation `nullOpSizeOf` returns the size in bytes of a data structure or primitive type, as a `usize`.
2079+
Operation `nullOpAlignOf` returns the required alignment of a data structure or primitive type, as a `usize`.
2080+
This information is read from the layout in the `TypeInfo` if available, or a fixed constant for primitive types.
20812081

20822082
```k
20832083
// FIXME: 64 is hardcoded since usize not supported
2084+
rule <k> rvalueNullaryOp(nullOpSizeOf, TY)
2085+
=>
2086+
Integer(#sizeOf(lookupTy(TY)), 64, false)
2087+
...
2088+
</k>
2089+
requires lookupTy(TY) =/=K typeInfoVoidType
20842090
rule <k> rvalueNullaryOp(nullOpAlignOf, TY)
20852091
=>
20862092
Integer(#alignOf(lookupTy(TY)), 64, false)
@@ -2089,6 +2095,8 @@ rule <k> rvalueNullaryOp(nullOpAlignOf, TY)
20892095
requires lookupTy(TY) =/=K typeInfoVoidType
20902096
```
20912097

2098+
`nullOpOffsetOf(VariantAndFieldIndices)`
2099+
20922100
#### Other operations
20932101

20942102
The unary operation `unOpPtrMetadata`, when given a reference or pointer to a slice, will return the reference or pointer metadata.

kmir/src/kmir/kdist/mir-semantics/rt/numbers.md

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -147,31 +147,6 @@ This truncation function is instrumental in the implementation of Integer arithm
147147
[preserves-definedness]
148148
```
149149

150-
## Alignment of Primitives
151-
152-
```k
153-
// FIXME: Alignment is platform specific
154-
syntax Int ::= #alignOf( TypeInfo ) [function]
155-
rule #alignOf( typeInfoPrimitiveType(primTypeBool) ) => 1
156-
rule #alignOf( typeInfoPrimitiveType(primTypeChar) ) => 4
157-
rule #alignOf( typeInfoPrimitiveType(primTypeInt(intTyIsize)) ) => 8 // FIXME: Hard coded since usize not implemented
158-
rule #alignOf( typeInfoPrimitiveType(primTypeInt(intTyI8)) ) => 1
159-
rule #alignOf( typeInfoPrimitiveType(primTypeInt(intTyI16)) ) => 2
160-
rule #alignOf( typeInfoPrimitiveType(primTypeInt(intTyI32)) ) => 4
161-
rule #alignOf( typeInfoPrimitiveType(primTypeInt(intTyI64)) ) => 8
162-
rule #alignOf( typeInfoPrimitiveType(primTypeInt(intTyI128)) ) => 16
163-
rule #alignOf( typeInfoPrimitiveType(primTypeUint(uintTyUsize)) ) => 8 // FIXME: Hard coded since usize not implemented
164-
rule #alignOf( typeInfoPrimitiveType(primTypeUint(uintTyU8)) ) => 1
165-
rule #alignOf( typeInfoPrimitiveType(primTypeUint(uintTyU16)) ) => 2
166-
rule #alignOf( typeInfoPrimitiveType(primTypeUint(uintTyU32)) ) => 4
167-
rule #alignOf( typeInfoPrimitiveType(primTypeUint(uintTyU64)) ) => 8
168-
rule #alignOf( typeInfoPrimitiveType(primTypeUint(uintTyU128)) ) => 16
169-
rule #alignOf( typeInfoPrimitiveType(primTypeFloat(floatTyF16)) ) => 2
170-
rule #alignOf( typeInfoPrimitiveType(primTypeFloat(floatTyF32)) ) => 4
171-
rule #alignOf( typeInfoPrimitiveType(primTypeFloat(floatTyF64)) ) => 8
172-
rule #alignOf( typeInfoPrimitiveType(primTypeFloat(floatTyF128)) ) => 16
173-
```
174-
175150
```k
176151
endmodule
177152
```

kmir/src/kmir/kdist/mir-semantics/rt/types.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,69 @@ Slices, `str`s and dynamic types require it, and any `Ty` that `is_sized` does
203203
rule #zeroSizedType(_) => false [owise]
204204
```
205205

206+
## Alignment and Size of Types as per `TypeInfo`
207+
208+
The `alignOf` and `sizeOf` nullary operations return the alignment / size in bytes as a `usize`.
209+
This information is either hard-wired for primitive types (numbers, first and foremost), or read from the layout in `TypeInfo`.
210+
211+
```k
212+
syntax Int ::= #sizeOf ( TypeInfo ) [function, total]
213+
| #alignOf ( TypeInfo ) [function, total]
214+
215+
// primitive int types: use bit width (both for size and alignment)
216+
rule #sizeOf(typeInfoPrimitiveType(primTypeInt(NUMTY))) => #bitWidth(NUMTY) /Int 8 [preserves-definedness]
217+
rule #alignOf(typeInfoPrimitiveType(primTypeInt(NUMTY))) => #bitWidth(NUMTY) /Int 8 [preserves-definedness]
218+
rule #sizeOf(typeInfoPrimitiveType(primTypeUint(NUMTY))) => #bitWidth(NUMTY) /Int 8 [preserves-definedness]
219+
rule #alignOf(typeInfoPrimitiveType(primTypeUint(NUMTY))) => #bitWidth(NUMTY) /Int 8 [preserves-definedness]
220+
rule #sizeOf(typeInfoPrimitiveType(primTypeFloat(NUMTY))) => #bitWidth(NUMTY) /Int 8 [preserves-definedness]
221+
rule #alignOf(typeInfoPrimitiveType(primTypeFloat(NUMTY))) => #bitWidth(NUMTY) /Int 8 [preserves-definedness]
222+
// bool and char
223+
rule #sizeOf(typeInfoPrimitiveType(primTypeBool)) => 1
224+
rule #alignOf(typeInfoPrimitiveType(primTypeBool)) => 1
225+
rule #sizeOf(typeInfoPrimitiveType(primTypeChar)) => 4
226+
rule #alignOf(typeInfoPrimitiveType(primTypeChar)) => 4
227+
// The str primitive has alignment of a Char but size 0 (indicating dynamic size)
228+
rule #sizeOf(typeInfoPrimitiveType(primTypeStr)) => 0
229+
rule #alignOf(typeInfoPrimitiveType(primTypeStr)) => 4
230+
// enums, structs , and tuples provide the values from their layout information
231+
rule #sizeOf(typeInfoEnumType(_, _, _, _, someLayoutShape(layoutShape(_, _, _, _, machineSize( BITS ))))) => BITS /Int 8 [preserves-definedness]
232+
rule #sizeOf(typeInfoEnumType(_, _, _, _, someLayoutShape(layoutShape(_, _, _, _, machineSize(mirInt(BITS)))))) => BITS /Int 8 [preserves-definedness]
233+
rule #sizeOf(typeInfoEnumType(_, _, _, _, noLayoutShape)) => 0
234+
rule #alignOf(typeInfoEnumType(_, _, _, _, someLayoutShape(layoutShape(_, _, _, align(BYTES),_)))) => BYTES
235+
rule #alignOf(typeInfoEnumType(_, _, _, _, noLayoutShape)) => 1
236+
// struct
237+
rule #sizeOf(typeInfoStructType(_, _, _, someLayoutShape(layoutShape(_, _, _, _, machineSize( BITS ))))) => BITS /Int 8 [preserves-definedness]
238+
rule #sizeOf(typeInfoStructType(_, _, _, someLayoutShape(layoutShape(_, _, _, _, machineSize(mirInt(BITS)))))) => BITS /Int 8 [preserves-definedness]
239+
rule #sizeOf(typeInfoStructType(_, _, _, noLayoutShape)) => 0
240+
rule #alignOf(typeInfoStructType(_, _, _, someLayoutShape(layoutShape(_, _, _, align(BYTES),_)))) => BYTES
241+
rule #alignOf(typeInfoStructType(_, _, _, noLayoutShape)) => 1
242+
// tuple
243+
rule #sizeOf(typeInfoTupleType(_, someLayoutShape(layoutShape(_, _, _, _, machineSize( BITS ))))) => BITS /Int 8 [preserves-definedness]
244+
rule #sizeOf(typeInfoTupleType(_, someLayoutShape(layoutShape(_, _, _, _, machineSize(mirInt(BITS)))))) => BITS /Int 8 [preserves-definedness]
245+
rule #sizeOf(typeInfoTupleType(_, noLayoutShape)) => 0
246+
rule #alignOf(typeInfoTupleType(_, someLayoutShape(layoutShape(_, _, _, align(BYTES),_)))) => BYTES
247+
rule #alignOf(typeInfoTupleType(_, noLayoutShape)) => 1
248+
// size of union types: FIXME use layout (currently not in K AST)
249+
// rule #sizeOf(typeInfoUnionType(_, _)) => FIXME
250+
// rule #alignOf(typeInfoUnionType(_, _)) => FIXME
251+
// arrays with known length have the alignment of the element type, and a size multiplying element count and element size
252+
rule #sizeOf(typeInfoArrayType(ELEM_TY, someTyConst(tyConst(KIND, _)))) => #sizeOf(lookupTy(ELEM_TY)) *Int readTyConstInt(KIND)
253+
rule #sizeOf(typeInfoArrayType( _ , noTyConst )) => 0
254+
rule #alignOf(typeInfoArrayType(ELEM_TY, _)) => #alignOf(lookupTy(ELEM_TY))
255+
// thin ptr and ref types have the size of `usize` and twice that for fat pointers/refs. Alignment is that of `usize`
256+
rule #sizeOf(typeInfoPtrType(POINTEE_TY))
257+
=> #sizeOf(typeInfoPrimitiveType(primTypeUint(uintTyUsize)))
258+
*Int (#if #metadataSize(POINTEE_TY) ==K dynamicSize(1) #then 2 #else 1 #fi)
259+
rule #sizeOf(typeInfoRefType(POINTEE_TY))
260+
=> #sizeOf(typeInfoPrimitiveType(primTypeUint(uintTyUsize)))
261+
*Int (#if #metadataSize(POINTEE_TY) ==K dynamicSize(1) #then 2 #else 1 #fi)
262+
rule #alignOf(typeInfoPtrType(_)) => #alignOf(typeInfoPrimitiveType(primTypeUint(uintTyUsize)))
263+
rule #alignOf(typeInfoRefType(_)) => #alignOf(typeInfoPrimitiveType(primTypeUint(uintTyUsize)))
264+
// other types (fun and void types) have size and alignment 0
265+
rule #sizeOf(_) => 0 [owise]
266+
rule #alignOf(_) => 0 [owise]
267+
```
268+
206269
```k
207270
endmodule
208271
```

kmir/src/kmir/testing/fixtures.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313

1414
from pytest import FixtureRequest, Parser
1515

16+
import sys
17+
18+
19+
def pytest_configure(config) -> None:
20+
sys.setrecursionlimit(1000000)
21+
1622

1723
def assert_or_update_show_output(actual_text: str, expected_file: Path, *, update: bool) -> None:
1824
if update:
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
use std::mem::{size_of, align_of};
2+
3+
4+
fn check_size_and_alignment<T>(size: usize, align: usize){
5+
let s = size_of::<T>();
6+
let a = align_of::<T>();
7+
8+
assert_eq!(s, size);
9+
assert_eq!(a, align);
10+
}
11+
12+
13+
fn main() {
14+
// // Basic integer types
15+
check_size_and_alignment::<u8>(1, 1);
16+
check_size_and_alignment::<u32>(4, 4);
17+
18+
check_size_and_alignment::<u8>(1, 1);
19+
20+
check_size_and_alignment::<i8>(1, 1);
21+
22+
check_size_and_alignment::<u16>(2, 2);
23+
24+
check_size_and_alignment::<i16>(2, 2);
25+
26+
check_size_and_alignment::<u32>(4, 4);
27+
28+
check_size_and_alignment::<i32>(4, 4);
29+
30+
check_size_and_alignment::<u64>(8, 8);
31+
32+
check_size_and_alignment::<i64>(8, 8);
33+
34+
check_size_and_alignment::<u128>(16, 16);
35+
36+
check_size_and_alignment::<i128>(16, 16);
37+
38+
// // Floating point types
39+
check_size_and_alignment::<f32>(4, 4);
40+
41+
check_size_and_alignment::<f64>(8, 8);
42+
43+
// // Other basic types
44+
check_size_and_alignment::<bool>(1, 1);
45+
46+
check_size_and_alignment::<char>(4, 4);
47+
48+
// // Pointer-sized types (64-bit)
49+
check_size_and_alignment::<usize>(8, 8);
50+
51+
check_size_and_alignment::<isize>(8, 8);
52+
53+
check_size_and_alignment::<&u32>(8, 8);
54+
55+
check_size_and_alignment::<*const u32>(8, 8);
56+
57+
check_size_and_alignment::<*mut u32>(8, 8);
58+
59+
// Fat pointers (2x pointer size on 64-bit)
60+
check_size_and_alignment::<&[u32]>(16, 8);
61+
62+
// check_size_and_alignment::<&str>(16, 8);
63+
64+
check_size_and_alignment::<&mut [u32]>(16, 8);
65+
66+
// // Arrays
67+
check_size_and_alignment::<[u8; 0]>(0, 1);
68+
69+
check_size_and_alignment::<[u8; 4]>(4, 1);
70+
71+
check_size_and_alignment::<[u8; 16]>(16, 1);
72+
73+
check_size_and_alignment::<[u32; 4]>(16, 4);
74+
75+
check_size_and_alignment::<[u64; 3]>(24, 8);
76+
77+
// // Tuples
78+
check_size_and_alignment::<()>(0, 1);
79+
80+
check_size_and_alignment::<(u8,)>(1, 1);
81+
82+
check_size_and_alignment::<(u8, u8)>(2, 1);
83+
84+
check_size_and_alignment::<(u8, u16)>(4, 2);
85+
86+
check_size_and_alignment::<(u8, u32)>(8, 4);
87+
88+
check_size_and_alignment::<(u8, u64)>(16, 8);
89+
90+
check_size_and_alignment::<(u32, u32)>(8, 4);
91+
92+
check_size_and_alignment::<(u64, u8, u64)>(24, 8);
93+
94+
// rustc will permute fields (less padding)
95+
#[allow(dead_code)]
96+
struct Padded {
97+
a: u8,
98+
b: u64,
99+
c: u8,
100+
}
101+
check_size_and_alignment::<Padded>(16, 8);
102+
103+
// cannot permute fields
104+
#[allow(dead_code)]
105+
#[repr(C)]
106+
struct ReprC {
107+
a: u8,
108+
b: u64,
109+
c: u8,
110+
}
111+
check_size_and_alignment::<ReprC>(24, 8);
112+
113+
#[allow(dead_code)]
114+
#[repr(packed)]
115+
struct ReprPacked {
116+
a: u8,
117+
b: u64,
118+
c: u8,
119+
}
120+
check_size_and_alignment::<ReprPacked>(10, 1);
121+
122+
#[allow(dead_code)]
123+
struct SmallStruct {
124+
a: u8,
125+
b: u8,
126+
c: u8,
127+
}
128+
check_size_and_alignment::<SmallStruct>(3, 1);
129+
130+
#[allow(dead_code)]
131+
struct AlignedStruct {
132+
a: u32,
133+
b: u32,
134+
}
135+
check_size_and_alignment::<AlignedStruct>(8, 4);
136+
137+
#[allow(dead_code)]
138+
#[repr(align(16))]
139+
struct Align16 {
140+
a: u8,
141+
}
142+
check_size_and_alignment::<Align16>(16, 16);
143+
144+
#[allow(dead_code)]
145+
#[repr(align(32))]
146+
struct Align32 {
147+
a: u32,
148+
}
149+
check_size_and_alignment::<Align32>(32, 32);
150+
151+
// Enums
152+
#[allow(dead_code)]
153+
enum SimpleEnum {
154+
A,
155+
B,
156+
C,
157+
}
158+
check_size_and_alignment::<SimpleEnum>(1, 1);
159+
160+
#[allow(dead_code)]
161+
enum EnumWithData {
162+
Variant1(u32),
163+
Variant2(u64),
164+
}
165+
check_size_and_alignment::<EnumWithData>(16, 8);
166+
167+
#[allow(dead_code)]
168+
enum ComplexEnum {
169+
Small(u8),
170+
Medium(u32),
171+
Large(u64, u64),
172+
}
173+
check_size_and_alignment::<ComplexEnum>(24, 8);
174+
175+
// // Option optimization
176+
check_size_and_alignment::<Option<u32>>(8, 4);
177+
178+
check_size_and_alignment::<Option<u64>>(16, 8);
179+
180+
// Null pointer optimization
181+
check_size_and_alignment::<Option<&u32>>(8, 8);
182+
183+
check_size_and_alignment::<Option<Box<u32>>>(8, 8);
184+
185+
// Result
186+
check_size_and_alignment::<Result<u32, u32>>(8, 4);
187+
188+
check_size_and_alignment::<Result<u64, u8>>(16, 8);
189+
190+
// Zero-sized types
191+
struct ZeroSized;
192+
check_size_and_alignment::<ZeroSized>(0, 1);
193+
194+
struct PhantomStruct<T> {
195+
_marker: std::marker::PhantomData<T>,
196+
}
197+
check_size_and_alignment::<PhantomStruct<u64>>(0, 1);
198+
199+
// // String and Vec (heap-allocated)
200+
check_size_and_alignment::<String>(24, 8);
201+
202+
check_size_and_alignment::<Vec<u32>>(24, 8);
203+
204+
check_size_and_alignment::<Box<u32>>(8, 8);
205+
206+
check_size_and_alignment::<Box<[u32]>>(16, 8);
207+
208+
}

0 commit comments

Comments
 (0)