| 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,13 +51,14 @@ gpa: Allocator, |
| 51 | air: Air, | 51 | air: Air, |
| 52 | liveness: Liveness, | 52 | liveness: Liveness, |
| 53 | bin_file: *link.File, | 53 | bin_file: *link.File, |
| 54 | debug_output: DebugInfoOutput, | ||
| 54 | target: *const std.Target, | 55 | target: *const std.Target, |
| 55 | mod_fn: *const Module.Fn, | 56 | mod_fn: *const Module.Fn, |
| 56 | err_msg: ?*ErrorMsg, | 57 | err_msg: ?*ErrorMsg, |
| 57 | args: []MCValue, | 58 | args: []MCValue, |
| 58 | ret_mcv: MCValue, | 59 | ret_mcv: MCValue, |
| 59 | fn_type: Type, | 60 | fn_type: Type, |
| 60 | arg_index: usize, | 61 | arg_index: u32, |
| 61 | src_loc: Module.SrcLoc, | 62 | src_loc: Module.SrcLoc, |
| 62 | stack_align: u32, | 63 | stack_align: u32, |
| 63 | 64 | ||
| ... | @@ -75,6 +76,12 @@ end_di_column: u32, | ... | @@ -75,6 +76,12 @@ end_di_column: u32, |
| 75 | /// which is a relative jump, based on the address following the reloc. | 76 | /// which is a relative jump, based on the address following the reloc. |
| 76 | exitlude_jump_relocs: std.ArrayListUnmanaged(usize) = .{}, | 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 | /// Whenever there is a runtime branch, we push a Branch onto this stack, | 85 | /// Whenever there is a runtime branch, we push a Branch onto this stack, |
| 79 | /// and pop it off when the runtime branch joins. This provides an "overlay" | 86 | /// and pop it off when the runtime branch joins. This provides an "overlay" |
| 80 | /// of the table of mappings from instructions to `MCValue` from within the branch. | 87 | /// of the table of mappings from instructions to `MCValue` from within the branch. |
| ... | @@ -159,6 +166,220 @@ const MCValue = union(enum) { | ... | @@ -159,6 +166,220 @@ const MCValue = union(enum) { |
| 159 | stack_argument_offset: u32, | 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 | const Branch = struct { | 383 | const Branch = struct { |
| 163 | inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{}, | 384 | inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .{}, |
| 164 | 385 | ||
| ... | @@ -261,6 +482,7 @@ pub fn generate( | ... | @@ -261,6 +482,7 @@ pub fn generate( |
| 261 | .gpa = bin_file.allocator, | 482 | .gpa = bin_file.allocator, |
| 262 | .air = air, | 483 | .air = air, |
| 263 | .liveness = liveness, | 484 | .liveness = liveness, |
| 485 | .debug_output = debug_output, | ||
| 264 | .target = &bin_file.options.target, | 486 | .target = &bin_file.options.target, |
| 265 | .bin_file = bin_file, | 487 | .bin_file = bin_file, |
| 266 | .mod_fn = module_fn, | 488 | .mod_fn = module_fn, |
| ... | @@ -278,6 +500,7 @@ pub fn generate( | ... | @@ -278,6 +500,7 @@ pub fn generate( |
| 278 | defer function.stack.deinit(bin_file.allocator); | 500 | defer function.stack.deinit(bin_file.allocator); |
| 279 | defer function.blocks.deinit(bin_file.allocator); | 501 | defer function.blocks.deinit(bin_file.allocator); |
| 280 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); | 502 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| 503 | defer function.dbg_info_relocs.deinit(bin_file.allocator); | ||
| 281 | 504 | ||
| 282 | var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { | 505 | var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) { |
| 283 | error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, | 506 | error.CodegenFail => return FnResult{ .fail = function.err_msg.? }, |
| ... | @@ -301,6 +524,10 @@ pub fn generate( | ... | @@ -301,6 +524,10 @@ pub fn generate( |
| 301 | else => |e| return e, | 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 | var mir = Mir{ | 531 | var mir = Mir{ |
| 305 | .instructions = function.mir_instructions.toOwnedSlice(), | 532 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 306 | .extra = function.mir_extra.toOwnedSlice(bin_file.allocator), | 533 | .extra = function.mir_extra.toOwnedSlice(bin_file.allocator), |
| ... | @@ -853,23 +1080,20 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -853,23 +1080,20 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 853 | 1080 | ||
| 854 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | 1081 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 855 | /// after codegen for this symbol is done. | 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 | switch (self.debug_output) { | 1084 | switch (self.debug_output) { |
| 858 | .dwarf => |dbg_out| { | 1085 | .dwarf => |dw| { |
| 859 | assert(ty.hasRuntimeBits()); | 1086 | const dbg_info = &dw.dbg_info; |
| 860 | const index = dbg_out.dbg_info.items.len; | 1087 | const index = dbg_info.items.len; |
| 861 | try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 | 1088 | try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 |
| 862 | 1089 | const mod = self.bin_file.options.module.?; | |
| 863 | const gop = try dbg_out.dbg_info_type_relocs.getOrPutContext(self.gpa, ty, .{ | 1090 | const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl); |
| 864 | .target = self.target.*, | 1091 | const atom = switch (self.bin_file.tag) { |
| 865 | }); | 1092 | .elf => &fn_owner_decl.link.elf.dbg_info_atom, |
| 866 | if (!gop.found_existing) { | 1093 | .macho => &fn_owner_decl.link.macho.dbg_info_atom, |
| 867 | gop.value_ptr.* = .{ | 1094 | else => unreachable, |
| 868 | .off = undefined, | 1095 | }; |
| 869 | .relocs = .{}, | 1096 | try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); |
| 870 | }; | ||
| 871 | } | ||
| 872 | try gop.value_ptr.relocs.append(self.gpa, @intCast(u32, index)); | ||
| 873 | }, | 1097 | }, |
| 874 | .plan9 => {}, | 1098 | .plan9 => {}, |
| 875 | .none => {}, | 1099 | .none => {}, |
| ... | @@ -3866,8 +4090,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3866,8 +4090,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3866 | self.arg_index += 1; | 4090 | self.arg_index += 1; |
| 3867 | 4091 | ||
| 3868 | const ty = self.air.typeOfIndex(inst); | 4092 | const ty = self.air.typeOfIndex(inst); |
| 3869 | |||
| 3870 | const result = self.args[arg_index]; | 4093 | const result = self.args[arg_index]; |
| 4094 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); | ||
| 4095 | |||
| 3871 | const mcv = switch (result) { | 4096 | const mcv = switch (result) { |
| 3872 | // Copy registers to the stack | 4097 | // Copy registers to the stack |
| 3873 | .register => |reg| blk: { | 4098 | .register => |reg| blk: { |
| ... | @@ -3883,8 +4108,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3883,8 +4108,14 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3883 | }, | 4108 | }, |
| 3884 | else => result, | 4109 | else => result, |
| 3885 | }; | 4110 | }; |
| 3886 | // TODO generate debug info | 4111 | |
| 3887 | // try self.genArgDbgInfo(inst, mcv); | 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 | if (self.liveness.isUnused(inst)) | 4120 | if (self.liveness.isUnused(inst)) |
| 3890 | return self.finishAirBookkeeping(); | 4121 | return self.finishAirBookkeeping(); |
| ... | @@ -4335,10 +4566,21 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4335,10 +4566,21 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 4335 | 4566 | ||
| 4336 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | 4567 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4337 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 4568 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4338 | const name = self.air.nullTerminatedString(pl_op.payload); | ||
| 4339 | const operand = pl_op.operand; | 4569 | const operand = pl_op.operand; |
| 4340 | // TODO emit debug info for this variable | 4570 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4341 | _ = name; | 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 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); | 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,6 +296,13 @@ pub const Register = enum(u8) { |
| 296 | pub fn dwarfLocOp(self: Register) u8 { | 296 | pub fn dwarfLocOp(self: Register) u8 { |
| 297 | return @as(u8, self.enc()) + DW.OP.reg0; | 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 | test "Register.enc" { | 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,64 +3797,68 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3797 | const ty = self.air.typeOfIndex(inst); | 3797 | const ty = self.air.typeOfIndex(inst); |
| 3798 | const mcv = self.args[arg_index]; | 3798 | const mcv = self.args[arg_index]; |
| 3799 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index); | 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 | if (self.liveness.isUnused(inst)) | 3801 | if (self.liveness.isUnused(inst)) |
| 3803 | return self.finishAirBookkeeping(); | 3802 | return self.finishAirBookkeeping(); |
| 3804 | 3803 | ||
| 3805 | const dst_mcv: MCValue = blk: { | 3804 | const dst_mcv: MCValue = switch (mcv) { |
| 3806 | switch (mcv) { | 3805 | .register => |reg| blk: { |
| 3807 | .register => |reg| { | 3806 | self.register_manager.getRegAssumeFree(reg.to64(), inst); |
| 3808 | self.register_manager.getRegAssumeFree(reg.to64(), inst); | 3807 | break :blk MCValue{ .register = reg }; |
| 3809 | switch (self.debug_output) { | 3808 | }, |
| 3810 | .dwarf => |dw| { | 3809 | .stack_offset => |off| blk: { |
| 3811 | const dbg_info = &dw.dbg_info; | 3810 | const offset = @intCast(i32, self.max_end_stack) - off + 16; |
| 3812 | try dbg_info.ensureUnusedCapacity(3); | 3811 | break :blk MCValue{ .stack_offset = -offset }; |
| 3813 | dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter)); | 3812 | }, |
| 3814 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 3813 | else => return self.fail("TODO implement arg for {}", .{mcv}), |
| 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 | } | ||
| 3853 | }; | 3814 | }; |
| 3815 | try self.genArgDbgInfo(ty, name, dst_mcv); | ||
| 3854 | 3816 | ||
| 3855 | return self.finishAir(inst, dst_mcv, .{ .none, .none, .none }); | 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 | fn airBreakpoint(self: *Self) !void { | 3862 | fn airBreakpoint(self: *Self) !void { |
| 3859 | _ = try self.addInst(.{ | 3863 | _ = try self.addInst(.{ |
| 3860 | .tag = .interrupt, | 3864 | .tag = .interrupt, |
| ... | @@ -4424,7 +4428,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4424,7 +4428,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4424 | } | 4428 | } |
| 4425 | 4429 | ||
| 4426 | fn genVarDbgInfo( | 4430 | fn genVarDbgInfo( |
| 4427 | self: *Self, | 4431 | self: Self, |
| 4428 | tag: Air.Inst.Tag, | 4432 | tag: Air.Inst.Tag, |
| 4429 | ty: Type, | 4433 | ty: Type, |
| 4430 | mcv: MCValue, | 4434 | mcv: MCValue, |
| ... | @@ -4445,17 +4449,23 @@ fn genVarDbgInfo( | ... | @@ -4445,17 +4449,23 @@ fn genVarDbgInfo( |
| 4445 | reg.dwarfLocOp(), | 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 | try dbg_info.ensureUnusedCapacity(7); | 4456 | try dbg_info.ensureUnusedCapacity(7); |
| 4450 | const fixup = dbg_info.items.len; | 4457 | const fixup = dbg_info.items.len; |
| 4451 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 4458 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 4452 | 1, // we will backpatch it after we encode the displacement in LEB128 | 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 | leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; | 4462 | leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable; |
| 4456 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | 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 | const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); | 4469 | const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8)); |
| 4460 | const is_ptr = switch (tag) { | 4470 | const is_ptr = switch (tag) { |
| 4461 | .dbg_var_ptr => true, | 4471 | .dbg_var_ptr => true, |
| ... | @@ -4494,27 +4504,23 @@ fn genVarDbgInfo( | ... | @@ -4494,27 +4504,23 @@ fn genVarDbgInfo( |
| 4494 | else => {}, | 4504 | else => {}, |
| 4495 | } | 4505 | } |
| 4496 | }, | 4506 | }, |
| 4507 | |||
| 4497 | .immediate => |x| { | 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 | try dbg_info.ensureUnusedCapacity(2); | 4509 | try dbg_info.ensureUnusedCapacity(2); |
| 4503 | const fixup = dbg_info.items.len; | 4510 | const fixup = dbg_info.items.len; |
| 4504 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 4511 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 4505 | 1, | 4512 | 1, |
| 4506 | switch (signedness) { | 4513 | if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu, |
| 4507 | .signed => DW.OP.consts, | ||
| 4508 | .unsigned => DW.OP.constu, | ||
| 4509 | }, | ||
| 4510 | }); | 4514 | }); |
| 4511 | switch (signedness) { | 4515 | if (ty.isSignedInt()) { |
| 4512 | .signed => try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)), | 4516 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); |
| 4513 | .unsigned => try leb128.writeULEB128(dbg_info.writer(), x), | 4517 | } else { |
| 4518 | try leb128.writeULEB128(dbg_info.writer(), x); | ||
| 4514 | } | 4519 | } |
| 4515 | try dbg_info.append(DW.OP.stack_value); | 4520 | try dbg_info.append(DW.OP.stack_value); |
| 4516 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); | 4521 | dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2); |
| 4517 | }, | 4522 | }, |
| 4523 | |||
| 4518 | .undef => { | 4524 | .undef => { |
| 4519 | // DW.AT.location, DW.FORM.exprloc | 4525 | // DW.AT.location, DW.FORM.exprloc |
| 4520 | // uleb128(exprloc_len) | 4526 | // uleb128(exprloc_len) |
| ... | @@ -4530,12 +4536,14 @@ fn genVarDbgInfo( | ... | @@ -4530,12 +4536,14 @@ fn genVarDbgInfo( |
| 4530 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); | 4536 | dbg_info.appendSliceAssumeCapacity(implicit_value_len.items); |
| 4531 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); | 4537 | dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size); |
| 4532 | }, | 4538 | }, |
| 4539 | |||
| 4533 | .none => { | 4540 | .none => { |
| 4534 | try dbg_info.ensureUnusedCapacity(3); | 4541 | try dbg_info.ensureUnusedCapacity(3); |
| 4535 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc | 4542 | dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc |
| 4536 | 2, DW.OP.lit0, DW.OP.stack_value, | 4543 | 2, DW.OP.lit0, DW.OP.stack_value, |
| 4537 | }); | 4544 | }); |
| 4538 | }, | 4545 | }, |
| 4546 | |||
| 4539 | else => { | 4547 | else => { |
| 4540 | try dbg_info.ensureUnusedCapacity(2); | 4548 | try dbg_info.ensureUnusedCapacity(2); |
| 4541 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 4549 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| ... | @@ -4556,7 +4564,7 @@ fn genVarDbgInfo( | ... | @@ -4556,7 +4564,7 @@ fn genVarDbgInfo( |
| 4556 | 4564 | ||
| 4557 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | 4565 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 4558 | /// after codegen for this symbol is done. | 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 | switch (self.debug_output) { | 4568 | switch (self.debug_output) { |
| 4561 | .dwarf => |dw| { | 4569 | .dwarf => |dw| { |
| 4562 | const dbg_info = &dw.dbg_info; | 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,8 +135,6 @@ pub const Condition = enum(u5) { |
| 135 | } | 135 | } |
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | // zig fmt: off | ||
| 139 | |||
| 140 | /// Definitions of all of the general purpose x64 registers. The order is semantically meaningful. | 138 | /// Definitions of all of the general purpose x64 registers. The order is semantically meaningful. |
| 141 | /// The registers are defined such that IDs go in descending order of 64-bit, | 139 | /// The registers are defined such that IDs go in descending order of 64-bit, |
| 142 | /// 32-bit, 16-bit, and then 8-bit, and each set contains exactly sixteen | 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,6 +150,7 @@ pub const Condition = enum(u5) { |
| 152 | /// The ID can be easily determined by figuring out what range the register is | 150 | /// The ID can be easily determined by figuring out what range the register is |
| 153 | /// in, and then subtracting the base. | 151 | /// in, and then subtracting the base. |
| 154 | pub const Register = enum(u7) { | 152 | pub const Register = enum(u7) { |
| 153 | // zig fmt: off | ||
| 155 | // 0 through 15, 64-bit registers. 8-15 are extended. | 154 | // 0 through 15, 64-bit registers. 8-15 are extended. |
| 156 | // id is just the int value. | 155 | // id is just the int value. |
| 157 | rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, | 156 | rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, |
| ... | @@ -184,6 +183,7 @@ pub const Register = enum(u7) { | ... | @@ -184,6 +183,7 @@ pub const Register = enum(u7) { |
| 184 | 183 | ||
| 185 | // Pseudo-value for MIR instructions. | 184 | // Pseudo-value for MIR instructions. |
| 186 | none, | 185 | none, |
| 186 | // zig fmt: on | ||
| 187 | 187 | ||
| 188 | pub fn id(self: Register) u7 { | 188 | pub fn id(self: Register) u7 { |
| 189 | return switch (@enumToInt(self)) { | 189 | return switch (@enumToInt(self)) { |
| ... | @@ -192,7 +192,7 @@ pub const Register = enum(u7) { | ... | @@ -192,7 +192,7 @@ pub const Register = enum(u7) { |
| 192 | else => unreachable, | 192 | else => unreachable, |
| 193 | }; | 193 | }; |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | /// Returns the bit-width of the register. | 196 | /// Returns the bit-width of the register. |
| 197 | pub fn size(self: Register) u9 { | 197 | pub fn size(self: Register) u9 { |
| 198 | return switch (@enumToInt(self)) { | 198 | return switch (@enumToInt(self)) { |
| ... | @@ -258,27 +258,66 @@ pub const Register = enum(u7) { | ... | @@ -258,27 +258,66 @@ pub const Register = enum(u7) { |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | pub fn dwarfLocOp(self: Register) u8 { | 260 | pub fn dwarfLocOp(self: Register) u8 { |
| 261 | return switch (self.to64()) { | 261 | switch (@enumToInt(self)) { |
| 262 | .rax => DW.OP.reg0, | 262 | 0...63 => return switch (self.to64()) { |
| 263 | .rdx => DW.OP.reg1, | 263 | .rax => DW.OP.reg0, |
| 264 | .rcx => DW.OP.reg2, | 264 | .rdx => DW.OP.reg1, |
| 265 | .rbx => DW.OP.reg3, | 265 | .rcx => DW.OP.reg2, |
| 266 | .rsi => DW.OP.reg4, | 266 | .rbx => DW.OP.reg3, |
| 267 | .rdi => DW.OP.reg5, | 267 | .rsi => DW.OP.reg4, |
| 268 | .rbp => DW.OP.reg6, | 268 | .rdi => DW.OP.reg5, |
| 269 | .rsp => DW.OP.reg7, | 269 | .rbp => DW.OP.reg6, |
| 270 | 270 | .rsp => DW.OP.reg7, | |
| 271 | .r8 => DW.OP.reg8, | 271 | |
| 272 | .r9 => DW.OP.reg9, | 272 | .r8 => DW.OP.reg8, |
| 273 | .r10 => DW.OP.reg10, | 273 | .r9 => DW.OP.reg9, |
| 274 | .r11 => DW.OP.reg11, | 274 | .r10 => DW.OP.reg10, |
| 275 | .r12 => DW.OP.reg12, | 275 | .r11 => DW.OP.reg11, |
| 276 | .r13 => DW.OP.reg13, | 276 | .r12 => DW.OP.reg12, |
| 277 | .r14 => DW.OP.reg14, | 277 | .r13 => DW.OP.reg13, |
| 278 | .r15 => DW.OP.reg15, | 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 | else => unreachable, | 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,8 +405,11 @@ pub const DeclState = struct { |
| 405 | const value: u64 = if (values) |vals| value: { | 405 | const value: u64 = if (values) |vals| value: { |
| 406 | if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered | 406 | if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered |
| 407 | const value = vals.keys()[field_i]; | 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 | var int_buffer: Value.Payload.U64 = undefined; | 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 | } else @intCast(u64, field_i); | 413 | } else @intCast(u64, field_i); |
| 411 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); | 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,8 +329,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 329 | 329 | ||
| 330 | if (!options.strip and options.module != null) { | 330 | if (!options.strip and options.module != null) { |
| 331 | // Create dSYM bundle. | 331 | // Create dSYM bundle. |
| 332 | const dir = options.module.?.zig_cache_artifact_directory; | 332 | log.debug("creating {s}.dSYM bundle", .{emit.sub_path}); |
| 333 | log.debug("creating {s}.dSYM bundle in {?s}", .{ emit.sub_path, dir.path }); | ||
| 334 | 333 | ||
| 335 | const d_sym_path = try fmt.allocPrint( | 334 | const d_sym_path = try fmt.allocPrint( |
| 336 | allocator, | 335 | allocator, |
| ... | @@ -339,7 +338,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { | ... | @@ -339,7 +338,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 339 | ); | 338 | ); |
| 340 | defer allocator.free(d_sym_path); | 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 | defer d_sym_bundle.close(); | 342 | defer d_sym_bundle.close(); |
| 344 | 343 | ||
| 345 | const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{ | 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,8 +1146,6 @@ test "size of enum with only one tag which has explicit integer tag type" { |
| 1146 | } | 1146 | } |
| 1147 | 1147 | ||
| 1148 | test "switch on an extern enum with negative value" { | 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 | if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest; | 1149 | if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 1152 | 1150 | ||
| 1153 | const Foo = enum(c_int) { | 1151 | const Foo = enum(c_int) { |