diff --git a/src/Air.zig b/src/Air.zig index aa821dc420..5c559a4088 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -456,6 +456,8 @@ pub const Inst = struct { /// Same as `dbg_var_ptr` except the local is a const, not a var, and the /// operand is the local's value. dbg_var_val, + /// Same as `dbg_var_val` except the local is an inline function argument. + dbg_arg_inline, /// ?T => bool /// Result type is always bool. /// Uses the `un_op` field. @@ -1022,10 +1024,7 @@ pub const Inst = struct { ty: Ref, /// Index into `extra` of a null-terminated string representing the parameter name. /// This is `.none` if debug info is stripped. - name: enum(u32) { - none = std.math.maxInt(u32), - _, - }, + name: NullTerminatedString, }, ty_op: struct { ty: Ref, @@ -1440,6 +1439,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) .dbg_stmt, .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, .store, .store_safe, .fence, @@ -1562,14 +1562,16 @@ pub fn value(air: Air, inst: Inst.Ref, pt: Zcu.PerThread) !?Value { return air.typeOfIndex(index, &pt.zcu.intern_pool).onePossibleValue(pt); } -pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 { - const bytes = std.mem.sliceAsBytes(air.extra[index..]); - var end: usize = 0; - while (bytes[end] != 0) { - end += 1; +pub const NullTerminatedString = enum(u32) { + none = std.math.maxInt(u32), + _, + + pub fn toSlice(nts: NullTerminatedString, air: Air) [:0]const u8 { + if (nts == .none) return ""; + const bytes = std.mem.sliceAsBytes(air.extra[@intFromEnum(nts)..]); + return bytes[0..std.mem.indexOfScalar(u8, bytes, 0).? :0]; } - return bytes[0..end :0]; -} +}; /// Returns whether the given instruction must always be lowered, for instance /// because it can cause side effects. If an instruction does not need to be @@ -1596,6 +1598,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .dbg_inline_block, .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, .ret, .ret_safe, .ret_load, diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig index 77c8344a86..4b92a3a94f 100644 --- a/src/Air/types_resolved.zig +++ b/src/Air/types_resolved.zig @@ -339,6 +339,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool { .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => { if (!checkRef(data.pl_op.operand, zcu)) return false; }, diff --git a/src/Compilation.zig b/src/Compilation.zig index 48387e4501..dc7d0ba925 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2997,14 +2997,26 @@ pub fn saveState(comp: *Compilation) !void { addBuf(&bufs, mem.sliceAsBytes(ip.free_dep_entries.items)); for (ip.locals, pt_headers.items) |*local, pt_header| { - addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); - addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]); - addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); - addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); + if (pt_header.intern_pool.limbs_len > 0) { + addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); + } + if (pt_header.intern_pool.extra_len > 0) { + addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); + } + if (pt_header.intern_pool.items_len > 0) { + addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); + addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); + } + if (pt_header.intern_pool.string_bytes_len > 0) { + addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]); + } + if (pt_header.intern_pool.tracked_insts_len > 0) { + addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); + } + if (pt_header.intern_pool.files_len > 0) { + addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); + addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); + } } //// TODO: compilation errors diff --git a/src/Liveness.zig b/src/Liveness.zig index 4ca28758e2..b75fc402dd 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -464,6 +464,7 @@ pub fn categorizeOperand( .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => { const o = air_datas[@intFromEnum(inst)].pl_op.operand; if (o == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); @@ -1097,6 +1098,7 @@ fn analyzeInst( .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => { const operand = inst_datas[@intFromEnum(inst)].pl_op.operand; return analyzeOperands(a, pass, data, inst, .{ operand, .none, .none }); diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig index 4392f25e10..7a9959481a 100644 --- a/src/Liveness/Verify.zig +++ b/src/Liveness/Verify.zig @@ -157,6 +157,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { }, .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, .wasm_memory_grow, => { const pl_op = data[@intFromEnum(inst)].pl_op; diff --git a/src/Sema.zig b/src/Sema.zig index b511fead33..9feda2c3f1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -376,7 +376,7 @@ pub const Block = struct { c_import_buf: ?*std.ArrayList(u8) = null, - /// If not `null`, this boolean is set when a `dbg_var_ptr` or `dbg_var_val` + /// If not `null`, this boolean is set when a `dbg_var_ptr`, `dbg_var_val`, or `dbg_arg_inline`. /// instruction is emitted. It signals that the innermost lexically /// enclosing `block`/`block_inline` should be translated into a real AIR /// `block` in order for codegen to match lexical scoping for debug vars. @@ -6567,7 +6567,7 @@ fn addDbgVar( const operand_ty = sema.typeOf(operand); const val_ty = switch (air_tag) { .dbg_var_ptr => operand_ty.childType(mod), - .dbg_var_val => operand_ty, + .dbg_var_val, .dbg_arg_inline => operand_ty, else => unreachable, }; if (try sema.typeRequiresComptime(val_ty)) return; @@ -6586,25 +6586,26 @@ fn addDbgVar( if (block.need_debug_scope) |ptr| ptr.* = true; // Add the name to the AIR. - const name_extra_index = try sema.appendAirString(name); + const name_nts = try sema.appendAirString(name); _ = try block.addInst(.{ .tag = air_tag, .data = .{ .pl_op = .{ - .payload = name_extra_index, + .payload = @intFromEnum(name_nts), .operand = operand, } }, }); } -pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!u32 { - const str_extra_index: u32 = @intCast(sema.air_extra.items.len); +pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!Air.NullTerminatedString { + if (str.len == 0) return .none; + const nts: Air.NullTerminatedString = @enumFromInt(sema.air_extra.items.len); const elements_used = str.len / 4 + 1; const elements = try sema.air_extra.addManyAsSlice(sema.gpa, elements_used); const buffer = mem.sliceAsBytes(elements); @memcpy(buffer[0..str.len], str); buffer[str.len] = 0; - return str_extra_index; + return nts; } fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -7748,14 +7749,14 @@ fn analyzeCall( const param_name = sema.code.nullTerminatedString(extra.data.name); const inst = sema.inst_map.get(param).?; - try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name); + try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name); }, .param_anytype, .param_anytype_comptime => { const inst_data = sema.code.instructions.items(.data)[@intFromEnum(param)].str_tok; const param_name = inst_data.get(sema.code); const inst = sema.inst_map.get(param).?; - try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name); + try sema.addDbgVar(&child_block, inst, .dbg_arg_inline, param_name); }, else => continue, }; @@ -8266,7 +8267,7 @@ fn instantiateGenericCall( .name = if (child_block.ownerModule().strip) .none else - @enumFromInt(try sema.appendAirString(fn_zir.nullTerminatedString(param_name))), + try sema.appendAirString(fn_zir.nullTerminatedString(param_name)), } }, })); try child_block.params.append(sema.arena, .{ diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 0db30bfdbd..291518f5f0 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -1240,11 +1240,11 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { }; } - const nav_already_populated, const queue_linker_work = switch (ip.indexToKey(decl_val.toIntern())) { - .func => |f| .{ f.owner_nav == nav_index, false }, - .variable => |v| .{ false, v.owner_nav == nav_index }, - .@"extern" => .{ false, false }, - else => .{ false, true }, + const nav_already_populated, const queue_linker_work, const resolve_type = switch (ip.indexToKey(decl_val.toIntern())) { + .func => |f| .{ f.owner_nav == nav_index, true, false }, + .variable => |v| .{ false, v.owner_nav == nav_index, true }, + .@"extern" => .{ false, false, false }, + else => .{ false, true, true }, }; if (nav_already_populated) { @@ -1317,14 +1317,16 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { queue_codegen: { if (!queue_linker_work) break :queue_codegen; - // Needed for codegen_nav which will call updateDecl and then the - // codegen backend wants full access to the Decl Type. - // We also need this for the `isFnOrHasRuntimeBits` check below. - // TODO: we could make the language more lenient by deferring this work - // to the `codegen_nav` job. - try decl_ty.resolveFully(pt); + if (resolve_type) { + // Needed for codegen_nav which will call updateDecl and then the + // codegen backend wants full access to the Decl Type. + // We also need this for the `isFnOrHasRuntimeBits` check below. + // TODO: we could make the language more lenient by deferring this work + // to the `codegen_nav` job. + try decl_ty.resolveFully(pt); + } - if (!decl_ty.isFnOrHasRuntimeBits(pt)) { + if (!resolve_type or !decl_ty.hasRuntimeBits(pt)) { if (zcu.comp.config.use_llvm) break :queue_codegen; if (file.mod.strip) break :queue_codegen; } @@ -2158,7 +2160,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! .name = if (inner_block.ownerModule().strip) .none else - @enumFromInt(try sema.appendAirString(sema.code.nullTerminatedString(param_name))), + try sema.appendAirString(sema.code.nullTerminatedString(param_name)), } }, }); } diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index cb16dba688..882f3e98e3 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -170,7 +170,9 @@ const DbgInfoReloc = struct { fn genDbgInfo(reloc: DbgInfoReloc, function: Self) !void { switch (reloc.tag) { - .arg => try reloc.genArgDbgInfo(function), + .arg, + .dbg_arg_inline, + => try reloc.genArgDbgInfo(function), .dbg_var_ptr, .dbg_var_val, @@ -201,7 +203,7 @@ const DbgInfoReloc = struct { else => unreachable, // not a possible argument }; - try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc); + try dw.genLocalDebugInfo(.local_arg, reloc.name, reloc.ty, loc); }, .plan9 => {}, .none => {}, @@ -237,7 +239,7 @@ const DbgInfoReloc = struct { break :blk .empty; }, }; - try dwarf.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc); + try dwarf.genLocalDebugInfo(.local_var, reloc.name, reloc.ty, loc); }, .plan9 => {}, .none => {}, @@ -799,6 +801,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => try self.airDbgVar(inst), .call => try self.airCall(inst, .auto), @@ -4220,17 +4223,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const ty = self.typeOfIndex(inst); const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; - - const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; - if (name_nts != .none) { - const name = self.air.nullTerminatedString(@intFromEnum(name_nts)); - try self.dbg_info_relocs.append(self.gpa, .{ - .tag = tag, - .ty = ty, - .name = name, - .mcv = self.args[arg_index], - }); - } + const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; + if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{ + .tag = tag, + .ty = ty, + .name = name.toSlice(self.air), + .mcv = self.args[arg_index], + }); const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index]; return self.finishAir(inst, result, .{ .none, .none, .none }); @@ -4644,14 +4643,14 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const ty = self.typeOf(operand); const mcv = try self.resolveInst(operand); - const name = self.air.nullTerminatedString(pl_op.payload); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv }); try self.dbg_info_relocs.append(self.gpa, .{ .tag = tag, .ty = ty, - .name = name, + .name = name.toSlice(self.air), .mcv = mcv, }); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 6e33b9b51f..796d3e34dc 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -248,7 +248,9 @@ const DbgInfoReloc = struct { fn genDbgInfo(reloc: DbgInfoReloc, function: Self) !void { switch (reloc.tag) { - .arg => try reloc.genArgDbgInfo(function), + .arg, + .dbg_arg_inline, + => try reloc.genArgDbgInfo(function), .dbg_var_ptr, .dbg_var_val, @@ -279,7 +281,7 @@ const DbgInfoReloc = struct { else => unreachable, // not a possible argument }; - try dw.genVarDebugInfo(.local_arg, reloc.name, reloc.ty, loc); + try dw.genLocalDebugInfo(.local_arg, reloc.name, reloc.ty, loc); }, .plan9 => {}, .none => {}, @@ -315,7 +317,7 @@ const DbgInfoReloc = struct { break :blk .empty; }, }; - try dw.genVarDebugInfo(.local_var, reloc.name, reloc.ty, loc); + try dw.genLocalDebugInfo(.local_var, reloc.name, reloc.ty, loc); }, .plan9 => {}, .none => {}, @@ -786,6 +788,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => try self.airDbgVar(inst), .call => try self.airCall(inst, .auto), @@ -4199,16 +4202,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const ty = self.typeOfIndex(inst); const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; - const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; - if (name_nts != .none) { - const name = self.air.nullTerminatedString(@intFromEnum(name_nts)); - try self.dbg_info_relocs.append(self.gpa, .{ - .tag = tag, - .ty = ty, - .name = name, - .mcv = self.args[arg_index], - }); - } + const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; + if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{ + .tag = tag, + .ty = ty, + .name = name.toSlice(self.air), + .mcv = self.args[arg_index], + }); const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index]; return self.finishAir(inst, result, .{ .none, .none, .none }); @@ -4612,14 +4612,14 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const ty = self.typeOf(operand); const mcv = try self.resolveInst(operand); - const name = self.air.nullTerminatedString(pl_op.payload); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv }); try self.dbg_info_relocs.append(self.gpa, .{ .tag = tag, .ty = ty, - .name = name, + .name = name.toSlice(self.air), .mcv = mcv, }); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index bfbd91ba21..deeb0dc4da 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1644,6 +1644,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => try func.airDbgVar(inst), .dbg_inline_block => try func.airDbgInlineBlock(inst), @@ -4673,11 +4674,15 @@ fn genArgDbgInfo(func: Func, inst: Air.Inst.Index, mcv: MCValue) !void { const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg; const ty = arg.ty.toType(); if (arg.name == .none) return; - const name = func.air.nullTerminatedString(@intFromEnum(arg.name)); switch (func.debug_output) { .dwarf => |dw| switch (mcv) { - .register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{ .reg = reg.dwarfNum() }), + .register => |reg| try dw.genLocalDebugInfo( + .local_arg, + arg.name.toSlice(func.air), + ty, + .{ .reg = reg.dwarfNum() }, + ), .load_frame => {}, else => {}, }, @@ -5179,16 +5184,17 @@ fn airDbgVar(func: *Func, inst: Air.Inst.Index) !void { const operand = pl_op.operand; const ty = func.typeOf(operand); const mcv = try func.resolveInst(operand); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); - const name = func.air.nullTerminatedString(pl_op.payload); - - try func.genVarDbgInfo(ty, mcv, name); + const tag = func.air.instructions.items(.tag)[@intFromEnum(inst)]; + try func.genVarDbgInfo(tag, ty, mcv, name.toSlice(func.air)); return func.finishAir(inst, .unreach, .{ operand, .none, .none }); } fn genVarDbgInfo( func: Func, + tag: Air.Inst.Tag, ty: Type, mcv: MCValue, name: []const u8, @@ -5205,7 +5211,11 @@ fn genVarDbgInfo( break :blk .empty; }, }; - try dwarf.genVarDebugInfo(.local_var, name, ty, loc); + try dwarf.genLocalDebugInfo(switch (tag) { + else => unreachable, + .dbg_var_ptr, .dbg_var_val => .local_var, + .dbg_arg_inline => .local_arg, + }, name, ty, loc); }, .plan9 => {}, .none => {}, diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index a3d3f107a2..99192aa554 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -643,6 +643,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => try self.airDbgVar(inst), .call => try self.airCall(inst, .auto), @@ -1662,7 +1663,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const name = self.air.nullTerminatedString(pl_op.payload); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); const operand = pl_op.operand; // TODO emit debug info for this variable _ = name; @@ -3582,13 +3583,15 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; const ty = arg.ty.toType(); if (arg.name == .none) return; - const name = self.air.nullTerminatedString(@intFromEnum(arg.name)); switch (self.debug_output) { .dwarf => |dw| switch (mcv) { - .register => |reg| try dw.genVarDebugInfo(.local_arg, name, ty, .{ - .reg = reg.dwarfNum(), - }), + .register => |reg| try dw.genLocalDebugInfo( + .local_arg, + arg.name.toSlice(self.air), + ty, + .{ .reg = reg.dwarfNum() }, + ), else => {}, }, else => {}, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 33b1fd31c2..d2e9db8062 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1917,8 +1917,9 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .dbg_stmt => func.airDbgStmt(inst), .dbg_inline_block => func.airDbgInlineBlock(inst), - .dbg_var_ptr => func.airDbgVar(inst, true), - .dbg_var_val => func.airDbgVar(inst, false), + .dbg_var_ptr => func.airDbgVar(inst, .local_var, true), + .dbg_var_val => func.airDbgVar(inst, .local_var, false), + .dbg_arg_inline => func.airDbgVar(inst, .local_arg, false), .call => func.airCall(inst, .auto), .call_always_tail => func.airCall(inst, .always_tail), @@ -2585,13 +2586,13 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { switch (func.debug_output) { .dwarf => |dwarf| { - const name_nts = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; - if (name_nts != .none) { - const name = func.air.nullTerminatedString(@intFromEnum(name_nts)); - try dwarf.genVarDebugInfo(.local_arg, name, arg_ty, .{ - .wasm_ext = .{ .local = arg.local.value }, - }); - } + const name = func.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; + if (name != .none) try dwarf.genLocalDebugInfo( + .local_arg, + name.toSlice(func.air), + arg_ty, + .{ .wasm_ext = .{ .local = arg.local.value } }, + ); }, else => {}, } @@ -6454,7 +6455,12 @@ fn airDbgInlineBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { try func.lowerBlock(inst, ty_pl.ty.toType(), @ptrCast(func.air.extra[extra.end..][0..extra.data.body_len])); } -fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void { +fn airDbgVar( + func: *CodeGen, + inst: Air.Inst.Index, + local_tag: link.File.Dwarf.WipNav.LocalTag, + is_ptr: bool, +) InnerError!void { _ = is_ptr; if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{}); @@ -6464,8 +6470,8 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand }); - const name = func.air.nullTerminatedString(pl_op.payload); - log.debug(" var name = ({s})", .{name}); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); + log.debug(" var name = ({s})", .{name.toSlice(func.air)}); const loc: link.File.Dwarf.Loc = switch (operand) { .local => |local| .{ .wasm_ext = .{ .local = local.value } }, @@ -6474,7 +6480,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) InnerError!void break :blk .empty; }, }; - try func.debug_output.dwarf.genVarDebugInfo(.local_var, name, ty, loc); + try func.debug_output.dwarf.genLocalDebugInfo(local_tag, name.toSlice(func.air), ty, loc); return func.finishAir(inst, .none, &.{}); } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 86fb2bf3e9..1fd231460e 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -64,8 +64,8 @@ va_info: union { sysv: struct { gp_count: u32, fp_count: u32, - overflow_arg_area: FrameAddr, - reg_save_area: FrameAddr, + overflow_arg_area: bits.FrameAddr, + reg_save_area: bits.FrameAddr, }, win64: struct {}, }, @@ -81,9 +81,6 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, /// MIR extra data mir_extra: std.ArrayListUnmanaged(u32) = .{}, -stack_args: std.ArrayListUnmanaged(StackVar) = .{}, -stack_vars: std.ArrayListUnmanaged(StackVar) = .{}, - /// Byte offset within the source file of the ending curly. end_di_line: u32, end_di_column: u32, @@ -113,10 +110,6 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; -const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; -const RegisterOffset = struct { reg: Register, off: i32 = 0 }; -const SymbolOffset = struct { sym: u32, off: i32 = 0 }; - const Owner = union(enum) { nav_index: InternPool.Nav.Index, lazy_sym: link.File.LazySymbol, @@ -174,7 +167,7 @@ pub const MCValue = union(enum) { /// The value is split across two registers. register_pair: [2]Register, /// The value is a constant offset from the value in a register. - register_offset: RegisterOffset, + register_offset: bits.RegisterOffset, /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register. register_overflow: struct { reg: Register, eflags: Condition }, /// The value is in memory at a hard-coded address. @@ -182,11 +175,11 @@ pub const MCValue = union(enum) { memory: u64, /// The value is in memory at an address not-yet-allocated by the linker. /// This traditionally corresponds to a relocation emitted in a relocatable object file. - load_symbol: SymbolOffset, + load_symbol: bits.SymbolOffset, /// The address of the memory location not-yet-allocated by the linker. - lea_symbol: SymbolOffset, + lea_symbol: bits.SymbolOffset, /// The value is in memory at a constant offset from the address in a register. - indirect: RegisterOffset, + indirect: bits.RegisterOffset, /// The value is in memory. /// Payload is a symbol index. load_direct: u32, @@ -207,10 +200,10 @@ pub const MCValue = union(enum) { lea_tlv: u32, /// The value stored at an offset from a frame index /// Payload is a frame address. - load_frame: FrameAddr, + load_frame: bits.FrameAddr, /// The address of an offset from a frame index /// Payload is a frame address. - lea_frame: FrameAddr, + lea_frame: bits.FrameAddr, /// Supports integer_per_element abi elementwise_regs_then_frame: packed struct { regs: u3 = 0, frame_off: i29 = 0, frame_index: FrameIndex }, /// This indicates that we have already allocated a frame index for this instruction, @@ -426,10 +419,7 @@ pub const MCValue = union(enum) { .load_symbol => |sym_off| { assert(sym_off.off == 0); return .{ - .base = .{ .reloc = .{ - .atom_index = try function.owner.getSymbolIndex(function), - .sym_index = sym_off.sym, - } }, + .base = .{ .reloc = sym_off.sym_index }, .mod = .{ .rm = .{ .size = size, .disp = sym_off.off, @@ -456,8 +446,8 @@ pub const MCValue = union(enum) { .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg), }), - .load_symbol => |pl| try writer.print("[{} + 0x{x}]", .{ pl.sym, pl.off }), - .lea_symbol => |pl| try writer.print("{} + 0x{x}", .{ pl.sym, pl.off }), + .load_symbol => |pl| try writer.print("[{} + 0x{x}]", .{ pl.sym_index, pl.off }), + .lea_symbol => |pl| try writer.print("{} + 0x{x}", .{ pl.sym_index, pl.off }), .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), @@ -728,12 +718,6 @@ const InstTracking = struct { } }; -const StackVar = struct { - name: []const u8, - type: Type, - frame_addr: FrameAddr, -}; - const FrameAlloc = struct { abi_size: u31, spill_pad: u3, @@ -839,8 +823,6 @@ pub fn generate( function.exitlude_jump_relocs.deinit(gpa); function.mir_instructions.deinit(gpa); function.mir_extra.deinit(gpa); - function.stack_args.deinit(gpa); - function.stack_vars.deinit(gpa); } wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)}); @@ -913,9 +895,6 @@ pub fn generate( else => |e| return e, }; - try function.genStackVarDebugInfo(.local_arg, function.stack_args.items); - try function.genStackVarDebugInfo(.local_var, function.stack_vars.items); - var mir: Mir = .{ .instructions = function.mir_instructions.toOwnedSlice(), .extra = try function.mir_extra.toOwnedSlice(gpa), @@ -924,6 +903,7 @@ pub fn generate( defer mir.deinit(gpa); var emit: Emit = .{ + .air = function.air, .lower = .{ .bin_file = bin_file, .allocator = gpa, @@ -934,6 +914,13 @@ pub fn generate( .link_mode = comp.config.link_mode, .pic = mod.pic, }, + .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) { + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ + .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), + }, + else => |e| return e, + }, .debug_output = debug_output, .code = code, .prev_di_pc = 0, @@ -1013,14 +1000,15 @@ pub fn generateLazy( else => |e| return e, }; - var mir = Mir{ + var mir: Mir = .{ .instructions = function.mir_instructions.toOwnedSlice(), .extra = try function.mir_extra.toOwnedSlice(gpa), .frame_locs = function.frame_locs.toOwnedSlice(), }; defer mir.deinit(gpa); - var emit = Emit{ + var emit: Emit = .{ + .air = function.air, .lower = .{ .bin_file = bin_file, .allocator = gpa, @@ -1031,6 +1019,13 @@ pub fn generateLazy( .link_mode = comp.config.link_mode, .pic = mod.pic, }, + .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) { + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ + .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), + }, + else => |e| return e, + }, .debug_output = debug_output, .code = code, .prev_di_pc = undefined, // no debug info yet @@ -1116,7 +1111,7 @@ fn formatWipMir( ) @TypeOf(writer).Error!void { const comp = data.self.bin_file.comp; const mod = comp.root_mod; - var lower = Lower{ + var lower: Lower = .{ .bin_file = data.self.bin_file, .allocator = data.self.gpa, .mir = .{ @@ -1204,6 +1199,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { self.mir_extra.appendAssumeCapacity(switch (field.type) { u32 => @field(extra, field.name), i32, Mir.Memory.Info => @bitCast(@field(extra, field.name)), + bits.FrameIndex => @intFromEnum(@field(extra, field.name)), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), }); } @@ -1357,6 +1353,124 @@ fn asmPlaceholder(self: *Self) !Mir.Inst.Index { }); } +const MirTagAir = enum { dbg_local }; + +fn asmAir(self: *Self, tag: MirTagAir, inst: Air.Inst.Index) !void { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_a, + }, + .data = .{ .a = .{ .air_inst = inst } }, + }); +} + +fn asmAirImmediate(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void { + switch (imm) { + .signed => |s| _ = try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_ai_s, + }, + .data = .{ .ai = .{ + .air_inst = inst, + .i = @bitCast(s), + } }, + }), + .unsigned => |u| _ = if (math.cast(u32, u)) |small| try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_ai_u, + }, + .data = .{ .ai = .{ + .air_inst = inst, + .i = small, + } }, + }) else try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_ai_64, + }, + .data = .{ .ai = .{ + .air_inst = inst, + .i = try self.addExtra(Mir.Imm64.encode(u)), + } }, + }), + .reloc => |sym_off| _ = if (sym_off.off == 0) try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_as, + }, + .data = .{ .as = .{ + .air_inst = inst, + .sym_index = sym_off.sym_index, + } }, + }) else try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_aso, + }, + .data = .{ .ax = .{ + .air_inst = inst, + .payload = try self.addExtra(sym_off), + } }, + }), + } +} + +fn asmAirRegisterImmediate( + self: *Self, + tag: MirTagAir, + inst: Air.Inst.Index, + reg: Register, + imm: Immediate, +) !void { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_aro, + }, + .data = .{ .rx = .{ + .r1 = reg, + .payload = try self.addExtra(Mir.AirOffset{ + .air_inst = inst, + .off = imm.signed, + }), + } }, + }); +} + +fn asmAirFrameAddress( + self: *Self, + tag: MirTagAir, + inst: Air.Inst.Index, + frame_addr: bits.FrameAddr, +) !void { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_af, + }, + .data = .{ .ax = .{ + .air_inst = inst, + .payload = try self.addExtra(frame_addr), + } }, + }); +} + +fn asmAirMemory(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !void { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_am, + }, + .data = .{ .ax = .{ + .air_inst = inst, + .payload = try self.addExtra(Mir.Memory.encode(m)), + } }, + }); +} + fn asmOpOnly(self: *Self, tag: Mir.Inst.FixedTag) !void { _ = try self.addInst(.{ .tag = tag[1], @@ -1395,9 +1509,9 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void { .reloc => .rel, }, .data = switch (imm) { - .reloc => |x| reloc: { + .reloc => |sym_off| reloc: { assert(tag[0] == ._); - break :reloc .{ .reloc = x }; + break :reloc .{ .reloc = sym_off }; }, .signed, .unsigned => .{ .i = .{ .fixes = tag[0], @@ -1424,31 +1538,22 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.FixedTag, reg1: Register, reg2 } fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm: Immediate) !void { - const ops: Mir.Inst.Ops = switch (imm) { - .signed => .ri_s, - .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64, + const ops: Mir.Inst.Ops, const i: u32 = switch (imm) { + .signed => |s| .{ .ri_s, @bitCast(s) }, + .unsigned => |u| if (math.cast(u32, u)) |small| + .{ .ri_u, small } + else + .{ .ri_64, try self.addExtra(Mir.Imm64.encode(imm.unsigned)) }, .reloc => unreachable, }; _ = try self.addInst(.{ .tag = tag[1], .ops = ops, - .data = switch (ops) { - .ri_s, .ri_u => .{ .ri = .{ - .fixes = tag[0], - .r1 = reg, - .i = switch (imm) { - .signed => |s| @bitCast(s), - .unsigned => |u| @intCast(u), - .reloc => unreachable, - }, - } }, - .ri64 => .{ .rx = .{ - .fixes = tag[0], - .r1 = reg, - .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)), - } }, - else => unreachable, - }, + .data = .{ .ri = .{ + .fixes = tag[0], + .r1 = reg, + .i = i, + } }, }); } @@ -2158,6 +2263,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => try self.airDbgVar(inst), .call => try self.airCall(inst, .auto), @@ -2485,12 +2591,12 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo }; } -fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment { +fn getFrameAddrAlignment(self: *Self, frame_addr: bits.FrameAddr) Alignment { const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off))); } -fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { +fn getFrameAddrSize(self: *Self, frame_addr: bits.FrameAddr) u32 { return self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_size - @as(u31, @intCast(frame_addr.off)); } @@ -11951,87 +12057,65 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { fn airDbgArg(self: *Self, inst: Air.Inst.Index) !void { defer self.finishAirBookkeeping(); if (self.debug_output == .none) return; - const name_nts = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; - const name = self.air.nullTerminatedString(@intFromEnum(name_nts)); - if (name.len > 0) { - const arg_ty = self.typeOfIndex(inst); - const arg_mcv = self.getResolvedInstValue(inst).short; - try self.genVarDebugInfo(.local_arg, .dbg_var_val, name, arg_ty, arg_mcv); - } + const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; + if (name != .none) try self.genLocalDebugInfo(inst, self.getResolvedInstValue(inst).short); if (self.liveness.isUnused(inst)) try self.processDeath(inst); } -fn genVarDebugInfo( +fn genLocalDebugInfo( self: *Self, - var_tag: link.File.Dwarf.WipNav.VarTag, - tag: Air.Inst.Tag, - name: []const u8, - ty: Type, + inst: Air.Inst.Index, mcv: MCValue, ) !void { - const stack_vars = switch (var_tag) { - .local_arg => &self.stack_args, - .local_var => &self.stack_vars, - }; - switch (self.debug_output) { - .dwarf => |dwarf| switch (tag) { - else => unreachable, - .dbg_var_ptr => { - const var_ty = ty.childType(self.pt.zcu); - switch (mcv) { - else => { - log.info("dbg_var_ptr({s}({}))", .{ @tagName(mcv), mcv }); - unreachable; - }, - .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable, - .lea_frame => |frame_addr| try stack_vars.append(self.gpa, .{ - .name = name, - .type = var_ty, - .frame_addr = frame_addr, - }), - .lea_symbol => |sym_off| try dwarf.genVarDebugInfo(var_tag, name, var_ty, .{ .plus = .{ - &.{ .addr = .{ .sym = sym_off.sym } }, - &.{ .consts = sym_off.off }, - } }), - } - }, - .dbg_var_val => switch (mcv) { - .none => try dwarf.genVarDebugInfo(var_tag, name, ty, .empty), + if (self.debug_output == .none) return; + switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) { + else => unreachable, + .arg, .dbg_arg_inline, .dbg_var_val => |tag| { + switch (mcv) { + .none => try self.asmAir(.dbg_local, inst), .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable, - .immediate => |immediate| try dwarf.genVarDebugInfo(var_tag, name, ty, .{ .stack_value = &.{ - .constu = immediate, - } }), + .immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, Immediate.u(imm)), + .lea_frame => |frame_addr| try self.asmAirFrameAddress(.dbg_local, inst, frame_addr), + .lea_symbol => |sym_off| try self.asmAirImmediate(.dbg_local, inst, Immediate.rel(sym_off)), else => { + const ty = switch (tag) { + else => unreachable, + .arg => self.typeOfIndex(inst), + .dbg_arg_inline, .dbg_var_val => self.typeOf( + self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op.operand, + ), + }; const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(ty, self.pt)); try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{}); - try stack_vars.append(self.gpa, .{ - .name = name, - .type = ty, - .frame_addr = .{ .index = frame_index }, + try self.asmAirMemory(.dbg_local, inst, .{ + .base = .{ .frame = frame_index }, + .mod = .{ .rm = .{ .size = .qword } }, }); }, - }, + } }, - .plan9 => {}, - .none => {}, - } -} - -fn genStackVarDebugInfo( - self: Self, - var_tag: link.File.Dwarf.WipNav.VarTag, - stack_vars: []const StackVar, -) !void { - switch (self.debug_output) { - .dwarf => |dwarf| for (stack_vars) |stack_var| { - const frame_loc = self.frame_locs.get(@intFromEnum(stack_var.frame_addr.index)); - try dwarf.genVarDebugInfo(var_tag, stack_var.name, stack_var.type, .{ .plus = .{ - &.{ .breg = frame_loc.base.dwarfNum() }, - &.{ .consts = @as(i33, frame_loc.disp) + stack_var.frame_addr.off }, - } }); + .dbg_var_ptr => switch (mcv) { + else => unreachable, + .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable, + .lea_frame => |frame_addr| try self.asmAirMemory(.dbg_local, inst, .{ + .base = .{ .frame = frame_addr.index }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = frame_addr.off, + } }, + }), + .lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{ + .base = .{ .reloc = sym_off.sym_index }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = sym_off.off, + } }, + }), + .lea_direct, .lea_got, .lea_tlv => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{ + .base = .{ .reloc = sym_index }, + .mod = .{ .rm = .{ .size = .qword } }, + }), }, - .plan9 => {}, - .none => {}, } } @@ -12351,10 +12435,7 @@ fn genCall(self: *Self, info: union(enum) { if (self.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index })); } else if (self.bin_file.cast(.coff)) |coff_file| { const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; @@ -12364,10 +12445,7 @@ fn genCall(self: *Self, info: union(enum) { const zo = macho_file.getZigObject().?; const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav); const sym = zo.symbols.items[sym_index]; - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.nlist_idx, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym.nlist_idx })); } else if (self.bin_file.cast(.plan9)) |p9| { const atom_index = try p9.seeNav(pt, func.owner_nav); const atom = p9.getAtom(atom_index); @@ -12385,19 +12463,13 @@ fn genCall(self: *Self, info: union(enum) { @"extern".name.toSlice(ip), @"extern".lib_name.toSlice(ip), ); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else if (self.bin_file.cast(.macho)) |macho_file| { const target_sym_index = try macho_file.getGlobalSymbol( @"extern".name.toSlice(ip), @"extern".lib_name.toSlice(ip), ); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else try self.genExternSymbolRef( .call, @"extern".lib_name.toSlice(ip), @@ -12412,16 +12484,10 @@ fn genCall(self: *Self, info: union(enum) { }, .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| { const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else if (self.bin_file.cast(.macho)) |macho_file| { const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else try self.genExternSymbolRef(.call, lib.lib, lib.callee), } return call_info.return_value.short; @@ -13060,29 +13126,21 @@ fn airDbgInlineBlock(self: *Self, inst: Air.Inst.Index) !void { self.inline_func = extra.data.func; _ = try self.addInst(.{ .tag = .pseudo, - .ops = .pseudo_dbg_inline_func, + .ops = .pseudo_dbg_enter_inline_func, .data = .{ .func = extra.data.func }, }); try self.lowerBlock(inst, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len])); _ = try self.addInst(.{ .tag = .pseudo, - .ops = .pseudo_dbg_inline_func, + .ops = .pseudo_dbg_leave_inline_func, .data = .{ .func = old_inline_func }, }); } fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const operand = pl_op.operand; - const ty = self.typeOf(operand); - const mcv = try self.resolveInst(operand); - - const name = self.air.nullTerminatedString(pl_op.payload); - - const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; - try self.genVarDebugInfo(.local_var, tag, name, ty, mcv); - - return self.finishAir(inst, .unreach, .{ operand, .none, .none }); + try self.genLocalDebugInfo(inst, try self.resolveInst(pl_op.operand)); + return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); } fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index { @@ -14970,10 +15028,7 @@ fn genSetReg( .general_purpose => { assert(sym_off.off == 0); try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{ - .base = .{ .reloc = .{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_off.sym, - } }, + .base = .{ .reloc = sym_off.sym_index }, .mod = .{ .rm = .{ .size = self.memSize(ty), .disp = sym_off.off, @@ -14991,10 +15046,7 @@ fn genSetReg( .ops = .direct_reloc, .data = .{ .rx = .{ .r1 = registerAlias(dst_reg, abi_size), - .payload = try self.addExtra(bits.Symbol{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_index, - }), + .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }), } }, }); return; @@ -15019,52 +15071,38 @@ fn genSetReg( }, ); }, - .lea_symbol => |sym_index| { - const atom_index = try self.owner.getSymbolIndex(self); - switch (self.bin_file.tag) { - .elf, .macho => { - try self.asmRegisterMemory( - .{ ._, .lea }, - dst_reg.to64(), - .{ - .base = .{ .reloc = .{ - .atom_index = atom_index, - .sym_index = sym_index.sym, - } }, - .mod = .{ .rm = .{ - .size = .qword, - .disp = sym_index.off, - } }, - }, - ); + .lea_symbol => |sym_off| switch (self.bin_file.tag) { + .elf, .macho => try self.asmRegisterMemory( + .{ ._, .lea }, + dst_reg.to64(), + .{ + .base = .{ .reloc = sym_off.sym_index }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = sym_off.off, + } }, }, - else => return self.fail("TODO emit symbol sequence on {s}", .{ - @tagName(self.bin_file.tag), - }), - } - }, - .lea_direct, .lea_got => |sym_index| { - const atom_index = try self.owner.getSymbolIndex(self); - _ = try self.addInst(.{ - .tag = switch (src_mcv) { - .lea_direct => .lea, - .lea_got => .mov, - else => unreachable, - }, - .ops = switch (src_mcv) { - .lea_direct => .direct_reloc, - .lea_got => .got_reloc, - else => unreachable, - }, - .data = .{ .rx = .{ - .r1 = dst_reg.to64(), - .payload = try self.addExtra(bits.Symbol{ - .atom_index = atom_index, - .sym_index = sym_index, - }), - } }, - }); + ), + else => return self.fail("TODO emit symbol sequence on {s}", .{ + @tagName(self.bin_file.tag), + }), }, + .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{ + .tag = switch (src_mcv) { + .lea_direct => .lea, + .lea_got => .mov, + else => unreachable, + }, + .ops = switch (src_mcv) { + .lea_direct => .direct_reloc, + .lea_got => .got_reloc, + else => unreachable, + }, + .data = .{ .rx = .{ + .r1 = dst_reg.to64(), + .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }), + } }, + }), .lea_tlv => unreachable, // TODO: remove this .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts), } @@ -15085,7 +15123,7 @@ fn genSetMem( .none => .{ .immediate = @bitCast(@as(i64, disp)) }, .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } }, - .reloc => |base_symbol| .{ .lea_symbol = .{ .sym = base_symbol.sym_index, .off = disp } }, + .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } }, }; switch (src_mcv) { .none, @@ -15328,7 +15366,6 @@ fn genExternSymbolRef( lib: ?[]const u8, callee: []const u8, ) InnerError!void { - const atom_index = try self.owner.getSymbolIndex(self); if (self.bin_file.cast(.coff)) |coff_file| { const global_index = try coff_file.getGlobalSymbol(callee, lib); _ = try self.addInst(.{ @@ -15336,8 +15373,7 @@ fn genExternSymbolRef( .ops = .import_reloc, .data = .{ .rx = .{ .r1 = .rax, - .payload = try self.addExtra(bits.Symbol{ - .atom_index = atom_index, + .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = link.File.Coff.global_symbol_bit | global_index, }), } }, @@ -15364,10 +15400,10 @@ fn genLazySymbolRef( if (self.mod.pic) { switch (tag) { .lea, .call => try self.genSetReg(reg, Type.usize, .{ - .lea_symbol = .{ .sym = sym_index }, + .lea_symbol = .{ .sym_index = sym_index }, }, .{}), .mov => try self.genSetReg(reg, Type.usize, .{ - .load_symbol = .{ .sym = sym_index }, + .load_symbol = .{ .sym_index = sym_index }, }, .{}), else => unreachable, } @@ -15376,19 +15412,13 @@ fn genLazySymbolRef( .call => try self.asmRegister(.{ ._, .call }, reg), else => unreachable, } - } else { - const reloc = bits.Symbol{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_index, - }; - switch (tag) { - .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ - .base = .{ .reloc = reloc }, - .mod = .{ .rm = .{ .size = .qword } }, - }), - .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(reloc)), - else => unreachable, - } + } else switch (tag) { + .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ + .base = .{ .reloc = sym_index }, + .mod = .{ .rm = .{ .size = .qword } }, + }), + .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index })), + else => unreachable, } } else if (self.bin_file.cast(.plan9)) |p9_file| { const atom_index = p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| @@ -15438,10 +15468,10 @@ fn genLazySymbolRef( const sym = zo.symbols.items[sym_index]; switch (tag) { .lea, .call => try self.genSetReg(reg, Type.usize, .{ - .lea_symbol = .{ .sym = sym.nlist_idx }, + .lea_symbol = .{ .sym_index = sym.nlist_idx }, }, .{}), .mov => try self.genSetReg(reg, Type.usize, .{ - .load_symbol = .{ .sym = sym.nlist_idx }, + .load_symbol = .{ .sym_index = sym.nlist_idx }, }, .{}), else => unreachable, } @@ -18786,7 +18816,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { .{ .frame = frame_index }, 0, Type.usize, - .{ .lea_symbol = .{ .sym = tlv_sym } }, + .{ .lea_symbol = .{ .sym_index = tlv_sym } }, .{}, ); break :init .{ .load_frame = .{ .index = frame_index } }; @@ -18842,8 +18872,8 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { .undef => .undef, .immediate => |imm| .{ .immediate = imm }, .memory => |addr| .{ .memory = addr }, - .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, - .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } }, + .load_symbol => |sym_index| .{ .load_symbol = .{ .sym_index = sym_index } }, + .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index } }, .load_direct => |sym_index| .{ .load_direct = sym_index }, .lea_direct => |sym_index| .{ .lea_direct = sym_index }, .load_got => |sym_index| .{ .lea_got = sym_index }, diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index f168464f6f..579fd00d9d 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -1,6 +1,8 @@ //! This file contains the functionality for emitting x86_64 MIR as machine code +air: Air, lower: Lower, +atom_index: u32, debug_output: DebugInfoOutput, code: *std.ArrayList(u8), @@ -36,83 +38,84 @@ pub fn emitMir(emit: *Emit) Error!void { }) switch (lowered_relocs[0].target) { .inst => |target| try emit.relocs.append(emit.lower.allocator, .{ .source = start_offset, + .source_offset = end_offset - 4, .target = target, - .offset = end_offset - 4, + .target_offset = lowered_relocs[0].off, .length = @intCast(end_offset - start_offset), }), - .linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(.elf)) |elf_file| { + .linker_extern_fn => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { // Add relocation to the decl. const zo = elf_file.zigObjectPtr().?; - const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; + const atom_ptr = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.PLT32); try atom_ptr.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type, - .r_addend = -4, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off - 4, }); } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { // Add relocation to the decl. const zo = macho_file.getZigObject().?; - const atom = zo.symbols.items[symbol.atom_index].getAtom(macho_file).?; + const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; try atom.addReloc(macho_file, .{ .tag = .@"extern", .offset = end_offset - 4, - .target = symbol.sym_index, - .addend = 0, + .target = sym_index, + .addend = lowered_relocs[0].off, .type = .branch, .meta = .{ .pcrel = true, .has_subtractor = false, .length = 2, - .symbolnum = @intCast(symbol.sym_index), + .symbolnum = @intCast(sym_index), }, }); } else if (emit.lower.bin_file.cast(.coff)) |coff_file| { // Add relocation to the decl. const atom_index = coff_file.getAtomIndexForSymbol( - .{ .sym_index = symbol.atom_index, .file = null }, + .{ .sym_index = emit.atom_index, .file = null }, ).?; - const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0) - coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index) + const target = if (link.File.Coff.global_symbol_bit & sym_index != 0) + coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index) else - link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null }; + link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null }; try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = .direct, .target = target, .offset = end_offset - 4, - .addend = 0, + .addend = @intCast(lowered_relocs[0].off), .pcrel = true, .length = 2, }); } else return emit.fail("TODO implement extern reloc for {s}", .{ @tagName(emit.lower.bin_file.tag), }), - .linker_tlsld => |data| { + .linker_tlsld => |sym_index| { const elf_file = emit.lower.bin_file.cast(.elf).?; const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(data.atom_index).atom(elf_file).?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = -4, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off - 4, }); }, - .linker_dtpoff => |data| { + .linker_dtpoff => |sym_index| { const elf_file = emit.lower.bin_file.cast(.elf).?; const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(data.atom_index).atom(elf_file).?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = 0, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off, }); }, - .linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| { + .linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(data.atom_index).atom(elf_file).?; - const sym = zo.symbol(data.sym_index); + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; + const sym = zo.symbol(sym_index); if (emit.lower.pic) { const r_type: u32 = if (sym.flags.is_extern_ptr) @intFromEnum(std.elf.R_X86_64.GOTPCREL) @@ -120,8 +123,8 @@ pub fn emitMir(emit: *Emit) Error!void { @intFromEnum(std.elf.R_X86_64.PC32); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = -4, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off - 4, }); } else { const r_type: u32 = if (sym.flags.is_tls) @@ -130,14 +133,14 @@ pub fn emitMir(emit: *Emit) Error!void { @intFromEnum(std.elf.R_X86_64.@"32"); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = 0, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off, }); } } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; - const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?; - const sym = &zo.symbols.items[data.sym_index]; + const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; + const sym = &zo.symbols.items[sym_index]; const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr) .got_load else if (sym.flags.tlv) @@ -147,33 +150,33 @@ pub fn emitMir(emit: *Emit) Error!void { try atom.addReloc(macho_file, .{ .tag = .@"extern", .offset = @intCast(end_offset - 4), - .target = data.sym_index, - .addend = 0, + .target = sym_index, + .addend = lowered_relocs[0].off, .type = @"type", .meta = .{ .pcrel = true, .has_subtractor = false, .length = 2, - .symbolnum = @intCast(data.sym_index), + .symbolnum = @intCast(sym_index), }, }); } else unreachable, .linker_got, .linker_direct, .linker_import, - => |symbol| if (emit.lower.bin_file.cast(.elf)) |_| { + => |sym_index| if (emit.lower.bin_file.cast(.elf)) |_| { unreachable; } else if (emit.lower.bin_file.cast(.macho)) |_| { unreachable; } else if (emit.lower.bin_file.cast(.coff)) |coff_file| { const atom_index = coff_file.getAtomIndexForSymbol(.{ - .sym_index = symbol.atom_index, + .sym_index = emit.atom_index, .file = null, }).?; - const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0) - coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index) + const target = if (link.File.Coff.global_symbol_bit & sym_index != 0) + coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index) else - link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null }; + link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null }; try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = switch (lowered_relocs[0].target) { .linker_got => .got, @@ -183,16 +186,15 @@ pub fn emitMir(emit: *Emit) Error!void { }, .target = target, .offset = @intCast(end_offset - 4), - .addend = 0, + .addend = @intCast(lowered_relocs[0].off), .pcrel = true, .length = 2, }); } else if (emit.lower.bin_file.cast(.plan9)) |p9_file| { - const atom_index = symbol.atom_index; - try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct - .target = symbol.sym_index, // we set sym_index to just be the atom index + try p9_file.addReloc(emit.atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct + .target = sym_index, // we set sym_index to just be the atom index .offset = @intCast(end_offset - 4), - .addend = 0, + .addend = @intCast(lowered_relocs[0].off), .type = .pcrel, }); } else return emit.fail("TODO implement linker reloc for {s}", .{ @@ -232,13 +234,151 @@ pub fn emitMir(emit: *Emit) Error!void { .none => {}, } }, - .pseudo_dbg_inline_func => { + .pseudo_dbg_enter_inline_func => { switch (emit.debug_output) { .dwarf => |dw| { - log.debug("mirDbgInline (line={d}, col={d})", .{ + log.debug("mirDbgEnterInline (line={d}, col={d})", .{ emit.prev_di_line, emit.prev_di_column, }); - try dw.setInlineFunc(mir_inst.data.func); + try dw.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_line, emit.prev_di_column); + }, + .plan9 => {}, + .none => {}, + } + }, + .pseudo_dbg_leave_inline_func => { + switch (emit.debug_output) { + .dwarf => |dw| { + log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ + emit.prev_di_line, emit.prev_di_column, + }); + try dw.leaveInlineFunc(mir_inst.data.func, emit.code.items.len); + }, + .plan9 => {}, + .none => {}, + } + }, + .pseudo_dbg_local_a, + .pseudo_dbg_local_ai_s, + .pseudo_dbg_local_ai_u, + .pseudo_dbg_local_ai_64, + .pseudo_dbg_local_as, + .pseudo_dbg_local_aso, + .pseudo_dbg_local_aro, + .pseudo_dbg_local_af, + .pseudo_dbg_local_am, + => { + switch (emit.debug_output) { + .dwarf => |dw| { + var loc_buf: [2]link.File.Dwarf.Loc = undefined; + const air_inst_index, const loc: link.File.Dwarf.Loc = switch (mir_inst.ops) { + else => unreachable, + .pseudo_dbg_local_a => .{ mir_inst.data.a.air_inst, .empty }, + .pseudo_dbg_local_ai_s, + .pseudo_dbg_local_ai_u, + .pseudo_dbg_local_ai_64, + => .{ mir_inst.data.ai.air_inst, .{ .stack_value = stack_value: { + loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.ai.i)) { + .signed => |s| .{ .consts = s }, + .unsigned => |u| .{ .constu = u }, + }; + break :stack_value &loc_buf[0]; + } } }, + .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{ + .sym = mir_inst.data.as.sym_index, + } } }, + .pseudo_dbg_local_aso => loc: { + const sym_off = emit.lower.mir.extraData( + bits.SymbolOffset, + mir_inst.data.ax.payload, + ).data; + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + sym: { + loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } }; + break :sym &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = sym_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_aro => loc: { + const air_off = emit.lower.mir.extraData( + Mir.AirOffset, + mir_inst.data.rx.payload, + ).data; + break :loc .{ air_off.air_inst, .{ .plus = .{ + reg: { + loc_buf[0] = .{ .breg = mir_inst.data.rx.r1.dwarfNum() }; + break :reg &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = air_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_af => loc: { + const reg_off = emit.lower.mir.resolveFrameAddr(emit.lower.mir.extraData( + bits.FrameAddr, + mir_inst.data.ax.payload, + ).data); + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + reg: { + loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() }; + break :reg &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = reg_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_am => loc: { + const mem = emit.lower.mem(mir_inst.data.ax.payload); + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + base: { + loc_buf[0] = switch (mem.base()) { + .none => .{ .constu = 0 }, + .reg => |reg| .{ .breg = reg.dwarfNum() }, + .frame => unreachable, + .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } }, + }; + break :base &loc_buf[0]; + }, + disp: { + loc_buf[1] = switch (mem.disp()) { + .signed => |s| .{ .consts = s }, + .unsigned => |u| .{ .constu = u }, + }; + break :disp &loc_buf[1]; + }, + } } }; + }, + }; + const ip = &emit.lower.bin_file.comp.module.?.intern_pool; + const air_inst = emit.air.instructions.get(@intFromEnum(air_inst_index)); + const name: Air.NullTerminatedString = switch (air_inst.tag) { + else => unreachable, + .arg => air_inst.data.arg.name, + .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => @enumFromInt(air_inst.data.pl_op.payload), + }; + try dw.genLocalDebugInfo( + switch (air_inst.tag) { + else => unreachable, + .arg, .dbg_arg_inline => .local_arg, + .dbg_var_ptr, .dbg_var_val => .local_var, + }, + name.toSlice(emit.air), + switch (air_inst.tag) { + else => unreachable, + .arg => emit.air.typeOfIndex(air_inst_index, ip), + .dbg_var_ptr => emit.air.typeOf(air_inst.data.pl_op.operand, ip).childTypeIp(ip), + .dbg_var_val, .dbg_arg_inline => emit.air.typeOf(air_inst.data.pl_op.operand, ip), + }, + loc, + ); }, .plan9 => {}, .none => {}, @@ -268,10 +408,12 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error { const Reloc = struct { /// Offset of the instruction. source: usize, + /// Offset of the relocation within the instruction. + source_offset: u32, /// Target of the relocation. target: Mir.Inst.Index, - /// Offset of the relocation within the instruction. - offset: u32, + /// Offset from the target instruction. + target_offset: i32, /// Length of the instruction. length: u5, }; @@ -284,8 +426,8 @@ fn fixupRelocs(emit: *Emit) Error!void { for (emit.relocs.items) |reloc| { const target = emit.code_offset_mapping.get(reloc.target) orelse return emit.fail("JMP/CALL relocation target not found!", .{}); - const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)); - mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], @intCast(disp), .little); + const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)) + reloc.target_offset; + std.mem.writeInt(i32, emit.code.items[reloc.source_offset..][0..4], @intCast(disp), .little); } } @@ -338,11 +480,12 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { } } +const bits = @import("bits.zig"); const link = @import("../../link.zig"); const log = std.log.scoped(.emit); -const mem = std.mem; const std = @import("std"); +const Air = @import("../../Air.zig"); const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; const Emit = @This(); const Lower = @import("Lower.zig"); diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 2275ed5f9b..e46160c319 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -4,10 +4,10 @@ bin_file: *link.File, output_mode: std.builtin.OutputMode, link_mode: std.builtin.LinkMode, pic: bool, -allocator: Allocator, +allocator: std.mem.Allocator, mir: Mir, cc: std.builtin.CallingConvention, -err_msg: ?*ErrorMsg = null, +err_msg: ?*Zcu.ErrorMsg = null, src_loc: Zcu.LazySrcLoc, result_insts_len: u8 = undefined, result_relocs_len: u8 = undefined, @@ -52,16 +52,17 @@ pub const Error = error{ pub const Reloc = struct { lowered_inst_index: u8, target: Target, + off: i32, const Target = union(enum) { inst: Mir.Inst.Index, - linker_reloc: bits.Symbol, - linker_tlsld: bits.Symbol, - linker_dtpoff: bits.Symbol, - linker_extern_fn: bits.Symbol, - linker_got: bits.Symbol, - linker_direct: bits.Symbol, - linker_import: bits.Symbol, + linker_reloc: u32, + linker_tlsld: u32, + linker_dtpoff: u32, + linker_extern_fn: u32, + linker_got: u32, + linker_direct: u32, + linker_import: u32, }; }; @@ -173,19 +174,19 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_j_z_and_np_inst => { assert(inst.data.inst.fixes == ._); try lower.emit(.none, .jnz, &.{ - .{ .imm = lower.reloc(.{ .inst = index + 1 }) }, + .{ .imm = lower.reloc(.{ .inst = index + 1 }, 0) }, }); try lower.emit(.none, .jnp, &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }); }, .pseudo_j_nz_or_p_inst => { assert(inst.data.inst.fixes == ._); try lower.emit(.none, .jnz, &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }); try lower.emit(.none, .jp, &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }); }, @@ -195,7 +196,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .imm = Immediate.s(@bitCast(inst.data.ri.i)) }, }); try lower.emit(.none, .jz, &.{ - .{ .imm = lower.reloc(.{ .inst = index + 1 }) }, + .{ .imm = lower.reloc(.{ .inst = index + 1 }, 0) }, }); try lower.emit(.none, .lea, &.{ .{ .reg = inst.data.ri.r1 }, @@ -211,7 +212,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .reg = inst.data.ri.r1.to32() }, }); try lower.emit(.none, .jmp, &.{ - .{ .imm = lower.reloc(.{ .inst = index }) }, + .{ .imm = lower.reloc(.{ .inst = index }, 0) }, }); assert(lower.result_insts_len == pseudo_probe_align_insts); }, @@ -257,7 +258,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .imm = Immediate.s(page_size) }, }); try lower.emit(.none, .jae, &.{ - .{ .imm = lower.reloc(.{ .inst = index }) }, + .{ .imm = lower.reloc(.{ .inst = index }, 0) }, }); assert(lower.result_insts_len == pseudo_probe_adjust_loop_insts); }, @@ -267,7 +268,17 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_dbg_prologue_end_none, .pseudo_dbg_line_line_column, .pseudo_dbg_epilogue_begin_none, - .pseudo_dbg_inline_func, + .pseudo_dbg_enter_inline_func, + .pseudo_dbg_leave_inline_func, + .pseudo_dbg_local_a, + .pseudo_dbg_local_ai_s, + .pseudo_dbg_local_ai_u, + .pseudo_dbg_local_ai_64, + .pseudo_dbg_local_as, + .pseudo_dbg_local_aso, + .pseudo_dbg_local_aro, + .pseudo_dbg_local_af, + .pseudo_dbg_local_am, .pseudo_dead_none, => {}, else => unreachable, @@ -283,17 +294,18 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error { @setCold(true); assert(lower.err_msg == null); - lower.err_msg = try ErrorMsg.create(lower.allocator, lower.src_loc, format, args); + lower.err_msg = try Zcu.ErrorMsg.create(lower.allocator, lower.src_loc, format, args); return error.LowerFail; } -fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate { +pub fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate { return switch (ops) { .rri_s, .ri_s, .i_s, .mi_s, .rmi_s, + .pseudo_dbg_local_ai_s, => Immediate.s(@bitCast(i)), .rrri, @@ -306,22 +318,26 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate { .mri, .rrm, .rrmi, + .pseudo_dbg_local_ai_u, => Immediate.u(i), - .ri64 => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()), + .ri_64, + .pseudo_dbg_local_ai_64, + => Immediate.u(lower.mir.extraData(Mir.Imm64, i).data.decode()), else => unreachable, }; } -fn mem(lower: Lower, payload: u32) Memory { +pub fn mem(lower: Lower, payload: u32) Memory { return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode(); } -fn reloc(lower: *Lower, target: Reloc.Target) Immediate { +fn reloc(lower: *Lower, target: Reloc.Target, off: i32) Immediate { lower.result_relocs[lower.result_relocs_len] = .{ .lowered_inst_index = lower.result_insts_len, .target = target, + .off = off, }; lower.result_relocs_len += 1; return Immediate.s(0); @@ -337,37 +353,36 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) else => op, .mem => |mem_op| switch (mem_op.base()) { else => op, - .reloc => |sym| op: { + .reloc => |sym_index| op: { assert(prefix == .none); assert(mem_op.sib.disp == 0); assert(mem_op.sib.scale_index.scale == 0); if (lower.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; - const elf_sym = zo.symbol(sym.sym_index); + const elf_sym = zo.symbol(sym_index); if (elf_sym.flags.is_tls) { // TODO handle extern TLS vars, i.e., emit GD model if (lower.pic) { // Here, we currently assume local dynamic TLS vars, and so // we emit LD model. - _ = lower.reloc(.{ .linker_tlsld = sym }); + _ = lower.reloc(.{ .linker_tlsld = sym_index }, 0); lower.result_insts[lower.result_insts_len] = try Instruction.new(.none, .lea, &[_]Operand{ .{ .reg = .rdi }, .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, }); lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_extern_fn = .{ - .atom_index = sym.atom_index, - .sym_index = try elf_file.getGlobalSymbol("__tls_get_addr", null), - } }); + _ = lower.reloc(.{ + .linker_extern_fn = try elf_file.getGlobalSymbol("__tls_get_addr", null), + }, 0); lower.result_insts[lower.result_insts_len] = try Instruction.new(.none, .call, &[_]Operand{ .{ .imm = Immediate.s(0) }, }); lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_dtpoff = sym }); + _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0); emit_mnemonic = .lea; break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ .reg = .rax }, @@ -381,7 +396,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, }); lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); emit_mnemonic = .lea; break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ .reg = .rax }, @@ -390,7 +405,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) } } - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); if (lower.pic) switch (mnemonic) { .lea => { if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov; @@ -427,10 +442,10 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) } } else if (lower.bin_file.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; - const macho_sym = zo.symbols.items[sym.sym_index]; + const macho_sym = zo.symbols.items[sym_index]; if (macho_sym.flags.tlv) { - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); lower.result_insts[lower.result_insts_len] = try Instruction.new(.none, .mov, &[_]Operand{ .{ .reg = .rdi }, @@ -446,7 +461,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) break :op .{ .reg = .rax }; } - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); break :op switch (mnemonic) { .lea => { if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov; @@ -490,8 +505,8 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .rrrr => inst.data.rrrr.fixes, .rrri => inst.data.rrri.fixes, .rri_s, .rri_u => inst.data.rri.fixes, - .ri_s, .ri_u => inst.data.ri.fixes, - .ri64, .rm, .rmi_s, .mr => inst.data.rx.fixes, + .ri_s, .ri_u, .ri_64 => inst.data.ri.fixes, + .rm, .rmi_s, .mr => inst.data.rx.fixes, .mrr, .rrm, .rmr => inst.data.rrx.fixes, .rmi, .mri => inst.data.rix.fixes, .rrmr => inst.data.rrrx.fixes, @@ -525,7 +540,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { }, switch (inst.ops) { .none => &.{}, .inst => &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }, .i_s, .i_u => &.{ .{ .imm = lower.imm(inst.ops, inst.data.i.i) }, @@ -554,14 +569,10 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .{ .reg = inst.data.rrri.r3 }, .{ .imm = lower.imm(inst.ops, inst.data.rrri.i) }, }, - .ri_s, .ri_u => &.{ + .ri_s, .ri_u, .ri_64 => &.{ .{ .reg = inst.data.ri.r1 }, .{ .imm = lower.imm(inst.ops, inst.data.ri.i) }, }, - .ri64 => &.{ - .{ .reg = inst.data.rx.r1 }, - .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) }, - }, .rri_s, .rri_u => &.{ .{ .reg = inst.data.rri.r1 }, .{ .reg = inst.data.rri.r2 }, @@ -631,17 +642,17 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) }, }, .extern_fn_reloc, .rel => &.{ - .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) }, + .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc.sym_index }, inst.data.reloc.off) }, }, .got_reloc, .direct_reloc, .import_reloc => ops: { const reg = inst.data.rx.r1; - const extra = lower.mir.extraData(bits.Symbol, inst.data.rx.payload).data; + const extra = lower.mir.extraData(bits.SymbolOffset, inst.data.rx.payload).data; _ = lower.reloc(switch (inst.ops) { - .got_reloc => .{ .linker_got = extra }, - .direct_reloc => .{ .linker_direct = extra }, - .import_reloc => .{ .linker_import = extra }, + .got_reloc => .{ .linker_got = extra.sym_index }, + .direct_reloc => .{ .linker_direct = extra.sym_index }, + .import_reloc => .{ .linker_import = extra.sym_index }, else => unreachable, - }); + }, extra.off); break :ops &.{ .{ .reg = reg }, .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) }, @@ -670,9 +681,6 @@ const encoder = @import("encoder.zig"); const link = @import("../../link.zig"); const std = @import("std"); -const Air = @import("../../Air.zig"); -const Allocator = std.mem.Allocator; -const ErrorMsg = Zcu.ErrorMsg; const Immediate = Instruction.Immediate; const Instruction = encoder.Instruction; const Lower = @This(); diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 75fe8cffe2..3992594b1b 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -760,8 +760,8 @@ pub const Inst = struct { /// Uses `ri` payload. ri_u, /// Register, 64-bit unsigned immediate operands. - /// Uses `rx` payload with payload type `Imm64`. - ri64, + /// Uses `ri` payload with `i` index of extra data of type `Imm64`. + ri_64, /// Immediate (sign-extended) operand. /// Uses `imm` payload. i_s, @@ -796,7 +796,7 @@ pub const Inst = struct { /// Uses `rrix` payload with extra data of type `Memory`. rrmi, /// Single memory operand. - /// Uses `x` with extra data of type `Memory`. + /// Uses `x` payload with extra data of type `Memory`. m, /// Memory, immediate (sign-extend) operands. /// Uses `x` payload with extra data of type `Imm32` followed by `Memory`. @@ -820,16 +820,16 @@ pub const Inst = struct { /// Uses `reloc` payload. extern_fn_reloc, /// Linker relocation - GOT indirection. - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. got_reloc, /// Linker relocation - direct reference. - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. direct_reloc, /// Linker relocation - imports table indirection (binding). - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. import_reloc, /// Linker relocation - threadlocal variable via GOT indirection. - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. tlv_reloc, // Pseudo instructions: @@ -868,16 +868,16 @@ pub const Inst = struct { pseudo_j_nz_or_p_inst, /// Probe alignment - /// Uses `ri` payload + /// Uses `ri` payload. pseudo_probe_align_ri_s, /// Probe adjust unrolled - /// Uses `ri` payload + /// Uses `ri` payload. pseudo_probe_adjust_unrolled_ri_s, /// Probe adjust setup - /// Uses `rri` payload + /// Uses `rri` payload. pseudo_probe_adjust_setup_rri_s, /// Probe adjust loop - /// Uses `rr` payload + /// Uses `rr` payload. pseudo_probe_adjust_loop_rr, /// Push registers /// Uses `reg_list` payload. @@ -893,8 +893,37 @@ pub const Inst = struct { pseudo_dbg_line_line_column, /// Start of epilogue pseudo_dbg_epilogue_begin_none, - /// Start or end of inline function - pseudo_dbg_inline_func, + /// Start of inline function + pseudo_dbg_enter_inline_func, + /// End of inline function + pseudo_dbg_leave_inline_func, + /// Local argument or variable. + /// Uses `a` payload. + pseudo_dbg_local_a, + /// Local argument or variable. + /// Uses `ai` payload. + pseudo_dbg_local_ai_s, + /// Local argument or variable. + /// Uses `ai` payload. + pseudo_dbg_local_ai_u, + /// Local argument or variable. + /// Uses `ai` payload with extra data of type `Imm64`. + pseudo_dbg_local_ai_64, + /// Local argument or variable. + /// Uses `as` payload. + pseudo_dbg_local_as, + /// Local argument or variable. + /// Uses `ax` payload with extra data of type `bits.SymbolOffset`. + pseudo_dbg_local_aso, + /// Local argument or variable. + /// Uses `rx` payload with extra data of type `AirOffset`. + pseudo_dbg_local_aro, + /// Local argument or variable. + /// Uses `ax` payload with extra data of type `bits.FrameAddr`. + pseudo_dbg_local_af, + /// Local argument or variable. + /// Uses `ax` payload with extra data of type `Memory`. + pseudo_dbg_local_am, /// Tombstone /// Emitter should skip this instruction. @@ -997,10 +1026,28 @@ pub const Inst = struct { fixes: Fixes = ._, payload: u32, }, + ix: struct { + payload: u32, + }, + a: struct { + air_inst: Air.Inst.Index, + }, + ai: struct { + air_inst: Air.Inst.Index, + i: u32, + }, + as: struct { + air_inst: Air.Inst.Index, + sym_index: u32, + }, + ax: struct { + air_inst: Air.Inst.Index, + payload: u32, + }, /// Relocation for the linker where: - /// * `atom_index` is the index of the source /// * `sym_index` is the index of the target - reloc: bits.Symbol, + /// * `off` is the offset from the target + reloc: bits.SymbolOffset, /// Debug line and column position line_column: struct { line: u32, @@ -1020,6 +1067,8 @@ pub const Inst = struct { } }; +pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 }; + /// Used in conjunction with payload to transfer a list of used registers in a compact manner. pub const RegisterList = struct { bitset: BitSet = BitSet.initEmpty(), @@ -1118,15 +1167,13 @@ pub const Memory = struct { .none => undefined, .reg => |reg| @intFromEnum(reg), .frame => |frame_index| @intFromEnum(frame_index), - .reloc => |symbol| symbol.sym_index, + .reloc => |sym_index| sym_index, }, .off = switch (mem.mod) { .rm => |rm| @bitCast(rm.disp), .off => |off| @truncate(off), }, - .extra = if (mem.base == .reloc) - mem.base.reloc.atom_index - else if (mem.mod == .off) + .extra = if (mem.mod == .off) @intCast(mem.mod.off >> 32) else undefined, @@ -1146,7 +1193,7 @@ pub const Memory = struct { .none => .none, .reg => .{ .reg = @enumFromInt(mem.base) }, .frame => .{ .frame = @enumFromInt(mem.base) }, - .reloc => .{ .reloc = .{ .atom_index = mem.extra, .sym_index = mem.base } }, + .reloc => .{ .reloc = mem.base }, }, .scale_index = switch (mem.info.index) { .none => null, @@ -1186,6 +1233,7 @@ pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end: @field(result, field.name) = switch (field.type) { u32 => mir.extra[i], i32, Memory.Info => @bitCast(mir.extra[i]), + bits.FrameIndex, Air.Inst.Index => @enumFromInt(mir.extra[i]), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), }; i += 1; @@ -1201,6 +1249,11 @@ pub const FrameLoc = struct { disp: i32, }; +pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffset { + const frame_loc = mir.frame_locs.get(@intFromEnum(frame_addr.index)); + return .{ .reg = frame_loc.base, .off = frame_loc.disp + frame_addr.off }; +} + pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory { return switch (mem.info.base) { .none, .reg, .reloc => mem, @@ -1225,6 +1278,7 @@ const builtin = @import("builtin"); const encoder = @import("encoder.zig"); const std = @import("std"); +const Air = @import("../../Air.zig"); const IntegerBitSet = std.bit_set.IntegerBitSet; const InternPool = @import("../../InternPool.zig"); const Mir = @This(); diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 56b5fcc5d4..839084456a 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -447,26 +447,11 @@ pub const FrameIndex = enum(u32) { } }; -/// A linker symbol not yet allocated in VM. -pub const Symbol = struct { - /// Index of the containing atom. - atom_index: u32, - /// Index into the linker's symbol table. - sym_index: u32, +pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; - pub fn format( - sym: Symbol, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.writeAll("Symbol("); - try std.fmt.formatType(sym.atom_index, fmt, options, writer, 0); - try writer.writeAll(", "); - try std.fmt.formatType(sym.sym_index, fmt, options, writer, 0); - try writer.writeByte(')'); - } -}; +pub const RegisterOffset = struct { reg: Register, off: i32 = 0 }; + +pub const SymbolOffset = struct { sym_index: u32, off: i32 = 0 }; pub const Memory = struct { base: Base, @@ -476,7 +461,7 @@ pub const Memory = struct { none, reg: Register, frame: FrameIndex, - reloc: Symbol, + reloc: u32, pub const Tag = @typeInfo(Base).Union.tag_type.?; @@ -568,7 +553,7 @@ pub const Memory = struct { pub const Immediate = union(enum) { signed: i32, unsigned: u64, - reloc: Symbol, + reloc: SymbolOffset, pub fn u(x: u64) Immediate { return .{ .unsigned = x }; @@ -578,19 +563,19 @@ pub const Immediate = union(enum) { return .{ .signed = x }; } - pub fn rel(symbol: Symbol) Immediate { - return .{ .reloc = symbol }; + pub fn rel(sym_off: SymbolOffset) Immediate { + return .{ .reloc = sym_off }; } pub fn format( imm: Immediate, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, + comptime _: []const u8, + _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { switch (imm) { - .reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0), - inline else => |x| try writer.print("{d}", .{x}), + inline else => |int| try writer.print("{d}", .{int}), + .reloc => |sym_off| try writer.print("Symbol({[sym_index]d}) + {[off]d}", sym_off), } } }; diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index b525b0e11e..ce5b9c4d0f 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -128,8 +128,8 @@ pub const Instruction = struct { } }; } - pub fn rip(ptr_size: PtrSize, disp: i32) Memory { - return .{ .rip = .{ .ptr_size = ptr_size, .disp = disp } }; + pub fn rip(ptr_size: PtrSize, displacement: i32) Memory { + return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } }; } pub fn isSegmentRegister(mem: Memory) bool { @@ -158,6 +158,14 @@ pub const Instruction = struct { }; } + pub fn disp(mem: Memory) Immediate { + return switch (mem) { + .sib => |s| Immediate.s(s.disp), + .rip => |r| Immediate.s(r.disp), + .moffs => |m| Immediate.u(m.offset), + }; + } + pub fn bitSize(mem: Memory) u64 { return switch (mem) { .rip => |r| r.ptr_size.bitSize(), @@ -258,17 +266,12 @@ pub const Instruction = struct { try writer.writeByte('['); - var any = false; + var any = true; switch (sib.base) { - .none => {}, - .reg => |reg| { - try writer.print("{s}", .{@tagName(reg)}); - any = true; - }, - inline .frame, .reloc => |payload| { - try writer.print("{}", .{payload}); - any = true; - }, + .none => any = false, + .reg => |reg| try writer.print("{s}", .{@tagName(reg)}), + .frame => |frame_index| try writer.print("{}", .{frame_index}), + .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}), } if (mem.scaleIndex()) |si| { if (any) try writer.writeAll(" + "); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 7c35a178a0..397cb071b6 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3293,7 +3293,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .dbg_stmt => try airDbgStmt(f, inst), .dbg_inline_block => try airDbgInlineBlock(f, inst), - .dbg_var_ptr, .dbg_var_val => try airDbgVar(f, inst), + .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => try airDbgVar(f, inst), .call => try airCall(f, inst, .auto), .call_always_tail => .none, @@ -4590,14 +4590,15 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue { fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { const pt = f.object.dg.pt; const zcu = pt.zcu; + const tag = f.air.instructions.items(.tag)[@intFromEnum(inst)]; const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const name = f.air.nullTerminatedString(pl_op.payload); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); const operand_is_undef = if (try f.air.value(pl_op.operand, pt)) |v| v.isUndefDeep(zcu) else false; if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand); try reap(f, inst, &.{pl_op.operand}); const writer = f.object.writer(); - try writer.print("/* var:{s} */\n", .{name}); + try writer.print("/* {s}:{s} */\n", .{ @tagName(tag), name.toSlice(f.air) }); return .none; } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8fb4fa7ef9..233cf7e3eb 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1665,6 +1665,7 @@ pub const Object = struct { .ret_ptr = ret_ptr, .args = args.items, .arg_index = 0, + .arg_inline_index = 0, .func_inst_table = .{}, .blocks = .{}, .sync_scope = if (owner_mod.single_threaded) .singlethread else .system, @@ -4769,7 +4770,8 @@ pub const FuncGen = struct { /// it omits 0-bit types. If the function uses sret as the first parameter, /// this slice does not include it. args: []const Builder.Value, - arg_index: usize, + arg_index: u32, + arg_inline_index: u32, err_ret_trace: Builder.Value = .none, @@ -5082,7 +5084,8 @@ pub const FuncGen = struct { .dbg_stmt => try self.airDbgStmt(inst), .dbg_inline_block => try self.airDbgInlineBlock(inst), .dbg_var_ptr => try self.airDbgVarPtr(inst), - .dbg_var_val => try self.airDbgVarVal(inst), + .dbg_var_val => try self.airDbgVarVal(inst, false), + .dbg_arg_inline => try self.airDbgVarVal(inst, true), .c_va_arg => try self.airCVaArg(inst), .c_va_copy => try self.airCVaCopy(inst), @@ -6677,6 +6680,7 @@ pub const FuncGen = struct { fn airDbgInlineBlock(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.DbgInlineBlock, ty_pl.payload); + self.arg_inline_index = 0; return self.lowerBlock(inst, extra.data.func, @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len])); } @@ -6685,11 +6689,11 @@ pub const FuncGen = struct { const mod = o.pt.zcu; const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const operand = try self.resolveInst(pl_op.operand); - const name = self.air.nullTerminatedString(pl_op.payload); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); const ptr_ty = self.typeOf(pl_op.operand); const debug_local_var = try o.builder.debugLocalVar( - try o.builder.metadataString(name), + try o.builder.metadataString(name.toSlice(self.air)), self.file, self.scope, self.prev_dbg_line, @@ -6712,15 +6716,25 @@ pub const FuncGen = struct { return .none; } - fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { + fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index, is_arg: bool) !Builder.Value { const o = self.ng.object; const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const operand = try self.resolveInst(pl_op.operand); const operand_ty = self.typeOf(pl_op.operand); - const name = self.air.nullTerminatedString(pl_op.payload); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); - const debug_local_var = try o.builder.debugLocalVar( - try o.builder.metadataString(name), + const debug_local_var = if (is_arg) try o.builder.debugParameter( + try o.builder.metadataString(name.toSlice(self.air)), + self.file, + self.scope, + self.prev_dbg_line, + try o.lowerDebugType(operand_ty), + arg_no: { + self.arg_inline_index += 1; + break :arg_no self.arg_inline_index; + }, + ) else try o.builder.debugLocalVar( + try o.builder.metadataString(name.toSlice(self.air)), self.file, self.scope, self.prev_dbg_line, @@ -8835,12 +8849,12 @@ pub const FuncGen = struct { const lbrace_col = func.lbrace_column + 1; const debug_parameter = try o.builder.debugParameter( - try o.builder.metadataString(self.air.nullTerminatedString(@intFromEnum(name))), + try o.builder.metadataString(name.toSlice(self.air)), self.file, self.scope, lbrace_line, try o.lowerDebugType(inst_ty), - @intCast(self.arg_index), + self.arg_index, ); const old_location = self.wip.debug_location; diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index b13be401ab..a89dd8f10b 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -6366,8 +6366,8 @@ const NavGen = struct { fn airDbgVar(self: *NavGen, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const target_id = try self.resolve(pl_op.operand); - const name = self.air.nullTerminatedString(pl_op.payload); - try self.spv.debugName(target_id, name); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); + try self.spv.debugName(target_id, name.toSlice(self.air)); } fn airAssembly(self: *NavGen, inst: Air.Inst.Index) !?IdRef { diff --git a/src/link/C.zig b/src/link/C.zig index a704175865..585389aa3f 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -317,8 +317,18 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ! defer tracy.end(); const gpa = self.base.comp.gpa; - const zcu = pt.zcu; + const ip = &zcu.intern_pool; + + const nav = ip.getNav(nav_index); + const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { + .func => return, + .@"extern" => .none, + .variable => |variable| variable.init, + else => nav.status.resolved.val, + }; + if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) return; + const gop = try self.navs.getOrPut(gpa, nav_index); errdefer _ = self.navs.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index f2359d503f..d6ebcc278e 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1207,6 +1207,7 @@ pub fn updateNav( const nav_val = zcu.navValue(nav_index); const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { + .func => return, .variable => |variable| Value.fromInterned(variable.init), .@"extern" => |@"extern"| { if (ip.isFunctionType(@"extern".ty)) return; @@ -1220,7 +1221,7 @@ pub fn updateNav( else => nav_val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) { const atom_index = try self.getOrCreateAtomForNav(nav_index); Atom.freeRelocations(self, atom_index); const atom = self.getAtom(atom_index); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 1b5739030b..60c0bac4a8 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -21,8 +21,9 @@ pub const UpdateError = std.fs.File.OpenError || std.fs.File.SetEndPosError || std.fs.File.CopyRangeError || + std.fs.File.PReadError || std.fs.File.PWriteError || - error{ Overflow, Underflow, UnexpectedEndOfFile }; + error{ EndOfStream, Overflow, Underflow, UnexpectedEndOfFile }; pub const FlushError = UpdateError || @@ -253,10 +254,8 @@ const Section = struct { .trailer_len = trailer_len, .len = header_len + trailer_len, .entries = .{}, - .cross_entry_relocs = .{}, .cross_unit_relocs = .{}, .cross_section_relocs = .{}, - .external_relocs = .{}, }; if (sec.last.unwrap()) |last_unit| { const last_unit_ptr = sec.getUnit(last_unit); @@ -358,10 +357,8 @@ const Unit = struct { /// data length in bytes len: u32, entries: std.ArrayListUnmanaged(Entry), - cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc), cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc), cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc), - external_relocs: std.ArrayListUnmanaged(ExternalReloc), const Index = enum(u32) { main, @@ -381,12 +378,16 @@ const Unit = struct { } }; + fn clear(unit: *Unit) void { + unit.cross_unit_relocs.clearRetainingCapacity(); + unit.cross_section_relocs.clearRetainingCapacity(); + } + fn deinit(unit: *Unit, gpa: std.mem.Allocator) void { + for (unit.entries.items) |*entry| entry.deinit(gpa); unit.entries.deinit(gpa); - unit.cross_entry_relocs.deinit(gpa); unit.cross_unit_relocs.deinit(gpa); unit.cross_section_relocs.deinit(gpa); - unit.external_relocs.deinit(gpa); unit.* = undefined; } @@ -398,6 +399,10 @@ const Unit = struct { .next = .none, .off = 0, .len = 0, + .cross_entry_relocs = .{}, + .cross_unit_relocs = .{}, + .cross_section_relocs = .{}, + .external_relocs = .{}, }; if (unit.last.unwrap()) |last_entry| { const last_entry_ptr = unit.getEntry(last_entry); @@ -451,6 +456,14 @@ const Unit = struct { unit_ptr.len = len; } + fn trim(unit: *Unit) void { + const len = unit.getEntry(unit.first.unwrap() orelse return).off; + if (len == 0) return; + for (unit.entries.items) |*entry| entry.off -= len; + unit.off += len; + unit.len -= len; + } + fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { if (unit.off == new_off) return; if (try dwarf.getFile().?.copyRangeAll( @@ -463,6 +476,7 @@ const Unit = struct { } fn resizeHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void { + unit.trim(); if (unit.header_len == len) return; const available_len = if (unit.prev.unwrap()) |prev_unit| prev_excess: { const prev_unit_ptr = sec.getUnit(prev_unit); @@ -535,23 +549,11 @@ const Unit = struct { } fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { - for (unit.cross_entry_relocs.items) |reloc| { - try dwarf.resolveReloc( - sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| - unit.header_len + unit.getEntry(source_entry).off - else - 0) + reloc.source_off, - unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off, - dwarf.sectionOffsetBytes(), - ); - } + const unit_off = sec.off + unit.off; for (unit.cross_unit_relocs.items) |reloc| { const target_unit = sec.getUnit(reloc.target_unit); try dwarf.resolveReloc( - sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| - unit.header_len + unit.getEntry(source_entry).off - else - 0) + reloc.source_off, + unit_off + reloc.source_off, target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off else @@ -565,10 +567,7 @@ const Unit = struct { }; const target_unit = target_sec.getUnit(reloc.target_unit); try dwarf.resolveReloc( - sec.off + unit.off + (if (reloc.source_entry.unwrap()) |source_entry| - unit.header_len + unit.getEntry(source_entry).off - else - 0) + reloc.source_off, + unit_off + reloc.source_off, target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off else @@ -576,57 +575,8 @@ const Unit = struct { dwarf.sectionOffsetBytes(), ); } - if (dwarf.bin_file.cast(.elf)) |elf_file| { - const zo = elf_file.zigObjectPtr().?; - for (unit.external_relocs.items) |reloc| { - const symbol = zo.symbol(reloc.target_sym); - try dwarf.resolveReloc( - sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off, - @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) - - if (symbol.flags.is_tls) elf_file.dtpAddress() else 0), - @intFromEnum(dwarf.address_size), - ); - } - } else if (dwarf.bin_file.cast(.macho)) |macho_file| { - const zo = macho_file.getZigObject().?; - for (unit.external_relocs.items) |reloc| { - const ref = zo.getSymbolRef(reloc.target_sym, macho_file); - try dwarf.resolveReloc( - sec.off + unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off, - ref.getSymbol(macho_file).?.getAddress(.{}, macho_file), - @intFromEnum(dwarf.address_size), - ); - } - } + for (unit.entries.items) |*entry| try entry.resolveRelocs(unit, sec, dwarf); } - - const CrossEntryReloc = struct { - source_entry: Entry.Index.Optional = .none, - source_off: u32 = 0, - target_entry: Entry.Index, - target_off: u32 = 0, - }; - const CrossUnitReloc = struct { - source_entry: Entry.Index.Optional = .none, - source_off: u32 = 0, - target_unit: Unit.Index, - target_entry: Entry.Index.Optional = .none, - target_off: u32 = 0, - }; - const CrossSectionReloc = struct { - source_entry: Entry.Index.Optional = .none, - source_off: u32 = 0, - target_sec: Section.Index, - target_unit: Unit.Index, - target_entry: Entry.Index.Optional = .none, - target_off: u32 = 0, - }; - const ExternalReloc = struct { - source_entry: Entry.Index, - source_off: u32 = 0, - target_sym: u32, - target_off: u64 = 0, - }; }; /// An indivisible entry within a `Unit` containing section-specific data. @@ -637,6 +587,25 @@ const Entry = struct { off: u32, /// data length in bytes len: u32, + cross_entry_relocs: std.ArrayListUnmanaged(CrossEntryReloc), + cross_unit_relocs: std.ArrayListUnmanaged(CrossUnitReloc), + cross_section_relocs: std.ArrayListUnmanaged(CrossSectionReloc), + external_relocs: std.ArrayListUnmanaged(ExternalReloc), + + fn clear(entry: *Entry) void { + entry.cross_entry_relocs.clearRetainingCapacity(); + entry.cross_unit_relocs.clearRetainingCapacity(); + entry.cross_section_relocs.clearRetainingCapacity(); + entry.external_relocs.clearRetainingCapacity(); + } + + fn deinit(entry: *Entry, gpa: std.mem.Allocator) void { + entry.cross_entry_relocs.deinit(gpa); + entry.cross_unit_relocs.deinit(gpa); + entry.cross_section_relocs.deinit(gpa); + entry.external_relocs.deinit(gpa); + entry.* = undefined; + } const Index = enum(u32) { _, @@ -803,6 +772,88 @@ const Entry = struct { } @panic("missing dwarf relocation target"); } + + fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { + const entry_off = sec.off + unit.off + unit.header_len + entry.off; + for (entry.cross_entry_relocs.items) |reloc| { + try dwarf.resolveReloc( + entry_off + reloc.source_off, + unit.off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sec, dwarf).off + reloc.target_off, + dwarf.sectionOffsetBytes(), + ); + } + for (entry.cross_unit_relocs.items) |reloc| { + const target_unit = sec.getUnit(reloc.target_unit); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| + target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off + else + 0) + reloc.target_off, + dwarf.sectionOffsetBytes(), + ); + } + for (entry.cross_section_relocs.items) |reloc| { + const target_sec = switch (reloc.target_sec) { + inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section, + }; + const target_unit = target_sec.getUnit(reloc.target_unit); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + target_unit.off + (if (reloc.target_entry.unwrap()) |target_entry| + target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sec, dwarf).off + else + 0) + reloc.target_off, + dwarf.sectionOffsetBytes(), + ); + } + if (dwarf.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + for (entry.external_relocs.items) |reloc| { + const symbol = zo.symbol(reloc.target_sym); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + @bitCast(symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off)) - + if (symbol.flags.is_tls) elf_file.dtpAddress() else 0), + @intFromEnum(dwarf.address_size), + ); + } + } else if (dwarf.bin_file.cast(.macho)) |macho_file| { + const zo = macho_file.getZigObject().?; + for (entry.external_relocs.items) |reloc| { + const ref = zo.getSymbolRef(reloc.target_sym, macho_file); + try dwarf.resolveReloc( + entry_off + reloc.source_off, + ref.getSymbol(macho_file).?.getAddress(.{}, macho_file), + @intFromEnum(dwarf.address_size), + ); + } + } + } +}; + +const CrossEntryReloc = struct { + source_off: u32 = 0, + target_entry: Entry.Index, + target_off: u32 = 0, +}; +const CrossUnitReloc = struct { + source_off: u32 = 0, + target_unit: Unit.Index, + target_entry: Entry.Index.Optional = .none, + target_off: u32 = 0, +}; +const CrossSectionReloc = struct { + source_off: u32 = 0, + target_sec: Section.Index, + target_unit: Unit.Index, + target_entry: Entry.Index.Optional = .none, + target_off: u32 = 0, +}; +const ExternalReloc = struct { + source_off: u32 = 0, + target_sym: u32, + target_off: u64 = 0, }; pub const Loc = union(enum) { @@ -986,7 +1037,9 @@ pub const WipNav = struct { entry: Entry.Index, any_children: bool, func: InternPool.Index, + func_sym_index: u32, func_high_reloc: u32, + inlined_funcs_high_reloc: std.ArrayListUnmanaged(u32), debug_info: std.ArrayListUnmanaged(u8), debug_line: std.ArrayListUnmanaged(u8), debug_loclists: std.ArrayListUnmanaged(u8), @@ -994,6 +1047,7 @@ pub const WipNav = struct { pub fn deinit(wip_nav: *WipNav) void { const gpa = wip_nav.dwarf.gpa; + if (wip_nav.func != .none) wip_nav.inlined_funcs_high_reloc.deinit(gpa); wip_nav.debug_info.deinit(gpa); wip_nav.debug_line.deinit(gpa); wip_nav.debug_loclists.deinit(gpa); @@ -1004,10 +1058,10 @@ pub const WipNav = struct { return wip_nav.debug_info.writer(wip_nav.dwarf.gpa); } - pub const VarTag = enum { local_arg, local_var }; - pub fn genVarDebugInfo( + pub const LocalTag = enum { local_arg, local_var }; + pub fn genLocalDebugInfo( wip_nav: *WipNav, - tag: VarTag, + tag: LocalTag, name: []const u8, ty: Type, loc: Loc, @@ -1078,7 +1132,43 @@ pub const WipNav = struct { try dlw.writeByte(DW.LNS.set_epilogue_begin); } + pub fn enterInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64, line: u32, column: u32) UpdateError!void { + const dwarf = wip_nav.dwarf; + const zcu = wip_nav.pt.zcu; + const diw = wip_nav.debug_info.writer(dwarf.gpa); + try wip_nav.inlined_funcs_high_reloc.ensureUnusedCapacity(dwarf.gpa, 1); + + try uleb128(diw, @intFromEnum(AbbrevCode.inlined_func)); + try wip_nav.refNav(zcu.funcInfo(func).owner_nav); + try uleb128(diw, zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1); + try uleb128(diw, column + 1); + const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; + try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2); + external_relocs.appendAssumeCapacity(.{ + .source_off = @intCast(wip_nav.debug_info.items.len), + .target_sym = wip_nav.func_sym_index, + .target_off = code_off, + }); + try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); + wip_nav.inlined_funcs_high_reloc.appendAssumeCapacity(@intCast(external_relocs.items.len)); + external_relocs.appendAssumeCapacity(.{ + .source_off = @intCast(wip_nav.debug_info.items.len), + .target_sym = wip_nav.func_sym_index, + .target_off = undefined, + }); + try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); + try wip_nav.setInlineFunc(func); + } + + pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void { + const external_relocs = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; + external_relocs.items[wip_nav.inlined_funcs_high_reloc.pop()].target_off = code_off; + try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null)); + try wip_nav.setInlineFunc(func); + } + pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void { + wip_nav.any_children = true; const zcu = wip_nav.pt.zcu; const dwarf = wip_nav.dwarf; if (wip_nav.func == func) return; @@ -1096,8 +1186,7 @@ pub const WipNav = struct { try dlw.writeByte(DW.LNS.extended_op); try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); try dlw.writeByte(DW.LNE.ZIG_set_decl); - try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_line.items.len), .target_sec = .debug_info, .target_unit = new_unit, @@ -1133,9 +1222,9 @@ pub const WipNav = struct { fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void { const dwarf = wip_nav.dwarf; const gpa = dwarf.gpa; + const entry_ptr = dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry); if (sec != .debug_info) { - try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_section_relocs.append(gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try entry_ptr.cross_section_relocs.append(gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_sec = sec, .target_unit = unit, @@ -1143,16 +1232,14 @@ pub const WipNav = struct { .target_off = off, }); } else if (unit != wip_nav.unit) { - try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_unit_relocs.append(gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try entry_ptr.cross_unit_relocs.append(gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_unit = unit, .target_entry = entry.toOptional(), .target_off = off, }); } else { - try dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.append(gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try entry_ptr.cross_entry_relocs.append(gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_entry = entry, .target_off = off, @@ -1167,8 +1254,7 @@ pub const WipNav = struct { fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void { const dwarf = wip_nav.dwarf; - try dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + try dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = sym_index, }); @@ -1217,12 +1303,20 @@ pub const WipNav = struct { try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); } + fn refNav(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!void { + const zcu = wip_nav.pt.zcu; + const ip = &zcu.intern_pool; + const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod); + const nav_gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index); + if (!nav_gop.found_existing) nav_gop.value_ptr.* = try wip_nav.dwarf.addCommonEntry(unit); + try wip_nav.infoSectionOffset(.debug_info, unit, nav_gop.value_ptr.*, 0); + } + fn refForward(wip_nav: *WipNav) std.mem.Allocator.Error!u32 { const dwarf = wip_nav.dwarf; - const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs; + const cross_entry_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs; const reloc_index: u32 = @intCast(cross_entry_relocs.items.len); try cross_entry_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry.toOptional(), .source_off = @intCast(wip_nav.debug_info.items.len), .target_entry = undefined, .target_off = undefined, @@ -1232,7 +1326,7 @@ pub const WipNav = struct { } fn finishForward(wip_nav: *WipNav, reloc_index: u32) void { - const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).cross_entry_relocs.items[reloc_index]; + const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index]; reloc.target_entry = wip_nav.entry; reloc.target_off = @intCast(wip_nav.debug_info.items.len); } @@ -1545,7 +1639,15 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In const unit = try dwarf.getUnit(file.mod); const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); errdefer _ = dwarf.navs.pop(); - if (!nav_gop.found_existing) nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); + if (nav_gop.found_existing) { + for ([_]*Section{ + &dwarf.debug_aranges.section, + &dwarf.debug_info.section, + &dwarf.debug_line.section, + &dwarf.debug_loclists.section, + &dwarf.debug_rnglists.section, + }) |sec| sec.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear(); + } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); const nav_val = zcu.navValue(nav_index); var wip_nav: WipNav = .{ .dwarf = dwarf, @@ -1554,7 +1656,9 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In .entry = nav_gop.value_ptr.*, .any_children = false, .func = .none, + .func_sym_index = undefined, .func_high_reloc = undefined, + .inlined_funcs_high_reloc = undefined, .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, @@ -1608,16 +1712,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In try wip_nav.exprloc(.{ .addr = .{ .sym = sym_index } }); try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse ty.abiAlignment(pt).toByteUnits().?); - const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() }); - try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index| - zcu.all_exports.items[export_index..][0..1] - else if (zcu.multi_exports.get(func_unit)) |export_range| - zcu.all_exports.items[export_range.index..][0..export_range.len] - else - &.{}) |@"export"| - { - if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true; - } else false)); + try diw.writeByte(@intFromBool(false)); wip_nav.finishForward(ty_reloc_index); try uleb128(diw, @intFromEnum(AbbrevCode.is_const)); try wip_nav.refType(ty); @@ -1668,16 +1763,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In try wip_nav.exprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr); try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse ty.abiAlignment(pt).toByteUnits().?); - const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() }); - try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index| - zcu.all_exports.items[export_index..][0..1] - else if (zcu.multi_exports.get(func_unit)) |export_range| - zcu.all_exports.items[export_range.index..][0..export_range.len] - else - &.{}) |@"export"| - { - if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true; - } else false)); + try diw.writeByte(@intFromBool(false)); }, .func => |func| { assert(file.zir_loaded); @@ -1712,6 +1798,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In const func_type = ip.indexToKey(func.ty).func_type; wip_nav.func = nav_val.toIntern(); + wip_nav.func_sym_index = sym_index; + wip_nav.inlined_funcs_high_reloc = .{}; const diw = wip_nav.debug_info.writer(dwarf.gpa); try uleb128(diw, @intFromEnum(AbbrevCode.decl_func)); @@ -1723,32 +1811,23 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In try wip_nav.strp(nav.name.toSlice(ip)); try wip_nav.strp(nav.fqn.toSlice(ip)); try wip_nav.refType(Type.fromInterned(func_type.return_type)); - const external_relocs = &dwarf.debug_info.section.getUnit(unit).external_relocs; - try external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; + try external_relocs.ensureUnusedCapacity(dwarf.gpa, 2); + external_relocs.appendAssumeCapacity(.{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = sym_index, }); try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); wip_nav.func_high_reloc = @intCast(external_relocs.items.len); - try external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + external_relocs.appendAssumeCapacity(.{ .source_off = @intCast(wip_nav.debug_info.items.len), .target_sym = sym_index, + .target_off = undefined, }); try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size)); try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse target_info.defaultFunctionAlignment(file.mod.resolved_target.result).toByteUnits().?); - const func_unit = InternPool.AnalUnit.wrap(.{ .func = nav_val.toIntern() }); - try diw.writeByte(@intFromBool(for (if (zcu.single_exports.get(func_unit)) |export_index| - zcu.all_exports.items[export_index..][0..1] - else if (zcu.multi_exports.get(func_unit)) |export_range| - zcu.all_exports.items[export_range.index..][0..export_range.len] - else - &.{}) |@"export"| - { - if (@"export".exported == .nav and @"export".exported.nav == nav_index) break true; - } else false)); + try diw.writeByte(@intFromBool(false)); try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type)); const dlw = wip_nav.debug_line.writer(dwarf.gpa); @@ -1756,8 +1835,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In if (dwarf.incremental()) { try uleb128(dlw, 1 + dwarf.sectionOffsetBytes()); try dlw.writeByte(DW.LNE.ZIG_set_decl); - try dwarf.debug_line.section.getUnit(wip_nav.unit).cross_section_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry.toOptional(), + try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_line.items.len), .target_sec = .debug_info, .target_unit = wip_nav.unit, @@ -1772,8 +1850,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In } else { try uleb128(dlw, 1 + @intFromEnum(dwarf.address_size)); try dlw.writeByte(DW.LNE.set_address); - try dwarf.debug_line.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ .source_off = @intCast(wip_nav.debug_line.items.len), .target_sym = sym_index, }); @@ -1806,7 +1883,8 @@ pub fn finishWipNav( log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)}); if (wip_nav.func != .none) { - dwarf.debug_info.section.getUnit(wip_nav.unit).external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size; + const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs; + external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size; if (wip_nav.any_children) { const diw = wip_nav.debug_info.writer(dwarf.gpa); try uleb128(diw, @intFromEnum(AbbrevCode.null)); @@ -1817,8 +1895,7 @@ pub fn finishWipNav( ); var aranges_entry = [1]u8{0} ** (8 + 8); - try dwarf.debug_aranges.section.getUnit(wip_nav.unit).external_relocs.append(dwarf.gpa, .{ - .source_entry = wip_nav.entry, + try dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{ .target_sym = sym.index, }); dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0); @@ -1832,14 +1909,12 @@ pub fn finishWipNav( aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2], ); - try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).external_relocs.appendSlice(dwarf.gpa, &.{ + try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{ .{ - .source_entry = wip_nav.entry, .source_off = 1, .target_sym = sym.index, }, .{ - .source_entry = wip_nav.entry, .source_off = 1 + @intFromEnum(dwarf.address_size), .target_sym = sym.index, .target_off = sym.size, @@ -1891,7 +1966,9 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool .entry = undefined, .any_children = false, .func = .none, + .func_sym_index = undefined, .func_high_reloc = undefined, + .inlined_funcs_high_reloc = undefined, .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, @@ -1902,6 +1979,62 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); errdefer _ = dwarf.navs.pop(); switch (ip.indexToKey(nav_val.toIntern())) { + .func => |func| { + if (nav_gop.found_existing) { + const unit_ptr = dwarf.debug_info.section.getUnit(unit); + const entry_ptr = unit_ptr.getEntry(nav_gop.value_ptr.*); + if (entry_ptr.len >= AbbrevCode.decl_bytes) { + var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined; + if (try dwarf.getFile().?.preadAll( + &abbrev_code_buf, + dwarf.debug_info.section.off + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, + ) != abbrev_code_buf.len) return error.InputOutput; + var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf); + const abbrev_code: AbbrevCode = @enumFromInt( + try std.leb.readUleb128(@typeInfo(AbbrevCode).Enum.tag_type, abbrev_code_fbs.reader()), + ); + switch (abbrev_code) { + else => unreachable, + .decl_func, .decl_func_empty => return, + .decl_func_generic, .decl_func_generic_empty => {}, + } + } + entry_ptr.clear(); + } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit); + wip_nav.entry = nav_gop.value_ptr.*; + + const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: { + const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace); + break :parent .{ + parent_namespace_ptr.owner_type, + if (parent_namespace_ptr.pub_decls.containsContext(nav_index, .{ .zcu = zcu })) + DW.ACCESS.public + else if (parent_namespace_ptr.priv_decls.containsContext(nav_index, .{ .zcu = zcu })) + DW.ACCESS.private + else + unreachable, + }; + } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; + + const func_type = ip.indexToKey(func.ty).func_type; + const diw = wip_nav.debug_info.writer(dwarf.gpa); + try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (func_type.param_types.len > 0 or func_type.is_var_args) .decl_func_generic else .decl_func_generic_empty))); + try wip_nav.refType(Type.fromInterned(parent_type)); + assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf)); + try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian); + try uleb128(diw, loc.column + 1); + try diw.writeByte(accessibility); + try wip_nav.strp(nav.name.toSlice(ip)); + try wip_nav.refType(Type.fromInterned(func_type.return_type)); + if (func_type.param_types.len > 0 or func_type.is_var_args) { + for (0..func_type.param_types.len) |param_index| { + try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param)); + try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index])); + } + if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args)); + try uleb128(diw, @intFromEnum(AbbrevCode.null)); + } + }, .struct_type => done: { const loaded_struct = ip.loadStructType(nav_val.toIntern()); @@ -2304,7 +2437,9 @@ fn updateType( .entry = dwarf.types.get(type_index).?, .any_children = false, .func = .none, + .func_sym_index = undefined, .func_high_reloc = undefined, + .inlined_funcs_high_reloc = undefined, .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, @@ -2467,13 +2602,25 @@ fn updateType( .error_union_type => |error_union_type| { const error_union_error_set_type = Type.fromInterned(error_union_type.error_set_type); const error_union_payload_type = Type.fromInterned(error_union_type.payload_type); - const error_union_error_set_offset = codegen.errUnionErrorOffset(error_union_payload_type, pt); - const error_union_payload_offset = codegen.errUnionPayloadOffset(error_union_payload_type, pt); + const error_union_error_set_offset, const error_union_payload_offset = switch (error_union_type.payload_type) { + .generic_poison_type => .{ 0, 0 }, + else => .{ + codegen.errUnionErrorOffset(error_union_payload_type, pt), + codegen.errUnionPayloadOffset(error_union_payload_type, pt), + }, + }; try uleb128(diw, @intFromEnum(AbbrevCode.union_type)); try wip_nav.strp(name); - try uleb128(diw, ty.abiSize(pt)); - try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); + if (error_union_type.error_set_type != .generic_poison_type and + error_union_type.payload_type != .generic_poison_type) + { + try uleb128(diw, ty.abiSize(pt)); + try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?); + } else { + try uleb128(diw, 0); + try uleb128(diw, 1); + } { try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union)); try wip_nav.infoSectionOffset( @@ -2655,10 +2802,16 @@ fn updateType( } if (error_set_type.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, - .inferred_error_set_type => |func| { - try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type)); - try wip_nav.strp(name); - try wip_nav.refType(Type.fromInterned(ip.funcIesResolvedUnordered(func))); + .inferred_error_set_type => |func| switch (ip.funcIesResolvedUnordered(func)) { + .none => { + try uleb128(diw, @intFromEnum(AbbrevCode.void_type)); + try wip_nav.strp(name); + }, + else => |ies| { + try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type)); + try wip_nav.strp(name); + try wip_nav.refType(Type.fromInterned(ies)); + }, }, // values, not types @@ -2705,7 +2858,9 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP .entry = type_gop.value_ptr.*, .any_children = false, .func = .none, + .func_sym_index = undefined, .func_high_reloc = undefined, + .inlined_funcs_high_reloc = undefined, .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, @@ -2766,7 +2921,9 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP .entry = type_gop.value_ptr.*, .any_children = false, .func = .none, + .func_sym_index = undefined, .func_high_reloc = undefined, + .inlined_funcs_high_reloc = undefined, .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, @@ -2940,7 +3097,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { .entry = entry, .any_children = false, .func = .none, + .func_sym_index = undefined, .func_high_reloc = undefined, + .inlined_funcs_high_reloc = undefined, .debug_info = .{}, .debug_line = .{}, .debug_loclists = .{}, @@ -2998,7 +3157,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (dwarf.debug_aranges.section.dirty) { for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| { const unit: Unit.Index = @enumFromInt(unit_index); - try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 1); + unit_ptr.clear(); + try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 1); header.clearRetainingCapacity(); try header.ensureTotalCapacity(unit_ptr.header_len); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| @@ -3029,8 +3189,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (dwarf.debug_info.section.dirty) { for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| { const unit: Unit.Index = @enumFromInt(unit_index); - try unit_ptr.cross_unit_relocs.ensureUnusedCapacity(dwarf.gpa, 1); - try unit_ptr.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 7); + unit_ptr.clear(); + try unit_ptr.cross_unit_relocs.ensureTotalCapacity(dwarf.gpa, 1); + try unit_ptr.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 7); header.clearRetainingCapacity(); try header.ensureTotalCapacity(unit_ptr.header_len); const unit_len = (if (unit_ptr.next.unwrap()) |next_unit| @@ -3121,7 +3282,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count()))); for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| { - try unit.cross_section_relocs.ensureUnusedCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count())); + unit.clear(); + try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count())); header.clearRetainingCapacity(); try header.ensureTotalCapacity(unit.header_len); const unit_len = (if (unit.next.unwrap()) |next_unit| @@ -3310,6 +3472,8 @@ const AbbrevCode = enum(u8) { decl_var, decl_func, decl_func_empty, + decl_func_generic, + decl_func_generic_empty, // the rest are unrestricted compile_unit, module, @@ -3344,10 +3508,11 @@ const AbbrevCode = enum(u8) { struct_type, packed_struct_type, union_type, + inlined_func, local_arg, local_var, - const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_empty)); + const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_generic_empty)); const Attr = struct { DeclValEnum(DW.AT), @@ -3451,6 +3616,19 @@ const AbbrevCode = enum(u8) { .{ .noreturn, .flag }, }, }, + .decl_func_generic = .{ + .tag = .subprogram, + .children = true, + .attrs = decl_abbrev_common_attrs ++ .{ + .{ .type, .ref_addr }, + }, + }, + .decl_func_generic_empty = .{ + .tag = .subprogram, + .attrs = decl_abbrev_common_attrs ++ .{ + .{ .type, .ref_addr }, + }, + }, .compile_unit = .{ .tag = .compile_unit, .children = true, @@ -3706,6 +3884,17 @@ const AbbrevCode = enum(u8) { .{ .alignment, .udata }, }, }, + .inlined_func = .{ + .tag = .inlined_subroutine, + .children = true, + .attrs = &.{ + .{ .abstract_origin, .ref_addr }, + .{ .call_line, .udata }, + .{ .call_column, .udata }, + .{ .low_pc, .addr }, + .{ .high_pc, .addr }, + }, + }, .local_arg = .{ .tag = .formal_parameter, .attrs = &.{ diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index d592f6e9d3..a6a6f76d04 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1122,9 +1122,9 @@ pub fn updateNav( log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index }); - const nav_val = zcu.navValue(nav_index); - const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .variable => |variable| Value.fromInterned(variable.init), + const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { + .func => .none, + .variable => |variable| variable.init, .@"extern" => |@"extern"| { if (ip.isFunctionType(@"extern".ty)) return; const sym_index = try self.getGlobalSymbol( @@ -1135,10 +1135,10 @@ pub fn updateNav( self.symbol(sym_index).flags.is_extern_ptr = true; return; }, - else => nav_val, + else => nav.status.resolved.val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) { const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index); self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); @@ -1153,7 +1153,7 @@ pub fn updateNav( &elf_file.base, pt, zcu.navSrcLoc(nav_index), - nav_init, + Value.fromInterned(nav_init), &code_buffer, if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, .{ .parent_atom_index = sym_index }, diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 4827dae268..d6b77243a1 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -869,10 +869,11 @@ pub fn updateNav( const zcu = pt.zcu; const ip = &zcu.intern_pool; + const nav = ip.getNav(nav_index); - const nav_val = zcu.navValue(nav_index); - const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .variable => |variable| Value.fromInterned(variable.init), + const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { + .func => .none, + .variable => |variable| variable.init, .@"extern" => |@"extern"| { if (ip.isFunctionType(@"extern".ty)) return; // Extern variable gets a __got entry only @@ -883,10 +884,10 @@ pub fn updateNav( sym.flags.is_extern_ptr = true; return; }, - else => nav_val, + else => nav.status.resolved.val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) { const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index); self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); @@ -900,7 +901,7 @@ pub fn updateNav( &macho_file.base, pt, zcu.navSrcLoc(nav_index), - nav_init, + Value.fromInterned(nav_init), &code_buffer, if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, .{ .parent_atom_index = sym_index }, diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index eeba9ad61b..27a3bf7bc8 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -448,6 +448,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde const nav = ip.getNav(nav_index); const nav_val = zcu.navValue(nav_index); const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { + .func => return, .variable => |variable| Value.fromInterned(variable.init), .@"extern" => { log.debug("found extern decl: {}", .{nav.name.fmt(ip)}); @@ -456,7 +457,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde else => nav_val, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) { const atom_idx = try self.seeNav(pt, nav_index); var code_buffer = std.ArrayList(u8).init(gpa); diff --git a/src/link/Wasm/ZigObject.zig b/src/link/Wasm/ZigObject.zig index 0f73edefab..05c15f0732 100644 --- a/src/link/Wasm/ZigObject.zig +++ b/src/link/Wasm/ZigObject.zig @@ -259,7 +259,7 @@ pub fn updateNav( else => .{ false, .none, nav_val }, }; - if (nav_init.typeOf(zcu).isFnOrHasRuntimeBits(pt)) { + if (nav_init.typeOf(zcu).hasRuntimeBits(pt)) { const gpa = wasm_file.base.comp.gpa; const atom_index = try zig_object.getOrCreateAtomForNav(wasm_file, pt, nav_index); const atom = wasm_file.getAtomPtr(atom_index); diff --git a/src/print_air.zig b/src/print_air.zig index 137461e6e4..4db66a1d3c 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -283,6 +283,7 @@ const Writer = struct { .dbg_var_ptr, .dbg_var_val, + .dbg_arg_inline, => try w.writeDbgVar(s, inst), .struct_field_ptr => try w.writeStructField(s, inst), @@ -358,10 +359,7 @@ const Writer = struct { try w.writeType(s, arg.ty.toType()); switch (arg.name) { .none => {}, - _ => { - const name = w.air.nullTerminatedString(@intFromEnum(arg.name)); - try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)}); - }, + _ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}), } } @@ -686,8 +684,8 @@ const Writer = struct { fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; try w.writeOperand(s, inst, 0, pl_op.operand); - const name = w.air.nullTerminatedString(pl_op.payload); - try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)}); + const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); + try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))}); } fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { diff --git a/test/src/Debugger.zig b/test/src/Debugger.zig index 2ff141dd84..f92f7f8a95 100644 --- a/test/src/Debugger.zig +++ b/test/src/Debugger.zig @@ -587,7 +587,7 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { }, ); db.addLldbTest( - "cross_module_call", + "inline_call", target, &.{ .{ @@ -595,8 +595,18 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { .source = \\const module = @import("module"); \\pub fn main() void { - \\ module.foo(123); - \\ module.bar(456); + \\ fa(12); + \\ fb(34); + \\ module.fc(56); + \\ module.fd(78); + \\} + \\fn fa(pa: u32) void { + \\ const la = ~pa; + \\ _ = la; + \\} + \\inline fn fb(pb: u32) void { + \\ const lb = ~pb; + \\ _ = lb; \\} \\ , @@ -605,34 +615,84 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void { .import = "module", .path = "module.zig", .source = - \\pub fn foo(x: u32) void { - \\ _ = x; + \\pub fn fc(pc: u32) void { + \\ const lc = ~pc; + \\ _ = lc; \\} - \\pub inline fn bar(y: u32) void { - \\ _ = y; + \\pub inline fn fd(pd: u32) void { + \\ const ld = ~pd; + \\ _ = ld; \\} \\ , }, }, - \\breakpoint set --file module.zig --source-pattern-regexp '_ = x;' + \\settings set frame-format 'frame #${frame.index}:{ ${module.file.basename}{\`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${line.file.basename}:${line.number}{:${line.column}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\n' + \\ + \\breakpoint set --file main.zig --source-pattern-regexp '_ = la;' \\process launch - \\source info + \\frame variable pa la + \\thread backtrace --count 2 \\breakpoint delete --force 1 \\ - \\breakpoint set --file module.zig --line 5 + \\breakpoint set --file main.zig --source-pattern-regexp '_ = lb;' \\process continue - \\source info + \\frame variable pb lb + \\thread backtrace --count 2 \\breakpoint delete --force 2 + \\ + \\breakpoint set --file module.zig --source-pattern-regexp '_ = lc;' + \\process continue + \\frame variable pc lc + \\thread backtrace --count 2 + \\breakpoint delete --force 3 + \\ + \\breakpoint set --file module.zig --line 7 + \\process continue + \\frame variable pd ld + \\thread backtrace --count 2 + \\breakpoint delete --force 4 , &.{ - \\/module.zig:2:5 + \\(lldb) frame variable pa la + \\(u32) pa = 12 + \\(u32) la = 4294967283 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 1.1 + \\ * frame #0: inline_call`main.fa(pa=12) at main.zig:10:5 + \\ frame #1: inline_call`main.main at main.zig:3:7 \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. , - \\/module.zig:5:5 + \\(lldb) frame variable pb lb + \\(u32) pb = 34 + \\(u32) lb = 4294967261 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 2.1 + \\ * frame #0: inline_call`main.main [inlined] fb(pb=34) at main.zig:14:5 + \\ frame #1: inline_call`main.main at main.zig:4:7 \\(lldb) breakpoint delete --force 2 \\1 breakpoints deleted; 0 breakpoint locations disabled. + , + \\(lldb) frame variable pc lc + \\(u32) pc = 56 + \\(u32) lc = 4294967239 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 3.1 + \\ * frame #0: inline_call`module.fc(pc=56) at module.zig:3:5 + \\ frame #1: inline_call`main.main at main.zig:5:14 + \\(lldb) breakpoint delete --force 3 + \\1 breakpoints deleted; 0 breakpoint locations disabled. + , + \\(lldb) frame variable pd ld + \\(u32) pd = 78 + \\(u32) ld = 4294967217 + \\(lldb) thread backtrace --count 2 + \\* thread #1, name = 'inline_call', stop reason = breakpoint 4.1 + \\ * frame #0: inline_call`main.main [inlined] fd(pd=78) at module.zig:7:5 + \\ frame #1: inline_call`main.main at main.zig:6:14 + \\(lldb) breakpoint delete --force 4 + \\1 breakpoints deleted; 0 breakpoint locations disabled. }, ); }