authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-08 20:40:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-08 20:40:16-07:00
logf4d5fcde727d93da9ebe17a27cc62270545ccda6
tree1bb04bf9a99acb6619fae6f2d550672c1249e55c
parent7c0614ea659b3f404f9d702c990afcac5f0b1479

AstGen: avoid redundant "ref" instructions

Whenever a `ref` instruction is needed, it is created and saved in `AstGen.ref_table` instead of being immediately appended to the current block body. Then, when the referenced instruction is being added to the parent block (e.g. from setBlockBody), if it has a ref_table entry, then the ref instruction is added directly after the instruction being referenced. This makes sure two properties are upheld: 1. All pointers to the same locals return the same address. This is required to be compliant with the language specification. 2. `ref` instructions will dominate their uses. This is a required property of ZIR. A complication arises when a ref instruction refs another ref instruction. The logic in appendBodyWithFixups must take this into account, recursively handling ref refs.

3 files changed, 182 insertions(+), 60 deletions(-)

src/AstGen.zig+170-58
...@@ -45,6 +45,17 @@ fn_block: ?*GenZir = null,...@@ -45,6 +45,17 @@ fn_block: ?*GenZir = null,
45imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{},45imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{},
46/// Used for temporary storage when building payloads.46/// Used for temporary storage when building payloads.
47scratch: std.ArrayListUnmanaged(u32) = .{},47scratch: std.ArrayListUnmanaged(u32) = .{},
48/// Whenever a `ref` instruction is needed, it is created and saved in this
49/// table instead of being immediately appended to the current block body.
50/// Then, when the instruction is being added to the parent block (typically from
51/// setBlockBody), if it has a ref_table entry, then the ref instruction is added
52/// there. This makes sure two properties are upheld:
53/// 1. All pointers to the same locals return the same address. This is required
54/// to be compliant with the language specification.
55/// 2. `ref` instructions will dominate their uses. This is a required property
56/// of ZIR.
57/// The key is the ref operand; the value is the ref instruction.
58ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
4859
49const InnerError = error{ OutOfMemory, AnalysisFail };60const InnerError = error{ OutOfMemory, AnalysisFail };
5061
...@@ -199,6 +210,7 @@ pub fn deinit(astgen: *AstGen, gpa: Allocator) void {...@@ -199,6 +210,7 @@ pub fn deinit(astgen: *AstGen, gpa: Allocator) void {
199 astgen.compile_errors.deinit(gpa);210 astgen.compile_errors.deinit(gpa);
200 astgen.imports.deinit(gpa);211 astgen.imports.deinit(gpa);
201 astgen.scratch.deinit(gpa);212 astgen.scratch.deinit(gpa);
213 astgen.ref_table.deinit(gpa);
202}214}
203215
204pub const ResultLoc = union(enum) {216pub const ResultLoc = union(enum) {
...@@ -4216,11 +4228,12 @@ fn structDeclInner(...@@ -4216,11 +4228,12 @@ fn structDeclInner(
4216 }4228 }
42174229
4218 const body = block_scope.instructionsSlice();4230 const body = block_scope.instructionsSlice();
4231 const body_len = astgen.countBodyLenAfterFixups(body);
42194232
4220 try gz.setStruct(decl_inst, .{4233 try gz.setStruct(decl_inst, .{
4221 .src_node = node,4234 .src_node = node,
4222 .layout = layout,4235 .layout = layout,
4223 .body_len = @intCast(u32, body.len),4236 .body_len = body_len,
4224 .fields_len = field_count,4237 .fields_len = field_count,
4225 .decls_len = decl_count,4238 .decls_len = decl_count,
4226 .known_non_opv = known_non_opv,4239 .known_non_opv = known_non_opv,
...@@ -4230,9 +4243,9 @@ fn structDeclInner(...@@ -4230,9 +4243,9 @@ fn structDeclInner(
4230 wip_members.finishBits(bits_per_field);4243 wip_members.finishBits(bits_per_field);
4231 const decls_slice = wip_members.declsSlice();4244 const decls_slice = wip_members.declsSlice();
4232 const fields_slice = wip_members.fieldsSlice();4245 const fields_slice = wip_members.fieldsSlice();
4233 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body.len + fields_slice.len);4246 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len);
4234 astgen.extra.appendSliceAssumeCapacity(decls_slice);4247 astgen.extra.appendSliceAssumeCapacity(decls_slice);
4235 astgen.extra.appendSliceAssumeCapacity(body);4248 astgen.appendBodyWithFixups(body);
4236 astgen.extra.appendSliceAssumeCapacity(fields_slice);4249 astgen.extra.appendSliceAssumeCapacity(fields_slice);
42374250
4238 block_scope.unstack();4251 block_scope.unstack();
...@@ -4364,12 +4377,13 @@ fn unionDeclInner(...@@ -4364,12 +4377,13 @@ fn unionDeclInner(
4364 }4377 }
43654378
4366 const body = block_scope.instructionsSlice();4379 const body = block_scope.instructionsSlice();
4380 const body_len = astgen.countBodyLenAfterFixups(body);
43674381
4368 try gz.setUnion(decl_inst, .{4382 try gz.setUnion(decl_inst, .{
4369 .src_node = node,4383 .src_node = node,
4370 .layout = layout,4384 .layout = layout,
4371 .tag_type = arg_inst,4385 .tag_type = arg_inst,
4372 .body_len = @intCast(u32, body.len),4386 .body_len = body_len,
4373 .fields_len = field_count,4387 .fields_len = field_count,
4374 .decls_len = decl_count,4388 .decls_len = decl_count,
4375 .auto_enum_tag = have_auto_enum,4389 .auto_enum_tag = have_auto_enum,
...@@ -4378,9 +4392,9 @@ fn unionDeclInner(...@@ -4378,9 +4392,9 @@ fn unionDeclInner(
4378 wip_members.finishBits(bits_per_field);4392 wip_members.finishBits(bits_per_field);
4379 const decls_slice = wip_members.declsSlice();4393 const decls_slice = wip_members.declsSlice();
4380 const fields_slice = wip_members.fieldsSlice();4394 const fields_slice = wip_members.fieldsSlice();
4381 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body.len + fields_slice.len);4395 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len);
4382 astgen.extra.appendSliceAssumeCapacity(decls_slice);4396 astgen.extra.appendSliceAssumeCapacity(decls_slice);
4383 astgen.extra.appendSliceAssumeCapacity(body);4397 astgen.appendBodyWithFixups(body);
4384 astgen.extra.appendSliceAssumeCapacity(fields_slice);4398 astgen.extra.appendSliceAssumeCapacity(fields_slice);
43854399
4386 block_scope.unstack();4400 block_scope.unstack();
...@@ -4616,12 +4630,13 @@ fn containerDecl(...@@ -4616,12 +4630,13 @@ fn containerDecl(
4616 }4630 }
46174631
4618 const body = block_scope.instructionsSlice();4632 const body = block_scope.instructionsSlice();
4633 const body_len = astgen.countBodyLenAfterFixups(body);
46194634
4620 try gz.setEnum(decl_inst, .{4635 try gz.setEnum(decl_inst, .{
4621 .src_node = node,4636 .src_node = node,
4622 .nonexhaustive = nonexhaustive,4637 .nonexhaustive = nonexhaustive,
4623 .tag_type = arg_inst,4638 .tag_type = arg_inst,
4624 .body_len = @intCast(u32, body.len),4639 .body_len = body_len,
4625 .fields_len = @intCast(u32, counts.total_fields),4640 .fields_len = @intCast(u32, counts.total_fields),
4626 .decls_len = @intCast(u32, counts.decls),4641 .decls_len = @intCast(u32, counts.decls),
4627 });4642 });
...@@ -4629,9 +4644,9 @@ fn containerDecl(...@@ -4629,9 +4644,9 @@ fn containerDecl(
4629 wip_members.finishBits(bits_per_field);4644 wip_members.finishBits(bits_per_field);
4630 const decls_slice = wip_members.declsSlice();4645 const decls_slice = wip_members.declsSlice();
4631 const fields_slice = wip_members.fieldsSlice();4646 const fields_slice = wip_members.fieldsSlice();
4632 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body.len + fields_slice.len);4647 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len);
4633 astgen.extra.appendSliceAssumeCapacity(decls_slice);4648 astgen.extra.appendSliceAssumeCapacity(decls_slice);
4634 astgen.extra.appendSliceAssumeCapacity(body);4649 astgen.appendBodyWithFixups(body);
4635 astgen.extra.appendSliceAssumeCapacity(fields_slice);4650 astgen.extra.appendSliceAssumeCapacity(fields_slice);
46364651
4637 block_scope.unstack();4652 block_scope.unstack();
...@@ -5403,10 +5418,12 @@ fn setCondBrPayload(...@@ -5403,10 +5418,12 @@ fn setCondBrPayload(
5403 const astgen = then_scope.astgen;5418 const astgen = then_scope.astgen;
5404 const then_body = then_scope.instructionsSliceUpto(else_scope);5419 const then_body = then_scope.instructionsSliceUpto(else_scope);
5405 const else_body = else_scope.instructionsSlice();5420 const else_body = else_scope.instructionsSlice();
5406 const then_body_len = @intCast(u32, then_body.len + @boolToInt(then_break != 0));5421 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(then_break != 0);
5407 const else_body_len = @intCast(u32, else_body.len + @boolToInt(else_break != 0));5422 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(else_break != 0);
5408 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +5423 try astgen.extra.ensureUnusedCapacity(
5409 then_body_len + else_body_len);5424 astgen.gpa,
5425 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len,
5426 );
54105427
5411 const zir_datas = astgen.instructions.items(.data);5428 const zir_datas = astgen.instructions.items(.data);
5412 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{5429 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
...@@ -5414,9 +5431,9 @@ fn setCondBrPayload(...@@ -5414,9 +5431,9 @@ fn setCondBrPayload(
5414 .then_body_len = then_body_len,5431 .then_body_len = then_body_len,
5415 .else_body_len = else_body_len,5432 .else_body_len = else_body_len,
5416 });5433 });
5417 astgen.extra.appendSliceAssumeCapacity(then_body);5434 astgen.appendBodyWithFixups(then_body);
5418 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break);5435 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break);
5419 astgen.extra.appendSliceAssumeCapacity(else_body);5436 astgen.appendBodyWithFixups(else_body);
5420 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break);5437 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break);
5421}5438}
54225439
...@@ -5437,10 +5454,12 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -5437,10 +5454,12 @@ fn setCondBrPayloadElideBlockStorePtr(
5437 const else_body = else_scope.instructionsSlice();5454 const else_body = else_scope.instructionsSlice();
5438 const has_then_break = then_break != 0;5455 const has_then_break = then_break != 0;
5439 const has_else_break = else_break != 0;5456 const has_else_break = else_break != 0;
5440 const then_body_len = @intCast(u32, then_body.len + @boolToInt(has_then_break));5457 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(has_then_break);
5441 const else_body_len = @intCast(u32, else_body.len + @boolToInt(has_else_break));5458 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(has_else_break);
5442 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +5459 try astgen.extra.ensureUnusedCapacity(
5443 then_body_len + else_body_len);5460 astgen.gpa,
5461 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len,
5462 );
54445463
5445 const zir_tags = astgen.instructions.items(.tag);5464 const zir_tags = astgen.instructions.items(.tag);
5446 const zir_datas = astgen.instructions.items(.data);5465 const zir_datas = astgen.instructions.items(.data);
...@@ -5475,7 +5494,7 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -5475,7 +5494,7 @@ fn setCondBrPayloadElideBlockStorePtr(
5475 continue;5494 continue;
5476 }5495 }
5477 }5496 }
5478 astgen.extra.appendAssumeCapacity(src_inst);5497 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst);
5479 }5498 }
5480 if (has_then_break) astgen.extra.appendAssumeCapacity(then_break);5499 if (has_then_break) astgen.extra.appendAssumeCapacity(then_break);
54815500
...@@ -5495,7 +5514,7 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -5495,7 +5514,7 @@ fn setCondBrPayloadElideBlockStorePtr(
5495 continue;5514 continue;
5496 }5515 }
5497 }5516 }
5498 astgen.extra.appendAssumeCapacity(src_inst);5517 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst);
5499 }5518 }
5500 if (has_else_break) astgen.extra.appendAssumeCapacity(else_break);5519 if (has_else_break) astgen.extra.appendAssumeCapacity(else_break);
5501}5520}
...@@ -6249,8 +6268,10 @@ fn switchExpr(...@@ -6249,8 +6268,10 @@ fn switchExpr(
6249 }6268 }
62506269
6251 const case_slice = case_scope.instructionsSlice();6270 const case_slice = case_scope.instructionsSlice();
6252 payloads.items[body_len_index] = @intCast(u32, case_slice.len);6271 const body_len = astgen.countBodyLenAfterFixups(case_slice);
6253 try payloads.appendSlice(gpa, case_slice);6272 try payloads.ensureUnusedCapacity(gpa, body_len);
6273 payloads.items[body_len_index] = body_len;
6274 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
6254 }6275 }
6255 }6276 }
6256 // Now that the item expressions are generated we can add this.6277 // Now that the item expressions are generated we can add this.
...@@ -7043,10 +7064,11 @@ fn typeOf(...@@ -7043,10 +7064,11 @@ fn typeOf(
7043 node: Ast.Node.Index,7064 node: Ast.Node.Index,
7044 args: []const Ast.Node.Index,7065 args: []const Ast.Node.Index,
7045) InnerError!Zir.Inst.Ref {7066) InnerError!Zir.Inst.Ref {
7067 const astgen = gz.astgen;
7046 if (args.len < 1) {7068 if (args.len < 1) {
7047 return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{});7069 return astgen.failNode(node, "expected at least 1 argument, found 0", .{});
7048 }7070 }
7049 const gpa = gz.astgen.gpa;7071 const gpa = astgen.gpa;
7050 if (args.len == 1) {7072 if (args.len == 1) {
7051 const typeof_inst = try gz.makeBlockInst(.typeof_builtin, node);7073 const typeof_inst = try gz.makeBlockInst(.typeof_builtin, node);
70527074
...@@ -7065,7 +7087,7 @@ fn typeOf(...@@ -7065,7 +7087,7 @@ fn typeOf(
7065 return rvalue(gz, rl, indexToRef(typeof_inst), node);7087 return rvalue(gz, rl, indexToRef(typeof_inst), node);
7066 }7088 }
7067 const payload_size: u32 = std.meta.fields(Zir.Inst.TypeOfPeer).len;7089 const payload_size: u32 = std.meta.fields(Zir.Inst.TypeOfPeer).len;
7068 const payload_index = try reserveExtra(gz.astgen, payload_size + args.len);7090 const payload_index = try reserveExtra(astgen, payload_size + args.len);
7069 var args_index = payload_index + payload_size;7091 var args_index = payload_index + payload_size;
70707092
7071 const typeof_inst = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, args.len);7093 const typeof_inst = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, args.len);
...@@ -7075,17 +7097,19 @@ fn typeOf(...@@ -7075,17 +7097,19 @@ fn typeOf(
70757097
7076 for (args) |arg, i| {7098 for (args) |arg, i| {
7077 const param_ref = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, arg, node);7099 const param_ref = try reachableExpr(&typeof_scope, &typeof_scope.base, .none, arg, node);
7078 gz.astgen.extra.items[args_index + i] = @enumToInt(param_ref);7100 astgen.extra.items[args_index + i] = @enumToInt(param_ref);
7079 }7101 }
7080 _ = try typeof_scope.addBreak(.break_inline, refToIndex(typeof_inst).?, .void_value);7102 _ = try typeof_scope.addBreak(.break_inline, refToIndex(typeof_inst).?, .void_value);
70817103
7082 const body = typeof_scope.instructionsSlice();7104 const body = typeof_scope.instructionsSlice();
7083 gz.astgen.setExtra(payload_index, Zir.Inst.TypeOfPeer{7105 const body_len = astgen.countBodyLenAfterFixups(body);
7084 .body_len = @intCast(u32, body.len),7106 astgen.setExtra(payload_index, Zir.Inst.TypeOfPeer{
7085 .body_index = @intCast(u32, gz.astgen.extra.items.len),7107 .body_len = @intCast(u32, body_len),
7108 .body_index = @intCast(u32, astgen.extra.items.len),
7086 .src_node = gz.nodeIndexToRelative(node),7109 .src_node = gz.nodeIndexToRelative(node),
7087 });7110 });
7088 try gz.astgen.extra.appendSlice(gpa, body);7111 try astgen.extra.ensureUnusedCapacity(gpa, body_len);
7112 astgen.appendBodyWithFixups(body);
7089 typeof_scope.unstack();7113 typeof_scope.unstack();
70907114
7091 return rvalue(gz, rl, typeof_inst, node);7115 return rvalue(gz, rl, typeof_inst, node);
...@@ -9032,9 +9056,22 @@ fn rvalue(...@@ -9032,9 +9056,22 @@ fn rvalue(
9032 },9056 },
9033 .ref => {9057 .ref => {
9034 // We need a pointer but we have a value.9058 // We need a pointer but we have a value.
9035 const tree = gz.astgen.tree;9059 // Unfortunately it's not quite as simple as directly emitting a ref
9060 // instruction here because we need subsequent address-of operator on
9061 // const locals to return the same address.
9062 const astgen = gz.astgen;
9063 const tree = astgen.tree;
9036 const src_token = tree.firstToken(src_node);9064 const src_token = tree.firstToken(src_node);
9037 return gz.addUnTok(.ref, result, src_token);9065 const result_index = refToIndex(result) orelse
9066 return gz.addUnTok(.ref, result, src_token);
9067 const zir_tags = gz.astgen.instructions.items(.tag);
9068 if (zir_tags[result_index].isParam())
9069 return gz.addUnTok(.ref, result, src_token);
9070 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);
9071 if (!gop.found_existing) {
9072 gop.value_ptr.* = try gz.makeUnTok(.ref, result, src_token);
9073 }
9074 return indexToRef(gop.value_ptr.*);
9038 },9075 },
9039 .ty => |ty_inst| {9076 .ty => |ty_inst| {
9040 // Quickly eliminate some common, unnecessary type coercion.9077 // Quickly eliminate some common, unnecessary type coercion.
...@@ -9976,43 +10013,58 @@ const GenZir = struct {...@@ -9976,43 +10013,58 @@ const GenZir = struct {
997610013
9977 /// Assumes nothing stacked on `gz`. Unstacks `gz`.10014 /// Assumes nothing stacked on `gz`. Unstacks `gz`.
9978 fn setBoolBrBody(gz: *GenZir, inst: Zir.Inst.Index) !void {10015 fn setBoolBrBody(gz: *GenZir, inst: Zir.Inst.Index) !void {
9979 const gpa = gz.astgen.gpa;10016 const astgen = gz.astgen;
10017 const gpa = astgen.gpa;
9980 const body = gz.instructionsSlice();10018 const body = gz.instructionsSlice();
9981 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);10019 const body_len = astgen.countBodyLenAfterFixups(body);
9982 const zir_datas = gz.astgen.instructions.items(.data);10020 try astgen.extra.ensureUnusedCapacity(
9983 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(10021 gpa,
9984 Zir.Inst.Block{ .body_len = @intCast(u32, body.len) },10022 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len,
9985 );10023 );
9986 gz.astgen.extra.appendSliceAssumeCapacity(body);10024 const zir_datas = astgen.instructions.items(.data);
10025 zir_datas[inst].bool_br.payload_index = astgen.addExtraAssumeCapacity(
10026 Zir.Inst.Block{ .body_len = body_len },
10027 );
10028 astgen.appendBodyWithFixups(body);
9987 gz.unstack();10029 gz.unstack();
9988 }10030 }
998910031
9990 /// Assumes nothing stacked on `gz`. Unstacks `gz`.10032 /// Assumes nothing stacked on `gz`. Unstacks `gz`.
9991 fn setBlockBody(gz: *GenZir, inst: Zir.Inst.Index) !void {10033 fn setBlockBody(gz: *GenZir, inst: Zir.Inst.Index) !void {
9992 const gpa = gz.astgen.gpa;10034 const astgen = gz.astgen;
10035 const gpa = astgen.gpa;
9993 const body = gz.instructionsSlice();10036 const body = gz.instructionsSlice();
9994 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);10037 const body_len = astgen.countBodyLenAfterFixups(body);
9995 const zir_datas = gz.astgen.instructions.items(.data);10038 try astgen.extra.ensureUnusedCapacity(
9996 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(10039 gpa,
9997 Zir.Inst.Block{ .body_len = @intCast(u32, body.len) },10040 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len,
10041 );
10042 const zir_datas = astgen.instructions.items(.data);
10043 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(
10044 Zir.Inst.Block{ .body_len = body_len },
9998 );10045 );
9999 gz.astgen.extra.appendSliceAssumeCapacity(body);10046 astgen.appendBodyWithFixups(body);
10000 gz.unstack();10047 gz.unstack();
10001 }10048 }
1000210049
10003 /// Assumes nothing stacked on `gz`. Unstacks `gz`.10050 /// Assumes nothing stacked on `gz`. Unstacks `gz`.
10004 fn setTryBody(gz: *GenZir, inst: Zir.Inst.Index, operand: Zir.Inst.Ref) !void {10051 fn setTryBody(gz: *GenZir, inst: Zir.Inst.Index, operand: Zir.Inst.Ref) !void {
10005 const gpa = gz.astgen.gpa;10052 const astgen = gz.astgen;
10053 const gpa = astgen.gpa;
10006 const body = gz.instructionsSlice();10054 const body = gz.instructionsSlice();
10007 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Try).Struct.fields.len + body.len);10055 const body_len = astgen.countBodyLenAfterFixups(body);
10008 const zir_datas = gz.astgen.instructions.items(.data);10056 try astgen.extra.ensureUnusedCapacity(
10009 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(10057 gpa,
10058 @typeInfo(Zir.Inst.Try).Struct.fields.len + body_len,
10059 );
10060 const zir_datas = astgen.instructions.items(.data);
10061 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(
10010 Zir.Inst.Try{10062 Zir.Inst.Try{
10011 .operand = operand,10063 .operand = operand,
10012 .body_len = @intCast(u32, body.len),10064 .body_len = body_len,
10013 },10065 },
10014 );10066 );
10015 gz.astgen.extra.appendSliceAssumeCapacity(body);10067 astgen.appendBodyWithFixups(body);
10016 gz.unstack();10068 gz.unstack();
10017 }10069 }
1001810070
...@@ -10089,6 +10141,7 @@ const GenZir = struct {...@@ -10089,6 +10141,7 @@ const GenZir = struct {
10089 if (args.ret_gz) |ret_gz|10141 if (args.ret_gz) |ret_gz|
10090 ret_body = ret_gz.instructionsSlice();10142 ret_body = ret_gz.instructionsSlice();
10091 }10143 }
10144 const body_len = astgen.countBodyLenAfterFixups(body);
1009210145
10093 if (args.cc_ref != .none or args.lib_name != 0 or10146 if (args.cc_ref != .none or args.lib_name != 0 or
10094 args.is_var_args or args.is_test or args.is_extern or10147 args.is_var_args or args.is_test or args.is_extern or
...@@ -10114,13 +10167,13 @@ const GenZir = struct {...@@ -10114,13 +10167,13 @@ const GenZir = struct {
10114 fancyFnExprExtraLen(section_body, args.section_ref) +10167 fancyFnExprExtraLen(section_body, args.section_ref) +
10115 fancyFnExprExtraLen(cc_body, args.cc_ref) +10168 fancyFnExprExtraLen(cc_body, args.cc_ref) +
10116 fancyFnExprExtraLen(ret_body, ret_ref) +10169 fancyFnExprExtraLen(ret_body, ret_ref) +
10117 body.len + src_locs.len +10170 body_len + src_locs.len +
10118 @boolToInt(args.lib_name != 0) +10171 @boolToInt(args.lib_name != 0) +
10119 @boolToInt(args.noalias_bits != 0),10172 @boolToInt(args.noalias_bits != 0),
10120 );10173 );
10121 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{10174 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{
10122 .param_block = args.param_block,10175 .param_block = args.param_block,
10123 .body_len = @intCast(u32, body.len),10176 .body_len = body_len,
10124 .bits = .{10177 .bits = .{
10125 .is_var_args = args.is_var_args,10178 .is_var_args = args.is_var_args,
10126 .is_inferred_error = args.is_inferred_error,10179 .is_inferred_error = args.is_inferred_error,
...@@ -10187,7 +10240,7 @@ const GenZir = struct {...@@ -10187,7 +10240,7 @@ const GenZir = struct {
10187 astgen.extra.appendAssumeCapacity(args.noalias_bits);10240 astgen.extra.appendAssumeCapacity(args.noalias_bits);
10188 }10241 }
1018910242
10190 astgen.extra.appendSliceAssumeCapacity(body);10243 astgen.appendBodyWithFixups(body);
10191 astgen.extra.appendSliceAssumeCapacity(src_locs);10244 astgen.extra.appendSliceAssumeCapacity(src_locs);
1019210245
10193 // Order is important when unstacking.10246 // Order is important when unstacking.
...@@ -10214,9 +10267,9 @@ const GenZir = struct {...@@ -10214,9 +10267,9 @@ const GenZir = struct {
10214 } else {10267 } else {
10215 try astgen.extra.ensureUnusedCapacity(10268 try astgen.extra.ensureUnusedCapacity(
10216 gpa,10269 gpa,
10217 @typeInfo(Zir.Inst.Func).Struct.fields.len +10270 @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 +
10218 @maximum(ret_body.len, @boolToInt(ret_ref != .none)) +10271 @maximum(ret_body.len, @boolToInt(ret_ref != .none)) +
10219 body.len + src_locs.len,10272 body_len + src_locs.len,
10220 );10273 );
10221 const ret_body_len = if (ret_body.len != 0)10274 const ret_body_len = if (ret_body.len != 0)
10222 @intCast(u32, ret_body.len)10275 @intCast(u32, ret_body.len)
...@@ -10226,7 +10279,7 @@ const GenZir = struct {...@@ -10226,7 +10279,7 @@ const GenZir = struct {
10226 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{10279 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
10227 .param_block = args.param_block,10280 .param_block = args.param_block,
10228 .ret_body_len = ret_body_len,10281 .ret_body_len = ret_body_len,
10229 .body_len = @intCast(u32, body.len),10282 .body_len = body_len,
10230 });10283 });
10231 const zir_datas = astgen.instructions.items(.data);10284 const zir_datas = astgen.instructions.items(.data);
10232 if (ret_body.len != 0) {10285 if (ret_body.len != 0) {
...@@ -10235,7 +10288,7 @@ const GenZir = struct {...@@ -10235,7 +10288,7 @@ const GenZir = struct {
10235 } else if (ret_ref != .none) {10288 } else if (ret_ref != .none) {
10236 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));10289 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref));
10237 }10290 }
10238 astgen.extra.appendSliceAssumeCapacity(body);10291 astgen.appendBodyWithFixups(body);
10239 astgen.extra.appendSliceAssumeCapacity(src_locs);10292 astgen.extra.appendSliceAssumeCapacity(src_locs);
1024010293
10241 // Order is important when unstacking.10294 // Order is important when unstacking.
...@@ -10593,6 +10646,26 @@ const GenZir = struct {...@@ -10593,6 +10646,26 @@ const GenZir = struct {
10593 });10646 });
10594 }10647 }
1059510648
10649 fn makeUnTok(
10650 gz: *GenZir,
10651 tag: Zir.Inst.Tag,
10652 operand: Zir.Inst.Ref,
10653 /// Absolute token index. This function does the conversion to Decl offset.
10654 abs_tok_index: Ast.TokenIndex,
10655 ) !Zir.Inst.Index {
10656 const astgen = gz.astgen;
10657 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
10658 assert(operand != .none);
10659 try astgen.instructions.append(astgen.gpa, .{
10660 .tag = tag,
10661 .data = .{ .un_tok = .{
10662 .operand = operand,
10663 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
10664 } },
10665 });
10666 return new_index;
10667 }
10668
10596 fn addStrTok(10669 fn addStrTok(
10597 gz: *GenZir,10670 gz: *GenZir,
10598 tag: Zir.Inst.Tag,10671 tag: Zir.Inst.Tag,
...@@ -11337,3 +11410,42 @@ fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool {...@@ -11337,3 +11410,42 @@ fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool {
11337 else => false,11410 else => false,
11338 };11411 };
11339}11412}
11413
11414/// Assumes capacity for body has already been added. Needed capacity taking into
11415/// account fixups can be found with `countBodyLenAfterFixups`.
11416fn appendBodyWithFixups(astgen: *AstGen, body: []const Zir.Inst.Index) void {
11417 return appendBodyWithFixupsArrayList(astgen, &astgen.extra, body);
11418}
11419
11420fn appendBodyWithFixupsArrayList(
11421 astgen: *AstGen,
11422 list: *std.ArrayListUnmanaged(u32),
11423 body: []const Zir.Inst.Index,
11424) void {
11425 for (body) |body_inst| {
11426 appendPossiblyRefdBodyInst(astgen, list, body_inst);
11427 }
11428}
11429
11430fn appendPossiblyRefdBodyInst(
11431 astgen: *AstGen,
11432 list: *std.ArrayListUnmanaged(u32),
11433 body_inst: Zir.Inst.Index,
11434) void {
11435 list.appendAssumeCapacity(body_inst);
11436 const kv = astgen.ref_table.fetchRemove(body_inst) orelse return;
11437 const ref_inst = kv.value;
11438 return appendPossiblyRefdBodyInst(astgen, list, ref_inst);
11439}
11440
11441fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
11442 var count = body.len;
11443 for (body) |body_inst| {
11444 var check_inst = body_inst;
11445 while (astgen.ref_table.get(check_inst)) |ref_inst| {
11446 count += 1;
11447 check_inst = ref_inst;
11448 }
11449 }
11450 return @intCast(u32, count);
11451}
src/Zir.zig+12
...@@ -1271,6 +1271,18 @@ pub const Inst = struct {...@@ -1271,6 +1271,18 @@ pub const Inst = struct {
1271 };1271 };
1272 }1272 }
12731273
1274 pub fn isParam(tag: Tag) bool {
1275 return switch (tag) {
1276 .param,
1277 .param_comptime,
1278 .param_anytype,
1279 .param_anytype_comptime,
1280 => true,
1281
1282 else => false,
1283 };
1284 }
1285
1274 /// AstGen uses this to find out if `Ref.void_value` should be used in place1286 /// AstGen uses this to find out if `Ref.void_value` should be used in place
1275 /// of the result of a given instruction. This allows Sema to forego adding1287 /// of the result of a given instruction. This allows Sema to forego adding
1276 /// the instruction to the map after analysis.1288 /// the instruction to the map after analysis.
test/behavior/eval.zig-2
...@@ -1191,8 +1191,6 @@ test "no dependency loop for alignment of self tagged union" {...@@ -1191,8 +1191,6 @@ test "no dependency loop for alignment of self tagged union" {
1191}1191}
11921192
1193test "equality of pointers to comptime const" {1193test "equality of pointers to comptime const" {
1194 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1195
1196 const a: i32 = undefined;1194 const a: i32 = undefined;
1197 comptime assert(&a == &a);1195 comptime assert(&a == &a);
1198}1196}