@fraczak/k 6.10.3 → 6.10.4

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.
@@ -6,7 +6,9 @@ import { fileURLToPath } from "node:url";
6
6
  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
+ import { specializeKVM } from "@fraczak/k/kvm.mjs";
9
10
  import { compileObjectToLLVM } from "./llvm.mjs";
11
+ import { compileKVMModuleToLLVM } from "./kvm2llvm.mjs";
10
12
 
11
13
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
12
14
 
@@ -553,6 +555,40 @@ export function compileObjectToExecutable(object, outputPath, { relation = objec
553
555
  });
554
556
  }
555
557
 
558
+ export function compileKVMToExecutable(kvmInput, outputPath, {
559
+ entry = null,
560
+ inputPattern = null,
561
+ runtimeMode = "fast",
562
+ clangOpt = "-O3"
563
+ } = {}) {
564
+ let kvm = kvmInput;
565
+ if (kvm?.format === "k-vm") {
566
+ if (kvm.layer === "KVM-P" && inputPattern) {
567
+ kvm = specializeKVM(kvm, inputPattern);
568
+ }
569
+ }
570
+ const functions = kvm.functions || (typeof kvm === "object" && !Array.isArray(kvm) ? kvm : null);
571
+ if (!functions) throw new Error("Expected .kvm input to contain a functions object");
572
+ const entryFunc = entry || kvm.entry || kvm.relation || "__main__";
573
+ const mainFunc = functions[entryFunc];
574
+ if (!mainFunc) throw new Error(`No kVM entry function '${entryFunc}' found`);
575
+ const compiledInputPattern = inputPattern || mainFunc?.inputPattern || kvm.inputPattern;
576
+ const outputPattern = mainFunc?.outputPattern || kvm.outputPattern;
577
+ const llvm = compileKVMModuleToLLVM(entryFunc, functions, {
578
+ relation: entryFunc,
579
+ inputPattern: compiledInputPattern,
580
+ outputPattern,
581
+ runtimeMode
582
+ });
583
+ compileLLVMToExecutable(llvm, outputPath, {
584
+ driver: stdioDriverSource({
585
+ inputPattern: compiledInputPattern,
586
+ outputPattern
587
+ }),
588
+ clangOpt
589
+ });
590
+ }
591
+
556
592
  export function compileObjectAndRun(object, { relation = object.main, input, expected = null, inputPattern = null }) {
557
593
  const { llvm } = compileObjectToLLVM(object, {
558
594
  relation,
@@ -49,6 +49,7 @@ function cStringBytes(text) {
49
49
  export function runtimeDeclarations() {
50
50
  return [
51
51
  "%k_rt_mark = type { ptr, i64 }",
52
+ "%k_rt_tail_mark = type { %k_rt_mark, %k_rt_mark }",
52
53
  "%k_result = type { i32, ptr }",
53
54
  "",
54
55
  "declare %k_rt_mark @k_rt_mark(ptr)",
@@ -316,7 +317,7 @@ function lowerRtCompact(ctx, val, tailMarkSlot = "%tail_mark_slot") {
316
317
  const hasBlock = ctx.tempName("has_block");
317
318
  const markBlockPtr = ctx.tempName("mark_block_ptr");
318
319
  ctx.lines.push(` ${hasBlock} = icmp ne ptr ${curBlock}, null`);
319
- ctx.lines.push(` ${markBlockPtr} = getelementptr inbounds %k_rt_mark, ptr ${tailMarkSlot}, i32 0, i32 0`);
320
+ ctx.lines.push(` ${markBlockPtr} = getelementptr inbounds %k_rt_tail_mark, ptr ${tailMarkSlot}, i32 0, i32 1, i32 0`);
320
321
  const markBlock = ctx.tempName("mark_block");
321
322
  ctx.lines.push(` ${markBlock} = load ptr, ptr ${markBlockPtr}`);
322
323
 
@@ -340,7 +341,7 @@ function lowerRtCompact(ctx, val, tailMarkSlot = "%tail_mark_slot") {
340
341
  ctx.lines.push(`${loadGrowthBlock}:`);
341
342
  const curUsed = loadI64At(ctx, curBlock, K_ARENA_BLOCK_USED_OFFSET, "cur_used");
342
343
  const markUsedPtr = ctx.tempName("mark_used_ptr");
343
- ctx.lines.push(` ${markUsedPtr} = getelementptr inbounds %k_rt_mark, ptr ${tailMarkSlot}, i32 0, i32 1`);
344
+ ctx.lines.push(` ${markUsedPtr} = getelementptr inbounds %k_rt_tail_mark, ptr ${tailMarkSlot}, i32 0, i32 1, i32 1`);
344
345
  const markUsed = ctx.tempName("mark_used");
345
346
  ctx.lines.push(` ${markUsed} = load i64, ptr ${markUsedPtr}`);
346
347
  const growth = ctx.tempName("arena_growth");
@@ -605,11 +606,16 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
605
606
 
606
607
  if (isCatchTail) {
607
608
  ctx.allocas.push(" %tail_input_slot = alloca ptr");
608
- ctx.allocas.push(" %tail_mark_slot = alloca %k_rt_mark");
609
+ ctx.allocas.push(" %tail_mark_slot = alloca %k_rt_tail_mark");
609
610
  ctx.lines.push(" store ptr %input, ptr %tail_input_slot");
610
611
  const initMark = ctx.tempName("init_mark");
611
612
  ctx.lines.push(` ${initMark} = call %k_rt_mark @k_rt_mark(ptr %rt)`);
612
- ctx.lines.push(` store %k_rt_mark ${initMark}, ptr %tail_mark_slot`);
613
+ const baseMarkPtr = ctx.tempName("base_mark_ptr");
614
+ const lastMarkPtr = ctx.tempName("last_mark_ptr");
615
+ ctx.lines.push(` ${baseMarkPtr} = getelementptr inbounds %k_rt_tail_mark, ptr %tail_mark_slot, i32 0, i32 0`);
616
+ ctx.lines.push(` store %k_rt_mark ${initMark}, ptr ${baseMarkPtr}`);
617
+ ctx.lines.push(` ${lastMarkPtr} = getelementptr inbounds %k_rt_tail_mark, ptr %tail_mark_slot, i32 0, i32 1`);
618
+ ctx.lines.push(` store %k_rt_mark ${initMark}, ptr ${lastMarkPtr}`);
613
619
  ctx.lines.push(" br label %tail_loop");
614
620
  ctx.lines.push("tail_loop:");
615
621
  ctx.lines.push(" %tail_input = load ptr, ptr %tail_input_slot");
@@ -95,6 +95,17 @@ printf '{"x":"left","y":"right"}' \
95
95
 
96
96
  printf '{"x":"left"}' | node ../../codecs/k-parse.mjs | "$TMP_DIR/run-exe" && exit 1 || test "$?" -eq 5
97
97
 
98
+ node ../../objects/compile.mjs '?{<{}=X0 left, ...> x, <X0 right, ...> y} .x' "$TMP_DIR/run-proj.kvm"
99
+ node ./bin/k-llvm-compile.mjs "$TMP_DIR/run-proj.kvm" "$TMP_DIR/run-proj-kvm.ll"
100
+ grep -q '@k_llvm_metadata' "$TMP_DIR/run-proj-kvm.ll"
101
+ grep -q 'define %k_result @k_main' "$TMP_DIR/run-proj-kvm.ll"
102
+ node ./bin/k-llvm-build.mjs "$TMP_DIR/run-proj.kvm" -o "$TMP_DIR/run-kvm-exe"
103
+ printf '{"x":"left","y":"right"}' \
104
+ | node ../../codecs/k-parse.mjs \
105
+ | "$TMP_DIR/run-kvm-exe" \
106
+ | node ../../codecs/k-print.mjs \
107
+ | grep -qx '"left"'
108
+
98
109
  node ./bin/k-llvm-build.mjs '?<{} left, {} right, ...>' -o "$TMP_DIR/id-exe"
99
110
  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));" \
100
111
  | "$TMP_DIR/id-exe" \
@@ -1,6 +1,7 @@
1
1
  import assert from "node:assert";
2
2
  import { compileObjectBuffer, decodeObject } from "@fraczak/k/object.mjs";
3
- import { compileObjectToLLVM, emitLLVMModule, llvmIdentifier } from "../src/llvm.mjs";
3
+ import { compileObjectToLLVM, compileLLVMArtifactFromKVM, emitLLVMModule, llvmIdentifier } from "../src/llvm.mjs";
4
+ import { objectToKVMArtifact } from "@fraczak/k/kvm.mjs";
4
5
 
5
6
  function kirP(body, { patternGraph = null } = {}) {
6
7
  return {
@@ -256,4 +257,17 @@ const { llvm: productRecurseLLVM } = compileObjectToLLVM(productRecurseObject, {
256
257
  // Calls inside product fields must not return tail status (i32 2)
257
258
  assert.doesNotMatch(productRecurseLLVM, /insertvalue %k_result undef, i32 2, 0/);
258
259
 
260
+ const kvmArtifact = objectToKVMArtifact(productObject, "__main__");
261
+ assert.equal(kvmArtifact.format, "k-vm");
262
+ const kvmLLVM = compileLLVMArtifactFromKVM(kvmArtifact, {
263
+ inputPattern: [
264
+ ["closed-product", [["x", 1], ["y", 2]]],
265
+ ["closed-product", [["valA", 1]]],
266
+ ["closed-product", [["valB", 2]]]
267
+ ]
268
+ });
269
+ assert.match(kvmLLVM, /source_filename = "k-llvm:__main__"/);
270
+ assert.match(kvmLLVM, /define %k_result @k_main/);
271
+ assert.match(kvmLLVM, /store ptr %product_fields\d+, ptr %ptr_slot\d+/);
272
+
259
273
  console.log("OK");
@@ -6,6 +6,22 @@ import { fileURLToPath } from "node:url";
6
6
 
7
7
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
8
8
  const node = process.execPath;
9
+
10
+ function printHelp() {
11
+ console.log(`Usage: node backends/wasm/scripts/run-tests.mjs [options]
12
+
13
+ Runs WebAssembly backend test suite and integration tests.
14
+
15
+ Options:
16
+ -h, --help
17
+ Show this help message and exit.`);
18
+ }
19
+
20
+ if (process.argv.includes("-h") || process.argv.includes("--help")) {
21
+ printHelp();
22
+ process.exit(0);
23
+ }
24
+
9
25
  const tests = [
10
26
  ["tests/test-wasm.mjs", node, ["tests/test-wasm.mjs"]],
11
27
  ["tests/integration.sh", path.join(root, "tests/integration.sh"), []]