1//! Analyzed Intermediate Representation. 2//! This data is produced by Sema and consumed by codegen. 3//! Unlike ZIR where there is one instance for an entire source file, each function 4//! gets its own `Air` instance. 5 6const std = @import("std"); 7const builtin = @import("builtin"); 8const Value = @import("value.zig").Value; 9const Type = @import("type.zig").Type; 10const Module = @import("Module.zig"); 11const assert = std.debug.assert; 12const Air = @This(); 13 14instructions: std.MultiArrayList(Inst).Slice, 15/// The meaning of this data is determined by `Inst.Tag` value. 16/// The first few indexes are reserved. See `ExtraIndex` for the values. 17extra: []const u32, 18values: []const Value, 19 20pub const ExtraIndex = enum(u32) { 21 /// Payload index of the main `Block` in the `extra` array. 22 main_block, 23 24 _, 25}; 26 27pub const Inst = struct { 28 tag: Tag, 29 data: Data, 30 31 pub const Tag = enum(u8) { 32 /// The first N instructions in the main block must be one arg instruction per 33 /// function parameter. This makes function parameters participate in 34 /// liveness analysis without any special handling. 35 /// Uses the `ty_str` field. 36 /// The string is the parameter name. 37 arg, 38 /// Float or integer addition. For integers, wrapping is undefined behavior. 39 /// Both operands are guaranteed to be the same type, and the result type 40 /// is the same as both operands. 41 /// Uses the `bin_op` field. 42 add, 43 /// Integer addition. Wrapping is defined to be twos complement wrapping. 44 /// Both operands are guaranteed to be the same type, and the result type 45 /// is the same as both operands. 46 /// Uses the `bin_op` field. 47 addwrap, 48 /// Saturating integer addition. 49 /// Both operands are guaranteed to be the same type, and the result type 50 /// is the same as both operands. 51 /// Uses the `bin_op` field. 52 add_sat, 53 /// Float or integer subtraction. For integers, wrapping is undefined behavior. 54 /// Both operands are guaranteed to be the same type, and the result type 55 /// is the same as both operands. 56 /// Uses the `bin_op` field. 57 sub, 58 /// Integer subtraction. Wrapping is defined to be twos complement wrapping. 59 /// Both operands are guaranteed to be the same type, and the result type 60 /// is the same as both operands. 61 /// Uses the `bin_op` field. 62 subwrap, 63 /// Saturating integer subtraction. 64 /// Both operands are guaranteed to be the same type, and the result type 65 /// is the same as both operands. 66 /// Uses the `bin_op` field. 67 sub_sat, 68 /// Float or integer multiplication. For integers, wrapping is undefined behavior. 69 /// Both operands are guaranteed to be the same type, and the result type 70 /// is the same as both operands. 71 /// Uses the `bin_op` field. 72 mul, 73 /// Integer multiplication. Wrapping is defined to be twos complement wrapping. 74 /// Both operands are guaranteed to be the same type, and the result type 75 /// is the same as both operands. 76 /// Uses the `bin_op` field. 77 mulwrap, 78 /// Saturating integer multiplication. 79 /// Both operands are guaranteed to be the same type, and the result type 80 /// is the same as both operands. 81 /// Uses the `bin_op` field. 82 mul_sat, 83 /// Float division. 84 /// Both operands are guaranteed to be the same type, and the result type 85 /// is the same as both operands. 86 /// Uses the `bin_op` field. 87 div_float, 88 /// Truncating integer or float division. For integers, wrapping is undefined behavior. 89 /// Both operands are guaranteed to be the same type, and the result type 90 /// is the same as both operands. 91 /// Uses the `bin_op` field. 92 div_trunc, 93 /// Flooring integer or float division. For integers, wrapping is undefined behavior. 94 /// Both operands are guaranteed to be the same type, and the result type 95 /// is the same as both operands. 96 /// Uses the `bin_op` field. 97 div_floor, 98 /// Integer or float division. Guaranteed no remainder. 99 /// For integers, wrapping is undefined behavior. 100 /// Both operands are guaranteed to be the same type, and the result type 101 /// is the same as both operands. 102 /// Uses the `bin_op` field. 103 div_exact, 104 /// Integer or float remainder division. 105 /// Both operands are guaranteed to be the same type, and the result type 106 /// is the same as both operands. 107 /// Uses the `bin_op` field. 108 rem, 109 /// Integer or float modulus division. 110 /// Both operands are guaranteed to be the same type, and the result type 111 /// is the same as both operands. 112 /// Uses the `bin_op` field. 113 mod, 114 /// Add an offset to a pointer, returning a new pointer. 115 /// The offset is in element type units, not bytes. 116 /// Wrapping is undefined behavior. 117 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. 118 /// Uses the `bin_op` field. 119 ptr_add, 120 /// Subtract an offset from a pointer, returning a new pointer. 121 /// The offset is in element type units, not bytes. 122 /// Wrapping is undefined behavior. 123 /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. 124 /// Uses the `bin_op` field. 125 ptr_sub, 126 /// Given two operands which can be floats, integers, or vectors, returns the 127 /// greater of the operands. For vectors it operates element-wise. 128 /// Both operands are guaranteed to be the same type, and the result type 129 /// is the same as both operands. 130 /// Uses the `bin_op` field. 131 max, 132 /// Given two operands which can be floats, integers, or vectors, returns the 133 /// lesser of the operands. For vectors it operates element-wise. 134 /// Both operands are guaranteed to be the same type, and the result type 135 /// is the same as both operands. 136 /// Uses the `bin_op` field. 137 min, 138 /// Allocates stack local memory. 139 /// Uses the `ty` field. 140 alloc, 141 /// If the function will pass the result by-ref, this instruction returns the 142 /// result pointer. Otherwise it is equivalent to `alloc`. 143 /// Uses the `ty` field. 144 ret_ptr, 145 /// Inline assembly. Uses the `ty_pl` field. Payload is `Asm`. 146 assembly, 147 /// Bitwise AND. `&`. 148 /// Result type is the same as both operands. 149 /// Uses the `bin_op` field. 150 bit_and, 151 /// Bitwise OR. `|`. 152 /// Result type is the same as both operands. 153 /// Uses the `bin_op` field. 154 bit_or, 155 /// Shift right. `>>` 156 /// Uses the `bin_op` field. 157 shr, 158 /// Shift left. `<<` 159 /// Uses the `bin_op` field. 160 shl, 161 /// Shift left; For unsigned integers, the shift produces a poison value if it shifts 162 /// out any non-zero bits. For signed integers, the shift produces a poison value if 163 /// it shifts out any bits that disagree with the resultant sign bit. 164 /// Uses the `bin_op` field. 165 shl_exact, 166 /// Saturating integer shift left. `<<|` 167 /// Uses the `bin_op` field. 168 shl_sat, 169 /// Bitwise XOR. `^` 170 /// Uses the `bin_op` field. 171 xor, 172 /// Boolean or binary NOT. 173 /// Uses the `ty_op` field. 174 not, 175 /// Reinterpret the memory representation of a value as a different type. 176 /// Uses the `ty_op` field. 177 bitcast, 178 /// Uses the `ty_pl` field with payload `Block`. 179 block, 180 /// A labeled block of code that loops forever. At the end of the body it is implied 181 /// to repeat; no explicit "repeat" instruction terminates loop bodies. 182 /// Result type is always noreturn; no instructions in a block follow this one. 183 /// Uses the `ty_pl` field. Payload is `Block`. 184 loop, 185 /// Return from a block with a result. 186 /// Result type is always noreturn; no instructions in a block follow this one. 187 /// Uses the `br` field. 188 br, 189 /// Lowers to a hardware trap instruction, or the next best thing. 190 /// Result type is always void. 191 breakpoint, 192 /// Function call. 193 /// Result type is the return type of the function being called. 194 /// Uses the `pl_op` field with the `Call` payload. operand is the callee. 195 /// Triggers `resolveTypeLayout` on the return type of the callee. 196 call, 197 /// Count leading zeroes of an integer according to its representation in twos complement. 198 /// Result type will always be an unsigned integer big enough to fit the answer. 199 /// Uses the `ty_op` field. 200 clz, 201 /// Count trailing zeroes of an integer according to its representation in twos complement. 202 /// Result type will always be an unsigned integer big enough to fit the answer. 203 /// Uses the `ty_op` field. 204 ctz, 205 /// Count number of 1 bits in an integer according to its representation in twos complement. 206 /// Result type will always be an unsigned integer big enough to fit the answer. 207 /// Uses the `ty_op` field. 208 popcount, 209 210 /// `<`. Result type is always bool. 211 /// Uses the `bin_op` field. 212 cmp_lt, 213 /// `<=`. Result type is always bool. 214 /// Uses the `bin_op` field. 215 cmp_lte, 216 /// `==`. Result type is always bool. 217 /// Uses the `bin_op` field. 218 cmp_eq, 219 /// `>=`. Result type is always bool. 220 /// Uses the `bin_op` field. 221 cmp_gte, 222 /// `>`. Result type is always bool. 223 /// Uses the `bin_op` field. 224 cmp_gt, 225 /// `!=`. Result type is always bool. 226 /// Uses the `bin_op` field. 227 cmp_neq, 228 229 /// Conditional branch. 230 /// Result type is always noreturn; no instructions in a block follow this one. 231 /// Uses the `pl_op` field. Operand is the condition. Payload is `CondBr`. 232 cond_br, 233 /// Switch branch. 234 /// Result type is always noreturn; no instructions in a block follow this one. 235 /// Uses the `pl_op` field. Operand is the condition. Payload is `SwitchBr`. 236 switch_br, 237 /// A comptime-known value. Uses the `ty_pl` field, payload is index of 238 /// `values` array. 239 constant, 240 /// A comptime-known type. Uses the `ty` field. 241 const_ty, 242 /// Notes the beginning of a source code statement and marks the line and column. 243 /// Result type is always void. 244 /// Uses the `dbg_stmt` field. 245 dbg_stmt, 246 /// ?T => bool 247 /// Result type is always bool. 248 /// Uses the `un_op` field. 249 is_null, 250 /// ?T => bool (inverted logic) 251 /// Result type is always bool. 252 /// Uses the `un_op` field. 253 is_non_null, 254 /// *?T => bool 255 /// Result type is always bool. 256 /// Uses the `un_op` field. 257 is_null_ptr, 258 /// *?T => bool (inverted logic) 259 /// Result type is always bool. 260 /// Uses the `un_op` field. 261 is_non_null_ptr, 262 /// E!T => bool 263 /// Result type is always bool. 264 /// Uses the `un_op` field. 265 is_err, 266 /// E!T => bool (inverted logic) 267 /// Result type is always bool. 268 /// Uses the `un_op` field. 269 is_non_err, 270 /// *E!T => bool 271 /// Result type is always bool. 272 /// Uses the `un_op` field. 273 is_err_ptr, 274 /// *E!T => bool (inverted logic) 275 /// Result type is always bool. 276 /// Uses the `un_op` field. 277 is_non_err_ptr, 278 /// Result type is always bool. 279 /// Uses the `bin_op` field. 280 bool_and, 281 /// Result type is always bool. 282 /// Uses the `bin_op` field. 283 bool_or, 284 /// Read a value from a pointer. 285 /// Uses the `ty_op` field. 286 load, 287 /// Converts a pointer to its address. Result type is always `usize`. 288 /// Uses the `un_op` field. 289 ptrtoint, 290 /// Given a boolean, returns 0 or 1. 291 /// Result type is always `u1`. 292 /// Uses the `un_op` field. 293 bool_to_int, 294 /// Return a value from a function. 295 /// Result type is always noreturn; no instructions in a block follow this one. 296 /// Uses the `un_op` field. 297 /// Triggers `resolveTypeLayout` on the return type. 298 ret, 299 /// This instruction communicates that the function's result value is pointed to by 300 /// the operand. If the function will pass the result by-ref, the operand is a 301 /// `ret_ptr` instruction. Otherwise, this instruction is equivalent to a `load` 302 /// on the operand, followed by a `ret` on the loaded value. 303 /// Result type is always noreturn; no instructions in a block follow this one. 304 /// Uses the `un_op` field. 305 /// Triggers `resolveTypeLayout` on the return type. 306 ret_load, 307 /// Write a value to a pointer. LHS is pointer, RHS is value. 308 /// Result type is always void. 309 /// Uses the `bin_op` field. 310 store, 311 /// Indicates the program counter will never get to this instruction. 312 /// Result type is always noreturn; no instructions in a block follow this one. 313 unreach, 314 /// Convert from a float type to a smaller one. 315 /// Uses the `ty_op` field. 316 fptrunc, 317 /// Convert from a float type to a wider one. 318 /// Uses the `ty_op` field. 319 fpext, 320 /// Returns an integer with a different type than the operand. The new type may have 321 /// fewer, the same, or more bits than the operand type. The new type may also 322 /// differ in signedness from the operand type. However, the instruction 323 /// guarantees that the same integer value fits in both types. 324 /// The new type may also be an enum type, in which case the integer cast operates on 325 /// the integer tag type of the enum. 326 /// See `trunc` for integer truncation. 327 /// Uses the `ty_op` field. 328 intcast, 329 /// Truncate higher bits from an integer, resulting in an integer with the same 330 /// sign but an equal or smaller number of bits. 331 /// Uses the `ty_op` field. 332 trunc, 333 /// ?T => T. If the value is null, undefined behavior. 334 /// Uses the `ty_op` field. 335 optional_payload, 336 /// *?T => *T. If the value is null, undefined behavior. 337 /// Uses the `ty_op` field. 338 optional_payload_ptr, 339 /// *?T => *T. Sets the value to non-null with an undefined payload value. 340 /// Uses the `ty_op` field. 341 optional_payload_ptr_set, 342 /// Given a payload value, wraps it in an optional type. 343 /// Uses the `ty_op` field. 344 wrap_optional, 345 /// E!T -> T. If the value is an error, undefined behavior. 346 /// Uses the `ty_op` field. 347 unwrap_errunion_payload, 348 /// E!T -> E. If the value is not an error, undefined behavior. 349 /// Uses the `ty_op` field. 350 unwrap_errunion_err, 351 /// *(E!T) -> *T. If the value is an error, undefined behavior. 352 /// Uses the `ty_op` field. 353 unwrap_errunion_payload_ptr, 354 /// *(E!T) -> E. If the value is not an error, undefined behavior. 355 /// Uses the `ty_op` field. 356 unwrap_errunion_err_ptr, 357 /// wrap from T to E!T 358 /// Uses the `ty_op` field. 359 wrap_errunion_payload, 360 /// wrap from E to E!T 361 /// Uses the `ty_op` field. 362 wrap_errunion_err, 363 /// Given a pointer to a struct or union and a field index, returns a pointer to the field. 364 /// Uses the `ty_pl` field, payload is `StructField`. 365 /// TODO rename to `agg_field_ptr`. 366 struct_field_ptr, 367 /// Given a pointer to a struct or union, returns a pointer to the field. 368 /// The field index is the number at the end of the name. 369 /// Uses `ty_op` field. 370 /// TODO rename to `agg_field_ptr_index_X` 371 struct_field_ptr_index_0, 372 struct_field_ptr_index_1, 373 struct_field_ptr_index_2, 374 struct_field_ptr_index_3, 375 /// Given a byval struct or union and a field index, returns the field byval. 376 /// Uses the `ty_pl` field, payload is `StructField`. 377 /// TODO rename to `agg_field_val` 378 struct_field_val, 379 /// Given a pointer to a tagged union, set its tag to the provided value. 380 /// Result type is always void. 381 /// Uses the `bin_op` field. LHS is union pointer, RHS is new tag value. 382 set_union_tag, 383 /// Given a tagged union value, get its tag value. 384 /// Uses the `ty_op` field. 385 get_union_tag, 386 /// Constructs a slice from a pointer and a length. 387 /// Uses the `ty_pl` field, payload is `Bin`. lhs is ptr, rhs is len. 388 slice, 389 /// Given a slice value, return the length. 390 /// Result type is always usize. 391 /// Uses the `ty_op` field. 392 slice_len, 393 /// Given a slice value, return the pointer. 394 /// Uses the `ty_op` field. 395 slice_ptr, 396 /// Given a pointer to a slice, return a pointer to the length of the slice. 397 /// Uses the `ty_op` field. 398 ptr_slice_len_ptr, 399 /// Given a pointer to a slice, return a pointer to the pointer of the slice. 400 /// Uses the `ty_op` field. 401 ptr_slice_ptr_ptr, 402 /// Given an array value and element index, return the element value at that index. 403 /// Result type is the element type of the array operand. 404 /// Uses the `bin_op` field. 405 array_elem_val, 406 /// Given a slice value, and element index, return the element value at that index. 407 /// Result type is the element type of the slice operand. 408 /// Uses the `bin_op` field. 409 slice_elem_val, 410 /// Given a slice value and element index, return a pointer to the element value at that index. 411 /// Result type is a pointer to the element type of the slice operand. 412 /// Uses the `ty_pl` field with payload `Bin`. 413 slice_elem_ptr, 414 /// Given a pointer value, and element index, return the element value at that index. 415 /// Result type is the element type of the pointer operand. 416 /// Uses the `bin_op` field. 417 ptr_elem_val, 418 /// Given a pointer value, and element index, return the element pointer at that index. 419 /// Result type is pointer to the element type of the pointer operand. 420 /// Uses the `ty_pl` field with payload `Bin`. 421 ptr_elem_ptr, 422 /// Given a pointer to an array, return a slice. 423 /// Uses the `ty_op` field. 424 array_to_slice, 425 /// Given a float operand, return the integer with the closest mathematical meaning. 426 /// Uses the `ty_op` field. 427 float_to_int, 428 /// Given an integer operand, return the float with the closest mathematical meaning. 429 /// Uses the `ty_op` field. 430 int_to_float, 431 432 /// Given dest ptr, value, and len, set all elements at dest to value. 433 /// Result type is always void. 434 /// Uses the `pl_op` field. Operand is the dest ptr. Payload is `Bin`. `lhs` is the 435 /// value, `rhs` is the length. 436 /// The element type may be any type, not just u8. 437 memset, 438 /// Given dest ptr, src ptr, and len, copy len elements from src to dest. 439 /// Result type is always void. 440 /// Uses the `pl_op` field. Operand is the dest ptr. Payload is `Bin`. `lhs` is the 441 /// src ptr, `rhs` is the length. 442 /// The element type may be any type, not just u8. 443 memcpy, 444 445 /// Uses the `ty_pl` field with payload `Cmpxchg`. 446 cmpxchg_weak, 447 /// Uses the `ty_pl` field with payload `Cmpxchg`. 448 cmpxchg_strong, 449 /// Lowers to a memory fence instruction. 450 /// Result type is always void. 451 /// Uses the `fence` field. 452 fence, 453 /// Atomically load from a pointer. 454 /// Result type is the element type of the pointer. 455 /// Uses the `atomic_load` field. 456 atomic_load, 457 /// Atomically store through a pointer. 458 /// Result type is always `void`. 459 /// Uses the `bin_op` field. LHS is pointer, RHS is element. 460 atomic_store_unordered, 461 /// Same as `atomic_store_unordered` but with `AtomicOrder.Monotonic`. 462 atomic_store_monotonic, 463 /// Same as `atomic_store_unordered` but with `AtomicOrder.Release`. 464 atomic_store_release, 465 /// Same as `atomic_store_unordered` but with `AtomicOrder.SeqCst`. 466 atomic_store_seq_cst, 467 /// Atomically read-modify-write via a pointer. 468 /// Result type is the element type of the pointer. 469 /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`. 470 atomic_rmw, 471 472 pub fn fromCmpOp(op: std.math.CompareOperator) Tag { 473 return switch (op) { 474 .lt => .cmp_lt, 475 .lte => .cmp_lte, 476 .eq => .cmp_eq, 477 .gte => .cmp_gte, 478 .gt => .cmp_gt, 479 .neq => .cmp_neq, 480 }; 481 } 482 483 pub fn toCmpOp(tag: Tag) ?std.math.CompareOperator { 484 return switch (tag) { 485 .cmp_lt => .lt, 486 .cmp_lte => .lte, 487 .cmp_eq => .eq, 488 .cmp_gte => .gte, 489 .cmp_gt => .gt, 490 .cmp_neq => .neq, 491 else => null, 492 }; 493 } 494 }; 495 496 /// The position of an AIR instruction within the `Air` instructions array. 497 pub const Index = u32; 498 499 pub const Ref = @import("Zir.zig").Inst.Ref; 500 501 /// All instructions have an 8-byte payload, which is contained within 502 /// this union. `Tag` determines which union field is active, as well as 503 /// how to interpret the data within. 504 pub const Data = union { 505 no_op: void, 506 un_op: Ref, 507 bin_op: struct { 508 lhs: Ref, 509 rhs: Ref, 510 }, 511 ty: Type, 512 ty_op: struct { 513 ty: Ref, 514 operand: Ref, 515 }, 516 ty_pl: struct { 517 ty: Ref, 518 // Index into a different array. 519 payload: u32, 520 }, 521 ty_str: struct { 522 ty: Ref, 523 // ZIR string table index. 524 str: u32, 525 }, 526 br: struct { 527 block_inst: Index, 528 operand: Ref, 529 }, 530 pl_op: struct { 531 operand: Ref, 532 payload: u32, 533 }, 534 dbg_stmt: struct { 535 line: u32, 536 column: u32, 537 }, 538 fence: std.builtin.AtomicOrder, 539 atomic_load: struct { 540 ptr: Ref, 541 order: std.builtin.AtomicOrder, 542 }, 543 544 // Make sure we don't accidentally add a field to make this union 545 // bigger than expected. Note that in Debug builds, Zig is allowed 546 // to insert a secret field for safety checks. 547 comptime { 548 if (builtin.mode != .Debug) { 549 assert(@sizeOf(Data) == 8); 550 } 551 } 552 }; 553}; 554 555/// Trailing is a list of instruction indexes for every `body_len`. 556pub const Block = struct { 557 body_len: u32, 558}; 559 560/// Trailing is a list of `Inst.Ref` for every `args_len`. 561pub const Call = struct { 562 args_len: u32, 563}; 564 565/// This data is stored inside extra, with two sets of trailing `Inst.Ref`: 566/// * 0. the then body, according to `then_body_len`. 567/// * 1. the else body, according to `else_body_len`. 568pub const CondBr = struct { 569 then_body_len: u32, 570 else_body_len: u32, 571}; 572 573/// Trailing: 574/// * 0. `Case` for each `cases_len` 575/// * 1. the else body, according to `else_body_len`. 576pub const SwitchBr = struct { 577 cases_len: u32, 578 else_body_len: u32, 579 580 /// Trailing: 581 /// * item: Inst.Ref // for each `items_len`. 582 /// * instruction index for each `body_len`. 583 pub const Case = struct { 584 items_len: u32, 585 body_len: u32, 586 }; 587}; 588 589pub const StructField = struct { 590 /// Whether this is a pointer or byval is determined by the AIR tag. 591 struct_operand: Inst.Ref, 592 field_index: u32, 593}; 594 595pub const Bin = struct { 596 lhs: Inst.Ref, 597 rhs: Inst.Ref, 598}; 599 600/// Trailing: 601/// 0. `Inst.Ref` for every outputs_len 602/// 1. `Inst.Ref` for every inputs_len 603pub const Asm = struct { 604 /// Index to the corresponding ZIR instruction. 605 /// `asm_source`, `outputs_len`, `inputs_len`, `clobbers_len`, `is_volatile`, and 606 /// clobbers are found via here. 607 zir_index: u32, 608}; 609 610pub const Cmpxchg = struct { 611 ptr: Inst.Ref, 612 expected_value: Inst.Ref, 613 new_value: Inst.Ref, 614 /// 0b00000000000000000000000000000XXX - success_order 615 /// 0b00000000000000000000000000XXX000 - failure_order 616 flags: u32, 617 618 pub fn successOrder(self: Cmpxchg) std.builtin.AtomicOrder { 619 return @intToEnum(std.builtin.AtomicOrder, @truncate(u3, self.flags)); 620 } 621 622 pub fn failureOrder(self: Cmpxchg) std.builtin.AtomicOrder { 623 return @intToEnum(std.builtin.AtomicOrder, @truncate(u3, self.flags >> 3)); 624 } 625}; 626 627pub const AtomicRmw = struct { 628 operand: Inst.Ref, 629 /// 0b00000000000000000000000000000XXX - ordering 630 /// 0b0000000000000000000000000XXXX000 - op 631 flags: u32, 632 633 pub fn ordering(self: AtomicRmw) std.builtin.AtomicOrder { 634 return @intToEnum(std.builtin.AtomicOrder, @truncate(u3, self.flags)); 635 } 636 637 pub fn op(self: AtomicRmw) std.builtin.AtomicRmwOp { 638 return @intToEnum(std.builtin.AtomicRmwOp, @truncate(u4, self.flags >> 3)); 639 } 640}; 641 642pub fn getMainBody(air: Air) []const Air.Inst.Index { 643 const body_index = air.extra[@enumToInt(ExtraIndex.main_block)]; 644 const extra = air.extraData(Block, body_index); 645 return air.extra[extra.end..][0..extra.data.body_len]; 646} 647 648pub fn typeOf(air: Air, inst: Air.Inst.Ref) Type { 649 const ref_int = @enumToInt(inst); 650 if (ref_int < Air.Inst.Ref.typed_value_map.len) { 651 return Air.Inst.Ref.typed_value_map[ref_int].ty; 652 } 653 return air.typeOfIndex(@intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len)); 654} 655 656pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { 657 const datas = air.instructions.items(.data); 658 switch (air.instructions.items(.tag)[inst]) { 659 .arg => return air.getRefType(datas[inst].ty_str.ty), 660 661 .add, 662 .addwrap, 663 .add_sat, 664 .sub, 665 .subwrap, 666 .sub_sat, 667 .mul, 668 .mulwrap, 669 .mul_sat, 670 .div_float, 671 .div_trunc, 672 .div_floor, 673 .div_exact, 674 .rem, 675 .mod, 676 .bit_and, 677 .bit_or, 678 .xor, 679 .ptr_add, 680 .ptr_sub, 681 .shr, 682 .shl, 683 .shl_exact, 684 .shl_sat, 685 .min, 686 .max, 687 => return air.typeOf(datas[inst].bin_op.lhs), 688 689 .cmp_lt, 690 .cmp_lte, 691 .cmp_eq, 692 .cmp_gte, 693 .cmp_gt, 694 .cmp_neq, 695 .is_null, 696 .is_non_null, 697 .is_null_ptr, 698 .is_non_null_ptr, 699 .is_err, 700 .is_non_err, 701 .is_err_ptr, 702 .is_non_err_ptr, 703 .bool_and, 704 .bool_or, 705 => return Type.initTag(.bool), 706 707 .const_ty => return Type.initTag(.type), 708 709 .alloc, 710 .ret_ptr, 711 => return datas[inst].ty, 712 713 .assembly, 714 .block, 715 .constant, 716 .struct_field_ptr, 717 .struct_field_val, 718 .slice_elem_ptr, 719 .ptr_elem_ptr, 720 .cmpxchg_weak, 721 .cmpxchg_strong, 722 .slice, 723 => return air.getRefType(datas[inst].ty_pl.ty), 724 725 .not, 726 .bitcast, 727 .load, 728 .fpext, 729 .fptrunc, 730 .intcast, 731 .trunc, 732 .optional_payload, 733 .optional_payload_ptr, 734 .optional_payload_ptr_set, 735 .wrap_optional, 736 .unwrap_errunion_payload, 737 .unwrap_errunion_err, 738 .unwrap_errunion_payload_ptr, 739 .unwrap_errunion_err_ptr, 740 .wrap_errunion_payload, 741 .wrap_errunion_err, 742 .slice_ptr, 743 .ptr_slice_len_ptr, 744 .ptr_slice_ptr_ptr, 745 .struct_field_ptr_index_0, 746 .struct_field_ptr_index_1, 747 .struct_field_ptr_index_2, 748 .struct_field_ptr_index_3, 749 .array_to_slice, 750 .float_to_int, 751 .int_to_float, 752 .get_union_tag, 753 .clz, 754 .ctz, 755 .popcount, 756 => return air.getRefType(datas[inst].ty_op.ty), 757 758 .loop, 759 .br, 760 .cond_br, 761 .switch_br, 762 .ret, 763 .ret_load, 764 .unreach, 765 => return Type.initTag(.noreturn), 766 767 .breakpoint, 768 .dbg_stmt, 769 .store, 770 .fence, 771 .atomic_store_unordered, 772 .atomic_store_monotonic, 773 .atomic_store_release, 774 .atomic_store_seq_cst, 775 .memset, 776 .memcpy, 777 .set_union_tag, 778 => return Type.initTag(.void), 779 780 .ptrtoint, 781 .slice_len, 782 => return Type.initTag(.usize), 783 784 .bool_to_int => return Type.initTag(.u1), 785 786 .call => { 787 const callee_ty = air.typeOf(datas[inst].pl_op.operand); 788 switch (callee_ty.zigTypeTag()) { 789 .Fn => return callee_ty.fnReturnType(), 790 .Pointer => return callee_ty.childType().fnReturnType(), 791 else => unreachable, 792 } 793 }, 794 795 .slice_elem_val, .ptr_elem_val, .array_elem_val => { 796 const ptr_ty = air.typeOf(datas[inst].bin_op.lhs); 797 return ptr_ty.elemType(); 798 }, 799 .atomic_load => { 800 const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr); 801 return ptr_ty.elemType(); 802 }, 803 .atomic_rmw => { 804 const ptr_ty = air.typeOf(datas[inst].pl_op.operand); 805 return ptr_ty.elemType(); 806 }, 807 } 808} 809 810pub fn getRefType(air: Air, ref: Air.Inst.Ref) Type { 811 const ref_int = @enumToInt(ref); 812 if (ref_int < Air.Inst.Ref.typed_value_map.len) { 813 var buffer: Value.ToTypeBuffer = undefined; 814 return Air.Inst.Ref.typed_value_map[ref_int].val.toType(&buffer); 815 } 816 const inst_index = ref_int - Air.Inst.Ref.typed_value_map.len; 817 const air_tags = air.instructions.items(.tag); 818 const air_datas = air.instructions.items(.data); 819 assert(air_tags[inst_index] == .const_ty); 820 return air_datas[inst_index].ty; 821} 822 823/// Returns the requested data, as well as the new index which is at the start of the 824/// trailers for the object. 825pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end: usize } { 826 const fields = std.meta.fields(T); 827 var i: usize = index; 828 var result: T = undefined; 829 inline for (fields) |field| { 830 @field(result, field.name) = switch (field.field_type) { 831 u32 => air.extra[i], 832 Inst.Ref => @intToEnum(Inst.Ref, air.extra[i]), 833 i32 => @bitCast(i32, air.extra[i]), 834 else => @compileError("bad field type"), 835 }; 836 i += 1; 837 } 838 return .{ 839 .data = result, 840 .end = i, 841 }; 842} 843 844pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { 845 air.instructions.deinit(gpa); 846 gpa.free(air.extra); 847 gpa.free(air.values); 848 air.* = undefined; 849} 850 851const ref_start_index: u32 = Air.Inst.Ref.typed_value_map.len; 852 853pub fn indexToRef(inst: Air.Inst.Index) Air.Inst.Ref { 854 return @intToEnum(Air.Inst.Ref, ref_start_index + inst); 855} 856 857pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index { 858 const ref_int = @enumToInt(inst); 859 if (ref_int >= ref_start_index) { 860 return ref_int - ref_start_index; 861 } else { 862 return null; 863 } 864} 865 866/// Returns `null` if runtime-known. 867pub fn value(air: Air, inst: Air.Inst.Ref) ?Value { 868 const ref_int = @enumToInt(inst); 869 if (ref_int < Air.Inst.Ref.typed_value_map.len) { 870 return Air.Inst.Ref.typed_value_map[ref_int].val; 871 } 872 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); 873 const air_datas = air.instructions.items(.data); 874 switch (air.instructions.items(.tag)[inst_index]) { 875 .constant => return air.values[air_datas[inst_index].ty_pl.payload], 876 .const_ty => unreachable, 877 else => return air.typeOfIndex(inst_index).onePossibleValue(), 878 } 879} 880