authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-17 22:20:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-18 16:56:12-07:00
log32edb9b55d0e41a58a11e0437149c4a9705c4699
treec0497c52c28ae9f97a9fcb5c57fa89e33838f5bd
parentdee96e2e2f464c3b8edc8ec3a63cd3b1860e3a9d

stage2: eliminate ZIR arg instruction references to ZIR

Prior to this commit, the AIR arg instruction kept a reference to a ZIR string index for the corresponding parameter name. This is used by DWARF emitting code. However, this is a design flaw because we want AIR objects to be independent from ZIR. This commit saves the parameter names into memory managed by `Module.Fn`. This is sub-optimal because we should be able to get the parameter names from the ZIR for a function without having them redundantly stored along with `Fn` memory. However the current way that ZIR param instructions are encoded does not support this case. They appear in the same ZIR body as the function instruction, just before it. Instead, they should be embedded within the function instruction, which will allow this TODO to be solved. That improvement is too big for this commit, however. After this there is one last dependency to untangle, which is for inline assembly. The issue for that is #10784.

7 files changed, 48 insertions(+), 52 deletions(-)

src/Air.zig+2-9
...@@ -32,8 +32,7 @@ pub const Inst = struct {...@@ -32,8 +32,7 @@ pub const Inst = struct {
32 /// The first N instructions in the main block must be one arg instruction per32 /// The first N instructions in the main block must be one arg instruction per
33 /// function parameter. This makes function parameters participate in33 /// function parameter. This makes function parameters participate in
34 /// liveness analysis without any special handling.34 /// liveness analysis without any special handling.
35 /// Uses the `ty_str` field.35 /// Uses the `ty` field.
36 /// The string is the parameter name.
37 arg,36 arg,
38 /// Float or integer addition. For integers, wrapping is undefined behavior.37 /// Float or integer addition. For integers, wrapping is undefined behavior.
39 /// Both operands are guaranteed to be the same type, and the result type38 /// Both operands are guaranteed to be the same type, and the result type
...@@ -615,11 +614,6 @@ pub const Inst = struct {...@@ -615,11 +614,6 @@ pub const Inst = struct {
615 // Index into a different array.614 // Index into a different array.
616 payload: u32,615 payload: u32,
617 },616 },
618 ty_str: struct {
619 ty: Ref,
620 // ZIR string table index.
621 str: u32,
622 },
623 br: struct {617 br: struct {
624 block_inst: Index,618 block_inst: Index,
625 operand: Ref,619 operand: Ref,
...@@ -759,8 +753,6 @@ pub fn typeOf(air: Air, inst: Air.Inst.Ref) Type {...@@ -759,8 +753,6 @@ pub fn typeOf(air: Air, inst: Air.Inst.Ref) Type {
759pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {753pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
760 const datas = air.instructions.items(.data);754 const datas = air.instructions.items(.data);
761 switch (air.instructions.items(.tag)[inst]) {755 switch (air.instructions.items(.tag)[inst]) {
762 .arg => return air.getRefType(datas[inst].ty_str.ty),
763
764 .add,756 .add,
765 .addwrap,757 .addwrap,
766 .add_sat,758 .add_sat,
...@@ -827,6 +819,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -827,6 +819,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
827819
828 .alloc,820 .alloc,
829 .ret_ptr,821 .ret_ptr,
822 .arg,
830 => return datas[inst].ty,823 => return datas[inst].ty,
831824
832 .assembly,825 .assembly,
src/Module.zig+21-5
...@@ -1370,6 +1370,14 @@ pub const Fn = struct {...@@ -1370,6 +1370,14 @@ pub const Fn = struct {
1370 /// ZIR instruction.1370 /// ZIR instruction.
1371 zir_body_inst: Zir.Inst.Index,1371 zir_body_inst: Zir.Inst.Index,
13721372
1373 /// Prefer to use `getParamName` to access this because of the future improvement
1374 /// we want to do mentioned in the TODO below.
1375 /// Stored in gpa.
1376 /// TODO: change param ZIR instructions to be embedded inside the function
1377 /// ZIR instruction instead of before it, so that `zir_body_inst` can be used to
1378 /// determine param names rather than redundantly storing them here.
1379 param_names: []const [:0]const u8,
1380
1373 /// Relative to owner Decl.1381 /// Relative to owner Decl.
1374 lbrace_line: u32,1382 lbrace_line: u32,
1375 /// Relative to owner Decl.1383 /// Relative to owner Decl.
...@@ -1466,6 +1474,18 @@ pub const Fn = struct {...@@ -1466,6 +1474,18 @@ pub const Fn = struct {
1466 gpa.destroy(node);1474 gpa.destroy(node);
1467 it = next;1475 it = next;
1468 }1476 }
1477
1478 for (func.param_names) |param_name| {
1479 gpa.free(param_name);
1480 }
1481 gpa.free(func.param_names);
1482 }
1483
1484 pub fn getParamName(func: Fn, index: u32) [:0]const u8 {
1485 // TODO rework ZIR of parameters so that this function looks up
1486 // param names in ZIR instead of redundantly saving them into Fn.
1487 // const zir = func.owner_decl.getFileScope().zir;
1488 return func.param_names[index];
1469 }1489 }
1470};1490};
14711491
...@@ -4606,15 +4626,11 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem...@@ -4606,15 +4626,11 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
4606 runtime_param_index += 1;4626 runtime_param_index += 1;
4607 continue;4627 continue;
4608 }4628 }
4609 const ty_ref = try sema.addType(param_type);
4610 const arg_index = @intCast(u32, sema.air_instructions.len);4629 const arg_index = @intCast(u32, sema.air_instructions.len);
4611 inner_block.instructions.appendAssumeCapacity(arg_index);4630 inner_block.instructions.appendAssumeCapacity(arg_index);
4612 sema.air_instructions.appendAssumeCapacity(.{4631 sema.air_instructions.appendAssumeCapacity(.{
4613 .tag = .arg,4632 .tag = .arg,
4614 .data = .{ .ty_str = .{4633 .data = .{ .ty = param_type },
4615 .ty = ty_ref,
4616 .str = param.name,
4617 } },
4618 });4634 });
4619 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));4635 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
4620 total_param_index += 1;4636 total_param_index += 1;
src/Sema.zig+14-14
...@@ -134,6 +134,7 @@ pub const Block = struct {...@@ -134,6 +134,7 @@ pub const Block = struct {
134 /// `noreturn` means `anytype`.134 /// `noreturn` means `anytype`.
135 ty: Type,135 ty: Type,
136 is_comptime: bool,136 is_comptime: bool,
137 name: []const u8,
137 };138 };
138139
139 /// This `Block` maps a block ZIR instruction to the corresponding140 /// This `Block` maps a block ZIR instruction to the corresponding
...@@ -284,13 +285,10 @@ pub const Block = struct {...@@ -284,13 +285,10 @@ pub const Block = struct {
284 });285 });
285 }286 }
286287
287 fn addArg(block: *Block, ty: Type, name: u32) error{OutOfMemory}!Air.Inst.Ref {288 fn addArg(block: *Block, ty: Type) error{OutOfMemory}!Air.Inst.Ref {
288 return block.addInst(.{289 return block.addInst(.{
289 .tag = .arg,290 .tag = .arg,
290 .data = .{ .ty_str = .{291 .data = .{ .ty = ty },
291 .ty = try block.sema.addType(ty),
292 .str = name,
293 } },
294 });292 });
295 }293 }
296294
...@@ -4645,7 +4643,7 @@ fn analyzeCall(...@@ -4645,7 +4643,7 @@ fn analyzeCall(
4645 } else {4643 } else {
4646 // We insert into the map an instruction which is runtime-known4644 // We insert into the map an instruction which is runtime-known
4647 // but has the type of the argument.4645 // but has the type of the argument.
4648 const child_arg = try child_block.addArg(arg_ty, 0);4646 const child_arg = try child_block.addArg(arg_ty);
4649 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);4647 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
4650 }4648 }
4651 }4649 }
...@@ -5712,6 +5710,11 @@ fn funcCommon(...@@ -5712,6 +5710,11 @@ fn funcCommon(
5712 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;5710 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
5713 } else null;5711 } else null;
57145712
5713 const param_names = try sema.gpa.alloc([:0]const u8, block.params.items.len);
5714 for (param_names) |*param_name, i| {
5715 param_name.* = try sema.gpa.dupeZ(u8, block.params.items[i].name);
5716 }
5717
5715 const fn_payload = try sema.arena.create(Value.Payload.Function);5718 const fn_payload = try sema.arena.create(Value.Payload.Function);
5716 new_func.* = .{5719 new_func.* = .{
5717 .state = anal_state,5720 .state = anal_state,
...@@ -5722,6 +5725,7 @@ fn funcCommon(...@@ -5722,6 +5725,7 @@ fn funcCommon(
5722 .rbrace_line = src_locs.rbrace_line,5725 .rbrace_line = src_locs.rbrace_line,
5723 .lbrace_column = @truncate(u16, src_locs.columns),5726 .lbrace_column = @truncate(u16, src_locs.columns),
5724 .rbrace_column = @truncate(u16, src_locs.columns >> 16),5727 .rbrace_column = @truncate(u16, src_locs.columns >> 16),
5728 .param_names = param_names,
5725 };5729 };
5726 if (maybe_inferred_error_set_node) |node| {5730 if (maybe_inferred_error_set_node) |node| {
5727 new_func.inferred_error_sets.prepend(node);5731 new_func.inferred_error_sets.prepend(node);
...@@ -5746,10 +5750,6 @@ fn zirParam(...@@ -5746,10 +5750,6 @@ fn zirParam(
5746 const param_name = sema.code.nullTerminatedString(extra.data.name);5750 const param_name = sema.code.nullTerminatedString(extra.data.name);
5747 const body = sema.code.extra[extra.end..][0..extra.data.body_len];5751 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
57485752
5749 // TODO check if param_name shadows a Decl. This only needs to be done if
5750 // usingnamespace is implemented.
5751 _ = param_name;
5752
5753 // We could be in a generic function instantiation, or we could be evaluating a generic5753 // We could be in a generic function instantiation, or we could be evaluating a generic
5754 // function without any comptime args provided.5754 // function without any comptime args provided.
5755 const param_ty = param_ty: {5755 const param_ty = param_ty: {
...@@ -5776,6 +5776,7 @@ fn zirParam(...@@ -5776,6 +5776,7 @@ fn zirParam(
5776 try block.params.append(sema.gpa, .{5776 try block.params.append(sema.gpa, .{
5777 .ty = Type.initTag(.generic_poison),5777 .ty = Type.initTag(.generic_poison),
5778 .is_comptime = comptime_syntax,5778 .is_comptime = comptime_syntax,
5779 .name = param_name,
5779 });5780 });
5780 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);5781 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
5781 return;5782 return;
...@@ -5801,6 +5802,7 @@ fn zirParam(...@@ -5801,6 +5802,7 @@ fn zirParam(
5801 try block.params.append(sema.gpa, .{5802 try block.params.append(sema.gpa, .{
5802 .ty = param_ty,5803 .ty = param_ty,
5803 .is_comptime = is_comptime,5804 .is_comptime = is_comptime,
5805 .name = param_name,
5804 });5806 });
5805 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));5807 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
5806 try sema.inst_map.putNoClobber(sema.gpa, inst, result);5808 try sema.inst_map.putNoClobber(sema.gpa, inst, result);
...@@ -5816,10 +5818,6 @@ fn zirParamAnytype(...@@ -5816,10 +5818,6 @@ fn zirParamAnytype(
5816 const src = inst_data.src();5818 const src = inst_data.src();
5817 const param_name = inst_data.get(sema.code);5819 const param_name = inst_data.get(sema.code);
58185820
5819 // TODO check if param_name shadows a Decl. This only needs to be done if
5820 // usingnamespace is implemented.
5821 _ = param_name;
5822
5823 if (sema.inst_map.get(inst)) |air_ref| {5821 if (sema.inst_map.get(inst)) |air_ref| {
5824 const param_ty = sema.typeOf(air_ref);5822 const param_ty = sema.typeOf(air_ref);
5825 if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) {5823 if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) {
...@@ -5831,6 +5829,7 @@ fn zirParamAnytype(...@@ -5831,6 +5829,7 @@ fn zirParamAnytype(
5831 try block.params.append(sema.gpa, .{5829 try block.params.append(sema.gpa, .{
5832 .ty = param_ty,5830 .ty = param_ty,
5833 .is_comptime = false,5831 .is_comptime = false,
5832 .name = param_name,
5834 });5833 });
5835 return;5834 return;
5836 }5835 }
...@@ -5840,6 +5839,7 @@ fn zirParamAnytype(...@@ -5840,6 +5839,7 @@ fn zirParamAnytype(
5840 try block.params.append(sema.gpa, .{5839 try block.params.append(sema.gpa, .{
5841 .ty = Type.initTag(.generic_poison),5840 .ty = Type.initTag(.generic_poison),
5842 .is_comptime = comptime_syntax,5841 .is_comptime = comptime_syntax,
5842 .name = param_name,
5843 });5843 });
5844 try sema.inst_map.put(sema.gpa, inst, .generic_poison);5844 try sema.inst_map.put(sema.gpa, inst, .generic_poison);
5845}5845}
src/arch/arm/Emit.zig+2-4
...@@ -393,11 +393,9 @@ fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {...@@ -393,11 +393,9 @@ fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
393fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {393fn genArgDbgInfo(self: *Emit, inst: Air.Inst.Index, arg_index: u32) !void {
394 const mcv = self.function.args[arg_index];394 const mcv = self.function.args[arg_index];
395395
396 const ty_str = self.function.air.instructions.items(.data)[inst].ty_str;396 const ty = self.function.air.instructions.items(.data)[inst].ty;
397 const zir = &self.function.mod_fn.owner_decl.getFileScope().zir;397 const name = self.function.mod_fn.getParamName(arg_index);
398 const name = zir.nullTerminatedString(ty_str.str);
399 const name_with_null = name.ptr[0 .. name.len + 1];398 const name_with_null = name.ptr[0 .. name.len + 1];
400 const ty = self.function.air.getRefType(ty_str.ty);
401399
402 switch (mcv) {400 switch (mcv) {
403 .register => |reg| {401 .register => |reg| {
src/arch/riscv64/CodeGen.zig+4-6
...@@ -1340,12 +1340,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1340,12 +1340,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
1340 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });1340 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
1341}1341}
13421342
1343fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue) !void {1343fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
1344 const ty_str = self.air.instructions.items(.data)[inst].ty_str;1344 const ty = self.air.instructions.items(.data)[inst].ty;
1345 const zir = &self.mod_fn.owner_decl.getFileScope().zir;1345 const name = self.mod_fn.getParamName(arg_index);
1346 const name = zir.nullTerminatedString(ty_str.str);
1347 const name_with_null = name.ptr[0 .. name.len + 1];1346 const name_with_null = name.ptr[0 .. name.len + 1];
1348 const ty = self.air.getRefType(ty_str.ty);
13491347
1350 switch (mcv) {1348 switch (mcv) {
1351 .register => |reg| {1349 .register => |reg| {
...@@ -1388,7 +1386,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -1388,7 +1386,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1388 // TODO support stack-only arguments1386 // TODO support stack-only arguments
1389 // TODO Copy registers to the stack1387 // TODO Copy registers to the stack
1390 const mcv = result;1388 const mcv = result;
1391 try self.genArgDbgInfo(inst, mcv);1389 try self.genArgDbgInfo(inst, mcv, @intCast(u32, arg_index));
13921390
1393 if (self.liveness.isUnused(inst))1391 if (self.liveness.isUnused(inst))
1394 return self.finishAirBookkeeping();1392 return self.finishAirBookkeeping();
src/arch/x86_64/Emit.zig+4-6
...@@ -946,15 +946,13 @@ fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -946,15 +946,13 @@ fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
946 const payload = emit.mir.instructions.items(.data)[inst].payload;946 const payload = emit.mir.instructions.items(.data)[inst].payload;
947 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;947 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;
948 const mcv = emit.mir.function.args[arg_dbg_info.arg_index];948 const mcv = emit.mir.function.args[arg_dbg_info.arg_index];
949 try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv, arg_dbg_info.max_stack);949 try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv, arg_dbg_info.max_stack, arg_dbg_info.arg_index);
950}950}
951951
952fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32) !void {952fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, max_stack: u32, arg_index: u32) !void {
953 const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;953 const ty = emit.mir.function.air.instructions.items(.data)[inst].ty;
954 const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;954 const name = emit.mir.function.mod_fn.getParamName(arg_index);
955 const name = zir.nullTerminatedString(ty_str.str);
956 const name_with_null = name.ptr[0 .. name.len + 1];955 const name_with_null = name.ptr[0 .. name.len + 1];
957 const ty = emit.mir.function.air.getRefType(ty_str.ty);
958956
959 switch (mcv) {957 switch (mcv) {
960 .register => |reg| {958 .register => |reg| {
src/print_air.zig+1-8
...@@ -100,8 +100,6 @@ const Writer = struct {...@@ -100,8 +100,6 @@ const Writer = struct {
100 const tag = tags[inst];100 const tag = tags[inst];
101 try s.print("= {s}(", .{@tagName(tags[inst])});101 try s.print("= {s}(", .{@tagName(tags[inst])});
102 switch (tag) {102 switch (tag) {
103 .arg => try w.writeTyStr(s, inst),
104
105 .add,103 .add,
106 .addwrap,104 .addwrap,
107 .add_sat,105 .add_sat,
...@@ -181,6 +179,7 @@ const Writer = struct {...@@ -181,6 +179,7 @@ const Writer = struct {
181 .const_ty,179 .const_ty,
182 .alloc,180 .alloc,
183 .ret_ptr,181 .ret_ptr,
182 .arg,
184 => try w.writeTy(s, inst),183 => try w.writeTy(s, inst),
185184
186 .not,185 .not,
...@@ -257,12 +256,6 @@ const Writer = struct {...@@ -257,12 +256,6 @@ const Writer = struct {
257 }256 }
258 }257 }
259258
260 fn writeTyStr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
261 const ty_str = w.air.instructions.items(.data)[inst].ty_str;
262 const name = w.zir.nullTerminatedString(ty_str.str);
263 try s.print("\"{}\", {}", .{ std.zig.fmtEscapes(name), w.air.getRefType(ty_str.ty) });
264 }
265
266 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {259 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
267 const bin_op = w.air.instructions.items(.data)[inst].bin_op;260 const bin_op = w.air.instructions.items(.data)[inst].bin_op;
268 try w.writeOperand(s, inst, 0, bin_op.lhs);261 try w.writeOperand(s, inst, 0, bin_op.lhs);