@fraczak/k 6.3.2 → 6.4.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/DOCS/CODECS.md +258 -0
- package/DOCS/DICTIONARY.md +1172 -0
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
- package/DOCS/KIR_V1.md +221 -0
- package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
- package/DOCS/PROFILING_AND_TRACING.md +196 -0
- package/DOCS/REPL.md +76 -14
- package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
- package/DOCS/dependency-graph.md +144 -0
- package/Examples/arithmetics.k +51 -48
- package/Examples/bnat.k +1 -1
- package/Examples/buda.k +44 -0
- package/Examples/ieee.k +300 -8671
- package/Examples/poly.k +67 -0
- package/README.md +68 -19
- package/augmentation.mjs +9 -7
- package/backend-api.mjs +11 -2
- package/backends/arm64/README.md +104 -0
- package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
- package/backends/arm64/bin/k-arm64-run.mjs +58 -0
- package/backends/arm64/bin/k-arm64.mjs +88 -0
- package/backends/arm64/scripts/run-tests.mjs +41 -0
- package/backends/arm64/src/arm64.mjs +229 -0
- package/backends/arm64/src/cli.mjs +155 -0
- package/backends/arm64/src/kvm2arm64.mjs +906 -0
- package/backends/arm64/src/runtime.c +728 -0
- package/backends/arm64/tests/integration.sh +112 -0
- package/backends/arm64/tests/test-arm64.mjs +240 -0
- package/backends/llvm/README.md +135 -0
- package/backends/llvm/bin/k-llvm-build.mjs +71 -0
- package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
- package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
- package/backends/llvm/bin/k-llvm-run.mjs +90 -0
- package/backends/llvm/runtime/krt.c +1508 -0
- package/backends/llvm/runtime/krt.h +109 -0
- package/backends/llvm/scripts/conformance.mjs +76 -0
- package/backends/llvm/scripts/run-tests.mjs +28 -0
- package/backends/llvm/src/executable.mjs +562 -0
- package/backends/llvm/src/kvm2llvm.mjs +998 -0
- package/backends/llvm/src/llvm.mjs +1092 -0
- package/backends/llvm/tests/composition-driver.c +22 -0
- package/backends/llvm/tests/identity-driver.c +27 -0
- package/backends/llvm/tests/integration.sh +153 -0
- package/backends/llvm/tests/perf-support.mjs +735 -0
- package/backends/llvm/tests/product-driver.c +23 -0
- package/backends/llvm/tests/projection-driver.c +19 -0
- package/backends/llvm/tests/relation-driver.c +29 -0
- package/backends/llvm/tests/test-llvm.mjs +240 -0
- package/backends/llvm/tests/union-driver.c +31 -0
- package/backends/llvm/tests/variant-driver.c +19 -0
- package/backends/llvm/tests/variant-projection-driver.c +21 -0
- package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
- package/backends/wasm/README.md +97 -0
- package/backends/wasm/TECHNICAL-DEBT.md +60 -0
- package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
- package/backends/wasm/bin/k-wasm-run.mjs +140 -0
- package/backends/wasm/bin/k-wasm.mjs +49 -0
- package/backends/wasm/demo_ieee.mjs +319 -0
- package/backends/wasm/runtime.wat +102 -0
- package/backends/wasm/scripts/run-tests.mjs +41 -0
- package/backends/wasm/src/cli.mjs +133 -0
- package/backends/wasm/src/kvm2wasm.mjs +661 -0
- package/backends/wasm/src/wasm.mjs +1010 -0
- package/backends/wasm/tests/integration.sh +182 -0
- package/backends/wasm/tests/perf-support.mjs +336 -0
- package/backends/wasm/tests/test-wasm.mjs +617 -0
- package/browser/repl-browser.mjs +1584 -0
- package/browser/shims/assert.mjs +19 -0
- package/browser/shims/buffer.mjs +224 -0
- package/browser/shims/crypto.mjs +103 -0
- package/browser/shims/fs.mjs +159 -0
- package/browser/shims/os.mjs +17 -0
- package/browser/shims/path.mjs +54 -0
- package/browser/shims/process.mjs +44 -0
- package/browser/shims/readline.mjs +11 -0
- package/browser/shims/url.mjs +12 -0
- package/browser/vfs-data.mjs +19 -0
- package/codecs/README.md +3 -0
- package/codecs/json.mjs +16 -2
- package/codecs/runtime/show-value.mjs +2 -2
- package/conformance/helper-reuse/case.json +8 -0
- package/conformance/helper-reuse/expected.kv +1 -0
- package/conformance/helper-reuse/input.kv +1 -0
- package/conformance/helper-reuse/program.k +2 -0
- package/conformance/identity/case.json +8 -0
- package/conformance/identity/expected.kv +1 -0
- package/conformance/identity/input.kv +1 -0
- package/conformance/identity/program.k +1 -0
- package/conformance/product-projection/case.json +8 -0
- package/conformance/product-projection/expected.kv +1 -0
- package/conformance/product-projection/input.kv +1 -0
- package/conformance/product-projection/program.k +1 -0
- package/conformance/run.mjs +149 -0
- package/conformance/variant-construction/case.json +8 -0
- package/conformance/variant-construction/expected.kv +1 -0
- package/conformance/variant-construction/input.kv +1 -0
- package/conformance/variant-construction/program.k +1 -0
- package/harness/adapters/arm64.mjs +105 -0
- package/harness/adapters/kvm.mjs +144 -0
- package/harness/adapters/llvm.mjs +118 -0
- package/harness/adapters/native.mjs +77 -0
- package/harness/adapters/wasm.mjs +169 -0
- package/harness/backend.mjs +95 -0
- package/harness/cli.mjs +130 -0
- package/harness/format.mjs +95 -0
- package/harness/index.mjs +25 -0
- package/harness/persistent.mjs +121 -0
- package/harness/registry.mjs +44 -0
- package/harness/suite.mjs +257 -0
- package/harness/suites/poly.mjs +156 -0
- package/harness/trace.mjs +50 -0
- package/harness/util.mjs +92 -0
- package/intrinsics.mjs +41 -0
- package/kir.mjs +399 -0
- package/kvm.mjs +585 -81
- package/objects/README.md +37 -3
- package/objects/compile.mjs +15 -22
- package/objects/inspect.mjs +96 -0
- package/objects/validate.mjs +415 -0
- package/package.json +51 -19
- package/repl-codecs.mjs +133 -20
- package/repl.mjs +408 -59
- package/run.mjs +2 -7
- package/scripts/benchmark.mjs +406 -22
- package/scripts/build-repl-html.mjs +1784 -0
- package/scripts/perf-ieee.mjs +586 -0
- package/scripts/perf-int.mjs +531 -0
- package/scripts/perf-poly.mjs +945 -0
- package/scripts/render-benchmark.mjs +12 -8
- package/scripts/run-tests.mjs +6 -0
- package/tests/integration.sh +19 -2
- package/tests/test-arithmetics.mjs +54 -0
- package/tests/test-ieee-arithmetic.mjs +6 -2
- package/tests/test-kir.mjs +85 -0
- package/tests/test-kvm-polymorphic.mjs +278 -0
- package/tests/test-kvm.mjs +25 -6
- package/tests/test-poly.mjs +129 -0
- package/tests/test-repl-html.mjs +303 -0
- package/tests/test-repl.mjs +175 -1
- package/tests/test-validate-object.mjs +40 -0
- package/a.klib +0 -1
- package/a.kvm +0 -142676
- package/a.wasm +0 -0
- package/benchmark-results.html +0 -532
- package/benchmark-results.json +0 -480
- package/k-vscode/.vscode/launch.json +0 -14
- package/k-vscode/README.md +0 -75
- package/k-vscode/extension.js +0 -273
- package/k-vscode/language-configuration.json +0 -42
- package/k-vscode/package.json +0 -79
- package/k-vscode/snippets/k.json +0 -92
- package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
- package/k-vscode/test/background-ranges.test.js +0 -50
- package/k-vscode/themes/k-contrast-color-theme.json +0 -104
- package/scripts/git-hooks/pre-commit +0 -10
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { isProduct, isVariant } from "@fraczak/k/Value.mjs";
|
|
7
|
+
import { exportPatternGraph } from "@fraczak/k/codecs/runtime/codec.mjs";
|
|
8
|
+
import { patternToPropertyList } from "@fraczak/k/codecs/runtime/pattern-json.mjs";
|
|
9
|
+
import { compileObjectToLLVM } from "./llvm.mjs";
|
|
10
|
+
|
|
11
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
12
|
+
|
|
13
|
+
function relationForObject(object, relationName = object.main) {
|
|
14
|
+
if (!relationName) throw new Error("A relation name is required");
|
|
15
|
+
if (object.rels?.[relationName]) return object.rels[relationName];
|
|
16
|
+
const alias = object.relAlias?.[relationName];
|
|
17
|
+
if (alias && object.rels?.[alias]) return object.rels[alias];
|
|
18
|
+
throw new Error(`Relation '${relationName}' not found`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function inputPatternForObjectValue(object, value, relationName = object.main) {
|
|
22
|
+
if (value.pattern) return value.pattern;
|
|
23
|
+
return inputPatternForObjectRelation(object, relationName);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function inputPatternForObjectRelation(object, relationName = object.main) {
|
|
27
|
+
const rel = relationForObject(object, relationName);
|
|
28
|
+
const inputPatternId = rel.typePatternGraph.find(rel.def.patterns[0]);
|
|
29
|
+
return patternToPropertyList(exportPatternGraph(rel.typePatternGraph, inputPatternId));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function cString(text) {
|
|
33
|
+
return JSON.stringify(String(text));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function cByteArray(text) {
|
|
37
|
+
const bytes = [...Buffer.from(String(text), "utf8")];
|
|
38
|
+
return bytes.length === 0 ? "{0}" : `{${bytes.map((byte) => `0x${byte.toString(16).padStart(2, "0")}`).join(", ")}}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const patternKindConstants = {
|
|
42
|
+
"any": "KP_ANY",
|
|
43
|
+
"open-product": "KP_OPEN_PRODUCT",
|
|
44
|
+
"open-union": "KP_OPEN_UNION",
|
|
45
|
+
"closed-product": "KP_CLOSED_PRODUCT",
|
|
46
|
+
"closed-union": "KP_CLOSED_UNION"
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function emitPattern(name, pattern) {
|
|
50
|
+
if (!Array.isArray(pattern)) throw new Error(`${name} pattern must be a property-list array`);
|
|
51
|
+
const lines = [];
|
|
52
|
+
for (let nodeIndex = 0; nodeIndex < pattern.length; nodeIndex++) {
|
|
53
|
+
const node = pattern[nodeIndex];
|
|
54
|
+
if (!Array.isArray(node) || node.length !== 2) {
|
|
55
|
+
throw new Error(`${name} pattern node ${nodeIndex} is invalid`);
|
|
56
|
+
}
|
|
57
|
+
const [, edges] = node;
|
|
58
|
+
if (!Array.isArray(edges)) throw new Error(`${name} pattern node ${nodeIndex} edges are invalid`);
|
|
59
|
+
for (let edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
|
|
60
|
+
const edge = edges[edgeIndex];
|
|
61
|
+
if (!Array.isArray(edge) || edge.length !== 2) {
|
|
62
|
+
throw new Error(`${name} pattern node ${nodeIndex} edge is invalid`);
|
|
63
|
+
}
|
|
64
|
+
const [label] = edge;
|
|
65
|
+
lines.push(`static const unsigned char ${name}_label_${nodeIndex}_${edgeIndex}[] = ${cByteArray(label)};`);
|
|
66
|
+
}
|
|
67
|
+
if (edges.length === 0) continue;
|
|
68
|
+
lines.push(`static k_pattern_edge ${name}_edges_${nodeIndex}[] = {`);
|
|
69
|
+
for (let edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
|
|
70
|
+
const edge = edges[edgeIndex];
|
|
71
|
+
const [label, target] = edge;
|
|
72
|
+
const labelLength = Buffer.byteLength(String(label), "utf8");
|
|
73
|
+
const labelRef = `${name}_label_${nodeIndex}_${edgeIndex}`;
|
|
74
|
+
lines.push(` {(const char *)${labelRef}, ${labelLength}, ${Number(target)}}${edgeIndex === edges.length - 1 ? "" : ","}`);
|
|
75
|
+
}
|
|
76
|
+
lines.push("};");
|
|
77
|
+
}
|
|
78
|
+
lines.push(`static k_pattern_node ${name}_nodes[] = {`);
|
|
79
|
+
pattern.forEach(([kind, edges], index) => {
|
|
80
|
+
const constant = patternKindConstants[kind];
|
|
81
|
+
if (constant == null) throw new Error(`${name} pattern node ${index} has unsupported kind '${kind}'`);
|
|
82
|
+
const edgeRef = edges.length === 0 ? "NULL" : `${name}_edges_${index}`;
|
|
83
|
+
lines.push(` {${constant}, ${edges.length}, ${edgeRef}}${index === pattern.length - 1 ? "" : ","}`);
|
|
84
|
+
});
|
|
85
|
+
lines.push("};");
|
|
86
|
+
lines.push(`static k_pattern ${name} = {${pattern.length}, ${name}_nodes};`);
|
|
87
|
+
return lines.join("\n");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function emitValueBuilder(value, ctx) {
|
|
91
|
+
if (isProduct(value)) {
|
|
92
|
+
const name = `v${ctx.next++}`;
|
|
93
|
+
const fields = Object.entries(value.product);
|
|
94
|
+
ctx.lines.push(` k_value *${name} = k_product(rt, ${fields.length});`);
|
|
95
|
+
for (const [label, child] of fields) {
|
|
96
|
+
const childName = emitValueBuilder(child, ctx);
|
|
97
|
+
ctx.lines.push(` k_product_set(${name}, ${cString(label)}, ${childName});`);
|
|
98
|
+
}
|
|
99
|
+
return name;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (isVariant(value)) {
|
|
103
|
+
const childName = emitValueBuilder(value.value, ctx);
|
|
104
|
+
const name = `v${ctx.next++}`;
|
|
105
|
+
ctx.lines.push(` k_value *${name} = k_variant(rt, ${cString(value.tag)}, ${childName});`);
|
|
106
|
+
return name;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
throw new Error(`Unsupported k value: ${JSON.stringify(value)}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function builderFunction(name, value) {
|
|
113
|
+
const ctx = { next: 0, lines: [] };
|
|
114
|
+
const result = emitValueBuilder(value, ctx);
|
|
115
|
+
return [
|
|
116
|
+
`static k_value *${name}(k_rt *rt) {`,
|
|
117
|
+
...ctx.lines,
|
|
118
|
+
` return ${result};`,
|
|
119
|
+
"}",
|
|
120
|
+
""
|
|
121
|
+
].join("\n");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function driverSource({ input, expected = null }) {
|
|
125
|
+
const expectedBuilder = expected == null ? "" : builderFunction("build_expected", expected);
|
|
126
|
+
const expectedCheck = expected == null
|
|
127
|
+
? [
|
|
128
|
+
" k_print_json(stdout, result.value);",
|
|
129
|
+
" fputc('\\n', stdout);"
|
|
130
|
+
]
|
|
131
|
+
: [
|
|
132
|
+
" k_value *expected = build_expected(rt);",
|
|
133
|
+
" if (!k_equal(result.value, expected)) return 3;"
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
return [
|
|
137
|
+
'#include "krt.h"',
|
|
138
|
+
"#include <stdio.h>",
|
|
139
|
+
"",
|
|
140
|
+
"extern k_result k_main(k_rt *rt, k_value *input);",
|
|
141
|
+
"",
|
|
142
|
+
builderFunction("build_input", input),
|
|
143
|
+
expectedBuilder,
|
|
144
|
+
"int main(void) {",
|
|
145
|
+
" k_rt *rt = k_rt_new();",
|
|
146
|
+
" if (rt == 0) return 1;",
|
|
147
|
+
" k_value *input = build_input(rt);",
|
|
148
|
+
" k_result result = k_main(rt, input);",
|
|
149
|
+
" if (result.status != K_STATUS_OK) return 2;",
|
|
150
|
+
...expectedCheck,
|
|
151
|
+
" k_rt_free(rt);",
|
|
152
|
+
" return 0;",
|
|
153
|
+
"}",
|
|
154
|
+
""
|
|
155
|
+
].join("\n");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function runCommand(command, args, options = {}) {
|
|
159
|
+
const result = spawnSync(command, args, {
|
|
160
|
+
cwd: root,
|
|
161
|
+
encoding: "utf8",
|
|
162
|
+
...options
|
|
163
|
+
});
|
|
164
|
+
if (result.error && result.status !== 0) throw result.error;
|
|
165
|
+
if (result.status !== 0) {
|
|
166
|
+
const detail = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
|
167
|
+
throw new Error(`${command} ${args.join(" ")} failed with status ${result.status}${detail ? `\n${detail}` : ""}`);
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function compileAndRunLLVM(llvm, { input, expected = null, tmpPrefix = "k-llvm-run-" }) {
|
|
173
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), tmpPrefix));
|
|
174
|
+
try {
|
|
175
|
+
const llPath = path.join(tmpDir, "program.ll");
|
|
176
|
+
const driverPath = path.join(tmpDir, "driver.c");
|
|
177
|
+
const exePath = path.join(tmpDir, "program");
|
|
178
|
+
fs.writeFileSync(llPath, llvm);
|
|
179
|
+
fs.writeFileSync(driverPath, driverSource({ input, expected }));
|
|
180
|
+
runCommand("clang", [
|
|
181
|
+
"-O3",
|
|
182
|
+
"-Wno-override-module",
|
|
183
|
+
"-Iruntime",
|
|
184
|
+
"runtime/krt.c",
|
|
185
|
+
driverPath,
|
|
186
|
+
llPath,
|
|
187
|
+
"-o",
|
|
188
|
+
exePath
|
|
189
|
+
]);
|
|
190
|
+
return runCommand(exePath, []);
|
|
191
|
+
} finally {
|
|
192
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function stdioDriverSource({ inputPattern = null, outputPattern = null } = {}) {
|
|
197
|
+
if (inputPattern == null || outputPattern == null) {
|
|
198
|
+
return [
|
|
199
|
+
'#include "krt.h"',
|
|
200
|
+
"",
|
|
201
|
+
"extern k_result k_main(k_rt *rt, k_value *input);",
|
|
202
|
+
"",
|
|
203
|
+
"int main(void) {",
|
|
204
|
+
" k_rt *rt = k_rt_new();",
|
|
205
|
+
" if (rt == 0) return 1;",
|
|
206
|
+
" k_value *input = k_read_wire(stdin, rt);",
|
|
207
|
+
" if (input == 0) return 2;",
|
|
208
|
+
" k_result result = k_main(rt, input);",
|
|
209
|
+
" if (result.status != K_STATUS_OK) return 3;",
|
|
210
|
+
" if (!k_write_wire(stdout, result.value)) return 4;",
|
|
211
|
+
" k_rt_free(rt);",
|
|
212
|
+
" return 0;",
|
|
213
|
+
"}",
|
|
214
|
+
""
|
|
215
|
+
].join("\n");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return [
|
|
219
|
+
'#include "krt.h"',
|
|
220
|
+
"#include <stdint.h>",
|
|
221
|
+
"#include <stdio.h>",
|
|
222
|
+
"#include <stdlib.h>",
|
|
223
|
+
"#include <string.h>",
|
|
224
|
+
"#include <time.h>",
|
|
225
|
+
"",
|
|
226
|
+
emitPattern("compiled_input_pattern", inputPattern),
|
|
227
|
+
"",
|
|
228
|
+
emitPattern("compiled_output_pattern", outputPattern),
|
|
229
|
+
"",
|
|
230
|
+
"extern k_result k_main(k_rt *rt, k_value *input);",
|
|
231
|
+
"",
|
|
232
|
+
"static int read_exact(FILE *in, unsigned char *buffer, size_t length) {",
|
|
233
|
+
" size_t offset = 0;",
|
|
234
|
+
" while (offset < length) {",
|
|
235
|
+
" size_t n = fread(buffer + offset, 1, length - offset, in);",
|
|
236
|
+
" if (n == 0) {",
|
|
237
|
+
" if (ferror(in)) return -1;",
|
|
238
|
+
" return offset == 0 ? 0 : -1;",
|
|
239
|
+
" }",
|
|
240
|
+
" offset += n;",
|
|
241
|
+
" }",
|
|
242
|
+
" return 1;",
|
|
243
|
+
"}",
|
|
244
|
+
"",
|
|
245
|
+
"static uint64_t monotonic_ns(void) {",
|
|
246
|
+
" struct timespec ts;",
|
|
247
|
+
" if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0;",
|
|
248
|
+
" return ((uint64_t)ts.tv_sec * 1000000000ull) + (uint64_t)ts.tv_nsec;",
|
|
249
|
+
"}",
|
|
250
|
+
"",
|
|
251
|
+
"static int is_trace_enabled(void) {",
|
|
252
|
+
" static int cached = -1;",
|
|
253
|
+
" if (cached < 0) {",
|
|
254
|
+
" const char *e1 = getenv(\"K_TRACE\");",
|
|
255
|
+
" const char *e2 = getenv(\"TRACE\");",
|
|
256
|
+
" cached = ((e1 && *e1 && strcmp(e1, \"0\") != 0) || (e2 && *e2 && strcmp(e2, \"0\") != 0)) ? 1 : 0;",
|
|
257
|
+
" }",
|
|
258
|
+
" return cached;",
|
|
259
|
+
"}",
|
|
260
|
+
"",
|
|
261
|
+
"static int write_frame(k_wire_prefix *prefix, k_pattern *pattern, k_value *value) {",
|
|
262
|
+
" size_t length = 0;",
|
|
263
|
+
" unsigned char *payload = k_encode_wire_as_with_prefix(prefix, pattern, value, &length);",
|
|
264
|
+
" if (payload == NULL || length > UINT32_MAX) {",
|
|
265
|
+
" free(payload);",
|
|
266
|
+
" return 0;",
|
|
267
|
+
" }",
|
|
268
|
+
" unsigned char header[4] = {",
|
|
269
|
+
" (unsigned char)((length >> 24) & 0xff),",
|
|
270
|
+
" (unsigned char)((length >> 16) & 0xff),",
|
|
271
|
+
" (unsigned char)((length >> 8) & 0xff),",
|
|
272
|
+
" (unsigned char)(length & 0xff)",
|
|
273
|
+
" };",
|
|
274
|
+
" int ok = fwrite(header, 1, 4, stdout) == 4 && fwrite(payload, 1, length, stdout) == length && fflush(stdout) == 0;",
|
|
275
|
+
" free(payload);",
|
|
276
|
+
" return ok;",
|
|
277
|
+
"}",
|
|
278
|
+
"",
|
|
279
|
+
"static int run_value(k_rt *rt, k_wire_prefix *output_prefix, k_value *input_value) {",
|
|
280
|
+
" k_result result = k_main(rt, input_value);",
|
|
281
|
+
" if (result.status != K_STATUS_OK) return 3;",
|
|
282
|
+
" return write_frame(output_prefix, &compiled_output_pattern, result.value) ? 0 : 4;",
|
|
283
|
+
"}",
|
|
284
|
+
"",
|
|
285
|
+
"static int run_payload(k_rt *rt, k_wire_prefix *input_prefix, k_wire_prefix *output_prefix, const unsigned char *payload, size_t length) {",
|
|
286
|
+
" k_value *fast_input = k_decode_wire_value_with_prefix(payload, length, input_prefix, &compiled_input_pattern, rt);",
|
|
287
|
+
" if (fast_input != 0) return run_value(rt, output_prefix, fast_input);",
|
|
288
|
+
" k_wire_input input = k_decode_wire_envelope(payload, length, rt);",
|
|
289
|
+
" if (input.value == 0 || input.pattern == 0) {",
|
|
290
|
+
" k_wire_input_free(input);",
|
|
291
|
+
" return 2;",
|
|
292
|
+
" }",
|
|
293
|
+
" if (!k_pattern_equal(input.pattern, &compiled_input_pattern)) {",
|
|
294
|
+
" k_wire_input_free(input);",
|
|
295
|
+
" return 5;",
|
|
296
|
+
" }",
|
|
297
|
+
" int status = run_value(rt, output_prefix, input.value);",
|
|
298
|
+
" k_wire_input_free(input);",
|
|
299
|
+
" return status;",
|
|
300
|
+
"}",
|
|
301
|
+
"",
|
|
302
|
+
"static int run_server(void) {",
|
|
303
|
+
" k_rt *rt = k_rt_new();",
|
|
304
|
+
" if (rt == 0) return 1;",
|
|
305
|
+
" k_wire_prefix input_prefix = k_wire_prefix_for_pattern(&compiled_input_pattern);",
|
|
306
|
+
" k_wire_prefix output_prefix = k_wire_prefix_for_pattern(&compiled_output_pattern);",
|
|
307
|
+
" if (!input_prefix.ok || !output_prefix.ok) {",
|
|
308
|
+
" k_wire_prefix_free(input_prefix);",
|
|
309
|
+
" k_wire_prefix_free(output_prefix);",
|
|
310
|
+
" k_rt_free(rt);",
|
|
311
|
+
" return 8;",
|
|
312
|
+
" }",
|
|
313
|
+
" for (;;) {",
|
|
314
|
+
" uint64_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0;",
|
|
315
|
+
" int tracing = is_trace_enabled();",
|
|
316
|
+
" if (tracing) t0 = monotonic_ns();",
|
|
317
|
+
" unsigned char header[4];",
|
|
318
|
+
" int header_status = read_exact(stdin, header, 4);",
|
|
319
|
+
" if (header_status == 0) {",
|
|
320
|
+
" k_wire_prefix_free(input_prefix);",
|
|
321
|
+
" k_wire_prefix_free(output_prefix);",
|
|
322
|
+
" k_rt_free(rt);",
|
|
323
|
+
" return 0;",
|
|
324
|
+
" }",
|
|
325
|
+
" if (header_status < 0) {",
|
|
326
|
+
" k_wire_prefix_free(input_prefix);",
|
|
327
|
+
" k_wire_prefix_free(output_prefix);",
|
|
328
|
+
" k_rt_free(rt);",
|
|
329
|
+
" return 6;",
|
|
330
|
+
" }",
|
|
331
|
+
" uint32_t length = ((uint32_t)header[0] << 24) | ((uint32_t)header[1] << 16) | ((uint32_t)header[2] << 8) | (uint32_t)header[3];",
|
|
332
|
+
" unsigned char *payload = malloc(length == 0 ? 1 : length);",
|
|
333
|
+
" if (payload == NULL) {",
|
|
334
|
+
" k_wire_prefix_free(input_prefix);",
|
|
335
|
+
" k_wire_prefix_free(output_prefix);",
|
|
336
|
+
" k_rt_free(rt);",
|
|
337
|
+
" return 7;",
|
|
338
|
+
" }",
|
|
339
|
+
" int payload_status = read_exact(stdin, payload, length);",
|
|
340
|
+
" if (payload_status != 1) {",
|
|
341
|
+
" free(payload);",
|
|
342
|
+
" k_wire_prefix_free(input_prefix);",
|
|
343
|
+
" k_wire_prefix_free(output_prefix);",
|
|
344
|
+
" k_rt_free(rt);",
|
|
345
|
+
" return 6;",
|
|
346
|
+
" }",
|
|
347
|
+
" if (tracing) t1 = monotonic_ns();",
|
|
348
|
+
" k_value *in_val = k_decode_wire_value_with_prefix(payload, length, &input_prefix, &compiled_input_pattern, rt);",
|
|
349
|
+
" if (in_val == 0) {",
|
|
350
|
+
" k_wire_input envelope = k_decode_wire_envelope(payload, length, rt);",
|
|
351
|
+
" if (envelope.value != 0 && envelope.pattern != 0 && k_pattern_equal(envelope.pattern, &compiled_input_pattern)) {",
|
|
352
|
+
" in_val = envelope.value;",
|
|
353
|
+
" } else {",
|
|
354
|
+
" k_wire_input_free(envelope);",
|
|
355
|
+
" }",
|
|
356
|
+
" }",
|
|
357
|
+
" free(payload);",
|
|
358
|
+
" if (in_val == 0) {",
|
|
359
|
+
" k_rt_reset(rt);",
|
|
360
|
+
" k_wire_prefix_free(input_prefix);",
|
|
361
|
+
" k_wire_prefix_free(output_prefix);",
|
|
362
|
+
" k_rt_free(rt);",
|
|
363
|
+
" return 2;",
|
|
364
|
+
" }",
|
|
365
|
+
" if (tracing) t2 = monotonic_ns();",
|
|
366
|
+
" k_result result = k_main(rt, in_val);",
|
|
367
|
+
" if (tracing) t3 = monotonic_ns();",
|
|
368
|
+
" if (result.status != K_STATUS_OK) {",
|
|
369
|
+
" k_rt_reset(rt);",
|
|
370
|
+
" k_wire_prefix_free(input_prefix);",
|
|
371
|
+
" k_wire_prefix_free(output_prefix);",
|
|
372
|
+
" k_rt_free(rt);",
|
|
373
|
+
" return 3;",
|
|
374
|
+
" }",
|
|
375
|
+
" size_t out_len = 0;",
|
|
376
|
+
" unsigned char *out_payload = k_encode_wire_as_with_prefix(&output_prefix, &compiled_output_pattern, result.value, &out_len);",
|
|
377
|
+
" if (tracing) t4 = monotonic_ns();",
|
|
378
|
+
" int ok = 0;",
|
|
379
|
+
" uint64_t write_start = t4;",
|
|
380
|
+
" if (out_payload != NULL && out_len <= UINT32_MAX) {",
|
|
381
|
+
" unsigned char out_hdr[4] = {",
|
|
382
|
+
" (unsigned char)((out_len >> 24) & 0xff),",
|
|
383
|
+
" (unsigned char)((out_len >> 16) & 0xff),",
|
|
384
|
+
" (unsigned char)((out_len >> 8) & 0xff),",
|
|
385
|
+
" (unsigned char)(out_len & 0xff)",
|
|
386
|
+
" };",
|
|
387
|
+
" ok = (fwrite(out_hdr, 1, 4, stdout) == 4 && fwrite(out_payload, 1, out_len, stdout) == out_len && fflush(stdout) == 0);",
|
|
388
|
+
" }",
|
|
389
|
+
" free(out_payload);",
|
|
390
|
+
" if (tracing) {",
|
|
391
|
+
" t5 = monotonic_ns();",
|
|
392
|
+
" fprintf(stderr, \"K_TRACE_PHASES backend=llvm ipc_read_ns=%llu decode_ns=%llu flat_in_ns=0 eval_ns=%llu flat_out_ns=0 encode_ns=%llu ipc_write_ns=%llu total_ns=%llu\\n\",",
|
|
393
|
+
" (unsigned long long)(t1 >= t0 ? t1 - t0 : 0),",
|
|
394
|
+
" (unsigned long long)(t2 >= t1 ? t2 - t1 : 0),",
|
|
395
|
+
" (unsigned long long)(t3 >= t2 ? t3 - t2 : 0),",
|
|
396
|
+
" (unsigned long long)(t4 >= t3 ? t4 - t3 : 0),",
|
|
397
|
+
" (unsigned long long)(t5 >= write_start ? t5 - write_start : 0),",
|
|
398
|
+
" (unsigned long long)(t5 >= t0 ? t5 - t0 : 0));",
|
|
399
|
+
" fflush(stderr);",
|
|
400
|
+
" }",
|
|
401
|
+
" k_rt_reset(rt);",
|
|
402
|
+
" if (!ok) {",
|
|
403
|
+
" k_wire_prefix_free(input_prefix);",
|
|
404
|
+
" k_wire_prefix_free(output_prefix);",
|
|
405
|
+
" k_rt_free(rt);",
|
|
406
|
+
" return 4;",
|
|
407
|
+
" }",
|
|
408
|
+
" }",
|
|
409
|
+
"}",
|
|
410
|
+
"",
|
|
411
|
+
"static int parse_size_arg(const char *text, size_t *out) {",
|
|
412
|
+
" if (text == NULL || *text == 0) return 0;",
|
|
413
|
+
" size_t value = 0;",
|
|
414
|
+
" for (const char *p = text; *p != 0; p++) {",
|
|
415
|
+
" if (*p < '0' || *p > '9') return 0;",
|
|
416
|
+
" size_t digit = (size_t)(*p - '0');",
|
|
417
|
+
" if (value > (((size_t)-1) - digit) / 10) return 0;",
|
|
418
|
+
" value = value * 10 + digit;",
|
|
419
|
+
" }",
|
|
420
|
+
" if (value == 0) return 0;",
|
|
421
|
+
" *out = value;",
|
|
422
|
+
" return 1;",
|
|
423
|
+
"}",
|
|
424
|
+
"",
|
|
425
|
+
"static int run_bench_main(const char *count_text) {",
|
|
426
|
+
" size_t count = 0;",
|
|
427
|
+
" if (!parse_size_arg(count_text, &count)) return 9;",
|
|
428
|
+
" k_rt *input_rt = k_rt_new();",
|
|
429
|
+
" k_rt *run_rt = k_rt_new();",
|
|
430
|
+
" if (input_rt == 0 || run_rt == 0) return 1;",
|
|
431
|
+
" k_wire_input input = k_read_wire_envelope(stdin, input_rt);",
|
|
432
|
+
" if (input.value == 0 || input.pattern == 0) {",
|
|
433
|
+
" k_wire_input_free(input);",
|
|
434
|
+
" k_rt_free(run_rt);",
|
|
435
|
+
" k_rt_free(input_rt);",
|
|
436
|
+
" return 2;",
|
|
437
|
+
" }",
|
|
438
|
+
" if (!k_pattern_equal(input.pattern, &compiled_input_pattern)) {",
|
|
439
|
+
" k_wire_input_free(input);",
|
|
440
|
+
" k_rt_free(run_rt);",
|
|
441
|
+
" k_rt_free(input_rt);",
|
|
442
|
+
" return 5;",
|
|
443
|
+
" }",
|
|
444
|
+
" uint64_t started_at = monotonic_ns();",
|
|
445
|
+
" for (size_t i = 0; i < count; i++) {",
|
|
446
|
+
" k_result result = k_main(run_rt, input.value);",
|
|
447
|
+
" if (result.status != K_STATUS_OK) {",
|
|
448
|
+
" k_wire_input_free(input);",
|
|
449
|
+
" k_rt_free(run_rt);",
|
|
450
|
+
" k_rt_free(input_rt);",
|
|
451
|
+
" return 3;",
|
|
452
|
+
" }",
|
|
453
|
+
" k_rt_reset(run_rt);",
|
|
454
|
+
" }",
|
|
455
|
+
" uint64_t ended_at = monotonic_ns();",
|
|
456
|
+
" uint64_t elapsed = ended_at >= started_at ? ended_at - started_at : 0;",
|
|
457
|
+
" fprintf(stderr, \"K_LLVM_BENCH_MAIN calls=%zu total_ns=%llu per_call_ns=%.2f\\n\", count, (unsigned long long)elapsed, count == 0 ? 0.0 : (double)elapsed / (double)count);",
|
|
458
|
+
" k_wire_input_free(input);",
|
|
459
|
+
" k_rt_free(run_rt);",
|
|
460
|
+
" k_rt_free(input_rt);",
|
|
461
|
+
" return 0;",
|
|
462
|
+
"}",
|
|
463
|
+
"",
|
|
464
|
+
"int main(int argc, char **argv) {",
|
|
465
|
+
" if (argc == 2 && strcmp(argv[1], \"--server\") == 0) return run_server();",
|
|
466
|
+
" if (argc == 3 && strcmp(argv[1], \"--bench-main\") == 0) return run_bench_main(argv[2]);",
|
|
467
|
+
" uint64_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;",
|
|
468
|
+
" int tracing = is_trace_enabled();",
|
|
469
|
+
" if (tracing) t0 = monotonic_ns();",
|
|
470
|
+
" k_rt *rt = k_rt_new();",
|
|
471
|
+
" if (rt == 0) return 1;",
|
|
472
|
+
" k_wire_prefix output_prefix = k_wire_prefix_for_pattern(&compiled_output_pattern);",
|
|
473
|
+
" k_wire_input input = k_read_wire_envelope(stdin, rt);",
|
|
474
|
+
" if (input.value == 0 || input.pattern == 0) {",
|
|
475
|
+
" k_wire_prefix_free(output_prefix);",
|
|
476
|
+
" k_rt_free(rt);",
|
|
477
|
+
" return 2;",
|
|
478
|
+
" }",
|
|
479
|
+
" if (!k_pattern_equal(input.pattern, &compiled_input_pattern)) {",
|
|
480
|
+
" k_wire_input_free(input);",
|
|
481
|
+
" k_wire_prefix_free(output_prefix);",
|
|
482
|
+
" k_rt_free(rt);",
|
|
483
|
+
" return 5;",
|
|
484
|
+
" }",
|
|
485
|
+
" if (tracing) t1 = monotonic_ns();",
|
|
486
|
+
" k_result result = k_main(rt, input.value);",
|
|
487
|
+
" if (tracing) t2 = monotonic_ns();",
|
|
488
|
+
" if (result.status != K_STATUS_OK) {",
|
|
489
|
+
" k_wire_input_free(input);",
|
|
490
|
+
" k_wire_prefix_free(output_prefix);",
|
|
491
|
+
" k_rt_free(rt);",
|
|
492
|
+
" return 3;",
|
|
493
|
+
" }",
|
|
494
|
+
" size_t output_length = 0;",
|
|
495
|
+
" unsigned char *output_payload = k_encode_wire_as_with_prefix(&output_prefix, &compiled_output_pattern, result.value, &output_length);",
|
|
496
|
+
" if (tracing) t3 = monotonic_ns();",
|
|
497
|
+
" int ok = output_payload != NULL && fwrite(output_payload, 1, output_length, stdout) == output_length && fflush(stdout) == 0;",
|
|
498
|
+
" if (tracing) {",
|
|
499
|
+
" t4 = monotonic_ns();",
|
|
500
|
+
" fprintf(stderr, \"K_TRACE_PHASES backend=llvm ipc_read_ns=%llu decode_ns=0 flat_in_ns=0 eval_ns=%llu flat_out_ns=0 encode_ns=%llu ipc_write_ns=0 total_ns=%llu\\n\",",
|
|
501
|
+
" (unsigned long long)(t1 >= t0 ? t1 - t0 : 0),",
|
|
502
|
+
" (unsigned long long)(t2 >= t1 ? t2 - t1 : 0),",
|
|
503
|
+
" (unsigned long long)(t3 >= t2 ? t3 - t2 : 0),",
|
|
504
|
+
" (unsigned long long)(t4 >= t3 ? t4 - t3 : 0),",
|
|
505
|
+
" (unsigned long long)(t4 >= t0 ? t4 - t0 : 0));",
|
|
506
|
+
" fflush(stderr);",
|
|
507
|
+
" }",
|
|
508
|
+
" free(output_payload);",
|
|
509
|
+
" k_wire_input_free(input);",
|
|
510
|
+
" k_wire_prefix_free(output_prefix);",
|
|
511
|
+
" if (!ok) return 4;",
|
|
512
|
+
" k_rt_free(rt);",
|
|
513
|
+
" return 0;",
|
|
514
|
+
"}",
|
|
515
|
+
""
|
|
516
|
+
].join("\n");
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export function compileLLVMToExecutable(llvm, outputPath, { driver = stdioDriverSource(), tmpPrefix = "k-llvm-build-", clangOpt = "-O3" } = {}) {
|
|
520
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), tmpPrefix));
|
|
521
|
+
try {
|
|
522
|
+
const llPath = path.join(tmpDir, "program.ll");
|
|
523
|
+
const driverPath = path.join(tmpDir, "driver.c");
|
|
524
|
+
fs.writeFileSync(llPath, llvm);
|
|
525
|
+
fs.writeFileSync(driverPath, driver);
|
|
526
|
+
runCommand("clang", [
|
|
527
|
+
...(Array.isArray(clangOpt) ? clangOpt : String(clangOpt).split(/\s+/).filter(Boolean)),
|
|
528
|
+
"-Wno-override-module",
|
|
529
|
+
"-Iruntime",
|
|
530
|
+
"runtime/krt.c",
|
|
531
|
+
driverPath,
|
|
532
|
+
llPath,
|
|
533
|
+
"-o",
|
|
534
|
+
outputPath
|
|
535
|
+
]);
|
|
536
|
+
} finally {
|
|
537
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export function compileObjectToExecutable(object, outputPath, { relation = object.main, inputPattern = null, runtimeMode = "fast", clangOpt = "-O3" } = {}) {
|
|
542
|
+
const { inputPattern: compiledInputPattern, outputPattern, llvm } = compileObjectToLLVM(object, {
|
|
543
|
+
relation,
|
|
544
|
+
inputPattern: inputPattern || inputPatternForObjectRelation(object, relation),
|
|
545
|
+
runtimeMode
|
|
546
|
+
});
|
|
547
|
+
compileLLVMToExecutable(llvm, outputPath, {
|
|
548
|
+
driver: stdioDriverSource({
|
|
549
|
+
inputPattern: compiledInputPattern,
|
|
550
|
+
outputPattern
|
|
551
|
+
}),
|
|
552
|
+
clangOpt
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export function compileObjectAndRun(object, { relation = object.main, input, expected = null, inputPattern = null }) {
|
|
557
|
+
const { llvm } = compileObjectToLLVM(object, {
|
|
558
|
+
relation,
|
|
559
|
+
inputPattern: inputPattern || inputPatternForObjectValue(object, input, relation)
|
|
560
|
+
});
|
|
561
|
+
return compileAndRunLLVM(llvm, { input, expected });
|
|
562
|
+
}
|