@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
package/src/l3/volstore.ts
CHANGED
|
@@ -92,9 +92,10 @@
|
|
|
92
92
|
// both configurations and with any window. No row demands the read spelling, and a variation with no
|
|
93
93
|
// inhabitant is what "earn the level" forbids.
|
|
94
94
|
import { type IrType, T, scalarTypeForAccess } from '../ir/types';
|
|
95
|
-
import { cellAddress, inRange } from './address';
|
|
96
|
-
import { type Expr, type SFn, type Stmt, stmtChildren } from './ast';
|
|
95
|
+
import { cellAddress, inRange, qualifiedBase } from './address';
|
|
96
|
+
import { type Expr, type SFn, type Stmt, dotBase, stmtChildren } from './ast';
|
|
97
97
|
import { type Gate, firstRejection } from './gates';
|
|
98
|
+
import { derefStrideOk } from './typing';
|
|
98
99
|
|
|
99
100
|
/** One STORE lvalue as the gates read it. */
|
|
100
101
|
interface AccessCtx {
|
|
@@ -141,9 +142,6 @@ export const VOL_STORE_GATES: readonly Gate<AccessCtx>[] = [
|
|
|
141
142
|
},
|
|
142
143
|
];
|
|
143
144
|
|
|
144
|
-
/** Does this base already assert volatility — a `volatile` cast at any depth of the cast chain? */
|
|
145
|
-
const qualifiedBase = (e: Expr): boolean => e.k === 'cast' && (e.volatile === true || qualifiedBase(e.e));
|
|
146
|
-
|
|
147
145
|
/** The pointee the deref cast carries: the access's own scalar type. */
|
|
148
146
|
const pointee = (ix: Extract<Expr, { k: 'index' }>): IrType => scalarTypeForAccess(ix.width, ix.signed);
|
|
149
147
|
|
|
@@ -169,8 +167,17 @@ function qualify(lval: Expr, window: readonly [number, number] | undefined): Exp
|
|
|
169
167
|
if (firstRejection(VOL_STORE_GATES, ctx) !== null) {
|
|
170
168
|
return lval;
|
|
171
169
|
}
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
return qualifiedAccess(lval);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** An indexed access with `volatile` on the pointee of its deref cast. An existing scalar pointer
|
|
174
|
+
* cast takes the qualifier in place; a bare base gets one minted, exactly the node
|
|
175
|
+
* backend/cfamily.ts's own deref legalization would have synthesized. Also how
|
|
176
|
+
* {@link qualifiedMemoryAccess} spells an indexed access the lift marked `volatile`. */
|
|
177
|
+
export function qualifiedAccess(lval: Extract<Expr, { k: 'index' }>): Extract<Expr, { k: 'index' }> {
|
|
178
|
+
if (qualifiedBase(lval.base)) {
|
|
179
|
+
return lval;
|
|
180
|
+
}
|
|
174
181
|
const base: Expr =
|
|
175
182
|
lval.base.k === 'cast' && lval.base.to.kind === 'ptr'
|
|
176
183
|
? { ...lval.base, volatile: true }
|
|
@@ -178,6 +185,88 @@ function qualify(lval: Expr, window: readonly [number, number] | undefined): Exp
|
|
|
178
185
|
return { ...lval, base };
|
|
179
186
|
}
|
|
180
187
|
|
|
188
|
+
/** A memory access the lift marked `volatile` (frontend/device-pins.ts), spelled through a
|
|
189
|
+
* `volatile` pointee: an indexed access by {@link qualifiedAccess}; a recovered struct member
|
|
190
|
+
* through the struct pointer it is reached by — `((volatile struct S *)0x40000B0)[ch].field_0`,
|
|
191
|
+
* `((volatile struct S *)p)->field_0` — whether that pointer is already a cast or a variable
|
|
192
|
+
* `typeOf` types as one; and a union view through the member it views. A named global — `gSym`,
|
|
193
|
+
* `gSym.field` — is returned unchanged, since its declaration owns its qualifiers. Null when the
|
|
194
|
+
* pointer the access is reached by has no type to cast it to, for the caller to refuse rather
|
|
195
|
+
* than drop the qualifier. */
|
|
196
|
+
export function qualifiedMemoryAccess(e: Expr, typeOf: (x: Expr) => IrType | undefined): Expr | null {
|
|
197
|
+
if (e.k === 'index') {
|
|
198
|
+
return qualifiedAccess(e);
|
|
199
|
+
}
|
|
200
|
+
if (e.k !== 'field') {
|
|
201
|
+
return e;
|
|
202
|
+
}
|
|
203
|
+
const element = dotBase(e);
|
|
204
|
+
if (element !== undefined) {
|
|
205
|
+
const base = qualifiedPointer(element.base, typeOf);
|
|
206
|
+
return base === null ? null : { ...e, base: { ...element, base } };
|
|
207
|
+
}
|
|
208
|
+
if (e.dot === true) {
|
|
209
|
+
if (e.base.k !== 'field') {
|
|
210
|
+
return e;
|
|
211
|
+
}
|
|
212
|
+
const member = qualifiedMemoryAccess(e.base, typeOf);
|
|
213
|
+
return member === null ? null : { ...e, base: member };
|
|
214
|
+
}
|
|
215
|
+
const base = qualifiedPointer(e.base, typeOf);
|
|
216
|
+
return base === null ? null : { ...e, base };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Does this access reach the object it names through a pointer cast — one the tree spells,
|
|
220
|
+
* `((struct T *)&gSym)->f`, or one the C-family printer puts on a base that does not stride the
|
|
221
|
+
* access as spelled (backend/cfamily.ts `legalizedIndexBase`), `((u16 *)&gSym)[3]` — rather than
|
|
222
|
+
* through the object's own name, element or member? The pointee of such a cast carries none of the
|
|
223
|
+
* object's declared qualifiers unless it says so itself. `typeOf` is the rendered C type the
|
|
224
|
+
* printer judges a base by. */
|
|
225
|
+
export function castOffDeclaration(e: Expr, typeOf: (x: Expr) => IrType | undefined): boolean {
|
|
226
|
+
if (e.k === 'field') {
|
|
227
|
+
// A dot member over an element prints that element's base as spelled.
|
|
228
|
+
const element = dotBase(e);
|
|
229
|
+
if (element !== undefined) {
|
|
230
|
+
return addressCast(element.base, typeOf);
|
|
231
|
+
}
|
|
232
|
+
return e.dot === true ? castOffDeclaration(e.base, typeOf) : addressCast(e.base, typeOf);
|
|
233
|
+
}
|
|
234
|
+
if (e.k !== 'index') {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
if (addressCast(e.base, typeOf)) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
if (e.lead !== undefined && e.lead.length > 0) {
|
|
241
|
+
return false; // a multidimensional global's subscript prints its base as spelled
|
|
242
|
+
}
|
|
243
|
+
return !derefStrideOk(
|
|
244
|
+
typeOf(e.base) ?? (e.baseElem !== undefined ? T.ptr(e.baseElem) : undefined),
|
|
245
|
+
e.width,
|
|
246
|
+
e.signed,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Is there a cast between this address and the object it is taken from: one on it, under its
|
|
251
|
+
* arithmetic, or on the access whose element or member it is? */
|
|
252
|
+
const addressCast = (p: Expr, typeOf: (x: Expr) => IrType | undefined): boolean =>
|
|
253
|
+
p.k === 'cast' ||
|
|
254
|
+
(p.k === 'bin' && (addressCast(p.l, typeOf) || addressCast(p.r, typeOf))) ||
|
|
255
|
+
((p.k === 'index' || p.k === 'field') && castOffDeclaration(p, typeOf));
|
|
256
|
+
|
|
257
|
+
/** A pointer expression carrying `volatile` on its pointee: a pointer cast takes it in place, and
|
|
258
|
+
* any other pointer is cast to its own type with it. */
|
|
259
|
+
function qualifiedPointer(p: Expr, typeOf: (x: Expr) => IrType | undefined): Expr | null {
|
|
260
|
+
if (qualifiedBase(p)) {
|
|
261
|
+
return p;
|
|
262
|
+
}
|
|
263
|
+
if (p.k === 'cast' && p.to.kind === 'ptr') {
|
|
264
|
+
return { ...p, volatile: true };
|
|
265
|
+
}
|
|
266
|
+
const t = typeOf(p);
|
|
267
|
+
return t?.kind === 'ptr' ? { k: 'cast', to: t, volatile: true, e: p } : null;
|
|
268
|
+
}
|
|
269
|
+
|
|
181
270
|
/** How many stores this tree would qualify — the enumeration gate, so a function with no device
|
|
182
271
|
* store costs one walk and no candidate.
|
|
183
272
|
*
|
package/src/mangle.ts
CHANGED
|
@@ -129,6 +129,36 @@ export function demangle(sym: string): CppSig | null {
|
|
|
129
129
|
return { name, cls, params };
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
/** How a class opens where gcc 2 names one: a length (`3Foo`), a nesting count (`Q21A1B`, and
|
|
133
|
+
* `Q_12_` past nine levels) or a template (`t3Vec1Zi`). A member function's const and volatile
|
|
134
|
+
* marks come before it (`get__C3Fooi`, `get__V3Fooi`, `get__CQ21A1Bi`), and CodeWarrior's class
|
|
135
|
+
* opens the same way, its marks following the class (`getStartHour__11PlayerStateCFv`). */
|
|
136
|
+
const GCC2_CLASS = String.raw`(?:\d|Q(?:\d|_\d+_)|t\d)`;
|
|
137
|
+
|
|
138
|
+
/** How many argument words a C++ symbol may be handed ahead of its declared parameters: 1 where it
|
|
139
|
+
* may name a MEMBER function, whose `this` the declared list leaves out; 0 where it cannot; and
|
|
140
|
+
* `undefined` for a constructor or destructor, which may also take a flag no declaration states
|
|
141
|
+
* (an in-charge or delete flag, beside `this`). Either mangling scheme a target here compiles with
|
|
142
|
+
* puts the class right after the `__`, length-prefixed or `Q<n>`-nested: CodeWarrior's
|
|
143
|
+
* `pick__3FooFiPi` (`__ct__3FooFv`, `__dt__3FooFv`), and gcc 2's `pick__3FooiPi` (a const method
|
|
144
|
+
* `pick__C3FooiPi`, a volatile one `pick__V3FooiPi`, a constructor `__3Foo`, a destructor `_$_3Foo`
|
|
145
|
+
* or `_._3Foo`, every one of which this abstains on, nested `_._Q21A1B` included), where a
|
|
146
|
+
* TEMPLATE class is spelled `t<n><name><args>` in the class's place (`get__t3Vec1Zii`, a
|
|
147
|
+
* constructor `__t3Vec1Zii`, `operator=` `__as__t3Vec1ZiRCt3Vec1Zi`). A free function (`f__Fii`)
|
|
148
|
+
* and a plain C name answer 0. A STATIC member mangles as a method does and takes no
|
|
149
|
+
* `this`, so 1 is "may", and a reader that needs the exact count must not take it as one.
|
|
150
|
+
*
|
|
151
|
+
* THE PATTERNS ERR TOWARDS A MEMBER, because the errors cost differently: a method read as free
|
|
152
|
+
* loses its `this` word, and the own-declaration bound (`proto.ts` `ownArgumentWords`) then turns
|
|
153
|
+
* its last parameter into an uninitialised local, where a C name read as a method only leaves one
|
|
154
|
+
* more register a parameter. */
|
|
155
|
+
export function implicitArgumentWords(sym: string): 0 | 1 | undefined {
|
|
156
|
+
if (/^__(?:ct|dt)__/.test(sym) || new RegExp(`^__${GCC2_CLASS}`).test(sym) || /^_[$.]_/.test(sym)) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
return new RegExp(`__[CV]*${GCC2_CLASS}`).test(sym) ? 1 : 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
132
162
|
/** A class qualifier off the front of `s` — `12RefCountable`, or `Q23zen17particleGenerator` for a
|
|
133
163
|
* nested one — as its scope names and the remaining string; null when `s` does not open with one. */
|
|
134
164
|
function parseQualifier(s: string): { scopes: string[]; rest: string } | null {
|
|
@@ -178,7 +208,17 @@ export function demangledName(sym: string): string | null {
|
|
|
178
208
|
return null;
|
|
179
209
|
}
|
|
180
210
|
|
|
181
|
-
/** Spell a CppType as C++ source
|
|
211
|
+
/** Spell a CppType as C++ source where no declarator is involved — a return type, a cast
|
|
212
|
+
* (`Vec *`, `unsigned int`). */
|
|
182
213
|
export function spellType(t: CppType): string {
|
|
183
214
|
return t.base + (t.ptr ? ' ' + '*'.repeat(t.ptr) : '');
|
|
184
215
|
}
|
|
216
|
+
|
|
217
|
+
/** Declare a name of a CppType, C declarator rules: a pointer binds its `*` to the declarator
|
|
218
|
+
* (`Vec *p`), everything else is the prefix `spellType name`. The C-family backend's `cDeclare`
|
|
219
|
+
* says the same of an `IrType`; C++ has its own type vocabulary (`CppType`, from the mangled
|
|
220
|
+
* name) and so needs its own declarator, or one function spells its pointers two ways — the type
|
|
221
|
+
* prefix in the parameter list and the declarator form in the body. */
|
|
222
|
+
export function declareCpp(t: CppType, name: string): string {
|
|
223
|
+
return t.ptr > 0 ? `${t.base} ${'*'.repeat(t.ptr)}${name}` : `${t.base} ${name}`;
|
|
224
|
+
}
|