authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-09 18:04:26-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-12-09 18:04:26-05:00
log8245d7fac0400d7e9de2a6fd4cfbc3609ad0f201
treeb7d46c56f96bbf32397b71479c85f3e363e48672
parent3aab81b0abe2efeab8a2c7cdae2146252b4f703f
parent135c733eefa8cd43e84e7b39aa292359c680fe1e
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22164 from mlugg/astgen-ref-dedup

AstGen: correctly deduplicate `ref` of `param` and `alloc_inferred`

6 files changed, 398 insertions(+), 253 deletions(-)

lib/std/zig/AstGen.zig+214-207
...@@ -1373,7 +1373,9 @@ fn fnProtoExpr(...@@ -1373,7 +1373,9 @@ fn fnProtoExpr(
1373 const main_tokens = tree.nodes.items(.main_token);1373 const main_tokens = tree.nodes.items(.main_token);
1374 const name_token = param.name_token orelse main_tokens[param_type_node];1374 const name_token = param.name_token orelse main_tokens[param_type_node];
1375 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;1375 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1376 const param_inst = try block_scope.addParam(&param_gz, tag, name_token, param_name, param.first_doc_comment);1376 // We pass `prev_param_insts` as `&.{}` here because a function prototype can't refer to previous
1377 // arguments (we haven't set up scopes here).
1378 const param_inst = try block_scope.addParam(&param_gz, &.{}, tag, name_token, param_name, param.first_doc_comment);
1377 assert(param_inst_expected == param_inst);1379 assert(param_inst_expected == param_inst);
1378 }1380 }
1379 }1381 }
...@@ -1423,6 +1425,13 @@ fn fnProtoExpr(...@@ -1423,6 +1425,13 @@ fn fnProtoExpr(
1423 .addrspace_ref = .none,1425 .addrspace_ref = .none,
1424 .addrspace_gz = null,1426 .addrspace_gz = null,
14251427
1428 .align_param_refs = &.{},
1429 .addrspace_param_refs = &.{},
1430 .section_param_refs = &.{},
1431 .cc_param_refs = &.{},
1432 .ret_param_refs = &.{},
1433 .param_insts = &.{},
1434
1426 .param_block = block_inst,1435 .param_block = block_inst,
1427 .body_gz = null,1436 .body_gz = null,
1428 .lib_name = .empty,1437 .lib_name = .empty,
...@@ -3189,28 +3198,13 @@ fn deferStmt(...@@ -3189,28 +3198,13 @@ fn deferStmt(
3189 try checkUsed(gz, scope, sub_scope);3198 try checkUsed(gz, scope, sub_scope);
3190 _ = try defer_gen.addBreak(.break_inline, @enumFromInt(0), .void_value);3199 _ = try defer_gen.addBreak(.break_inline, @enumFromInt(0), .void_value);
31913200
3192 // We must handle ref_table for remapped_err_code manually.
3193 const body = defer_gen.instructionsSlice();3201 const body = defer_gen.instructionsSlice();
3194 const body_len = blk: {3202 const extra_insts: []const Zir.Inst.Index = if (opt_remapped_err_code.unwrap()) |ec| &.{ec} else &.{};
3195 var refs: u32 = 0;3203 const body_len = gz.astgen.countBodyLenAfterFixupsExtraRefs(body, extra_insts);
3196 if (opt_remapped_err_code.unwrap()) |remapped_err_code| {
3197 var cur_inst = remapped_err_code;
3198 while (gz.astgen.ref_table.get(cur_inst)) |ref_inst| {
3199 refs += 1;
3200 cur_inst = ref_inst;
3201 }
3202 }
3203 break :blk gz.astgen.countBodyLenAfterFixups(body) + refs;
3204 };
32053204
3206 const index: u32 = @intCast(gz.astgen.extra.items.len);3205 const index: u32 = @intCast(gz.astgen.extra.items.len);
3207 try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len);3206 try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len);
3208 if (opt_remapped_err_code.unwrap()) |remapped_err_code| {3207 gz.astgen.appendBodyWithFixupsExtraRefsArrayList(&gz.astgen.extra, body, extra_insts);
3209 if (gz.astgen.ref_table.fetchRemove(remapped_err_code)) |kv| {
3210 gz.astgen.appendPossiblyRefdBodyInst(&gz.astgen.extra, kv.value);
3211 }
3212 }
3213 gz.astgen.appendBodyWithFixups(body);
32143208
3215 const defer_scope = try block_arena.create(Scope.Defer);3209 const defer_scope = try block_arena.create(Scope.Defer);
32163210
...@@ -3313,11 +3307,8 @@ fn varDecl(...@@ -3313,11 +3307,8 @@ fn varDecl(
3313 const is_comptime = gz.is_comptime or3307 const is_comptime = gz.is_comptime or
3314 tree.nodes.items(.tag)[var_decl.ast.init_node] == .@"comptime";3308 tree.nodes.items(.tag)[var_decl.ast.init_node] == .@"comptime";
33153309
3316 var resolve_inferred_alloc: Zir.Inst.Ref = .none;
3317 var opt_type_inst: Zir.Inst.Ref = .none;
3318 const init_rl: ResultInfo.Loc = if (type_node != 0) init_rl: {3310 const init_rl: ResultInfo.Loc = if (type_node != 0) init_rl: {
3319 const type_inst = try typeExpr(gz, scope, type_node);3311 const type_inst = try typeExpr(gz, scope, type_node);
3320 opt_type_inst = type_inst;
3321 if (align_inst == .none) {3312 if (align_inst == .none) {
3322 break :init_rl .{ .ptr = .{ .inst = try gz.addUnNode(.alloc, type_inst, node) } };3313 break :init_rl .{ .ptr = .{ .inst = try gz.addUnNode(.alloc, type_inst, node) } };
3323 } else {3314 } else {
...@@ -3345,12 +3336,11 @@ fn varDecl(...@@ -3345,12 +3336,11 @@ fn varDecl(
3345 .is_comptime = is_comptime,3336 .is_comptime = is_comptime,
3346 });3337 });
3347 };3338 };
3348 resolve_inferred_alloc = alloc_inst;
3349 break :init_rl .{ .inferred_ptr = alloc_inst };3339 break :init_rl .{ .inferred_ptr = alloc_inst };
3350 };3340 };
3351 const var_ptr = switch (init_rl) {3341 const var_ptr: Zir.Inst.Ref, const resolve_inferred: bool = switch (init_rl) {
3352 .ptr => |ptr| ptr.inst,3342 .ptr => |ptr| .{ ptr.inst, false },
3353 .inferred_ptr => |inst| inst,3343 .inferred_ptr => |inst| .{ inst, true },
3354 else => unreachable,3344 else => unreachable,
3355 };3345 };
3356 const init_result_info: ResultInfo = .{ .rl = init_rl, .ctx = .const_init };3346 const init_result_info: ResultInfo = .{ .rl = init_rl, .ctx = .const_init };
...@@ -3365,10 +3355,10 @@ fn varDecl(...@@ -3365,10 +3355,10 @@ fn varDecl(
3365 if (nodeMayAppendToErrorTrace(tree, var_decl.ast.init_node))3355 if (nodeMayAppendToErrorTrace(tree, var_decl.ast.init_node))
3366 _ = try gz.addSaveErrRetIndex(.{ .if_of_error_type = init_inst });3356 _ = try gz.addSaveErrRetIndex(.{ .if_of_error_type = init_inst });
33673357
3368 const const_ptr = if (resolve_inferred_alloc != .none) p: {3358 const const_ptr = if (resolve_inferred)
3369 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);3359 try gz.addUnNode(.resolve_inferred_alloc, var_ptr, node)
3370 break :p var_ptr;3360 else
3371 } else try gz.addUnNode(.make_ptr_const, var_ptr, node);3361 try gz.addUnNode(.make_ptr_const, var_ptr, node);
33723362
3373 try gz.addDbgVar(.dbg_var_ptr, ident_name, const_ptr);3363 try gz.addDbgVar(.dbg_var_ptr, ident_name, const_ptr);
33743364
...@@ -3388,8 +3378,7 @@ fn varDecl(...@@ -3388,8 +3378,7 @@ fn varDecl(
3388 if (var_decl.comptime_token != null and gz.is_comptime)3378 if (var_decl.comptime_token != null and gz.is_comptime)
3389 return astgen.failTok(var_decl.comptime_token.?, "'comptime var' is redundant in comptime scope", .{});3379 return astgen.failTok(var_decl.comptime_token.?, "'comptime var' is redundant in comptime scope", .{});
3390 const is_comptime = var_decl.comptime_token != null or gz.is_comptime;3380 const is_comptime = var_decl.comptime_token != null or gz.is_comptime;
3391 var resolve_inferred_alloc: Zir.Inst.Ref = .none;3381 const alloc: Zir.Inst.Ref, const resolve_inferred: bool, const result_info: ResultInfo = if (var_decl.ast.type_node != 0) a: {
3392 const alloc: Zir.Inst.Ref, const result_info: ResultInfo = if (var_decl.ast.type_node != 0) a: {
3393 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);3382 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
3394 const alloc = alloc: {3383 const alloc = alloc: {
3395 if (align_inst == .none) {3384 if (align_inst == .none) {
...@@ -3408,7 +3397,7 @@ fn varDecl(...@@ -3408,7 +3397,7 @@ fn varDecl(
3408 });3397 });
3409 }3398 }
3410 };3399 };
3411 break :a .{ alloc, .{ .rl = .{ .ptr = .{ .inst = alloc } } } };3400 break :a .{ alloc, false, .{ .rl = .{ .ptr = .{ .inst = alloc } } } };
3412 } else a: {3401 } else a: {
3413 const alloc = alloc: {3402 const alloc = alloc: {
3414 if (align_inst == .none) {3403 if (align_inst == .none) {
...@@ -3427,25 +3416,24 @@ fn varDecl(...@@ -3427,25 +3416,24 @@ fn varDecl(
3427 });3416 });
3428 }3417 }
3429 };3418 };
3430 resolve_inferred_alloc = alloc;3419 break :a .{ alloc, true, .{ .rl = .{ .inferred_ptr = alloc } } };
3431 break :a .{ alloc, .{ .rl = .{ .inferred_ptr = alloc } } };
3432 };3420 };
3433 const prev_anon_name_strategy = gz.anon_name_strategy;3421 const prev_anon_name_strategy = gz.anon_name_strategy;
3434 gz.anon_name_strategy = .dbg_var;3422 gz.anon_name_strategy = .dbg_var;
3435 _ = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, is_comptime);3423 _ = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, is_comptime);
3436 gz.anon_name_strategy = prev_anon_name_strategy;3424 gz.anon_name_strategy = prev_anon_name_strategy;
3437 if (resolve_inferred_alloc != .none) {3425 const final_ptr: Zir.Inst.Ref = if (resolve_inferred) ptr: {
3438 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);3426 break :ptr try gz.addUnNode(.resolve_inferred_alloc, alloc, node);
3439 }3427 } else alloc;
34403428
3441 try gz.addDbgVar(.dbg_var_ptr, ident_name, alloc);3429 try gz.addDbgVar(.dbg_var_ptr, ident_name, final_ptr);
34423430
3443 const sub_scope = try block_arena.create(Scope.LocalPtr);3431 const sub_scope = try block_arena.create(Scope.LocalPtr);
3444 sub_scope.* = .{3432 sub_scope.* = .{
3445 .parent = scope,3433 .parent = scope,
3446 .gen_zir = gz,3434 .gen_zir = gz,
3447 .name = ident_name,3435 .name = ident_name,
3448 .ptr = alloc,3436 .ptr = final_ptr,
3449 .token_src = name_token,3437 .token_src = name_token,
3450 .maybe_comptime = is_comptime,3438 .maybe_comptime = is_comptime,
3451 .id_cat = .@"local variable",3439 .id_cat = .@"local variable",
...@@ -3726,26 +3714,25 @@ fn assignDestructureMaybeDecls(...@@ -3726,26 +3714,25 @@ fn assignDestructureMaybeDecls(
3726 else => continue, // We were mutating an existing lvalue - nothing to do3714 else => continue, // We were mutating an existing lvalue - nothing to do
3727 }3715 }
3728 const full_var_decl = tree.fullVarDecl(variable_node).?;3716 const full_var_decl = tree.fullVarDecl(variable_node).?;
3729 const raw_ptr = switch (variable_rl) {3717 const raw_ptr, const resolve_inferred = switch (variable_rl) {
3730 .discard => unreachable,3718 .discard => unreachable,
3731 .typed_ptr => |typed_ptr| typed_ptr.inst,3719 .typed_ptr => |typed_ptr| .{ typed_ptr.inst, false },
3732 .inferred_ptr => |ptr_inst| ptr_inst,3720 .inferred_ptr => |ptr_inst| .{ ptr_inst, true },
3733 };3721 };
3734 // If the alloc was inferred, resolve it.
3735 if (full_var_decl.ast.type_node == 0) {
3736 _ = try gz.addUnNode(.resolve_inferred_alloc, raw_ptr, variable_node);
3737 }
3738 const is_const = switch (token_tags[full_var_decl.ast.mut_token]) {3722 const is_const = switch (token_tags[full_var_decl.ast.mut_token]) {
3739 .keyword_var => false,3723 .keyword_var => false,
3740 .keyword_const => true,3724 .keyword_const => true,
3741 else => unreachable,3725 else => unreachable,
3742 };3726 };
3743 // If the alloc was const, make it const.3727
3744 const var_ptr = if (is_const and full_var_decl.ast.type_node != 0) make_const: {3728 // If the alloc was inferred, resolve it. If the alloc was const, make it const.
3745 // Note that we don't do this if type_node == 0 since `resolve_inferred_alloc`3729 const final_ptr = if (resolve_inferred)
3746 // handles it for us.3730 try gz.addUnNode(.resolve_inferred_alloc, raw_ptr, variable_node)
3747 break :make_const try gz.addUnNode(.make_ptr_const, raw_ptr, node);3731 else if (is_const)
3748 } else raw_ptr;3732 try gz.addUnNode(.make_ptr_const, raw_ptr, node)
3733 else
3734 raw_ptr;
3735
3749 const name_token = full_var_decl.ast.mut_token + 1;3736 const name_token = full_var_decl.ast.mut_token + 1;
3750 const ident_name_raw = tree.tokenSlice(name_token);3737 const ident_name_raw = tree.tokenSlice(name_token);
3751 const ident_name = try astgen.identAsString(name_token);3738 const ident_name = try astgen.identAsString(name_token);
...@@ -3756,14 +3743,14 @@ fn assignDestructureMaybeDecls(...@@ -3756,14 +3743,14 @@ fn assignDestructureMaybeDecls(
3756 ident_name_raw,3743 ident_name_raw,
3757 if (is_const) .@"local constant" else .@"local variable",3744 if (is_const) .@"local constant" else .@"local variable",
3758 );3745 );
3759 try gz.addDbgVar(.dbg_var_ptr, ident_name, var_ptr);3746 try gz.addDbgVar(.dbg_var_ptr, ident_name, final_ptr);
3760 // Finally, create the scope.3747 // Finally, create the scope.
3761 const sub_scope = try block_arena.create(Scope.LocalPtr);3748 const sub_scope = try block_arena.create(Scope.LocalPtr);
3762 sub_scope.* = .{3749 sub_scope.* = .{
3763 .parent = cur_scope,3750 .parent = cur_scope,
3764 .gen_zir = gz,3751 .gen_zir = gz,
3765 .name = ident_name,3752 .name = ident_name,
3766 .ptr = var_ptr,3753 .ptr = final_ptr,
3767 .token_src = name_token,3754 .token_src = name_token,
3768 .maybe_comptime = is_const or is_comptime,3755 .maybe_comptime = is_const or is_comptime,
3769 .id_cat = if (is_const) .@"local constant" else .@"local variable",3756 .id_cat = if (is_const) .@"local constant" else .@"local variable",
...@@ -4182,6 +4169,9 @@ fn fnDecl(...@@ -4182,6 +4169,9 @@ fn fnDecl(
41824169
4183 wip_members.nextDecl(decl_inst);4170 wip_members.nextDecl(decl_inst);
41844171
4172 // Note that the capacity here may not be sufficient, as this does not include `anytype` parameters.
4173 var param_insts: std.ArrayListUnmanaged(Zir.Inst.Index) = try .initCapacity(astgen.arena, fn_proto.ast.params.len);
4174
4185 var noalias_bits: u32 = 0;4175 var noalias_bits: u32 = 0;
4186 var params_scope = &fn_gz.base;4176 var params_scope = &fn_gz.base;
4187 const is_var_args = is_var_args: {4177 const is_var_args = is_var_args: {
...@@ -4266,7 +4256,7 @@ fn fnDecl(...@@ -4266,7 +4256,7 @@ fn fnDecl(
4266 const main_tokens = tree.nodes.items(.main_token);4256 const main_tokens = tree.nodes.items(.main_token);
4267 const name_token = param.name_token orelse main_tokens[param_type_node];4257 const name_token = param.name_token orelse main_tokens[param_type_node];
4268 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;4258 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
4269 const param_inst = try decl_gz.addParam(&param_gz, tag, name_token, param_name, param.first_doc_comment);4259 const param_inst = try decl_gz.addParam(&param_gz, param_insts.items, tag, name_token, param_name, param.first_doc_comment);
4270 assert(param_inst_expected == param_inst);4260 assert(param_inst_expected == param_inst);
4271 break :param param_inst.toRef();4261 break :param param_inst.toRef();
4272 };4262 };
...@@ -4283,6 +4273,7 @@ fn fnDecl(...@@ -4283,6 +4273,7 @@ fn fnDecl(
4283 .id_cat = .@"function parameter",4273 .id_cat = .@"function parameter",
4284 };4274 };
4285 params_scope = &sub_scope.base;4275 params_scope = &sub_scope.base;
4276 try param_insts.append(astgen.arena, param_inst.toIndex().?);
4286 }4277 }
4287 break :is_var_args false;4278 break :is_var_args false;
4288 };4279 };
...@@ -4316,6 +4307,7 @@ fn fnDecl(...@@ -4316,6 +4307,7 @@ fn fnDecl(
4316 _ = try align_gz.addBreak(.break_inline, @enumFromInt(0), inst);4307 _ = try align_gz.addBreak(.break_inline, @enumFromInt(0), inst);
4317 break :inst inst;4308 break :inst inst;
4318 };4309 };
4310 const align_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43194311
4320 var addrspace_gz = decl_gz.makeSubBlock(params_scope);4312 var addrspace_gz = decl_gz.makeSubBlock(params_scope);
4321 defer addrspace_gz.unstack();4313 defer addrspace_gz.unstack();
...@@ -4329,6 +4321,7 @@ fn fnDecl(...@@ -4329,6 +4321,7 @@ fn fnDecl(
4329 _ = try addrspace_gz.addBreak(.break_inline, @enumFromInt(0), inst);4321 _ = try addrspace_gz.addBreak(.break_inline, @enumFromInt(0), inst);
4330 break :inst inst;4322 break :inst inst;
4331 };4323 };
4324 const addrspace_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43324325
4333 var section_gz = decl_gz.makeSubBlock(params_scope);4326 var section_gz = decl_gz.makeSubBlock(params_scope);
4334 defer section_gz.unstack();4327 defer section_gz.unstack();
...@@ -4341,6 +4334,7 @@ fn fnDecl(...@@ -4341,6 +4334,7 @@ fn fnDecl(
4341 _ = try section_gz.addBreak(.break_inline, @enumFromInt(0), inst);4334 _ = try section_gz.addBreak(.break_inline, @enumFromInt(0), inst);
4342 break :inst inst;4335 break :inst inst;
4343 };4336 };
4337 const section_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43444338
4345 var cc_gz = decl_gz.makeSubBlock(params_scope);4339 var cc_gz = decl_gz.makeSubBlock(params_scope);
4346 defer cc_gz.unstack();4340 defer cc_gz.unstack();
...@@ -4377,6 +4371,7 @@ fn fnDecl(...@@ -4377,6 +4371,7 @@ fn fnDecl(
4377 break :blk .none;4371 break :blk .none;
4378 }4372 }
4379 };4373 };
4374 const cc_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43804375
4381 var ret_gz = decl_gz.makeSubBlock(params_scope);4376 var ret_gz = decl_gz.makeSubBlock(params_scope);
4382 defer ret_gz.unstack();4377 defer ret_gz.unstack();
...@@ -4389,6 +4384,7 @@ fn fnDecl(...@@ -4389,6 +4384,7 @@ fn fnDecl(
4389 _ = try ret_gz.addBreak(.break_inline, @enumFromInt(0), inst);4384 _ = try ret_gz.addBreak(.break_inline, @enumFromInt(0), inst);
4390 break :inst inst;4385 break :inst inst;
4391 };4386 };
4387 const ret_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43924388
4393 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {4389 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
4394 if (!is_extern) {4390 if (!is_extern) {
...@@ -4401,15 +4397,21 @@ fn fnDecl(...@@ -4401,15 +4397,21 @@ fn fnDecl(
4401 .src_node = decl_node,4397 .src_node = decl_node,
4402 .cc_ref = cc_ref,4398 .cc_ref = cc_ref,
4403 .cc_gz = &cc_gz,4399 .cc_gz = &cc_gz,
4400 .cc_param_refs = cc_body_param_refs,
4404 .align_ref = align_ref,4401 .align_ref = align_ref,
4405 .align_gz = &align_gz,4402 .align_gz = &align_gz,
4403 .align_param_refs = align_body_param_refs,
4406 .ret_ref = ret_ref,4404 .ret_ref = ret_ref,
4407 .ret_gz = &ret_gz,4405 .ret_gz = &ret_gz,
4406 .ret_param_refs = ret_body_param_refs,
4408 .section_ref = section_ref,4407 .section_ref = section_ref,
4409 .section_gz = &section_gz,4408 .section_gz = &section_gz,
4409 .section_param_refs = section_body_param_refs,
4410 .addrspace_ref = addrspace_ref,4410 .addrspace_ref = addrspace_ref,
4411 .addrspace_gz = &addrspace_gz,4411 .addrspace_gz = &addrspace_gz,
4412 .addrspace_param_refs = addrspace_body_param_refs,
4412 .param_block = decl_inst,4413 .param_block = decl_inst,
4414 .param_insts = param_insts.items,
4413 .body_gz = null,4415 .body_gz = null,
4414 .lib_name = lib_name,4416 .lib_name = lib_name,
4415 .is_var_args = is_var_args,4417 .is_var_args = is_var_args,
...@@ -4471,17 +4473,23 @@ fn fnDecl(...@@ -4471,17 +4473,23 @@ fn fnDecl(
4471 .src_node = decl_node,4473 .src_node = decl_node,
4472 .cc_ref = cc_ref,4474 .cc_ref = cc_ref,
4473 .cc_gz = &cc_gz,4475 .cc_gz = &cc_gz,
4476 .cc_param_refs = cc_body_param_refs,
4474 .align_ref = align_ref,4477 .align_ref = align_ref,
4475 .align_gz = &align_gz,4478 .align_gz = &align_gz,
4479 .align_param_refs = align_body_param_refs,
4476 .ret_ref = ret_ref,4480 .ret_ref = ret_ref,
4477 .ret_gz = &ret_gz,4481 .ret_gz = &ret_gz,
4482 .ret_param_refs = ret_body_param_refs,
4478 .section_ref = section_ref,4483 .section_ref = section_ref,
4479 .section_gz = &section_gz,4484 .section_gz = &section_gz,
4485 .section_param_refs = section_body_param_refs,
4480 .addrspace_ref = addrspace_ref,4486 .addrspace_ref = addrspace_ref,
4481 .addrspace_gz = &addrspace_gz,4487 .addrspace_gz = &addrspace_gz,
4488 .addrspace_param_refs = addrspace_body_param_refs,
4482 .lbrace_line = lbrace_line,4489 .lbrace_line = lbrace_line,
4483 .lbrace_column = lbrace_column,4490 .lbrace_column = lbrace_column,
4484 .param_block = decl_inst,4491 .param_block = decl_inst,
4492 .param_insts = param_insts.items,
4485 .body_gz = &fn_gz,4493 .body_gz = &fn_gz,
4486 .lib_name = lib_name,4494 .lib_name = lib_name,
4487 .is_var_args = is_var_args,4495 .is_var_args = is_var_args,
...@@ -4972,6 +4980,13 @@ fn testDecl(...@@ -4972,6 +4980,13 @@ fn testDecl(
4972 .addrspace_ref = .none,4980 .addrspace_ref = .none,
4973 .addrspace_gz = null,4981 .addrspace_gz = null,
49744982
4983 .align_param_refs = &.{},
4984 .addrspace_param_refs = &.{},
4985 .section_param_refs = &.{},
4986 .cc_param_refs = &.{},
4987 .ret_param_refs = &.{},
4988 .param_insts = &.{},
4989
4975 .lbrace_line = lbrace_line,4990 .lbrace_line = lbrace_line,
4976 .lbrace_column = lbrace_column,4991 .lbrace_column = lbrace_column,
4977 .param_block = decl_inst,4992 .param_block = decl_inst,
...@@ -7429,19 +7444,7 @@ fn switchExprErrUnion(...@@ -7429,19 +7444,7 @@ fn switchExprErrUnion(
7429 }7444 }
74307445
7431 const case_slice = case_scope.instructionsSlice();7446 const case_slice = case_scope.instructionsSlice();
7432 // Since we use the switch_block_err_union instruction itself to refer7447 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(case_slice, &.{switch_block});
7433 // to the capture, which will not be added to the child block, we need
7434 // to handle ref_table manually.
7435 const refs_len = refs: {
7436 var n: usize = 0;
7437 var check_inst = switch_block;
7438 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7439 n += 1;
7440 check_inst = ref_inst;
7441 }
7442 break :refs n;
7443 };
7444 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
7445 try payloads.ensureUnusedCapacity(gpa, body_len);7448 try payloads.ensureUnusedCapacity(gpa, body_len);
7446 const capture: Zir.Inst.SwitchBlock.ProngInfo.Capture = switch (node_ty) {7449 const capture: Zir.Inst.SwitchBlock.ProngInfo.Capture = switch (node_ty) {
7447 .@"catch" => .none,7450 .@"catch" => .none,
...@@ -7458,10 +7461,7 @@ fn switchExprErrUnion(...@@ -7458,10 +7461,7 @@ fn switchExprErrUnion(
7458 .is_inline = false,7461 .is_inline = false,
7459 .has_tag_capture = false,7462 .has_tag_capture = false,
7460 });7463 });
7461 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {7464 appendBodyWithFixupsExtraRefsArrayList(astgen, payloads, case_slice, &.{switch_block});
7462 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7463 }
7464 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
7465 }7465 }
74667466
7467 const err_name = blk: {7467 const err_name = blk: {
...@@ -7624,26 +7624,8 @@ fn switchExprErrUnion(...@@ -7624,26 +7624,8 @@ fn switchExprErrUnion(
7624 }7624 }
76257625
7626 const case_slice = case_scope.instructionsSlice();7626 const case_slice = case_scope.instructionsSlice();
7627 // Since we use the switch_block_err_union instruction itself to refer7627 const extra_insts: []const Zir.Inst.Index = if (uses_err) &.{ switch_block, err_inst } else &.{switch_block};
7628 // to the capture, which will not be added to the child block, we need7628 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(case_slice, extra_insts);
7629 // to handle ref_table manually.
7630 const refs_len = refs: {
7631 var n: usize = 0;
7632 var check_inst = switch_block;
7633 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7634 n += 1;
7635 check_inst = ref_inst;
7636 }
7637 if (uses_err) {
7638 check_inst = err_inst;
7639 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7640 n += 1;
7641 check_inst = ref_inst;
7642 }
7643 }
7644 break :refs n;
7645 };
7646 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
7647 try payloads.ensureUnusedCapacity(gpa, body_len);7629 try payloads.ensureUnusedCapacity(gpa, body_len);
7648 payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{7630 payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{
7649 .body_len = @intCast(body_len),7631 .body_len = @intCast(body_len),
...@@ -7651,15 +7633,7 @@ fn switchExprErrUnion(...@@ -7651,15 +7633,7 @@ fn switchExprErrUnion(
7651 .is_inline = case.inline_token != null,7633 .is_inline = case.inline_token != null,
7652 .has_tag_capture = false,7634 .has_tag_capture = false,
7653 });7635 });
7654 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {7636 appendBodyWithFixupsExtraRefsArrayList(astgen, payloads, case_slice, extra_insts);
7655 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7656 }
7657 if (uses_err) {
7658 if (astgen.ref_table.fetchRemove(err_inst)) |kv| {
7659 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7660 }
7661 }
7662 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
7663 }7637 }
7664 }7638 }
7665 // Now that the item expressions are generated we can add this.7639 // Now that the item expressions are generated we can add this.
...@@ -8106,27 +8080,8 @@ fn switchExpr(...@@ -8106,27 +8080,8 @@ fn switchExpr(
8106 }8080 }
81078081
8108 const case_slice = case_scope.instructionsSlice();8082 const case_slice = case_scope.instructionsSlice();
8109 // Since we use the switch_block instruction itself to refer to the8083 const extra_insts: []const Zir.Inst.Index = if (has_tag_capture) &.{ switch_block, tag_inst } else &.{switch_block};
8110 // capture, which will not be added to the child block, we need to8084 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(case_slice, extra_insts);
8111 // handle ref_table manually, and the same for the inline tag
8112 // capture instruction.
8113 const refs_len = refs: {
8114 var n: usize = 0;
8115 var check_inst = switch_block;
8116 while (astgen.ref_table.get(check_inst)) |ref_inst| {
8117 n += 1;
8118 check_inst = ref_inst;
8119 }
8120 if (has_tag_capture) {
8121 check_inst = tag_inst;
8122 while (astgen.ref_table.get(check_inst)) |ref_inst| {
8123 n += 1;
8124 check_inst = ref_inst;
8125 }
8126 }
8127 break :refs n;
8128 };
8129 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
8130 try payloads.ensureUnusedCapacity(gpa, body_len);8085 try payloads.ensureUnusedCapacity(gpa, body_len);
8131 payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{8086 payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{
8132 .body_len = @intCast(body_len),8087 .body_len = @intCast(body_len),
...@@ -8134,15 +8089,7 @@ fn switchExpr(...@@ -8134,15 +8089,7 @@ fn switchExpr(
8134 .is_inline = case.inline_token != null,8089 .is_inline = case.inline_token != null,
8135 .has_tag_capture = has_tag_capture,8090 .has_tag_capture = has_tag_capture,
8136 });8091 });
8137 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {8092 appendBodyWithFixupsExtraRefsArrayList(astgen, payloads, case_slice, extra_insts);
8138 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
8139 }
8140 if (has_tag_capture) {
8141 if (astgen.ref_table.fetchRemove(tag_inst)) |kv| {
8142 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
8143 }
8144 }
8145 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
8146 }8093 }
8147 }8094 }
81488095
...@@ -11201,9 +11148,6 @@ fn rvalueInner(...@@ -11201,9 +11148,6 @@ fn rvalueInner(
11201 const src_token = tree.firstToken(src_node);11148 const src_token = tree.firstToken(src_node);
11202 const result_index = coerced_result.toIndex() orelse11149 const result_index = coerced_result.toIndex() orelse
11203 return gz.addUnTok(.ref, coerced_result, src_token);11150 return gz.addUnTok(.ref, coerced_result, src_token);
11204 const zir_tags = gz.astgen.instructions.items(.tag);
11205 if (zir_tags[@intFromEnum(result_index)].isParam() or astgen.isInferred(coerced_result))
11206 return gz.addUnTok(.ref, coerced_result, src_token);
11207 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);11151 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);
11208 if (!gop.found_existing) {11152 if (!gop.found_existing) {
11209 gop.value_ptr.* = try gz.makeUnTok(.ref, coerced_result, src_token);11153 gop.value_ptr.* = try gz.makeUnTok(.ref, coerced_result, src_token);
...@@ -12232,36 +12176,46 @@ const GenZir = struct {...@@ -12232,36 +12176,46 @@ const GenZir = struct {
12232 /// * ret_gz12176 /// * ret_gz
12233 /// * body_gz (top)12177 /// * body_gz (top)
12234 /// Unstacks all of those except for `gz`.12178 /// Unstacks all of those except for `gz`.
12235 fn addFunc(gz: *GenZir, args: struct {12179 fn addFunc(
12236 src_node: Ast.Node.Index,12180 gz: *GenZir,
12237 lbrace_line: u32 = 0,12181 args: struct {
12238 lbrace_column: u32 = 0,12182 src_node: Ast.Node.Index,
12239 param_block: Zir.Inst.Index,12183 lbrace_line: u32 = 0,
1224012184 lbrace_column: u32 = 0,
12241 align_gz: ?*GenZir,12185 param_block: Zir.Inst.Index,
12242 addrspace_gz: ?*GenZir,12186
12243 section_gz: ?*GenZir,12187 align_gz: ?*GenZir,
12244 cc_gz: ?*GenZir,12188 addrspace_gz: ?*GenZir,
12245 ret_gz: ?*GenZir,12189 section_gz: ?*GenZir,
12246 body_gz: ?*GenZir,12190 cc_gz: ?*GenZir,
1224712191 ret_gz: ?*GenZir,
12248 align_ref: Zir.Inst.Ref,12192 body_gz: ?*GenZir,
12249 addrspace_ref: Zir.Inst.Ref,12193
12250 section_ref: Zir.Inst.Ref,12194 align_param_refs: []Zir.Inst.Index,
12251 cc_ref: Zir.Inst.Ref,12195 addrspace_param_refs: []Zir.Inst.Index,
12252 ret_ref: Zir.Inst.Ref,12196 section_param_refs: []Zir.Inst.Index,
1225312197 cc_param_refs: []Zir.Inst.Index,
12254 lib_name: Zir.NullTerminatedString,12198 ret_param_refs: []Zir.Inst.Index,
12255 noalias_bits: u32,12199 param_insts: []Zir.Inst.Index, // refs to params in `body_gz` should still be in `astgen.ref_table`
12256 is_var_args: bool,12200
12257 is_inferred_error: bool,12201 align_ref: Zir.Inst.Ref,
12258 is_test: bool,12202 addrspace_ref: Zir.Inst.Ref,
12259 is_extern: bool,12203 section_ref: Zir.Inst.Ref,
12260 is_noinline: bool,12204 cc_ref: Zir.Inst.Ref,
1226112205 ret_ref: Zir.Inst.Ref,
12262 /// Ignored if `body_gz == null`.12206
12263 proto_hash: std.zig.SrcHash,12207 lib_name: Zir.NullTerminatedString,
12264 }) !Zir.Inst.Ref {12208 noalias_bits: u32,
12209 is_var_args: bool,
12210 is_inferred_error: bool,
12211 is_test: bool,
12212 is_extern: bool,
12213 is_noinline: bool,
12214
12215 /// Ignored if `body_gz == null`.
12216 proto_hash: std.zig.SrcHash,
12217 },
12218 ) !Zir.Inst.Ref {
12265 assert(args.src_node != 0);12219 assert(args.src_node != 0);
12266 const astgen = gz.astgen;12220 const astgen = gz.astgen;
12267 const gpa = astgen.gpa;12221 const gpa = astgen.gpa;
...@@ -12309,7 +12263,7 @@ const GenZir = struct {...@@ -12309,7 +12263,7 @@ const GenZir = struct {
12309 if (args.ret_gz) |ret_gz|12263 if (args.ret_gz) |ret_gz|
12310 ret_body = ret_gz.instructionsSlice();12264 ret_body = ret_gz.instructionsSlice();
12311 }12265 }
12312 const body_len = astgen.countBodyLenAfterFixups(body);12266 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(body, args.param_insts);
1231312267
12314 if (args.cc_ref != .none or args.lib_name != .empty or args.is_var_args or args.is_test or12268 if (args.cc_ref != .none or args.lib_name != .empty or args.is_var_args or args.is_test or
12315 args.is_extern or args.align_ref != .none or args.section_ref != .none or12269 args.is_extern or args.align_ref != .none or args.section_ref != .none or
...@@ -12329,11 +12283,11 @@ const GenZir = struct {...@@ -12329,11 +12283,11 @@ const GenZir = struct {
12329 try astgen.extra.ensureUnusedCapacity(12283 try astgen.extra.ensureUnusedCapacity(
12330 gpa,12284 gpa,
12331 @typeInfo(Zir.Inst.FuncFancy).@"struct".fields.len +12285 @typeInfo(Zir.Inst.FuncFancy).@"struct".fields.len +
12332 fancyFnExprExtraLen(astgen, align_body, args.align_ref) +12286 fancyFnExprExtraLen(astgen, args.align_param_refs, align_body, args.align_ref) +
12333 fancyFnExprExtraLen(astgen, addrspace_body, args.addrspace_ref) +12287 fancyFnExprExtraLen(astgen, args.addrspace_param_refs, addrspace_body, args.addrspace_ref) +
12334 fancyFnExprExtraLen(astgen, section_body, args.section_ref) +12288 fancyFnExprExtraLen(astgen, args.section_param_refs, section_body, args.section_ref) +
12335 fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) +12289 fancyFnExprExtraLen(astgen, args.cc_param_refs, cc_body, args.cc_ref) +
12336 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +12290 fancyFnExprExtraLen(astgen, args.ret_param_refs, ret_body, ret_ref) +
12337 body_len + src_locs_and_hash.len +12291 body_len + src_locs_and_hash.len +
12338 @intFromBool(args.lib_name != .empty) +12292 @intFromBool(args.lib_name != .empty) +
12339 @intFromBool(args.noalias_bits != 0),12293 @intFromBool(args.noalias_bits != 0),
...@@ -12369,7 +12323,11 @@ const GenZir = struct {...@@ -12369,7 +12323,11 @@ const GenZir = struct {
1236912323
12370 const zir_datas = astgen.instructions.items(.data);12324 const zir_datas = astgen.instructions.items(.data);
12371 if (align_body.len != 0) {12325 if (align_body.len != 0) {
12372 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, align_body));12326 astgen.extra.appendAssumeCapacity(
12327 astgen.countBodyLenAfterFixups(args.align_param_refs) +
12328 astgen.countBodyLenAfterFixups(align_body),
12329 );
12330 astgen.appendBodyWithFixups(args.align_param_refs);
12373 astgen.appendBodyWithFixups(align_body);12331 astgen.appendBodyWithFixups(align_body);
12374 const break_extra = zir_datas[@intFromEnum(align_body[align_body.len - 1])].@"break".payload_index;12332 const break_extra = zir_datas[@intFromEnum(align_body[align_body.len - 1])].@"break".payload_index;
12375 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =12333 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
...@@ -12378,7 +12336,11 @@ const GenZir = struct {...@@ -12378,7 +12336,11 @@ const GenZir = struct {
12378 astgen.extra.appendAssumeCapacity(@intFromEnum(args.align_ref));12336 astgen.extra.appendAssumeCapacity(@intFromEnum(args.align_ref));
12379 }12337 }
12380 if (addrspace_body.len != 0) {12338 if (addrspace_body.len != 0) {
12381 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, addrspace_body));12339 astgen.extra.appendAssumeCapacity(
12340 astgen.countBodyLenAfterFixups(args.addrspace_param_refs) +
12341 astgen.countBodyLenAfterFixups(addrspace_body),
12342 );
12343 astgen.appendBodyWithFixups(args.addrspace_param_refs);
12382 astgen.appendBodyWithFixups(addrspace_body);12344 astgen.appendBodyWithFixups(addrspace_body);
12383 const break_extra =12345 const break_extra =
12384 zir_datas[@intFromEnum(addrspace_body[addrspace_body.len - 1])].@"break".payload_index;12346 zir_datas[@intFromEnum(addrspace_body[addrspace_body.len - 1])].@"break".payload_index;
...@@ -12388,7 +12350,11 @@ const GenZir = struct {...@@ -12388,7 +12350,11 @@ const GenZir = struct {
12388 astgen.extra.appendAssumeCapacity(@intFromEnum(args.addrspace_ref));12350 astgen.extra.appendAssumeCapacity(@intFromEnum(args.addrspace_ref));
12389 }12351 }
12390 if (section_body.len != 0) {12352 if (section_body.len != 0) {
12391 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, section_body));12353 astgen.extra.appendAssumeCapacity(
12354 astgen.countBodyLenAfterFixups(args.section_param_refs) +
12355 astgen.countBodyLenAfterFixups(section_body),
12356 );
12357 astgen.appendBodyWithFixups(args.section_param_refs);
12392 astgen.appendBodyWithFixups(section_body);12358 astgen.appendBodyWithFixups(section_body);
12393 const break_extra =12359 const break_extra =
12394 zir_datas[@intFromEnum(section_body[section_body.len - 1])].@"break".payload_index;12360 zir_datas[@intFromEnum(section_body[section_body.len - 1])].@"break".payload_index;
...@@ -12398,7 +12364,11 @@ const GenZir = struct {...@@ -12398,7 +12364,11 @@ const GenZir = struct {
12398 astgen.extra.appendAssumeCapacity(@intFromEnum(args.section_ref));12364 astgen.extra.appendAssumeCapacity(@intFromEnum(args.section_ref));
12399 }12365 }
12400 if (cc_body.len != 0) {12366 if (cc_body.len != 0) {
12401 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, cc_body));12367 astgen.extra.appendAssumeCapacity(
12368 astgen.countBodyLenAfterFixups(args.cc_param_refs) +
12369 astgen.countBodyLenAfterFixups(cc_body),
12370 );
12371 astgen.appendBodyWithFixups(args.cc_param_refs);
12402 astgen.appendBodyWithFixups(cc_body);12372 astgen.appendBodyWithFixups(cc_body);
12403 const break_extra = zir_datas[@intFromEnum(cc_body[cc_body.len - 1])].@"break".payload_index;12373 const break_extra = zir_datas[@intFromEnum(cc_body[cc_body.len - 1])].@"break".payload_index;
12404 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =12374 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
...@@ -12407,7 +12377,11 @@ const GenZir = struct {...@@ -12407,7 +12377,11 @@ const GenZir = struct {
12407 astgen.extra.appendAssumeCapacity(@intFromEnum(args.cc_ref));12377 astgen.extra.appendAssumeCapacity(@intFromEnum(args.cc_ref));
12408 }12378 }
12409 if (ret_body.len != 0) {12379 if (ret_body.len != 0) {
12410 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, ret_body));12380 astgen.extra.appendAssumeCapacity(
12381 astgen.countBodyLenAfterFixups(args.ret_param_refs) +
12382 astgen.countBodyLenAfterFixups(ret_body),
12383 );
12384 astgen.appendBodyWithFixups(args.ret_param_refs);
12411 astgen.appendBodyWithFixups(ret_body);12385 astgen.appendBodyWithFixups(ret_body);
12412 const break_extra = zir_datas[@intFromEnum(ret_body[ret_body.len - 1])].@"break".payload_index;12386 const break_extra = zir_datas[@intFromEnum(ret_body[ret_body.len - 1])].@"break".payload_index;
12413 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =12387 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
...@@ -12420,7 +12394,7 @@ const GenZir = struct {...@@ -12420,7 +12394,7 @@ const GenZir = struct {
12420 astgen.extra.appendAssumeCapacity(args.noalias_bits);12394 astgen.extra.appendAssumeCapacity(args.noalias_bits);
12421 }12395 }
1242212396
12423 astgen.appendBodyWithFixups(body);12397 astgen.appendBodyWithFixupsExtraRefsArrayList(&astgen.extra, body, args.param_insts);
12424 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);12398 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1242512399
12426 // Order is important when unstacking.12400 // Order is important when unstacking.
...@@ -12448,12 +12422,12 @@ const GenZir = struct {...@@ -12448,12 +12422,12 @@ const GenZir = struct {
12448 try astgen.extra.ensureUnusedCapacity(12422 try astgen.extra.ensureUnusedCapacity(
12449 gpa,12423 gpa,
12450 @typeInfo(Zir.Inst.Func).@"struct".fields.len + 1 +12424 @typeInfo(Zir.Inst.Func).@"struct".fields.len + 1 +
12451 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +12425 fancyFnExprExtraLen(astgen, args.ret_param_refs, ret_body, ret_ref) +
12452 body_len + src_locs_and_hash.len,12426 body_len + src_locs_and_hash.len,
12453 );12427 );
1245412428
12455 const ret_body_len = if (ret_body.len != 0)12429 const ret_body_len = if (ret_body.len != 0)
12456 countBodyLenAfterFixups(astgen, ret_body)12430 countBodyLenAfterFixups(astgen, args.ret_param_refs) + countBodyLenAfterFixups(astgen, ret_body)
12457 else12431 else
12458 @intFromBool(ret_ref != .none);12432 @intFromBool(ret_ref != .none);
1245912433
...@@ -12464,6 +12438,7 @@ const GenZir = struct {...@@ -12464,6 +12438,7 @@ const GenZir = struct {
12464 });12438 });
12465 const zir_datas = astgen.instructions.items(.data);12439 const zir_datas = astgen.instructions.items(.data);
12466 if (ret_body.len != 0) {12440 if (ret_body.len != 0) {
12441 astgen.appendBodyWithFixups(args.ret_param_refs);
12467 astgen.appendBodyWithFixups(ret_body);12442 astgen.appendBodyWithFixups(ret_body);
1246812443
12469 const break_extra = zir_datas[@intFromEnum(ret_body[ret_body.len - 1])].@"break".payload_index;12444 const break_extra = zir_datas[@intFromEnum(ret_body[ret_body.len - 1])].@"break".payload_index;
...@@ -12472,7 +12447,7 @@ const GenZir = struct {...@@ -12472,7 +12447,7 @@ const GenZir = struct {
12472 } else if (ret_ref != .none) {12447 } else if (ret_ref != .none) {
12473 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));12448 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));
12474 }12449 }
12475 astgen.appendBodyWithFixups(body);12450 astgen.appendBodyWithFixupsExtraRefsArrayList(&astgen.extra, body, args.param_insts);
12476 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);12451 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1247712452
12478 // Order is important when unstacking.12453 // Order is important when unstacking.
...@@ -12498,10 +12473,11 @@ const GenZir = struct {...@@ -12498,10 +12473,11 @@ const GenZir = struct {
12498 }12473 }
12499 }12474 }
1250012475
12501 fn fancyFnExprExtraLen(astgen: *AstGen, body: []Zir.Inst.Index, ref: Zir.Inst.Ref) u32 {12476 fn fancyFnExprExtraLen(astgen: *AstGen, param_refs_body: []Zir.Inst.Index, main_body: []Zir.Inst.Index, ref: Zir.Inst.Ref) u32 {
12502 // In the case of non-empty body, there is one for the body length,12477 return countBodyLenAfterFixups(astgen, param_refs_body) +
12503 // and then one for each instruction.12478 countBodyLenAfterFixups(astgen, main_body) +
12504 return countBodyLenAfterFixups(astgen, body) + @intFromBool(ref != .none);12479 // If there is a body, we need an element for its length; otherwise, if there is a ref, we need to include that.
12480 @intFromBool(main_body.len > 0 or ref != .none);
12505 }12481 }
1250612482
12507 fn addVar(gz: *GenZir, args: struct {12483 fn addVar(gz: *GenZir, args: struct {
...@@ -12673,6 +12649,9 @@ const GenZir = struct {...@@ -12673,6 +12649,9 @@ const GenZir = struct {
12673 fn addParam(12649 fn addParam(
12674 gz: *GenZir,12650 gz: *GenZir,
12675 param_gz: *GenZir,12651 param_gz: *GenZir,
12652 /// Previous parameters, which might be referenced in `param_gz` (the new parameter type).
12653 /// `ref`s of these instructions will be put into this param's type body, and removed from `AstGen.ref_table`.
12654 prev_param_insts: []const Zir.Inst.Index,
12676 tag: Zir.Inst.Tag,12655 tag: Zir.Inst.Tag,
12677 /// Absolute token index. This function does the conversion to Decl offset.12656 /// Absolute token index. This function does the conversion to Decl offset.
12678 abs_tok_index: Ast.TokenIndex,12657 abs_tok_index: Ast.TokenIndex,
...@@ -12681,7 +12660,7 @@ const GenZir = struct {...@@ -12681,7 +12660,7 @@ const GenZir = struct {
12681 ) !Zir.Inst.Index {12660 ) !Zir.Inst.Index {
12682 const gpa = gz.astgen.gpa;12661 const gpa = gz.astgen.gpa;
12683 const param_body = param_gz.instructionsSlice();12662 const param_body = param_gz.instructionsSlice();
12684 const body_len = gz.astgen.countBodyLenAfterFixups(param_body);12663 const body_len = gz.astgen.countBodyLenAfterFixupsExtraRefs(param_body, prev_param_insts);
12685 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);12664 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
12686 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).@"struct".fields.len + body_len);12665 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).@"struct".fields.len + body_len);
1268712666
...@@ -12695,7 +12674,7 @@ const GenZir = struct {...@@ -12695,7 +12674,7 @@ const GenZir = struct {
12695 .doc_comment = doc_comment_index,12674 .doc_comment = doc_comment_index,
12696 .body_len = @intCast(body_len),12675 .body_len = @intCast(body_len),
12697 });12676 });
12698 gz.astgen.appendBodyWithFixups(param_body);12677 gz.astgen.appendBodyWithFixupsExtraRefsArrayList(&gz.astgen.extra, param_body, prev_param_insts);
12699 param_gz.unstack();12678 param_gz.unstack();
1270012679
12701 const new_index: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);12680 const new_index: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
...@@ -13938,27 +13917,6 @@ fn scanContainer(...@@ -13938,27 +13917,6 @@ fn scanContainer(
13938 return decl_count;13917 return decl_count;
13939}13918}
1394013919
13941fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool {
13942 const inst = ref.toIndex() orelse return false;
13943 const zir_tags = astgen.instructions.items(.tag);
13944 return switch (zir_tags[@intFromEnum(inst)]) {
13945 .alloc_inferred,
13946 .alloc_inferred_mut,
13947 .alloc_inferred_comptime,
13948 .alloc_inferred_comptime_mut,
13949 => true,
13950
13951 .extended => {
13952 const zir_data = astgen.instructions.items(.data);
13953 if (zir_data[@intFromEnum(inst)].extended.opcode != .alloc) return false;
13954 const small: Zir.Inst.AllocExtended.Small = @bitCast(zir_data[@intFromEnum(inst)].extended.small);
13955 return !small.has_type;
13956 },
13957
13958 else => false,
13959 };
13960}
13961
13962/// Assumes capacity for body has already been added. Needed capacity taking into13920/// Assumes capacity for body has already been added. Needed capacity taking into
13963/// account fixups can be found with `countBodyLenAfterFixups`.13921/// account fixups can be found with `countBodyLenAfterFixups`.
13964fn appendBodyWithFixups(astgen: *AstGen, body: []const Zir.Inst.Index) void {13922fn appendBodyWithFixups(astgen: *AstGen, body: []const Zir.Inst.Index) void {
...@@ -13970,6 +13928,20 @@ fn appendBodyWithFixupsArrayList(...@@ -13970,6 +13928,20 @@ fn appendBodyWithFixupsArrayList(
13970 list: *std.ArrayListUnmanaged(u32),13928 list: *std.ArrayListUnmanaged(u32),
13971 body: []const Zir.Inst.Index,13929 body: []const Zir.Inst.Index,
13972) void {13930) void {
13931 astgen.appendBodyWithFixupsExtraRefsArrayList(list, body, &.{});
13932}
13933
13934fn appendBodyWithFixupsExtraRefsArrayList(
13935 astgen: *AstGen,
13936 list: *std.ArrayListUnmanaged(u32),
13937 body: []const Zir.Inst.Index,
13938 extra_refs: []const Zir.Inst.Index,
13939) void {
13940 for (extra_refs) |extra_inst| {
13941 if (astgen.ref_table.fetchRemove(extra_inst)) |kv| {
13942 appendPossiblyRefdBodyInst(astgen, list, kv.value);
13943 }
13944 }
13973 for (body) |body_inst| {13945 for (body) |body_inst| {
13974 appendPossiblyRefdBodyInst(astgen, list, body_inst);13946 appendPossiblyRefdBodyInst(astgen, list, body_inst);
13975 }13947 }
...@@ -13987,6 +13959,14 @@ fn appendPossiblyRefdBodyInst(...@@ -13987,6 +13959,14 @@ fn appendPossiblyRefdBodyInst(
13987}13959}
1398813960
13989fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {13961fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
13962 return astgen.countBodyLenAfterFixupsExtraRefs(body, &.{});
13963}
13964
13965/// Return the number of instructions in `body` after prepending the `ref` instructions in `ref_table`.
13966/// As well as all instructions in `body`, we also prepend `ref`s of any instruction in `extra_refs`.
13967/// For instance, if an index has been reserved with a special meaning to a child block, it must be
13968/// passed to `extra_refs` to ensure `ref`s of that index are added correctly.
13969fn countBodyLenAfterFixupsExtraRefs(astgen: *AstGen, body: []const Zir.Inst.Index, extra_refs: []const Zir.Inst.Index) u32 {
13990 var count = body.len;13970 var count = body.len;
13991 for (body) |body_inst| {13971 for (body) |body_inst| {
13992 var check_inst = body_inst;13972 var check_inst = body_inst;
...@@ -13995,6 +13975,13 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {...@@ -13995,6 +13975,13 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
13995 check_inst = ref_inst;13975 check_inst = ref_inst;
13996 }13976 }
13997 }13977 }
13978 for (extra_refs) |extra_inst| {
13979 var check_inst = extra_inst;
13980 while (astgen.ref_table.get(check_inst)) |ref_inst| {
13981 count += 1;
13982 check_inst = ref_inst;
13983 }
13984 }
13998 return @intCast(count);13985 return @intCast(count);
13999}13986}
1400013987
...@@ -14176,3 +14163,23 @@ fn setDeclaration(...@@ -14176,3 +14163,23 @@ fn setDeclaration(
14176 }14163 }
14177 value_gz.unstack();14164 value_gz.unstack();
14178}14165}
14166
14167/// Given a list of instructions, returns a list of all instructions which are a `ref` of one of the originals,
14168/// from `astgen.ref_table`, non-recursively. The entries are removed from `astgen.ref_table`, and the returned
14169/// slice can then be treated as its own body, to append `ref` instructions to a body other than the one they
14170/// would normally exist in.
14171///
14172/// This is used when lowering functions. Very rarely, the callconv expression, align expression, etc may reference
14173/// function parameters via `&param`; in this case, we need to lower to a `ref` instruction in the callconv/align/etc
14174/// body, rather than in the declaration body. However, we don't append these bodies to `extra` until we've evaluated
14175/// *all* of the bodies into a big `GenZir` stack. Therefore, we use this function to pull out these per-body `ref`
14176/// instructions which must be emitted.
14177fn fetchRemoveRefEntries(astgen: *AstGen, param_insts: []const Zir.Inst.Index) ![]Zir.Inst.Index {
14178 var refs: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
14179 for (param_insts) |param_inst| {
14180 if (astgen.ref_table.fetchRemove(param_inst)) |kv| {
14181 try refs.append(astgen.arena, kv.value);
14182 }
14183 }
14184 return refs.items;
14185}
lib/std/zig/Zir.zig+3-13
...@@ -998,6 +998,8 @@ pub const Inst = struct {...@@ -998,6 +998,8 @@ pub const Inst = struct {
998 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.998 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
999 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which999 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
1000 /// is the allocation that needs to have its type inferred.1000 /// is the allocation that needs to have its type inferred.
1001 /// Results in the final resolved pointer. The `alloc_inferred[_comptime][_mut]`
1002 /// instruction should never be referred to after this instruction.
1001 /// Uses the `un_node` field. The AST node is the var decl.1003 /// Uses the `un_node` field. The AST node is the var decl.
1002 resolve_inferred_alloc,1004 resolve_inferred_alloc,
1003 /// Turns a pointer coming from an `alloc` or `Extended.alloc` into a constant1005 /// Turns a pointer coming from an `alloc` or `Extended.alloc` into a constant
...@@ -1301,18 +1303,6 @@ pub const Inst = struct {...@@ -1301,18 +1303,6 @@ pub const Inst = struct {
1301 };1303 };
1302 }1304 }
13031305
1304 pub fn isParam(tag: Tag) bool {
1305 return switch (tag) {
1306 .param,
1307 .param_comptime,
1308 .param_anytype,
1309 .param_anytype_comptime,
1310 => true,
1311
1312 else => false,
1313 };
1314 }
1315
1316 /// AstGen uses this to find out if `Ref.void_value` should be used in place1306 /// AstGen uses this to find out if `Ref.void_value` should be used in place
1317 /// of the result of a given instruction. This allows Sema to forego adding1307 /// of the result of a given instruction. This allows Sema to forego adding
1318 /// the instruction to the map after analysis.1308 /// the instruction to the map after analysis.
...@@ -1328,7 +1318,6 @@ pub const Inst = struct {...@@ -1328,7 +1318,6 @@ pub const Inst = struct {
1328 .atomic_store,1318 .atomic_store,
1329 .store_node,1319 .store_node,
1330 .store_to_inferred_ptr,1320 .store_to_inferred_ptr,
1331 .resolve_inferred_alloc,
1332 .validate_deref,1321 .validate_deref,
1333 .validate_destructure,1322 .validate_destructure,
1334 .@"export",1323 .@"export",
...@@ -1367,6 +1356,7 @@ pub const Inst = struct {...@@ -1367,6 +1356,7 @@ pub const Inst = struct {
1367 .alloc_inferred_mut,1356 .alloc_inferred_mut,
1368 .alloc_inferred_comptime,1357 .alloc_inferred_comptime,
1369 .alloc_inferred_comptime_mut,1358 .alloc_inferred_comptime_mut,
1359 .resolve_inferred_alloc,
1370 .make_ptr_const,1360 .make_ptr_const,
1371 .array_cat,1361 .array_cat,
1372 .array_mul,1362 .array_mul,
src/InternPool.zig+3-1
...@@ -314,7 +314,9 @@ pub fn rehashTrackedInsts(...@@ -314,7 +314,9 @@ pub fn rehashTrackedInsts(
314314
315 // We know how big each shard must be, so ensure we have the capacity we need.315 // We know how big each shard must be, so ensure we have the capacity we need.
316 for (ip.shards) |*shard| {316 for (ip.shards) |*shard| {
317 const want_capacity = std.math.ceilPowerOfTwo(u32, shard.mutate.tracked_inst_map.len * 5 / 3) catch unreachable;317 const want_capacity = if (shard.mutate.tracked_inst_map.len == 0) 0 else cap: {
318 break :cap std.math.ceilPowerOfTwo(u32, shard.mutate.tracked_inst_map.len * 5 / 3) catch unreachable;
319 };
318 const have_capacity = shard.shared.tracked_inst_map.header().capacity; // no acquire because we hold the mutex320 const have_capacity = shard.shared.tracked_inst_map.header().capacity; // no acquire because we hold the mutex
319 if (have_capacity >= want_capacity) {321 if (have_capacity >= want_capacity) {
320 @memset(shard.shared.tracked_inst_map.entries[0..have_capacity], .{ .value = .none, .hash = undefined });322 @memset(shard.shared.tracked_inst_map.entries[0..have_capacity], .{ .value = .none, .hash = undefined });
src/Sema.zig+24-22
...@@ -1051,6 +1051,7 @@ fn analyzeBodyInner(...@@ -1051,6 +1051,7 @@ fn analyzeBodyInner(
1051 .alloc_inferred_mut => try sema.zirAllocInferred(block, false),1051 .alloc_inferred_mut => try sema.zirAllocInferred(block, false),
1052 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(true),1052 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(true),
1053 .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(false),1053 .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(false),
1054 .resolve_inferred_alloc => try sema.zirResolveInferredAlloc(block, inst),
1054 .alloc_mut => try sema.zirAllocMut(block, inst),1055 .alloc_mut => try sema.zirAllocMut(block, inst),
1055 .alloc_comptime_mut => try sema.zirAllocComptime(block, inst),1056 .alloc_comptime_mut => try sema.zirAllocComptime(block, inst),
1056 .make_ptr_const => try sema.zirMakePtrConst(block, inst),1057 .make_ptr_const => try sema.zirMakePtrConst(block, inst),
...@@ -1418,11 +1419,6 @@ fn analyzeBodyInner(...@@ -1418,11 +1419,6 @@ fn analyzeBodyInner(
1418 i += 1;1419 i += 1;
1419 continue;1420 continue;
1420 },1421 },
1421 .resolve_inferred_alloc => {
1422 try sema.zirResolveInferredAlloc(block, inst);
1423 i += 1;
1424 continue;
1425 },
1426 .validate_struct_init_ty => {1422 .validate_struct_init_ty => {
1427 try sema.zirValidateStructInitTy(block, inst, false);1423 try sema.zirValidateStructInitTy(block, inst, false);
1428 i += 1;1424 i += 1;
...@@ -4158,7 +4154,7 @@ fn zirAllocInferred(...@@ -4158,7 +4154,7 @@ fn zirAllocInferred(
4158 return result_index.toRef();4154 return result_index.toRef();
4159}4155}
41604156
4161fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {4157fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4162 const tracy = trace(@src());4158 const tracy = trace(@src());
4163 defer tracy.end();4159 defer tracy.end();
41644160
...@@ -4175,7 +4171,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4175,7 +4171,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4175 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {4171 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {
4176 .inferred_alloc_comptime => {4172 .inferred_alloc_comptime => {
4177 // The work was already done for us by `Sema.storeToInferredAllocComptime`.4173 // The work was already done for us by `Sema.storeToInferredAllocComptime`.
4178 // All we need to do is remap the pointer.4174 // All we need to do is return the pointer.
4179 const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;4175 const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;
4180 const resolved_ptr = iac.ptr;4176 const resolved_ptr = iac.ptr;
41814177
...@@ -4200,8 +4196,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4200,8 +4196,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4200 }4196 }
4201 }4197 }
42024198
4203 // Remap the ZIR operand to the resolved pointer value4199 return Air.internedToRef(resolved_ptr);
4204 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(resolved_ptr));
4205 },4200 },
4206 .inferred_alloc => {4201 .inferred_alloc => {
4207 const ia1 = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc;4202 const ia1 = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc;
...@@ -4228,15 +4223,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4228,15 +4223,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4228 const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty);4223 const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty);
4229 const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty);4224 const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty);
42304225
4231 // Remap the ZIR operand to the resolved pointer value
4232 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(new_const_ptr.toIntern()));
4233
4234 // Unless the block is comptime, `alloc_inferred` always produces4226 // Unless the block is comptime, `alloc_inferred` always produces
4235 // a runtime constant. The final inferred type needs to be4227 // a runtime constant. The final inferred type needs to be
4236 // fully resolved so it can be lowered in codegen.4228 // fully resolved so it can be lowered in codegen.
4237 try final_elem_ty.resolveFully(pt);4229 try final_elem_ty.resolveFully(pt);
42384230
4239 return;4231 return Air.internedToRef(new_const_ptr.toIntern());
4240 }4232 }
42414233
4242 if (try final_elem_ty.comptimeOnlySema(pt)) {4234 if (try final_elem_ty.comptimeOnlySema(pt)) {
...@@ -4255,11 +4247,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4255,11 +4247,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4255 .data = .{ .ty = final_ptr_ty },4247 .data = .{ .ty = final_ptr_ty },
4256 });4248 });
42574249
4258 if (ia1.is_const) {
4259 // Remap the ZIR operand to the pointer const
4260 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, try sema.makePtrConst(block, ptr));
4261 }
4262
4263 // Now we need to go back over all the store instructions, and do the logic as if4250 // Now we need to go back over all the store instructions, and do the logic as if
4264 // the new result ptr type was available.4251 // the new result ptr type was available.
42654252
...@@ -4297,6 +4284,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4297,6 +4284,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4297 });4284 });
4298 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(replacement_block.instructions.items));4285 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(replacement_block.instructions.items));
4299 }4286 }
4287
4288 if (ia1.is_const) {
4289 return sema.makePtrConst(block, ptr);
4290 } else {
4291 return ptr;
4292 }
4300 },4293 },
4301 else => unreachable,4294 else => unreachable,
4302 }4295 }
...@@ -33044,7 +33037,9 @@ fn analyzeRef(...@@ -33044,7 +33037,9 @@ fn analyzeRef(
33044 }33037 }
33045 }33038 }
3304633039
33047 try sema.requireRuntimeBlock(block, src, null);33040 // No `requireRuntimeBlock`; it's okay to `ref` to a runtime value in a comptime context,
33041 // it's just that we can only use the *type* of the result, since the value is runtime-known.
33042
33048 const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local);33043 const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local);
33049 const ptr_type = try pt.ptrTypeSema(.{33044 const ptr_type = try pt.ptrTypeSema(.{
33050 .child = operand_ty.toIntern(),33045 .child = operand_ty.toIntern(),
...@@ -33058,10 +33053,17 @@ fn analyzeRef(...@@ -33058,10 +33053,17 @@ fn analyzeRef(
33058 .flags = .{ .address_space = address_space },33053 .flags = .{ .address_space = address_space },
33059 });33054 });
33060 const alloc = try block.addTy(.alloc, mut_ptr_type);33055 const alloc = try block.addTy(.alloc, mut_ptr_type);
33061 try sema.storePtr(block, src, alloc, operand);
3306233056
33063 // TODO: Replace with sema.coerce when that supports adding pointer constness.33057 // In a comptime context, the store would fail, since the operand is runtime-known. But that's
33064 return sema.bitCast(block, ptr_type, alloc, src, null);33058 // okay; we don't actually need this store to succeed, since we're creating a runtime value in a
33059 // comptime scope, so the value can never be used aside from to get its type.
33060 if (!block.is_comptime) {
33061 try sema.storePtr(block, src, alloc, operand);
33062 }
33063
33064 // Cast to the constant pointer type. We do this directly rather than going via `coerce` to
33065 // avoid errors in the `block.is_comptime` case.
33066 return block.addBitCast(ptr_type, alloc);
33065}33067}
3306633068
33067fn analyzeLoad(33069fn analyzeLoad(
src/codegen/c.zig+74-10
...@@ -48,6 +48,60 @@ pub const CValue = union(enum) {...@@ -48,6 +48,60 @@ pub const CValue = union(enum) {
48 payload_identifier: []const u8,48 payload_identifier: []const u8,
49 /// Rendered with fmtCTypePoolString49 /// Rendered with fmtCTypePoolString
50 ctype_pool_string: CType.Pool.String,50 ctype_pool_string: CType.Pool.String,
51
52 fn eql(lhs: CValue, rhs: CValue) bool {
53 return switch (lhs) {
54 .none => rhs == .none,
55 .new_local, .local => |lhs_local| switch (rhs) {
56 .new_local, .local => |rhs_local| lhs_local == rhs_local,
57 else => false,
58 },
59 .local_ref => |lhs_local| switch (rhs) {
60 .local_ref => |rhs_local| lhs_local == rhs_local,
61 else => false,
62 },
63 .constant => |lhs_val| switch (rhs) {
64 .constant => |rhs_val| lhs_val.toIntern() == rhs_val.toIntern(),
65 else => false,
66 },
67 .arg => |lhs_arg_index| switch (rhs) {
68 .arg => |rhs_arg_index| lhs_arg_index == rhs_arg_index,
69 else => false,
70 },
71 .arg_array => |lhs_arg_index| switch (rhs) {
72 .arg_array => |rhs_arg_index| lhs_arg_index == rhs_arg_index,
73 else => false,
74 },
75 .field => |lhs_field_index| switch (rhs) {
76 .field => |rhs_field_index| lhs_field_index == rhs_field_index,
77 else => false,
78 },
79 .nav => |lhs_nav| switch (rhs) {
80 .nav => |rhs_nav| lhs_nav == rhs_nav,
81 else => false,
82 },
83 .nav_ref => |lhs_nav| switch (rhs) {
84 .nav_ref => |rhs_nav| lhs_nav == rhs_nav,
85 else => false,
86 },
87 .undef => |lhs_ty| switch (rhs) {
88 .undef => |rhs_ty| lhs_ty.toIntern() == rhs_ty.toIntern(),
89 else => false,
90 },
91 .identifier => |lhs_id| switch (rhs) {
92 .identifier => |rhs_id| std.mem.eql(u8, lhs_id, rhs_id),
93 else => false,
94 },
95 .payload_identifier => |lhs_id| switch (rhs) {
96 .payload_identifier => |rhs_id| std.mem.eql(u8, lhs_id, rhs_id),
97 else => false,
98 },
99 .ctype_pool_string => |lhs_str| switch (rhs) {
100 .ctype_pool_string => |rhs_str| lhs_str.index == rhs_str.index,
101 else => false,
102 },
103 };
104 }
51};105};
52106
53const BlockData = struct {107const BlockData = struct {
...@@ -4219,17 +4273,23 @@ fn airCmpOp(...@@ -4219,17 +4273,23 @@ fn airCmpOp(
4219 const writer = f.object.writer();4273 const writer = f.object.writer();
4220 const local = try f.allocLocal(inst, inst_ty);4274 const local = try f.allocLocal(inst, inst_ty);
4221 const v = try Vectorize.start(f, inst, writer, lhs_ty);4275 const v = try Vectorize.start(f, inst, writer, lhs_ty);
4276 const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
4222 try f.writeCValue(writer, local, .Other);4277 try f.writeCValue(writer, local, .Other);
4223 try v.elem(f, writer);4278 try v.elem(f, writer);
4224 try writer.writeAll(" = ");4279 try a.assign(f, writer);
4225 if (need_cast) try writer.writeAll("(void*)");4280 if (lhs != .undef and lhs.eql(rhs)) try writer.writeAll(switch (operator) {
4226 try f.writeCValue(writer, lhs, .Other);4281 .lt, .neq, .gt => "false",
4227 try v.elem(f, writer);4282 .lte, .eq, .gte => "true",
4228 try writer.writeAll(compareOperatorC(operator));4283 }) else {
4229 if (need_cast) try writer.writeAll("(void*)");4284 if (need_cast) try writer.writeAll("(void*)");
4230 try f.writeCValue(writer, rhs, .Other);4285 try f.writeCValue(writer, lhs, .Other);
4231 try v.elem(f, writer);4286 try v.elem(f, writer);
4232 try writer.writeAll(";\n");4287 try writer.writeAll(compareOperatorC(operator));
4288 if (need_cast) try writer.writeAll("(void*)");
4289 try f.writeCValue(writer, rhs, .Other);
4290 try v.elem(f, writer);
4291 }
4292 try a.end(f, writer);
4233 try v.end(f, inst, writer);4293 try v.end(f, inst, writer);
42344294
4235 return local;4295 return local;
...@@ -4270,7 +4330,11 @@ fn airEquality(...@@ -4270,7 +4330,11 @@ fn airEquality(
4270 try a.assign(f, writer);4330 try a.assign(f, writer);
42714331
4272 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);4332 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
4273 switch (operand_ctype.info(ctype_pool)) {4333 if (lhs != .undef and lhs.eql(rhs)) try writer.writeAll(switch (operator) {
4334 .lt, .lte, .gte, .gt => unreachable,
4335 .neq => "false",
4336 .eq => "true",
4337 }) else switch (operand_ctype.info(ctype_pool)) {
4274 .basic, .pointer => {4338 .basic, .pointer => {
4275 try f.writeCValue(writer, lhs, .Other);4339 try f.writeCValue(writer, lhs, .Other);
4276 try writer.writeAll(compareOperatorC(operator));4340 try writer.writeAll(compareOperatorC(operator));
test/behavior/fn.zig+80
...@@ -617,3 +617,83 @@ test "inline function with comptime-known comptime-only return type called at ru...@@ -617,3 +617,83 @@ test "inline function with comptime-known comptime-only return type called at ru
617 try expectEqual(111, a);617 try expectEqual(111, a);
618 try expectEqual(f32, T);618 try expectEqual(f32, T);
619}619}
620
621test "address of function parameter is consistent" {
622 const S = struct {
623 fn paramAddrMatch(x: u8) bool {
624 return &x == &x;
625 }
626 };
627 try expect(S.paramAddrMatch(0));
628 comptime assert(S.paramAddrMatch(0));
629}
630
631test "address of function parameter is consistent in other parameter type" {
632 const S = struct {
633 fn paramAddrMatch(comptime x: u8, y: if (&x != &x) unreachable else u8) void {
634 _ = y;
635 }
636 };
637 S.paramAddrMatch(1, 2);
638}
639
640test "address of function parameter is consistent in function align" {
641 switch (builtin.target.cpu.arch) {
642 .wasm32, .wasm64 => return, // function alignment not supported
643 else => {},
644 }
645 const S = struct {
646 fn paramAddrMatch(comptime x: u8) align(if (&x != &x) unreachable else 1) void {}
647 };
648 S.paramAddrMatch(1);
649}
650
651test "address of function parameter is consistent in function callconv" {
652 const S = struct {
653 fn paramAddrMatch(comptime x: u8) callconv(if (&x != &x) unreachable else .auto) void {}
654 };
655 S.paramAddrMatch(1);
656}
657
658test "address of function parameter is consistent in function return type" {
659 const S = struct {
660 fn paramAddrMatch(comptime x: u8) if (&x != &x) unreachable else void {}
661 };
662 S.paramAddrMatch(1);
663}
664
665test "address of function parameter is consistent in function addrspace" {
666 const S = struct {
667 fn paramAddrMatch(comptime x: u8) addrspace(if (&x != &x) unreachable else .generic) void {}
668 };
669 S.paramAddrMatch(1);
670}
671
672test "function parameter self equality" {
673 const S = struct {
674 fn equal(x: u32) bool {
675 return x == x;
676 }
677 fn notEqual(x: u32) bool {
678 return x != x;
679 }
680 fn lessThan(x: u32) bool {
681 return x < x;
682 }
683 fn lessThanOrEqual(x: u32) bool {
684 return x <= x;
685 }
686 fn greaterThan(x: u32) bool {
687 return x > x;
688 }
689 fn greaterThanOrEqual(x: u32) bool {
690 return x >= x;
691 }
692 };
693 try expect(S.equal(42));
694 try expect(!S.notEqual(42));
695 try expect(!S.lessThan(42));
696 try expect(S.lessThanOrEqual(42));
697 try expect(!S.greaterThan(42));
698 try expect(S.greaterThanOrEqual(42));
699}