forked from nulang-org/nulang
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtype_metadata.rs
More file actions
187 lines (169 loc) · 5.98 KB
/
Copy pathtype_metadata.rs
File metadata and controls
187 lines (169 loc) · 5.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! Compile-time type knowledge for code generation.
//!
//! Maps program values (registers or MIR locals) to statically-known types
//! so that backends (JIT, AOT) can emit unboxed native code instead of
//! NaN-tag-aware runtime operations.
//!
//! Shared between the JIT (`src/jit/typed_compiler.rs`) and the AOT
//! compiler (`src/aot/`).
/// The static type of a value known at compile time.
///
/// - `Int`: NaN-tagged integer → strip tag, use direct i64 ops.
/// - `Float`: Raw f64 bits → use direct f64 ops.
/// - `Bool`: NaN-tagged boolean → compare directly against tagged constants.
/// - `Unknown`: Fall back to runtime helpers / boxed representation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum KnownType {
#[default]
Unknown,
Int,
Float,
Bool,
}
/// Number of registers in the VM frame.
pub const REG_COUNT: usize = 256;
/// Static type information for the 256 VM registers.
///
/// A flat `[KnownType; 256]` array replaces the previous `HashMap<usize, KnownType>`
/// for deterministic O(1) access with no hashing overhead. Unknown slots are
/// represented by `KnownType::Unknown` (the default).
///
/// # Example
/// ```
/// use nulang::type_metadata::{TypeMetadata, KnownType};
///
/// let mut meta = TypeMetadata::new();
/// meta.set_type(0, KnownType::Int); // R0 is known Int
/// meta.set_type(1, KnownType::Float); // R1 is known Float
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeMetadata {
pub regs: [KnownType; REG_COUNT],
}
impl Default for TypeMetadata {
fn default() -> Self {
Self {
regs: [KnownType::Unknown; REG_COUNT],
}
}
}
/// Convert a language-level `Type` to a `KnownType` for code generation.
///
/// Only primitive types are statically known; polymorphic, compound, and
/// effectful types all map to `Unknown`.
pub fn type_to_known_type(ty: &crate::types::Type) -> KnownType {
match ty {
crate::types::Type::Primitive(p) => match p {
crate::types::PrimitiveType::Int => KnownType::Int,
crate::types::PrimitiveType::Float => KnownType::Float,
crate::types::PrimitiveType::Bool => KnownType::Bool,
_ => KnownType::Unknown,
},
_ => KnownType::Unknown,
}
}
impl TypeMetadata {
/// Create a new TypeMetadata with all registers Unknown.
pub fn new() -> Self {
Self::default()
}
/// Set the known type for a register index.
/// Silently ignores indices beyond REG_COUNT (defense against MIR overflow).
pub fn set_type(&mut self, reg: usize, ty: KnownType) {
if reg < REG_COUNT {
self.regs[reg] = ty;
}
}
/// Get the known type for a register index.
pub fn get_type(&self, reg: usize) -> KnownType {
if reg < REG_COUNT {
self.regs[reg]
} else {
KnownType::Unknown
}
}
/// Check whether both operands have the same known type.
pub fn both_known(&self, r1: usize, r2: usize, expected: KnownType) -> bool {
r1 < REG_COUNT && r2 < REG_COUNT && self.regs[r1] == expected && self.regs[r2] == expected
}
/// Check whether a single value has the expected known type.
pub fn is_known(&self, reg: usize, expected: KnownType) -> bool {
reg < REG_COUNT && self.regs[reg] == expected
}
/// Mark the destination as having a known type after an operation.
///
/// For arithmetic: the result type is the same as the operand type.
/// For comparisons: the result is always Bool.
pub fn propagate_result(&mut self, dst: usize, operand_reg: usize) {
if operand_reg < REG_COUNT && dst < REG_COUNT {
self.regs[dst] = self.regs[operand_reg];
}
}
/// Mark the destination as Bool (used after comparisons).
pub fn set_bool_result(&mut self, dst: usize) {
if dst < REG_COUNT {
self.regs[dst] = KnownType::Bool;
}
}
/// Returns true if no register has a known type (all Unknown).
pub fn is_empty(&self) -> bool {
self.regs.iter().all(|&t| t == KnownType::Unknown)
}
/// Build TypeMetadata from an iterator of (register_index, Type) pairs.
///
/// Converts language-level `Type` values to `KnownType` by stripping
/// away polymorphic wrappers: only primitive `Int`, `Float`, and `Bool`
/// are statically known; everything else becomes `Unknown`.
pub fn from_mir_locals<'a>(
locals: impl Iterator<Item = (usize, &'a crate::types::Type)>,
) -> Self {
let mut meta = TypeMetadata::new();
for (reg, ty) in locals {
if reg >= REG_COUNT {
continue; // MIR locals beyond frame register capacity — skip type tracking
}
let known = type_to_known_type(ty);
if known != KnownType::Unknown {
meta.set_type(reg, known);
}
}
meta
}
}
// ---------------------------------------------------------------------------
// Capability Metadata
// ---------------------------------------------------------------------------
pub struct CapabilityMetadata {
pub caps: [crate::types::Capability; REG_COUNT],
}
impl Default for CapabilityMetadata {
fn default() -> Self {
Self {
caps: [crate::types::Capability::Tag; REG_COUNT],
}
}
}
impl CapabilityMetadata {
pub fn new() -> Self {
Self::default()
}
pub fn set_cap(&mut self, reg: usize, cap: crate::types::Capability) {
if reg < REG_COUNT {
self.caps[reg] = cap;
}
}
pub fn get_cap(&self, reg: usize) -> crate::types::Capability {
self.caps[reg]
}
pub fn from_mir_function(func: &crate::mir::Function) -> Self {
let mut meta = Self::new();
let local_base = crate::mir::FunctionBuilder::LOCAL_BASE;
for local in &func.locals {
let reg = local_base as usize + local.id.0 as usize;
if reg < REG_COUNT {
meta.caps[reg] = local.cap;
}
}
meta
}
}