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,545 @@
1
+ """Tests for type-specific MIR optimization pass."""
2
+
3
+ from machine_dialect.ast import (
4
+ DefineStatement,
5
+ Identifier,
6
+ Program,
7
+ SetStatement,
8
+ WholeNumberLiteral,
9
+ )
10
+ from machine_dialect.lexer.tokens import Token, TokenType
11
+ from machine_dialect.mir.basic_block import BasicBlock
12
+ from machine_dialect.mir.hir_to_mir import HIRToMIRLowering
13
+ from machine_dialect.mir.mir_function import MIRFunction
14
+ from machine_dialect.mir.mir_instructions import (
15
+ BinaryOp,
16
+ Copy,
17
+ LoadConst,
18
+ UnaryOp,
19
+ )
20
+ from machine_dialect.mir.mir_types import MIRType, MIRUnionType
21
+ from machine_dialect.mir.mir_values import Constant, Temp, Variable
22
+ from machine_dialect.mir.optimizations.type_specific import TypeSpecificOptimization
23
+
24
+
25
+ class TestTypeSpecificOptimization:
26
+ """Test type-specific MIR optimization."""
27
+
28
+ def setup_method(self) -> None:
29
+ """Set up test fixtures."""
30
+ self.optimizer = TypeSpecificOptimization()
31
+ self.dummy_token = Token(TokenType.KW_DEFINE, "Define", 1, 1)
32
+
33
+ def test_integer_constant_folding(self) -> None:
34
+ """Test integer constant folding with type information."""
35
+ # Create a function with integer variables
36
+ func = MIRFunction("test", [])
37
+
38
+ # Add typed locals
39
+ x = Variable("x", MIRType.INT)
40
+ func.add_local(x)
41
+
42
+ # Create a basic block
43
+ block = BasicBlock("entry")
44
+
45
+ # Add integer arithmetic: result = 5 + 3
46
+ result = Temp(MIRType.INT, 0)
47
+ block.add_instruction(BinaryOp(result, "+", Constant(5, MIRType.INT), Constant(3, MIRType.INT), (1, 1)))
48
+
49
+ func.cfg.add_block(block)
50
+ func.cfg.set_entry_block(block)
51
+
52
+ # Run optimization
53
+ modified = self.optimizer.run_on_function(func)
54
+
55
+ # Check that the operation was folded
56
+ assert modified
57
+ assert len(block.instructions) == 1
58
+ assert isinstance(block.instructions[0], LoadConst)
59
+ assert block.instructions[0].constant.value == 8
60
+ assert self.optimizer.stats["constant_folded"] == 1
61
+
62
+ def test_float_constant_folding(self) -> None:
63
+ """Test float constant folding with type information."""
64
+ func = MIRFunction("test", [])
65
+
66
+ # Create a basic block
67
+ block = BasicBlock("entry")
68
+
69
+ # Add float arithmetic: result = 3.14 * 2.0
70
+ result = Temp(MIRType.FLOAT, 0)
71
+ block.add_instruction(
72
+ BinaryOp(result, "*", Constant(3.14, MIRType.FLOAT), Constant(2.0, MIRType.FLOAT), (1, 1))
73
+ )
74
+
75
+ func.cfg.add_block(block)
76
+ func.cfg.set_entry_block(block)
77
+
78
+ # Run optimization
79
+ modified = self.optimizer.run_on_function(func)
80
+
81
+ # Check that the operation was folded
82
+ assert modified
83
+ assert len(block.instructions) == 1
84
+ assert isinstance(block.instructions[0], LoadConst)
85
+ assert block.instructions[0].constant.value == 6.28
86
+ assert self.optimizer.stats["constant_folded"] == 1
87
+
88
+ def test_boolean_short_circuit_and_false(self) -> None:
89
+ """Test boolean short-circuit optimization for AND with False."""
90
+ func = MIRFunction("test", [])
91
+
92
+ # Create a basic block
93
+ block = BasicBlock("entry")
94
+
95
+ # Add boolean operation: result = False and x
96
+ x = Variable("x", MIRType.BOOL)
97
+ result = Temp(MIRType.BOOL, 0)
98
+ block.add_instruction(BinaryOp(result, "and", Constant(False, MIRType.BOOL), x, (1, 1)))
99
+
100
+ func.cfg.add_block(block)
101
+ func.cfg.set_entry_block(block)
102
+
103
+ # Run optimization
104
+ modified = self.optimizer.run_on_function(func)
105
+
106
+ # Check that the operation was short-circuited
107
+ assert modified
108
+ assert len(block.instructions) == 1
109
+ assert isinstance(block.instructions[0], LoadConst)
110
+ assert block.instructions[0].constant.value is False
111
+ assert self.optimizer.stats["boolean_optimized"] == 1
112
+
113
+ def test_boolean_short_circuit_or_true(self) -> None:
114
+ """Test boolean short-circuit optimization for OR with True."""
115
+ func = MIRFunction("test", [])
116
+
117
+ # Create a basic block
118
+ block = BasicBlock("entry")
119
+
120
+ # Add boolean operation: result = True or x
121
+ x = Variable("x", MIRType.BOOL)
122
+ result = Temp(MIRType.BOOL, 0)
123
+ block.add_instruction(BinaryOp(result, "or", Constant(True, MIRType.BOOL), x, (1, 1)))
124
+
125
+ func.cfg.add_block(block)
126
+ func.cfg.set_entry_block(block)
127
+
128
+ # Run optimization
129
+ modified = self.optimizer.run_on_function(func)
130
+
131
+ # Check that the operation was short-circuited
132
+ assert modified
133
+ assert len(block.instructions) == 1
134
+ assert isinstance(block.instructions[0], LoadConst)
135
+ assert block.instructions[0].constant.value is True
136
+
137
+ def test_integer_identity_add_zero(self) -> None:
138
+ """Test integer identity optimization: x + 0 -> x."""
139
+ func = MIRFunction("test", [])
140
+
141
+ # Add typed local
142
+ x = Variable("x", MIRType.INT)
143
+ func.add_local(x)
144
+
145
+ # Create a basic block
146
+ block = BasicBlock("entry")
147
+
148
+ # Add operation: result = x + 0
149
+ result = Temp(MIRType.INT, 0)
150
+ block.add_instruction(BinaryOp(result, "+", x, Constant(0, MIRType.INT), (1, 1)))
151
+
152
+ func.cfg.add_block(block)
153
+ func.cfg.set_entry_block(block)
154
+
155
+ # Run optimization
156
+ modified = self.optimizer.run_on_function(func)
157
+
158
+ # Check that the operation was simplified
159
+ assert modified
160
+ assert len(block.instructions) == 1
161
+ assert isinstance(block.instructions[0], Copy)
162
+ assert block.instructions[0].source == x
163
+
164
+ def test_integer_multiply_by_zero(self) -> None:
165
+ """Test integer optimization: x * 0 -> 0."""
166
+ func = MIRFunction("test", [])
167
+
168
+ # Add typed local
169
+ x = Variable("x", MIRType.INT)
170
+ func.add_local(x)
171
+
172
+ # Create a basic block
173
+ block = BasicBlock("entry")
174
+
175
+ # Add operation: result = x * 0
176
+ result = Temp(MIRType.INT, 0)
177
+ block.add_instruction(BinaryOp(result, "*", x, Constant(0, MIRType.INT), (1, 1)))
178
+
179
+ func.cfg.add_block(block)
180
+ func.cfg.set_entry_block(block)
181
+
182
+ # Run optimization
183
+ modified = self.optimizer.run_on_function(func)
184
+
185
+ # Check that the operation was simplified
186
+ assert modified
187
+ assert len(block.instructions) == 1
188
+ assert isinstance(block.instructions[0], LoadConst)
189
+ assert block.instructions[0].constant.value == 0
190
+
191
+ def test_unary_negation_constant_folding(self) -> None:
192
+ """Test unary negation constant folding."""
193
+ func = MIRFunction("test", [])
194
+
195
+ # Create a basic block
196
+ block = BasicBlock("entry")
197
+
198
+ # Add unary operation: result = -42
199
+ result = Temp(MIRType.INT, 0)
200
+ block.add_instruction(UnaryOp(result, "-", Constant(42, MIRType.INT), (1, 1)))
201
+
202
+ func.cfg.add_block(block)
203
+ func.cfg.set_entry_block(block)
204
+
205
+ # Run optimization
206
+ modified = self.optimizer.run_on_function(func)
207
+
208
+ # Check that the operation was folded
209
+ assert modified
210
+ assert len(block.instructions) == 1
211
+ assert isinstance(block.instructions[0], LoadConst)
212
+ assert block.instructions[0].constant.value == -42
213
+
214
+ def test_union_type_handling(self) -> None:
215
+ """Test handling of union types."""
216
+ func = MIRFunction("test", [])
217
+
218
+ # Add variable with union type metadata
219
+ x = Variable("x", MIRType.UNKNOWN)
220
+ x.union_type = MIRUnionType([MIRType.INT, MIRType.STRING])
221
+ func.add_local(x)
222
+
223
+ # Create a basic block
224
+ block = BasicBlock("entry")
225
+
226
+ # Add operation with union type variable
227
+ result = Temp(MIRType.UNKNOWN, 0)
228
+ block.add_instruction(BinaryOp(result, "+", x, Constant(1, MIRType.INT), (1, 1)))
229
+
230
+ func.cfg.add_block(block)
231
+ func.cfg.set_entry_block(block)
232
+
233
+ # Run optimization - should not optimize due to unknown runtime type
234
+ modified = self.optimizer.run_on_function(func)
235
+
236
+ # Check that the operation was not modified (can't optimize union types)
237
+ assert not modified
238
+ assert len(block.instructions) == 1
239
+ assert isinstance(block.instructions[0], BinaryOp)
240
+
241
+ def test_string_concatenation_folding(self) -> None:
242
+ """Test string concatenation constant folding."""
243
+ func = MIRFunction("test", [])
244
+
245
+ # Create a basic block
246
+ block = BasicBlock("entry")
247
+
248
+ # Add string concatenation: result = "Hello, " + "World!"
249
+ result = Temp(MIRType.STRING, 0)
250
+ block.add_instruction(
251
+ BinaryOp(result, "+", Constant("Hello, ", MIRType.STRING), Constant("World!", MIRType.STRING), (1, 1))
252
+ )
253
+
254
+ func.cfg.add_block(block)
255
+ func.cfg.set_entry_block(block)
256
+
257
+ # Run optimization
258
+ modified = self.optimizer.run_on_function(func)
259
+
260
+ # Check that the operation was folded
261
+ assert modified
262
+ assert len(block.instructions) == 1
263
+ assert isinstance(block.instructions[0], LoadConst)
264
+ assert block.instructions[0].constant.value == "Hello, World!"
265
+
266
+ def test_comparison_constant_folding(self) -> None:
267
+ """Test comparison operation constant folding."""
268
+ func = MIRFunction("test", [])
269
+
270
+ # Create a basic block
271
+ block = BasicBlock("entry")
272
+
273
+ # Add comparison: result = 5 < 10
274
+ result = Temp(MIRType.BOOL, 0)
275
+ block.add_instruction(BinaryOp(result, "<", Constant(5, MIRType.INT), Constant(10, MIRType.INT), (1, 1)))
276
+
277
+ func.cfg.add_block(block)
278
+ func.cfg.set_entry_block(block)
279
+
280
+ # Run optimization
281
+ modified = self.optimizer.run_on_function(func)
282
+
283
+ # Check that the operation was folded
284
+ assert modified
285
+ assert len(block.instructions) == 1
286
+ assert isinstance(block.instructions[0], LoadConst)
287
+ assert block.instructions[0].constant.value is True
288
+
289
+ def test_integration_with_hir_lowering(self) -> None:
290
+ """Test integration with HIR to MIR lowering."""
291
+ # Create a program with type definitions
292
+ program = Program(
293
+ [
294
+ DefineStatement(self.dummy_token, Identifier(self.dummy_token, "x"), ["Whole Number"], None),
295
+ DefineStatement(self.dummy_token, Identifier(self.dummy_token, "y"), ["Whole Number"], None),
296
+ SetStatement(
297
+ self.dummy_token, Identifier(self.dummy_token, "x"), WholeNumberLiteral(self.dummy_token, 5)
298
+ ),
299
+ SetStatement(
300
+ self.dummy_token, Identifier(self.dummy_token, "y"), WholeNumberLiteral(self.dummy_token, 10)
301
+ ),
302
+ ]
303
+ )
304
+
305
+ # Lower to MIR
306
+ lowering = HIRToMIRLowering()
307
+ mir_module = lowering.lower_program(program)
308
+
309
+ # Get the main function
310
+ main_func = mir_module.get_function("__main__")
311
+ assert main_func is not None
312
+
313
+ # Check that type information was propagated
314
+ assert "x" in lowering.type_context
315
+ assert lowering.type_context["x"] == MIRType.INT
316
+ assert "y" in lowering.type_context
317
+ assert lowering.type_context["y"] == MIRType.INT
318
+
319
+ def test_strength_reduction_multiply_power_of_two(self) -> None:
320
+ """Test strength reduction: x * 8 -> x << 3."""
321
+ func = MIRFunction("test", [])
322
+
323
+ # Add typed local
324
+ x = Variable("x", MIRType.INT)
325
+ func.add_local(x)
326
+
327
+ # Create a basic block
328
+ block = BasicBlock("entry")
329
+
330
+ # Add operation: result = x * 8
331
+ result = Temp(MIRType.INT, 0)
332
+ block.add_instruction(BinaryOp(result, "*", x, Constant(8, MIRType.INT), (1, 1)))
333
+
334
+ func.cfg.add_block(block)
335
+ func.cfg.set_entry_block(block)
336
+
337
+ # Run optimization
338
+ modified = self.optimizer.run_on_function(func)
339
+
340
+ # Check that the operation was converted to shift
341
+ assert modified
342
+ assert len(block.instructions) == 1
343
+ from machine_dialect.mir.mir_instructions import ShiftOp
344
+
345
+ assert isinstance(block.instructions[0], ShiftOp)
346
+ assert block.instructions[0].op == "<<"
347
+ assert isinstance(block.instructions[0].right, Constant)
348
+ assert block.instructions[0].right.value == 3 # 8 = 2^3
349
+
350
+ def test_strength_reduction_divide_power_of_two(self) -> None:
351
+ """Test strength reduction: x / 16 -> x >> 4."""
352
+ func = MIRFunction("test", [])
353
+
354
+ # Add typed local
355
+ x = Variable("x", MIRType.INT)
356
+ func.add_local(x)
357
+
358
+ # Create a basic block
359
+ block = BasicBlock("entry")
360
+
361
+ # Add operation: result = x / 16
362
+ result = Temp(MIRType.INT, 0)
363
+ block.add_instruction(BinaryOp(result, "/", x, Constant(16, MIRType.INT), (1, 1)))
364
+
365
+ func.cfg.add_block(block)
366
+ func.cfg.set_entry_block(block)
367
+
368
+ # Run optimization
369
+ modified = self.optimizer.run_on_function(func)
370
+
371
+ # Check that the operation was converted to shift
372
+ assert modified
373
+ assert len(block.instructions) == 1
374
+ from machine_dialect.mir.mir_instructions import ShiftOp
375
+
376
+ assert isinstance(block.instructions[0], ShiftOp)
377
+ assert block.instructions[0].op == ">>"
378
+ assert isinstance(block.instructions[0].right, Constant)
379
+ assert block.instructions[0].right.value == 4 # 16 = 2^4
380
+
381
+ def test_modulo_power_of_two(self) -> None:
382
+ """Test strength reduction: x % 32 -> x & 31."""
383
+ func = MIRFunction("test", [])
384
+
385
+ # Add typed local
386
+ x = Variable("x", MIRType.INT)
387
+ func.add_local(x)
388
+
389
+ # Create a basic block
390
+ block = BasicBlock("entry")
391
+
392
+ # Add operation: result = x % 32
393
+ result = Temp(MIRType.INT, 0)
394
+ block.add_instruction(BinaryOp(result, "%", x, Constant(32, MIRType.INT), (1, 1)))
395
+
396
+ func.cfg.add_block(block)
397
+ func.cfg.set_entry_block(block)
398
+
399
+ # Run optimization
400
+ modified = self.optimizer.run_on_function(func)
401
+
402
+ # Check that the operation was converted to bitwise AND
403
+ assert modified
404
+ assert len(block.instructions) == 1
405
+ assert isinstance(block.instructions[0], BinaryOp)
406
+ assert block.instructions[0].op == "&"
407
+ assert isinstance(block.instructions[0].right, Constant)
408
+ assert block.instructions[0].right.value == 31 # 32 - 1
409
+
410
+ def test_self_subtraction(self) -> None:
411
+ """Test self-operation: x - x -> 0."""
412
+ func = MIRFunction("test", [])
413
+
414
+ # Add typed local
415
+ x = Variable("x", MIRType.INT)
416
+ func.add_local(x)
417
+
418
+ # Create a basic block
419
+ block = BasicBlock("entry")
420
+
421
+ # Add operation: result = x - x
422
+ result = Temp(MIRType.INT, 0)
423
+ block.add_instruction(BinaryOp(result, "-", x, x, (1, 1)))
424
+
425
+ func.cfg.add_block(block)
426
+ func.cfg.set_entry_block(block)
427
+
428
+ # Run optimization
429
+ modified = self.optimizer.run_on_function(func)
430
+
431
+ # Check that the operation was simplified
432
+ assert modified
433
+ assert len(block.instructions) == 1
434
+ assert isinstance(block.instructions[0], LoadConst)
435
+ assert block.instructions[0].constant.value == 0
436
+
437
+ def test_self_division(self) -> None:
438
+ """Test self-operation: x / x -> 1."""
439
+ func = MIRFunction("test", [])
440
+
441
+ # Add typed local
442
+ x = Variable("x", MIRType.INT)
443
+ func.add_local(x)
444
+
445
+ # Create a basic block
446
+ block = BasicBlock("entry")
447
+
448
+ # Add operation: result = x / x
449
+ result = Temp(MIRType.INT, 0)
450
+ block.add_instruction(BinaryOp(result, "/", x, x, (1, 1)))
451
+
452
+ func.cfg.add_block(block)
453
+ func.cfg.set_entry_block(block)
454
+
455
+ # Run optimization
456
+ modified = self.optimizer.run_on_function(func)
457
+
458
+ # Check that the operation was simplified
459
+ assert modified
460
+ assert len(block.instructions) == 1
461
+ assert isinstance(block.instructions[0], LoadConst)
462
+ assert block.instructions[0].constant.value == 1
463
+
464
+ def test_self_equality(self) -> None:
465
+ """Test self-comparison: x == x -> True."""
466
+ func = MIRFunction("test", [])
467
+
468
+ # Add typed local
469
+ x = Variable("x", MIRType.INT)
470
+ func.add_local(x)
471
+
472
+ # Create a basic block
473
+ block = BasicBlock("entry")
474
+
475
+ # Add operation: result = x == x
476
+ result = Temp(MIRType.BOOL, 0)
477
+ block.add_instruction(BinaryOp(result, "==", x, x, (1, 1)))
478
+
479
+ func.cfg.add_block(block)
480
+ func.cfg.set_entry_block(block)
481
+
482
+ # Run optimization
483
+ modified = self.optimizer.run_on_function(func)
484
+
485
+ # Check that the operation was simplified
486
+ assert modified
487
+ assert len(block.instructions) == 1
488
+ assert isinstance(block.instructions[0], LoadConst)
489
+ assert block.instructions[0].constant.value is True
490
+
491
+ def test_multiply_by_two_to_addition(self) -> None:
492
+ """Test optimization: x * 2 -> x + x."""
493
+ func = MIRFunction("test", [])
494
+
495
+ # Add typed local
496
+ x = Variable("x", MIRType.INT)
497
+ func.add_local(x)
498
+
499
+ # Create a basic block
500
+ block = BasicBlock("entry")
501
+
502
+ # Add operation: result = x * 2
503
+ result = Temp(MIRType.INT, 0)
504
+ block.add_instruction(BinaryOp(result, "*", x, Constant(2, MIRType.INT), (1, 1)))
505
+
506
+ func.cfg.add_block(block)
507
+ func.cfg.set_entry_block(block)
508
+
509
+ # Run optimization
510
+ modified = self.optimizer.run_on_function(func)
511
+
512
+ # Check that the operation was converted to addition
513
+ assert modified
514
+ assert len(block.instructions) == 1
515
+ assert isinstance(block.instructions[0], BinaryOp)
516
+ assert block.instructions[0].op == "+"
517
+ assert block.instructions[0].left == x
518
+ assert block.instructions[0].right == x
519
+
520
+ def test_boolean_idempotent_and(self) -> None:
521
+ """Test boolean idempotent: x and x -> x."""
522
+ func = MIRFunction("test", [])
523
+
524
+ # Add typed local
525
+ x = Variable("x", MIRType.BOOL)
526
+ func.add_local(x)
527
+
528
+ # Create a basic block
529
+ block = BasicBlock("entry")
530
+
531
+ # Add operation: result = x and x
532
+ result = Temp(MIRType.BOOL, 0)
533
+ block.add_instruction(BinaryOp(result, "and", x, x, (1, 1)))
534
+
535
+ func.cfg.add_block(block)
536
+ func.cfg.set_entry_block(block)
537
+
538
+ # Run optimization
539
+ modified = self.optimizer.run_on_function(func)
540
+
541
+ # Check that the operation was simplified
542
+ assert modified
543
+ assert len(block.instructions) == 1
544
+ assert isinstance(block.instructions[0], Copy)
545
+ assert block.instructions[0].source == x