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.array_hash_map.Auto(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.array_hash_map.Auto(InternPool.Nav.Index, void),
32/// Not directly used by `Emit`, but the linker needs this to ensure these types are interned.
33func_tys: std.array_hash_map.Auto(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 iNN_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 index function for the type
168 /// provided in `ip_index`.
169 call_tag_index,
170 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) containing
171 /// the base address of the table of enum tag names slices.
172 ///
173 /// Uses `ip_index`.
174 enum_tag_name_table_ref,
175 /// Lowers to a `call` instruction, using `intrinsic`.
176 call_intrinsic,
177 /// Pops a value from the stack, and discards it.
178 ///
179 /// Uses `tag` (no additional data).
180 drop = 0x1A,
181 /// Pops three values from the stack and pushes
182 /// the first or second value dependent on the third value.
183 /// Uses `tag`
184 select = 0x1B,
185 /// Loads a local at given index onto the stack.
186 ///
187 /// Uses `label`
188 local_get = 0x20,
189 /// Pops a value from the stack into the local at given index.
190 /// Stack value must be of the same type as the local.
191 ///
192 /// Uses `label`
193 local_set = 0x21,
194 /// Sets a local at given index using the value at the top of the stack without popping the value.
195 /// Stack value must have the same type as the local.
196 ///
197 /// Uses `label`
198 local_tee = 0x22,
199 /// Pops a value from the stack and sets the stack pointer global.
200 /// The value must be the same type as the stack pointer global.
201 ///
202 /// Uses `tag` (no additional data).
203 global_set_sp,
204 /// Loads a 32-bit integer from memory (data section) onto the stack
205 /// Pops the value from the stack which represents the offset into memory.
206 ///
207 /// Uses `payload` of type `MemArg`.
208 i32_load = 0x28,
209 /// Loads a value from memory onto the stack, based on the signedness
210 /// and bitsize of the type.
211 ///
212 /// Uses `payload` with type `MemArg`
213 i64_load = 0x29,
214 /// Loads a value from memory onto the stack, based on the signedness
215 /// and bitsize of the type.
216 ///
217 /// Uses `payload` with type `MemArg`
218 f32_load = 0x2A,
219 /// Loads a value from memory onto the stack, based on the signedness
220 /// and bitsize of the type.
221 ///
222 /// Uses `payload` with type `MemArg`
223 f64_load = 0x2B,
224 /// Loads a value from memory onto the stack, based on the signedness
225 /// and bitsize of the type.
226 ///
227 /// Uses `payload` with type `MemArg`
228 i32_load8_s = 0x2C,
229 /// Loads a value from memory onto the stack, based on the signedness
230 /// and bitsize of the type.
231 ///
232 /// Uses `payload` with type `MemArg`
233 i32_load8_u = 0x2D,
234 /// Loads a value from memory onto the stack, based on the signedness
235 /// and bitsize of the type.
236 ///
237 /// Uses `payload` with type `MemArg`
238 i32_load16_s = 0x2E,
239 /// Loads a value from memory onto the stack, based on the signedness
240 /// and bitsize of the type.
241 ///
242 /// Uses `payload` with type `MemArg`
243 i32_load16_u = 0x2F,
244 /// Loads a value from memory onto the stack, based on the signedness
245 /// and bitsize of the type.
246 ///
247 /// Uses `payload` with type `MemArg`
248 i64_load8_s = 0x30,
249 /// Loads a value from memory onto the stack, based on the signedness
250 /// and bitsize of the type.
251 ///
252 /// Uses `payload` with type `MemArg`
253 i64_load8_u = 0x31,
254 /// Loads a value from memory onto the stack, based on the signedness
255 /// and bitsize of the type.
256 ///
257 /// Uses `payload` with type `MemArg`
258 i64_load16_s = 0x32,
259 /// Loads a value from memory onto the stack, based on the signedness
260 /// and bitsize of the type.
261 ///
262 /// Uses `payload` with type `MemArg`
263 i64_load16_u = 0x33,
264 /// Loads a value from memory onto the stack, based on the signedness
265 /// and bitsize of the type.
266 ///
267 /// Uses `payload` with type `MemArg`
268 i64_load32_s = 0x34,
269 /// Loads a value from memory onto the stack, based on the signedness
270 /// and bitsize of the type.
271 ///
272 /// Uses `payload` with type `MemArg`
273 i64_load32_u = 0x35,
274 /// Pops 2 values from the stack, where the first value represents the value to write into memory
275 /// and the second value represents the offset into memory where the value must be written to.
276 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
277 ///
278 /// Uses `payload` of type `MemArg`.
279 i32_store = 0x36,
280 /// Pops 2 values from the stack, where the first value represents the value to write into memory
281 /// and the second value represents the offset into memory where the value must be written to.
282 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
283 ///
284 /// Uses `Payload` with type `MemArg`
285 i64_store = 0x37,
286 /// Pops 2 values from the stack, where the first value represents the value to write into memory
287 /// and the second value represents the offset into memory where the value must be written to.
288 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
289 ///
290 /// Uses `Payload` with type `MemArg`
291 f32_store = 0x38,
292 /// Pops 2 values from the stack, where the first value represents the value to write into memory
293 /// and the second value represents the offset into memory where the value must be written to.
294 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
295 ///
296 /// Uses `Payload` with type `MemArg`
297 f64_store = 0x39,
298 /// Pops 2 values from the stack, where the first value represents the value to write into memory
299 /// and the second value represents the offset into memory where the value must be written to.
300 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
301 ///
302 /// Uses `Payload` with type `MemArg`
303 i32_store8 = 0x3A,
304 /// Pops 2 values from the stack, where the first value represents the value to write into memory
305 /// and the second value represents the offset into memory where the value must be written to.
306 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
307 ///
308 /// Uses `Payload` with type `MemArg`
309 i32_store16 = 0x3B,
310 /// Pops 2 values from the stack, where the first value represents the value to write into memory
311 /// and the second value represents the offset into memory where the value must be written to.
312 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
313 ///
314 /// Uses `Payload` with type `MemArg`
315 i64_store8 = 0x3C,
316 /// Pops 2 values from the stack, where the first value represents the value to write into memory
317 /// and the second value represents the offset into memory where the value must be written to.
318 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
319 ///
320 /// Uses `Payload` with type `MemArg`
321 i64_store16 = 0x3D,
322 /// Pops 2 values from the stack, where the first value represents the value to write into memory
323 /// and the second value represents the offset into memory where the value must be written to.
324 /// This opcode is typed and expects the stack value's type to be equal to this opcode's type.
325 ///
326 /// Uses `Payload` with type `MemArg`
327 i64_store32 = 0x3E,
328 /// Returns the memory size in amount of pages.
329 ///
330 /// Uses `label`
331 memory_size = 0x3F,
332 /// Increases the memory by given number of pages.
333 ///
334 /// Uses `label`
335 memory_grow = 0x40,
336 /// Loads a 32-bit signed immediate value onto the stack
337 ///
338 /// Uses `imm32`
339 i32_const,
340 /// Loads a i64-bit signed immediate value onto the stack
341 ///
342 /// uses `payload` of type `Imm64`
343 i64_const,
344 /// Loads a 32-bit float value onto the stack.
345 ///
346 /// Uses `float32`
347 f32_const,
348 /// Loads a 64-bit float value onto the stack.
349 ///
350 /// Uses `payload` of type `Float64`
351 f64_const,
352 /// Uses `tag`
353 i32_eqz = 0x45,
354 /// Uses `tag`
355 i32_eq = 0x46,
356 /// Uses `tag`
357 i32_ne = 0x47,
358 /// Uses `tag`
359 i32_lt_s = 0x48,
360 /// Uses `tag`
361 i32_lt_u = 0x49,
362 /// Uses `tag`
363 i32_gt_s = 0x4A,
364 /// Uses `tag`
365 i32_gt_u = 0x4B,
366 /// Uses `tag`
367 i32_le_s = 0x4C,
368 /// Uses `tag`
369 i32_le_u = 0x4D,
370 /// Uses `tag`
371 i32_ge_s = 0x4E,
372 /// Uses `tag`
373 i32_ge_u = 0x4F,
374 /// Uses `tag`
375 i64_eqz = 0x50,
376 /// Uses `tag`
377 i64_eq = 0x51,
378 /// Uses `tag`
379 i64_ne = 0x52,
380 /// Uses `tag`
381 i64_lt_s = 0x53,
382 /// Uses `tag`
383 i64_lt_u = 0x54,
384 /// Uses `tag`
385 i64_gt_s = 0x55,
386 /// Uses `tag`
387 i64_gt_u = 0x56,
388 /// Uses `tag`
389 i64_le_s = 0x57,
390 /// Uses `tag`
391 i64_le_u = 0x58,
392 /// Uses `tag`
393 i64_ge_s = 0x59,
394 /// Uses `tag`
395 i64_ge_u = 0x5A,
396 /// Uses `tag`
397 f32_eq = 0x5B,
398 /// Uses `tag`
399 f32_ne = 0x5C,
400 /// Uses `tag`
401 f32_lt = 0x5D,
402 /// Uses `tag`
403 f32_gt = 0x5E,
404 /// Uses `tag`
405 f32_le = 0x5F,
406 /// Uses `tag`
407 f32_ge = 0x60,
408 /// Uses `tag`
409 f64_eq = 0x61,
410 /// Uses `tag`
411 f64_ne = 0x62,
412 /// Uses `tag`
413 f64_lt = 0x63,
414 /// Uses `tag`
415 f64_gt = 0x64,
416 /// Uses `tag`
417 f64_le = 0x65,
418 /// Uses `tag`
419 f64_ge = 0x66,
420 /// Uses `tag`
421 i32_clz = 0x67,
422 /// Uses `tag`
423 i32_ctz = 0x68,
424 /// Uses `tag`
425 i32_popcnt = 0x69,
426 /// Uses `tag`
427 i32_add = 0x6A,
428 /// Uses `tag`
429 i32_sub = 0x6B,
430 /// Uses `tag`
431 i32_mul = 0x6C,
432 /// Uses `tag`
433 i32_div_s = 0x6D,
434 /// Uses `tag`
435 i32_div_u = 0x6E,
436 /// Uses `tag`
437 i32_rem_s = 0x6F,
438 /// Uses `tag`
439 i32_rem_u = 0x70,
440 /// Uses `tag`
441 i32_and = 0x71,
442 /// Uses `tag`
443 i32_or = 0x72,
444 /// Uses `tag`
445 i32_xor = 0x73,
446 /// Uses `tag`
447 i32_shl = 0x74,
448 /// Uses `tag`
449 i32_shr_s = 0x75,
450 /// Uses `tag`
451 i32_shr_u = 0x76,
452 /// Uses `tag`
453 i64_clz = 0x79,
454 /// Uses `tag`
455 i64_ctz = 0x7A,
456 /// Uses `tag`
457 i64_popcnt = 0x7B,
458 /// Uses `tag`
459 i64_add = 0x7C,
460 /// Uses `tag`
461 i64_sub = 0x7D,
462 /// Uses `tag`
463 i64_mul = 0x7E,
464 /// Uses `tag`
465 i64_div_s = 0x7F,
466 /// Uses `tag`
467 i64_div_u = 0x80,
468 /// Uses `tag`
469 i64_rem_s = 0x81,
470 /// Uses `tag`
471 i64_rem_u = 0x82,
472 /// Uses `tag`
473 i64_and = 0x83,
474 /// Uses `tag`
475 i64_or = 0x84,
476 /// Uses `tag`
477 i64_xor = 0x85,
478 /// Uses `tag`
479 i64_shl = 0x86,
480 /// Uses `tag`
481 i64_shr_s = 0x87,
482 /// Uses `tag`
483 i64_shr_u = 0x88,
484 /// Uses `tag`
485 f32_abs = 0x8B,
486 /// Uses `tag`
487 f32_neg = 0x8C,
488 /// Uses `tag`
489 f32_ceil = 0x8D,
490 /// Uses `tag`
491 f32_floor = 0x8E,
492 /// Uses `tag`
493 f32_trunc = 0x8F,
494 /// Uses `tag`
495 f32_nearest = 0x90,
496 /// Uses `tag`
497 f32_sqrt = 0x91,
498 /// Uses `tag`
499 f32_add = 0x92,
500 /// Uses `tag`
501 f32_sub = 0x93,
502 /// Uses `tag`
503 f32_mul = 0x94,
504 /// Uses `tag`
505 f32_div = 0x95,
506 /// Uses `tag`
507 f32_min = 0x96,
508 /// Uses `tag`
509 f32_max = 0x97,
510 /// Uses `tag`
511 f32_copysign = 0x98,
512 /// Uses `tag`
513 f64_abs = 0x99,
514 /// Uses `tag`
515 f64_neg = 0x9A,
516 /// Uses `tag`
517 f64_ceil = 0x9B,
518 /// Uses `tag`
519 f64_floor = 0x9C,
520 /// Uses `tag`
521 f64_trunc = 0x9D,
522 /// Uses `tag`
523 f64_nearest = 0x9E,
524 /// Uses `tag`
525 f64_sqrt = 0x9F,
526 /// Uses `tag`
527 f64_add = 0xA0,
528 /// Uses `tag`
529 f64_sub = 0xA1,
530 /// Uses `tag`
531 f64_mul = 0xA2,
532 /// Uses `tag`
533 f64_div = 0xA3,
534 /// Uses `tag`
535 f64_min = 0xA4,
536 /// Uses `tag`
537 f64_max = 0xA5,
538 /// Uses `tag`
539 f64_copysign = 0xA6,
540 /// Uses `tag`
541 i32_wrap_i64 = 0xA7,
542 /// Uses `tag`
543 i32_trunc_f32_s = 0xA8,
544 /// Uses `tag`
545 i32_trunc_f32_u = 0xA9,
546 /// Uses `tag`
547 i32_trunc_f64_s = 0xAA,
548 /// Uses `tag`
549 i32_trunc_f64_u = 0xAB,
550 /// Uses `tag`
551 i64_extend_i32_s = 0xAC,
552 /// Uses `tag`
553 i64_extend_i32_u = 0xAD,
554 /// Uses `tag`
555 i64_trunc_f32_s = 0xAE,
556 /// Uses `tag`
557 i64_trunc_f32_u = 0xAF,
558 /// Uses `tag`
559 i64_trunc_f64_s = 0xB0,
560 /// Uses `tag`
561 i64_trunc_f64_u = 0xB1,
562 /// Uses `tag`
563 f32_convert_i32_s = 0xB2,
564 /// Uses `tag`
565 f32_convert_i32_u = 0xB3,
566 /// Uses `tag`
567 f32_convert_i64_s = 0xB4,
568 /// Uses `tag`
569 f32_convert_i64_u = 0xB5,
570 /// Uses `tag`
571 f32_demote_f64 = 0xB6,
572 /// Uses `tag`
573 f64_convert_i32_s = 0xB7,
574 /// Uses `tag`
575 f64_convert_i32_u = 0xB8,
576 /// Uses `tag`
577 f64_convert_i64_s = 0xB9,
578 /// Uses `tag`
579 f64_convert_i64_u = 0xBA,
580 /// Uses `tag`
581 f64_promote_f32 = 0xBB,
582 /// Uses `tag`
583 i32_reinterpret_f32 = 0xBC,
584 /// Uses `tag`
585 i64_reinterpret_f64 = 0xBD,
586 /// Uses `tag`
587 f32_reinterpret_i32 = 0xBE,
588 /// Uses `tag`
589 f64_reinterpret_i64 = 0xBF,
590 /// Uses `tag`
591 i32_extend8_s = 0xC0,
592 /// Uses `tag`
593 i32_extend16_s = 0xC1,
594 /// Uses `tag`
595 i64_extend8_s = 0xC2,
596 /// Uses `tag`
597 i64_extend16_s = 0xC3,
598 /// Uses `tag`
599 i64_extend32_s = 0xC4,
600 /// The instruction consists of a prefixed opcode.
601 /// The prefixed opcode can be found at payload's index.
602 ///
603 /// The `data` field depends on the extension instruction and
604 /// may contain additional data.
605 misc_prefix,
606 /// The instruction consists of a simd opcode.
607 /// The actual simd-opcode is found at payload's index.
608 ///
609 /// The `data` field depends on the simd instruction and
610 /// may contain additional data.
611 simd_prefix,
612 /// The instruction consists of an atomics opcode.
613 /// The actual atomics-opcode is found at payload's index.
614 ///
615 /// The `data` field depends on the atomics instruction and
616 /// may contain additional data.
617 atomics_prefix = 0xFE,
618
619 /// From a given wasm opcode, returns a MIR tag.
620 pub fn fromOpcode(opcode: std.wasm.Opcode) Tag {
621 return @as(Tag, @fromBackingInt(@intCast(@backingInt(opcode)))); // Given `Opcode` is not present as a tag for MIR yet
622 }
623
624 /// Returns a wasm opcode from a given MIR tag.
625 pub fn toOpcode(self: Tag) std.wasm.Opcode {
626 return @as(std.wasm.Opcode, @fromBackingInt(@intCast(@backingInt(self))));
627 }
628 };
629
630 /// All instructions contain a 4-byte payload, which is contained within
631 /// this union. `Tag` determines which union tag is active, as well as
632 /// how to interpret the data within.
633 pub const Data = union {
634 /// Uses no additional data
635 tag: void,
636 /// Contains the result type of a block
637 block_type: std.wasm.BlockType,
638 /// Label: Each structured control instruction introduces an implicit label.
639 /// Labels are targets for branch instructions that reference them with
640 /// label indices. Unlike with other index spaces, indexing of labels
641 /// is relative by nesting depth, that is, label 0 refers to the
642 /// innermost structured control instruction enclosing the referring
643 /// branch instruction, while increasing indices refer to those farther
644 /// out. Consequently, labels can only be referenced from within the
645 /// associated structured control instruction.
646 label: u32,
647 /// Local: The index space for locals is only accessible inside a function and
648 /// includes the parameters of that function, which precede the local
649 /// variables.
650 local: u32,
651 /// A 32-bit immediate value.
652 imm32: i32,
653 /// A 32-bit float value
654 float32: f32,
655 /// Index into `extra`. Meaning of what can be found there is context-dependent.
656 payload: u32,
657
658 ip_index: InternPool.Index,
659 nav_index: InternPool.Nav.Index,
660 intrinsic: Intrinsic,
661
662 comptime {
663 switch (builtin.mode) {
664 .debug, .safe => {},
665 .fast, .small => assert(@sizeOf(Data) == 4),
666 }
667 }
668 };
669};
670
671pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
672 mir.instructions.deinit(gpa);
673 gpa.free(mir.extra);
674 gpa.free(mir.locals);
675 mir.uavs.deinit(gpa);
676 mir.indirect_function_set.deinit(gpa);
677 mir.func_tys.deinit(gpa);
678 mir.* = undefined;
679}
680
681pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayList(u8)) std.mem.Allocator.Error!void {
682 var emit: Emit = .{
683 .mir = mir.*,
684 .wasm = wasm,
685 .code = code,
686 };
687 try emit.lower();
688}
689
690pub fn extraData(self: *const Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
691 const info = @typeInfo(T).@"struct";
692 var i: usize = index;
693 var result: T = undefined;
694 inline for (info.field_names, info.field_types) |field_name, field_type| {
695 @field(result, field_name) = switch (field_type) {
696 u32 => self.extra[i],
697 i32 => @bitCast(self.extra[i]),
698 Wasm.UavsObjIndex,
699 Wasm.UavsExeIndex,
700 InternPool.Nav.Index,
701 InternPool.Index,
702 => @fromBackingInt(@intCast(self.extra[i])),
703 else => @compileError("Unsupported field type " ++ @typeName(field_type)),
704 };
705 i += 1;
706 }
707
708 return .{ .data = result, .end = i };
709}
710
711pub const JumpTable = struct {
712 /// Length of the jump table and the amount of entries it contains (includes default)
713 length: u32,
714};
715
716pub const Imm64 = struct {
717 msb: u32,
718 lsb: u32,
719
720 pub fn init(full: u64) Imm64 {
721 return .{
722 .msb = @truncate(full >> 32),
723 .lsb = @truncate(full),
724 };
725 }
726
727 pub fn toInt(i: Imm64) u64 {
728 return (@as(u64, i.msb) << 32) | @as(u64, i.lsb);
729 }
730};
731
732pub const Float64 = struct {
733 msb: u32,
734 lsb: u32,
735
736 pub fn init(f: f64) Float64 {
737 const int: u64 = @bitCast(f);
738 return .{
739 .msb = @truncate(int >> 32),
740 .lsb = @truncate(int),
741 };
742 }
743
744 pub fn toInt(f: Float64) u64 {
745 return (@as(u64, f.msb) << 32) | @as(u64, f.lsb);
746 }
747};
748
749pub const MemArg = struct {
750 offset: u32,
751 alignment: u32,
752};
753
754pub const UavRefOff = struct {
755 value: InternPool.Index,
756 offset: i32,
757};
758
759pub const NavRefOff = struct {
760 nav_index: InternPool.Nav.Index,
761 offset: i32,
762};
763
764/// Maps a source line with wasm bytecode
765pub const DbgLineColumn = struct {
766 line: u32,
767 column: u32,
768};
769
770/// Tag names exactly match the corresponding symbol name.
771pub const Intrinsic = enum(u32) {
772 __addhf3,
773 __addtf3,
774 __addxf3,
775 __ashlti3,
776 __ashrti3,
777 __bitreversedi2,
778 __bitreversesi2,
779 __bswapdi2,
780 __bswapsi2,
781 __ceilh,
782 __ceilx,
783 __cosh,
784 __cosx,
785 __divei5,
786 __divhf3,
787 __divtf3,
788 __divti3,
789 __divxf3,
790 __eqtf2,
791 __eqxf2,
792 __exp2h,
793 __exp2x,
794 __exph,
795 __expx,
796 __extenddftf2,
797 __extenddfxf2,
798 __extendhfsf2,
799 __extendhftf2,
800 __extendhfxf2,
801 __extendsftf2,
802 __extendsfxf2,
803 __extendxftf2,
804 __fabsh,
805 __fabsx,
806 __fixdfdi,
807 __fixdfei,
808 __fixdfsi,
809 __fixdfti,
810 __fixhfdi,
811 __fixhfei,
812 __fixhfsi,
813 __fixhfti,
814 __fixsfdi,
815 __fixsfei,
816 __fixsfsi,
817 __fixsfti,
818 __fixtfdi,
819 __fixtfei,
820 __fixtfsi,
821 __fixtfti,
822 __fixunsdfdi,
823 __fixunsdfei,
824 __fixunsdfsi,
825 __fixunsdfti,
826 __fixunshfdi,
827 __fixunshfei,
828 __fixunshfsi,
829 __fixunshfti,
830 __fixunssfdi,
831 __fixunssfei,
832 __fixunssfsi,
833 __fixunssfti,
834 __fixunstfdi,
835 __fixunstfei,
836 __fixunstfsi,
837 __fixunstfti,
838 __fixunsxfdi,
839 __fixunsxfei,
840 __fixunsxfsi,
841 __fixunsxfti,
842 __fixxfdi,
843 __fixxfei,
844 __fixxfsi,
845 __fixxfti,
846 __floatdidf,
847 __floatdihf,
848 __floatdisf,
849 __floatditf,
850 __floatdixf,
851 __floateidf,
852 __floateihf,
853 __floateisf,
854 __floateitf,
855 __floateixf,
856 __floatsidf,
857 __floatsihf,
858 __floatsisf,
859 __floatsitf,
860 __floatsixf,
861 __floattidf,
862 __floattihf,
863 __floattisf,
864 __floattitf,
865 __floattixf,
866 __floatundidf,
867 __floatundihf,
868 __floatundisf,
869 __floatunditf,
870 __floatundixf,
871 __floatuneidf,
872 __floatuneihf,
873 __floatuneisf,
874 __floatuneitf,
875 __floatuneixf,
876 __floatunsidf,
877 __floatunsihf,
878 __floatunsisf,
879 __floatunsitf,
880 __floatunsixf,
881 __floatuntidf,
882 __floatuntihf,
883 __floatuntisf,
884 __floatuntitf,
885 __floatuntixf,
886 __floorh,
887 __floorx,
888 __fmah,
889 __fmax,
890 __fmaxh,
891 __fmaxx,
892 __fminh,
893 __fminx,
894 __fmodh,
895 __fmodx,
896 __getf2,
897 __gexf2,
898 __gttf2,
899 __gtxf2,
900 __letf2,
901 __lexf2,
902 __log10h,
903 __log10x,
904 __log2h,
905 __log2x,
906 __logh,
907 __logx,
908 __lshrti3,
909 __lttf2,
910 __ltxf2,
911 __modei5,
912 __modti3,
913 __mulhf3,
914 __mulodi4,
915 __muloti4,
916 __multf3,
917 __multi3,
918 __mulxf3,
919 __netf2,
920 __nexf2,
921 __roundh,
922 __roundx,
923 __sinh,
924 __sinx,
925 __sqrth,
926 __sqrtx,
927 __subhf3,
928 __subtf3,
929 __subxf3,
930 __tanh,
931 __tanx,
932 __trunch,
933 __truncsfhf2,
934 __trunctfdf2,
935 __trunctfhf2,
936 __trunctfsf2,
937 __trunctfxf2,
938 __truncx,
939 __truncxfdf2,
940 __truncxfhf2,
941 __truncxfsf2,
942 __udivei5,
943 __udivti3,
944 __umodei5,
945 __umodti3,
946 ceilf128,
947 cos,
948 cosf,
949 cosf128,
950 exp,
951 exp2,
952 exp2f,
953 exp2f128,
954 expf,
955 expf128,
956 fabsf128,
957 floorf128,
958 fma,
959 fmaf,
960 fmaf128,
961 fmax,
962 fmaxf,
963 fmaxf128,
964 fmin,
965 fminf,
966 fminf128,
967 fmod,
968 fmodf,
969 fmodf128,
970 log,
971 log10,
972 log10f,
973 log10f128,
974 log2,
975 log2f,
976 log2f128,
977 logf,
978 logf128,
979 roundf128,
980 sin,
981 sinf,
982 sinf128,
983 sqrtf128,
984 tan,
985 tanf,
986 tanf128,
987 truncf128,
988 memcpy,
989 memmove,
990 memset,
991 __addo_limb64,
992 __subo_limb64,
993 __cmp_limb64,
994 __and_limb64,
995 __or_limb64,
996 __xor_limb64,
997 __not_limb64,
998 __shlo_limb64,
999 __shr_limb64,
1000 __clz_limb64,
1001 __ctz_limb64,
1002 __popcount_limb64,
1003 __bitreverse_limb64,
1004 __byteswap_limb64,
1005 __mulo_limb64,
1006 __abs_limb64,
1007};