@fraczak/k 7.0.1 → 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 (89) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/DOCS/BIG_PICTURE.md +5 -5
  3. package/DOCS/FILE_FORMATS.md +241 -18
  4. package/DOCS/OBJECT_FILE_AND_PATTERN.md +9 -9
  5. package/DOCS/PATTERNS.md +3 -3
  6. package/DOCS/POLYMORPHIC_IR.md +104 -0
  7. package/DOCS/PROFILING_AND_TRACING.md +60 -72
  8. package/DOCS/REPL.md +3 -3
  9. package/DOCS/book/03-types-as-finite-automata.md +4 -4
  10. package/DOCS/book/06-values-in-memory.md +9 -9
  11. package/DOCS/book/08-operational-semantics-and-execution.md +1 -1
  12. package/DOCS/book/09-compiler-architecture.md +2 -2
  13. package/DOCS/book/10-from-ast-to-intermediate-representation.md +2 -2
  14. package/DOCS/book/14-canonical-serialization.md +1 -1
  15. package/Examples/arithmetics.k +2 -2
  16. package/Examples/bnat.k +1 -1
  17. package/Examples/karatsuba-mult.k +2 -2
  18. package/JOURNAL.md +288 -0
  19. package/README.md +13 -10
  20. package/access-table.mjs +343 -0
  21. package/backend-api.mjs +18 -0
  22. package/backends/llvm/README.md +20 -21
  23. package/backends/llvm/bin/k-llvm-build.mjs +105 -32
  24. package/backends/llvm/bin/k-llvm-compile.mjs +63 -24
  25. package/backends/llvm/bin/k-llvm.mjs +292 -0
  26. package/backends/llvm/runtime/krt.c +41 -0
  27. package/backends/llvm/runtime/krt.h +2 -0
  28. package/backends/llvm/src/cli.mjs +95 -17
  29. package/backends/llvm/src/executable.mjs +132 -15
  30. package/backends/llvm/src/kvm2llvm.mjs +50 -23
  31. package/backends/llvm/src/llvm.mjs +133 -20
  32. package/backends/llvm/tests/integration.sh +11 -11
  33. package/backends/llvm/{bin → tests}/k-llvm-run.mjs +48 -22
  34. package/backends/llvm/tests/perf-support.mjs +25 -58
  35. package/backends/llvm/tests/test-llvm.mjs +25 -4
  36. package/backends/wasm/bin/k-wasm-compile.mjs +46 -20
  37. package/backends/wasm/bin/k-wasm-run.mjs +61 -20
  38. package/backends/wasm/bin/k-wasm.mjs +47 -13
  39. package/backends/wasm/src/cli.mjs +141 -19
  40. package/backends/wasm/src/wasm.mjs +132 -24
  41. package/backends/wasm/tests/test-wasm.mjs +5 -5
  42. package/browser/repl-browser.mjs +16 -5
  43. package/browser/vfs-data.mjs +5 -5
  44. package/codecs/k-parse.mjs +29 -8
  45. package/codecs/k-print.mjs +22 -6
  46. package/codecs/runtime/codec-sdk.mjs +8 -4
  47. package/codecs/show.mjs +20 -6
  48. package/core.k +8 -8
  49. package/harness/format.mjs +2 -2
  50. package/harness/registry.mjs +0 -2
  51. package/k.mjs +56 -16
  52. package/kir.mjs +200 -75
  53. package/kvm.mjs +49 -12
  54. package/objects/compile.mjs +37 -23
  55. package/objects/decompile.mjs +40 -10
  56. package/objects/extract-aliases.mjs +44 -14
  57. package/objects/inspect.mjs +19 -14
  58. package/objects/validate.mjs +18 -11
  59. package/package.json +10 -7
  60. package/pkir.mjs +772 -0
  61. package/repl.mjs +36 -18
  62. package/scripts/benchmark-idempotency.mjs +12 -8
  63. package/scripts/benchmark.mjs +5 -9
  64. package/scripts/build-repl-html.mjs +16 -4
  65. package/scripts/perf-ieee.mjs +253 -103
  66. package/scripts/perf-int.mjs +585 -297
  67. package/scripts/perf-multiplication.mjs +66 -25
  68. package/scripts/perf-poly.mjs +292 -164
  69. package/scripts/run-tests.mjs +3 -0
  70. package/tests/code-derivation/pattern-envelope.mjs +4 -4
  71. package/tests/test-access-table.mjs +213 -0
  72. package/tests/test-kvm-polymorphic.mjs +2 -2
  73. package/tests/test-pkir.mjs +530 -0
  74. package/tests/test-polymorphic-tdd.mjs +196 -0
  75. package/tests/test-repl-html.mjs +15 -2
  76. package/tests/test-repl.mjs +30 -1
  77. package/backends/arm64/README.md +0 -103
  78. package/backends/arm64/bin/k-arm64-compile.mjs +0 -93
  79. package/backends/arm64/bin/k-arm64-run.mjs +0 -58
  80. package/backends/arm64/bin/k-arm64.mjs +0 -88
  81. package/backends/arm64/scripts/run-tests.mjs +0 -57
  82. package/backends/arm64/src/arm64.mjs +0 -229
  83. package/backends/arm64/src/cli.mjs +0 -155
  84. package/backends/arm64/src/kvm2arm64.mjs +0 -906
  85. package/backends/arm64/src/runtime.c +0 -744
  86. package/backends/arm64/tests/integration.sh +0 -112
  87. package/backends/arm64/tests/test-arm64.mjs +0 -240
  88. package/backends/llvm/bin/k-llvm-jit.mjs +0 -160
  89. package/harness/adapters/arm64.mjs +0 -105
@@ -24,8 +24,6 @@ import {
24
24
  csvEnv,
25
25
  formatTiming,
26
26
  createLLVMRunner,
27
- createARM64Runner,
28
- arm64LaneName,
29
27
  llvmLaneName,
30
28
  makeCacheDir,
31
29
  parseNonNegativeIntEnv,
@@ -56,7 +54,6 @@ import {
56
54
  writeValueToArena
57
55
  } from "../backends/wasm/tests/perf-support.mjs";
58
56
 
59
- import { compileARM64ArtifactFromObject } from "../backends/arm64/src/arm64.mjs";
60
57
  import { compileWasmArtifactFromObject } from "../backends/wasm/src/wasm.mjs";
61
58
  import { inputPatternForObjectRelation } from "../backends/llvm/src/executable.mjs";
62
59
 
@@ -65,7 +62,7 @@ function printHelp() {
65
62
 
66
63
  Polymorphic List Operations Benchmark Harness.
67
64
  Benchmarks reverse, concat, split_by, get_nth, and length on
68
- Examples/poly.k across Native JS, kVM interpreter, LLVM, Wasm, and ARM64.
65
+ Examples/poly.k across Native JS, kVM interpreter, LLVM, Wasm, and PKIR.
69
66
 
70
67
  Options:
71
68
  --trace
@@ -74,18 +71,20 @@ Options:
74
71
  Enable per-function call count profiling.
75
72
  --wasm-in-process
76
73
  Run WebAssembly in-process instead of persistent subprocess runner.
74
+ --pkir-only
75
+ Run only PKIR backend.
77
76
  -h, --help
78
77
  Show this help message and exit.
79
78
 
80
79
  Environment Variables:
81
80
  BACKENDS
82
- Target backend to run: 'llvm', 'wasm', or 'arm64'.
81
+ Target backend to run: 'llvm', 'wasm', or 'pkir'.
83
82
  LLVM_ONLY
84
83
  Run only LLVM backend ('1' to enable).
85
84
  WASM_ONLY
86
85
  Run only WebAssembly backend ('1' to enable).
87
- ARM64_ONLY
88
- Run only ARM64 backend ('1' to enable).
86
+ PKIR_ONLY
87
+ Run only PKIR backend ('1' to enable).
89
88
  BACKENDS_ONLY
90
89
  Skip JS and kVM interpreter baselines ('1' to enable).
91
90
  LIST_LENGTH
@@ -96,14 +95,6 @@ Environment Variables:
96
95
  Enable nanosecond execution tracing ('1' to enable).
97
96
  PROFILE, K_PROFILE
98
97
  Enable per-function call count profiling ('1' to enable).
99
- ARM64_WARMUP_ITERATIONS
100
- Warmup iterations for ARM64 backend (default: 1).
101
- ARM64_OPT
102
- ARM64 backend optimization flags (default: -O2).
103
- ARM64_SPAWN_PER_CALL
104
- Spawn process per ARM64 call instead of persistent ('1' or '0').
105
- ARM64_PIPELINE
106
- Use persistent pipelined runner for ARM64 ('1' or '0').
107
98
  LLVM_WARMUP_ITERATIONS
108
99
  Warmup iterations for LLVM backend (default: 1).
109
100
  LLVM_SPAWN_PER_CALL
@@ -129,15 +120,52 @@ if (process.argv.includes("-h") || process.argv.includes("--help")) {
129
120
 
130
121
  // Backend selection
131
122
  const backendsEnv = process.env.BACKENDS?.toLowerCase();
132
- const llvmOnly = process.env.LLVM_ONLY === "1" || backendsEnv === "llvm";
133
- const wasmOnly = process.env.WASM_ONLY === "1" || backendsEnv === "wasm";
134
- const arm64Only = process.env.ARM64_ONLY === "1" || backendsEnv === "arm64";
135
-
136
- const isArm64Host = process.arch === "arm64" && process.platform === "linux";
137
- const runARM64 = !wasmOnly && !llvmOnly && (isArm64Host || arm64Only);
138
- const runLLVM = !wasmOnly && !arm64Only;
139
- const runWasm = !llvmOnly && !arm64Only;
140
- const runBaselines = !process.env.BACKENDS_ONLY && (process.env.LLVM_ONLY !== "1") && (process.env.WASM_ONLY !== "1") && (process.env.ARM64_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
+ }
141
169
 
142
170
  const ops = ["reverse", "concat", "split_by", "get_nth", "length"];
143
171
  const benchNames = Object.fromEntries(ops.map(op => [op, `bench_${op}`]));
@@ -146,10 +174,6 @@ const iterations = parsePositiveIntEnv("ITERATIONS", 3);
146
174
  const runTrace = process.argv.includes("--trace") || process.env.TRACE === "1" || process.env.K_TRACE === "1";
147
175
  const runProfile = runTrace || process.argv.includes("--profile") || process.env.K_PROFILE === "1" || process.env.PROFILE === "1";
148
176
 
149
- // ARM64 options
150
- const arm64WarmupIterations = parseNonNegativeIntEnv("ARM64_WARMUP_ITERATIONS", 1);
151
- const arm64OptLevel = process.env.ARM64_OPT || "-O2";
152
-
153
177
  // LLVM options
154
178
  const llvmWarmupIterations = parseNonNegativeIntEnv("LLVM_WARMUP_ITERATIONS", 1);
155
179
  const cacheDir = makeCacheDir("k-poly-perf-");
@@ -164,6 +188,9 @@ function wasmLaneName() {
164
188
  const mode = wasmPipe ? "persistent" : "in-process";
165
189
  return `WebAssembly (${mode})`;
166
190
  }
191
+ function pkirLaneName() {
192
+ return "PKIR (Wasm persistent)";
193
+ }
167
194
 
168
195
 
169
196
  console.log("==> Loading @fraczak/k/Examples/arithmetics.k as library");
@@ -193,7 +220,7 @@ function buildExportPreamble(exports, libraries) {
193
220
  return lines.join("\n") + "\n";
194
221
  }
195
222
 
196
- const neededExports = ["0", "int", "inc", "dec", "nat", "zero_int?"];
223
+ const neededExports = ["0", "int", "inc", "dec", "nat", "zero_int?", "neg?", "GT"];
197
224
  const exportPreamble = buildExportPreamble(neededExports, [arithmeticsLib]);
198
225
  const polyLib = loadLibrary(compileLibrary(exportPreamble + polySource, {
199
226
  source: polyPath,
@@ -219,7 +246,7 @@ for (const op of ops) {
219
246
  }
220
247
 
221
248
  function intValue(text) {
222
- return valueForCode(parseIntValue(text), state.typeAliases.int, codes.find);
249
+ return parseIntValue(text);
223
250
  }
224
251
 
225
252
  function makeList(elements) {
@@ -315,13 +342,37 @@ if (runLLVM) {
315
342
  relHash: relation.relHash,
316
343
  inputPattern: tc.inputPattern,
317
344
  cacheDir,
318
- sourceLabel: `@fraczak/k/Examples/poly.k#${relation.relationName}`
345
+ sourceLabel:
346
+ `@fraczak/k/Examples/poly.k#${relation.relationName}`,
347
+ usePKIR: false
319
348
  });
320
349
  }
321
350
  codes.load(state.codes);
322
351
  printCompileFailures(testSuite);
323
352
  }
324
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
+
325
376
  // Setup Wasm
326
377
  let wasmExports = null;
327
378
  let wasmProfileFunctions = [];
@@ -364,6 +415,34 @@ if (runWasm) {
364
415
  }
365
416
  }
366
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
+
367
446
  function createWasmRunner(testSuite) {
368
447
  const wasmCases = testSuite.filter(tc => tc.wasm?.status === "ok");
369
448
  const servers = new Map();
@@ -392,39 +471,32 @@ function createWasmRunner(testSuite) {
392
471
  };
393
472
  }
394
473
 
395
- // Setup ARM64
396
- const arm64Exes = new Map();
397
- if (runARM64) {
398
- console.log(`==> Compiling Linux ARM64 executables (${arm64OptLevel})...`);
399
- for (const tc of testSuite) {
400
- const relation = relations[tc.op];
401
- try {
402
- const exePath = path.join(cacheDir, `perf_poly_arm64_${tc.op}`);
403
- compileARM64ArtifactFromObject(relation.object, {
404
- entry: relation.relationName,
405
- inputPattern: tc.inputPattern,
406
- outputPattern: tc.outputPattern,
407
- outputPath: exePath,
408
- optLevel: arm64OptLevel,
409
- profile: runProfile
410
- });
411
- tc.arm64 = { status: "ok", exePath };
412
- arm64Exes.set(tc.op, tc.arm64);
413
- } catch (error) {
414
- tc.arm64 = {
415
- status: "failed",
416
- error: error.stack || error.message || String(error)
417
- };
418
- arm64Exes.set(tc.op, tc.arm64);
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);
419
482
  }
483
+ return server;
420
484
  }
421
- const failedOps = [...arm64Exes.entries()].filter(([_, v]) => v.status !== "ok");
422
- if (failedOps.length > 0) {
423
- console.log("Linux ARM64 compilation failures:");
424
- for (const [op, res] of failedOps) {
425
- console.log(` ${op}: ${res.error.split("\n")[0]}`);
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();
426
498
  }
427
- }
499
+ };
428
500
  }
429
501
 
430
502
  function printBenchmarkDescription() {
@@ -434,9 +506,10 @@ function printBenchmarkDescription() {
434
506
  lanes.push("Native JS (Envelope-Free)");
435
507
  lanes.push("kVM Interpreter (Env-Free)");
436
508
  }
437
- if (runLLVM) lanes.push(llvmLaneName());
509
+ if (runLLVM) lanes.push(llvmLaneNameStr());
510
+ if (runLLVMPKIR) lanes.push(llvmPkirLaneNameStr());
438
511
  if (runWasm) lanes.push(wasmLaneName());
439
- if (runARM64) lanes.push(arm64LaneName(arm64OptLevel));
512
+ if (runPKIR) lanes.push(pkirLaneName());
440
513
 
441
514
  console.log("==> Benchmark description");
442
515
  console.log(" source: @fraczak/k/Examples/poly.k");
@@ -448,16 +521,17 @@ function printBenchmarkDescription() {
448
521
  console.log(` llvm-ready cases: ${testSuite.filter(tc => tc.llvm?.status === "ok").length}`);
449
522
  console.log(` llvm warmup iterations: ${llvmWarmupIterations}`);
450
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
+ }
451
528
  if (runWasm) {
452
529
  console.log(` wasm runner mode: ${wasmPipe ? "persistent pipe" : "in-process"}`);
453
530
  console.log(` wasm warmup iterations: ${wasmWarmupIterations}`);
454
531
  if (!wasmPipe) console.log(` wasm arena reset: ${wasmReset ? "yes" : "no"}`);
455
532
  }
456
- if (runARM64) {
457
- console.log(` arm64-ready cases: ${testSuite.filter(tc => tc.arm64?.status === "ok").length}`);
458
- console.log(` arm64 warmup iterations: ${arm64WarmupIterations}`);
459
- console.log(` arm64 opt level: ${arm64OptLevel}`);
460
- console.log(` arm64 runner mode: ${process.env.ARM64_SPAWN_PER_CALL === "1" ? "spawn per call" : "persistent"}`);
533
+ if (runPKIR) {
534
+ console.log(` pkir warmup iterations: ${wasmWarmupIterations}`);
461
535
  }
462
536
  console.log(` iterations: ${iterations}`);
463
537
  console.log(` benchmark lanes: ${lanes.join("; ")}`);
@@ -494,6 +568,23 @@ if (runLLVM) {
494
568
  }
495
569
  }
496
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
+
497
588
  // 3. Wasm lane
498
589
  let wasmResult = null;
499
590
  if (runWasm) {
@@ -539,22 +630,21 @@ if (runWasm) {
539
630
  }
540
631
  }
541
632
 
542
- // 4. Linux ARM64 lane
543
- let arm64Result = null;
544
- if (runARM64) {
545
- const arm64Cases = testSuite.filter(tc => tc.arm64?.status === "ok");
546
- if (arm64Cases.length === testSuite.length) {
547
- const arm64Runner = createARM64Runner(testSuite);
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);
548
639
  try {
549
- if (arm64WarmupIterations > 0) {
550
- console.log(`==> Warming Linux ARM64 (${arm64WarmupIterations} iterations)...`);
551
- await arm64Runner.run(arm64WarmupIterations);
640
+ if (wasmWarmupIterations > 0) {
641
+ console.log(`==> Warming PKIR (${wasmWarmupIterations} iterations)...`);
642
+ await pkirRunner.run(wasmWarmupIterations);
552
643
  }
553
-
554
- console.log(`==> Running Linux ARM64 (${iterations} iterations)...`);
555
- arm64Result = await arm64Runner.run(iterations);
644
+ console.log(`==> Running PKIR (${iterations} iterations)...`);
645
+ pkirResult = await pkirRunner.run(iterations);
556
646
  } finally {
557
- arm64Runner.close();
647
+ pkirRunner.close();
558
648
  }
559
649
  }
560
650
  }
@@ -570,14 +660,18 @@ if (runBaselines) {
570
660
  console.log(`${laneIndex++}. kVM Interpreter (Env-Free): ${formatTiming(kvmFreeResult)}`);
571
661
  }
572
662
  if (runLLVM) {
573
- 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)}`);
574
669
  }
575
670
  if (runWasm) {
576
671
  console.log(`${laneIndex++}. ${wasmLaneName().padEnd(29)} ${formatTiming(wasmResult)}`);
577
672
  }
578
- if (runARM64) {
579
- const timingStr = arm64Result ? formatTiming(arm64Result) : "compile failed";
580
- console.log(`${laneIndex++}. ${arm64LaneName(arm64OptLevel).padEnd(29)} ${timingStr}`);
673
+ if (runPKIR) {
674
+ console.log(`${laneIndex++}. ${pkirLaneName().padEnd(29)} ${formatTiming(pkirResult)}`);
581
675
  }
582
676
  console.log("=====================================================================\n");
583
677
 
@@ -605,6 +699,23 @@ for (const tc of testSuite) {
605
699
  }
606
700
  }
607
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
+
608
719
  if (runWasm) {
609
720
  if (wasmPipe) {
610
721
  if (tc.wasm?.status !== "ok") {
@@ -644,22 +755,23 @@ for (const tc of testSuite) {
644
755
  }
645
756
  }
646
757
 
647
- if (runARM64) {
648
- if (tc.arm64?.status !== "ok") {
649
- tc.arm64Conformance = "compile-failed";
758
+ if (runPKIR) {
759
+ if (tc.pkir?.status !== "ok") {
760
+ tc.pkirConformance = "compile-failed";
650
761
  } else {
651
762
  try {
652
- const outputWire = await runExecutable(tc.arm64.exePath, tc.inputWire);
763
+ const outputWire = await runExecutable(tc.pkir.exePath, tc.inputWire);
653
764
  const actual = decodeWire(outputWire).value;
654
- assert.ok(safeDeepEqual(actual, tc.expected), `ARM64 output mismatch for ${tc.op}`);
655
- tc.arm64Conformance = "ok";
765
+ assert.ok(safeDeepEqual(actual, tc.expected), `PKIR output mismatch for ${tc.op}`);
766
+ tc.pkirConformance = "ok";
656
767
  } catch (error) {
657
- tc.arm64Conformance = "failed";
658
- tc.arm64.error = error.stack || error.message || String(error);
659
- console.log(`Linux ARM64 conformance failure for ${tc.op}:`, tc.arm64.error.split("\n")[0]);
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]);
660
771
  }
661
772
  }
662
773
  }
774
+
663
775
  }
664
776
 
665
777
  const validationSummary = [];
@@ -668,19 +780,24 @@ if (runLLVM) {
668
780
  const llvmOk = testSuite.filter(tc => tc.llvmConformance === "ok").length;
669
781
  validationSummary.push(`LLVM ${llvmOk}/${testSuite.length}`);
670
782
  }
783
+ if (runLLVMPKIR) {
784
+ const pkirOk = testSuite.filter(tc => tc.llvmPkirConformance === "ok").length;
785
+ validationSummary.push(`LLVM-PKIR ${pkirOk}/${testSuite.length}`);
786
+ }
671
787
  if (runWasm) {
672
788
  const wasmOk = testSuite.filter(tc => tc.wasmConformance === "ok").length;
673
789
  validationSummary.push(`Wasm ${wasmOk}/${testSuite.length}`);
674
790
  }
675
- if (runARM64) {
676
- const arm64Ok = testSuite.filter(tc => tc.arm64Conformance === "ok").length;
677
- validationSummary.push(`Linux ARM64 ${arm64Ok}/${testSuite.length}`);
791
+ if (runPKIR) {
792
+ const pkirOk = testSuite.filter(tc => tc.pkirConformance === "ok").length;
793
+ validationSummary.push(`PKIR ${pkirOk}/${testSuite.length}`);
678
794
  }
679
795
 
680
796
  console.log(`Conformance validation: ${validationSummary.join(", ")} cases match expected values.`);
681
797
  if (runLLVM && shouldStrictFail(testSuite)) process.exitCode = 1;
798
+ if (runLLVMPKIR && shouldStrictFail(testSuite.map(tc => ({ ...tc, llvm: tc.llvmPKIR })))) process.exitCode = 1;
682
799
  if (runWasm && testSuite.some(tc => tc.wasmConformance !== "ok")) process.exitCode = 1;
683
- if (runARM64 && testSuite.some(tc => tc.arm64Conformance !== "ok")) process.exitCode = 1;
800
+ if (runPKIR && testSuite.some(tc => tc.pkirConformance !== "ok")) process.exitCode = 1;
684
801
 
685
802
  if (runTrace && process.exitCode !== 1) {
686
803
  console.log("\n=================== RUNNING MACRO-PHASE TRACING ===================");
@@ -696,6 +813,18 @@ if (runTrace && process.exitCode !== 1) {
696
813
  }
697
814
  }
698
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
+
699
828
  const wasmServers = new Map();
700
829
  if (runWasm && wasmPipe) {
701
830
  for (const tc of testSuite) {
@@ -705,11 +834,11 @@ if (runTrace && process.exitCode !== 1) {
705
834
  }
706
835
  }
707
836
 
708
- const arm64Servers = new Map();
709
- if (runARM64) {
837
+ const pkirServers = new Map();
838
+ if (runPKIR) {
710
839
  for (const tc of testSuite) {
711
- if (tc.arm64?.status === "ok") {
712
- arm64Servers.set(tc.op, new PersistentExecutable(tc.arm64.exePath));
840
+ if (tc.pkir?.status === "ok") {
841
+ pkirServers.set(tc.op, new PersistentExecutable(tc.pkir.exePath));
713
842
  }
714
843
  }
715
844
  }
@@ -746,43 +875,28 @@ if (runTrace && process.exitCode !== 1) {
746
875
  const op = tc.op;
747
876
  const opData = { op, label: tc.label };
748
877
 
749
- // 1. ARM64
750
- if (arm64Servers.has(op)) {
751
- const server = arm64Servers.get(op);
878
+ // 2. LLVM
879
+ if (llvmServers.has(op)) {
880
+ const server = llvmServers.get(op);
752
881
  for (let i = 0; i < 3; i++) await server.requestWithTrace(tc.inputWire);
753
882
  const samples = [];
754
- let arm64Profile = null;
755
883
  for (let i = 0; i < sampleReps; i++) {
756
884
  const res = await server.requestWithTrace(tc.inputWire);
757
- if (res.trace) {
758
- samples.push(res.trace);
759
- if (res.trace.profile) arm64Profile = res.trace.profile;
760
- }
761
- }
762
- opData.arm64 = averageTrace(samples);
763
- if (arm64Profile) {
764
- if (arm64Profile.__main__ !== undefined) {
765
- if (arm64Profile[op] !== undefined) {
766
- arm64Profile[benchNames[op]] = arm64Profile.__main__;
767
- } else {
768
- arm64Profile[op] = arm64Profile.__main__;
769
- }
770
- delete arm64Profile.__main__;
771
- }
772
- opData.arm64Profile = arm64Profile;
885
+ if (res.trace) samples.push(res.trace);
773
886
  }
887
+ opData.llvm = averageTrace(samples);
774
888
  }
775
889
 
776
- // 2. LLVM
777
- if (llvmServers.has(op)) {
778
- const server = llvmServers.get(op);
890
+ // 2b. LLVM-PKIR
891
+ if (llvmPkirServers.has(op)) {
892
+ const server = llvmPkirServers.get(op);
779
893
  for (let i = 0; i < 3; i++) await server.requestWithTrace(tc.inputWire);
780
894
  const samples = [];
781
895
  for (let i = 0; i < sampleReps; i++) {
782
896
  const res = await server.requestWithTrace(tc.inputWire);
783
897
  if (res.trace) samples.push(res.trace);
784
898
  }
785
- opData.llvm = averageTrace(samples);
899
+ opData.llvmPkir = averageTrace(samples);
786
900
  }
787
901
 
788
902
  // 3. Wasm
@@ -845,6 +959,18 @@ if (runTrace && process.exitCode !== 1) {
845
959
  }
846
960
  }
847
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
+
848
974
  // 4. kVM
849
975
  if (runBaselines) {
850
976
  const relDef = relations[op].relDef;
@@ -891,8 +1017,9 @@ if (runTrace && process.exitCode !== 1) {
891
1017
  }
892
1018
 
893
1019
  for (const s of llvmServers.values()) s.close();
894
- for (const s of arm64Servers.values()) s.close();
1020
+ for (const s of llvmPkirServers.values()) s.close();
895
1021
  for (const s of wasmServers.values()) s.close();
1022
+ for (const s of pkirServers.values()) s.close();
896
1023
 
897
1024
  function formatUs(ns) {
898
1025
  if (ns == null || ns === 0) return " - ";
@@ -911,26 +1038,36 @@ if (runTrace && process.exitCode !== 1) {
911
1038
  { name: "Total Request Time", key: "totalNs", isTotal: true }
912
1039
  ];
913
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
+
914
1055
  for (const item of phaseResults) {
915
1056
  console.log(`\n--- Operation: ${item.op} (${item.label}) ---`);
916
- console.log("Phase | Linux ARM64 | LLVM | WebAssembly | kVM Interp");
917
- console.log("-------------------------+---------------+---------------+---------------+---------------");
1057
+ console.log(traceHeader);
1058
+ console.log(traceDivider);
918
1059
  for (const phase of phases) {
919
1060
  if (phase.isTotal) {
920
- console.log("-------------------------+---------------+---------------+---------------+---------------");
1061
+ console.log(traceDivider);
921
1062
  }
922
1063
  const pName = phase.name.padEnd(24);
923
- const arm64Col = formatUs(item.arm64?.[phase.key]);
924
- const llvmCol = formatUs(item.llvm?.[phase.key]);
925
- const wasmCol = formatUs(item.wasm?.[phase.key]);
926
- const kvmCol = formatUs(item.kvm?.[phase.key]);
927
- console.log(`${pName} | ${arm64Col} | ${llvmCol} | ${wasmCol} | ${kvmCol}`);
1064
+ const cols = [pName, ...activeTraceLanes.map(l => formatUs(item[l.id]?.[phase.key]))];
1065
+ console.log(cols.join(" | "));
928
1066
  }
929
1067
 
930
- const hasProfile = item.arm64Profile || item.wasmProfile || item.kvmProfile;
1068
+ const hasProfile = item.wasmProfile || item.kvmProfile;
931
1069
  if (hasProfile) {
932
1070
  const allFuncs = new Set([
933
- ...Object.keys(item.arm64Profile || {}),
934
1071
  ...Object.keys(item.wasmProfile || {}),
935
1072
  ...Object.keys(item.kvmProfile || {})
936
1073
  ]);
@@ -945,37 +1082,33 @@ if (runTrace && process.exitCode !== 1) {
945
1082
  });
946
1083
 
947
1084
  console.log(`\n Function Call Profile: ${item.op}`);
948
- console.log(" Function Name | Linux ARM64 Calls | WebAssembly Calls | kVM Interp Calls");
949
- console.log(" -------------------------+-------------------+-------------------+------------------");
950
- let arm64Total = 0, wasmTotal = 0, kvmTotal = 0;
1085
+ console.log(" Function Name | WebAssembly Calls | kVM Interp Calls");
1086
+ console.log(" -------------------------+-------------------+------------------");
1087
+ let wasmTotal = 0, kvmTotal = 0;
951
1088
  for (const fn of sortedFuncs) {
952
- const aCount = item.arm64Profile?.[fn] ?? 0;
953
1089
  const wCount = item.wasmProfile?.[fn] ?? 0;
954
1090
  const kCount = item.kvmProfile?.[fn] ?? 0;
955
- arm64Total += aCount;
956
1091
  wasmTotal += wCount;
957
1092
  kvmTotal += kCount;
958
1093
  const fnCol = fn.padEnd(24);
959
- const aStr = (aCount > 0 ? String(aCount) : "-").padStart(17);
960
1094
  const wStr = (wCount > 0 ? String(wCount) : "-").padStart(17);
961
1095
  const kStr = (kCount > 0 ? String(kCount) : "-").padStart(16);
962
- console.log(` ${fnCol} | ${aStr} | ${wStr} | ${kStr}`);
1096
+ console.log(` ${fnCol} | ${wStr} | ${kStr}`);
963
1097
  }
964
- console.log(" -------------------------+-------------------+-------------------+------------------");
1098
+ console.log(" -------------------------+-------------------+------------------");
965
1099
  const totCol = "Total Calls".padEnd(24);
966
- const aTotStr = String(arm64Total).padStart(17);
967
1100
  const wTotStr = String(wasmTotal).padStart(17);
968
1101
  const kTotStr = String(kvmTotal).padStart(16);
969
- console.log(` ${totCol} | ${aTotStr} | ${wTotStr} | ${kTotStr}`);
1102
+ console.log(` ${totCol} | ${wTotStr} | ${kTotStr}`);
970
1103
  }
971
1104
  }
972
1105
 
973
1106
  console.log(`\n=== AVERAGE ACROSS ALL ${phaseResults.length} OPERATIONS ===`);
974
- console.log("Phase | Linux ARM64 | LLVM | WebAssembly | kVM Interp");
975
- console.log("-------------------------+---------------+---------------+---------------+---------------");
1107
+ console.log(traceHeader);
1108
+ console.log(traceDivider);
976
1109
  for (const phase of phases) {
977
1110
  if (phase.isTotal) {
978
- console.log("-------------------------+---------------+---------------+---------------+---------------");
1111
+ console.log(traceDivider);
979
1112
  }
980
1113
  const pName = phase.name.padEnd(24);
981
1114
  const avg = (backend) => {
@@ -983,30 +1116,25 @@ if (runTrace && process.exitCode !== 1) {
983
1116
  if (vals.length === 0) return null;
984
1117
  return vals.reduce((a, b) => a + b, 0) / vals.length;
985
1118
  };
986
- const arm64Col = formatUs(avg("arm64"));
987
- const llvmCol = formatUs(avg("llvm"));
988
- const wasmCol = formatUs(avg("wasm"));
989
- const kvmCol = formatUs(avg("kvm"));
990
- console.log(`${pName} | ${arm64Col} | ${llvmCol} | ${wasmCol} | ${kvmCol}`);
1119
+ const cols = [pName, ...activeTraceLanes.map(l => formatUs(avg(l.id)))];
1120
+ console.log(cols.join(" | "));
991
1121
  }
992
1122
 
993
- if (phaseResults.some(r => r.arm64Profile || r.wasmProfile || r.kvmProfile)) {
1123
+ if (phaseResults.some(r => r.wasmProfile || r.kvmProfile)) {
994
1124
  console.log("\n=== FUNCTION CALL COUNT SUMMARY ACROSS ALL OPERATIONS ===");
995
- console.log("Operation (Case) | Linux ARM64 Calls | WebAssembly Calls | kVM Interp Calls");
996
- console.log("-------------------------+-------------------+-------------------+------------------");
997
- let arm64Grand = 0, wasmGrand = 0, kvmGrand = 0;
1125
+ console.log("Operation (Case) | WebAssembly Calls | kVM Interp Calls");
1126
+ console.log("-------------------------+-------------------+------------------");
1127
+ let wasmGrand = 0, kvmGrand = 0;
998
1128
  for (const r of phaseResults) {
999
- const aSum = Object.values(r.arm64Profile || {}).reduce((a, b) => a + b, 0);
1000
1129
  const wSum = Object.values(r.wasmProfile || {}).reduce((a, b) => a + b, 0);
1001
1130
  const kSum = Object.values(r.kvmProfile || {}).reduce((a, b) => a + b, 0);
1002
- arm64Grand += aSum;
1003
1131
  wasmGrand += wSum;
1004
1132
  kvmGrand += kSum;
1005
1133
  const opCol = `${r.op} (${r.label})`.slice(0, 24).padEnd(24);
1006
- console.log(`${opCol} | ${String(aSum).padStart(17)} | ${String(wSum).padStart(17)} | ${String(kSum).padStart(16)}`);
1134
+ console.log(`${opCol} | ${String(wSum).padStart(17)} | ${String(kSum).padStart(16)}`);
1007
1135
  }
1008
- console.log("-------------------------+-------------------+-------------------+------------------");
1009
- console.log(`${"Total Calls".padEnd(24)} | ${String(arm64Grand).padStart(17)} | ${String(wasmGrand).padStart(17)} | ${String(kvmGrand).padStart(16)}`);
1136
+ console.log("-------------------------+-------------------+------------------");
1137
+ console.log(`${"Total Calls".padEnd(24)} | ${String(wasmGrand).padStart(17)} | ${String(kvmGrand).padStart(16)}`);
1010
1138
  }
1011
1139
  console.log("=====================================================================\n");
1012
1140
  }