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,410 @@
|
|
1
|
+
"""MIR transformation utilities for optimization passes.
|
2
|
+
|
3
|
+
This module provides utilities for transforming MIR code, including
|
4
|
+
instruction manipulation, block operations, and SSA preservation.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from collections.abc import Callable
|
8
|
+
|
9
|
+
from machine_dialect.mir.basic_block import BasicBlock
|
10
|
+
from machine_dialect.mir.mir_function import MIRFunction
|
11
|
+
from machine_dialect.mir.mir_instructions import (
|
12
|
+
ConditionalJump,
|
13
|
+
Jump,
|
14
|
+
Label,
|
15
|
+
MIRInstruction,
|
16
|
+
Phi,
|
17
|
+
Return,
|
18
|
+
)
|
19
|
+
from machine_dialect.mir.mir_values import MIRValue
|
20
|
+
|
21
|
+
|
22
|
+
class MIRTransformer:
|
23
|
+
"""Utility class for transforming MIR code."""
|
24
|
+
|
25
|
+
def __init__(self, function: MIRFunction) -> None:
|
26
|
+
"""Initialize the transformer.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
function: Function to transform.
|
30
|
+
"""
|
31
|
+
self.function = function
|
32
|
+
self.modified = False
|
33
|
+
|
34
|
+
def replace_instruction(
|
35
|
+
self,
|
36
|
+
block: BasicBlock,
|
37
|
+
old_inst: MIRInstruction,
|
38
|
+
new_inst: MIRInstruction,
|
39
|
+
) -> bool:
|
40
|
+
"""Replace an instruction in a block.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
block: The block containing the instruction.
|
44
|
+
old_inst: Instruction to replace.
|
45
|
+
new_inst: Replacement instruction.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
True if replacement was successful.
|
49
|
+
"""
|
50
|
+
try:
|
51
|
+
index = block.instructions.index(old_inst)
|
52
|
+
block.instructions[index] = new_inst
|
53
|
+
self.modified = True
|
54
|
+
return True
|
55
|
+
except ValueError:
|
56
|
+
# Check phi nodes
|
57
|
+
try:
|
58
|
+
index = block.phi_nodes.index(old_inst) # type: ignore
|
59
|
+
if isinstance(new_inst, Phi):
|
60
|
+
block.phi_nodes[index] = new_inst
|
61
|
+
self.modified = True
|
62
|
+
return True
|
63
|
+
except (ValueError, TypeError):
|
64
|
+
pass
|
65
|
+
return False
|
66
|
+
|
67
|
+
def remove_instruction(
|
68
|
+
self,
|
69
|
+
block: BasicBlock,
|
70
|
+
inst: MIRInstruction,
|
71
|
+
) -> bool:
|
72
|
+
"""Remove an instruction from a block.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
block: The block containing the instruction.
|
76
|
+
inst: Instruction to remove.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
True if removal was successful.
|
80
|
+
"""
|
81
|
+
try:
|
82
|
+
block.instructions.remove(inst)
|
83
|
+
self.modified = True
|
84
|
+
return True
|
85
|
+
except ValueError:
|
86
|
+
# Check phi nodes
|
87
|
+
try:
|
88
|
+
block.phi_nodes.remove(inst) # type: ignore
|
89
|
+
self.modified = True
|
90
|
+
return True
|
91
|
+
except (ValueError, TypeError):
|
92
|
+
pass
|
93
|
+
return False
|
94
|
+
|
95
|
+
def insert_instruction(
|
96
|
+
self,
|
97
|
+
block: BasicBlock,
|
98
|
+
inst: MIRInstruction,
|
99
|
+
position: int | None = None,
|
100
|
+
) -> None:
|
101
|
+
"""Insert an instruction into a block.
|
102
|
+
|
103
|
+
Args:
|
104
|
+
block: The block to insert into.
|
105
|
+
inst: Instruction to insert.
|
106
|
+
position: Position to insert at (None for end).
|
107
|
+
"""
|
108
|
+
if isinstance(inst, Phi):
|
109
|
+
block.phi_nodes.append(inst)
|
110
|
+
else:
|
111
|
+
if position is None:
|
112
|
+
# Insert before terminator if present
|
113
|
+
if block.get_terminator():
|
114
|
+
block.instructions.insert(-1, inst)
|
115
|
+
else:
|
116
|
+
block.instructions.append(inst)
|
117
|
+
else:
|
118
|
+
block.instructions.insert(position, inst)
|
119
|
+
self.modified = True
|
120
|
+
|
121
|
+
def replace_uses(
|
122
|
+
self,
|
123
|
+
old_value: MIRValue,
|
124
|
+
new_value: MIRValue,
|
125
|
+
block: BasicBlock | None = None,
|
126
|
+
) -> int:
|
127
|
+
"""Replace all uses of a value.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
old_value: Value to replace.
|
131
|
+
new_value: Replacement value.
|
132
|
+
block: Optional block to limit replacement to.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
Number of replacements made.
|
136
|
+
"""
|
137
|
+
count = 0
|
138
|
+
blocks = [block] if block else self.function.cfg.blocks.values()
|
139
|
+
|
140
|
+
for b in blocks:
|
141
|
+
# Process phi nodes
|
142
|
+
for phi in b.phi_nodes:
|
143
|
+
for i, (val, label) in enumerate(phi.incoming):
|
144
|
+
if val == old_value:
|
145
|
+
phi.incoming[i] = (new_value, label)
|
146
|
+
count += 1
|
147
|
+
self.modified = True
|
148
|
+
|
149
|
+
# Process instructions
|
150
|
+
for inst in b.instructions:
|
151
|
+
inst.replace_use(old_value, new_value)
|
152
|
+
# Check if replacement occurred
|
153
|
+
if new_value in inst.get_uses():
|
154
|
+
count += 1
|
155
|
+
self.modified = True
|
156
|
+
|
157
|
+
return count
|
158
|
+
|
159
|
+
def remove_dead_instructions(self, block: BasicBlock) -> int:
|
160
|
+
"""Remove dead instructions from a block.
|
161
|
+
|
162
|
+
Args:
|
163
|
+
block: Block to clean.
|
164
|
+
|
165
|
+
Returns:
|
166
|
+
Number of instructions removed.
|
167
|
+
"""
|
168
|
+
removed = 0
|
169
|
+
to_remove = []
|
170
|
+
|
171
|
+
for inst in block.instructions:
|
172
|
+
# Skip side-effecting instructions
|
173
|
+
if isinstance(inst, Return | Jump | ConditionalJump | Label):
|
174
|
+
continue
|
175
|
+
if hasattr(inst, "has_side_effects") and inst.has_side_effects():
|
176
|
+
continue
|
177
|
+
|
178
|
+
# Check if any definitions are used
|
179
|
+
defs = inst.get_defs()
|
180
|
+
if defs and all(self._is_dead_value(v) for v in defs):
|
181
|
+
to_remove.append(inst)
|
182
|
+
|
183
|
+
for inst in to_remove:
|
184
|
+
self.remove_instruction(block, inst)
|
185
|
+
removed += 1
|
186
|
+
|
187
|
+
return removed
|
188
|
+
|
189
|
+
def _is_dead_value(self, value: MIRValue) -> bool:
|
190
|
+
"""Check if a value is dead (unused).
|
191
|
+
|
192
|
+
Args:
|
193
|
+
value: Value to check.
|
194
|
+
|
195
|
+
Returns:
|
196
|
+
True if the value is dead.
|
197
|
+
"""
|
198
|
+
# This is a simplified check - should use use-def chains
|
199
|
+
for block in self.function.cfg.blocks.values():
|
200
|
+
for phi in block.phi_nodes:
|
201
|
+
if value in [v for v, _ in phi.incoming]:
|
202
|
+
return False
|
203
|
+
for inst in block.instructions:
|
204
|
+
if value in inst.get_uses():
|
205
|
+
return False
|
206
|
+
return True
|
207
|
+
|
208
|
+
def split_block(
|
209
|
+
self,
|
210
|
+
block: BasicBlock,
|
211
|
+
split_point: int,
|
212
|
+
new_label: str,
|
213
|
+
) -> BasicBlock:
|
214
|
+
"""Split a block at a given instruction index.
|
215
|
+
|
216
|
+
Args:
|
217
|
+
block: Block to split.
|
218
|
+
split_point: Index to split at.
|
219
|
+
new_label: Label for the new block.
|
220
|
+
|
221
|
+
Returns:
|
222
|
+
The new block containing instructions after split point.
|
223
|
+
"""
|
224
|
+
# Create new block
|
225
|
+
new_block = BasicBlock(new_label)
|
226
|
+
|
227
|
+
# Move instructions after split point to new block
|
228
|
+
new_block.instructions = block.instructions[split_point:]
|
229
|
+
block.instructions = block.instructions[:split_point]
|
230
|
+
|
231
|
+
# Update CFG edges
|
232
|
+
# New block takes over original block's successors
|
233
|
+
new_block.successors = block.successors.copy()
|
234
|
+
for succ in new_block.successors:
|
235
|
+
# Update predecessor
|
236
|
+
idx = succ.predecessors.index(block)
|
237
|
+
succ.predecessors[idx] = new_block
|
238
|
+
|
239
|
+
# Original block now jumps to new block
|
240
|
+
block.successors = [new_block]
|
241
|
+
new_block.predecessors = [block]
|
242
|
+
|
243
|
+
# Add jump instruction if needed
|
244
|
+
if not block.get_terminator():
|
245
|
+
block.add_instruction(Jump(new_label, (0, 0)))
|
246
|
+
|
247
|
+
# Add new block to CFG
|
248
|
+
self.function.cfg.add_block(new_block)
|
249
|
+
self.modified = True
|
250
|
+
|
251
|
+
return new_block
|
252
|
+
|
253
|
+
def merge_blocks(self, pred: BasicBlock, succ: BasicBlock) -> bool:
|
254
|
+
"""Merge two blocks if possible.
|
255
|
+
|
256
|
+
Args:
|
257
|
+
pred: Predecessor block.
|
258
|
+
succ: Successor block.
|
259
|
+
|
260
|
+
Returns:
|
261
|
+
True if merge was successful.
|
262
|
+
"""
|
263
|
+
# Can only merge if pred has single successor and succ has single predecessor
|
264
|
+
if len(pred.successors) != 1 or len(succ.predecessors) != 1:
|
265
|
+
return False
|
266
|
+
|
267
|
+
# Can't merge if succ has phi nodes
|
268
|
+
if succ.phi_nodes:
|
269
|
+
return False
|
270
|
+
|
271
|
+
# Remove jump from pred if it exists
|
272
|
+
if pred.get_terminator() and isinstance(pred.get_terminator(), Jump):
|
273
|
+
pred.instructions.pop()
|
274
|
+
|
275
|
+
# Move instructions from succ to pred
|
276
|
+
pred.instructions.extend(succ.instructions)
|
277
|
+
|
278
|
+
# Update CFG
|
279
|
+
pred.successors = succ.successors
|
280
|
+
for s in succ.successors:
|
281
|
+
idx = s.predecessors.index(succ)
|
282
|
+
s.predecessors[idx] = pred
|
283
|
+
|
284
|
+
# Remove succ from CFG
|
285
|
+
del self.function.cfg.blocks[succ.label]
|
286
|
+
self.modified = True
|
287
|
+
|
288
|
+
return True
|
289
|
+
|
290
|
+
def eliminate_unreachable_blocks(self) -> int:
|
291
|
+
"""Remove unreachable blocks from the function.
|
292
|
+
|
293
|
+
Returns:
|
294
|
+
Number of blocks removed.
|
295
|
+
"""
|
296
|
+
# Find reachable blocks via DFS
|
297
|
+
reachable = set()
|
298
|
+
worklist = []
|
299
|
+
|
300
|
+
if self.function.cfg.entry_block:
|
301
|
+
worklist.append(self.function.cfg.entry_block)
|
302
|
+
|
303
|
+
while worklist:
|
304
|
+
block = worklist.pop()
|
305
|
+
if block in reachable:
|
306
|
+
continue
|
307
|
+
reachable.add(block)
|
308
|
+
worklist.extend(block.successors)
|
309
|
+
|
310
|
+
# Remove unreachable blocks
|
311
|
+
removed = 0
|
312
|
+
unreachable = [b for b in self.function.cfg.blocks.values() if b not in reachable]
|
313
|
+
|
314
|
+
for block in unreachable:
|
315
|
+
# Update predecessors' successor lists
|
316
|
+
for pred in block.predecessors:
|
317
|
+
pred.successors.remove(block)
|
318
|
+
|
319
|
+
# Update successors' predecessor lists
|
320
|
+
for succ in block.successors:
|
321
|
+
succ.predecessors.remove(block)
|
322
|
+
|
323
|
+
# Remove from CFG
|
324
|
+
del self.function.cfg.blocks[block.label]
|
325
|
+
removed += 1
|
326
|
+
self.modified = True
|
327
|
+
|
328
|
+
return removed
|
329
|
+
|
330
|
+
def simplify_cfg(self) -> bool:
|
331
|
+
"""Simplify the control flow graph.
|
332
|
+
|
333
|
+
Returns:
|
334
|
+
True if any simplification was performed.
|
335
|
+
"""
|
336
|
+
initial_modified = self.modified
|
337
|
+
|
338
|
+
# Remove unreachable blocks
|
339
|
+
self.eliminate_unreachable_blocks()
|
340
|
+
|
341
|
+
# Merge blocks where possible
|
342
|
+
changed = True
|
343
|
+
while changed:
|
344
|
+
changed = False
|
345
|
+
for block in list(self.function.cfg.blocks.values()):
|
346
|
+
if len(block.successors) == 1:
|
347
|
+
succ = block.successors[0]
|
348
|
+
if self.merge_blocks(block, succ):
|
349
|
+
changed = True
|
350
|
+
break
|
351
|
+
|
352
|
+
# Remove empty blocks (except entry)
|
353
|
+
for block in list(self.function.cfg.blocks.values()):
|
354
|
+
if block != self.function.cfg.entry_block and not block.instructions and not block.phi_nodes:
|
355
|
+
# Redirect predecessors to successors
|
356
|
+
if len(block.successors) == 1:
|
357
|
+
succ = block.successors[0]
|
358
|
+
for pred in block.predecessors:
|
359
|
+
# Update pred's successors
|
360
|
+
idx = pred.successors.index(block)
|
361
|
+
pred.successors[idx] = succ
|
362
|
+
# Update succ's predecessors
|
363
|
+
idx = succ.predecessors.index(block)
|
364
|
+
succ.predecessors[idx] = pred
|
365
|
+
# Update jump targets
|
366
|
+
term = pred.get_terminator()
|
367
|
+
if isinstance(term, Jump) and term.label == block.label:
|
368
|
+
term.label = succ.label
|
369
|
+
elif isinstance(term, ConditionalJump):
|
370
|
+
if term.true_label == block.label:
|
371
|
+
term.true_label = succ.label
|
372
|
+
if term.false_label == block.label:
|
373
|
+
term.false_label = succ.label
|
374
|
+
|
375
|
+
del self.function.cfg.blocks[block.label]
|
376
|
+
self.modified = True
|
377
|
+
|
378
|
+
return self.modified != initial_modified
|
379
|
+
|
380
|
+
def apply_to_all_instructions(
|
381
|
+
self,
|
382
|
+
transform: Callable[[MIRInstruction], MIRInstruction | None],
|
383
|
+
) -> int:
|
384
|
+
"""Apply a transformation to all instructions.
|
385
|
+
|
386
|
+
Args:
|
387
|
+
transform: Function that transforms or removes instructions.
|
388
|
+
|
389
|
+
Returns:
|
390
|
+
Number of instructions modified.
|
391
|
+
"""
|
392
|
+
count = 0
|
393
|
+
|
394
|
+
for block in self.function.cfg.blocks.values():
|
395
|
+
# Process instructions
|
396
|
+
new_instructions = []
|
397
|
+
for inst in block.instructions:
|
398
|
+
result = transform(inst)
|
399
|
+
if result is not None:
|
400
|
+
new_instructions.append(result)
|
401
|
+
if result != inst:
|
402
|
+
count += 1
|
403
|
+
self.modified = True
|
404
|
+
else:
|
405
|
+
count += 1
|
406
|
+
self.modified = True
|
407
|
+
|
408
|
+
block.instructions = new_instructions
|
409
|
+
|
410
|
+
return count
|