authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-29 17:54:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-30 12:03:53-07:00
log9da3a058d82573efeaf12fe61ab6a312649175ec
treeb86f6f08761289b95c46e10879e476da455de218
parentf846dc420fff629572caa1175bfa64e5fcffaeb5

stage2: add missing data to ZIR encoding of functions

The main purpose of this commit is to prepare to implement support for callconv(), align(), linksection(), and addrspace() annotations on generic functions where the provided expression depends on comptime parameters (making the function generic). It's a rather involved change, so this commit only makes the necessary changes to AstGen without regressing any behavior, and a follow-up commit can finish the task by making the enhancements to Sema. By my quick estimation, the new encoding for functions is a negligible improvement - along the lines of 0.005% fewer total ZIR bytes on average. Still, it's nice that this commit, while adding more data into ZIR, actually ends up reducing the storage size thanks to a slightly more sophisticated encoding. Zir.Inst.ExtendedFunc is renamed to Zir.Inst.FuncFancy to eliminate confusion about it being an extended instruction (it used to be but is no longer). The encoding for this instruction is completely reworked. The encoding for Zir.Inst.Func is also changed slightly - when the return type body length is 1, then only a Zir.Inst.Ref is provided; not a full body. linksection() and addrspace() are now communicated via func_fancy ZIR instruction rather than as part of the corresponding decl. This allows their expressions to observe comptime parameters.

5 files changed, 803 insertions(+), 241 deletions(-)

src/AstGen.zig+271-81
......@@ -73,7 +73,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
7373 Zir.Inst.Call.Flags => @bitCast(u32, @field(extra, field.name)),
7474 Zir.Inst.BuiltinCall.Flags => @bitCast(u32, @field(extra, field.name)),
7575 Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)),
76 Zir.Inst.ExtendedFunc.Bits => @bitCast(u32, @field(extra, field.name)),
76 Zir.Inst.FuncFancy.Bits => @bitCast(u32, @field(extra, field.name)),
7777 else => @compileError("bad field type"),
7878 };
7979 i += 1;
......@@ -1205,7 +1205,7 @@ fn fnProtoExpr(
12051205 break :is_var_args false;
12061206 };
12071207
1208 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
1208 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
12091209 break :inst try expr(&block_scope, scope, align_rl, fn_proto.ast.align_expr);
12101210 };
12111211
......@@ -1232,19 +1232,24 @@ fn fnProtoExpr(
12321232 if (is_inferred_error) {
12331233 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
12341234 }
1235 var ret_gz = block_scope.makeSubBlock(scope);
1236 defer ret_gz.unstack();
1237 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
1238 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
1235 const ret_ty = try expr(&block_scope, scope, coerced_type_rl, fn_proto.ast.return_type);
12391236
12401237 const result = try block_scope.addFunc(.{
12411238 .src_node = fn_proto.ast.proto_node,
1239
1240 .cc_ref = cc,
1241 .cc_gz = null,
1242 .align_ref = align_ref,
1243 .align_gz = null,
1244 .ret_ref = ret_ty,
1245 .ret_gz = null,
1246 .section_ref = .none,
1247 .section_gz = null,
1248 .addrspace_ref = .none,
1249 .addrspace_gz = null,
1250
12421251 .param_block = block_inst,
1243 .ret_gz = &ret_gz,
1244 .ret_br = ret_br,
12451252 .body_gz = null,
1246 .cc = cc,
1247 .align_inst = align_inst,
12481253 .lib_name = 0,
12491254 .is_var_args = is_var_args,
12501255 .is_inferred_error = false,
......@@ -2282,7 +2287,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22822287 .field_val_named,
22832288 .func,
22842289 .func_inferred,
2285 .func_extended,
2290 .func_fancy,
22862291 .int,
22872292 .int_big,
22882293 .float,
......@@ -3395,9 +3400,8 @@ fn fnDecl(
33953400
33963401 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
33973402
3398 const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;
3399 // Alignment is passed in the func instruction in this case.
3400 wip_members.nextDecl(is_pub, is_export, false, has_section_or_addrspace);
3403 // align, linksection, and addrspace is passed in the func instruction in this case.
3404 wip_members.nextDecl(is_pub, is_export, false, false);
34013405
34023406 var params_scope = &fn_gz.base;
34033407 const is_var_args = is_var_args: {
......@@ -3483,17 +3487,49 @@ fn fnDecl(
34833487 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
34843488 const is_inferred_error = token_tags[maybe_bang] == .bang;
34853489
3486 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
3487 break :inst try expr(&decl_gz, params_scope, align_rl, fn_proto.ast.align_expr);
3490 // After creating the function ZIR instruction, it will need to update the break
3491 // instructions inside the expression blocks for align, addrspace, cc, and ret_ty
3492 // to use the function instruction as the "block" to break from.
3493
3494 var align_gz = decl_gz.makeSubBlock(params_scope);
3495 defer align_gz.unstack();
3496 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
3497 const inst = try expr(&decl_gz, params_scope, coerced_align_rl, fn_proto.ast.align_expr);
3498 if (align_gz.instructionsSlice().len == 0) {
3499 // In this case we will send a len=0 body which can be encoded more efficiently.
3500 break :inst inst;
3501 }
3502 _ = try align_gz.addBreak(.break_inline, 0, inst);
3503 break :inst inst;
34883504 };
3489 const addrspace_inst: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
3490 break :inst try expr(&decl_gz, params_scope, .{ .ty = .address_space_type }, fn_proto.ast.addrspace_expr);
3505
3506 var addrspace_gz = decl_gz.makeSubBlock(params_scope);
3507 defer addrspace_gz.unstack();
3508 const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
3509 const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .address_space_type }, fn_proto.ast.addrspace_expr);
3510 if (addrspace_gz.instructionsSlice().len == 0) {
3511 // In this case we will send a len=0 body which can be encoded more efficiently.
3512 break :inst inst;
3513 }
3514 _ = try addrspace_gz.addBreak(.break_inline, 0, inst);
3515 break :inst inst;
34913516 };
3492 const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
3493 break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
3517
3518 var section_gz = decl_gz.makeSubBlock(params_scope);
3519 defer section_gz.unstack();
3520 const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
3521 const inst = try expr(&decl_gz, params_scope, .{ .coerced_ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
3522 if (section_gz.instructionsSlice().len == 0) {
3523 // In this case we will send a len=0 body which can be encoded more efficiently.
3524 break :inst inst;
3525 }
3526 _ = try section_gz.addBreak(.break_inline, 0, inst);
3527 break :inst inst;
34943528 };
34953529
3496 const cc: Zir.Inst.Ref = blk: {
3530 var cc_gz = decl_gz.makeSubBlock(params_scope);
3531 defer cc_gz.unstack();
3532 const cc_ref: Zir.Inst.Ref = blk: {
34973533 if (fn_proto.ast.callconv_expr != 0) {
34983534 if (has_inline_keyword) {
34993535 return astgen.failNode(
......@@ -3502,12 +3538,18 @@ fn fnDecl(
35023538 .{},
35033539 );
35043540 }
3505 break :blk try expr(
3541 const inst = try expr(
35063542 &decl_gz,
35073543 params_scope,
3508 .{ .ty = .calling_convention_type },
3544 .{ .coerced_ty = .calling_convention_type },
35093545 fn_proto.ast.callconv_expr,
35103546 );
3547 if (cc_gz.instructionsSlice().len == 0) {
3548 // In this case we will send a len=0 body which can be encoded more efficiently.
3549 break :blk inst;
3550 }
3551 _ = try cc_gz.addBreak(.break_inline, 0, inst);
3552 break :blk inst;
35113553 } else if (is_extern) {
35123554 // note: https://github.com/ziglang/zig/issues/5269
35133555 break :blk .calling_convention_c;
......@@ -3520,8 +3562,18 @@ fn fnDecl(
35203562
35213563 var ret_gz = decl_gz.makeSubBlock(params_scope);
35223564 defer ret_gz.unstack();
3523 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
3524 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
3565 const ret_ref: Zir.Inst.Ref = switch (nodePrimitive(tree, fn_proto.ast.return_type)) {
3566 .none => inst: {
3567 const inst = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
3568 if (ret_gz.instructionsSlice().len == 0) {
3569 // In this case we will send a len=0 body which can be encoded more efficiently.
3570 break :inst inst;
3571 }
3572 _ = try ret_gz.addBreak(.break_inline, 0, inst);
3573 break :inst inst;
3574 },
3575 else => |p| p,
3576 };
35253577
35263578 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
35273579 if (!is_extern) {
......@@ -3532,12 +3584,18 @@ fn fnDecl(
35323584 }
35333585 break :func try decl_gz.addFunc(.{
35343586 .src_node = decl_node,
3587 .cc_ref = cc_ref,
3588 .cc_gz = &cc_gz,
3589 .align_ref = align_ref,
3590 .align_gz = &align_gz,
3591 .ret_ref = ret_ref,
35353592 .ret_gz = &ret_gz,
3536 .ret_br = ret_br,
3593 .section_ref = section_ref,
3594 .section_gz = &section_gz,
3595 .addrspace_ref = addrspace_ref,
3596 .addrspace_gz = &addrspace_gz,
35373597 .param_block = block_inst,
35383598 .body_gz = null,
3539 .cc = cc,
3540 .align_inst = align_inst,
35413599 .lib_name = lib_name,
35423600 .is_var_args = is_var_args,
35433601 .is_inferred_error = false,
......@@ -3571,14 +3629,20 @@ fn fnDecl(
35713629
35723630 break :func try decl_gz.addFunc(.{
35733631 .src_node = decl_node,
3632 .cc_ref = cc_ref,
3633 .cc_gz = &cc_gz,
3634 .align_ref = align_ref,
3635 .align_gz = &align_gz,
3636 .ret_ref = ret_ref,
3637 .ret_gz = &ret_gz,
3638 .section_ref = section_ref,
3639 .section_gz = &section_gz,
3640 .addrspace_ref = addrspace_ref,
3641 .addrspace_gz = &addrspace_gz,
35743642 .lbrace_line = lbrace_line,
35753643 .lbrace_column = lbrace_column,
35763644 .param_block = block_inst,
3577 .ret_gz = &ret_gz,
3578 .ret_br = ret_br,
35793645 .body_gz = &fn_gz,
3580 .cc = cc,
3581 .align_inst = align_inst,
35823646 .lib_name = lib_name,
35833647 .is_var_args = is_var_args,
35843648 .is_inferred_error = is_inferred_error,
......@@ -3604,10 +3668,6 @@ fn fnDecl(
36043668 wip_members.appendToDecl(fn_name_str_index);
36053669 wip_members.appendToDecl(block_inst);
36063670 wip_members.appendToDecl(doc_comment_index);
3607 if (has_section_or_addrspace) {
3608 wip_members.appendToDecl(@enumToInt(section_inst));
3609 wip_members.appendToDecl(@enumToInt(addrspace_inst));
3610 }
36113671}
36123672
36133673fn globalVarDecl(
......@@ -4001,14 +4061,22 @@ fn testDecl(
40014061
40024062 const func_inst = try decl_block.addFunc(.{
40034063 .src_node = node,
4064
4065 .cc_ref = .none,
4066 .cc_gz = null,
4067 .align_ref = .none,
4068 .align_gz = null,
4069 .ret_ref = .void_type,
4070 .ret_gz = null,
4071 .section_ref = .none,
4072 .section_gz = null,
4073 .addrspace_ref = .none,
4074 .addrspace_gz = null,
4075
40044076 .lbrace_line = lbrace_line,
40054077 .lbrace_column = lbrace_column,
40064078 .param_block = block_inst,
4007 .ret_gz = null,
4008 .ret_br = 0,
40094079 .body_gz = &fn_block,
4010 .cc = .none,
4011 .align_inst = .none,
40124080 .lib_name = 0,
40134081 .is_var_args = false,
40144082 .is_inferred_error = true,
......@@ -8957,6 +9025,31 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
89579025 }
89589026}
89599027
9028fn nodePrimitive(tree: *const Ast, start_node: Ast.Node.Index) Zir.Inst.Ref {
9029 const node_tags = tree.nodes.items(.tag);
9030 const node_datas = tree.nodes.items(.data);
9031
9032 var node = start_node;
9033 while (true) {
9034 switch (node_tags[node]) {
9035 // Forward the question to the LHS sub-expression.
9036 .grouped_expression => node = node_datas[node].lhs,
9037
9038 .identifier => {
9039 const main_tokens = tree.nodes.items(.main_token);
9040 const ident_bytes = tree.tokenSlice(main_tokens[node]);
9041 if (primitives.get(ident_bytes)) |primitive| {
9042 return primitive;
9043 } else {
9044 return .none;
9045 }
9046 },
9047
9048 else => return .none,
9049 }
9050 }
9051}
9052
89609053/// Applies `rl` semantics to `result`. Expressions which do not do their own handling of
89619054/// result locations must call this function on their result.
89629055/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
......@@ -9952,17 +10045,34 @@ const GenZir = struct {
995210045 gz.unstack();
995310046 }
995410047
9955 /// Supports `body_gz` stacked on `ret_gz` stacked on `gz`. Unstacks `body_gz` and `ret_gz`.
10048 /// Must be called with the following stack set up:
10049 /// * gz (bottom)
10050 /// * align_gz
10051 /// * addrspace_gz
10052 /// * section_gz
10053 /// * cc_gz
10054 /// * ret_gz
10055 /// * body_gz (top)
10056 /// Unstacks all of those except for `gz`.
995610057 fn addFunc(gz: *GenZir, args: struct {
995710058 src_node: Ast.Node.Index,
995810059 lbrace_line: u32 = 0,
995910060 lbrace_column: u32 = 0,
9960 body_gz: ?*GenZir,
996110061 param_block: Zir.Inst.Index,
10062
10063 align_gz: ?*GenZir,
10064 addrspace_gz: ?*GenZir,
10065 section_gz: ?*GenZir,
10066 cc_gz: ?*GenZir,
996210067 ret_gz: ?*GenZir,
9963 ret_br: Zir.Inst.Index,
9964 cc: Zir.Inst.Ref,
9965 align_inst: Zir.Inst.Ref,
10068 body_gz: ?*GenZir,
10069
10070 align_ref: Zir.Inst.Ref,
10071 addrspace_ref: Zir.Inst.Ref,
10072 section_ref: Zir.Inst.Ref,
10073 cc_ref: Zir.Inst.Ref,
10074 ret_ref: Zir.Inst.Ref,
10075
996610076 lib_name: u32,
996710077 is_var_args: bool,
996810078 is_inferred_error: bool,
......@@ -9972,11 +10082,13 @@ const GenZir = struct {
997210082 assert(args.src_node != 0);
997310083 const astgen = gz.astgen;
997410084 const gpa = astgen.gpa;
10085 const ret_ref = if (args.ret_ref == .void_type) .none else args.ret_ref;
10086 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
997510087
997610088 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
997710089
997810090 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
9979 var ret_ty: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
10091 var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
998010092 var src_locs_buffer: [3]u32 = undefined;
998110093 var src_locs: []u32 = src_locs_buffer[0..0];
998210094 if (args.body_gz) |body_gz| {
......@@ -10000,61 +10112,120 @@ const GenZir = struct {
1000010112
1000110113 body = body_gz.instructionsSlice();
1000210114 if (args.ret_gz) |ret_gz|
10003 ret_ty = ret_gz.instructionsSliceUpto(body_gz);
10115 ret_body = ret_gz.instructionsSliceUpto(body_gz);
1000410116 } else {
1000510117 if (args.ret_gz) |ret_gz|
10006 ret_ty = ret_gz.instructionsSlice();
10118 ret_body = ret_gz.instructionsSlice();
1000710119 }
1000810120
10009 if (args.cc != .none or args.lib_name != 0 or
10010 args.is_var_args or args.is_test or args.align_inst != .none or
10011 args.is_extern)
10121 if (args.cc_ref != .none or args.lib_name != 0 or
10122 args.is_var_args or args.is_test or args.is_extern or
10123 args.align_ref != .none or args.section_ref != .none or
10124 args.addrspace_ref != .none)
1001210125 {
10126 var align_body: []Zir.Inst.Index = &.{};
10127 var addrspace_body: []Zir.Inst.Index = &.{};
10128 var section_body: []Zir.Inst.Index = &.{};
10129 var cc_body: []Zir.Inst.Index = &.{};
10130 if (args.ret_gz != null) {
10131 align_body = args.align_gz.?.instructionsSliceUpto(args.addrspace_gz.?);
10132 addrspace_body = args.addrspace_gz.?.instructionsSliceUpto(args.section_gz.?);
10133 section_body = args.section_gz.?.instructionsSliceUpto(args.cc_gz.?);
10134 cc_body = args.cc_gz.?.instructionsSliceUpto(args.ret_gz.?);
10135 }
10136
1001310137 try astgen.extra.ensureUnusedCapacity(
1001410138 gpa,
10015 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
10016 ret_ty.len + body.len + src_locs.len +
10017 @boolToInt(args.lib_name != 0) +
10018 @boolToInt(args.align_inst != .none) +
10019 @boolToInt(args.cc != .none),
10139 @typeInfo(Zir.Inst.FuncFancy).Struct.fields.len +
10140 fancyFnExprExtraLen(align_body, args.align_ref) +
10141 fancyFnExprExtraLen(addrspace_body, args.addrspace_ref) +
10142 fancyFnExprExtraLen(section_body, args.section_ref) +
10143 fancyFnExprExtraLen(cc_body, args.cc_ref) +
10144 fancyFnExprExtraLen(ret_body, ret_ref) +
10145 body.len + src_locs.len +
10146 @boolToInt(args.lib_name != 0),
1002010147 );
10021 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
10148 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{
1002210149 .param_block = args.param_block,
10023 .ret_body_len = @intCast(u32, ret_ty.len),
1002410150 .body_len = @intCast(u32, body.len),
1002510151 .bits = .{
1002610152 .is_var_args = args.is_var_args,
1002710153 .is_inferred_error = args.is_inferred_error,
10028 .has_lib_name = args.lib_name != 0,
10029 .has_cc = args.cc != .none,
10030 .has_align = args.align_inst != .none,
1003110154 .is_test = args.is_test,
1003210155 .is_extern = args.is_extern,
10156 .has_lib_name = args.lib_name != 0,
10157
10158 .has_align_ref = args.align_ref != .none,
10159 .has_addrspace_ref = args.addrspace_ref != .none,
10160 .has_section_ref = args.section_ref != .none,
10161 .has_cc_ref = args.cc_ref != .none,
10162 .has_ret_ty_ref = ret_ref != .none,
10163
10164 .has_align_body = align_body.len != 0,
10165 .has_addrspace_body = addrspace_body.len != 0,
10166 .has_section_body = section_body.len != 0,
10167 .has_cc_body = cc_body.len != 0,
10168 .has_ret_ty_body = ret_body.len != 0,
1003310169 },
1003410170 });
1003510171 if (args.lib_name != 0) {
1003610172 astgen.extra.appendAssumeCapacity(args.lib_name);
1003710173 }
10038 if (args.cc != .none) {
10039 astgen.extra.appendAssumeCapacity(@enumToInt(args.cc));
10174
10175 const zir_datas = astgen.instructions.items(.data);
10176 if (align_body.len != 0) {
10177 astgen.extra.appendAssumeCapacity(@intCast(u32, align_body.len));
10178 astgen.extra.appendSliceAssumeCapacity(align_body);
10179 zir_datas[align_body[align_body.len - 1]].@"break".block_inst = new_index;
10180 } else if (args.align_ref != .none) {
10181 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_ref));
10182 }
10183 if (addrspace_body.len != 0) {
10184 astgen.extra.appendAssumeCapacity(@intCast(u32, addrspace_body.len));
10185 astgen.extra.appendSliceAssumeCapacity(addrspace_body);
10186 zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".block_inst = new_index;
10187 } else if (args.addrspace_ref != .none) {
10188 astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_ref));
10189 }
10190 if (section_body.len != 0) {
10191 astgen.extra.appendAssumeCapacity(@intCast(u32, section_body.len));
10192 astgen.extra.appendSliceAssumeCapacity(section_body);
10193 zir_datas[section_body[section_body.len - 1]].@"break".block_inst = new_index;
10194 } else if (args.section_ref != .none) {
10195 astgen.extra.appendAssumeCapacity(@enumToInt(args.section_ref));
1004010196 }
10041 if (args.align_inst != .none) {
10042 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
10197 if (cc_body.len != 0) {
10198 astgen.extra.appendAssumeCapacity(@intCast(u32, cc_body.len));
10199 astgen.extra.appendSliceAssumeCapacity(cc_body);
10200 zir_datas[cc_body[cc_body.len - 1]].@"break".block_inst = new_index;
10201 } else if (args.cc_ref != .none) {
10202 astgen.extra.appendAssumeCapacity(@enumToInt(args.cc_ref));
1004310203 }
10044 astgen.extra.appendSliceAssumeCapacity(ret_ty);
10204 if (ret_body.len != 0) {
10205 astgen.extra.appendAssumeCapacity(@intCast(u32, ret_body.len));
10206 astgen.extra.appendSliceAssumeCapacity(ret_body);
10207 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index;
10208 } else if (ret_ref != .none) {
10209 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
10210 }
10211
1004510212 astgen.extra.appendSliceAssumeCapacity(body);
1004610213 astgen.extra.appendSliceAssumeCapacity(src_locs);
10047 // order is important when unstacking
10214
10215 // Order is important when unstacking.
1004810216 if (args.body_gz) |body_gz| body_gz.unstack();
10049 if (args.ret_gz) |ret_gz| ret_gz.unstack();
10217 if (args.ret_gz != null) {
10218 args.ret_gz.?.unstack();
10219 args.cc_gz.?.unstack();
10220 args.section_gz.?.unstack();
10221 args.addrspace_gz.?.unstack();
10222 args.align_gz.?.unstack();
10223 }
10224
1005010225 try gz.instructions.ensureUnusedCapacity(gpa, 1);
1005110226
10052 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
10053 if (args.ret_br != 0) {
10054 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
10055 }
1005610227 astgen.instructions.appendAssumeCapacity(.{
10057 .tag = .func_extended,
10228 .tag = .func_fancy,
1005810229 .data = .{ .pl_node = .{
1005910230 .src_node = gz.nodeIndexToRelative(args.src_node),
1006010231 .payload_index = payload_index,
......@@ -10066,27 +10237,40 @@ const GenZir = struct {
1006610237 try astgen.extra.ensureUnusedCapacity(
1006710238 gpa,
1006810239 @typeInfo(Zir.Inst.Func).Struct.fields.len +
10069 ret_ty.len + body.len + src_locs.len,
10240 @maximum(ret_body.len, @boolToInt(ret_ref != .none)) +
10241 body.len + src_locs.len,
1007010242 );
10243 const ret_body_len = if (ret_body.len != 0)
10244 @intCast(u32, ret_body.len)
10245 else
10246 @boolToInt(ret_ref != .none);
1007110247
1007210248 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
1007310249 .param_block = args.param_block,
10074 .ret_body_len = @intCast(u32, ret_ty.len),
10250 .ret_body_len = ret_body_len,
1007510251 .body_len = @intCast(u32, body.len),
1007610252 });
10077 astgen.extra.appendSliceAssumeCapacity(ret_ty);
10253 const zir_datas = astgen.instructions.items(.data);
10254 if (ret_body.len != 0) {
10255 astgen.extra.appendSliceAssumeCapacity(ret_body);
10256 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index;
10257 } else if (ret_ref != .none) {
10258 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
10259 }
1007810260 astgen.extra.appendSliceAssumeCapacity(body);
1007910261 astgen.extra.appendSliceAssumeCapacity(src_locs);
10080 // order is important when unstacking
10262
10263 // Order is important when unstacking.
1008110264 if (args.body_gz) |body_gz| body_gz.unstack();
1008210265 if (args.ret_gz) |ret_gz| ret_gz.unstack();
10266 if (args.cc_gz) |cc_gz| cc_gz.unstack();
10267 if (args.section_gz) |section_gz| section_gz.unstack();
10268 if (args.addrspace_gz) |addrspace_gz| addrspace_gz.unstack();
10269 if (args.align_gz) |align_gz| align_gz.unstack();
10270
1008310271 try gz.instructions.ensureUnusedCapacity(gpa, 1);
1008410272
1008510273 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
10086 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
10087 if (args.ret_br != 0) {
10088 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
10089 }
1009010274 astgen.instructions.appendAssumeCapacity(.{
1009110275 .tag = tag,
1009210276 .data = .{ .pl_node = .{
......@@ -10099,6 +10283,12 @@ const GenZir = struct {
1009910283 }
1010010284 }
1010110285
10286 fn fancyFnExprExtraLen(body: []Zir.Inst.Index, ref: Zir.Inst.Ref) usize {
10287 // In the case of non-empty body, there is one for the body length,
10288 // and then one for each instruction.
10289 return body.len + @boolToInt(ref != .none);
10290 }
10291
1010210292 fn addVar(gz: *GenZir, args: struct {
1010310293 align_inst: Zir.Inst.Ref,
1010410294 lib_name: u32,
src/Module.zig+2-2
......@@ -1595,9 +1595,9 @@ pub const Fn = struct {
15951595 switch (zir_tags[func.zir_body_inst]) {
15961596 .func => return false,
15971597 .func_inferred => return true,
1598 .func_extended => {
1598 .func_fancy => {
15991599 const inst_data = zir.instructions.items(.data)[func.zir_body_inst].pl_node;
1600 const extra = zir.extraData(Zir.Inst.ExtendedFunc, inst_data.payload_index);
1600 const extra = zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
16011601 return extra.data.bits.is_inferred_error;
16021602 },
16031603 else => unreachable,
src/Sema.zig+189-68
......@@ -747,7 +747,7 @@ fn analyzeBodyInner(
747747 .field_call_bind => try sema.zirFieldCallBind(block, inst),
748748 .func => try sema.zirFunc(block, inst, false),
749749 .func_inferred => try sema.zirFunc(block, inst, true),
750 .func_extended => try sema.zirFuncExtended(block, inst),
750 .func_fancy => try sema.zirFuncFancy(block, inst),
751751 .import => try sema.zirImport(block, inst),
752752 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
753753 .int => try sema.zirInt(block, inst),
......@@ -5186,7 +5186,10 @@ fn analyzeCall(
51865186 // on parameters, we must now do the same for the return type as we just did with
51875187 // each of the parameters, resolving the return type and providing it to the child
51885188 // `Sema` so that it can be used for the `ret_ptr` instruction.
5189 const ret_ty_inst = try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst);
5189 const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
5190 try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
5191 else
5192 try sema.resolveInst(fn_info.ret_ty_ref);
51905193 const ret_ty_src = func_src; // TODO better source location
51915194 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
51925195 // Create a fresh inferred error set type for inline/comptime calls.
......@@ -6497,9 +6500,34 @@ fn zirFunc(
64976500
64986501 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
64996502 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
6503 const target = sema.mod.getTarget();
6504 const ret_ty_src = inst_data.src(); // TODO better source location
6505
65006506 var extra_index = extra.end;
6501 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
6502 extra_index += ret_ty_body.len;
6507
6508 const ret_ty: Type = switch (extra.data.ret_body_len) {
6509 0 => Type.void,
6510 1 => blk: {
6511 const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
6512 extra_index += 1;
6513 if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| {
6514 break :blk ret_ty;
6515 } else |err| switch (err) {
6516 error.GenericPoison => {
6517 break :blk Type.initTag(.generic_poison);
6518 },
6519 else => |e| return e,
6520 }
6521 },
6522 else => blk: {
6523 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
6524 extra_index += ret_ty_body.len;
6525
6526 const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type);
6527 var buffer: Value.ToTypeBuffer = undefined;
6528 break :blk try ret_ty_val.toType(&buffer).copy(sema.arena);
6529 },
6530 };
65036531
65046532 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
65056533 const has_body = extra.data.body_len != 0;
......@@ -6517,9 +6545,11 @@ fn zirFunc(
65176545 block,
65186546 inst_data.src_node,
65196547 inst,
6520 ret_ty_body,
6548 0,
6549 target_util.defaultAddressSpace(target, .function),
6550 null,
65216551 cc,
6522 Value.@"null",
6552 ret_ty,
65236553 false,
65246554 inferred_error_set,
65256555 false,
......@@ -6529,6 +6559,44 @@ fn zirFunc(
65296559 );
65306560}
65316561
6562// TODO this function and its callsites along with funcCommon need to be reworked
6563// to handle when callconv, align, linksection, addrspace depend on comptime values
6564// (thus triggering error.GenericPoison)
6565fn resolveGenericBody(
6566 sema: *Sema,
6567 block: *Block,
6568 src: LazySrcLoc,
6569 body: []const Zir.Inst.Index,
6570 func_inst: Zir.Inst.Index,
6571 dest_ty: Type,
6572) !Value {
6573 assert(body.len != 0);
6574
6575 const err = err: {
6576 // Make sure any nested param instructions don't clobber our work.
6577 const prev_params = block.params;
6578 block.params = .{};
6579 defer {
6580 block.params.deinit(sema.gpa);
6581 block.params = prev_params;
6582 }
6583 const uncasted = sema.resolveBody(block, body, func_inst) catch |err| break :err err;
6584 const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err;
6585 const val = sema.resolveConstValue(block, src, result) catch |err| break :err err;
6586 return val;
6587 };
6588 switch (err) {
6589 error.GenericPoison => {
6590 if (dest_ty.tag() == .type) {
6591 return Value.initTag(.generic_poison_type);
6592 } else {
6593 return Value.initTag(.generic_poison);
6594 }
6595 },
6596 else => |e| return e,
6597 }
6598}
6599
65326600/// Given a library name, examines if the library name should end up in
65336601/// `link.File.Options.system_libs` table (for example, libc is always
65346602/// specified via dedicated flag `link.File.Options.link_libc` instead),
......@@ -6597,9 +6665,11 @@ fn funcCommon(
65976665 block: *Block,
65986666 src_node_offset: i32,
65996667 func_inst: Zir.Inst.Index,
6600 ret_ty_body: []const Zir.Inst.Index,
6668 alignment: u32,
6669 address_space: std.builtin.AddressSpace,
6670 section: ?[*:0]const u8,
66016671 cc: std.builtin.CallingConvention,
6602 align_val: Value,
6672 bare_return_type: Type,
66036673 var_args: bool,
66046674 inferred_error_set: bool,
66056675 is_extern: bool,
......@@ -6609,42 +6679,11 @@ fn funcCommon(
66096679) CompileError!Air.Inst.Ref {
66106680 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
66116681
6612 // The return type body might be a type expression that depends on generic parameters.
6613 // In such case we need to use a generic_poison value for the return type and mark
6614 // the function as generic.
6615 var is_generic = false;
6616 const bare_return_type: Type = ret_ty: {
6617 if (ret_ty_body.len == 0) break :ret_ty Type.void;
6618
6619 const err = err: {
6620 // Make sure any nested param instructions don't clobber our work.
6621 const prev_params = block.params;
6622 block.params = .{};
6623 defer {
6624 block.params.deinit(sema.gpa);
6625 block.params = prev_params;
6626 }
6627 if (sema.resolveBody(block, ret_ty_body, func_inst)) |ret_ty_inst| {
6628 if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
6629 break :ret_ty ret_ty;
6630 } else |err| break :err err;
6631 } else |err| break :err err;
6632 // Check for generic params.
6633 for (block.params.items) |param| {
6634 if (param.ty.tag() == .generic_poison) is_generic = true;
6635 }
6636 };
6637 switch (err) {
6638 error.GenericPoison => {
6639 // The type is not available until the generic instantiation.
6640 is_generic = true;
6641 break :ret_ty Type.initTag(.generic_poison);
6642 },
6643 else => |e| return e,
6644 }
6645 };
6646
6647 const mod = sema.mod;
6682 var is_generic = bare_return_type.tag() == .generic_poison;
6683 // Check for generic params.
6684 for (block.params.items) |param| {
6685 if (param.ty.tag() == .generic_poison) is_generic = true;
6686 }
66486687
66496688 const new_func: *Module.Fn = new_func: {
66506689 if (!has_body) break :new_func undefined;
......@@ -6661,18 +6700,7 @@ fn funcCommon(
66616700 errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
66626701 // Note: no need to errdefer since this will still be in its default state at the end of the function.
66636702
6664 const target = mod.getTarget();
6665
66666703 const fn_ty: Type = fn_ty: {
6667 const alignment: u32 = if (align_val.tag() == .null_value) 0 else a: {
6668 const alignment = @intCast(u32, align_val.toUnsignedInt(target));
6669 if (alignment == target_util.defaultFunctionAlignment(target)) {
6670 break :a 0;
6671 } else {
6672 break :a alignment;
6673 }
6674 };
6675
66766704 // Hot path for some common function types.
66776705 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
66786706 if (!is_generic and block.params.items.len == 0 and !var_args and
......@@ -6747,6 +6775,12 @@ fn funcCommon(
67476775 });
67486776 };
67496777
6778 if (sema.owner_decl.owns_tv) {
6779 sema.owner_decl.@"linksection" = section;
6780 sema.owner_decl.@"align" = alignment;
6781 sema.owner_decl.@"addrspace" = address_space;
6782 }
6783
67506784 if (is_extern) {
67516785 const new_extern_fn = try sema.gpa.create(Module.ExternFn);
67526786 errdefer sema.gpa.destroy(new_extern_fn);
......@@ -16723,16 +16757,20 @@ fn zirVarExtended(
1672316757 return result;
1672416758}
1672516759
16726fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
16760fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1672716761 const tracy = trace(@src());
1672816762 defer tracy.end();
1672916763
1673016764 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1673116765 const src = inst_data.src();
16732 const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, inst_data.payload_index);
16766 const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
16767 const target = sema.mod.getTarget();
1673316768
16734 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
1673516769 const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align
16770 const addrspace_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at addrspace
16771 const section_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at section
16772 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
16773 const ret_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at the return type
1673616774
1673716775 var extra_index: usize = extra.end;
1673816776
......@@ -16742,22 +16780,103 @@ fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
1674216780 break :blk lib_name;
1674316781 } else null;
1674416782
16745 const cc: std.builtin.CallingConvention = if (extra.data.bits.has_cc) blk: {
16783 const @"align": u32 = if (extra.data.bits.has_align_body) blk: {
16784 const body_len = sema.code.extra[extra_index];
16785 extra_index += 1;
16786 const body = sema.code.extra[extra_index..][0..body_len];
16787 extra_index += body.len;
16788
16789 const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u16);
16790 const alignment = @intCast(u32, val.toUnsignedInt(target));
16791 if (alignment == target_util.defaultFunctionAlignment(target)) {
16792 break :blk 0;
16793 } else {
16794 break :blk alignment;
16795 }
16796 } else if (extra.data.bits.has_align_ref) blk: {
16797 const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
16798 extra_index += 1;
16799 const align_tv = try sema.resolveInstConst(block, align_src, align_ref);
16800 const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target));
16801 if (alignment == target_util.defaultFunctionAlignment(target)) {
16802 break :blk 0;
16803 } else {
16804 break :blk alignment;
16805 }
16806 } else 0;
16807
16808 const @"addrspace": std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {
16809 const body_len = sema.code.extra[extra_index];
16810 extra_index += 1;
16811 const body = sema.code.extra[extra_index..][0..body_len];
16812 extra_index += body.len;
16813
16814 const addrspace_ty = try sema.getBuiltinType(block, addrspace_src, "AddressSpace");
16815 const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty);
16816 break :blk val.toEnum(std.builtin.AddressSpace);
16817 } else if (extra.data.bits.has_addrspace_ref) blk: {
16818 const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
16819 extra_index += 1;
16820 const addrspace_tv = try sema.resolveInstConst(block, addrspace_src, addrspace_ref);
16821 break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
16822 } else target_util.defaultAddressSpace(target, .function);
16823
16824 const @"linksection": ?[*:0]const u8 = if (extra.data.bits.has_section_body) {
16825 const body_len = sema.code.extra[extra_index];
16826 extra_index += 1;
16827 const body = sema.code.extra[extra_index..][0..body_len];
16828 extra_index += body.len;
16829
16830 const val = try sema.resolveGenericBody(block, section_src, body, inst, Type.initTag(.const_slice_u8));
16831 _ = val;
16832 return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
16833 } else if (extra.data.bits.has_section_ref) {
16834 const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
16835 extra_index += 1;
16836 const section_tv = try sema.resolveInstConst(block, section_src, section_ref);
16837 _ = section_tv;
16838 return sema.fail(block, section_src, "TODO implement linksection on functions", .{});
16839 } else null;
16840
16841 const cc: std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
16842 const body_len = sema.code.extra[extra_index];
16843 extra_index += 1;
16844 const body = sema.code.extra[extra_index..][0..body_len];
16845 extra_index += body.len;
16846
16847 const cc_ty = try sema.getBuiltinType(block, addrspace_src, "CallingConvention");
16848 const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty);
16849 break :blk val.toEnum(std.builtin.CallingConvention);
16850 } else if (extra.data.bits.has_cc_ref) blk: {
1674616851 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
1674716852 extra_index += 1;
1674816853 const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);
1674916854 break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
1675016855 } else .Unspecified;
1675116856
16752 const align_val: Value = if (extra.data.bits.has_align) blk: {
16753 const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
16857 const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: {
16858 const body_len = sema.code.extra[extra_index];
1675416859 extra_index += 1;
16755 const align_tv = try sema.resolveInstConst(block, align_src, align_ref);
16756 break :blk align_tv.val;
16757 } else Value.@"null";
16860 const body = sema.code.extra[extra_index..][0..body_len];
16861 extra_index += body.len;
1675816862
16759 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
16760 extra_index += ret_ty_body.len;
16863 const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type);
16864 var buffer: Value.ToTypeBuffer = undefined;
16865 const ty = try val.toType(&buffer).copy(sema.arena);
16866 break :blk ty;
16867 } else if (extra.data.bits.has_ret_ty_ref) blk: {
16868 const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
16869 extra_index += 1;
16870 const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref) catch |err| switch (err) {
16871 error.GenericPoison => {
16872 break :blk Type.initTag(.generic_poison);
16873 },
16874 else => |e| return e,
16875 };
16876 var buffer: Value.ToTypeBuffer = undefined;
16877 const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena);
16878 break :blk ty;
16879 } else Type.void;
1676116880
1676216881 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
1676316882 const has_body = extra.data.body_len != 0;
......@@ -16774,9 +16893,11 @@ fn zirFuncExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
1677416893 block,
1677516894 inst_data.src_node,
1677616895 inst,
16777 ret_ty_body,
16896 @"align",
16897 @"addrspace",
16898 @"linksection",
1677816899 cc,
16779 align_val,
16900 ret_ty,
1678016901 is_var_args,
1678116902 is_inferred_error,
1678216903 is_extern,
src/Zir.zig+209-53
......@@ -74,7 +74,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en
7474 Inst.Call.Flags => @bitCast(Inst.Call.Flags, code.extra[i]),
7575 Inst.BuiltinCall.Flags => @bitCast(Inst.BuiltinCall.Flags, code.extra[i]),
7676 Inst.SwitchBlock.Bits => @bitCast(Inst.SwitchBlock.Bits, code.extra[i]),
77 Inst.ExtendedFunc.Bits => @bitCast(Inst.ExtendedFunc.Bits, code.extra[i]),
77 Inst.FuncFancy.Bits => @bitCast(Inst.FuncFancy.Bits, code.extra[i]),
7878 else => @compileError("bad field type"),
7979 };
8080 i += 1;
......@@ -424,8 +424,8 @@ pub const Inst = struct {
424424 func_inferred,
425425 /// Represents a function declaration or function prototype, depending on
426426 /// whether body_len is 0.
427 /// Uses the `pl_node` union field. `payload_index` points to a `ExtendedFunc`.
428 func_extended,
427 /// Uses the `pl_node` union field. `payload_index` points to a `FuncFancy`.
428 func_fancy,
429429 /// Implements the `@import` builtin.
430430 /// Uses the `str_tok` field.
431431 import,
......@@ -1070,7 +1070,7 @@ pub const Inst = struct {
10701070 .field_val_named,
10711071 .func,
10721072 .func_inferred,
1073 .func_extended,
1073 .func_fancy,
10741074 .has_decl,
10751075 .int,
10761076 .int_big,
......@@ -1356,7 +1356,7 @@ pub const Inst = struct {
13561356 .field_val_named,
13571357 .func,
13581358 .func_inferred,
1359 .func_extended,
1359 .func_fancy,
13601360 .has_decl,
13611361 .int,
13621362 .int_big,
......@@ -1611,7 +1611,7 @@ pub const Inst = struct {
16111611 .field_call_bind = .pl_node,
16121612 .func = .pl_node,
16131613 .func_inferred = .pl_node,
1614 .func_extended = .pl_node,
1614 .func_fancy = .pl_node,
16151615 .import = .str_tok,
16161616 .int = .int,
16171617 .int_big = .str,
......@@ -2620,29 +2620,100 @@ pub const Inst = struct {
26202620 };
26212621
26222622 /// Trailing:
2623 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
2624 /// 1. cc: Ref, // if has_cc is set
2625 /// 2. align: Ref, // if has_align is set
2626 /// 3. return_type: Index // for each ret_body_len
2627 /// 4. body: Index // for each body_len
2628 /// 5. src_locs: Func.SrcLocs // if body_len != 0
2629 pub const ExtendedFunc = struct {
2623 /// if (ret_body_len == 1) {
2624 /// 0. return_type: Ref
2625 /// }
2626 /// if (ret_body_len > 1) {
2627 /// 1. return_type: Index // for each ret_body_len
2628 /// }
2629 /// 2. body: Index // for each body_len
2630 /// 3. src_locs: SrcLocs // if body_len != 0
2631 pub const Func = struct {
26302632 /// If this is 0 it means a void return type.
2633 /// If this is 1 it means return_type is a simple Ref
26312634 ret_body_len: u32,
26322635 /// Points to the block that contains the param instructions for this function.
26332636 param_block: Index,
26342637 body_len: u32,
2638
2639 pub const SrcLocs = struct {
2640 /// Line index in the source file relative to the parent decl.
2641 lbrace_line: u32,
2642 /// Line index in the source file relative to the parent decl.
2643 rbrace_line: u32,
2644 /// lbrace_column is least significant bits u16
2645 /// rbrace_column is most significant bits u16
2646 columns: u32,
2647 };
2648 };
2649
2650 /// Trailing:
2651 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
2652 /// if (has_align_ref and !has_align_body) {
2653 /// 1. align: Ref,
2654 /// }
2655 /// if (has_align_body) {
2656 /// 2. align_body_len: u32
2657 /// 3. align_body: u32 // for each align_body_len
2658 /// }
2659 /// if (has_addrspace_ref and !has_addrspace_body) {
2660 /// 4. addrspace: Ref,
2661 /// }
2662 /// if (has_addrspace_body) {
2663 /// 5. addrspace_body_len: u32
2664 /// 6. addrspace_body: u32 // for each addrspace_body_len
2665 /// }
2666 /// if (has_section_ref and !has_section_body) {
2667 /// 7. section: Ref,
2668 /// }
2669 /// if (has_section_body) {
2670 /// 8. section_body_len: u32
2671 /// 9. section_body: u32 // for each section_body_len
2672 /// }
2673 /// if (has_cc_ref and !has_cc_body) {
2674 /// 10. cc: Ref,
2675 /// }
2676 /// if (has_cc_body) {
2677 /// 11. cc_body_len: u32
2678 /// 12. cc_body: u32 // for each cc_body_len
2679 /// }
2680 /// if (has_ret_ty_ref and !has_ret_ty_body) {
2681 /// 13. ret_ty: Ref,
2682 /// }
2683 /// if (has_ret_ty_body) {
2684 /// 14. ret_ty_body_len: u32
2685 /// 15. ret_ty_body: u32 // for each ret_ty_body_len
2686 /// }
2687 /// 16. body: Index // for each body_len
2688 /// 17. src_locs: Func.SrcLocs // if body_len != 0
2689 pub const FuncFancy = struct {
2690 /// Points to the block that contains the param instructions for this function.
2691 param_block: Index,
2692 body_len: u32,
26352693 bits: Bits,
26362694
2695 /// If both has_cc_ref and has_cc_body are false, it means auto calling convention.
2696 /// If both has_align_ref and has_align_body are false, it means default alignment.
2697 /// If both has_ret_ty_ref and has_ret_ty_body are false, it means void return type.
2698 /// If both has_section_ref and has_section_body are false, it means default section.
2699 /// If both has_addrspace_ref and has_addrspace_body are false, it means default addrspace.
26372700 pub const Bits = packed struct {
26382701 is_var_args: bool,
26392702 is_inferred_error: bool,
2640 has_lib_name: bool,
2641 has_cc: bool,
2642 has_align: bool,
26432703 is_test: bool,
26442704 is_extern: bool,
2645 _: u25 = undefined,
2705 has_align_ref: bool,
2706 has_align_body: bool,
2707 has_addrspace_ref: bool,
2708 has_addrspace_body: bool,
2709 has_section_ref: bool,
2710 has_section_body: bool,
2711 has_cc_ref: bool,
2712 has_cc_body: bool,
2713 has_ret_ty_ref: bool,
2714 has_ret_ty_body: bool,
2715 has_lib_name: bool,
2716 _: u17 = undefined,
26462717 };
26472718 };
26482719
......@@ -2664,28 +2735,6 @@ pub const Inst = struct {
26642735 };
26652736 };
26662737
2667 /// Trailing:
2668 /// 0. return_type: Index // for each ret_body_len
2669 /// 1. body: Index // for each body_len
2670 /// 2. src_locs: SrcLocs // if body_len != 0
2671 pub const Func = struct {
2672 /// If this is 0 it means a void return type.
2673 ret_body_len: u32,
2674 /// Points to the block that contains the param instructions for this function.
2675 param_block: Index,
2676 body_len: u32,
2677
2678 pub const SrcLocs = struct {
2679 /// Line index in the source file relative to the parent decl.
2680 lbrace_line: u32,
2681 /// Line index in the source file relative to the parent decl.
2682 rbrace_line: u32,
2683 /// lbrace_column is least significant bits u16
2684 /// rbrace_column is most significant bits u16
2685 columns: u32,
2686 };
2687 };
2688
26892738 /// This data is stored inside extra, with trailing operands according to `operands_len`.
26902739 /// Each operand is a `Ref`.
26912740 pub const MultiOp = struct {
......@@ -3487,7 +3536,7 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
34873536 switch (tags[decl_inst]) {
34883537 // Functions are allowed and yield no iterations.
34893538 // There is one case matching this in the extended instruction set below.
3490 .func, .func_inferred, .func_extended => return declIteratorInner(zir, 0, 0),
3539 .func, .func_inferred, .func_fancy => return declIteratorInner(zir, 0, 0),
34913540
34923541 .extended => {
34933542 const extended = datas[decl_inst].extended;
......@@ -3593,18 +3642,77 @@ fn findDeclsInner(
35933642
35943643 const inst_data = datas[inst].pl_node;
35953644 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
3596 const body = zir.extra[extra.end..][0..extra.data.body_len];
3645 var extra_index: usize = extra.end;
3646 switch (extra.data.ret_body_len) {
3647 0 => {},
3648 1 => extra_index += 1,
3649 else => {
3650 const body = zir.extra[extra_index..][0..extra.data.ret_body_len];
3651 extra_index += body.len;
3652 try zir.findDeclsBody(list, body);
3653 },
3654 }
3655 const body = zir.extra[extra_index..][0..extra.data.body_len];
35973656 return zir.findDeclsBody(list, body);
35983657 },
3599 .func_extended => {
3658 .func_fancy => {
36003659 try list.append(inst);
36013660
36023661 const inst_data = datas[inst].pl_node;
3603 const extra = zir.extraData(Inst.ExtendedFunc, inst_data.payload_index);
3662 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
36043663 var extra_index: usize = extra.end;
36053664 extra_index += @boolToInt(extra.data.bits.has_lib_name);
3606 extra_index += @boolToInt(extra.data.bits.has_cc);
3607 extra_index += @boolToInt(extra.data.bits.has_align);
3665
3666 if (extra.data.bits.has_align_body) {
3667 const body_len = zir.extra[extra_index];
3668 extra_index += 1;
3669 const body = zir.extra[extra_index..][0..body_len];
3670 try zir.findDeclsBody(list, body);
3671 extra_index += body.len;
3672 } else if (extra.data.bits.has_align_ref) {
3673 extra_index += 1;
3674 }
3675
3676 if (extra.data.bits.has_addrspace_body) {
3677 const body_len = zir.extra[extra_index];
3678 extra_index += 1;
3679 const body = zir.extra[extra_index..][0..body_len];
3680 try zir.findDeclsBody(list, body);
3681 extra_index += body.len;
3682 } else if (extra.data.bits.has_addrspace_ref) {
3683 extra_index += 1;
3684 }
3685
3686 if (extra.data.bits.has_section_body) {
3687 const body_len = zir.extra[extra_index];
3688 extra_index += 1;
3689 const body = zir.extra[extra_index..][0..body_len];
3690 try zir.findDeclsBody(list, body);
3691 extra_index += body.len;
3692 } else if (extra.data.bits.has_section_ref) {
3693 extra_index += 1;
3694 }
3695
3696 if (extra.data.bits.has_cc_body) {
3697 const body_len = zir.extra[extra_index];
3698 extra_index += 1;
3699 const body = zir.extra[extra_index..][0..body_len];
3700 try zir.findDeclsBody(list, body);
3701 extra_index += body.len;
3702 } else if (extra.data.bits.has_cc_ref) {
3703 extra_index += 1;
3704 }
3705
3706 if (extra.data.bits.has_ret_ty_body) {
3707 const body_len = zir.extra[extra_index];
3708 extra_index += 1;
3709 const body = zir.extra[extra_index..][0..body_len];
3710 try zir.findDeclsBody(list, body);
3711 extra_index += body.len;
3712 } else if (extra.data.bits.has_ret_ty_ref) {
3713 extra_index += 1;
3714 }
3715
36083716 const body = zir.extra[extra_index..][0..extra.data.body_len];
36093717 return zir.findDeclsBody(list, body);
36103718 },
......@@ -3729,6 +3837,7 @@ pub const FnInfo = struct {
37293837 param_body_inst: Inst.Index,
37303838 ret_ty_body: []const Inst.Index,
37313839 body: []const Inst.Index,
3840 ret_ty_ref: Zir.Inst.Ref,
37323841 total_params_len: u32,
37333842};
37343843
......@@ -3738,38 +3847,84 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
37383847 const info: struct {
37393848 param_block: Inst.Index,
37403849 body: []const Inst.Index,
3850 ret_ty_ref: Inst.Ref,
37413851 ret_ty_body: []const Inst.Index,
37423852 } = switch (tags[fn_inst]) {
37433853 .func, .func_inferred => blk: {
37443854 const inst_data = datas[fn_inst].pl_node;
37453855 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
3856
37463857 var extra_index: usize = extra.end;
3858 var ret_ty_ref: Inst.Ref = .none;
3859 var ret_ty_body: []const Inst.Index = &.{};
37473860
3748 const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
3749 extra_index += ret_ty_body.len;
3861 switch (extra.data.ret_body_len) {
3862 0 => {
3863 ret_ty_ref = .void_type;
3864 },
3865 1 => {
3866 ret_ty_ref = @intToEnum(Inst.Ref, zir.extra[extra_index]);
3867 extra_index += 1;
3868 },
3869 else => {
3870 ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
3871 extra_index += ret_ty_body.len;
3872 },
3873 }
37503874
37513875 const body = zir.extra[extra_index..][0..extra.data.body_len];
37523876 extra_index += body.len;
37533877
37543878 break :blk .{
37553879 .param_block = extra.data.param_block,
3880 .ret_ty_ref = ret_ty_ref,
37563881 .ret_ty_body = ret_ty_body,
37573882 .body = body,
37583883 };
37593884 },
3760 .func_extended => blk: {
3885 .func_fancy => blk: {
37613886 const inst_data = datas[fn_inst].pl_node;
3762 const extra = zir.extraData(Inst.ExtendedFunc, inst_data.payload_index);
3887 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
3888
37633889 var extra_index: usize = extra.end;
3890 var ret_ty_ref: Inst.Ref = .void_type;
3891 var ret_ty_body: []const Inst.Index = &.{};
3892
37643893 extra_index += @boolToInt(extra.data.bits.has_lib_name);
3765 extra_index += @boolToInt(extra.data.bits.has_cc);
3766 extra_index += @boolToInt(extra.data.bits.has_align);
3767 const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
3768 extra_index += ret_ty_body.len;
3894 if (extra.data.bits.has_align_body) {
3895 extra_index += zir.extra[extra_index] + 1;
3896 } else if (extra.data.bits.has_align_ref) {
3897 extra_index += 1;
3898 }
3899 if (extra.data.bits.has_addrspace_body) {
3900 extra_index += zir.extra[extra_index] + 1;
3901 } else if (extra.data.bits.has_addrspace_ref) {
3902 extra_index += 1;
3903 }
3904 if (extra.data.bits.has_section_body) {
3905 extra_index += zir.extra[extra_index] + 1;
3906 } else if (extra.data.bits.has_section_ref) {
3907 extra_index += 1;
3908 }
3909 if (extra.data.bits.has_cc_body) {
3910 extra_index += zir.extra[extra_index] + 1;
3911 } else if (extra.data.bits.has_cc_ref) {
3912 extra_index += 1;
3913 }
3914 if (extra.data.bits.has_ret_ty_body) {
3915 const body_len = zir.extra[extra_index];
3916 extra_index += 1;
3917 ret_ty_body = zir.extra[extra_index..][0..body_len];
3918 extra_index += ret_ty_body.len;
3919 } else if (extra.data.bits.has_ret_ty_ref) {
3920 ret_ty_ref = @intToEnum(Inst.Ref, zir.extra[extra_index]);
3921 extra_index += 1;
3922 }
37693923 const body = zir.extra[extra_index..][0..extra.data.body_len];
37703924 extra_index += body.len;
37713925 break :blk .{
37723926 .param_block = extra.data.param_block,
3927 .ret_ty_ref = ret_ty_ref,
37733928 .ret_ty_body = ret_ty_body,
37743929 .body = body,
37753930 };
......@@ -3792,6 +3947,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
37923947 .param_body = param_body,
37933948 .param_body_inst = info.param_block,
37943949 .ret_ty_body = info.ret_ty_body,
3950 .ret_ty_ref = info.ret_ty_ref,
37953951 .body = info.body,
37963952 .total_params_len = total_params_len,
37973953 };
src/print_zir.zig+132-37
......@@ -429,7 +429,7 @@ const Writer = struct {
429429
430430 .func => try self.writeFunc(stream, inst, false),
431431 .func_inferred => try self.writeFunc(stream, inst, true),
432 .func_extended => try self.writeFuncExtended(stream, inst),
432 .func_fancy => try self.writeFuncFancy(stream, inst),
433433
434434 .@"unreachable" => try self.writeUnreachable(stream, inst),
435435
......@@ -1912,10 +1912,24 @@ const Writer = struct {
19121912 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
19131913 const src = inst_data.src();
19141914 const extra = self.code.extraData(Zir.Inst.Func, inst_data.payload_index);
1915
19151916 var extra_index = extra.end;
1917 var ret_ty_ref: Zir.Inst.Ref = .none;
1918 var ret_ty_body: []const Zir.Inst.Index = &.{};
19161919
1917 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
1918 extra_index += ret_ty_body.len;
1920 switch (extra.data.ret_body_len) {
1921 0 => {
1922 ret_ty_ref = .void_type;
1923 },
1924 1 => {
1925 ret_ty_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1926 extra_index += 1;
1927 },
1928 else => {
1929 ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
1930 extra_index += ret_ty_body.len;
1931 },
1932 }
19191933
19201934 const body = self.code.extra[extra_index..][0..extra.data.body_len];
19211935 extra_index += body.len;
......@@ -1926,43 +1940,96 @@ const Writer = struct {
19261940 }
19271941 return self.writeFuncCommon(
19281942 stream,
1929 ret_ty_body,
19301943 inferred_error_set,
19311944 false,
19321945 false,
1946
19331947 .none,
1948 &.{},
19341949 .none,
1950 &.{},
1951 .none,
1952 &.{},
1953 .none,
1954 &.{},
1955 ret_ty_ref,
1956 ret_ty_body,
1957
19351958 body,
19361959 src,
19371960 src_locs,
19381961 );
19391962 }
19401963
1941 fn writeFuncExtended(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1964 fn writeFuncFancy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
19421965 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1943 const extra = self.code.extraData(Zir.Inst.ExtendedFunc, inst_data.payload_index);
1966 const extra = self.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
19441967 const src = inst_data.src();
19451968
19461969 var extra_index: usize = extra.end;
1970 var align_ref: Zir.Inst.Ref = .none;
1971 var align_body: []const Zir.Inst.Index = &.{};
1972 var addrspace_ref: Zir.Inst.Ref = .none;
1973 var addrspace_body: []const Zir.Inst.Index = &.{};
1974 var section_ref: Zir.Inst.Ref = .none;
1975 var section_body: []const Zir.Inst.Index = &.{};
1976 var cc_ref: Zir.Inst.Ref = .none;
1977 var cc_body: []const Zir.Inst.Index = &.{};
1978 var ret_ty_ref: Zir.Inst.Ref = .none;
1979 var ret_ty_body: []const Zir.Inst.Index = &.{};
1980
19471981 if (extra.data.bits.has_lib_name) {
19481982 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
19491983 extra_index += 1;
19501984 try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)});
19511985 }
19521986 try self.writeFlag(stream, "test, ", extra.data.bits.is_test);
1953 const cc: Zir.Inst.Ref = if (!extra.data.bits.has_cc) .none else blk: {
1954 const cc = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1987
1988 if (extra.data.bits.has_align_body) {
1989 const body_len = self.code.extra[extra_index];
19551990 extra_index += 1;
1956 break :blk cc;
1957 };
1958 const align_inst: Zir.Inst.Ref = if (!extra.data.bits.has_align) .none else blk: {
1959 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1991 align_body = self.code.extra[extra_index..][0..body_len];
1992 extra_index += align_body.len;
1993 } else if (extra.data.bits.has_align_ref) {
1994 align_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
19601995 extra_index += 1;
1961 break :blk align_inst;
1962 };
1963
1964 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
1965 extra_index += ret_ty_body.len;
1996 }
1997 if (extra.data.bits.has_addrspace_body) {
1998 const body_len = self.code.extra[extra_index];
1999 extra_index += 1;
2000 addrspace_body = self.code.extra[extra_index..][0..body_len];
2001 extra_index += addrspace_body.len;
2002 } else if (extra.data.bits.has_addrspace_ref) {
2003 addrspace_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
2004 extra_index += 1;
2005 }
2006 if (extra.data.bits.has_section_body) {
2007 const body_len = self.code.extra[extra_index];
2008 extra_index += 1;
2009 section_body = self.code.extra[extra_index..][0..body_len];
2010 extra_index += section_body.len;
2011 } else if (extra.data.bits.has_section_ref) {
2012 section_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
2013 extra_index += 1;
2014 }
2015 if (extra.data.bits.has_cc_body) {
2016 const body_len = self.code.extra[extra_index];
2017 extra_index += 1;
2018 cc_body = self.code.extra[extra_index..][0..body_len];
2019 extra_index += cc_body.len;
2020 } else if (extra.data.bits.has_cc_ref) {
2021 cc_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
2022 extra_index += 1;
2023 }
2024 if (extra.data.bits.has_ret_ty_body) {
2025 const body_len = self.code.extra[extra_index];
2026 extra_index += 1;
2027 ret_ty_body = self.code.extra[extra_index..][0..body_len];
2028 extra_index += ret_ty_body.len;
2029 } else if (extra.data.bits.has_ret_ty_ref) {
2030 ret_ty_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
2031 extra_index += 1;
2032 }
19662033
19672034 const body = self.code.extra[extra_index..][0..extra.data.body_len];
19682035 extra_index += body.len;
......@@ -1973,12 +2040,19 @@ const Writer = struct {
19732040 }
19742041 return self.writeFuncCommon(
19752042 stream,
1976 ret_ty_body,
19772043 extra.data.bits.is_inferred_error,
19782044 extra.data.bits.is_var_args,
19792045 extra.data.bits.is_extern,
1980 cc,
1981 align_inst,
2046 align_ref,
2047 align_body,
2048 addrspace_ref,
2049 addrspace_body,
2050 section_ref,
2051 section_body,
2052 cc_ref,
2053 cc_body,
2054 ret_ty_ref,
2055 ret_ty_body,
19822056 body,
19832057 src,
19842058 src_locs,
......@@ -2122,30 +2196,33 @@ const Writer = struct {
21222196 fn writeFuncCommon(
21232197 self: *Writer,
21242198 stream: anytype,
2125 ret_ty_body: []const Zir.Inst.Index,
21262199 inferred_error_set: bool,
21272200 var_args: bool,
21282201 is_extern: bool,
2129 cc: Zir.Inst.Ref,
2130 align_inst: Zir.Inst.Ref,
2202 align_ref: Zir.Inst.Ref,
2203 align_body: []const Zir.Inst.Index,
2204 addrspace_ref: Zir.Inst.Ref,
2205 addrspace_body: []const Zir.Inst.Index,
2206 section_ref: Zir.Inst.Ref,
2207 section_body: []const Zir.Inst.Index,
2208 cc_ref: Zir.Inst.Ref,
2209 cc_body: []const Zir.Inst.Index,
2210 ret_ty_ref: Zir.Inst.Ref,
2211 ret_ty_body: []const Zir.Inst.Index,
21312212 body: []const Zir.Inst.Index,
21322213 src: LazySrcLoc,
21332214 src_locs: Zir.Inst.Func.SrcLocs,
21342215 ) !void {
2135 if (ret_ty_body.len == 0) {
2136 try stream.writeAll("ret_ty=void");
2137 } else {
2138 try stream.writeAll("ret_ty=");
2139 try self.writeBracedBody(stream, ret_ty_body);
2140 }
2141
2142 try self.writeOptionalInstRef(stream, ", cc=", cc);
2143 try self.writeOptionalInstRef(stream, ", align=", align_inst);
2144 try self.writeFlag(stream, ", vargs", var_args);
2145 try self.writeFlag(stream, ", extern", is_extern);
2146 try self.writeFlag(stream, ", inferror", inferred_error_set);
2147
2148 try stream.writeAll(", body=");
2216 try self.writeOptionalInstRefOrBody(stream, "align=", align_ref, align_body);
2217 try self.writeOptionalInstRefOrBody(stream, "addrspace=", addrspace_ref, addrspace_body);
2218 try self.writeOptionalInstRefOrBody(stream, "section=", section_ref, section_body);
2219 try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body);
2220 try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body);
2221 try self.writeFlag(stream, "vargs, ", var_args);
2222 try self.writeFlag(stream, "extern, ", is_extern);
2223 try self.writeFlag(stream, "inferror, ", inferred_error_set);
2224
2225 try stream.writeAll("body=");
21492226 try self.writeBracedBody(stream, body);
21502227 try stream.writeAll(") ");
21512228 if (body.len != 0) {
......@@ -2195,6 +2272,24 @@ const Writer = struct {
21952272 try self.writeInstRef(stream, inst);
21962273 }
21972274
2275 fn writeOptionalInstRefOrBody(
2276 self: *Writer,
2277 stream: anytype,
2278 prefix: []const u8,
2279 ref: Zir.Inst.Ref,
2280 body: []const Zir.Inst.Index,
2281 ) !void {
2282 if (body.len != 0) {
2283 try stream.writeAll(prefix);
2284 try self.writeBracedBody(stream, body);
2285 try stream.writeAll(", ");
2286 } else if (ref != .none) {
2287 try stream.writeAll(prefix);
2288 try self.writeInstRef(stream, ref);
2289 try stream.writeAll(", ");
2290 }
2291 }
2292
21982293 fn writeFlag(
21992294 self: *Writer,
22002295 stream: anytype,