46
#unknown: Set<Identifier> = new Set();
47
#context: Set<Identifier> = new Set();
48
49
- constructor(env: Environment, blocks: Map<BlockId, BasicBlock>) {
50
- this.#blocks = blocks;
49
+ constructor(env: Environment, blocks: ReadonlyMap<BlockId, BasicBlock>) {
50
+ this.#blocks = new Map(blocks);
51
this.#env = env;
52
}
53
55
return this.#env.nextIdentifierId;
56
}
57
58
+ defineFunction(func: HIRFunction): void {
59
+ for (const [id, block] of func.body.blocks) {
60
+ this.#blocks.set(id, block);
61
+ }
62
+ }
63
+
64
+ enter(fn: () => void): void {
65
+ const current = this.#current;
66
+ fn();
67
+ this.#current = current;
68
+ }
69
+
70
state(): State {
71
invariant(
72
this.#current !== null,
137
if (block.preds.size == 0) {
138
// We're at the entry block and haven't found our defintion yet.
139
// console.log(
128
- // `Unable to find "${printIdentifier(oldId)}", assuming it's a global`
140
+ // `Unable to find "${printIdentifier(
141
+ // oldId
142
+ // )}" in bb${blockId}, assuming it's a global`
143
// );
144
this.#unknown.add(oldId);
145
return oldId;
227
}
228
229
export default function enterSSA(func: HIRFunction): void {
216
- const visitedBlocks: Set<BasicBlock> = new Set();
230
const builder = new SSABuilder(func.env, func.body.blocks);
231
+ enterSSAImpl(func, builder, func.body.entry);
232
+}
233
+
234
+function enterSSAImpl(
235
+ func: HIRFunction,
236
+ builder: SSABuilder,
237
+ rootEntry: BlockId
238
+): void {
239
+ const visitedBlocks: Set<BasicBlock> = new Set();
240
for (const [blockId, block] of func.body.blocks) {
241
invariant(
242
!visitedBlocks.has(block),
246
247
builder.startBlock(block);
248
227
- if (func.body.entry === blockId) {
228
- func.context = func.context.map((p) => builder.defineContext(p));
249
+ if (blockId === rootEntry) {
250
+ // NOTE: func.context should be empty for the root function
251
+ if (func.context.length !== 0) {
252
+ CompilerError.invariant(
253
+ `Expected function context to be empty for outer function declarations`,
254
+ func.loc
255
+ );
256
+ }
257
func.params = func.params.map((p) => builder.definePlace(p));
258
}
259
262
mapInstructionOperands(instr, (place) => builder.getPlace(place));
263
264
if (instr.value.kind === "FunctionExpression") {
237
- enterSSA(instr.value.loweredFunc);
265
+ const loweredFunc = instr.value.loweredFunc;
266
+ const entry = loweredFunc.body.blocks.get(loweredFunc.body.entry)!;
267
+ invariant(
268
+ entry.preds.size === 0,
269
+ "Expected function expression entry block to have zero predecessors"
270
+ );
271
+ entry.preds.add(blockId);
272
+ builder.defineFunction(loweredFunc);
273
+ builder.enter(() => {
274
+ loweredFunc.context = loweredFunc.context.map((p) =>
275
+ builder.getPlace(p)
276
+ );
277
+ loweredFunc.params = loweredFunc.params.map((p) =>
278
+ builder.definePlace(p)
279
+ );
280
+ enterSSAImpl(loweredFunc, builder, rootEntry);
281
+ });
282
+ entry.preds.clear();
283
}
284
}
285