| 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 | |
| 9 | const Mir = @This(); |
| 10 | const InternPool = @import("../../InternPool.zig"); |
| 11 | const Wasm = @import("../../link/Wasm.zig"); |
| 12 | const Emit = @import("Emit.zig"); |
| 13 | const Alignment = InternPool.Alignment; |
| 14 | |
| 15 | const builtin = @import("builtin"); |
| 16 | const std = @import("std"); |
| 17 | const assert = std.debug.assert; |
| 18 | const leb = std.leb; |
| 19 | |
| 20 | instructions: std.MultiArrayList(Inst).Slice, |
| 21 | /// A slice of indexes where the meaning of the data is determined by the |
| 22 | /// `Inst.Tag` value. |
| 23 | extra: []const u32, |
| 24 | locals: []const std.wasm.Valtype, |
| 25 | prologue: 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. |
| 29 | uavs: 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. |
| 31 | indirect_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. |
| 33 | func_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. |
| 35 | error_name_table_ref_count: u32, |
| 36 | |
| 37 | pub 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 | |
| 60 | pub 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 | |
| 671 | pub 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 | |
| 681 | pub 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 | |
| 690 | pub 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 | |
| 711 | pub const JumpTable = struct { |
| 712 | /// Length of the jump table and the amount of entries it contains (includes default) |
| 713 | length: u32, |
| 714 | }; |
| 715 | |
| 716 | pub 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 | |
| 732 | pub 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 | |
| 749 | pub const MemArg = struct { |
| 750 | offset: u32, |
| 751 | alignment: u32, |
| 752 | }; |
| 753 | |
| 754 | pub const UavRefOff = struct { |
| 755 | value: InternPool.Index, |
| 756 | offset: i32, |
| 757 | }; |
| 758 | |
| 759 | pub const NavRefOff = struct { |
| 760 | nav_index: InternPool.Nav.Index, |
| 761 | offset: i32, |
| 762 | }; |
| 763 | |
| 764 | /// Maps a source line with wasm bytecode |
| 765 | pub const DbgLineColumn = struct { |
| 766 | line: u32, |
| 767 | column: u32, |
| 768 | }; |
| 769 | |
| 770 | /// Tag names exactly match the corresponding symbol name. |
| 771 | pub 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 | }; |