@fraczak/k 7.0.2 → 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 +42 -0
- package/DOCS/FILE_FORMATS.md +238 -15
- package/DOCS/POLYMORPHIC_IR.md +104 -0
- package/JOURNAL.md +288 -0
- package/README.md +10 -2
- 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 +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/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/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 +10 -3
- package/pkir.mjs +772 -0
- package/repl.mjs +36 -18
- package/scripts/build-repl-html.mjs +14 -2
- 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-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/llvm/bin/k-llvm-jit.mjs +0 -160
|
@@ -1914,6 +1914,14 @@ unsigned char *k_encode_wire_as(k_pattern *pattern, k_value *value, size_t *out_
|
|
|
1914
1914
|
return bytes;
|
|
1915
1915
|
}
|
|
1916
1916
|
|
|
1917
|
+
unsigned char *k_encode_wire(k_value *value, size_t *out_length) {
|
|
1918
|
+
k_pattern *pattern = derive_pattern(value);
|
|
1919
|
+
if (pattern == NULL) return NULL;
|
|
1920
|
+
unsigned char *bytes = k_encode_wire_as(pattern, value, out_length);
|
|
1921
|
+
free_pattern(pattern);
|
|
1922
|
+
return bytes;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1917
1925
|
int k_write_wire_as(FILE *out, k_pattern *pattern, k_value *value) {
|
|
1918
1926
|
size_t length = 0;
|
|
1919
1927
|
unsigned char *bytes = k_encode_wire_as(pattern, value, &length);
|
|
@@ -110,6 +110,7 @@ void k_wire_prefix_free(k_wire_prefix prefix);
|
|
|
110
110
|
k_value *k_decode_wire_value_with_prefix(const unsigned char *bytes, size_t length, k_wire_prefix *prefix, k_pattern *pattern, k_rt *rt);
|
|
111
111
|
unsigned char *k_encode_wire_as_with_prefix(k_wire_prefix *prefix, k_pattern *pattern, k_value *value, size_t *out_length);
|
|
112
112
|
unsigned char *k_encode_wire_as(k_pattern *pattern, k_value *value, size_t *out_length);
|
|
113
|
+
unsigned char *k_encode_wire(k_value *value, size_t *out_length);
|
|
113
114
|
int k_write_wire(FILE *out, k_value *value);
|
|
114
115
|
int k_write_wire_as(FILE *out, k_pattern *pattern, k_value *value);
|
|
115
116
|
|
|
@@ -1,20 +1,73 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
compileLibrary,
|
|
5
|
+
compileObjectBuffer,
|
|
6
|
+
decodeObject,
|
|
7
|
+
loadLibrary
|
|
8
|
+
} from "@fraczak/k/object.mjs";
|
|
4
9
|
|
|
5
10
|
export function readAll(stream) {
|
|
6
11
|
return new Promise((resolve, reject) => {
|
|
7
12
|
const chunks = [];
|
|
8
|
-
stream.on("data", (chunk) =>
|
|
13
|
+
stream.on("data", (chunk) => {
|
|
14
|
+
chunks.push(
|
|
15
|
+
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
|
|
16
|
+
);
|
|
17
|
+
});
|
|
9
18
|
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
10
19
|
stream.on("error", reject);
|
|
11
20
|
});
|
|
12
21
|
}
|
|
13
22
|
|
|
23
|
+
export function loadLibraryFromPath(libPath) {
|
|
24
|
+
const ext = path.extname(libPath).toLowerCase();
|
|
25
|
+
if (ext === ".klib" || ext === ".ko") {
|
|
26
|
+
return loadLibrary(decodeObject(fs.readFileSync(libPath)));
|
|
27
|
+
}
|
|
28
|
+
if (ext === ".k") {
|
|
29
|
+
let depLibs = [];
|
|
30
|
+
const baseName = path.basename(libPath);
|
|
31
|
+
if (baseName === "poly.k") {
|
|
32
|
+
const dir = path.dirname(libPath);
|
|
33
|
+
const arithPath = path.join(dir, "arithmetics.k");
|
|
34
|
+
if (fs.existsSync(arithPath)) {
|
|
35
|
+
const arithLib = loadLibrary(
|
|
36
|
+
compileLibrary(fs.readFileSync(arithPath, "utf8"), {
|
|
37
|
+
source: arithPath
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
depLibs.push(arithLib);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const rawSource = fs.readFileSync(libPath, "utf8");
|
|
44
|
+
if (depLibs.length > 0) {
|
|
45
|
+
const neededExports = [
|
|
46
|
+
"0", "int", "inc", "dec", "nat", "zero_int?", "neg?", "GT"
|
|
47
|
+
];
|
|
48
|
+
const preamble = buildExportPreamble(neededExports, depLibs);
|
|
49
|
+
const compiled = compileLibrary(preamble + rawSource, {
|
|
50
|
+
source: libPath,
|
|
51
|
+
libraries: depLibs
|
|
52
|
+
});
|
|
53
|
+
const mergedLib = loadLibrary(compiled);
|
|
54
|
+
for (const dep of depLibs) {
|
|
55
|
+
for (const [k, v] of Object.entries(dep.relAlias || {})) {
|
|
56
|
+
if (!mergedLib.relAlias[k]) mergedLib.relAlias[k] = v;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return mergedLib;
|
|
60
|
+
}
|
|
61
|
+
return loadLibrary(compileLibrary(rawSource, { source: libPath }));
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Unsupported library extension: ${ext}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
14
66
|
export function parseCompileOptions(args) {
|
|
15
67
|
const libraries = [];
|
|
16
68
|
const exportSpecs = [];
|
|
17
69
|
let loadedLibrary = false;
|
|
70
|
+
let usePKIR = false;
|
|
18
71
|
|
|
19
72
|
while (args.length > 0) {
|
|
20
73
|
if (args[0] === "--") {
|
|
@@ -22,22 +75,26 @@ export function parseCompileOptions(args) {
|
|
|
22
75
|
break;
|
|
23
76
|
}
|
|
24
77
|
if (args[0] === "--lib") {
|
|
25
|
-
if (loadedLibrary)
|
|
78
|
+
if (loadedLibrary) {
|
|
79
|
+
throw new Error("--lib may only be specified once");
|
|
80
|
+
}
|
|
26
81
|
args.shift();
|
|
27
82
|
const libPath = args.shift();
|
|
28
83
|
if (!libPath) throw new Error("--lib requires a file argument");
|
|
29
|
-
|
|
30
|
-
if (ext === ".k") {
|
|
31
|
-
libraries.push(loadLibrary(compileLibrary(fs.readFileSync(libPath, "utf8"), { source: libPath })));
|
|
32
|
-
} else {
|
|
33
|
-
libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
|
|
34
|
-
}
|
|
84
|
+
libraries.push(loadLibraryFromPath(libPath));
|
|
35
85
|
loadedLibrary = true;
|
|
36
86
|
} else if (args[0] === "--export") {
|
|
37
87
|
args.shift();
|
|
38
88
|
const spec = args.shift();
|
|
39
|
-
if (!spec)
|
|
89
|
+
if (!spec) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
"--export requires a spec argument (name or libname:localname)"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
40
94
|
exportSpecs.push(spec);
|
|
95
|
+
} else if (args[0] === "--pkir") {
|
|
96
|
+
args.shift();
|
|
97
|
+
usePKIR = true;
|
|
41
98
|
} else if (args[0].startsWith("--")) {
|
|
42
99
|
break;
|
|
43
100
|
} else {
|
|
@@ -45,7 +102,7 @@ export function parseCompileOptions(args) {
|
|
|
45
102
|
}
|
|
46
103
|
}
|
|
47
104
|
|
|
48
|
-
return { libraries, exportSpecs };
|
|
105
|
+
return { libraries, exportSpecs, usePKIR };
|
|
49
106
|
}
|
|
50
107
|
|
|
51
108
|
export function fileInputType(filePath) {
|
|
@@ -53,6 +110,7 @@ export function fileInputType(filePath) {
|
|
|
53
110
|
if (ext === ".ko") return "ko";
|
|
54
111
|
if (ext === ".kvm") return "kvm";
|
|
55
112
|
if (ext === ".klib") return "klib";
|
|
113
|
+
if (ext === ".pkir") return "pkir";
|
|
56
114
|
return "source-file";
|
|
57
115
|
}
|
|
58
116
|
|
|
@@ -69,11 +127,15 @@ export function resolveProgramInput(args, { allowStdinSource = false } = {}) {
|
|
|
69
127
|
return { kind, path: inputArg, sourceName: inputArg };
|
|
70
128
|
}
|
|
71
129
|
|
|
72
|
-
if ([".k", ".ko", ".kvm", ".klib"].includes(ext)) {
|
|
130
|
+
if ([".k", ".ko", ".kvm", ".klib", ".pkir"].includes(ext)) {
|
|
73
131
|
throw new Error(`Input file not found: ${inputArg}`);
|
|
74
132
|
}
|
|
75
133
|
|
|
76
|
-
return {
|
|
134
|
+
return {
|
|
135
|
+
kind: "inline-source",
|
|
136
|
+
source: inputArg,
|
|
137
|
+
sourceName: "<inline>"
|
|
138
|
+
};
|
|
77
139
|
}
|
|
78
140
|
|
|
79
141
|
export function buildExportPreamble(exports = [], libraries = []) {
|
|
@@ -94,9 +156,15 @@ export function buildExportPreamble(exports = [], libraries = []) {
|
|
|
94
156
|
}
|
|
95
157
|
const lines = [];
|
|
96
158
|
for (const spec of exports) {
|
|
97
|
-
const [libName, localName] = spec.includes(":")
|
|
159
|
+
const [libName, localName] = spec.includes(":")
|
|
160
|
+
? spec.split(":", 2)
|
|
161
|
+
: [spec, spec];
|
|
98
162
|
const hash = aliasMap[libName];
|
|
99
|
-
if (!hash)
|
|
163
|
+
if (!hash) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`--export: '${libName}' not found in loaded libraries`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
100
168
|
const body = hash.startsWith("@") ? hash.slice(1) : hash;
|
|
101
169
|
lines.push(`${localName} = @${body};`);
|
|
102
170
|
}
|
|
@@ -116,7 +184,9 @@ export async function compileProgramInputToObject(
|
|
|
116
184
|
});
|
|
117
185
|
object = decodeObject(objBuffer);
|
|
118
186
|
} else if (input.kind === "stdin-source") {
|
|
119
|
-
if (!stdin)
|
|
187
|
+
if (!stdin) {
|
|
188
|
+
throw new Error("stdin source requested without a stdin stream");
|
|
189
|
+
}
|
|
120
190
|
const source = (await readAll(stdin)).toString("utf8");
|
|
121
191
|
const preamble = buildExportPreamble(exportSpecs, libraries);
|
|
122
192
|
const objBuffer = compileObjectBuffer(preamble + source, {
|
|
@@ -135,7 +205,15 @@ export async function compileProgramInputToObject(
|
|
|
135
205
|
} else if (input.kind === "ko" || input.kind === "klib") {
|
|
136
206
|
object = decodeObject(fs.readFileSync(input.path));
|
|
137
207
|
} else if (input.kind === "kvm") {
|
|
138
|
-
throw new Error(
|
|
208
|
+
throw new Error(
|
|
209
|
+
"Input is already lowered to .kvm bytecode; use " +
|
|
210
|
+
"compileLLVMArtifactFromKVM or compileKVMToExecutable."
|
|
211
|
+
);
|
|
212
|
+
} else if (input.kind === "pkir") {
|
|
213
|
+
throw new Error(
|
|
214
|
+
"Input is already lowered to .pkir IR; use " +
|
|
215
|
+
"compileLLVMArtifactFromPKIR or compilePKIRToExecutable."
|
|
216
|
+
);
|
|
139
217
|
} else {
|
|
140
218
|
throw new Error(`Unsupported input kind: ${input.kind}`);
|
|
141
219
|
}
|
|
@@ -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
|