main
ts 87 lines 2.56 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {CompilerError} from '..';
9 import {BlockId, GotoVariant, HIRFunction} from './HIR';
10
11 export function pruneUnusedLabelsHIR(fn: HIRFunction): void {
12 const merged: Array<{
13 label: BlockId;
14 next: BlockId;
15 fallthrough: BlockId;
16 }> = [];
17 const rewrites: Map<BlockId, BlockId> = new Map();
18 for (const [blockId, block] of fn.body.blocks) {
19 const terminal = block.terminal;
20 if (terminal.kind === 'label') {
21 const {block: nextId, fallthrough: fallthroughId} = terminal;
22 const next = fn.body.blocks.get(nextId)!;
23 const fallthrough = fn.body.blocks.get(fallthroughId)!;
24 if (
25 next.terminal.kind === 'goto' &&
26 next.terminal.variant === GotoVariant.Break &&
27 next.terminal.block === fallthroughId
28 ) {
29 if (next.kind === 'block' && fallthrough.kind === 'block') {
30 // Only merge normal block types
31 merged.push({
32 label: blockId,
33 next: nextId,
34 fallthrough: fallthroughId,
35 });
36 }
37 }
38 }
39 }
40
41 for (const {
42 label: originalLabelId,
43 next: nextId,
44 fallthrough: fallthroughId,
45 } of merged) {
46 const labelId = rewrites.get(originalLabelId) ?? originalLabelId;
47 const label = fn.body.blocks.get(labelId)!;
48 const next = fn.body.blocks.get(nextId)!;
49 const fallthrough = fn.body.blocks.get(fallthroughId)!;
50
51 // Merge block and fallthrough
52 CompilerError.invariant(
53 next.phis.size === 0 && fallthrough.phis.size === 0,
54 {
55 reason: 'Unexpected phis when merging label blocks',
56 loc: label.terminal.loc,
57 },
58 );
59
60 CompilerError.invariant(
61 next.preds.size === 1 &&
62 fallthrough.preds.size === 1 &&
63 next.preds.has(originalLabelId) &&
64 fallthrough.preds.has(nextId),
65 {
66 reason: 'Unexpected block predecessors when merging label blocks',
67 loc: label.terminal.loc,
68 },
69 );
70
71 label.instructions.push(...next.instructions, ...fallthrough.instructions);
72 label.terminal = fallthrough.terminal;
73 fn.body.blocks.delete(nextId);
74 fn.body.blocks.delete(fallthroughId);
75 rewrites.set(fallthroughId, labelId);
76 }
77
78 for (const [_, block] of fn.body.blocks) {
79 for (const pred of block.preds) {
80 const rewritten = rewrites.get(pred);
81 if (rewritten != null) {
82 block.preds.delete(pred);
83 block.preds.add(rewritten);
84 }
85 }
86 }
87 }