@fraczak/k 7.0.0 → 7.0.2
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 +50 -0
- package/DOCS/BIG_PICTURE.md +5 -5
- package/DOCS/FILE_FORMATS.md +5 -5
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +9 -9
- package/DOCS/PATTERNS.md +3 -3
- 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/README.md +3 -8
- package/backend-api.mjs +9 -1
- package/backends/llvm/runtime/krt.c +33 -0
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/scripts/run-tests.mjs +5 -0
- package/backends/llvm/src/executable.mjs +4 -4
- package/backends/llvm/src/kvm2llvm.mjs +42 -19
- package/backends/llvm/src/llvm.mjs +30 -36
- package/backends/llvm/tests/integration.sh +2 -2
- package/backends/llvm/tests/perf-support.mjs +1 -55
- package/backends/llvm/tests/test-llvm.mjs +3 -3
- package/backends/llvm/tests/test-open-product-misalignment.mjs +140 -0
- package/backends/wasm/demo_ieee.mjs +2 -3
- package/backends/wasm/runtime.wat +157 -5
- package/backends/wasm/src/kvm2wasm.mjs +57 -34
- package/backends/wasm/src/wasm.mjs +40 -18
- package/backends/wasm/tests/perf-support.mjs +4 -4
- package/backends/wasm/tests/test-wasm.mjs +13 -14
- package/browser/vfs-data.mjs +6 -6
- package/core.k +8 -8
- package/harness/format.mjs +2 -2
- package/harness/registry.mjs +0 -2
- package/kir.mjs +299 -17
- package/package.json +1 -5
- package/scripts/benchmark-idempotency.mjs +12 -8
- package/scripts/benchmark.mjs +5 -9
- package/scripts/build-repl-html.mjs +2 -2
- package/scripts/perf-ieee.mjs +17 -118
- package/scripts/perf-int.mjs +313 -318
- package/scripts/perf-multiplication.mjs +10 -20
- package/scripts/perf-poly.mjs +29 -183
- package/tests/code-derivation/pattern-envelope.mjs +4 -4
- package/tests/test-kvm-polymorphic.mjs +2 -2
- package/tests/test-repl-html.mjs +15 -0
- package/tests/test-repl.mjs +10 -0
- 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/harness/adapters/arm64.mjs +0 -105
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,56 @@ 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.0.2] — 2026-10-13 — LLVM Squaring Scaling & Backend Streamlining
|
|
9
|
+
|
|
10
|
+
### Features & Performance Improvements
|
|
11
|
+
|
|
12
|
+
- **Multiplication Algorithm Scaling Benchmark (LLVM & Multi-Backend)**:
|
|
13
|
+
- Added successive squaring scale benchmark comparing standard long
|
|
14
|
+
multiplication (`times`) and Karatsuba multiplication (`karatsuba`)
|
|
15
|
+
across bit lengths doubling up to 7,650+ bits.
|
|
16
|
+
- Added support for squaring execution and memory (peak RSS / heap)
|
|
17
|
+
tracking across LLVM, WebAssembly, and interpreter lanes.
|
|
18
|
+
- Aligned product field layouts and offset indexing in `kvm2llvm.mjs`.
|
|
19
|
+
|
|
20
|
+
### Bug Fixes & Compatibility
|
|
21
|
+
|
|
22
|
+
- **LLVM Open/Closed Pattern Compatibility on Wire Input**:
|
|
23
|
+
- Allowed open and closed pattern compatibility when validating and
|
|
24
|
+
unpacking wire inputs in the LLVM runtime (`krt.c` and
|
|
25
|
+
`executable.mjs`).
|
|
26
|
+
- Gracefully accepts framed inputs matching open-product schemas.
|
|
27
|
+
|
|
28
|
+
### Chores & Maintenance
|
|
29
|
+
|
|
30
|
+
- **Backend Streamlining (Wasm & LLVM Focus)**:
|
|
31
|
+
- Removed legacy experimental ARM64 backend (`backends/arm64`) to focus
|
|
32
|
+
on WebAssembly (portable) and LLVM (native) backends.
|
|
33
|
+
- Updated documentation (`DOCS/FILE_FORMATS.md`,
|
|
34
|
+
`DOCS/PROFILING_AND_TRACING.md`) and benchmark suites.
|
|
35
|
+
- Enhanced pattern graph specialization and KIR monomorphization in
|
|
36
|
+
`kir.mjs`.
|
|
37
|
+
|
|
38
|
+
## [7.0.1] — 2026-10-10 — Call-Graph Pattern Graph Specialization
|
|
39
|
+
|
|
40
|
+
### Bug Fixes & Backend Alignments
|
|
41
|
+
|
|
42
|
+
- **Pattern Graph Specialization Across Call Graphs**:
|
|
43
|
+
- Implemented `specializeObjectRelations` in `kir.mjs` to propagate input
|
|
44
|
+
schemas across relation call graphs via monomorphization.
|
|
45
|
+
- Statically resolves field projection offsets for open product and
|
|
46
|
+
polymorphic helper relations without dynamic fallback (`@k_product_get_n`).
|
|
47
|
+
- Fixed WASM predicted field index calculation and aligned product header
|
|
48
|
+
memory layout (`tagId` at header slots).
|
|
49
|
+
- Resolved polymorphic list and open product projection alignment across
|
|
50
|
+
LLVM, WASM, and Web REPL.
|
|
51
|
+
- **Filter Relation Naming Convention (`?` Suffix)**:
|
|
52
|
+
- Standardized naming convention for all filter and schema relations to use
|
|
53
|
+
the `?` suffix (e.g. `int?`, `bits?`, `bit?`, `string?`, `pattern?`,
|
|
54
|
+
`bnat?`, `nat?`, `bool?`, matching `list?`).
|
|
55
|
+
- Separated integer filter schema `int? = ?<...>` from constructor
|
|
56
|
+
`int = nat | '+'` in `Examples/arithmetics.k`, removing symbol collision.
|
|
57
|
+
|
|
8
58
|
## [7.0.0] — 2026-10-10 — Unified Schemas, Relational Contracts, and Pure Syntax
|
|
9
59
|
|
|
10
60
|
### Breaking Language & Syntax Changes
|
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
|
@@ -288,12 +288,12 @@ Export all currently loaded relations and types into a reusable library:
|
|
|
288
288
|
`make_variant`, `project_variant`, `jump_if_fail`, `call`, and loops).
|
|
289
289
|
|
|
290
290
|
2. **$1 \times N$ Backend Decoupling:**
|
|
291
|
-
Rather than having every code generator (LLVM, WebAssembly,
|
|
292
|
-
|
|
291
|
+
Rather than having every code generator (LLVM, WebAssembly, and the
|
|
292
|
+
interpreter) independently lower the relational tree and
|
|
293
293
|
re-implement type-guided control flow, relational-to-imperative
|
|
294
294
|
lowering occurs once in `kvm.mjs`. All backends consume the exact same
|
|
295
295
|
~10 linear kVM instructions (`kvm2llvm.mjs`, `kvm2wasm.mjs`,
|
|
296
|
-
`
|
|
296
|
+
`kvm.mjs`).
|
|
297
297
|
|
|
298
298
|
3. **Microsecond Polymorphic Specialization (`layer: "KVM-P"`):**
|
|
299
299
|
In polymorphic programs, specializing `.ko` requires re-running the
|
|
@@ -398,9 +398,9 @@ In `k`, there are no primitive numerical types or built-in integer
|
|
|
398
398
|
literals. Identifiers such as `5` or `10` are not language keywords;
|
|
399
399
|
they are defined relations (aliases) in `Examples/arithmetics.k`:
|
|
400
400
|
- `5` and `10` are nullary relations (constants) of type `{} -> bits`,
|
|
401
|
-
defined as binary digit trees over `bits = ?< {} _, bits 0, bits 1 > = bits
|
|
401
|
+
defined as binary digit trees over `bits? = ?< {} _, bits? 0, bits? 1 > = bits?;`.
|
|
402
402
|
- Arithmetic operations (`plus`, `minus`, `times`, `inc`) operate on
|
|
403
|
-
signed integers (`int =
|
|
403
|
+
signed integers (`int? = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" >`).
|
|
404
404
|
- Passing a bit-representation like `5` to an integer relation requires
|
|
405
405
|
applying the `int` constructor (`5 int`), producing a constant
|
|
406
406
|
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
|
|
@@ -5,7 +5,6 @@ and function-level call profiling infrastructure for `k` backends.
|
|
|
5
5
|
|
|
6
6
|
The profiling framework allows fine-grained performance analysis of polymorphic `k`
|
|
7
7
|
programs across multiple execution targets:
|
|
8
|
-
- **Linux ARM64** (native standalone ELF executable via direct kVM assembly emission)
|
|
9
8
|
- **WebAssembly** (in-process Wasm module via single-pass kVM lowering)
|
|
10
9
|
- **LLVM** (native specialized executable via KIR-P lowering)
|
|
11
10
|
- **kVM Interpreter** (in-process TypeScript/JavaScript kVM evaluator)
|
|
@@ -15,17 +14,23 @@ programs across multiple execution targets:
|
|
|
15
14
|
|
|
16
15
|
## 1. Motivation: Apples-to-Apples Backend Comparison
|
|
17
16
|
|
|
18
|
-
When measuring end-to-end request latency across backends, wall-clock
|
|
19
|
-
dominated by factors outside the core relation algorithm:
|
|
20
|
-
- **Process IPC**: Out-of-process native executables (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- **
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
When measuring end-to-end request latency across backends, wall-clock
|
|
18
|
+
time can be dominated by factors outside the core relation algorithm:
|
|
19
|
+
- **Process IPC**: Out-of-process native executables (LLVM)
|
|
20
|
+
communicate via stdin/stdout pipes, incurring OS context switches and
|
|
21
|
+
pipe buffer copies.
|
|
22
|
+
- **Wire Codec**: Decoding and validating the binary wire format
|
|
23
|
+
(`pattern + value`) and encoding the response.
|
|
24
|
+
- **In-Memory Representation**: WebAssembly converts incoming values into
|
|
25
|
+
a flat linear memory arena layout.
|
|
26
|
+
- **Pure Evaluation**: The actual relational instruction loop performing
|
|
27
|
+
the algorithm.
|
|
28
|
+
|
|
29
|
+
Without detailed accounting, native LLVM binaries communicating over
|
|
30
|
+
pipes can appear slower than in-process WebAssembly or the interpreter
|
|
31
|
+
simply because of IPC overhead. The tracing infrastructure breaks
|
|
32
|
+
request latency down into nanosecond-level phases so that pure
|
|
33
|
+
execution time can be measured and compared directly.
|
|
29
34
|
|
|
30
35
|
In addition, **per-function invocation profiling** verifies that every backend performs the
|
|
31
36
|
exact same number of relational evaluations and loop iterations for a given input.
|
|
@@ -56,37 +61,41 @@ Following `k`'s canonical content-addressed design:
|
|
|
56
61
|
|
|
57
62
|
When tracing is enabled, each request is instrumented to measure 7 discrete phases with nanosecond precision:
|
|
58
63
|
|
|
59
|
-
| Phase | Description |
|
|
60
|
-
| :--- | :--- | :---: | :---: | :---: |
|
|
61
|
-
| **1. IPC Read (Pipe In)** | Waiting for and reading input payload from stdin | Yes |
|
|
62
|
-
| **2. Wire Decode & Validate** | Decoding wire buffer and validating against pattern | Yes |
|
|
63
|
-
| **3. Flat Input Prep (Arena)** | Flattening decoded structures into linear arena memory |
|
|
64
|
-
| **4. Pure Evaluation** | Core relational execution loop | **Yes** | **Yes** | **Yes** |
|
|
65
|
-
| **5. Flat Output Prep (Arena)** | Serializing/reading in-memory representations |
|
|
66
|
-
| **6. Wire Encode** | Encoding result to canonical wire format | Yes |
|
|
67
|
-
| **7. IPC Write (Pipe Out)** | Writing output wire bytes to stdout pipe | Yes | Yes
|
|
64
|
+
| Phase | Description | LLVM | WebAssembly | kVM Interp |
|
|
65
|
+
| :--- | :--- | :---: | :---: | :---: |
|
|
66
|
+
| **1. IPC Read (Pipe In)** | Waiting for and reading input payload from stdin | Yes | N/A (in-process) | N/A (in-process) |
|
|
67
|
+
| **2. Wire Decode & Validate** | Decoding wire buffer and validating against pattern | Yes | N/A (in-process) | N/A (in-process) |
|
|
68
|
+
| **3. Flat Input Prep (Arena)** | Flattening decoded structures into linear arena memory | N/A | Yes | N/A |
|
|
69
|
+
| **4. Pure Evaluation** | Core relational execution loop | **Yes** | **Yes** | **Yes** |
|
|
70
|
+
| **5. Flat Output Prep (Arena)** | Serializing/reading in-memory representations | N/A | Yes | N/A |
|
|
71
|
+
| **6. Wire Encode** | Encoding result to canonical wire format | Yes | N/A (in-process) | N/A (in-process) |
|
|
72
|
+
| **7. IPC Write (Pipe Out)** | Writing output wire bytes to stdout pipe | Yes | Yes (driver) | N/A |
|
|
68
73
|
|
|
69
74
|
### Phase Timing Output Example
|
|
70
75
|
|
|
71
76
|
```text
|
|
72
77
|
--- Operation: reverse (len 40) ---
|
|
73
|
-
Phase |
|
|
74
|
-
|
|
75
|
-
1. IPC Read (Pipe In) |
|
|
76
|
-
2. Wire Decode & Validate |
|
|
77
|
-
3. Flat Input Prep (Arena) |
|
|
78
|
-
4. Pure Evaluation | 0.
|
|
79
|
-
5. Flat Output Prep (Arena) |
|
|
80
|
-
6. Wire Encode |
|
|
81
|
-
7. IPC Write (Pipe Out) | 11.
|
|
82
|
-
|
|
83
|
-
Total Request Time |
|
|
78
|
+
Phase | LLVM | WebAssembly | kVM Interp
|
|
79
|
+
-------------------------+---------------+---------------+---------------
|
|
80
|
+
1. IPC Read (Pipe In) | 161.42 µs | - | -
|
|
81
|
+
2. Wire Decode & Validate | 1.58 µs | - | -
|
|
82
|
+
3. Flat Input Prep (Arena) | - | 80.88 µs | -
|
|
83
|
+
4. Pure Evaluation | 0.54 µs | 1.71 µs | 26.04 µs
|
|
84
|
+
5. Flat Output Prep (Arena) | - | 76.71 µs | -
|
|
85
|
+
6. Wire Encode | 4.88 µs | - | -
|
|
86
|
+
7. IPC Write (Pipe Out) | 11.08 µs | 0.62 µs | -
|
|
87
|
+
-------------------------+---------------+---------------+---------------
|
|
88
|
+
Total Request Time | 179.50 µs | 159.92 µs | 26.04 µs
|
|
84
89
|
```
|
|
85
90
|
|
|
86
91
|
**Key Takeaways**:
|
|
87
|
-
- **Pure evaluation** in
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
- **Pure evaluation** in LLVM native code (`0.54 µs`) is ~3.2× faster
|
|
93
|
+
than WebAssembly (`1.71 µs`) and ~48× faster than the interpreter
|
|
94
|
+
(`26.04 µs`).
|
|
95
|
+
- **End-to-end request time** for native binaries is dominated by pipe
|
|
96
|
+
IPC read (`~160 µs`).
|
|
97
|
+
- **WebAssembly overhead** is concentrated in flat arena conversion
|
|
98
|
+
(`~80 µs` in, `~76 µs` out).
|
|
90
99
|
|
|
91
100
|
---
|
|
92
101
|
|
|
@@ -100,22 +109,20 @@ every backend executes the exact same call path.
|
|
|
100
109
|
|
|
101
110
|
```text
|
|
102
111
|
Function Call Profile: reverse
|
|
103
|
-
Function Name |
|
|
104
|
-
|
|
105
|
-
reverse |
|
|
106
|
-
_reverse |
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-------------------------+-------------------+-------------------+------------------
|
|
114
|
-
Total Calls | 163 | 163 | 163
|
|
112
|
+
Function Name | WebAssembly Calls | kVM Interp Calls
|
|
113
|
+
-------------------------+-------------------+------------------
|
|
114
|
+
reverse | 1 | 1
|
|
115
|
+
_reverse | 41 | 41
|
|
116
|
+
car | 40 | 40
|
|
117
|
+
cdr | 40 | 40
|
|
118
|
+
cons | 40 | 40
|
|
119
|
+
nil | 1 | 1
|
|
120
|
+
-------------------------+-------------------+------------------
|
|
121
|
+
Total Calls | 163 | 163
|
|
115
122
|
```
|
|
116
123
|
|
|
117
|
-
*(Note:
|
|
118
|
-
|
|
124
|
+
*(Note: Both backends arrive at the exact same total call count:
|
|
125
|
+
163 calls for reversing a list of length 40).*
|
|
119
126
|
|
|
120
127
|
---
|
|
121
128
|
|
|
@@ -143,9 +150,7 @@ node scripts/perf-poly.mjs --trace
|
|
|
143
150
|
| `TRACE_SAMPLES` | `5` | Repetitions sampled and averaged for phase timings. |
|
|
144
151
|
| `TRACE` | `0` | Set to `1` (or pass `--trace`) to enable phase breakdown. |
|
|
145
152
|
| `PROFILE` | `1` (with trace) | Set to `0` to disable function call counters. |
|
|
146
|
-
| `ARM64_OPT` | `-O2` | Optimization level for the native ARM64 runtime (`-O0`, `-O1`, `-O2`, `-O3`). |
|
|
147
153
|
| `WASM_RESET` | `1` | Reset the WebAssembly linear memory arena between calls (`1` or `0`). |
|
|
148
|
-
| `ARM64_ONLY` | `0` | Run only the Linux ARM64 native target. |
|
|
149
154
|
| `WASM_ONLY` | `0` | Run only the WebAssembly target. |
|
|
150
155
|
| `LLVM_ONLY` | `0` | Run only the LLVM target. |
|
|
151
156
|
| `BACKENDS_ONLY` | `0` | Skip the native JS baseline lanes. |
|
|
@@ -156,34 +161,17 @@ node scripts/perf-poly.mjs --trace
|
|
|
156
161
|
# Fast smoke check with list length 10 and 1 iteration:
|
|
157
162
|
ITERATIONS=1 LIST_LENGTH=10 npm run perf:poly:trace
|
|
158
163
|
|
|
159
|
-
#
|
|
160
|
-
LIST_LENGTH=100
|
|
164
|
+
# Trace WebAssembly on large lists (100 elements):
|
|
165
|
+
LIST_LENGTH=100 WASM_ONLY=1 npm run perf:poly:trace
|
|
161
166
|
|
|
162
|
-
# Isolate
|
|
163
|
-
|
|
167
|
+
# Isolate LLVM native execution:
|
|
168
|
+
LLVM_ONLY=1 npm run perf:poly:trace
|
|
164
169
|
```
|
|
165
170
|
|
|
166
171
|
---
|
|
167
172
|
|
|
168
173
|
## 6. Implementation Architecture
|
|
169
174
|
|
|
170
|
-
### Linux ARM64 Backend
|
|
171
|
-
- **Code Emission** ([`backends/arm64/src/kvm2arm64.mjs`](../backends/arm64/src/kvm2arm64.mjs)): When `options.profile` is active, each function emits counter increment instructions in its entry sequence:
|
|
172
|
-
```asm
|
|
173
|
-
adrp x9, k_prof_<func>
|
|
174
|
-
add x9, x9, :lo12:k_prof_<func>
|
|
175
|
-
ldr x10, [x9]
|
|
176
|
-
add x10, x10, #1
|
|
177
|
-
str x10, [x9]
|
|
178
|
-
```
|
|
179
|
-
Counters are emitted into a dedicated `.data` section, and an exported metadata table `k_profile_entries[]` is generated.
|
|
180
|
-
- **Runtime Reporting** ([`backends/arm64/src/runtime.c`](../backends/arm64/src/runtime.c)):
|
|
181
|
-
- Nanosecond phase timestamps are sampled via `clock_gettime(CLOCK_MONOTONIC, ...)` and emitted over stderr formatted as:
|
|
182
|
-
```text
|
|
183
|
-
K_TRACE_PHASES backend=arm64 ipc_read_ns=... decode_ns=... flat_in_ns=... eval_ns=... flat_out_ns=... encode_ns=... ipc_write_ns=... total_ns=...
|
|
184
|
-
```
|
|
185
|
-
- `dump_profile_counts()` emits nonzero function call counts between `K_PROFILE_BEGIN` and `K_PROFILE_END` tags.
|
|
186
|
-
|
|
187
175
|
### WebAssembly Backend
|
|
188
176
|
- **Code Emission** ([`backends/wasm/src/kvm2wasm.mjs`](../backends/wasm/src/kvm2wasm.mjs)): Emits mutable 64-bit Wasm globals:
|
|
189
177
|
```wat
|
package/DOCS/REPL.md
CHANGED
|
@@ -58,7 +58,7 @@ Examples:
|
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
```k
|
|
61
|
-
> bool = ?<{} true, {} false>;
|
|
61
|
+
> bool? = ?<{} true, {} false>;
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
```k
|
|
@@ -147,7 +147,7 @@ aliases, and metadata into the session. Aliases are recovered from
|
|
|
147
147
|
|
|
148
148
|
In `k`, there are no primitive numbers or built-in numerical literals.
|
|
149
149
|
Values such as integers are represented as algebraic bit trees (e.g.
|
|
150
|
-
`bits = ?< {} _, B 0, B 1 > = B;`).
|
|
150
|
+
`bits? = ?< {} _, B 0, B 1 > = B;`).
|
|
151
151
|
|
|
152
152
|
A codec translates between external text and enveloped *k* values:
|
|
153
153
|
- `parse(text)`: parses an external string into an enveloped *k* value.
|
|
@@ -309,7 +309,7 @@ Evaluated values print in k syntax together with the inferred envelope:
|
|
|
309
309
|
## Example Session
|
|
310
310
|
|
|
311
311
|
```text
|
|
312
|
-
> nat = ?< {} 0, N +1 > = N;
|
|
312
|
+
> nat? = ?< {} 0, N +1 > = N;
|
|
313
313
|
> inc = | +1;
|
|
314
314
|
> {} | 0
|
|
315
315
|
{}|0 ?<{} 0, ...>
|
|
@@ -7,8 +7,8 @@ A schema in `k` describes a set of finite labeled trees, which can be recognized
|
|
|
7
7
|
For example, the recursive schema of a `list`:
|
|
8
8
|
|
|
9
9
|
```k-lang
|
|
10
|
-
bool = ?< {} true, {} false >;
|
|
11
|
-
list = ?< {} nil, { < {} true, {} false > head, L tail } cons > = L;
|
|
10
|
+
bool? = ?< {} true, {} false >;
|
|
11
|
+
list? = ?< {} nil, { < {} true, {} false > head, L tail } cons > = L;
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
corresponds to the following 4-rule grammar:
|
|
@@ -44,7 +44,7 @@ Each schema structure introduces one or more *states* in the automaton. A union
|
|
|
44
44
|
For example, consider the `bool` schema:
|
|
45
45
|
|
|
46
46
|
```k-lang
|
|
47
|
-
bool = ?< {} true, {} false >;
|
|
47
|
+
bool? = ?< {} true, {} false >;
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
This schema translates to an automaton with two states:
|
|
@@ -88,7 +88,7 @@ This traversal produces a unique and deterministic numbering for any finite dire
|
|
|
88
88
|
For a schema representing binary natural numbers:
|
|
89
89
|
|
|
90
90
|
```k-lang
|
|
91
|
-
bnat = ?< Bnat 0, Bnat 1, {} _ > = Bnat;
|
|
91
|
+
bnat? = ?< Bnat 0, Bnat 1, {} _ > = Bnat;
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
the canonical automaton form is:
|
|
@@ -111,11 +111,11 @@ Each node in the value tree is encoded based on its automaton state:
|
|
|
111
111
|
|
|
112
112
|
#### **Example: Natural numbers**
|
|
113
113
|
|
|
114
|
-
For type `bnat
|
|
114
|
+
For type `bnat?`, intuitively binary natural numbers defined by `bnat? = ?< Bnat 0, Bnat 1, {} _ > = Bnat;`, we get
|
|
115
115
|
|
|
116
116
|
```text
|
|
117
|
-
> :rel bnat
|
|
118
|
-
bnat = ?< Bnat 0, Bnat 1, {} _ > = Bnat; -- @...
|
|
117
|
+
> :rel bnat?
|
|
118
|
+
bnat? = ?< Bnat 0, Bnat 1, {} _ > = Bnat; -- @...
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
The corresponding Context-Free grammar is:
|
|
@@ -191,7 +191,7 @@ Subtrees that happen to produce the same local payload bits under different type
|
|
|
191
191
|
Consider a binary tree with repeated leaf patterns:
|
|
192
192
|
|
|
193
193
|
```k-lang
|
|
194
|
-
tree = ?< { T left, T right } branch, int leaf > = T;
|
|
194
|
+
tree? = ?< { T left, T right } branch, int? leaf > = T;
|
|
195
195
|
```
|
|
196
196
|
|
|
197
197
|
Value: A tree corresponding to the structure:
|
|
@@ -293,8 +293,8 @@ These are encoder-side construction choices for reaching the same canonical resu
|
|
|
293
293
|
Consider a list of similar records:
|
|
294
294
|
|
|
295
295
|
```k-lang
|
|
296
|
-
record = ?{ string name, int age, string department };
|
|
297
|
-
company = ?< { record head, C tail } cons, {} nil > = C;
|
|
296
|
+
record? = ?{ string? name, int? age, string? department };
|
|
297
|
+
company? = ?< { record? head, C tail } cons, {} nil > = C;
|
|
298
298
|
```
|
|
299
299
|
|
|
300
300
|
Value representing 1000 employees where 80% work in "Engineering":
|
|
@@ -712,9 +712,9 @@ const Arena = struct {
|
|
|
712
712
|
Consider processing a large JSON-like structure where we only need one field:
|
|
713
713
|
|
|
714
714
|
```k-lang
|
|
715
|
-
metadata = ?{ timestamp created, string author };
|
|
716
|
-
list = ?< { nat value, L next } cons, {} nil > = L;
|
|
717
|
-
record = ?{ string name, list data, metadata meta };
|
|
715
|
+
metadata? = ?{ timestamp created, string? author };
|
|
716
|
+
list? = ?< { nat? value, L next } cons, {} nil > = L;
|
|
717
|
+
record? = ?{ string? name, list? data, metadata? meta };
|
|
718
718
|
```
|
|
719
719
|
|
|
720
720
|
For the input program `\x.x.name` (extract name field):
|
|
@@ -73,8 +73,8 @@ These tables ensure that generated code can find fields and variants by number r
|
|
|
73
73
|
Consider a simple k program:
|
|
74
74
|
|
|
75
75
|
```k-lang
|
|
76
|
-
bool = ?< {} true, {} false >;
|
|
77
|
-
neg = bool < /true | false, /false | true > bool
|
|
76
|
+
bool? = ?< {} true, {} false >;
|
|
77
|
+
neg = bool? < /true | false, /false | true > bool?;
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
1. **Parsing:**
|
|
@@ -42,7 +42,7 @@ Each function in the program becomes a small list or tree of such IR instruction
|
|
|
42
42
|
Source program:
|
|
43
43
|
|
|
44
44
|
```k-lang
|
|
45
|
-
bool = ?< {} true, {} false >;
|
|
45
|
+
bool? = ?< {} true, {} false >;
|
|
46
46
|
neg = ?< {} true, {} false > < /true | false, /false | true >;
|
|
47
47
|
```
|
|
48
48
|
|
|
@@ -50,7 +50,7 @@ The IR for `neg` can be written informally as:
|
|
|
50
50
|
|
|
51
51
|
```text
|
|
52
52
|
neg:
|
|
53
|
-
CHECK_FILTER bool
|
|
53
|
+
CHECK_FILTER bool?
|
|
54
54
|
UNION [
|
|
55
55
|
SEQ [ PROJECT true, CONST false ],
|
|
56
56
|
SEQ [ PROJECT false, CONST true ]
|
|
@@ -68,7 +68,7 @@ This rule allows the decoder to know, from the type alone, how many bits to read
|
|
|
68
68
|
For the type
|
|
69
69
|
|
|
70
70
|
```k-lang
|
|
71
|
-
bnat = ?< Bnat 0, Bnat 1, {} _ > = Bnat;
|
|
71
|
+
bnat? = ?< Bnat 0, Bnat 1, {} _ > = Bnat;
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
the canonical form has three transitions from state C0.
|
package/Examples/arithmetics.k
CHANGED
|
@@ -3,7 +3,7 @@ swap_yes_no = < /yes |no, /no |yes >;
|
|
|
3
3
|
yes = {}|yes;
|
|
4
4
|
no = yes swap_yes_no;
|
|
5
5
|
|
|
6
|
-
bits = ?< {} _, bits 0, bits 1 > = bits
|
|
6
|
+
bits? = ?< {} _, bits? 0, bits? 1 > = bits?;
|
|
7
7
|
|
|
8
8
|
0b = {} | _;
|
|
9
9
|
-- |1 = | 1;
|
|
@@ -64,7 +64,7 @@ GT = {inOrder /no if, () then} . then;
|
|
|
64
64
|
EQ = {inOrder /yes if, {.x y, .y x} inOrder /yes and, () then} .then;
|
|
65
65
|
|
|
66
66
|
--------------------------------------
|
|
67
|
-
int = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" >;
|
|
67
|
+
int? = ?< <bits 0, bits 1, {} _>=bits "+", bits "-" >;
|
|
68
68
|
|
|
69
69
|
remove_leading_zeros = <
|
|
70
70
|
/0 remove_leading_zeros,
|
package/Examples/bnat.k
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
yes = {} | yes;
|
|
6
6
|
no = {} | no;
|
|
7
7
|
|
|
8
|
-
bits = ?< {} _, bits 0, bits 1 > = bits
|
|
8
|
+
bits? = ?< {} _, bits? 0, bits? 1 > = bits?;
|
|
9
9
|
0b = {} | _;
|
|
10
10
|
0 = 0b |0;
|
|
11
11
|
1 = 0b |1;
|
|
12
12
|
|
|
13
|
-
unat = ?< {} _, unat 1 > = unat
|
|
13
|
+
unat? = ?< {} _, unat? 1 > = unat?;
|
|
14
14
|
0u = {} | _;
|
|
15
15
|
|
|
16
16
|
empty = < /_ yes, no >;
|
package/README.md
CHANGED
|
@@ -122,9 +122,9 @@ All data structures in k are built from products and tagged unions (variants).
|
|
|
122
122
|
Relations and pattern filters describe their domains:
|
|
123
123
|
|
|
124
124
|
```k
|
|
125
|
-
bit = ?< {} 0, {} 1 >;
|
|
126
|
-
byte = ?{ Bit 0, Bit 1, Bit 2, Bit 3, Bit 4, Bit 5, Bit 6, Bit 7 };
|
|
127
|
-
bits = ?< {} _, bits 0, bits 1 > = bits
|
|
125
|
+
bit? = ?< {} 0, {} 1 >;
|
|
126
|
+
byte? = ?{ Bit 0, Bit 1, Bit 2, Bit 3, Bit 4, Bit 5, Bit 6, Bit 7 };
|
|
127
|
+
bits? = ?< {} _, bits? 0, bits? 1 > = bits?;
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
There are no built-in primitive values. The empty product `{}` is the
|
|
@@ -236,7 +236,6 @@ For a detailed guide to all four formats, commands, and workflows, see
|
|
|
236
236
|
| `k-vm` | Execute or inspect lowered kVM bytecode artifacts (`.kvm`) |
|
|
237
237
|
| `k-wasm` / `k-wasm-compile` / `k-wasm-run` | Compile and run via WebAssembly backend |
|
|
238
238
|
| `k-llvm-build` / `k-llvm-compile` / `k-llvm-run` | Compile and run via LLVM backend |
|
|
239
|
-
| `k-arm64` / `k-arm64-compile` / `k-arm64-run` | Compile and run via Linux ARM64 native backend |
|
|
240
239
|
|
|
241
240
|
Installed binary names are `k-` plus the source basename without
|
|
242
241
|
`.mjs`, except for `k.mjs` itself. Source names that already include
|
|
@@ -251,9 +250,6 @@ Backends live under [`backends/`](backends/) as npm workspaces:
|
|
|
251
250
|
and the standalone Web REPL.
|
|
252
251
|
- [`backends/llvm`](backends/llvm/) lowers polymorphic kVM programs into
|
|
253
252
|
LLVM IR and compiled native test executables.
|
|
254
|
-
- [`backends/arm64`](backends/arm64/) lowers polymorphic kVM programs
|
|
255
|
-
directly into standalone Linux ARM64 native executables without external
|
|
256
|
-
compiler dependencies.
|
|
257
253
|
|
|
258
254
|
All backends integrate with the compiler and binary codecs through
|
|
259
255
|
[`backend-api.mjs`](backend-api.mjs).
|
|
@@ -353,7 +349,6 @@ npm run prepare # regenerate parsers from .jison grammars
|
|
|
353
349
|
npm test # run the fail-fast full suite with per-test timings
|
|
354
350
|
npm run test:wasm # run the WebAssembly backend tests
|
|
355
351
|
npm run test:llvm # run the LLVM backend tests
|
|
356
|
-
npm run test:arm64 # run the Linux ARM64 backend tests
|
|
357
352
|
npm run build:repl-html # build the standalone single-file Web REPL (repl.html)
|
|
358
353
|
npm run compare # run multi-backend benchmark and conformance harness
|
|
359
354
|
npm run perf:poly # run polymorphic benchmark across backends
|
package/backend-api.mjs
CHANGED
|
@@ -4,7 +4,15 @@ export { decodeWire, encodeToWire } from "./codecs/runtime/prefix-codec.mjs";
|
|
|
4
4
|
export { exportPatternGraph, NODE_KIND } from "./codecs/runtime/codec.mjs";
|
|
5
5
|
export { patternToPropertyList, propertyListToPattern } from "./codecs/runtime/pattern-json.mjs";
|
|
6
6
|
export { Value, fromObject, isProduct, isVariant, isValue } from "./Value.mjs";
|
|
7
|
-
export {
|
|
7
|
+
export {
|
|
8
|
+
KIR_FORMAT,
|
|
9
|
+
KIR_VERSION,
|
|
10
|
+
objectToKIRP,
|
|
11
|
+
relationPatternPropertyList,
|
|
12
|
+
retypeObjectRelation,
|
|
13
|
+
retypeObjectRelationForBackend,
|
|
14
|
+
specializeObjectRelations
|
|
15
|
+
} from "./kir.mjs";
|
|
8
16
|
export { compileLibrary, decodeObject, loadLibrary } from "./object.mjs";
|
|
9
17
|
export { createState, evaluateInput } from "./repl.mjs";
|
|
10
18
|
export { parse as parseFloat64, print as printFloat64 } from "./codecs/ieee.mjs";
|