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,289 @@
1
+ """Report formatters for optimization reports.
2
+
3
+ This module provides different output formats for optimization reports
4
+ including text, HTML, and JSON.
5
+ """
6
+
7
+ import json
8
+ from abc import ABC, abstractmethod
9
+ from typing import Any
10
+
11
+ from machine_dialect.mir.reporting.optimization_reporter import ModuleMetrics
12
+
13
+
14
+ class ReportFormatter(ABC):
15
+ """Abstract base class for report formatters."""
16
+
17
+ @abstractmethod
18
+ def format(self, metrics: ModuleMetrics) -> str:
19
+ """Format the metrics into a report.
20
+
21
+ Args:
22
+ metrics: Module metrics to format.
23
+
24
+ Returns:
25
+ Formatted report as a string.
26
+ """
27
+ pass
28
+
29
+
30
+ class TextReportFormatter(ReportFormatter):
31
+ """Formats reports as plain text."""
32
+
33
+ def __init__(self, detailed: bool = True) -> None:
34
+ """Initialize text formatter.
35
+
36
+ Args:
37
+ detailed: Whether to include detailed per-pass statistics.
38
+ """
39
+ self.detailed = detailed
40
+
41
+ def format(self, metrics: ModuleMetrics) -> str:
42
+ """Format metrics as text report.
43
+
44
+ Args:
45
+ metrics: Module metrics.
46
+
47
+ Returns:
48
+ Text report.
49
+ """
50
+ lines = []
51
+ summary = metrics.get_summary()
52
+
53
+ # Header
54
+ lines.append("=" * 70)
55
+ lines.append(f"OPTIMIZATION REPORT - {summary['module_name']}")
56
+ lines.append("=" * 70)
57
+ lines.append("")
58
+
59
+ # Summary section
60
+ lines.append("SUMMARY")
61
+ lines.append("-" * 30)
62
+ lines.append(f"Optimization Level: {summary['optimization_level']}")
63
+ lines.append(f"Total Passes Run: {summary['total_passes']}")
64
+ lines.append(f"Total Time: {summary['total_time_ms']:.2f}ms")
65
+
66
+ if summary["total_time_ms"] > 0:
67
+ avg_time = summary["total_time_ms"] / summary["total_passes"]
68
+ lines.append(f"Average Pass Time: {avg_time:.2f}ms")
69
+ lines.append("")
70
+
71
+ # Passes applied
72
+ if summary["passes_applied"]:
73
+ lines.append("PASSES APPLIED")
74
+ lines.append("-" * 30)
75
+ for i, pass_name in enumerate(summary["passes_applied"], 1):
76
+ lines.append(f"{i:2}. {pass_name}")
77
+ lines.append("")
78
+
79
+ # Overall improvements
80
+ if summary["improvements"]:
81
+ lines.append("OVERALL IMPROVEMENTS")
82
+ lines.append("-" * 30)
83
+ for metric, improvement in sorted(summary["improvements"].items()):
84
+ if improvement > 0:
85
+ lines.append(f" {metric:30} {improvement:6.1f}% reduction")
86
+ elif improvement < 0:
87
+ lines.append(f" {metric:30} {-improvement:6.1f}% increase")
88
+ lines.append("")
89
+
90
+ # Total metrics
91
+ if summary["total_metrics"]:
92
+ lines.append("TOTAL OPTIMIZATIONS")
93
+ lines.append("-" * 30)
94
+ for metric, value in sorted(summary["total_metrics"].items()):
95
+ if value > 0:
96
+ lines.append(f" {metric:30} {value:6}")
97
+ lines.append("")
98
+
99
+ # Detailed pass statistics
100
+ if self.detailed and metrics.pass_metrics:
101
+ lines.append("=" * 70)
102
+ lines.append("DETAILED PASS STATISTICS")
103
+ lines.append("=" * 70)
104
+
105
+ for i, pass_metrics in enumerate(metrics.pass_metrics, 1):
106
+ lines.append("")
107
+ lines.append(f"[{i}] {pass_metrics.pass_name}")
108
+ lines.append("-" * 50)
109
+ lines.append(f" Phase: {pass_metrics.phase}")
110
+ lines.append(f" Time: {pass_metrics.time_ms:.2f}ms")
111
+
112
+ if pass_metrics.metrics:
113
+ lines.append(" Changes:")
114
+ for key, value in sorted(pass_metrics.metrics.items()):
115
+ if value > 0:
116
+ lines.append(f" - {key}: {value}")
117
+
118
+ # Calculate improvements
119
+ improvements = []
120
+ for key in pass_metrics.before_stats:
121
+ if key in pass_metrics.after_stats:
122
+ before = pass_metrics.before_stats[key]
123
+ after = pass_metrics.after_stats[key]
124
+ if before != after:
125
+ improvement = pass_metrics.get_improvement(key)
126
+ improvements.append((key, before, after, improvement))
127
+
128
+ if improvements:
129
+ lines.append(" Impact:")
130
+ for key, before, after, improvement in improvements:
131
+ if improvement > 0:
132
+ lines.append(f" - {key}: {before} → {after} (-{improvement:.1f}%)")
133
+ else:
134
+ lines.append(f" - {key}: {before} → {after} (+{-improvement:.1f}%)")
135
+
136
+ # Function metrics
137
+ if metrics.function_metrics:
138
+ lines.append("")
139
+ lines.append("=" * 70)
140
+ lines.append("FUNCTION-LEVEL STATISTICS")
141
+ lines.append("=" * 70)
142
+
143
+ for func_name, func_metrics in metrics.function_metrics.items():
144
+ lines.append("")
145
+ lines.append(f"Function: {func_name}")
146
+ lines.append("-" * 30)
147
+ for key, value in sorted(func_metrics.items()):
148
+ lines.append(f" {key:20} {value}")
149
+
150
+ lines.append("")
151
+ lines.append("=" * 70)
152
+ return "\n".join(lines)
153
+
154
+
155
+ class HTMLReportFormatter(ReportFormatter):
156
+ """Formats reports as HTML."""
157
+
158
+ def format(self, metrics: ModuleMetrics) -> str:
159
+ """Format metrics as HTML report.
160
+
161
+ Args:
162
+ metrics: Module metrics.
163
+
164
+ Returns:
165
+ HTML report.
166
+ """
167
+ summary = metrics.get_summary()
168
+
169
+ html = []
170
+ html.append("<!DOCTYPE html>")
171
+ html.append("<html>")
172
+ html.append("<head>")
173
+ html.append("<title>Optimization Report</title>")
174
+ html.append("<style>")
175
+ html.append(
176
+ """
177
+ body { font-family: monospace; margin: 20px; }
178
+ h1 { color: #333; }
179
+ h2 { color: #666; border-bottom: 2px solid #ddd; }
180
+ table { border-collapse: collapse; width: 100%; margin: 20px 0; }
181
+ th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
182
+ th { background-color: #f2f2f2; }
183
+ .improvement { color: green; font-weight: bold; }
184
+ .regression { color: red; font-weight: bold; }
185
+ .metric { background-color: #f9f9f9; }
186
+ .pass-header { background-color: #e9e9e9; font-weight: bold; }
187
+ """
188
+ )
189
+ html.append("</style>")
190
+ html.append("</head>")
191
+ html.append("<body>")
192
+
193
+ # Header
194
+ html.append(f"<h1>Optimization Report - {summary['module_name']}</h1>")
195
+
196
+ # Summary
197
+ html.append("<h2>Summary</h2>")
198
+ html.append("<table>")
199
+ html.append(f"<tr><td>Optimization Level</td><td>{summary['optimization_level']}</td></tr>")
200
+ html.append(f"<tr><td>Total Passes</td><td>{summary['total_passes']}</td></tr>")
201
+ html.append(f"<tr><td>Total Time</td><td>{summary['total_time_ms']:.2f}ms</td></tr>")
202
+ html.append("</table>")
203
+
204
+ # Passes Applied
205
+ if summary["passes_applied"]:
206
+ html.append("<h2>Passes Applied</h2>")
207
+ html.append("<ol>")
208
+ for pass_name in summary["passes_applied"]:
209
+ html.append(f"<li>{pass_name}</li>")
210
+ html.append("</ol>")
211
+
212
+ # Improvements
213
+ if summary["improvements"]:
214
+ html.append("<h2>Overall Improvements</h2>")
215
+ html.append("<table>")
216
+ html.append("<tr><th>Metric</th><th>Improvement</th></tr>")
217
+ for metric, improvement in sorted(summary["improvements"].items()):
218
+ if improvement > 0:
219
+ html.append(f"<tr><td>{metric}</td><td class='improvement'>-{improvement:.1f}%</td></tr>")
220
+ elif improvement < 0:
221
+ html.append(f"<tr><td>{metric}</td><td class='regression'>+{-improvement:.1f}%</td></tr>")
222
+ html.append("</table>")
223
+
224
+ # Detailed Pass Statistics
225
+ if metrics.pass_metrics:
226
+ html.append("<h2>Detailed Pass Statistics</h2>")
227
+ html.append("<table>")
228
+ html.append("<tr><th>Pass</th><th>Phase</th><th>Time (ms)</th><th>Metrics</th></tr>")
229
+
230
+ for pass_metrics in metrics.pass_metrics:
231
+ metrics_str = ", ".join(f"{k}: {v}" for k, v in pass_metrics.metrics.items() if v > 0)
232
+ html.append("<tr>")
233
+ html.append(f"<td>{pass_metrics.pass_name}</td>")
234
+ html.append(f"<td>{pass_metrics.phase}</td>")
235
+ html.append(f"<td>{pass_metrics.time_ms:.2f}</td>")
236
+ html.append(f"<td>{metrics_str or 'N/A'}</td>")
237
+ html.append("</tr>")
238
+
239
+ html.append("</table>")
240
+
241
+ html.append("</body>")
242
+ html.append("</html>")
243
+
244
+ return "\n".join(html)
245
+
246
+
247
+ class JSONReportFormatter(ReportFormatter):
248
+ """Formats reports as JSON."""
249
+
250
+ def format(self, metrics: ModuleMetrics) -> str:
251
+ """Format metrics as JSON report.
252
+
253
+ Args:
254
+ metrics: Module metrics.
255
+
256
+ Returns:
257
+ JSON report.
258
+ """
259
+ data: dict[str, Any] = {
260
+ "module_name": metrics.module_name,
261
+ "optimization_level": metrics.optimization_level,
262
+ "total_time_ms": metrics.total_time_ms,
263
+ "summary": metrics.get_summary(),
264
+ "passes": [],
265
+ "functions": metrics.function_metrics,
266
+ }
267
+
268
+ # Add detailed pass information
269
+ for pass_metrics in metrics.pass_metrics:
270
+ pass_data: dict[str, Any] = {
271
+ "name": pass_metrics.pass_name,
272
+ "phase": pass_metrics.phase,
273
+ "time_ms": pass_metrics.time_ms,
274
+ "metrics": pass_metrics.metrics,
275
+ "before_stats": pass_metrics.before_stats,
276
+ "after_stats": pass_metrics.after_stats,
277
+ "improvements": {},
278
+ }
279
+
280
+ # Calculate improvements
281
+ for key in pass_metrics.before_stats:
282
+ if key in pass_metrics.after_stats:
283
+ improvement = pass_metrics.get_improvement(key)
284
+ if improvement != 0:
285
+ pass_data["improvements"][key] = improvement
286
+
287
+ data["passes"].append(pass_data)
288
+
289
+ return json.dumps(data, indent=2)
@@ -0,0 +1,342 @@
1
+ """SSA (Static Single Assignment) construction for MIR.
2
+
3
+ This module implements SSA construction with dominance frontier calculation
4
+ and phi node insertion for the MIR representation.
5
+ """
6
+
7
+ from collections import OrderedDict, defaultdict
8
+
9
+ from machine_dialect.mir.basic_block import CFG, BasicBlock
10
+ from machine_dialect.mir.mir_function import MIRFunction
11
+ from machine_dialect.mir.mir_instructions import Copy, LoadConst, LoadVar, MIRInstruction, Phi, StoreVar
12
+ from machine_dialect.mir.mir_values import Variable
13
+
14
+
15
+ class DominanceInfo:
16
+ """Dominance information for a control flow graph."""
17
+
18
+ def __init__(self, cfg: CFG) -> None:
19
+ """Initialize dominance information.
20
+
21
+ Args:
22
+ cfg: The control flow graph to analyze.
23
+ """
24
+ self.cfg = cfg
25
+ self.dominators: dict[BasicBlock, set[BasicBlock]] = {}
26
+ self.immediate_dominators: dict[BasicBlock, BasicBlock | None] = {}
27
+ self.dominance_frontier: dict[BasicBlock, set[BasicBlock]] = {}
28
+ self.dominator_tree_children: dict[BasicBlock, set[BasicBlock]] = defaultdict(set)
29
+
30
+ self._compute_dominators()
31
+ self._compute_immediate_dominators()
32
+ self._compute_dominance_frontier()
33
+
34
+ def _compute_dominators(self) -> None:
35
+ """Compute dominators for all blocks using iterative algorithm."""
36
+ entry = self.cfg.entry_block
37
+ if not entry:
38
+ return
39
+
40
+ # Initialize dominators
41
+ blocks = list(self.cfg.blocks.values())
42
+ self.dominators[entry] = {entry}
43
+
44
+ # All other blocks are initially dominated by all blocks
45
+ for block in blocks:
46
+ if block != entry:
47
+ self.dominators[block] = set(blocks)
48
+
49
+ # Iterate until fixed point
50
+ changed = True
51
+ while changed:
52
+ changed = False
53
+ for block in blocks:
54
+ if block == entry:
55
+ continue
56
+
57
+ # Compute new dominators
58
+ new_doms = set(blocks)
59
+ for pred in block.predecessors:
60
+ if pred in self.dominators:
61
+ new_doms &= self.dominators[pred]
62
+ new_doms.add(block)
63
+
64
+ # Check if changed
65
+ if new_doms != self.dominators[block]:
66
+ self.dominators[block] = new_doms
67
+ changed = True
68
+
69
+ def _compute_immediate_dominators(self) -> None:
70
+ """Compute immediate dominators from dominator sets."""
71
+ for block in self.dominators:
72
+ # Immediate dominator is the unique dominator that doesn't
73
+ # dominate any other dominators
74
+ doms = self.dominators[block] - {block}
75
+ if not doms:
76
+ self.immediate_dominators[block] = None
77
+ continue
78
+
79
+ # Find the immediate dominator
80
+ idom = None
81
+ for dom in doms:
82
+ # Check if dom dominates any other dominator
83
+ is_immediate = True
84
+ for other in doms:
85
+ if other != dom and dom in self.dominators.get(other, set()):
86
+ is_immediate = False
87
+ break
88
+ if is_immediate:
89
+ idom = dom
90
+ break
91
+
92
+ self.immediate_dominators[block] = idom
93
+ if idom:
94
+ self.dominator_tree_children[idom].add(block)
95
+
96
+ def _compute_dominance_frontier(self) -> None:
97
+ """Compute dominance frontier for all blocks."""
98
+ # Initialize empty frontiers
99
+ for block in self.dominators:
100
+ self.dominance_frontier[block] = set()
101
+
102
+ # For each block
103
+ for block in self.dominators:
104
+ # Check each successor
105
+ for succ in block.successors:
106
+ # Walk up dominator tree from block
107
+ runner: BasicBlock | None = block
108
+ while runner and runner != self.immediate_dominators.get(succ):
109
+ self.dominance_frontier[runner].add(succ)
110
+ runner = self.immediate_dominators.get(runner)
111
+
112
+ def dominates(self, a: BasicBlock, b: BasicBlock) -> bool:
113
+ """Check if block a dominates block b.
114
+
115
+ Args:
116
+ a: Potential dominator block.
117
+ b: Block to check.
118
+
119
+ Returns:
120
+ True if a dominates b.
121
+ """
122
+ return a in self.dominators.get(b, set())
123
+
124
+ def strictly_dominates(self, a: BasicBlock, b: BasicBlock) -> bool:
125
+ """Check if block a strictly dominates block b.
126
+
127
+ Args:
128
+ a: Potential dominator block.
129
+ b: Block to check.
130
+
131
+ Returns:
132
+ True if a strictly dominates b (dominates and a != b).
133
+ """
134
+ return a != b and self.dominates(a, b)
135
+
136
+
137
+ class SSAConstructor:
138
+ """Constructs SSA form for MIR functions."""
139
+
140
+ def __init__(self, function: MIRFunction) -> None:
141
+ """Initialize SSA constructor.
142
+
143
+ Args:
144
+ function: The function to convert to SSA form.
145
+ """
146
+ self.function = function
147
+ self.dominance = DominanceInfo(function.cfg)
148
+ self.variable_definitions: dict[Variable, set[BasicBlock]] = defaultdict(set)
149
+ self.variable_uses: dict[Variable, set[BasicBlock]] = defaultdict(set)
150
+ self.phi_nodes: dict[tuple[BasicBlock, Variable], Phi] = {}
151
+ self.variable_stacks: dict[Variable, list[Variable]] = defaultdict(list)
152
+ self.version_counters: dict[str, int] = defaultdict(int)
153
+
154
+ def construct_ssa(self) -> None:
155
+ """Convert the function to SSA form."""
156
+ self._collect_variable_info()
157
+ self._insert_phi_nodes()
158
+ self._rename_variables()
159
+
160
+ def _collect_variable_info(self) -> None:
161
+ """Collect information about variable definitions and uses."""
162
+ for block in self.function.cfg.blocks.values():
163
+ for inst in block.instructions:
164
+ # Check for variable definitions
165
+ for def_val in inst.get_defs():
166
+ if isinstance(def_val, Variable):
167
+ self.variable_definitions[def_val].add(block)
168
+
169
+ # Check for variable uses
170
+ for use_val in inst.get_uses():
171
+ if isinstance(use_val, Variable):
172
+ self.variable_uses[use_val].add(block)
173
+
174
+ def _insert_phi_nodes(self) -> None:
175
+ """Insert phi nodes at dominance frontiers."""
176
+ # For each variable
177
+ for var in self.variable_definitions:
178
+ # Get blocks where variable is defined
179
+ def_blocks = self.variable_definitions[var]
180
+
181
+ # Compute iterated dominance frontier
182
+ worklist = list(def_blocks)
183
+ phi_blocks = set()
184
+ processed = set()
185
+
186
+ while worklist:
187
+ block = worklist.pop()
188
+ if block in processed:
189
+ continue
190
+ processed.add(block)
191
+
192
+ # Add phi nodes at dominance frontier
193
+ for df_block in self.dominance.dominance_frontier.get(block, set()):
194
+ if df_block not in phi_blocks:
195
+ phi_blocks.add(df_block)
196
+
197
+ # Create phi node
198
+ phi_var = self._new_version(var)
199
+ # TODO: Review if (0, 0) is the best approach for generated phi nodes' source location
200
+ phi = Phi(phi_var, [], (0, 0)) # Default source location for generated phi nodes
201
+
202
+ # Insert phi in phi_nodes list
203
+ df_block.phi_nodes.append(phi)
204
+ self.phi_nodes[(df_block, var)] = phi
205
+
206
+ # Phi node is also a definition
207
+ if df_block not in def_blocks:
208
+ worklist.append(df_block)
209
+
210
+ def _rename_variables(self) -> None:
211
+ """Rename variables to SSA form."""
212
+ entry = self.function.cfg.entry_block
213
+ if entry:
214
+ self._rename_block(entry, set())
215
+
216
+ def _rename_block(self, block: BasicBlock, visited: set[BasicBlock]) -> None:
217
+ """Rename variables in a block and its dominated blocks.
218
+
219
+ Args:
220
+ block: The block to process.
221
+ visited: Set of already visited blocks.
222
+ """
223
+ if block in visited:
224
+ return
225
+ visited.add(block)
226
+
227
+ # Save stack state
228
+ stack_state: dict[Variable, int] = {}
229
+ for var in self.variable_stacks:
230
+ stack_state[var] = len(self.variable_stacks[var])
231
+
232
+ # Process phi nodes first
233
+ for phi in block.phi_nodes:
234
+ # Find original variable for this phi
235
+ for (phi_block, var), stored_phi in self.phi_nodes.items():
236
+ if phi_block == block and stored_phi == phi:
237
+ # Push new version (phi.dest is MIRValue but should be Variable)
238
+ if isinstance(phi.dest, Variable):
239
+ self.variable_stacks[var].append(phi.dest)
240
+ break
241
+
242
+ # Rebuild instruction list, preserving LoadConst and other non-Variable instructions
243
+ new_instructions: list[MIRInstruction] = []
244
+ temp_definitions = OrderedDict() # Track LoadConst for ordering
245
+
246
+ # Rename uses and definitions
247
+ for inst in block.instructions:
248
+ if isinstance(inst, Phi):
249
+ continue # Already handled in phi_nodes list
250
+
251
+ # Special handling for LoadConst - preserve as-is
252
+ if isinstance(inst, LoadConst):
253
+ # LoadConst defines a Temp, not a Variable, so don't rename
254
+ # Just preserve the instruction
255
+ new_instructions.append(inst)
256
+ if hasattr(inst.dest, "name"):
257
+ temp_definitions[inst.dest] = inst
258
+ continue
259
+
260
+ # Rename uses for Variable-based instructions
261
+ if isinstance(inst, StoreVar):
262
+ # Special case: StoreVar uses source, defines var
263
+ if isinstance(inst.source, Variable):
264
+ if self.variable_stacks[inst.source]:
265
+ inst.source = self.variable_stacks[inst.source][-1]
266
+ elif isinstance(inst, LoadVar):
267
+ # Special case: LoadVar uses var, defines dest
268
+ if self.variable_stacks[inst.var]:
269
+ inst.var = self.variable_stacks[inst.var][-1]
270
+ else:
271
+ # General case: rename all uses
272
+ for use_val in inst.get_uses():
273
+ if isinstance(use_val, Variable):
274
+ if self.variable_stacks[use_val]:
275
+ inst.replace_use(use_val, self.variable_stacks[use_val][-1])
276
+
277
+ # Rename definitions
278
+ for def_val in inst.get_defs():
279
+ if isinstance(def_val, Variable):
280
+ new_var = self._new_version(def_val)
281
+ if isinstance(inst, StoreVar):
282
+ inst.var = new_var
283
+ elif isinstance(inst, Copy) and inst.dest == def_val:
284
+ inst.dest = new_var
285
+ # Push new version
286
+ self.variable_stacks[def_val].append(new_var)
287
+
288
+ new_instructions.append(inst)
289
+
290
+ # Replace the instruction list with the rebuilt one
291
+ block.instructions = new_instructions
292
+
293
+ # Update phi nodes in successors
294
+ for succ in block.successors:
295
+ # Phi nodes are now in the phi_nodes list, not instructions
296
+ for phi in succ.phi_nodes:
297
+ # Find original variable for this phi
298
+ for (phi_block, var), stored_phi in self.phi_nodes.items():
299
+ if phi_block == succ and stored_phi == phi:
300
+ # Add incoming value from this block
301
+ if self.variable_stacks[var]:
302
+ phi.add_incoming(
303
+ self.variable_stacks[var][-1],
304
+ block.label,
305
+ )
306
+ break
307
+
308
+ # Process dominated blocks
309
+ for child in self.dominance.dominator_tree_children.get(block, set()):
310
+ self._rename_block(child, visited)
311
+
312
+ # Restore stack state
313
+ for var, old_size in stack_state.items():
314
+ while len(self.variable_stacks[var]) > old_size:
315
+ self.variable_stacks[var].pop()
316
+
317
+ def _new_version(self, var: Variable) -> Variable:
318
+ """Create a new SSA version of a variable.
319
+
320
+ Args:
321
+ var: The original variable.
322
+
323
+ Returns:
324
+ A new versioned variable.
325
+ """
326
+ base_name = var.name
327
+ version = self.version_counters[base_name]
328
+ self.version_counters[base_name] += 1
329
+
330
+ # Create new variable with version number
331
+ new_var = Variable(base_name, var.type, version=version)
332
+ return new_var
333
+
334
+
335
+ def construct_ssa(function: MIRFunction) -> None:
336
+ """Convert a MIR function to SSA form.
337
+
338
+ Args:
339
+ function: The function to convert.
340
+ """
341
+ constructor = SSAConstructor(function)
342
+ constructor.construct_ssa()
@@ -0,0 +1 @@
1
+ """Tests for Machine Dialectâ„¢ MIR."""