@fraczak/k 7.0.2 → 7.2.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 +75 -0
- package/DOCS/CODECS.md +37 -2
- package/DOCS/CODEC_ARCHITECTURE.md +12 -5
- package/DOCS/FILE_FORMATS.md +238 -15
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/DOCS/REPL.md +11 -3
- package/DOCS/WEB_REPL_REQUIREMENTS.md +1 -1
- package/JOURNAL.md +288 -0
- package/README.md +12 -3
- package/Value.mjs +28 -3
- package/access-table.mjs +343 -0
- package/backend-api.mjs +23 -1
- 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 +8 -0
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/cli.mjs +95 -17
- package/backends/llvm/src/executable.mjs +128 -11
- package/backends/llvm/src/kvm2llvm.mjs +10 -5
- package/backends/llvm/src/llvm.mjs +121 -9
- 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 +24 -3
- package/backends/llvm/tests/test-llvm.mjs +22 -1
- 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 +130 -23
- package/browser/repl-browser.mjs +16 -5
- package/browser/tree-view.mjs +47 -8
- package/browser/vfs-data.mjs +6 -5
- package/codecs/README.md +1 -0
- package/codecs/djson.mjs +270 -0
- package/codecs/int.mjs +2 -1
- package/codecs/json.mjs +7 -2
- package/codecs/k-parse.mjs +36 -9
- package/codecs/k-print.mjs +26 -6
- package/codecs/runtime/codec-sdk.mjs +24 -6
- package/codecs/runtime/pattern-json.mjs +80 -1
- package/codecs/runtime/prefix-codec.mjs +629 -67
- package/codecs/runtime/show-value.mjs +93 -51
- package/codecs/runtime/unicode-string.mjs +29 -6
- package/codecs/show.mjs +24 -6
- package/codecs/utf16.mjs +2 -1
- package/k.mjs +56 -16
- package/kir.mjs +58 -19
- 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 +11 -3
- package/pkir.mjs +772 -0
- package/repl.mjs +92 -23
- package/scripts/build-repl-html.mjs +22 -3
- package/scripts/perf-ieee.mjs +264 -13
- package/scripts/perf-int.mjs +315 -22
- package/scripts/perf-multiplication.mjs +58 -7
- package/scripts/perf-poly.mjs +306 -24
- package/scripts/run-tests.mjs +3 -0
- package/tests/test-access-table.mjs +213 -0
- package/tests/test-codecs.mjs +168 -0
- package/tests/test-pkir.mjs +530 -0
- package/tests/test-polymorphic-tdd.mjs +196 -0
- package/tests/test-repl-html.mjs +16 -2
- package/tests/test-repl.mjs +63 -1
- package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
|
@@ -7,7 +7,8 @@ import { isProduct, isVariant } from "@fraczak/k/Value.mjs";
|
|
|
7
7
|
import { exportPatternGraph } from "@fraczak/k/codecs/runtime/codec.mjs";
|
|
8
8
|
import { patternToPropertyList } from "@fraczak/k/codecs/runtime/pattern-json.mjs";
|
|
9
9
|
import { specializeKVM } from "@fraczak/k/kvm.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import { lowerPKIRToKVM } from "@fraczak/k/backend-api.mjs";
|
|
11
|
+
import { compileObjectToLLVM, compileLLVMArtifactFromPKIR } from "./llvm.mjs";
|
|
11
12
|
import { compileKVMModuleToLLVM } from "./kvm2llvm.mjs";
|
|
12
13
|
|
|
13
14
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
@@ -263,6 +264,9 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
|
|
|
263
264
|
"static int write_frame(k_wire_prefix *prefix, k_pattern *pattern, k_value *value) {",
|
|
264
265
|
" size_t length = 0;",
|
|
265
266
|
" unsigned char *payload = k_encode_wire_as_with_prefix(prefix, pattern, value, &length);",
|
|
267
|
+
" if (payload == NULL) {",
|
|
268
|
+
" payload = k_encode_wire(value, &length);",
|
|
269
|
+
" }",
|
|
266
270
|
" if (payload == NULL || length > UINT32_MAX) {",
|
|
267
271
|
" free(payload);",
|
|
268
272
|
" return 0;",
|
|
@@ -376,6 +380,9 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
|
|
|
376
380
|
" }",
|
|
377
381
|
" size_t out_len = 0;",
|
|
378
382
|
" unsigned char *out_payload = k_encode_wire_as_with_prefix(&output_prefix, &compiled_output_pattern, result.value, &out_len);",
|
|
383
|
+
" if (out_payload == NULL) {",
|
|
384
|
+
" out_payload = k_encode_wire(result.value, &out_len);",
|
|
385
|
+
" }",
|
|
379
386
|
" if (tracing) t4 = monotonic_ns();",
|
|
380
387
|
" int ok = 0;",
|
|
381
388
|
" uint64_t write_start = t4;",
|
|
@@ -495,6 +502,9 @@ export function stdioDriverSource({ inputPattern = null, outputPattern = null }
|
|
|
495
502
|
" }",
|
|
496
503
|
" size_t output_length = 0;",
|
|
497
504
|
" unsigned char *output_payload = k_encode_wire_as_with_prefix(&output_prefix, &compiled_output_pattern, result.value, &output_length);",
|
|
505
|
+
" if (output_payload == NULL) {",
|
|
506
|
+
" output_payload = k_encode_wire(result.value, &output_length);",
|
|
507
|
+
" }",
|
|
498
508
|
" if (tracing) t3 = monotonic_ns();",
|
|
499
509
|
" int ok = output_payload != NULL && fwrite(output_payload, 1, output_length, stdout) == output_length && fflush(stdout) == 0;",
|
|
500
510
|
" if (tracing) {",
|
|
@@ -540,12 +550,25 @@ export function compileLLVMToExecutable(llvm, outputPath, { driver = stdioDriver
|
|
|
540
550
|
}
|
|
541
551
|
}
|
|
542
552
|
|
|
543
|
-
export function compileObjectToExecutable(
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
553
|
+
export function compileObjectToExecutable(
|
|
554
|
+
object,
|
|
555
|
+
outputPath,
|
|
556
|
+
{
|
|
557
|
+
relation = object.main,
|
|
558
|
+
inputPattern = null,
|
|
559
|
+
runtimeMode = "fast",
|
|
560
|
+
clangOpt = "-O3",
|
|
561
|
+
usePKIR = false
|
|
562
|
+
} = {}
|
|
563
|
+
) {
|
|
564
|
+
const { inputPattern: compiledInputPattern, outputPattern, llvm } =
|
|
565
|
+
compileObjectToLLVM(object, {
|
|
566
|
+
relation,
|
|
567
|
+
inputPattern:
|
|
568
|
+
inputPattern || inputPatternForObjectRelation(object, relation),
|
|
569
|
+
runtimeMode,
|
|
570
|
+
usePKIR
|
|
571
|
+
});
|
|
549
572
|
compileLLVMToExecutable(llvm, outputPath, {
|
|
550
573
|
driver: stdioDriverSource({
|
|
551
574
|
inputPattern: compiledInputPattern,
|
|
@@ -559,7 +582,8 @@ export function compileKVMToExecutable(kvmInput, outputPath, {
|
|
|
559
582
|
entry = null,
|
|
560
583
|
inputPattern = null,
|
|
561
584
|
runtimeMode = "fast",
|
|
562
|
-
clangOpt = "-O3"
|
|
585
|
+
clangOpt = "-O3",
|
|
586
|
+
usePKIR = false
|
|
563
587
|
} = {}) {
|
|
564
588
|
let kvm = kvmInput;
|
|
565
589
|
if (kvm?.format === "k-vm") {
|
|
@@ -578,7 +602,8 @@ export function compileKVMToExecutable(kvmInput, outputPath, {
|
|
|
578
602
|
relation: entryFunc,
|
|
579
603
|
inputPattern: compiledInputPattern,
|
|
580
604
|
outputPattern,
|
|
581
|
-
runtimeMode
|
|
605
|
+
runtimeMode,
|
|
606
|
+
usePKIR
|
|
582
607
|
});
|
|
583
608
|
compileLLVMToExecutable(llvm, outputPath, {
|
|
584
609
|
driver: stdioDriverSource({
|
|
@@ -589,10 +614,102 @@ export function compileKVMToExecutable(kvmInput, outputPath, {
|
|
|
589
614
|
});
|
|
590
615
|
}
|
|
591
616
|
|
|
592
|
-
export function
|
|
617
|
+
export function compilePKIRToExecutable(
|
|
618
|
+
pkirInput,
|
|
619
|
+
outputPath,
|
|
620
|
+
{
|
|
621
|
+
entry = null,
|
|
622
|
+
inputPattern = null,
|
|
623
|
+
runtimeMode = "fast",
|
|
624
|
+
clangOpt = "-O3"
|
|
625
|
+
} = {}
|
|
626
|
+
) {
|
|
627
|
+
let kvmProgram;
|
|
628
|
+
let entryFunc;
|
|
629
|
+
if (
|
|
630
|
+
(pkirInput.format === "pk-ir" || pkirInput.format === "k-pkir") &&
|
|
631
|
+
pkirInput.functions
|
|
632
|
+
) {
|
|
633
|
+
kvmProgram = {};
|
|
634
|
+
for (const [name, f] of Object.entries(pkirInput.functions)) {
|
|
635
|
+
kvmProgram[name] = lowerPKIRToKVM(f);
|
|
636
|
+
}
|
|
637
|
+
entryFunc =
|
|
638
|
+
entry ||
|
|
639
|
+
pkirInput.entry ||
|
|
640
|
+
Object.keys(kvmProgram)[0] ||
|
|
641
|
+
"__main__";
|
|
642
|
+
} else if (pkirInput.instructions) {
|
|
643
|
+
const kvm = lowerPKIRToKVM(pkirInput);
|
|
644
|
+
entryFunc = pkirInput.name || entry || "__main__";
|
|
645
|
+
kvmProgram = { [entryFunc]: kvm };
|
|
646
|
+
const scan = (insts) => {
|
|
647
|
+
for (const inst of insts || []) {
|
|
648
|
+
if (inst.op === "call" && inst.func && !kvmProgram[inst.func]) {
|
|
649
|
+
kvmProgram[inst.func] = kvm;
|
|
650
|
+
}
|
|
651
|
+
if (inst.branches) {
|
|
652
|
+
for (const b of inst.branches) scan(b.body);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
scan(kvm.body);
|
|
657
|
+
} else if (pkirInput.functions) {
|
|
658
|
+
kvmProgram = {};
|
|
659
|
+
for (const [name, f] of Object.entries(pkirInput.functions)) {
|
|
660
|
+
kvmProgram[name] = lowerPKIRToKVM(f);
|
|
661
|
+
}
|
|
662
|
+
entryFunc =
|
|
663
|
+
entry ||
|
|
664
|
+
pkirInput.entry ||
|
|
665
|
+
Object.keys(kvmProgram)[0] ||
|
|
666
|
+
"__main__";
|
|
667
|
+
} else {
|
|
668
|
+
const kvm = lowerPKIRToKVM(pkirInput);
|
|
669
|
+
entryFunc = pkirInput.name || entry || "__main__";
|
|
670
|
+
kvmProgram = { [entryFunc]: kvm };
|
|
671
|
+
}
|
|
672
|
+
return compileKVMToExecutable(
|
|
673
|
+
{
|
|
674
|
+
format: "k-vm",
|
|
675
|
+
layer: "KVM",
|
|
676
|
+
entry: entryFunc,
|
|
677
|
+
functions: kvmProgram
|
|
678
|
+
},
|
|
679
|
+
outputPath,
|
|
680
|
+
{
|
|
681
|
+
entry: entryFunc,
|
|
682
|
+
inputPattern,
|
|
683
|
+
runtimeMode,
|
|
684
|
+
clangOpt,
|
|
685
|
+
usePKIR: true
|
|
686
|
+
}
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export function compileObjectAndRun(
|
|
691
|
+
object,
|
|
692
|
+
{
|
|
693
|
+
relation = object.main,
|
|
694
|
+
input,
|
|
695
|
+
expected = null,
|
|
696
|
+
inputPattern = null,
|
|
697
|
+
usePKIR = false
|
|
698
|
+
}
|
|
699
|
+
) {
|
|
593
700
|
const { llvm } = compileObjectToLLVM(object, {
|
|
594
701
|
relation,
|
|
595
|
-
inputPattern:
|
|
702
|
+
inputPattern:
|
|
703
|
+
inputPattern || inputPatternForObjectValue(object, input, relation),
|
|
704
|
+
usePKIR
|
|
596
705
|
});
|
|
597
706
|
return compileAndRunLLVM(llvm, { input, expected });
|
|
598
707
|
}
|
|
708
|
+
|
|
709
|
+
export function compilePKIRAndRun(
|
|
710
|
+
pkirInput,
|
|
711
|
+
{ input, expected = null, options = {} } = {}
|
|
712
|
+
) {
|
|
713
|
+
const llvm = compileLLVMArtifactFromPKIR(pkirInput, options);
|
|
714
|
+
return compileAndRunLLVM(llvm, { input, expected });
|
|
715
|
+
}
|
|
@@ -451,12 +451,15 @@ function hasSelfTailCall(insts, funcName, isTail = true) {
|
|
|
451
451
|
return false;
|
|
452
452
|
}
|
|
453
453
|
|
|
454
|
-
function getFieldEdgeIndex(inst, regPatterns, kvmFunc) {
|
|
454
|
+
function getFieldEdgeIndex(inst, regPatterns, kvmFunc, ctx = {}) {
|
|
455
455
|
const srcReg = cleanReg(inst.src);
|
|
456
456
|
const srcPattern = regPatterns.get(srcReg) || (srcReg === "in" ? kvmFunc.inputPattern : null);
|
|
457
457
|
if (Array.isArray(srcPattern) && srcPattern.length > 0) {
|
|
458
458
|
const root = srcPattern[0];
|
|
459
|
-
|
|
459
|
+
const allowed = ctx.usePKIR
|
|
460
|
+
? root[0] === "closed-product"
|
|
461
|
+
: (root[0] === "open-product" || root[0] === "closed-product");
|
|
462
|
+
if (allowed && Array.isArray(root[1])) {
|
|
460
463
|
const idx = root[1].findIndex(([l]) => l === inst.label);
|
|
461
464
|
if (idx >= 0) return idx;
|
|
462
465
|
}
|
|
@@ -514,6 +517,7 @@ export function compileKVMModuleToLLVM(entryName, kvmProgram, options = {}) {
|
|
|
514
517
|
labels,
|
|
515
518
|
functionNames,
|
|
516
519
|
runtimeMode,
|
|
520
|
+
usePKIR: Boolean(options.usePKIR),
|
|
517
521
|
armIndex: 0,
|
|
518
522
|
unionExprIndex: 0,
|
|
519
523
|
syntheticFunctions: [],
|
|
@@ -584,6 +588,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
584
588
|
labels: moduleCtx.labels,
|
|
585
589
|
functionNames: moduleCtx.functionNames,
|
|
586
590
|
runtimeMode: moduleCtx.runtimeMode,
|
|
591
|
+
usePKIR: moduleCtx.usePKIR,
|
|
587
592
|
allocas: [],
|
|
588
593
|
lines: [],
|
|
589
594
|
currentBlock: "entry",
|
|
@@ -675,7 +680,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
675
680
|
case "project_field": {
|
|
676
681
|
const input = getReg(inst.src);
|
|
677
682
|
nullCheck(ctx, input, failTarget);
|
|
678
|
-
const edgeIndex = getFieldEdgeIndex(inst, regPatterns, kvmFunc);
|
|
683
|
+
const edgeIndex = getFieldEdgeIndex(inst, regPatterns, kvmFunc, ctx);
|
|
679
684
|
const label = ctx.labelRef(inst.label);
|
|
680
685
|
let val;
|
|
681
686
|
if (edgeIndex >= 0 && ctx.runtimeMode !== "compact") {
|
|
@@ -865,7 +870,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
865
870
|
const exprName = `@k_union_expr_${exprIndex}`;
|
|
866
871
|
const exprFunc = {
|
|
867
872
|
name: `union_expr_${exprIndex}`,
|
|
868
|
-
inputPattern:
|
|
873
|
+
inputPattern: regPatterns.get(cleanReg(inst.src)) || null,
|
|
869
874
|
outputPattern: kvmFunc.outputPattern,
|
|
870
875
|
body: [
|
|
871
876
|
{ op: "id", dest: "%v0", src: "%in" },
|
|
@@ -899,7 +904,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
899
904
|
|
|
900
905
|
const armFunc = {
|
|
901
906
|
name: `union_arm_${armIndex}`,
|
|
902
|
-
inputPattern:
|
|
907
|
+
inputPattern: regPatterns.get(cleanReg(inst.src)) || null,
|
|
903
908
|
outputPattern: kvmFunc.outputPattern,
|
|
904
909
|
body: branch.body
|
|
905
910
|
};
|
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
objectToKVMArtifact,
|
|
8
8
|
specializeKVM,
|
|
9
9
|
lowerKIRToKVM,
|
|
10
|
-
objectToKIRP
|
|
10
|
+
objectToKIRP,
|
|
11
|
+
compileRelationToPKIR,
|
|
12
|
+
lowerPKIRToKVM,
|
|
13
|
+
exportPatternGraph,
|
|
14
|
+
patternToPropertyList
|
|
11
15
|
} from "@fraczak/k/backend-api.mjs";
|
|
12
16
|
import { compileKVMModuleToLLVM } from "./kvm2llvm.mjs";
|
|
13
17
|
|
|
@@ -923,7 +927,8 @@ function emitFunctionBody(symbol, body, ctx, linkage = "", options = {}) {
|
|
|
923
927
|
}
|
|
924
928
|
const value = lowerExpr(ctx, body, input, { tail: options.tail !== false });
|
|
925
929
|
if (value === false) {
|
|
926
|
-
// The expression emitted complete control flow, including all
|
|
930
|
+
// The expression emitted complete control flow, including all
|
|
931
|
+
// returns.
|
|
927
932
|
} else if (value == null) {
|
|
928
933
|
unsupported(ctx);
|
|
929
934
|
} else {
|
|
@@ -1010,25 +1015,74 @@ export function emitLLVMModule(input, options = {}) {
|
|
|
1010
1015
|
}
|
|
1011
1016
|
|
|
1012
1017
|
export function compileObjectToLLVM(object, options = {}) {
|
|
1013
|
-
const inputPattern = options.inputPattern
|
|
1018
|
+
const inputPattern = options.inputPattern
|
|
1019
|
+
? readPattern(options.inputPattern)
|
|
1020
|
+
: null;
|
|
1014
1021
|
const relation = options.relation || object.main;
|
|
1015
1022
|
let targetObject = object;
|
|
1016
1023
|
let entryInputPattern = inputPattern;
|
|
1017
1024
|
let outputPattern = null;
|
|
1018
1025
|
|
|
1019
|
-
if (
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1026
|
+
if (options.usePKIR) {
|
|
1027
|
+
const rel = object.rels?.[relation] ||
|
|
1028
|
+
(object.relAlias?.[relation] &&
|
|
1029
|
+
object.rels?.[object.relAlias[relation]]) ||
|
|
1030
|
+
object.rels?.[object.main];
|
|
1031
|
+
if (rel?.typePatternGraph) {
|
|
1032
|
+
const graph = rel.typePatternGraph;
|
|
1033
|
+
if (!entryInputPattern &&
|
|
1034
|
+
rel.def?.patterns?.[0] !== undefined) {
|
|
1035
|
+
const inId = graph.find(rel.def.patterns[0]);
|
|
1036
|
+
entryInputPattern =
|
|
1037
|
+
patternToPropertyList(exportPatternGraph(graph, inId));
|
|
1038
|
+
}
|
|
1039
|
+
if (rel.def?.patterns?.[1] !== undefined) {
|
|
1040
|
+
const outId = graph.find(rel.def.patterns[1]);
|
|
1041
|
+
outputPattern =
|
|
1042
|
+
patternToPropertyList(exportPatternGraph(graph, outId));
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
} else if (inputPattern) {
|
|
1046
|
+
const retyped = retypeObjectRelationForBackend(
|
|
1047
|
+
object, relation, inputPattern, {
|
|
1048
|
+
source: options.source || "<k-llvm>"
|
|
1049
|
+
}
|
|
1050
|
+
);
|
|
1023
1051
|
targetObject = retyped.retypedObject;
|
|
1024
1052
|
entryInputPattern = retyped.inputPattern;
|
|
1025
1053
|
outputPattern = retyped.outputPattern;
|
|
1026
1054
|
}
|
|
1027
1055
|
|
|
1028
|
-
|
|
1029
|
-
|
|
1056
|
+
let functions;
|
|
1057
|
+
let retypedKir = null;
|
|
1030
1058
|
const entry = relation || targetObject.main || "__main__";
|
|
1031
1059
|
|
|
1060
|
+
if (options.usePKIR) {
|
|
1061
|
+
functions = {};
|
|
1062
|
+
for (const [name, relDef] of Object.entries(targetObject.rels || {})) {
|
|
1063
|
+
const pkir = compileRelationToPKIR(relDef, name);
|
|
1064
|
+
functions[name] = lowerPKIRToKVM(pkir);
|
|
1065
|
+
}
|
|
1066
|
+
for (const [alias, target] of Object.entries(targetObject.relAlias || {})) {
|
|
1067
|
+
if (functions[target] && !functions[alias]) {
|
|
1068
|
+
functions[alias] = functions[target];
|
|
1069
|
+
}
|
|
1070
|
+
const stripped = target.startsWith("@") ? target.slice(1) : target;
|
|
1071
|
+
if (functions[stripped] && !functions[alias]) {
|
|
1072
|
+
functions[alias] = functions[stripped];
|
|
1073
|
+
}
|
|
1074
|
+
if (functions[alias] && !functions[target]) {
|
|
1075
|
+
functions[target] = functions[alias];
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
if (relation && !functions[relation] && functions[targetObject.main]) {
|
|
1079
|
+
functions[relation] = functions[targetObject.main];
|
|
1080
|
+
}
|
|
1081
|
+
} else {
|
|
1082
|
+
retypedKir = objectToKIRP(targetObject);
|
|
1083
|
+
functions = lowerKIRToKVM(retypedKir);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1032
1086
|
const specializedKvm = {
|
|
1033
1087
|
format: "k-vm",
|
|
1034
1088
|
version: 1,
|
|
@@ -1065,6 +1119,63 @@ export function compileLLVMArtifactFromKVM(kvmInput, options = {}) {
|
|
|
1065
1119
|
return compileKVMModuleToLLVM(entry, functions, options);
|
|
1066
1120
|
}
|
|
1067
1121
|
|
|
1122
|
+
export function compileLLVMArtifactFromPKIR(pkirInput, options = {}) {
|
|
1123
|
+
let kvmProgram;
|
|
1124
|
+
let entry;
|
|
1125
|
+
if (
|
|
1126
|
+
(pkirInput.format === "pk-ir" || pkirInput.format === "k-pkir") &&
|
|
1127
|
+
pkirInput.functions
|
|
1128
|
+
) {
|
|
1129
|
+
entry =
|
|
1130
|
+
pkirInput.entry ||
|
|
1131
|
+
options.entry ||
|
|
1132
|
+
Object.keys(pkirInput.functions)[0] ||
|
|
1133
|
+
"__main__";
|
|
1134
|
+
kvmProgram = {};
|
|
1135
|
+
for (const [name, f] of Object.entries(pkirInput.functions)) {
|
|
1136
|
+
kvmProgram[name] = lowerPKIRToKVM(f);
|
|
1137
|
+
}
|
|
1138
|
+
} else if (pkirInput.instructions) {
|
|
1139
|
+
const kvm = lowerPKIRToKVM(pkirInput);
|
|
1140
|
+
entry = pkirInput.name || options.entry || "__main__";
|
|
1141
|
+
kvmProgram = { [entry]: kvm };
|
|
1142
|
+
const scan = (insts) => {
|
|
1143
|
+
for (const inst of insts || []) {
|
|
1144
|
+
if (inst.op === "call" && inst.func && !kvmProgram[inst.func]) {
|
|
1145
|
+
kvmProgram[inst.func] = kvm;
|
|
1146
|
+
}
|
|
1147
|
+
if (inst.branches) {
|
|
1148
|
+
for (const b of inst.branches) scan(b.body);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
scan(kvm.body);
|
|
1153
|
+
} else if (pkirInput.functions) {
|
|
1154
|
+
entry =
|
|
1155
|
+
pkirInput.entry ||
|
|
1156
|
+
options.entry ||
|
|
1157
|
+
Object.keys(pkirInput.functions)[0] ||
|
|
1158
|
+
"__main__";
|
|
1159
|
+
kvmProgram = {};
|
|
1160
|
+
for (const [name, f] of Object.entries(pkirInput.functions)) {
|
|
1161
|
+
kvmProgram[name] = lowerPKIRToKVM(f);
|
|
1162
|
+
}
|
|
1163
|
+
} else {
|
|
1164
|
+
const kvm = lowerPKIRToKVM(pkirInput);
|
|
1165
|
+
entry = pkirInput.name || options.entry || "__main__";
|
|
1166
|
+
kvmProgram = { [entry]: kvm };
|
|
1167
|
+
}
|
|
1168
|
+
return compileLLVMArtifactFromKVM(
|
|
1169
|
+
{
|
|
1170
|
+
format: "k-vm",
|
|
1171
|
+
layer: "KVM",
|
|
1172
|
+
entry,
|
|
1173
|
+
functions: kvmProgram
|
|
1174
|
+
},
|
|
1175
|
+
options
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1068
1179
|
export function compileLLVMArtifactFromObject(object, options = {}) {
|
|
1069
1180
|
return compileObjectToLLVM(object, options);
|
|
1070
1181
|
}
|
|
@@ -1080,6 +1191,7 @@ export default {
|
|
|
1080
1191
|
compileBufferToLLVM,
|
|
1081
1192
|
compileObjectToLLVM,
|
|
1082
1193
|
compileLLVMArtifactFromKVM,
|
|
1194
|
+
compileLLVMArtifactFromPKIR,
|
|
1083
1195
|
compileLLVMArtifactFromObject,
|
|
1084
1196
|
emitLLVMModule,
|
|
1085
1197
|
llvmIdentifier
|
|
@@ -72,19 +72,19 @@ node ./bin/k-llvm-compile.mjs --help | grep -q 'Compile a k .ko/.klib object'
|
|
|
72
72
|
|
|
73
73
|
node ./bin/k-llvm-build.mjs --help | grep -q 'binary k pattern+value envelope'
|
|
74
74
|
|
|
75
|
-
node ./bin/k-llvm
|
|
75
|
+
node ./bin/k-llvm.mjs --help | grep -q 'binary pattern+value wire stream'
|
|
76
76
|
|
|
77
|
-
node ./
|
|
77
|
+
node ./tests/k-llvm-run.mjs --help | grep -q 'Compile and execute a k .ko/.klib object'
|
|
78
78
|
|
|
79
79
|
node ../../objects/compile.mjs '.x' "$TMP_DIR/run.ko"
|
|
80
80
|
printf '{"x":"left","y":"right"}' > "$TMP_DIR/run-input.kv"
|
|
81
81
|
printf '"left"' > "$TMP_DIR/run-expected.kv"
|
|
82
|
-
node ./
|
|
83
|
-
node ./
|
|
82
|
+
node ./tests/k-llvm-run.mjs --expect "$TMP_DIR/run-expected.kv" "$TMP_DIR/run.ko" "$TMP_DIR/run-input.kv" | grep -qx 'OK'
|
|
83
|
+
node ./tests/k-llvm-run.mjs "$TMP_DIR/run.ko" "$TMP_DIR/run-input.kv" | grep -qx '"left"'
|
|
84
84
|
|
|
85
85
|
node ../../objects/compile.mjs '{ .x fieldA, .y fieldB }' "$TMP_DIR/run-product.ko"
|
|
86
86
|
printf '{"x":"left","y":"right"}' > "$TMP_DIR/run-product-input.kv"
|
|
87
|
-
node ./
|
|
87
|
+
node ./tests/k-llvm-run.mjs "$TMP_DIR/run-product.ko" "$TMP_DIR/run-product-input.kv" | grep -qx '{"fieldA":"left","fieldB":"right"}'
|
|
88
88
|
|
|
89
89
|
node ./bin/k-llvm-build.mjs '?{<{}=X0 left, ...> x, <X0 right, ...> y} .x' -o "$TMP_DIR/run-exe"
|
|
90
90
|
printf '{"x":"left","y":"right"}' \
|
|
@@ -130,31 +130,31 @@ printf '987654321' \
|
|
|
130
130
|
|
|
131
131
|
printf '{"x":"left","y":"right"}' \
|
|
132
132
|
| node ../../codecs/k-parse.mjs \
|
|
133
|
-
| node ./bin/k-llvm
|
|
133
|
+
| node ./bin/k-llvm.mjs --cache-dir "$TMP_DIR/jit-cache" "$TMP_DIR/run.ko" \
|
|
134
134
|
| node ../../codecs/k-print.mjs \
|
|
135
135
|
| grep -qx '"left"'
|
|
136
136
|
|
|
137
137
|
node --input-type=module -e "import { stdout } from 'node:process'; import { encodeToWire } from '../../codecs/runtime/prefix-codec.mjs'; import { Value } from '../../Value.mjs'; const pattern = [[\"open-union\",[[\"left\",1],[\"right\",1]]],[\"closed-product\",[]]]; stdout.write(encodeToWire(Value.variant(\"left\", Value.product({}), pattern), pattern));" \
|
|
138
|
-
| node ./bin/k-llvm
|
|
138
|
+
| node ./bin/k-llvm.mjs --cache-dir "$TMP_DIR/jit-cache" "$TMP_DIR/id.ko" \
|
|
139
139
|
| node --input-type=module -e "import { stdin } from 'node:process'; import { decodeWire } from '../../codecs/runtime/prefix-codec.mjs'; const chunks = []; stdin.on('data', (chunk) => chunks.push(chunk)); stdin.on('end', () => console.log(JSON.stringify(decodeWire(Buffer.concat(chunks)).pattern)));" \
|
|
140
140
|
| grep -Fqx '[["open-union",[["left",1],["right",1]]],["closed-product",[]]]'
|
|
141
141
|
|
|
142
142
|
node ../../objects/compile.mjs '/"ह" |"😀"' "$TMP_DIR/unicode-variant.ko"
|
|
143
143
|
node --input-type=module -e "import { stdout } from 'node:process'; import { encodeToWire } from '../../codecs/runtime/prefix-codec.mjs'; import { Value } from '../../Value.mjs'; const pattern = [[\"closed-union\", [[\"ह\", 1]]], [\"closed-product\", []]]; stdout.write(encodeToWire(Value.variant('ह', Value.product({}), pattern), pattern));" \
|
|
144
|
-
| node ./bin/k-llvm
|
|
144
|
+
| node ./bin/k-llvm.mjs --cache-dir "$TMP_DIR/jit-cache" "$TMP_DIR/unicode-variant.ko" \
|
|
145
145
|
| node ../../codecs/k-print.mjs \
|
|
146
146
|
| grep -qx '"😀"'
|
|
147
147
|
|
|
148
148
|
node ../../objects/compile.mjs '/"a\u0000b" |"nul-ok"' "$TMP_DIR/nul-variant.ko"
|
|
149
149
|
node --input-type=module -e "import { stdout } from 'node:process'; import { encodeToWire } from '../../codecs/runtime/prefix-codec.mjs'; import { Value } from '../../Value.mjs'; const tag = 'a\u0000b'; const pattern = [[\"closed-union\", [[tag, 1]]], [\"closed-product\", []]]; stdout.write(encodeToWire(Value.variant(tag, Value.product({}), pattern), pattern));" \
|
|
150
|
-
| node ./bin/k-llvm
|
|
150
|
+
| node ./bin/k-llvm.mjs --cache-dir "$TMP_DIR/jit-cache" "$TMP_DIR/nul-variant.ko" \
|
|
151
151
|
| node ../../codecs/k-print.mjs \
|
|
152
152
|
| grep -qx '"nul-ok"'
|
|
153
153
|
|
|
154
154
|
node --input-type=module -e "import { stdout } from 'node:process'; import { encodeToWire } from '../../codecs/runtime/prefix-codec.mjs'; import { Value } from '../../Value.mjs'; const labels = ['a', 'é', 'ह', '\uE000', '😀', '𠀀', 'a\u0000b']; const pattern = [[\"closed-product\", labels.map((label) => [label, 1])], [\"closed-product\", []]]; const value = Value.product(Object.fromEntries(labels.map((label) => [label, Value.product({})])), pattern); stdout.write(encodeToWire(value, pattern));" \
|
|
155
|
-
| node ./bin/k-llvm
|
|
155
|
+
| node ./bin/k-llvm.mjs --cache-dir "$TMP_DIR/jit-cache" "$TMP_DIR/id.ko" \
|
|
156
156
|
| node --input-type=module -e "import assert from 'node:assert/strict'; import { stdin } from 'node:process'; import { decodeWire } from '../../codecs/runtime/prefix-codec.mjs'; const chunks = []; for await (const chunk of stdin) chunks.push(chunk); const labels = ['a', 'é', 'ह', '\uE000', '😀', '𠀀', 'a\u0000b']; const { pattern } = decodeWire(Buffer.concat(chunks)); assert.equal(pattern[0][0], 'closed-product'); assert.deepEqual(new Set(pattern[0][1].map(([label]) => label)), new Set(labels));"
|
|
157
157
|
|
|
158
158
|
node --input-type=module -e "import { stdout } from 'node:process'; import { encodeToWire } from '../../codecs/runtime/prefix-codec.mjs'; import { Value } from '../../Value.mjs'; const labels = ['a', 'é', 'ह', '\uE000', '😀', '𠀀', 'a\u0000b']; const pattern = [[\"open-union\", labels.map((label) => [label, 1])], [\"closed-product\", []]]; stdout.write(encodeToWire(Value.variant('a\u0000b', Value.product({}), pattern), pattern));" \
|
|
159
|
-
| node ./bin/k-llvm
|
|
159
|
+
| node ./bin/k-llvm.mjs --cache-dir "$TMP_DIR/jit-cache" "$TMP_DIR/id.ko" \
|
|
160
160
|
| node --input-type=module -e "import assert from 'node:assert/strict'; import { stdin } from 'node:process'; import { decodeWire } from '../../codecs/runtime/prefix-codec.mjs'; const chunks = []; for await (const chunk of stdin) chunks.push(chunk); const labels = ['a', 'é', 'ह', '\uE000', '😀', '𠀀', 'a\u0000b']; const { pattern, value } = decodeWire(Buffer.concat(chunks)); assert.equal(pattern[0][0], 'open-union'); assert.deepEqual(new Set(pattern[0][1].map(([label]) => label)), new Set(labels)); assert.equal(value.tag, 'a\u0000b');"
|
|
@@ -6,22 +6,35 @@ import { decodeObject } from "@fraczak/k/object.mjs";
|
|
|
6
6
|
import { parseValue } from "@fraczak/k/valueIO.mjs";
|
|
7
7
|
import { compileObjectAndRun } from "../src/executable.mjs";
|
|
8
8
|
|
|
9
|
-
function
|
|
9
|
+
function helpText() {
|
|
10
10
|
const prog = argv[1] || "k-llvm-run.mjs";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
return [
|
|
12
|
+
"Compile and execute a k .ko/.klib object through LLVM.",
|
|
13
|
+
"",
|
|
14
|
+
`Usage: ${prog} [options] object-file [input.kv]`,
|
|
15
|
+
"",
|
|
16
|
+
"Arguments:",
|
|
17
|
+
" object-file Input .ko or .klib file.",
|
|
18
|
+
" input.kv Input value. Reads text from stdin when omitted.",
|
|
19
|
+
"",
|
|
20
|
+
"Options:",
|
|
21
|
+
" --retype rel Relation to specialize (default: main).",
|
|
22
|
+
" --input-pattern value Input pattern property-list JSON or file.",
|
|
23
|
+
" --expect value Expected output value JSON/text or file.",
|
|
24
|
+
" --pkir Lower via Polymorphic K IR (PKIR).",
|
|
25
|
+
" -h, --help Show this help.",
|
|
26
|
+
"",
|
|
27
|
+
"Without --expect, the runner prints the result as compact JSON.",
|
|
28
|
+
"",
|
|
29
|
+
"Examples:",
|
|
30
|
+
` ${prog} program.ko input.kv`,
|
|
31
|
+
` ${prog} --expect expected.kv program.ko input.kv`,
|
|
32
|
+
` echo '{"x":"left"}' | ${prog} program.ko`
|
|
33
|
+
].join("\n");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function usage(stream = console.error) {
|
|
37
|
+
stream(helpText());
|
|
25
38
|
}
|
|
26
39
|
|
|
27
40
|
async function readStdinText() {
|
|
@@ -33,7 +46,9 @@ async function readStdinText() {
|
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
function readMaybeFile(textOrPath) {
|
|
36
|
-
return fs.existsSync(textOrPath)
|
|
49
|
+
return fs.existsSync(textOrPath)
|
|
50
|
+
? fs.readFileSync(textOrPath, "utf8")
|
|
51
|
+
: textOrPath;
|
|
37
52
|
}
|
|
38
53
|
|
|
39
54
|
function readPattern(inputPattern) {
|
|
@@ -51,6 +66,7 @@ try {
|
|
|
51
66
|
let relation = null;
|
|
52
67
|
let inputPattern = null;
|
|
53
68
|
let expectedText = null;
|
|
69
|
+
let usePKIR = false;
|
|
54
70
|
while (args.length > 0 && args[0].startsWith("--")) {
|
|
55
71
|
const option = args.shift();
|
|
56
72
|
if (option === "--retype") {
|
|
@@ -58,10 +74,16 @@ try {
|
|
|
58
74
|
if (!relation) throw new Error("--retype requires a relation name");
|
|
59
75
|
} else if (option === "--input-pattern") {
|
|
60
76
|
inputPattern = args.shift();
|
|
61
|
-
if (!inputPattern)
|
|
77
|
+
if (!inputPattern) {
|
|
78
|
+
throw new Error("--input-pattern requires JSON or a file path");
|
|
79
|
+
}
|
|
62
80
|
} else if (option === "--expect") {
|
|
63
81
|
expectedText = args.shift();
|
|
64
|
-
if (!expectedText)
|
|
82
|
+
if (!expectedText) {
|
|
83
|
+
throw new Error("--expect requires a value or file path");
|
|
84
|
+
}
|
|
85
|
+
} else if (option === "--pkir") {
|
|
86
|
+
usePKIR = true;
|
|
65
87
|
} else {
|
|
66
88
|
throw new Error(`Unknown option: ${option}`);
|
|
67
89
|
}
|
|
@@ -73,18 +95,22 @@ try {
|
|
|
73
95
|
if (args.length > 0) throw new Error(`Unexpected argument: ${args[0]}`);
|
|
74
96
|
|
|
75
97
|
const object = decodeObject(fs.readFileSync(objectPath));
|
|
76
|
-
const inputText = inputPath == null
|
|
98
|
+
const inputText = inputPath == null
|
|
99
|
+
? await readStdinText()
|
|
100
|
+
: fs.readFileSync(inputPath, "utf8");
|
|
77
101
|
const input = parseValue(inputText);
|
|
78
|
-
const expected = expectedText == null
|
|
102
|
+
const expected = expectedText == null
|
|
103
|
+
? null
|
|
104
|
+
: parseValue(readMaybeFile(expectedText));
|
|
79
105
|
const result = compileObjectAndRun(object, {
|
|
80
106
|
relation: relation || object.main,
|
|
81
107
|
input,
|
|
82
108
|
expected,
|
|
83
|
-
inputPattern: readPattern(inputPattern)
|
|
109
|
+
inputPattern: readPattern(inputPattern),
|
|
110
|
+
usePKIR
|
|
84
111
|
});
|
|
85
112
|
stdout.write(expected == null ? result.stdout : "OK\n");
|
|
86
113
|
} catch (error) {
|
|
87
114
|
console.error(error.stack || error.message || String(error));
|
|
88
|
-
usage();
|
|
89
115
|
exit(1);
|
|
90
116
|
}
|
|
@@ -148,7 +148,17 @@ export function wireInput(value, pattern = value.pattern) {
|
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
export function compileCaseExecutable({
|
|
151
|
+
export function compileCaseExecutable({
|
|
152
|
+
object,
|
|
153
|
+
relationName,
|
|
154
|
+
relHash,
|
|
155
|
+
inputPattern,
|
|
156
|
+
cacheDir,
|
|
157
|
+
sourceLabel,
|
|
158
|
+
runtimeMode = "fast",
|
|
159
|
+
clangOpt = "-O3",
|
|
160
|
+
usePKIR = false
|
|
161
|
+
}) {
|
|
152
162
|
const key = sha256([
|
|
153
163
|
"k-llvm-perf-v1",
|
|
154
164
|
backendFingerprint(),
|
|
@@ -157,12 +167,23 @@ export function compileCaseExecutable({ object, relationName, relHash, inputPatt
|
|
|
157
167
|
sourceLabel,
|
|
158
168
|
relationName,
|
|
159
169
|
relHash,
|
|
160
|
-
JSON.stringify(inputPattern)
|
|
170
|
+
JSON.stringify(inputPattern),
|
|
171
|
+
usePKIR ? "pkir" : "kir"
|
|
161
172
|
].join("\0"));
|
|
162
173
|
const exePath = path.join(cacheDir, `${key}.exe`);
|
|
163
174
|
if (!fs.existsSync(exePath)) {
|
|
164
175
|
const tmpPath = path.join(cacheDir, `${key}.${process.pid}.tmp`);
|
|
165
|
-
compileObjectToExecutable(
|
|
176
|
+
compileObjectToExecutable(
|
|
177
|
+
cloneObjectPayload(object),
|
|
178
|
+
tmpPath,
|
|
179
|
+
{
|
|
180
|
+
relation: relationName,
|
|
181
|
+
inputPattern,
|
|
182
|
+
runtimeMode,
|
|
183
|
+
clangOpt,
|
|
184
|
+
usePKIR
|
|
185
|
+
}
|
|
186
|
+
);
|
|
166
187
|
fs.renameSync(tmpPath, exePath);
|
|
167
188
|
}
|
|
168
189
|
return exePath;
|