@asmlift/core 0.9.0 → 0.10.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/README.md +25 -24
- package/package.json +1 -1
- package/src/aggregate.ts +149 -0
- package/src/backend/c.ts +1 -0
- package/src/backend/cfamily.ts +165 -50
- package/src/backend/cpp.ts +2 -1
- package/src/backend/pascal.ts +31 -12
- package/src/contracts.ts +173 -16
- package/src/declare.ts +69 -20
- package/src/frontend/asmdata.ts +7 -1
- package/src/frontend/call-plan.ts +964 -60
- package/src/frontend/dead-reads.ts +628 -0
- package/src/frontend/device-pins.ts +23 -4
- package/src/frontend/emit.ts +4 -3
- package/src/frontend/fpu.ts +224 -17
- package/src/frontend/frame-objects.ts +1232 -192
- package/src/frontend/frontend.ts +64 -3
- package/src/frontend/high-half.ts +53 -4
- package/src/frontend/jump-table.ts +530 -0
- package/src/frontend/local-object.ts +158 -32
- package/src/frontend/mips.ts +2076 -215
- package/src/frontend/own-struct-return.ts +500 -0
- package/src/frontend/ppc.ts +2711 -232
- package/src/frontend/register-struct-call.ts +484 -0
- package/src/frontend/reloc-symbol.ts +22 -7
- package/src/frontend/ssa.ts +1460 -44
- package/src/frontend/stackargs.ts +106 -57
- package/src/frontend/thumb.ts +2044 -318
- package/src/ir/alias.ts +42 -0
- package/src/ir/bits.ts +681 -1
- package/src/ir/core.ts +100 -5
- package/src/ir/discipline.ts +86 -21
- package/src/ir/entry.ts +159 -0
- package/src/{structure → ir}/loops.ts +6 -2
- package/src/ir/opcodes.ts +109 -9
- package/src/ir/types.ts +86 -2
- package/src/ir/verify.ts +80 -11
- package/src/l3/ast.ts +290 -18
- package/src/l3/basecse.ts +33 -5
- package/src/l3/constinit.ts +382 -0
- package/src/l3/dce.ts +2 -2
- package/src/l3/initfirst.ts +42 -11
- package/src/l3/intcell.ts +2 -1
- package/src/l3/narrowdecl.ts +77 -36
- package/src/l3/pollguard.ts +8 -2
- package/src/l3/ptrcell.ts +31 -34
- package/src/l3/ptrfield.ts +123 -8
- package/src/l3/regspell.ts +9 -4
- package/src/l3/reindex.ts +283 -96
- package/src/l3/storage.ts +98 -1
- package/src/l3/symbol-refs.ts +84 -6
- package/src/l3/tailmerge.ts +4 -2
- package/src/l3/typing.ts +108 -15
- package/src/l3/unreduce.ts +6 -5
- package/src/l3/volatileptr.ts +17 -54
- package/src/mangle.ts +30 -0
- package/src/pattern/engine.ts +361 -73
- package/src/pipeline.ts +541 -24
- package/src/proto-context.ts +905 -45
- package/src/proto.ts +555 -40
- package/src/raise/aggmembers.ts +290 -0
- package/src/raise/arrays.ts +5 -1
- package/src/raise/declared-volatile.ts +207 -31
- package/src/raise/floathelpers.ts +254 -33
- package/src/raise/gvn.ts +3 -3
- package/src/raise/latch.ts +162 -6
- package/src/raise/memberarrays.ts +10 -4
- package/src/raise/offsetnames.ts +10 -26
- package/src/raise/pairparams.ts +33 -0
- package/src/raise/paramwidth.ts +196 -6
- package/src/raise/pre-recovery.ts +102 -19
- package/src/raise/pre-structure.ts +54 -0
- package/src/raise/recover.ts +12 -5
- package/src/raise/reroll.ts +694 -0
- package/src/raise/shortcircuit.ts +26 -12
- package/src/raise/softdiv.ts +1 -1
- package/src/raise/storesign.ts +153 -0
- package/src/raise/struct-arrays.ts +30 -11
- package/src/raise/structs.ts +396 -33
- package/src/raise/truncload.ts +4 -3
- package/src/raise/unthread.ts +400 -0
- package/src/rank-declare.ts +118 -12
- package/src/rank-variations.ts +89 -31
- package/src/rank.ts +307 -54
- package/src/runtime-helpers.ts +140 -22
- package/src/structure/analysis.ts +165 -2
- package/src/structure/arith-ops.ts +23 -0
- package/src/structure/globalaccess.ts +111 -9
- package/src/structure/hazards.ts +16 -64
- package/src/structure/local-statics.ts +145 -9
- package/src/structure/namecoalesce.ts +1 -1
- package/src/structure/pointer-spelling.ts +1106 -0
- package/src/structure/redundant-test.ts +1 -1
- package/src/structure/structure.ts +2180 -1054
- package/src/structure/switch-recover.ts +244 -100
- package/src/symbols.ts +6 -0
- package/src/target.ts +765 -52
- package/src/trace.ts +26 -8
- package/src/variation-definitions.ts +126 -14
- package/src/variation-gates.ts +2 -0
- package/src/variation-tokens.ts +5 -1
package/src/rank-variations.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
import type { Gate } from './l3/gates';
|
|
28
28
|
import type { HoistPlacement } from './l3/hoist';
|
|
29
29
|
import { initFirstGuards } from './l3/initfirst';
|
|
30
|
-
import { narrowDeclarations, narrowReadDeclarations } from './l3/narrowdecl';
|
|
30
|
+
import { narrowDeclarations, narrowLoadDeclarations, narrowReadDeclarations } from './l3/narrowdecl';
|
|
31
31
|
import { pollGuards, pollReads } from './l3/pollguard';
|
|
32
32
|
import { unmergeJoins } from './l3/unmerge';
|
|
33
33
|
// TYPE-ONLY, and deliberately: the structure-variation table types its `options` as
|
|
@@ -71,7 +71,7 @@ export interface StructureVariation {
|
|
|
71
71
|
| 'derivedHome'
|
|
72
72
|
| 'mergeHome'
|
|
73
73
|
| 'escapeHome'
|
|
74
|
-
| '
|
|
74
|
+
| 'signedCmp'
|
|
75
75
|
| 'freshMerge'
|
|
76
76
|
| 'copyDefPos'
|
|
77
77
|
| 'siteSense';
|
|
@@ -225,17 +225,22 @@ export const STRUCTURE_VARIATIONS: readonly StructureVariation[] = [
|
|
|
225
225
|
perLiftGate: hasEscapingExtension,
|
|
226
226
|
strip: true,
|
|
227
227
|
},
|
|
228
|
-
// `/
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
//
|
|
234
|
-
//
|
|
228
|
+
// `/signed-cmp` — spell an unsigned compare SIGNED (structure.ts unsignedCompareSpelling OFF): no
|
|
229
|
+
// `(u32)` cast at an icmp_u* and no u32 reconciliation of a mixed-claimant declaration. The
|
|
230
|
+
// default is the one spelling value-faithful without a proof; this one is a real source where the
|
|
231
|
+
// compiler PROVED both sides non-negative (only then does it emit the unsigned branch from a
|
|
232
|
+
// signed compare), which emission cannot always repeat. Where the proof does not hold it is a
|
|
233
|
+
// different program, so rank.ts judges every emitted tree (`signedOverUnsignedCompare`) and makes
|
|
234
|
+
// a signed rendering `Candidate.matchOnly`, whichever setting or respell spelled it. A tie or a
|
|
235
|
+
// better nonmatch score is no evidence for it (`synthetic:selloop:gcc2.7.2kmc`).
|
|
236
|
+
// KNOWN GAP, in the safe direction: the judgment reads the tree's declarations, and globals are
|
|
237
|
+
// not among them, so a compare that renders unsigned only through a `void *` global the backend
|
|
238
|
+
// declares (ptrcell.test.ts KR1, `g >= gLimit`) is still withheld on a nonmatch.
|
|
239
|
+
// Gated on the function having an unsigned compare at all.
|
|
235
240
|
{
|
|
236
|
-
flag: '
|
|
237
|
-
name: '
|
|
238
|
-
options: (on) => ({ unsignedCompareSpelling: on }),
|
|
241
|
+
flag: 'signedCmp',
|
|
242
|
+
name: 'signed-cmp',
|
|
243
|
+
options: (on) => ({ unsignedCompareSpelling: !on }),
|
|
239
244
|
sharedGate: (sharedLift) => sharedLift.blocks.some((b) => b.ops.some((op) => op.opcode.startsWith('icmp_u'))),
|
|
240
245
|
strip: true,
|
|
241
246
|
},
|
|
@@ -373,24 +378,31 @@ export const STRUCTURE_VARIATIONS: readonly StructureVariation[] = [
|
|
|
373
378
|
},
|
|
374
379
|
];
|
|
375
380
|
|
|
376
|
-
/** The
|
|
377
|
-
|
|
378
|
-
* variation outside this table, derived onto every source. Two members need not commute
|
|
379
|
-
* (`/narrow-decl` and `/narrow-read` compete for one cast), and table order then decides which one
|
|
380
|
-
* takes it in the all-together candidate. Each fires alone, plus
|
|
381
|
-
* all of them together in table order — not the full subset lattice; the pairs question is
|
|
382
|
-
* settled by applyStacked' skip-on-decline below, and a row demanding a true EXCLUSION pair —
|
|
383
|
-
* every member fires, the match needs a strict subset of them — is what would earn the lattice.
|
|
384
|
-
* So a member appended here also changes the all-together candidate wherever it fires beside two
|
|
385
|
-
* or more of the others. */
|
|
386
|
-
export const STACKED_VARIATIONS: { name: VariationName; apply: (sfn: SFn) => SFn | null }[] = [
|
|
381
|
+
/** The statement-order/shape members. */
|
|
382
|
+
const STACKED_SHAPES: { name: VariationName; apply: (sfn: SFn) => SFn | null }[] = [
|
|
387
383
|
{ name: 'initfirst', apply: initFirstGuards },
|
|
388
384
|
{ name: 'pollguard', apply: pollGuards },
|
|
389
385
|
{ name: 'pollread', apply: pollReads },
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
/** The declaration-width members: one dimension, the width each kind of local is declared at
|
|
389
|
+
* (l3/narrowdecl.ts). A function holding a cast-written local,
|
|
390
|
+
* load-written locals and call-result locals may need any combination of the three kinds narrow
|
|
391
|
+
* while all three fire (the matching suite compiles all eight), so every subset is offered. */
|
|
392
|
+
const STACKED_WIDTHS: { name: VariationName; apply: (sfn: SFn) => SFn | null }[] = [
|
|
390
393
|
{ name: 'narrow-decl', apply: narrowDeclarations },
|
|
394
|
+
{ name: 'narrow-load', apply: narrowLoadDeclarations },
|
|
391
395
|
{ name: 'narrow-read', apply: narrowReadDeclarations },
|
|
392
396
|
];
|
|
393
397
|
|
|
398
|
+
/** The STACKED variations (sanctioned in the POLICY note at rank.ts's respell site): each entry is
|
|
399
|
+
* a statement-order/shape or declaration-width respell variation orthogonal to every respell
|
|
400
|
+
* variation outside this table, derived onto every source. Two members need not commute
|
|
401
|
+
* (`/narrow-decl` and `/narrow-read` compete for one cast, `/narrow-load` and `/narrow-read` for
|
|
402
|
+
* one local), and table order then decides which one takes it in a candidate holding both. Which
|
|
403
|
+
* of them a candidate applies is STACKED_SUBSETS. */
|
|
404
|
+
export const STACKED_VARIATIONS = [...STACKED_SHAPES, ...STACKED_WIDTHS];
|
|
405
|
+
|
|
394
406
|
/** The PRE-RESPELL variations (sanctioned in the POLICY note at rank.ts's respell site): a tree
|
|
395
407
|
* rewrite applied BEFORE the respell set, so the whole set derives from its output instead of
|
|
396
408
|
* composing onto it. Same record type as STACKED_VARIATIONS above, and deliberately so — the only difference is
|
|
@@ -458,17 +470,47 @@ export const STACKED_VARIATIONS: { name: VariationName; apply: (sfn: SFn) => SFn
|
|
|
458
470
|
* method are in `apps/benchmark/dataset/synthetic.ts`'s `/unmerge` block. */
|
|
459
471
|
export const PRE_RESPELL_VARIATIONS: typeof STACKED_VARIATIONS = [{ name: 'unmerge', apply: unmergeJoins }];
|
|
460
472
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
473
|
+
/** Every subset of `xs`, the empty one first, each in `xs`' order. */
|
|
474
|
+
const subsets = <X>(xs: readonly X[]): X[][] =>
|
|
475
|
+
xs.reduce<X[][]>((acc, x) => [...acc, ...acc.map((s) => [...s, x])], [[]]);
|
|
476
|
+
|
|
477
|
+
/** The stacked members a candidate applies: the table's two dimensions crossed, a shape choice
|
|
478
|
+
* (none, each shape alone, or every shape) by a width choice (any subset of the widths, none
|
|
479
|
+
* included), the shapes first. A product, because a function may need a shape AND a strict subset
|
|
480
|
+
* of the widths that fire: `initfirst` beside a narrow cast-written local and wide load-written
|
|
481
|
+
* ones (the matching suite compiles that pair both ways). The shapes are not a lattice of their own:
|
|
482
|
+
* applyStacked's skip-on-decline makes "every shape" each pair of them wherever the third declines,
|
|
483
|
+
* and a row demanding a strict subset of the shapes while all fire is what would earn one. Fewest
|
|
484
|
+
* members first, so where everything else ties the smaller set is enumerated first and wins. */
|
|
485
|
+
export const STACKED_SUBSETS: (typeof STACKED_VARIATIONS)[number][][] = subsets(STACKED_WIDTHS)
|
|
486
|
+
.flatMap((widths) =>
|
|
487
|
+
[[], ...STACKED_SHAPES.map((x) => [x]), ...(STACKED_SHAPES.length > 1 ? [STACKED_SHAPES] : [])].map((shapes) => [
|
|
488
|
+
...shapes,
|
|
489
|
+
...widths,
|
|
490
|
+
]),
|
|
491
|
+
)
|
|
492
|
+
.filter((subset) => subset.length > 0)
|
|
493
|
+
.sort((a, b) => a.length - b.length);
|
|
494
|
+
|
|
495
|
+
/** A stacked member that threw, named by the members that fired before it and then itself: the
|
|
496
|
+
* step that threw, which every subset reaching it shares. Reported under that name rather than
|
|
497
|
+
* the whole subset's, so a consumer deduping on the step prints one broken member once and not
|
|
498
|
+
* once per subset holding it. */
|
|
499
|
+
export class StackedMemberThrew extends Error {
|
|
500
|
+
constructor(
|
|
501
|
+
readonly variations: readonly VariationName[],
|
|
502
|
+
cause: unknown,
|
|
503
|
+
) {
|
|
504
|
+
super(cause instanceof Error ? cause.message : String(cause), { cause });
|
|
505
|
+
}
|
|
506
|
+
}
|
|
465
507
|
|
|
466
508
|
/** The subset applied in table order, SKIP-ON-DECLINE: a member that declines contributes
|
|
467
509
|
* nothing rather than killing the combination — the all-shapes candidate is "everything that
|
|
468
510
|
* fires", so a pair is reachable whenever the third declines. The variations are the members that
|
|
469
|
-
* actually FIRED, so they never name a variation that declined; a fired
|
|
470
|
-
* duplicates a smaller subset
|
|
471
|
-
* nothing fired. */
|
|
511
|
+
* actually FIRED, so they never name a variation that declined; a fired set that
|
|
512
|
+
* duplicates a smaller subset's derives the same tree, which the caller emits once
|
|
513
|
+
* (`firstFired`). Null when nothing fired. A member that throws throws StackedMemberThrew. */
|
|
472
514
|
export const applyStacked = (
|
|
473
515
|
subset: readonly (typeof STACKED_VARIATIONS)[number][],
|
|
474
516
|
from: SFn,
|
|
@@ -476,7 +518,12 @@ export const applyStacked = (
|
|
|
476
518
|
let cur = from;
|
|
477
519
|
const fired: VariationName[] = [];
|
|
478
520
|
for (const sp of subset) {
|
|
479
|
-
|
|
521
|
+
let r: SFn | null;
|
|
522
|
+
try {
|
|
523
|
+
r = sp.apply(cur);
|
|
524
|
+
} catch (e) {
|
|
525
|
+
throw new StackedMemberThrew([...fired, sp.name], e);
|
|
526
|
+
}
|
|
480
527
|
if (r) {
|
|
481
528
|
cur = r;
|
|
482
529
|
fired.push(sp.name);
|
|
@@ -485,6 +532,17 @@ export const applyStacked = (
|
|
|
485
532
|
return fired.length > 0 ? { out: cur, variations: fired } : null;
|
|
486
533
|
};
|
|
487
534
|
|
|
535
|
+
/** Whether `fired` is a fired set not yet in `seen`, recording it. Two subsets that fire the same
|
|
536
|
+
* members derive the same tree, so a caller emits only the first. */
|
|
537
|
+
export const firstFired = (seen: Set<string>, fired: readonly VariationName[]): boolean => {
|
|
538
|
+
const key = fired.join('/');
|
|
539
|
+
if (seen.has(key)) {
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
seen.add(key);
|
|
543
|
+
return true;
|
|
544
|
+
};
|
|
545
|
+
|
|
488
546
|
/** The locals a variation added — a NAME diff rather than a positional slice, so a pass that ever
|
|
489
547
|
* reorders locals cannot silently empty the set. It is what scopes `/volatile` to the pointers
|
|
490
548
|
* the variation itself created (volatilePtrLocals' `only`), leaving the tree's own locals alone. */
|