| author | |
| committer | |
| log | 84f584317897bfc1d529361b79721d22d130d4d3 |
| tree | 6bee6902f5290641d98ffc37eb2c68a96c5a9067 |
| parent | 95ecd521b8f169a80e543f8a07aef4807a1d46d8 |
stage2: misc DWARF debug info fixes and additions for x86_64 and aarch647 files changed, 412 insertions(+), 116 deletions(-)
src/arch/aarch64/CodeGen.zig+265-23| ... | ... | @@ -51,13 +51,14 @@ gpa: Allocator, |
| 51 | 51 | air: Air, |
| 52 | 52 | liveness: Liveness, |
| 53 | 53 | bin_file: *link.File, |
| 54 | debug_output: DebugInfoOutput, | |
| 54 | 55 | target: *const std.Target, |
| 55 | 56 | mod_fn: *const Module.Fn, |
| 56 | 57 | err_msg: ?*ErrorMsg, |
| 57 | 58 | args: []MCValue, |
| 58 | 59 | ret_mcv: MCValue, |
| 59 | 60 | fn_type: Type, |
| 60 | arg_index: usize, | |
| 61 | arg_index: u32, | |
| 61 | 62 | src_loc: Module.SrcLoc, |
| 62 | 63 | stack_align: u32, |
| 63 | 64 | |
| ... | ... | @@ -75,6 +76,12 @@ end_di_column: u32, |
| 75 | 76 | /// which is a relative jump, based on the address following the reloc. |
| 76 | 77 | exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{}, |
| 77 | 78 | |
| 79 | /// We postpone the creation of debug info for function args and locals | |
| 80 | /// until after all Mir instructions have been generated. Only then we | |
| 81 | /// will know saved_regs_stack_space which is necessary in order to | |
| 82 | /// calculate the right stack offsest with respect to the `.fp` register. | |
| 83 | dbg_info_relocs: std.ArrayListUnmanaged(DbgInfoReloc) = .{}, | |
| 84 | ||
| 78 | 85 | /// Whenever there is a runtime branch, we push a Branch onto this stack, |
| 79 | 86 | /// and pop it off when the runtime branch joins. This provides an "overlay" |
| 80 | 87 | /// of the table of mappings from instructions to `MCValue` from within the branch. |
| ... | ... | @@ -159,6 +166,220 @@ const MCValue = union(enum) { |
| 159 | 166 | stack_argument_offset: u32, |
| 160 | 167 | }; |
| 161 | 168 | |
| 169 | const DbgInfoReloc = struct { | |
| 170 | tag: Air.Inst.Tag, | |
| 171 | ty: Type, | |
| 172 | name: [:0]const u8, | |
| 173 | mcv: MCValue, | |
| 174 | ||
| 175 | fn genDbgInfo(reloc: DbgInfoReloc, function: Self) !void { | |
| 176 | switch (reloc.tag) { | |
| 177 | .arg => try reloc.genArgDbgInfo(function), | |
| 178 | ||
| 179 | .dbg_var_ptr, | |
| 180 | .dbg_var_val, | |
| 181 | => try reloc.genVarDbgInfo(function), | |
| 182 | ||
| 183 | else => unreachable, | |
| 184 | } | |
| 185 | } | |
| 186 | ||
| 187 | fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void { | |
| 188 | const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1]; | |
| 189 | ||
| 190 | switch (function.debug_output) { | |
| 191 | .dwarf => |dw| { | |
| 192 | const dbg_info = &dw.dbg_info; | |
| 193 | switch (reloc.mcv) { | |
| 194 | .register => |reg| { | |
| 195 | try dbg_info.ensureUnusedCapacity(3); | |
| 196 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 197 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 198 | 1, // ULEB128 dwarf expression length | |
| 199 | reg.dwarfLocOp(), | |
| 200 | }); | |
| 201 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 202 | try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4 | |
| 203 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 204 | }, | |
| 205 | ||
| 206 | .stack_offset, | |
| 207 | .stack_argument_offset, | |
| 208 | => |offset| { | |
| 209 | const adjusted_offset = switch (reloc.mcv) { | |
| 210 | .stack_offset => -@intCast(i32, offset), | |
| 211 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), | |
| 212 | else => unreachable, | |
| 213 | }; | |
| 214 | ||
| 215 | try dbg_info.ensureUnusedCapacity(8); | |
| 216 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 217 | const fixup = dbg_info.items.len; | |
| 218 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 219 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 220 | Register.x29.dwarfLocOpDeref(), // frame pointer | |
| 221 | }); | |
| 222 | leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable; | |
| 223 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 224 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 225 | try function.addDbgInfoTypeReloc(reloc.ty); // DW.AT.type, DW.FORM.ref4 | |
| 226 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 227 | ||
| 228 | }, | |
| 229 | ||
| 230 | else => unreachable, // not a possible argument | |
| 231 | } | |
| 232 | }, | |
| 233 | .plan9 => {}, | |
| 234 | .none => {}, | |
| 235 | } | |
| 236 | } | |
| 237 | ||
| 238 | fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void { | |
| 239 | const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1]; | |
| 240 | const ty = switch (reloc.tag) { | |
| 241 | .dbg_var_ptr => reloc.ty.childType(), | |
| 242 | .dbg_var_val => reloc.ty, | |
| 243 | else => unreachable, | |
| 244 | }; | |
| 245 | ||
| 246 | switch (function.debug_output) { | |
| 247 | .dwarf => |dw| { | |
| 248 | const dbg_info = &dw.dbg_info; | |
| 249 | try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); | |
| 250 | const endian = function.target.cpu.arch.endian(); | |
| 251 | ||
| 252 | switch (reloc.mcv) { | |
| 253 | .register => |reg| { | |
| 254 | try dbg_info.ensureUnusedCapacity(2); | |
| 255 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 256 | 1, // ULEB128 dwarf expression length | |
| 257 | reg.dwarfLocOp(), | |
| 258 | }); | |
| 259 | }, | |
| 260 | ||
| 261 | .ptr_stack_offset, | |
| 262 | .stack_offset, | |
| 263 | .stack_argument_offset, | |
| 264 | => |offset| { | |
| 265 | const adjusted_offset = switch (reloc.mcv) { | |
| 266 | .ptr_stack_offset, | |
| 267 | .stack_offset, | |
| 268 | => -@intCast(i32, offset), | |
| 269 | .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset), | |
| 270 | else => unreachable, | |
| 271 | }; | |
| 272 | ||
| 273 | try dbg_info.ensureUnusedCapacity(7); | |
| 274 | const fixup = dbg_info.items.len; | |
| 275 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 276 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 277 | Register.x29.dwarfLocOpDeref(), // frame pointer | |
| 278 | }); | |
| 279 | leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable; | |
| 280 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 281 | }, | |
| 282 | ||
| 283 | .memory, | |
| 284 | .linker_load, | |
| 285 | => { | |
| 286 | const ptr_width = @intCast(u8, @divExact(function.target.cpu.arch.ptrBitWidth(), 8)); | |
| 287 | const is_ptr = switch (reloc.tag) { | |
| 288 | .dbg_var_ptr => true, | |
| 289 | .dbg_var_val => false, | |
| 290 | else => unreachable, | |
| 291 | }; | |
| 292 | try dbg_info.ensureUnusedCapacity(2 + ptr_width); | |
| 293 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 294 | 1 + ptr_width + @boolToInt(is_ptr), | |
| 295 | DW.OP.addr, // literal address | |
| 296 | }); | |
| 297 | const offset = @intCast(u32, dbg_info.items.len); | |
| 298 | const addr = switch (reloc.mcv) { | |
| 299 | .memory => |addr| addr, | |
| 300 | else => 0, | |
| 301 | }; | |
| 302 | switch (ptr_width) { | |
| 303 | 0...4 => { | |
| 304 | try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian); | |
| 305 | }, | |
| 306 | 5...8 => { | |
| 307 | try dbg_info.writer().writeInt(u64, addr, endian); | |
| 308 | }, | |
| 309 | else => unreachable, | |
| 310 | } | |
| 311 | if (is_ptr) { | |
| 312 | // We need deref the address as we point to the value via GOT entry. | |
| 313 | try dbg_info.append(DW.OP.deref); | |
| 314 | } | |
| 315 | switch (reloc.mcv) { | |
| 316 | .linker_load => |load_struct| try dw.addExprlocReloc( | |
| 317 | load_struct.sym_index, | |
| 318 | offset, | |
| 319 | is_ptr, | |
| 320 | ), | |
| 321 | else => {}, | |
| 322 | } | |
| 323 | }, | |
| 324 | ||
| 325 | .immediate => |x| { | |
| 326 | try dbg_info.ensureUnusedCapacity(2); | |
| 327 | const fixup = dbg_info.items.len; | |
| 328 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 329 | 1, | |
| 330 | if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu, | |
| 331 | }); | |
| 332 | if (ty.isSignedInt()) { | |
| 333 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); | |
| 334 | } else { | |
| 335 | try leb128.writeULEB128(dbg_info.writer(), x); | |
| 336 | } | |
| 337 | try dbg_info.append(DW.OP.stack_value); | |
| 338 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 339 | }, | |
| 340 | ||
| 341 | .undef => { | |
| 342 | // DW.AT.location, DW.FORM.exprloc | |
| 343 | // uleb128(exprloc_len) | |
| 344 | // DW.OP.implicit_value uleb128(len_of_bytes) bytes | |
| 345 | const abi_size = @intCast(u32, ty.abiSize(function.target.*)); | |
| 346 | var implicit_value_len = std.ArrayList(u8).init(function.gpa); | |
| 347 | defer implicit_value_len.deinit(); | |
| 348 | try leb128.writeULEB128(implicit_value_len.writer(), abi_size); | |
| 349 | const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size; | |
| 350 | try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len); | |
| 351 | try dbg_info.ensureUnusedCapacity(total_exprloc_len); | |
| 352 | dbg_info.appendAssumeCapacity(DW.OP.implicit_value); | |
| 353 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); | |
| 354 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); | |
| 355 | }, | |
| 356 | ||
| 357 | .none => { | |
| 358 | try dbg_info.ensureUnusedCapacity(3); | |
| 359 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 360 | 2, DW.OP.lit0, DW.OP.stack_value, | |
| 361 | }); | |
| 362 | }, | |
| 363 | ||
| 364 | else => { | |
| 365 | try dbg_info.ensureUnusedCapacity(2); | |
| 366 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 367 | 1, DW.OP.nop, | |
| 368 | }); | |
| 369 | log.debug("TODO generate debug info for {}", .{reloc.mcv}); | |
| 370 | }, | |
| 371 | } | |
| 372 | ||
| 373 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 374 | try function.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 375 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 376 | }, | |
| 377 | .plan9 => {}, | |
| 378 | .none => {}, | |
| 379 | } | |
| 380 | } | |
| 381 | }; | |
| 382 | ||
| 162 | 383 | const Branch = struct { |
| 163 | 384 | inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{}, |
| 164 | 385 | |
| ... | ... | @@ -261,6 +482,7 @@ pub fn generate( |
| 261 | 482 | .gpa = bin_file.allocator, |
| 262 | 483 | .air = air, |
| 263 | 484 | .liveness = liveness, |
| 485 | .debug_output = debug_output, | |
| 264 | 486 | .target = &bin_file.options.target, |
| 265 | 487 | .bin_file = bin_file, |
| 266 | 488 | .mod_fn = module_fn, |
| ... | ... | @@ -278,6 +500,7 @@ pub fn generate( |
| 278 | 500 | defer function.stack.deinit(bin_file.allocator); |
| 279 | 501 | defer function.blocks.deinit(bin_file.allocator); |
| 280 | 502 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| 503 | defer function.dbg_info_relocs.deinit(bin_file.allocator); | |
| 281 | 504 | |
| 282 | 505 | var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { |
| 283 | 506 | error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, |
| ... | ... | @@ -301,6 +524,10 @@ pub fn generate( |
| 301 | 524 | else => |e| return e, |
| 302 | 525 | }; |
| 303 | 526 | |
| 527 | for (function.dbg_info_relocs.items) |reloc| { | |
| 528 | try reloc.genDbgInfo(function); | |
| 529 | } | |
| 530 | ||
| 304 | 531 | var mir = Mir{ |
| 305 | 532 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 306 | 533 | .extra = function.mir_extra.toOwnedSlice(bin_file.allocator), |
| ... | ... | @@ -853,23 +1080,20 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 853 | 1080 | |
| 854 | 1081 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 855 | 1082 | /// after codegen for this symbol is done. |
| 856 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { | |
| 1083 | fn addDbgInfoTypeReloc(self: Self, ty: Type) !void { | |
| 857 | 1084 | switch (self.debug_output) { |
| 858 | .dwarf => |dbg_out| { | |
| 859 | assert(ty.hasRuntimeBits()); | |
| 860 | const index = dbg_out.dbg_info.items.len; | |
| 861 | try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 862 | ||
| 863 | const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{ | |
| 864 | .target = self.target.*, | |
| 865 | }); | |
| 866 | if (!gop.found_existing) { | |
| 867 | gop.value_ptr.* = .{ | |
| 868 | .off = undefined, | |
| 869 | .relocs = .{}, | |
| 870 | }; | |
| 871 | } | |
| 872 | try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index)); | |
| 1085 | .dwarf => |dw| { | |
| 1086 | const dbg_info = &dw.dbg_info; | |
| 1087 | const index = dbg_info.items.len; | |
| 1088 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | |
| 1089 | const mod = self.bin_file.options.module.?; | |
| 1090 | const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); | |
| 1091 | const atom = switch (self.bin_file.tag) { | |
| 1092 | .elf => &fn_owner_decl.link.elf.dbg_info_atom, | |
| 1093 | .macho => &fn_owner_decl.link.macho.dbg_info_atom, | |
| 1094 | else => unreachable, | |
| 1095 | }; | |
| 1096 | try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); | |
| 873 | 1097 | }, |
| 874 | 1098 | .plan9 => {}, |
| 875 | 1099 | .none => {}, |
| ... | ... | @@ -3866,8 +4090,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3866 | 4090 | self.arg_index += 1; |
| 3867 | 4091 | |
| 3868 | 4092 | const ty = self.air.typeOfIndex(inst); |
| 3869 | ||
| 3870 | 4093 | const result = self.args[arg_index]; |
| 4094 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); | |
| 4095 | ||
| 3871 | 4096 | const mcv = switch (result) { |
| 3872 | 4097 | // Copy registers to the stack |
| 3873 | 4098 | .register => |reg| blk: { |
| ... | ... | @@ -3883,8 +4108,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3883 | 4108 | }, |
| 3884 | 4109 | else => result, |
| 3885 | 4110 | }; |
| 3886 | // TODO generate debug info | |
| 3887 | // try self.genArgDbgInfo(inst, mcv); | |
| 4111 | ||
| 4112 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 4113 | try self.dbg_info_relocs.append(self.gpa, .{ | |
| 4114 | .tag = tag, | |
| 4115 | .ty = ty, | |
| 4116 | .name = name, | |
| 4117 | .mcv = result, | |
| 4118 | }); | |
| 3888 | 4119 | |
| 3889 | 4120 | if (self.liveness.isUnused(inst)) |
| 3890 | 4121 | return self.finishAirBookkeeping(); |
| ... | ... | @@ -4335,10 +4566,21 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 4335 | 4566 | |
| 4336 | 4567 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4337 | 4568 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4338 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 4339 | 4569 | const operand = pl_op.operand; |
| 4340 | // TODO emit debug info for this variable | |
| 4341 | _ = name; | |
| 4570 | const tag = self.air.instructions.items(.tag)[inst]; | |
| 4571 | const ty = self.air.typeOf(operand); | |
| 4572 | const mcv = try self.resolveInst(operand); | |
| 4573 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 4574 | ||
| 4575 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv }); | |
| 4576 | ||
| 4577 | try self.dbg_info_relocs.append(self.gpa, .{ | |
| 4578 | .tag = tag, | |
| 4579 | .ty = ty, | |
| 4580 | .name = name, | |
| 4581 | .mcv = mcv, | |
| 4582 | }); | |
| 4583 | ||
| 4342 | 4584 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); |
| 4343 | 4585 | } |
| 4344 | 4586 |
src/arch/aarch64/bits.zig+7| ... | ... | @@ -296,6 +296,13 @@ pub const Register = enum(u8) { |
| 296 | 296 | pub fn dwarfLocOp(self: Register) u8 { |
| 297 | 297 | return @as(u8, self.enc()) + DW.OP.reg0; |
| 298 | 298 | } |
| 299 | ||
| 300 | /// DWARF encodings that push a value onto the DWARF stack that is either | |
| 301 | /// the contents of a register or the result of adding the contents a given | |
| 302 | /// register to a given signed offset. | |
| 303 | pub fn dwarfLocOpDeref(self: Register) u8 { | |
| 304 | return @as(u8, self.enc()) + DW.OP.breg0; | |
| 305 | } | |
| 299 | 306 | }; |
| 300 | 307 | |
| 301 | 308 | test "Register.enc" { |
src/arch/x86_64/CodeGen.zig+73-65| ... | ... | @@ -3797,64 +3797,68 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3797 | 3797 | const ty = self.air.typeOfIndex(inst); |
| 3798 | 3798 | const mcv = self.args[arg_index]; |
| 3799 | 3799 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); |
| 3800 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 3801 | 3800 | |
| 3802 | 3801 | if (self.liveness.isUnused(inst)) |
| 3803 | 3802 | return self.finishAirBookkeeping(); |
| 3804 | 3803 | |
| 3805 | const dst_mcv: MCValue = blk: { | |
| 3806 | switch (mcv) { | |
| 3807 | .register => |reg| { | |
| 3808 | self.register_manager.getRegAssumeFree(reg.to64(), inst); | |
| 3809 | switch (self.debug_output) { | |
| 3810 | .dwarf => |dw| { | |
| 3811 | const dbg_info = &dw.dbg_info; | |
| 3812 | try dbg_info.ensureUnusedCapacity(3); | |
| 3813 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 3814 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 3815 | 1, // ULEB128 dwarf expression length | |
| 3816 | reg.dwarfLocOp(), | |
| 3817 | }); | |
| 3818 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 3819 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 3820 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 3821 | }, | |
| 3822 | .plan9 => {}, | |
| 3823 | .none => {}, | |
| 3824 | } | |
| 3825 | break :blk mcv; | |
| 3826 | }, | |
| 3827 | .stack_offset => |off| { | |
| 3828 | const offset = @intCast(i32, self.max_end_stack) - off + 16; | |
| 3829 | switch (self.debug_output) { | |
| 3830 | .dwarf => |dw| { | |
| 3831 | const dbg_info = &dw.dbg_info; | |
| 3832 | try dbg_info.ensureUnusedCapacity(8); | |
| 3833 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 3834 | const fixup = dbg_info.items.len; | |
| 3835 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 3836 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 3837 | DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer | |
| 3838 | }); | |
| 3839 | leb128.writeILEB128(dbg_info.writer(), offset) catch unreachable; | |
| 3840 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 3841 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 3842 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 3843 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 3844 | ||
| 3845 | }, | |
| 3846 | .plan9 => {}, | |
| 3847 | .none => {}, | |
| 3848 | } | |
| 3849 | break :blk MCValue{ .stack_offset = -offset }; | |
| 3850 | }, | |
| 3851 | else => return self.fail("TODO implement arg for {}", .{mcv}), | |
| 3852 | } | |
| 3804 | const dst_mcv: MCValue = switch (mcv) { | |
| 3805 | .register => |reg| blk: { | |
| 3806 | self.register_manager.getRegAssumeFree(reg.to64(), inst); | |
| 3807 | break :blk MCValue{ .register = reg }; | |
| 3808 | }, | |
| 3809 | .stack_offset => |off| blk: { | |
| 3810 | const offset = @intCast(i32, self.max_end_stack) - off + 16; | |
| 3811 | break :blk MCValue{ .stack_offset = -offset }; | |
| 3812 | }, | |
| 3813 | else => return self.fail("TODO implement arg for {}", .{mcv}), | |
| 3853 | 3814 | }; |
| 3815 | try self.genArgDbgInfo(ty, name, dst_mcv); | |
| 3854 | 3816 | |
| 3855 | 3817 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); |
| 3856 | 3818 | } |
| 3857 | 3819 | |
| 3820 | fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { | |
| 3821 | const name_with_null = name.ptr[0 .. name.len + 1]; | |
| 3822 | switch (self.debug_output) { | |
| 3823 | .dwarf => |dw| { | |
| 3824 | const dbg_info = &dw.dbg_info; | |
| 3825 | switch (mcv) { | |
| 3826 | .register => |reg| { | |
| 3827 | try dbg_info.ensureUnusedCapacity(3); | |
| 3828 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 3829 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 3830 | 1, // ULEB128 dwarf expression length | |
| 3831 | reg.dwarfLocOp(), | |
| 3832 | }); | |
| 3833 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 3834 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 3835 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 3836 | }, | |
| 3837 | ||
| 3838 | .stack_offset => |off| { | |
| 3839 | try dbg_info.ensureUnusedCapacity(8); | |
| 3840 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | |
| 3841 | const fixup = dbg_info.items.len; | |
| 3842 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | |
| 3843 | 1, // we will backpatch it after we encode the displacement in LEB128 | |
| 3844 | Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer | |
| 3845 | }); | |
| 3846 | leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; | |
| 3847 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | |
| 3848 | try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); | |
| 3849 | try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 | |
| 3850 | dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string | |
| 3851 | ||
| 3852 | }, | |
| 3853 | ||
| 3854 | else => unreachable, // not a valid function parameter | |
| 3855 | } | |
| 3856 | }, | |
| 3857 | .plan9 => {}, | |
| 3858 | .none => {}, | |
| 3859 | } | |
| 3860 | } | |
| 3861 | ||
| 3858 | 3862 | fn airBreakpoint(self: *Self) !void { |
| 3859 | 3863 | _ = try self.addInst(.{ |
| 3860 | 3864 | .tag = .interrupt, |
| ... | ... | @@ -4424,7 +4428,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4424 | 4428 | } |
| 4425 | 4429 | |
| 4426 | 4430 | fn genVarDbgInfo( |
| 4427 | self: *Self, | |
| 4431 | self: Self, | |
| 4428 | 4432 | tag: Air.Inst.Tag, |
| 4429 | 4433 | ty: Type, |
| 4430 | 4434 | mcv: MCValue, |
| ... | ... | @@ -4445,17 +4449,23 @@ fn genVarDbgInfo( |
| 4445 | 4449 | reg.dwarfLocOp(), |
| 4446 | 4450 | }); |
| 4447 | 4451 | }, |
| 4448 | .ptr_stack_offset, .stack_offset => |off| { | |
| 4452 | ||
| 4453 | .ptr_stack_offset, | |
| 4454 | .stack_offset, | |
| 4455 | => |off| { | |
| 4449 | 4456 | try dbg_info.ensureUnusedCapacity(7); |
| 4450 | 4457 | const fixup = dbg_info.items.len; |
| 4451 | 4458 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 4452 | 4459 | 1, // we will backpatch it after we encode the displacement in LEB128 |
| 4453 | DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer | |
| 4460 | Register.rbp.dwarfLocOpDeref(), // TODO handle -fomit-frame-pointer | |
| 4454 | 4461 | }); |
| 4455 | 4462 | leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; |
| 4456 | 4463 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); |
| 4457 | 4464 | }, |
| 4458 | .memory, .linker_load => { | |
| 4465 | ||
| 4466 | .memory, | |
| 4467 | .linker_load, | |
| 4468 | => { | |
| 4459 | 4469 | const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); |
| 4460 | 4470 | const is_ptr = switch (tag) { |
| 4461 | 4471 | .dbg_var_ptr => true, |
| ... | ... | @@ -4494,27 +4504,23 @@ fn genVarDbgInfo( |
| 4494 | 4504 | else => {}, |
| 4495 | 4505 | } |
| 4496 | 4506 | }, |
| 4507 | ||
| 4497 | 4508 | .immediate => |x| { |
| 4498 | const signedness: std.builtin.Signedness = blk: { | |
| 4499 | if (ty.zigTypeTag() != .Int) break :blk .unsigned; | |
| 4500 | break :blk ty.intInfo(self.target.*).signedness; | |
| 4501 | }; | |
| 4502 | 4509 | try dbg_info.ensureUnusedCapacity(2); |
| 4503 | 4510 | const fixup = dbg_info.items.len; |
| 4504 | 4511 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 4505 | 4512 | 1, |
| 4506 | switch (signedness) { | |
| 4507 | .signed => DW.OP.consts, | |
| 4508 | .unsigned => DW.OP.constu, | |
| 4509 | }, | |
| 4513 | if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu, | |
| 4510 | 4514 | }); |
| 4511 | switch (signedness) { | |
| 4512 | .signed => try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)), | |
| 4513 | .unsigned => try leb128.writeULEB128(dbg_info.writer(), x), | |
| 4515 | if (ty.isSignedInt()) { | |
| 4516 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); | |
| 4517 | } else { | |
| 4518 | try leb128.writeULEB128(dbg_info.writer(), x); | |
| 4514 | 4519 | } |
| 4515 | 4520 | try dbg_info.append(DW.OP.stack_value); |
| 4516 | 4521 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); |
| 4517 | 4522 | }, |
| 4523 | ||
| 4518 | 4524 | .undef => { |
| 4519 | 4525 | // DW.AT.location, DW.FORM.exprloc |
| 4520 | 4526 | // uleb128(exprloc_len) |
| ... | ... | @@ -4530,12 +4536,14 @@ fn genVarDbgInfo( |
| 4530 | 4536 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); |
| 4531 | 4537 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); |
| 4532 | 4538 | }, |
| 4539 | ||
| 4533 | 4540 | .none => { |
| 4534 | 4541 | try dbg_info.ensureUnusedCapacity(3); |
| 4535 | 4542 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc |
| 4536 | 4543 | 2, DW.OP.lit0, DW.OP.stack_value, |
| 4537 | 4544 | }); |
| 4538 | 4545 | }, |
| 4546 | ||
| 4539 | 4547 | else => { |
| 4540 | 4548 | try dbg_info.ensureUnusedCapacity(2); |
| 4541 | 4549 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| ... | ... | @@ -4556,7 +4564,7 @@ fn genVarDbgInfo( |
| 4556 | 4564 | |
| 4557 | 4565 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 4558 | 4566 | /// after codegen for this symbol is done. |
| 4559 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { | |
| 4567 | fn addDbgInfoTypeReloc(self: Self, ty: Type) !void { | |
| 4560 | 4568 | switch (self.debug_output) { |
| 4561 | 4569 | .dwarf => |dw| { |
| 4562 | 4570 | const dbg_info = &dw.dbg_info; |
src/arch/x86_64/bits.zig+61-22| ... | ... | @@ -135,8 +135,6 @@ pub const Condition = enum(u5) { |
| 135 | 135 | } |
| 136 | 136 | }; |
| 137 | 137 | |
| 138 | // zig fmt: off | |
| 139 | ||
| 140 | 138 | /// Definitions of all of the general purpose x64 registers. The order is semantically meaningful. |
| 141 | 139 | /// The registers are defined such that IDs go in descending order of 64-bit, |
| 142 | 140 | /// 32-bit, 16-bit, and then 8-bit, and each set contains exactly sixteen |
| ... | ... | @@ -152,6 +150,7 @@ pub const Condition = enum(u5) { |
| 152 | 150 | /// The ID can be easily determined by figuring out what range the register is |
| 153 | 151 | /// in, and then subtracting the base. |
| 154 | 152 | pub const Register = enum(u7) { |
| 153 | // zig fmt: off | |
| 155 | 154 | // 0 through 15, 64-bit registers. 8-15 are extended. |
| 156 | 155 | // id is just the int value. |
| 157 | 156 | rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, |
| ... | ... | @@ -184,6 +183,7 @@ pub const Register = enum(u7) { |
| 184 | 183 | |
| 185 | 184 | // Pseudo-value for MIR instructions. |
| 186 | 185 | none, |
| 186 | // zig fmt: on | |
| 187 | 187 | |
| 188 | 188 | pub fn id(self: Register) u7 { |
| 189 | 189 | return switch (@enumToInt(self)) { |
| ... | ... | @@ -192,7 +192,7 @@ pub const Register = enum(u7) { |
| 192 | 192 | else => unreachable, |
| 193 | 193 | }; |
| 194 | 194 | } |
| 195 | ||
| 195 | ||
| 196 | 196 | /// Returns the bit-width of the register. |
| 197 | 197 | pub fn size(self: Register) u9 { |
| 198 | 198 | return switch (@enumToInt(self)) { |
| ... | ... | @@ -258,27 +258,66 @@ pub const Register = enum(u7) { |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | 260 | pub fn dwarfLocOp(self: Register) u8 { |
| 261 | return switch (self.to64()) { | |
| 262 | .rax => DW.OP.reg0, | |
| 263 | .rdx => DW.OP.reg1, | |
| 264 | .rcx => DW.OP.reg2, | |
| 265 | .rbx => DW.OP.reg3, | |
| 266 | .rsi => DW.OP.reg4, | |
| 267 | .rdi => DW.OP.reg5, | |
| 268 | .rbp => DW.OP.reg6, | |
| 269 | .rsp => DW.OP.reg7, | |
| 270 | ||
| 271 | .r8 => DW.OP.reg8, | |
| 272 | .r9 => DW.OP.reg9, | |
| 273 | .r10 => DW.OP.reg10, | |
| 274 | .r11 => DW.OP.reg11, | |
| 275 | .r12 => DW.OP.reg12, | |
| 276 | .r13 => DW.OP.reg13, | |
| 277 | .r14 => DW.OP.reg14, | |
| 278 | .r15 => DW.OP.reg15, | |
| 261 | switch (@enumToInt(self)) { | |
| 262 | 0...63 => return switch (self.to64()) { | |
| 263 | .rax => DW.OP.reg0, | |
| 264 | .rdx => DW.OP.reg1, | |
| 265 | .rcx => DW.OP.reg2, | |
| 266 | .rbx => DW.OP.reg3, | |
| 267 | .rsi => DW.OP.reg4, | |
| 268 | .rdi => DW.OP.reg5, | |
| 269 | .rbp => DW.OP.reg6, | |
| 270 | .rsp => DW.OP.reg7, | |
| 271 | ||
| 272 | .r8 => DW.OP.reg8, | |
| 273 | .r9 => DW.OP.reg9, | |
| 274 | .r10 => DW.OP.reg10, | |
| 275 | .r11 => DW.OP.reg11, | |
| 276 | .r12 => DW.OP.reg12, | |
| 277 | .r13 => DW.OP.reg13, | |
| 278 | .r14 => DW.OP.reg14, | |
| 279 | .r15 => DW.OP.reg15, | |
| 280 | ||
| 281 | else => unreachable, | |
| 282 | }, | |
| 283 | ||
| 284 | 64...79 => return @as(u8, self.enc()) + DW.OP.reg17, | |
| 279 | 285 | |
| 280 | 286 | else => unreachable, |
| 281 | }; | |
| 287 | } | |
| 288 | } | |
| 289 | ||
| 290 | /// DWARF encodings that push a value onto the DWARF stack that is either | |
| 291 | /// the contents of a register or the result of adding the contents a given | |
| 292 | /// register to a given signed offset. | |
| 293 | pub fn dwarfLocOpDeref(self: Register) u8 { | |
| 294 | switch (@enumToInt(self)) { | |
| 295 | 0...63 => return switch (self.to64()) { | |
| 296 | .rax => DW.OP.breg0, | |
| 297 | .rdx => DW.OP.breg1, | |
| 298 | .rcx => DW.OP.breg2, | |
| 299 | .rbx => DW.OP.breg3, | |
| 300 | .rsi => DW.OP.breg4, | |
| 301 | .rdi => DW.OP.breg5, | |
| 302 | .rbp => DW.OP.breg6, | |
| 303 | .rsp => DW.OP.fbreg, | |
| 304 | ||
| 305 | .r8 => DW.OP.breg8, | |
| 306 | .r9 => DW.OP.breg9, | |
| 307 | .r10 => DW.OP.breg10, | |
| 308 | .r11 => DW.OP.breg11, | |
| 309 | .r12 => DW.OP.breg12, | |
| 310 | .r13 => DW.OP.breg13, | |
| 311 | .r14 => DW.OP.breg14, | |
| 312 | .r15 => DW.OP.breg15, | |
| 313 | ||
| 314 | else => unreachable, | |
| 315 | }, | |
| 316 | ||
| 317 | 64...79 => return @as(u8, self.enc()) + DW.OP.breg17, | |
| 318 | ||
| 319 | else => unreachable, | |
| 320 | } | |
| 282 | 321 | } |
| 283 | 322 | }; |
| 284 | 323 |
src/link/Dwarf.zig+4-1| ... | ... | @@ -405,8 +405,11 @@ pub const DeclState = struct { |
| 405 | 405 | const value: u64 = if (values) |vals| value: { |
| 406 | 406 | if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered |
| 407 | 407 | const value = vals.keys()[field_i]; |
| 408 | // TODO do not assume a 64bit enum value - could be bigger. | |
| 409 | // See https://github.com/ziglang/zig/issues/645 | |
| 408 | 410 | var int_buffer: Value.Payload.U64 = undefined; |
| 409 | break :value value.enumToInt(ty, &int_buffer).toUnsignedInt(target); | |
| 411 | const field_int_val = value.enumToInt(ty, &int_buffer); | |
| 412 | break :value @bitCast(u64, field_int_val.toSignedInt()); | |
| 410 | 413 | } else @intCast(u64, field_i); |
| 411 | 414 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); |
| 412 | 415 | } |
src/link/MachO.zig+2-3| ... | ... | @@ -329,8 +329,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 329 | 329 | |
| 330 | 330 | if (!options.strip and options.module != null) { |
| 331 | 331 | // Create dSYM bundle. |
| 332 | const dir = options.module.?.zig_cache_artifact_directory; | |
| 333 | log.debug("creating {s}.dSYM bundle in {?s}", .{ emit.sub_path, dir.path }); | |
| 332 | log.debug("creating {s}.dSYM bundle", .{emit.sub_path}); | |
| 334 | 333 | |
| 335 | 334 | const d_sym_path = try fmt.allocPrint( |
| 336 | 335 | allocator, |
| ... | ... | @@ -339,7 +338,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 339 | 338 | ); |
| 340 | 339 | defer allocator.free(d_sym_path); |
| 341 | 340 | |
| 342 | var d_sym_bundle = try dir.handle.makeOpenPath(d_sym_path, .{}); | |
| 341 | var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{}); | |
| 343 | 342 | defer d_sym_bundle.close(); |
| 344 | 343 | |
| 345 | 344 | const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{ |
test/behavior/enum.zig-2| ... | ... | @@ -1146,8 +1146,6 @@ test "size of enum with only one tag which has explicit integer tag type" { |
| 1146 | 1146 | } |
| 1147 | 1147 | |
| 1148 | 1148 | test "switch on an extern enum with negative value" { |
| 1149 | // TODO x86, wasm backends fail because they assume that enum tag types are unsigned | |
| 1150 | if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 1151 | 1149 | if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 1152 | 1150 | |
| 1153 | 1151 | const Foo = enum(c_int) { |