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