@scriptc/compiler 0.3.5 → 0.3.6
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/ambient/scriptc-node-fallback.d.ts +278 -32
- package/dist/backend/llvm/dyn.js +31 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +45 -1
- package/dist/backend/llvm/emitter.js +412 -104
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.js +1 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +25 -1
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +11 -0
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +28 -1
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +61 -1
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +21 -3
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +10 -0
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +43 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-test.js +16 -3
- package/dist/backend/llvm/lib-test.js.map +1 -1
- package/dist/backend/llvm/nullable-unions.d.ts +6 -3
- package/dist/backend/llvm/nullable-unions.js +2 -0
- package/dist/backend/llvm/nullable-unions.js.map +1 -1
- package/dist/backend/llvm/record-results.d.ts +1 -1
- package/dist/backend/llvm/record-results.js +2 -2
- package/dist/backend/llvm/record-results.js.map +1 -1
- package/dist/backend/llvm/reference-writes.js +1 -0
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +3 -0
- package/dist/backend/llvm/shapes.js +5 -0
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/speculative-integers.d.ts +74 -0
- package/dist/backend/llvm/speculative-integers.js +571 -0
- package/dist/backend/llvm/speculative-integers.js.map +1 -0
- package/dist/backend/llvm/speculative-integers.test.d.ts +1 -0
- package/dist/backend/llvm/speculative-integers.test.js +148 -0
- package/dist/backend/llvm/speculative-integers.test.js.map +1 -0
- package/dist/backend/may-throw.js +2 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/executable.js +3 -0
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +1 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/runtime-pack.d.ts +7 -3
- package/dist/backend/runtime-pack.js +12 -6
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +15 -6
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/contracts/check.js +1 -0
- package/dist/contracts/check.js.map +1 -1
- package/dist/coverage/surface-manifest.js +3 -3
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +1 -1
- package/dist/diagnostics/diagnostic.js +6 -2
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/builtin-calls.js +10 -0
- package/dist/frontend/lowering/builtin-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/callable-aliases.js +31 -3
- package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
- package/dist/frontend/lowering/builtins/compression.d.ts +9 -0
- package/dist/frontend/lowering/builtins/compression.js +145 -30
- package/dist/frontend/lowering/builtins/compression.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.js +12 -1
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +5 -3
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +4 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +11 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.d.ts +8 -0
- package/dist/frontend/lowering/builtins/filesystem.js +139 -2
- package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
- package/dist/frontend/lowering/builtins/hash-stream.d.ts +12 -0
- package/dist/frontend/lowering/builtins/hash-stream.js +80 -0
- package/dist/frontend/lowering/builtins/hash-stream.js.map +1 -0
- package/dist/frontend/lowering/builtins/module-calls.js +13 -3
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.js +9 -2
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/readline.d.ts +45 -13
- package/dist/frontend/lowering/builtins/readline.js +812 -47
- package/dist/frontend/lowering/builtins/readline.js.map +1 -1
- package/dist/frontend/lowering/builtins/workers.d.ts +4 -0
- package/dist/frontend/lowering/builtins/workers.js +58 -0
- package/dist/frontend/lowering/builtins/workers.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.d.ts +55 -0
- package/dist/frontend/lowering/class-protocols.js +735 -0
- package/dist/frontend/lowering/class-protocols.js.map +1 -1
- package/dist/frontend/lowering/containers/array-from-async.d.ts +18 -0
- package/dist/frontend/lowering/containers/array-from-async.js +282 -0
- package/dist/frontend/lowering/containers/array-from-async.js.map +1 -0
- package/dist/frontend/lowering/containers/collection-grouping.js +2 -1
- package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +27 -23
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/divergences.js +188 -15
- package/dist/frontend/lowering/divergences.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +71 -22
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +39 -1
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js +10 -1
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +107 -13
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +23 -3
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-mock.d.ts +11 -1
- package/dist/frontend/lowering/lower-mock.js +377 -61
- package/dist/frontend/lowering/lower-mock.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +1 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +161 -16
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +48 -7
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +1 -3
- package/dist/frontend/lowering/lower-stream.js +317 -20
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.js +147 -48
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +10 -0
- package/dist/frontend/lowering/lowerer.js +8 -0
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/null-prototype.d.ts +13 -0
- package/dist/frontend/lowering/null-prototype.js +33 -0
- package/dist/frontend/lowering/null-prototype.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +3 -3
- package/dist/frontend/lowering/surfaces.js +27 -5
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/mock-shapes.d.ts +5 -0
- package/dist/frontend/mock-shapes.js +27 -2
- package/dist/frontend/mock-shapes.js.map +1 -1
- package/dist/frontend/program.js +5 -4
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/type-mapper.js +95 -4
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +18 -8
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-effects.js +36 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +167 -6
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/function-references.test.js +1 -0
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/int32-slots.js +22 -0
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +28 -0
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loop-facts.d.ts +14 -6
- package/dist/ir/integer-loop-facts.js +119 -35
- package/dist/ir/integer-loop-facts.js.map +1 -1
- package/dist/ir/integer-ranges.js +1 -5
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +60 -0
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/ir.d.ts +13 -0
- package/dist/ir/ir.js +4 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/runtime-features.d.ts +3 -1
- package/dist/ir/runtime-features.js +96 -6
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/runtime-features.test.js +62 -0
- package/dist/ir/runtime-features.test.js.map +1 -1
- package/dist/ir/traverse.js +4 -0
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +45 -3
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +38 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/ir-policy.js +5 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +31 -19
|
@@ -13,6 +13,7 @@ import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCou
|
|
|
13
13
|
import { moduleRuntimeFeatures } from "../../ir/runtime-features.js";
|
|
14
14
|
import { matchIntegerArrayForLoop, matchIntegerBytesForLoop, matchIntegerCountedForLoop, } from "../../ir/integer-loops.js";
|
|
15
15
|
import { emitCountedLoopLimit } from "./counted-loops.js";
|
|
16
|
+
import { emitSafeIntegerCheck, emitSpeculativeInteger, planSpeculativeLoop, speculativeReads, speculativeWriteTarget, SPECULATIVE_RANGE, } from "./speculative-integers.js";
|
|
16
17
|
import { emitLiteralSwitch } from "./switch-dispatch.js";
|
|
17
18
|
import { findBytesBounds } from "./bytes-bounds.js";
|
|
18
19
|
import { emitByteWindowGuard, findInitializedByteLoopBindings, matchByteWindow, } from "./byte-windows.js";
|
|
@@ -101,7 +102,7 @@ import { literalCapWord, literalCapWord32 } from "./string-key-hash.js";
|
|
|
101
102
|
import { MAP_ITER_DECL, NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL, } from "./map-number-lookup.js";
|
|
102
103
|
import { STRING_READ_HELPERS, stringScanDecl } from "./string-reads.js";
|
|
103
104
|
import { emitConcatInputs, emitMixedConcat, numberPart, stringParts, } from "./string-construction.js";
|
|
104
|
-
import { arrNewCall, boxAccess, boxNewCall, boxReleaseSym, computeTraced, elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, FN_ATTRS, inlineRcDecls, limitInlineDynReleases, llFieldType, releaseSym, retainSym, traceArg, typedRefConstructor, vAdapters, } from "./shapes.js";
|
|
105
|
+
import { arrNewCall, boxAccess, boxNewCall, boxReleaseSym, computeTraced, elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, FN_ATTRS, inlineRcDecls, limitInlineDynReleases, llFieldType, mapFlagsOffset, releaseSym, retainSym, traceArg, typedRefConstructor, vAdapters, } from "./shapes.js";
|
|
105
106
|
import { INLINE_LITERAL_BYTES, literalEqualityDefinition } from "./string-literal-equality.js";
|
|
106
107
|
export { LlvmUnsupportedError } from "./unsupported.js";
|
|
107
108
|
function ffiCallbackDummyLl(callback) {
|
|
@@ -421,6 +422,9 @@ export class LlEmitter {
|
|
|
421
422
|
stableGlobals = new Set();
|
|
422
423
|
tdzGlobals = new Map();
|
|
423
424
|
constantNumericTables;
|
|
425
|
+
/** Constant-key reads on checked-dynamic objects, each with its own
|
|
426
|
+
* zero-initialized ScrDynReadIc (scr_runtime.h). */
|
|
427
|
+
dynReadIcSites = 0;
|
|
424
428
|
/** May-throw analysis (computeMayThrow): pending
|
|
425
429
|
* checks are emitted only after calls that can actually raise. */
|
|
426
430
|
mayThrow;
|
|
@@ -562,6 +566,17 @@ export class LlEmitter {
|
|
|
562
566
|
/** Active induction bindings retain their width independently of size_t. */
|
|
563
567
|
integerLoopBindings = new Map();
|
|
564
568
|
countedLoopsEnabled = false;
|
|
569
|
+
/** Speculative integer loops (speculative-integers.ts) run in this function. */
|
|
570
|
+
speculativeLoopsEnabled = false;
|
|
571
|
+
/** The fast copy of a speculative integer loop being emitted: its
|
|
572
|
+
* integer-computed writes and where each resumes in the ordinary copy. */
|
|
573
|
+
speculation = null;
|
|
574
|
+
/** The ordinary copy being emitted: resume labels still to place. */
|
|
575
|
+
speculationResume = null;
|
|
576
|
+
/** The function being emitted, for speculative globals. */
|
|
577
|
+
speculativeFunction = "";
|
|
578
|
+
/** Every function that writes each number global (computed on demand). */
|
|
579
|
+
globalWriters = null;
|
|
565
580
|
/** Whole-program final reference fields (ir/final-fields.ts). */
|
|
566
581
|
finalFields;
|
|
567
582
|
/** The current function may borrow final fields of borrowable objects:
|
|
@@ -1691,6 +1706,11 @@ export class LlEmitter {
|
|
|
1691
1706
|
out.push(d);
|
|
1692
1707
|
out.push(``);
|
|
1693
1708
|
const flushedDecls = new Set(this.decls);
|
|
1709
|
+
{
|
|
1710
|
+
const tl = this.mod.workers === true || this.mod.lib?.threadInstances === true ? "thread_local " : "";
|
|
1711
|
+
for (let site = 0; site < this.dynReadIcSites; site++)
|
|
1712
|
+
out.push(`@sc_dyn_read_ic_${site} = internal ${tl}global { ptr, ${this.sizeType}, ${this.sizeType}, ptr } zeroinitializer`);
|
|
1713
|
+
}
|
|
1694
1714
|
for (const table of this.constantNumericTables.values()) {
|
|
1695
1715
|
const n = table.values.length;
|
|
1696
1716
|
let tableTmp = 0;
|
|
@@ -3723,6 +3743,259 @@ export class LlEmitter {
|
|
|
3723
3743
|
this.B.line(`store i32 0, ptr ${slot}`);
|
|
3724
3744
|
return slot;
|
|
3725
3745
|
}
|
|
3746
|
+
/** Emit a loop's condition, body and update through `emitCopy`, twice
|
|
3747
|
+
* when speculative-integers.ts plans a fast integer copy. Both copies
|
|
3748
|
+
* share the loop's setup and exit; the ordinary copy comes first so the
|
|
3749
|
+
* fast copy is only emitted when every resume point exists. */
|
|
3750
|
+
emitLoopCopies(loop, allowed, exit, emitCopy) {
|
|
3751
|
+
const plan = allowed &&
|
|
3752
|
+
this.speculativeLoopsEnabled &&
|
|
3753
|
+
this.speculation === null &&
|
|
3754
|
+
this.speculationResume === null
|
|
3755
|
+
? planSpeculativeLoop(loop, (id) => this.speculativeLocal(id), (id) => this.integerLoopBindings.has(id) || this.int32Locals.has(id), (e) => {
|
|
3756
|
+
const range = this.integerRanges.get(e);
|
|
3757
|
+
return (range !== undefined &&
|
|
3758
|
+
range !== null &&
|
|
3759
|
+
range.min >= -Number.MAX_SAFE_INTEGER &&
|
|
3760
|
+
range.max <= Number.MAX_SAFE_INTEGER);
|
|
3761
|
+
}, (id) => this.speculativeLocal(id) || this.speculativeInvariantGlobal(id))
|
|
3762
|
+
: null;
|
|
3763
|
+
if (!plan) {
|
|
3764
|
+
emitCopy(exit);
|
|
3765
|
+
return;
|
|
3766
|
+
}
|
|
3767
|
+
const B = this.B;
|
|
3768
|
+
const entries = new Map();
|
|
3769
|
+
let ok = "true";
|
|
3770
|
+
for (const [id, live] of plan.locals) {
|
|
3771
|
+
if (!live)
|
|
3772
|
+
continue;
|
|
3773
|
+
const value = B.tmp();
|
|
3774
|
+
B.line(`${value} = load double, ptr ${this.binding(id).slot}`);
|
|
3775
|
+
const [integer, exact] = emitSafeIntegerCheck(this, value);
|
|
3776
|
+
entries.set(id, integer);
|
|
3777
|
+
if (ok === "true")
|
|
3778
|
+
ok = exact;
|
|
3779
|
+
else {
|
|
3780
|
+
const both = B.tmp();
|
|
3781
|
+
B.line(`${both} = and i1 ${ok}, ${exact}`);
|
|
3782
|
+
ok = both;
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
const fast = B.newLabel("spec.fast"), slow = B.newLabel("spec.slow");
|
|
3786
|
+
B.condBr(ok, fast, slow);
|
|
3787
|
+
const resume = new Map();
|
|
3788
|
+
for (const s of plan.writes)
|
|
3789
|
+
resume.set(s, { label: B.newLabel("spec.resume"), placed: false });
|
|
3790
|
+
B.startBlock(slow);
|
|
3791
|
+
this.speculationResume = resume;
|
|
3792
|
+
try {
|
|
3793
|
+
emitCopy(exit);
|
|
3794
|
+
}
|
|
3795
|
+
finally {
|
|
3796
|
+
this.speculationResume = null;
|
|
3797
|
+
}
|
|
3798
|
+
B.startBlock(fast);
|
|
3799
|
+
if (![...resume.values()].every((r) => r.placed)) {
|
|
3800
|
+
B.br(slow);
|
|
3801
|
+
return;
|
|
3802
|
+
}
|
|
3803
|
+
for (const id of plan.locals.keys()) {
|
|
3804
|
+
const shadow = B.slot();
|
|
3805
|
+
B.entryAllocas.push(`${shadow} = alloca i64 ; speculative integer ${this.currentLocals.get(id)?.name ?? id}`);
|
|
3806
|
+
const entry = entries.get(id);
|
|
3807
|
+
if (entry !== undefined) {
|
|
3808
|
+
// The same double, now visibly an integer conversion: the double
|
|
3809
|
+
// phis of the fast copy fold into integer phis.
|
|
3810
|
+
const exact = B.tmp();
|
|
3811
|
+
B.line(`store i64 ${entry}, ptr ${shadow}`);
|
|
3812
|
+
B.line(`${exact} = sitofp i64 ${entry} to double`);
|
|
3813
|
+
B.line(`store double ${exact}, ptr ${this.binding(id).slot}`);
|
|
3814
|
+
}
|
|
3815
|
+
else
|
|
3816
|
+
B.line(`store i64 0, ptr ${shadow}`);
|
|
3817
|
+
this.integerLoopBindings.set(id, {
|
|
3818
|
+
slot: shadow,
|
|
3819
|
+
type: "i64",
|
|
3820
|
+
signed: true,
|
|
3821
|
+
range: SPECULATIVE_RANGE,
|
|
3822
|
+
});
|
|
3823
|
+
}
|
|
3824
|
+
// A global's store stays in the loop (calls may read it). When nothing
|
|
3825
|
+
// in the loop can observe it, its double is written once on leaving the
|
|
3826
|
+
// copy instead, so the loop keeps it in a register as the double copy
|
|
3827
|
+
// would.
|
|
3828
|
+
const deferred = new Set();
|
|
3829
|
+
// Worker loops also leave through their cancellation poll.
|
|
3830
|
+
if (plan.observerFree && !this.mod.workers)
|
|
3831
|
+
for (const s of plan.writes) {
|
|
3832
|
+
const id = speculativeWriteTarget(s).localId;
|
|
3833
|
+
if (!this.currentLocals.has(id))
|
|
3834
|
+
deferred.add(id);
|
|
3835
|
+
}
|
|
3836
|
+
this.speculation = {
|
|
3837
|
+
writes: plan.writes,
|
|
3838
|
+
resume: new Map([...resume].map(([s, r]) => [s, r.label])),
|
|
3839
|
+
deferred,
|
|
3840
|
+
};
|
|
3841
|
+
try {
|
|
3842
|
+
if (deferred.size === 0)
|
|
3843
|
+
emitCopy(exit);
|
|
3844
|
+
else {
|
|
3845
|
+
const leave = B.newLabel("spec.leave");
|
|
3846
|
+
emitCopy(leave);
|
|
3847
|
+
B.startBlock(leave);
|
|
3848
|
+
this.writeBackSpeculativeGlobals(deferred);
|
|
3849
|
+
B.br(exit);
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
finally {
|
|
3853
|
+
this.speculation = null;
|
|
3854
|
+
for (const id of plan.locals.keys())
|
|
3855
|
+
this.integerLoopBindings.delete(id);
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
writeBackSpeculativeGlobals(deferred) {
|
|
3859
|
+
const B = this.B;
|
|
3860
|
+
for (const id of deferred) {
|
|
3861
|
+
const integer = B.tmp(), number = B.tmp();
|
|
3862
|
+
B.line(`${integer} = load i64, ptr ${this.integerLoopBindings.get(id).slot}`);
|
|
3863
|
+
B.line(`${number} = sitofp i64 ${integer} to double`);
|
|
3864
|
+
B.line(`store double ${number}, ptr ${this.binding(id).slot}`);
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
/** A number local whose only storage is its own double slot, so an i64
|
|
3868
|
+
* shadow beside it can stand for it within one loop. */
|
|
3869
|
+
speculativeLocal(id) {
|
|
3870
|
+
const local = this.currentLocals.get(id);
|
|
3871
|
+
if (!local)
|
|
3872
|
+
return this.speculativeGlobal(id);
|
|
3873
|
+
if (local.type.kind !== "f64" || local.boxed || local.tdz)
|
|
3874
|
+
return false;
|
|
3875
|
+
return !(this.captureIds.has(id) ||
|
|
3876
|
+
this.int32Locals.has(id) ||
|
|
3877
|
+
this.integerLoopBindings.has(id) ||
|
|
3878
|
+
this.integerViews.has(id) ||
|
|
3879
|
+
this.localUnionStorage.has(id) ||
|
|
3880
|
+
this.reboundOwnerSlots.has(id) ||
|
|
3881
|
+
this.lazyCaptureBoxes.has(id) ||
|
|
3882
|
+
this.privateSplitLocals.has(id));
|
|
3883
|
+
}
|
|
3884
|
+
/** A module-level number written only by the file's top-level code that
|
|
3885
|
+
* is emitting this loop. Calls may still read it: the fast copy keeps its
|
|
3886
|
+
* double current. An init function runs once and is never re-entered, so
|
|
3887
|
+
* no call from the loop can write the global behind the shadow. */
|
|
3888
|
+
speculativeGlobal(id) {
|
|
3889
|
+
if (!this.speculativeFunction.startsWith("%init."))
|
|
3890
|
+
return false;
|
|
3891
|
+
const writers = this.numberGlobalWriters(id);
|
|
3892
|
+
return (writers !== null &&
|
|
3893
|
+
(writers.size === 0 || (writers.size === 1 && writers.has(this.speculativeFunction))));
|
|
3894
|
+
}
|
|
3895
|
+
/** A module-level number a loop of any function only reads, written by
|
|
3896
|
+
* nothing but top-level code: an init function never runs during a loop
|
|
3897
|
+
* of another function, so the entry value stays its value. */
|
|
3898
|
+
speculativeInvariantGlobal(id) {
|
|
3899
|
+
const writers = this.numberGlobalWriters(id);
|
|
3900
|
+
return writers !== null && [...writers].every((name) => name.startsWith("%init."));
|
|
3901
|
+
}
|
|
3902
|
+
/** The functions writing a number global a shadow may stand for, or null
|
|
3903
|
+
* when the global is not such a number. */
|
|
3904
|
+
numberGlobalWriters(id) {
|
|
3905
|
+
if (this.globalTypes.get(id)?.kind !== "f64")
|
|
3906
|
+
return null;
|
|
3907
|
+
if (this.tdzGlobals.has(id) || this.integerViews.has(id))
|
|
3908
|
+
return null;
|
|
3909
|
+
if (!this.globalWriters) {
|
|
3910
|
+
const writers = new Map();
|
|
3911
|
+
for (const fn of this.mod.functions) {
|
|
3912
|
+
const note = (localId) => {
|
|
3913
|
+
if (!localId.startsWith("%g."))
|
|
3914
|
+
return;
|
|
3915
|
+
const set = writers.get(localId) ?? new Set();
|
|
3916
|
+
set.add(fn.name);
|
|
3917
|
+
writers.set(localId, set);
|
|
3918
|
+
};
|
|
3919
|
+
everyStmtList(fn.body, {
|
|
3920
|
+
stmt: (s) => {
|
|
3921
|
+
if (s.kind === "assign" || s.kind === "varDecl")
|
|
3922
|
+
note(s.localId);
|
|
3923
|
+
return true;
|
|
3924
|
+
},
|
|
3925
|
+
expr: (e) => {
|
|
3926
|
+
if (e.kind === "assignExpr" || e.kind === "incDec")
|
|
3927
|
+
note(e.localId);
|
|
3928
|
+
return true;
|
|
3929
|
+
},
|
|
3930
|
+
});
|
|
3931
|
+
}
|
|
3932
|
+
this.globalWriters = writers;
|
|
3933
|
+
}
|
|
3934
|
+
return this.globalWriters.get(id) ?? new Set();
|
|
3935
|
+
}
|
|
3936
|
+
/** A speculated write in the fast copy: compute the value as a safe
|
|
3937
|
+
* integer, store it to the shadow and its exact double to the local.
|
|
3938
|
+
* Any failed check re-executes the statement in the ordinary copy. */
|
|
3939
|
+
emitSpeculativeWrite(s, resume) {
|
|
3940
|
+
const B = this.B;
|
|
3941
|
+
const target = speculativeWriteTarget(s);
|
|
3942
|
+
const binding = this.integerLoopBindings.get(target.localId);
|
|
3943
|
+
const failed = B.newLabel("spec.bail");
|
|
3944
|
+
let bails = false;
|
|
3945
|
+
this.declare("declare i1 @llvm.expect.i1(i1, i1)");
|
|
3946
|
+
const bail = (condition) => {
|
|
3947
|
+
if (condition === "false")
|
|
3948
|
+
return;
|
|
3949
|
+
bails = true;
|
|
3950
|
+
const expected = B.tmp();
|
|
3951
|
+
B.line(`${expected} = call i1 @llvm.expect.i1(i1 ${condition}, i1 false)`);
|
|
3952
|
+
const next = B.newLabel("spec.ok");
|
|
3953
|
+
B.condBr(expected, failed, next);
|
|
3954
|
+
B.startBlock(next);
|
|
3955
|
+
};
|
|
3956
|
+
// Heap reads come first, before any check, and release their temporaries
|
|
3957
|
+
// at once: a bailing path then owns nothing, and reads have no effect
|
|
3958
|
+
// whose reordering before the arithmetic could be observed.
|
|
3959
|
+
const reads = new Map();
|
|
3960
|
+
if (target.value !== null) {
|
|
3961
|
+
this.frames.push([]);
|
|
3962
|
+
for (const read of speculativeReads(target.value))
|
|
3963
|
+
reads.set(read, this.emitExpr(read));
|
|
3964
|
+
this.releaseFrame(this.frames.pop());
|
|
3965
|
+
}
|
|
3966
|
+
this.frames.push([]);
|
|
3967
|
+
let result;
|
|
3968
|
+
if (target.value === null) {
|
|
3969
|
+
const old = B.tmp();
|
|
3970
|
+
result = B.tmp();
|
|
3971
|
+
B.line(`${old} = load i64, ptr ${binding.slot}`);
|
|
3972
|
+
B.line(`${result} = ${target.op === "+" ? "add" : "sub"} nsw i64 ${old}, 1`);
|
|
3973
|
+
const biased = B.tmp(), outside = B.tmp();
|
|
3974
|
+
B.line(`${biased} = add i64 ${result}, ${Number.MAX_SAFE_INTEGER}`);
|
|
3975
|
+
B.line(`${outside} = icmp ugt i64 ${biased}, ${2 * Number.MAX_SAFE_INTEGER}`);
|
|
3976
|
+
bail(outside);
|
|
3977
|
+
}
|
|
3978
|
+
else
|
|
3979
|
+
result = emitSpeculativeInteger(this, target.value, bail, reads);
|
|
3980
|
+
// Speculable values read only numbers past this point.
|
|
3981
|
+
if (this.frames.pop().length > 0)
|
|
3982
|
+
throw new InternalCompilerError("llvm emitter bug: speculative write owns a temporary");
|
|
3983
|
+
B.line(`store i64 ${result}, ptr ${binding.slot}`);
|
|
3984
|
+
const deferred = this.speculation.deferred;
|
|
3985
|
+
if (!deferred.has(target.localId)) {
|
|
3986
|
+
const number = B.tmp();
|
|
3987
|
+
B.line(`${number} = sitofp i64 ${result} to double`);
|
|
3988
|
+
B.line(`store double ${number}, ptr ${this.binding(target.localId).slot}`);
|
|
3989
|
+
}
|
|
3990
|
+
if (!bails)
|
|
3991
|
+
return;
|
|
3992
|
+
const done = B.newLabel("spec.done");
|
|
3993
|
+
B.br(done);
|
|
3994
|
+
B.startBlock(failed);
|
|
3995
|
+
this.writeBackSpeculativeGlobals(deferred);
|
|
3996
|
+
B.br(resume);
|
|
3997
|
+
B.startBlock(done);
|
|
3998
|
+
}
|
|
3726
3999
|
/** The amortized cancellation poll, emitted on the loop's back edge (the
|
|
3727
4000
|
* continue target), after the body. A poll in the header would be a loop
|
|
3728
4001
|
* exit ahead of the body; LLVM then cannot rotate the loop, so loads that
|
|
@@ -4161,6 +4434,14 @@ export class LlEmitter {
|
|
|
4161
4434
|
this.B.line(`${v} = load ptr, ptr ${p}`);
|
|
4162
4435
|
return v;
|
|
4163
4436
|
}
|
|
4437
|
+
/** The pointer to ScrMap.flags of an index-signature record's overflow
|
|
4438
|
+
* map (byte offset sizeof(size_t) + 3; SCR_MAP_NULL_PROTO is bit 0). */
|
|
4439
|
+
recordMapFlagsPtr(objName, shapeId) {
|
|
4440
|
+
const ovf = this.recordOvfPtr(objName, shapeId);
|
|
4441
|
+
const p = this.B.tmp();
|
|
4442
|
+
this.B.line(`${p} = getelementptr inbounds i8, ptr ${ovf}, i64 ${mapFlagsOffset(this.sizeType)}`);
|
|
4443
|
+
return p;
|
|
4444
|
+
}
|
|
4164
4445
|
/** Loads a record field (i8-stored bools trunc to i1). An inline union
|
|
4165
4446
|
* field answers a private stack box with the slot's own bits, ABSENT
|
|
4166
4447
|
* included: it may only be borrowed. */
|
|
@@ -4750,6 +5031,10 @@ export class LlEmitter {
|
|
|
4750
5031
|
fn.captures !== undefined ? this.lazyCaptures.stableCaptures(fn.name) : new Set();
|
|
4751
5032
|
this.integerLoopBindings.clear();
|
|
4752
5033
|
this.countedLoopsEnabled = this.debug === null && !fn.async && !fn.generator;
|
|
5034
|
+
this.speculativeLoopsEnabled = this.countedLoopsEnabled;
|
|
5035
|
+
this.speculativeFunction = fn.name;
|
|
5036
|
+
this.speculation = null;
|
|
5037
|
+
this.speculationResume = null;
|
|
4753
5038
|
this.finalFieldBorrows =
|
|
4754
5039
|
!fn.async && !fn.generator && constructorClass(fn.name) === null && this.finalFields.size > 0;
|
|
4755
5040
|
this.byteWindowsEnabled = this.countedLoopsEnabled;
|
|
@@ -5727,6 +6012,17 @@ export class LlEmitter {
|
|
|
5727
6012
|
this.releaseScope(scope);
|
|
5728
6013
|
}
|
|
5729
6014
|
emitStmt(s) {
|
|
6015
|
+
const resume = this.speculationResume?.get(s);
|
|
6016
|
+
if (resume && !resume.placed && !this.B.isTerminated()) {
|
|
6017
|
+
// The fast copy's failed checks re-execute this statement here.
|
|
6018
|
+
resume.placed = true;
|
|
6019
|
+
this.B.br(resume.label);
|
|
6020
|
+
this.B.startBlock(resume.label);
|
|
6021
|
+
}
|
|
6022
|
+
if (this.speculation?.writes.has(s)) {
|
|
6023
|
+
this.emitSpeculativeWrite(s, this.speculation.resume.get(s));
|
|
6024
|
+
return;
|
|
6025
|
+
}
|
|
5730
6026
|
const previous = this.B.debugLocation;
|
|
5731
6027
|
this.B.debugLocation = this.debug?.location(s.loc, this.debugScope) ?? null;
|
|
5732
6028
|
const loop = s.kind === "while" || s.kind === "doWhile" || s.kind === "for" || s.kind === "forOf";
|
|
@@ -6357,57 +6653,61 @@ export class LlEmitter {
|
|
|
6357
6653
|
}
|
|
6358
6654
|
case "while": {
|
|
6359
6655
|
const workerBudget = this.workerLoopBudget(s);
|
|
6360
|
-
const lc = B.newLabel("loop.c");
|
|
6361
|
-
const lb = B.newLabel("loop.b");
|
|
6362
6656
|
const le = B.newLabel("loop.e");
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
B.startBlock(lb);
|
|
6368
|
-
this.jumpTargets.push({
|
|
6369
|
-
kind: "loop",
|
|
6370
|
-
brkLabel: le,
|
|
6371
|
-
contLabel: lp,
|
|
6372
|
-
labels: s.labels,
|
|
6373
|
-
frameDepth: this.frames.length,
|
|
6374
|
-
scopeDepth: this.scopes.length,
|
|
6375
|
-
finallyDepth: this.finallyStack.length,
|
|
6376
|
-
});
|
|
6377
|
-
this.emitBlock(s.body);
|
|
6378
|
-
this.jumpTargets.pop();
|
|
6379
|
-
B.br(lp);
|
|
6380
|
-
if (lp !== lc) {
|
|
6381
|
-
B.startBlock(lp);
|
|
6382
|
-
this.emitWorkerLoopCheck(workerBudget);
|
|
6657
|
+
this.emitLoopCopies(s, true, le, (exit) => {
|
|
6658
|
+
const lc = B.newLabel("loop.c");
|
|
6659
|
+
const lb = B.newLabel("loop.b");
|
|
6660
|
+
const lp = workerBudget !== null ? B.newLabel("loop.p") : lc;
|
|
6383
6661
|
B.br(lc);
|
|
6384
|
-
|
|
6662
|
+
B.startBlock(lc);
|
|
6663
|
+
B.condBr(this.emitCondition(s.cond), lb, exit);
|
|
6664
|
+
B.startBlock(lb);
|
|
6665
|
+
this.jumpTargets.push({
|
|
6666
|
+
kind: "loop",
|
|
6667
|
+
brkLabel: exit,
|
|
6668
|
+
contLabel: lp,
|
|
6669
|
+
labels: s.labels,
|
|
6670
|
+
frameDepth: this.frames.length,
|
|
6671
|
+
scopeDepth: this.scopes.length,
|
|
6672
|
+
finallyDepth: this.finallyStack.length,
|
|
6673
|
+
});
|
|
6674
|
+
this.emitBlock(s.body);
|
|
6675
|
+
this.jumpTargets.pop();
|
|
6676
|
+
B.br(lp);
|
|
6677
|
+
if (lp !== lc) {
|
|
6678
|
+
B.startBlock(lp);
|
|
6679
|
+
this.emitWorkerLoopCheck(workerBudget);
|
|
6680
|
+
B.br(lc);
|
|
6681
|
+
}
|
|
6682
|
+
});
|
|
6385
6683
|
B.startBlock(le);
|
|
6386
6684
|
break;
|
|
6387
6685
|
}
|
|
6388
6686
|
case "doWhile": {
|
|
6389
6687
|
const workerBudget = this.workerLoopBudget(s);
|
|
6390
6688
|
// Body first (runs at least once); continue jumps to the CONDITION.
|
|
6391
|
-
const lb = B.newLabel("loop.b");
|
|
6392
|
-
const lc = B.newLabel("loop.c");
|
|
6393
6689
|
const le = B.newLabel("loop.e");
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6690
|
+
this.emitLoopCopies(s, true, le, (exit) => {
|
|
6691
|
+
const lb = B.newLabel("loop.b");
|
|
6692
|
+
const lc = B.newLabel("loop.c");
|
|
6693
|
+
B.br(lb);
|
|
6694
|
+
B.startBlock(lb);
|
|
6695
|
+
this.jumpTargets.push({
|
|
6696
|
+
kind: "loop",
|
|
6697
|
+
brkLabel: exit,
|
|
6698
|
+
contLabel: lc,
|
|
6699
|
+
labels: s.labels,
|
|
6700
|
+
frameDepth: this.frames.length,
|
|
6701
|
+
scopeDepth: this.scopes.length,
|
|
6702
|
+
finallyDepth: this.finallyStack.length,
|
|
6703
|
+
});
|
|
6704
|
+
this.emitBlock(s.body);
|
|
6705
|
+
this.jumpTargets.pop();
|
|
6706
|
+
B.br(lc);
|
|
6707
|
+
B.startBlock(lc);
|
|
6708
|
+
this.emitWorkerLoopCheck(workerBudget);
|
|
6709
|
+
B.condBr(this.emitCondition(s.cond), lb, exit);
|
|
6404
6710
|
});
|
|
6405
|
-
this.emitBlock(s.body);
|
|
6406
|
-
this.jumpTargets.pop();
|
|
6407
|
-
B.br(lc);
|
|
6408
|
-
B.startBlock(lc);
|
|
6409
|
-
this.emitWorkerLoopCheck(workerBudget);
|
|
6410
|
-
B.condBr(this.emitCondition(s.cond), lb, le);
|
|
6411
6711
|
B.startBlock(le);
|
|
6412
6712
|
break;
|
|
6413
6713
|
}
|
|
@@ -6539,8 +6839,6 @@ export class LlEmitter {
|
|
|
6539
6839
|
for (const initializer of initializers)
|
|
6540
6840
|
this.emitStmt(initializer);
|
|
6541
6841
|
}
|
|
6542
|
-
const lc = B.newLabel("loop.c");
|
|
6543
|
-
const lb = B.newLabel("loop.b");
|
|
6544
6842
|
const le = B.newLabel("loop.e");
|
|
6545
6843
|
// JS `for (let i ...)`: each iteration gets a FRESH binding holding
|
|
6546
6844
|
// a copy of the previous one (closures made in iteration k keep
|
|
@@ -6567,70 +6865,76 @@ export class LlEmitter {
|
|
|
6567
6865
|
}
|
|
6568
6866
|
};
|
|
6569
6867
|
const workerBudget = this.workerLoopBudget(s);
|
|
6570
|
-
const lu = s.update || capturedLets.length > 0 || workerBudget !== null ? B.newLabel("loop.u") : lc;
|
|
6571
6868
|
freshenBindings();
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
const
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
B.line(`${lenPtr} = getelementptr inbounds %${integerArrayLoop ? "ScrArr" : "ScrBytes"}, ptr ${receiver.name}, i64 0, i32 1`);
|
|
6581
|
-
if (integerArrayLoop)
|
|
6582
|
-
this.markMemoryPointer(lenPtr, "array:header");
|
|
6583
|
-
B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
|
|
6584
|
-
B.line(`${index} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
6585
|
-
B.line(`${inBounds} = icmp ult ${this.sizeType} ${index}, ${len}`);
|
|
6586
|
-
B.condBr(inBounds, lb, le);
|
|
6587
|
-
}
|
|
6588
|
-
else if (countedLoop && integerSlot && countedLimit) {
|
|
6589
|
-
const index = B.tmp();
|
|
6590
|
-
const inBounds = B.tmp();
|
|
6591
|
-
B.line(`${index} = load i64, ptr ${integerSlot}`);
|
|
6592
|
-
B.line(`${inBounds} = icmp ${countedLoop.step > 0 ? "slt" : "sgt"} i64 ${index}, ${countedLimit}`);
|
|
6593
|
-
B.condBr(inBounds, lb, le);
|
|
6594
|
-
}
|
|
6595
|
-
else if (s.cond)
|
|
6596
|
-
B.condBr(this.emitCondition(s.cond), lb, le);
|
|
6597
|
-
else
|
|
6598
|
-
B.br(lb);
|
|
6599
|
-
B.startBlock(lb);
|
|
6600
|
-
this.jumpTargets.push({
|
|
6601
|
-
kind: "loop",
|
|
6602
|
-
brkLabel: le,
|
|
6603
|
-
contLabel: lu,
|
|
6604
|
-
labels: s.labels,
|
|
6605
|
-
frameDepth: this.frames.length,
|
|
6606
|
-
scopeDepth: this.scopes.length,
|
|
6607
|
-
finallyDepth: this.finallyStack.length,
|
|
6608
|
-
});
|
|
6609
|
-
this.emitBlock(s.body);
|
|
6610
|
-
this.jumpTargets.pop();
|
|
6611
|
-
B.br(lu);
|
|
6612
|
-
if (lu !== lc) {
|
|
6613
|
-
B.startBlock(lu);
|
|
6614
|
-
this.emitWorkerLoopCheck(workerBudget);
|
|
6615
|
-
freshenBindings();
|
|
6869
|
+
this.emitLoopCopies(s, capturedLets.length === 0, le, (exit) => {
|
|
6870
|
+
const lc = B.newLabel("loop.c");
|
|
6871
|
+
const lb = B.newLabel("loop.b");
|
|
6872
|
+
const lu = s.update || capturedLets.length > 0 || workerBudget !== null
|
|
6873
|
+
? B.newLabel("loop.u")
|
|
6874
|
+
: lc;
|
|
6875
|
+
B.br(lc);
|
|
6876
|
+
B.startBlock(lc);
|
|
6616
6877
|
if (integerLoop && integerSlot) {
|
|
6617
|
-
const
|
|
6618
|
-
const
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
B.
|
|
6878
|
+
const receiver = this.emitStableReceiver(integerLoop.limitReceiver, []);
|
|
6879
|
+
const lenPtr = B.tmp();
|
|
6880
|
+
const len = B.tmp();
|
|
6881
|
+
const index = B.tmp();
|
|
6882
|
+
const inBounds = B.tmp();
|
|
6883
|
+
B.line(`${lenPtr} = getelementptr inbounds %${integerArrayLoop ? "ScrArr" : "ScrBytes"}, ptr ${receiver.name}, i64 0, i32 1`);
|
|
6884
|
+
if (integerArrayLoop)
|
|
6885
|
+
this.markMemoryPointer(lenPtr, "array:header");
|
|
6886
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
|
|
6887
|
+
B.line(`${index} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
6888
|
+
B.line(`${inBounds} = icmp ult ${this.sizeType} ${index}, ${len}`);
|
|
6889
|
+
B.condBr(inBounds, lb, exit);
|
|
6622
6890
|
}
|
|
6623
|
-
else if (countedLoop && integerSlot) {
|
|
6624
|
-
const
|
|
6625
|
-
const
|
|
6626
|
-
B.line(`${
|
|
6627
|
-
B.line(`${
|
|
6628
|
-
B.
|
|
6891
|
+
else if (countedLoop && integerSlot && countedLimit) {
|
|
6892
|
+
const index = B.tmp();
|
|
6893
|
+
const inBounds = B.tmp();
|
|
6894
|
+
B.line(`${index} = load i64, ptr ${integerSlot}`);
|
|
6895
|
+
B.line(`${inBounds} = icmp ${countedLoop.step > 0 ? "slt" : "sgt"} i64 ${index}, ${countedLimit}`);
|
|
6896
|
+
B.condBr(inBounds, lb, exit);
|
|
6629
6897
|
}
|
|
6630
|
-
else if (s.
|
|
6631
|
-
this.
|
|
6632
|
-
|
|
6633
|
-
|
|
6898
|
+
else if (s.cond)
|
|
6899
|
+
B.condBr(this.emitCondition(s.cond), lb, exit);
|
|
6900
|
+
else
|
|
6901
|
+
B.br(lb);
|
|
6902
|
+
B.startBlock(lb);
|
|
6903
|
+
this.jumpTargets.push({
|
|
6904
|
+
kind: "loop",
|
|
6905
|
+
brkLabel: exit,
|
|
6906
|
+
contLabel: lu,
|
|
6907
|
+
labels: s.labels,
|
|
6908
|
+
frameDepth: this.frames.length,
|
|
6909
|
+
scopeDepth: this.scopes.length,
|
|
6910
|
+
finallyDepth: this.finallyStack.length,
|
|
6911
|
+
});
|
|
6912
|
+
this.emitBlock(s.body);
|
|
6913
|
+
this.jumpTargets.pop();
|
|
6914
|
+
B.br(lu);
|
|
6915
|
+
if (lu !== lc) {
|
|
6916
|
+
B.startBlock(lu);
|
|
6917
|
+
this.emitWorkerLoopCheck(workerBudget);
|
|
6918
|
+
freshenBindings();
|
|
6919
|
+
if (integerLoop && integerSlot) {
|
|
6920
|
+
const old = B.tmp();
|
|
6921
|
+
const next = B.tmp();
|
|
6922
|
+
B.line(`${old} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
6923
|
+
B.line(`${next} = add nuw ${this.sizeType} ${old}, 1`);
|
|
6924
|
+
B.line(`store ${this.sizeType} ${next}, ptr ${integerSlot}`);
|
|
6925
|
+
}
|
|
6926
|
+
else if (countedLoop && integerSlot) {
|
|
6927
|
+
const old = B.tmp();
|
|
6928
|
+
const next = B.tmp();
|
|
6929
|
+
B.line(`${old} = load i64, ptr ${integerSlot}`);
|
|
6930
|
+
B.line(`${next} = add nsw i64 ${old}, ${countedLoop.step}`);
|
|
6931
|
+
B.line(`store i64 ${next}, ptr ${integerSlot}`);
|
|
6932
|
+
}
|
|
6933
|
+
else if (s.update)
|
|
6934
|
+
this.emitStmt(s.update);
|
|
6935
|
+
B.br(lc);
|
|
6936
|
+
}
|
|
6937
|
+
});
|
|
6634
6938
|
B.startBlock(le);
|
|
6635
6939
|
this.releaseScope(this.scopes.pop());
|
|
6636
6940
|
if (integerLoop)
|
|
@@ -8424,6 +8728,10 @@ export class LlEmitter {
|
|
|
8424
8728
|
emitExpr(e) {
|
|
8425
8729
|
return emitExpr(this, e);
|
|
8426
8730
|
}
|
|
8731
|
+
/** A fresh read-site cache for one constant-key dyn read. */
|
|
8732
|
+
dynReadIcSite() {
|
|
8733
|
+
return `@sc_dyn_read_ic_${this.dynReadIcSites++}`;
|
|
8734
|
+
}
|
|
8427
8735
|
dynKind(d) {
|
|
8428
8736
|
return dynKind(this, d);
|
|
8429
8737
|
}
|