Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
35bac06
convert static config data into functions (with dummy values, compile…
jberthold Sep 30, 2025
2f19a1f
add a notes file describing the approach (in docs, should remove or e…
jberthold Sep 30, 2025
d5e7613
Merge remote-tracking branch 'origin/master' into EXPERIMENT-compilin…
jberthold Sep 30, 2025
01b2a04
CHERRY-PICK-ME Adjust Makefile to avoid nix-formatting files that are…
jberthold Sep 30, 2025
902361f
WIP generate module (plugged into gen-spec for manual testing
jberthold Oct 1, 2025
0a7c31d
Change type for lookupAlloc and decodeAlloc to Evaluation
jberthold Oct 1, 2025
bfde0a5
suppress duplicate adtDef equations (polymorphic ADTs), adjust #decod…
jberthold Oct 1, 2025
992b34a
remove @ chars from function names to make llvm's lld happy :explodin…
jberthold Oct 1, 2025
918be67
Draft code for proving with static data in a module
jberthold Oct 1, 2025
048865e
formatting etc
jberthold Oct 1, 2025
e258ac7
Reduce item table before generating the K module (prevents re-use, en…
jberthold Oct 1, 2025
0c960e5
Use info logging to report status and module file
jberthold Oct 1, 2025
4bed164
CHERRY-PICK-ME escape \n, @, and " when printing bytes as ascii text
jberthold Oct 2, 2025
d14e002
Merge remote-tracking branch 'origin/master' into EXPERIMENT-compilin…
jberthold Oct 13, 2025
df4e06f
adjust alloc equation generation. Status: Not working as expected
jberthold Oct 13, 2025
d01cf2c
WIP implementing run-x
jberthold Oct 13, 2025
4457782
WIP run-x: try-catch around module compilation
jberthold Oct 13, 2025
1d72581
update the notes with some insight about blockers and workarounds
jberthold Oct 13, 2025
311b631
WIP adding a `run-x` command for testing
jberthold Oct 13, 2025
a7c1f42
fix lookupAlloc in generated module, use custom constructor in prove-x
jberthold Oct 14, 2025
5c402e9
WIP generating kore function equations for the module
jberthold Oct 14, 2025
d09c5f3
produce and render function equations using pyk, define shorter symbols
jberthold Oct 14, 2025
e576a1e
complete definition.kore generation and llvm kompile (draft)
jberthold Oct 14, 2025
2245172
fix app and sorts in rule rendering, simply print rules unless output…
jberthold Oct 14, 2025
bde92b8
move kore generation into a KMIR constructor, adjustments
jberthold Oct 15, 2025
0f67a25
Add definedness and totality to avoid fall-back
jberthold Oct 15, 2025
ba427bc
WIP hacking in kore-based running and proving. run-x not working as e…
jberthold Oct 15, 2025
e2ac856
Reduce logging for pyk.ktool.kprint
jberthold Oct 15, 2025
de64d26
Merge remote-tracking branch 'origin/master' into EXPERIMENT-compilin…
jberthold Oct 15, 2025
0a40519
remove K module based approach
jberthold Oct 15, 2025
cf54a71
prune read-only config parts from make_call_config
jberthold Oct 15, 2025
94b98d5
refactor KMIR.prove-rs to a static method, move code out of __main__.…
jberthold Oct 15, 2025
0c92042
Merge remote-tracking branch 'origin/master' into EXPERIMENT-compilin…
jberthold Oct 15, 2025
e59b649
Remove default dir out-kore, implement non-symbolic compilation path
jberthold Oct 16, 2025
00ccba1
Remove run-x, moving code to `_kmir_run`
jberthold Oct 16, 2025
8320c06
fix llvm execution
jberthold Oct 16, 2025
11a4869
Remove all read-only data from the expectation files for exec-smir tests
jberthold Oct 16, 2025
5db61f0
Merge remote-tracking branch 'origin/master' into EXPERIMENT-compilin…
jberthold Oct 16, 2025
43d8dd3
remove outdated test_prove test (was based on K spec files)
jberthold Oct 16, 2025
f0c68e6
Fix prove_rs routine (scope of tmp_dir was too short)
jberthold Oct 16, 2025
074ef3c
Change `test_prove_termination` to use `prove_rs` instead of `gen-spe…
jberthold Oct 16, 2025
03547fa
adjust expectations for 3 prove-rs tests which call panic (unknown fu…
jberthold Oct 17, 2025
56ddf51
notes file update
jberthold Oct 17, 2025
30aa4f3
notes update
jberthold Oct 17, 2025
312eb7f
restore (unused) gen-spec, remove prove-x helper, remove stale code
jberthold Oct 17, 2025
4109071
Adjust expectations for panic calls in single-lib and cli_statistics …
jberthold Oct 17, 2025
148a88b
WIP attempt to create type lookups fixture for test_decode_value
jberthold Oct 17, 2025
0b036d7
adjust dir name for LLVM compilation
jberthold Oct 17, 2025
9e925ba
Synchronise llvm-kompile call with file lock before test_decode_value
jberthold Oct 17, 2025
6ae2a0a
fml
jberthold Oct 17, 2025
6414c85
Adjust expectation for enum-two-refs-fail (K decoding checks isValue …
jberthold Oct 17, 2025
f20af1e
remove notes file
jberthold Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions kmir/src/kmir/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging
import sys
import tempfile
from argparse import ArgumentParser
from pathlib import Path
from typing import TYPE_CHECKING
Expand Down Expand Up @@ -57,13 +58,14 @@ def _kmir_run(opts: RunOpts) -> None:
# target = opts.bin if opts.bin else cargo.default_target
smir_info = cargo.smir_for_project(clean=False)

result = kmir.run_smir(smir_info, start_symbol=opts.start_symbol, depth=opts.depth)
print(kmir.kore_to_pretty(result))
with tempfile.TemporaryDirectory() as work_dir:
kmir = KMIR.from_kompiled_kore(smir_info, symbolic=opts.haskell_backend, target_dir=work_dir)
result = kmir.run_smir(smir_info, start_symbol=opts.start_symbol, depth=opts.depth)
print(kmir.kore_to_pretty(result))


def _kmir_prove_rs(opts: ProveRSOpts) -> None:
kmir = KMIR(HASKELL_DEF_DIR, LLVM_LIB_DIR, bug_report=opts.bug_report)
proof = kmir.prove_rs(opts)
proof = KMIR.prove_rs(opts)
print(str(proof.summary))
if not proof.passed:
sys.exit(1)
Expand Down
1 change: 1 addition & 0 deletions kmir/src/kmir/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
LLVM_DEF_DIR: Final = kdist.which('mir-semantics.llvm')
LLVM_LIB_DIR: Final = kdist.which('mir-semantics.llvm-library')
HASKELL_DEF_DIR: Final = kdist.which('mir-semantics.haskell')
KMIR_SOURCE_DIR: Final = kdist.which('mir-semantics.source')
97 changes: 41 additions & 56 deletions kmir/src/kmir/kdist/mir-semantics/kmir.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,20 @@ Execution of a program begins by creating a stack frame for the `main`
function and executing its function body. Before execution begins, the
function map and the initial memory have to be set up.

```k
All of this is done in the client code so we omit the initialisation code which was historically placed here.

```
// #init step, assuming a singleton in the K cell
rule <k> #init(_NAME:Symbol _ALLOCS:GlobalAllocs FUNCTIONS:FunctionNames ITEMS:MonoItems TYPES:TypeMappings _MACHINE:MachineInfo)
rule <k> #init(_NAME:Symbol _ALLOCS:GlobalAllocs FUNCTIONS:FunctionNames _ITEMS:MonoItems _TYPES:TypeMappings _MACHINE:MachineInfo)
=>
#execFunction(#findItem(ITEMS, FUNCNAME), FUNCTIONS)
</k>
<functions> _ => #mkFunctionMap(FUNCTIONS, ITEMS) </functions>
<start-symbol> FUNCNAME </start-symbol>
<types> _ => #mkTypeMap(.Map, TYPES) </types>
```

The `Map` of types is static information used for decoding constants and allocated data into `Value`s.
It maps `Ty` IDs to `TypeInfo` that can be supplied to decoding and casting functions as well as operations involving `Aggregate` values (related to `struct`s and `enum`s).

```k
```
syntax Map ::= #mkTypeMap ( Map, TypeMappings ) [function, total, symbol("mkTypeMap")]

rule #mkTypeMap(ACC, .TypeMappings) => ACC
Expand All @@ -83,7 +82,7 @@ they are callee in a `Call` terminator within an `Item`).

The function _names_ and _ids_ are not relevant for calls and therefore dropped.

```k
```
syntax Map ::= #mkFunctionMap ( FunctionNames, MonoItems ) [ function, total, symbol("mkFunctionMap") ]
| #accumFunctions ( Map, Map, FunctionNames ) [ function, total ]
| #accumItems ( Map, MonoItems ) [ function, total ]
Expand Down Expand Up @@ -138,7 +137,7 @@ structure from its function body and then execute the first basic
block of the body. The function's `Ty` index in the `functions` map must
be known to populate the `currentFunc` field.

```k
```
// find function through its MonoItemFn.name
syntax MonoItem ::= #findItem ( MonoItems, Symbol ) [ function ]

Expand Down Expand Up @@ -185,20 +184,9 @@ be known to populate the `currentFunc` field.
[owise]

rule #tyFromName(_, .List) => ty(-1) // HACK see #mainIsMinusOne above

syntax List ::= toKList(BasicBlocks) [function, total]

rule toKList( .BasicBlocks ) => .List
rule toKList(B:BasicBlock REST:BasicBlocks) => ListItem(B) toKList(REST)

syntax List ::= #reserveFor( LocalDecls ) [function, total]

rule #reserveFor(.LocalDecls) => .List

rule #reserveFor(localDecl(TY, _, MUT) REST:LocalDecls)
=>
ListItem(newLocal(TY, MUT)) #reserveFor(REST)
```
#### Function Execution


Executing a function body consists of repeated calls to `#execBlock`
for the basic blocks that, together, constitute the function body. The
Expand Down Expand Up @@ -345,7 +333,7 @@ If the local `_0` does not have a value (i.e., it remained uninitialised), the f
</k>
<currentFunc> _ => CALLER </currentFunc>
//<currentFrame>
<currentBody> _ => #getBlocks(FUNCS, CALLER) </currentBody>
<currentBody> _ => #getBlocks(CALLER) </currentBody>
<caller> CALLER => NEWCALLER </caller>
<dest> DEST => NEWDEST </dest>
<target> someBasicBlockIdx(TARGET) => NEWTARGET </target>
Expand All @@ -354,9 +342,6 @@ If the local `_0` does not have a value (i.e., it remained uninitialised), the f
//</currentFrame>
// remaining call stack (without top frame)
<stack> ListItem(StackFrame(NEWCALLER, NEWDEST, NEWTARGET, UNWIND, NEWLOCALS)) STACK => STACK </stack>
<functions> FUNCS </functions>
requires CALLER in_keys(FUNCS)
[preserves-definedness] // CALLER lookup defined

// no value to return, skip writing
rule <k> #execTerminator(terminator(terminatorKindReturn, _SPAN)) ~> _
Expand All @@ -365,7 +350,7 @@ If the local `_0` does not have a value (i.e., it remained uninitialised), the f
</k>
<currentFunc> _ => CALLER </currentFunc>
//<currentFrame>
<currentBody> _ => #getBlocks(FUNCS, CALLER) </currentBody>
<currentBody> _ => #getBlocks(CALLER) </currentBody>
<caller> CALLER => NEWCALLER </caller>
<dest> _ => NEWDEST </dest>
<target> someBasicBlockIdx(TARGET) => NEWTARGET </target>
Expand All @@ -374,15 +359,11 @@ If the local `_0` does not have a value (i.e., it remained uninitialised), the f
//</currentFrame>
// remaining call stack (without top frame)
<stack> ListItem(StackFrame(NEWCALLER, NEWDEST, NEWTARGET, UNWIND, NEWLOCALS)) STACK => STACK </stack>
<functions> FUNCS </functions>
requires CALLER in_keys(FUNCS)
[preserves-definedness] // CALLER lookup defined

syntax List ::= #getBlocks(Map, Ty) [function]
| #getBlocksAux(MonoItemKind) [function, total]
syntax List ::= #getBlocks( Ty ) [function, total]
| #getBlocksAux( MonoItemKind ) [function, total]

rule #getBlocks(FUNCS, ID) => #getBlocksAux({FUNCS[ID]}:>MonoItemKind)
requires ID in_keys(FUNCS)
rule #getBlocks(TY) => #getBlocksAux(lookupFunction(TY))

// returns blocks from the body
rule #getBlocksAux(monoItemFn(_, _, noBody)) => .List
Expand All @@ -391,6 +372,11 @@ If the local `_0` does not have a value (i.e., it remained uninitialised), the f
rule #getBlocksAux(monoItemStatic(_, _, _)) => .List // should not occur in calls
rule #getBlocksAux(monoItemGlobalAsm(_)) => .List // not supported
rule #getBlocksAux(IntrinsicFunction(_)) => .List // intrinsics have no body

syntax List ::= toKList(BasicBlocks) [function, total]
// ---------------------------------------------------
rule toKList( .BasicBlocks ) => .List
rule toKList(B:BasicBlock REST:BasicBlocks) => ListItem(B) toKList(REST)
```

When a `terminatorKindReturn` is executed but the optional target is empty
Expand Down Expand Up @@ -434,18 +420,14 @@ where the returned result should go.
// Intrinsic function call - execute directly without state switching
rule <k> #execTerminator(terminator(terminatorKindCall(FUNC, ARGS, DEST, TARGET, _UNWIND), _SPAN)) ~> _
=>
#execIntrinsic({FUNCTIONS[#tyOfCall(FUNC)]}:>MonoItemKind, ARGS, DEST) ~> #continueAt(TARGET)
#execIntrinsic(lookupFunction(#tyOfCall(FUNC)), ARGS, DEST) ~> #continueAt(TARGET)
</k>
<functions> FUNCTIONS </functions>
requires #tyOfCall(FUNC) in_keys(FUNCTIONS)
andBool isMonoItemKind(FUNCTIONS[#tyOfCall(FUNC)])
andBool isIntrinsicFunction({FUNCTIONS[#tyOfCall(FUNC)]}:>MonoItemKind)
[preserves-definedness] // callee lookup defined
requires isIntrinsicFunction(lookupFunction(#tyOfCall(FUNC)))

// Regular function call - full state switching and stack setup
rule <k> #execTerminator(terminator(terminatorKindCall(FUNC, ARGS, DEST, TARGET, UNWIND), _SPAN)) ~> _
=>
#setUpCalleeData({FUNCTIONS[#tyOfCall(FUNC)]}:>MonoItemKind, ARGS)
#setUpCalleeData(lookupFunction(#tyOfCall(FUNC)), ARGS)
</k>
<currentFunc> CALLER => #tyOfCall(FUNC) </currentFunc>
<currentFrame>
Expand All @@ -457,11 +439,7 @@ where the returned result should go.
<locals> LOCALS </locals>
</currentFrame>
<stack> STACK => ListItem(StackFrame(OLDCALLER, OLDDEST, OLDTARGET, OLDUNWIND, LOCALS)) STACK </stack>
<functions> FUNCTIONS </functions>
requires #tyOfCall(FUNC) in_keys(FUNCTIONS)
andBool isMonoItemKind(FUNCTIONS[#tyOfCall(FUNC)])
andBool notBool isIntrinsicFunction({FUNCTIONS[#tyOfCall(FUNC)]}:>MonoItemKind)
[preserves-definedness] // callee lookup defined
requires notBool isIntrinsicFunction(lookupFunction(#tyOfCall(FUNC)))

syntax Bool ::= isIntrinsicFunction(MonoItemKind) [function]
rule isIntrinsicFunction(IntrinsicFunction(_)) => true
Expand Down Expand Up @@ -506,6 +484,14 @@ An operand may be a `Reference` (the only way a function could access another fu
</currentFrame>
// TODO: Haven't handled "noBody" case

syntax List ::= #reserveFor( LocalDecls ) [function, total]

rule #reserveFor(.LocalDecls) => .List

rule #reserveFor(localDecl(TY, _, MUT) REST:LocalDecls)
=>
ListItem(newLocal(TY, MUT)) #reserveFor(REST)


syntax KItem ::= #setArgsFromStack ( Int, Operands)
| #setArgFromStack ( Int, Operand)
Expand Down Expand Up @@ -631,11 +617,10 @@ Execution gets stuck (no matching rule) when operands have different types or un
```k
// Raw eq: dereference operands, extract types, and delegate to typed comparison
rule <k> #execIntrinsic(IntrinsicFunction(symbol("raw_eq")), ARG1:Operand ARG2:Operand .Operands, PLACE)
=> #execRawEqTyped(PLACE, #withDeref(ARG1), #extractOperandType(#withDeref(ARG1), LOCALS, TYPEMAP),
#withDeref(ARG2), #extractOperandType(#withDeref(ARG2), LOCALS, TYPEMAP))
=> #execRawEqTyped(PLACE, #withDeref(ARG1), #extractOperandType(#withDeref(ARG1), LOCALS),
#withDeref(ARG2), #extractOperandType(#withDeref(ARG2), LOCALS))
... </k>
<locals> LOCALS </locals>
<types> TYPEMAP </types>

// Compare values only if types are identical
syntax KItem ::= #execRawEqTyped(Place, Evaluation, MaybeTy, Evaluation, MaybeTy) [seqstrict(2,4)]
Expand All @@ -655,17 +640,17 @@ Execution gets stuck (no matching rule) when operands have different types or un
rule #withDeref(OP) => OP [owise]

// Extract type from operands (locals with projections, constants, fallback to unknown)
syntax MaybeTy ::= #extractOperandType(Operand, List, Map) [function, total]
rule #extractOperandType(operandCopy(place(local(I), PROJS)), LOCALS, TYPEMAP)
=> getTyOf(tyOfLocal({LOCALS[I]}:>TypedLocal), PROJS, TYPEMAP)
syntax MaybeTy ::= #extractOperandType(Operand, List) [function, total]
rule #extractOperandType(operandCopy(place(local(I), PROJS)), LOCALS)
=> getTyOf(tyOfLocal({LOCALS[I]}:>TypedLocal), PROJS)
requires 0 <=Int I andBool I <Int size(LOCALS) andBool isTypedLocal(LOCALS[I])
[preserves-definedness]
rule #extractOperandType(operandMove(place(local(I), PROJS)), LOCALS, TYPEMAP)
=> getTyOf(tyOfLocal({LOCALS[I]}:>TypedLocal), PROJS, TYPEMAP)
rule #extractOperandType(operandMove(place(local(I), PROJS)), LOCALS)
=> getTyOf(tyOfLocal({LOCALS[I]}:>TypedLocal), PROJS)
requires 0 <=Int I andBool I <Int size(LOCALS) andBool isTypedLocal(LOCALS[I])
[preserves-definedness]
rule #extractOperandType(operandConstant(constOperand(_, _, mirConst(_, TY, _))), _, _) => TY
rule #extractOperandType(_, _, _) => TyUnknown [owise]
rule #extractOperandType(operandConstant(constOperand(_, _, mirConst(_, TY, _))), _) => TY
rule #extractOperandType(_, _) => TyUnknown [owise]
```

### Stopping on Program Errors
Expand Down Expand Up @@ -694,6 +679,6 @@ The top-level module `KMIR` includes both the control flow constructs (and trans
module KMIR
imports KMIR-CONTROL-FLOW
imports KMIR-LEMMAS
imports KMIR-SYMBOLIC-LOCALS
// imports KMIR-SYMBOLIC-LOCALS

endmodule
22 changes: 14 additions & 8 deletions kmir/src/kmir/kdist/mir-semantics/rt/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,21 @@ module KMIR-CONFIGURATION
</currentFrame>
// remaining call stack (without top frame)
<stack> .List </stack>
// static and dynamic allocations: AllocId -> Value
<memory> .Map </memory>
// ============ static information ============
// function store, Ty -> MonoItemFn
<functions> .Map </functions>
<start-symbol> symbol($STARTSYM:String) </start-symbol>
// static information about the base type interning in the MIR
<types> .Map </types>
</kmir>
```

Additional fields of the configuration contain _static_ information.

* The function store mapping `Ty` to `MonoItemFn` (and `IntrinsicFn`). This is essentially the entire program.
* The allocation store, mapping `AllocId` to `Value` (or error markers if undecoded)
* The type metadata map, associating `Ty` with a `TypeInfo` (which may contain more `Ty`s)
* The mapping from `AdtDef` ID to `Ty`

For better performance, this information is reified to K functions,
rather than carrying static `Map` structures with the configuration.

The functions are defined in the `RT-VALUE` module for now but should have their own module.

```k
endmodule
```
Loading