@asmlift/core 0.8.1 → 0.9.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 +34 -30
- package/package.json +1 -1
- package/src/aggregate.ts +248 -0
- package/src/backend/c.ts +5 -2
- package/src/backend/cfamily.ts +236 -37
- package/src/backend/cpp.ts +114 -9
- package/src/backend/pascal.ts +39 -0
- 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 +615 -79
- package/src/declare.ts +75 -5
- package/src/frontend/asmdata.ts +19 -5
- package/src/frontend/call-plan.ts +686 -0
- package/src/frontend/device-pins.ts +277 -0
- package/src/frontend/errors.ts +5 -0
- package/src/frontend/flags-edge.ts +101 -0
- package/src/frontend/fpu.ts +167 -0
- package/src/frontend/frame-objects.ts +2131 -0
- package/src/frontend/high-half.ts +2 -1
- package/src/frontend/local-object.ts +490 -0
- package/src/frontend/mips.ts +363 -40
- package/src/frontend/opaque.ts +97 -18
- package/src/frontend/ppc.ts +520 -129
- package/src/frontend/reloc-symbol.ts +94 -13
- package/src/frontend/splat.ts +108 -5
- package/src/frontend/ssa.ts +669 -76
- package/src/frontend/stackargs.ts +120 -39
- package/src/frontend/thumb.ts +2764 -2018
- package/src/ir/alias.ts +29 -0
- package/src/ir/core.ts +101 -3
- package/src/ir/discipline.ts +248 -0
- package/src/ir/float-bits.ts +47 -0
- package/src/ir/opcodes.ts +84 -112
- package/src/ir/parse.ts +1 -0
- package/src/ir/types.ts +118 -2
- package/src/ir/verify.ts +150 -3
- package/src/l3/address.ts +5 -0
- package/src/l3/argcopy.ts +38 -6
- package/src/l3/ast.ts +186 -14
- package/src/l3/coalesce.ts +21 -13
- package/src/l3/dce.ts +32 -10
- package/src/l3/gates.ts +9 -3
- package/src/l3/hoist.ts +8 -7
- package/src/l3/initfirst.ts +27 -9
- package/src/l3/intcell.ts +97 -0
- package/src/l3/mentions.ts +10 -4
- package/src/l3/narrowdecl.ts +218 -0
- package/src/l3/nearbase.ts +10 -5
- package/src/l3/parkfirst.ts +8 -5
- package/src/l3/pollguard.ts +3 -2
- package/src/l3/ptrcell.ts +357 -0
- package/src/l3/regspell.ts +17 -3
- package/src/l3/reindex.ts +10 -7
- package/src/l3/symbol-refs.ts +104 -23
- package/src/l3/tailmerge.ts +6 -19
- package/src/l3/typing.ts +137 -25
- package/src/l3/unreduce.ts +4 -4
- package/src/l3/volstore.ts +96 -7
- package/src/mangle.ts +11 -1
- package/src/pattern/engine.ts +19 -16
- package/src/pipeline.ts +57 -12
- package/src/proto-context.ts +788 -0
- package/src/proto.ts +689 -50
- package/src/raise/arrays.ts +4 -3
- package/src/raise/declared-volatile.ts +131 -0
- package/src/raise/divpow2.ts +2 -2
- package/src/raise/errors.ts +17 -0
- package/src/raise/floathelpers.ts +243 -0
- package/src/raise/globalshape.ts +11 -5
- package/src/raise/gvn.ts +26 -5
- package/src/raise/narrow.ts +29 -2
- package/src/raise/narrowlocal.ts +11 -6
- package/src/raise/offsetnames.ts +510 -0
- package/src/raise/pairparams.ts +81 -0
- package/src/raise/paramwidth.ts +7 -0
- package/src/raise/pre-recovery.ts +78 -4
- package/src/raise/recover.ts +14 -10
- package/src/raise/retsink.ts +1 -1
- package/src/raise/shortcircuit.ts +41 -19
- package/src/raise/softdiv.ts +21 -23
- package/src/raise/struct-arrays.ts +5 -4
- package/src/raise/structs.ts +311 -98
- package/src/raise/truncload.ts +366 -0
- package/src/raise/widehelpers.ts +106 -0
- package/src/rank-declare.ts +30 -5
- package/src/rank-variations.ts +36 -8
- package/src/rank.ts +267 -79
- package/src/runtime-helpers.ts +287 -0
- package/src/stillborn.ts +289 -0
- package/src/structure/analysis.ts +1285 -448
- package/src/structure/hazards.ts +633 -58
- package/src/structure/local-statics.ts +381 -0
- package/src/structure/namecoalesce.ts +1 -1
- package/src/structure/redundant-test.ts +99 -0
- package/src/structure/structure.ts +1772 -395
- package/src/structure/switch-recover.ts +159 -78
- package/src/symbols.ts +38 -3
- package/src/target.ts +662 -59
- package/src/trace.ts +44 -24
- package/src/variation-definitions.ts +119 -1
- package/src/variation-tokens.ts +20 -6
package/src/pipeline.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
assertDerefsTyped,
|
|
7
7
|
assertEffectsPreserved,
|
|
8
8
|
assertLocalsWritten,
|
|
9
|
+
assertPostIncrUnshared,
|
|
9
10
|
assertResolved,
|
|
10
11
|
assertTypesRecovered,
|
|
11
12
|
} from './contracts';
|
|
@@ -23,10 +24,12 @@ import { eliminateDeadStores } from './l3/dce';
|
|
|
23
24
|
import { mergeCommonTails } from './l3/tailmerge';
|
|
24
25
|
import { dropUnspelledReturns } from './l3/tailret';
|
|
25
26
|
import { DEFAULT_IDIOM_PATTERNS, RewritePattern, applyPattern, dce, patternApplies } from './pattern/engine';
|
|
26
|
-
import { type FnProto, type Prototypes, prototypesFromSymbols } from './proto';
|
|
27
|
+
import { type FnProto, type Prototypes, declaresVoidReturn, prototypesFromSymbols } from './proto';
|
|
28
|
+
import { stampDeclaredVolatileUnder } from './raise/declared-volatile';
|
|
27
29
|
import { RaiseUnsupportedError } from './raise/errors';
|
|
28
30
|
import { assumedShapes, inferGlobalArrays, orderLicensedGlobals } from './raise/globalshape';
|
|
29
31
|
import { foldEmptyLatches } from './raise/latch';
|
|
32
|
+
import { OFFSET_NAME_PASS } from './raise/offsetnames';
|
|
30
33
|
import { type PreRecoveryOptions, type PreRecoveryPass, runPreRecovery } from './raise/pre-recovery';
|
|
31
34
|
import { recoverTypes } from './raise/recover';
|
|
32
35
|
import { sinkReturns } from './raise/retsink';
|
|
@@ -109,6 +112,14 @@ export interface DecompileResult {
|
|
|
109
112
|
* bare, and every name the caller's own map described (raise/globalshape.ts `assumedShapes`
|
|
110
113
|
* computes that narrowing and names the corpus row behind each half). */
|
|
111
114
|
assumedSymbols: SymbolInfo[];
|
|
115
|
+
/** THE NAMES THIS SOURCE REACHED BY ARITHMETIC, not by the map alone (raise/offsetnames.ts).
|
|
116
|
+
* A pool-loaded `gaddr` is the map answering about an address the machine code carries; a
|
|
117
|
+
* walked one is asmlift computing `addr(base) + K` and asking about THAT — so the base's own
|
|
118
|
+
* address in the map is load-bearing for a name the reader sees spelled bare. Sibling of
|
|
119
|
+
* `assumedSymbols` and reported beside it (`main.ts`'s `[walked]` block, the trace's
|
|
120
|
+
* `stage:offsetnames`), and it is also the only thing in a result that says a walk spelling
|
|
121
|
+
* stopped being enumerable here. Empty on every run with no symbol map. */
|
|
122
|
+
walkedNames: string[];
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
export function decompile(
|
|
@@ -144,8 +155,7 @@ function runTower(
|
|
|
144
155
|
// CALLEES (a function still in assembly has none), which is what makes this transferable.
|
|
145
156
|
const prototypes = prototypesFromSymbols(opts.symbols, opts.prototypes ?? {});
|
|
146
157
|
// (1) lift: ISA frontend (resolved by target) → L1 with block-argument SSA
|
|
147
|
-
const fn =
|
|
148
|
-
verify(fn);
|
|
158
|
+
const fn = liftStamped(name, asm, target, prototypes, opts.asmData, opts.symbols);
|
|
149
159
|
// Every dump carries the write-order record (ir/print.ts `PrintOptions`): it decides the
|
|
150
160
|
// edge-copy order and the raising folds mutate it, so two dumps compare whole program states.
|
|
151
161
|
const raw = print(fn, { writeOrder: true });
|
|
@@ -157,6 +167,18 @@ function runTower(
|
|
|
157
167
|
// …and the ORDER half of the same reading, which reaches names the shape derivation refuses (a
|
|
158
168
|
// struct element among them). Read off the same lifted fn, for the same reason.
|
|
159
169
|
const orderLicensed = orderLicensedGlobals(fn, target);
|
|
170
|
+
// (1.6) …and the NAMES the map holds for the addresses this function's machine code built by
|
|
171
|
+
// arithmetic off a named one (raise/offsetnames.ts). After the two readings above, which are
|
|
172
|
+
// about the lift as the frontend emitted it; before everything below, so the whole raising
|
|
173
|
+
// tower sees a walked-to cell as the named global it is.
|
|
174
|
+
//
|
|
175
|
+
// The two readings therefore attribute a walked access to the base rather than to the name this
|
|
176
|
+
// pass gives it, and that costs nothing either way: a SHAPE is a declaration, so a name the map
|
|
177
|
+
// describes — which every base here is, or the pass could not have fired — is dropped from
|
|
178
|
+
// `inferredSymbols`, and the ORDER licence only enables a cast spelling that is byte-correct
|
|
179
|
+
// under any declaration. Measured: with this call moved ABOVE both readings, the three corpus
|
|
180
|
+
// rows the pass fires on keep their fan size, their winner and their score exactly.
|
|
181
|
+
const walkedNames = opts.symbols ? OFFSET_NAME_PASS.run(fn, opts.symbols, target.compilerBehaviors) : [];
|
|
160
182
|
|
|
161
183
|
// (2) idiom fold: apply serializable patterns on the IR (the AI-improvement surface),
|
|
162
184
|
// gated generically by the Target's capabilities (not an `arch ==` branch).
|
|
@@ -172,7 +194,7 @@ function runTower(
|
|
|
172
194
|
// every unresolved value spelled as a loud ASMLIFT_ERROR marker (annotate).
|
|
173
195
|
const mapSymbols = opts.symbols ? symbolsByName(opts.symbols) : undefined;
|
|
174
196
|
const sfn = structureChecked(fn, {
|
|
175
|
-
...structureOptionsFor(target, prototypes[name]
|
|
197
|
+
...structureOptionsFor(target, declaresVoidReturn(prototypes[name]), prototypes),
|
|
176
198
|
// What the EMITTED LANGUAGE can say is a structuring input wherever two recoveries of one
|
|
177
199
|
// shape are behaviourally identical and only one of them is printable (switch fall-through
|
|
178
200
|
// vs plain if-nesting): recovery must not mint a tree this backend would refuse.
|
|
@@ -196,9 +218,28 @@ function runTower(
|
|
|
196
218
|
// spell bare, and a name the caller's own map described, are both obligations this reader
|
|
197
219
|
// does not have (raise/globalshape.ts `assumedShapes`).
|
|
198
220
|
assumedSymbols: assumedShapes(inferredSymbols, sfn, mapSymbols),
|
|
221
|
+
walkedNames,
|
|
199
222
|
};
|
|
200
223
|
}
|
|
201
224
|
|
|
225
|
+
/** Stage 1 — lift: the target's ISA frontend → L1, verified, with every read of an object
|
|
226
|
+
* `symbols` declares volatile stamped `declared` (raise/declared-volatile.ts) before any pass asks
|
|
227
|
+
* whether it may be deleted. Every entry path lifts through here, each lift under the map its
|
|
228
|
+
* structuring will be handed. */
|
|
229
|
+
export function liftStamped(
|
|
230
|
+
name: string,
|
|
231
|
+
asm: string,
|
|
232
|
+
target: TargetDescription,
|
|
233
|
+
prototypes: Prototypes,
|
|
234
|
+
asmData: AsmData | undefined,
|
|
235
|
+
symbols: SymbolMap | undefined,
|
|
236
|
+
): Fn {
|
|
237
|
+
const fn = frontendFor(target).lift(name, asm, target, prototypes, asmData, symbols);
|
|
238
|
+
verify(fn);
|
|
239
|
+
stampDeclaredVolatileUnder(fn, symbols, target.compilerBehaviors);
|
|
240
|
+
return fn;
|
|
241
|
+
}
|
|
242
|
+
|
|
202
243
|
// ── the shared raising tower ────────────────────────────────────────────────────────────────
|
|
203
244
|
// decompile(), decompileTraced (trace.ts), rank.ts's decompileRanked and the cli's
|
|
204
245
|
// decompileWithReport + its score probe (report.ts) all raise a lifted fn through the SAME stage
|
|
@@ -314,7 +355,7 @@ export function raiseRecovered(
|
|
|
314
355
|
/** Run `body`; if it declines, name the unmodelled instructions the function carries.
|
|
315
356
|
*
|
|
316
357
|
* An `opaque` degrades its own value AND makes its block impure, so a shape recognizer refuses:
|
|
317
|
-
*
|
|
358
|
+
* a loop none of whose recognizers takes it declines with "unrecovered back-edge …".
|
|
318
359
|
* True and useless — the shape is fine, an instruction is missing — and the benchmark classifies
|
|
319
360
|
* declines by that text, so the round is filed as a loop-capability gap and the improvement loop
|
|
320
361
|
* builds the wrong thing.
|
|
@@ -331,20 +372,21 @@ function attributeOpaques<T>(fn: Fn, body: () => T): T {
|
|
|
331
372
|
throw e;
|
|
332
373
|
}
|
|
333
374
|
const seen = reachableBlocks(fn);
|
|
334
|
-
|
|
375
|
+
// THE REASONS, not the mnemonics: an `opaque` a recogniser left behind for a runtime helper it
|
|
376
|
+
// could not fold carries no mnemonic at all, and asking for one would attribute the decline to
|
|
377
|
+
// an instruction named `?`.
|
|
378
|
+
const reasons = new Set<string>();
|
|
335
379
|
for (const b of seen) {
|
|
336
380
|
for (const op of b.ops) {
|
|
337
381
|
if (op.opcode === 'opaque') {
|
|
338
|
-
|
|
382
|
+
reasons.add(gapReasonFor(op.attrs));
|
|
339
383
|
}
|
|
340
384
|
}
|
|
341
385
|
}
|
|
342
|
-
if (!
|
|
386
|
+
if (!reasons.size || /unmodelled instruction|no model for the runtime helper/.test(e.message)) {
|
|
343
387
|
throw e;
|
|
344
388
|
}
|
|
345
|
-
|
|
346
|
-
// misses the mnemonic-anchored classes and every attributed decline lands in the generic bucket.
|
|
347
|
-
const list = [...names].sort().map(gapReasonFor).join(', ');
|
|
389
|
+
const list = [...reasons].sort().join(', ');
|
|
348
390
|
throw new StructureError(`${e.message} — and the function carries ${list}, which is the more likely cause`);
|
|
349
391
|
}
|
|
350
392
|
}
|
|
@@ -382,11 +424,13 @@ export function structureChecked(
|
|
|
382
424
|
assertResolved(raw);
|
|
383
425
|
assertDerefsTyped(raw);
|
|
384
426
|
assertLocalsWritten(raw);
|
|
427
|
+
assertPostIncrUnshared(raw);
|
|
385
428
|
assertEffectsPreserved(fn, raw);
|
|
386
429
|
// The hoist moves the deref cast from each `index` node onto the local's initializer, so
|
|
387
430
|
// re-validate deref typing on the rewritten tree.
|
|
388
431
|
const sfn = readabilityRewrites(raw);
|
|
389
432
|
assertDerefsTyped(sfn);
|
|
433
|
+
assertPostIncrUnshared(sfn);
|
|
390
434
|
// Re-checked after the readability rewrites for the same reason deref typing is: a pass that
|
|
391
435
|
// merges arms or drops statements must not be able to lose or duplicate a call.
|
|
392
436
|
assertEffectsPreserved(fn, sfn);
|
|
@@ -445,8 +489,9 @@ export function stubResult(name: string, asm: string, backend: LanguageBackend,
|
|
|
445
489
|
ir: { raw: '', folded: '', recovered: '' },
|
|
446
490
|
patternHits: 0,
|
|
447
491
|
diagnostics: [{ stage, reason: msg }],
|
|
448
|
-
// A stub spells no global, so it assumes nothing about one.
|
|
492
|
+
// A stub spells no global, so it assumes nothing about one and walked to none.
|
|
449
493
|
assumedSymbols: [],
|
|
494
|
+
walkedNames: [],
|
|
450
495
|
};
|
|
451
496
|
}
|
|
452
497
|
|