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};