zexus 1.6.2

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 (227) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +2513 -0
  3. package/bin/zexus +2 -0
  4. package/bin/zpics +2 -0
  5. package/bin/zpm +2 -0
  6. package/bin/zx +2 -0
  7. package/bin/zx-deploy +2 -0
  8. package/bin/zx-dev +2 -0
  9. package/bin/zx-run +2 -0
  10. package/package.json +66 -0
  11. package/scripts/README.md +24 -0
  12. package/scripts/postinstall.js +44 -0
  13. package/shared_config.json +24 -0
  14. package/src/README.md +1525 -0
  15. package/src/tests/run_zexus_tests.py +117 -0
  16. package/src/tests/test_all_phases.zx +346 -0
  17. package/src/tests/test_blockchain_features.zx +306 -0
  18. package/src/tests/test_complexity_features.zx +321 -0
  19. package/src/tests/test_core_integration.py +185 -0
  20. package/src/tests/test_phase10_ecosystem.zx +177 -0
  21. package/src/tests/test_phase1_modifiers.zx +87 -0
  22. package/src/tests/test_phase2_plugins.zx +80 -0
  23. package/src/tests/test_phase3_security.zx +97 -0
  24. package/src/tests/test_phase4_vfs.zx +116 -0
  25. package/src/tests/test_phase5_types.zx +117 -0
  26. package/src/tests/test_phase6_metaprogramming.zx +125 -0
  27. package/src/tests/test_phase7_optimization.zx +132 -0
  28. package/src/tests/test_phase9_advanced_types.zx +157 -0
  29. package/src/tests/test_security_features.py +419 -0
  30. package/src/tests/test_security_features.zx +276 -0
  31. package/src/tests/test_simple_zx.zx +1 -0
  32. package/src/tests/test_verification_simple.zx +69 -0
  33. package/src/zexus/__init__.py +28 -0
  34. package/src/zexus/__main__.py +5 -0
  35. package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
  36. package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
  37. package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
  38. package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
  39. package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
  40. package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
  41. package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
  42. package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
  43. package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
  44. package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
  45. package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
  46. package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
  47. package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
  48. package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
  49. package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
  50. package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
  51. package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
  52. package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
  53. package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
  54. package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
  55. package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
  56. package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
  57. package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
  58. package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
  59. package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
  60. package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  61. package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
  62. package/src/zexus/advanced_types.py +401 -0
  63. package/src/zexus/blockchain/__init__.py +40 -0
  64. package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
  65. package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
  66. package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
  67. package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
  68. package/src/zexus/blockchain/crypto.py +463 -0
  69. package/src/zexus/blockchain/ledger.py +255 -0
  70. package/src/zexus/blockchain/transaction.py +267 -0
  71. package/src/zexus/builtin_modules.py +284 -0
  72. package/src/zexus/builtin_plugins.py +317 -0
  73. package/src/zexus/capability_system.py +372 -0
  74. package/src/zexus/cli/__init__.py +2 -0
  75. package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
  76. package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
  77. package/src/zexus/cli/main.py +707 -0
  78. package/src/zexus/cli/zpm.py +203 -0
  79. package/src/zexus/compare_interpreter_compiler.py +146 -0
  80. package/src/zexus/compiler/__init__.py +169 -0
  81. package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
  82. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  83. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  84. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  85. package/src/zexus/compiler/bytecode.py +266 -0
  86. package/src/zexus/compiler/compat_runtime.py +277 -0
  87. package/src/zexus/compiler/lexer.py +257 -0
  88. package/src/zexus/compiler/parser.py +779 -0
  89. package/src/zexus/compiler/semantic.py +118 -0
  90. package/src/zexus/compiler/zexus_ast.py +454 -0
  91. package/src/zexus/complexity_system.py +575 -0
  92. package/src/zexus/concurrency_system.py +493 -0
  93. package/src/zexus/config.py +201 -0
  94. package/src/zexus/crypto_bridge.py +19 -0
  95. package/src/zexus/dependency_injection.py +423 -0
  96. package/src/zexus/ecosystem.py +434 -0
  97. package/src/zexus/environment.py +101 -0
  98. package/src/zexus/environment_manager.py +119 -0
  99. package/src/zexus/error_reporter.py +314 -0
  100. package/src/zexus/evaluator/__init__.py +12 -0
  101. package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  103. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  104. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  105. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  106. package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
  107. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  108. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  109. package/src/zexus/evaluator/bytecode_compiler.py +700 -0
  110. package/src/zexus/evaluator/core.py +891 -0
  111. package/src/zexus/evaluator/expressions.py +827 -0
  112. package/src/zexus/evaluator/functions.py +3989 -0
  113. package/src/zexus/evaluator/integration.py +396 -0
  114. package/src/zexus/evaluator/statements.py +4303 -0
  115. package/src/zexus/evaluator/utils.py +126 -0
  116. package/src/zexus/evaluator_original.py +2041 -0
  117. package/src/zexus/external_bridge.py +16 -0
  118. package/src/zexus/find_affected_imports.sh +155 -0
  119. package/src/zexus/hybrid_orchestrator.py +152 -0
  120. package/src/zexus/input_validation.py +259 -0
  121. package/src/zexus/lexer.py +571 -0
  122. package/src/zexus/logging.py +89 -0
  123. package/src/zexus/lsp/__init__.py +9 -0
  124. package/src/zexus/lsp/completion_provider.py +207 -0
  125. package/src/zexus/lsp/definition_provider.py +22 -0
  126. package/src/zexus/lsp/hover_provider.py +71 -0
  127. package/src/zexus/lsp/server.py +269 -0
  128. package/src/zexus/lsp/symbol_provider.py +31 -0
  129. package/src/zexus/metaprogramming.py +321 -0
  130. package/src/zexus/module_cache.py +89 -0
  131. package/src/zexus/module_manager.py +107 -0
  132. package/src/zexus/object.py +973 -0
  133. package/src/zexus/optimization.py +424 -0
  134. package/src/zexus/parser/__init__.py +31 -0
  135. package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
  136. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  137. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  138. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  139. package/src/zexus/parser/integration.py +86 -0
  140. package/src/zexus/parser/parser.py +3977 -0
  141. package/src/zexus/parser/strategy_context.py +7254 -0
  142. package/src/zexus/parser/strategy_structural.py +1033 -0
  143. package/src/zexus/persistence.py +391 -0
  144. package/src/zexus/plugin_system.py +290 -0
  145. package/src/zexus/policy_engine.py +365 -0
  146. package/src/zexus/profiler/__init__.py +5 -0
  147. package/src/zexus/profiler/profiler.py +233 -0
  148. package/src/zexus/purity_system.py +398 -0
  149. package/src/zexus/runtime/__init__.py +20 -0
  150. package/src/zexus/runtime/async_runtime.py +324 -0
  151. package/src/zexus/search_old_imports.sh +65 -0
  152. package/src/zexus/security.py +1407 -0
  153. package/src/zexus/stack_trace.py +233 -0
  154. package/src/zexus/stdlib/__init__.py +27 -0
  155. package/src/zexus/stdlib/blockchain.py +341 -0
  156. package/src/zexus/stdlib/compression.py +167 -0
  157. package/src/zexus/stdlib/crypto.py +124 -0
  158. package/src/zexus/stdlib/datetime.py +163 -0
  159. package/src/zexus/stdlib/db_mongo.py +199 -0
  160. package/src/zexus/stdlib/db_mysql.py +162 -0
  161. package/src/zexus/stdlib/db_postgres.py +163 -0
  162. package/src/zexus/stdlib/db_sqlite.py +133 -0
  163. package/src/zexus/stdlib/encoding.py +230 -0
  164. package/src/zexus/stdlib/fs.py +195 -0
  165. package/src/zexus/stdlib/http.py +219 -0
  166. package/src/zexus/stdlib/http_server.py +248 -0
  167. package/src/zexus/stdlib/json_module.py +61 -0
  168. package/src/zexus/stdlib/math.py +360 -0
  169. package/src/zexus/stdlib/os_module.py +265 -0
  170. package/src/zexus/stdlib/regex.py +148 -0
  171. package/src/zexus/stdlib/sockets.py +253 -0
  172. package/src/zexus/stdlib/test_framework.zx +208 -0
  173. package/src/zexus/stdlib/test_runner.zx +119 -0
  174. package/src/zexus/stdlib_integration.py +341 -0
  175. package/src/zexus/strategy_recovery.py +256 -0
  176. package/src/zexus/syntax_validator.py +356 -0
  177. package/src/zexus/testing/zpics.py +407 -0
  178. package/src/zexus/testing/zpics_runtime.py +369 -0
  179. package/src/zexus/type_system.py +374 -0
  180. package/src/zexus/validation_system.py +569 -0
  181. package/src/zexus/virtual_filesystem.py +355 -0
  182. package/src/zexus/vm/__init__.py +8 -0
  183. package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
  184. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  185. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  186. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  187. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  188. package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
  189. package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
  190. package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
  191. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  192. package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
  193. package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
  194. package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
  195. package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
  196. package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
  197. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  198. package/src/zexus/vm/async_optimizer.py +420 -0
  199. package/src/zexus/vm/bytecode.py +428 -0
  200. package/src/zexus/vm/bytecode_converter.py +297 -0
  201. package/src/zexus/vm/cache.py +532 -0
  202. package/src/zexus/vm/jit.py +720 -0
  203. package/src/zexus/vm/memory_manager.py +520 -0
  204. package/src/zexus/vm/memory_pool.py +511 -0
  205. package/src/zexus/vm/optimizer.py +478 -0
  206. package/src/zexus/vm/parallel_vm.py +899 -0
  207. package/src/zexus/vm/peephole_optimizer.py +452 -0
  208. package/src/zexus/vm/profiler.py +527 -0
  209. package/src/zexus/vm/register_allocator.py +462 -0
  210. package/src/zexus/vm/register_vm.py +520 -0
  211. package/src/zexus/vm/ssa_converter.py +757 -0
  212. package/src/zexus/vm/vm.py +1392 -0
  213. package/src/zexus/zexus_ast.py +1782 -0
  214. package/src/zexus/zexus_token.py +253 -0
  215. package/src/zexus/zpm/__init__.py +15 -0
  216. package/src/zexus/zpm/installer.py +116 -0
  217. package/src/zexus/zpm/package_manager.py +208 -0
  218. package/src/zexus/zpm/publisher.py +98 -0
  219. package/src/zexus/zpm/registry.py +110 -0
  220. package/src/zexus.egg-info/PKG-INFO +2235 -0
  221. package/src/zexus.egg-info/SOURCES.txt +876 -0
  222. package/src/zexus.egg-info/dependency_links.txt +1 -0
  223. package/src/zexus.egg-info/entry_points.txt +3 -0
  224. package/src/zexus.egg-info/not-zip-safe +1 -0
  225. package/src/zexus.egg-info/requires.txt +14 -0
  226. package/src/zexus.egg-info/top_level.txt +2 -0
  227. package/zexus.json +14 -0
@@ -0,0 +1,462 @@
1
+ """
2
+ Register Allocator for Zexus Register VM
3
+
4
+ Implements graph coloring register allocation with:
5
+ - Live range analysis
6
+ - Interference graph construction
7
+ - Graph coloring with spilling
8
+ - Register coalescing
9
+ - Optimized register assignment
10
+
11
+ Phase 8.5 of VM Optimization Project
12
+ """
13
+
14
+ from dataclasses import dataclass, field
15
+ from typing import Dict, List, Set, Tuple, Optional, Any
16
+ from collections import defaultdict
17
+ from enum import Enum
18
+
19
+
20
+ class RegisterType(Enum):
21
+ """Register types"""
22
+ GENERAL = 0 # General purpose registers
23
+ TEMP = 1 # Temporary registers
24
+ ARGUMENT = 2 # Function argument registers
25
+ RETURN = 3 # Return value registers
26
+
27
+
28
+ @dataclass
29
+ class LiveRange:
30
+ """Live range for a variable"""
31
+ variable: str
32
+ start: int
33
+ end: int
34
+ uses: List[int] = field(default_factory=list)
35
+ defs: List[int] = field(default_factory=list)
36
+
37
+ def overlaps(self, other: 'LiveRange') -> bool:
38
+ """Check if this live range overlaps with another"""
39
+ return not (self.end < other.start or other.end < self.start)
40
+
41
+ def __hash__(self):
42
+ return hash((self.variable, self.start, self.end))
43
+
44
+
45
+ @dataclass
46
+ class InterferenceGraph:
47
+ """Graph representing register interference"""
48
+ nodes: Set[str] = field(default_factory=set)
49
+ edges: Dict[str, Set[str]] = field(default_factory=lambda: defaultdict(set))
50
+
51
+ def add_node(self, var: str):
52
+ """Add a node (variable) to the graph"""
53
+ self.nodes.add(var)
54
+ if var not in self.edges:
55
+ self.edges[var] = set()
56
+
57
+ def add_edge(self, var1: str, var2: str):
58
+ """Add an interference edge between two variables"""
59
+ self.add_node(var1)
60
+ self.add_node(var2)
61
+ self.edges[var1].add(var2)
62
+ self.edges[var2].add(var1)
63
+
64
+ def degree(self, var: str) -> int:
65
+ """Get the degree (number of neighbors) of a variable"""
66
+ return len(self.edges.get(var, set()))
67
+
68
+ def neighbors(self, var: str) -> Set[str]:
69
+ """Get neighbors of a variable"""
70
+ return self.edges.get(var, set())
71
+
72
+ def remove_node(self, var: str):
73
+ """Remove a node from the graph"""
74
+ if var in self.nodes:
75
+ self.nodes.remove(var)
76
+
77
+ # Remove edges
78
+ neighbors = self.edges.get(var, set())
79
+ for neighbor in neighbors:
80
+ self.edges[neighbor].discard(var)
81
+
82
+ if var in self.edges:
83
+ del self.edges[var]
84
+
85
+
86
+ @dataclass
87
+ class AllocationResult:
88
+ """Result of register allocation"""
89
+ allocation: Dict[str, int] # Variable -> Register mapping
90
+ spilled: Set[str] # Variables that had to be spilled to memory
91
+ num_registers_used: int
92
+ coalesced_moves: int = 0
93
+
94
+
95
+ class RegisterAllocator:
96
+ """
97
+ Graph coloring register allocator
98
+
99
+ Uses the classic graph coloring algorithm with improvements:
100
+ - Chaitin-Briggs coloring with optimistic spilling
101
+ - Coalescing of move-related variables
102
+ - Biased coloring for better cache locality
103
+ - Spill cost minimization
104
+ """
105
+
106
+ def __init__(self, num_registers: int = 16, num_temp_registers: int = 8):
107
+ """
108
+ Initialize register allocator
109
+
110
+ Args:
111
+ num_registers: Number of general-purpose registers available
112
+ num_temp_registers: Number of temporary registers
113
+ """
114
+ self.num_registers = num_registers
115
+ self.num_temp_registers = num_temp_registers
116
+ self.total_registers = num_registers + num_temp_registers
117
+
118
+ # Reserved registers
119
+ self.reserved = {0, 1} # R0 (zero), R1 (stack pointer)
120
+ self.available_registers = set(range(2, self.num_registers))
121
+ self.temp_registers = set(range(self.num_registers, self.total_registers))
122
+
123
+ # Statistics
124
+ self.stats = {
125
+ 'allocations': 0,
126
+ 'spills': 0,
127
+ 'coalesced_moves': 0,
128
+ 'colorings': 0,
129
+ }
130
+
131
+ def allocate(
132
+ self,
133
+ instructions: List[Tuple],
134
+ live_ranges: Dict[str, LiveRange]
135
+ ) -> AllocationResult:
136
+ """
137
+ Allocate registers for variables
138
+
139
+ Args:
140
+ instructions: List of instructions
141
+ live_ranges: Live ranges for all variables
142
+
143
+ Returns:
144
+ AllocationResult with allocation and spilled variables
145
+ """
146
+ self.stats['allocations'] += 1
147
+
148
+ # Build interference graph
149
+ interference_graph = self._build_interference_graph(live_ranges)
150
+
151
+ # Find move-related variables for coalescing
152
+ move_pairs = self._find_move_pairs(instructions)
153
+
154
+ # Coalesce moves when possible
155
+ coalesced = self._coalesce_moves(interference_graph, move_pairs)
156
+
157
+ # Color the graph
158
+ allocation, spilled = self._color_graph(
159
+ interference_graph,
160
+ self.available_registers
161
+ )
162
+
163
+ return AllocationResult(
164
+ allocation=allocation,
165
+ spilled=spilled,
166
+ num_registers_used=len(set(allocation.values())),
167
+ coalesced_moves=coalesced
168
+ )
169
+
170
+ def _build_interference_graph(
171
+ self,
172
+ live_ranges: Dict[str, LiveRange]
173
+ ) -> InterferenceGraph:
174
+ """
175
+ Build interference graph from live ranges
176
+
177
+ Two variables interfere if their live ranges overlap
178
+ """
179
+ graph = InterferenceGraph()
180
+
181
+ # Add all variables as nodes
182
+ for var in live_ranges:
183
+ graph.add_node(var)
184
+
185
+ # Add edges for interfering variables
186
+ variables = list(live_ranges.keys())
187
+ for i, var1 in enumerate(variables):
188
+ for var2 in variables[i + 1:]:
189
+ if live_ranges[var1].overlaps(live_ranges[var2]):
190
+ graph.add_edge(var1, var2)
191
+
192
+ return graph
193
+
194
+ def _find_move_pairs(self, instructions: List[Tuple]) -> List[Tuple[str, str]]:
195
+ """
196
+ Find pairs of variables related by move instructions
197
+
198
+ Args:
199
+ instructions: List of instructions (tuples or Instruction objects)
200
+
201
+ Returns:
202
+ List of (source, dest) variable pairs
203
+ """
204
+ move_pairs = []
205
+
206
+ # Normalize instructions
207
+ normalized = []
208
+ for instr in instructions:
209
+ if instr is None:
210
+ normalized.append(None)
211
+ elif hasattr(instr, 'opcode') and hasattr(instr, 'arg'):
212
+ normalized.append((instr.opcode, instr.arg))
213
+ else:
214
+ normalized.append(instr)
215
+
216
+ for instr in normalized:
217
+ if not instr or len(instr) < 2:
218
+ continue
219
+
220
+ opcode = instr[0]
221
+
222
+ # Detect move instructions (LOAD_FAST followed by STORE_FAST is a move)
223
+ if opcode == 'LOAD_FAST' and len(instr) >= 3:
224
+ source = instr[1]
225
+ dest = instr[2] if len(instr) > 2 else None
226
+ if source and dest and isinstance(source, str) and isinstance(dest, str):
227
+ move_pairs.append((source, dest))
228
+
229
+ # MOVE opcode
230
+ elif opcode == 'MOVE' and len(instr) >= 3:
231
+ source = instr[1]
232
+ dest = instr[2]
233
+ if isinstance(source, str) and isinstance(dest, str):
234
+ move_pairs.append((source, dest))
235
+
236
+ return move_pairs
237
+
238
+ def _coalesce_moves(
239
+ self,
240
+ graph: InterferenceGraph,
241
+ move_pairs: List[Tuple[str, str]]
242
+ ) -> int:
243
+ """
244
+ Coalesce move-related variables when possible
245
+
246
+ Two variables can be coalesced if:
247
+ 1. They are related by a move
248
+ 2. They don't interfere
249
+ 3. Coalescing won't make the graph uncolorable
250
+
251
+ Returns:
252
+ Number of moves coalesced
253
+ """
254
+ coalesced_count = 0
255
+
256
+ for source, dest in move_pairs:
257
+ # Check if both variables exist in graph
258
+ if source not in graph.nodes or dest not in graph.nodes:
259
+ continue
260
+
261
+ # Check if they interfere
262
+ if dest in graph.neighbors(source):
263
+ continue
264
+
265
+ # Check Briggs' conservative criterion:
266
+ # Coalescing is safe if the merged node has < K neighbors with degree >= K
267
+ combined_neighbors = graph.neighbors(source) | graph.neighbors(dest)
268
+ high_degree_neighbors = sum(
269
+ 1 for n in combined_neighbors
270
+ if graph.degree(n) >= self.num_registers
271
+ )
272
+
273
+ if high_degree_neighbors < self.num_registers:
274
+ # Safe to coalesce
275
+ self._merge_nodes(graph, source, dest)
276
+ coalesced_count += 1
277
+
278
+ self.stats['coalesced_moves'] += coalesced_count
279
+ return coalesced_count
280
+
281
+ def _merge_nodes(self, graph: InterferenceGraph, var1: str, var2: str):
282
+ """
283
+ Merge two nodes in the interference graph
284
+
285
+ Combines var1 and var2 into a single node (var1)
286
+ """
287
+ # Add all edges from var2 to var1
288
+ for neighbor in graph.neighbors(var2):
289
+ if neighbor != var1:
290
+ graph.add_edge(var1, neighbor)
291
+
292
+ # Remove var2
293
+ graph.remove_node(var2)
294
+
295
+ def _color_graph(
296
+ self,
297
+ graph: InterferenceGraph,
298
+ available_colors: Set[int]
299
+ ) -> Tuple[Dict[str, int], Set[str]]:
300
+ """
301
+ Color the interference graph using graph coloring algorithm
302
+
303
+ Uses Chaitin-Briggs algorithm with optimistic spilling.
304
+
305
+ Returns:
306
+ (allocation dict, set of spilled variables)
307
+ """
308
+ self.stats['colorings'] += 1
309
+
310
+ allocation = {}
311
+ spilled = set()
312
+ stack = []
313
+ remaining_graph = InterferenceGraph()
314
+ remaining_graph.nodes = graph.nodes.copy()
315
+ remaining_graph.edges = {k: v.copy() for k, v in graph.edges.items()}
316
+
317
+ # Simplification phase: remove nodes with degree < K
318
+ while remaining_graph.nodes:
319
+ # Find node with degree < K
320
+ low_degree_node = None
321
+ for node in remaining_graph.nodes:
322
+ if remaining_graph.degree(node) < len(available_colors):
323
+ low_degree_node = node
324
+ break
325
+
326
+ if low_degree_node:
327
+ # Remove and push to stack
328
+ stack.append((low_degree_node, remaining_graph.neighbors(low_degree_node).copy()))
329
+ remaining_graph.remove_node(low_degree_node)
330
+ else:
331
+ # Need to spill - choose node with highest degree
332
+ if not remaining_graph.nodes:
333
+ break
334
+
335
+ spill_node = max(remaining_graph.nodes, key=lambda n: remaining_graph.degree(n))
336
+ stack.append((spill_node, remaining_graph.neighbors(spill_node).copy()))
337
+ remaining_graph.remove_node(spill_node)
338
+ spilled.add(spill_node)
339
+ self.stats['spills'] += 1
340
+
341
+ # Coloring phase: assign colors from stack
342
+ while stack:
343
+ node, neighbors = stack.pop()
344
+
345
+ # Get colors used by neighbors
346
+ used_colors = {
347
+ allocation[n] for n in neighbors
348
+ if n in allocation
349
+ }
350
+
351
+ # Find available color
352
+ available = available_colors - used_colors
353
+
354
+ if available:
355
+ # Assign first available color
356
+ allocation[node] = min(available)
357
+ elif node not in spilled:
358
+ # Optimistic coloring failed - must spill
359
+ spilled.add(node)
360
+ self.stats['spills'] += 1
361
+
362
+ return allocation, spilled
363
+
364
+ def get_stats(self) -> Dict[str, Any]:
365
+ """Get allocation statistics"""
366
+ return self.stats.copy()
367
+
368
+ def reset_stats(self):
369
+ """Reset statistics"""
370
+ self.stats = {
371
+ 'allocations': 0,
372
+ 'spills': 0,
373
+ 'coalesced_moves': 0,
374
+ 'colorings': 0,
375
+ }
376
+
377
+
378
+ def compute_live_ranges(instructions: List[Tuple]) -> Dict[str, LiveRange]:
379
+ """
380
+ Compute live ranges for all variables in instructions
381
+
382
+ Args:
383
+ instructions: List of instructions (tuples or Instruction objects)
384
+
385
+ Returns:
386
+ Dictionary mapping variable names to their live ranges
387
+ """
388
+ live_ranges = {}
389
+
390
+ # Normalize instructions
391
+ normalized = []
392
+ for instr in instructions:
393
+ if instr is None:
394
+ normalized.append(None)
395
+ elif hasattr(instr, 'opcode') and hasattr(instr, 'arg'):
396
+ # Instruction object from peephole optimizer
397
+ normalized.append((instr.opcode, instr.arg))
398
+ else:
399
+ # Already a tuple
400
+ normalized.append(instr)
401
+
402
+ # First pass: find all def and use positions
403
+ for i, instr in enumerate(normalized):
404
+ if not instr or len(instr) < 2:
405
+ continue
406
+
407
+ opcode = instr[0]
408
+
409
+ # Extract variable uses and defs
410
+ defs, uses = _extract_vars(instr)
411
+
412
+ # Update live ranges
413
+ for var in defs:
414
+ if var not in live_ranges:
415
+ live_ranges[var] = LiveRange(variable=var, start=i, end=i)
416
+ live_ranges[var].defs.append(i)
417
+ live_ranges[var].end = max(live_ranges[var].end, i)
418
+
419
+ for var in uses:
420
+ if var not in live_ranges:
421
+ live_ranges[var] = LiveRange(variable=var, start=i, end=i)
422
+ live_ranges[var].uses.append(i)
423
+ live_ranges[var].start = min(live_ranges[var].start, i)
424
+ live_ranges[var].end = max(live_ranges[var].end, i)
425
+
426
+ return live_ranges
427
+
428
+
429
+ def _extract_vars(instr: Tuple) -> Tuple[List[str], List[str]]:
430
+ """
431
+ Extract variables defined and used in an instruction
432
+
433
+ Args:
434
+ instr: Instruction tuple
435
+
436
+ Returns:
437
+ (defs, uses) - lists of variable names
438
+ """
439
+ opcode = instr[0] if instr else None
440
+ defs = []
441
+ uses = []
442
+
443
+ # Simple heuristic: first arg is often dest, rest are sources
444
+ if opcode in ('LOAD_FAST', 'STORE_FAST'):
445
+ if len(instr) > 1 and isinstance(instr[1], str):
446
+ if opcode == 'STORE_FAST':
447
+ defs.append(instr[1])
448
+ else:
449
+ uses.append(instr[1])
450
+
451
+ elif opcode in ('BINARY_ADD', 'BINARY_SUB', 'BINARY_MUL', 'BINARY_DIV'):
452
+ # Typically: dest = src1 op src2
453
+ if len(instr) >= 4:
454
+ dest, src1, src2 = instr[1], instr[2], instr[3]
455
+ if isinstance(dest, str):
456
+ defs.append(dest)
457
+ if isinstance(src1, str):
458
+ uses.append(src1)
459
+ if isinstance(src2, str):
460
+ uses.append(src2)
461
+
462
+ return defs, uses