Skip to content

Commit 122030f

Browse files
authored
Add span information (#1088)
This PR propagates the span through the semantics, to help with inspection/debugging either the programs or the semantics. We do this by using a new `<currentSpan>` cell, that contains the span of the instruction currently executing and is updated as needed in statements and in terminators (in each terminator rule, so as not to affect the step count - commit #2). The span is also added as part of the information maintained for a stack frame, saved in calls and restored on returns. So, we are able to get a location trace using the `<currentSpan>` plus the stack. The updated expected outputs show the new behavior, where each configuration now contains the `<currentSpan>` cell and each `StackFrame` contains the span. Running this small example and stopping mid-execution: ``` fn add(a: i32, b: i32) -> i32 { let c = a + b; // line 2 c } fn main() { let x = 3; let y = 4; let z = add(x, y); // line 9 assert!(z == 7); } ``` , stopping inside add while evaluating a + b gives: - `<currentSpan>` : the a + b line (line 2, inside add) - `<stack>` : the suspended main frame has the add(x, y) call-site span (line 9), below it the entry frame The trace shows add:2 -> main:9 -> entry (represented by span(0)) showing where execution is and how it got there.
1 parent 7bce18b commit 122030f

88 files changed

Lines changed: 422 additions & 98 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

kmir/src/kmir/kast.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ def mk_call_terminator(target: int, arg_count: int) -> KInner:
286286
KApply(
287287
'constOperand(_,_,_)_BODY_ConstOperand_Span_MaybeUserTypeAnnotationIndex_MirConst',
288288
(
289+
# synthetic span(0) sentinel (see note on the span below)
289290
KApply('span', token(0)),
290291
KApply('noUserTypeAnnotationIndex_BODY_MaybeUserTypeAnnotationIndex', ()),
291292
KApply(
@@ -312,6 +313,9 @@ def mk_call_terminator(target: int, arg_count: int) -> KInner:
312313
KApply('UnwindAction::Continue', ()),
313314
),
314315
),
316+
# Synthetic call-site span for this generated entry/main-call terminator (no real source
317+
# location). Note this differs from the rt/configuration.md <currentSpan> default of
318+
# span(-1), which is the "no span yet" sentinel.
315319
KApply('span', token(0)),
316320
),
317321
),

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

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ blocks, or call another function).
8484
8585
rule <k> #execStmts(.Statements) => .K ... </k>
8686
87-
rule <k> #execStmts(STATEMENT:Statement STATEMENTS:Statements)
87+
rule <k> #execStmts((statement(_, SPAN) #as STATEMENT) STATEMENTS:Statements)
8888
=>
8989
#execStmt(STATEMENT) ~> #execStmts(STATEMENTS)
9090
...
9191
</k>
92+
<currentSpan> _ => SPAN </currentSpan>
9293
```
9394

9495
`Statement` execution handles the different `StatementKind`s. Some of
@@ -158,10 +159,11 @@ function call, pushing a new stack frame and returning to a different
158159
block after the call returns.
159160

160161
```k
161-
rule [termGoto]: <k> #execTerminator(terminator(terminatorKindGoto(I), _SPAN)) ~> _CONT
162+
rule [termGoto]: <k> #execTerminator(terminator(terminatorKindGoto(I), SPAN)) ~> _CONT
162163
=>
163164
#execBlockIdx(I)
164165
</k>
166+
<currentSpan> _ => SPAN </currentSpan>
165167
```
166168

167169
A `SwitchInt` terminator selects one of the blocks given as _targets_,
@@ -173,10 +175,11 @@ will be `129`.
173175
```k
174176
syntax KItem ::= #selectBlock ( SwitchTargets , Evaluation ) [strict(2)]
175177
176-
rule [termSwitchInt]: <k> #execTerminator(terminator(terminatorKindSwitchInt(DISCR, TARGETS), _SPAN)) ~> _CONT
178+
rule [termSwitchInt]: <k> #execTerminator(terminator(terminatorKindSwitchInt(DISCR, TARGETS), SPAN)) ~> _CONT
177179
=>
178180
#selectBlock(TARGETS, DISCR)
179181
</k>
182+
<currentSpan> _ => SPAN </currentSpan>
180183
181184
// These rules preserve definedness because all the same subterms show up on each side except:
182185
// - `branch(...)`, which is a constructor.
@@ -233,9 +236,10 @@ If the local `_0` does not have a value (i.e., it remained uninitialised), the f
233236
<target> someBasicBlockIdx(TARGET) => NEWTARGET </target>
234237
<unwind> _ => UNWIND </unwind>
235238
<locals> ListItem(typedValue(VAL:Value, _, _)) _ => NEWLOCALS </locals>
239+
<currentSpan> _ => NEWSPAN </currentSpan> // restore caller's call-site span
236240
//</currentFrame>
237241
// remaining call stack (without top frame)
238-
<stack> ListItem(StackFrame(NEWCALLER, NEWDEST, NEWTARGET, UNWIND, NEWLOCALS)) STACK => STACK </stack>
242+
<stack> ListItem(StackFrame(NEWCALLER, NEWDEST, NEWTARGET, UNWIND, NEWLOCALS, NEWSPAN)) STACK => STACK </stack>
239243
<functions> FUNCSMAP </functions>
240244
241245
// no value to return, skip writing
@@ -251,9 +255,10 @@ If the local `_0` does not have a value (i.e., it remained uninitialised), the f
251255
<target> someBasicBlockIdx(TARGET) => NEWTARGET </target>
252256
<unwind> _ => UNWIND </unwind>
253257
<locals> ListItem(_:NewLocal) _ => NEWLOCALS </locals>
258+
<currentSpan> _ => NEWSPAN </currentSpan> // restore caller's call-site span
254259
//</currentFrame>
255260
// remaining call stack (without top frame)
256-
<stack> ListItem(StackFrame(NEWCALLER, NEWDEST, NEWTARGET, UNWIND, NEWLOCALS)) STACK => STACK </stack>
261+
<stack> ListItem(StackFrame(NEWCALLER, NEWDEST, NEWTARGET, UNWIND, NEWLOCALS, NEWSPAN)) STACK => STACK </stack>
257262
<functions> FUNCSMAP </functions>
258263
259264
```
@@ -329,13 +334,15 @@ where the returned result should go.
329334
=> #execTerminatorCall(Ty, lookupFunction(FUNCSMAP, Ty), ARGS, DEST, TARGET, UNWIND, SPAN)
330335
...
331336
</k>
337+
<currentSpan> _ => SPAN </currentSpan>
332338
<functions> FUNCSMAP </functions>
333339
334340
rule <k> #execTerminator(terminator(terminatorKindCall(operandMove(place(local(I), PROJS)), ARGS, DEST, TARGET, UNWIND), SPAN))
335341
=> #execTerminatorCall({#projectedCallTy(TYPESMAP, I, PROJS, LOCALS)}:>Ty, lookupFunction(FUNCSMAP, {#projectedCallTy(TYPESMAP, I, PROJS, LOCALS)}:>Ty), ARGS, DEST, TARGET, UNWIND, SPAN)
336342
...
337343
</k>
338344
<locals> LOCALS </locals>
345+
<currentSpan> _ => SPAN </currentSpan>
339346
<functions> FUNCSMAP </functions>
340347
<types> TYPESMAP </types>
341348
requires isTy(#projectedCallTy(TYPESMAP, I, PROJS, LOCALS))
@@ -385,8 +392,9 @@ where the returned result should go.
385392
<target> OLDTARGET => TARGET </target>
386393
<unwind> OLDUNWIND => UNWIND </unwind>
387394
<locals> LOCALS </locals>
395+
... // leaves <currentSpan> unchanged: callee arg setup is related to the caller's call-site span
388396
</currentFrame>
389-
<stack> STACK => ListItem(StackFrame(OLDCALLER, OLDDEST, OLDTARGET, OLDUNWIND, LOCALS)) STACK </stack>
397+
<stack> STACK => ListItem(StackFrame(OLDCALLER, OLDDEST, OLDTARGET, OLDUNWIND, LOCALS, SPAN)) STACK </stack>
390398
requires notBool isIntrinsicFunction(FUNC)
391399
392400
// Filter check injected after every call: fires as a cut-point only when the function matches the break-on list
@@ -511,7 +519,7 @@ An operand may be a `Reference` (the only way a function could access another fu
511519
#setLocalValue(place(local(IDX), .ProjectionElems), #incrementRef(getValue(CALLERLOCALS, I)))
512520
...
513521
</k>
514-
<stack> ListItem(StackFrame(_, _, _, _, CALLERLOCALS)) _:List </stack>
522+
<stack> ListItem(StackFrame(_, _, _, _, CALLERLOCALS, _)) _:List </stack>
515523
requires 0 <=Int I
516524
andBool I <Int size(CALLERLOCALS)
517525
andBool isTypedValue(CALLERLOCALS[I])
@@ -523,7 +531,7 @@ An operand may be a `Reference` (the only way a function could access another fu
523531
#setLocalValue(place(local(IDX), .ProjectionElems), #incrementRef(getValue(CALLERLOCALS, I)))
524532
...
525533
</k>
526-
<stack> (ListItem(StackFrame(_, _, _, _, CALLERLOCALS) #as CALLERFRAME => #updateStackLocal(CALLERFRAME, I, Moved))) _:List
534+
<stack> (ListItem(StackFrame(_, _, _, _, CALLERLOCALS, _) #as CALLERFRAME => #updateStackLocal(CALLERFRAME, I, Moved))) _:List
527535
</stack>
528536
requires 0 <=Int I
529537
andBool I <Int size(CALLERLOCALS)
@@ -657,10 +665,11 @@ Otherwise the provided message is passed to a `panic!` call, ending the program
657665
```k
658666
syntax MIRError ::= AssertError ( AssertMessage )
659667
660-
rule [termAssert]: <k> #execTerminator(terminator(assert(COND, EXPECTED, MSG, TARGET, _UNWIND), _SPAN)) ~> _CONT
668+
rule [termAssert]: <k> #execTerminator(terminator(assert(COND, EXPECTED, MSG, TARGET, _UNWIND), SPAN)) ~> _CONT
661669
=>
662670
#expect(COND, EXPECTED, MSG) ~> #execBlockIdx(TARGET)
663671
</k>
672+
<currentSpan> _ => SPAN </currentSpan>
664673
665674
syntax KItem ::= #expect ( Evaluation, Bool, AssertMessage ) [strict(1)]
666675
@@ -684,19 +693,21 @@ Other terminators that matter at the MIR level "Runtime" are `Drop` and `Unreach
684693
Drops are elaborated to Noops but still define the continuing control flow. Unreachable terminators lead to a program error.
685694

686695
```k
687-
rule [termDrop]: <k> #execTerminator(terminator(terminatorKindDrop(_PLACE, TARGET, _UNWIND), _SPAN))
696+
rule [termDrop]: <k> #execTerminator(terminator(terminatorKindDrop(_PLACE, TARGET, _UNWIND), SPAN))
688697
=>
689698
#execBlockIdx(TARGET)
690699
...
691700
</k>
701+
<currentSpan> _ => SPAN </currentSpan>
692702
693703
syntax MIRError ::= "ReachedUnreachable"
694704
695-
rule [termUnreachable]: <k> #execTerminator(terminator(terminatorKindUnreachable, _SPAN))
705+
rule [termUnreachable]: <k> #execTerminator(terminator(terminatorKindUnreachable, SPAN))
696706
=>
697707
ReachedUnreachable
698708
...
699709
</k>
710+
<currentSpan> _ => SPAN </currentSpan>
700711
```
701712

702713
### Stopping on Program Errors

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ module KMIR-CONFIGURATION
2828
dest:Place, // place to store return value
2929
target:MaybeBasicBlockIdx, // basic block to return to
3030
UnwindAction, // action to perform on panic
31-
locals:List) // return val, args, local variables
31+
locals:List, // return val, args, local variables
32+
span:Span) // call-site span of this frame
3233
3334
configuration <kmir>
3435
<k> $PGM:KItem </k>
@@ -42,6 +43,10 @@ module KMIR-CONFIGURATION
4243
<target> noBasicBlockIdx </target>
4344
<unwind> unwindActionUnreachable </unwind>
4445
<locals> .List </locals>
46+
// span of the instruction currently executing in this frame.
47+
// span(-1) is the "no span yet" sentinel (a real Span is an interned, non-negative index).
48+
// Note: this is intentionally distinct from the span(0) synthetic entry/main-call span set in kast.py.
49+
<currentSpan> span(-1) </currentSpan>
4550
</currentFrame>
4651
// remaining call stack (without top frame)
4752
<stack> .List </stack>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,8 @@ These helpers mark down, as we traverse the projection, what `Place` we are curr
365365
366366
syntax StackFrame ::= #updateStackLocal ( StackFrame, Int, Value ) [function]
367367
368-
rule #updateStackLocal(StackFrame(CALLER, DEST, TARGET, UNWIND, LOCALS), I, VAL)
369-
=> StackFrame(CALLER, DEST, TARGET, UNWIND, LOCALS[I <- typedValue(VAL, tyOfLocal(getLocal(LOCALS, I)), mutabilityMut)])
368+
rule #updateStackLocal(StackFrame(CALLER, DEST, TARGET, UNWIND, LOCALS, SPAN), I, VAL)
369+
=> StackFrame(CALLER, DEST, TARGET, UNWIND, LOCALS[I <- typedValue(VAL, tyOfLocal(getLocal(LOCALS, I)), mutabilityMut)], SPAN)
370370
requires 0 <=Int I
371371
andBool I <Int size(LOCALS)
372372
andBool isTypedLocal(LOCALS[I])

kmir/src/tests/integration/data/exec-smir/allocs/array_const_compare.state

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,12 @@
4545
ListItem ( typedValue ( Moved , ty ( 30 ) , mutabilityMut ) )
4646
ListItem ( newLocal ( ty ( 68 ) , mutabilityMut ) )
4747
</locals>
48+
<currentSpan>
49+
span ( 278 )
50+
</currentSpan>
4851
</currentFrame>
4952
<stack>
50-
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List ) )
53+
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List , span ( 0 ) ) )
5154
</stack>
5255
<functions>
5356
noMap

kmir/src/tests/integration/data/exec-smir/allocs/array_nest_compare.state

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,12 @@
6161
ListItem ( typedValue ( Moved , ty ( 30 ) , mutabilityMut ) )
6262
ListItem ( newLocal ( ty ( 84 ) , mutabilityMut ) )
6363
</locals>
64+
<currentSpan>
65+
span ( 266 )
66+
</currentSpan>
6467
</currentFrame>
6568
<stack>
66-
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List ) )
69+
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List , span ( 0 ) ) )
6770
</stack>
6871
<functions>
6972
noMap

kmir/src/tests/integration/data/exec-smir/allocs/enum-two-refs-fail.state

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
ListItem ( newLocal ( ty ( 25 ) , mutabilityMut ) )
4949
ListItem ( newLocal ( ty ( 25 ) , mutabilityMut ) )
5050
</locals>
51+
<currentSpan>
52+
span ( 145 )
53+
</currentSpan>
5154
</currentFrame>
5255
<stack>
5356
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( 0 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionContinue , ListItem ( newLocal ( ty ( 1 ) , mutabilityMut ) )
@@ -72,8 +75,8 @@
7275
ListItem ( newLocal ( ty ( 84 ) , mutabilityMut ) )
7376
ListItem ( newLocal ( ty ( 1 ) , mutabilityNot ) )
7477
ListItem ( newLocal ( ty ( 68 ) , mutabilityMut ) )
75-
ListItem ( newLocal ( ty ( 69 ) , mutabilityNot ) ) ) )
76-
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List ) )
78+
ListItem ( newLocal ( ty ( 69 ) , mutabilityNot ) ) , span ( 116 ) ) )
79+
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List , span ( 0 ) ) )
7780
</stack>
7881
<functions>
7982
noMap

kmir/src/tests/integration/data/exec-smir/allocs/option_consts.state

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,12 @@
108108
ListItem ( newLocal ( ty ( 84 ) , mutabilityNot ) )
109109
ListItem ( newLocal ( ty ( 86 ) , mutabilityMut ) )
110110
</locals>
111+
<currentSpan>
112+
span ( 374 )
113+
</currentSpan>
111114
</currentFrame>
112115
<stack>
113-
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List ) )
116+
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List , span ( 0 ) ) )
114117
</stack>
115118
<functions>
116119
noMap

kmir/src/tests/integration/data/exec-smir/arithmetic/arithmetic-unchecked-runs.state

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,12 @@
5050
ListItem ( typedValue ( Aggregate ( variantIdx ( 0 ) , ListItem ( Moved )
5151
ListItem ( Moved ) ) , ty ( 36 ) , mutabilityMut ) )
5252
</locals>
53+
<currentSpan>
54+
span ( 116 )
55+
</currentSpan>
5356
</currentFrame>
5457
<stack>
55-
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List ) )
58+
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List , span ( 0 ) ) )
5659
</stack>
5760
<functions>
5861
noMap

kmir/src/tests/integration/data/exec-smir/arithmetic/arithmetic.state

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,12 @@
6363
ListItem ( typedValue ( Aggregate ( variantIdx ( 0 ) , ListItem ( Moved )
6464
ListItem ( Moved ) ) , ty ( 29 ) , mutabilityMut ) )
6565
</locals>
66+
<currentSpan>
67+
span ( 67 )
68+
</currentSpan>
6669
</currentFrame>
6770
<stack>
68-
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List ) )
71+
ListItem ( StackFrame ( ty ( -1 ) , place (... local: local ( -1 ) , projection: .ProjectionElems ) , noBasicBlockIdx , unwindActionUnreachable , .List , span ( 0 ) ) )
6972
</stack>
7073
<functions>
7174
noMap

0 commit comments

Comments
 (0)