@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.
Files changed (130) hide show
  1. package/README.md +36 -31
  2. package/package.json +1 -1
  3. package/src/aggregate.ts +397 -0
  4. package/src/backend/c.ts +6 -2
  5. package/src/backend/cfamily.ts +370 -56
  6. package/src/backend/cpp.ts +116 -10
  7. package/src/backend/pascal.ts +69 -11
  8. package/src/cdecl/constant.ts +59 -0
  9. package/src/cdecl/lex.ts +209 -0
  10. package/src/cdecl/parse.ts +975 -0
  11. package/src/cdecl/spell.ts +69 -0
  12. package/src/codegen-flags.ts +38 -6
  13. package/src/compiler-diagnostics.ts +194 -0
  14. package/src/contracts.ts +777 -84
  15. package/src/declare.ts +132 -13
  16. package/src/frontend/asmdata.ts +26 -6
  17. package/src/frontend/call-plan.ts +1590 -0
  18. package/src/frontend/dead-reads.ts +628 -0
  19. package/src/frontend/device-pins.ts +296 -0
  20. package/src/frontend/emit.ts +4 -3
  21. package/src/frontend/errors.ts +5 -0
  22. package/src/frontend/flags-edge.ts +101 -0
  23. package/src/frontend/fpu.ts +374 -0
  24. package/src/frontend/frame-objects.ts +3171 -0
  25. package/src/frontend/frontend.ts +64 -3
  26. package/src/frontend/high-half.ts +55 -5
  27. package/src/frontend/jump-table.ts +530 -0
  28. package/src/frontend/local-object.ts +616 -0
  29. package/src/frontend/mips.ts +2392 -208
  30. package/src/frontend/opaque.ts +97 -18
  31. package/src/frontend/own-struct-return.ts +500 -0
  32. package/src/frontend/ppc.ts +3137 -267
  33. package/src/frontend/register-struct-call.ts +484 -0
  34. package/src/frontend/reloc-symbol.ts +109 -13
  35. package/src/frontend/splat.ts +108 -5
  36. package/src/frontend/ssa.ts +2098 -89
  37. package/src/frontend/stackargs.ts +172 -42
  38. package/src/frontend/thumb.ts +4563 -2091
  39. package/src/ir/alias.ts +71 -0
  40. package/src/ir/bits.ts +681 -1
  41. package/src/ir/core.ts +199 -6
  42. package/src/ir/discipline.ts +313 -0
  43. package/src/ir/entry.ts +159 -0
  44. package/src/ir/float-bits.ts +47 -0
  45. package/src/{structure → ir}/loops.ts +6 -2
  46. package/src/ir/opcodes.ts +193 -121
  47. package/src/ir/parse.ts +1 -0
  48. package/src/ir/types.ts +202 -2
  49. package/src/ir/verify.ts +219 -3
  50. package/src/l3/address.ts +5 -0
  51. package/src/l3/argcopy.ts +38 -6
  52. package/src/l3/ast.ts +467 -23
  53. package/src/l3/basecse.ts +33 -5
  54. package/src/l3/coalesce.ts +21 -13
  55. package/src/l3/constinit.ts +382 -0
  56. package/src/l3/dce.ts +34 -12
  57. package/src/l3/gates.ts +9 -3
  58. package/src/l3/hoist.ts +8 -7
  59. package/src/l3/initfirst.ts +68 -19
  60. package/src/l3/intcell.ts +98 -0
  61. package/src/l3/mentions.ts +10 -4
  62. package/src/l3/narrowdecl.ts +259 -0
  63. package/src/l3/nearbase.ts +10 -5
  64. package/src/l3/parkfirst.ts +8 -5
  65. package/src/l3/pollguard.ts +11 -4
  66. package/src/l3/ptrcell.ts +354 -0
  67. package/src/l3/ptrfield.ts +123 -8
  68. package/src/l3/regspell.ts +26 -7
  69. package/src/l3/reindex.ts +293 -103
  70. package/src/l3/storage.ts +98 -1
  71. package/src/l3/symbol-refs.ts +182 -23
  72. package/src/l3/tailmerge.ts +9 -20
  73. package/src/l3/typing.ts +237 -32
  74. package/src/l3/unreduce.ts +10 -9
  75. package/src/l3/volatileptr.ts +17 -54
  76. package/src/l3/volstore.ts +96 -7
  77. package/src/mangle.ts +41 -1
  78. package/src/pattern/engine.ts +373 -82
  79. package/src/pipeline.ts +589 -27
  80. package/src/proto-context.ts +1648 -0
  81. package/src/proto.ts +1203 -49
  82. package/src/raise/aggmembers.ts +290 -0
  83. package/src/raise/arrays.ts +8 -3
  84. package/src/raise/declared-volatile.ts +307 -0
  85. package/src/raise/divpow2.ts +2 -2
  86. package/src/raise/errors.ts +17 -0
  87. package/src/raise/floathelpers.ts +464 -0
  88. package/src/raise/globalshape.ts +11 -5
  89. package/src/raise/gvn.ts +29 -8
  90. package/src/raise/latch.ts +162 -6
  91. package/src/raise/memberarrays.ts +10 -4
  92. package/src/raise/narrow.ts +29 -2
  93. package/src/raise/narrowlocal.ts +11 -6
  94. package/src/raise/offsetnames.ts +494 -0
  95. package/src/raise/pairparams.ts +114 -0
  96. package/src/raise/paramwidth.ts +203 -6
  97. package/src/raise/pre-recovery.ts +174 -17
  98. package/src/raise/pre-structure.ts +54 -0
  99. package/src/raise/recover.ts +26 -15
  100. package/src/raise/reroll.ts +694 -0
  101. package/src/raise/retsink.ts +1 -1
  102. package/src/raise/shortcircuit.ts +66 -30
  103. package/src/raise/softdiv.ts +21 -23
  104. package/src/raise/storesign.ts +153 -0
  105. package/src/raise/struct-arrays.ts +34 -14
  106. package/src/raise/structs.ts +674 -98
  107. package/src/raise/truncload.ts +367 -0
  108. package/src/raise/unthread.ts +400 -0
  109. package/src/raise/widehelpers.ts +106 -0
  110. package/src/rank-declare.ts +143 -12
  111. package/src/rank-variations.ts +117 -31
  112. package/src/rank.ts +563 -122
  113. package/src/runtime-helpers.ts +405 -0
  114. package/src/stillborn.ts +289 -0
  115. package/src/structure/analysis.ts +1449 -449
  116. package/src/structure/arith-ops.ts +23 -0
  117. package/src/structure/globalaccess.ts +111 -9
  118. package/src/structure/hazards.ts +641 -114
  119. package/src/structure/local-statics.ts +517 -0
  120. package/src/structure/namecoalesce.ts +2 -2
  121. package/src/structure/pointer-spelling.ts +1106 -0
  122. package/src/structure/redundant-test.ts +99 -0
  123. package/src/structure/structure.ts +3478 -975
  124. package/src/structure/switch-recover.ts +403 -178
  125. package/src/symbols.ts +44 -3
  126. package/src/target.ts +1387 -71
  127. package/src/trace.ts +66 -28
  128. package/src/variation-definitions.ts +243 -13
  129. package/src/variation-gates.ts +2 -0
  130. 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
+ }