Skip to content

Commit 7956bca

Browse files
authored
Merging latest master into feature/p-token (#981)
- fix(kompile): map linked NormalSym functions to monoItemFn(noBody) [953](#953) - fix(rt): generalize direct-tag enum decoding to any variant count and discriminant [955](#955) - fix(rt): closure aggregate + #setTupleArgs fallback [952](#952) - fix(rt): bug fix for castKindPtrToPtr [974](#974) - fix(rt): repair closure callee setup for iter-eq repro [957](#957)
2 parents 1413178 + 133ebf3 commit 7956bca

25 files changed

Lines changed: 670 additions & 89 deletions

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,8 @@ Therefore a heuristics is used here:
565565
_SPAN
566566
)
567567
=>
568-
#setTupleArgs(2, getValue(LOCALS, TUPLE)) ~> #execBlock(FIRST)
568+
#setLocalValue(place(local(1), .ProjectionElems), #incrementRef(getValue(LOCALS, CLOSURE)))
569+
~> #setTupleArgs(2, getValue(LOCALS, TUPLE)) ~> #execBlock(FIRST)
569570
// arguments are tuple components, stored as _2 .. _n
570571
...
571572
</k>
@@ -609,6 +610,11 @@ Therefore a heuristics is used here:
609610
// unpack tuple and set arguments individually
610611
rule <k> #setTupleArgs(IDX, Aggregate(variantIdx(0), ARGS)) => #setTupleArgs(IDX, ARGS) ... </k>
611612
613+
rule <k> #setTupleArgs(IDX, VAL:Value)
614+
=> #setTupleArgs(IDX, ListItem(VAL))
615+
...
616+
</k> [owise]
617+
612618
rule <k> #setTupleArgs(_, .List ) => .K ... </k>
613619
614620
rule <k> #setTupleArgs(IDX, ListItem(VAL) REST:List)

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,12 @@ Literal arrays are also built using this RValue.
10511051
...
10521052
</k>
10531053
1054+
rule <k> ARGS:List ~> #mkAggregate(aggregateKindClosure(_DEF, _TY_ARGS))
1055+
=>
1056+
Aggregate(variantIdx(0), ARGS)
1057+
...
1058+
</k>
1059+
10541060
10551061
// #readOperands accumulates a list of `TypedLocal` values from operands
10561062
syntax KItem ::= #readOperands ( Operands )
@@ -1434,6 +1440,20 @@ which have the same representation `Value::Range`.
14341440
Also, casts to and from _transparent wrappers_ (newtypes that just forward field `0`, i.e. `struct Wrapper<T>(T)`)
14351441
are allowed, and supported by a special projection `WrapStruct`.
14361442

1443+
When the source and target types are pointer types with the same pointee type (i.e., differing only in mutability),
1444+
the cast preserves the source pointer and its metadata unchanged.
1445+
1446+
```k
1447+
rule <k> #cast(PtrLocal(OFFSET, PLACE, MUT, META), castKindPtrToPtr, TY_SOURCE, TY_TARGET)
1448+
=> PtrLocal(OFFSET, PLACE, MUT, META)
1449+
...
1450+
</k>
1451+
requires pointeeTy(lookupTy(TY_SOURCE)) ==K pointeeTy(lookupTy(TY_TARGET))
1452+
[priority(45), preserves-definedness] // valid map lookups checked
1453+
```
1454+
1455+
Otherwise, compute the type projection and convert metadata accordingly.
1456+
14371457
```k
14381458
rule <k> #cast(PtrLocal(OFFSET, place(LOCAL, PROJS), MUT, META), castKindPtrToPtr, TY_SOURCE, TY_TARGET)
14391459
=>

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

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -297,27 +297,26 @@ If there are no fields, the enum can be decoded by using their data as the discr
297297
requires TAG =/=Int DISCRIMINANT
298298
```
299299

300-
#### Enums with two variants
300+
#### Enums with direct tag encoding and fields
301301

302-
Having two variants with possibly zero or one field each is a very common case,
303-
it includes a number of standard library types such as `Option` and `Result`.
304-
305-
The following rules are specialised to the case of encoding an `Option`.
306-
An important distinction here is whether or not the tag is niche-encoded.
307-
If the option holds data that has all-zero as a possible value, a separate tag is used, usually as the first field.
308-
In both cases we expect the tag to be in the single shared field, and the discriminant to be just 0 and 1.
302+
Decodes any enum with `tagEncodingDirect` and a `primitiveInt` tag,
303+
with arbitrary variant counts, discriminant values, and field counts per variant.
304+
The tag is read as an unsigned little-endian integer, matched against the discriminant
305+
list to find the variant index, and then the variant's fields are decoded using the
306+
per-variant layout offsets.
309307

310308
```k
309+
// General entry rule: direct-tag enum with at least one field somewhere.
311310
rule #decodeValue(
312311
BYTES
313312
, typeInfoEnumType(...
314313
name: _
315314
, adtDef: _
316-
, discriminants: discriminant(0) discriminant(1) .Discriminants
317-
, fields: (.Tys : (FIELD_TYPE .Tys) : .Tyss)
315+
, discriminants: DISCRIMINANTS
316+
, fields: FIELD_TYPESS
318317
, layout:
319318
someLayoutShape(layoutShape(...
320-
fields: fieldsShapeArbitrary(mk(... offsets: machineSize(0) .MachineSizes))
319+
fields: _FIELDS
321320
, variants:
322321
variantsShapeMultiple(
323322
mk(...
@@ -329,7 +328,7 @@ In both cases we expect the tag to be in the single shared field, and the discri
329328
)
330329
, tagEncoding: tagEncodingDirect
331330
, tagField: 0
332-
, variants: _VARIANTS
331+
, variants: VARIANT_LAYOUTS
333332
)
334333
)
335334
, abi: _ABI
@@ -338,22 +337,59 @@ In both cases we expect the tag to be in the single shared field, and the discri
338337
))
339338
) #as ENUM_TYPE
340339
)
341-
=> #decodeOptionTag01(BYTES, TAG_WIDTH, FIELD_TYPE, ENUM_TYPE)
342-
343-
syntax Evaluation ::= #decodeOptionTag01 ( Bytes , IntegerLength , Ty , TypeInfo ) [function, total]
344-
// --------------------------------------------------------------------------------------
345-
rule #decodeOptionTag01(BYTES, _LEN, _TY, _ENUM_TYPE)
346-
=> Aggregate(variantIdx(0), .List)
347-
requires 0 ==Int BYTES[0] // expect only 0 or 1 as tags, so higher bytes do not matter
348-
[preserves-definedness]
349-
rule #decodeOptionTag01(BYTES, LEN, TY, _ENUM_TYPE)
350-
=> Aggregate(variantIdx(1), ListItem(#decodeValue(substrBytes(BYTES, #byteLength(LEN), lengthBytes(BYTES)), lookupTy(TY))))
351-
requires 1 ==Int BYTES[0] // expect only 0 or 1 as tags, so higher bytes do not matter
340+
=> #decodeEnumDirectFields(
341+
BYTES,
342+
#findVariantIdx(#decodeEnumDirectTag(BYTES, TAG_WIDTH), DISCRIMINANTS),
343+
FIELD_TYPESS,
344+
VARIANT_LAYOUTS,
345+
ENUM_TYPE
346+
)
347+
requires notBool #noFields(FIELD_TYPESS)
348+
349+
// ---------------------------------------------------------------------------
350+
// #decodeEnumDirectFields: given the variant index, decode its fields
351+
// ---------------------------------------------------------------------------
352+
syntax Evaluation ::= #decodeEnumDirectFields ( Bytes , VariantIdx , Tyss , LayoutShapes , TypeInfo ) [function, total]
353+
// --------------------------------------------------------------------------------------------------------------------------
354+
rule #decodeEnumDirectFields(BYTES, variantIdx(IDX), FIELD_TYPESS, VARIANT_LAYOUTS, _ENUM_TYPE)
355+
=> Aggregate(
356+
variantIdx(IDX),
357+
#decodeFieldsWithOffsets(BYTES, #nthTys(FIELD_TYPESS, IDX), #nthVariantOffsets(VARIANT_LAYOUTS, IDX))
358+
)
359+
requires 0 <=Int IDX
352360
[preserves-definedness]
353-
rule #decodeOptionTag01(BYTES, _LEN, _TY, ENUM_TYPE)
361+
362+
// Error cases: variant not found or other failure
363+
rule #decodeEnumDirectFields(BYTES, _, _FIELD_TYPESS, _VARIANT_LAYOUTS, ENUM_TYPE)
354364
=> UnableToDecode(BYTES, ENUM_TYPE)
355365
[owise]
356366
367+
// ---------------------------------------------------------------------------
368+
// #decodeEnumDirectTag: read the tag bytes as an unsigned little-endian int
369+
// ---------------------------------------------------------------------------
370+
syntax Int ::= #decodeEnumDirectTag ( Bytes , IntegerLength ) [function, total]
371+
rule #decodeEnumDirectTag(BYTES, TAG_WIDTH)
372+
=> Bytes2Int(substrBytes(BYTES, 0, #byteLength(TAG_WIDTH)), LE, Unsigned)
373+
requires lengthBytes(BYTES) >=Int #byteLength(TAG_WIDTH)
374+
[preserves-definedness]
375+
rule #decodeEnumDirectTag(_, _) => -1 [owise]
376+
377+
// ---------------------------------------------------------------------------
378+
// List-indexing helpers
379+
// ---------------------------------------------------------------------------
380+
381+
// Index into a Tyss (list of per-variant field type lists)
382+
syntax Tys ::= #nthTys ( Tyss , Int ) [function, total]
383+
rule #nthTys(TYS : _REST, 0) => TYS
384+
rule #nthTys(_TYS : REST, N) => #nthTys(REST, N -Int 1) requires N >Int 0
385+
rule #nthTys(_, _) => .Tys [owise]
386+
387+
// Index into variant layouts and extract field offsets in one step (total)
388+
syntax MachineSizes ::= #nthVariantOffsets ( LayoutShapes , Int ) [function, total]
389+
rule #nthVariantOffsets(layoutShape(fieldsShapeArbitrary(mk(OFFSETS)), _, _, _, _) _REST, 0) => OFFSETS
390+
rule #nthVariantOffsets(_L REST, N) => #nthVariantOffsets(REST, N -Int 1) requires N >Int 0
391+
rule #nthVariantOffsets(_, _) => .MachineSizes [owise]
392+
357393
syntax Int ::= #byteLength ( IntegerLength ) [function, total]
358394
// -----------------------------------------------------------
359395
rule #byteLength(integerLengthI8 ) => 1

kmir/src/kmir/kompile.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,13 +521,25 @@ def _functions(kmir: KMIR, smir_info: SMIRInfo) -> dict[int, KInner]:
521521
for ty in smir_info.function_symbols_reverse[item_name]:
522522
functions[ty] = parsed_item_kinner.args[1]
523523

524-
# Add intrinsic functions
524+
# Add intrinsic functions and linked normal symbols that have no local body in `items`.
525+
# Normal symbols must still map to `monoItemFn(..., noBody)` instead of falling back to UNKNOWN FUNCTION.
525526
for ty, sym in smir_info.function_symbols.items():
526-
if 'IntrinsicSym' in sym and ty not in functions:
527+
if ty in functions:
528+
continue
529+
if 'IntrinsicSym' in sym:
527530
functions[ty] = KApply(
528531
'IntrinsicFunction',
529532
[KApply('symbol(_)_LIB_Symbol_String', [stringToken(sym['IntrinsicSym'])])],
530533
)
534+
elif isinstance(sym.get('NormalSym'), str):
535+
functions[ty] = KApply(
536+
'MonoItemKind::MonoItemFn',
537+
(
538+
KApply('symbol(_)_LIB_Symbol_String', (stringToken(sym['NormalSym']),)),
539+
KApply('defId(_)_BODY_DefId_Int', (intToken(ty),)),
540+
KApply('noBody_BODY_MaybeBody', ()),
541+
),
542+
)
531543

532544
return functions
533545

kmir/src/kmir/testing/fixtures.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
import re
4+
import sys
35
from difflib import unified_diff
46
from typing import TYPE_CHECKING
57

@@ -13,24 +15,36 @@
1315

1416
from pytest import FixtureRequest, Parser
1517

16-
import sys
17-
1818

1919
def pytest_configure(config) -> None:
2020
sys.setrecursionlimit(1000000)
2121

2222

23+
def _normalize_symbol_hashes(text: str) -> str:
24+
"""Normalize rustc symbol hash suffixes that drift across builds/environments."""
25+
# Normalize mangled symbol hashes, including generic names with `$` and `.`.
26+
# Keep trailing `E` when present; truncated variants may omit it.
27+
text = re.sub(r'(_ZN[0-9A-Za-z_$.]+17h)[0-9a-fA-F]+E', r'\1<hash>E', text)
28+
text = re.sub(r'(_ZN[0-9A-Za-z_$.]+17h)[0-9a-fA-F]+', r'\1<hash>', text)
29+
# Normalize demangled hash suffixes (`...::h<hex>`).
30+
text = re.sub(r'(::h)[0-9a-fA-F]{8,}', r'\1<hash>', text)
31+
return text
32+
33+
2334
def assert_or_update_show_output(
2435
actual_text: str, expected_file: Path, *, update: bool, path_replacements: dict[str, str] | None = None
2536
) -> None:
2637
if path_replacements:
2738
for old, new in path_replacements.items():
2839
actual_text = actual_text.replace(old, new)
40+
# Normalize rustc symbol hash suffixes that can drift across builds/environments.
41+
actual_text = _normalize_symbol_hashes(actual_text)
2942
if update:
3043
expected_file.write_text(actual_text)
3144
else:
3245
assert expected_file.is_file()
3346
expected_text = expected_file.read_text()
47+
expected_text = _normalize_symbol_hashes(expected_text)
3448
if actual_text != expected_text:
3549
diff = '\n'.join(
3650
unified_diff(

kmir/src/kmir/utils.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ def _extract_alloc_id(operands: KInner) -> int | None:
288288
return None
289289

290290

291-
def _annotate_unknown_function(k_cell: KInner, smir_info: SMIRInfo) -> list[str]:
292-
"""If the k cell is `#setUpCalleeData` for `** UNKNOWN FUNCTION **`, return annotation lines with decoded info."""
291+
def _annotate_nobody_function(k_cell: KInner, smir_info: SMIRInfo) -> list[str]:
292+
"""If the k cell is `#setUpCalleeData` for a `noBody` callee, return annotation lines with decoded info."""
293293

294294
from .alloc import Allocation, AllocId, AllocInfo, Memory
295295
from .linker import _demangle
@@ -307,16 +307,14 @@ def _annotate_unknown_function(k_cell: KInner, smir_info: SMIRInfo) -> list[str]
307307
KApply(
308308
label=KLabel(name='MonoItemKind::MonoItemFn'),
309309
args=[
310-
KApply(args=[KToken(token=symbol_name)]),
310+
KApply(args=[KToken()]),
311311
KApply(label=KLabel(name='defId(_)_BODY_DefId_Int'), args=[KToken(token=def_id_str)]),
312312
_,
313313
],
314314
),
315315
operands,
316316
KApply(label=KLabel(name='span'), args=[KToken(token=span_str)]),
317-
] if (
318-
symbol_name == '\"** UNKNOWN FUNCTION **\"'
319-
):
317+
]:
320318
def_id = int(def_id_str)
321319
span = int(span_str)
322320
case _:
@@ -379,7 +377,7 @@ def render_leaf_k_cells(proof: APRProof, cterm_show: CTermShow, smir_info: SMIRI
379377
lines.extend(f' {k_line}' for k_line in k_lines)
380378

381379
if smir_info is not None and k_cell is not None:
382-
annotations = _annotate_unknown_function(k_cell, smir_info)
380+
annotations = _annotate_nobody_function(k_cell, smir_info)
383381
lines.extend(annotations)
384382

385383
if idx != len(leaves) - 1:

kmir/src/tests/integration/data/crate-tests/single-lib/small_test_lib::testing::test_add_in_range.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
┃ │
1717
┃ │ (6 steps)
1818
┃ └─ 6 (stuck, leaf)
19-
┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) ,
19+
┃ #setUpCalleeData ( monoItemFn ( ... name: symbol ( "_ZN3std7process4exit17h<hash>
2020
2121
┗━━┓ subst: .Subst
2222
┃ constraint:

kmir/src/tests/integration/data/exec-smir/intrinsic/blackbox_function_symbols.expected.json

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,69 @@
11
{
22
"-6": {
3-
"NormalSym": "_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17hb524060ed0e83bbbE"
3+
"NormalSym": "_ZN4core3ptr85drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$17h<hash>E"
44
},
55
"-5": {
6-
"NormalSym": "_ZN4core3ptr28drop_in_place$LT$$RF$u32$GT$17hb92e31f0aaa3d322E"
6+
"NormalSym": "_ZN4core3ptr28drop_in_place$LT$$RF$u32$GT$17h<hash>E"
77
},
88
"-4": {
9-
"NormalSym": "_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h526a5c5d4d9d3202E"
9+
"NormalSym": "_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h<hash>E"
1010
},
1111
"-3": {
12-
"NormalSym": "_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h3a8781eea2f9ddb7E"
12+
"NormalSym": "_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17h<hash>E"
1313
},
1414
"-2": {
15-
"NormalSym": "_ZN3std2rt10lang_start17h17250425291430deE"
15+
"NormalSym": "_ZN3std2rt10lang_start17h<hash>E"
1616
},
1717
"-1": {
18-
"NormalSym": "_ZN8blackbox4main17h56268fefa1135d9eE"
18+
"NormalSym": "_ZN8blackbox4main17h<hash>E"
1919
},
2020
"0": {
21-
"NormalSym": "_ZN3std2rt19lang_start_internal17h018b8394ba015d86E"
21+
"NormalSym": "_ZN3std2rt19lang_start_internal17h<hash>E"
2222
},
2323
"13": {
24-
"NormalSym": "_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h3ac302c9481e885fE"
24+
"NormalSym": "_ZN3std3sys9backtrace28__rust_begin_short_backtrace17h<hash>E"
2525
},
2626
"14": {
27-
"NormalSym": "_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h8eaae5c69aab66e9E"
27+
"NormalSym": "_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h<hash>E"
2828
},
2929
"19": {
30-
"NormalSym": "_ZN4core3ops8function6FnOnce9call_once17haae505bd39892fd2E"
30+
"NormalSym": "_ZN4core3ops8function6FnOnce9call_once17h<hash>E"
3131
},
3232
"20": {
3333
"IntrinsicSym": "black_box"
3434
},
3535
"21": {
36-
"NormalSym": "_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17h99c61f0bde9a2afdE"
36+
"NormalSym": "_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17h<hash>E"
3737
},
3838
"27": {
39-
"NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17hb987357f13dc6cc8E"
39+
"NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17h<hash>E"
4040
},
4141
"28": {
42-
"NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17h7baa47f3e5cbe44cE"
42+
"NormalSym": "_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17h<hash>E"
4343
},
4444
"29": {
45-
"NormalSym": "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17hec74c53b91325b16E"
45+
"NormalSym": "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17h<hash>E"
4646
},
4747
"30": {
48-
"NormalSym": "_ZN4core3ops8function6FnOnce9call_once17h2d8e0aae13049ae8E"
48+
"NormalSym": "_ZN4core3ops8function6FnOnce9call_once17h<hash>E"
4949
},
5050
"32": {
51-
"NormalSym": "_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h5c121846c1652782E"
51+
"NormalSym": "_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h<hash>E"
5252
},
5353
"35": {
5454
"IntrinsicSym": "black_box"
5555
},
5656
"36": {
57-
"NormalSym": "_ZN4core9panicking19assert_failed_inner17h1d286061ca0adfe7E"
57+
"NormalSym": "_ZN4core9panicking19assert_failed_inner17h<hash>E"
5858
},
5959
"43": {
60-
"NormalSym": "_ZN8blackbox7add_one17h19d5f3b41fdf13daE"
60+
"NormalSym": "_ZN8blackbox7add_one17h<hash>E"
6161
},
6262
"44": {
63-
"NormalSym": "_ZN4core4hint9black_box17h0bfc654765aa2ddfE"
63+
"NormalSym": "_ZN4core4hint9black_box17h<hash>E"
6464
},
6565
"45": {
66-
"NormalSym": "_ZN4core9panicking13assert_failed17h9acd0d94a91ca0eaE"
66+
"NormalSym": "_ZN4core9panicking13assert_failed17h<hash>E"
6767
},
6868
"48": {
6969
"NoOpSym": ""

0 commit comments

Comments
 (0)