machine-dialect 0.1.0a1__py3-none-any.whl

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.
Files changed (268) hide show
  1. machine_dialect/__main__.py +667 -0
  2. machine_dialect/agent/__init__.py +5 -0
  3. machine_dialect/agent/agent.py +360 -0
  4. machine_dialect/ast/__init__.py +95 -0
  5. machine_dialect/ast/ast_node.py +35 -0
  6. machine_dialect/ast/call_expression.py +82 -0
  7. machine_dialect/ast/dict_extraction.py +60 -0
  8. machine_dialect/ast/expressions.py +439 -0
  9. machine_dialect/ast/literals.py +309 -0
  10. machine_dialect/ast/program.py +35 -0
  11. machine_dialect/ast/statements.py +1433 -0
  12. machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
  13. machine_dialect/ast/tests/test_boolean_literal.py +29 -0
  14. machine_dialect/ast/tests/test_collection_hir.py +138 -0
  15. machine_dialect/ast/tests/test_define_statement.py +142 -0
  16. machine_dialect/ast/tests/test_desugar.py +541 -0
  17. machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
  18. machine_dialect/cfg/__init__.py +6 -0
  19. machine_dialect/cfg/config.py +156 -0
  20. machine_dialect/cfg/examples.py +221 -0
  21. machine_dialect/cfg/generate_with_ai.py +187 -0
  22. machine_dialect/cfg/openai_generation.py +200 -0
  23. machine_dialect/cfg/parser.py +94 -0
  24. machine_dialect/cfg/tests/__init__.py +1 -0
  25. machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
  26. machine_dialect/cfg/tests/test_config.py +188 -0
  27. machine_dialect/cfg/tests/test_examples.py +391 -0
  28. machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
  29. machine_dialect/cfg/tests/test_openai_generation.py +256 -0
  30. machine_dialect/codegen/__init__.py +5 -0
  31. machine_dialect/codegen/bytecode_module.py +89 -0
  32. machine_dialect/codegen/bytecode_serializer.py +300 -0
  33. machine_dialect/codegen/opcodes.py +101 -0
  34. machine_dialect/codegen/register_codegen.py +1996 -0
  35. machine_dialect/codegen/symtab.py +208 -0
  36. machine_dialect/codegen/tests/__init__.py +1 -0
  37. machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
  38. machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
  39. machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
  40. machine_dialect/codegen/tests/test_symtab.py +418 -0
  41. machine_dialect/codegen/vm_serializer.py +621 -0
  42. machine_dialect/compiler/__init__.py +18 -0
  43. machine_dialect/compiler/compiler.py +197 -0
  44. machine_dialect/compiler/config.py +149 -0
  45. machine_dialect/compiler/context.py +149 -0
  46. machine_dialect/compiler/phases/__init__.py +19 -0
  47. machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
  48. machine_dialect/compiler/phases/codegen.py +40 -0
  49. machine_dialect/compiler/phases/hir_generation.py +39 -0
  50. machine_dialect/compiler/phases/mir_generation.py +86 -0
  51. machine_dialect/compiler/phases/optimization.py +110 -0
  52. machine_dialect/compiler/phases/parsing.py +39 -0
  53. machine_dialect/compiler/pipeline.py +143 -0
  54. machine_dialect/compiler/tests/__init__.py +1 -0
  55. machine_dialect/compiler/tests/test_compiler.py +568 -0
  56. machine_dialect/compiler/vm_runner.py +173 -0
  57. machine_dialect/errors/__init__.py +32 -0
  58. machine_dialect/errors/exceptions.py +369 -0
  59. machine_dialect/errors/messages.py +82 -0
  60. machine_dialect/errors/tests/__init__.py +0 -0
  61. machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
  62. machine_dialect/errors/tests/test_name_errors.py +118 -0
  63. machine_dialect/helpers/__init__.py +0 -0
  64. machine_dialect/helpers/stopwords.py +225 -0
  65. machine_dialect/helpers/validators.py +30 -0
  66. machine_dialect/lexer/__init__.py +9 -0
  67. machine_dialect/lexer/constants.py +23 -0
  68. machine_dialect/lexer/lexer.py +907 -0
  69. machine_dialect/lexer/tests/__init__.py +0 -0
  70. machine_dialect/lexer/tests/helpers.py +86 -0
  71. machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
  72. machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
  73. machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
  74. machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
  75. machine_dialect/lexer/tests/test_comments.py +200 -0
  76. machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
  77. machine_dialect/lexer/tests/test_lexer_position.py +113 -0
  78. machine_dialect/lexer/tests/test_list_tokens.py +282 -0
  79. machine_dialect/lexer/tests/test_stopwords.py +80 -0
  80. machine_dialect/lexer/tests/test_strict_equality.py +129 -0
  81. machine_dialect/lexer/tests/test_token.py +41 -0
  82. machine_dialect/lexer/tests/test_tokenization.py +294 -0
  83. machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
  84. machine_dialect/lexer/tests/test_url_literals.py +169 -0
  85. machine_dialect/lexer/tokens.py +487 -0
  86. machine_dialect/linter/__init__.py +10 -0
  87. machine_dialect/linter/__main__.py +144 -0
  88. machine_dialect/linter/linter.py +154 -0
  89. machine_dialect/linter/rules/__init__.py +8 -0
  90. machine_dialect/linter/rules/base.py +112 -0
  91. machine_dialect/linter/rules/statement_termination.py +99 -0
  92. machine_dialect/linter/tests/__init__.py +1 -0
  93. machine_dialect/linter/tests/mdrules/__init__.py +0 -0
  94. machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
  95. machine_dialect/linter/tests/test_linter.py +81 -0
  96. machine_dialect/linter/tests/test_rules.py +110 -0
  97. machine_dialect/linter/tests/test_violations.py +71 -0
  98. machine_dialect/linter/violations.py +51 -0
  99. machine_dialect/mir/__init__.py +69 -0
  100. machine_dialect/mir/analyses/__init__.py +20 -0
  101. machine_dialect/mir/analyses/alias_analysis.py +315 -0
  102. machine_dialect/mir/analyses/dominance_analysis.py +49 -0
  103. machine_dialect/mir/analyses/escape_analysis.py +286 -0
  104. machine_dialect/mir/analyses/loop_analysis.py +272 -0
  105. machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
  106. machine_dialect/mir/analyses/type_analysis.py +448 -0
  107. machine_dialect/mir/analyses/use_def_chains.py +232 -0
  108. machine_dialect/mir/basic_block.py +385 -0
  109. machine_dialect/mir/dataflow.py +445 -0
  110. machine_dialect/mir/debug_info.py +208 -0
  111. machine_dialect/mir/hir_to_mir.py +1738 -0
  112. machine_dialect/mir/mir_dumper.py +366 -0
  113. machine_dialect/mir/mir_function.py +167 -0
  114. machine_dialect/mir/mir_instructions.py +1877 -0
  115. machine_dialect/mir/mir_interpreter.py +556 -0
  116. machine_dialect/mir/mir_module.py +225 -0
  117. machine_dialect/mir/mir_printer.py +480 -0
  118. machine_dialect/mir/mir_transformer.py +410 -0
  119. machine_dialect/mir/mir_types.py +367 -0
  120. machine_dialect/mir/mir_validation.py +455 -0
  121. machine_dialect/mir/mir_values.py +268 -0
  122. machine_dialect/mir/optimization_config.py +233 -0
  123. machine_dialect/mir/optimization_pass.py +251 -0
  124. machine_dialect/mir/optimization_pipeline.py +355 -0
  125. machine_dialect/mir/optimizations/__init__.py +84 -0
  126. machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
  127. machine_dialect/mir/optimizations/branch_prediction.py +372 -0
  128. machine_dialect/mir/optimizations/constant_propagation.py +634 -0
  129. machine_dialect/mir/optimizations/cse.py +398 -0
  130. machine_dialect/mir/optimizations/dce.py +288 -0
  131. machine_dialect/mir/optimizations/inlining.py +551 -0
  132. machine_dialect/mir/optimizations/jump_threading.py +487 -0
  133. machine_dialect/mir/optimizations/licm.py +405 -0
  134. machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
  135. machine_dialect/mir/optimizations/strength_reduction.py +422 -0
  136. machine_dialect/mir/optimizations/tail_call.py +207 -0
  137. machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
  138. machine_dialect/mir/optimizations/type_narrowing.py +397 -0
  139. machine_dialect/mir/optimizations/type_specialization.py +447 -0
  140. machine_dialect/mir/optimizations/type_specific.py +906 -0
  141. machine_dialect/mir/optimize_mir.py +89 -0
  142. machine_dialect/mir/pass_manager.py +391 -0
  143. machine_dialect/mir/profiling/__init__.py +26 -0
  144. machine_dialect/mir/profiling/profile_collector.py +318 -0
  145. machine_dialect/mir/profiling/profile_data.py +372 -0
  146. machine_dialect/mir/profiling/profile_reader.py +272 -0
  147. machine_dialect/mir/profiling/profile_writer.py +226 -0
  148. machine_dialect/mir/register_allocation.py +302 -0
  149. machine_dialect/mir/reporting/__init__.py +17 -0
  150. machine_dialect/mir/reporting/optimization_reporter.py +314 -0
  151. machine_dialect/mir/reporting/report_formatter.py +289 -0
  152. machine_dialect/mir/ssa_construction.py +342 -0
  153. machine_dialect/mir/tests/__init__.py +1 -0
  154. machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
  155. machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
  156. machine_dialect/mir/tests/test_algebraic_division.py +126 -0
  157. machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
  158. machine_dialect/mir/tests/test_basic_block.py +425 -0
  159. machine_dialect/mir/tests/test_branch_prediction.py +459 -0
  160. machine_dialect/mir/tests/test_call_lowering.py +168 -0
  161. machine_dialect/mir/tests/test_collection_lowering.py +604 -0
  162. machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
  163. machine_dialect/mir/tests/test_custom_passes.py +166 -0
  164. machine_dialect/mir/tests/test_debug_info.py +285 -0
  165. machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
  166. machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
  167. machine_dialect/mir/tests/test_double_negation.py +231 -0
  168. machine_dialect/mir/tests/test_escape_analysis.py +233 -0
  169. machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
  170. machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
  171. machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
  172. machine_dialect/mir/tests/test_inlining.py +435 -0
  173. machine_dialect/mir/tests/test_licm.py +472 -0
  174. machine_dialect/mir/tests/test_mir_dumper.py +313 -0
  175. machine_dialect/mir/tests/test_mir_instructions.py +445 -0
  176. machine_dialect/mir/tests/test_mir_module.py +860 -0
  177. machine_dialect/mir/tests/test_mir_printer.py +387 -0
  178. machine_dialect/mir/tests/test_mir_types.py +123 -0
  179. machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
  180. machine_dialect/mir/tests/test_mir_validation.py +378 -0
  181. machine_dialect/mir/tests/test_mir_values.py +168 -0
  182. machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
  183. machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
  184. machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
  185. machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
  186. machine_dialect/mir/tests/test_pass_manager.py +294 -0
  187. machine_dialect/mir/tests/test_pass_registration.py +64 -0
  188. machine_dialect/mir/tests/test_profiling.py +356 -0
  189. machine_dialect/mir/tests/test_register_allocation.py +307 -0
  190. machine_dialect/mir/tests/test_report_formatters.py +372 -0
  191. machine_dialect/mir/tests/test_ssa_construction.py +433 -0
  192. machine_dialect/mir/tests/test_tail_call.py +236 -0
  193. machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
  194. machine_dialect/mir/tests/test_type_narrowing.py +277 -0
  195. machine_dialect/mir/tests/test_type_specialization.py +421 -0
  196. machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
  197. machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
  198. machine_dialect/mir/type_inference.py +368 -0
  199. machine_dialect/parser/__init__.py +12 -0
  200. machine_dialect/parser/enums.py +45 -0
  201. machine_dialect/parser/parser.py +3655 -0
  202. machine_dialect/parser/protocols.py +11 -0
  203. machine_dialect/parser/symbol_table.py +169 -0
  204. machine_dialect/parser/tests/__init__.py +0 -0
  205. machine_dialect/parser/tests/helper_functions.py +193 -0
  206. machine_dialect/parser/tests/test_action_statements.py +334 -0
  207. machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
  208. machine_dialect/parser/tests/test_call_statements.py +154 -0
  209. machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
  210. machine_dialect/parser/tests/test_collection_mutations.py +264 -0
  211. machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
  212. machine_dialect/parser/tests/test_define_integration.py +468 -0
  213. machine_dialect/parser/tests/test_define_statements.py +311 -0
  214. machine_dialect/parser/tests/test_dict_extraction.py +115 -0
  215. machine_dialect/parser/tests/test_empty_literal.py +155 -0
  216. machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
  217. machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
  218. machine_dialect/parser/tests/test_if_empty_block.py +61 -0
  219. machine_dialect/parser/tests/test_if_statements.py +299 -0
  220. machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
  221. machine_dialect/parser/tests/test_infix_expressions.py +680 -0
  222. machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
  223. machine_dialect/parser/tests/test_interaction_statements.py +269 -0
  224. machine_dialect/parser/tests/test_list_literals.py +277 -0
  225. machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
  226. machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
  227. machine_dialect/parser/tests/test_parse_errors.py +114 -0
  228. machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
  229. machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
  230. machine_dialect/parser/tests/test_program.py +13 -0
  231. machine_dialect/parser/tests/test_return_statements.py +89 -0
  232. machine_dialect/parser/tests/test_set_statements.py +152 -0
  233. machine_dialect/parser/tests/test_strict_equality.py +258 -0
  234. machine_dialect/parser/tests/test_symbol_table.py +217 -0
  235. machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
  236. machine_dialect/parser/tests/test_utility_statements.py +423 -0
  237. machine_dialect/parser/token_buffer.py +159 -0
  238. machine_dialect/repl/__init__.py +3 -0
  239. machine_dialect/repl/repl.py +426 -0
  240. machine_dialect/repl/tests/__init__.py +0 -0
  241. machine_dialect/repl/tests/test_repl.py +606 -0
  242. machine_dialect/semantic/__init__.py +12 -0
  243. machine_dialect/semantic/analyzer.py +906 -0
  244. machine_dialect/semantic/error_messages.py +189 -0
  245. machine_dialect/semantic/tests/__init__.py +1 -0
  246. machine_dialect/semantic/tests/test_analyzer.py +364 -0
  247. machine_dialect/semantic/tests/test_error_messages.py +104 -0
  248. machine_dialect/tests/edge_cases/__init__.py +10 -0
  249. machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
  250. machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
  251. machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
  252. machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
  253. machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
  254. machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
  255. machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
  256. machine_dialect/tests/integration/test_list_compilation.py +395 -0
  257. machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
  258. machine_dialect/type_checking/__init__.py +21 -0
  259. machine_dialect/type_checking/tests/__init__.py +1 -0
  260. machine_dialect/type_checking/tests/test_type_system.py +230 -0
  261. machine_dialect/type_checking/type_system.py +270 -0
  262. machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
  263. machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
  264. machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
  265. machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
  266. machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
  267. machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
  268. machine_dialect_vm/__init__.pyi +15 -0
@@ -0,0 +1,410 @@
1
+ """MIR transformation utilities for optimization passes.
2
+
3
+ This module provides utilities for transforming MIR code, including
4
+ instruction manipulation, block operations, and SSA preservation.
5
+ """
6
+
7
+ from collections.abc import Callable
8
+
9
+ from machine_dialect.mir.basic_block import BasicBlock
10
+ from machine_dialect.mir.mir_function import MIRFunction
11
+ from machine_dialect.mir.mir_instructions import (
12
+ ConditionalJump,
13
+ Jump,
14
+ Label,
15
+ MIRInstruction,
16
+ Phi,
17
+ Return,
18
+ )
19
+ from machine_dialect.mir.mir_values import MIRValue
20
+
21
+
22
+ class MIRTransformer:
23
+ """Utility class for transforming MIR code."""
24
+
25
+ def __init__(self, function: MIRFunction) -> None:
26
+ """Initialize the transformer.
27
+
28
+ Args:
29
+ function: Function to transform.
30
+ """
31
+ self.function = function
32
+ self.modified = False
33
+
34
+ def replace_instruction(
35
+ self,
36
+ block: BasicBlock,
37
+ old_inst: MIRInstruction,
38
+ new_inst: MIRInstruction,
39
+ ) -> bool:
40
+ """Replace an instruction in a block.
41
+
42
+ Args:
43
+ block: The block containing the instruction.
44
+ old_inst: Instruction to replace.
45
+ new_inst: Replacement instruction.
46
+
47
+ Returns:
48
+ True if replacement was successful.
49
+ """
50
+ try:
51
+ index = block.instructions.index(old_inst)
52
+ block.instructions[index] = new_inst
53
+ self.modified = True
54
+ return True
55
+ except ValueError:
56
+ # Check phi nodes
57
+ try:
58
+ index = block.phi_nodes.index(old_inst) # type: ignore
59
+ if isinstance(new_inst, Phi):
60
+ block.phi_nodes[index] = new_inst
61
+ self.modified = True
62
+ return True
63
+ except (ValueError, TypeError):
64
+ pass
65
+ return False
66
+
67
+ def remove_instruction(
68
+ self,
69
+ block: BasicBlock,
70
+ inst: MIRInstruction,
71
+ ) -> bool:
72
+ """Remove an instruction from a block.
73
+
74
+ Args:
75
+ block: The block containing the instruction.
76
+ inst: Instruction to remove.
77
+
78
+ Returns:
79
+ True if removal was successful.
80
+ """
81
+ try:
82
+ block.instructions.remove(inst)
83
+ self.modified = True
84
+ return True
85
+ except ValueError:
86
+ # Check phi nodes
87
+ try:
88
+ block.phi_nodes.remove(inst) # type: ignore
89
+ self.modified = True
90
+ return True
91
+ except (ValueError, TypeError):
92
+ pass
93
+ return False
94
+
95
+ def insert_instruction(
96
+ self,
97
+ block: BasicBlock,
98
+ inst: MIRInstruction,
99
+ position: int | None = None,
100
+ ) -> None:
101
+ """Insert an instruction into a block.
102
+
103
+ Args:
104
+ block: The block to insert into.
105
+ inst: Instruction to insert.
106
+ position: Position to insert at (None for end).
107
+ """
108
+ if isinstance(inst, Phi):
109
+ block.phi_nodes.append(inst)
110
+ else:
111
+ if position is None:
112
+ # Insert before terminator if present
113
+ if block.get_terminator():
114
+ block.instructions.insert(-1, inst)
115
+ else:
116
+ block.instructions.append(inst)
117
+ else:
118
+ block.instructions.insert(position, inst)
119
+ self.modified = True
120
+
121
+ def replace_uses(
122
+ self,
123
+ old_value: MIRValue,
124
+ new_value: MIRValue,
125
+ block: BasicBlock | None = None,
126
+ ) -> int:
127
+ """Replace all uses of a value.
128
+
129
+ Args:
130
+ old_value: Value to replace.
131
+ new_value: Replacement value.
132
+ block: Optional block to limit replacement to.
133
+
134
+ Returns:
135
+ Number of replacements made.
136
+ """
137
+ count = 0
138
+ blocks = [block] if block else self.function.cfg.blocks.values()
139
+
140
+ for b in blocks:
141
+ # Process phi nodes
142
+ for phi in b.phi_nodes:
143
+ for i, (val, label) in enumerate(phi.incoming):
144
+ if val == old_value:
145
+ phi.incoming[i] = (new_value, label)
146
+ count += 1
147
+ self.modified = True
148
+
149
+ # Process instructions
150
+ for inst in b.instructions:
151
+ inst.replace_use(old_value, new_value)
152
+ # Check if replacement occurred
153
+ if new_value in inst.get_uses():
154
+ count += 1
155
+ self.modified = True
156
+
157
+ return count
158
+
159
+ def remove_dead_instructions(self, block: BasicBlock) -> int:
160
+ """Remove dead instructions from a block.
161
+
162
+ Args:
163
+ block: Block to clean.
164
+
165
+ Returns:
166
+ Number of instructions removed.
167
+ """
168
+ removed = 0
169
+ to_remove = []
170
+
171
+ for inst in block.instructions:
172
+ # Skip side-effecting instructions
173
+ if isinstance(inst, Return | Jump | ConditionalJump | Label):
174
+ continue
175
+ if hasattr(inst, "has_side_effects") and inst.has_side_effects():
176
+ continue
177
+
178
+ # Check if any definitions are used
179
+ defs = inst.get_defs()
180
+ if defs and all(self._is_dead_value(v) for v in defs):
181
+ to_remove.append(inst)
182
+
183
+ for inst in to_remove:
184
+ self.remove_instruction(block, inst)
185
+ removed += 1
186
+
187
+ return removed
188
+
189
+ def _is_dead_value(self, value: MIRValue) -> bool:
190
+ """Check if a value is dead (unused).
191
+
192
+ Args:
193
+ value: Value to check.
194
+
195
+ Returns:
196
+ True if the value is dead.
197
+ """
198
+ # This is a simplified check - should use use-def chains
199
+ for block in self.function.cfg.blocks.values():
200
+ for phi in block.phi_nodes:
201
+ if value in [v for v, _ in phi.incoming]:
202
+ return False
203
+ for inst in block.instructions:
204
+ if value in inst.get_uses():
205
+ return False
206
+ return True
207
+
208
+ def split_block(
209
+ self,
210
+ block: BasicBlock,
211
+ split_point: int,
212
+ new_label: str,
213
+ ) -> BasicBlock:
214
+ """Split a block at a given instruction index.
215
+
216
+ Args:
217
+ block: Block to split.
218
+ split_point: Index to split at.
219
+ new_label: Label for the new block.
220
+
221
+ Returns:
222
+ The new block containing instructions after split point.
223
+ """
224
+ # Create new block
225
+ new_block = BasicBlock(new_label)
226
+
227
+ # Move instructions after split point to new block
228
+ new_block.instructions = block.instructions[split_point:]
229
+ block.instructions = block.instructions[:split_point]
230
+
231
+ # Update CFG edges
232
+ # New block takes over original block's successors
233
+ new_block.successors = block.successors.copy()
234
+ for succ in new_block.successors:
235
+ # Update predecessor
236
+ idx = succ.predecessors.index(block)
237
+ succ.predecessors[idx] = new_block
238
+
239
+ # Original block now jumps to new block
240
+ block.successors = [new_block]
241
+ new_block.predecessors = [block]
242
+
243
+ # Add jump instruction if needed
244
+ if not block.get_terminator():
245
+ block.add_instruction(Jump(new_label, (0, 0)))
246
+
247
+ # Add new block to CFG
248
+ self.function.cfg.add_block(new_block)
249
+ self.modified = True
250
+
251
+ return new_block
252
+
253
+ def merge_blocks(self, pred: BasicBlock, succ: BasicBlock) -> bool:
254
+ """Merge two blocks if possible.
255
+
256
+ Args:
257
+ pred: Predecessor block.
258
+ succ: Successor block.
259
+
260
+ Returns:
261
+ True if merge was successful.
262
+ """
263
+ # Can only merge if pred has single successor and succ has single predecessor
264
+ if len(pred.successors) != 1 or len(succ.predecessors) != 1:
265
+ return False
266
+
267
+ # Can't merge if succ has phi nodes
268
+ if succ.phi_nodes:
269
+ return False
270
+
271
+ # Remove jump from pred if it exists
272
+ if pred.get_terminator() and isinstance(pred.get_terminator(), Jump):
273
+ pred.instructions.pop()
274
+
275
+ # Move instructions from succ to pred
276
+ pred.instructions.extend(succ.instructions)
277
+
278
+ # Update CFG
279
+ pred.successors = succ.successors
280
+ for s in succ.successors:
281
+ idx = s.predecessors.index(succ)
282
+ s.predecessors[idx] = pred
283
+
284
+ # Remove succ from CFG
285
+ del self.function.cfg.blocks[succ.label]
286
+ self.modified = True
287
+
288
+ return True
289
+
290
+ def eliminate_unreachable_blocks(self) -> int:
291
+ """Remove unreachable blocks from the function.
292
+
293
+ Returns:
294
+ Number of blocks removed.
295
+ """
296
+ # Find reachable blocks via DFS
297
+ reachable = set()
298
+ worklist = []
299
+
300
+ if self.function.cfg.entry_block:
301
+ worklist.append(self.function.cfg.entry_block)
302
+
303
+ while worklist:
304
+ block = worklist.pop()
305
+ if block in reachable:
306
+ continue
307
+ reachable.add(block)
308
+ worklist.extend(block.successors)
309
+
310
+ # Remove unreachable blocks
311
+ removed = 0
312
+ unreachable = [b for b in self.function.cfg.blocks.values() if b not in reachable]
313
+
314
+ for block in unreachable:
315
+ # Update predecessors' successor lists
316
+ for pred in block.predecessors:
317
+ pred.successors.remove(block)
318
+
319
+ # Update successors' predecessor lists
320
+ for succ in block.successors:
321
+ succ.predecessors.remove(block)
322
+
323
+ # Remove from CFG
324
+ del self.function.cfg.blocks[block.label]
325
+ removed += 1
326
+ self.modified = True
327
+
328
+ return removed
329
+
330
+ def simplify_cfg(self) -> bool:
331
+ """Simplify the control flow graph.
332
+
333
+ Returns:
334
+ True if any simplification was performed.
335
+ """
336
+ initial_modified = self.modified
337
+
338
+ # Remove unreachable blocks
339
+ self.eliminate_unreachable_blocks()
340
+
341
+ # Merge blocks where possible
342
+ changed = True
343
+ while changed:
344
+ changed = False
345
+ for block in list(self.function.cfg.blocks.values()):
346
+ if len(block.successors) == 1:
347
+ succ = block.successors[0]
348
+ if self.merge_blocks(block, succ):
349
+ changed = True
350
+ break
351
+
352
+ # Remove empty blocks (except entry)
353
+ for block in list(self.function.cfg.blocks.values()):
354
+ if block != self.function.cfg.entry_block and not block.instructions and not block.phi_nodes:
355
+ # Redirect predecessors to successors
356
+ if len(block.successors) == 1:
357
+ succ = block.successors[0]
358
+ for pred in block.predecessors:
359
+ # Update pred's successors
360
+ idx = pred.successors.index(block)
361
+ pred.successors[idx] = succ
362
+ # Update succ's predecessors
363
+ idx = succ.predecessors.index(block)
364
+ succ.predecessors[idx] = pred
365
+ # Update jump targets
366
+ term = pred.get_terminator()
367
+ if isinstance(term, Jump) and term.label == block.label:
368
+ term.label = succ.label
369
+ elif isinstance(term, ConditionalJump):
370
+ if term.true_label == block.label:
371
+ term.true_label = succ.label
372
+ if term.false_label == block.label:
373
+ term.false_label = succ.label
374
+
375
+ del self.function.cfg.blocks[block.label]
376
+ self.modified = True
377
+
378
+ return self.modified != initial_modified
379
+
380
+ def apply_to_all_instructions(
381
+ self,
382
+ transform: Callable[[MIRInstruction], MIRInstruction | None],
383
+ ) -> int:
384
+ """Apply a transformation to all instructions.
385
+
386
+ Args:
387
+ transform: Function that transforms or removes instructions.
388
+
389
+ Returns:
390
+ Number of instructions modified.
391
+ """
392
+ count = 0
393
+
394
+ for block in self.function.cfg.blocks.values():
395
+ # Process instructions
396
+ new_instructions = []
397
+ for inst in block.instructions:
398
+ result = transform(inst)
399
+ if result is not None:
400
+ new_instructions.append(result)
401
+ if result != inst:
402
+ count += 1
403
+ self.modified = True
404
+ else:
405
+ count += 1
406
+ self.modified = True
407
+
408
+ block.instructions = new_instructions
409
+
410
+ return count