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