@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/declare.ts
CHANGED
|
@@ -19,8 +19,10 @@
|
|
|
19
19
|
// ldrb+lsl+asr where u8 is ldrb alone, so a guessed signedness is a wrong-bytes decl;
|
|
20
20
|
// • `volatile` is load-bearing (a non-volatile MMIO decl lets the compiler fold/reorder
|
|
21
21
|
// accesses), `const` is the ROM-table spelling;
|
|
22
|
-
// • code symbols get `void Name(void);`
|
|
23
|
-
//
|
|
22
|
+
// • code symbols get `void Name(void);` when value-referenced, and a CALL TARGET gets its own
|
|
23
|
+
// prototype re-spelled from the project's `FnProto` — only where that states both a typed
|
|
24
|
+
// parameter list and a `returns`, because `void Name(void);` over a call that passes
|
|
25
|
+
// arguments is C89 poison (core decides it: `spellableProto`);
|
|
24
26
|
// • nothing guesses, with TWO documented exceptions: a SHAPED symbol without the facts to
|
|
25
27
|
// declare faithfully is SKIPPED — the candidate then fails to compile LOUDLY and is
|
|
26
28
|
// dropped by rankBy. Exception one is the 4-byte signless-non-pointer cell (see
|
|
@@ -51,6 +53,7 @@
|
|
|
51
53
|
import { type StructFieldDecl, renderStructDecl } from './backend/cfamily';
|
|
52
54
|
import { T } from './ir/types';
|
|
53
55
|
import type { SymbolRef } from './l3/symbol-refs';
|
|
56
|
+
import { type AggregateLayout, type AggregateMember, declaredWidth, spellableType } from './proto';
|
|
54
57
|
import {
|
|
55
58
|
ENUM_IS_SIGNED,
|
|
56
59
|
type SymbolInfo,
|
|
@@ -134,6 +137,43 @@ function structDecl(tag: string, layout: SymbolStructField[] | undefined, size:
|
|
|
134
137
|
return renderStructDecl(tag, fields);
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
/** A struct the project's headers define, transcribed from their declaration so the compiler lays
|
|
141
|
+
* it out as it lays out theirs: each member in order with its extents and bit width, a nested
|
|
142
|
+
* struct or union inline, and every type spelled so that it needs nothing else declared — a
|
|
143
|
+
* pointer as `void *`, an enum as an inline enum of its own, a scalar the prelude does not name
|
|
144
|
+
* as the prelude's type of its width and signedness. Its members are what size it, not what is
|
|
145
|
+
* read of it: no emitted expression names one (aggregate.ts `aggregateType`). */
|
|
146
|
+
function declaredStructDecl(tag: string, layout: AggregateLayout): string {
|
|
147
|
+
let enums = 0;
|
|
148
|
+
const scalar = (spelling: string): string => {
|
|
149
|
+
const s = spelling
|
|
150
|
+
.replace(/\b(?:const|volatile)\b/g, ' ')
|
|
151
|
+
.trim()
|
|
152
|
+
.replace(/\s+/g, ' ');
|
|
153
|
+
if (s.endsWith('*')) {
|
|
154
|
+
return 'void *';
|
|
155
|
+
}
|
|
156
|
+
if (/^enum\b/.test(s)) {
|
|
157
|
+
return `enum { asmlift_${tag}_enum${enums++} }`;
|
|
158
|
+
}
|
|
159
|
+
if (s === 'float' || s === 'double' || spellableType(s)) {
|
|
160
|
+
return s;
|
|
161
|
+
}
|
|
162
|
+
const bits = declaredWidth(s);
|
|
163
|
+
return `${/^u\d|\bunsigned\b/.test(s) ? 'u' : 's'}${bits}`;
|
|
164
|
+
};
|
|
165
|
+
const body = (members: readonly AggregateMember[]): string =>
|
|
166
|
+
members
|
|
167
|
+
.map((m) => {
|
|
168
|
+
const type = typeof m.type === 'string' ? scalar(m.type) : `${m.type.kind} { ${body(m.type.members!)} }`;
|
|
169
|
+
const declarator = `${m.name}${(m.dims ?? []).map((n) => `[${n}]`).join('')}`;
|
|
170
|
+
const bits = m.bits !== undefined ? ` : ${m.bits}` : '';
|
|
171
|
+
return `${type}${type.endsWith('*') || declarator === '' ? '' : ' '}${declarator}${bits};`;
|
|
172
|
+
})
|
|
173
|
+
.join(' ');
|
|
174
|
+
return `struct ${tag} { ${body(layout.members!)} };`;
|
|
175
|
+
}
|
|
176
|
+
|
|
137
177
|
/**
|
|
138
178
|
* Render the declaration block for a candidate's recorded symbol references. Deterministic
|
|
139
179
|
* (refs arrive name-sorted from core; struct decls dedupe by tag). The block is prepended by
|
|
@@ -144,7 +184,8 @@ function structDecl(tag: string, layout: SymbolStructField[] | undefined, size:
|
|
|
144
184
|
export function renderDeclarations(refs: SymbolRef[]): string {
|
|
145
185
|
const lines: string[] = [];
|
|
146
186
|
const declaredTags = new Set<string>();
|
|
147
|
-
|
|
187
|
+
const declaredTypedefs = new Set<string>();
|
|
188
|
+
for (const { name, info, access, proto, returned, holdsPointer } of refs) {
|
|
148
189
|
// An address-cast macro declares itself: the header's own body, verbatim. It must NOT become
|
|
149
190
|
// an `extern` — that is the whole point of the fact (an extern emits a relocated pool word
|
|
150
191
|
// where the macro emits the numeric one the target shows).
|
|
@@ -152,10 +193,33 @@ export function renderDeclarations(refs: SymbolRef[]): string {
|
|
|
152
193
|
lines.push(`#define ${name} ${info.macroBody}`);
|
|
153
194
|
continue;
|
|
154
195
|
}
|
|
196
|
+
// A CALL TARGET the project declared completely — its own prototype, re-spelled from the
|
|
197
|
+
// parameter and return type texts the project wrote. This is the one declaration here that
|
|
198
|
+
// is load-bearing for the CALL and not only for the name: an implicit declaration is `int`,
|
|
199
|
+
// which narrows a 64-bit return and adds the sign-extension the target does not have. A
|
|
200
|
+
// parameterless list is spelled `(void)`, never `()`, because `()` declares nothing about
|
|
201
|
+
// the arguments and gcc-2.9 then promotes them.
|
|
202
|
+
if (proto !== undefined) {
|
|
203
|
+
// A STRUCT IT RETURNS THROUGH MEMORY is the headers' type, spelled as they spell it, so it is
|
|
204
|
+
// defined here with the rest of what they own: by its tag, once, whoever else declares that
|
|
205
|
+
// tag — and a typedef name is bound to it on top.
|
|
206
|
+
if (returned?.declared !== undefined) {
|
|
207
|
+
if (!declaredTags.has(returned.name)) {
|
|
208
|
+
declaredTags.add(returned.name);
|
|
209
|
+
lines.push(declaredStructDecl(returned.name, returned.layout));
|
|
210
|
+
}
|
|
211
|
+
if (!/^(?:struct|union)\s/.test(returned.declared) && !declaredTypedefs.has(returned.declared)) {
|
|
212
|
+
declaredTypedefs.add(returned.declared);
|
|
213
|
+
lines.push(`typedef struct ${returned.name} ${returned.declared};`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
lines.push(`${proto.returns} ${name}(${proto.params.length > 0 ? proto.params.join(', ') : 'void'});`);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
155
219
|
if (info.kind === 'code') {
|
|
156
220
|
// value-referenced code symbol ((u32)Func): any prototype makes the name visible, and
|
|
157
|
-
// the address is arity-independent.
|
|
158
|
-
//
|
|
221
|
+
// the address is arity-independent. A call target reaches this module only with a complete
|
|
222
|
+
// prototype, which the branch above already printed — see collectSymbolRefs.
|
|
159
223
|
lines.push(`void ${name}(void);`);
|
|
160
224
|
continue;
|
|
161
225
|
}
|
|
@@ -247,6 +311,12 @@ export function renderDeclarations(refs: SymbolRef[]): string {
|
|
|
247
311
|
// argument applies. For a `synthesized` one it does not — the width came from the
|
|
248
312
|
// target's own asm, so this line is a hypothesis fitted to the bytes; see the module
|
|
249
313
|
// note's "WHERE THE ONLY-LOSES-SCORE ARGUMENT STOPS".
|
|
314
|
+
// A global that holds a pointer (ref.holdsPointer) is `void *`, the type every object
|
|
315
|
+
// pointer converts to without a cast; the qualifiers bind to the cell.
|
|
316
|
+
if (holdsPointer) {
|
|
317
|
+
lines.push(`extern void *${info.volatile ? 'volatile ' : ''}${info.const ? 'const ' : ''}${name};`);
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
250
320
|
const t = access ? intType(access.width, access.signed) : null;
|
|
251
321
|
lines.push(`extern ${quals(info)}${t ?? 'u32'} ${name};`);
|
|
252
322
|
break;
|
package/src/frontend/asmdata.ts
CHANGED
|
@@ -29,10 +29,22 @@ export interface Reloc {
|
|
|
29
29
|
export interface AsmData {
|
|
30
30
|
sections: Map<string, Uint8Array>; // section name → raw bytes (file order)
|
|
31
31
|
relocs: Reloc[];
|
|
32
|
-
symbols: Map<string,
|
|
32
|
+
symbols: Map<string, AsmSymbol>;
|
|
33
|
+
/** how many symbols the `objdump -t` listing printed — the symbol table's entries past its null one */
|
|
34
|
+
symbolCount: number;
|
|
33
35
|
bigEndian: boolean;
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
/** One `objdump -t` symbol: its section, offset in it and size, and `index`, its position in the
|
|
39
|
+
* listing counting from 1 — its symbol-table index, which is what a per-symbol side table in the
|
|
40
|
+
* object (mwcc's `.comment`, frontend/local-object.ts) is indexed by. */
|
|
41
|
+
export interface AsmSymbol {
|
|
42
|
+
section: string;
|
|
43
|
+
value: number;
|
|
44
|
+
size: number;
|
|
45
|
+
index: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
const readU32 = (b: Uint8Array, off: number, big: boolean): number =>
|
|
37
49
|
big
|
|
38
50
|
? ((b[off] << 24) | (b[off + 1] << 16) | (b[off + 2] << 8) | b[off + 3]) >>> 0
|
|
@@ -112,7 +124,8 @@ export function parseAsmData(
|
|
|
112
124
|
}
|
|
113
125
|
|
|
114
126
|
// --- `objdump -t`: `VALUE FLAGS SECTION\tSIZE NAME` (section/size split by TAB) ---
|
|
115
|
-
const symbols = new Map<string,
|
|
127
|
+
const symbols = new Map<string, AsmSymbol>();
|
|
128
|
+
let symbolCount = 0;
|
|
116
129
|
for (const line of symbolsDump.split('\n')) {
|
|
117
130
|
const tab = line.indexOf('\t');
|
|
118
131
|
if (tab < 0) {
|
|
@@ -121,14 +134,15 @@ export function parseAsmData(
|
|
|
121
134
|
const left = line.slice(0, tab),
|
|
122
135
|
right = line.slice(tab + 1);
|
|
123
136
|
const lm = left.match(/^([0-9a-f]+)\s+.{6,8}\s(\S+)\s*$/i); // value … flags(7) section
|
|
124
|
-
const rm = right.match(/^[0-9a-f]
|
|
137
|
+
const rm = right.match(/^([0-9a-f]+)\s+(.+?)\s*$/i); // size name
|
|
125
138
|
if (!lm || !rm) {
|
|
126
139
|
continue;
|
|
127
140
|
}
|
|
128
|
-
|
|
141
|
+
symbolCount++;
|
|
142
|
+
symbols.set(rm[2], { section: lm[2], value: parseInt(lm[1], 16), size: parseInt(rm[1], 16), index: symbolCount });
|
|
129
143
|
}
|
|
130
144
|
|
|
131
|
-
return { sections, relocs, symbols, bigEndian };
|
|
145
|
+
return { sections, relocs, symbols, symbolCount, bigEndian };
|
|
132
146
|
}
|
|
133
147
|
|
|
134
148
|
/** Read a dense jump table's N target `.text` byte-offsets, or `null` if ANYTHING doesn't resolve
|