@asmlift/core 0.8.1 → 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 +36 -31
- package/package.json +1 -1
- package/src/aggregate.ts +397 -0
- package/src/backend/c.ts +6 -2
- package/src/backend/cfamily.ts +370 -56
- package/src/backend/cpp.ts +116 -10
- package/src/backend/pascal.ts +69 -11
- package/src/cdecl/constant.ts +59 -0
- package/src/cdecl/lex.ts +209 -0
- package/src/cdecl/parse.ts +975 -0
- package/src/cdecl/spell.ts +69 -0
- package/src/codegen-flags.ts +38 -6
- package/src/compiler-diagnostics.ts +194 -0
- package/src/contracts.ts +777 -84
- package/src/declare.ts +132 -13
- package/src/frontend/asmdata.ts +26 -6
- package/src/frontend/call-plan.ts +1590 -0
- package/src/frontend/dead-reads.ts +628 -0
- package/src/frontend/device-pins.ts +296 -0
- package/src/frontend/emit.ts +4 -3
- package/src/frontend/errors.ts +5 -0
- package/src/frontend/flags-edge.ts +101 -0
- package/src/frontend/fpu.ts +374 -0
- package/src/frontend/frame-objects.ts +3171 -0
- package/src/frontend/frontend.ts +64 -3
- package/src/frontend/high-half.ts +55 -5
- package/src/frontend/jump-table.ts +530 -0
- package/src/frontend/local-object.ts +616 -0
- package/src/frontend/mips.ts +2392 -208
- package/src/frontend/opaque.ts +97 -18
- package/src/frontend/own-struct-return.ts +500 -0
- package/src/frontend/ppc.ts +3137 -267
- package/src/frontend/register-struct-call.ts +484 -0
- package/src/frontend/reloc-symbol.ts +109 -13
- package/src/frontend/splat.ts +108 -5
- package/src/frontend/ssa.ts +2098 -89
- package/src/frontend/stackargs.ts +172 -42
- package/src/frontend/thumb.ts +4563 -2091
- package/src/ir/alias.ts +71 -0
- package/src/ir/bits.ts +681 -1
- package/src/ir/core.ts +199 -6
- package/src/ir/discipline.ts +313 -0
- package/src/ir/entry.ts +159 -0
- package/src/ir/float-bits.ts +47 -0
- package/src/{structure → ir}/loops.ts +6 -2
- package/src/ir/opcodes.ts +193 -121
- package/src/ir/parse.ts +1 -0
- package/src/ir/types.ts +202 -2
- package/src/ir/verify.ts +219 -3
- package/src/l3/address.ts +5 -0
- package/src/l3/argcopy.ts +38 -6
- package/src/l3/ast.ts +467 -23
- package/src/l3/basecse.ts +33 -5
- package/src/l3/coalesce.ts +21 -13
- package/src/l3/constinit.ts +382 -0
- package/src/l3/dce.ts +34 -12
- package/src/l3/gates.ts +9 -3
- package/src/l3/hoist.ts +8 -7
- package/src/l3/initfirst.ts +68 -19
- package/src/l3/intcell.ts +98 -0
- package/src/l3/mentions.ts +10 -4
- package/src/l3/narrowdecl.ts +259 -0
- package/src/l3/nearbase.ts +10 -5
- package/src/l3/parkfirst.ts +8 -5
- package/src/l3/pollguard.ts +11 -4
- package/src/l3/ptrcell.ts +354 -0
- package/src/l3/ptrfield.ts +123 -8
- package/src/l3/regspell.ts +26 -7
- package/src/l3/reindex.ts +293 -103
- package/src/l3/storage.ts +98 -1
- package/src/l3/symbol-refs.ts +182 -23
- package/src/l3/tailmerge.ts +9 -20
- package/src/l3/typing.ts +237 -32
- package/src/l3/unreduce.ts +10 -9
- package/src/l3/volatileptr.ts +17 -54
- package/src/l3/volstore.ts +96 -7
- package/src/mangle.ts +41 -1
- package/src/pattern/engine.ts +373 -82
- package/src/pipeline.ts +589 -27
- package/src/proto-context.ts +1648 -0
- package/src/proto.ts +1203 -49
- package/src/raise/aggmembers.ts +290 -0
- package/src/raise/arrays.ts +8 -3
- package/src/raise/declared-volatile.ts +307 -0
- package/src/raise/divpow2.ts +2 -2
- package/src/raise/errors.ts +17 -0
- package/src/raise/floathelpers.ts +464 -0
- package/src/raise/globalshape.ts +11 -5
- package/src/raise/gvn.ts +29 -8
- package/src/raise/latch.ts +162 -6
- package/src/raise/memberarrays.ts +10 -4
- package/src/raise/narrow.ts +29 -2
- package/src/raise/narrowlocal.ts +11 -6
- package/src/raise/offsetnames.ts +494 -0
- package/src/raise/pairparams.ts +114 -0
- package/src/raise/paramwidth.ts +203 -6
- package/src/raise/pre-recovery.ts +174 -17
- package/src/raise/pre-structure.ts +54 -0
- package/src/raise/recover.ts +26 -15
- package/src/raise/reroll.ts +694 -0
- package/src/raise/retsink.ts +1 -1
- package/src/raise/shortcircuit.ts +66 -30
- package/src/raise/softdiv.ts +21 -23
- package/src/raise/storesign.ts +153 -0
- package/src/raise/struct-arrays.ts +34 -14
- package/src/raise/structs.ts +674 -98
- package/src/raise/truncload.ts +367 -0
- package/src/raise/unthread.ts +400 -0
- package/src/raise/widehelpers.ts +106 -0
- package/src/rank-declare.ts +143 -12
- package/src/rank-variations.ts +117 -31
- package/src/rank.ts +563 -122
- package/src/runtime-helpers.ts +405 -0
- package/src/stillborn.ts +289 -0
- package/src/structure/analysis.ts +1449 -449
- package/src/structure/arith-ops.ts +23 -0
- package/src/structure/globalaccess.ts +111 -9
- package/src/structure/hazards.ts +641 -114
- package/src/structure/local-statics.ts +517 -0
- package/src/structure/namecoalesce.ts +2 -2
- package/src/structure/pointer-spelling.ts +1106 -0
- package/src/structure/redundant-test.ts +99 -0
- package/src/structure/structure.ts +3478 -975
- package/src/structure/switch-recover.ts +403 -178
- package/src/symbols.ts +44 -3
- package/src/target.ts +1387 -71
- package/src/trace.ts +66 -28
- package/src/variation-definitions.ts +243 -13
- package/src/variation-gates.ts +2 -0
- package/src/variation-tokens.ts +25 -7
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// asmlift structurer — whether a test that READS MEMORY, and whose two arms spell the SAME
|
|
2
|
+
// statements, can be left out of the C. It decides nothing (both outcomes run the same code next —
|
|
3
|
+
// usually none, or the same edge copy into a join), and leaving it out must drop no access the
|
|
4
|
+
// machine made on that path. Without this the `if` reaches `l3/tailmerge.ts` and `l3/dce.ts`,
|
|
5
|
+
// which hoist the common statements and keep a condition that reads memory as a bare statement
|
|
6
|
+
// (`a1[14] >= 1;`), because they cannot tell a read the machine made there from one it made
|
|
7
|
+
// elsewhere.
|
|
8
|
+
//
|
|
9
|
+
// The IR can. The test is left out when every memory read in its operand cone is a load whose
|
|
10
|
+
// value something OUTSIDE the cone also reads, on the test's own path: a reader in a block that
|
|
11
|
+
// dominates the test's, or one that post-dominates it, and inside exactly the loops the test is
|
|
12
|
+
// in. The C then performs that read as often as the test runs, so the bare statement would be a
|
|
13
|
+
// second read of a value the machine loaded once. A reader on a SIBLING path is not one:
|
|
14
|
+
// `if (a1 != 0) *a2 = *a0; else *a0 < 0;` reads `*a0` on both paths, and without its test the
|
|
15
|
+
// `a1 == 0` path reads nothing. Nor is a reader after the loop the test is in: it post-dominates
|
|
16
|
+
// the test and runs once, where the test and its load run on every iteration, so a volatile
|
|
17
|
+
// register read N times would be read once. A load only this test
|
|
18
|
+
// reads is the machine's one access there and keeps the statement, as does a call or other effect
|
|
19
|
+
// in the cone. A `volatile` load needs nothing more: an on-path reader already performs the one
|
|
20
|
+
// access the machine made, and keeping the test beside it would add a second.
|
|
21
|
+
//
|
|
22
|
+
// A test that reads NO memory is left to the passes after this one: an empty `if` over registers
|
|
23
|
+
// is one `l3/dce.ts` already deletes, and one whose two arms are the same non-empty statements
|
|
24
|
+
// prints as the lift spelled it. Collapsing those too was measured behaviour-preserving (9 more
|
|
25
|
+
// GameCube functions change, 0 benchmark rows) and is left out because nothing in them is read
|
|
26
|
+
// twice.
|
|
27
|
+
//
|
|
28
|
+
// Where the shape comes from: CodeWarrior folds a `case` label into `default:` and keeps its test,
|
|
29
|
+
// so `case 1: … case 0: default: …` dispatches `beq case1; bge default; b default` (mwcc_242_81;
|
|
30
|
+
// ac-decomp mTG_select_tag_decide_needlework, and aSNMgr_set_appear_info_guest, whose two edges
|
|
31
|
+
// carry the same merge value); pikmin UpdateMgr::removeClient keeps an assert's `blt`, whose other
|
|
32
|
+
// side held only a dead load.
|
|
33
|
+
//
|
|
34
|
+
// RENDERING ONLY, and deliberately not a CFG rewrite ahead of the raising tower: a pre-recovery
|
|
35
|
+
// pass turning the same `cond_br` into a `br` costs `af:adds:ido7.1` 6/41 -> 18/41. ido guards a
|
|
36
|
+
// `div` with `bne v0, at` over the numerator, the MIPS lift keeps that trap check as a branch whose
|
|
37
|
+
// arms meet, and that compare is the out-of-block reader that offers `/escape-home` on the
|
|
38
|
+
// numerator, the spelling that wins.
|
|
39
|
+
import type { Block, Op, Value } from '../ir/core';
|
|
40
|
+
import { effectful } from '../ir/discipline';
|
|
41
|
+
import type { NaturalLoop } from '../ir/loops';
|
|
42
|
+
import { opSig } from '../ir/opcodes';
|
|
43
|
+
import type { UseSite } from './analysis';
|
|
44
|
+
|
|
45
|
+
export interface RedundantTestDeps {
|
|
46
|
+
defs: Map<Value, Op>;
|
|
47
|
+
useSitesOf: Map<Value, UseSite[]>;
|
|
48
|
+
dom: Map<Block, Set<Block>>;
|
|
49
|
+
ipdom: Map<Block, Block | null>;
|
|
50
|
+
loops: Iterable<NaturalLoop>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Whether `branch`, the terminator of `at`, only re-reads what the machine read on its path. */
|
|
54
|
+
export function testRereadsOnly(branch: Op, at: Block, deps: RedundantTestDeps): boolean {
|
|
55
|
+
const { defs, useSitesOf, dom, ipdom } = deps;
|
|
56
|
+
const loops = [...deps.loops];
|
|
57
|
+
const cone = new Set<Op>();
|
|
58
|
+
const loads: Op[] = [];
|
|
59
|
+
const work = [...branch.operands];
|
|
60
|
+
for (let v = work.pop(); v !== undefined; v = work.pop()) {
|
|
61
|
+
const op = defs.get(v);
|
|
62
|
+
if (op === undefined || cone.has(op)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (effectful(op)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
cone.add(op);
|
|
69
|
+
if (opSig(op.opcode)?.reads === true) {
|
|
70
|
+
loads.push(op);
|
|
71
|
+
}
|
|
72
|
+
work.push(...op.operands);
|
|
73
|
+
}
|
|
74
|
+
// Dominance and post-dominance say a reader runs whenever the test does, not as often: a loop
|
|
75
|
+
// between them repeats one and not the other.
|
|
76
|
+
const sameLoops = (b: Block): boolean => loops.every((l) => l.body.has(b) === l.body.has(at));
|
|
77
|
+
const onPath = (b: Block): boolean => {
|
|
78
|
+
if (!sameLoops(b)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (dom.get(at)?.has(b)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
for (let p = ipdom.get(at); p; p = ipdom.get(p)) {
|
|
85
|
+
if (p === b) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
};
|
|
91
|
+
return (
|
|
92
|
+
loads.length > 0 &&
|
|
93
|
+
loads.every((ld) =>
|
|
94
|
+
ld.results.some((r) =>
|
|
95
|
+
(useSitesOf.get(r) ?? []).some((u) => u.op !== branch && !cone.has(u.op) && onPath(u.blk)),
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
}
|