master
1//! Machine Intermediate Representation.
2//! This representation is produced by wasm Codegen.
3//! Each of these instructions have a 1:1 mapping to a wasm opcode,
4//! but may contain metadata for a specific opcode such as an immediate.
5//! MIR can be lowered to both textual code (wat) and binary format (wasm).
6//! The main benefits of MIR is optimization passes, pre-allocated locals,
7//! and known jump labels for blocks.
8
9const Mir = @This();
10const InternPool = @import("../../InternPool.zig");
11const Wasm = @import("../../link/Wasm.zig");
12const Emit = @import("Emit.zig");
13const Alignment = InternPool.Alignment;
14
15const builtin = @import("builtin");
16const std = @import("std");
17const assert = std.debug.assert;
18const leb = std.leb;
19
20instructions: std.MultiArrayList(Inst).Slice,
21/// A slice of indexes where the meaning of the data is determined by the
22/// `Inst.Tag` value.
23extra: []const u32,
24locals: []const std.wasm.Valtype,
25prologue: Prologue,
26
27/// Not directly used by `Emit`, but the linker needs this to merge it with a global set.
28/// Value is the explicit alignment if greater than natural alignment, `.none` otherwise.
29uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
30/// Not directly used by `Emit`, but the linker needs this to merge it with a global set.
31indirect_function_set: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void),
32/// Not directly used by `Emit`, but the linker needs this to ensure these types are interned.
33func_tys: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
34/// Not directly used by `Emit`, but the linker needs this to add it to its own refcount.
35error_name_table_ref_count: u32,
36
37pub const Prologue = extern struct {
38 flags: Flags,
39 sp_local: u32,
40 stack_size: u32,
41 bottom_stack_local: u32,
42
43 pub const Flags = packed struct(u32) {
44 stack_alignment: Alignment,
45 padding: u26 = 0,
46 };
47
48 pub const none: Prologue = .{
49 .sp_local = 0,
50 .flags = .{ .stack_alignment = .none },
51 .stack_size = 0,
52 .bottom_stack_local = 0,
53 };
54
55 pub fn isNone(p: *const Prologue) bool {
56 return p.flags.stack_alignment != .none;
57 }
58};
59
60pub const Inst = struct {
61 /// The opcode that represents this instruction
62 tag: Tag,
63 /// Data is determined by the set `tag`.
64 /// For example, `data` will be an i32 for when `tag` is 'i32_const'.
65 data: Data,
66
67 /// The position of a given MIR isntruction with the instruction list.
68 pub const Index = u32;
69
70 /// Some tags match wasm opcode values to facilitate trivial lowering.
71 pub const Tag = enum(u8) {
72 /// Uses `tag`.
73 @"unreachable" = 0x00,
74 /// Emits epilogue begin debug information. Marks the end of the function.
75 ///
76 /// Uses `tag` (no additional data).
77 dbg_epilogue_begin,
78 /// Creates a new block that can be jump from.
79 ///
80 /// Type of the block is given in data `block_type`
81 block = 0x02,
82 /// Creates a new loop.
83 ///
84 /// Type of the loop is given in data `block_type`
85 loop = 0x03,
86 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
87 /// memory address of an unnamed constant. When emitting an object
88 /// file, this adds a relocation.
89 ///
90 /// This may not refer to a function.
91 ///
92 /// Uses `ip_index`.
93 uav_ref,
94 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
95 /// memory address of an unnamed constant, offset by an integer value.
96 /// When emitting an object file, this adds a relocation.
97 ///
98 /// This may not refer to a function.
99 ///
100 /// Uses `payload` pointing to a `UavRefOff`.
101 uav_ref_off,
102 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
103 /// memory address of a named constant.
104 ///
105 /// May not refer to a function.
106 ///
107 /// Uses `nav_index`.
108 nav_ref,
109 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
110 /// memory address of named constant, offset by an integer value.
111 /// When emitting an object file, this adds a relocation.
112 ///
113 /// May not refer to a function.
114 ///
115 /// Uses `payload` pointing to a `NavRefOff`.
116 nav_ref_off,
117 /// Lowers to an i32_const which is the index of the function in the
118 /// table section.
119 ///
120 /// Uses `nav_index`.
121 func_ref,
122 /// Inserts debug information about the current line and column
123 /// of the source code
124 ///
125 /// Uses `payload` of which the payload type is `DbgLineColumn`
126 dbg_line,
127 /// Lowers to an i32_const containing the number of unique Zig error
128 /// names.
129 /// Uses `tag`.
130 errors_len,
131 /// Represents the end of a function body or an initialization expression
132 ///
133 /// Uses `tag` (no additional data).
134 end = 0x0B,
135 /// Breaks from the current block to a label
136 ///
137 /// Uses `label` where index represents the label to jump to
138 br = 0x0C,
139 /// Breaks from the current block if the stack value is non-zero
140 ///
141 /// Uses `label` where index represents the label to jump to
142 br_if = 0x0D,
143 /// Jump table that takes the stack value as an index where each value
144 /// represents the label to jump to.
145 ///
146 /// Data is extra of which the Payload's type is `JumpTable`
147 br_table,
148 /// Returns from the function
149 ///
150 /// Uses `tag`.
151 @"return" = 0x0F,
152 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) containing
153 /// the base address of the table of error code names, with each
154 /// element being a null-terminated slice.
155 ///
156 /// Uses `tag`.
157 error_name_table_ref,
158 /// Calls a function using `nav_index`.
159 call_nav,
160 /// Calls a function pointer by its function signature
161 /// and index into the function table.
162 ///
163 /// Uses `ip_index`; the `InternPool.Index` is the function type.
164 call_indirect,
165 /// Calls a function by its index.
166 ///
167 /// The function is the auto-generated tag name function for the type
168 /// provided in `ip_index`.
169 call_tag_name,
170 /// Lowers to a `call` instruction, using `intrinsic`.
171 call_intrinsic,
172 /// Pops three values from the stack and pushes
173 /// the first or second value dependent on the third value.
174 /// Uses `tag`
175 select = 0x1B,
176 /// Loads a local at given index onto the stack.
177 ///
178 /// Uses `label`
179 local_get = 0x20,
180 /// Pops a value from the stack into the local at given index.
181 /// Stack value must be of the same type as the local.
182 ///
183 /// Uses `label`
184 local_set = 0x21,
185 /// Sets a local at given index using the value at the top of the stack without popping the value.
186 /// Stack value must have the same type as the local.
187 ///
188 /// Uses `label`
189 local_tee = 0x22,
190 /// Pops a value from the stack and sets the stack pointer global.
191 /// The value must be the same type as the stack pointer global.
192 ///
193 /// Uses `tag` (no additional data).
194 global_set_sp,
195 /// Loads a 32-bit integer from memory (data section) onto the stack
196 /// Pops the value from the stack which represents the offset into memory.
197 ///
198 /// Uses `payload` of type `MemArg`.
199 i32_load = 0x28,
200 /// Loads a value from memory onto the stack, based on the signedness
201 /// and bitsize of the type.
202 ///
203 /// Uses `payload` with type `MemArg`
204 i64_load = 0x29,
205 /// Loads a value from memory onto the stack, based on the signedness
206 /// and bitsize of the type.
207 ///
208 /// Uses `payload` with type `MemArg`
209 f32_load = 0x2A,
210 /// Loads a value from memory onto the stack, based on the signedness
211 /// and bitsize of the type.
212 ///
213 /// Uses `payload` with type `MemArg`
214 f64_load = 0x2B,
215 /// Loads a value from memory onto the stack, based on the signedness
216 /// and bitsize of the type.
217 ///
218 /// Uses `payload` with type `MemArg`
219 i32_load8_s = 0x2C,
220 /// Loads a value from memory onto the stack, based on the signedness
221 /// and bitsize of the type.
222 ///
223 /// Uses `payload` with type `MemArg`
224 i32_load8_u = 0x2D,
225 /// Loads a value from memory onto the stack, based on the signedness
226 /// and bitsize of the type.
227 ///
228 /// Uses `payload` with type `MemArg`
229 i32_load16_s = 0x2E,
230 /// Loads a value from memory onto the stack, based on the signedness
231 /// and bitsize of the type.
232 ///
233 /// Uses `payload` with type `MemArg`
234 i32_load16_u = 0x2F,
235 /// Loads a value from memory onto the stack, based on the signedness
236 /// and bitsize of the type.
237 ///
238 /// Uses `payload` with type `MemArg`
239 i64_load8_s = 0x30,
240 /// Loads a value from memory onto the stack, based on the signedness
241 /// and bitsize of the type.
242 ///
243 /// Uses `payload` with type `MemArg`
244 i64_load8_u = 0x31,
245 /// Loads a value from memory onto the stack, based on the signedness
246 /// and bitsize of the type.
247 ///
248 /// Uses `payload` with type `MemArg`
249 i64_load16_s = 0x32,
250 /// Loads a value from memory onto the stack, based on the signedness
251 /// and bitsize of the type.
252 ///
253 /// Uses `payload` with type `MemArg`
254 i64_load16_u = 0x33,
255 /// Loads a value from memory onto the stack, based on the signedness
256 /// and bitsize of the type.
257 ///
258 /// Uses `payload` with type `MemArg`
259 i64_load32_s = 0x34,
260 /// Loads a value from memory onto the stack, based on the signedness
261 /// and bitsize of the type.
262 ///
263 /// Uses `payload` with type `MemArg`
264 i64_load32_u = 0x35,
265 /// Pops 2 values from the stack, where the first value represents the value to write into memory
266 /// and the second value represents the offset into memory where the value must be written to.
267 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
268 ///
269 /// Uses `payload` of type `MemArg`.
270 i32_store = 0x36,
271 /// Pops 2 values from the stack, where the first value represents the value to write into memory
272 /// and the second value represents the offset into memory where the value must be written to.
273 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
274 ///
275 /// Uses `Payload` with type `MemArg`
276 i64_store = 0x37,
277 /// Pops 2 values from the stack, where the first value represents the value to write into memory
278 /// and the second value represents the offset into memory where the value must be written to.
279 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
280 ///
281 /// Uses `Payload` with type `MemArg`
282 f32_store = 0x38,
283 /// Pops 2 values from the stack, where the first value represents the value to write into memory
284 /// and the second value represents the offset into memory where the value must be written to.
285 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
286 ///
287 /// Uses `Payload` with type `MemArg`
288 f64_store = 0x39,
289 /// Pops 2 values from the stack, where the first value represents the value to write into memory
290 /// and the second value represents the offset into memory where the value must be written to.
291 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
292 ///
293 /// Uses `Payload` with type `MemArg`
294 i32_store8 = 0x3A,
295 /// Pops 2 values from the stack, where the first value represents the value to write into memory
296 /// and the second value represents the offset into memory where the value must be written to.
297 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
298 ///
299 /// Uses `Payload` with type `MemArg`
300 i32_store16 = 0x3B,
301 /// Pops 2 values from the stack, where the first value represents the value to write into memory
302 /// and the second value represents the offset into memory where the value must be written to.
303 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
304 ///
305 /// Uses `Payload` with type `MemArg`
306 i64_store8 = 0x3C,
307 /// Pops 2 values from the stack, where the first value represents the value to write into memory
308 /// and the second value represents the offset into memory where the value must be written to.
309 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
310 ///
311 /// Uses `Payload` with type `MemArg`
312 i64_store16 = 0x3D,
313 /// Pops 2 values from the stack, where the first value represents the value to write into memory
314 /// and the second value represents the offset into memory where the value must be written to.
315 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
316 ///
317 /// Uses `Payload` with type `MemArg`
318 i64_store32 = 0x3E,
319 /// Returns the memory size in amount of pages.
320 ///
321 /// Uses `label`
322 memory_size = 0x3F,
323 /// Increases the memory by given number of pages.
324 ///
325 /// Uses `label`
326 memory_grow = 0x40,
327 /// Loads a 32-bit signed immediate value onto the stack
328 ///
329 /// Uses `imm32`
330 i32_const,
331 /// Loads a i64-bit signed immediate value onto the stack
332 ///
333 /// uses `payload` of type `Imm64`
334 i64_const,
335 /// Loads a 32-bit float value onto the stack.
336 ///
337 /// Uses `float32`
338 f32_const,
339 /// Loads a 64-bit float value onto the stack.
340 ///
341 /// Uses `payload` of type `Float64`
342 f64_const,
343 /// Uses `tag`
344 i32_eqz = 0x45,
345 /// Uses `tag`
346 i32_eq = 0x46,
347 /// Uses `tag`
348 i32_ne = 0x47,
349 /// Uses `tag`
350 i32_lt_s = 0x48,
351 /// Uses `tag`
352 i32_lt_u = 0x49,
353 /// Uses `tag`
354 i32_gt_s = 0x4A,
355 /// Uses `tag`
356 i32_gt_u = 0x4B,
357 /// Uses `tag`
358 i32_le_s = 0x4C,
359 /// Uses `tag`
360 i32_le_u = 0x4D,
361 /// Uses `tag`
362 i32_ge_s = 0x4E,
363 /// Uses `tag`
364 i32_ge_u = 0x4F,
365 /// Uses `tag`
366 i64_eqz = 0x50,
367 /// Uses `tag`
368 i64_eq = 0x51,
369 /// Uses `tag`
370 i64_ne = 0x52,
371 /// Uses `tag`
372 i64_lt_s = 0x53,
373 /// Uses `tag`
374 i64_lt_u = 0x54,
375 /// Uses `tag`
376 i64_gt_s = 0x55,
377 /// Uses `tag`
378 i64_gt_u = 0x56,
379 /// Uses `tag`
380 i64_le_s = 0x57,
381 /// Uses `tag`
382 i64_le_u = 0x58,
383 /// Uses `tag`
384 i64_ge_s = 0x59,
385 /// Uses `tag`
386 i64_ge_u = 0x5A,
387 /// Uses `tag`
388 f32_eq = 0x5B,
389 /// Uses `tag`
390 f32_ne = 0x5C,
391 /// Uses `tag`
392 f32_lt = 0x5D,
393 /// Uses `tag`
394 f32_gt = 0x5E,
395 /// Uses `tag`
396 f32_le = 0x5F,
397 /// Uses `tag`
398 f32_ge = 0x60,
399 /// Uses `tag`
400 f64_eq = 0x61,
401 /// Uses `tag`
402 f64_ne = 0x62,
403 /// Uses `tag`
404 f64_lt = 0x63,
405 /// Uses `tag`
406 f64_gt = 0x64,
407 /// Uses `tag`
408 f64_le = 0x65,
409 /// Uses `tag`
410 f64_ge = 0x66,
411 /// Uses `tag`
412 i32_clz = 0x67,
413 /// Uses `tag`
414 i32_ctz = 0x68,
415 /// Uses `tag`
416 i32_popcnt = 0x69,
417 /// Uses `tag`
418 i32_add = 0x6A,
419 /// Uses `tag`
420 i32_sub = 0x6B,
421 /// Uses `tag`
422 i32_mul = 0x6C,
423 /// Uses `tag`
424 i32_div_s = 0x6D,
425 /// Uses `tag`
426 i32_div_u = 0x6E,
427 /// Uses `tag`
428 i32_rem_s = 0x6F,
429 /// Uses `tag`
430 i32_rem_u = 0x70,
431 /// Uses `tag`
432 i32_and = 0x71,
433 /// Uses `tag`
434 i32_or = 0x72,
435 /// Uses `tag`
436 i32_xor = 0x73,
437 /// Uses `tag`
438 i32_shl = 0x74,
439 /// Uses `tag`
440 i32_shr_s = 0x75,
441 /// Uses `tag`
442 i32_shr_u = 0x76,
443 /// Uses `tag`
444 i64_clz = 0x79,
445 /// Uses `tag`
446 i64_ctz = 0x7A,
447 /// Uses `tag`
448 i64_popcnt = 0x7B,
449 /// Uses `tag`
450 i64_add = 0x7C,
451 /// Uses `tag`
452 i64_sub = 0x7D,
453 /// Uses `tag`
454 i64_mul = 0x7E,
455 /// Uses `tag`
456 i64_div_s = 0x7F,
457 /// Uses `tag`
458 i64_div_u = 0x80,
459 /// Uses `tag`
460 i64_rem_s = 0x81,
461 /// Uses `tag`
462 i64_rem_u = 0x82,
463 /// Uses `tag`
464 i64_and = 0x83,
465 /// Uses `tag`
466 i64_or = 0x84,
467 /// Uses `tag`
468 i64_xor = 0x85,
469 /// Uses `tag`
470 i64_shl = 0x86,
471 /// Uses `tag`
472 i64_shr_s = 0x87,
473 /// Uses `tag`
474 i64_shr_u = 0x88,
475 /// Uses `tag`
476 f32_abs = 0x8B,
477 /// Uses `tag`
478 f32_neg = 0x8C,
479 /// Uses `tag`
480 f32_ceil = 0x8D,
481 /// Uses `tag`
482 f32_floor = 0x8E,
483 /// Uses `tag`
484 f32_trunc = 0x8F,
485 /// Uses `tag`
486 f32_nearest = 0x90,
487 /// Uses `tag`
488 f32_sqrt = 0x91,
489 /// Uses `tag`
490 f32_add = 0x92,
491 /// Uses `tag`
492 f32_sub = 0x93,
493 /// Uses `tag`
494 f32_mul = 0x94,
495 /// Uses `tag`
496 f32_div = 0x95,
497 /// Uses `tag`
498 f32_min = 0x96,
499 /// Uses `tag`
500 f32_max = 0x97,
501 /// Uses `tag`
502 f32_copysign = 0x98,
503 /// Uses `tag`
504 f64_abs = 0x99,
505 /// Uses `tag`
506 f64_neg = 0x9A,
507 /// Uses `tag`
508 f64_ceil = 0x9B,
509 /// Uses `tag`
510 f64_floor = 0x9C,
511 /// Uses `tag`
512 f64_trunc = 0x9D,
513 /// Uses `tag`
514 f64_nearest = 0x9E,
515 /// Uses `tag`
516 f64_sqrt = 0x9F,
517 /// Uses `tag`
518 f64_add = 0xA0,
519 /// Uses `tag`
520 f64_sub = 0xA1,
521 /// Uses `tag`
522 f64_mul = 0xA2,
523 /// Uses `tag`
524 f64_div = 0xA3,
525 /// Uses `tag`
526 f64_min = 0xA4,
527 /// Uses `tag`
528 f64_max = 0xA5,
529 /// Uses `tag`
530 f64_copysign = 0xA6,
531 /// Uses `tag`
532 i32_wrap_i64 = 0xA7,
533 /// Uses `tag`
534 i32_trunc_f32_s = 0xA8,
535 /// Uses `tag`
536 i32_trunc_f32_u = 0xA9,
537 /// Uses `tag`
538 i32_trunc_f64_s = 0xAA,
539 /// Uses `tag`
540 i32_trunc_f64_u = 0xAB,
541 /// Uses `tag`
542 i64_extend_i32_s = 0xAC,
543 /// Uses `tag`
544 i64_extend_i32_u = 0xAD,
545 /// Uses `tag`
546 i64_trunc_f32_s = 0xAE,
547 /// Uses `tag`
548 i64_trunc_f32_u = 0xAF,
549 /// Uses `tag`
550 i64_trunc_f64_s = 0xB0,
551 /// Uses `tag`
552 i64_trunc_f64_u = 0xB1,
553 /// Uses `tag`
554 f32_convert_i32_s = 0xB2,
555 /// Uses `tag`
556 f32_convert_i32_u = 0xB3,
557 /// Uses `tag`
558 f32_convert_i64_s = 0xB4,
559 /// Uses `tag`
560 f32_convert_i64_u = 0xB5,
561 /// Uses `tag`
562 f32_demote_f64 = 0xB6,
563 /// Uses `tag`
564 f64_convert_i32_s = 0xB7,
565 /// Uses `tag`
566 f64_convert_i32_u = 0xB8,
567 /// Uses `tag`
568 f64_convert_i64_s = 0xB9,
569 /// Uses `tag`
570 f64_convert_i64_u = 0xBA,
571 /// Uses `tag`
572 f64_promote_f32 = 0xBB,
573 /// Uses `tag`
574 i32_reinterpret_f32 = 0xBC,
575 /// Uses `tag`
576 i64_reinterpret_f64 = 0xBD,
577 /// Uses `tag`
578 f32_reinterpret_i32 = 0xBE,
579 /// Uses `tag`
580 f64_reinterpret_i64 = 0xBF,
581 /// Uses `tag`
582 i32_extend8_s = 0xC0,
583 /// Uses `tag`
584 i32_extend16_s = 0xC1,
585 /// Uses `tag`
586 i64_extend8_s = 0xC2,
587 /// Uses `tag`
588 i64_extend16_s = 0xC3,
589 /// Uses `tag`
590 i64_extend32_s = 0xC4,
591 /// The instruction consists of a prefixed opcode.
592 /// The prefixed opcode can be found at payload's index.
593 ///
594 /// The `data` field depends on the extension instruction and
595 /// may contain additional data.
596 misc_prefix,
597 /// The instruction consists of a simd opcode.
598 /// The actual simd-opcode is found at payload's index.
599 ///
600 /// The `data` field depends on the simd instruction and
601 /// may contain additional data.
602 simd_prefix,
603 /// The instruction consists of an atomics opcode.
604 /// The actual atomics-opcode is found at payload's index.
605 ///
606 /// The `data` field depends on the atomics instruction and
607 /// may contain additional data.
608 atomics_prefix = 0xFE,
609
610 /// From a given wasm opcode, returns a MIR tag.
611 pub fn fromOpcode(opcode: std.wasm.Opcode) Tag {
612 return @as(Tag, @enumFromInt(@intFromEnum(opcode))); // Given `Opcode` is not present as a tag for MIR yet
613 }
614
615 /// Returns a wasm opcode from a given MIR tag.
616 pub fn toOpcode(self: Tag) std.wasm.Opcode {
617 return @as(std.wasm.Opcode, @enumFromInt(@intFromEnum(self)));
618 }
619 };
620
621 /// All instructions contain a 4-byte payload, which is contained within
622 /// this union. `Tag` determines which union tag is active, as well as
623 /// how to interpret the data within.
624 pub const Data = union {
625 /// Uses no additional data
626 tag: void,
627 /// Contains the result type of a block
628 block_type: std.wasm.BlockType,
629 /// Label: Each structured control instruction introduces an implicit label.
630 /// Labels are targets for branch instructions that reference them with
631 /// label indices. Unlike with other index spaces, indexing of labels
632 /// is relative by nesting depth, that is, label 0 refers to the
633 /// innermost structured control instruction enclosing the referring
634 /// branch instruction, while increasing indices refer to those farther
635 /// out. Consequently, labels can only be referenced from within the
636 /// associated structured control instruction.
637 label: u32,
638 /// Local: The index space for locals is only accessible inside a function and
639 /// includes the parameters of that function, which precede the local
640 /// variables.
641 local: u32,
642 /// A 32-bit immediate value.
643 imm32: i32,
644 /// A 32-bit float value
645 float32: f32,
646 /// Index into `extra`. Meaning of what can be found there is context-dependent.
647 payload: u32,
648
649 ip_index: InternPool.Index,
650 nav_index: InternPool.Nav.Index,
651 intrinsic: Intrinsic,
652
653 comptime {
654 switch (builtin.mode) {
655 .Debug, .ReleaseSafe => {},
656 .ReleaseFast, .ReleaseSmall => assert(@sizeOf(Data) == 4),
657 }
658 }
659 };
660};
661
662pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
663 mir.instructions.deinit(gpa);
664 gpa.free(mir.extra);
665 gpa.free(mir.locals);
666 mir.uavs.deinit(gpa);
667 mir.indirect_function_set.deinit(gpa);
668 mir.func_tys.deinit(gpa);
669 mir.* = undefined;
670}
671
672pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayList(u8)) std.mem.Allocator.Error!void {
673 const gpa = wasm.base.comp.gpa;
674
675 // Write the locals in the prologue of the function body.
676 try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38);
677
678 var w: std.Io.Writer = .fixed(code.unusedCapacitySlice());
679
680 w.writeLeb128(@as(u32, @intCast(mir.locals.len))) catch unreachable;
681
682 for (mir.locals) |local| {
683 w.writeLeb128(@as(u32, 1)) catch unreachable;
684 w.writeByte(@intFromEnum(local)) catch unreachable;
685 }
686
687 // Stack management section of function prologue.
688 const stack_alignment = mir.prologue.flags.stack_alignment;
689 if (stack_alignment.toByteUnits()) |align_bytes| {
690 const sp_global: Wasm.GlobalIndex = .stack_pointer;
691 // load stack pointer
692 w.writeByte(@intFromEnum(std.wasm.Opcode.global_get)) catch unreachable;
693 w.writeUleb128(@intFromEnum(sp_global)) catch unreachable;
694 // store stack pointer so we can restore it when we return from the function
695 w.writeByte(@intFromEnum(std.wasm.Opcode.local_tee)) catch unreachable;
696 w.writeUleb128(mir.prologue.sp_local) catch unreachable;
697 // get the total stack size
698 const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size));
699 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)) catch unreachable;
700 w.writeSleb128(aligned_stack) catch unreachable;
701 // subtract it from the current stack pointer
702 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_sub)) catch unreachable;
703 // Get negative stack alignment
704 const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1;
705 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)) catch unreachable;
706 w.writeSleb128(neg_stack_align) catch unreachable;
707 // Bitwise-and the value to get the new stack pointer to ensure the
708 // pointers are aligned with the abi alignment.
709 w.writeByte(@intFromEnum(std.wasm.Opcode.i32_and)) catch unreachable;
710 // The bottom will be used to calculate all stack pointer offsets.
711 w.writeByte(@intFromEnum(std.wasm.Opcode.local_tee)) catch unreachable;
712 w.writeUleb128(mir.prologue.bottom_stack_local) catch unreachable;
713 // Store the current stack pointer value into the global stack pointer so other function calls will
714 // start from this value instead and not overwrite the current stack.
715 w.writeByte(@intFromEnum(std.wasm.Opcode.global_set)) catch unreachable;
716 w.writeUleb128(@intFromEnum(sp_global)) catch unreachable;
717 }
718
719 code.items.len += w.end;
720
721 var emit: Emit = .{
722 .mir = mir.*,
723 .wasm = wasm,
724 .code = code,
725 };
726 try emit.lowerToCode();
727}
728
729pub fn extraData(self: *const Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
730 const fields = std.meta.fields(T);
731 var i: usize = index;
732 var result: T = undefined;
733 inline for (fields) |field| {
734 @field(result, field.name) = switch (field.type) {
735 u32 => self.extra[i],
736 i32 => @bitCast(self.extra[i]),
737 Wasm.UavsObjIndex,
738 Wasm.UavsExeIndex,
739 InternPool.Nav.Index,
740 InternPool.Index,
741 => @enumFromInt(self.extra[i]),
742 else => |field_type| @compileError("Unsupported field type " ++ @typeName(field_type)),
743 };
744 i += 1;
745 }
746
747 return .{ .data = result, .end = i };
748}
749
750pub const JumpTable = struct {
751 /// Length of the jump table and the amount of entries it contains (includes default)
752 length: u32,
753};
754
755pub const Imm64 = struct {
756 msb: u32,
757 lsb: u32,
758
759 pub fn init(full: u64) Imm64 {
760 return .{
761 .msb = @truncate(full >> 32),
762 .lsb = @truncate(full),
763 };
764 }
765
766 pub fn toInt(i: Imm64) u64 {
767 return (@as(u64, i.msb) << 32) | @as(u64, i.lsb);
768 }
769};
770
771pub const Float64 = struct {
772 msb: u32,
773 lsb: u32,
774
775 pub fn init(f: f64) Float64 {
776 const int: u64 = @bitCast(f);
777 return .{
778 .msb = @truncate(int >> 32),
779 .lsb = @truncate(int),
780 };
781 }
782
783 pub fn toInt(f: Float64) u64 {
784 return (@as(u64, f.msb) << 32) | @as(u64, f.lsb);
785 }
786};
787
788pub const MemArg = struct {
789 offset: u32,
790 alignment: u32,
791};
792
793pub const UavRefOff = struct {
794 value: InternPool.Index,
795 offset: i32,
796};
797
798pub const NavRefOff = struct {
799 nav_index: InternPool.Nav.Index,
800 offset: i32,
801};
802
803/// Maps a source line with wasm bytecode
804pub const DbgLineColumn = struct {
805 line: u32,
806 column: u32,
807};
808
809/// Tag names exactly match the corresponding symbol name.
810pub const Intrinsic = enum(u32) {
811 __addhf3,
812 __addtf3,
813 __addxf3,
814 __ashlti3,
815 __ashrti3,
816 __bitreversedi2,
817 __bitreversesi2,
818 __bswapdi2,
819 __bswapsi2,
820 __ceilh,
821 __ceilx,
822 __cosh,
823 __cosx,
824 __divhf3,
825 __divtf3,
826 __divti3,
827 __divxf3,
828 __eqtf2,
829 __eqxf2,
830 __exp2h,
831 __exp2x,
832 __exph,
833 __expx,
834 __extenddftf2,
835 __extenddfxf2,
836 __extendhfsf2,
837 __extendhftf2,
838 __extendhfxf2,
839 __extendsftf2,
840 __extendsfxf2,
841 __extendxftf2,
842 __fabsh,
843 __fabsx,
844 __fixdfdi,
845 __fixdfsi,
846 __fixdfti,
847 __fixhfdi,
848 __fixhfsi,
849 __fixhfti,
850 __fixsfdi,
851 __fixsfsi,
852 __fixsfti,
853 __fixtfdi,
854 __fixtfsi,
855 __fixtfti,
856 __fixunsdfdi,
857 __fixunsdfsi,
858 __fixunsdfti,
859 __fixunshfdi,
860 __fixunshfsi,
861 __fixunshfti,
862 __fixunssfdi,
863 __fixunssfsi,
864 __fixunssfti,
865 __fixunstfdi,
866 __fixunstfsi,
867 __fixunstfti,
868 __fixunsxfdi,
869 __fixunsxfsi,
870 __fixunsxfti,
871 __fixxfdi,
872 __fixxfsi,
873 __fixxfti,
874 __floatdidf,
875 __floatdihf,
876 __floatdisf,
877 __floatditf,
878 __floatdixf,
879 __floatsidf,
880 __floatsihf,
881 __floatsisf,
882 __floatsitf,
883 __floatsixf,
884 __floattidf,
885 __floattihf,
886 __floattisf,
887 __floattitf,
888 __floattixf,
889 __floatundidf,
890 __floatundihf,
891 __floatundisf,
892 __floatunditf,
893 __floatundixf,
894 __floatunsidf,
895 __floatunsihf,
896 __floatunsisf,
897 __floatunsitf,
898 __floatunsixf,
899 __floatuntidf,
900 __floatuntihf,
901 __floatuntisf,
902 __floatuntitf,
903 __floatuntixf,
904 __floorh,
905 __floorx,
906 __fmah,
907 __fmax,
908 __fmaxh,
909 __fmaxx,
910 __fminh,
911 __fminx,
912 __fmodh,
913 __fmodx,
914 __getf2,
915 __gexf2,
916 __gttf2,
917 __gtxf2,
918 __letf2,
919 __lexf2,
920 __log10h,
921 __log10x,
922 __log2h,
923 __log2x,
924 __logh,
925 __logx,
926 __lshrti3,
927 __lttf2,
928 __ltxf2,
929 __modti3,
930 __mulhf3,
931 __mulodi4,
932 __muloti4,
933 __multf3,
934 __multi3,
935 __mulxf3,
936 __netf2,
937 __nexf2,
938 __roundh,
939 __roundx,
940 __sinh,
941 __sinx,
942 __sqrth,
943 __sqrtx,
944 __subhf3,
945 __subtf3,
946 __subxf3,
947 __tanh,
948 __tanx,
949 __trunch,
950 __truncsfhf2,
951 __trunctfdf2,
952 __trunctfhf2,
953 __trunctfsf2,
954 __trunctfxf2,
955 __truncx,
956 __truncxfdf2,
957 __truncxfhf2,
958 __truncxfsf2,
959 __udivti3,
960 __umodti3,
961 ceilq,
962 cos,
963 cosf,
964 cosq,
965 exp,
966 exp2,
967 exp2f,
968 exp2q,
969 expf,
970 expq,
971 fabsq,
972 floorq,
973 fma,
974 fmaf,
975 fmaq,
976 fmax,
977 fmaxf,
978 fmaxq,
979 fmin,
980 fminf,
981 fminq,
982 fmod,
983 fmodf,
984 fmodq,
985 log,
986 log10,
987 log10f,
988 log10q,
989 log2,
990 log2f,
991 log2q,
992 logf,
993 logq,
994 roundq,
995 sin,
996 sinf,
997 sinq,
998 sqrtq,
999 tan,
1000 tanf,
1001 tanq,
1002 truncq,
1003};