@fraczak/k 7.0.1 → 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 +36 -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/backends/llvm/runtime/krt.c +33 -0
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/executable.mjs +4 -4
- package/backends/llvm/src/kvm2llvm.mjs +40 -18
- package/backends/llvm/src/llvm.mjs +12 -11
- package/backends/llvm/tests/perf-support.mjs +1 -55
- package/backends/llvm/tests/test-llvm.mjs +3 -3
- package/backends/wasm/src/wasm.mjs +2 -1
- package/backends/wasm/tests/test-wasm.mjs +5 -5
- package/browser/vfs-data.mjs +5 -5
- package/core.k +8 -8
- package/harness/format.mjs +2 -2
- package/harness/registry.mjs +0 -2
- package/kir.mjs +142 -56
- 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/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
|
@@ -292,7 +292,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
|
|
|
292
292
|
" k_wire_input_free(input);",
|
|
293
293
|
" return 2;",
|
|
294
294
|
" }",
|
|
295
|
-
" if (!
|
|
295
|
+
" if (!k_pattern_compatible(input.pattern, &compiled_input_pattern)) {",
|
|
296
296
|
" k_wire_input_free(input);",
|
|
297
297
|
" return 5;",
|
|
298
298
|
" }",
|
|
@@ -350,7 +350,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
|
|
|
350
350
|
" k_value *in_val = k_decode_wire_value_with_prefix(payload, length, &input_prefix, &compiled_input_pattern, rt);",
|
|
351
351
|
" if (in_val == 0) {",
|
|
352
352
|
" k_wire_input envelope = k_decode_wire_envelope(payload, length, rt);",
|
|
353
|
-
" if (envelope.value != 0 && envelope.pattern != 0 &&
|
|
353
|
+
" if (envelope.value != 0 && envelope.pattern != 0 && k_pattern_compatible(envelope.pattern, &compiled_input_pattern)) {",
|
|
354
354
|
" in_val = envelope.value;",
|
|
355
355
|
" } else {",
|
|
356
356
|
" k_wire_input_free(envelope);",
|
|
@@ -437,7 +437,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
|
|
|
437
437
|
" k_rt_free(input_rt);",
|
|
438
438
|
" return 2;",
|
|
439
439
|
" }",
|
|
440
|
-
" if (!
|
|
440
|
+
" if (!k_pattern_compatible(input.pattern, &compiled_input_pattern)) {",
|
|
441
441
|
" k_wire_input_free(input);",
|
|
442
442
|
" k_rt_free(run_rt);",
|
|
443
443
|
" k_rt_free(input_rt);",
|
|
@@ -478,7 +478,7 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
|
|
|
478
478
|
" k_rt_free(rt);",
|
|
479
479
|
" return 2;",
|
|
480
480
|
" }",
|
|
481
|
-
" if (!
|
|
481
|
+
" if (!k_pattern_compatible(input.pattern, &compiled_input_pattern)) {",
|
|
482
482
|
" k_wire_input_free(input);",
|
|
483
483
|
" k_wire_prefix_free(output_prefix);",
|
|
484
484
|
" k_rt_free(rt);",
|
|
@@ -35,15 +35,17 @@ function alignArenaSize(size) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function cStringBytes(text) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
.
|
|
38
|
+
const buf = Buffer.from(text, "utf8");
|
|
39
|
+
let out = "";
|
|
40
|
+
for (let i = 0; i < buf.length; i++) {
|
|
41
|
+
const byte = buf[i];
|
|
42
|
+
if (byte === 10) out += "\\0A";
|
|
43
|
+
else if (byte === 34) out += "\\22";
|
|
44
|
+
else if (byte === 92) out += "\\5C";
|
|
45
|
+
else if (byte >= 32 && byte <= 126) out += String.fromCharCode(byte);
|
|
46
|
+
else out += `\\${byte.toString(16).padStart(2, "0").toUpperCase()}`;
|
|
47
|
+
}
|
|
48
|
+
return out + "\\00";
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export function runtimeDeclarations() {
|
|
@@ -551,8 +553,7 @@ export function compileKVMModuleToLLVM(entryName, kvmProgram, options = {}) {
|
|
|
551
553
|
const payload = JSON.stringify({
|
|
552
554
|
format: ARTIFACT_FORMAT,
|
|
553
555
|
version: ARTIFACT_VERSION,
|
|
554
|
-
relation
|
|
555
|
-
kvm: kvmProgram
|
|
556
|
+
relation
|
|
556
557
|
});
|
|
557
558
|
const payloadBytes = Buffer.byteLength(payload, "utf8") + 1;
|
|
558
559
|
const symbol = llvmIdentifier(options.symbol || relation);
|
|
@@ -815,11 +816,32 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
815
816
|
storeI64At(ctx, product, K_VALUE_PRODUCT_CAPACITY_OFFSET, N);
|
|
816
817
|
storePtrAt(ctx, product, K_VALUE_PRODUCT_FIELDS_OFFSET, fields);
|
|
817
818
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
819
|
+
let sortedFields;
|
|
820
|
+
if (Array.isArray(inst.pattern) && inst.pattern.length > 0) {
|
|
821
|
+
const root = inst.pattern[0];
|
|
822
|
+
if (
|
|
823
|
+
(root[0] === "open-product" ||
|
|
824
|
+
root[0] === "closed-product") &&
|
|
825
|
+
Array.isArray(root[1])
|
|
826
|
+
) {
|
|
827
|
+
const order = new Map(root[1].map(([l], i) => [l, i]));
|
|
828
|
+
sortedFields = [...fieldValues].sort((a, b) => {
|
|
829
|
+
const aI = order.has(a.label)
|
|
830
|
+
? order.get(a.label)
|
|
831
|
+
: 999999;
|
|
832
|
+
const bI = order.has(b.label)
|
|
833
|
+
? order.get(b.label)
|
|
834
|
+
: 999999;
|
|
835
|
+
if (aI !== bI) return aI - bI;
|
|
836
|
+
return a.label.localeCompare(b.label);
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (!sortedFields) {
|
|
841
|
+
sortedFields = [...fieldValues].sort((a, b) =>
|
|
842
|
+
a.label.localeCompare(b.label)
|
|
843
|
+
);
|
|
844
|
+
}
|
|
823
845
|
|
|
824
846
|
for (let sIdx = 0; sIdx < N; sIdx++) {
|
|
825
847
|
const { label: fLabel, val: fVal } = sortedFields[sIdx];
|
|
@@ -838,7 +860,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
838
860
|
const uInput = getReg(inst.src);
|
|
839
861
|
|
|
840
862
|
if (!isTopLevel) {
|
|
841
|
-
// Nested union: synthesize
|
|
863
|
+
// Nested union: synthesize helper @k_union_expr_${index}
|
|
842
864
|
const exprIndex = moduleCtx.unionExprIndex++;
|
|
843
865
|
const exprName = `@k_union_expr_${exprIndex}`;
|
|
844
866
|
const exprFunc = {
|
|
@@ -863,7 +885,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
863
885
|
break;
|
|
864
886
|
}
|
|
865
887
|
|
|
866
|
-
// Top-level union: synthesize
|
|
888
|
+
// Top-level union: synthesize arms @k_union_arm_${index}
|
|
867
889
|
const mark = lowerRtMark(ctx);
|
|
868
890
|
const unionDone = ctx.blockName("union_done");
|
|
869
891
|
const N = inst.branches.length;
|
|
@@ -45,15 +45,17 @@ function alignArenaSize(size) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
function cStringBytes(text) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.
|
|
48
|
+
const buf = Buffer.from(text, "utf8");
|
|
49
|
+
let out = "";
|
|
50
|
+
for (let i = 0; i < buf.length; i++) {
|
|
51
|
+
const byte = buf[i];
|
|
52
|
+
if (byte === 10) out += "\\0A";
|
|
53
|
+
else if (byte === 34) out += "\\22";
|
|
54
|
+
else if (byte === 92) out += "\\5C";
|
|
55
|
+
else if (byte >= 32 && byte <= 126) out += String.fromCharCode(byte);
|
|
56
|
+
else out += `\\${byte.toString(16).padStart(2, "0").toUpperCase()}`;
|
|
57
|
+
}
|
|
58
|
+
return out + "\\00";
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
function readPattern(inputPattern) {
|
|
@@ -986,8 +988,7 @@ export function emitLLVMModule(input, options = {}) {
|
|
|
986
988
|
const payload = JSON.stringify({
|
|
987
989
|
format: ARTIFACT_FORMAT,
|
|
988
990
|
version: ARTIFACT_VERSION,
|
|
989
|
-
relation
|
|
990
|
-
kir
|
|
991
|
+
relation
|
|
991
992
|
});
|
|
992
993
|
const payloadBytes = Buffer.byteLength(payload, "utf8") + 1;
|
|
993
994
|
const symbol = llvmIdentifier(options.symbol || relation);
|
|
@@ -216,7 +216,7 @@ export function runExecutableMainBench(exePath, inputWire, calls) {
|
|
|
216
216
|
reject(new Error(`${exePath} --bench-main failed with status ${status}\n${text}`.trim()));
|
|
217
217
|
return;
|
|
218
218
|
}
|
|
219
|
-
const match = text.match(/
|
|
219
|
+
const match = text.match(/K_LLVM_BENCH_MAIN calls=(\d+) total_ns=(\d+) per_call_ns=([0-9.]+)/);
|
|
220
220
|
if (!match) {
|
|
221
221
|
reject(new Error(`${exePath} --bench-main did not report timing\n${text}`.trim()));
|
|
222
222
|
return;
|
|
@@ -599,61 +599,7 @@ export function llvmLaneName() {
|
|
|
599
599
|
: "LLVM Executable (persistent)";
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
-
export function arm64LaneName(optLevel = "-O2") {
|
|
603
|
-
const mode = process.env.ARM64_SPAWN_PER_CALL === "1"
|
|
604
|
-
? "spawn/call"
|
|
605
|
-
: (process.env.ARM64_PIPELINE === "1" ? "persistent, pipelined" : "persistent");
|
|
606
|
-
return `Linux ARM64 ${optLevel} (${mode})`;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
export function createARM64Runner(testSuite) {
|
|
610
|
-
const arm64Cases = testSuite.filter(tc => tc.arm64?.status === "ok");
|
|
611
|
-
if (process.env.ARM64_SPAWN_PER_CALL === "1") {
|
|
612
|
-
return {
|
|
613
|
-
run(iterations) {
|
|
614
|
-
if (arm64Cases.length === 0) return null;
|
|
615
|
-
return runTimedIterationsAsync(iterations, async () => {
|
|
616
|
-
for (const tc of arm64Cases) {
|
|
617
|
-
await runExecutable(tc.arm64.exePath, tc.inputWire);
|
|
618
|
-
}
|
|
619
|
-
});
|
|
620
|
-
},
|
|
621
|
-
close() {}
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
602
|
|
|
625
|
-
const servers = new Map();
|
|
626
|
-
function serverFor(exePath) {
|
|
627
|
-
let server = servers.get(exePath);
|
|
628
|
-
if (server == null) {
|
|
629
|
-
server = new PersistentExecutable(exePath);
|
|
630
|
-
servers.set(exePath, server);
|
|
631
|
-
}
|
|
632
|
-
return server;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
return {
|
|
636
|
-
async run(iterations) {
|
|
637
|
-
if (arm64Cases.length === 0) return null;
|
|
638
|
-
return runTimedIterationsAsync(iterations, async () => {
|
|
639
|
-
if (process.env.ARM64_PIPELINE === "1") {
|
|
640
|
-
const pending = [];
|
|
641
|
-
for (const tc of arm64Cases) {
|
|
642
|
-
pending.push(serverFor(tc.arm64.exePath).request(tc.inputWire));
|
|
643
|
-
}
|
|
644
|
-
await Promise.all(pending);
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
for (const tc of arm64Cases) {
|
|
648
|
-
await serverFor(tc.arm64.exePath).request(tc.inputWire);
|
|
649
|
-
}
|
|
650
|
-
});
|
|
651
|
-
},
|
|
652
|
-
close() {
|
|
653
|
-
for (const server of servers.values()) server.close();
|
|
654
|
-
}
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
603
|
|
|
658
604
|
export function average(times) {
|
|
659
605
|
return times.reduce((sum, time) => sum + time, 0) / times.length;
|
|
@@ -239,11 +239,11 @@ assert.doesNotMatch(nestedUnionLLVM, /call void @k_product_set_at\(ptr %product\
|
|
|
239
239
|
assert.doesNotMatch(nestedUnionLLVM, /ptr false/);
|
|
240
240
|
|
|
241
241
|
const productRecurseObject = decodeObject(compileObjectBuffer(`
|
|
242
|
-
list = ?< {} nil, { {} car, list cdr } cons >;
|
|
243
|
-
foo = list <
|
|
242
|
+
list? = ?< {} nil, { {} car, list? cdr } cons >;
|
|
243
|
+
foo = list? <
|
|
244
244
|
/nil |nil,
|
|
245
245
|
/cons { .car car, .cdr foo cdr } |cons
|
|
246
|
-
> list
|
|
246
|
+
> list?;
|
|
247
247
|
foo
|
|
248
248
|
`, { source: "llvm-product-recurse.k" }));
|
|
249
249
|
const { llvm: productRecurseLLVM } = compileObjectToLLVM(productRecurseObject, {
|
|
@@ -439,7 +439,8 @@ function relTypeStatus(defs, name) {
|
|
|
439
439
|
const rel = defs.rels?.[name];
|
|
440
440
|
const explicit = rel?.typeDerivation?.status;
|
|
441
441
|
if (explicit) return explicit;
|
|
442
|
-
const
|
|
442
|
+
const stats = compileStatsByRelName(defs.compileStats);
|
|
443
|
+
const scc = stats.get(name) || (name.includes("$") ? stats.get(name.split("$")[0]) : null);
|
|
443
444
|
if (scc) return scc.converged ? "converged" : "not-converged";
|
|
444
445
|
return "unknown";
|
|
445
446
|
}
|
|
@@ -443,11 +443,11 @@ console.log("==> Running End-to-End Peano Addition & Serialization Tests");
|
|
|
443
443
|
const runtimeWat = fs.readFileSync("runtime.wat", "utf8");
|
|
444
444
|
|
|
445
445
|
const script = `
|
|
446
|
-
nat = ?< {} 0, nat +1 >;
|
|
447
|
-
0 = {} | 0 nat
|
|
448
|
-
inc = | +1 nat
|
|
449
|
-
dec = nat / +1;
|
|
450
|
-
add = ?{ nat x, nat y } = X <
|
|
446
|
+
nat? = ?< {} 0, nat? +1 >;
|
|
447
|
+
0 = {} | 0 nat?;
|
|
448
|
+
inc = | +1 nat?;
|
|
449
|
+
dec = nat? / +1;
|
|
450
|
+
add = ?{ nat? x, nat? y } = X <
|
|
451
451
|
{ . x dec x, . y inc y } ?X add,
|
|
452
452
|
. y
|
|
453
453
|
>;
|