vxx / vlib / v3 / mir / mir.v
408 lines · 375 sloc · 8.41 KB · 6c4d26f1f98c5464b012a375667ab345e462f7e0
Raw
1module mir
2
3import v3.ssa
4
5// TargetArch lists target arch values used by mir.
6pub enum TargetArch {
7 unknown
8 arm64
9}
10
11// AbiKind lists abi kind values used by mir.
12pub enum AbiKind {
13 unknown
14 aapcs64
15}
16
17// Target represents target data used by mir.
18pub struct Target {
19pub:
20 arch TargetArch
21 abi AbiKind
22 pointer_size int
23 int_arg_regs int
24 ret_regs int
25 stack_align int
26}
27
28// AbiLocationKind lists abi location kind values used by mir.
29pub enum AbiLocationKind {
30 none
31 register
32 stack
33 indirect
34}
35
36// AbiLocation represents abi location data used by mir.
37pub struct AbiLocation {
38pub:
39 kind AbiLocationKind
40 register_index int
41 register_count int
42 stack_offset int
43 size int
44}
45
46// FunctionAbi represents function abi data used by mir.
47pub struct FunctionAbi {
48pub:
49 params []AbiLocation
50 ret AbiLocation
51 stack_args_size int
52 stack_align int
53}
54
55// Value represents value data used by mir.
56pub struct Value {
57pub mut:
58 id int
59 kind ssa.ValueKind
60 typ ssa.TypeID
61 name string
62 index int
63 uses []ssa.ValueID
64}
65
66// Instruction represents instruction data used by mir.
67pub struct Instruction {
68pub mut:
69 op ssa.OpCode
70 operands []ssa.ValueID
71 typ ssa.TypeID
72 block int
73}
74
75// BasicBlock represents basic block data used by mir.
76pub struct BasicBlock {
77pub mut:
78 id int
79 name string
80 parent int
81 instrs []ssa.ValueID
82 preds []ssa.BlockID
83 succs []ssa.BlockID
84}
85
86// Function represents function data used by mir.
87pub struct Function {
88pub mut:
89 id int
90 name string
91 typ ssa.TypeID
92 blocks []ssa.BlockID
93 params []ssa.ValueID
94 is_c_extern bool
95 abi FunctionAbi
96}
97
98// Module represents module data used by mir.
99@[heap]
100pub struct Module {
101pub mut:
102 target Target
103 type_store ssa.TypeStore
104 values []Value
105 instrs []Instruction
106 blocks []BasicBlock
107 funcs []Function
108 globals []ssa.GlobalVar
109}
110
111// default_target returns a conservative target descriptor for target-neutral MIR.
112pub fn default_target() Target {
113 return Target{
114 arch: .unknown
115 abi: .unknown
116 pointer_size: 8
117 stack_align: 8
118 }
119}
120
121// arm64_target returns the target descriptor used by the native ARM64 pipeline.
122pub fn arm64_target() Target {
123 return Target{
124 arch: .arm64
125 abi: .aapcs64
126 pointer_size: 8
127 int_arg_regs: 8
128 ret_regs: 8
129 stack_align: 16
130 }
131}
132
133// lower_from_ssa lowers an SSA module into target-neutral MIR.
134pub fn lower_from_ssa(m &ssa.Module) Module {
135 return lower_from_ssa_for_target(m, default_target())
136}
137
138// lower_from_ssa_for_target lowers an SSA module into MIR with target ABI metadata.
139pub fn lower_from_ssa_for_target(m &ssa.Module, target Target) Module {
140 mut mod := Module{
141 target: target
142 type_store: m.type_store
143 values: []Value{len: m.values.len}
144 instrs: []Instruction{len: m.instrs.len}
145 blocks: []BasicBlock{len: m.blocks.len}
146 funcs: []Function{len: m.funcs.len}
147 globals: m.globals
148 }
149
150 for i, val in m.values {
151 mod.values[i] = Value{
152 id: val.id
153 kind: val.kind
154 typ: val.typ
155 name: val.name
156 index: val.index
157 uses: val.uses
158 }
159 }
160
161 for i, instr in m.instrs {
162 mod.instrs[i] = Instruction{
163 op: instr.op
164 operands: instr.operands
165 typ: instr.typ
166 block: instr.block
167 }
168 }
169
170 for i, blk in m.blocks {
171 mod.blocks[i] = BasicBlock{
172 id: blk.id
173 name: blk.name
174 parent: blk.parent
175 instrs: blk.instrs
176 preds: blk.preds
177 succs: blk.succs
178 }
179 }
180
181 for i, f in m.funcs {
182 mod.funcs[i] = Function{
183 id: f.id
184 name: f.name
185 typ: f.typ
186 blocks: f.blocks
187 params: f.params
188 is_c_extern: f.is_c_extern
189 }
190 }
191
192 for i, f in mod.funcs {
193 mut func := f
194 func.abi = mod.build_function_abi(func)
195 mod.funcs[i] = func
196 }
197
198 return mod
199}
200
201// type_size returns type size data for Module.
202pub fn (m &Module) type_size(typ_id ssa.TypeID) int {
203 return m.type_size_inner(typ_id, 0)
204}
205
206// type_size_inner returns type size inner data for Module.
207fn (m &Module) type_size_inner(typ_id ssa.TypeID, depth int) int {
208 if typ_id <= 0 || typ_id >= m.type_store.types.len {
209 return 0
210 }
211 if depth > 32 {
212 return 8
213 }
214 typ := m.type_store.types[typ_id]
215 if typ.width > 0 {
216 return (typ.width + 7) / 8
217 }
218 if typ.elem_type > 0 && typ.fields.len == 0 {
219 return 8
220 }
221 if typ.fields.len == 0 {
222 if typ.params.len > 0 || typ.ret_type > 0 {
223 return 8
224 }
225 return 0
226 }
227 if typ.fields.len > 256 {
228 return 8
229 }
230 mut offset := 0
231 mut max_align := 1
232 for i in 0 .. typ.fields.len {
233 field_typ := typ.fields[i]
234 align := m.type_align_inner(field_typ, depth + 1)
235 if align > max_align {
236 max_align = align
237 }
238 if align > 1 && offset % align != 0 {
239 offset = (offset + align - 1) & ~(align - 1)
240 }
241 offset += m.type_size_inner(field_typ, depth + 1)
242 }
243 total := if max_align > 1 && offset % max_align != 0 {
244 (offset + max_align - 1) & ~(max_align - 1)
245 } else {
246 offset
247 }
248 if total > 0 {
249 return total
250 }
251 return 8
252}
253
254// type_align returns type align data for Module.
255pub fn (m &Module) type_align(typ_id ssa.TypeID) int {
256 return m.type_align_inner(typ_id, 0)
257}
258
259// type_align_inner returns type align inner data for Module.
260fn (m &Module) type_align_inner(typ_id ssa.TypeID, depth int) int {
261 if typ_id <= 0 || typ_id >= m.type_store.types.len {
262 return 1
263 }
264 if depth > 32 {
265 return 8
266 }
267 typ := m.type_store.types[typ_id]
268 if typ.width > 0 {
269 size := (typ.width + 7) / 8
270 if size >= 8 {
271 return 8
272 }
273 if size >= 4 {
274 return 4
275 }
276 return 1
277 }
278 if typ.elem_type > 0 && typ.fields.len == 0 {
279 return 8
280 }
281 if typ.fields.len > 0 {
282 if typ.fields.len > 256 {
283 return 8
284 }
285 mut max_align := 1
286 for i in 0 .. typ.fields.len {
287 field_typ := typ.fields[i]
288 a := m.type_align_inner(field_typ, depth + 1)
289 if a > max_align {
290 max_align = a
291 }
292 }
293 return max_align
294 }
295 if typ.params.len > 0 || typ.ret_type > 0 {
296 return 8
297 }
298 size := m.type_size_inner(typ_id, depth + 1)
299 if size >= 8 {
300 return 8
301 }
302 if size >= 4 {
303 return 4
304 }
305 return 1
306}
307
308// build_function_abi builds function abi data for mir.
309fn (m &Module) build_function_abi(f Function) FunctionAbi {
310 mut params := []AbiLocation{}
311 mut next_reg := 0
312 mut next_stack := 0
313 word_size := m.target_word_size()
314 for pid in f.params {
315 size := m.value_size(pid)
316 n_words := words_for(size, word_size)
317 if m.target.int_arg_regs > 0 && next_reg + n_words <= m.target.int_arg_regs {
318 params << AbiLocation{
319 kind: .register
320 register_index: next_reg
321 register_count: n_words
322 size: size
323 }
324 next_reg += n_words
325 continue
326 }
327 stack_offset := align_to(next_stack, word_size)
328 params << AbiLocation{
329 kind: .stack
330 register_count: n_words
331 stack_offset: stack_offset
332 size: size
333 }
334 next_stack = stack_offset + align_to(size, word_size)
335 }
336
337 ret_size := m.type_size(f.typ)
338 ret_words := words_for(ret_size, word_size)
339 ret := if ret_size == 0 {
340 AbiLocation{
341 kind: .none
342 }
343 } else if m.target.ret_regs > 0 && ret_words <= m.target.ret_regs {
344 AbiLocation{
345 kind: .register
346 register_index: 0
347 register_count: ret_words
348 size: ret_size
349 }
350 } else {
351 AbiLocation{
352 kind: .indirect
353 register_index: 0
354 register_count: 1
355 size: ret_size
356 }
357 }
358 return FunctionAbi{
359 params: params
360 ret: ret
361 stack_args_size: align_to(next_stack, m.target_stack_align())
362 stack_align: m.target_stack_align()
363 }
364}
365
366// value_size returns value size data for Module.
367fn (m &Module) value_size(val_id ssa.ValueID) int {
368 if val_id <= 0 || val_id >= m.values.len {
369 return m.target_word_size()
370 }
371 size := m.type_size(m.values[val_id].typ)
372 if size > 0 {
373 return size
374 }
375 return m.target_word_size()
376}
377
378// target_word_size supports target word size handling for Module.
379fn (m &Module) target_word_size() int {
380 if m.target.pointer_size > 0 {
381 return m.target.pointer_size
382 }
383 return 8
384}
385
386// target_stack_align supports target stack align handling for Module.
387fn (m &Module) target_stack_align() int {
388 if m.target.stack_align > 0 {
389 return m.target.stack_align
390 }
391 return m.target_word_size()
392}
393
394// words_for supports words for handling for mir.
395fn words_for(size int, word_size int) int {
396 if size <= 0 {
397 return 0
398 }
399 return (size + word_size - 1) / word_size
400}
401
402// align_to supports align to handling for mir.
403fn align_to(value int, alignment int) int {
404 if alignment <= 1 {
405 return value
406 }
407 return (value + alignment - 1) & ~(alignment - 1)
408}
409