@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
@@ -11,21 +11,19 @@ import {
11
11
  evaluateInput,
12
12
  executeKVM,
13
13
  exportPatternGraph,
14
- parseFloat64,
15
14
  patternToPropertyList,
16
15
  propertyListToPattern,
17
16
  run,
18
17
  run_converged,
19
- valueForCode,
20
18
  Value
21
19
  } from "@fraczak/k/backend-api.mjs";
20
+ import { parse as parseFloatValue } from "@fraczak/k/codecs/ieee.mjs";
21
+ import { inputPatternForObjectRelation } from "../backends/llvm/src/executable.mjs";
22
22
 
23
23
  import {
24
24
  csvEnv,
25
25
  formatTiming,
26
26
  createLLVMRunner,
27
- createARM64Runner,
28
- arm64LaneName,
29
27
  llvmLaneName,
30
28
  makeCacheDir,
31
29
  parseNonNegativeIntEnv,
@@ -50,14 +48,13 @@ import {
50
48
  } from "../backends/wasm/tests/perf-support.mjs";
51
49
 
52
50
  import { compileWasmArtifactFromObject } from "../backends/wasm/src/wasm.mjs";
53
- import { compileARM64ArtifactFromObject } from "../backends/arm64/src/arm64.mjs";
54
51
 
55
52
  function printHelp() {
56
53
  console.log(`Usage: node scripts/perf-ieee.mjs [options]
57
54
 
58
55
  IEEE 754 Floating-Point Arithmetic Benchmark Harness.
59
56
  Benchmarks add, sub, mul, and div on Examples/ieee.k across
60
- Native JS, kVM interpreter, LLVM, Wasm, and ARM64 backends.
57
+ Native JS, kVM interpreter, LLVM, Wasm, and PKIR backends.
61
58
 
62
59
  Options:
63
60
  --opt=<levels>, --opts=<levels>
@@ -68,18 +65,20 @@ Options:
68
65
  Run full LLVM optimization sweep (-O0, -O1, -O2).
69
66
  --wasm-in-process
70
67
  Run WebAssembly in-process instead of persistent subprocess runner.
68
+ --pkir-only
69
+ Run only PKIR backend.
71
70
  -h, --help
72
71
  Show this help message and exit.
73
72
 
74
73
  Environment Variables:
75
74
  BACKENDS
76
- Target backend to run: 'llvm', 'wasm', or 'arm64'.
75
+ Target backend to run: 'llvm', 'wasm', or 'pkir'.
77
76
  LLVM_ONLY
78
77
  Run only LLVM backend ('1' to enable).
79
78
  WASM_ONLY
80
79
  Run only WebAssembly backend ('1' to enable).
81
- ARM64_ONLY
82
- Run only ARM64 backend ('1' to enable).
80
+ PKIR_ONLY
81
+ Run only PKIR backend ('1' to enable).
83
82
  BACKENDS_ONLY
84
83
  Skip JS and kVM interpreter baselines ('1' to enable).
85
84
  VALUES
@@ -87,14 +86,6 @@ Environment Variables:
87
86
  (default: 0.5,-4,0,Infinity,-Infinity,NaN).
88
87
  ITERATIONS
89
88
  Measured iterations per benchmark (default: 3).
90
- ARM64_WARMUP_ITERATIONS
91
- Warmup iterations for ARM64 backend (default: 1).
92
- ARM64_OPT
93
- ARM64 backend optimization flags (default: -O2).
94
- ARM64_SPAWN_PER_CALL
95
- Spawn process per ARM64 call instead of persistent ('1' or '0').
96
- ARM64_PIPELINE
97
- Use persistent pipelined runner for ARM64 ('1' or '0').
98
89
  LLVM_WARMUP_ITERATIONS
99
90
  Warmup iterations for LLVM backend (default: 1).
100
91
  LLVM_SPAWN_PER_CALL
@@ -129,24 +120,57 @@ 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 = ["add", "sub", "mul", "div"];
143
171
  const values = csvEnv("VALUES", "0.5,-4,0,Infinity,-Infinity,NaN");
144
172
  const iterations = parsePositiveIntEnv("ITERATIONS", 3);
145
173
 
146
- // ARM64 options
147
- const arm64WarmupIterations = parseNonNegativeIntEnv("ARM64_WARMUP_ITERATIONS", 1);
148
- const arm64OptLevel = process.env.ARM64_OPT || "-O2";
149
-
150
174
  // LLVM options
151
175
  const llvmWarmupIterations = parseNonNegativeIntEnv("LLVM_WARMUP_ITERATIONS", 1);
152
176
  const llvmRuntimeMode = process.env.K_LLVM_IEEE_RUNTIME_MODE || "fast";
@@ -193,6 +217,9 @@ function wasmLaneName() {
193
217
  const mode = wasmPipe ? "persistent" : "in-process";
194
218
  return `WebAssembly (${mode})`;
195
219
  }
220
+ function pkirLaneName() {
221
+ return "PKIR (Wasm persistent)";
222
+ }
196
223
 
197
224
  console.log("==> Initializing state and loading @fraczak/k/Examples/ieee.k");
198
225
  const state = createState();
@@ -200,10 +227,7 @@ const ieeePath = fileURLToPath(import.meta.resolve("@fraczak/k/Examples/ieee.k")
200
227
  await evaluateInput(`:load ${ieeePath}`, state);
201
228
 
202
229
  function generatePerfK(values) {
203
- const paramFields = values.map((_, i) => ` float64 p${i}`).join(",\n");
204
- const lines = [
205
- `$params = {\n${paramFields}\n};`
206
- ];
230
+ const lines = [];
207
231
  for (const op of ops) {
208
232
  lines.push(`perf_${op} =`);
209
233
  lines.push(" {");
@@ -216,7 +240,7 @@ function generatePerfK(values) {
216
240
  lines.push(cases.join(",\n"));
217
241
  lines.push(" };");
218
242
  }
219
- lines.push("perf_ieee = ?params");
243
+ lines.push("perf_ieee =");
220
244
  lines.push(" {");
221
245
  lines.push(" perf_add add,");
222
246
  lines.push(" perf_sub sub,");
@@ -230,7 +254,8 @@ const perfKSource = generatePerfK(values);
230
254
  await evaluateInput(perfKSource, state);
231
255
 
232
256
  const ieeeRaw = fs.readFileSync(ieeePath, "utf8");
233
- // Exclude trailing unassigned expression and comment block to ensure clean parse
257
+ // Exclude trailing unassigned expression and comment block to ensure
258
+ // clean parse.
234
259
  const endIdx = ieeeRaw.indexOf("\n()\n");
235
260
  const ieeeBase = endIdx !== -1 ? ieeeRaw.slice(0, endIdx) : ieeeRaw;
236
261
  const fullSource = `${ieeeBase}\n${perfKSource}\nperf_ieee`;
@@ -242,18 +267,16 @@ const relation = prepareRelation(state, "perf_ieee", {
242
267
  });
243
268
  codes.load(state.codes);
244
269
 
245
- const float64Hash = state.typeAliases.float64;
246
- function float64(text) {
247
- return valueForCode(parseFloat64(text), float64Hash, codes.find);
248
- }
249
-
250
270
  const paramsObj = {};
251
271
  for (let i = 0; i < values.length; i++) {
252
- paramsObj[`p${i}`] = float64(values[i]);
272
+ paramsObj[`p${i}`] = parseFloatValue(values[i]);
253
273
  }
254
- const rawProduct = Value.product(paramsObj);
255
- const inputVal = valueForCode(rawProduct, state.typeAliases.params, codes.find);
256
- const { inputWire, inputPattern } = wireInput(inputVal);
274
+ const inputVal = Value.product(paramsObj);
275
+ const inferredPattern = inputPatternForObjectRelation(
276
+ relation.object,
277
+ relation.relationName
278
+ );
279
+ const { inputWire, inputPattern } = wireInput(inputVal, inferredPattern);
257
280
 
258
281
  console.log("==> Computing expected results via Native JS");
259
282
  run_converged.defs = state;
@@ -275,7 +298,8 @@ if (runLLVM) {
275
298
  cacheDir,
276
299
  sourceLabel: "@fraczak/k/Examples/ieee.k#perf_ieee",
277
300
  runtimeMode: llvmRuntimeMode,
278
- clangOpt: opt
301
+ clangOpt: opt,
302
+ usePKIR: false
279
303
  });
280
304
  const singleCase = [{
281
305
  op: "perf_ieee",
@@ -292,6 +316,37 @@ if (runLLVM) {
292
316
  codes.load(state.codes);
293
317
  }
294
318
 
319
+ // Setup LLVM-PKIR
320
+ const llvmPkirCasesByOpt = new Map();
321
+ if (runLLVMPKIR) {
322
+ for (const opt of llvmOptLevels) {
323
+ console.log(`==> Compiling LLVM-PKIR executable (${opt})...`);
324
+ const llvm = tryCompileCase({
325
+ object: relation.object,
326
+ relationName: relation.relationName,
327
+ relHash: relation.relHash,
328
+ inputPattern,
329
+ cacheDir,
330
+ sourceLabel: "@fraczak/k/Examples/ieee.k#perf_ieee",
331
+ runtimeMode: llvmRuntimeMode,
332
+ clangOpt: opt,
333
+ usePKIR: true
334
+ });
335
+ const singleCase = [{
336
+ op: "perf_ieee",
337
+ label: "params",
338
+ inputVal,
339
+ inputWire,
340
+ inputPattern,
341
+ expected,
342
+ llvm
343
+ }];
344
+ llvmPkirCasesByOpt.set(opt, singleCase);
345
+ printCompileFailures(singleCase);
346
+ }
347
+ codes.load(state.codes);
348
+ }
349
+
295
350
  // Setup Wasm
296
351
  let wasmExports = null;
297
352
  let wasmPtrIn = null;
@@ -327,36 +382,34 @@ if (runWasm) {
327
382
  const relDef = relation.relDef;
328
383
  const graph = relDef.typePatternGraph;
329
384
 
330
- const inputPatternNodeId = graph.find(relDef.def.patterns[0]);
331
- const inputPat = propertyListToPattern(patternToPropertyList(exportPatternGraph(graph, inputPatternNodeId)));
332
-
333
385
  const outputPatternNodeId = graph.find(relDef.def.patterns[1]);
334
386
  wasmOutputPatternPropertyList = patternToPropertyList(exportPatternGraph(graph, outputPatternNodeId));
335
387
  wasmOutputPattern = propertyListToPattern(wasmOutputPatternPropertyList);
336
388
 
337
- wasmPtrIn = writeValueToArena(wasmExports, inputVal, inputPat, 0);
389
+ wasmPtrIn = writeValueToArena(wasmExports, inputVal, propertyListToPattern(inputPattern), 0);
338
390
  wasmFuncName = cleanName(state.relAliases.perf_ieee);
339
391
  }
340
392
  }
341
393
 
342
- // Setup ARM64
343
- let arm64ExePath = null;
344
- let arm64CompileError = null;
345
-
346
- if (runARM64) {
347
- console.log(`==> Compiling Linux ARM64 executable (${arm64OptLevel})...`);
394
+ // Setup PKIR
395
+ let pkirExePath = null;
396
+ let pkirCompileError = null;
397
+ if (runPKIR) {
398
+ console.log("==> Compiling PKIR executable (persistent runner)...");
348
399
  try {
349
- arm64ExePath = path.join(cacheDir, "perf_ieee_arm64");
350
- compileARM64ArtifactFromObject(relation.object, {
400
+ const pkirPath = path.join(cacheDir, "perf_ieee_pkir.wasm");
401
+ pkirExePath = path.join(cacheDir, "perf_ieee_pkir.exe");
402
+ const wasmBuf = await compileWasmArtifactFromObject(relation.object, {
351
403
  entry: "__main__",
352
- inputPattern,
353
- outputPath: arm64ExePath,
354
- optLevel: arm64OptLevel
404
+ usePKIR: true
355
405
  });
406
+ fs.writeFileSync(pkirPath, wasmBuf);
407
+ const runBin = fileURLToPath(import.meta.resolve("../backends/wasm/bin/k-wasm-run.mjs"));
408
+ fs.writeFileSync(pkirExePath, `#!/bin/sh\nexec node "${runBin}" "${pkirPath}" "$@"\n`, { mode: 0o755 });
356
409
  } catch (error) {
357
- arm64CompileError = error.stack || error.message || String(error);
358
- console.log("Linux ARM64 compilation failed:");
359
- console.log(arm64CompileError.split("\n").slice(0, 8).join("\n"));
410
+ pkirCompileError = error.stack || error.message || String(error);
411
+ console.log("PKIR compilation failed:");
412
+ console.log(pkirCompileError.split("\n").slice(0, 8).join("\n"));
360
413
  }
361
414
  }
362
415
 
@@ -369,12 +422,28 @@ function printBenchmarkDescription() {
369
422
  }
370
423
  if (runLLVM) {
371
424
  for (const opt of llvmOptLevels) {
372
- const mode = llvmLaneName().replace(/^LLVM Executable\\s*\\((.*)\\)$/, "$1");
373
- lanes.push(llvmOptLevels.length > 1 ? `LLVM ${opt} (${mode})` : llvmLaneName());
425
+ const mode = llvmLaneName()
426
+ .replace(/^LLVM Executable\s*\((.*)\)$/, "$1");
427
+ lanes.push(
428
+ llvmOptLevels.length > 1
429
+ ? `LLVM ${opt} (${mode})`
430
+ : llvmLaneName()
431
+ );
432
+ }
433
+ }
434
+ if (runLLVMPKIR) {
435
+ for (const opt of llvmOptLevels) {
436
+ const mode = llvmLaneName()
437
+ .replace(/^LLVM Executable\s*\((.*)\)$/, "$1");
438
+ lanes.push(
439
+ llvmOptLevels.length > 1
440
+ ? `LLVM-PKIR ${opt} (${mode})`
441
+ : llvmLaneName().replace("LLVM", "LLVM-PKIR")
442
+ );
374
443
  }
375
444
  }
376
445
  if (runWasm) lanes.push(wasmLaneName());
377
- if (runARM64) lanes.push(arm64LaneName(arm64OptLevel));
446
+ if (runPKIR) lanes.push(pkirLaneName());
378
447
 
379
448
  console.log("==> Benchmark description");
380
449
  console.log(" source: @fraczak/k/Examples/ieee.k#perf_ieee (single program)");
@@ -387,6 +456,11 @@ function printBenchmarkDescription() {
387
456
  console.log(` llvm clang opts: ${llvmOptLevels.join(", ")}`);
388
457
  console.log(` llvm cache dir: ${cacheDir}`);
389
458
  }
459
+ if (runLLVMPKIR) {
460
+ console.log(` llvm-pkir warmup iterations: ${llvmWarmupIterations}`);
461
+ console.log(` llvm-pkir runtime mode: ${llvmRuntimeMode}`);
462
+ console.log(` llvm-pkir clang opts: ${llvmOptLevels.join(", ")}`);
463
+ }
390
464
  if (runWasm) {
391
465
  console.log(` wasm runner mode: ${wasmPipe ? "persistent pipe" : "in-process"}`);
392
466
  console.log(` wasm warmup iterations: ${wasmWarmupIterations}`);
@@ -394,10 +468,8 @@ function printBenchmarkDescription() {
394
468
  console.log(` wasm arena reset: ${wasmReset ? "yes" : "no"}`);
395
469
  }
396
470
  }
397
- if (runARM64) {
398
- console.log(` arm64 warmup iterations: ${arm64WarmupIterations}`);
399
- console.log(` arm64 opt level: ${arm64OptLevel}`);
400
- console.log(` arm64 runner mode: ${process.env.ARM64_SPAWN_PER_CALL === "1" ? "spawn per call" : "persistent"}`);
471
+ if (runPKIR) {
472
+ console.log(` pkir warmup iterations: ${wasmWarmupIterations}`);
401
473
  }
402
474
  console.log(` iterations: ${iterations}`);
403
475
  console.log(` benchmark lanes: ${lanes.join("; ")}`);
@@ -459,6 +531,28 @@ if (runLLVM) {
459
531
  }
460
532
  }
461
533
 
534
+ // 2b. LLVM-PKIR lanes
535
+ const llvmPkirResults = new Map();
536
+ if (runLLVMPKIR) {
537
+ for (const opt of llvmOptLevels) {
538
+ const casesForOpt = llvmPkirCasesByOpt.get(opt);
539
+ const llvmRunner = createLLVMRunner(casesForOpt);
540
+ try {
541
+ if (llvmWarmupIterations > 0) {
542
+ console.log(`==> Warming LLVM-PKIR (${opt}) executable (${llvmWarmupIterations} iterations)...`);
543
+ await llvmRunner.run(llvmWarmupIterations);
544
+ }
545
+ console.log(`==> Running LLVM-PKIR (${opt}) (${iterations} iterations)...`);
546
+ const result = await llvmRunner.run(iterations);
547
+ llvmPkirResults.set(opt, result);
548
+ } catch (err) {
549
+ console.log(`==> LLVM-PKIR (${opt}) execution failed: ${err.message?.split("\n")[0]}`);
550
+ } finally {
551
+ llvmRunner.close();
552
+ }
553
+ }
554
+ }
555
+
462
556
  // 3. Wasm lane
463
557
  let wasmResult = null;
464
558
  if (runWasm) {
@@ -501,24 +595,25 @@ if (runWasm) {
501
595
  }
502
596
  }
503
597
 
504
- // 4. Linux ARM64 lane
505
- let arm64Result = null;
506
- if (runARM64 && arm64ExePath) {
507
- const arm64Runner = createARM64Runner([{
508
- op: "perf_ieee",
509
- inputWire,
510
- arm64: { status: "ok", exePath: arm64ExePath }
511
- }]);
512
- try {
513
- if (arm64WarmupIterations > 0) {
514
- console.log(`==> Warming Linux ARM64 (${arm64WarmupIterations} iterations)...`);
515
- await arm64Runner.run(arm64WarmupIterations);
598
+ // 4. PKIR lane
599
+ let pkirResult = null;
600
+ if (runPKIR) {
601
+ if (pkirExePath) {
602
+ const server = new PersistentExecutable(pkirExePath);
603
+ try {
604
+ if (wasmWarmupIterations > 0) {
605
+ console.log(`==> Warming PKIR (${wasmWarmupIterations} iterations)...`);
606
+ for (let i = 0; i < wasmWarmupIterations; i++) {
607
+ await server.request(inputWire);
608
+ }
609
+ }
610
+ console.log(`==> Running PKIR (${iterations} iterations)...`);
611
+ pkirResult = await runTimedIterationsAsync(iterations, async () => {
612
+ await server.request(inputWire);
613
+ });
614
+ } finally {
615
+ server.close();
516
616
  }
517
-
518
- console.log(`==> Running Linux ARM64 (${iterations} iterations)...`);
519
- arm64Result = await arm64Runner.run(iterations);
520
- } finally {
521
- arm64Runner.close();
522
617
  }
523
618
  }
524
619
 
@@ -534,19 +629,37 @@ if (runBaselines) {
534
629
  }
535
630
  if (runLLVM) {
536
631
  for (const opt of llvmOptLevels) {
632
+ const mode = llvmLaneName()
633
+ .replace(/^LLVM Executable\s*\((.*)\)$/, "$1");
537
634
  const title = llvmOptLevels.length > 1
538
- ? `LLVM ${opt} (${llvmLaneName().replace(/^LLVM Executable\\s*\\((.*)\\)$/, "$1")})`
635
+ ? `LLVM ${opt} (${mode})`
539
636
  : llvmLaneName();
540
- console.log(`${laneIndex++}. ${title.padEnd(29)} ${formatTiming(llvmResults.get(opt))}`);
637
+ console.log(
638
+ `${laneIndex++}. ${title.padEnd(29)} ` +
639
+ `${formatTiming(llvmResults.get(opt))}`
640
+ );
641
+ }
642
+ }
643
+ if (runLLVMPKIR) {
644
+ for (const opt of llvmOptLevels) {
645
+ const mode = llvmLaneName()
646
+ .replace(/^LLVM Executable\s*\((.*)\)$/, "$1");
647
+ const title = llvmOptLevels.length > 1
648
+ ? `LLVM-PKIR ${opt} (${mode})`
649
+ : llvmLaneName().replace("LLVM", "LLVM-PKIR");
650
+ console.log(
651
+ `${laneIndex++}. ${title.padEnd(29)} ` +
652
+ `${formatTiming(llvmPkirResults.get(opt))}`
653
+ );
541
654
  }
542
655
  }
543
656
  if (runWasm) {
544
657
  const timingStr = wasmResult ? formatTiming(wasmResult) : "compile failed";
545
658
  console.log(`${laneIndex++}. ${wasmLaneName().padEnd(29)} ${timingStr}`);
546
659
  }
547
- if (runARM64) {
548
- const timingStr = arm64Result ? formatTiming(arm64Result) : "compile failed";
549
- console.log(`${laneIndex++}. ${arm64LaneName(arm64OptLevel).padEnd(29)} ${timingStr}`);
660
+ if (runPKIR) {
661
+ const timingStr = pkirResult ? formatTiming(pkirResult) : "compile failed";
662
+ console.log(`${laneIndex++}. ${pkirLaneName().padEnd(29)} ${timingStr}`);
550
663
  }
551
664
  console.log("==============================================================\n");
552
665
 
@@ -585,6 +698,28 @@ if (runLLVM) {
585
698
  }
586
699
  }
587
700
 
701
+ if (runLLVMPKIR) {
702
+ for (const opt of llvmOptLevels) {
703
+ const casesForOpt = llvmPkirCasesByOpt.get(opt);
704
+ const tc = casesForOpt[0];
705
+ if (tc.llvm.status !== "ok") {
706
+ tc.llvmConformance = "compile-failed";
707
+ } else {
708
+ try {
709
+ const outputWire = await runExecutable(tc.llvm.exePath, tc.inputWire);
710
+ const actual = decodeWire(outputWire).value;
711
+ assert.deepEqual(toPlainObject(actual), toPlainObject(expected));
712
+ tc.llvmConformance = "ok";
713
+ } catch (error) {
714
+ tc.llvmConformance = "failed";
715
+ tc.llvm.error = error.stack || error.message || String(error);
716
+ console.log(`LLVM-PKIR (${opt}) conformance failure:`);
717
+ console.log(tc.llvm.error.split("\n").slice(0, 8).join("\n"));
718
+ }
719
+ }
720
+ }
721
+ }
722
+
588
723
  let wasmOk = false;
589
724
  if (runWasm) {
590
725
  if (wasmPipe) {
@@ -621,18 +756,18 @@ if (runWasm) {
621
756
  }
622
757
  }
623
758
 
624
- let arm64Ok = false;
625
- if (runARM64) {
626
- if (!arm64ExePath) {
627
- console.log("Linux ARM64 conformance failure: executable was not compiled");
759
+ let pkirOk = false;
760
+ if (runPKIR) {
761
+ if (!pkirExePath) {
762
+ console.log("PKIR conformance failure: executable was not compiled");
628
763
  } else {
629
764
  try {
630
- const outputWire = await runExecutable(arm64ExePath, inputWire);
765
+ const outputWire = await runExecutable(pkirExePath, inputWire);
631
766
  const actual = decodeWire(outputWire).value;
632
767
  assert.deepEqual(toPlainObject(actual), toPlainObject(expected));
633
- arm64Ok = true;
768
+ pkirOk = true;
634
769
  } catch (error) {
635
- console.log("Linux ARM64 conformance failure:", error.message || error);
770
+ console.log("PKIR conformance failure:", error.message || error);
636
771
  }
637
772
  }
638
773
  }
@@ -646,11 +781,20 @@ if (runLLVM) {
646
781
  validationSummary.push(`LLVM ${opt} (${tc.llvmConformance === "ok" ? `all ${totalOps} ops` : tc.llvmConformance})`);
647
782
  }
648
783
  }
784
+ if (runLLVMPKIR) {
785
+ for (const opt of llvmOptLevels) {
786
+ const casesForOpt = llvmPkirCasesByOpt.get(opt);
787
+ const tc = casesForOpt[0];
788
+ validationSummary.push(
789
+ `LLVM-PKIR ${opt} (${tc.llvmConformance === "ok" ? `all ${totalOps} ops` : tc.llvmConformance})`
790
+ );
791
+ }
792
+ }
649
793
  if (runWasm) {
650
794
  validationSummary.push(`Wasm (${wasmOk ? `all ${totalOps} ops` : "failed"})`);
651
795
  }
652
- if (runARM64) {
653
- validationSummary.push(`Linux ARM64 (${arm64Ok ? `all ${totalOps} ops` : "failed"})`);
796
+ if (runPKIR) {
797
+ validationSummary.push(`PKIR (${pkirOk ? `all ${totalOps} ops` : "failed"})`);
654
798
  }
655
799
 
656
800
  console.log(`Conformance validation: ${validationSummary.join(", ")} match expected values.`);
@@ -660,5 +804,11 @@ if (runLLVM) {
660
804
  if (shouldStrictFail(casesForOpt)) process.exitCode = 1;
661
805
  }
662
806
  }
807
+ if (runLLVMPKIR) {
808
+ for (const opt of llvmOptLevels) {
809
+ const casesForOpt = llvmPkirCasesByOpt.get(opt);
810
+ if (shouldStrictFail(casesForOpt)) process.exitCode = 1;
811
+ }
812
+ }
663
813
  if (runWasm && !wasmOk) process.exitCode = 1;
664
- if (runARM64 && !arm64Ok) process.exitCode = 1;
814
+ if (runPKIR && !pkirOk) process.exitCode = 1;