1
1
from collections .abc import Callable
2
2
3
- from .code import Code , Op , OpType
3
+ from .code import Block , Code , Op , OpType
4
+
5
+ def get_code_block (code : Code , label : str ) -> Block :
6
+ """
7
+ Get an IR block from code and a label. Return None if the block does
8
+ not exist.
9
+ """
10
+
11
+ for block in code .blocks :
12
+ if block .label == label :
13
+ return block
14
+
15
+ return None
16
+
17
+
18
+ def get_code_next_block (code : Code , block : Block ) -> Block :
19
+ """
20
+ Get the IR block from code after a block. Return None if a next
21
+ block does not exist.
22
+ """
23
+
24
+ for i in range (len (code .blocks ) - 1 ):
25
+ if code .blocks [i ] == block :
26
+ return code .blocks [i + 1 ]
27
+
28
+ return None
29
+
30
+
31
+ def is_op_label (op : Op ) -> bool :
32
+ """
33
+ Get whether an IR operation is a label. Label operations are
34
+ operations that contain a reference to a block.
35
+ """
36
+
37
+ return op .type in (
38
+ OpType .JUMP_LABEL , OpType .JUMP_NOT_ZERO_LABEL ,
39
+ OpType .JUMP_ZERO_LABEL , OpType .PUSH_LABEL )
40
+
4
41
5
42
def is_op_terminator (op : Op ) -> bool :
6
43
"""
7
44
Get whether an IR operation is a terminator. Terminator operations
8
45
are operations that guarantee that any subsequent operations will
9
46
not be executed.
10
47
"""
48
+
11
49
return op .type in (OpType .HALT , OpType .JUMP_LABEL , OpType .RETURN )
12
50
13
51
52
+ def is_block_terminated (block : Block ) -> bool :
53
+ """
54
+ Get whether an IR block is terminated. Terminated blocks are blocks
55
+ that contain a terminator operation.
56
+ """
57
+
58
+ for op in block .ops :
59
+ if is_op_terminator (op ):
60
+ return True
61
+
62
+ return False
63
+
64
+
14
65
def optimizer_eliminate_unreachable_ops (code : Code ) -> bool :
15
66
"""
16
- Eliminates unreachable IR operations that follow a terminator
17
- operation. Returns whether any optimization was performed.
67
+ Eliminate unreachable IR operations that follow a terminator
68
+ operation. Return whether any optimization was performed.
18
69
"""
19
70
20
71
was_optimized : bool = False
@@ -29,11 +80,46 @@ def optimizer_eliminate_unreachable_ops(code: Code) -> bool:
29
80
return was_optimized
30
81
31
82
83
+ def optimizer_eliminate_unreachable_blocks (code : Code ) -> bool :
84
+ """
85
+ Eliminate unreachable IR blocks that are never referenced by a label
86
+ operation or preceded by an unterminated block. Return whether any
87
+ optimization was performed.
88
+ """
89
+
90
+ was_optimized : bool = False
91
+ pending_blocks : list [Block ] = [get_code_block (code , ".main" )]
92
+ reachable_blocks : list [Block ] = []
93
+
94
+ while pending_blocks :
95
+ block : Block = pending_blocks .pop ()
96
+
97
+ if block is None or block in reachable_blocks :
98
+ continue
99
+
100
+ reachable_blocks .append (block )
101
+
102
+ for op in block .ops :
103
+ if is_op_label (op ):
104
+ pending_blocks .append (get_code_block (code , op .str_value ))
105
+
106
+ if not is_block_terminated (block ):
107
+ pending_blocks .append (get_code_next_block (code , block ))
108
+
109
+ for i in range (len (code .blocks ) - 1 , - 1 , - 1 ):
110
+ if not code .blocks [i ] in reachable_blocks :
111
+ code .blocks .pop (i )
112
+ was_optimized = True
113
+
114
+ return was_optimized
115
+
116
+
32
117
def optimize_code (code : Code ) -> None :
33
118
""" Optimize an IR code program. """
34
119
35
120
OPTIMIZERS : list [Callable [[Code ], bool ]] = [
36
121
optimizer_eliminate_unreachable_ops ,
122
+ optimizer_eliminate_unreachable_blocks ,
37
123
]
38
124
39
125
should_optimize : bool = True
0 commit comments