machine-dialect 0.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. machine_dialect/__main__.py +667 -0
  2. machine_dialect/agent/__init__.py +5 -0
  3. machine_dialect/agent/agent.py +360 -0
  4. machine_dialect/ast/__init__.py +95 -0
  5. machine_dialect/ast/ast_node.py +35 -0
  6. machine_dialect/ast/call_expression.py +82 -0
  7. machine_dialect/ast/dict_extraction.py +60 -0
  8. machine_dialect/ast/expressions.py +439 -0
  9. machine_dialect/ast/literals.py +309 -0
  10. machine_dialect/ast/program.py +35 -0
  11. machine_dialect/ast/statements.py +1433 -0
  12. machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
  13. machine_dialect/ast/tests/test_boolean_literal.py +29 -0
  14. machine_dialect/ast/tests/test_collection_hir.py +138 -0
  15. machine_dialect/ast/tests/test_define_statement.py +142 -0
  16. machine_dialect/ast/tests/test_desugar.py +541 -0
  17. machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
  18. machine_dialect/cfg/__init__.py +6 -0
  19. machine_dialect/cfg/config.py +156 -0
  20. machine_dialect/cfg/examples.py +221 -0
  21. machine_dialect/cfg/generate_with_ai.py +187 -0
  22. machine_dialect/cfg/openai_generation.py +200 -0
  23. machine_dialect/cfg/parser.py +94 -0
  24. machine_dialect/cfg/tests/__init__.py +1 -0
  25. machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
  26. machine_dialect/cfg/tests/test_config.py +188 -0
  27. machine_dialect/cfg/tests/test_examples.py +391 -0
  28. machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
  29. machine_dialect/cfg/tests/test_openai_generation.py +256 -0
  30. machine_dialect/codegen/__init__.py +5 -0
  31. machine_dialect/codegen/bytecode_module.py +89 -0
  32. machine_dialect/codegen/bytecode_serializer.py +300 -0
  33. machine_dialect/codegen/opcodes.py +101 -0
  34. machine_dialect/codegen/register_codegen.py +1996 -0
  35. machine_dialect/codegen/symtab.py +208 -0
  36. machine_dialect/codegen/tests/__init__.py +1 -0
  37. machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
  38. machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
  39. machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
  40. machine_dialect/codegen/tests/test_symtab.py +418 -0
  41. machine_dialect/codegen/vm_serializer.py +621 -0
  42. machine_dialect/compiler/__init__.py +18 -0
  43. machine_dialect/compiler/compiler.py +197 -0
  44. machine_dialect/compiler/config.py +149 -0
  45. machine_dialect/compiler/context.py +149 -0
  46. machine_dialect/compiler/phases/__init__.py +19 -0
  47. machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
  48. machine_dialect/compiler/phases/codegen.py +40 -0
  49. machine_dialect/compiler/phases/hir_generation.py +39 -0
  50. machine_dialect/compiler/phases/mir_generation.py +86 -0
  51. machine_dialect/compiler/phases/optimization.py +110 -0
  52. machine_dialect/compiler/phases/parsing.py +39 -0
  53. machine_dialect/compiler/pipeline.py +143 -0
  54. machine_dialect/compiler/tests/__init__.py +1 -0
  55. machine_dialect/compiler/tests/test_compiler.py +568 -0
  56. machine_dialect/compiler/vm_runner.py +173 -0
  57. machine_dialect/errors/__init__.py +32 -0
  58. machine_dialect/errors/exceptions.py +369 -0
  59. machine_dialect/errors/messages.py +82 -0
  60. machine_dialect/errors/tests/__init__.py +0 -0
  61. machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
  62. machine_dialect/errors/tests/test_name_errors.py +118 -0
  63. machine_dialect/helpers/__init__.py +0 -0
  64. machine_dialect/helpers/stopwords.py +225 -0
  65. machine_dialect/helpers/validators.py +30 -0
  66. machine_dialect/lexer/__init__.py +9 -0
  67. machine_dialect/lexer/constants.py +23 -0
  68. machine_dialect/lexer/lexer.py +907 -0
  69. machine_dialect/lexer/tests/__init__.py +0 -0
  70. machine_dialect/lexer/tests/helpers.py +86 -0
  71. machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
  72. machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
  73. machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
  74. machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
  75. machine_dialect/lexer/tests/test_comments.py +200 -0
  76. machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
  77. machine_dialect/lexer/tests/test_lexer_position.py +113 -0
  78. machine_dialect/lexer/tests/test_list_tokens.py +282 -0
  79. machine_dialect/lexer/tests/test_stopwords.py +80 -0
  80. machine_dialect/lexer/tests/test_strict_equality.py +129 -0
  81. machine_dialect/lexer/tests/test_token.py +41 -0
  82. machine_dialect/lexer/tests/test_tokenization.py +294 -0
  83. machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
  84. machine_dialect/lexer/tests/test_url_literals.py +169 -0
  85. machine_dialect/lexer/tokens.py +487 -0
  86. machine_dialect/linter/__init__.py +10 -0
  87. machine_dialect/linter/__main__.py +144 -0
  88. machine_dialect/linter/linter.py +154 -0
  89. machine_dialect/linter/rules/__init__.py +8 -0
  90. machine_dialect/linter/rules/base.py +112 -0
  91. machine_dialect/linter/rules/statement_termination.py +99 -0
  92. machine_dialect/linter/tests/__init__.py +1 -0
  93. machine_dialect/linter/tests/mdrules/__init__.py +0 -0
  94. machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
  95. machine_dialect/linter/tests/test_linter.py +81 -0
  96. machine_dialect/linter/tests/test_rules.py +110 -0
  97. machine_dialect/linter/tests/test_violations.py +71 -0
  98. machine_dialect/linter/violations.py +51 -0
  99. machine_dialect/mir/__init__.py +69 -0
  100. machine_dialect/mir/analyses/__init__.py +20 -0
  101. machine_dialect/mir/analyses/alias_analysis.py +315 -0
  102. machine_dialect/mir/analyses/dominance_analysis.py +49 -0
  103. machine_dialect/mir/analyses/escape_analysis.py +286 -0
  104. machine_dialect/mir/analyses/loop_analysis.py +272 -0
  105. machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
  106. machine_dialect/mir/analyses/type_analysis.py +448 -0
  107. machine_dialect/mir/analyses/use_def_chains.py +232 -0
  108. machine_dialect/mir/basic_block.py +385 -0
  109. machine_dialect/mir/dataflow.py +445 -0
  110. machine_dialect/mir/debug_info.py +208 -0
  111. machine_dialect/mir/hir_to_mir.py +1738 -0
  112. machine_dialect/mir/mir_dumper.py +366 -0
  113. machine_dialect/mir/mir_function.py +167 -0
  114. machine_dialect/mir/mir_instructions.py +1877 -0
  115. machine_dialect/mir/mir_interpreter.py +556 -0
  116. machine_dialect/mir/mir_module.py +225 -0
  117. machine_dialect/mir/mir_printer.py +480 -0
  118. machine_dialect/mir/mir_transformer.py +410 -0
  119. machine_dialect/mir/mir_types.py +367 -0
  120. machine_dialect/mir/mir_validation.py +455 -0
  121. machine_dialect/mir/mir_values.py +268 -0
  122. machine_dialect/mir/optimization_config.py +233 -0
  123. machine_dialect/mir/optimization_pass.py +251 -0
  124. machine_dialect/mir/optimization_pipeline.py +355 -0
  125. machine_dialect/mir/optimizations/__init__.py +84 -0
  126. machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
  127. machine_dialect/mir/optimizations/branch_prediction.py +372 -0
  128. machine_dialect/mir/optimizations/constant_propagation.py +634 -0
  129. machine_dialect/mir/optimizations/cse.py +398 -0
  130. machine_dialect/mir/optimizations/dce.py +288 -0
  131. machine_dialect/mir/optimizations/inlining.py +551 -0
  132. machine_dialect/mir/optimizations/jump_threading.py +487 -0
  133. machine_dialect/mir/optimizations/licm.py +405 -0
  134. machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
  135. machine_dialect/mir/optimizations/strength_reduction.py +422 -0
  136. machine_dialect/mir/optimizations/tail_call.py +207 -0
  137. machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
  138. machine_dialect/mir/optimizations/type_narrowing.py +397 -0
  139. machine_dialect/mir/optimizations/type_specialization.py +447 -0
  140. machine_dialect/mir/optimizations/type_specific.py +906 -0
  141. machine_dialect/mir/optimize_mir.py +89 -0
  142. machine_dialect/mir/pass_manager.py +391 -0
  143. machine_dialect/mir/profiling/__init__.py +26 -0
  144. machine_dialect/mir/profiling/profile_collector.py +318 -0
  145. machine_dialect/mir/profiling/profile_data.py +372 -0
  146. machine_dialect/mir/profiling/profile_reader.py +272 -0
  147. machine_dialect/mir/profiling/profile_writer.py +226 -0
  148. machine_dialect/mir/register_allocation.py +302 -0
  149. machine_dialect/mir/reporting/__init__.py +17 -0
  150. machine_dialect/mir/reporting/optimization_reporter.py +314 -0
  151. machine_dialect/mir/reporting/report_formatter.py +289 -0
  152. machine_dialect/mir/ssa_construction.py +342 -0
  153. machine_dialect/mir/tests/__init__.py +1 -0
  154. machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
  155. machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
  156. machine_dialect/mir/tests/test_algebraic_division.py +126 -0
  157. machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
  158. machine_dialect/mir/tests/test_basic_block.py +425 -0
  159. machine_dialect/mir/tests/test_branch_prediction.py +459 -0
  160. machine_dialect/mir/tests/test_call_lowering.py +168 -0
  161. machine_dialect/mir/tests/test_collection_lowering.py +604 -0
  162. machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
  163. machine_dialect/mir/tests/test_custom_passes.py +166 -0
  164. machine_dialect/mir/tests/test_debug_info.py +285 -0
  165. machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
  166. machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
  167. machine_dialect/mir/tests/test_double_negation.py +231 -0
  168. machine_dialect/mir/tests/test_escape_analysis.py +233 -0
  169. machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
  170. machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
  171. machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
  172. machine_dialect/mir/tests/test_inlining.py +435 -0
  173. machine_dialect/mir/tests/test_licm.py +472 -0
  174. machine_dialect/mir/tests/test_mir_dumper.py +313 -0
  175. machine_dialect/mir/tests/test_mir_instructions.py +445 -0
  176. machine_dialect/mir/tests/test_mir_module.py +860 -0
  177. machine_dialect/mir/tests/test_mir_printer.py +387 -0
  178. machine_dialect/mir/tests/test_mir_types.py +123 -0
  179. machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
  180. machine_dialect/mir/tests/test_mir_validation.py +378 -0
  181. machine_dialect/mir/tests/test_mir_values.py +168 -0
  182. machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
  183. machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
  184. machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
  185. machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
  186. machine_dialect/mir/tests/test_pass_manager.py +294 -0
  187. machine_dialect/mir/tests/test_pass_registration.py +64 -0
  188. machine_dialect/mir/tests/test_profiling.py +356 -0
  189. machine_dialect/mir/tests/test_register_allocation.py +307 -0
  190. machine_dialect/mir/tests/test_report_formatters.py +372 -0
  191. machine_dialect/mir/tests/test_ssa_construction.py +433 -0
  192. machine_dialect/mir/tests/test_tail_call.py +236 -0
  193. machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
  194. machine_dialect/mir/tests/test_type_narrowing.py +277 -0
  195. machine_dialect/mir/tests/test_type_specialization.py +421 -0
  196. machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
  197. machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
  198. machine_dialect/mir/type_inference.py +368 -0
  199. machine_dialect/parser/__init__.py +12 -0
  200. machine_dialect/parser/enums.py +45 -0
  201. machine_dialect/parser/parser.py +3655 -0
  202. machine_dialect/parser/protocols.py +11 -0
  203. machine_dialect/parser/symbol_table.py +169 -0
  204. machine_dialect/parser/tests/__init__.py +0 -0
  205. machine_dialect/parser/tests/helper_functions.py +193 -0
  206. machine_dialect/parser/tests/test_action_statements.py +334 -0
  207. machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
  208. machine_dialect/parser/tests/test_call_statements.py +154 -0
  209. machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
  210. machine_dialect/parser/tests/test_collection_mutations.py +264 -0
  211. machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
  212. machine_dialect/parser/tests/test_define_integration.py +468 -0
  213. machine_dialect/parser/tests/test_define_statements.py +311 -0
  214. machine_dialect/parser/tests/test_dict_extraction.py +115 -0
  215. machine_dialect/parser/tests/test_empty_literal.py +155 -0
  216. machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
  217. machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
  218. machine_dialect/parser/tests/test_if_empty_block.py +61 -0
  219. machine_dialect/parser/tests/test_if_statements.py +299 -0
  220. machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
  221. machine_dialect/parser/tests/test_infix_expressions.py +680 -0
  222. machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
  223. machine_dialect/parser/tests/test_interaction_statements.py +269 -0
  224. machine_dialect/parser/tests/test_list_literals.py +277 -0
  225. machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
  226. machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
  227. machine_dialect/parser/tests/test_parse_errors.py +114 -0
  228. machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
  229. machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
  230. machine_dialect/parser/tests/test_program.py +13 -0
  231. machine_dialect/parser/tests/test_return_statements.py +89 -0
  232. machine_dialect/parser/tests/test_set_statements.py +152 -0
  233. machine_dialect/parser/tests/test_strict_equality.py +258 -0
  234. machine_dialect/parser/tests/test_symbol_table.py +217 -0
  235. machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
  236. machine_dialect/parser/tests/test_utility_statements.py +423 -0
  237. machine_dialect/parser/token_buffer.py +159 -0
  238. machine_dialect/repl/__init__.py +3 -0
  239. machine_dialect/repl/repl.py +426 -0
  240. machine_dialect/repl/tests/__init__.py +0 -0
  241. machine_dialect/repl/tests/test_repl.py +606 -0
  242. machine_dialect/semantic/__init__.py +12 -0
  243. machine_dialect/semantic/analyzer.py +906 -0
  244. machine_dialect/semantic/error_messages.py +189 -0
  245. machine_dialect/semantic/tests/__init__.py +1 -0
  246. machine_dialect/semantic/tests/test_analyzer.py +364 -0
  247. machine_dialect/semantic/tests/test_error_messages.py +104 -0
  248. machine_dialect/tests/edge_cases/__init__.py +10 -0
  249. machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
  250. machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
  251. machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
  252. machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
  253. machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
  254. machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
  255. machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
  256. machine_dialect/tests/integration/test_list_compilation.py +395 -0
  257. machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
  258. machine_dialect/type_checking/__init__.py +21 -0
  259. machine_dialect/type_checking/tests/__init__.py +1 -0
  260. machine_dialect/type_checking/tests/test_type_system.py +230 -0
  261. machine_dialect/type_checking/type_system.py +270 -0
  262. machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
  263. machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
  264. machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
  265. machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
  266. machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
  267. machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
  268. machine_dialect_vm/__init__.pyi +15 -0
@@ -0,0 +1,315 @@
1
+ """Alias analysis for MIR.
2
+
3
+ This module provides alias analysis to determine when different variables
4
+ may refer to the same memory location, supporting optimizations like
5
+ escape analysis and redundant load elimination.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum
10
+
11
+ from machine_dialect.mir.basic_block import BasicBlock
12
+ from machine_dialect.mir.mir_function import MIRFunction
13
+ from machine_dialect.mir.mir_instructions import (
14
+ Copy,
15
+ GetAttr,
16
+ LoadVar,
17
+ MIRInstruction,
18
+ Phi,
19
+ SetAttr,
20
+ StoreVar,
21
+ )
22
+ from machine_dialect.mir.mir_types import MIRType
23
+ from machine_dialect.mir.mir_values import Variable
24
+ from machine_dialect.mir.optimization_pass import (
25
+ FunctionAnalysisPass,
26
+ PassInfo,
27
+ PassType,
28
+ PreservationLevel,
29
+ )
30
+
31
+
32
+ class AliasType(Enum):
33
+ """Type of aliasing relationship."""
34
+
35
+ NO_ALIAS = "no_alias" # Definitely different locations
36
+ MAY_ALIAS = "may_alias" # Might be the same location
37
+ MUST_ALIAS = "must_alias" # Definitely the same location
38
+ PARTIAL_ALIAS = "partial_alias" # Overlapping but not identical
39
+
40
+
41
+ @dataclass
42
+ class AliasSet:
43
+ """Set of potentially aliasing values.
44
+
45
+ Attributes:
46
+ members: Values that may alias each other.
47
+ alias_type: Type of aliasing relationship.
48
+ attributes: Attributes accessed on these values.
49
+ """
50
+
51
+ members: set[Variable] = field(default_factory=set)
52
+ alias_type: AliasType = AliasType.MAY_ALIAS
53
+ attributes: set[str] = field(default_factory=set)
54
+
55
+ def add_member(self, var: Variable) -> None:
56
+ """Add a variable to the alias set.
57
+
58
+ Args:
59
+ var: Variable to add.
60
+ """
61
+ self.members.add(var)
62
+
63
+ def merge(self, other: "AliasSet") -> None:
64
+ """Merge another alias set into this one.
65
+
66
+ Args:
67
+ other: Alias set to merge.
68
+ """
69
+ self.members.update(other.members)
70
+ self.attributes.update(other.attributes)
71
+ # Downgrade alias type to be conservative
72
+ if other.alias_type == AliasType.MAY_ALIAS or self.alias_type == AliasType.MAY_ALIAS:
73
+ self.alias_type = AliasType.MAY_ALIAS
74
+
75
+
76
+ class AliasInfo:
77
+ """Container for alias analysis results."""
78
+
79
+ def __init__(self) -> None:
80
+ """Initialize alias information."""
81
+ self.alias_sets: list[AliasSet] = []
82
+ self.var_to_set: dict[str, AliasSet] = {}
83
+
84
+ def get_aliases(self, var: Variable) -> set[Variable]:
85
+ """Get all variables that may alias with the given variable.
86
+
87
+ Args:
88
+ var: Variable to query.
89
+
90
+ Returns:
91
+ Set of potentially aliasing variables.
92
+ """
93
+ alias_set = self.var_to_set.get(var.name)
94
+ if alias_set:
95
+ return alias_set.members - {var}
96
+ return set()
97
+
98
+ def may_alias(self, var1: Variable, var2: Variable) -> bool:
99
+ """Check if two variables may alias.
100
+
101
+ Args:
102
+ var1: First variable.
103
+ var2: Second variable.
104
+
105
+ Returns:
106
+ True if variables may alias.
107
+ """
108
+ set1 = self.var_to_set.get(var1.name)
109
+ set2 = self.var_to_set.get(var2.name)
110
+ return set1 is set2 if (set1 and set2) else False
111
+
112
+ def must_alias(self, var1: Variable, var2: Variable) -> bool:
113
+ """Check if two variables must alias.
114
+
115
+ Args:
116
+ var1: First variable.
117
+ var2: Second variable.
118
+
119
+ Returns:
120
+ True if variables must alias.
121
+ """
122
+ set1 = self.var_to_set.get(var1.name)
123
+ set2 = self.var_to_set.get(var2.name)
124
+ if set1 is set2 and set1:
125
+ return set1.alias_type == AliasType.MUST_ALIAS
126
+ return False
127
+
128
+
129
+ class AliasAnalysis(FunctionAnalysisPass):
130
+ """Analyze pointer aliasing relationships."""
131
+
132
+ def get_info(self) -> PassInfo:
133
+ """Get pass information.
134
+
135
+ Returns:
136
+ Pass information.
137
+ """
138
+ return PassInfo(
139
+ name="alias-analysis",
140
+ description="Analyze variable aliasing relationships",
141
+ pass_type=PassType.ANALYSIS,
142
+ requires=[],
143
+ preserves=PreservationLevel.ALL,
144
+ )
145
+
146
+ def run_on_function(self, function: MIRFunction) -> AliasInfo:
147
+ """Analyze aliasing in a function.
148
+
149
+ Args:
150
+ function: The function to analyze.
151
+
152
+ Returns:
153
+ Alias analysis results.
154
+ """
155
+ alias_info = AliasInfo()
156
+
157
+ # Initialize each variable in its own set
158
+ self._initialize_variables(function, alias_info)
159
+
160
+ # Analyze instructions to find aliasing
161
+ for block in function.cfg.blocks.values():
162
+ self._analyze_block(block, alias_info)
163
+
164
+ # Handle phi nodes specially
165
+ self._analyze_phi_nodes(function, alias_info)
166
+
167
+ return alias_info
168
+
169
+ def _initialize_variables(self, function: MIRFunction, alias_info: AliasInfo) -> None:
170
+ """Initialize alias sets for all variables.
171
+
172
+ Args:
173
+ function: The function being analyzed.
174
+ alias_info: Alias information to populate.
175
+ """
176
+ # Create initial alias sets for locals
177
+ for var_name in function.locals:
178
+ var = Variable(var_name, MIRType.INT)
179
+ alias_set = AliasSet()
180
+ alias_set.add_member(var)
181
+ alias_set.alias_type = AliasType.NO_ALIAS # Initially no aliases
182
+ alias_info.alias_sets.append(alias_set)
183
+ alias_info.var_to_set[var_name] = alias_set
184
+
185
+ # Create initial sets for parameters
186
+ for param in function.params:
187
+ alias_set = AliasSet()
188
+ alias_set.add_member(param)
189
+ # Parameters may alias with external data
190
+ alias_set.alias_type = AliasType.MAY_ALIAS
191
+ alias_info.alias_sets.append(alias_set)
192
+ alias_info.var_to_set[param.name] = alias_set
193
+
194
+ def _analyze_block(self, block: BasicBlock, alias_info: AliasInfo) -> None:
195
+ """Analyze aliasing in a block.
196
+
197
+ Args:
198
+ block: The block to analyze.
199
+ alias_info: Alias information to update.
200
+ """
201
+ for inst in block.instructions:
202
+ self._analyze_instruction(inst, alias_info)
203
+
204
+ def _analyze_instruction(self, inst: MIRInstruction, alias_info: AliasInfo) -> None:
205
+ """Analyze aliasing effects of an instruction.
206
+
207
+ Args:
208
+ inst: The instruction to analyze.
209
+ alias_info: Alias information to update.
210
+ """
211
+ # Copy creates must-alias relationship
212
+ if isinstance(inst, Copy):
213
+ if isinstance(inst.source, Variable) and isinstance(inst.dest, Variable):
214
+ self._merge_alias_sets(inst.source, inst.dest, AliasType.MUST_ALIAS, alias_info)
215
+
216
+ # Load creates may-alias relationship
217
+ elif isinstance(inst, LoadVar):
218
+ if isinstance(inst.dest, Variable) and isinstance(inst.var, Variable):
219
+ self._merge_alias_sets(inst.var, inst.dest, AliasType.MAY_ALIAS, alias_info)
220
+
221
+ # Store can create aliasing through memory
222
+ elif isinstance(inst, StoreVar):
223
+ if isinstance(inst.source, Variable) and isinstance(inst.var, Variable):
224
+ self._merge_alias_sets(inst.var, inst.source, AliasType.MAY_ALIAS, alias_info)
225
+
226
+ # GetAttr tracks attribute access
227
+ elif isinstance(inst, GetAttr):
228
+ if isinstance(inst.obj, Variable) and isinstance(inst.dest, Variable):
229
+ obj_set = alias_info.var_to_set.get(inst.obj.name)
230
+ if obj_set:
231
+ obj_set.attributes.add(inst.attr)
232
+ # Result may alias with the field
233
+ self._merge_alias_sets(inst.obj, inst.dest, AliasType.PARTIAL_ALIAS, alias_info)
234
+
235
+ # SetAttr tracks attribute modification
236
+ elif isinstance(inst, SetAttr):
237
+ if isinstance(inst.obj, Variable):
238
+ obj_set = alias_info.var_to_set.get(inst.obj.name)
239
+ if obj_set:
240
+ obj_set.attributes.add(inst.attr)
241
+
242
+ def _merge_alias_sets(
243
+ self,
244
+ var1: Variable,
245
+ var2: Variable,
246
+ alias_type: AliasType,
247
+ alias_info: AliasInfo,
248
+ ) -> None:
249
+ """Merge alias sets for two variables.
250
+
251
+ Args:
252
+ var1: First variable.
253
+ var2: Second variable.
254
+ alias_type: Type of aliasing.
255
+ alias_info: Alias information to update.
256
+ """
257
+ set1 = alias_info.var_to_set.get(var1.name)
258
+ set2 = alias_info.var_to_set.get(var2.name)
259
+
260
+ if not set1 and not set2:
261
+ # Create new set for both
262
+ new_set = AliasSet()
263
+ new_set.add_member(var1)
264
+ new_set.add_member(var2)
265
+ new_set.alias_type = alias_type
266
+ alias_info.alias_sets.append(new_set)
267
+ alias_info.var_to_set[var1.name] = new_set
268
+ alias_info.var_to_set[var2.name] = new_set
269
+ elif set1 and not set2:
270
+ # Add var2 to set1
271
+ set1.add_member(var2)
272
+ if alias_type == AliasType.MAY_ALIAS or set1.alias_type != alias_type:
273
+ set1.alias_type = AliasType.MAY_ALIAS
274
+ alias_info.var_to_set[var2.name] = set1
275
+ elif not set1 and set2:
276
+ # Add var1 to set2
277
+ set2.add_member(var1)
278
+ if alias_type == AliasType.MAY_ALIAS or set2.alias_type != alias_type:
279
+ set2.alias_type = AliasType.MAY_ALIAS
280
+ alias_info.var_to_set[var1.name] = set2
281
+ elif set1 and set2 and set1 is not set2:
282
+ # Merge sets
283
+ set1.merge(set2)
284
+ if alias_type == AliasType.MAY_ALIAS:
285
+ set1.alias_type = AliasType.MAY_ALIAS
286
+ # Update all members of set2 to point to set1
287
+ for member in set2.members:
288
+ alias_info.var_to_set[member.name] = set1
289
+ # Remove set2 from list
290
+ alias_info.alias_sets.remove(set2)
291
+
292
+ def _analyze_phi_nodes(self, function: MIRFunction, alias_info: AliasInfo) -> None:
293
+ """Analyze phi nodes for aliasing.
294
+
295
+ Args:
296
+ function: The function being analyzed.
297
+ alias_info: Alias information to update.
298
+ """
299
+ for block in function.cfg.blocks.values():
300
+ for inst in block.instructions:
301
+ if isinstance(inst, Phi):
302
+ # All phi inputs may alias with the output
303
+ if isinstance(inst.dest, Variable):
304
+ for value, _ in inst.incoming:
305
+ if isinstance(value, Variable):
306
+ self._merge_alias_sets(
307
+ inst.dest,
308
+ value,
309
+ AliasType.MAY_ALIAS,
310
+ alias_info,
311
+ )
312
+
313
+ def finalize(self) -> None:
314
+ """Finalize the pass."""
315
+ pass
@@ -0,0 +1,49 @@
1
+ """Dominance analysis for MIR.
2
+
3
+ This module provides a pass wrapper for dominance analysis.
4
+ """
5
+
6
+ from machine_dialect.mir.mir_function import MIRFunction
7
+ from machine_dialect.mir.optimization_pass import (
8
+ FunctionAnalysisPass,
9
+ PassInfo,
10
+ PassType,
11
+ PreservationLevel,
12
+ )
13
+ from machine_dialect.mir.ssa_construction import DominanceInfo
14
+
15
+
16
+ class DominanceAnalysis(FunctionAnalysisPass):
17
+ """Analysis pass that computes dominance information."""
18
+
19
+ def get_info(self) -> PassInfo:
20
+ """Get pass information.
21
+
22
+ Returns:
23
+ Pass information.
24
+ """
25
+ return PassInfo(
26
+ name="dominance",
27
+ description="Compute dominance information",
28
+ pass_type=PassType.ANALYSIS,
29
+ requires=[],
30
+ preserves=PreservationLevel.ALL,
31
+ )
32
+
33
+ def run_on_function(self, function: MIRFunction) -> DominanceInfo:
34
+ """Compute dominance for a function.
35
+
36
+ Args:
37
+ function: The function to analyze.
38
+
39
+ Returns:
40
+ Dominance information.
41
+ """
42
+ return DominanceInfo(function.cfg)
43
+
44
+ def finalize(self) -> None:
45
+ """Finalize the analysis pass.
46
+
47
+ Nothing to clean up for dominance analysis.
48
+ """
49
+ pass
@@ -0,0 +1,286 @@
1
+ """Escape analysis for MIR variables.
2
+
3
+ This module analyzes variable escape behavior to determine which variables
4
+ can be safely allocated on the stack instead of the heap, improving memory
5
+ efficiency and cache locality.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum
10
+
11
+ from machine_dialect.mir.basic_block import BasicBlock
12
+ from machine_dialect.mir.mir_function import MIRFunction
13
+ from machine_dialect.mir.mir_instructions import (
14
+ Call,
15
+ Copy,
16
+ MIRInstruction,
17
+ Return,
18
+ SetAttr,
19
+ StoreVar,
20
+ )
21
+ from machine_dialect.mir.mir_types import MIRType
22
+ from machine_dialect.mir.mir_values import Variable
23
+ from machine_dialect.mir.optimization_pass import (
24
+ FunctionAnalysisPass,
25
+ PassInfo,
26
+ PassType,
27
+ PreservationLevel,
28
+ )
29
+
30
+
31
+ class EscapeState(Enum):
32
+ """Escape state of a variable."""
33
+
34
+ NO_ESCAPE = "no_escape" # Can be stack allocated
35
+ ARG_ESCAPE = "arg_escape" # Escapes as function argument
36
+ RETURN_ESCAPE = "return_escape" # Escapes via return
37
+ HEAP_ESCAPE = "heap_escape" # Stored in heap object
38
+ GLOBAL_ESCAPE = "global_escape" # Escapes globally
39
+
40
+
41
+ @dataclass
42
+ class VariableEscapeInfo:
43
+ """Information about a variable's escape behavior.
44
+
45
+ Attributes:
46
+ variable: The variable being analyzed.
47
+ state: Current escape state.
48
+ escape_sites: Instructions where escape occurs.
49
+ aliases: Other variables that alias this one.
50
+ stack_eligible: Whether eligible for stack allocation.
51
+ """
52
+
53
+ variable: Variable
54
+ state: EscapeState = EscapeState.NO_ESCAPE
55
+ escape_sites: list[MIRInstruction] = field(default_factory=list)
56
+ aliases: set[Variable] = field(default_factory=set)
57
+ stack_eligible: bool = True
58
+
59
+ def mark_escape(self, state: EscapeState, site: MIRInstruction) -> None:
60
+ """Mark variable as escaping.
61
+
62
+ Args:
63
+ state: New escape state.
64
+ site: Instruction causing escape.
65
+ """
66
+ # Upgrade escape state (more restrictive wins)
67
+ if state == EscapeState.GLOBAL_ESCAPE or self.state == EscapeState.GLOBAL_ESCAPE:
68
+ self.state = EscapeState.GLOBAL_ESCAPE
69
+ self.stack_eligible = False
70
+ elif state == EscapeState.HEAP_ESCAPE or self.state == EscapeState.HEAP_ESCAPE:
71
+ self.state = EscapeState.HEAP_ESCAPE
72
+ self.stack_eligible = False
73
+ elif state == EscapeState.RETURN_ESCAPE or self.state == EscapeState.RETURN_ESCAPE:
74
+ self.state = EscapeState.RETURN_ESCAPE
75
+ self.stack_eligible = False
76
+ elif state == EscapeState.ARG_ESCAPE or self.state == EscapeState.ARG_ESCAPE:
77
+ self.state = EscapeState.ARG_ESCAPE
78
+ self.stack_eligible = False
79
+
80
+ self.escape_sites.append(site)
81
+
82
+
83
+ class EscapeInfo:
84
+ """Container for escape analysis results."""
85
+
86
+ def __init__(self) -> None:
87
+ """Initialize escape information."""
88
+ self.variable_info: dict[str, VariableEscapeInfo] = {}
89
+ self.stack_eligible: set[Variable] = set()
90
+ self.escaping_vars: set[Variable] = set()
91
+
92
+ def get_info(self, var: Variable) -> VariableEscapeInfo | None:
93
+ """Get escape info for a variable.
94
+
95
+ Args:
96
+ var: The variable to query.
97
+
98
+ Returns:
99
+ Escape information or None.
100
+ """
101
+ return self.variable_info.get(var.name)
102
+
103
+ def is_stack_eligible(self, var: Variable) -> bool:
104
+ """Check if variable can be stack allocated.
105
+
106
+ Args:
107
+ var: The variable to check.
108
+
109
+ Returns:
110
+ True if stack eligible.
111
+ """
112
+ info = self.get_info(var)
113
+ return info.stack_eligible if info else False
114
+
115
+ def does_escape(self, var: Variable) -> bool:
116
+ """Check if variable escapes.
117
+
118
+ Args:
119
+ var: The variable to check.
120
+
121
+ Returns:
122
+ True if variable escapes.
123
+ """
124
+ info = self.get_info(var)
125
+ return info.state != EscapeState.NO_ESCAPE if info else False
126
+
127
+
128
+ class EscapeAnalysis(FunctionAnalysisPass):
129
+ """Analyze variable escape behavior for stack allocation optimization."""
130
+
131
+ def get_info(self) -> PassInfo:
132
+ """Get pass information.
133
+
134
+ Returns:
135
+ Pass information.
136
+ """
137
+ return PassInfo(
138
+ name="escape-analysis",
139
+ description="Analyze variable escape behavior",
140
+ pass_type=PassType.ANALYSIS,
141
+ requires=[],
142
+ preserves=PreservationLevel.ALL,
143
+ )
144
+
145
+ def run_on_function(self, function: MIRFunction) -> EscapeInfo:
146
+ """Analyze escape behavior in a function.
147
+
148
+ Args:
149
+ function: The function to analyze.
150
+
151
+ Returns:
152
+ Escape analysis results.
153
+ """
154
+ escape_info = EscapeInfo()
155
+
156
+ # Initialize info for all variables
157
+ self._initialize_variables(function, escape_info)
158
+
159
+ # Analyze each block
160
+ for block in function.cfg.blocks.values():
161
+ self._analyze_block(block, escape_info)
162
+
163
+ # Propagate escape through aliases
164
+ self._propagate_escapes(escape_info)
165
+
166
+ # Collect final results
167
+ self._finalize_results(escape_info)
168
+
169
+ return escape_info
170
+
171
+ def _initialize_variables(self, function: MIRFunction, escape_info: EscapeInfo) -> None:
172
+ """Initialize escape info for all variables.
173
+
174
+ Args:
175
+ function: The function being analyzed.
176
+ escape_info: Escape information to populate.
177
+ """
178
+ # Add local variables
179
+ for var_name in function.locals:
180
+ var = Variable(var_name, MIRType.INT) # Default to INT for simplicity
181
+ escape_info.variable_info[var_name] = VariableEscapeInfo(variable=var)
182
+
183
+ # Parameters are more complex - they're already "from outside"
184
+ # but we track if they escape further
185
+ for param in function.params:
186
+ info = VariableEscapeInfo(variable=param)
187
+ # Parameters themselves don't escape just by existing
188
+ escape_info.variable_info[param.name] = info
189
+
190
+ def _analyze_block(self, block: BasicBlock, escape_info: EscapeInfo) -> None:
191
+ """Analyze escape behavior in a block.
192
+
193
+ Args:
194
+ block: The block to analyze.
195
+ escape_info: Escape information to update.
196
+ """
197
+ for inst in block.instructions:
198
+ self._analyze_instruction(inst, escape_info)
199
+
200
+ def _analyze_instruction(self, inst: MIRInstruction, escape_info: EscapeInfo) -> None:
201
+ """Analyze escape behavior of an instruction.
202
+
203
+ Args:
204
+ inst: The instruction to analyze.
205
+ escape_info: Escape information to update.
206
+ """
207
+ # Check for returns
208
+ if isinstance(inst, Return):
209
+ if inst.value and isinstance(inst.value, Variable):
210
+ info = escape_info.variable_info.get(inst.value.name)
211
+ if info:
212
+ info.mark_escape(EscapeState.RETURN_ESCAPE, inst)
213
+
214
+ # Check for function calls
215
+ elif isinstance(inst, Call):
216
+ # Arguments to calls may escape
217
+ for arg in inst.args:
218
+ if isinstance(arg, Variable):
219
+ info = escape_info.variable_info.get(arg.name)
220
+ if info:
221
+ # Conservative: assume args escape
222
+ # Could be refined with interprocedural analysis
223
+ info.mark_escape(EscapeState.ARG_ESCAPE, inst)
224
+
225
+ # Check for stores to heap objects
226
+ elif isinstance(inst, SetAttr):
227
+ if isinstance(inst.value, Variable):
228
+ info = escape_info.variable_info.get(inst.value.name)
229
+ if info:
230
+ info.mark_escape(EscapeState.HEAP_ESCAPE, inst)
231
+
232
+ # Check for copies (creates aliases)
233
+ elif isinstance(inst, Copy):
234
+ if isinstance(inst.source, Variable) and isinstance(inst.dest, Variable):
235
+ src_info = escape_info.variable_info.get(inst.source.name)
236
+ dest_info = escape_info.variable_info.get(inst.dest.name)
237
+ if src_info and dest_info:
238
+ # Track aliasing
239
+ src_info.aliases.add(inst.dest)
240
+ dest_info.aliases.add(inst.source)
241
+
242
+ # Check for stores to global/external locations
243
+ elif isinstance(inst, StoreVar):
244
+ if isinstance(inst.source, Variable):
245
+ info = escape_info.variable_info.get(inst.source.name)
246
+ if info:
247
+ # Storing to another variable might be escape
248
+ # Conservative for now
249
+ if inst.var.name not in escape_info.variable_info:
250
+ # Storing to unknown location
251
+ info.mark_escape(EscapeState.GLOBAL_ESCAPE, inst)
252
+
253
+ def _propagate_escapes(self, escape_info: EscapeInfo) -> None:
254
+ """Propagate escape states through aliases.
255
+
256
+ Args:
257
+ escape_info: Escape information to update.
258
+ """
259
+ # If a variable escapes, all its aliases escape
260
+ changed = True
261
+ while changed:
262
+ changed = False
263
+ for var_info in escape_info.variable_info.values():
264
+ if var_info.state != EscapeState.NO_ESCAPE:
265
+ for alias in var_info.aliases:
266
+ alias_info = escape_info.variable_info.get(alias.name)
267
+ if alias_info and alias_info.state == EscapeState.NO_ESCAPE:
268
+ alias_info.state = var_info.state
269
+ alias_info.stack_eligible = False
270
+ changed = True
271
+
272
+ def _finalize_results(self, escape_info: EscapeInfo) -> None:
273
+ """Finalize escape analysis results.
274
+
275
+ Args:
276
+ escape_info: Escape information to finalize.
277
+ """
278
+ for var_info in escape_info.variable_info.values():
279
+ if var_info.stack_eligible:
280
+ escape_info.stack_eligible.add(var_info.variable)
281
+ else:
282
+ escape_info.escaping_vars.add(var_info.variable)
283
+
284
+ def finalize(self) -> None:
285
+ """Finalize the pass."""
286
+ pass