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,372 @@
1
+ """Branch prediction optimization pass.
2
+
3
+ This module uses profiling data to optimize branch layout and convert
4
+ predictable branches to more efficient code patterns.
5
+ """
6
+
7
+ from dataclasses import dataclass
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
+ )
15
+ from machine_dialect.mir.mir_module import MIRModule
16
+ from machine_dialect.mir.optimization_pass import (
17
+ ModulePass,
18
+ PassInfo,
19
+ PassType,
20
+ PreservationLevel,
21
+ )
22
+ from machine_dialect.mir.profiling.profile_data import ProfileData
23
+
24
+
25
+ @dataclass
26
+ class BranchInfo:
27
+ """Information about a branch for optimization.
28
+
29
+ Attributes:
30
+ block: The basic block containing the branch.
31
+ instruction: The branch instruction.
32
+ taken_probability: Probability of branch being taken.
33
+ is_predictable: Whether branch is highly predictable.
34
+ is_loop_header: Whether this is a loop header branch.
35
+ """
36
+
37
+ block: BasicBlock
38
+ instruction: ConditionalJump
39
+ taken_probability: float
40
+ is_predictable: bool
41
+ is_loop_header: bool = False
42
+
43
+
44
+ class BranchPredictionOptimization(ModulePass):
45
+ """Branch prediction optimization pass.
46
+
47
+ This pass uses profile data to:
48
+ 1. Reorder basic blocks for better branch prediction
49
+ 2. Convert highly predictable branches to conditional moves
50
+ 3. Add branch hints for the VM
51
+ """
52
+
53
+ def __init__(self, profile_data: ProfileData | None = None, predictability_threshold: float = 0.95) -> None:
54
+ """Initialize branch prediction optimization.
55
+
56
+ Args:
57
+ profile_data: Optional profiling data with branch statistics.
58
+ predictability_threshold: Threshold for considering branch predictable.
59
+ """
60
+ super().__init__()
61
+ self.profile_data = profile_data
62
+ self.predictability_threshold = predictability_threshold
63
+ self.stats = {
64
+ "branches_analyzed": 0,
65
+ "blocks_reordered": 0,
66
+ "branches_converted_to_select": 0,
67
+ "branch_hints_added": 0,
68
+ }
69
+
70
+ def get_info(self) -> PassInfo:
71
+ """Get pass information.
72
+
73
+ Returns:
74
+ Pass information.
75
+ """
76
+ return PassInfo(
77
+ name="branch-prediction",
78
+ description="Optimize branches using profile data",
79
+ pass_type=PassType.OPTIMIZATION,
80
+ requires=[],
81
+ preserves=PreservationLevel.CFG,
82
+ )
83
+
84
+ def finalize(self) -> None:
85
+ """Finalize the pass after running."""
86
+ pass
87
+
88
+ def run_on_module(self, module: MIRModule) -> bool:
89
+ """Run branch prediction optimization on a module.
90
+
91
+ Args:
92
+ module: The module to optimize.
93
+
94
+ Returns:
95
+ True if the module was modified.
96
+ """
97
+ modified = False
98
+
99
+ # Process each function
100
+ for function in module.functions.values():
101
+ if self._optimize_function_branches(function):
102
+ modified = True
103
+
104
+ return modified
105
+
106
+ def _optimize_function_branches(self, function: MIRFunction) -> bool:
107
+ """Optimize branches in a function.
108
+
109
+ Args:
110
+ function: The function to optimize.
111
+
112
+ Returns:
113
+ True if the function was modified.
114
+ """
115
+ modified = False
116
+
117
+ # Collect branch information
118
+ branches = self._collect_branch_info(function)
119
+
120
+ # Phase 1: Convert highly predictable branches to select instructions
121
+ for branch_info in branches:
122
+ if branch_info.is_predictable and self._can_convert_to_select(branch_info):
123
+ if self._convert_to_select(branch_info):
124
+ self.stats["branches_converted_to_select"] += 1
125
+ modified = True
126
+
127
+ # Phase 2: Reorder blocks for better branch prediction
128
+ if self._reorder_blocks(function, branches):
129
+ self.stats["blocks_reordered"] += 1
130
+ modified = True
131
+
132
+ # Phase 3: Add branch hints
133
+ for branch_info in branches:
134
+ if self._add_branch_hint(branch_info):
135
+ self.stats["branch_hints_added"] += 1
136
+ modified = True
137
+
138
+ return modified
139
+
140
+ def _collect_branch_info(self, function: MIRFunction) -> list[BranchInfo]:
141
+ """Collect information about branches in a function.
142
+
143
+ Args:
144
+ function: The function to analyze.
145
+
146
+ Returns:
147
+ List of branch information.
148
+ """
149
+ branches = []
150
+
151
+ for block_name, block in function.cfg.blocks.items():
152
+ # Check if block ends with conditional jump
153
+ if block.instructions:
154
+ last_inst = block.instructions[-1]
155
+ if isinstance(last_inst, ConditionalJump):
156
+ self.stats["branches_analyzed"] += 1
157
+
158
+ # Get profile data if available
159
+ taken_prob = 0.5 # Default to unpredictable
160
+ is_predictable = False
161
+
162
+ if self.profile_data:
163
+ # Look up branch profile
164
+ branch_key = f"{function.name}:{block_name}"
165
+ if branch_key in self.profile_data.branches:
166
+ branch_profile = self.profile_data.branches[branch_key]
167
+ taken_prob = branch_profile.taken_probability
168
+ is_predictable = branch_profile.predictable
169
+ else:
170
+ # Simple heuristic: backwards branches (loops) are likely taken
171
+ if last_inst.true_label < block_name:
172
+ taken_prob = 0.9
173
+ is_predictable = True
174
+
175
+ # Check if it's a loop header
176
+ is_loop_header = self._is_loop_header(function, block_name)
177
+
178
+ branches.append(
179
+ BranchInfo(
180
+ block=block,
181
+ instruction=last_inst,
182
+ taken_probability=taken_prob,
183
+ is_predictable=is_predictable
184
+ or (
185
+ taken_prob >= self.predictability_threshold
186
+ or taken_prob <= (1 - self.predictability_threshold)
187
+ ),
188
+ is_loop_header=is_loop_header,
189
+ )
190
+ )
191
+
192
+ return branches
193
+
194
+ def _is_loop_header(self, function: MIRFunction, block_name: str) -> bool:
195
+ """Check if a block is a loop header.
196
+
197
+ Args:
198
+ function: The function containing the block.
199
+ block_name: Name of the block to check.
200
+
201
+ Returns:
202
+ True if the block is a loop header.
203
+ """
204
+ # Simple heuristic: block has a back edge to itself
205
+ block = function.cfg.blocks.get(block_name)
206
+ if block and block.instructions:
207
+ last_inst = block.instructions[-1]
208
+ if isinstance(last_inst, ConditionalJump | Jump):
209
+ # Check if it jumps back to itself or an earlier block
210
+ targets = []
211
+ if isinstance(last_inst, ConditionalJump):
212
+ targets = [last_inst.true_label]
213
+ if last_inst.false_label:
214
+ targets.append(last_inst.false_label)
215
+ elif isinstance(last_inst, Jump):
216
+ targets = [last_inst.label]
217
+
218
+ for target in targets:
219
+ if target <= block_name: # Back edge
220
+ return True
221
+
222
+ return False
223
+
224
+ def _can_convert_to_select(self, branch_info: BranchInfo) -> bool:
225
+ """Check if a branch can be converted to a select instruction.
226
+
227
+ Args:
228
+ branch_info: Information about the branch.
229
+
230
+ Returns:
231
+ True if conversion is possible.
232
+ """
233
+ # Don't convert loop headers (would break loop structure)
234
+ if branch_info.is_loop_header:
235
+ return False
236
+
237
+ # Check if both targets are simple (single assignment followed by join)
238
+ # This is a simplified check - real implementation would be more thorough
239
+
240
+ # For now, only convert very simple patterns
241
+ block = branch_info.block
242
+ if len(block.instructions) < 2:
243
+ return False
244
+
245
+ # Look for pattern: compare, branch
246
+ # Could be converted to: select
247
+
248
+ return False # Conservative for now
249
+
250
+ def _convert_to_select(self, branch_info: BranchInfo) -> bool:
251
+ """Convert a predictable branch to a select instruction.
252
+
253
+ Args:
254
+ branch_info: Information about the branch to convert.
255
+
256
+ Returns:
257
+ True if conversion was performed.
258
+ """
259
+ # This would convert patterns like:
260
+ # if (cond) { x = a; } else { x = b; }
261
+ # To:
262
+ # x = select(cond, a, b)
263
+
264
+ # For now, not implemented
265
+ return False
266
+
267
+ def _reorder_blocks(self, function: MIRFunction, branches: list[BranchInfo]) -> bool:
268
+ """Reorder blocks to optimize branch prediction.
269
+
270
+ Args:
271
+ function: The function to reorder.
272
+ branches: Branch information.
273
+
274
+ Returns:
275
+ True if blocks were reordered.
276
+ """
277
+ # Strategy: Place likely successors immediately after their predecessors
278
+ # This makes the likely path fall-through (no taken branch)
279
+
280
+ modified = False
281
+ new_order: list[str] = []
282
+ visited: set[str] = set()
283
+
284
+ # Start with entry block
285
+ entry = function.cfg.entry_block
286
+ if not entry:
287
+ return False
288
+
289
+ # Build new order using likely paths
290
+ work_list: list[str] = [entry.label]
291
+
292
+ while work_list:
293
+ current = work_list.pop(0)
294
+ if current in visited:
295
+ continue
296
+
297
+ visited.add(current)
298
+ new_order.append(current)
299
+
300
+ # Find branch in this block
301
+ block = function.cfg.blocks.get(current)
302
+ if not block:
303
+ continue
304
+
305
+ # Find likely successor
306
+ for branch_info in branches:
307
+ if branch_info.block == block:
308
+ # Add likely target first (so it's next in layout)
309
+ if branch_info.taken_probability >= 0.5:
310
+ # Likely to take branch
311
+ if branch_info.instruction.true_label not in visited:
312
+ work_list.insert(0, branch_info.instruction.true_label)
313
+ if branch_info.instruction.false_label and branch_info.instruction.false_label not in visited:
314
+ work_list.append(branch_info.instruction.false_label)
315
+ else:
316
+ # Likely to fall through
317
+ if branch_info.instruction.false_label and branch_info.instruction.false_label not in visited:
318
+ work_list.insert(0, branch_info.instruction.false_label)
319
+ if branch_info.instruction.true_label not in visited:
320
+ work_list.append(branch_info.instruction.true_label)
321
+ break
322
+ else:
323
+ # No branch, add successors in order
324
+ # (would need CFG successor information here)
325
+ pass
326
+
327
+ # Add any unvisited blocks
328
+ for block_name in function.cfg.blocks:
329
+ if block_name not in visited:
330
+ new_order.append(block_name)
331
+
332
+ # Check if order changed
333
+ old_order = list(function.cfg.blocks.keys())
334
+ if new_order != old_order:
335
+ # Reorder the blocks dictionary
336
+ # Note: In Python 3.7+, dict preserves insertion order
337
+ new_blocks = {}
338
+ for block_name in new_order:
339
+ if block_name in function.cfg.blocks:
340
+ new_blocks[block_name] = function.cfg.blocks[block_name]
341
+ function.cfg.blocks = new_blocks
342
+ modified = True
343
+
344
+ return modified
345
+
346
+ def _add_branch_hint(self, branch_info: BranchInfo) -> bool:
347
+ """Add branch prediction hint to instruction.
348
+
349
+ Args:
350
+ branch_info: Information about the branch.
351
+
352
+ Returns:
353
+ True if hint was added.
354
+ """
355
+ # Add hint as metadata on the instruction
356
+ # The VM can use this to optimize branch prediction
357
+
358
+ inst = branch_info.instruction
359
+
360
+ # Add prediction hint attribute using type: ignore for dynamic attributes
361
+ if not hasattr(inst, "prediction_hint"):
362
+ if branch_info.taken_probability >= 0.5:
363
+ inst.prediction_hint = "likely_taken" # type: ignore[attr-defined]
364
+ else:
365
+ inst.prediction_hint = "likely_not_taken" # type: ignore[attr-defined]
366
+
367
+ # Also store the probability for more precise optimization
368
+ inst.taken_probability = branch_info.taken_probability # type: ignore[attr-defined]
369
+
370
+ return True
371
+
372
+ return False