| author | |
| committer | |
| log | 03438118369605df178f4bfdb5b1a8ad6a349be7 |
| tree | 27ea1fa1f07ebc7f704f7d00331e08896a0354d9 |
| parent | 0f112b9f6d390ad4c95b7bf214a8243ad9e3b9a7 |
11 files changed, 134 insertions(+), 2 deletions(-)
src/Air.zig+4-1| ... | ... | @@ -7,7 +7,6 @@ const std = @import("std"); |
| 7 | 7 | const builtin = @import("builtin"); |
| 8 | 8 | const Value = @import("value.zig").Value; |
| 9 | 9 | const Type = @import("type.zig").Type; |
| 10 | const Module = @import("Module.zig"); | |
| 11 | 10 | const assert = std.debug.assert; |
| 12 | 11 | const Air = @This(); |
| 13 | 12 | |
| ... | ... | @@ -327,6 +326,9 @@ pub const Inst = struct { |
| 327 | 326 | /// Result type is always void. |
| 328 | 327 | /// Uses the `dbg_stmt` field. |
| 329 | 328 | dbg_stmt, |
| 329 | /// Marks change of source function. Emitted around an inline call. | |
| 330 | /// Uses `ty_pl` with the payload being the index of a Value.Function in air.values. | |
| 331 | dbg_func, | |
| 330 | 332 | /// Marks the beginning of a local variable. The operand is a pointer pointing |
| 331 | 333 | /// to the storage for the variable. The local may be a const or a var. |
| 332 | 334 | /// Result type is always void. |
| ... | ... | @@ -971,6 +973,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 971 | 973 | |
| 972 | 974 | .breakpoint, |
| 973 | 975 | .dbg_stmt, |
| 976 | .dbg_func, | |
| 974 | 977 | .dbg_var_ptr, |
| 975 | 978 | .dbg_var_val, |
| 976 | 979 | .store, |
src/Liveness.zig+1| ... | ... | @@ -314,6 +314,7 @@ fn analyzeInst( |
| 314 | 314 | .const_ty, |
| 315 | 315 | .breakpoint, |
| 316 | 316 | .dbg_stmt, |
| 317 | .dbg_func, | |
| 317 | 318 | .unreach, |
| 318 | 319 | .fence, |
| 319 | 320 | .ret_addr, |
src/Sema.zig+32| ... | ... | @@ -4639,6 +4639,10 @@ fn analyzeCall( |
| 4639 | 4639 | // comptime state. |
| 4640 | 4640 | var should_memoize = true; |
| 4641 | 4641 | |
| 4642 | var new_fn_info = module_fn.owner_decl.ty.fnInfo(); | |
| 4643 | new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len); | |
| 4644 | new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr; | |
| 4645 | ||
| 4642 | 4646 | // This will have return instructions analyzed as break instructions to |
| 4643 | 4647 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" |
| 4644 | 4648 | // for a function body, which means we must map the parameter ZIR instructions to |
| ... | ... | @@ -4658,6 +4662,7 @@ fn analyzeCall( |
| 4658 | 4662 | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 4659 | 4663 | const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst); |
| 4660 | 4664 | const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst); |
| 4665 | new_fn_info.param_types[arg_i] = param_ty; | |
| 4661 | 4666 | const arg_src = call_src; // TODO: better source location |
| 4662 | 4667 | const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src); |
| 4663 | 4668 | try sema.inst_map.putNoClobber(gpa, inst, casted_arg); |
| ... | ... | @@ -4685,6 +4690,7 @@ fn analyzeCall( |
| 4685 | 4690 | .param_anytype, .param_anytype_comptime => { |
| 4686 | 4691 | // No coercion needed. |
| 4687 | 4692 | const uncasted_arg = uncasted_args[arg_i]; |
| 4693 | new_fn_info.param_types[arg_i] = sema.typeOf(uncasted_arg); | |
| 4688 | 4694 | try sema.inst_map.putNoClobber(gpa, inst, uncasted_arg); |
| 4689 | 4695 | |
| 4690 | 4696 | if (is_comptime_call) { |
| ... | ... | @@ -4735,6 +4741,7 @@ fn analyzeCall( |
| 4735 | 4741 | } |
| 4736 | 4742 | break :blk bare_return_type; |
| 4737 | 4743 | }; |
| 4744 | new_fn_info.return_type = fn_ret_ty; | |
| 4738 | 4745 | const parent_fn_ret_ty = sema.fn_ret_ty; |
| 4739 | 4746 | sema.fn_ret_ty = fn_ret_ty; |
| 4740 | 4747 | defer sema.fn_ret_ty = parent_fn_ret_ty; |
| ... | ... | @@ -4757,6 +4764,9 @@ fn analyzeCall( |
| 4757 | 4764 | } |
| 4758 | 4765 | } |
| 4759 | 4766 | |
| 4767 | const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info); | |
| 4768 | if (!is_comptime_call) try sema.emitDbgFunc(block, parent_func.?, module_fn, new_func_resolved_ty); | |
| 4769 | ||
| 4760 | 4770 | const result = result: { |
| 4761 | 4771 | sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) { |
| 4762 | 4772 | error.ComptimeReturn => break :result inlining.comptime_result, |
| ... | ... | @@ -4771,6 +4781,8 @@ fn analyzeCall( |
| 4771 | 4781 | break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 4772 | 4782 | }; |
| 4773 | 4783 | |
| 4784 | if (!is_comptime_call) try sema.emitDbgFunc(block, module_fn, parent_func.?, parent_func.?.owner_decl.ty); | |
| 4785 | ||
| 4774 | 4786 | if (should_memoize and is_comptime_call) { |
| 4775 | 4787 | const result_val = try sema.resolveConstMaybeUndefVal(block, call_src, result); |
| 4776 | 4788 | |
| ... | ... | @@ -5175,6 +5187,26 @@ fn instantiateGenericCall( |
| 5175 | 5187 | return func_inst; |
| 5176 | 5188 | } |
| 5177 | 5189 | |
| 5190 | fn emitDbgFunc( | |
| 5191 | sema: *Sema, | |
| 5192 | block: *Block, | |
| 5193 | old_func: *Module.Fn, | |
| 5194 | new_func: *Module.Fn, | |
| 5195 | new_func_ty: Type, | |
| 5196 | ) CompileError!void { | |
| 5197 | // No change of file; no dbg_func needed. | |
| 5198 | if (old_func == new_func) return; | |
| 5199 | ||
| 5200 | try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func)); | |
| 5201 | _ = try block.addInst(.{ | |
| 5202 | .tag = .dbg_func, | |
| 5203 | .data = .{ .ty_pl = .{ | |
| 5204 | .ty = try sema.addType(new_func_ty), | |
| 5205 | .payload = @intCast(u32, sema.air_values.items.len - 1), | |
| 5206 | } }, | |
| 5207 | }); | |
| 5208 | } | |
| 5209 | ||
| 5178 | 5210 | fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5179 | 5211 | _ = block; |
| 5180 | 5212 | const tracy = trace(@src()); |
src/arch/aarch64/CodeGen.zig+9| ... | ... | @@ -598,6 +598,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 598 | 598 | .fence => try self.airFence(), |
| 599 | 599 | .cond_br => try self.airCondBr(inst), |
| 600 | 600 | .dbg_stmt => try self.airDbgStmt(inst), |
| 601 | .dbg_func => try self.airDbgFunc(inst), | |
| 601 | 602 | .fptrunc => try self.airFptrunc(inst), |
| 602 | 603 | .fpext => try self.airFpext(inst), |
| 603 | 604 | .intcast => try self.airIntCast(inst), |
| ... | ... | @@ -2715,6 +2716,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 2715 | 2716 | return self.finishAirBookkeeping(); |
| 2716 | 2717 | } |
| 2717 | 2718 | |
| 2719 | fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void { | |
| 2720 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 2721 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 2722 | // TODO emit debug info for function change | |
| 2723 | _ = function; | |
| 2724 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | |
| 2725 | } | |
| 2726 | ||
| 2718 | 2727 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 2719 | 2728 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2720 | 2729 | const name = self.air.nullTerminatedString(pl_op.payload); |
src/arch/arm/CodeGen.zig+9| ... | ... | @@ -595,6 +595,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 595 | 595 | .fence => try self.airFence(), |
| 596 | 596 | .cond_br => try self.airCondBr(inst), |
| 597 | 597 | .dbg_stmt => try self.airDbgStmt(inst), |
| 598 | .dbg_func => try self.airDbgFunc(inst), | |
| 598 | 599 | .fptrunc => try self.airFptrunc(inst), |
| 599 | 600 | .fpext => try self.airFpext(inst), |
| 600 | 601 | .intcast => try self.airIntCast(inst), |
| ... | ... | @@ -2835,6 +2836,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 2835 | 2836 | return self.finishAirBookkeeping(); |
| 2836 | 2837 | } |
| 2837 | 2838 | |
| 2839 | fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void { | |
| 2840 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 2841 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 2842 | // TODO emit debug info for function change | |
| 2843 | _ = function; | |
| 2844 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | |
| 2845 | } | |
| 2846 | ||
| 2838 | 2847 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 2839 | 2848 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2840 | 2849 | const name = self.air.nullTerminatedString(pl_op.payload); |
src/arch/riscv64/CodeGen.zig+9| ... | ... | @@ -562,6 +562,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 562 | 562 | .fence => try self.airFence(), |
| 563 | 563 | .cond_br => try self.airCondBr(inst), |
| 564 | 564 | .dbg_stmt => try self.airDbgStmt(inst), |
| 565 | .dbg_func => try self.airDbgFunc(inst), | |
| 565 | 566 | .fptrunc => try self.airFptrunc(inst), |
| 566 | 567 | .fpext => try self.airFpext(inst), |
| 567 | 568 | .intcast => try self.airIntCast(inst), |
| ... | ... | @@ -1640,6 +1641,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1640 | 1641 | return self.finishAirBookkeeping(); |
| 1641 | 1642 | } |
| 1642 | 1643 | |
| 1644 | fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void { | |
| 1645 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 1646 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 1647 | // TODO emit debug info for function change | |
| 1648 | _ = function; | |
| 1649 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | |
| 1650 | } | |
| 1651 | ||
| 1643 | 1652 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 1644 | 1653 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1645 | 1654 | const name = self.air.nullTerminatedString(pl_op.payload); |
src/arch/wasm/CodeGen.zig+1| ... | ... | @@ -1227,6 +1227,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1227 | 1227 | |
| 1228 | 1228 | // TODO |
| 1229 | 1229 | .dbg_stmt, |
| 1230 | .dbg_func, | |
| 1230 | 1231 | .dbg_var_ptr, |
| 1231 | 1232 | .dbg_var_val, |
| 1232 | 1233 | => WValue.none, |
src/arch/x86_64/CodeGen.zig+9| ... | ... | @@ -679,6 +679,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 679 | 679 | .fence => try self.airFence(), |
| 680 | 680 | .cond_br => try self.airCondBr(inst), |
| 681 | 681 | .dbg_stmt => try self.airDbgStmt(inst), |
| 682 | .dbg_func => try self.airDbgFunc(inst), | |
| 682 | 683 | .fptrunc => try self.airFptrunc(inst), |
| 683 | 684 | .fpext => try self.airFpext(inst), |
| 684 | 685 | .intcast => try self.airIntCast(inst), |
| ... | ... | @@ -3670,6 +3671,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 3670 | 3671 | return self.finishAirBookkeeping(); |
| 3671 | 3672 | } |
| 3672 | 3673 | |
| 3674 | fn airDbgFunc(self: *Self, inst: Air.Inst.Index) !void { | |
| 3675 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 3676 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 3677 | // TODO emit debug info for function change | |
| 3678 | _ = function; | |
| 3679 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | |
| 3680 | } | |
| 3681 | ||
| 3673 | 3682 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 3674 | 3683 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3675 | 3684 | const name = self.air.nullTerminatedString(pl_op.payload); |
src/codegen/c.zig+9| ... | ... | @@ -1687,6 +1687,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1687 | 1687 | .block => try airBlock(f, inst), |
| 1688 | 1688 | .bitcast => try airBitcast(f, inst), |
| 1689 | 1689 | .dbg_stmt => try airDbgStmt(f, inst), |
| 1690 | .dbg_func => try airDbgFunc(f, inst), | |
| 1690 | 1691 | .intcast => try airIntCast(f, inst), |
| 1691 | 1692 | .trunc => try airTrunc(f, inst), |
| 1692 | 1693 | .bool_to_int => try airBoolToInt(f, inst), |
| ... | ... | @@ -2660,6 +2661,14 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2660 | 2661 | return CValue.none; |
| 2661 | 2662 | } |
| 2662 | 2663 | |
| 2664 | fn airDbgFunc(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 2665 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | |
| 2666 | const writer = f.object.writer(); | |
| 2667 | const function = f.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 2668 | try writer.print("/* dbg func:{s} */\n", .{function.owner_decl.name}); | |
| 2669 | return CValue.none; | |
| 2670 | } | |
| 2671 | ||
| 2663 | 2672 | fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2664 | 2673 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 2665 | 2674 | const name = f.air.nullTerminatedString(pl_op.payload); |
src/codegen/llvm.zig+44-1| ... | ... | @@ -1754,11 +1754,14 @@ pub const DeclGen = struct { |
| 1754 | 1754 | /// Note that this can be called before the function's semantic analysis has |
| 1755 | 1755 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 1756 | 1756 | fn resolveLlvmFunction(dg: *DeclGen, decl: *Module.Decl) !*const llvm.Value { |
| 1757 | return dg.resolveLlvmFunctionExtra(decl, decl.ty); | |
| 1758 | } | |
| 1759 | ||
| 1760 | fn resolveLlvmFunctionExtra(dg: *DeclGen, decl: *Module.Decl, zig_fn_type: Type) !*const llvm.Value { | |
| 1757 | 1761 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl); |
| 1758 | 1762 | if (gop.found_existing) return gop.value_ptr.*; |
| 1759 | 1763 | |
| 1760 | 1764 | assert(decl.has_tv); |
| 1761 | const zig_fn_type = decl.ty; | |
| 1762 | 1765 | const fn_info = zig_fn_type.fnInfo(); |
| 1763 | 1766 | const target = dg.module.getTarget(); |
| 1764 | 1767 | const sret = firstParamSRet(fn_info, target); |
| ... | ... | @@ -3460,6 +3463,7 @@ pub const FuncGen = struct { |
| 3460 | 3463 | .const_ty => unreachable, |
| 3461 | 3464 | .unreach => self.airUnreach(inst), |
| 3462 | 3465 | .dbg_stmt => self.airDbgStmt(inst), |
| 3466 | .dbg_func => try self.airDbgFunc(inst), | |
| 3463 | 3467 | .dbg_var_ptr => try self.airDbgVarPtr(inst), |
| 3464 | 3468 | .dbg_var_val => try self.airDbgVarVal(inst), |
| 3465 | 3469 | // zig fmt: on |
| ... | ... | @@ -4181,6 +4185,45 @@ pub const FuncGen = struct { |
| 4181 | 4185 | return null; |
| 4182 | 4186 | } |
| 4183 | 4187 | |
| 4188 | fn airDbgFunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 4189 | const dib = self.dg.object.di_builder orelse return null; | |
| 4190 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | |
| 4191 | ||
| 4192 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 4193 | const decl = function.owner_decl; | |
| 4194 | const fn_ty = try self.air.getRefType(ty_pl.ty).copy(self.dg.object.type_map_arena.allocator()); | |
| 4195 | const llvm_func = try self.dg.resolveLlvmFunctionExtra(decl, fn_ty); | |
| 4196 | const fn_info = fn_ty.fnInfo(); | |
| 4197 | const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope); | |
| 4198 | ||
| 4199 | const line_number = decl.src_line + 1; | |
| 4200 | const is_internal_linkage = !self.dg.module.decl_exports.contains(decl); | |
| 4201 | const noret_bit: c_uint = if (fn_info.return_type.isNoReturn()) | |
| 4202 | llvm.DIFlags.NoReturn | |
| 4203 | else | |
| 4204 | 0; | |
| 4205 | const subprogram = dib.createFunction( | |
| 4206 | di_file.toScope(), | |
| 4207 | decl.name, | |
| 4208 | llvm_func.getValueName(), | |
| 4209 | di_file, | |
| 4210 | line_number, | |
| 4211 | try self.dg.lowerDebugType(fn_ty), | |
| 4212 | is_internal_linkage, | |
| 4213 | true, // is definition | |
| 4214 | line_number + function.lbrace_line, // scope line | |
| 4215 | llvm.DIFlags.StaticMember | noret_bit, | |
| 4216 | self.dg.module.comp.bin_file.options.optimize_mode != .Debug, | |
| 4217 | null, // decl_subprogram | |
| 4218 | ); | |
| 4219 | try self.dg.object.di_map.put(self.gpa, decl, subprogram.toNode()); | |
| 4220 | ||
| 4221 | llvm_func.fnSetSubprogram(subprogram); | |
| 4222 | ||
| 4223 | self.di_scope = subprogram.toScope(); | |
| 4224 | return null; | |
| 4225 | } | |
| 4226 | ||
| 4184 | 4227 | fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 4185 | 4228 | const dib = self.dg.object.di_builder orelse return null; |
| 4186 | 4229 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
src/print_air.zig+7| ... | ... | @@ -242,6 +242,7 @@ const Writer = struct { |
| 242 | 242 | .constant => try w.writeConstant(s, inst), |
| 243 | 243 | .assembly => try w.writeAssembly(s, inst), |
| 244 | 244 | .dbg_stmt => try w.writeDbgStmt(s, inst), |
| 245 | .dbg_func => try w.writeDbgFunc(s, inst), | |
| 245 | 246 | .aggregate_init => try w.writeAggregateInit(s, inst), |
| 246 | 247 | .union_init => try w.writeUnionInit(s, inst), |
| 247 | 248 | .br => try w.writeBr(s, inst), |
| ... | ... | @@ -552,6 +553,12 @@ const Writer = struct { |
| 552 | 553 | try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); |
| 553 | 554 | } |
| 554 | 555 | |
| 556 | fn writeDbgFunc(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | |
| 557 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | |
| 558 | const function = w.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 559 | try s.print("{s}", .{function.owner_decl.name}); | |
| 560 | } | |
| 561 | ||
| 555 | 562 | fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 556 | 563 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 557 | 564 | try w.writeOperand(s, inst, 0, pl_op.operand); |