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.
- machine_dialect/__main__.py +667 -0
- machine_dialect/agent/__init__.py +5 -0
- machine_dialect/agent/agent.py +360 -0
- machine_dialect/ast/__init__.py +95 -0
- machine_dialect/ast/ast_node.py +35 -0
- machine_dialect/ast/call_expression.py +82 -0
- machine_dialect/ast/dict_extraction.py +60 -0
- machine_dialect/ast/expressions.py +439 -0
- machine_dialect/ast/literals.py +309 -0
- machine_dialect/ast/program.py +35 -0
- machine_dialect/ast/statements.py +1433 -0
- machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
- machine_dialect/ast/tests/test_boolean_literal.py +29 -0
- machine_dialect/ast/tests/test_collection_hir.py +138 -0
- machine_dialect/ast/tests/test_define_statement.py +142 -0
- machine_dialect/ast/tests/test_desugar.py +541 -0
- machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
- machine_dialect/cfg/__init__.py +6 -0
- machine_dialect/cfg/config.py +156 -0
- machine_dialect/cfg/examples.py +221 -0
- machine_dialect/cfg/generate_with_ai.py +187 -0
- machine_dialect/cfg/openai_generation.py +200 -0
- machine_dialect/cfg/parser.py +94 -0
- machine_dialect/cfg/tests/__init__.py +1 -0
- machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
- machine_dialect/cfg/tests/test_config.py +188 -0
- machine_dialect/cfg/tests/test_examples.py +391 -0
- machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
- machine_dialect/cfg/tests/test_openai_generation.py +256 -0
- machine_dialect/codegen/__init__.py +5 -0
- machine_dialect/codegen/bytecode_module.py +89 -0
- machine_dialect/codegen/bytecode_serializer.py +300 -0
- machine_dialect/codegen/opcodes.py +101 -0
- machine_dialect/codegen/register_codegen.py +1996 -0
- machine_dialect/codegen/symtab.py +208 -0
- machine_dialect/codegen/tests/__init__.py +1 -0
- machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
- machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
- machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
- machine_dialect/codegen/tests/test_symtab.py +418 -0
- machine_dialect/codegen/vm_serializer.py +621 -0
- machine_dialect/compiler/__init__.py +18 -0
- machine_dialect/compiler/compiler.py +197 -0
- machine_dialect/compiler/config.py +149 -0
- machine_dialect/compiler/context.py +149 -0
- machine_dialect/compiler/phases/__init__.py +19 -0
- machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
- machine_dialect/compiler/phases/codegen.py +40 -0
- machine_dialect/compiler/phases/hir_generation.py +39 -0
- machine_dialect/compiler/phases/mir_generation.py +86 -0
- machine_dialect/compiler/phases/optimization.py +110 -0
- machine_dialect/compiler/phases/parsing.py +39 -0
- machine_dialect/compiler/pipeline.py +143 -0
- machine_dialect/compiler/tests/__init__.py +1 -0
- machine_dialect/compiler/tests/test_compiler.py +568 -0
- machine_dialect/compiler/vm_runner.py +173 -0
- machine_dialect/errors/__init__.py +32 -0
- machine_dialect/errors/exceptions.py +369 -0
- machine_dialect/errors/messages.py +82 -0
- machine_dialect/errors/tests/__init__.py +0 -0
- machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
- machine_dialect/errors/tests/test_name_errors.py +118 -0
- machine_dialect/helpers/__init__.py +0 -0
- machine_dialect/helpers/stopwords.py +225 -0
- machine_dialect/helpers/validators.py +30 -0
- machine_dialect/lexer/__init__.py +9 -0
- machine_dialect/lexer/constants.py +23 -0
- machine_dialect/lexer/lexer.py +907 -0
- machine_dialect/lexer/tests/__init__.py +0 -0
- machine_dialect/lexer/tests/helpers.py +86 -0
- machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
- machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
- machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
- machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
- machine_dialect/lexer/tests/test_comments.py +200 -0
- machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
- machine_dialect/lexer/tests/test_lexer_position.py +113 -0
- machine_dialect/lexer/tests/test_list_tokens.py +282 -0
- machine_dialect/lexer/tests/test_stopwords.py +80 -0
- machine_dialect/lexer/tests/test_strict_equality.py +129 -0
- machine_dialect/lexer/tests/test_token.py +41 -0
- machine_dialect/lexer/tests/test_tokenization.py +294 -0
- machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
- machine_dialect/lexer/tests/test_url_literals.py +169 -0
- machine_dialect/lexer/tokens.py +487 -0
- machine_dialect/linter/__init__.py +10 -0
- machine_dialect/linter/__main__.py +144 -0
- machine_dialect/linter/linter.py +154 -0
- machine_dialect/linter/rules/__init__.py +8 -0
- machine_dialect/linter/rules/base.py +112 -0
- machine_dialect/linter/rules/statement_termination.py +99 -0
- machine_dialect/linter/tests/__init__.py +1 -0
- machine_dialect/linter/tests/mdrules/__init__.py +0 -0
- machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
- machine_dialect/linter/tests/test_linter.py +81 -0
- machine_dialect/linter/tests/test_rules.py +110 -0
- machine_dialect/linter/tests/test_violations.py +71 -0
- machine_dialect/linter/violations.py +51 -0
- machine_dialect/mir/__init__.py +69 -0
- machine_dialect/mir/analyses/__init__.py +20 -0
- machine_dialect/mir/analyses/alias_analysis.py +315 -0
- machine_dialect/mir/analyses/dominance_analysis.py +49 -0
- machine_dialect/mir/analyses/escape_analysis.py +286 -0
- machine_dialect/mir/analyses/loop_analysis.py +272 -0
- machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
- machine_dialect/mir/analyses/type_analysis.py +448 -0
- machine_dialect/mir/analyses/use_def_chains.py +232 -0
- machine_dialect/mir/basic_block.py +385 -0
- machine_dialect/mir/dataflow.py +445 -0
- machine_dialect/mir/debug_info.py +208 -0
- machine_dialect/mir/hir_to_mir.py +1738 -0
- machine_dialect/mir/mir_dumper.py +366 -0
- machine_dialect/mir/mir_function.py +167 -0
- machine_dialect/mir/mir_instructions.py +1877 -0
- machine_dialect/mir/mir_interpreter.py +556 -0
- machine_dialect/mir/mir_module.py +225 -0
- machine_dialect/mir/mir_printer.py +480 -0
- machine_dialect/mir/mir_transformer.py +410 -0
- machine_dialect/mir/mir_types.py +367 -0
- machine_dialect/mir/mir_validation.py +455 -0
- machine_dialect/mir/mir_values.py +268 -0
- machine_dialect/mir/optimization_config.py +233 -0
- machine_dialect/mir/optimization_pass.py +251 -0
- machine_dialect/mir/optimization_pipeline.py +355 -0
- machine_dialect/mir/optimizations/__init__.py +84 -0
- machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
- machine_dialect/mir/optimizations/branch_prediction.py +372 -0
- machine_dialect/mir/optimizations/constant_propagation.py +634 -0
- machine_dialect/mir/optimizations/cse.py +398 -0
- machine_dialect/mir/optimizations/dce.py +288 -0
- machine_dialect/mir/optimizations/inlining.py +551 -0
- machine_dialect/mir/optimizations/jump_threading.py +487 -0
- machine_dialect/mir/optimizations/licm.py +405 -0
- machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
- machine_dialect/mir/optimizations/strength_reduction.py +422 -0
- machine_dialect/mir/optimizations/tail_call.py +207 -0
- machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
- machine_dialect/mir/optimizations/type_narrowing.py +397 -0
- machine_dialect/mir/optimizations/type_specialization.py +447 -0
- machine_dialect/mir/optimizations/type_specific.py +906 -0
- machine_dialect/mir/optimize_mir.py +89 -0
- machine_dialect/mir/pass_manager.py +391 -0
- machine_dialect/mir/profiling/__init__.py +26 -0
- machine_dialect/mir/profiling/profile_collector.py +318 -0
- machine_dialect/mir/profiling/profile_data.py +372 -0
- machine_dialect/mir/profiling/profile_reader.py +272 -0
- machine_dialect/mir/profiling/profile_writer.py +226 -0
- machine_dialect/mir/register_allocation.py +302 -0
- machine_dialect/mir/reporting/__init__.py +17 -0
- machine_dialect/mir/reporting/optimization_reporter.py +314 -0
- machine_dialect/mir/reporting/report_formatter.py +289 -0
- machine_dialect/mir/ssa_construction.py +342 -0
- machine_dialect/mir/tests/__init__.py +1 -0
- machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
- machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
- machine_dialect/mir/tests/test_algebraic_division.py +126 -0
- machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
- machine_dialect/mir/tests/test_basic_block.py +425 -0
- machine_dialect/mir/tests/test_branch_prediction.py +459 -0
- machine_dialect/mir/tests/test_call_lowering.py +168 -0
- machine_dialect/mir/tests/test_collection_lowering.py +604 -0
- machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
- machine_dialect/mir/tests/test_custom_passes.py +166 -0
- machine_dialect/mir/tests/test_debug_info.py +285 -0
- machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
- machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
- machine_dialect/mir/tests/test_double_negation.py +231 -0
- machine_dialect/mir/tests/test_escape_analysis.py +233 -0
- machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
- machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
- machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
- machine_dialect/mir/tests/test_inlining.py +435 -0
- machine_dialect/mir/tests/test_licm.py +472 -0
- machine_dialect/mir/tests/test_mir_dumper.py +313 -0
- machine_dialect/mir/tests/test_mir_instructions.py +445 -0
- machine_dialect/mir/tests/test_mir_module.py +860 -0
- machine_dialect/mir/tests/test_mir_printer.py +387 -0
- machine_dialect/mir/tests/test_mir_types.py +123 -0
- machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
- machine_dialect/mir/tests/test_mir_validation.py +378 -0
- machine_dialect/mir/tests/test_mir_values.py +168 -0
- machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
- machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
- machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
- machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
- machine_dialect/mir/tests/test_pass_manager.py +294 -0
- machine_dialect/mir/tests/test_pass_registration.py +64 -0
- machine_dialect/mir/tests/test_profiling.py +356 -0
- machine_dialect/mir/tests/test_register_allocation.py +307 -0
- machine_dialect/mir/tests/test_report_formatters.py +372 -0
- machine_dialect/mir/tests/test_ssa_construction.py +433 -0
- machine_dialect/mir/tests/test_tail_call.py +236 -0
- machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
- machine_dialect/mir/tests/test_type_narrowing.py +277 -0
- machine_dialect/mir/tests/test_type_specialization.py +421 -0
- machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
- machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
- machine_dialect/mir/type_inference.py +368 -0
- machine_dialect/parser/__init__.py +12 -0
- machine_dialect/parser/enums.py +45 -0
- machine_dialect/parser/parser.py +3655 -0
- machine_dialect/parser/protocols.py +11 -0
- machine_dialect/parser/symbol_table.py +169 -0
- machine_dialect/parser/tests/__init__.py +0 -0
- machine_dialect/parser/tests/helper_functions.py +193 -0
- machine_dialect/parser/tests/test_action_statements.py +334 -0
- machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
- machine_dialect/parser/tests/test_call_statements.py +154 -0
- machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
- machine_dialect/parser/tests/test_collection_mutations.py +264 -0
- machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
- machine_dialect/parser/tests/test_define_integration.py +468 -0
- machine_dialect/parser/tests/test_define_statements.py +311 -0
- machine_dialect/parser/tests/test_dict_extraction.py +115 -0
- machine_dialect/parser/tests/test_empty_literal.py +155 -0
- machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
- machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
- machine_dialect/parser/tests/test_if_empty_block.py +61 -0
- machine_dialect/parser/tests/test_if_statements.py +299 -0
- machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
- machine_dialect/parser/tests/test_infix_expressions.py +680 -0
- machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
- machine_dialect/parser/tests/test_interaction_statements.py +269 -0
- machine_dialect/parser/tests/test_list_literals.py +277 -0
- machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
- machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
- machine_dialect/parser/tests/test_parse_errors.py +114 -0
- machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
- machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
- machine_dialect/parser/tests/test_program.py +13 -0
- machine_dialect/parser/tests/test_return_statements.py +89 -0
- machine_dialect/parser/tests/test_set_statements.py +152 -0
- machine_dialect/parser/tests/test_strict_equality.py +258 -0
- machine_dialect/parser/tests/test_symbol_table.py +217 -0
- machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
- machine_dialect/parser/tests/test_utility_statements.py +423 -0
- machine_dialect/parser/token_buffer.py +159 -0
- machine_dialect/repl/__init__.py +3 -0
- machine_dialect/repl/repl.py +426 -0
- machine_dialect/repl/tests/__init__.py +0 -0
- machine_dialect/repl/tests/test_repl.py +606 -0
- machine_dialect/semantic/__init__.py +12 -0
- machine_dialect/semantic/analyzer.py +906 -0
- machine_dialect/semantic/error_messages.py +189 -0
- machine_dialect/semantic/tests/__init__.py +1 -0
- machine_dialect/semantic/tests/test_analyzer.py +364 -0
- machine_dialect/semantic/tests/test_error_messages.py +104 -0
- machine_dialect/tests/edge_cases/__init__.py +10 -0
- machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
- machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
- machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
- machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
- machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
- machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
- machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
- machine_dialect/tests/integration/test_list_compilation.py +395 -0
- machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
- machine_dialect/type_checking/__init__.py +21 -0
- machine_dialect/type_checking/tests/__init__.py +1 -0
- machine_dialect/type_checking/tests/test_type_system.py +230 -0
- machine_dialect/type_checking/type_system.py +270 -0
- machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
- machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
- machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
- machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
- machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
- machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
- 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
|