Commit ae495de54d

Andrew Kelley <andrew@ziglang.org>
2021-04-19 07:38:41
AstGen: implement all the builtin functions
1 parent 5a3045b
src/AstGen.zig
@@ -51,6 +51,7 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {
         astgen.extra.appendAssumeCapacity(switch (field.field_type) {
             u32 => @field(extra, field.name),
             Zir.Inst.Ref => @enumToInt(@field(extra, field.name)),
+            i32 => @bitCast(u32, @field(extra, field.name)),
             else => @compileError("bad field type"),
         });
     }
@@ -237,6 +238,9 @@ pub const ResultLoc = union(enum) {
     }
 };
 
+pub const align_rl: ResultLoc = .{ .ty = .u16_type };
+pub const bool_rl: ResultLoc = .{ .ty = .bool_type };
+
 pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
     return expr(gz, scope, .{ .ty = .type_type }, type_node);
 }
@@ -469,20 +473,22 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
             try assign(gz, scope, node);
             return rvalue(gz, scope, rl, .void_value, node);
         },
-        .assign_bit_and => {
-            try assignOp(gz, scope, node, .bit_and);
+
+        .assign_bit_shift_left => {
+            try assignShift(gz, scope, node, .shl);
             return rvalue(gz, scope, rl, .void_value, node);
         },
-        .assign_bit_or => {
-            try assignOp(gz, scope, node, .bit_or);
+        .assign_bit_shift_right => {
+            try assignShift(gz, scope, node, .shr);
             return rvalue(gz, scope, rl, .void_value, node);
         },
-        .assign_bit_shift_left => {
-            try assignOp(gz, scope, node, .shl);
+
+        .assign_bit_and => {
+            try assignOp(gz, scope, node, .bit_and);
             return rvalue(gz, scope, rl, .void_value, node);
         },
-        .assign_bit_shift_right => {
-            try assignOp(gz, scope, node, .shr);
+        .assign_bit_or => {
+            try assignOp(gz, scope, node, .bit_or);
             return rvalue(gz, scope, rl, .void_value, node);
         },
         .assign_bit_xor => {
@@ -522,51 +528,54 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
             return rvalue(gz, scope, rl, .void_value, node);
         },
 
-        .add => return simpleBinOp(gz, scope, rl, node, .add),
+        // zig fmt: off
+        .bit_shift_left  => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),
+        .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),
+
+        .add      => return simpleBinOp(gz, scope, rl, node, .add),
         .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),
-        .sub => return simpleBinOp(gz, scope, rl, node, .sub),
+        .sub      => return simpleBinOp(gz, scope, rl, node, .sub),
         .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),
-        .mul => return simpleBinOp(gz, scope, rl, node, .mul),
+        .mul      => return simpleBinOp(gz, scope, rl, node, .mul),
         .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),
-        .div => return simpleBinOp(gz, scope, rl, node, .div),
-        .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem),
-        .bit_and => return simpleBinOp(gz, scope, rl, node, .bit_and),
-        .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or),
-        .bit_shift_left => return simpleBinOp(gz, scope, rl, node, .shl),
-        .bit_shift_right => return simpleBinOp(gz, scope, rl, node, .shr),
-        .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor),
-
-        .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq),
-        .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq),
-        .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt),
+        .div      => return simpleBinOp(gz, scope, rl, node, .div),
+        .mod      => return simpleBinOp(gz, scope, rl, node, .mod_rem),
+        .bit_and  => return simpleBinOp(gz, scope, rl, node, .bit_and),
+        .bit_or   => return simpleBinOp(gz, scope, rl, node, .bit_or),
+        .bit_xor  => return simpleBinOp(gz, scope, rl, node, .xor),
+
+        .bang_equal       => return simpleBinOp(gz, scope, rl, node, .cmp_neq),
+        .equal_equal      => return simpleBinOp(gz, scope, rl, node, .cmp_eq),
+        .greater_than     => return simpleBinOp(gz, scope, rl, node, .cmp_gt),
         .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte),
-        .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt),
-        .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte),
+        .less_than        => return simpleBinOp(gz, scope, rl, node, .cmp_lt),
+        .less_or_equal    => return simpleBinOp(gz, scope, rl, node, .cmp_lte),
 
-        .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat),
-        .array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul),
+        .array_cat        => return simpleBinOp(gz, scope, rl, node, .array_cat),
+        .array_mult       => return simpleBinOp(gz, scope, rl, node, .array_mul),
 
-        .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type),
+        .error_union      => return simpleBinOp(gz, scope, rl, node, .error_union_type),
         .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets),
 
         .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and),
-        .bool_or => return boolBinOp(gz, scope, rl, node, .bool_br_or),
+        .bool_or  => return boolBinOp(gz, scope, rl, node, .bool_br_or),
 
         .bool_not => return boolNot(gz, scope, rl, node),
-        .bit_not => return bitNot(gz, scope, rl, node),
+        .bit_not  => return bitNot(gz, scope, rl, node),
 
-        .negation => return negation(gz, scope, rl, node, .negate),
+        .negation      => return negation(gz, scope, rl, node, .negate),
         .negation_wrap => return negation(gz, scope, rl, node, .negate_wrap),
 
         .identifier => return identifier(gz, scope, rl, node),
 
         .asm_simple => return asmExpr(gz, scope, rl, node, tree.asmSimple(node)),
-        .@"asm" => return asmExpr(gz, scope, rl, node, tree.asmFull(node)),
+        .@"asm"     => return asmExpr(gz, scope, rl, node, tree.asmFull(node)),
 
-        .string_literal => return stringLiteral(gz, scope, rl, node),
+        .string_literal           => return stringLiteral(gz, scope, rl, node),
         .multiline_string_literal => return multilineStringLiteral(gz, scope, rl, node),
 
         .integer_literal => return integerLiteral(gz, scope, rl, node),
+        // zig fmt: on
 
         .builtin_call_two, .builtin_call_two_comma => {
             if (node_datas[node].lhs == 0) {
@@ -1181,13 +1190,14 @@ fn labeledBlockExpr(
             // All break operands are values that did not use the result location pointer.
             if (strat.elide_store_to_block_ptr_instructions) {
                 for (block_scope.labeled_store_to_block_ptr_list.items) |inst| {
-                    zir_tags[inst] = .elided;
-                    zir_datas[inst] = undefined;
+                    // Mark as elided for removal below.
+                    assert(zir_tags[inst] == .store_to_block_ptr);
+                    zir_datas[inst].bin.lhs = .none;
                 }
-                // TODO technically not needed since we changed the tag to elided but
-                // would be better still to elide the ones that are in this list.
+                try block_scope.setBlockBodyEliding(block_inst);
+            } else {
+                try block_scope.setBlockBody(block_inst);
             }
-            try block_scope.setBlockBody(block_inst);
             const block_ref = gz.indexToRef(block_inst);
             switch (rl) {
                 .ref => return block_ref,
@@ -1222,20 +1232,24 @@ fn blockExprStmts(
             .simple_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)),
             .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)),
 
+            // zig fmt: off
             .assign => try assign(gz, scope, statement),
-            .assign_bit_and => try assignOp(gz, scope, statement, .bit_and),
-            .assign_bit_or => try assignOp(gz, scope, statement, .bit_or),
-            .assign_bit_shift_left => try assignOp(gz, scope, statement, .shl),
-            .assign_bit_shift_right => try assignOp(gz, scope, statement, .shr),
-            .assign_bit_xor => try assignOp(gz, scope, statement, .xor),
-            .assign_div => try assignOp(gz, scope, statement, .div),
-            .assign_sub => try assignOp(gz, scope, statement, .sub),
+
+            .assign_bit_shift_left  => try assignShift(gz, scope, statement, .shl),
+            .assign_bit_shift_right => try assignShift(gz, scope, statement, .shr),
+
+            .assign_bit_and  => try assignOp(gz, scope, statement, .bit_and),
+            .assign_bit_or   => try assignOp(gz, scope, statement, .bit_or),
+            .assign_bit_xor  => try assignOp(gz, scope, statement, .xor),
+            .assign_div      => try assignOp(gz, scope, statement, .div),
+            .assign_sub      => try assignOp(gz, scope, statement, .sub),
             .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap),
-            .assign_mod => try assignOp(gz, scope, statement, .mod_rem),
-            .assign_add => try assignOp(gz, scope, statement, .add),
+            .assign_mod      => try assignOp(gz, scope, statement, .mod_rem),
+            .assign_add      => try assignOp(gz, scope, statement, .add),
             .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap),
-            .assign_mul => try assignOp(gz, scope, statement, .mul),
+            .assign_mul      => try assignOp(gz, scope, statement, .mul),
             .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap),
+            // zig fmt: on
 
             else => {
                 // We need to emit an error if the result is not `noreturn` or `void`, but
@@ -1313,7 +1327,6 @@ fn blockExprStmts(
                         .func_var_args,
                         .func_extra,
                         .func_extra_var_args,
-                        .has_decl,
                         .int,
                         .float,
                         .float128,
@@ -1390,6 +1403,7 @@ fn blockExprStmts(
                         .switch_capture_else_ref,
                         .struct_init_empty,
                         .struct_init,
+                        .union_init_ptr,
                         .field_type,
                         .struct_decl,
                         .struct_decl_packed,
@@ -1404,7 +1418,6 @@ fn blockExprStmts(
                         .size_of,
                         .bit_size_of,
                         .this,
-                        .fence,
                         .ret_addr,
                         .builtin_src,
                         .add_with_overflow,
@@ -1412,10 +1425,80 @@ fn blockExprStmts(
                         .mul_with_overflow,
                         .shl_with_overflow,
                         .log2_int_type,
+                        .typeof_log2_int_type,
+                        .error_return_trace,
+                        .frame,
+                        .frame_address,
+                        .ptr_to_int,
+                        .align_of,
+                        .bool_to_int,
+                        .embed_file,
+                        .error_name,
+                        .sqrt,
+                        .sin,
+                        .cos,
+                        .exp,
+                        .exp2,
+                        .log,
+                        .log2,
+                        .log10,
+                        .fabs,
+                        .floor,
+                        .ceil,
+                        .trunc,
+                        .round,
+                        .tag_name,
+                        .reify,
+                        .type_name,
+                        .frame_type,
+                        .frame_size,
+                        .float_to_int,
+                        .int_to_float,
+                        .int_to_ptr,
+                        .float_cast,
+                        .int_cast,
+                        .err_set_cast,
+                        .ptr_cast,
+                        .truncate,
+                        .align_cast,
+                        .has_decl,
+                        .has_field,
+                        .clz,
+                        .ctz,
+                        .pop_count,
+                        .byte_swap,
+                        .bit_reverse,
+                        .div_exact,
+                        .div_floor,
+                        .div_trunc,
+                        .mod,
+                        .rem,
+                        .shl_exact,
+                        .shr_exact,
+                        .bit_offset_of,
+                        .byte_offset_of,
+                        .cmpxchg_strong,
+                        .cmpxchg_weak,
+                        .splat,
+                        .reduce,
+                        .shuffle,
+                        .atomic_load,
+                        .atomic_rmw,
+                        .atomic_store,
+                        .mul_add,
+                        .builtin_call,
+                        .field_ptr_type,
+                        .field_parent_ptr,
+                        .memcpy,
+                        .memset,
+                        .builtin_async_call,
+                        .c_import,
+                        .extended,
                         => break :b false,
 
                         // ZIR instructions that are always either `noreturn` or `void`.
                         .breakpoint,
+                        .fence,
                         .dbg_stmt_node,
                         .ensure_result_used,
                         .ensure_result_non_error,
@@ -1432,7 +1515,6 @@ fn blockExprStmts(
                         .ret_tok,
                         .ret_coerce,
                         .@"unreachable",
-                        .elided,
                         .store,
                         .store_node,
                         .store_to_block_ptr,
@@ -1441,6 +1523,11 @@ fn blockExprStmts(
                         .repeat,
                         .repeat_inline,
                         .validate_struct_init_ptr,
+                        .panic,
+                        .set_align_stack,
+                        .set_cold,
+                        .set_float_mode,
+                        .set_runtime_safety,
                         => break :b true,
                     }
                 } else switch (maybe_unused_result) {
@@ -1702,12 +1789,34 @@ fn assignOp(
     _ = try gz.addBin(.store, lhs_ptr, result);
 }
 
+fn assignShift(
+    gz: *GenZir,
+    scope: *Scope,
+    infix_node: ast.Node.Index,
+    op_inst_tag: Zir.Inst.Tag,
+) InnerError!void {
+    const astgen = gz.astgen;
+    const tree = &astgen.file.tree;
+    const node_datas = tree.nodes.items(.data);
+
+    const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
+    const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
+    const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node);
+    const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs);
+
+    const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
+        .lhs = lhs,
+        .rhs = rhs,
+    });
+    _ = try gz.addBin(.store, lhs_ptr, result);
+}
+
 fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
     const astgen = gz.astgen;
     const tree = &astgen.file.tree;
     const node_datas = tree.nodes.items(.data);
 
-    const operand = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs);
+    const operand = try expr(gz, scope, bool_rl, node_datas[node].lhs);
     const result = try gz.addUnNode(.bool_not, operand, node);
     return rvalue(gz, scope, rl, result, node);
 }
@@ -1778,7 +1887,7 @@ fn ptrType(
         trailing_count += 1;
     }
     if (ptr_info.ast.align_node != 0) {
-        align_ref = try expr(gz, scope, .none, ptr_info.ast.align_node);
+        align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node);
         trailing_count += 1;
     }
     if (ptr_info.ast.bit_range_start != 0) {
@@ -1978,19 +2087,16 @@ fn fnDecl(
     );
 
     const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
-        // TODO instead of enum literal type, this needs to be the
-        // std.builtin.CallingConvention enum. We need to implement importing other files
-        // and enums in order to fix this.
         try AstGen.expr(
             &decl_gz,
             &decl_gz.base,
-            .{ .ty = .enum_literal_type },
+            .{ .ty = .calling_convention_type },
             fn_proto.ast.callconv_expr,
         )
     else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269
-        try decl_gz.addSmallStr(.enum_literal_small, "C")
+        Zir.Inst.Ref.calling_convention_c
     else
-        .none;
+        Zir.Inst.Ref.none;
 
     const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
         if (is_extern) {
@@ -3079,7 +3185,7 @@ fn boolBinOp(
 ) InnerError!Zir.Inst.Ref {
     const node_datas = gz.tree().nodes.items(.data);
 
-    const lhs = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs);
+    const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs);
     const bool_br = try gz.addBoolBr(zir_tag, lhs);
 
     var rhs_scope: GenZir = .{
@@ -3089,7 +3195,7 @@ fn boolBinOp(
         .force_comptime = gz.force_comptime,
     };
     defer rhs_scope.instructions.deinit(gz.astgen.gpa);
-    const rhs = try expr(&rhs_scope, &rhs_scope.base, .{ .ty = .bool_type }, node_datas[node].rhs);
+    const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);
     _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
     try rhs_scope.setBoolBrBody(bool_br);
 
@@ -3122,7 +3228,7 @@ fn ifExpr(
         } else if (if_full.payload_token) |payload_token| {
             return astgen.failTok(payload_token, "TODO implement if optional", .{});
         } else {
-            break :c try expr(&block_scope, &block_scope.base, .{ .ty = .bool_type }, if_full.ast.cond_expr);
+            break :c try expr(&block_scope, &block_scope.base, bool_rl, if_full.ast.cond_expr);
         }
     };
 
@@ -3291,8 +3397,7 @@ fn whileExpr(
         } else if (while_full.payload_token) |payload_token| {
             return astgen.failTok(payload_token, "TODO implement while optional", .{});
         } else {
-            const bool_type_rl: ResultLoc = .{ .ty = .bool_type };
-            break :c try expr(&continue_scope, &continue_scope.base, bool_type_rl, while_full.ast.cond_expr);
+            break :c try expr(&continue_scope, &continue_scope.base, bool_rl, while_full.ast.cond_expr);
         }
     };
 
@@ -4758,37 +4863,8 @@ fn builtinCall(
         }
     }
 
+    // zig fmt: off
     switch (info.tag) {
-        .ptr_to_int => {
-            const operand = try expr(gz, scope, .none, params[0]);
-            const result = try gz.addUnNode(.ptrtoint, operand, node);
-            return rvalue(gz, scope, rl, result, node);
-        },
-        .float_cast => {
-            const dest_type = try typeExpr(gz, scope, params[0]);
-            const rhs = try expr(gz, scope, .none, params[1]);
-            const result = try gz.addPlNode(.floatcast, node, Zir.Inst.Bin{
-                .lhs = dest_type,
-                .rhs = rhs,
-            });
-            return rvalue(gz, scope, rl, result, node);
-        },
-        .int_cast => {
-            const dest_type = try typeExpr(gz, scope, params[0]);
-            const rhs = try expr(gz, scope, .none, params[1]);
-            const result = try gz.addPlNode(.intcast, node, Zir.Inst.Bin{
-                .lhs = dest_type,
-                .rhs = rhs,
-            });
-            return rvalue(gz, scope, rl, result, node);
-        },
-        .breakpoint => {
-            _ = try gz.add(.{
-                .tag = .breakpoint,
-                .data = .{ .node = gz.nodeIndexToRelative(node) },
-            });
-            return rvalue(gz, scope, rl, .void_value, node);
-        },
         .import => {
             const node_tags = tree.nodes.items(.tag);
             const node_datas = tree.nodes.items(.data);
@@ -4804,26 +4880,6 @@ fn builtinCall(
             const result = try gz.addStrTok(.import, str.index, str_lit_token);
             return rvalue(gz, scope, rl, result, node);
         },
-        .error_to_int => {
-            const target = try expr(gz, scope, .none, params[0]);
-            const result = try gz.addUnNode(.error_to_int, target, node);
-            return rvalue(gz, scope, rl, result, node);
-        },
-        .int_to_error => {
-            const target = try expr(gz, scope, .{ .ty = .u16_type }, params[0]);
-            const result = try gz.addUnNode(.int_to_error, target, node);
-            return rvalue(gz, scope, rl, result, node);
-        },
-        .compile_error => {
-            const target = try expr(gz, scope, .none, params[0]);
-            const result = try gz.addUnNode(.compile_error, target, node);
-            return rvalue(gz, scope, rl, result, node);
-        },
-        .set_eval_branch_quota => {
-            const quota = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
-            const result = try gz.addUnNode(.set_eval_branch_quota, quota, node);
-            return rvalue(gz, scope, rl, result, node);
-        },
         .compile_log => {
             const arg_refs = try astgen.gpa.alloc(Zir.Inst.Ref, params.len);
             defer astgen.gpa.free(arg_refs);
@@ -4850,23 +4906,11 @@ fn builtinCall(
             });
             return rvalue(gz, scope, rl, result, node);
         },
-        .as => return as(gz, scope, rl, node, params[0], params[1]),
-        .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),
-        .TypeOf => return typeOf(gz, scope, rl, node, params),
-
-        .int_to_enum => {
-            const result = try gz.addPlNode(.int_to_enum, node, Zir.Inst.Bin{
-                .lhs = try typeExpr(gz, scope, params[0]),
-                .rhs = try expr(gz, scope, .none, params[1]),
-            });
-            return rvalue(gz, scope, rl, result, node);
-        },
-
-        .enum_to_int => {
-            const operand = try expr(gz, scope, .none, params[0]);
-            const result = try gz.addUnNode(.enum_to_int, operand, node);
-            return rvalue(gz, scope, rl, result, node);
-        },
+        .as         => return as(       gz, scope, rl, node, params[0], params[1]),
+        .bit_cast   => return bitCast(  gz, scope, rl, node, params[0], params[1]),
+        .TypeOf     => return typeOf(   gz, scope, rl, node, params),
+        .union_init => return unionInit(gz, scope, rl, node, params),
+        .c_import   => return cImport(  gz, scope, rl, node, params[0]),
 
         .@"export" => {
             // TODO: @export is supposed to be able to export things other than functions.
@@ -4882,38 +4926,147 @@ fn builtinCall(
             return rvalue(gz, scope, rl, .void_value, node);
         },
 
-        .has_decl => {
-            const container_type = try typeExpr(gz, scope, params[0]);
-            const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
-            const result = try gz.addPlNode(.has_decl, node, Zir.Inst.Bin{
-                .lhs = container_type,
-                .rhs = name,
+        .breakpoint => return simpleNoOpVoid(gz, scope, rl, node, .breakpoint),
+        .fence      => return simpleNoOpVoid(gz, scope, rl, node, .fence),
+
+        .This               => return rvalue(gz, scope, rl, try gz.addNode(.this,               node), node),
+        .return_address     => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr,           node), node),
+        .src                => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src,        node), node),
+        .error_return_trace => return rvalue(gz, scope, rl, try gz.addNode(.error_return_trace, node), node),
+        .frame              => return rvalue(gz, scope, rl, try gz.addNode(.frame,              node), node),
+        .frame_address      => return rvalue(gz, scope, rl, try gz.addNode(.frame_address,      node), node),
+
+        .type_info   => return simpleUnOpType(gz, scope, rl, node, params[0], .type_info),
+        .size_of     => return simpleUnOpType(gz, scope, rl, node, params[0], .size_of),
+        .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of),
+        .align_of    => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of),
+
+        .ptr_to_int            => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .ptr_to_int),
+        .error_to_int          => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .error_to_int),
+        .int_to_error          => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u16_type },            params[0], .int_to_error),
+        .compile_error         => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error),
+        .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u32_type },            params[0], .set_eval_branch_quota),
+        .enum_to_int           => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .enum_to_int),
+        .bool_to_int           => return simpleUnOp(gz, scope, rl, node, bool_rl,                         params[0], .bool_to_int),
+        .embed_file            => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file),
+        .error_name            => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type },       params[0], .error_name),
+        .panic                 => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic),
+        .set_align_stack       => return simpleUnOp(gz, scope, rl, node, align_rl,                        params[0], .set_align_stack),
+        .set_cold              => return simpleUnOp(gz, scope, rl, node, bool_rl,                         params[0], .set_cold),
+        .set_float_mode        => return simpleUnOp(gz, scope, rl, node, .{ .ty = .float_mode_type },     params[0], .set_float_mode),
+        .set_runtime_safety    => return simpleUnOp(gz, scope, rl, node, bool_rl,                         params[0], .set_runtime_safety),
+        .sqrt                  => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .sqrt),
+        .sin                   => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .sin),
+        .cos                   => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .cos),
+        .exp                   => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .exp),
+        .exp2                  => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .exp2),
+        .log                   => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .log),
+        .log2                  => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .log2),
+        .log10                 => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .log10),
+        .fabs                  => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .fabs),
+        .floor                 => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .floor),
+        .ceil                  => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .ceil),
+        .trunc                 => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .trunc),
+        .round                 => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .round),
+        .tag_name              => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .tag_name),
+        .Type                  => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .reify),
+        .type_name             => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .type_name),
+        .Frame                 => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .frame_type),
+        .frame_size            => return simpleUnOp(gz, scope, rl, node, .none,                           params[0], .frame_size),
+
+        .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int),
+        .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float),
+        .int_to_ptr   => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_ptr),
+        .int_to_enum  => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_enum),
+        .float_cast   => return typeCast(gz, scope, rl, node, params[0], params[1], .float_cast),
+        .int_cast     => return typeCast(gz, scope, rl, node, params[0], params[1], .int_cast),
+        .err_set_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .err_set_cast),
+        .ptr_cast     => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast),
+        .truncate     => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate),
+        .align_cast => {
+            const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]);
+            const rhs = try expr(gz, scope, .none, params[1]);
+            const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{
+                .lhs = dest_align,
+                .rhs = rhs,
             });
             return rvalue(gz, scope, rl, result, node);
         },
 
-        .type_info => {
-            const operand = try typeExpr(gz, scope, params[0]);
-            const result = try gz.addUnNode(.type_info, operand, node);
+        .has_decl  => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl),
+        .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field),
+
+        .clz         => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz),
+        .ctz         => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz),
+        .pop_count   => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count),
+        .byte_swap   => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap),
+        .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse),
+
+        .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact),
+        .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor),
+        .div_trunc => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_trunc),
+        .mod       => return divBuiltin(gz, scope, rl, node, params[0], params[1], .mod),
+        .rem       => return divBuiltin(gz, scope, rl, node, params[0], params[1], .rem),
+
+        .shl_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shl_exact),
+        .shr_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shr_exact),
+
+        .bit_offset_of  => return offsetOf(gz, scope, rl, node, params[0], params[1], .bit_offset_of),
+        .byte_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .byte_offset_of),
+
+        .c_undef   => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_undef),
+        .c_include => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_include),
+
+        .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong),
+        .cmpxchg_weak   => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak),
+
+        .wasm_memory_size => {
+            const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
+            const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{
+                .node = gz.nodeIndexToRelative(node),
+                .operand = operand,
+            });
             return rvalue(gz, scope, rl, result, node);
         },
-
-        .size_of => {
-            const operand = try typeExpr(gz, scope, params[0]);
-            const result = try gz.addUnNode(.size_of, operand, node);
+        .wasm_memory_grow => {
+            const index_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
+            const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]);
+            const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{
+                .node = gz.nodeIndexToRelative(node),
+                .lhs = index_arg,
+                .rhs = delta_arg,
+            });
             return rvalue(gz, scope, rl, result, node);
         },
-
-        .bit_size_of => {
-            const operand = try typeExpr(gz, scope, params[0]);
-            const result = try gz.addUnNode(.bit_size_of, operand, node);
+        .c_define => {
+            const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]);
+            const value = try comptimeExpr(gz, scope, .none, params[1]);
+            const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{
+                .node = gz.nodeIndexToRelative(node),
+                .lhs = name,
+                .rhs = value,
+            });
             return rvalue(gz, scope, rl, result, node);
         },
 
-        .This => return rvalue(gz, scope, rl, try gz.addNode(.this, node), node),
-        .fence => return rvalue(gz, scope, rl, try gz.addNode(.fence, node), node),
-        .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node),
-        .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node),
+        .splat => {
+            const len = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
+            const scalar = try expr(gz, scope, .none, params[1]);
+            const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
+                .lhs = len,
+                .rhs = scalar,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .reduce => {
+            const op = try expr(gz, scope, .{ .ty = .reduce_op_type }, params[0]);
+            const scalar = try expr(gz, scope, .none, params[1]);
+            const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{
+                .lhs = op,
+                .rhs = scalar,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
 
         .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow),
         .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow),
@@ -4941,83 +5094,373 @@ fn builtinCall(
             return rvalue(gz, scope, rl, result, node);
         },
 
-        .align_cast,
-        .align_of,
-        .atomic_load,
-        .atomic_rmw,
-        .atomic_store,
-        .bit_offset_of,
-        .bool_to_int,
-        .mul_add,
-        .byte_swap,
-        .bit_reverse,
-        .byte_offset_of,
-        .call,
-        .c_define,
-        .c_import,
-        .c_include,
-        .clz,
-        .cmpxchg_strong,
-        .cmpxchg_weak,
-        .ctz,
-        .c_undef,
-        .div_exact,
-        .div_floor,
-        .div_trunc,
-        .embed_file,
-        .error_name,
-        .error_return_trace,
-        .err_set_cast,
-        .field_parent_ptr,
-        .float_to_int,
-        .has_field,
-        .int_to_float,
-        .int_to_ptr,
-        .memcpy,
-        .memset,
-        .wasm_memory_size,
-        .wasm_memory_grow,
-        .mod,
-        .panic,
-        .pop_count,
-        .ptr_cast,
-        .rem,
-        .set_align_stack,
-        .set_cold,
-        .set_float_mode,
-        .set_runtime_safety,
-        .shl_exact,
-        .shr_exact,
-        .shuffle,
-        .splat,
-        .reduce,
-        .sqrt,
-        .sin,
-        .cos,
-        .exp,
-        .exp2,
-        .log,
-        .log2,
-        .log10,
-        .fabs,
-        .floor,
-        .ceil,
-        .trunc,
-        .round,
-        .tag_name,
-        .truncate,
-        .Type,
-        .type_name,
-        .union_init,
-        .async_call,
-        .frame,
-        .Frame,
-        .frame_address,
-        .frame_size,
-        => return astgen.failNode(node, "TODO: implement builtin function {s}", .{
-            builtin_name,
-        }),
+        .atomic_load => {
+            const int_type = try typeExpr(gz, scope, params[0]);
+            const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
+                .ptr_type_simple = .{
+                    .is_allowzero = false,
+                    .is_mutable = false,
+                    .is_volatile = false,
+                    .size = .One,
+                    .elem_type = int_type,
+                },
+            } });
+            const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]);
+            const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[2]);
+            const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.Bin{
+                .lhs = ptr,
+                .rhs = ordering,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .atomic_rmw => {
+            const int_type = try typeExpr(gz, scope, params[0]);
+            const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
+                .ptr_type_simple = .{
+                    .is_allowzero = false,
+                    .is_mutable = true,
+                    .is_volatile = false,
+                    .size = .One,
+                    .elem_type = int_type,
+                },
+            } });
+            const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]);
+            const operation = try expr(gz, scope, .{ .ty = .atomic_rmw_op_type }, params[2]);
+            const operand = try expr(gz, scope, .{ .ty = int_type }, params[3]);
+            const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]);
+            const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{
+                .ptr = ptr,
+                .operation = operation,
+                .operand = operand,
+                .ordering = ordering,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .atomic_store => {
+            const int_type = try typeExpr(gz, scope, params[0]);
+            const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
+                .ptr_type_simple = .{
+                    .is_allowzero = false,
+                    .is_mutable = true,
+                    .is_volatile = false,
+                    .size = .One,
+                    .elem_type = int_type,
+                },
+            } });
+            const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]);
+            const operand = try expr(gz, scope, .{ .ty = int_type }, params[2]);
+            const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[3]);
+            const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{
+                .ptr = ptr,
+                .operand = operand,
+                .ordering = ordering,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .mul_add => {
+            const float_type = try typeExpr(gz, scope, params[0]);
+            const mulend1 = try expr(gz, scope, .{ .ty = float_type }, params[1]);
+            const mulend2 = try expr(gz, scope, .{ .ty = float_type }, params[2]);
+            const addend = try expr(gz, scope, .{ .ty = float_type }, params[3]);
+            const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{
+                .mulend1 = mulend1,
+                .mulend2 = mulend2,
+                .addend = addend,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .call => {
+            const options = try comptimeExpr(gz, scope, .{ .ty = .call_options_type }, params[0]);
+            const callee = try expr(gz, scope, .none, params[1]);
+            const args = try expr(gz, scope, .none, params[2]);
+            const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{
+                .options = options,
+                .callee = callee,
+                .args = args,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .field_parent_ptr => {
+            const parent_type = try typeExpr(gz, scope, params[0]);
+            const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
+            const field_ptr_type = try gz.addBin(.field_ptr_type, parent_type, field_name);
+            const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{
+                .parent_type = parent_type,
+                .field_name = field_name,
+                .field_ptr = try expr(gz, scope, .{ .ty = field_ptr_type }, params[2]),
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .memcpy => {
+            const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{
+                .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]),
+                .source = try expr(gz, scope, .{ .ty = .manyptr_const_u8_type }, params[1]),
+                .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]),
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .memset => {
+            const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{
+                .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]),
+                .byte = try expr(gz, scope, .{ .ty = .u8_type }, params[1]),
+                .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]),
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .shuffle => {
+            const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{
+                .elem_type = try typeExpr(gz, scope, params[0]),
+                .a = try expr(gz, scope, .none, params[1]),
+                .b = try expr(gz, scope, .none, params[2]),
+                .mask = try comptimeExpr(gz, scope, .none, params[3]),
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+        .async_call => {
+            const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{
+                .frame_buffer = try expr(gz, scope, .none, params[0]),
+                .result_ptr = try expr(gz, scope, .none, params[1]),
+                .fn_ptr = try expr(gz, scope, .none, params[2]),
+                .args = try expr(gz, scope, .none, params[3]),
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
     }
+    // zig fmt: on
+}
+
+fn simpleNoOpVoid(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    _ = try gz.addNode(tag, node);
+    return rvalue(gz, scope, rl, .void_value, node);
+}
+
+fn hasDeclOrField(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    lhs_node: ast.Node.Index,
+    rhs_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const container_type = try typeExpr(gz, scope, lhs_node);
+    const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node);
+    const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
+        .lhs = container_type,
+        .rhs = name,
+    });
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn typeCast(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    lhs_node: ast.Node.Index,
+    rhs_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
+        .lhs = try typeExpr(gz, scope, lhs_node),
+        .rhs = try expr(gz, scope, .none, rhs_node),
+    });
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn simpleUnOpType(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    operand_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const operand = try typeExpr(gz, scope, operand_node);
+    const result = try gz.addUnNode(tag, operand, node);
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn simpleUnOp(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    operand_rl: ResultLoc,
+    operand_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const operand = try expr(gz, scope, operand_rl, operand_node);
+    const result = try gz.addUnNode(tag, operand, node);
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn cmpxchg(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    params: []const ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const int_type = try typeExpr(gz, scope, params[0]);
+    const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{
+        .ptr_type_simple = .{
+            .is_allowzero = false,
+            .is_mutable = true,
+            .is_volatile = false,
+            .size = .One,
+            .elem_type = int_type,
+        },
+    } });
+    const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{
+        // zig fmt: off
+        .ptr            = try expr(gz, scope, .{ .ty = ptr_type },              params[1]),
+        .expected_value = try expr(gz, scope, .{ .ty = int_type },              params[2]),
+        .new_value      = try expr(gz, scope, .{ .ty = int_type },              params[3]),
+        .success_order  = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]),
+        .fail_order     = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[5]),
+        // zig fmt: on
+    });
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn bitBuiltin(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    int_type_node: ast.Node.Index,
+    operand_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const int_type = try typeExpr(gz, scope, int_type_node);
+    const operand = try expr(gz, scope, .{ .ty = int_type }, operand_node);
+    const result = try gz.addUnNode(tag, operand, node);
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn divBuiltin(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    lhs_node: ast.Node.Index,
+    rhs_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
+        .lhs = try expr(gz, scope, .none, lhs_node),
+        .rhs = try expr(gz, scope, .none, rhs_node),
+    });
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn simpleCBuiltin(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    operand_node: ast.Node.Index,
+    tag: Zir.Inst.Extended,
+) InnerError!Zir.Inst.Ref {
+    const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node);
+    _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{
+        .node = gz.nodeIndexToRelative(node),
+        .operand = operand,
+    });
+    return rvalue(gz, scope, rl, .void_value, node);
+}
+
+fn offsetOf(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    lhs_node: ast.Node.Index,
+    rhs_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const type_inst = try typeExpr(gz, scope, lhs_node);
+    const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node);
+    const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
+        .lhs = type_inst,
+        .rhs = field_name,
+    });
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn shiftOp(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    lhs_node: ast.Node.Index,
+    rhs_node: ast.Node.Index,
+    tag: Zir.Inst.Tag,
+) InnerError!Zir.Inst.Ref {
+    const lhs = try expr(gz, scope, .none, lhs_node);
+    const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node);
+    const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node);
+    const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
+        .lhs = lhs,
+        .rhs = rhs,
+    });
+    return rvalue(gz, scope, rl, result, node);
+}
+
+fn cImport(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    body_node: ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+    const astgen = gz.astgen;
+    const gpa = astgen.gpa;
+
+    var block_scope: GenZir = .{
+        .parent = scope,
+        .decl_node_index = gz.decl_node_index,
+        .astgen = astgen,
+        .force_comptime = true,
+        .instructions = .{},
+    };
+    defer block_scope.instructions.deinit(gpa);
+
+    const block_inst = try gz.addBlock(.c_import, node);
+    const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);
+    if (!gz.refIsNoReturn(block_result)) {
+        _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
+    }
+    try block_scope.setBlockBody(block_inst);
+    try gz.instructions.append(gpa, block_inst);
+
+    return rvalue(gz, scope, rl, .void_value, node);
+}
+
+fn unionInit(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: ast.Node.Index,
+    params: []const ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+    const union_type = try typeExpr(gz, scope, params[0]);
+    const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
+    const union_init_ptr = try gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{
+        .union_type = union_type,
+        .field_name = field_name,
+    });
+    // TODO: set up a store_to_block_ptr elision thing here
+    const result = try expr(gz, scope, .{ .ptr = union_init_ptr }, params[2]);
+    return rvalue(gz, scope, rl, result, node);
 }
 
 fn overflowArithmetic(
src/Module.zig
@@ -1198,6 +1198,30 @@ pub const Scope = struct {
             gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);
         }
 
+        /// Same as `setBlockBody` except we don't copy instructions which are
+        /// `store_to_block_ptr` instructions with lhs set to .none.
+        pub fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void {
+            const gpa = gz.astgen.gpa;
+            try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
+                @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
+            const zir_datas = gz.astgen.instructions.items(.data);
+            const zir_tags = gz.astgen.instructions.items(.tag);
+            const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{
+                .body_len = @intCast(u32, gz.instructions.items.len),
+            });
+            zir_datas[inst].pl_node.payload_index = block_pl_index;
+            for (gz.instructions.items) |sub_inst| {
+                if (zir_tags[sub_inst] == .store_to_block_ptr and
+                    zir_datas[sub_inst].bin.lhs == .none)
+                {
+                    // Decrement `body_len`.
+                    gz.astgen.extra.items[block_pl_index] -= 1;
+                    continue;
+                }
+                gz.astgen.extra.appendAssumeCapacity(sub_inst);
+            }
+        }
+
         pub fn identAsString(gz: *GenZir, ident_token: ast.TokenIndex) !u32 {
             const astgen = gz.astgen;
             const gpa = astgen.gpa;
@@ -1445,6 +1469,30 @@ pub const Scope = struct {
             return gz.indexToRef(new_index);
         }
 
+        pub fn addExtendedPayload(
+            gz: *GenZir,
+            opcode: Zir.Inst.Extended,
+            extra: anytype,
+        ) !Zir.Inst.Ref {
+            const gpa = gz.astgen.gpa;
+
+            try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
+            try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
+
+            const payload_index = try gz.astgen.addExtra(extra);
+            const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
+            gz.astgen.instructions.appendAssumeCapacity(.{
+                .tag = .extended,
+                .data = .{ .extended = .{
+                    .opcode = opcode,
+                    .small = undefined,
+                    .operand = payload_index,
+                } },
+            });
+            gz.instructions.appendAssumeCapacity(new_index);
+            return gz.indexToRef(new_index);
+        }
+
         pub fn addArrayTypeSentinel(
             gz: *GenZir,
             len: Zir.Inst.Ref,
src/Sema.zig
@@ -131,159 +131,227 @@ pub fn analyzeBody(
     while (true) : (i += 1) {
         const inst = body[i];
         map[inst] = switch (tags[inst]) {
-            .elided => continue,
-
-            .alloc => try sema.zirAlloc(block, inst),
-            .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
-            .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
-            .alloc_mut => try sema.zirAllocMut(block, inst),
-            .array_cat => try sema.zirArrayCat(block, inst),
-            .array_mul => try sema.zirArrayMul(block, inst),
-            .array_type => try sema.zirArrayType(block, inst),
-            .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
-            .as => try sema.zirAs(block, inst),
-            .as_node => try sema.zirAsNode(block, inst),
-            .@"asm" => try sema.zirAsm(block, inst, false),
-            .asm_volatile => try sema.zirAsm(block, inst, true),
-            .bit_and => try sema.zirBitwise(block, inst, .bit_and),
-            .bit_not => try sema.zirBitNot(block, inst),
-            .bit_or => try sema.zirBitwise(block, inst, .bit_or),
-            .bitcast => try sema.zirBitcast(block, inst),
-            .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
-            .block => try sema.zirBlock(block, inst),
-            .bool_not => try sema.zirBoolNot(block, inst),
-            .bool_and => try sema.zirBoolOp(block, inst, false),
-            .bool_or => try sema.zirBoolOp(block, inst, true),
-            .bool_br_and => try sema.zirBoolBr(block, inst, false),
-            .bool_br_or => try sema.zirBoolBr(block, inst, true),
-            .call => try sema.zirCall(block, inst, .auto, false),
-            .call_chkused => try sema.zirCall(block, inst, .auto, true),
-            .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
-            .call_none => try sema.zirCallNone(block, inst, false),
-            .call_none_chkused => try sema.zirCallNone(block, inst, true),
-            .cmp_eq => try sema.zirCmp(block, inst, .eq),
-            .cmp_gt => try sema.zirCmp(block, inst, .gt),
-            .cmp_gte => try sema.zirCmp(block, inst, .gte),
-            .cmp_lt => try sema.zirCmp(block, inst, .lt),
-            .cmp_lte => try sema.zirCmp(block, inst, .lte),
-            .cmp_neq => try sema.zirCmp(block, inst, .neq),
-            .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
-            .decl_ref => try sema.zirDeclRef(block, inst),
-            .decl_val => try sema.zirDeclVal(block, inst),
-            .load => try sema.zirLoad(block, inst),
-            .elem_ptr => try sema.zirElemPtr(block, inst),
-            .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
-            .elem_val => try sema.zirElemVal(block, inst),
-            .elem_val_node => try sema.zirElemValNode(block, inst),
-            .enum_literal => try sema.zirEnumLiteral(block, inst),
-            .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),
-            .enum_to_int => try sema.zirEnumToInt(block, inst),
-            .int_to_enum => try sema.zirIntToEnum(block, inst),
-            .err_union_code => try sema.zirErrUnionCode(block, inst),
-            .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
-            .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
-            .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
-            .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
+            // zig fmt: off
+            .alloc                        => try sema.zirAlloc(block, inst),
+            .alloc_inferred               => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
+            .alloc_inferred_mut           => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
+            .alloc_mut                    => try sema.zirAllocMut(block, inst),
+            .array_cat                    => try sema.zirArrayCat(block, inst),
+            .array_mul                    => try sema.zirArrayMul(block, inst),
+            .array_type                   => try sema.zirArrayType(block, inst),
+            .array_type_sentinel          => try sema.zirArrayTypeSentinel(block, inst),
+            .as                           => try sema.zirAs(block, inst),
+            .as_node                      => try sema.zirAsNode(block, inst),
+            .@"asm"                       => try sema.zirAsm(block, inst, false),
+            .asm_volatile                 => try sema.zirAsm(block, inst, true),
+            .bit_and                      => try sema.zirBitwise(block, inst, .bit_and),
+            .bit_not                      => try sema.zirBitNot(block, inst),
+            .bit_or                       => try sema.zirBitwise(block, inst, .bit_or),
+            .bitcast                      => try sema.zirBitcast(block, inst),
+            .bitcast_result_ptr           => try sema.zirBitcastResultPtr(block, inst),
+            .block                        => try sema.zirBlock(block, inst),
+            .bool_not                     => try sema.zirBoolNot(block, inst),
+            .bool_and                     => try sema.zirBoolOp(block, inst, false),
+            .bool_or                      => try sema.zirBoolOp(block, inst, true),
+            .bool_br_and                  => try sema.zirBoolBr(block, inst, false),
+            .bool_br_or                   => try sema.zirBoolBr(block, inst, true),
+            .c_import                     => try sema.zirCImport(block, inst),
+            .call                         => try sema.zirCall(block, inst, .auto, false),
+            .call_chkused                 => try sema.zirCall(block, inst, .auto, true),
+            .call_compile_time            => try sema.zirCall(block, inst, .compile_time, false),
+            .call_none                    => try sema.zirCallNone(block, inst, false),
+            .call_none_chkused            => try sema.zirCallNone(block, inst, true),
+            .cmp_eq                       => try sema.zirCmp(block, inst, .eq),
+            .cmp_gt                       => try sema.zirCmp(block, inst, .gt),
+            .cmp_gte                      => try sema.zirCmp(block, inst, .gte),
+            .cmp_lt                       => try sema.zirCmp(block, inst, .lt),
+            .cmp_lte                      => try sema.zirCmp(block, inst, .lte),
+            .cmp_neq                      => try sema.zirCmp(block, inst, .neq),
+            .coerce_result_ptr            => try sema.zirCoerceResultPtr(block, inst),
+            .decl_ref                     => try sema.zirDeclRef(block, inst),
+            .decl_val                     => try sema.zirDeclVal(block, inst),
+            .load                         => try sema.zirLoad(block, inst),
+            .elem_ptr                     => try sema.zirElemPtr(block, inst),
+            .elem_ptr_node                => try sema.zirElemPtrNode(block, inst),
+            .elem_val                     => try sema.zirElemVal(block, inst),
+            .elem_val_node                => try sema.zirElemValNode(block, inst),
+            .enum_literal                 => try sema.zirEnumLiteral(block, inst),
+            .enum_literal_small           => try sema.zirEnumLiteralSmall(block, inst),
+            .enum_to_int                  => try sema.zirEnumToInt(block, inst),
+            .int_to_enum                  => try sema.zirIntToEnum(block, inst),
+            .err_union_code               => try sema.zirErrUnionCode(block, inst),
+            .err_union_code_ptr           => try sema.zirErrUnionCodePtr(block, inst),
+            .err_union_payload_safe       => try sema.zirErrUnionPayload(block, inst, true),
+            .err_union_payload_safe_ptr   => try sema.zirErrUnionPayloadPtr(block, inst, true),
+            .err_union_payload_unsafe     => try sema.zirErrUnionPayload(block, inst, false),
             .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
-            .error_union_type => try sema.zirErrorUnionType(block, inst),
-            .error_value => try sema.zirErrorValue(block, inst),
-            .error_to_int => try sema.zirErrorToInt(block, inst),
-            .int_to_error => try sema.zirIntToError(block, inst),
-            .field_ptr => try sema.zirFieldPtr(block, inst),
-            .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
-            .field_val => try sema.zirFieldVal(block, inst),
-            .field_val_named => try sema.zirFieldValNamed(block, inst),
-            .floatcast => try sema.zirFloatcast(block, inst),
-            .func => try sema.zirFunc(block, inst, false),
-            .func_extra => try sema.zirFuncExtra(block, inst, false),
-            .func_extra_var_args => try sema.zirFuncExtra(block, inst, true),
-            .func_var_args => try sema.zirFunc(block, inst, true),
-            .has_decl => try sema.zirHasDecl(block, inst),
-            .import => try sema.zirImport(block, inst),
-            .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
-            .int => try sema.zirInt(block, inst),
-            .float => try sema.zirFloat(block, inst),
-            .float128 => try sema.zirFloat128(block, inst),
-            .int_type => try sema.zirIntType(block, inst),
-            .intcast => try sema.zirIntcast(block, inst),
-            .is_err => try sema.zirIsErr(block, inst),
-            .is_err_ptr => try sema.zirIsErrPtr(block, inst),
-            .is_non_null => try sema.zirIsNull(block, inst, true),
-            .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true),
-            .is_null => try sema.zirIsNull(block, inst, false),
-            .is_null_ptr => try sema.zirIsNullPtr(block, inst, false),
-            .loop => try sema.zirLoop(block, inst),
-            .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
-            .negate => try sema.zirNegate(block, inst, .sub),
-            .negate_wrap => try sema.zirNegate(block, inst, .subwrap),
-            .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
-            .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
-            .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
-            .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
-            .optional_type => try sema.zirOptionalType(block, inst),
-            .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, inst),
-            .param_type => try sema.zirParamType(block, inst),
-            .ptr_type => try sema.zirPtrType(block, inst),
-            .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
-            .ptrtoint => try sema.zirPtrtoint(block, inst),
-            .ref => try sema.zirRef(block, inst),
-            .ret_ptr => try sema.zirRetPtr(block, inst),
-            .ret_type => try sema.zirRetType(block, inst),
-            .shl => try sema.zirShl(block, inst),
-            .shr => try sema.zirShr(block, inst),
-            .slice_end => try sema.zirSliceEnd(block, inst),
-            .slice_sentinel => try sema.zirSliceSentinel(block, inst),
-            .slice_start => try sema.zirSliceStart(block, inst),
-            .str => try sema.zirStr(block, inst),
-            .switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
-            .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
-            .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
-            .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
-            .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
-            .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
-            .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
-            .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
-            .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
-            .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
-            .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
+            .error_union_type             => try sema.zirErrorUnionType(block, inst),
+            .error_value                  => try sema.zirErrorValue(block, inst),
+            .error_to_int                 => try sema.zirErrorToInt(block, inst),
+            .int_to_error                 => try sema.zirIntToError(block, inst),
+            .field_ptr                    => try sema.zirFieldPtr(block, inst),
+            .field_ptr_named              => try sema.zirFieldPtrNamed(block, inst),
+            .field_val                    => try sema.zirFieldVal(block, inst),
+            .field_val_named              => try sema.zirFieldValNamed(block, inst),
+            .floatcast                    => try sema.zirFloatcast(block, inst),
+            .func                         => try sema.zirFunc(block, inst, false),
+            .func_extra                   => try sema.zirFuncExtra(block, inst, false),
+            .func_extra_var_args          => try sema.zirFuncExtra(block, inst, true),
+            .func_var_args                => try sema.zirFunc(block, inst, true),
+            .import                       => try sema.zirImport(block, inst),
+            .indexable_ptr_len            => try sema.zirIndexablePtrLen(block, inst),
+            .int                          => try sema.zirInt(block, inst),
+            .float                        => try sema.zirFloat(block, inst),
+            .float128                     => try sema.zirFloat128(block, inst),
+            .int_type                     => try sema.zirIntType(block, inst),
+            .intcast                      => try sema.zirIntcast(block, inst),
+            .is_err                       => try sema.zirIsErr(block, inst),
+            .is_err_ptr                   => try sema.zirIsErrPtr(block, inst),
+            .is_non_null                  => try sema.zirIsNull(block, inst, true),
+            .is_non_null_ptr              => try sema.zirIsNullPtr(block, inst, true),
+            .is_null                      => try sema.zirIsNull(block, inst, false),
+            .is_null_ptr                  => try sema.zirIsNullPtr(block, inst, false),
+            .loop                         => try sema.zirLoop(block, inst),
+            .merge_error_sets             => try sema.zirMergeErrorSets(block, inst),
+            .negate                       => try sema.zirNegate(block, inst, .sub),
+            .negate_wrap                  => try sema.zirNegate(block, inst, .subwrap),
+            .optional_payload_safe        => try sema.zirOptionalPayload(block, inst, true),
+            .optional_payload_safe_ptr    => try sema.zirOptionalPayloadPtr(block, inst, true),
+            .optional_payload_unsafe      => try sema.zirOptionalPayload(block, inst, false),
+            .optional_payload_unsafe_ptr  => try sema.zirOptionalPayloadPtr(block, inst, false),
+            .optional_type                => try sema.zirOptionalType(block, inst),
+            .optional_type_from_ptr_elem  => try sema.zirOptionalTypeFromPtrElem(block, inst),
+            .param_type                   => try sema.zirParamType(block, inst),
+            .ptr_type                     => try sema.zirPtrType(block, inst),
+            .ptr_type_simple              => try sema.zirPtrTypeSimple(block, inst),
+            .ptrtoint                     => try sema.zirPtrtoint(block, inst),
+            .ref                          => try sema.zirRef(block, inst),
+            .ret_ptr                      => try sema.zirRetPtr(block, inst),
+            .ret_type                     => try sema.zirRetType(block, inst),
+            .shl                          => try sema.zirShl(block, inst),
+            .shr                          => try sema.zirShr(block, inst),
+            .slice_end                    => try sema.zirSliceEnd(block, inst),
+            .slice_sentinel               => try sema.zirSliceSentinel(block, inst),
+            .slice_start                  => try sema.zirSliceStart(block, inst),
+            .str                          => try sema.zirStr(block, inst),
+            .switch_block                 => try sema.zirSwitchBlock(block, inst, false, .none),
+            .switch_block_multi           => try sema.zirSwitchBlockMulti(block, inst, false, .none),
+            .switch_block_else            => try sema.zirSwitchBlock(block, inst, false, .@"else"),
+            .switch_block_else_multi      => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
+            .switch_block_under           => try sema.zirSwitchBlock(block, inst, false, .under),
+            .switch_block_under_multi     => try sema.zirSwitchBlockMulti(block, inst, false, .under),
+            .switch_block_ref             => try sema.zirSwitchBlock(block, inst, true, .none),
+            .switch_block_ref_multi       => try sema.zirSwitchBlockMulti(block, inst, true, .none),
+            .switch_block_ref_else        => try sema.zirSwitchBlock(block, inst, true, .@"else"),
+            .switch_block_ref_else_multi  => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
+            .switch_block_ref_under       => try sema.zirSwitchBlock(block, inst, true, .under),
             .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
-            .switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
-            .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
-            .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
-            .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
-            .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
-            .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
-            .type_info => try sema.zirTypeInfo(block, inst),
-            .size_of => try sema.zirSizeOf(block, inst),
-            .bit_size_of => try sema.zirBitSizeOf(block, inst),
-            .this => try sema.zirThis(block, inst),
-            .fence => try sema.zirFence(block, inst),
-            .ret_addr => try sema.zirRetAddr(block, inst),
-            .builtin_src => try sema.zirBuiltinSrc(block, inst),
-            .typeof => try sema.zirTypeof(block, inst),
-            .typeof_elem => try sema.zirTypeofElem(block, inst),
-            .typeof_peer => try sema.zirTypeofPeer(block, inst),
-            .log2_int_type => try sema.zirLog2IntType(block, inst),
-            .xor => try sema.zirBitwise(block, inst, .xor),
-            .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
-            .struct_init => try sema.zirStructInit(block, inst),
-            .field_type => try sema.zirFieldType(block, inst),
-
-            .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
-            .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
-            .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),
-            .enum_decl => try sema.zirEnumDecl(block, inst, false),
+            .switch_capture               => try sema.zirSwitchCapture(block, inst, false, false),
+            .switch_capture_ref           => try sema.zirSwitchCapture(block, inst, false, true),
+            .switch_capture_multi         => try sema.zirSwitchCapture(block, inst, true, false),
+            .switch_capture_multi_ref     => try sema.zirSwitchCapture(block, inst, true, true),
+            .switch_capture_else          => try sema.zirSwitchCaptureElse(block, inst, false),
+            .switch_capture_else_ref      => try sema.zirSwitchCaptureElse(block, inst, true),
+            .type_info                    => try sema.zirTypeInfo(block, inst),
+            .size_of                      => try sema.zirSizeOf(block, inst),
+            .bit_size_of                  => try sema.zirBitSizeOf(block, inst),
+            .this                         => try sema.zirThis(block, inst),
+            .ret_addr                     => try sema.zirRetAddr(block, inst),
+            .builtin_src                  => try sema.zirBuiltinSrc(block, inst),
+            .typeof                       => try sema.zirTypeof(block, inst),
+            .typeof_elem                  => try sema.zirTypeofElem(block, inst),
+            .typeof_peer                  => try sema.zirTypeofPeer(block, inst),
+            .log2_int_type                => try sema.zirLog2IntType(block, inst),
+            .typeof_log2_int_type         => try sema.zirTypeofLog2IntType(block, inst),
+            .xor                          => try sema.zirBitwise(block, inst, .xor),
+            .struct_init_empty            => try sema.zirStructInitEmpty(block, inst),
+            .struct_init                  => try sema.zirStructInit(block, inst),
+            .union_init_ptr               => try sema.zirUnionInitPtr(block, inst),
+            .field_type                   => try sema.zirFieldType(block, inst),
+            .error_return_trace           => try sema.zirErrorReturnTrace(block, inst),
+            .frame                        => try sema.zirFrame(block, inst),
+            .frame_address                => try sema.zirFrameAddress(block, inst),
+            .ptr_to_int                   => try sema.zirPtrToInt(block, inst),
+            .align_of                     => try sema.zirAlignOf(block, inst),
+            .bool_to_int                  => try sema.zirBoolToInt(block, inst),
+            .embed_file                   => try sema.zirEmbedFile(block, inst),
+            .error_name                   => try sema.zirErrorName(block, inst),
+            .tag_name                     => try sema.zirTagName(block, inst),
+            .reify                        => try sema.zirReify(block, inst),
+            .type_name                    => try sema.zirTypeName(block, inst),
+            .frame_type                   => try sema.zirFrameType(block, inst),
+            .frame_size                   => try sema.zirFrameSize(block, inst),
+            .float_to_int                 => try sema.zirFloatToInt(block, inst),
+            .int_to_float                 => try sema.zirIntToFloat(block, inst),
+            .int_to_ptr                   => try sema.zirIntToPtr(block, inst),
+            .float_cast                   => try sema.zirFloatCast(block, inst),
+            .int_cast                     => try sema.zirIntCast(block, inst),
+            .err_set_cast                 => try sema.zirErrSetCast(block, inst),
+            .ptr_cast                     => try sema.zirPtrCast(block, inst),
+            .truncate                     => try sema.zirTruncate(block, inst),
+            .align_cast                   => try sema.zirAlignCast(block, inst),
+            .has_decl                     => try sema.zirHasDecl(block, inst),
+            .has_field                    => try sema.zirHasField(block, inst),
+            .clz                          => try sema.zirClz(block, inst),
+            .ctz                          => try sema.zirCtz(block, inst),
+            .pop_count                    => try sema.zirPopCount(block, inst),
+            .byte_swap                    => try sema.zirByteSwap(block, inst),
+            .bit_reverse                  => try sema.zirBitReverse(block, inst),
+            .div_exact                    => try sema.zirDivExact(block, inst),
+            .div_floor                    => try sema.zirDivFloor(block, inst),
+            .div_trunc                    => try sema.zirDivTrunc(block, inst),
+            .mod                          => try sema.zirMod(block, inst),
+            .rem                          => try sema.zirRem(block, inst),
+            .shl_exact                    => try sema.zirShlExact(block, inst),
+            .shr_exact                    => try sema.zirShrExact(block, inst),
+            .bit_offset_of                => try sema.zirBitOffsetOf(block, inst),
+            .byte_offset_of               => try sema.zirByteOffsetOf(block, inst),
+            .cmpxchg_strong               => try sema.zirCmpxchg(block, inst),
+            .cmpxchg_weak                 => try sema.zirCmpxchg(block, inst),
+            .splat                        => try sema.zirSplat(block, inst),
+            .reduce                       => try sema.zirReduce(block, inst),
+            .shuffle                      => try sema.zirShuffle(block, inst),
+            .atomic_load                  => try sema.zirAtomicLoad(block, inst),
+            .atomic_rmw                   => try sema.zirAtomicRmw(block, inst),
+            .atomic_store                 => try sema.zirAtomicStore(block, inst),
+            .mul_add                      => try sema.zirMulAdd(block, inst),
+            .builtin_call                 => try sema.zirBuiltinCall(block, inst),
+            .field_ptr_type               => try sema.zirFieldPtrType(block, inst),
+            .field_parent_ptr             => try sema.zirFieldParentPtr(block, inst),
+            .memcpy                       => try sema.zirMemcpy(block, inst),
+            .memset                       => try sema.zirMemset(block, inst),
+            .builtin_async_call           => try sema.zirBuiltinAsyncCall(block, inst),
+            .extended                     => try sema.zirExtended(block, inst),
+
+            .sqrt  => try sema.zirUnaryMath(block, inst),
+            .sin   => try sema.zirUnaryMath(block, inst),
+            .cos   => try sema.zirUnaryMath(block, inst),
+            .exp   => try sema.zirUnaryMath(block, inst),
+            .exp2  => try sema.zirUnaryMath(block, inst),
+            .log   => try sema.zirUnaryMath(block, inst),
+            .log2  => try sema.zirUnaryMath(block, inst),
+            .log10 => try sema.zirUnaryMath(block, inst),
+            .fabs  => try sema.zirUnaryMath(block, inst),
+            .floor => try sema.zirUnaryMath(block, inst),
+            .ceil  => try sema.zirUnaryMath(block, inst),
+            .trunc => try sema.zirUnaryMath(block, inst),
+            .round => try sema.zirUnaryMath(block, inst),
+
+            .struct_decl             => try sema.zirStructDecl(block, inst, .Auto),
+            .struct_decl_packed      => try sema.zirStructDecl(block, inst, .Packed),
+            .struct_decl_extern      => try sema.zirStructDecl(block, inst, .Extern),
+            .enum_decl               => try sema.zirEnumDecl(block, inst, false),
             .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),
-            .union_decl => try sema.zirUnionDecl(block, inst),
-            .opaque_decl => try sema.zirOpaqueDecl(block, inst),
+            .union_decl              => try sema.zirUnionDecl(block, inst),
+            .opaque_decl             => try sema.zirOpaqueDecl(block, inst),
 
-            .add => try sema.zirArithmetic(block, inst),
+            .add     => try sema.zirArithmetic(block, inst),
             .addwrap => try sema.zirArithmetic(block, inst),
-            .div => try sema.zirArithmetic(block, inst),
+            .div     => try sema.zirArithmetic(block, inst),
             .mod_rem => try sema.zirArithmetic(block, inst),
-            .mul => try sema.zirArithmetic(block, inst),
+            .mul     => try sema.zirArithmetic(block, inst),
             .mulwrap => try sema.zirArithmetic(block, inst),
-            .sub => try sema.zirArithmetic(block, inst),
+            .sub     => try sema.zirArithmetic(block, inst),
             .subwrap => try sema.zirArithmetic(block, inst),
 
             .add_with_overflow => try sema.zirOverflowArithmetic(block, inst),
@@ -294,15 +362,17 @@ pub fn analyzeBody(
             // Instructions that we know to *always* be noreturn based solely on their tag.
             // These functions match the return type of analyzeBody so that we can
             // tail call them here.
-            .condbr => return sema.zirCondbr(block, inst),
-            .@"break" => return sema.zirBreak(block, inst),
-            .break_inline => return inst,
-            .compile_error => return sema.zirCompileError(block, inst),
-            .ret_coerce => return sema.zirRetTok(block, inst, true),
-            .ret_node => return sema.zirRetNode(block, inst),
-            .ret_tok => return sema.zirRetTok(block, inst, false),
+            .break_inline   => return inst,
+            .condbr         => return sema.zirCondbr(block, inst),
+            .@"break"       => return sema.zirBreak(block, inst),
+            .compile_error  => return sema.zirCompileError(block, inst),
+            .ret_coerce     => return sema.zirRetTok(block, inst, true),
+            .ret_node       => return sema.zirRetNode(block, inst),
+            .ret_tok        => return sema.zirRetTok(block, inst, false),
             .@"unreachable" => return sema.zirUnreachable(block, inst),
-            .repeat => return sema.zirRepeat(block, inst),
+            .repeat         => return sema.zirRepeat(block, inst),
+            .panic          => return sema.zirPanic(block, inst),
+            // zig fmt: on
 
             // Instructions that we know can *never* be noreturn based solely on
             // their tag. We avoid needlessly checking if they are noreturn and
@@ -313,6 +383,10 @@ pub fn analyzeBody(
                 try sema.zirBreakpoint(block, inst);
                 continue;
             },
+            .fence => {
+                try sema.zirFence(block, inst);
+                continue;
+            },
             .dbg_stmt_node => {
                 try sema.zirDbgStmtNode(block, inst);
                 continue;
@@ -365,6 +439,22 @@ pub fn analyzeBody(
                 try sema.zirExport(block, inst);
                 continue;
             },
+            .set_align_stack => {
+                try sema.zirSetAlignStack(block, inst);
+                continue;
+            },
+            .set_cold => {
+                try sema.zirSetAlignStack(block, inst);
+                continue;
+            },
+            .set_float_mode => {
+                try sema.zirSetFloatMode(block, inst);
+                continue;
+            },
+            .set_runtime_safety => {
+                try sema.zirSetRuntimeSafety(block, inst);
+                continue;
+            },
 
             // Special case instructions to handle comptime control flow.
             .repeat_inline => {
@@ -1382,6 +1472,13 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
     return always_noreturn;
 }
 
+fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src: LazySrcLoc = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirPanic", .{});
+    //return always_noreturn;
+}
+
 fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const tracy = trace(@src());
     defer tracy.end();
@@ -1443,6 +1540,16 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerE
     return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
 }
 
+fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const tracy = trace(@src());
+    defer tracy.end();
+
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+
+    return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{});
+}
+
 fn zirBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const tracy = trace(@src());
     defer tracy.end();
@@ -1597,6 +1704,30 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
     try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl);
 }
 
+fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src: LazySrcLoc = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetAlignStack", .{});
+}
+
+fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src: LazySrcLoc = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetCold", .{});
+}
+
+fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src: LazySrcLoc = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetFloatMode", .{});
+}
+
+fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src: LazySrcLoc = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetRuntimeSafety", .{});
+}
+
 fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
     const tracy = trace(@src());
     defer tracy.end();
@@ -1607,6 +1738,12 @@ fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
     _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
 }
 
+fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
+    const src_node = sema.code.instructions.items(.data)[inst].node;
+    const src: LazySrcLoc = .{ .node_offset = src_node };
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{});
+}
+
 fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {
     const tracy = trace(@src());
     defer tracy.end();
@@ -3874,10 +4011,15 @@ fn validateSwitchNoRange(
     return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
 }
 
-fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
-    const tracy = trace(@src());
-    defer tracy.end();
+fn zirHasField(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+    const src = inst_data.src();
+
+    return sema.mod.fail(&block.base, src, "TODO implement zirHasField", .{});
+}
 
+fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
     const src = inst_data.src();
@@ -4382,16 +4524,13 @@ fn zirThis(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*I
     const src: LazySrcLoc = .{ .node_offset = src_node };
     return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{});
 }
-fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
-    const src_node = sema.code.instructions.items(.data)[inst].node;
-    const src: LazySrcLoc = .{ .node_offset = src_node };
-    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{});
-}
+
 fn zirRetAddr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const src_node = sema.code.instructions.items(.data)[inst].node;
     const src: LazySrcLoc = .{ .node_offset = src_node };
     return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirRetAddr", .{});
 }
+
 fn zirBuiltinSrc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const src_node = sema.code.instructions.items(.data)[inst].node;
     const src: LazySrcLoc = .{ .node_offset = src_node };
@@ -4419,6 +4558,12 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
     return sema.mod.constType(sema.arena, src, elem_ty);
 }
 
+fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeofLog2IntType", .{});
+}
+
 fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
@@ -4827,6 +4972,12 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
     });
 }
 
+fn zirUnionInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirUnionInitPtr", .{});
+}
+
 fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
     const src = inst_data.src();
@@ -4839,6 +4990,380 @@ fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr
     return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldType", .{});
 }
 
+fn zirErrorReturnTrace(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrorReturnTrace", .{});
+}
+
+fn zirFrame(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrame", .{});
+}
+
+fn zirFrameAddress(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameAddress", .{});
+}
+
+fn zirPtrToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirPtrToInt", .{});
+}
+
+fn zirAlignOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirAlignOf", .{});
+}
+
+fn zirBoolToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirBoolToInt", .{});
+}
+
+fn zirEmbedFile(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirEmbedFile", .{});
+}
+
+fn zirErrorName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrorName", .{});
+}
+
+fn zirUnaryMath(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirUnaryMath", .{});
+}
+
+fn zirTagName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirTagName", .{});
+}
+
+fn zirReify(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirReify", .{});
+}
+
+fn zirTypeName(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirTypeName", .{});
+}
+
+fn zirFrameType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameType", .{});
+}
+
+fn zirFrameSize(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFrameSize", .{});
+}
+
+fn zirFloatToInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFloatToInt", .{});
+}
+
+fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToFloat", .{});
+}
+
+fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToPtr", .{});
+}
+
+fn zirFloatCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFloatCast", .{});
+}
+
+fn zirIntCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntCast", .{});
+}
+
+fn zirErrSetCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirErrSetCast", .{});
+}
+
+fn zirPtrCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirPtrCast", .{});
+}
+
+fn zirTruncate(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirTruncate", .{});
+}
+
+fn zirAlignCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirAlignCast", .{});
+}
+
+fn zirClz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirClz", .{});
+}
+
+fn zirCtz(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirCtz", .{});
+}
+
+fn zirPopCount(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirPopCount", .{});
+}
+
+fn zirByteSwap(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirByteSwap", .{});
+}
+
+fn zirBitReverse(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirBitReverse", .{});
+}
+
+fn zirDivExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivExact", .{});
+}
+
+fn zirDivFloor(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivFloor", .{});
+}
+
+fn zirDivTrunc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirDivTrunc", .{});
+}
+
+fn zirMod(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirMod", .{});
+}
+
+fn zirRem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirRem", .{});
+}
+
+fn zirShlExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirShlExact", .{});
+}
+
+fn zirShrExact(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirShrExact", .{});
+}
+
+fn zirBitOffsetOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirBitOffsetOf", .{});
+}
+
+fn zirByteOffsetOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirByteOffsetOf", .{});
+}
+
+fn zirCmpxchg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirCmpxchg", .{});
+}
+
+fn zirSplat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirSplat", .{});
+}
+
+fn zirReduce(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirReduce", .{});
+}
+
+fn zirShuffle(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirShuffle", .{});
+}
+
+fn zirAtomicLoad(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicLoad", .{});
+}
+
+fn zirAtomicRmw(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicRmw", .{});
+}
+
+fn zirAtomicStore(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirAtomicStore", .{});
+}
+
+fn zirMulAdd(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirMulAdd", .{});
+}
+
+fn zirBuiltinCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirBuiltinCall", .{});
+}
+
+fn zirFieldPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldPtrType", .{});
+}
+
+fn zirFieldParentPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldParentPtr", .{});
+}
+
+fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemcpy", .{});
+}
+
+fn zirMemset(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemset", .{});
+}
+
+fn zirBuiltinAsyncCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    return sema.mod.fail(&block.base, src, "TODO: Sema.zirBuiltinAsyncCall", .{});
+}
+
+fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const extended = sema.code.instructions.items(.data)[inst].extended;
+    switch (extended.opcode) {
+        // zig fmt: off
+        .c_undef            => return sema.zirCUndef(           block, inst, extended),
+        .c_include          => return sema.zirCInclude(         block, inst, extended),
+        .c_define           => return sema.zirCDefine(          block, inst, extended),
+        .wasm_memory_size   => return sema.zirWasmMemorySize(   block, inst, extended),
+        .wasm_memory_grow   => return sema.zirWasmMemoryGrow(   block, inst, extended),
+        // zig fmt: on
+    }
+}
+
+fn zirCUndef(
+    sema: *Sema,
+    block: *Scope.Block,
+    inst: Zir.Inst.Index,
+    extended: Zir.Inst.Extended.InstData,
+) InnerError!*Inst {
+    const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+    const src: LazySrcLoc = .{ .node_offset = extra.node };
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCUndef", .{});
+}
+
+fn zirCInclude(
+    sema: *Sema,
+    block: *Scope.Block,
+    inst: Zir.Inst.Index,
+    extended: Zir.Inst.Extended.InstData,
+) InnerError!*Inst {
+    const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+    const src: LazySrcLoc = .{ .node_offset = extra.node };
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCInclude", .{});
+}
+
+fn zirCDefine(
+    sema: *Sema,
+    block: *Scope.Block,
+    inst: Zir.Inst.Index,
+    extended: Zir.Inst.Extended.InstData,
+) InnerError!*Inst {
+    const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
+    const src: LazySrcLoc = .{ .node_offset = extra.node };
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCDefine", .{});
+}
+
+fn zirWasmMemorySize(
+    sema: *Sema,
+    block: *Scope.Block,
+    inst: Zir.Inst.Index,
+    extended: Zir.Inst.Extended.InstData,
+) InnerError!*Inst {
+    const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
+    const src: LazySrcLoc = .{ .node_offset = extra.node };
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirWasmMemorySize", .{});
+}
+
+fn zirWasmMemoryGrow(
+    sema: *Sema,
+    block: *Scope.Block,
+    inst: Zir.Inst.Index,
+    extended: Zir.Inst.Extended.InstData,
+) InnerError!*Inst {
+    const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
+    const src: LazySrcLoc = .{ .node_offset = extra.node };
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirWasmMemoryGrow", .{});
+}
+
 fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
     if (sema.func == null) {
         return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
src/type.zig
@@ -83,6 +83,8 @@ pub const Type = extern union {
             .pointer,
             .inferred_alloc_const,
             .inferred_alloc_mut,
+            .manyptr_u8,
+            .manyptr_const_u8,
             => return .Pointer,
 
             .optional,
@@ -96,11 +98,17 @@ pub const Type = extern union {
             .empty_struct,
             .empty_struct_literal,
             .@"struct",
+            .call_options,
             => return .Struct,
 
             .enum_full,
             .enum_nonexhaustive,
             .enum_simple,
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
             => return .Enum,
 
             .var_args_param => unreachable, // can be any type
@@ -205,6 +213,8 @@ pub const Type = extern union {
             .mut_slice,
             .optional_single_const_pointer,
             .optional_single_mut_pointer,
+            .manyptr_u8,
+            .manyptr_const_u8,
             => self.cast(Payload.ElemType),
 
             .inferred_alloc_const => unreachable,
@@ -271,6 +281,17 @@ pub const Type = extern union {
                 .@"volatile" = false,
                 .size = .Many,
             } },
+            .manyptr_const_u8 => return .{ .data = .{
+                .pointee_type = Type.initTag(.u8),
+                .sentinel = null,
+                .@"align" = 0,
+                .bit_offset = 0,
+                .host_size = 0,
+                .@"allowzero" = false,
+                .mutable = false,
+                .@"volatile" = false,
+                .size = .Many,
+            } },
             .many_mut_pointer => return .{ .data = .{
                 .pointee_type = self.castPointer().?.data,
                 .sentinel = null,
@@ -282,6 +303,17 @@ pub const Type = extern union {
                 .@"volatile" = false,
                 .size = .Many,
             } },
+            .manyptr_u8 => return .{ .data = .{
+                .pointee_type = Type.initTag(.u8),
+                .sentinel = null,
+                .@"align" = 0,
+                .bit_offset = 0,
+                .host_size = 0,
+                .@"allowzero" = false,
+                .mutable = true,
+                .@"volatile" = false,
+                .size = .Many,
+            } },
             .c_const_pointer => return .{ .data = .{
                 .pointee_type = self.castPointer().?.data,
                 .sentinel = null,
@@ -576,6 +608,14 @@ pub const Type = extern union {
             .inferred_alloc_mut,
             .var_args_param,
             .empty_struct_literal,
+            .manyptr_u8,
+            .manyptr_const_u8,
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
             => unreachable,
 
             .array_u8,
@@ -746,6 +786,14 @@ pub const Type = extern union {
                 .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),
                 .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"),
                 .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),
+                .manyptr_u8 => return writer.writeAll("[*]u8"),
+                .manyptr_const_u8 => return writer.writeAll("[*]const u8"),
+                .atomic_ordering => return writer.writeAll("std.builtin.AtomicOrdering"),
+                .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),
+                .calling_convention => return writer.writeAll("std.builtin.CallingConvention"),
+                .float_mode => return writer.writeAll("std.builtin.FloatMode"),
+                .reduce_op => return writer.writeAll("std.builtin.ReduceOp"),
+                .call_options => return writer.writeAll("std.builtin.CallOptions"),
                 .function => {
                     const payload = ty.castTag(.function).?.data;
                     try writer.writeAll("fn(");
@@ -952,6 +1000,14 @@ pub const Type = extern union {
             .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
             .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
             .enum_literal => return Value.initTag(.enum_literal_type),
+            .manyptr_u8 => return Value.initTag(.manyptr_u8_type),
+            .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type),
+            .atomic_ordering => return Value.initTag(.atomic_ordering_type),
+            .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),
+            .calling_convention => return Value.initTag(.calling_convention_type),
+            .float_mode => return Value.initTag(.float_mode_type),
+            .reduce_op => return Value.initTag(.reduce_op_type),
+            .call_options => return Value.initTag(.call_options_type),
             .inferred_alloc_const => unreachable,
             .inferred_alloc_mut => unreachable,
             else => return Value.Tag.ty.create(allocator, self),
@@ -1001,6 +1057,14 @@ pub const Type = extern union {
             .anyerror_void_error_union,
             .error_set,
             .error_set_single,
+            .manyptr_u8,
+            .manyptr_const_u8,
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
             => true,
 
             .@"struct" => {
@@ -1079,7 +1143,10 @@ pub const Type = extern union {
             .optional_single_mut_pointer,
             => return self.cast(Payload.ElemType).?.data.abiAlignment(target),
 
-            .const_slice_u8 => return 1,
+            .manyptr_u8,
+            .manyptr_const_u8,
+            .const_slice_u8,
+            => return 1,
 
             .pointer => {
                 const ptr_info = self.castTag(.pointer).?.data;
@@ -1102,6 +1169,12 @@ pub const Type = extern union {
             .bool,
             .array_u8_sentinel_0,
             .array_u8,
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
             => return 1,
 
             .fn_noreturn_no_args, // represents machine code; not a pointer
@@ -1136,6 +1209,8 @@ pub const Type = extern union {
             .optional_single_const_pointer,
             .optional_single_mut_pointer,
             .pointer,
+            .manyptr_u8,
+            .manyptr_const_u8,
             => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
 
             .c_short => return @divExact(CType.short.sizeInBits(target), 8),
@@ -1271,6 +1346,12 @@ pub const Type = extern union {
             .u8,
             .i8,
             .bool,
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
             => return 1,
 
             .array_u8 => self.castTag(.array_u8).?.data,
@@ -1322,6 +1403,10 @@ pub const Type = extern union {
                 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
             },
 
+            .manyptr_u8,
+            .manyptr_const_u8,
+            => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
+
             .c_short => return @divExact(CType.short.sizeInBits(target), 8),
             .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
             .c_int => return @divExact(CType.int.sizeInBits(target), 8),
@@ -1475,6 +1560,10 @@ pub const Type = extern union {
                 }
             },
 
+            .manyptr_u8,
+            .manyptr_const_u8,
+            => return target.cpu.arch.ptrBitWidth(),
+
             .c_short => return CType.short.sizeInBits(target),
             .c_ushort => return CType.ushort.sizeInBits(target),
             .c_int => return CType.int.sizeInBits(target),
@@ -1517,8 +1606,16 @@ pub const Type = extern union {
                 } else if (!payload.payload.hasCodeGenBits()) {
                     return payload.error_set.bitSize(target);
                 }
-                @panic("TODO abiSize error union");
+                @panic("TODO bitSize error union");
             },
+
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO at some point we gotta resolve builtin types"),
         };
     }
 
@@ -1564,6 +1661,8 @@ pub const Type = extern union {
 
             .many_const_pointer,
             .many_mut_pointer,
+            .manyptr_u8,
+            .manyptr_const_u8,
             => .Many,
 
             .c_const_pointer,
@@ -1604,6 +1703,7 @@ pub const Type = extern union {
             .single_const_pointer_to_comptime_int,
             .const_slice_u8,
             .const_slice,
+            .manyptr_const_u8,
             => true,
 
             .pointer => !self.castTag(.pointer).?.data.mutable,
@@ -1718,7 +1818,13 @@ pub const Type = extern union {
             .mut_slice,
             => self.castPointer().?.data,
 
-            .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
+            .array_u8,
+            .array_u8_sentinel_0,
+            .const_slice_u8,
+            .manyptr_u8,
+            .manyptr_const_u8,
+            => Type.initTag(.u8),
+
             .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
             .pointer => self.castTag(.pointer).?.data.pointee_type,
 
@@ -1811,6 +1917,8 @@ pub const Type = extern union {
             .single_const_pointer_to_comptime_int,
             .array,
             .array_u8,
+            .manyptr_u8,
+            .manyptr_const_u8,
             => return null,
 
             .pointer => return self.castTag(.pointer).?.data.sentinel,
@@ -2122,6 +2230,14 @@ pub const Type = extern union {
             .error_set_single,
             .@"opaque",
             .var_args_param,
+            .manyptr_u8,
+            .manyptr_const_u8,
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
             => return null,
 
             .@"struct" => {
@@ -2281,6 +2397,14 @@ pub const Type = extern union {
                 const enum_simple = ty.castTag(.enum_simple).?.data;
                 return enum_simple.fields.count();
             },
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO resolve std.builtin types"),
+
             else => unreachable,
         }
     }
@@ -2295,6 +2419,13 @@ pub const Type = extern union {
                 const enum_simple = ty.castTag(.enum_simple).?.data;
                 return enum_simple.fields.entries.items[field_index].key;
             },
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
     }
@@ -2309,6 +2440,13 @@ pub const Type = extern union {
                 const enum_simple = ty.castTag(.enum_simple).?.data;
                 return enum_simple.fields.getIndex(field_name);
             },
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
     }
@@ -2345,6 +2483,13 @@ pub const Type = extern union {
                 const enum_simple = ty.castTag(.enum_simple).?.data;
                 return S.fieldWithRange(enum_tag, enum_simple.fields.count());
             },
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
     }
@@ -2367,6 +2512,13 @@ pub const Type = extern union {
                 const error_set = ty.castTag(.error_set).?.data;
                 return error_set.srcLoc();
             },
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
     }
@@ -2390,6 +2542,13 @@ pub const Type = extern union {
                 return error_set.owner_decl;
             },
             .@"opaque" => @panic("TODO"),
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
     }
@@ -2422,6 +2581,13 @@ pub const Type = extern union {
                 const enum_simple = ty.castTag(.enum_simple).?.data;
                 return S.intInRange(int, enum_simple.fields.count());
             },
+            .atomic_ordering,
+            .atomic_rmw_op,
+            .calling_convention,
+            .float_mode,
+            .reduce_op,
+            .call_options,
+            => @panic("TODO resolve std.builtin types"),
 
             else => unreachable,
         }
@@ -2469,6 +2635,14 @@ pub const Type = extern union {
         comptime_float,
         noreturn,
         enum_literal,
+        manyptr_u8,
+        manyptr_const_u8,
+        atomic_ordering,
+        atomic_rmw_op,
+        calling_convention,
+        float_mode,
+        reduce_op,
+        call_options,
         @"null",
         @"undefined",
         fn_noreturn_no_args,
@@ -2572,6 +2746,14 @@ pub const Type = extern union {
                 .inferred_alloc_mut,
                 .var_args_param,
                 .empty_struct_literal,
+                .manyptr_u8,
+                .manyptr_const_u8,
+                .atomic_ordering,
+                .atomic_rmw_op,
+                .calling_convention,
+                .float_mode,
+                .reduce_op,
+                .call_options,
                 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
 
                 .array_u8,
src/value.zig
@@ -64,6 +64,14 @@ pub const Value = extern union {
         single_const_pointer_to_comptime_int_type,
         const_slice_u8_type,
         enum_literal_type,
+        manyptr_u8_type,
+        manyptr_const_u8_type,
+        atomic_ordering_type,
+        atomic_rmw_op_type,
+        calling_convention_type,
+        float_mode_type,
+        reduce_op_type,
+        call_options_type,
 
         undef,
         zero,
@@ -169,6 +177,14 @@ pub const Value = extern union {
                 .bool_true,
                 .bool_false,
                 .abi_align_default,
+                .manyptr_u8_type,
+                .manyptr_const_u8_type,
+                .atomic_ordering_type,
+                .atomic_rmw_op_type,
+                .calling_convention_type,
+                .float_mode_type,
+                .reduce_op_type,
+                .call_options_type,
                 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
 
                 .int_big_positive,
@@ -327,6 +343,14 @@ pub const Value = extern union {
             .bool_false,
             .empty_struct_value,
             .abi_align_default,
+            .manyptr_u8_type,
+            .manyptr_const_u8_type,
+            .atomic_ordering_type,
+            .atomic_rmw_op_type,
+            .calling_convention_type,
+            .float_mode_type,
+            .reduce_op_type,
+            .call_options_type,
             => unreachable,
 
             .ty => {
@@ -474,6 +498,14 @@ pub const Value = extern union {
             .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
             .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
             .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
+            .manyptr_u8_type => return out_stream.writeAll("[*]u8"),
+            .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),
+            .atomic_ordering_type => return out_stream.writeAll("std.builtin.AtomicOrdering"),
+            .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
+            .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),
+            .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"),
+            .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"),
+            .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"),
             .abi_align_default => return out_stream.writeAll("(default ABI alignment)"),
 
             .empty_struct_value => return out_stream.writeAll("struct {}{}"),
@@ -595,6 +627,14 @@ pub const Value = extern union {
             .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
             .const_slice_u8_type => Type.initTag(.const_slice_u8),
             .enum_literal_type => Type.initTag(.enum_literal),
+            .manyptr_u8_type => Type.initTag(.manyptr_u8),
+            .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),
+            .atomic_ordering_type => Type.initTag(.atomic_ordering),
+            .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),
+            .calling_convention_type => Type.initTag(.calling_convention),
+            .float_mode_type => Type.initTag(.float_mode),
+            .reduce_op_type => Type.initTag(.reduce_op),
+            .call_options_type => Type.initTag(.call_options),
 
             .int_type => {
                 const payload = self.castTag(.int_type).?.data;
@@ -1132,6 +1172,16 @@ pub const Value = extern union {
                 std.hash.autoHash(&hasher, payload.hash());
             },
             .inferred_alloc => unreachable,
+
+            .manyptr_u8_type,
+            .manyptr_const_u8_type,
+            .atomic_ordering_type,
+            .atomic_rmw_op_type,
+            .calling_convention_type,
+            .float_mode_type,
+            .reduce_op_type,
+            .call_options_type,
+            => @panic("TODO this hash function looks pretty broken. audit it"),
         }
         return hasher.final();
     }
@@ -1278,6 +1328,14 @@ pub const Value = extern union {
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
             .enum_literal_type,
+            .manyptr_u8_type,
+            .manyptr_const_u8_type,
+            .atomic_ordering_type,
+            .atomic_rmw_op_type,
+            .calling_convention_type,
+            .float_mode_type,
+            .reduce_op_type,
+            .call_options_type,
             => true,
 
             .zero,
src/Zir.zig
@@ -274,9 +274,6 @@ pub const Inst = struct {
         /// Uses the `bin` union field.
         /// LHS is destination element type, RHS is result pointer.
         coerce_result_ptr,
-        /// Emit an error message and fail compilation.
-        /// Uses the `un_node` field.
-        compile_error,
         /// Log compile time variables and emit an error message.
         /// Uses the `pl_node` union field. The AST node is the compile log builtin call.
         /// The payload is `MultiOp`.
@@ -339,9 +336,6 @@ pub const Inst = struct {
         /// Same as `elem_val` except also stores a source location node.
         /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
         elem_val_node,
-        /// This instruction has been deleted late in the astgen phase. It must
-        /// be ignored, and the corresponding `Data` is undefined.
-        elided,
         /// Emits a compile error if the operand is not `void`.
         /// Uses the `un_node` field.
         ensure_result_used,
@@ -391,9 +385,6 @@ pub const Inst = struct {
         func_extra,
         /// Same as `func_extra` but the function is variadic.
         func_extra_var_args,
-        /// Implements the `@hasDecl` builtin.
-        /// Uses the `pl_node` union field. Payload is `Bin`.
-        has_decl,
         /// Implements the `@import` builtin.
         /// Uses the `str_tok` field.
         import,
@@ -412,10 +403,6 @@ pub const Inst = struct {
         /// Make an integer type out of signedness and bit count.
         /// Payload is `int_type`
         int_type,
-        /// Convert an error type to `u16`
-        error_to_int,
-        /// Convert a `u16` to `anyerror`
-        int_to_error,
         /// Return a boolean false if an optional is null. `x != null`
         /// Uses the `un_node` field.
         is_non_null,
@@ -498,16 +485,6 @@ pub const Inst = struct {
         /// Same as `ret_tok` except the operand needs to get coerced to the function's
         /// return type.
         ret_coerce,
-        /// Changes the maximum number of backwards branches that compile-time
-        /// code execution can use before giving up and making a compile error.
-        /// Uses the `un_node` union field.
-        set_eval_branch_quota,
-        /// Integer shift-left. Zeroes are shifted in from the right hand side.
-        /// Uses the `pl_node` union field. Payload is `Bin`.
-        shl,
-        /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
-        /// Uses the `pl_node` union field. Payload is `Bin`.
-        shr,
         /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
         /// Uses the `ptr_type_simple` union field.
         ptr_type_simple,
@@ -573,6 +550,10 @@ pub const Inst = struct {
         /// of one or more params.
         /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
         typeof_peer,
+        /// Given a value, look at the type of it, which must be an integer type.
+        /// Returns the integer type for the RHS of a shift operation.
+        /// Uses the `un_node` field.
+        typeof_log2_int_type,
         /// Given an integer type, returns the integer type for the RHS of a shift operation.
         /// Uses the `un_node` field.
         log2_int_type,
@@ -712,12 +693,10 @@ pub const Inst = struct {
         /// struct value.
         /// Uses the `pl_node` field. Payload is `StructInit`.
         struct_init,
-        /// Converts an integer into an enum value.
-        /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
-        int_to_enum,
-        /// Converts an enum value into an integer. Resulting type will be the tag type
-        /// of the enum. Uses `un_node`.
-        enum_to_int,
+        /// Given a pointer to a union and a comptime known field name, activates that field
+        /// and returns a pointer to it.
+        /// Uses the `pl_node` field. Payload is `UnionInitPtr`.
+        union_init_ptr,
         /// Implements the `@typeInfo` builtin. Uses `un_node`.
         type_info,
         /// Implements the `@sizeOf` builtin. Uses `un_node`.
@@ -741,6 +720,224 @@ pub const Inst = struct {
         /// Implements the `@shlWithOverflow` builtin. Uses `pl_node` with `OverflowArithmetic`.
         shl_with_overflow,
 
+        /// Implements the `@errorReturnTrace` builtin.
+        /// Uses the `un_node` field.
+        error_return_trace,
+        /// Implements the `@frame` builtin.
+        /// Uses the `un_node` field.
+        frame,
+        /// Implements the `@frameAddress` builtin.
+        /// Uses the `un_node` field.
+        frame_address,
+
+        /// Implement builtin `@ptrToInt`. Uses `un_node`.
+        ptr_to_int,
+        /// Implement builtin `@errToInt`. Uses `un_node`.
+        error_to_int,
+        /// Implement builtin `@intToError`. Uses `un_node`.
+        int_to_error,
+        /// Emit an error message and fail compilation.
+        /// Uses the `un_node` field.
+        compile_error,
+        /// Changes the maximum number of backwards branches that compile-time
+        /// code execution can use before giving up and making a compile error.
+        /// Uses the `un_node` union field.
+        set_eval_branch_quota,
+        /// Converts an enum value into an integer. Resulting type will be the tag type
+        /// of the enum. Uses `un_node`.
+        enum_to_int,
+        /// Implement builtin `@alignOf`. Uses `un_node`.
+        align_of,
+        /// Implement builtin `@boolToInt`. Uses `un_node`.
+        bool_to_int,
+        /// Implement builtin `@embedFile`. Uses `un_node`.
+        embed_file,
+        /// Implement builtin `@errorName`. Uses `un_node`.
+        error_name,
+        /// Implement builtin `@panic`. Uses `un_node`.
+        panic,
+        /// Implement builtin `@setAlignStack`. Uses `un_node`.
+        set_align_stack,
+        /// Implement builtin `@setCold`. Uses `un_node`.
+        set_cold,
+        /// Implement builtin `@setFloatMode`. Uses `un_node`.
+        set_float_mode,
+        /// Implement builtin `@setRuntimeSafety`. Uses `un_node`.
+        set_runtime_safety,
+        /// Implement builtin `@sqrt`. Uses `un_node`.
+        sqrt,
+        /// Implement builtin `@sin`. Uses `un_node`.
+        sin,
+        /// Implement builtin `@cos`. Uses `un_node`.
+        cos,
+        /// Implement builtin `@exp`. Uses `un_node`.
+        exp,
+        /// Implement builtin `@exp2`. Uses `un_node`.
+        exp2,
+        /// Implement builtin `@log`. Uses `un_node`.
+        log,
+        /// Implement builtin `@log2`. Uses `un_node`.
+        log2,
+        /// Implement builtin `@log10`. Uses `un_node`.
+        log10,
+        /// Implement builtin `@fabs`. Uses `un_node`.
+        fabs,
+        /// Implement builtin `@floor`. Uses `un_node`.
+        floor,
+        /// Implement builtin `@ceil`. Uses `un_node`.
+        ceil,
+        /// Implement builtin `@trunc`. Uses `un_node`.
+        trunc,
+        /// Implement builtin `@round`. Uses `un_node`.
+        round,
+        /// Implement builtin `@tagName`. Uses `un_node`.
+        tag_name,
+        /// Implement builtin `@Type`. Uses `un_node`.
+        reify,
+        /// Implement builtin `@typeName`. Uses `un_node`.
+        type_name,
+        /// Implement builtin `@Frame`. Uses `un_node`.
+        frame_type,
+        /// Implement builtin `@frameSize`. Uses `un_node`.
+        frame_size,
+
+        /// Implements the `@floatToInt` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        float_to_int,
+        /// Implements the `@intToFloat` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        int_to_float,
+        /// Implements the `@intToPtr` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        int_to_ptr,
+        /// Converts an integer into an enum value.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        int_to_enum,
+        /// Implements the `@floatCast` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        float_cast,
+        /// Implements the `@intCast` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        int_cast,
+        /// Implements the `@errSetCast` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        err_set_cast,
+        /// Implements the `@ptrCast` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        ptr_cast,
+        /// Implements the `@truncate` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        truncate,
+        /// Implements the `@alignCast` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest alignment, `rhs` is operand.
+        align_cast,
+
+        /// Implements the `@hasDecl` builtin.
+        /// Uses the `pl_node` union field. Payload is `Bin`.
+        has_decl,
+        /// Implements the `@hasField` builtin.
+        /// Uses the `pl_node` union field. Payload is `Bin`.
+        has_field,
+
+        /// Implements the `@clz` builtin. Uses the `un_node` union field.
+        clz,
+        /// Implements the `@ctz` builtin. Uses the `un_node` union field.
+        ctz,
+        /// Implements the `@popCount` builtin. Uses the `un_node` union field.
+        pop_count,
+        /// Implements the `@byteSwap` builtin. Uses the `un_node` union field.
+        byte_swap,
+        /// Implements the `@bitReverse` builtin. Uses the `un_node` union field.
+        bit_reverse,
+
+        /// Implements the `@divExact` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        div_exact,
+        /// Implements the `@divFloor` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        div_floor,
+        /// Implements the `@divTrunc` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        div_trunc,
+        /// Implements the `@mod` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        mod,
+        /// Implements the `@rem` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        rem,
+
+        /// Integer shift-left. Zeroes are shifted in from the right hand side.
+        /// Uses the `pl_node` union field. Payload is `Bin`.
+        shl,
+        /// Implements the `@shlExact` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        shl_exact,
+        /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
+        /// Uses the `pl_node` union field. Payload is `Bin`.
+        shr,
+        /// Implements the `@shrExact` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        shr_exact,
+
+        /// Implements the `@bitOffsetOf` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        bit_offset_of,
+        /// Implements the `@byteOffsetOf` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        byte_offset_of,
+        /// Implements the `@cmpxchgStrong` builtin.
+        /// Uses the `pl_node` union field with payload `Cmpxchg`.
+        cmpxchg_strong,
+        /// Implements the `@cmpxchgWeak` builtin.
+        /// Uses the `pl_node` union field with payload `Cmpxchg`.
+        cmpxchg_weak,
+        /// Implements the `@splat` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        splat,
+        /// Implements the `@reduce` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        reduce,
+        /// Implements the `@shuffle` builtin.
+        /// Uses the `pl_node` union field with payload `Shuffle`.
+        shuffle,
+        /// Implements the `@atomicLoad` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        atomic_load,
+        /// Implements the `@atomicRmw` builtin.
+        /// Uses the `pl_node` union field with payload `AtomicRmw`.
+        atomic_rmw,
+        /// Implements the `@atomicStore` builtin.
+        /// Uses the `pl_node` union field with payload `AtomicStore`.
+        atomic_store,
+        /// Implements the `@mulAdd` builtin.
+        /// Uses the `pl_node` union field with payload `MulAdd`.
+        mul_add,
+        /// Implements the `@call` builtin.
+        /// Uses the `pl_node` union field with payload `BuiltinCall`.
+        builtin_call,
+        /// Given a type and a field name, returns a pointer to the field type.
+        /// Assumed to be part of a `@fieldParentPtr` builtin call.
+        /// Uses the `bin` union field. LHS is type, RHS is field name.
+        field_ptr_type,
+        /// Implements the `@fieldParentPtr` builtin.
+        /// Uses the `pl_node` union field with payload `FieldParentPtr`.
+        field_parent_ptr,
+        /// Implements the `@memcpy` builtin.
+        /// Uses the `pl_node` union field with payload `Memcpy`.
+        memcpy,
+        /// Implements the `@memset` builtin.
+        /// Uses the `pl_node` union field with payload `Memset`.
+        memset,
+        /// Implements the `@asyncCall` builtin.
+        /// Uses the `pl_node` union field with payload `AsyncCall`.
+        builtin_async_call,
+        /// Implements the `@cImport` builtin.
+        /// Uses the `pl_node` union field with payload `Block`.
+        c_import,
+        /// The ZIR instruction tag is one of the `Extended` ones.
+        /// Uses the `extended` union field.
+        extended,
+
         /// Returns whether the instruction is one of the control flow "noreturn" types.
         /// Function calls do not count.
         pub fn isNoReturn(tag: Tag) bool {
@@ -876,11 +1073,11 @@ pub const Inst = struct {
                 .slice_sentinel,
                 .import,
                 .typeof_peer,
+                .typeof_log2_int_type,
                 .log2_int_type,
                 .resolve_inferred_alloc,
                 .set_eval_branch_quota,
                 .compile_log,
-                .elided,
                 .switch_capture,
                 .switch_capture_ref,
                 .switch_capture_multi,
@@ -902,6 +1099,7 @@ pub const Inst = struct {
                 .validate_struct_init_ptr,
                 .struct_init_empty,
                 .struct_init,
+                .union_init_ptr,
                 .field_type,
                 .int_to_enum,
                 .enum_to_int,
@@ -916,6 +1114,77 @@ pub const Inst = struct {
                 .sub_with_overflow,
                 .mul_with_overflow,
                 .shl_with_overflow,
+                .error_return_trace,
+                .frame,
+                .frame_address,
+                .ptr_to_int,
+                .align_of,
+                .bool_to_int,
+                .embed_file,
+                .error_name,
+                .set_align_stack,
+                .set_cold,
+                .set_float_mode,
+                .set_runtime_safety,
+                .sqrt,
+                .sin,
+                .cos,
+                .exp,
+                .exp2,
+                .log,
+                .log2,
+                .log10,
+                .fabs,
+                .floor,
+                .ceil,
+                .trunc,
+                .round,
+                .tag_name,
+                .reify,
+                .type_name,
+                .frame_type,
+                .frame_size,
+                .float_to_int,
+                .int_to_float,
+                .int_to_ptr,
+                .float_cast,
+                .int_cast,
+                .err_set_cast,
+                .ptr_cast,
+                .truncate,
+                .align_cast,
+                .has_field,
+                .clz,
+                .ctz,
+                .pop_count,
+                .byte_swap,
+                .bit_reverse,
+                .div_exact,
+                .div_floor,
+                .div_trunc,
+                .mod,
+                .rem,
+                .shl_exact,
+                .shr_exact,
+                .bit_offset_of,
+                .byte_offset_of,
+                .cmpxchg_strong,
+                .cmpxchg_weak,
+                .splat,
+                .reduce,
+                .shuffle,
+                .atomic_load,
+                .atomic_rmw,
+                .atomic_store,
+                .mul_add,
+                .builtin_call,
+                .field_ptr_type,
+                .field_parent_ptr,
+                .memcpy,
+                .memset,
+                .builtin_async_call,
+                .c_import,
+                .extended,
                 => false,
 
                 .@"break",
@@ -929,11 +1198,33 @@ pub const Inst = struct {
                 .@"unreachable",
                 .repeat,
                 .repeat_inline,
+                .panic,
                 => true,
             };
         }
     };
 
+    /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
+    /// `noreturn` instructions may not go here; they must be part of the main `Tag` enum.
+    pub const Extended = enum(u16) {
+        /// `operand` is payload index to `UnNode`.
+        c_undef,
+        /// `operand` is payload index to `UnNode`.
+        c_include,
+        /// `operand` is payload index to `BinNode`.
+        c_define,
+        /// `operand` is payload index to `UnNode`.
+        wasm_memory_size,
+        /// `operand` is payload index to `BinNode`.
+        wasm_memory_grow,
+
+        pub const InstData = struct {
+            opcode: Extended,
+            small: u16,
+            operand: u32,
+        };
+    };
+
     /// The position of a ZIR instruction within the `Zir` instructions array.
     pub const Index = u32;
 
@@ -1002,6 +1293,14 @@ pub const Inst = struct {
         single_const_pointer_to_comptime_int_type,
         const_slice_u8_type,
         enum_literal_type,
+        manyptr_u8_type,
+        manyptr_const_u8_type,
+        atomic_ordering_type,
+        atomic_rmw_op_type,
+        calling_convention_type,
+        float_mode_type,
+        reduce_op_type,
+        call_options_type,
 
         /// `undefined` (untyped)
         undef,
@@ -1025,6 +1324,8 @@ pub const Inst = struct {
         zero_usize,
         /// `1` (usize)
         one_usize,
+        /// `std.builtin.CallingConvention.C`
+        calling_convention_c,
 
         _,
 
@@ -1191,6 +1492,38 @@ pub const Inst = struct {
                 .ty = Type.initTag(.type),
                 .val = Value.initTag(.enum_literal_type),
             },
+            .manyptr_u8_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.manyptr_u8_type),
+            },
+            .manyptr_const_u8_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.manyptr_const_u8_type),
+            },
+            .atomic_ordering_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.atomic_ordering_type),
+            },
+            .atomic_rmw_op_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.atomic_rmw_op_type),
+            },
+            .calling_convention_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.calling_convention_type),
+            },
+            .float_mode_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.float_mode_type),
+            },
+            .reduce_op_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.reduce_op_type),
+            },
+            .call_options_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.call_options_type),
+            },
 
             .undef = .{
                 .ty = Type.initTag(.@"undefined"),
@@ -1236,13 +1569,27 @@ pub const Inst = struct {
                 .ty = Type.initTag(.empty_struct_literal),
                 .val = Value.initTag(.empty_struct_value),
             },
+            .calling_convention_c = .{
+                .ty = Type.initTag(.calling_convention),
+                .val = .{ .ptr_otherwise = &calling_convention_c_payload.base },
+            },
         });
     };
 
+    /// We would like this to be const but `Value` wants a mutable pointer for
+    /// its payload field. Nothing should mutate this though.
+    var calling_convention_c_payload: Value.Payload.U32 = .{
+        .base = .{ .tag = .enum_field_index },
+        .data = @enumToInt(std.builtin.CallingConvention.C),
+    };
+
     /// All instructions have an 8-byte payload, which is contained within
     /// this union. `Tag` determines which union field is active, as well as
     /// how to interpret the data within.
     pub const Data = union {
+        /// Used for `Tag.extended`. The extended opcode determines the meaning
+        /// of the `small` and `operand` fields.
+        extended: Extended.InstData,
         /// Used for unary operators, with an AST node source location.
         un_node: struct {
             /// Offset from Decl AST node index.
@@ -1462,6 +1809,12 @@ pub const Inst = struct {
         args_len: u32,
     };
 
+    pub const BuiltinCall = struct {
+        options: Ref,
+        callee: Ref,
+        args: Ref,
+    };
+
     /// This data is stored inside extra, with two sets of trailing `Ref`:
     /// * 0. the then body, according to `then_body_len`.
     /// * 1. the else body, according to `else_body_len`.
@@ -1510,6 +1863,17 @@ pub const Inst = struct {
         rhs: Ref,
     };
 
+    pub const BinNode = struct {
+        node: i32,
+        lhs: Ref,
+        rhs: Ref,
+    };
+
+    pub const UnNode = struct {
+        node: i32,
+        operand: Ref,
+    };
+
     /// This form is supported when there are no ranges, and exactly 1 item per block.
     /// Depending on zir tag and len fields, extra fields trail
     /// this one in the extra array.
@@ -1679,6 +2043,70 @@ pub const Inst = struct {
         ptr: Ref,
     };
 
+    pub const Cmpxchg = struct {
+        ptr: Ref,
+        expected_value: Ref,
+        new_value: Ref,
+        success_order: Ref,
+        fail_order: Ref,
+    };
+
+    pub const AtomicRmw = struct {
+        ptr: Ref,
+        operation: Ref,
+        operand: Ref,
+        ordering: Ref,
+    };
+
+    pub const UnionInitPtr = struct {
+        union_type: Ref,
+        field_name: Ref,
+    };
+
+    pub const AtomicStore = struct {
+        ptr: Ref,
+        operand: Ref,
+        ordering: Ref,
+    };
+
+    pub const MulAdd = struct {
+        mulend1: Ref,
+        mulend2: Ref,
+        addend: Ref,
+    };
+
+    pub const FieldParentPtr = struct {
+        parent_type: Ref,
+        field_name: Ref,
+        field_ptr: Ref,
+    };
+
+    pub const Memcpy = struct {
+        dest: Ref,
+        source: Ref,
+        byte_count: Ref,
+    };
+
+    pub const Memset = struct {
+        dest: Ref,
+        byte: Ref,
+        byte_count: Ref,
+    };
+
+    pub const Shuffle = struct {
+        elem_type: Ref,
+        a: Ref,
+        b: Ref,
+        mask: Ref,
+    };
+
+    pub const AsyncCall = struct {
+        frame_buffer: Ref,
+        result_ptr: Ref,
+        fn_ptr: Ref,
+        args: Ref,
+    };
+
     /// Trailing: `CompileErrors.Item` for each `items_len`.
     pub const CompileErrors = struct {
         items_len: u32,
@@ -1749,13 +2177,11 @@ const Writer = struct {
             .negate_wrap,
             .call_none,
             .call_none_chkused,
-            .compile_error,
             .load,
             .ensure_result_used,
             .ensure_result_non_error,
             .ptrtoint,
             .ret_node,
-            .set_eval_branch_quota,
             .resolve_inferred_alloc,
             .optional_type,
             .optional_type_from_ptr_elem,
@@ -1769,8 +2195,6 @@ const Writer = struct {
             .err_union_payload_unsafe_ptr,
             .err_union_code,
             .err_union_code_ptr,
-            .int_to_error,
-            .error_to_int,
             .is_non_null,
             .is_null,
             .is_non_null_ptr,
@@ -1780,11 +2204,49 @@ const Writer = struct {
             .typeof,
             .typeof_elem,
             .struct_init_empty,
-            .enum_to_int,
             .type_info,
             .size_of,
             .bit_size_of,
+            .typeof_log2_int_type,
             .log2_int_type,
+            .ptr_to_int,
+            .error_to_int,
+            .int_to_error,
+            .compile_error,
+            .set_eval_branch_quota,
+            .enum_to_int,
+            .align_of,
+            .bool_to_int,
+            .embed_file,
+            .error_name,
+            .panic,
+            .set_align_stack,
+            .set_cold,
+            .set_float_mode,
+            .set_runtime_safety,
+            .sqrt,
+            .sin,
+            .cos,
+            .exp,
+            .exp2,
+            .log,
+            .log2,
+            .log10,
+            .fabs,
+            .floor,
+            .ceil,
+            .trunc,
+            .round,
+            .tag_name,
+            .reify,
+            .type_name,
+            .frame_type,
+            .frame_size,
+            .clz,
+            .ctz,
+            .pop_count,
+            .byte_swap,
+            .bit_reverse,
             => try self.writeUnNode(stream, inst),
 
             .ref,
@@ -1805,7 +2267,6 @@ const Writer = struct {
             .float => try self.writeFloat(stream, inst),
             .float128 => try self.writeFloat128(stream, inst),
             .str => try self.writeStr(stream, inst),
-            .elided => try stream.writeAll(")"),
             .int_type => try self.writeIntType(stream, inst),
 
             .@"break",
@@ -1824,7 +2285,20 @@ const Writer = struct {
             .slice_sentinel,
             .union_decl,
             .struct_init,
+            .union_init_ptr,
             .field_type,
+            .cmpxchg_strong,
+            .cmpxchg_weak,
+            .shuffle,
+            .atomic_rmw,
+            .atomic_store,
+            .mul_add,
+            .builtin_call,
+            .field_ptr_type,
+            .field_parent_ptr,
+            .memcpy,
+            .memset,
+            .builtin_async_call,
             => try self.writePlNode(stream, inst),
 
             .add_with_overflow,
@@ -1851,9 +2325,12 @@ const Writer = struct {
             .cmp_neq,
             .div,
             .has_decl,
+            .has_field,
             .mod_rem,
             .shl,
+            .shl_exact,
             .shr,
+            .shr_exact,
             .xor,
             .store_node,
             .error_union_type,
@@ -1861,7 +2338,26 @@ const Writer = struct {
             .merge_error_sets,
             .bit_and,
             .bit_or,
+            .float_to_int,
+            .int_to_float,
+            .int_to_ptr,
             .int_to_enum,
+            .float_cast,
+            .int_cast,
+            .err_set_cast,
+            .ptr_cast,
+            .truncate,
+            .align_cast,
+            .div_exact,
+            .div_floor,
+            .div_trunc,
+            .mod,
+            .rem,
+            .bit_offset_of,
+            .byte_offset_of,
+            .splat,
+            .reduce,
+            .atomic_load,
             => try self.writePlNodeBin(stream, inst),
 
             .call,
@@ -1874,6 +2370,7 @@ const Writer = struct {
             .block_inline_var,
             .loop,
             .validate_struct_init_ptr,
+            .c_import,
             => try self.writePlNodeBlock(stream, inst),
 
             .condbr,
@@ -1926,6 +2423,9 @@ const Writer = struct {
             .fence,
             .ret_addr,
             .builtin_src,
+            .error_return_trace,
+            .frame,
+            .frame_address,
             => try self.writeNode(stream, inst),
 
             .error_value,
@@ -1954,6 +2454,7 @@ const Writer = struct {
 
             .bitcast,
             .bitcast_result_ptr,
+            .extended,
             => try stream.writeAll("TODO)"),
         }
     }
BRANCH_TODO
@@ -737,5 +737,3 @@ fn errorSetDecl(
             try mod.analyzeExport(&decl_scope.base, export_src, name, decl);
         }
     }
-
-