v / vlib / v2 / mir / mir.v
375 lines · 343 sloc · 7.85 KB · a7153322629091f3f2d79f0bf318d0fb2c13c425
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4
5module mir
6
7import v2.ssa
8import v2.types
9
10pub enum ValueKind {
11 unknown
12 constant
13 argument
14 global
15 instruction
16 basic_block
17 string_literal
18 c_string_literal
19 func_ref
20}
21
22// str returns the symbolic name for a MIR value kind.
23pub fn (k ValueKind) str() string {
24 return match k {
25 .unknown { 'unknown' }
26 .constant { 'constant' }
27 .argument { 'argument' }
28 .global { 'global' }
29 .instruction { 'instruction' }
30 .basic_block { 'basic_block' }
31 .string_literal { 'string_literal' }
32 .c_string_literal { 'c_string_literal' }
33 .func_ref { 'func_ref' }
34 }
35}
36
37pub enum AbiArgClass as u8 {
38 in_reg
39 indirect
40}
41
42// Classification metadata for future ABI-aware codegen. The active x64
43// lowering path still consumes the legacy abi_*_class and abi_ret_indirect
44// projection fields in this palier.
45pub enum AbiPassMode {
46 direct
47 indirect
48}
49
50pub enum AbiEightbyteClass {
51 no_class
52 integer
53 sse
54 sseup
55 memory
56}
57
58pub struct AbiValueClass {
59pub mut:
60 mode AbiPassMode
61 size int
62 classes []AbiEightbyteClass
63}
64
65pub enum AbiLocationKind {
66 none
67 int_reg
68 sse_reg
69 stack
70}
71
72pub struct AbiLocation {
73pub mut:
74 kind AbiLocationKind
75 index int
76 offset int
77 class AbiEightbyteClass
78}
79
80pub struct AbiValueLayout {
81pub mut:
82 value_class AbiValueClass
83 locs []AbiLocation
84}
85
86pub struct Value {
87pub:
88 id int
89 typ ssa.TypeID
90 index int
91pub mut:
92 kind ValueKind
93 name string
94 uses []ssa.ValueID
95}
96
97pub struct Instruction {
98pub mut:
99 op ssa.OpCode
100 operands []ssa.ValueID
101 abi_ret_indirect bool
102 abi_arg_class []AbiArgClass
103 abi_ret_class AbiValueClass
104 abi_arg_classes []AbiValueClass
105 abi_arg_layouts []AbiValueLayout
106pub:
107 typ ssa.TypeID
108 block int
109 src_index int
110}
111
112pub struct BasicBlock {
113pub:
114 id int
115 val_id int
116 name string
117 parent int
118pub mut:
119 instrs []ssa.ValueID
120 preds []ssa.BlockID
121 succs []ssa.BlockID
122}
123
124pub struct Function {
125pub:
126 id int
127 name string
128 typ ssa.TypeID
129 linkage ssa.Linkage
130 call_conv ssa.CallConv
131 is_c_extern bool // C-language extern function (provided by libc/system libraries)
132pub mut:
133 blocks []ssa.BlockID
134 params []ssa.ValueID
135 abi_ret_indirect bool
136 abi_param_class []AbiArgClass
137 abi_ret_class AbiValueClass
138 abi_param_classes []AbiValueClass
139 abi_param_layouts []AbiValueLayout
140}
141
142@[heap]
143pub struct Module {
144pub:
145 name string
146 target ssa.TargetData
147 ssa_mod &ssa.Module = unsafe { nil }
148 env &types.Environment = unsafe { nil }
149pub mut:
150 type_store ssa.TypeStore
151 values []Value
152 instrs []Instruction
153 blocks []BasicBlock
154 funcs []Function
155 globals []ssa.GlobalVar
156}
157
158fn share_value_ids(values []ssa.ValueID) []ssa.ValueID {
159 return values
160}
161
162fn share_block_ids(blocks []ssa.BlockID) []ssa.BlockID {
163 return blocks
164}
165
166pub fn lower_from_ssa(ssa_mod &ssa.Module) Module {
167 mut mod := Module{
168 name: ssa_mod.name
169 target: ssa_mod.target
170 ssa_mod: ssa_mod
171 env: ssa_mod.env
172 type_store: ssa_mod.type_store
173 values: []Value{len: ssa_mod.values.len}
174 instrs: []Instruction{len: ssa_mod.instrs.len}
175 blocks: []BasicBlock{len: ssa_mod.blocks.len}
176 funcs: []Function{len: ssa_mod.funcs.len}
177 globals: ssa_mod.globals
178 }
179
180 for i, val in ssa_mod.values {
181 mod.values[i] = Value{
182 id: val.id
183 typ: val.typ
184 index: val.index
185 kind: value_kind_from_ssa(val.kind)
186 name: val.name
187 uses: share_value_ids(val.uses)
188 }
189 }
190
191 for i, instr in ssa_mod.instrs {
192 mod.instrs[i] = Instruction{
193 op: instr.op
194 operands: share_value_ids(instr.operands)
195 abi_ret_indirect: false
196 abi_arg_class: []AbiArgClass{}
197 abi_ret_class: AbiValueClass{}
198 abi_arg_classes: []AbiValueClass{}
199 abi_arg_layouts: []AbiValueLayout{}
200 typ: instr.typ
201 block: instr.block
202 src_index: i
203 }
204 }
205
206 for i, blk in ssa_mod.blocks {
207 mod.blocks[i] = BasicBlock{
208 id: blk.id
209 val_id: blk.val_id
210 name: blk.name
211 parent: blk.parent
212 instrs: share_value_ids(blk.instrs)
213 preds: share_block_ids(blk.preds)
214 succs: share_block_ids(blk.succs)
215 }
216 }
217
218 for i, f in ssa_mod.funcs {
219 mod.funcs[i] = Function{
220 id: f.id
221 name: f.name
222 typ: f.typ
223 linkage: f.linkage
224 call_conv: f.call_conv
225 is_c_extern: f.is_c_extern
226 blocks: share_block_ids(f.blocks)
227 params: share_value_ids(f.params)
228 abi_ret_indirect: false
229 abi_param_class: []AbiArgClass{len: f.params.len, init: .in_reg}
230 abi_ret_class: AbiValueClass{}
231 abi_param_classes: []AbiValueClass{len: f.params.len}
232 abi_param_layouts: []AbiValueLayout{len: f.params.len}
233 }
234 }
235
236 return mod
237}
238
239// release_after_native_codegen releases MIR storage after native codegen has
240// copied everything it needs into the object writer/linker.
241pub fn (mut m Module) release_after_native_codegen() {
242 unsafe {
243 m.values.free()
244 m.instrs.free()
245 m.blocks.free()
246 m.funcs.free()
247 m.globals.free()
248 m.type_store.types.free()
249 m.type_store.cache.free()
250 }
251 m.values = []Value{}
252 m.instrs = []Instruction{}
253 m.blocks = []BasicBlock{}
254 m.funcs = []Function{}
255 m.globals = []ssa.GlobalVar{}
256 m.type_store = ssa.TypeStore{}
257}
258
259pub fn (m &Module) ssa() &ssa.Module {
260 return m.ssa_mod
261}
262
263pub fn (m &Module) type_size(typ_id ssa.TypeID) int {
264 mut visiting := map[ssa.TypeID]bool{}
265 return m.type_size_with_seen(typ_id, mut visiting)
266}
267
268fn (m &Module) type_size_with_seen(typ_id ssa.TypeID, mut visiting map[ssa.TypeID]bool) int {
269 if m.ssa_mod == unsafe { nil } || typ_id < 0 || typ_id >= m.ssa_mod.type_store.types.len {
270 return 0
271 }
272 if typ_id == 0 {
273 return 0
274 }
275 if visiting[typ_id] {
276 return 8
277 }
278 visiting[typ_id] = true
279 typ := m.ssa_mod.type_store.types[typ_id]
280 size := match typ.kind {
281 .void_t {
282 0
283 }
284 .int_t {
285 if typ.width > 0 { (typ.width + 7) / 8 } else { 8 }
286 }
287 .float_t {
288 if typ.width > 0 { (typ.width + 7) / 8 } else { 8 }
289 }
290 .ptr_t {
291 8
292 }
293 .array_t {
294 elem_size := m.type_size_with_seen(typ.elem_type, mut visiting)
295 typ.len * elem_size
296 }
297 .struct_t {
298 mut total := 0
299 mut max_align := 1
300 for field_typ in typ.fields {
301 align := m.type_align_with_seen(field_typ, mut visiting)
302 if align > max_align {
303 max_align = align
304 }
305 if align > 1 && total % align != 0 {
306 total = (total + align - 1) & ~(align - 1)
307 }
308 total += m.type_size_with_seen(field_typ, mut visiting)
309 }
310 // Align struct size to its largest field alignment
311 if max_align > 1 && total % max_align != 0 {
312 total = (total + max_align - 1) & ~(max_align - 1)
313 }
314 if total > 0 {
315 total
316 } else {
317 8
318 }
319 }
320 .func_t {
321 8
322 }
323 .label_t {
324 0
325 }
326 .metadata_t {
327 0
328 }
329 }
330
331 visiting.delete(typ_id)
332 return size
333}
334
335pub fn (m &Module) type_align(typ_id ssa.TypeID) int {
336 mut visiting := map[ssa.TypeID]bool{}
337 return m.type_align_with_seen(typ_id, mut visiting)
338}
339
340fn (m &Module) type_align_with_seen(typ_id ssa.TypeID, mut visiting map[ssa.TypeID]bool) int {
341 if m.ssa_mod != unsafe { nil } && typ_id > 0 && typ_id < m.ssa_mod.type_store.types.len {
342 if visiting[typ_id] {
343 return 8
344 }
345 typ := m.ssa_mod.type_store.types[typ_id]
346 if typ.kind == .array_t {
347 return m.type_align_with_seen(typ.elem_type, mut visiting)
348 }
349 }
350 size := m.type_size_with_seen(typ_id, mut visiting)
351 if size >= 8 {
352 return 8
353 }
354 if size >= 4 {
355 return 4
356 }
357 if size >= 2 {
358 return 2
359 }
360 return 1
361}
362
363fn value_kind_from_ssa(kind ssa.ValueKind) ValueKind {
364 return match kind {
365 .unknown { .unknown }
366 .constant { .constant }
367 .argument { .argument }
368 .global { .global }
369 .instruction { .instruction }
370 .basic_block { .basic_block }
371 .string_literal { .string_literal }
372 .c_string_literal { .c_string_literal }
373 .func_ref { .func_ref }
374 }
375}
376