@fraczak/k 7.0.1 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/DOCS/BIG_PICTURE.md +5 -5
- package/DOCS/FILE_FORMATS.md +241 -18
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +9 -9
- package/DOCS/PATTERNS.md +3 -3
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/DOCS/PROFILING_AND_TRACING.md +60 -72
- package/DOCS/REPL.md +3 -3
- package/DOCS/book/03-types-as-finite-automata.md +4 -4
- package/DOCS/book/06-values-in-memory.md +9 -9
- package/DOCS/book/08-operational-semantics-and-execution.md +1 -1
- package/DOCS/book/09-compiler-architecture.md +2 -2
- package/DOCS/book/10-from-ast-to-intermediate-representation.md +2 -2
- package/DOCS/book/14-canonical-serialization.md +1 -1
- package/Examples/arithmetics.k +2 -2
- package/Examples/bnat.k +1 -1
- package/Examples/karatsuba-mult.k +2 -2
- package/JOURNAL.md +288 -0
- package/README.md +13 -10
- package/access-table.mjs +343 -0
- package/backend-api.mjs +18 -0
- package/backends/llvm/README.md +20 -21
- package/backends/llvm/bin/k-llvm-build.mjs +105 -32
- package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
- package/backends/llvm/bin/k-llvm.mjs +292 -0
- package/backends/llvm/runtime/krt.c +41 -0
- package/backends/llvm/runtime/krt.h +2 -0
- package/backends/llvm/src/cli.mjs +95 -17
- package/backends/llvm/src/executable.mjs +132 -15
- package/backends/llvm/src/kvm2llvm.mjs +50 -23
- package/backends/llvm/src/llvm.mjs +133 -20
- package/backends/llvm/tests/integration.sh +11 -11
- package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
- package/backends/llvm/tests/perf-support.mjs +25 -58
- package/backends/llvm/tests/test-llvm.mjs +25 -4
- package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
- package/backends/wasm/bin/k-wasm-run.mjs +61 -20
- package/backends/wasm/bin/k-wasm.mjs +47 -13
- package/backends/wasm/src/cli.mjs +141 -19
- package/backends/wasm/src/wasm.mjs +132 -24
- package/backends/wasm/tests/test-wasm.mjs +5 -5
- package/browser/repl-browser.mjs +16 -5
- package/browser/vfs-data.mjs +5 -5
- package/codecs/k-parse.mjs +29 -8
- package/codecs/k-print.mjs +22 -6
- package/codecs/runtime/codec-sdk.mjs +8 -4
- package/codecs/show.mjs +20 -6
- package/core.k +8 -8
- package/harness/format.mjs +2 -2
- package/harness/registry.mjs +0 -2
- package/k.mjs +56 -16
- package/kir.mjs +200 -75
- package/kvm.mjs +49 -12
- package/objects/compile.mjs +37 -23
- package/objects/decompile.mjs +40 -10
- package/objects/extract-aliases.mjs +44 -14
- package/objects/inspect.mjs +19 -14
- package/objects/validate.mjs +18 -11
- package/package.json +10 -7
- package/pkir.mjs +772 -0
- package/repl.mjs +36 -18
- package/scripts/benchmark-idempotency.mjs +12 -8
- package/scripts/benchmark.mjs +5 -9
- package/scripts/build-repl-html.mjs +16 -4
- package/scripts/perf-ieee.mjs +253 -103
- package/scripts/perf-int.mjs +585 -297
- package/scripts/perf-multiplication.mjs +66 -25
- package/scripts/perf-poly.mjs +292 -164
- package/scripts/run-tests.mjs +3 -0
- package/tests/code-derivation/pattern-envelope.mjs +4 -4
- package/tests/test-access-table.mjs +213 -0
- package/tests/test-kvm-polymorphic.mjs +2 -2
- package/tests/test-pkir.mjs +530 -0
- package/tests/test-polymorphic-tdd.mjs +196 -0
- package/tests/test-repl-html.mjs +15 -2
- package/tests/test-repl.mjs +30 -1
- package/backends/arm64/README.md +0 -103
- package/backends/arm64/bin/k-arm64-compile.mjs +0 -93
- package/backends/arm64/bin/k-arm64-run.mjs +0 -58
- package/backends/arm64/bin/k-arm64.mjs +0 -88
- package/backends/arm64/scripts/run-tests.mjs +0 -57
- package/backends/arm64/src/arm64.mjs +0 -229
- package/backends/arm64/src/cli.mjs +0 -155
- package/backends/arm64/src/kvm2arm64.mjs +0 -906
- package/backends/arm64/src/runtime.c +0 -744
- package/backends/arm64/tests/integration.sh +0 -112
- package/backends/arm64/tests/test-arm64.mjs +0 -240
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
- package/harness/adapters/arm64.mjs +0 -105
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,78 @@ All notable changes to this project will be documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
6
|
This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [7.1.0] — 2026-10-16 — Polymorphic K IR (PKIR) & CLI Standardization
|
|
9
|
+
|
|
10
|
+
### Features & Architecture Improvements
|
|
11
|
+
|
|
12
|
+
- **Polymorphic K IR (PKIR) & Access Table Engine**:
|
|
13
|
+
- Implemented `pkir.mjs` providing an intermediate representation
|
|
14
|
+
tailored for polymorphic relations with variant dispatch, projection
|
|
15
|
+
tables, and partial function failure semantics.
|
|
16
|
+
- Implemented `access-table.mjs` (`buildAccessTable`) for resolving
|
|
17
|
+
field offsets and variant selectors across arbitrary schemas.
|
|
18
|
+
- Added PKIR specialization (`specializePKIR`) eliminating dead
|
|
19
|
+
branches and baking in direct physical offsets.
|
|
20
|
+
- Supported PKIR execution and standalone executable generation across
|
|
21
|
+
both WebAssembly and LLVM backends.
|
|
22
|
+
- Added dedicated test suites: `tests/test-pkir.mjs`,
|
|
23
|
+
`tests/test-access-table.mjs`, and `tests/test-polymorphic-tdd.mjs`.
|
|
24
|
+
- Added specification and documentation in `DOCS/POLYMORPHIC_IR.md`
|
|
25
|
+
and updated `DOCS/FILE_FORMATS.md`.
|
|
26
|
+
|
|
27
|
+
- **Web REPL (`repl.html`) & Wasm Integration**:
|
|
28
|
+
- Enabled `.pkir` generation and lowering to WebAssembly in
|
|
29
|
+
`repl.mjs` and `repl.html`.
|
|
30
|
+
- Promoted Web REPL visibility in `README.md` (top banner,
|
|
31
|
+
zero-install section, further reading).
|
|
32
|
+
|
|
33
|
+
- **Multi-Backend CLI Standardization & Help Completeness**:
|
|
34
|
+
- Standardized CLI syntax, argument parsing, options, and help text
|
|
35
|
+
(`-h` / `--help`) across tools in `backends/*/bin/` and
|
|
36
|
+
`objects/`.
|
|
37
|
+
- Consolidated `backends/llvm/bin/` (`k-llvm.mjs`, `k-llvm-build.mjs`,
|
|
38
|
+
`k-llvm-compile.mjs`) to mirror `backends/wasm/bin/`.
|
|
39
|
+
- Aligned `--lib` and `--export` options across LLVM, Wasm, and object
|
|
40
|
+
tools.
|
|
41
|
+
- Documented explicit defaults (such as cache directories, Clang
|
|
42
|
+
optimization levels, and runtime modes) in CLI help texts.
|
|
43
|
+
|
|
44
|
+
- **Concurrent Multi-Backend Performance Benchmarks**:
|
|
45
|
+
- Added concurrent `llvm` and `llvm-pkir` execution lanes across all
|
|
46
|
+
performance suites (`perf:ieee`, `perf:int`, `perf:poly`,
|
|
47
|
+
`perf:mult`).
|
|
48
|
+
- Documented benchmark findings and throughput in `JOURNAL.md`.
|
|
49
|
+
|
|
50
|
+
## [7.0.2] — 2026-10-13 — LLVM Squaring Scaling & Backend Streamlining
|
|
51
|
+
|
|
52
|
+
### Features & Performance Improvements
|
|
53
|
+
|
|
54
|
+
- **Multiplication Algorithm Scaling Benchmark (LLVM & Multi-Backend)**:
|
|
55
|
+
- Added successive squaring scale benchmark comparing standard long
|
|
56
|
+
multiplication (`times`) and Karatsuba multiplication (`karatsuba`)
|
|
57
|
+
across bit lengths doubling up to 7,650+ bits.
|
|
58
|
+
- Added support for squaring execution and memory (peak RSS / heap)
|
|
59
|
+
tracking across LLVM, WebAssembly, and interpreter lanes.
|
|
60
|
+
- Aligned product field layouts and offset indexing in `kvm2llvm.mjs`.
|
|
61
|
+
|
|
62
|
+
### Bug Fixes & Compatibility
|
|
63
|
+
|
|
64
|
+
- **LLVM Open/Closed Pattern Compatibility on Wire Input**:
|
|
65
|
+
- Allowed open and closed pattern compatibility when validating and
|
|
66
|
+
unpacking wire inputs in the LLVM runtime (`krt.c` and
|
|
67
|
+
`executable.mjs`).
|
|
68
|
+
- Gracefully accepts framed inputs matching open-product schemas.
|
|
69
|
+
|
|
70
|
+
### Chores & Maintenance
|
|
71
|
+
|
|
72
|
+
- **Backend Streamlining (Wasm & LLVM Focus)**:
|
|
73
|
+
- Removed legacy experimental ARM64 backend (`backends/arm64`) to focus
|
|
74
|
+
on WebAssembly (portable) and LLVM (native) backends.
|
|
75
|
+
- Updated documentation (`DOCS/FILE_FORMATS.md`,
|
|
76
|
+
`DOCS/PROFILING_AND_TRACING.md`) and benchmark suites.
|
|
77
|
+
- Enhanced pattern graph specialization and KIR monomorphization in
|
|
78
|
+
`kir.mjs`.
|
|
79
|
+
|
|
8
80
|
## [7.0.1] — 2026-10-10 — Call-Graph Pattern Graph Specialization
|
|
9
81
|
|
|
10
82
|
### Bug Fixes & Backend Alignments
|
|
@@ -18,6 +90,12 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
18
90
|
memory layout (`tagId` at header slots).
|
|
19
91
|
- Resolved polymorphic list and open product projection alignment across
|
|
20
92
|
LLVM, WASM, and Web REPL.
|
|
93
|
+
- **Filter Relation Naming Convention (`?` Suffix)**:
|
|
94
|
+
- Standardized naming convention for all filter and schema relations to use
|
|
95
|
+
the `?` suffix (e.g. `int?`, `bits?`, `bit?`, `string?`, `pattern?`,
|
|
96
|
+
`bnat?`, `nat?`, `bool?`, matching `list?`).
|
|
97
|
+
- Separated integer filter schema `int? = ?<...>` from constructor
|
|
98
|
+
`int = nat | '+'` in `Examples/arithmetics.k`, removing symbol collision.
|
|
21
99
|
|
|
22
100
|
## [7.0.0] — 2026-10-10 — Unified Schemas, Relational Contracts, and Pure Syntax
|
|
23
101
|
|
package/DOCS/BIG_PICTURE.md
CHANGED
|
@@ -49,7 +49,7 @@ set of pairwise distinct labels `l1, l2, ..., ln`:
|
|
|
49
49
|
- Variant values are constructed using "|" (pipe) followed by the tag:
|
|
50
50
|
- Unit variant: `{} | nil`, `{} | zero`
|
|
51
51
|
- Variant with payload `v` at tag: `v | tag`
|
|
52
|
-
- Example (list): with `list = ?< {} nil, { X car, L cdr } cons > = L;`:
|
|
52
|
+
- Example (list): with `list? = ?< {} nil, { X car, L cdr } cons > = L;`:
|
|
53
53
|
- Empty list `[]`: `{} | nil`
|
|
54
54
|
- Singleton `[v]`: `{ v car, {} | nil cdr } | cons`
|
|
55
55
|
- Angle brackets `< ... >` denote ordered choice (union expressions); use
|
|
@@ -202,14 +202,14 @@ The contract derivation steps are:
|
|
|
202
202
|
#### Example 1
|
|
203
203
|
|
|
204
204
|
```text
|
|
205
|
-
bit = ?< {} o, {} i >;
|
|
205
|
+
bit? = ?< {} o, {} i >;
|
|
206
206
|
bit0 = | o;
|
|
207
207
|
bit1 = | i;
|
|
208
208
|
|
|
209
|
-
byte = ?{ bit b0, bit b1, bit b2, bit b3 };
|
|
209
|
+
byte? = ?{ bit? b0, bit? b1, bit? b2, bit? b3 };
|
|
210
210
|
zero = bit0 { () b0, () b1, () b2, () b3 };
|
|
211
211
|
|
|
212
|
-
inc = byte
|
|
212
|
+
inc = byte?
|
|
213
213
|
<
|
|
214
214
|
{ bit0 overflown, { .b0 /o bit1 b0, .b1 b1, .b2 b2, .b3 b3 } byte },
|
|
215
215
|
{ bit0 overflown, { bit0 b0, .b1 /o bit1 b1, .b2 b2, .b3 b3 } byte },
|
|
@@ -347,7 +347,7 @@ conversion via `5 int`.
|
|
|
347
347
|
Bit trees are defined algebraically:
|
|
348
348
|
|
|
349
349
|
```text
|
|
350
|
-
bits = ?< {} _, B 0, B 1 > = B;
|
|
350
|
+
bits? = ?< {} _, B 0, B 1 > = B;
|
|
351
351
|
```
|
|
352
352
|
|
|
353
353
|
### Literals for `@bits` are:
|
package/DOCS/FILE_FORMATS.md
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
# File Formats in the K Universe
|
|
2
2
|
|
|
3
|
-
The `k` toolchain operates across
|
|
4
|
-
`.ko`, `.klib`, and `.
|
|
5
|
-
in the pipeline from human-authored source to ahead-of-time
|
|
6
|
-
type-checked artifacts
|
|
3
|
+
The `k` toolchain operates across five primary file formats: `.k`,
|
|
4
|
+
`.ko`, `.klib`, `.kvm`, and `.pkir`. Each format occupies a distinct
|
|
5
|
+
position in the pipeline from human-authored source to ahead-of-time
|
|
6
|
+
(AOT) type-checked artifacts, intermediate representations, and
|
|
7
|
+
JIT/native execution.
|
|
7
8
|
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
## Overview & Comparison
|
|
11
12
|
|
|
12
|
-
| Extension
|
|
13
|
-
|
|
14
|
-
| **`.k`**
|
|
15
|
-
| **`.ko`**
|
|
16
|
-
| **`.klib
|
|
17
|
-
| **`.kvm`** | Polymorphic kVM
|
|
13
|
+
| Extension | Role | Format / Magic | Entrypoint |
|
|
14
|
+
|:---:|:---|:---|:---|
|
|
15
|
+
| **`.k`** | Human source code | UTF-8 plain text | Optional |
|
|
16
|
+
| **`.ko`** | Executable object | Binary (`KOBJ\n`) | Required |
|
|
17
|
+
| **`.klib`** | Reusable library | UTF-8 JSON | None |
|
|
18
|
+
| **`.kvm`** | Polymorphic kVM IR | `k-vm` (KVM-P) | Relations |
|
|
19
|
+
| **`.pkir`** | Polymorphic IR | `pk-ir` (v1) | Relations |
|
|
20
|
+
|
|
21
|
+
| Extension | Generated By | Consumed By |
|
|
22
|
+
|:---:|:---|:---|
|
|
23
|
+
| **`.k`** | Editor, `k-decompile` | `k.mjs`, `k-compile`, backends |
|
|
24
|
+
| **`.ko`** | `k-compile`, REPL (`:ko`) | `k.mjs`, backends, tools |
|
|
25
|
+
| **`.klib`** | `k-compile --lib` | REPL, linkers (`--lib`) |
|
|
26
|
+
| **`.kvm`** | `k-compile --format kvm` | `kvm.mjs`, backends |
|
|
27
|
+
| **`.pkir`** | `compileRelationToPKIR` | `executePKIR`, specializer |
|
|
18
28
|
|
|
19
29
|
### Format Transformation Workflow
|
|
20
30
|
|
|
@@ -30,20 +40,22 @@ flowchart TD
|
|
|
30
40
|
KO[".ko (Executable Object)"]
|
|
31
41
|
end
|
|
32
42
|
|
|
33
|
-
subgraph IR_Artifacts ["
|
|
34
|
-
KVM[".kvm (
|
|
43
|
+
subgraph IR_Artifacts ["Intermediate Representations"]
|
|
44
|
+
KVM[".kvm (kVM Bytecode)"]
|
|
45
|
+
PKIR[".pkir (Polymorphic IR)"]
|
|
35
46
|
end
|
|
36
47
|
|
|
37
48
|
subgraph Targets ["Execution Targets"]
|
|
38
49
|
WASM[".wasm (WebAssembly)"]
|
|
39
50
|
NATIVE["Native Binary"]
|
|
40
|
-
INTERP["Interpreter
|
|
51
|
+
INTERP["Interpreter / kVM / PKIR"]
|
|
41
52
|
end
|
|
42
53
|
|
|
43
54
|
%% Transformations from .k
|
|
44
55
|
K -->|"k-compile"| KO
|
|
45
56
|
K -->|"k-compile --lib"| KLIB
|
|
46
57
|
K -->|"k-compile --format kvm"| KVM
|
|
58
|
+
K -->|"compileRelationToPKIR"| PKIR
|
|
47
59
|
K -->|":load"| REPL
|
|
48
60
|
|
|
49
61
|
%% REPL exports
|
|
@@ -60,11 +72,22 @@ flowchart TD
|
|
|
60
72
|
KO -->|"k-llvm-build"| NATIVE
|
|
61
73
|
KO -->|"k.mjs"| INTERP
|
|
62
74
|
KO -->|"k-decompile"| K
|
|
75
|
+
KO -->|"compileRelationToPKIR"| PKIR
|
|
63
76
|
|
|
64
77
|
%% Lowering from .kvm
|
|
65
78
|
KVM -->|"k-wasm-compile"| WASM
|
|
66
79
|
KVM -->|"k-llvm-build"| NATIVE
|
|
67
80
|
KVM -->|"kvm.mjs / specializeKVM"| INTERP
|
|
81
|
+
|
|
82
|
+
%% Execution and Specialization from .pkir
|
|
83
|
+
PKIR -->|"executePKIR + AccessTable"| INTERP
|
|
84
|
+
PKIR -->|"specializePKIR"| PKIR_SPEC["Specialized PKIR"]
|
|
85
|
+
PKIR -->|"k-wasm-compile"| WASM
|
|
86
|
+
PKIR -->|"k-llvm-compile"| LLVM[".ll (LLVM IR)"]
|
|
87
|
+
PKIR -->|"k-llvm-build"| NATIVE
|
|
88
|
+
PKIR_SPEC -->|"executePKIR"| INTERP
|
|
89
|
+
PKIR_SPEC -->|"backend lowering"| WASM
|
|
90
|
+
PKIR_SPEC -->|"backend lowering"| NATIVE
|
|
68
91
|
```
|
|
69
92
|
|
|
70
93
|
---
|
|
@@ -288,12 +311,12 @@ Export all currently loaded relations and types into a reusable library:
|
|
|
288
311
|
`make_variant`, `project_variant`, `jump_if_fail`, `call`, and loops).
|
|
289
312
|
|
|
290
313
|
2. **$1 \times N$ Backend Decoupling:**
|
|
291
|
-
Rather than having every code generator (LLVM, WebAssembly,
|
|
292
|
-
|
|
314
|
+
Rather than having every code generator (LLVM, WebAssembly, and the
|
|
315
|
+
interpreter) independently lower the relational tree and
|
|
293
316
|
re-implement type-guided control flow, relational-to-imperative
|
|
294
317
|
lowering occurs once in `kvm.mjs`. All backends consume the exact same
|
|
295
318
|
~10 linear kVM instructions (`kvm2llvm.mjs`, `kvm2wasm.mjs`,
|
|
296
|
-
`
|
|
319
|
+
`kvm.mjs`).
|
|
297
320
|
|
|
298
321
|
3. **Microsecond Polymorphic Specialization (`layer: "KVM-P"`):**
|
|
299
322
|
In polymorphic programs, specializing `.ko` requires re-running the
|
|
@@ -365,6 +388,204 @@ k-compile add5.ko add5.kvm
|
|
|
365
388
|
|
|
366
389
|
---
|
|
367
390
|
|
|
391
|
+
## 5. `.pkir` — Polymorphic K Intermediate Representation File
|
|
392
|
+
|
|
393
|
+
### What It Is
|
|
394
|
+
`.pkir` is a state-indexed, slot-addressed intermediate representation
|
|
395
|
+
artifact (`format: "pk-ir"`, `version: 1`).
|
|
396
|
+
|
|
397
|
+
While `.kvm` models imperative register control-flow using symbolic
|
|
398
|
+
field strings (`project_field`, `inst.label`), `.pkir` addresses the
|
|
399
|
+
fundamental data-layout problem for polymorphic functions. It unifies
|
|
400
|
+
streaming bitstream processing and random-access memory tables:
|
|
401
|
+
|
|
402
|
+
1. **Slot Addressing & State Indexing:**
|
|
403
|
+
Eliminates all runtime string lookups (`val.product[label]`). Every
|
|
404
|
+
field access is compiled to an integer slot relative to an abstract
|
|
405
|
+
pattern state (`project_slot`, `slot`, `state`). Every variant test
|
|
406
|
+
is compiled to a branch index (`match_variant`, `branchId`, `state`).
|
|
407
|
+
|
|
408
|
+
2. **Duality of Transducers & Witnesses:**
|
|
409
|
+
- **Streaming Pushdown Transducers:** Navigates prefix-free serialized
|
|
410
|
+
wire streams using static skip counts (`skipCount`). Erasing and
|
|
411
|
+
linear operations execute in $O(\text{depth})$ stack memory with zero
|
|
412
|
+
node materialization.
|
|
413
|
+
- **Layout Witnesses (`AccessTable`):** Operates on random-access
|
|
414
|
+
memory arenas. Given any concrete input schema $S$ and function
|
|
415
|
+
access profile $P$, `buildAccessTable(S, P)` resolves physical byte
|
|
416
|
+
offsets $\Omega(S, P)$ in a single array load.
|
|
417
|
+
|
|
418
|
+
3. **Hybrid `KVal` Fat-Pointer Representation:**
|
|
419
|
+
Values remain compact serialized wire slices by default. When
|
|
420
|
+
non-linear access occurs (e.g. repeated reads or field reordering),
|
|
421
|
+
demand-driven **Spine Promotion** materializes only the outer product
|
|
422
|
+
node into an arena record while leaving child payloads as untouched
|
|
423
|
+
slices. Opaque payloads are never re-encoded or reconstructed.
|
|
424
|
+
|
|
425
|
+
### Payload Structure
|
|
426
|
+
|
|
427
|
+
A `.pkir` artifact is structured as follows:
|
|
428
|
+
|
|
429
|
+
```json
|
|
430
|
+
{
|
|
431
|
+
"format": "pk-ir",
|
|
432
|
+
"version": 1,
|
|
433
|
+
"name": "extract_id",
|
|
434
|
+
"inputReg": "%v0",
|
|
435
|
+
"outputReg": "%v1",
|
|
436
|
+
"inputPattern": 3,
|
|
437
|
+
"outputPattern": 4,
|
|
438
|
+
"patternGraph": { ... },
|
|
439
|
+
"accessProfile": {
|
|
440
|
+
"0": { "fields": ["id"], "variants": [] },
|
|
441
|
+
"3": { "fields": [], "variants": ["click", "sensor", "ping"] }
|
|
442
|
+
},
|
|
443
|
+
"instructions": [
|
|
444
|
+
{
|
|
445
|
+
"op": "union",
|
|
446
|
+
"dest": "%v1",
|
|
447
|
+
"src": "%v0",
|
|
448
|
+
"branches": [ ... ]
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
#### Instruction Set Summary
|
|
455
|
+
- `id`: Register assignment (`{ op: "id", dest, src }`).
|
|
456
|
+
- `project_slot`: State-indexed slot projection
|
|
457
|
+
(`{ op: "project_slot", dest, src, state, slot, label }`).
|
|
458
|
+
- `match_variant`: State-indexed variant match
|
|
459
|
+
(`{ op: "match_variant", dest, src, state, tag, branchId }`).
|
|
460
|
+
- `make_variant`: Variant construction
|
|
461
|
+
(`{ op: "make_variant", dest, src, tag }`).
|
|
462
|
+
- `product`: Product construction with sub-instruction streams.
|
|
463
|
+
- `union`: Multi-branch selection with failure backtracking.
|
|
464
|
+
- `call_rel`: Relation call / recursion
|
|
465
|
+
(`{ op: "call_rel", dest, ref, src }`).
|
|
466
|
+
- `fail`: Unconditional branch failure (`{ op: "fail" }`).
|
|
467
|
+
- **Specialized Instructions:**
|
|
468
|
+
- `project_offset`: Direct memory offset projection:
|
|
469
|
+
`{ op: "project_offset", dest, src, offset, skipCount, childState }`.
|
|
470
|
+
- `match_tag_imm`: Immediate discriminator test
|
|
471
|
+
(`{ op: "match_tag_imm", dest, src, tagId, branchId, childState }`).
|
|
472
|
+
|
|
473
|
+
### Why `.pkir` Exists (What You Gain)
|
|
474
|
+
|
|
475
|
+
1. **Elimination of the Envelope Tax (26x Speedup):**
|
|
476
|
+
Previous polymorphic execution required wrapping values in dynamic
|
|
477
|
+
envelopes $(v, P_v)$, suffering a 26x performance penalty during
|
|
478
|
+
envelope packing/unpacking (`scripts/perf-poly.mjs`). PKIR navigates
|
|
479
|
+
heterogeneous records directly via layout witnesses without envelopes.
|
|
480
|
+
|
|
481
|
+
2. **Sub-30µs Specialization Latency:**
|
|
482
|
+
`specializePKIR` bakes static byte offsets into instructions and prunes
|
|
483
|
+
dead union branches in ~27 microseconds (compared to 100–1500 ms for
|
|
484
|
+
traditional AOT/Wasm compilation), enabling instant JIT tiering.
|
|
485
|
+
|
|
486
|
+
3. **Zero Payload Re-Encoding:**
|
|
487
|
+
Preserves arbitrary opaque payloads (`data: payload_i`) as byte slices
|
|
488
|
+
without traversal or re-serialization during recursive list
|
|
489
|
+
processing (`search`, `poly_rev`).
|
|
490
|
+
|
|
491
|
+
4. **1:1 Machine Code Lowering:**
|
|
492
|
+
Specialized PKIR instructions map directly to WebAssembly (`i64.load
|
|
493
|
+
offset=C`, `i32.eq`) and LLVM machine instructions without dynamic
|
|
494
|
+
runtime fallbacks (`@k_product_get_n`).
|
|
495
|
+
|
|
496
|
+
### How to Generate
|
|
497
|
+
|
|
498
|
+
In JavaScript / Node.js API:
|
|
499
|
+
```javascript
|
|
500
|
+
import { compileRelationToPKIR } from "@fraczak/k/backend-api.mjs";
|
|
501
|
+
|
|
502
|
+
const pkir = compileRelationToPKIR(relDef, "extract_id");
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### How to Consume
|
|
506
|
+
|
|
507
|
+
- **Direct Execution with AccessTable:**
|
|
508
|
+
```javascript
|
|
509
|
+
import {
|
|
510
|
+
executePKIR,
|
|
511
|
+
buildAccessTable,
|
|
512
|
+
valueToKVal,
|
|
513
|
+
kvalToValue
|
|
514
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
515
|
+
|
|
516
|
+
const table = buildAccessTable(schemaS, patternP);
|
|
517
|
+
const kval = valueToKVal(inputVal, table.rootState);
|
|
518
|
+
const resKval = executePKIR(pkir, kval, table);
|
|
519
|
+
const result = kvalToValue(resKval);
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
- **Monomorphic Specialization (`specializePKIR`):**
|
|
523
|
+
```javascript
|
|
524
|
+
import {
|
|
525
|
+
specializePKIR,
|
|
526
|
+
executePKIR
|
|
527
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
528
|
+
|
|
529
|
+
// Inlines static byte offsets and prunes dead union branches:
|
|
530
|
+
const specialized = specializePKIR(pkir, table);
|
|
531
|
+
|
|
532
|
+
// Executes with zero table overhead:
|
|
533
|
+
const result = executePKIR(specialized, kval, null);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
- **Lowering to WebAssembly (`compileWasmArtifactFromPKIR`):**
|
|
537
|
+
```javascript
|
|
538
|
+
import {
|
|
539
|
+
compileWasmArtifactFromPKIR
|
|
540
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
541
|
+
|
|
542
|
+
const wasmBytes = await compileWasmArtifactFromPKIR(pkir);
|
|
543
|
+
```
|
|
544
|
+
CLI commands:
|
|
545
|
+
```bash
|
|
546
|
+
# Compile .pkir directly to WebAssembly binary:
|
|
547
|
+
node backends/wasm/bin/k-wasm-compile.mjs input.pkir -o prog.wasm
|
|
548
|
+
|
|
549
|
+
# Lower .k source via PKIR to WebAssembly:
|
|
550
|
+
node backends/wasm/bin/k-wasm-compile.mjs --pkir prog.k -o prog.wasm
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
- **Lowering to LLVM IR & Native Binaries:**
|
|
554
|
+
```javascript
|
|
555
|
+
import {
|
|
556
|
+
compileLLVMArtifactFromPKIR
|
|
557
|
+
} from "@fraczak/k/backend-api.mjs";
|
|
558
|
+
import {
|
|
559
|
+
compilePKIRToExecutable,
|
|
560
|
+
compilePKIRAndRun
|
|
561
|
+
} from "@fraczak/k/backends/llvm/src/executable.mjs";
|
|
562
|
+
|
|
563
|
+
// Compile PKIR directly to LLVM IR string:
|
|
564
|
+
const llvmIR = compileLLVMArtifactFromPKIR(pkir);
|
|
565
|
+
|
|
566
|
+
// Compile PKIR directly to a native executable:
|
|
567
|
+
compilePKIRToExecutable(pkir, "./prog.exe");
|
|
568
|
+
|
|
569
|
+
// Compile and execute in one step:
|
|
570
|
+
const res = compilePKIRAndRun(pkir, { input: inputVal });
|
|
571
|
+
```
|
|
572
|
+
CLI commands:
|
|
573
|
+
```bash
|
|
574
|
+
# Compile .pkir directly to LLVM IR:
|
|
575
|
+
node backends/llvm/bin/k-llvm-compile.mjs input.pkir -o prog.ll
|
|
576
|
+
|
|
577
|
+
# Lower .k source via PKIR to LLVM IR:
|
|
578
|
+
node backends/llvm/bin/k-llvm-compile.mjs --pkir prog.k -o prog.ll
|
|
579
|
+
|
|
580
|
+
# Compile .pkir directly to native executable:
|
|
581
|
+
node backends/llvm/bin/k-llvm-build.mjs input.pkir -o prog.exe
|
|
582
|
+
|
|
583
|
+
# Lower .k source via PKIR to native executable:
|
|
584
|
+
node backends/llvm/bin/k-llvm-build.mjs --pkir prog.k -o prog.exe
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
368
589
|
## Practical Rules & Common Gotchas
|
|
369
590
|
|
|
370
591
|
### 1. Library Aliases Require Explicit `--export`
|
|
@@ -398,9 +619,11 @@ In `k`, there are no primitive numerical types or built-in integer
|
|
|
398
619
|
literals. Identifiers such as `5` or `10` are not language keywords;
|
|
399
620
|
they are defined relations (aliases) in `Examples/arithmetics.k`:
|
|
400
621
|
- `5` and `10` are nullary relations (constants) of type `{} -> bits`,
|
|
401
|
-
defined as binary digit trees over
|
|
622
|
+
defined as binary digit trees over:
|
|
623
|
+
`bits? = ?< {} _, bits? 0, bits? 1 > = bits?;`.
|
|
402
624
|
- Arithmetic operations (`plus`, `minus`, `times`, `inc`) operate on
|
|
403
|
-
signed integers
|
|
625
|
+
signed integers:
|
|
626
|
+
`int? = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" >`.
|
|
404
627
|
- Passing a bit-representation like `5` to an integer relation requires
|
|
405
628
|
applying the `int` constructor (`5 int`), producing a constant
|
|
406
629
|
relation of type `{} -> int`.
|
|
@@ -15,18 +15,18 @@ The pattern is the framing protocol. There is no separate envelope type.
|
|
|
15
15
|
[`core.k`](../core.k) defines the canonical self-hosted pattern type:
|
|
16
16
|
|
|
17
17
|
```k
|
|
18
|
-
edge = ?{ string label, bits target };
|
|
19
|
-
edges = ?< {} nil, { edge car, E cdr } cons > = E;
|
|
18
|
+
edge? = ?{ string? label, bits? target };
|
|
19
|
+
edges? = ?< {} nil, { edge? car, E cdr } cons > = E;
|
|
20
20
|
|
|
21
|
-
pattern-node = ?<
|
|
21
|
+
pattern-node? = ?<
|
|
22
22
|
{} any,
|
|
23
|
-
edges open-product,
|
|
24
|
-
edges open-union,
|
|
25
|
-
edges closed-product,
|
|
26
|
-
edges closed-union
|
|
23
|
+
edges? open-product,
|
|
24
|
+
edges? open-union,
|
|
25
|
+
edges? closed-product,
|
|
26
|
+
edges? closed-union
|
|
27
27
|
>;
|
|
28
28
|
|
|
29
|
-
pattern = ?< {} nil, { pattern-node car, P cdr } cons > = P;
|
|
29
|
+
pattern? = ?< {} nil, { pattern-node? car, P cdr } cons > = P;
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
This does not mean `core.k` is pre-loaded into ordinary program execution. The
|
|
@@ -274,7 +274,7 @@ For a definitions-only source file:
|
|
|
274
274
|
|
|
275
275
|
```k
|
|
276
276
|
-- defs.k
|
|
277
|
-
nat = ?< {} zero, N succ > = N;
|
|
277
|
+
nat? = ?< {} zero, N succ > = N;
|
|
278
278
|
succ = |succ;
|
|
279
279
|
```
|
|
280
280
|
|
package/DOCS/PATTERNS.md
CHANGED
|
@@ -56,9 +56,9 @@ A k script can describe a pattern through:
|
|
|
56
56
|
Examples:
|
|
57
57
|
|
|
58
58
|
```k
|
|
59
|
-
bits = ?< {} _, bits 0, bits 1 > = bits
|
|
60
|
-
list = ?< {} nil, { < {} _, B 0, B 1 >=B car, L cdr } cons > = L;
|
|
61
|
-
list
|
|
59
|
+
bits? = ?< {} _, bits? 0, bits? 1 > = bits?;
|
|
60
|
+
list? = ?< {} nil, { < {} _, B 0, B 1 >=B car, L cdr } cons > = L;
|
|
61
|
+
list?
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
```k
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Polymorphic K Intermediate Representation (PKIR)
|
|
2
|
+
|
|
3
|
+
## 1. Overview
|
|
4
|
+
|
|
5
|
+
PKIR (Polymorphic K Intermediate Representation) is the target execution
|
|
6
|
+
contract for polymorphic `k` relations.
|
|
7
|
+
|
|
8
|
+
Unlike the high-level relational AST or traditional bytecode that
|
|
9
|
+
relies on runtime string lookups for field names and variant tags, PKIR
|
|
10
|
+
is a **state-indexed, slot-addressed intermediate representation**.
|
|
11
|
+
|
|
12
|
+
PKIR operates in two cooperating execution modes:
|
|
13
|
+
1. **Generic Polymorphic Mode**: Instructions execute against a
|
|
14
|
+
precomputed `AccessTable` (Layout Witness), accessing fields and
|
|
15
|
+
variants via static slot numbers and array lookups with zero string
|
|
16
|
+
comparisons.
|
|
17
|
+
2. **Specialized Monomorphic Mode**: Given an `AccessTable`, a fast linear
|
|
18
|
+
pass (`specializePKIR`) inlines offsets directly into immediate machine
|
|
19
|
+
instructions, pruning unreachable union branches for peak LLVM/Wasm
|
|
20
|
+
performance.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2. Core Concepts
|
|
25
|
+
|
|
26
|
+
### 2.1 The Structural Access Profile
|
|
27
|
+
|
|
28
|
+
Every PKIR relation is accompanied by an **Access Profile** derived from
|
|
29
|
+
its pattern graph:
|
|
30
|
+
- For every product pattern node $u$: a list of accessed field labels
|
|
31
|
+
defining dense, zero-based **logical slots**:
|
|
32
|
+
$$\text{fields}(u) = [ f_0, f_1, \dots, f_{k-1} ]$$
|
|
33
|
+
where slot $i$ corresponds to field $f_i$.
|
|
34
|
+
- For every union pattern node $u$: a list of matched variant tags
|
|
35
|
+
defining dense **branch targets**:
|
|
36
|
+
$$\text{variants}(u) = [ v_0, v_1, \dots, v_{m-1} ]$$
|
|
37
|
+
where branch $j$ corresponds to variant $v_j$.
|
|
38
|
+
|
|
39
|
+
### 2.2 Dual-Form Values (`KVal`)
|
|
40
|
+
|
|
41
|
+
Values in PKIR conform to the hybrid representation:
|
|
42
|
+
- **Serialized (Wire Slice)**: A pointer into an immutable prefix-free
|
|
43
|
+
bitstream, carrying a bit offset and schema state.
|
|
44
|
+
- **Materialized (Arena Node)**: An allocated record in memory containing
|
|
45
|
+
word-aligned pointers to child values.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. Instruction Set
|
|
50
|
+
|
|
51
|
+
PKIR instructions operate over a register file (`%v0`, `%v1`, ...):
|
|
52
|
+
|
|
53
|
+
### 3.1 Field & Variant Operations
|
|
54
|
+
|
|
55
|
+
- **`project_slot dest, src, state, slot`**:
|
|
56
|
+
Projects field at logical `slot` of pattern `state` from `src`.
|
|
57
|
+
At runtime with `AccessTable`:
|
|
58
|
+
```c
|
|
59
|
+
dest.ptr = src.ptr + table[src.state].slotToByteOffset[slot];
|
|
60
|
+
dest.state = table[src.state].slotToChildState[slot];
|
|
61
|
+
```
|
|
62
|
+
- **`match_tag src, state, branches`**:
|
|
63
|
+
Evaluates variant discriminator of `src` against pattern `state`.
|
|
64
|
+
At runtime with `AccessTable`:
|
|
65
|
+
```c
|
|
66
|
+
branch_idx = table[src.state].branchMap[src.tag];
|
|
67
|
+
dest.state = table[src.state].childStateMap[src.tag];
|
|
68
|
+
jump branches[branch_idx];
|
|
69
|
+
```
|
|
70
|
+
- **`make_variant dest, src, tag_id`**:
|
|
71
|
+
Wraps `src` into a tagged union with discriminator `tag_id`.
|
|
72
|
+
- **`make_product dest, [src0, src1, ...]`**:
|
|
73
|
+
Allocates a product node whose fields are registers `[src0, src1, ...]`.
|
|
74
|
+
|
|
75
|
+
### 3.2 Memory & Control Operations
|
|
76
|
+
|
|
77
|
+
- **`promote_spine dest, src`**:
|
|
78
|
+
If `src` is in serialized wire form, materializes only its immediate
|
|
79
|
+
outer record in the arena; children remain serialized wire slices.
|
|
80
|
+
If `src` is already materialized, acts as identity.
|
|
81
|
+
- **`dup dest1, dest2, src`**:
|
|
82
|
+
Zero-copy duplication of a value handle.
|
|
83
|
+
- **`call_rel dest, rel_name, src`**:
|
|
84
|
+
Invokes relation `rel_name` with input `src`.
|
|
85
|
+
- **`id dest, src`**:
|
|
86
|
+
Identity move.
|
|
87
|
+
- **`fail`**:
|
|
88
|
+
Signals partial function failure (backtracking or branch exit).
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 4. Execution Pipeline
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
[AOT Phase]
|
|
96
|
+
k source -> AST -> Type Pattern Graph -> PKIR Relation
|
|
97
|
+
|
|
98
|
+
[Runtime Invocation with (Schema S, Payload V)]
|
|
99
|
+
1. AccessTable = buildAccessTable(S, PKIR.patternGraph)
|
|
100
|
+
2. Choose execution tier:
|
|
101
|
+
- Tier 0 (Interpreter): executePKIR(PKIR, V, AccessTable)
|
|
102
|
+
- Tier 1 (Specialized AOT/JIT): specializePKIR(PKIR, AccessTable)
|
|
103
|
+
-> direct emission to LLVM / WebAssembly
|
|
104
|
+
```
|