machine-dialect 0.1.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- machine_dialect/__main__.py +667 -0
- machine_dialect/agent/__init__.py +5 -0
- machine_dialect/agent/agent.py +360 -0
- machine_dialect/ast/__init__.py +95 -0
- machine_dialect/ast/ast_node.py +35 -0
- machine_dialect/ast/call_expression.py +82 -0
- machine_dialect/ast/dict_extraction.py +60 -0
- machine_dialect/ast/expressions.py +439 -0
- machine_dialect/ast/literals.py +309 -0
- machine_dialect/ast/program.py +35 -0
- machine_dialect/ast/statements.py +1433 -0
- machine_dialect/ast/tests/test_ast_string_representation.py +62 -0
- machine_dialect/ast/tests/test_boolean_literal.py +29 -0
- machine_dialect/ast/tests/test_collection_hir.py +138 -0
- machine_dialect/ast/tests/test_define_statement.py +142 -0
- machine_dialect/ast/tests/test_desugar.py +541 -0
- machine_dialect/ast/tests/test_foreach_desugar.py +245 -0
- machine_dialect/cfg/__init__.py +6 -0
- machine_dialect/cfg/config.py +156 -0
- machine_dialect/cfg/examples.py +221 -0
- machine_dialect/cfg/generate_with_ai.py +187 -0
- machine_dialect/cfg/openai_generation.py +200 -0
- machine_dialect/cfg/parser.py +94 -0
- machine_dialect/cfg/tests/__init__.py +1 -0
- machine_dialect/cfg/tests/test_cfg_parser.py +252 -0
- machine_dialect/cfg/tests/test_config.py +188 -0
- machine_dialect/cfg/tests/test_examples.py +391 -0
- machine_dialect/cfg/tests/test_generate_with_ai.py +354 -0
- machine_dialect/cfg/tests/test_openai_generation.py +256 -0
- machine_dialect/codegen/__init__.py +5 -0
- machine_dialect/codegen/bytecode_module.py +89 -0
- machine_dialect/codegen/bytecode_serializer.py +300 -0
- machine_dialect/codegen/opcodes.py +101 -0
- machine_dialect/codegen/register_codegen.py +1996 -0
- machine_dialect/codegen/symtab.py +208 -0
- machine_dialect/codegen/tests/__init__.py +1 -0
- machine_dialect/codegen/tests/test_array_operations_codegen.py +295 -0
- machine_dialect/codegen/tests/test_bytecode_serializer.py +185 -0
- machine_dialect/codegen/tests/test_register_codegen_ssa.py +324 -0
- machine_dialect/codegen/tests/test_symtab.py +418 -0
- machine_dialect/codegen/vm_serializer.py +621 -0
- machine_dialect/compiler/__init__.py +18 -0
- machine_dialect/compiler/compiler.py +197 -0
- machine_dialect/compiler/config.py +149 -0
- machine_dialect/compiler/context.py +149 -0
- machine_dialect/compiler/phases/__init__.py +19 -0
- machine_dialect/compiler/phases/bytecode_optimization.py +90 -0
- machine_dialect/compiler/phases/codegen.py +40 -0
- machine_dialect/compiler/phases/hir_generation.py +39 -0
- machine_dialect/compiler/phases/mir_generation.py +86 -0
- machine_dialect/compiler/phases/optimization.py +110 -0
- machine_dialect/compiler/phases/parsing.py +39 -0
- machine_dialect/compiler/pipeline.py +143 -0
- machine_dialect/compiler/tests/__init__.py +1 -0
- machine_dialect/compiler/tests/test_compiler.py +568 -0
- machine_dialect/compiler/vm_runner.py +173 -0
- machine_dialect/errors/__init__.py +32 -0
- machine_dialect/errors/exceptions.py +369 -0
- machine_dialect/errors/messages.py +82 -0
- machine_dialect/errors/tests/__init__.py +0 -0
- machine_dialect/errors/tests/test_expected_token_errors.py +188 -0
- machine_dialect/errors/tests/test_name_errors.py +118 -0
- machine_dialect/helpers/__init__.py +0 -0
- machine_dialect/helpers/stopwords.py +225 -0
- machine_dialect/helpers/validators.py +30 -0
- machine_dialect/lexer/__init__.py +9 -0
- machine_dialect/lexer/constants.py +23 -0
- machine_dialect/lexer/lexer.py +907 -0
- machine_dialect/lexer/tests/__init__.py +0 -0
- machine_dialect/lexer/tests/helpers.py +86 -0
- machine_dialect/lexer/tests/test_apostrophe_identifiers.py +122 -0
- machine_dialect/lexer/tests/test_backtick_identifiers.py +140 -0
- machine_dialect/lexer/tests/test_boolean_literals.py +108 -0
- machine_dialect/lexer/tests/test_case_insensitive_keywords.py +188 -0
- machine_dialect/lexer/tests/test_comments.py +200 -0
- machine_dialect/lexer/tests/test_double_asterisk_keywords.py +127 -0
- machine_dialect/lexer/tests/test_lexer_position.py +113 -0
- machine_dialect/lexer/tests/test_list_tokens.py +282 -0
- machine_dialect/lexer/tests/test_stopwords.py +80 -0
- machine_dialect/lexer/tests/test_strict_equality.py +129 -0
- machine_dialect/lexer/tests/test_token.py +41 -0
- machine_dialect/lexer/tests/test_tokenization.py +294 -0
- machine_dialect/lexer/tests/test_underscore_literals.py +343 -0
- machine_dialect/lexer/tests/test_url_literals.py +169 -0
- machine_dialect/lexer/tokens.py +487 -0
- machine_dialect/linter/__init__.py +10 -0
- machine_dialect/linter/__main__.py +144 -0
- machine_dialect/linter/linter.py +154 -0
- machine_dialect/linter/rules/__init__.py +8 -0
- machine_dialect/linter/rules/base.py +112 -0
- machine_dialect/linter/rules/statement_termination.py +99 -0
- machine_dialect/linter/tests/__init__.py +1 -0
- machine_dialect/linter/tests/mdrules/__init__.py +0 -0
- machine_dialect/linter/tests/mdrules/test_md101_statement_termination.py +181 -0
- machine_dialect/linter/tests/test_linter.py +81 -0
- machine_dialect/linter/tests/test_rules.py +110 -0
- machine_dialect/linter/tests/test_violations.py +71 -0
- machine_dialect/linter/violations.py +51 -0
- machine_dialect/mir/__init__.py +69 -0
- machine_dialect/mir/analyses/__init__.py +20 -0
- machine_dialect/mir/analyses/alias_analysis.py +315 -0
- machine_dialect/mir/analyses/dominance_analysis.py +49 -0
- machine_dialect/mir/analyses/escape_analysis.py +286 -0
- machine_dialect/mir/analyses/loop_analysis.py +272 -0
- machine_dialect/mir/analyses/tests/test_type_analysis.py +736 -0
- machine_dialect/mir/analyses/type_analysis.py +448 -0
- machine_dialect/mir/analyses/use_def_chains.py +232 -0
- machine_dialect/mir/basic_block.py +385 -0
- machine_dialect/mir/dataflow.py +445 -0
- machine_dialect/mir/debug_info.py +208 -0
- machine_dialect/mir/hir_to_mir.py +1738 -0
- machine_dialect/mir/mir_dumper.py +366 -0
- machine_dialect/mir/mir_function.py +167 -0
- machine_dialect/mir/mir_instructions.py +1877 -0
- machine_dialect/mir/mir_interpreter.py +556 -0
- machine_dialect/mir/mir_module.py +225 -0
- machine_dialect/mir/mir_printer.py +480 -0
- machine_dialect/mir/mir_transformer.py +410 -0
- machine_dialect/mir/mir_types.py +367 -0
- machine_dialect/mir/mir_validation.py +455 -0
- machine_dialect/mir/mir_values.py +268 -0
- machine_dialect/mir/optimization_config.py +233 -0
- machine_dialect/mir/optimization_pass.py +251 -0
- machine_dialect/mir/optimization_pipeline.py +355 -0
- machine_dialect/mir/optimizations/__init__.py +84 -0
- machine_dialect/mir/optimizations/algebraic_simplification.py +733 -0
- machine_dialect/mir/optimizations/branch_prediction.py +372 -0
- machine_dialect/mir/optimizations/constant_propagation.py +634 -0
- machine_dialect/mir/optimizations/cse.py +398 -0
- machine_dialect/mir/optimizations/dce.py +288 -0
- machine_dialect/mir/optimizations/inlining.py +551 -0
- machine_dialect/mir/optimizations/jump_threading.py +487 -0
- machine_dialect/mir/optimizations/licm.py +405 -0
- machine_dialect/mir/optimizations/loop_unrolling.py +366 -0
- machine_dialect/mir/optimizations/strength_reduction.py +422 -0
- machine_dialect/mir/optimizations/tail_call.py +207 -0
- machine_dialect/mir/optimizations/tests/test_loop_unrolling.py +483 -0
- machine_dialect/mir/optimizations/type_narrowing.py +397 -0
- machine_dialect/mir/optimizations/type_specialization.py +447 -0
- machine_dialect/mir/optimizations/type_specific.py +906 -0
- machine_dialect/mir/optimize_mir.py +89 -0
- machine_dialect/mir/pass_manager.py +391 -0
- machine_dialect/mir/profiling/__init__.py +26 -0
- machine_dialect/mir/profiling/profile_collector.py +318 -0
- machine_dialect/mir/profiling/profile_data.py +372 -0
- machine_dialect/mir/profiling/profile_reader.py +272 -0
- machine_dialect/mir/profiling/profile_writer.py +226 -0
- machine_dialect/mir/register_allocation.py +302 -0
- machine_dialect/mir/reporting/__init__.py +17 -0
- machine_dialect/mir/reporting/optimization_reporter.py +314 -0
- machine_dialect/mir/reporting/report_formatter.py +289 -0
- machine_dialect/mir/ssa_construction.py +342 -0
- machine_dialect/mir/tests/__init__.py +1 -0
- machine_dialect/mir/tests/test_algebraic_associativity.py +204 -0
- machine_dialect/mir/tests/test_algebraic_complex_patterns.py +221 -0
- machine_dialect/mir/tests/test_algebraic_division.py +126 -0
- machine_dialect/mir/tests/test_algebraic_simplification.py +863 -0
- machine_dialect/mir/tests/test_basic_block.py +425 -0
- machine_dialect/mir/tests/test_branch_prediction.py +459 -0
- machine_dialect/mir/tests/test_call_lowering.py +168 -0
- machine_dialect/mir/tests/test_collection_lowering.py +604 -0
- machine_dialect/mir/tests/test_cross_block_constant_propagation.py +255 -0
- machine_dialect/mir/tests/test_custom_passes.py +166 -0
- machine_dialect/mir/tests/test_debug_info.py +285 -0
- machine_dialect/mir/tests/test_dict_extraction_lowering.py +192 -0
- machine_dialect/mir/tests/test_dictionary_lowering.py +299 -0
- machine_dialect/mir/tests/test_double_negation.py +231 -0
- machine_dialect/mir/tests/test_escape_analysis.py +233 -0
- machine_dialect/mir/tests/test_hir_to_mir.py +465 -0
- machine_dialect/mir/tests/test_hir_to_mir_complete.py +389 -0
- machine_dialect/mir/tests/test_hir_to_mir_simple.py +130 -0
- machine_dialect/mir/tests/test_inlining.py +435 -0
- machine_dialect/mir/tests/test_licm.py +472 -0
- machine_dialect/mir/tests/test_mir_dumper.py +313 -0
- machine_dialect/mir/tests/test_mir_instructions.py +445 -0
- machine_dialect/mir/tests/test_mir_module.py +860 -0
- machine_dialect/mir/tests/test_mir_printer.py +387 -0
- machine_dialect/mir/tests/test_mir_types.py +123 -0
- machine_dialect/mir/tests/test_mir_types_enhanced.py +132 -0
- machine_dialect/mir/tests/test_mir_validation.py +378 -0
- machine_dialect/mir/tests/test_mir_values.py +168 -0
- machine_dialect/mir/tests/test_one_based_indexing.py +202 -0
- machine_dialect/mir/tests/test_optimization_helpers.py +60 -0
- machine_dialect/mir/tests/test_optimization_pipeline.py +554 -0
- machine_dialect/mir/tests/test_optimization_reporter.py +318 -0
- machine_dialect/mir/tests/test_pass_manager.py +294 -0
- machine_dialect/mir/tests/test_pass_registration.py +64 -0
- machine_dialect/mir/tests/test_profiling.py +356 -0
- machine_dialect/mir/tests/test_register_allocation.py +307 -0
- machine_dialect/mir/tests/test_report_formatters.py +372 -0
- machine_dialect/mir/tests/test_ssa_construction.py +433 -0
- machine_dialect/mir/tests/test_tail_call.py +236 -0
- machine_dialect/mir/tests/test_type_annotated_instructions.py +192 -0
- machine_dialect/mir/tests/test_type_narrowing.py +277 -0
- machine_dialect/mir/tests/test_type_specialization.py +421 -0
- machine_dialect/mir/tests/test_type_specific_optimization.py +545 -0
- machine_dialect/mir/tests/test_type_specific_optimization_advanced.py +382 -0
- machine_dialect/mir/type_inference.py +368 -0
- machine_dialect/parser/__init__.py +12 -0
- machine_dialect/parser/enums.py +45 -0
- machine_dialect/parser/parser.py +3655 -0
- machine_dialect/parser/protocols.py +11 -0
- machine_dialect/parser/symbol_table.py +169 -0
- machine_dialect/parser/tests/__init__.py +0 -0
- machine_dialect/parser/tests/helper_functions.py +193 -0
- machine_dialect/parser/tests/test_action_statements.py +334 -0
- machine_dialect/parser/tests/test_boolean_literal_expressions.py +152 -0
- machine_dialect/parser/tests/test_call_statements.py +154 -0
- machine_dialect/parser/tests/test_call_statements_errors.py +187 -0
- machine_dialect/parser/tests/test_collection_mutations.py +264 -0
- machine_dialect/parser/tests/test_conditional_expressions.py +343 -0
- machine_dialect/parser/tests/test_define_integration.py +468 -0
- machine_dialect/parser/tests/test_define_statements.py +311 -0
- machine_dialect/parser/tests/test_dict_extraction.py +115 -0
- machine_dialect/parser/tests/test_empty_literal.py +155 -0
- machine_dialect/parser/tests/test_float_literal_expressions.py +163 -0
- machine_dialect/parser/tests/test_identifier_expressions.py +57 -0
- machine_dialect/parser/tests/test_if_empty_block.py +61 -0
- machine_dialect/parser/tests/test_if_statements.py +299 -0
- machine_dialect/parser/tests/test_illegal_tokens.py +86 -0
- machine_dialect/parser/tests/test_infix_expressions.py +680 -0
- machine_dialect/parser/tests/test_integer_literal_expressions.py +137 -0
- machine_dialect/parser/tests/test_interaction_statements.py +269 -0
- machine_dialect/parser/tests/test_list_literals.py +277 -0
- machine_dialect/parser/tests/test_no_none_in_ast.py +94 -0
- machine_dialect/parser/tests/test_panic_mode_recovery.py +171 -0
- machine_dialect/parser/tests/test_parse_errors.py +114 -0
- machine_dialect/parser/tests/test_possessive_syntax.py +182 -0
- machine_dialect/parser/tests/test_prefix_expressions.py +415 -0
- machine_dialect/parser/tests/test_program.py +13 -0
- machine_dialect/parser/tests/test_return_statements.py +89 -0
- machine_dialect/parser/tests/test_set_statements.py +152 -0
- machine_dialect/parser/tests/test_strict_equality.py +258 -0
- machine_dialect/parser/tests/test_symbol_table.py +217 -0
- machine_dialect/parser/tests/test_url_literal_expressions.py +209 -0
- machine_dialect/parser/tests/test_utility_statements.py +423 -0
- machine_dialect/parser/token_buffer.py +159 -0
- machine_dialect/repl/__init__.py +3 -0
- machine_dialect/repl/repl.py +426 -0
- machine_dialect/repl/tests/__init__.py +0 -0
- machine_dialect/repl/tests/test_repl.py +606 -0
- machine_dialect/semantic/__init__.py +12 -0
- machine_dialect/semantic/analyzer.py +906 -0
- machine_dialect/semantic/error_messages.py +189 -0
- machine_dialect/semantic/tests/__init__.py +1 -0
- machine_dialect/semantic/tests/test_analyzer.py +364 -0
- machine_dialect/semantic/tests/test_error_messages.py +104 -0
- machine_dialect/tests/edge_cases/__init__.py +10 -0
- machine_dialect/tests/edge_cases/test_boundary_access.py +256 -0
- machine_dialect/tests/edge_cases/test_empty_collections.py +166 -0
- machine_dialect/tests/edge_cases/test_invalid_operations.py +243 -0
- machine_dialect/tests/edge_cases/test_named_list_edge_cases.py +295 -0
- machine_dialect/tests/edge_cases/test_nested_structures.py +313 -0
- machine_dialect/tests/edge_cases/test_type_mixing.py +277 -0
- machine_dialect/tests/integration/test_array_operations_emulation.py +248 -0
- machine_dialect/tests/integration/test_list_compilation.py +395 -0
- machine_dialect/tests/integration/test_lists_and_dictionaries.py +322 -0
- machine_dialect/type_checking/__init__.py +21 -0
- machine_dialect/type_checking/tests/__init__.py +1 -0
- machine_dialect/type_checking/tests/test_type_system.py +230 -0
- machine_dialect/type_checking/type_system.py +270 -0
- machine_dialect-0.1.0a1.dist-info/METADATA +128 -0
- machine_dialect-0.1.0a1.dist-info/RECORD +268 -0
- machine_dialect-0.1.0a1.dist-info/WHEEL +5 -0
- machine_dialect-0.1.0a1.dist-info/entry_points.txt +3 -0
- machine_dialect-0.1.0a1.dist-info/licenses/LICENSE +201 -0
- machine_dialect-0.1.0a1.dist-info/top_level.txt +2 -0
- machine_dialect_vm/__init__.pyi +15 -0
@@ -0,0 +1,448 @@
|
|
1
|
+
"""Enhanced type analysis for MIR.
|
2
|
+
|
3
|
+
This module provides advanced type analysis capabilities including
|
4
|
+
type inference, type tracking, and generic type support.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from dataclasses import dataclass, field
|
8
|
+
from enum import Enum, auto
|
9
|
+
from typing import Any
|
10
|
+
|
11
|
+
from machine_dialect.mir.basic_block import BasicBlock
|
12
|
+
from machine_dialect.mir.mir_function import MIRFunction
|
13
|
+
from machine_dialect.mir.mir_instructions import (
|
14
|
+
BinaryOp,
|
15
|
+
Call,
|
16
|
+
Copy,
|
17
|
+
LoadConst,
|
18
|
+
MIRInstruction,
|
19
|
+
Phi,
|
20
|
+
UnaryOp,
|
21
|
+
)
|
22
|
+
from machine_dialect.mir.mir_types import MIRType, MIRUnionType
|
23
|
+
from machine_dialect.mir.mir_values import Constant, MIRValue, Temp, Variable
|
24
|
+
from machine_dialect.mir.optimization_pass import (
|
25
|
+
FunctionAnalysisPass,
|
26
|
+
PassInfo,
|
27
|
+
PassType,
|
28
|
+
PreservationLevel,
|
29
|
+
)
|
30
|
+
|
31
|
+
|
32
|
+
class TypeConstraint(Enum):
|
33
|
+
"""Type constraints for generic types."""
|
34
|
+
|
35
|
+
ANY = auto() # No constraint
|
36
|
+
NUMERIC = auto() # Int or Float
|
37
|
+
COMPARABLE = auto() # Supports comparison
|
38
|
+
CALLABLE = auto() # Function type
|
39
|
+
ITERABLE = auto() # Can be iterated
|
40
|
+
|
41
|
+
|
42
|
+
@dataclass
|
43
|
+
class GenericType:
|
44
|
+
"""Generic type representation.
|
45
|
+
|
46
|
+
Attributes:
|
47
|
+
name: Type variable name (e.g., 'T', 'U').
|
48
|
+
constraint: Optional constraint on the type.
|
49
|
+
concrete_type: Concrete type when specialized.
|
50
|
+
"""
|
51
|
+
|
52
|
+
name: str
|
53
|
+
constraint: TypeConstraint = TypeConstraint.ANY
|
54
|
+
concrete_type: MIRType | None = None
|
55
|
+
|
56
|
+
def is_bound(self) -> bool:
|
57
|
+
"""Check if generic type is bound to concrete type.
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
True if bound to a concrete type, False otherwise.
|
61
|
+
"""
|
62
|
+
return self.concrete_type is not None
|
63
|
+
|
64
|
+
def bind(self, mir_type: MIRType) -> bool:
|
65
|
+
"""Bind generic type to concrete type.
|
66
|
+
|
67
|
+
Args:
|
68
|
+
mir_type: The concrete type to bind to.
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
True if binding succeeded, False if incompatible.
|
72
|
+
"""
|
73
|
+
if self.is_bound():
|
74
|
+
return self.concrete_type == mir_type
|
75
|
+
|
76
|
+
# Check constraint compatibility
|
77
|
+
if not self._satisfies_constraint(mir_type):
|
78
|
+
return False
|
79
|
+
|
80
|
+
self.concrete_type = mir_type
|
81
|
+
return True
|
82
|
+
|
83
|
+
def _satisfies_constraint(self, mir_type: MIRType) -> bool:
|
84
|
+
"""Check if type satisfies constraint.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
mir_type: The type to check.
|
88
|
+
|
89
|
+
Returns:
|
90
|
+
True if constraint is satisfied.
|
91
|
+
"""
|
92
|
+
if self.constraint == TypeConstraint.ANY:
|
93
|
+
return True
|
94
|
+
elif self.constraint == TypeConstraint.NUMERIC:
|
95
|
+
return mir_type in (MIRType.INT, MIRType.FLOAT)
|
96
|
+
elif self.constraint == TypeConstraint.COMPARABLE:
|
97
|
+
return mir_type in (MIRType.INT, MIRType.FLOAT, MIRType.STRING)
|
98
|
+
elif self.constraint == TypeConstraint.CALLABLE:
|
99
|
+
return mir_type == MIRType.FUNCTION
|
100
|
+
else:
|
101
|
+
return True
|
102
|
+
|
103
|
+
|
104
|
+
@dataclass
|
105
|
+
class TypeInfo:
|
106
|
+
"""Extended type information for a value.
|
107
|
+
|
108
|
+
Attributes:
|
109
|
+
base_type: The base MIR type.
|
110
|
+
is_generic: Whether this is a generic type.
|
111
|
+
generic_type: Generic type information if applicable.
|
112
|
+
nullable: Whether the value can be null/empty.
|
113
|
+
constant_value: Known constant value if any.
|
114
|
+
"""
|
115
|
+
|
116
|
+
base_type: MIRType | MIRUnionType
|
117
|
+
is_generic: bool = False
|
118
|
+
generic_type: GenericType | None = None
|
119
|
+
nullable: bool = False
|
120
|
+
constant_value: Any = None
|
121
|
+
|
122
|
+
def get_concrete_type(self) -> MIRType | MIRUnionType:
|
123
|
+
"""Get the concrete type.
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
The concrete MIR type, or base type if not generic/bound.
|
127
|
+
"""
|
128
|
+
if self.is_generic and self.generic_type and self.generic_type.is_bound():
|
129
|
+
concrete = self.generic_type.concrete_type
|
130
|
+
if concrete is not None:
|
131
|
+
return concrete
|
132
|
+
return self.base_type
|
133
|
+
|
134
|
+
|
135
|
+
@dataclass
|
136
|
+
class TypeEnvironment:
|
137
|
+
"""Type environment for tracking value types.
|
138
|
+
|
139
|
+
Attributes:
|
140
|
+
types: Mapping from values to type information.
|
141
|
+
generic_bindings: Current generic type bindings.
|
142
|
+
"""
|
143
|
+
|
144
|
+
types: dict[MIRValue, TypeInfo] = field(default_factory=dict)
|
145
|
+
generic_bindings: dict[str, GenericType] = field(default_factory=dict)
|
146
|
+
|
147
|
+
def get_type(self, value: MIRValue) -> TypeInfo | None:
|
148
|
+
"""Get type information for a value.
|
149
|
+
|
150
|
+
Args:
|
151
|
+
value: The value to query.
|
152
|
+
|
153
|
+
Returns:
|
154
|
+
Type information if available, None otherwise.
|
155
|
+
"""
|
156
|
+
return self.types.get(value)
|
157
|
+
|
158
|
+
def set_type(self, value: MIRValue, type_info: TypeInfo) -> None:
|
159
|
+
"""Set type information for a value.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
value: The value to set type for.
|
163
|
+
type_info: The type information.
|
164
|
+
"""
|
165
|
+
self.types[value] = type_info
|
166
|
+
|
167
|
+
def merge(self, other: "TypeEnvironment") -> "TypeEnvironment":
|
168
|
+
"""Merge with another type environment.
|
169
|
+
|
170
|
+
Args:
|
171
|
+
other: The other environment to merge.
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
New environment containing merged type information.
|
175
|
+
"""
|
176
|
+
merged = TypeEnvironment()
|
177
|
+
|
178
|
+
# Merge types, choosing more specific when possible
|
179
|
+
for value in set(self.types.keys()) | set(other.types.keys()):
|
180
|
+
if value in self.types and value in other.types:
|
181
|
+
# Choose more specific type
|
182
|
+
self_type = self.types[value]
|
183
|
+
other_type = other.types[value]
|
184
|
+
|
185
|
+
if self_type.base_type == MIRType.UNKNOWN:
|
186
|
+
merged.types[value] = other_type
|
187
|
+
elif other_type.base_type == MIRType.UNKNOWN:
|
188
|
+
merged.types[value] = self_type
|
189
|
+
else:
|
190
|
+
# Keep first if both are known
|
191
|
+
merged.types[value] = self_type
|
192
|
+
elif value in self.types:
|
193
|
+
merged.types[value] = self.types[value]
|
194
|
+
else:
|
195
|
+
merged.types[value] = other.types[value]
|
196
|
+
|
197
|
+
# Merge generic bindings
|
198
|
+
merged.generic_bindings.update(self.generic_bindings)
|
199
|
+
merged.generic_bindings.update(other.generic_bindings)
|
200
|
+
|
201
|
+
return merged
|
202
|
+
|
203
|
+
|
204
|
+
class TypeAnalysis(FunctionAnalysisPass):
|
205
|
+
"""Enhanced type analysis pass.
|
206
|
+
|
207
|
+
This analysis provides detailed type information including
|
208
|
+
generic types, nullability, and constant values.
|
209
|
+
"""
|
210
|
+
|
211
|
+
def __init__(self) -> None:
|
212
|
+
"""Initialize type analysis."""
|
213
|
+
super().__init__()
|
214
|
+
self.environments: dict[str, TypeEnvironment] = {}
|
215
|
+
|
216
|
+
def get_info(self) -> PassInfo:
|
217
|
+
"""Get pass information.
|
218
|
+
|
219
|
+
Returns:
|
220
|
+
Pass metadata including name, description, and dependencies.
|
221
|
+
"""
|
222
|
+
return PassInfo(
|
223
|
+
name="type-analysis",
|
224
|
+
description="Enhanced type analysis with generics",
|
225
|
+
pass_type=PassType.ANALYSIS,
|
226
|
+
requires=[],
|
227
|
+
preserves=PreservationLevel.ALL,
|
228
|
+
)
|
229
|
+
|
230
|
+
def finalize(self) -> None:
|
231
|
+
"""Finalize the analysis.
|
232
|
+
|
233
|
+
Note:
|
234
|
+
Currently performs no finalization actions.
|
235
|
+
"""
|
236
|
+
pass
|
237
|
+
|
238
|
+
def run_on_function(self, function: MIRFunction) -> TypeEnvironment:
|
239
|
+
"""Run type analysis on a function.
|
240
|
+
|
241
|
+
Args:
|
242
|
+
function: The function to analyze.
|
243
|
+
|
244
|
+
Returns:
|
245
|
+
Type environment for the function.
|
246
|
+
"""
|
247
|
+
self._analyze_function(function)
|
248
|
+
return self.environments.get(function.name, TypeEnvironment())
|
249
|
+
|
250
|
+
def get_analysis(self, function: MIRFunction) -> TypeEnvironment:
|
251
|
+
"""Get type analysis results for a function.
|
252
|
+
|
253
|
+
Args:
|
254
|
+
function: The function to analyze.
|
255
|
+
|
256
|
+
Returns:
|
257
|
+
Type environment for the function.
|
258
|
+
"""
|
259
|
+
func_name = function.name
|
260
|
+
|
261
|
+
if func_name not in self.environments or not self.is_valid():
|
262
|
+
self._analyze_function(function)
|
263
|
+
|
264
|
+
return self.environments.get(func_name, TypeEnvironment())
|
265
|
+
|
266
|
+
def _analyze_function(self, function: MIRFunction) -> None:
|
267
|
+
"""Analyze types in a function.
|
268
|
+
|
269
|
+
Args:
|
270
|
+
function: The function to analyze.
|
271
|
+
"""
|
272
|
+
env = TypeEnvironment()
|
273
|
+
|
274
|
+
# Initialize parameter types
|
275
|
+
for param in function.params:
|
276
|
+
type_info = TypeInfo(base_type=param.type, nullable=param.type == MIRType.UNKNOWN)
|
277
|
+
env.set_type(param, type_info)
|
278
|
+
|
279
|
+
# Analyze each basic block
|
280
|
+
for block in function.cfg.blocks.values():
|
281
|
+
self._analyze_block(block, env)
|
282
|
+
|
283
|
+
# Store the environment
|
284
|
+
self.environments[function.name] = env
|
285
|
+
self._valid = True
|
286
|
+
|
287
|
+
def _analyze_block(self, block: BasicBlock, env: TypeEnvironment) -> None:
|
288
|
+
"""Analyze types in a basic block.
|
289
|
+
|
290
|
+
Args:
|
291
|
+
block: The block to analyze.
|
292
|
+
env: Current type environment.
|
293
|
+
"""
|
294
|
+
for inst in block.instructions:
|
295
|
+
self._analyze_instruction(inst, env)
|
296
|
+
|
297
|
+
def _analyze_instruction(self, inst: MIRInstruction, env: TypeEnvironment) -> None:
|
298
|
+
"""Analyze types for an instruction.
|
299
|
+
|
300
|
+
Args:
|
301
|
+
inst: The instruction to analyze.
|
302
|
+
env: Current type environment.
|
303
|
+
"""
|
304
|
+
if isinstance(inst, LoadConst):
|
305
|
+
# Constant has known type and value
|
306
|
+
type_info = TypeInfo(base_type=inst.constant.type, constant_value=inst.constant.value)
|
307
|
+
env.set_type(inst.dest, type_info)
|
308
|
+
|
309
|
+
elif isinstance(inst, Copy):
|
310
|
+
# Copy propagates type
|
311
|
+
source_type = env.get_type(inst.source)
|
312
|
+
if source_type:
|
313
|
+
env.set_type(inst.dest, source_type)
|
314
|
+
|
315
|
+
elif isinstance(inst, BinaryOp):
|
316
|
+
# Infer result type from operands
|
317
|
+
left_type = self._get_value_type(inst.left, env)
|
318
|
+
right_type = self._get_value_type(inst.right, env)
|
319
|
+
|
320
|
+
result_type = self._infer_binary_op_type(inst.op, left_type, right_type)
|
321
|
+
env.set_type(inst.dest, result_type)
|
322
|
+
|
323
|
+
elif isinstance(inst, UnaryOp):
|
324
|
+
# Infer result type from operand
|
325
|
+
operand_type = self._get_value_type(inst.operand, env)
|
326
|
+
result_type = self._infer_unary_op_type(inst.op, operand_type)
|
327
|
+
env.set_type(inst.dest, result_type)
|
328
|
+
|
329
|
+
elif isinstance(inst, Call):
|
330
|
+
# For now, mark result as unknown
|
331
|
+
# In future, could use function signatures
|
332
|
+
if inst.dest:
|
333
|
+
type_info = TypeInfo(base_type=MIRType.UNKNOWN)
|
334
|
+
env.set_type(inst.dest, type_info)
|
335
|
+
|
336
|
+
elif isinstance(inst, Phi):
|
337
|
+
# Phi node merges types from sources
|
338
|
+
source_types = [self._get_value_type(source, env) for source, _ in inst.incoming]
|
339
|
+
|
340
|
+
# Find common type
|
341
|
+
merged_type = self._merge_types(source_types)
|
342
|
+
env.set_type(inst.dest, merged_type)
|
343
|
+
|
344
|
+
def _get_value_type(self, value: MIRValue, env: TypeEnvironment) -> TypeInfo:
|
345
|
+
"""Get type info for a value.
|
346
|
+
|
347
|
+
Args:
|
348
|
+
value: The value to get type for.
|
349
|
+
env: Current type environment.
|
350
|
+
|
351
|
+
Returns:
|
352
|
+
Type information from environment or inferred from value.
|
353
|
+
"""
|
354
|
+
# Check environment first
|
355
|
+
type_info = env.get_type(value)
|
356
|
+
if type_info:
|
357
|
+
return type_info
|
358
|
+
|
359
|
+
# Fall back to basic type
|
360
|
+
if isinstance(value, Constant):
|
361
|
+
return TypeInfo(base_type=value.type, constant_value=value.value)
|
362
|
+
elif isinstance(value, Variable):
|
363
|
+
return TypeInfo(base_type=value.type)
|
364
|
+
elif isinstance(value, Temp):
|
365
|
+
return TypeInfo(base_type=value.type)
|
366
|
+
else:
|
367
|
+
return TypeInfo(base_type=MIRType.UNKNOWN)
|
368
|
+
|
369
|
+
def _infer_binary_op_type(self, op: str, left: TypeInfo, right: TypeInfo) -> TypeInfo:
|
370
|
+
"""Infer result type of binary operation.
|
371
|
+
|
372
|
+
Args:
|
373
|
+
op: The operator.
|
374
|
+
left: Left operand type.
|
375
|
+
right: Right operand type.
|
376
|
+
|
377
|
+
Returns:
|
378
|
+
Result type information.
|
379
|
+
"""
|
380
|
+
# Comparison operators return boolean
|
381
|
+
if op in ("==", "!=", "<", ">", "<=", ">="):
|
382
|
+
return TypeInfo(base_type=MIRType.BOOL)
|
383
|
+
|
384
|
+
# Logical operators work on booleans
|
385
|
+
if op in ("and", "or"):
|
386
|
+
return TypeInfo(base_type=MIRType.BOOL)
|
387
|
+
|
388
|
+
# Arithmetic operators
|
389
|
+
if op in ("+", "-", "*", "/", "%", "^"):
|
390
|
+
# If both are numeric, result is numeric
|
391
|
+
if left.base_type in (MIRType.INT, MIRType.FLOAT):
|
392
|
+
if right.base_type in (MIRType.INT, MIRType.FLOAT):
|
393
|
+
# Float dominates
|
394
|
+
if left.base_type == MIRType.FLOAT or right.base_type == MIRType.FLOAT:
|
395
|
+
return TypeInfo(base_type=MIRType.FLOAT)
|
396
|
+
else:
|
397
|
+
return TypeInfo(base_type=MIRType.INT)
|
398
|
+
|
399
|
+
# String concatenation
|
400
|
+
if op == "+" and left.base_type == MIRType.STRING:
|
401
|
+
return TypeInfo(base_type=MIRType.STRING)
|
402
|
+
|
403
|
+
# Default to unknown
|
404
|
+
return TypeInfo(base_type=MIRType.UNKNOWN)
|
405
|
+
|
406
|
+
def _infer_unary_op_type(self, op: str, operand: TypeInfo) -> TypeInfo:
|
407
|
+
"""Infer result type of unary operation.
|
408
|
+
|
409
|
+
Args:
|
410
|
+
op: The operator.
|
411
|
+
operand: Operand type.
|
412
|
+
|
413
|
+
Returns:
|
414
|
+
Result type information.
|
415
|
+
"""
|
416
|
+
if op == "-":
|
417
|
+
# Negation preserves numeric type
|
418
|
+
if operand.base_type in (MIRType.INT, MIRType.FLOAT):
|
419
|
+
return TypeInfo(base_type=operand.base_type)
|
420
|
+
elif op == "not":
|
421
|
+
# Logical not returns boolean
|
422
|
+
return TypeInfo(base_type=MIRType.BOOL)
|
423
|
+
|
424
|
+
return TypeInfo(base_type=MIRType.UNKNOWN)
|
425
|
+
|
426
|
+
def _merge_types(self, types: list[TypeInfo]) -> TypeInfo:
|
427
|
+
"""Merge multiple types into common type.
|
428
|
+
|
429
|
+
Args:
|
430
|
+
types: List of types to merge.
|
431
|
+
|
432
|
+
Returns:
|
433
|
+
Merged type information.
|
434
|
+
"""
|
435
|
+
if not types:
|
436
|
+
return TypeInfo(base_type=MIRType.UNKNOWN)
|
437
|
+
|
438
|
+
# If all same type, return that
|
439
|
+
base_types = [t.base_type for t in types]
|
440
|
+
if len(set(base_types)) == 1:
|
441
|
+
return types[0]
|
442
|
+
|
443
|
+
# If mix of int and float, return float
|
444
|
+
if set(base_types) <= {MIRType.INT, MIRType.FLOAT}:
|
445
|
+
return TypeInfo(base_type=MIRType.FLOAT)
|
446
|
+
|
447
|
+
# Otherwise unknown
|
448
|
+
return TypeInfo(base_type=MIRType.UNKNOWN, nullable=True)
|
@@ -0,0 +1,232 @@
|
|
1
|
+
"""Use-def and def-use chain analysis for MIR.
|
2
|
+
|
3
|
+
This module builds explicit use-def and def-use chains from the SSA form,
|
4
|
+
enabling efficient queries for optimization passes.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from collections import defaultdict
|
8
|
+
from dataclasses import dataclass
|
9
|
+
|
10
|
+
from machine_dialect.mir.basic_block import BasicBlock
|
11
|
+
from machine_dialect.mir.mir_function import MIRFunction
|
12
|
+
from machine_dialect.mir.mir_instructions import MIRInstruction
|
13
|
+
from machine_dialect.mir.mir_values import MIRValue, Temp, Variable
|
14
|
+
from machine_dialect.mir.optimization_pass import (
|
15
|
+
FunctionAnalysisPass,
|
16
|
+
PassInfo,
|
17
|
+
PassType,
|
18
|
+
PreservationLevel,
|
19
|
+
)
|
20
|
+
|
21
|
+
|
22
|
+
@dataclass
|
23
|
+
class UseDefInfo:
|
24
|
+
"""Use-def information for a value.
|
25
|
+
|
26
|
+
Attributes:
|
27
|
+
value: The MIR value.
|
28
|
+
definition: Instruction that defines this value.
|
29
|
+
uses: List of instructions that use this value.
|
30
|
+
defining_block: Block containing the definition.
|
31
|
+
use_blocks: Blocks containing uses.
|
32
|
+
"""
|
33
|
+
|
34
|
+
value: MIRValue
|
35
|
+
definition: MIRInstruction | None
|
36
|
+
uses: list[MIRInstruction]
|
37
|
+
defining_block: BasicBlock | None
|
38
|
+
use_blocks: list[BasicBlock]
|
39
|
+
|
40
|
+
|
41
|
+
class UseDefChains:
|
42
|
+
"""Container for use-def and def-use chains."""
|
43
|
+
|
44
|
+
def __init__(self) -> None:
|
45
|
+
"""Initialize use-def chains."""
|
46
|
+
# Map from value to its use-def info
|
47
|
+
self.use_def_map: dict[MIRValue, UseDefInfo] = {}
|
48
|
+
# Map from instruction to values it defines
|
49
|
+
self.inst_defs: dict[MIRInstruction, list[MIRValue]] = defaultdict(list)
|
50
|
+
# Map from instruction to values it uses
|
51
|
+
self.inst_uses: dict[MIRInstruction, list[MIRValue]] = defaultdict(list)
|
52
|
+
|
53
|
+
def get_definition(self, value: MIRValue) -> MIRInstruction | None:
|
54
|
+
"""Get the instruction that defines a value.
|
55
|
+
|
56
|
+
Args:
|
57
|
+
value: The value to query.
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
Defining instruction or None.
|
61
|
+
"""
|
62
|
+
info = self.use_def_map.get(value)
|
63
|
+
return info.definition if info else None
|
64
|
+
|
65
|
+
def get_uses(self, value: MIRValue) -> list[MIRInstruction]:
|
66
|
+
"""Get instructions that use a value.
|
67
|
+
|
68
|
+
Args:
|
69
|
+
value: The value to query.
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
List of using instructions.
|
73
|
+
"""
|
74
|
+
info = self.use_def_map.get(value)
|
75
|
+
return info.uses if info else []
|
76
|
+
|
77
|
+
def get_defined_values(self, inst: MIRInstruction) -> list[MIRValue]:
|
78
|
+
"""Get values defined by an instruction.
|
79
|
+
|
80
|
+
Args:
|
81
|
+
inst: The instruction to query.
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
List of defined values.
|
85
|
+
"""
|
86
|
+
return self.inst_defs.get(inst, [])
|
87
|
+
|
88
|
+
def get_used_values(self, inst: MIRInstruction) -> list[MIRValue]:
|
89
|
+
"""Get values used by an instruction.
|
90
|
+
|
91
|
+
Args:
|
92
|
+
inst: The instruction to query.
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
List of used values.
|
96
|
+
"""
|
97
|
+
return self.inst_uses.get(inst, [])
|
98
|
+
|
99
|
+
def is_dead(self, value: MIRValue) -> bool:
|
100
|
+
"""Check if a value is dead (has no uses).
|
101
|
+
|
102
|
+
Args:
|
103
|
+
value: The value to check.
|
104
|
+
|
105
|
+
Returns:
|
106
|
+
True if the value has no uses.
|
107
|
+
"""
|
108
|
+
info = self.use_def_map.get(value)
|
109
|
+
return info is None or len(info.uses) == 0
|
110
|
+
|
111
|
+
def has_single_use(self, value: MIRValue) -> bool:
|
112
|
+
"""Check if a value has exactly one use.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
value: The value to check.
|
116
|
+
|
117
|
+
Returns:
|
118
|
+
True if the value has exactly one use.
|
119
|
+
"""
|
120
|
+
info = self.use_def_map.get(value)
|
121
|
+
return info is not None and len(info.uses) == 1
|
122
|
+
|
123
|
+
def get_num_uses(self, value: MIRValue) -> int:
|
124
|
+
"""Get the number of uses of a value.
|
125
|
+
|
126
|
+
Args:
|
127
|
+
value: The value to check.
|
128
|
+
|
129
|
+
Returns:
|
130
|
+
Number of uses.
|
131
|
+
"""
|
132
|
+
info = self.use_def_map.get(value)
|
133
|
+
return len(info.uses) if info else 0
|
134
|
+
|
135
|
+
|
136
|
+
class UseDefChainsAnalysis(FunctionAnalysisPass):
|
137
|
+
"""Analysis pass that builds use-def chains."""
|
138
|
+
|
139
|
+
def get_info(self) -> PassInfo:
|
140
|
+
"""Get pass information.
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
Pass information.
|
144
|
+
"""
|
145
|
+
return PassInfo(
|
146
|
+
name="use-def-chains",
|
147
|
+
description="Build use-def and def-use chains",
|
148
|
+
pass_type=PassType.ANALYSIS,
|
149
|
+
requires=[],
|
150
|
+
preserves=PreservationLevel.ALL,
|
151
|
+
)
|
152
|
+
|
153
|
+
def run_on_function(self, function: MIRFunction) -> UseDefChains:
|
154
|
+
"""Build use-def chains for a function.
|
155
|
+
|
156
|
+
Args:
|
157
|
+
function: The function to analyze.
|
158
|
+
|
159
|
+
Returns:
|
160
|
+
Use-def chains.
|
161
|
+
"""
|
162
|
+
chains = UseDefChains()
|
163
|
+
|
164
|
+
# Process all blocks
|
165
|
+
for block in function.cfg.blocks.values():
|
166
|
+
# Process phi nodes
|
167
|
+
for phi in block.phi_nodes:
|
168
|
+
self._process_instruction(phi, block, chains)
|
169
|
+
|
170
|
+
# Process regular instructions
|
171
|
+
for inst in block.instructions:
|
172
|
+
self._process_instruction(inst, block, chains)
|
173
|
+
|
174
|
+
return chains
|
175
|
+
|
176
|
+
def _process_instruction(
|
177
|
+
self,
|
178
|
+
inst: MIRInstruction,
|
179
|
+
block: BasicBlock,
|
180
|
+
chains: UseDefChains,
|
181
|
+
) -> None:
|
182
|
+
"""Process a single instruction.
|
183
|
+
|
184
|
+
Args:
|
185
|
+
inst: Instruction to process.
|
186
|
+
block: Containing block.
|
187
|
+
chains: Chains to update.
|
188
|
+
"""
|
189
|
+
# Process definitions
|
190
|
+
for def_val in inst.get_defs():
|
191
|
+
if isinstance(def_val, Variable | Temp):
|
192
|
+
# Create or update use-def info
|
193
|
+
if def_val not in chains.use_def_map:
|
194
|
+
chains.use_def_map[def_val] = UseDefInfo(
|
195
|
+
value=def_val,
|
196
|
+
definition=inst,
|
197
|
+
uses=[],
|
198
|
+
defining_block=block,
|
199
|
+
use_blocks=[],
|
200
|
+
)
|
201
|
+
else:
|
202
|
+
# Update definition (for variables that may be redefined)
|
203
|
+
chains.use_def_map[def_val].definition = inst
|
204
|
+
chains.use_def_map[def_val].defining_block = block
|
205
|
+
|
206
|
+
# Record instruction's definitions
|
207
|
+
chains.inst_defs[inst].append(def_val)
|
208
|
+
|
209
|
+
# Process uses
|
210
|
+
for use_val in inst.get_uses():
|
211
|
+
if isinstance(use_val, Variable | Temp):
|
212
|
+
# Create use-def info if needed
|
213
|
+
if use_val not in chains.use_def_map:
|
214
|
+
chains.use_def_map[use_val] = UseDefInfo(
|
215
|
+
value=use_val,
|
216
|
+
definition=None, # No definition found yet
|
217
|
+
uses=[],
|
218
|
+
defining_block=None,
|
219
|
+
use_blocks=[],
|
220
|
+
)
|
221
|
+
|
222
|
+
# Add this instruction as a use
|
223
|
+
chains.use_def_map[use_val].uses.append(inst)
|
224
|
+
if block not in chains.use_def_map[use_val].use_blocks:
|
225
|
+
chains.use_def_map[use_val].use_blocks.append(block)
|
226
|
+
|
227
|
+
# Record instruction's uses
|
228
|
+
chains.inst_uses[inst].append(use_val)
|
229
|
+
|
230
|
+
def finalize(self) -> None:
|
231
|
+
"""Finalize the pass."""
|
232
|
+
pass
|