@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.
Files changed (54) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/DOCS/FILE_FORMATS.md +238 -15
  3. package/DOCS/POLYMORPHIC_IR.md +104 -0
  4. package/JOURNAL.md +288 -0
  5. package/README.md +10 -2
  6. package/access-table.mjs +343 -0
  7. package/backend-api.mjs +18 -0
  8. package/backends/llvm/README.md +20 -21
  9. package/backends/llvm/bin/k-llvm-build.mjs +105 -32
  10. package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
  11. package/backends/llvm/bin/k-llvm.mjs +292 -0
  12. package/backends/llvm/runtime/krt.c +8 -0
  13. package/backends/llvm/runtime/krt.h +1 -0
  14. package/backends/llvm/src/cli.mjs +95 -17
  15. package/backends/llvm/src/executable.mjs +128 -11
  16. package/backends/llvm/src/kvm2llvm.mjs +10 -5
  17. package/backends/llvm/src/llvm.mjs +121 -9
  18. package/backends/llvm/tests/integration.sh +11 -11
  19. package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
  20. package/backends/llvm/tests/perf-support.mjs +24 -3
  21. package/backends/llvm/tests/test-llvm.mjs +22 -1
  22. package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
  23. package/backends/wasm/bin/k-wasm-run.mjs +61 -20
  24. package/backends/wasm/bin/k-wasm.mjs +47 -13
  25. package/backends/wasm/src/cli.mjs +141 -19
  26. package/backends/wasm/src/wasm.mjs +130 -23
  27. package/browser/repl-browser.mjs +16 -5
  28. package/codecs/k-parse.mjs +29 -8
  29. package/codecs/k-print.mjs +22 -6
  30. package/codecs/runtime/codec-sdk.mjs +8 -4
  31. package/codecs/show.mjs +20 -6
  32. package/k.mjs +56 -16
  33. package/kir.mjs +58 -19
  34. package/kvm.mjs +49 -12
  35. package/objects/compile.mjs +37 -23
  36. package/objects/decompile.mjs +40 -10
  37. package/objects/extract-aliases.mjs +44 -14
  38. package/objects/inspect.mjs +19 -14
  39. package/objects/validate.mjs +18 -11
  40. package/package.json +10 -3
  41. package/pkir.mjs +772 -0
  42. package/repl.mjs +36 -18
  43. package/scripts/build-repl-html.mjs +14 -2
  44. package/scripts/perf-ieee.mjs +264 -13
  45. package/scripts/perf-int.mjs +315 -22
  46. package/scripts/perf-multiplication.mjs +58 -7
  47. package/scripts/perf-poly.mjs +306 -24
  48. package/scripts/run-tests.mjs +3 -0
  49. package/tests/test-access-table.mjs +213 -0
  50. package/tests/test-pkir.mjs +530 -0
  51. package/tests/test-polymorphic-tdd.mjs +196 -0
  52. package/tests/test-repl-html.mjs +15 -2
  53. package/tests/test-repl.mjs +30 -1
  54. package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
@@ -62,7 +62,7 @@ function printHelp() {
62
62
 
63
63
  Polymorphic List Operations Benchmark Harness.
64
64
  Benchmarks reverse, concat, split_by, get_nth, and length on
65
- Examples/poly.k across Native JS, kVM interpreter, LLVM, and Wasm.
65
+ Examples/poly.k across Native JS, kVM interpreter, LLVM, Wasm, and PKIR.
66
66
 
67
67
  Options:
68
68
  --trace
@@ -71,16 +71,20 @@ Options:
71
71
  Enable per-function call count profiling.
72
72
  --wasm-in-process
73
73
  Run WebAssembly in-process instead of persistent subprocess runner.
74
+ --pkir-only
75
+ Run only PKIR backend.
74
76
  -h, --help
75
77
  Show this help message and exit.
76
78
 
77
79
  Environment Variables:
78
80
  BACKENDS
79
- Target backend to run: 'llvm' or 'wasm'.
81
+ Target backend to run: 'llvm', 'wasm', or 'pkir'.
80
82
  LLVM_ONLY
81
83
  Run only LLVM backend ('1' to enable).
82
84
  WASM_ONLY
83
85
  Run only WebAssembly backend ('1' to enable).
86
+ PKIR_ONLY
87
+ Run only PKIR backend ('1' to enable).
84
88
  BACKENDS_ONLY
85
89
  Skip JS and kVM interpreter baselines ('1' to enable).
86
90
  LIST_LENGTH
@@ -116,11 +120,52 @@ if (process.argv.includes("-h") || process.argv.includes("--help")) {
116
120
 
117
121
  // Backend selection
118
122
  const backendsEnv = process.env.BACKENDS?.toLowerCase();
119
- const llvmOnly = process.env.LLVM_ONLY === "1" || backendsEnv === "llvm";
120
- const wasmOnly = process.env.WASM_ONLY === "1" || backendsEnv === "wasm";
121
- const runLLVM = !wasmOnly;
122
- const runWasm = !llvmOnly;
123
- const runBaselines = !process.env.BACKENDS_ONLY && (process.env.LLVM_ONLY !== "1") && (process.env.WASM_ONLY !== "1");
123
+ const backendsList = backendsEnv
124
+ ? backendsEnv.split(",").map(s => s.trim())
125
+ : null;
126
+ const llvmPkirOnly = process.env.LLVM_PKIR_ONLY === "1"
127
+ || (backendsList && backendsList.length === 1 &&
128
+ backendsList[0] === "llvm-pkir")
129
+ || process.argv.includes("--llvm-pkir-only");
130
+ const pkirOnly = !llvmPkirOnly && (
131
+ process.env.PKIR_ONLY === "1"
132
+ || (backendsList && backendsList.length === 1 &&
133
+ backendsList[0] === "pkir")
134
+ || process.argv.includes("--pkir-only")
135
+ );
136
+ const llvmOnly = !pkirOnly && !llvmPkirOnly && (
137
+ process.env.LLVM_ONLY === "1"
138
+ || (backendsList && backendsList.length === 1 &&
139
+ backendsList[0] === "llvm")
140
+ );
141
+ const wasmOnly = !pkirOnly && !llvmPkirOnly && !llvmOnly && (
142
+ process.env.WASM_ONLY === "1"
143
+ || (backendsList && backendsList.length === 1 &&
144
+ backendsList[0] === "wasm")
145
+ );
146
+ const runLLVM = backendsList
147
+ ? backendsList.includes("llvm")
148
+ : !wasmOnly && !pkirOnly && !llvmPkirOnly;
149
+ const runLLVMPKIR = backendsList
150
+ ? backendsList.includes("llvm-pkir")
151
+ : !wasmOnly && !pkirOnly && !llvmOnly;
152
+ const runWasm = backendsList
153
+ ? backendsList.includes("wasm")
154
+ : !llvmOnly && !pkirOnly && !llvmPkirOnly;
155
+ const runPKIR = backendsList
156
+ ? backendsList.includes("pkir")
157
+ : !llvmOnly && !wasmOnly && !llvmPkirOnly;
158
+ const runBaselines = !process.env.BACKENDS_ONLY
159
+ && (backendsList == null || backendsList.includes("kvm") ||
160
+ backendsList.includes("js"))
161
+ && !llvmOnly && !wasmOnly && !pkirOnly && !llvmPkirOnly;
162
+
163
+ function llvmLaneNameStr() {
164
+ return llvmLaneName();
165
+ }
166
+ function llvmPkirLaneNameStr() {
167
+ return llvmLaneName().replace("LLVM", "LLVM-PKIR");
168
+ }
124
169
 
125
170
  const ops = ["reverse", "concat", "split_by", "get_nth", "length"];
126
171
  const benchNames = Object.fromEntries(ops.map(op => [op, `bench_${op}`]));
@@ -143,6 +188,9 @@ function wasmLaneName() {
143
188
  const mode = wasmPipe ? "persistent" : "in-process";
144
189
  return `WebAssembly (${mode})`;
145
190
  }
191
+ function pkirLaneName() {
192
+ return "PKIR (Wasm persistent)";
193
+ }
146
194
 
147
195
 
148
196
  console.log("==> Loading @fraczak/k/Examples/arithmetics.k as library");
@@ -294,13 +342,37 @@ if (runLLVM) {
294
342
  relHash: relation.relHash,
295
343
  inputPattern: tc.inputPattern,
296
344
  cacheDir,
297
- sourceLabel: `@fraczak/k/Examples/poly.k#${relation.relationName}`
345
+ sourceLabel:
346
+ `@fraczak/k/Examples/poly.k#${relation.relationName}`,
347
+ usePKIR: false
298
348
  });
299
349
  }
300
350
  codes.load(state.codes);
301
351
  printCompileFailures(testSuite);
302
352
  }
303
353
 
354
+ // Setup LLVM-PKIR
355
+ if (runLLVMPKIR) {
356
+ console.log("==> Compiling LLVM-PKIR executables");
357
+ for (const tc of testSuite) {
358
+ const relation = relations[tc.op];
359
+ tc.llvmPKIR = tryCompileCase({
360
+ object: relation.object,
361
+ relationName: relation.relationName,
362
+ relHash: relation.relHash,
363
+ inputPattern: tc.inputPattern,
364
+ cacheDir,
365
+ sourceLabel:
366
+ `@fraczak/k/Examples/poly.k#${relation.relationName}`,
367
+ usePKIR: true
368
+ });
369
+ }
370
+ codes.load(state.codes);
371
+ printCompileFailures(
372
+ testSuite.map(tc => ({ ...tc, llvm: tc.llvmPKIR }))
373
+ );
374
+ }
375
+
304
376
  // Setup Wasm
305
377
  let wasmExports = null;
306
378
  let wasmProfileFunctions = [];
@@ -343,6 +415,34 @@ if (runWasm) {
343
415
  }
344
416
  }
345
417
 
418
+ // Setup PKIR (persistent runner)
419
+ const pkirExes = new Map();
420
+ if (runPKIR) {
421
+ console.log("==> Compiling PKIR executables (persistent runner)...");
422
+ for (const tc of testSuite) {
423
+ const relation = relations[tc.op];
424
+ try {
425
+ const wasmPath = path.join(cacheDir, `perf_poly_pkir_${tc.op}.wasm`);
426
+ const exePath = path.join(cacheDir, `perf_poly_pkir_${tc.op}.exe`);
427
+ const wasmBuf = await compileWasmArtifactFromObject(relation.object, {
428
+ entry: relation.relHash,
429
+ usePKIR: true
430
+ });
431
+ fs.writeFileSync(wasmPath, wasmBuf);
432
+ const runBin = fileURLToPath(import.meta.resolve("../backends/wasm/bin/k-wasm-run.mjs"));
433
+ fs.writeFileSync(exePath, `#!/bin/sh\nexec node "${runBin}" "${wasmPath}" "$@"\n`, { mode: 0o755 });
434
+ tc.pkir = { status: "ok", exePath, wasmPath };
435
+ pkirExes.set(tc.op, tc.pkir);
436
+ } catch (error) {
437
+ tc.pkir = {
438
+ status: "failed",
439
+ error: error.stack || error.message || String(error)
440
+ };
441
+ pkirExes.set(tc.op, tc.pkir);
442
+ }
443
+ }
444
+ }
445
+
346
446
  function createWasmRunner(testSuite) {
347
447
  const wasmCases = testSuite.filter(tc => tc.wasm?.status === "ok");
348
448
  const servers = new Map();
@@ -371,6 +471,34 @@ function createWasmRunner(testSuite) {
371
471
  };
372
472
  }
373
473
 
474
+ function createPKIRRunner(testSuite) {
475
+ const pkirCases = testSuite.filter(tc => tc.pkir?.status === "ok");
476
+ const servers = new Map();
477
+ function serverFor(exePath) {
478
+ let server = servers.get(exePath);
479
+ if (server == null) {
480
+ server = new PersistentExecutable(exePath);
481
+ servers.set(exePath, server);
482
+ }
483
+ return server;
484
+ }
485
+
486
+ return {
487
+ async run(iterations) {
488
+ if (pkirCases.length === 0) return null;
489
+ return runTimedIterationsAsync(iterations, async () => {
490
+ for (const tc of pkirCases) {
491
+ await serverFor(tc.pkir.exePath).request(tc.inputWire);
492
+ }
493
+ });
494
+ },
495
+ serverFor,
496
+ close() {
497
+ for (const server of servers.values()) server.close();
498
+ }
499
+ };
500
+ }
501
+
374
502
  function printBenchmarkDescription() {
375
503
  const lanes = [];
376
504
  if (runBaselines) {
@@ -378,8 +506,10 @@ function printBenchmarkDescription() {
378
506
  lanes.push("Native JS (Envelope-Free)");
379
507
  lanes.push("kVM Interpreter (Env-Free)");
380
508
  }
381
- if (runLLVM) lanes.push(llvmLaneName());
509
+ if (runLLVM) lanes.push(llvmLaneNameStr());
510
+ if (runLLVMPKIR) lanes.push(llvmPkirLaneNameStr());
382
511
  if (runWasm) lanes.push(wasmLaneName());
512
+ if (runPKIR) lanes.push(pkirLaneName());
383
513
 
384
514
  console.log("==> Benchmark description");
385
515
  console.log(" source: @fraczak/k/Examples/poly.k");
@@ -391,11 +521,18 @@ function printBenchmarkDescription() {
391
521
  console.log(` llvm-ready cases: ${testSuite.filter(tc => tc.llvm?.status === "ok").length}`);
392
522
  console.log(` llvm warmup iterations: ${llvmWarmupIterations}`);
393
523
  }
524
+ if (runLLVMPKIR) {
525
+ console.log(` llvm-pkir ready cases: ${testSuite.filter(tc => tc.llvmPKIR?.status === "ok").length}`);
526
+ console.log(` llvm-pkir warmup iterations: ${llvmWarmupIterations}`);
527
+ }
394
528
  if (runWasm) {
395
529
  console.log(` wasm runner mode: ${wasmPipe ? "persistent pipe" : "in-process"}`);
396
530
  console.log(` wasm warmup iterations: ${wasmWarmupIterations}`);
397
531
  if (!wasmPipe) console.log(` wasm arena reset: ${wasmReset ? "yes" : "no"}`);
398
532
  }
533
+ if (runPKIR) {
534
+ console.log(` pkir warmup iterations: ${wasmWarmupIterations}`);
535
+ }
399
536
  console.log(` iterations: ${iterations}`);
400
537
  console.log(` benchmark lanes: ${lanes.join("; ")}`);
401
538
  console.log(" conformance: all outputs are compared to native expected values");
@@ -431,6 +568,23 @@ if (runLLVM) {
431
568
  }
432
569
  }
433
570
 
571
+ // 2b. LLVM-PKIR lane
572
+ let llvmPkirResult = null;
573
+ if (runLLVMPKIR) {
574
+ const llvmPkirCases = testSuite.map(tc => ({ ...tc, llvm: tc.llvmPKIR }));
575
+ const llvmPkirRunner = createLLVMRunner(llvmPkirCases);
576
+ try {
577
+ if (llvmWarmupIterations > 0) {
578
+ console.log(`==> Warming LLVM-PKIR executables (${llvmWarmupIterations} iterations)...`);
579
+ await llvmPkirRunner.run(llvmWarmupIterations);
580
+ }
581
+ console.log(`==> Running LLVM-PKIR (${iterations} iterations)...`);
582
+ llvmPkirResult = await llvmPkirRunner.run(iterations);
583
+ } finally {
584
+ llvmPkirRunner.close();
585
+ }
586
+ }
587
+
434
588
  // 3. Wasm lane
435
589
  let wasmResult = null;
436
590
  if (runWasm) {
@@ -476,6 +630,25 @@ if (runWasm) {
476
630
  }
477
631
  }
478
632
 
633
+ // 4. PKIR lane
634
+ let pkirResult = null;
635
+ if (runPKIR) {
636
+ const pkirCases = testSuite.filter(tc => tc.pkir?.status === "ok");
637
+ if (pkirCases.length === testSuite.length) {
638
+ const pkirRunner = createPKIRRunner(testSuite);
639
+ try {
640
+ if (wasmWarmupIterations > 0) {
641
+ console.log(`==> Warming PKIR (${wasmWarmupIterations} iterations)...`);
642
+ await pkirRunner.run(wasmWarmupIterations);
643
+ }
644
+ console.log(`==> Running PKIR (${iterations} iterations)...`);
645
+ pkirResult = await pkirRunner.run(iterations);
646
+ } finally {
647
+ pkirRunner.close();
648
+ }
649
+ }
650
+ }
651
+
479
652
  console.log("\n=================== POLYMORPHIC BENCHMARK RESULTS ===================");
480
653
  console.log(`Polymorphic operations per iteration: ${testSuite.length}`);
481
654
  console.log(`Total requested operation calls: ${iterations * testSuite.length}`);
@@ -487,11 +660,19 @@ if (runBaselines) {
487
660
  console.log(`${laneIndex++}. kVM Interpreter (Env-Free): ${formatTiming(kvmFreeResult)}`);
488
661
  }
489
662
  if (runLLVM) {
490
- console.log(`${laneIndex++}. ${llvmLaneName().padEnd(29)} ${formatTiming(llvmResult)}`);
663
+ const name = llvmLaneNameStr().padEnd(29);
664
+ console.log(`${laneIndex++}. ${name} ${formatTiming(llvmResult)}`);
665
+ }
666
+ if (runLLVMPKIR) {
667
+ const name = llvmPkirLaneNameStr().padEnd(29);
668
+ console.log(`${laneIndex++}. ${name} ${formatTiming(llvmPkirResult)}`);
491
669
  }
492
670
  if (runWasm) {
493
671
  console.log(`${laneIndex++}. ${wasmLaneName().padEnd(29)} ${formatTiming(wasmResult)}`);
494
672
  }
673
+ if (runPKIR) {
674
+ console.log(`${laneIndex++}. ${pkirLaneName().padEnd(29)} ${formatTiming(pkirResult)}`);
675
+ }
495
676
  console.log("=====================================================================\n");
496
677
 
497
678
  // Conformance Validation
@@ -518,6 +699,23 @@ for (const tc of testSuite) {
518
699
  }
519
700
  }
520
701
 
702
+ if (runLLVMPKIR) {
703
+ if (tc.llvmPKIR.status !== "ok") {
704
+ tc.llvmPkirConformance = "compile-failed";
705
+ } else {
706
+ try {
707
+ const outputWire = await runExecutable(tc.llvmPKIR.exePath, tc.inputWire);
708
+ const actual = decodeWire(outputWire).value;
709
+ assert.ok(safeDeepEqual(actual, tc.expected), `LLVM-PKIR output mismatch for ${tc.op}`);
710
+ tc.llvmPkirConformance = "ok";
711
+ } catch (error) {
712
+ tc.llvmPkirConformance = "failed";
713
+ tc.llvmPKIR.error = error.stack || error.message || String(error);
714
+ console.log(`LLVM-PKIR conformance failure for ${tc.op}:`, tc.llvmPKIR.error.split("\n")[0]);
715
+ }
716
+ }
717
+ }
718
+
521
719
  if (runWasm) {
522
720
  if (wasmPipe) {
523
721
  if (tc.wasm?.status !== "ok") {
@@ -557,6 +755,23 @@ for (const tc of testSuite) {
557
755
  }
558
756
  }
559
757
 
758
+ if (runPKIR) {
759
+ if (tc.pkir?.status !== "ok") {
760
+ tc.pkirConformance = "compile-failed";
761
+ } else {
762
+ try {
763
+ const outputWire = await runExecutable(tc.pkir.exePath, tc.inputWire);
764
+ const actual = decodeWire(outputWire).value;
765
+ assert.ok(safeDeepEqual(actual, tc.expected), `PKIR output mismatch for ${tc.op}`);
766
+ tc.pkirConformance = "ok";
767
+ } catch (error) {
768
+ tc.pkirConformance = "failed";
769
+ tc.pkir.error = error.stack || error.message || String(error);
770
+ console.log(`PKIR conformance failure for ${tc.op}:`, tc.pkir.error.split("\n")[0]);
771
+ }
772
+ }
773
+ }
774
+
560
775
  }
561
776
 
562
777
  const validationSummary = [];
@@ -565,14 +780,24 @@ if (runLLVM) {
565
780
  const llvmOk = testSuite.filter(tc => tc.llvmConformance === "ok").length;
566
781
  validationSummary.push(`LLVM ${llvmOk}/${testSuite.length}`);
567
782
  }
783
+ if (runLLVMPKIR) {
784
+ const pkirOk = testSuite.filter(tc => tc.llvmPkirConformance === "ok").length;
785
+ validationSummary.push(`LLVM-PKIR ${pkirOk}/${testSuite.length}`);
786
+ }
568
787
  if (runWasm) {
569
788
  const wasmOk = testSuite.filter(tc => tc.wasmConformance === "ok").length;
570
789
  validationSummary.push(`Wasm ${wasmOk}/${testSuite.length}`);
571
790
  }
791
+ if (runPKIR) {
792
+ const pkirOk = testSuite.filter(tc => tc.pkirConformance === "ok").length;
793
+ validationSummary.push(`PKIR ${pkirOk}/${testSuite.length}`);
794
+ }
572
795
 
573
796
  console.log(`Conformance validation: ${validationSummary.join(", ")} cases match expected values.`);
574
797
  if (runLLVM && shouldStrictFail(testSuite)) process.exitCode = 1;
798
+ if (runLLVMPKIR && shouldStrictFail(testSuite.map(tc => ({ ...tc, llvm: tc.llvmPKIR })))) process.exitCode = 1;
575
799
  if (runWasm && testSuite.some(tc => tc.wasmConformance !== "ok")) process.exitCode = 1;
800
+ if (runPKIR && testSuite.some(tc => tc.pkirConformance !== "ok")) process.exitCode = 1;
576
801
 
577
802
  if (runTrace && process.exitCode !== 1) {
578
803
  console.log("\n=================== RUNNING MACRO-PHASE TRACING ===================");
@@ -588,6 +813,18 @@ if (runTrace && process.exitCode !== 1) {
588
813
  }
589
814
  }
590
815
 
816
+ const llvmPkirServers = new Map();
817
+ if (runLLVMPKIR) {
818
+ for (const tc of testSuite) {
819
+ if (tc.llvmPKIR?.status === "ok") {
820
+ llvmPkirServers.set(
821
+ tc.op,
822
+ new PersistentExecutable(tc.llvmPKIR.exePath)
823
+ );
824
+ }
825
+ }
826
+ }
827
+
591
828
  const wasmServers = new Map();
592
829
  if (runWasm && wasmPipe) {
593
830
  for (const tc of testSuite) {
@@ -597,6 +834,15 @@ if (runTrace && process.exitCode !== 1) {
597
834
  }
598
835
  }
599
836
 
837
+ const pkirServers = new Map();
838
+ if (runPKIR) {
839
+ for (const tc of testSuite) {
840
+ if (tc.pkir?.status === "ok") {
841
+ pkirServers.set(tc.op, new PersistentExecutable(tc.pkir.exePath));
842
+ }
843
+ }
844
+ }
845
+
600
846
  const averageTrace = (samples) => {
601
847
  if (!samples || samples.length === 0) return null;
602
848
  const avg = {};
@@ -641,6 +887,18 @@ if (runTrace && process.exitCode !== 1) {
641
887
  opData.llvm = averageTrace(samples);
642
888
  }
643
889
 
890
+ // 2b. LLVM-PKIR
891
+ if (llvmPkirServers.has(op)) {
892
+ const server = llvmPkirServers.get(op);
893
+ for (let i = 0; i < 3; i++) await server.requestWithTrace(tc.inputWire);
894
+ const samples = [];
895
+ for (let i = 0; i < sampleReps; i++) {
896
+ const res = await server.requestWithTrace(tc.inputWire);
897
+ if (res.trace) samples.push(res.trace);
898
+ }
899
+ opData.llvmPkir = averageTrace(samples);
900
+ }
901
+
644
902
  // 3. Wasm
645
903
  if (runWasm) {
646
904
  if (wasmPipe) {
@@ -701,6 +959,18 @@ if (runTrace && process.exitCode !== 1) {
701
959
  }
702
960
  }
703
961
 
962
+ // PKIR
963
+ if (runPKIR && pkirServers.has(op)) {
964
+ const server = pkirServers.get(op);
965
+ for (let i = 0; i < 3; i++) await server.requestWithTrace(tc.inputWire);
966
+ const samples = [];
967
+ for (let i = 0; i < sampleReps; i++) {
968
+ const res = await server.requestWithTrace(tc.inputWire);
969
+ if (res.trace) samples.push(res.trace);
970
+ }
971
+ opData.pkir = averageTrace(samples);
972
+ }
973
+
704
974
  // 4. kVM
705
975
  if (runBaselines) {
706
976
  const relDef = relations[op].relDef;
@@ -747,7 +1017,9 @@ if (runTrace && process.exitCode !== 1) {
747
1017
  }
748
1018
 
749
1019
  for (const s of llvmServers.values()) s.close();
1020
+ for (const s of llvmPkirServers.values()) s.close();
750
1021
  for (const s of wasmServers.values()) s.close();
1022
+ for (const s of pkirServers.values()) s.close();
751
1023
 
752
1024
  function formatUs(ns) {
753
1025
  if (ns == null || ns === 0) return " - ";
@@ -766,19 +1038,31 @@ if (runTrace && process.exitCode !== 1) {
766
1038
  { name: "Total Request Time", key: "totalNs", isTotal: true }
767
1039
  ];
768
1040
 
1041
+ const activeTraceLanes = [];
1042
+ if (runLLVM) {
1043
+ activeTraceLanes.push({ id: "llvm", label: "LLVM" });
1044
+ }
1045
+ if (runLLVMPKIR) {
1046
+ activeTraceLanes.push({ id: "llvmPkir", label: "LLVM-PKIR" });
1047
+ }
1048
+ if (runWasm) activeTraceLanes.push({ id: "wasm", label: "WebAssembly" });
1049
+ if (runPKIR) activeTraceLanes.push({ id: "pkir", label: "PKIR (Wasm)" });
1050
+ if (runBaselines) activeTraceLanes.push({ id: "kvm", label: "kVM Interp" });
1051
+
1052
+ const traceHeader = ["Phase ", ...activeTraceLanes.map(l => l.label.padEnd(13))].join(" | ");
1053
+ const traceDivider = ["------------------------", ...activeTraceLanes.map(() => "-------------")].join("-+-");
1054
+
769
1055
  for (const item of phaseResults) {
770
1056
  console.log(`\n--- Operation: ${item.op} (${item.label}) ---`);
771
- console.log("Phase | LLVM | WebAssembly | kVM Interp");
772
- console.log("-------------------------+---------------+---------------+---------------");
1057
+ console.log(traceHeader);
1058
+ console.log(traceDivider);
773
1059
  for (const phase of phases) {
774
1060
  if (phase.isTotal) {
775
- console.log("-------------------------+---------------+---------------+---------------");
1061
+ console.log(traceDivider);
776
1062
  }
777
1063
  const pName = phase.name.padEnd(24);
778
- const llvmCol = formatUs(item.llvm?.[phase.key]);
779
- const wasmCol = formatUs(item.wasm?.[phase.key]);
780
- const kvmCol = formatUs(item.kvm?.[phase.key]);
781
- console.log(`${pName} | ${llvmCol} | ${wasmCol} | ${kvmCol}`);
1064
+ const cols = [pName, ...activeTraceLanes.map(l => formatUs(item[l.id]?.[phase.key]))];
1065
+ console.log(cols.join(" | "));
782
1066
  }
783
1067
 
784
1068
  const hasProfile = item.wasmProfile || item.kvmProfile;
@@ -820,11 +1104,11 @@ if (runTrace && process.exitCode !== 1) {
820
1104
  }
821
1105
 
822
1106
  console.log(`\n=== AVERAGE ACROSS ALL ${phaseResults.length} OPERATIONS ===`);
823
- console.log("Phase | LLVM | WebAssembly | kVM Interp");
824
- console.log("-------------------------+---------------+---------------+---------------");
1107
+ console.log(traceHeader);
1108
+ console.log(traceDivider);
825
1109
  for (const phase of phases) {
826
1110
  if (phase.isTotal) {
827
- console.log("-------------------------+---------------+---------------+---------------");
1111
+ console.log(traceDivider);
828
1112
  }
829
1113
  const pName = phase.name.padEnd(24);
830
1114
  const avg = (backend) => {
@@ -832,10 +1116,8 @@ if (runTrace && process.exitCode !== 1) {
832
1116
  if (vals.length === 0) return null;
833
1117
  return vals.reduce((a, b) => a + b, 0) / vals.length;
834
1118
  };
835
- const llvmCol = formatUs(avg("llvm"));
836
- const wasmCol = formatUs(avg("wasm"));
837
- const kvmCol = formatUs(avg("kvm"));
838
- console.log(`${pName} | ${llvmCol} | ${wasmCol} | ${kvmCol}`);
1119
+ const cols = [pName, ...activeTraceLanes.map(l => formatUs(avg(l.id)))];
1120
+ console.log(cols.join(" | "));
839
1121
  }
840
1122
 
841
1123
  if (phaseResults.some(r => r.wasmProfile || r.kvmProfile)) {
@@ -51,6 +51,9 @@ const tests = [
51
51
  ["tests/test-arithmetics.mjs", node, ["tests/test-arithmetics.mjs"]],
52
52
  ["tests/test-karatsuba.mjs", node, ["tests/test-karatsuba.mjs"]],
53
53
  ["tests/test-poly.mjs", node, ["tests/test-poly.mjs"]],
54
+ ["tests/test-polymorphic-tdd.mjs", node, ["tests/test-polymorphic-tdd.mjs"]],
55
+ ["tests/test-access-table.mjs", node, ["tests/test-access-table.mjs"]],
56
+ ["tests/test-pkir.mjs", node, ["tests/test-pkir.mjs"]],
54
57
  ["tests/test-ieee-arithmetic.mjs", node, ["tests/test-ieee-arithmetic.mjs"]],
55
58
  ["tests/integration.sh", path.join(root, "tests/integration.sh"), []]
56
59
  ];