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,863 @@
1
+ """Tests for algebraic simplification and strength reduction optimization passes."""
2
+
3
+ from machine_dialect.mir.basic_block import BasicBlock
4
+ from machine_dialect.mir.mir_function import MIRFunction
5
+ from machine_dialect.mir.mir_instructions import BinaryOp, Copy, LoadConst
6
+ from machine_dialect.mir.mir_module import MIRModule
7
+ from machine_dialect.mir.mir_transformer import MIRTransformer
8
+ from machine_dialect.mir.mir_types import MIRType
9
+ from machine_dialect.mir.mir_values import Constant, Temp
10
+ from machine_dialect.mir.optimizations.algebraic_simplification import AlgebraicSimplification
11
+ from machine_dialect.mir.optimizations.strength_reduction import StrengthReduction
12
+
13
+
14
+ class TestAlgebraicSimplificationComparison:
15
+ """Test comparison operation simplifications in AlgebraicSimplification."""
16
+
17
+ def setup_method(self) -> None:
18
+ """Set up test fixtures."""
19
+ self.module = MIRModule("test")
20
+ self.func = MIRFunction("test_func", [], MIRType.BOOL)
21
+ self.block = BasicBlock("entry")
22
+ self.func.cfg.add_block(self.block)
23
+ self.func.cfg.entry_block = self.block
24
+ self.module.add_function(self.func)
25
+ self.transformer = MIRTransformer(self.func)
26
+ self.opt = AlgebraicSimplification()
27
+
28
+ def test_equal_same_value(self) -> None:
29
+ """Test x == x → true."""
30
+ t0 = Temp(MIRType.INT)
31
+ t1 = Temp(MIRType.BOOL)
32
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
33
+ self.block.add_instruction(BinaryOp(t1, "==", t0, t0, (1, 1)))
34
+
35
+ changed = self.opt.run_on_function(self.func)
36
+
37
+ assert changed
38
+ assert self.opt.stats.get("comparison_simplified") == 1
39
+ instructions = list(self.block.instructions)
40
+ assert isinstance(instructions[1], LoadConst)
41
+ load_inst = instructions[1]
42
+ assert isinstance(load_inst, LoadConst)
43
+ assert load_inst.constant.value is True
44
+
45
+ def test_not_equal_same_value(self) -> None:
46
+ """Test x != x → false."""
47
+ t0 = Temp(MIRType.INT)
48
+ t1 = Temp(MIRType.BOOL)
49
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
50
+ self.block.add_instruction(BinaryOp(t1, "!=", t0, t0, (1, 1)))
51
+
52
+ changed = self.opt.run_on_function(self.func)
53
+
54
+ assert changed
55
+ assert self.opt.stats.get("comparison_simplified") == 1
56
+ instructions = list(self.block.instructions)
57
+ assert isinstance(instructions[1], LoadConst)
58
+ load_inst = instructions[1]
59
+ assert isinstance(load_inst, LoadConst)
60
+ assert load_inst.constant.value is False
61
+
62
+ def test_less_than_same_value(self) -> None:
63
+ """Test x < x → false."""
64
+ t0 = Temp(MIRType.INT)
65
+ t1 = Temp(MIRType.BOOL)
66
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
67
+ self.block.add_instruction(BinaryOp(t1, "<", t0, t0, (1, 1)))
68
+
69
+ changed = self.opt.run_on_function(self.func)
70
+
71
+ assert changed
72
+ assert self.opt.stats.get("comparison_simplified") == 1
73
+ instructions = list(self.block.instructions)
74
+ assert isinstance(instructions[1], LoadConst)
75
+ load_inst = instructions[1]
76
+ assert isinstance(load_inst, LoadConst)
77
+ assert load_inst.constant.value is False
78
+
79
+ def test_greater_than_same_value(self) -> None:
80
+ """Test x > x → false."""
81
+ t0 = Temp(MIRType.INT)
82
+ t1 = Temp(MIRType.BOOL)
83
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
84
+ self.block.add_instruction(BinaryOp(t1, ">", t0, t0, (1, 1)))
85
+
86
+ changed = self.opt.run_on_function(self.func)
87
+
88
+ assert changed
89
+ assert self.opt.stats.get("comparison_simplified") == 1
90
+ instructions = list(self.block.instructions)
91
+ assert isinstance(instructions[1], LoadConst)
92
+ load_inst = instructions[1]
93
+ assert isinstance(load_inst, LoadConst)
94
+ assert load_inst.constant.value is False
95
+
96
+ def test_less_equal_same_value(self) -> None:
97
+ """Test x <= x → true."""
98
+ t0 = Temp(MIRType.INT)
99
+ t1 = Temp(MIRType.BOOL)
100
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
101
+ self.block.add_instruction(BinaryOp(t1, "<=", t0, t0, (1, 1)))
102
+
103
+ changed = self.opt.run_on_function(self.func)
104
+
105
+ assert changed
106
+ assert self.opt.stats.get("comparison_simplified") == 1
107
+ instructions = list(self.block.instructions)
108
+ assert isinstance(instructions[1], LoadConst)
109
+ load_inst = instructions[1]
110
+ assert isinstance(load_inst, LoadConst)
111
+ assert load_inst.constant.value is True
112
+
113
+ def test_greater_equal_same_value(self) -> None:
114
+ """Test x >= x → true."""
115
+ t0 = Temp(MIRType.INT)
116
+ t1 = Temp(MIRType.BOOL)
117
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
118
+ self.block.add_instruction(BinaryOp(t1, ">=", t0, t0, (1, 1)))
119
+
120
+ changed = self.opt.run_on_function(self.func)
121
+
122
+ assert changed
123
+ assert self.opt.stats.get("comparison_simplified") == 1
124
+ instructions = list(self.block.instructions)
125
+ assert isinstance(instructions[1], LoadConst)
126
+ load_inst = instructions[1]
127
+ assert isinstance(load_inst, LoadConst)
128
+ assert load_inst.constant.value is True
129
+
130
+ def test_comparison_different_values_no_change(self) -> None:
131
+ """Test that comparisons with different values are not simplified."""
132
+ t0 = Temp(MIRType.INT)
133
+ t1 = Temp(MIRType.INT)
134
+ t2 = Temp(MIRType.BOOL)
135
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
136
+ self.block.add_instruction(LoadConst(t1, Constant(43, MIRType.INT), (1, 1)))
137
+ self.block.add_instruction(BinaryOp(t2, "==", t0, t1, (1, 1)))
138
+
139
+ changed = self.opt.run_on_function(self.func)
140
+
141
+ assert not changed
142
+ assert "comparison_simplified" not in self.opt.stats
143
+ instructions = list(self.block.instructions)
144
+ assert isinstance(instructions[2], BinaryOp)
145
+
146
+
147
+ class TestAlgebraicSimplificationBitwise:
148
+ """Test bitwise operation simplifications in AlgebraicSimplification."""
149
+
150
+ def setup_method(self) -> None:
151
+ """Set up test fixtures."""
152
+ self.module = MIRModule("test")
153
+ self.func = MIRFunction("test_func", [], MIRType.INT)
154
+ self.block = BasicBlock("entry")
155
+ self.func.cfg.add_block(self.block)
156
+ self.func.cfg.entry_block = self.block
157
+ self.module.add_function(self.func)
158
+ self.transformer = MIRTransformer(self.func)
159
+ self.opt = AlgebraicSimplification()
160
+
161
+ def test_and_with_zero(self) -> None:
162
+ """Test x & 0 → 0."""
163
+ t0 = Temp(MIRType.INT)
164
+ t1 = Temp(MIRType.INT)
165
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
166
+ self.block.add_instruction(BinaryOp(t1, "&", t0, Constant(0, MIRType.INT), (1, 1)))
167
+
168
+ changed = self.opt.run_on_function(self.func)
169
+
170
+ assert changed
171
+ assert self.opt.stats.get("bitwise_simplified") == 1
172
+ instructions = list(self.block.instructions)
173
+ assert isinstance(instructions[1], LoadConst)
174
+ load_inst = instructions[1]
175
+ assert isinstance(load_inst, LoadConst)
176
+ assert load_inst.constant.value == 0
177
+
178
+ def test_and_with_self(self) -> None:
179
+ """Test x & x → x."""
180
+ t0 = Temp(MIRType.INT)
181
+ t1 = Temp(MIRType.INT)
182
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
183
+ self.block.add_instruction(BinaryOp(t1, "&", t0, t0, (1, 1)))
184
+
185
+ changed = self.opt.run_on_function(self.func)
186
+
187
+ assert changed
188
+ assert self.opt.stats.get("bitwise_simplified") == 1
189
+ instructions = list(self.block.instructions)
190
+ assert isinstance(instructions[1], Copy)
191
+ copy_inst = instructions[1]
192
+ assert isinstance(copy_inst, Copy)
193
+ assert copy_inst.source == t0
194
+
195
+ def test_and_with_all_ones(self) -> None:
196
+ """Test x & -1 → x (all ones)."""
197
+ t0 = Temp(MIRType.INT)
198
+ t1 = Temp(MIRType.INT)
199
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
200
+ self.block.add_instruction(BinaryOp(t1, "&", t0, Constant(-1, MIRType.INT), (1, 1)))
201
+
202
+ changed = self.opt.run_on_function(self.func)
203
+
204
+ assert changed
205
+ assert self.opt.stats.get("bitwise_simplified") == 1
206
+ instructions = list(self.block.instructions)
207
+ assert isinstance(instructions[1], Copy)
208
+ copy_inst = instructions[1]
209
+ assert isinstance(copy_inst, Copy)
210
+ assert copy_inst.source == t0
211
+
212
+ def test_or_with_zero(self) -> None:
213
+ """Test x | 0 → x."""
214
+ t0 = Temp(MIRType.INT)
215
+ t1 = Temp(MIRType.INT)
216
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
217
+ self.block.add_instruction(BinaryOp(t1, "|", t0, Constant(0, MIRType.INT), (1, 1)))
218
+
219
+ changed = self.opt.run_on_function(self.func)
220
+
221
+ assert changed
222
+ assert self.opt.stats.get("bitwise_simplified") == 1
223
+ instructions = list(self.block.instructions)
224
+ assert isinstance(instructions[1], Copy)
225
+ copy_inst = instructions[1]
226
+ assert isinstance(copy_inst, Copy)
227
+ assert copy_inst.source == t0
228
+
229
+ def test_or_with_self(self) -> None:
230
+ """Test x | x → x."""
231
+ t0 = Temp(MIRType.INT)
232
+ t1 = Temp(MIRType.INT)
233
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
234
+ self.block.add_instruction(BinaryOp(t1, "|", t0, t0, (1, 1)))
235
+
236
+ changed = self.opt.run_on_function(self.func)
237
+
238
+ assert changed
239
+ assert self.opt.stats.get("bitwise_simplified") == 1
240
+ instructions = list(self.block.instructions)
241
+ assert isinstance(instructions[1], Copy)
242
+ copy_inst = instructions[1]
243
+ assert isinstance(copy_inst, Copy)
244
+ assert copy_inst.source == t0
245
+
246
+ def test_or_with_all_ones(self) -> None:
247
+ """Test x | -1 → -1 (all ones)."""
248
+ t0 = Temp(MIRType.INT)
249
+ t1 = Temp(MIRType.INT)
250
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
251
+ self.block.add_instruction(BinaryOp(t1, "|", t0, Constant(-1, MIRType.INT), (1, 1)))
252
+
253
+ changed = self.opt.run_on_function(self.func)
254
+
255
+ assert changed
256
+ assert self.opt.stats.get("bitwise_simplified") == 1
257
+ instructions = list(self.block.instructions)
258
+ assert isinstance(instructions[1], LoadConst)
259
+ load_inst = instructions[1]
260
+ assert isinstance(load_inst, LoadConst)
261
+ assert load_inst.constant.value == -1
262
+
263
+ def test_xor_with_zero(self) -> None:
264
+ """Test x ^ 0 → x."""
265
+ t0 = Temp(MIRType.INT)
266
+ t1 = Temp(MIRType.INT)
267
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
268
+ self.block.add_instruction(BinaryOp(t1, "^", t0, Constant(0, MIRType.INT), (1, 1)))
269
+
270
+ changed = self.opt.run_on_function(self.func)
271
+
272
+ assert changed
273
+ assert self.opt.stats.get("bitwise_simplified") == 1
274
+ instructions = list(self.block.instructions)
275
+ assert isinstance(instructions[1], Copy)
276
+ copy_inst = instructions[1]
277
+ assert isinstance(copy_inst, Copy)
278
+ assert copy_inst.source == t0
279
+
280
+ def test_xor_with_self(self) -> None:
281
+ """Test x ^ x → 0."""
282
+ t0 = Temp(MIRType.INT)
283
+ t1 = Temp(MIRType.INT)
284
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
285
+ self.block.add_instruction(BinaryOp(t1, "^", t0, t0, (1, 1)))
286
+
287
+ changed = self.opt.run_on_function(self.func)
288
+
289
+ assert changed
290
+ assert self.opt.stats.get("bitwise_simplified") == 1
291
+ instructions = list(self.block.instructions)
292
+ assert isinstance(instructions[1], LoadConst)
293
+ load_inst = instructions[1]
294
+ assert isinstance(load_inst, LoadConst)
295
+ assert load_inst.constant.value == 0
296
+
297
+ def test_left_shift_zero(self) -> None:
298
+ """Test x << 0 → x."""
299
+ t0 = Temp(MIRType.INT)
300
+ t1 = Temp(MIRType.INT)
301
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
302
+ self.block.add_instruction(BinaryOp(t1, "<<", t0, Constant(0, MIRType.INT), (1, 1)))
303
+
304
+ changed = self.opt.run_on_function(self.func)
305
+
306
+ assert changed
307
+ assert self.opt.stats.get("shift_simplified") == 1
308
+ instructions = list(self.block.instructions)
309
+ assert isinstance(instructions[1], Copy)
310
+ copy_inst = instructions[1]
311
+ assert isinstance(copy_inst, Copy)
312
+ assert copy_inst.source == t0
313
+
314
+ def test_right_shift_zero(self) -> None:
315
+ """Test x >> 0 → x."""
316
+ t0 = Temp(MIRType.INT)
317
+ t1 = Temp(MIRType.INT)
318
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
319
+ self.block.add_instruction(BinaryOp(t1, ">>", t0, Constant(0, MIRType.INT), (1, 1)))
320
+
321
+ changed = self.opt.run_on_function(self.func)
322
+
323
+ assert changed
324
+ assert self.opt.stats.get("shift_simplified") == 1
325
+ instructions = list(self.block.instructions)
326
+ assert isinstance(instructions[1], Copy)
327
+ copy_inst = instructions[1]
328
+ assert isinstance(copy_inst, Copy)
329
+ assert copy_inst.source == t0
330
+
331
+
332
+ class TestAlgebraicSimplificationModulo:
333
+ """Test modulo operation simplifications in AlgebraicSimplification."""
334
+
335
+ def setup_method(self) -> None:
336
+ """Set up test fixtures."""
337
+ self.module = MIRModule("test")
338
+ self.func = MIRFunction("test_func", [], MIRType.INT)
339
+ self.block = BasicBlock("entry")
340
+ self.func.cfg.add_block(self.block)
341
+ self.func.cfg.entry_block = self.block
342
+ self.module.add_function(self.func)
343
+ self.transformer = MIRTransformer(self.func)
344
+ self.opt = AlgebraicSimplification()
345
+
346
+ def test_modulo_one(self) -> None:
347
+ """Test x % 1 → 0."""
348
+ t0 = Temp(MIRType.INT)
349
+ t1 = Temp(MIRType.INT)
350
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
351
+ self.block.add_instruction(BinaryOp(t1, "%", t0, Constant(1, MIRType.INT), (1, 1)))
352
+
353
+ changed = self.opt.run_on_function(self.func)
354
+
355
+ assert changed
356
+ assert self.opt.stats.get("modulo_simplified") == 1
357
+ instructions = list(self.block.instructions)
358
+ assert isinstance(instructions[1], LoadConst)
359
+ load_inst = instructions[1]
360
+ assert isinstance(load_inst, LoadConst)
361
+ assert load_inst.constant.value == 0
362
+
363
+ def test_modulo_self(self) -> None:
364
+ """Test x % x → 0."""
365
+ t0 = Temp(MIRType.INT)
366
+ t1 = Temp(MIRType.INT)
367
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
368
+ self.block.add_instruction(BinaryOp(t1, "%", t0, t0, (1, 1)))
369
+
370
+ changed = self.opt.run_on_function(self.func)
371
+
372
+ assert changed
373
+ assert self.opt.stats.get("modulo_simplified") == 1
374
+ instructions = list(self.block.instructions)
375
+ assert isinstance(instructions[1], LoadConst)
376
+ load_inst = instructions[1]
377
+ assert isinstance(load_inst, LoadConst)
378
+ assert load_inst.constant.value == 0
379
+
380
+ def test_zero_modulo(self) -> None:
381
+ """Test 0 % x → 0."""
382
+ t0 = Temp(MIRType.INT)
383
+ self.block.add_instruction(BinaryOp(t0, "%", Constant(0, MIRType.INT), Constant(42, MIRType.INT), (1, 1)))
384
+
385
+ changed = self.opt.run_on_function(self.func)
386
+
387
+ assert changed
388
+ assert self.opt.stats.get("modulo_simplified") == 1
389
+ instructions = list(self.block.instructions)
390
+ assert isinstance(instructions[0], LoadConst)
391
+ load_inst = instructions[0]
392
+ assert isinstance(load_inst, LoadConst)
393
+ assert load_inst.constant.value == 0
394
+
395
+ def test_modulo_no_simplification(self) -> None:
396
+ """Test that x % y with different values is not simplified."""
397
+ t0 = Temp(MIRType.INT)
398
+ t1 = Temp(MIRType.INT)
399
+ t2 = Temp(MIRType.INT)
400
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
401
+ self.block.add_instruction(LoadConst(t1, Constant(5, MIRType.INT), (1, 1)))
402
+ self.block.add_instruction(BinaryOp(t2, "%", t0, t1, (1, 1)))
403
+
404
+ changed = self.opt.run_on_function(self.func)
405
+
406
+ assert not changed
407
+ assert "modulo_simplified" not in self.opt.stats
408
+ instructions = list(self.block.instructions)
409
+ assert isinstance(instructions[2], BinaryOp)
410
+
411
+
412
+ class TestAlgebraicSimplificationUnary:
413
+ """Test unary operation simplifications in AlgebraicSimplification."""
414
+
415
+ def setup_method(self) -> None:
416
+ """Set up test fixtures."""
417
+ self.module = MIRModule("test")
418
+ self.func = MIRFunction("test_func", [], MIRType.INT)
419
+ self.block = BasicBlock("entry")
420
+ self.func.cfg.add_block(self.block)
421
+ self.func.cfg.entry_block = self.block
422
+ self.module.add_function(self.func)
423
+ self.transformer = MIRTransformer(self.func)
424
+ self.opt = AlgebraicSimplification()
425
+
426
+ def test_double_negation(self) -> None:
427
+ """Test -(-x) → x."""
428
+ from machine_dialect.mir.mir_instructions import UnaryOp
429
+
430
+ t0 = Temp(MIRType.INT)
431
+ t1 = Temp(MIRType.INT)
432
+ t2 = Temp(MIRType.INT)
433
+
434
+ # Create x = 42, t1 = -x, t2 = -t1
435
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
436
+ self.block.add_instruction(UnaryOp(t1, "-", t0, (1, 1)))
437
+ self.block.add_instruction(UnaryOp(t2, "-", t1, (1, 1)))
438
+
439
+ changed = self.opt.run_on_function(self.func)
440
+
441
+ assert changed
442
+ assert self.opt.stats.get("double_negation_eliminated") == 1
443
+ instructions = list(self.block.instructions)
444
+ # The last instruction should be Copy(t2, t0, (1, 1))
445
+ assert isinstance(instructions[2], Copy)
446
+ copy_inst = instructions[2]
447
+ assert isinstance(copy_inst, Copy)
448
+ assert copy_inst.source == t0
449
+ assert copy_inst.dest == t2
450
+
451
+ def test_double_not(self) -> None:
452
+ """Test not(not(x)) → x."""
453
+ from machine_dialect.mir.mir_instructions import UnaryOp
454
+
455
+ t0 = Temp(MIRType.BOOL)
456
+ t1 = Temp(MIRType.BOOL)
457
+ t2 = Temp(MIRType.BOOL)
458
+
459
+ # Create x = true, t1 = not x, t2 = not t1
460
+ self.block.add_instruction(LoadConst(t0, Constant(True, MIRType.BOOL), (1, 1)))
461
+ self.block.add_instruction(UnaryOp(t1, "not", t0, (1, 1)))
462
+ self.block.add_instruction(UnaryOp(t2, "not", t1, (1, 1)))
463
+
464
+ changed = self.opt.run_on_function(self.func)
465
+
466
+ assert changed
467
+ assert self.opt.stats.get("double_not_eliminated") == 1
468
+ instructions = list(self.block.instructions)
469
+ # The last instruction should be Copy(t2, t0, (1, 1))
470
+ assert isinstance(instructions[2], Copy)
471
+ copy_inst = instructions[2]
472
+ assert isinstance(copy_inst, Copy)
473
+ assert copy_inst.source == t0
474
+ assert copy_inst.dest == t2
475
+
476
+
477
+ class TestAlgebraicSimplificationPower:
478
+ """Test power operation simplifications in AlgebraicSimplification."""
479
+
480
+ def setup_method(self) -> None:
481
+ """Set up test fixtures."""
482
+ self.module = MIRModule("test")
483
+ self.func = MIRFunction("test_func", [], MIRType.INT)
484
+ self.block = BasicBlock("entry")
485
+ self.func.cfg.add_block(self.block)
486
+ self.func.cfg.entry_block = self.block
487
+ self.module.add_function(self.func)
488
+ self.transformer = MIRTransformer(self.func)
489
+ self.opt = AlgebraicSimplification()
490
+
491
+ def test_power_zero_simplification(self) -> None:
492
+ """Test x ** 0 → 1."""
493
+ # Create: t0 = 5 ** 0 (using constants directly)
494
+ t0 = Temp(MIRType.INT)
495
+ self.block.add_instruction(BinaryOp(t0, "**", Constant(5, MIRType.INT), Constant(0, MIRType.INT), (1, 1)))
496
+
497
+ # Run optimization
498
+ changed = self.opt.run_on_function(self.func)
499
+
500
+ # Should simplify to t0 = 1
501
+ assert changed
502
+ assert self.opt.stats.get("power_simplified") == 1
503
+
504
+ # Check that the power op was replaced with LoadConst(1)
505
+ instructions = list(self.block.instructions)
506
+ assert isinstance(instructions[0], LoadConst)
507
+ load_inst = instructions[0]
508
+ assert isinstance(load_inst, LoadConst)
509
+ assert load_inst.constant.value == 1
510
+
511
+ def test_power_one_simplification(self) -> None:
512
+ """Test x ** 1 → x."""
513
+ # Create: t1 = t0 ** 1 where t0 is a temp with value 7
514
+ t0 = Temp(MIRType.INT)
515
+ t1 = Temp(MIRType.INT)
516
+
517
+ self.block.add_instruction(LoadConst(t0, Constant(7, MIRType.INT), (1, 1)))
518
+ self.block.add_instruction(BinaryOp(t1, "**", t0, Constant(1, MIRType.INT), (1, 1)))
519
+
520
+ # Run optimization
521
+ changed = self.opt.run_on_function(self.func)
522
+
523
+ # Should simplify to t1 = t0
524
+ assert changed
525
+ assert self.opt.stats.get("power_simplified") == 1
526
+
527
+ # Check that the power op was replaced with Copy
528
+ instructions = list(self.block.instructions)
529
+ assert isinstance(instructions[1], Copy)
530
+ copy_inst = instructions[1]
531
+ assert isinstance(copy_inst, Copy)
532
+ assert copy_inst.source == t0
533
+
534
+ def test_power_two_to_multiply(self) -> None:
535
+ """Test x ** 2 → x * x."""
536
+ # Create: t1 = t0 ** 2 where t0 is a temp
537
+ t0 = Temp(MIRType.INT)
538
+ t1 = Temp(MIRType.INT)
539
+
540
+ self.block.add_instruction(LoadConst(t0, Constant(3, MIRType.INT), (1, 1)))
541
+ self.block.add_instruction(BinaryOp(t1, "**", t0, Constant(2, MIRType.INT), (1, 1)))
542
+
543
+ # Run optimization
544
+ changed = self.opt.run_on_function(self.func)
545
+
546
+ # Should convert to t1 = t0 * t0
547
+ assert changed
548
+ assert self.opt.stats.get("power_to_multiply") == 1
549
+
550
+ # Check that the power op was replaced with multiply
551
+ instructions = list(self.block.instructions)
552
+ assert isinstance(instructions[1], BinaryOp)
553
+ binary_inst = instructions[1]
554
+ assert isinstance(binary_inst, BinaryOp)
555
+ assert binary_inst.op == "*"
556
+ assert binary_inst.left == t0
557
+ assert binary_inst.right == t0
558
+
559
+ def test_zero_power_simplification(self) -> None:
560
+ """Test 0 ** x → 0 (for x > 0)."""
561
+ # Create: t0 = 0 ** 5 (using constants directly)
562
+ t0 = Temp(MIRType.INT)
563
+ self.block.add_instruction(BinaryOp(t0, "**", Constant(0, MIRType.INT), Constant(5, MIRType.INT), (1, 1)))
564
+
565
+ # Run optimization
566
+ changed = self.opt.run_on_function(self.func)
567
+
568
+ # Should simplify to t0 = 0
569
+ assert changed
570
+ assert self.opt.stats.get("power_simplified") == 1
571
+
572
+ # Check that the power op was replaced with LoadConst(0)
573
+ instructions = list(self.block.instructions)
574
+ assert isinstance(instructions[0], LoadConst)
575
+ load_inst = instructions[0]
576
+ assert isinstance(load_inst, LoadConst)
577
+ assert load_inst.constant.value == 0
578
+
579
+ def test_one_power_simplification(self) -> None:
580
+ """Test 1 ** x → 1."""
581
+ # Create: t0 = 1 ** 10 (using constants directly)
582
+ t0 = Temp(MIRType.INT)
583
+ self.block.add_instruction(BinaryOp(t0, "**", Constant(1, MIRType.INT), Constant(10, MIRType.INT), (1, 1)))
584
+
585
+ # Run optimization
586
+ changed = self.opt.run_on_function(self.func)
587
+
588
+ # Should simplify to t0 = 1
589
+ assert changed
590
+ assert self.opt.stats.get("power_simplified") == 1
591
+
592
+ # Check that the power op was replaced with LoadConst(1)
593
+ instructions = list(self.block.instructions)
594
+ assert isinstance(instructions[0], LoadConst)
595
+ load_inst = instructions[0]
596
+ assert isinstance(load_inst, LoadConst)
597
+ assert load_inst.constant.value == 1
598
+
599
+ def test_power_no_simplification(self) -> None:
600
+ """Test that x ** 3 is not simplified (no rule for it)."""
601
+ # Create: t0 = 2 ** 3 (using constants directly)
602
+ t0 = Temp(MIRType.INT)
603
+ self.block.add_instruction(BinaryOp(t0, "**", Constant(2, MIRType.INT), Constant(3, MIRType.INT), (1, 1)))
604
+
605
+ # Run optimization
606
+ changed = self.opt.run_on_function(self.func)
607
+
608
+ # Should not change (no rule for x ** 3)
609
+ assert not changed
610
+ assert "power_simplified" not in self.opt.stats
611
+ assert "power_to_multiply" not in self.opt.stats
612
+
613
+ # The power op should still be there
614
+ instructions = list(self.block.instructions)
615
+ assert isinstance(instructions[0], BinaryOp)
616
+ binary_inst = instructions[0]
617
+ assert isinstance(binary_inst, BinaryOp)
618
+ assert binary_inst.op == "**"
619
+
620
+
621
+ class TestStrengthReductionArithmetic:
622
+ """Test arithmetic simplifications in StrengthReduction."""
623
+
624
+ def setup_method(self) -> None:
625
+ """Set up test fixtures."""
626
+ self.module = MIRModule("test")
627
+ self.func = MIRFunction("test_func", [], MIRType.INT)
628
+ self.block = BasicBlock("entry")
629
+ self.func.cfg.add_block(self.block)
630
+ self.func.cfg.entry_block = self.block
631
+ self.module.add_function(self.func)
632
+ self.transformer = MIRTransformer(self.func)
633
+ self.opt = StrengthReduction()
634
+
635
+ def test_add_zero_simplification(self) -> None:
636
+ """Test x + 0 → x and 0 + x → x."""
637
+ # Test x + 0 with temp and constant
638
+ t0 = Temp(MIRType.INT)
639
+ t1 = Temp(MIRType.INT)
640
+
641
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
642
+ self.block.add_instruction(BinaryOp(t1, "+", t0, Constant(0, MIRType.INT), (1, 1)))
643
+
644
+ # Run optimization
645
+ changed = self.opt.run_on_function(self.func)
646
+
647
+ # Should simplify to t1 = t0
648
+ assert changed
649
+
650
+ # Check that the add was replaced with Copy
651
+ instructions = list(self.block.instructions)
652
+ assert isinstance(instructions[1], Copy)
653
+ copy_inst = instructions[1]
654
+ assert isinstance(copy_inst, Copy)
655
+ assert copy_inst.source == t0
656
+
657
+ def test_multiply_by_zero(self) -> None:
658
+ """Test x * 0 → 0 and 0 * x → 0."""
659
+ # Test x * 0 with constant
660
+ t0 = Temp(MIRType.INT)
661
+ self.block.add_instruction(BinaryOp(t0, "*", Constant(42, MIRType.INT), Constant(0, MIRType.INT), (1, 1)))
662
+
663
+ # Run optimization
664
+ changed = self.opt.run_on_function(self.func)
665
+
666
+ # Should simplify to t0 = 0
667
+ assert changed
668
+
669
+ # Check that the multiply was replaced with LoadConst(0)
670
+ instructions = list(self.block.instructions)
671
+ assert isinstance(instructions[0], LoadConst)
672
+ load_inst = instructions[0]
673
+ assert isinstance(load_inst, LoadConst)
674
+ assert load_inst.constant.value == 0
675
+
676
+ def test_multiply_by_one(self) -> None:
677
+ """Test x * 1 → x and 1 * x → x."""
678
+ # Test x * 1 with temp and constant
679
+ t0 = Temp(MIRType.INT)
680
+ t1 = Temp(MIRType.INT)
681
+
682
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
683
+ self.block.add_instruction(BinaryOp(t1, "*", t0, Constant(1, MIRType.INT), (1, 1)))
684
+
685
+ # Run optimization
686
+ changed = self.opt.run_on_function(self.func)
687
+
688
+ # Should simplify to t1 = t0
689
+ assert changed
690
+
691
+ # Check that the multiply was replaced with Copy
692
+ instructions = list(self.block.instructions)
693
+ assert isinstance(instructions[1], Copy)
694
+ copy_inst = instructions[1]
695
+ assert isinstance(copy_inst, Copy)
696
+ assert copy_inst.source == t0
697
+
698
+ def test_subtract_self(self) -> None:
699
+ """Test x - x → 0."""
700
+ # Test t0 - t0
701
+ t0 = Temp(MIRType.INT)
702
+ t1 = Temp(MIRType.INT)
703
+
704
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
705
+ self.block.add_instruction(BinaryOp(t1, "-", t0, t0, (1, 1)))
706
+
707
+ # Run optimization
708
+ changed = self.opt.run_on_function(self.func)
709
+
710
+ # Should simplify to t1 = 0
711
+ assert changed
712
+
713
+ # Check that the subtract was replaced with LoadConst(0)
714
+ instructions = list(self.block.instructions)
715
+ assert isinstance(instructions[1], LoadConst)
716
+ load_inst = instructions[1]
717
+ assert isinstance(load_inst, LoadConst)
718
+ assert load_inst.constant.value == 0
719
+
720
+ def test_divide_by_one(self) -> None:
721
+ """Test x / 1 → x."""
722
+ # Test x / 1 with temp and constant
723
+ t0 = Temp(MIRType.INT)
724
+ t1 = Temp(MIRType.INT)
725
+
726
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
727
+ self.block.add_instruction(BinaryOp(t1, "/", t0, Constant(1, MIRType.INT), (1, 1)))
728
+
729
+ # Run optimization
730
+ changed = self.opt.run_on_function(self.func)
731
+
732
+ # Should simplify to t1 = t0
733
+ assert changed
734
+
735
+ # Check that the divide was replaced with Copy
736
+ instructions = list(self.block.instructions)
737
+ assert isinstance(instructions[1], Copy)
738
+ copy_inst = instructions[1]
739
+ assert isinstance(copy_inst, Copy)
740
+ assert copy_inst.source == t0
741
+
742
+ def test_divide_self(self) -> None:
743
+ """Test x / x → 1 (for x != 0)."""
744
+ # Test t0 / t0
745
+ t0 = Temp(MIRType.INT)
746
+ t1 = Temp(MIRType.INT)
747
+
748
+ self.block.add_instruction(LoadConst(t0, Constant(42, MIRType.INT), (1, 1)))
749
+ self.block.add_instruction(BinaryOp(t1, "/", t0, t0, (1, 1)))
750
+
751
+ # Run optimization
752
+ changed = self.opt.run_on_function(self.func)
753
+
754
+ # Should simplify to t1 = 1
755
+ assert changed
756
+
757
+ # Check that the divide was replaced with LoadConst(1)
758
+ instructions = list(self.block.instructions)
759
+ assert isinstance(instructions[1], LoadConst)
760
+ load_inst = instructions[1]
761
+ assert isinstance(load_inst, LoadConst)
762
+ assert load_inst.constant.value == 1
763
+
764
+
765
+ class TestStrengthReductionBoolean:
766
+ """Test boolean operation simplifications in StrengthReduction."""
767
+
768
+ def setup_method(self) -> None:
769
+ """Set up test fixtures."""
770
+ self.module = MIRModule("test")
771
+ self.func = MIRFunction("test_func", [], MIRType.BOOL)
772
+ self.block = BasicBlock("entry")
773
+ self.func.cfg.add_block(self.block)
774
+ self.func.cfg.entry_block = self.block
775
+ self.module.add_function(self.func)
776
+ self.transformer = MIRTransformer(self.func)
777
+ self.opt = StrengthReduction()
778
+
779
+ def test_and_with_true(self) -> None:
780
+ """Test x and true → x."""
781
+ # Test x and true with temp and constant
782
+ t0 = Temp(MIRType.BOOL)
783
+ t1 = Temp(MIRType.BOOL)
784
+
785
+ self.block.add_instruction(LoadConst(t0, Constant(False, MIRType.BOOL), (1, 1)))
786
+ self.block.add_instruction(BinaryOp(t1, "and", t0, Constant(True, MIRType.BOOL), (1, 1)))
787
+
788
+ # Run optimization
789
+ changed = self.opt.run_on_function(self.func)
790
+
791
+ # Should simplify to t1 = t0
792
+ assert changed
793
+
794
+ # Check that the and was replaced with Copy
795
+ instructions = list(self.block.instructions)
796
+ assert isinstance(instructions[1], Copy)
797
+ copy_inst = instructions[1]
798
+ assert isinstance(copy_inst, Copy)
799
+ assert copy_inst.source == t0
800
+
801
+ def test_and_with_false(self) -> None:
802
+ """Test x and false → false."""
803
+ # Test x and false with constant
804
+ t0 = Temp(MIRType.BOOL)
805
+ self.block.add_instruction(
806
+ BinaryOp(t0, "and", Constant(True, MIRType.BOOL), Constant(False, MIRType.BOOL), (1, 1))
807
+ )
808
+
809
+ # Run optimization
810
+ changed = self.opt.run_on_function(self.func)
811
+
812
+ # Should simplify to t0 = false
813
+ assert changed
814
+
815
+ # Check that the and was replaced with LoadConst(False)
816
+ instructions = list(self.block.instructions)
817
+ assert isinstance(instructions[0], LoadConst)
818
+ load_inst = instructions[0]
819
+ assert isinstance(load_inst, LoadConst)
820
+ assert load_inst.constant.value is False
821
+
822
+ def test_or_with_false(self) -> None:
823
+ """Test x or false → x."""
824
+ # Test x or false with temp and constant
825
+ t0 = Temp(MIRType.BOOL)
826
+ t1 = Temp(MIRType.BOOL)
827
+
828
+ self.block.add_instruction(LoadConst(t0, Constant(True, MIRType.BOOL), (1, 1)))
829
+ self.block.add_instruction(BinaryOp(t1, "or", t0, Constant(False, MIRType.BOOL), (1, 1)))
830
+
831
+ # Run optimization
832
+ changed = self.opt.run_on_function(self.func)
833
+
834
+ # Should simplify to t1 = t0
835
+ assert changed
836
+
837
+ # Check that the or was replaced with Copy
838
+ instructions = list(self.block.instructions)
839
+ assert isinstance(instructions[1], Copy)
840
+ copy_inst = instructions[1]
841
+ assert isinstance(copy_inst, Copy)
842
+ assert copy_inst.source == t0
843
+
844
+ def test_or_with_true(self) -> None:
845
+ """Test x or true → true."""
846
+ # Test x or true with constant
847
+ t0 = Temp(MIRType.BOOL)
848
+ self.block.add_instruction(
849
+ BinaryOp(t0, "or", Constant(False, MIRType.BOOL), Constant(True, MIRType.BOOL), (1, 1))
850
+ )
851
+
852
+ # Run optimization
853
+ changed = self.opt.run_on_function(self.func)
854
+
855
+ # Should simplify to t0 = true
856
+ assert changed
857
+
858
+ # Check that the or was replaced with LoadConst(True)
859
+ instructions = list(self.block.instructions)
860
+ assert isinstance(instructions[0], LoadConst)
861
+ load_inst = instructions[0]
862
+ assert isinstance(load_inst, LoadConst)
863
+ assert load_inst.constant.value is True