@fraczak/k 6.5.0 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backends/arm64/README.md +0 -1
- package/backends/arm64/bin/k-arm64-compile.mjs +0 -8
- package/backends/arm64/src/runtime.c +20 -4
- package/backends/arm64/tests/integration.sh +1 -1
- package/backends/llvm/README.md +13 -11
- package/backends/llvm/bin/k-llvm-build.mjs +40 -38
- package/backends/llvm/bin/k-llvm-compile.mjs +42 -32
- package/backends/llvm/runtime/krt.c +387 -2
- package/backends/llvm/runtime/krt.h +1 -0
- package/backends/llvm/src/cli.mjs +153 -0
- package/backends/llvm/src/executable.mjs +1 -1
- package/backends/llvm/src/kvm2llvm.mjs +109 -30
- package/backends/llvm/tests/integration.sh +18 -22
- package/backends/llvm/tests/perf-support.mjs +1 -1
- package/backends/wasm/bin/k-wasm-compile.mjs +19 -4
- package/browser/repl-browser.mjs +24 -7
- package/browser/tree-view.mjs +599 -0
- package/package.json +1 -1
- package/repl.mjs +4 -0
- package/scripts/build-repl-html.mjs +301 -0
- package/scripts/perf-ieee.mjs +5 -2
- package/scripts/perf-int.mjs +331 -0
- package/scripts/run-tests.mjs +1 -0
- package/tests/test-repl-html.mjs +141 -0
- package/tests/test-tree-view.mjs +185 -0
|
@@ -53,6 +53,7 @@ export function runtimeDeclarations() {
|
|
|
53
53
|
"",
|
|
54
54
|
"declare %k_rt_mark @k_rt_mark(ptr)",
|
|
55
55
|
"declare void @k_rt_rewind(ptr, %k_rt_mark)",
|
|
56
|
+
"declare ptr @k_rt_compact(ptr, ptr, ptr)",
|
|
56
57
|
"declare ptr @k_rt_alloc(ptr, i64)",
|
|
57
58
|
"declare ptr @k_unit(ptr)",
|
|
58
59
|
"declare ptr @k_bit0(ptr)",
|
|
@@ -146,10 +147,11 @@ function lowerRawVariant(ctx, tag, payload) {
|
|
|
146
147
|
return variant;
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
function lowerProductGetAt(ctx, input, edgeIndex) {
|
|
150
|
+
function lowerProductGetAt(ctx, input, edgeIndex, label = null) {
|
|
150
151
|
const nonNullBlock = ctx.blockName("product_non_null");
|
|
151
152
|
const productBlock = ctx.blockName("product_kind");
|
|
152
153
|
const fieldBlock = ctx.blockName("product_field");
|
|
154
|
+
const fallbackBlock = ctx.blockName("product_fallback");
|
|
153
155
|
const missingBlock = ctx.blockName("product_missing");
|
|
154
156
|
const doneBlock = ctx.blockName("product_done");
|
|
155
157
|
const isMissing = ctx.tempName("product_is_missing");
|
|
@@ -172,16 +174,38 @@ function lowerProductGetAt(ctx, input, edgeIndex) {
|
|
|
172
174
|
const fields = loadPtrAt(ctx, input, K_VALUE_PRODUCT_FIELDS_OFFSET, "product_fields_ptr");
|
|
173
175
|
const slot = bytePtr(ctx, fields, edgeIndex * K_FIELD_SIZE, "field_slot");
|
|
174
176
|
const value = loadPtrAt(ctx, slot, K_FIELD_VALUE_OFFSET, "field");
|
|
175
|
-
ctx.lines.push(` br label %${doneBlock}`);
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
if (label) {
|
|
179
|
+
const fLabel = loadPtrAt(ctx, slot, K_FIELD_LABEL_OFFSET, "field_label");
|
|
180
|
+
const labelMatch = ctx.tempName("label_match");
|
|
181
|
+
ctx.lines.push(` ${labelMatch} = icmp eq ptr ${fLabel}, ${label.pointer}`);
|
|
182
|
+
ctx.lines.push(` br i1 ${labelMatch}, label %${doneBlock}, label %${fallbackBlock}`);
|
|
183
|
+
|
|
184
|
+
ctx.lines.push(`${fallbackBlock}:`);
|
|
185
|
+
const fallbackVal = ctx.tempName("fallback_field");
|
|
186
|
+
ctx.lines.push(` ${fallbackVal} = call ptr @k_product_get_n(ptr ${input}, ptr ${label.pointer}, i64 ${label.length})`);
|
|
187
|
+
ctx.lines.push(` br label %${doneBlock}`);
|
|
188
|
+
|
|
189
|
+
ctx.lines.push(`${missingBlock}:`);
|
|
190
|
+
ctx.lines.push(` br label %${doneBlock}`);
|
|
191
|
+
|
|
192
|
+
ctx.lines.push(`${doneBlock}:`);
|
|
193
|
+
const resultValue = ctx.tempName("field_value");
|
|
194
|
+
ctx.lines.push(` ${resultValue} = phi ptr [${value}, %${fieldBlock}], [${fallbackVal}, %${fallbackBlock}], [null, %${missingBlock}]`);
|
|
195
|
+
ctx.currentBlock = doneBlock;
|
|
196
|
+
return resultValue;
|
|
197
|
+
} else {
|
|
198
|
+
ctx.lines.push(` br label %${doneBlock}`);
|
|
179
199
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
ctx.lines.push(`${missingBlock}:`);
|
|
201
|
+
ctx.lines.push(` br label %${doneBlock}`);
|
|
202
|
+
|
|
203
|
+
ctx.lines.push(`${doneBlock}:`);
|
|
204
|
+
const resultValue = ctx.tempName("field_value");
|
|
205
|
+
ctx.lines.push(` ${resultValue} = phi ptr [${value}, %${fieldBlock}], [null, %${missingBlock}]`);
|
|
206
|
+
ctx.currentBlock = doneBlock;
|
|
207
|
+
return resultValue;
|
|
208
|
+
}
|
|
185
209
|
}
|
|
186
210
|
|
|
187
211
|
function lowerVariantMatchBranch(ctx, input, label, matchBlock, mismatchBlock) {
|
|
@@ -287,6 +311,56 @@ function lowerRtRewind(ctx, mark) {
|
|
|
287
311
|
ctx.currentBlock = doneBlock;
|
|
288
312
|
}
|
|
289
313
|
|
|
314
|
+
function lowerRtCompact(ctx, val, tailMarkSlot = "%tail_mark_slot") {
|
|
315
|
+
const curBlock = loadPtrAt(ctx, "%rt", K_RT_BLOCKS_OFFSET, "cur_block");
|
|
316
|
+
const hasBlock = ctx.tempName("has_block");
|
|
317
|
+
const markBlockPtr = ctx.tempName("mark_block_ptr");
|
|
318
|
+
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
|
+
const markBlock = ctx.tempName("mark_block");
|
|
321
|
+
ctx.lines.push(` ${markBlock} = load ptr, ptr ${markBlockPtr}`);
|
|
322
|
+
|
|
323
|
+
const diffBlock = ctx.tempName("diff_block");
|
|
324
|
+
ctx.lines.push(` ${diffBlock} = icmp ne ptr ${curBlock}, ${markBlock}`);
|
|
325
|
+
const needCheck = ctx.tempName("need_growth_check");
|
|
326
|
+
ctx.lines.push(` ${needCheck} = and i1 ${hasBlock}, ${diffBlock}`);
|
|
327
|
+
|
|
328
|
+
const checkGrowthBlock = ctx.blockName("check_growth");
|
|
329
|
+
const doCompactBlock = ctx.blockName("do_compact");
|
|
330
|
+
const doneBlock = ctx.blockName("compact_done");
|
|
331
|
+
|
|
332
|
+
ctx.lines.push(` br i1 ${needCheck}, label %${doCompactBlock}, label %${checkGrowthBlock}`);
|
|
333
|
+
|
|
334
|
+
ctx.lines.push(`${checkGrowthBlock}:`);
|
|
335
|
+
const checkBlockHasBlock = ctx.tempName("check_has_block");
|
|
336
|
+
ctx.lines.push(` ${checkBlockHasBlock} = icmp ne ptr ${curBlock}, null`);
|
|
337
|
+
const loadGrowthBlock = ctx.blockName("load_growth");
|
|
338
|
+
ctx.lines.push(` br i1 ${checkBlockHasBlock}, label %${loadGrowthBlock}, label %${doneBlock}`);
|
|
339
|
+
|
|
340
|
+
ctx.lines.push(`${loadGrowthBlock}:`);
|
|
341
|
+
const curUsed = loadI64At(ctx, curBlock, K_ARENA_BLOCK_USED_OFFSET, "cur_used");
|
|
342
|
+
const markUsedPtr = ctx.tempName("mark_used_ptr");
|
|
343
|
+
ctx.lines.push(` ${markUsedPtr} = getelementptr inbounds %k_rt_mark, ptr ${tailMarkSlot}, i32 0, i32 1`);
|
|
344
|
+
const markUsed = ctx.tempName("mark_used");
|
|
345
|
+
ctx.lines.push(` ${markUsed} = load i64, ptr ${markUsedPtr}`);
|
|
346
|
+
const growth = ctx.tempName("arena_growth");
|
|
347
|
+
ctx.lines.push(` ${growth} = sub i64 ${curUsed}, ${markUsed}`);
|
|
348
|
+
const threshExceeded = ctx.tempName("thresh_exceeded");
|
|
349
|
+
ctx.lines.push(` ${threshExceeded} = icmp ugt i64 ${growth}, 4194304`);
|
|
350
|
+
ctx.lines.push(` br i1 ${threshExceeded}, label %${doCompactBlock}, label %${doneBlock}`);
|
|
351
|
+
|
|
352
|
+
ctx.lines.push(`${doCompactBlock}:`);
|
|
353
|
+
const compacted = ctx.tempName("compacted");
|
|
354
|
+
ctx.lines.push(` ${compacted} = call ptr @k_rt_compact(ptr %rt, ptr ${val}, ptr ${tailMarkSlot})`);
|
|
355
|
+
ctx.lines.push(` br label %${doneBlock}`);
|
|
356
|
+
|
|
357
|
+
ctx.lines.push(`${doneBlock}:`);
|
|
358
|
+
const finalVal = ctx.tempName("compact_res");
|
|
359
|
+
ctx.lines.push(` ${finalVal} = phi ptr [${val}, %${checkGrowthBlock}], [${val}, %${loadGrowthBlock}], [${compacted}, %${doCompactBlock}]`);
|
|
360
|
+
ctx.currentBlock = doneBlock;
|
|
361
|
+
return finalVal;
|
|
362
|
+
}
|
|
363
|
+
|
|
290
364
|
function nullCheck(ctx, val, failTarget) {
|
|
291
365
|
const isMissing = ctx.tempName("missing");
|
|
292
366
|
const okBlock = ctx.blockName("nonnull");
|
|
@@ -322,7 +396,8 @@ function statusCheck(ctx, callResult, failTarget = "func_fail") {
|
|
|
322
396
|
if (ctx.catchTail) {
|
|
323
397
|
const tailInput = ctx.tempName("tail_arg");
|
|
324
398
|
ctx.lines.push(` ${tailInput} = extractvalue %k_result ${callResult}, 1`);
|
|
325
|
-
ctx
|
|
399
|
+
const compacted = lowerRtCompact(ctx, tailInput, "%tail_mark_slot");
|
|
400
|
+
ctx.lines.push(` store ptr ${compacted}, ptr %tail_input_slot`);
|
|
326
401
|
ctx.lines.push(" br label %tail_loop");
|
|
327
402
|
} else {
|
|
328
403
|
ctx.lines.push(` ret %k_result ${callResult}`);
|
|
@@ -366,8 +441,7 @@ function hasSelfTailCall(insts, funcName, isTail = true) {
|
|
|
366
441
|
if (inst.branches) {
|
|
367
442
|
const unionIsTail = isTail && tailValueAfter(insts, i + 1, inst.dest);
|
|
368
443
|
for (let bIdx = 0; bIdx < inst.branches.length; bIdx++) {
|
|
369
|
-
|
|
370
|
-
if (hasSelfTailCall(inst.branches[bIdx].body, funcName, unionIsTail && isLast)) return true;
|
|
444
|
+
if (hasSelfTailCall(inst.branches[bIdx].body, funcName, unionIsTail)) return true;
|
|
371
445
|
}
|
|
372
446
|
}
|
|
373
447
|
}
|
|
@@ -384,13 +458,6 @@ function getFieldEdgeIndex(inst, regPatterns, kvmFunc) {
|
|
|
384
458
|
if (idx >= 0) return idx;
|
|
385
459
|
}
|
|
386
460
|
}
|
|
387
|
-
if (Array.isArray(inst.pattern) && inst.pattern.length > 0) {
|
|
388
|
-
const root = inst.pattern[0];
|
|
389
|
-
if ((root[0] === "open-product" || root[0] === "closed-product") && Array.isArray(root[1])) {
|
|
390
|
-
const idx = root[1].findIndex(([l]) => l === inst.label);
|
|
391
|
-
if (idx >= 0) return idx;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
461
|
return -1;
|
|
395
462
|
}
|
|
396
463
|
|
|
@@ -538,7 +605,11 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
538
605
|
|
|
539
606
|
if (isCatchTail) {
|
|
540
607
|
ctx.allocas.push(" %tail_input_slot = alloca ptr");
|
|
608
|
+
ctx.allocas.push(" %tail_mark_slot = alloca %k_rt_mark");
|
|
541
609
|
ctx.lines.push(" store ptr %input, ptr %tail_input_slot");
|
|
610
|
+
const initMark = ctx.tempName("init_mark");
|
|
611
|
+
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`);
|
|
542
613
|
ctx.lines.push(" br label %tail_loop");
|
|
543
614
|
ctx.lines.push("tail_loop:");
|
|
544
615
|
ctx.lines.push(" %tail_input = load ptr, ptr %tail_input_slot");
|
|
@@ -598,17 +669,13 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
598
669
|
const input = getReg(inst.src);
|
|
599
670
|
nullCheck(ctx, input, failTarget);
|
|
600
671
|
const edgeIndex = getFieldEdgeIndex(inst, regPatterns, kvmFunc);
|
|
672
|
+
const label = ctx.labelRef(inst.label);
|
|
601
673
|
let val;
|
|
602
674
|
if (edgeIndex >= 0 && ctx.runtimeMode !== "compact") {
|
|
603
|
-
val = lowerProductGetAt(ctx, input, edgeIndex);
|
|
675
|
+
val = lowerProductGetAt(ctx, input, edgeIndex, label);
|
|
604
676
|
} else {
|
|
605
|
-
const label = ctx.labelRef(inst.label);
|
|
606
677
|
val = ctx.tempName("field");
|
|
607
|
-
|
|
608
|
-
ctx.lines.push(` ${val} = call ptr @k_product_get_at(ptr ${input}, i64 ${edgeIndex})`);
|
|
609
|
-
} else {
|
|
610
|
-
ctx.lines.push(` ${val} = call ptr @k_product_get_n(ptr ${input}, ptr ${label.pointer}, i64 ${label.length})`);
|
|
611
|
-
}
|
|
678
|
+
ctx.lines.push(` ${val} = call ptr @k_product_get_n(ptr ${input}, ptr ${label.pointer}, i64 ${label.length})`);
|
|
612
679
|
}
|
|
613
680
|
nullCheck(ctx, val, failTarget);
|
|
614
681
|
regValues.set(cleanReg(inst.dest), val);
|
|
@@ -656,7 +723,8 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
656
723
|
const v = getReg(inst.src);
|
|
657
724
|
if (isSelfTailCall(insts, i, tailRef)) {
|
|
658
725
|
if (ctx.catchTail) {
|
|
659
|
-
ctx
|
|
726
|
+
const compacted = lowerRtCompact(ctx, v, "%tail_mark_slot");
|
|
727
|
+
ctx.lines.push(` store ptr ${compacted}, ptr %tail_input_slot`);
|
|
660
728
|
ctx.lines.push(" br label %tail_loop");
|
|
661
729
|
return;
|
|
662
730
|
} else {
|
|
@@ -689,6 +757,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
689
757
|
const fieldValues = [];
|
|
690
758
|
const pSrc = getReg(inst.src);
|
|
691
759
|
const pPattern = regPatterns.get(cleanReg(inst.src)) || (cleanReg(inst.src) === "in" ? regPatterns.get("in") : null);
|
|
760
|
+
let productFailed = false;
|
|
692
761
|
|
|
693
762
|
for (let bIdx = 0; bIdx < N; bIdx++) {
|
|
694
763
|
const branch = inst.branches[bIdx];
|
|
@@ -715,12 +784,21 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
715
784
|
nextBlock: branchDone
|
|
716
785
|
});
|
|
717
786
|
|
|
787
|
+
if (!branchRegValues.has(cleanReg(branchRes))) {
|
|
788
|
+
productFailed = true;
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
791
|
+
|
|
718
792
|
ctx.lines.push(`${branchDone}:`);
|
|
719
793
|
ctx.currentBlock = branchDone;
|
|
720
|
-
const fVal = branchRegValues.get(cleanReg(branchRes))
|
|
794
|
+
const fVal = branchRegValues.get(cleanReg(branchRes));
|
|
721
795
|
fieldValues.push({ label: branch.label, val: fVal });
|
|
722
796
|
}
|
|
723
797
|
|
|
798
|
+
if (productFailed) {
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
801
|
+
|
|
724
802
|
const requestedSize = K_PRODUCT_HEADER_SIZE + (K_FIELD_SIZE * N);
|
|
725
803
|
const product = lowerRawAlloc(ctx, requestedSize, alignArenaSize(requestedSize));
|
|
726
804
|
nullCheck(ctx, product, failTarget);
|
|
@@ -796,7 +874,7 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
796
874
|
outputPattern: kvmFunc.outputPattern,
|
|
797
875
|
body: branch.body
|
|
798
876
|
};
|
|
799
|
-
const armTailRef =
|
|
877
|
+
const armTailRef = tailValueAfter(insts, i + 1, inst.dest) ? tailRef : null;
|
|
800
878
|
const armBody = lowerKVMFunction(armFunc, armName, armFunc.name, moduleCtx, "internal", { ...options, tailRef: armTailRef });
|
|
801
879
|
moduleCtx.syntheticFunctions.push(armBody);
|
|
802
880
|
|
|
@@ -818,7 +896,8 @@ function lowerKVMFunction(kvmFunc, symbol, funcName, moduleCtx, linkage = "", op
|
|
|
818
896
|
if (ctx.catchTail) {
|
|
819
897
|
const tailArg = ctx.tempName("arm_tail_arg");
|
|
820
898
|
ctx.lines.push(` ${tailArg} = extractvalue %k_result ${armCall}, 1`);
|
|
821
|
-
ctx
|
|
899
|
+
const compacted = lowerRtCompact(ctx, tailArg, "%tail_mark_slot");
|
|
900
|
+
ctx.lines.push(` store ptr ${compacted}, ptr %tail_input_slot`);
|
|
822
901
|
ctx.lines.push(" br label %tail_loop");
|
|
823
902
|
} else {
|
|
824
903
|
ctx.lines.push(` ret %k_result ${armCall}`);
|
|
@@ -10,8 +10,7 @@ command -v clang >/dev/null || {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
node ../../objects/compile.mjs '()' "$TMP_DIR/id.ko"
|
|
13
|
-
|
|
14
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/input.pattern.json" "$TMP_DIR/id.ko" "$TMP_DIR/id.ll"
|
|
13
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/id.ko" "$TMP_DIR/id.ll"
|
|
15
14
|
grep -q '@k_llvm_metadata' "$TMP_DIR/id.ll"
|
|
16
15
|
grep -q 'define %k_result @k_main' "$TMP_DIR/id.ll"
|
|
17
16
|
|
|
@@ -19,32 +18,28 @@ clang -Wno-override-module -Iruntime runtime/krt.c tests/identity-driver.c "$TMP
|
|
|
19
18
|
"$TMP_DIR/id"
|
|
20
19
|
|
|
21
20
|
node ../../objects/compile.mjs '.x' "$TMP_DIR/projection.ko"
|
|
22
|
-
|
|
23
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/projection.pattern.json" "$TMP_DIR/projection.ko" "$TMP_DIR/projection.ll"
|
|
21
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/projection.ko" "$TMP_DIR/projection.ll"
|
|
24
22
|
grep -q 'product_fields_ptr' "$TMP_DIR/projection.ll"
|
|
25
23
|
! grep -q 'call ptr @k_product_get_at' "$TMP_DIR/projection.ll"
|
|
26
24
|
clang -Wno-override-module -Iruntime runtime/krt.c tests/projection-driver.c "$TMP_DIR/projection.ll" -o "$TMP_DIR/projection"
|
|
27
25
|
"$TMP_DIR/projection"
|
|
28
26
|
|
|
29
27
|
node ../../objects/compile.mjs '{ .x fieldA, .y fieldB }' "$TMP_DIR/product.ko"
|
|
30
|
-
|
|
31
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/product.pattern.json" "$TMP_DIR/product.ko" "$TMP_DIR/product.ll"
|
|
28
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/product.ko" "$TMP_DIR/product.ll"
|
|
32
29
|
grep -q 'store i32 1, ptr %i32_slot' "$TMP_DIR/product.ll"
|
|
33
30
|
grep -q 'store ptr %product_fields' "$TMP_DIR/product.ll"
|
|
34
31
|
clang -Wno-override-module -Iruntime runtime/krt.c tests/product-driver.c "$TMP_DIR/product.ll" -o "$TMP_DIR/product"
|
|
35
32
|
"$TMP_DIR/product"
|
|
36
33
|
|
|
37
34
|
node ../../objects/compile.mjs '|tag' "$TMP_DIR/variant.ko"
|
|
38
|
-
|
|
39
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/variant.pattern.json" "$TMP_DIR/variant.ko" "$TMP_DIR/variant.ll"
|
|
35
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/variant.ko" "$TMP_DIR/variant.ll"
|
|
40
36
|
grep -q 'call ptr @k_rt_alloc' "$TMP_DIR/variant.ll"
|
|
41
37
|
grep -q 'store i32 2, ptr %i32_slot' "$TMP_DIR/variant.ll"
|
|
42
38
|
clang -Wno-override-module -Iruntime runtime/krt.c tests/variant-driver.c "$TMP_DIR/variant.ll" -o "$TMP_DIR/variant"
|
|
43
39
|
"$TMP_DIR/variant"
|
|
44
40
|
|
|
45
41
|
node ../../objects/compile.mjs '/tag' "$TMP_DIR/variant-projection.ko"
|
|
46
|
-
|
|
47
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/variant-projection.pattern.json" "$TMP_DIR/variant-projection.ko" "$TMP_DIR/variant-projection.ll"
|
|
42
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/variant-projection.ko" "$TMP_DIR/variant-projection.ll"
|
|
48
43
|
grep -q 'tag_byte_ptr' "$TMP_DIR/variant-projection.ll"
|
|
49
44
|
grep -q 'payload_slot' "$TMP_DIR/variant-projection.ll"
|
|
50
45
|
! grep -q 'call i32 @k_variant_tag_matches' "$TMP_DIR/variant-projection.ll"
|
|
@@ -53,24 +48,21 @@ clang -Wno-override-module -Iruntime runtime/krt.c tests/variant-projection-driv
|
|
|
53
48
|
"$TMP_DIR/variant-projection"
|
|
54
49
|
|
|
55
50
|
node ../../objects/compile.mjs '(.x .y)' "$TMP_DIR/composition.ko"
|
|
56
|
-
|
|
57
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/composition.pattern.json" "$TMP_DIR/composition.ko" "$TMP_DIR/composition.ll"
|
|
51
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/composition.ko" "$TMP_DIR/composition.ll"
|
|
58
52
|
grep -q 'product_fields_ptr' "$TMP_DIR/composition.ll"
|
|
59
53
|
! grep -q 'call ptr @k_product_get_at' "$TMP_DIR/composition.ll"
|
|
60
54
|
clang -Wno-override-module -Iruntime runtime/krt.c tests/composition-driver.c "$TMP_DIR/composition.ll" -o "$TMP_DIR/composition"
|
|
61
55
|
"$TMP_DIR/composition"
|
|
62
56
|
|
|
63
57
|
node ../../objects/compile.mjs 'pick = .x; {.a pick left, .b pick right}' "$TMP_DIR/relation.ko"
|
|
64
|
-
|
|
65
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/relation.pattern.json" "$TMP_DIR/relation.ko" "$TMP_DIR/relation.ll"
|
|
58
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/relation.ko" "$TMP_DIR/relation.ll"
|
|
66
59
|
grep -q 'define internal %k_result @k_rel_pick' "$TMP_DIR/relation.ll"
|
|
67
60
|
grep -q 'call %k_result @k_rel_pick' "$TMP_DIR/relation.ll"
|
|
68
61
|
clang -Wno-override-module -Iruntime runtime/krt.c tests/relation-driver.c "$TMP_DIR/relation.ll" -o "$TMP_DIR/relation"
|
|
69
62
|
"$TMP_DIR/relation"
|
|
70
63
|
|
|
71
64
|
node ../../objects/compile.mjs '< /x |left, /y |right >' "$TMP_DIR/union.ko"
|
|
72
|
-
|
|
73
|
-
node ./bin/k-llvm-compile.mjs --input-pattern "$TMP_DIR/union.pattern.json" "$TMP_DIR/union.ko" "$TMP_DIR/union.ll"
|
|
65
|
+
node ./bin/k-llvm-compile.mjs "$TMP_DIR/union.ko" "$TMP_DIR/union.ll"
|
|
74
66
|
grep -q 'define internal %k_result @k_union_arm_0' "$TMP_DIR/union.ll"
|
|
75
67
|
grep -q 'call %k_result @k_union_arm_1' "$TMP_DIR/union.ll"
|
|
76
68
|
clang -Wno-override-module -Iruntime runtime/krt.c tests/union-driver.c "$TMP_DIR/union.ll" -o "$TMP_DIR/union"
|
|
@@ -94,8 +86,7 @@ node ../../objects/compile.mjs '{ .x fieldA, .y fieldB }' "$TMP_DIR/run-product.
|
|
|
94
86
|
printf '{"x":"left","y":"right"}' > "$TMP_DIR/run-product-input.kv"
|
|
95
87
|
node ./bin/k-llvm-run.mjs "$TMP_DIR/run-product.ko" "$TMP_DIR/run-product-input.kv" | grep -qx '{"fieldA":"left","fieldB":"right"}'
|
|
96
88
|
|
|
97
|
-
|
|
98
|
-
node ./bin/k-llvm-build.mjs --input-pattern "$TMP_DIR/run-envelope.pattern.json" "$TMP_DIR/run.ko" "$TMP_DIR/run-exe"
|
|
89
|
+
node ./bin/k-llvm-build.mjs '?{<{}=X0 left, ...> x, <X0 right, ...> y} .x' -o "$TMP_DIR/run-exe"
|
|
99
90
|
printf '{"x":"left","y":"right"}' \
|
|
100
91
|
| node ../../codecs/k-parse.mjs \
|
|
101
92
|
| "$TMP_DIR/run-exe" \
|
|
@@ -104,15 +95,13 @@ printf '{"x":"left","y":"right"}' \
|
|
|
104
95
|
|
|
105
96
|
printf '{"x":"left"}' | node ../../codecs/k-parse.mjs | "$TMP_DIR/run-exe" && exit 1 || test "$?" -eq 5
|
|
106
97
|
|
|
107
|
-
|
|
108
|
-
node ./bin/k-llvm-build.mjs --input-pattern "$TMP_DIR/identity-variant.pattern.json" "$TMP_DIR/id.ko" "$TMP_DIR/id-exe"
|
|
98
|
+
node ./bin/k-llvm-build.mjs '?<{} left, {} right, ...>' -o "$TMP_DIR/id-exe"
|
|
109
99
|
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));" \
|
|
110
100
|
| "$TMP_DIR/id-exe" \
|
|
111
101
|
| node --input-type=module -e "import { stdin } from 'node:process'; import { decodeWire } from '../../codecs/runtime/prefix-codec.mjs'; const chunks = []; stdin.on('data', (chunk) => chunks.push(chunk)); stdin.on('end', () => console.log(JSON.stringify(decodeWire(Buffer.concat(chunks)).pattern)));" \
|
|
112
102
|
| grep -Fqx '[["open-union",[["left",1],["right",1]]],["closed-product",[]]]'
|
|
113
103
|
|
|
114
|
-
|
|
115
|
-
node ./bin/k-llvm-build.mjs --input-pattern "$TMP_DIR/identity-int.pattern.json" "$TMP_DIR/id.ko" "$TMP_DIR/id-int-exe"
|
|
104
|
+
node ./bin/k-llvm-build.mjs '$bits = < {} _, bits 0, bits 1 >; $int = < bits "+", bits "-" >; $int' -o "$TMP_DIR/id-int-exe"
|
|
116
105
|
printf '2' \
|
|
117
106
|
| node ../../codecs/int.mjs --parse \
|
|
118
107
|
| "$TMP_DIR/id-int-exe" \
|
|
@@ -121,6 +110,13 @@ printf '2' \
|
|
|
121
110
|
|
|
122
111
|
node --input-type=module -e "import assert from 'node:assert/strict'; import { spawn } from 'node:child_process'; import { encodeToWire, decodeWire } from '../../codecs/runtime/prefix-codec.mjs'; import { parse, INT_PATTERN } from '../../codecs/int.mjs'; const input = encodeToWire(parse('2'), INT_PATTERN); const header = Buffer.alloc(4); header.writeUInt32BE(input.length); const child = spawn(process.argv[1], ['--server']); const chunks = []; const stderr = []; child.stdout.on('data', (chunk) => chunks.push(chunk)); child.stderr.on('data', (chunk) => stderr.push(chunk)); child.stdin.end(Buffer.concat([header, input])); const status = await new Promise((resolve, reject) => { child.on('error', reject); child.on('close', resolve); }); assert.equal(status, 0, Buffer.concat(stderr).toString('utf8')); const output = Buffer.concat(chunks); const length = output.readUInt32BE(0); assert.equal(output.length, 4 + length); assert.deepEqual(decodeWire(output.subarray(4)).value.toJSON(), parse('2').toJSON());" "$TMP_DIR/id-int-exe"
|
|
123
112
|
|
|
113
|
+
node ./bin/k-llvm-build.mjs --lib ../../Examples/arithmetics.k --export times 's = {()x, ()y} times; s' -o "$TMP_DIR/square-exe"
|
|
114
|
+
printf '987654321' \
|
|
115
|
+
| node ../../codecs/int.mjs --parse \
|
|
116
|
+
| "$TMP_DIR/square-exe" \
|
|
117
|
+
| node ../../codecs/int.mjs --print \
|
|
118
|
+
| grep -qx '975461057789971041'
|
|
119
|
+
|
|
124
120
|
printf '{"x":"left","y":"right"}' \
|
|
125
121
|
| node ../../codecs/k-parse.mjs \
|
|
126
122
|
| node ./bin/k-llvm-jit.mjs --cache-dir "$TMP_DIR/jit-cache" "$TMP_DIR/run.ko" \
|
|
@@ -33,7 +33,7 @@ function sha256(text) {
|
|
|
33
33
|
function backendFingerprint() {
|
|
34
34
|
if (cachedBackendFingerprint != null) return cachedBackendFingerprint;
|
|
35
35
|
const hash = crypto.createHash("sha256");
|
|
36
|
-
for (const relPath of ["src/llvm.mjs", "src/executable.mjs", "runtime/krt.c", "runtime/krt.h"]) {
|
|
36
|
+
for (const relPath of ["src/llvm.mjs", "src/kvm2llvm.mjs", "src/executable.mjs", "runtime/krt.c", "runtime/krt.h"]) {
|
|
37
37
|
hash.update(relPath);
|
|
38
38
|
hash.update("\0");
|
|
39
39
|
hash.update(fs.readFileSync(path.join(root, relPath)));
|
|
@@ -20,6 +20,7 @@ function usage(stream = console.error) {
|
|
|
20
20
|
stream(" wasm-file Output .wasm path. Writes the binary artifact to stdout when omitted.");
|
|
21
21
|
stream("");
|
|
22
22
|
stream("Options:");
|
|
23
|
+
stream(" -o, --output Specify output file path explicitly.");
|
|
23
24
|
stream(" --lib file Load one .klib dependency before compiling.");
|
|
24
25
|
stream(" --export spec Export a library alias into source scope. May be repeated.");
|
|
25
26
|
stream(" spec is 'name' or 'libname:localname'.");
|
|
@@ -33,10 +34,24 @@ try {
|
|
|
33
34
|
exit(0);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
let explicitOutput = null;
|
|
38
|
+
const remainingArgs = [];
|
|
39
|
+
while (args.length > 0) {
|
|
40
|
+
const arg = args[0];
|
|
41
|
+
if (arg === "-o" || arg === "--output") {
|
|
42
|
+
args.shift();
|
|
43
|
+
explicitOutput = args.shift();
|
|
44
|
+
if (!explicitOutput) throw new Error("-o/--output requires a file argument");
|
|
45
|
+
} else {
|
|
46
|
+
remainingArgs.push(args.shift());
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { libraries, exportSpecs } = parseCompileOptions(remainingArgs);
|
|
51
|
+
const input = resolveProgramInput(remainingArgs, { allowStdinSource: true });
|
|
52
|
+
const positionalOutput = remainingArgs.shift();
|
|
53
|
+
if (remainingArgs.length > 0) throw new Error("Too many arguments");
|
|
54
|
+
const outputPath = explicitOutput || positionalOutput || null;
|
|
40
55
|
const artifact = await compileProgramInput(input, { libraries, exportSpecs, stdin });
|
|
41
56
|
if (outputPath == null) {
|
|
42
57
|
stdout.write(artifact);
|
package/browser/repl-browser.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import { Value, isProduct, isVariant } from "../Value.mjs";
|
|
21
21
|
import { encodeLibrary } from "../object.mjs";
|
|
22
22
|
import { setVfsFile, getVfsFile, getAllVfsFiles } from "./shims/fs.mjs";
|
|
23
|
+
import { createOutputEntryElement } from "./tree-view.mjs";
|
|
23
24
|
|
|
24
25
|
// Make Value and helpers globally available for custom codecs
|
|
25
26
|
if (typeof window !== "undefined") {
|
|
@@ -155,7 +156,7 @@ function setStatus(busy, text = "Ready") {
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
function appendEntry({ prompt, command, outputs = [], errors = [], warnings = [], duration = null, timing = null }) {
|
|
159
|
+
function appendEntry({ prompt, command, outputs = [], errors = [], warnings = [], duration = null, timing = null, value = null }) {
|
|
159
160
|
if (!outputEl) return;
|
|
160
161
|
|
|
161
162
|
const entry = document.createElement("div");
|
|
@@ -220,11 +221,26 @@ function appendEntry({ prompt, command, outputs = [], errors = [], warnings = []
|
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
// Outputs
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
224
|
+
if (value && outputs.length > 0) {
|
|
225
|
+
const rawText = outputs.join("\n");
|
|
226
|
+
const allLines = outputs[0].split("\n");
|
|
227
|
+
const codecOutputs = allLines.slice(1);
|
|
228
|
+
const timingText = outputs.length > 1 ? outputs[1] : null;
|
|
229
|
+
|
|
230
|
+
const outElement = createOutputEntryElement({
|
|
231
|
+
value,
|
|
232
|
+
rawText,
|
|
233
|
+
codecOutputs,
|
|
234
|
+
timingText
|
|
235
|
+
});
|
|
236
|
+
entry.appendChild(outElement);
|
|
237
|
+
} else {
|
|
238
|
+
for (const out of outputs) {
|
|
239
|
+
const outDiv = document.createElement("div");
|
|
240
|
+
outDiv.className = "entry-line line-output";
|
|
241
|
+
outDiv.innerHTML = ansiToHtml(out);
|
|
242
|
+
entry.appendChild(outDiv);
|
|
243
|
+
}
|
|
228
244
|
}
|
|
229
245
|
|
|
230
246
|
outputEl.appendChild(entry);
|
|
@@ -298,7 +314,8 @@ export async function executeCommand(input) {
|
|
|
298
314
|
errors,
|
|
299
315
|
warnings,
|
|
300
316
|
duration,
|
|
301
|
-
timing: state.lastTiming
|
|
317
|
+
timing: state.lastTiming,
|
|
318
|
+
value: state.lastResult
|
|
302
319
|
});
|
|
303
320
|
|
|
304
321
|
// Re-create completer with updated state
|