| author | |
| committer | |
| log | 18a909f61d87d6b8e89147b7b46d8d0785b24b4d |
| tree | 7a998dd9f553f346636fb1103fd38627bdeab328 |
| parent | 6cf8a49bb0e5a6df3154aa7c41602ef21057ce50 |
| parent | bc59a630ab7814ac0ca5487c780a03d7492648f7 |
7 files changed, 167 insertions(+), 29 deletions(-)
src/arch/x86/bits.zig+8-6| ... | @@ -32,11 +32,9 @@ pub const Register = enum(u8) { | ... | @@ -32,11 +32,9 @@ pub const Register = enum(u8) { |
| 32 | /// Returns the index into `callee_preserved_regs`. | 32 | /// Returns the index into `callee_preserved_regs`. |
| 33 | pub fn allocIndex(self: Register) ?u4 { | 33 | pub fn allocIndex(self: Register) ?u4 { |
| 34 | return switch (self) { | 34 | return switch (self) { |
| 35 | .eax, .ax, .al => 0, | 35 | .ebx, .bx, .bl => 0, |
| 36 | .ecx, .cx, .cl => 1, | 36 | .esi, .si => 1, |
| 37 | .edx, .dx, .dl => 2, | 37 | .edi, .di => 2, |
| 38 | .esi, .si => 3, | ||
| 39 | .edi, .di => 4, | ||
| 40 | else => null, | 38 | else => null, |
| 41 | }; | 39 | }; |
| 42 | } | 40 | } |
| ... | @@ -74,7 +72,11 @@ pub const Register = enum(u8) { | ... | @@ -74,7 +72,11 @@ pub const Register = enum(u8) { |
| 74 | 72 | ||
| 75 | // zig fmt: on | 73 | // zig fmt: on |
| 76 | 74 | ||
| 77 | pub const callee_preserved_regs = [_]Register{ .eax, .ecx, .edx, .esi, .edi }; | 75 | /// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered |
| 76 | /// and when the callee returns. | ||
| 77 | /// Note that .esp and .ebp also belong to this set, however, we never expect to use them | ||
| 78 | /// for anything else but stack offset tracking therefore we exclude them from this set. | ||
| 79 | pub const callee_preserved_regs = [_]Register{ .ebx, .esi, .edi }; | ||
| 78 | 80 | ||
| 79 | // TODO add these to Register enum and corresponding dwarfLocOp | 81 | // TODO add these to Register enum and corresponding dwarfLocOp |
| 80 | // // Return Address register. This is stored in `0(%esp, "")` and is not a physical register. | 82 | // // Return Address register. This is stored in `0(%esp, "")` and is not a physical register. |
src/arch/x86_64/CodeGen.zig+59-9| ... | @@ -159,6 +159,13 @@ pub const MCValue = union(enum) { | ... | @@ -159,6 +159,13 @@ pub const MCValue = union(enum) { |
| 159 | => true, | 159 | => true, |
| 160 | }; | 160 | }; |
| 161 | } | 161 | } |
| 162 | |||
| 163 | fn isRegister(mcv: MCValue) bool { | ||
| 164 | return switch (mcv) { | ||
| 165 | .register => true, | ||
| 166 | else => false, | ||
| 167 | }; | ||
| 168 | } | ||
| 162 | }; | 169 | }; |
| 163 | 170 | ||
| 164 | const Branch = struct { | 171 | const Branch = struct { |
| ... | @@ -349,6 +356,13 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -349,6 +356,13 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 349 | fn gen(self: *Self) InnerError!void { | 356 | fn gen(self: *Self) InnerError!void { |
| 350 | const cc = self.fn_type.fnCallingConvention(); | 357 | const cc = self.fn_type.fnCallingConvention(); |
| 351 | if (cc != .Naked) { | 358 | if (cc != .Naked) { |
| 359 | // push the callee_preserved_regs that were used | ||
| 360 | const backpatch_push_callee_preserved_regs_i = try self.addInst(.{ | ||
| 361 | .tag = .push_regs_from_callee_preserved_regs, | ||
| 362 | .ops = undefined, | ||
| 363 | .data = .{ .regs_to_push_or_pop = undefined }, // to be backpatched | ||
| 364 | }); | ||
| 365 | |||
| 352 | _ = try self.addInst(.{ | 366 | _ = try self.addInst(.{ |
| 353 | .tag = .push, | 367 | .tag = .push, |
| 354 | .ops = (Mir.Ops{ | 368 | .ops = (Mir.Ops{ |
| ... | @@ -423,6 +437,22 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -423,6 +437,22 @@ fn gen(self: *Self) InnerError!void { |
| 423 | }).encode(), | 437 | }).encode(), |
| 424 | .data = undefined, | 438 | .data = undefined, |
| 425 | }); | 439 | }); |
| 440 | // calculate the data for callee_preserved_regs to be pushed and popped | ||
| 441 | var callee_preserved_regs_push_data: u32 = 0x0; | ||
| 442 | inline for (callee_preserved_regs) |reg, i| { | ||
| 443 | if (self.register_manager.isRegAllocated(reg)) { | ||
| 444 | callee_preserved_regs_push_data |= 1 << @intCast(u5, i); | ||
| 445 | } | ||
| 446 | } | ||
| 447 | const data = self.mir_instructions.items(.data); | ||
| 448 | // backpatch the push instruction | ||
| 449 | data[backpatch_push_callee_preserved_regs_i].regs_to_push_or_pop = callee_preserved_regs_push_data; | ||
| 450 | // pop the callee_preserved_regs | ||
| 451 | _ = try self.addInst(.{ | ||
| 452 | .tag = .pop_regs_from_callee_preserved_regs, | ||
| 453 | .ops = undefined, | ||
| 454 | .data = .{ .regs_to_push_or_pop = callee_preserved_regs_push_data }, | ||
| 455 | }); | ||
| 426 | _ = try self.addInst(.{ | 456 | _ = try self.addInst(.{ |
| 427 | .tag = .ret, | 457 | .tag = .ret, |
| 428 | .ops = (Mir.Ops{ | 458 | .ops = (Mir.Ops{ |
| ... | @@ -737,6 +767,19 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa | ... | @@ -737,6 +767,19 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa |
| 737 | return MCValue{ .register = reg }; | 767 | return MCValue{ .register = reg }; |
| 738 | } | 768 | } |
| 739 | 769 | ||
| 770 | /// Like `copyToNewRegister` but allows to specify a list of excluded registers which | ||
| 771 | /// will not be selected for allocation. This can be done via `exceptions` slice. | ||
| 772 | fn copyToNewRegisterWithExceptions( | ||
| 773 | self: *Self, | ||
| 774 | reg_owner: Air.Inst.Index, | ||
| 775 | mcv: MCValue, | ||
| 776 | exceptions: []const Register, | ||
| 777 | ) !MCValue { | ||
| 778 | const reg = try self.register_manager.allocReg(reg_owner, exceptions); | ||
| 779 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); | ||
| 780 | return MCValue{ .register = reg }; | ||
| 781 | } | ||
| 782 | |||
| 740 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { | 783 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 741 | const stack_offset = try self.allocMemPtr(inst); | 784 | const stack_offset = try self.allocMemPtr(inst); |
| 742 | return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); | 785 | return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none }); |
| ... | @@ -1427,11 +1470,9 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -1427,11 +1470,9 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 1427 | // as the result MCValue. | 1470 | // as the result MCValue. |
| 1428 | var dst_mcv: MCValue = undefined; | 1471 | var dst_mcv: MCValue = undefined; |
| 1429 | var src_mcv: MCValue = undefined; | 1472 | var src_mcv: MCValue = undefined; |
| 1430 | var src_inst: Air.Inst.Ref = undefined; | ||
| 1431 | if (self.reuseOperand(inst, op_lhs, 0, lhs)) { | 1473 | if (self.reuseOperand(inst, op_lhs, 0, lhs)) { |
| 1432 | // LHS dies; use it as the destination. | 1474 | // LHS dies; use it as the destination. |
| 1433 | // Both operands cannot be memory. | 1475 | // Both operands cannot be memory. |
| 1434 | src_inst = op_rhs; | ||
| 1435 | if (lhs.isMemory() and rhs.isMemory()) { | 1476 | if (lhs.isMemory() and rhs.isMemory()) { |
| 1436 | dst_mcv = try self.copyToNewRegister(inst, lhs); | 1477 | dst_mcv = try self.copyToNewRegister(inst, lhs); |
| 1437 | src_mcv = rhs; | 1478 | src_mcv = rhs; |
| ... | @@ -1442,7 +1483,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -1442,7 +1483,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 1442 | } else if (self.reuseOperand(inst, op_rhs, 1, rhs)) { | 1483 | } else if (self.reuseOperand(inst, op_rhs, 1, rhs)) { |
| 1443 | // RHS dies; use it as the destination. | 1484 | // RHS dies; use it as the destination. |
| 1444 | // Both operands cannot be memory. | 1485 | // Both operands cannot be memory. |
| 1445 | src_inst = op_lhs; | ||
| 1446 | if (lhs.isMemory() and rhs.isMemory()) { | 1486 | if (lhs.isMemory() and rhs.isMemory()) { |
| 1447 | dst_mcv = try self.copyToNewRegister(inst, rhs); | 1487 | dst_mcv = try self.copyToNewRegister(inst, rhs); |
| 1448 | src_mcv = lhs; | 1488 | src_mcv = lhs; |
| ... | @@ -1452,13 +1492,23 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -1452,13 +1492,23 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 1452 | } | 1492 | } |
| 1453 | } else { | 1493 | } else { |
| 1454 | if (lhs.isMemory()) { | 1494 | if (lhs.isMemory()) { |
| 1455 | dst_mcv = try self.copyToNewRegister(inst, lhs); | 1495 | dst_mcv = if (rhs.isRegister()) |
| 1496 | // If the allocated register is the same as the rhs register, don't allocate that one | ||
| 1497 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation | ||
| 1498 | // in the presence of several binary operations performed in a single block. | ||
| 1499 | try self.copyToNewRegisterWithExceptions(inst, lhs, &.{rhs.register}) | ||
| 1500 | else | ||
| 1501 | try self.copyToNewRegister(inst, lhs); | ||
| 1456 | src_mcv = rhs; | 1502 | src_mcv = rhs; |
| 1457 | src_inst = op_rhs; | ||
| 1458 | } else { | 1503 | } else { |
| 1459 | dst_mcv = try self.copyToNewRegister(inst, rhs); | 1504 | dst_mcv = if (lhs.isRegister()) |
| 1505 | // If the allocated register is the same as the rhs register, don't allocate that one | ||
| 1506 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation | ||
| 1507 | // in the presence of several binary operations performed in a single block. | ||
| 1508 | try self.copyToNewRegisterWithExceptions(inst, rhs, &.{lhs.register}) | ||
| 1509 | else | ||
| 1510 | try self.copyToNewRegister(inst, rhs); | ||
| 1460 | src_mcv = lhs; | 1511 | src_mcv = lhs; |
| 1461 | src_inst = op_lhs; | ||
| 1462 | } | 1512 | } |
| 1463 | } | 1513 | } |
| 1464 | // This instruction supports only signed 32-bit immediates at most. If the immediate | 1514 | // This instruction supports only signed 32-bit immediates at most. If the immediate |
| ... | @@ -1902,10 +1952,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1902,10 +1952,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1902 | try self.register_manager.getReg(reg, null); | 1952 | try self.register_manager.getReg(reg, null); |
| 1903 | try self.genSetReg(arg_ty, reg, arg_mcv); | 1953 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 1904 | }, | 1954 | }, |
| 1905 | .stack_offset => { | 1955 | .stack_offset => |off| { |
| 1906 | // Here we need to emit instructions like this: | 1956 | // Here we need to emit instructions like this: |
| 1907 | // mov qword ptr [rsp + stack_offset], x | 1957 | // mov qword ptr [rsp + stack_offset], x |
| 1908 | return self.fail("TODO implement calling with parameters in memory", .{}); | 1958 | try self.genSetStack(arg_ty, off, arg_mcv); |
| 1909 | }, | 1959 | }, |
| 1910 | .ptr_stack_offset => { | 1960 | .ptr_stack_offset => { |
| 1911 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 1961 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
src/arch/x86_64/Emit.zig+36| ... | @@ -142,6 +142,9 @@ pub fn emitMir(emit: *Emit) InnerError!void { | ... | @@ -142,6 +142,9 @@ pub fn emitMir(emit: *Emit) InnerError!void { |
| 142 | .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst), | 142 | .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst), |
| 143 | .arg_dbg_info => try emit.mirArgDbgInfo(inst), | 143 | .arg_dbg_info => try emit.mirArgDbgInfo(inst), |
| 144 | 144 | ||
| 145 | .push_regs_from_callee_preserved_regs => try emit.mirPushPopRegsFromCalleePreservedRegs(.push, inst), | ||
| 146 | .pop_regs_from_callee_preserved_regs => try emit.mirPushPopRegsFromCalleePreservedRegs(.pop, inst), | ||
| 147 | |||
| 145 | else => { | 148 | else => { |
| 146 | return emit.fail("Implement MIR->Isel lowering for x86_64 for pseudo-inst: {s}", .{tag}); | 149 | return emit.fail("Implement MIR->Isel lowering for x86_64 for pseudo-inst: {s}", .{tag}); |
| 147 | }, | 150 | }, |
| ... | @@ -244,6 +247,39 @@ fn mirPushPop(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!v | ... | @@ -244,6 +247,39 @@ fn mirPushPop(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!v |
| 244 | 0b11 => unreachable, | 247 | 0b11 => unreachable, |
| 245 | } | 248 | } |
| 246 | } | 249 | } |
| 250 | fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { | ||
| 251 | const callee_preserved_regs = bits.callee_preserved_regs; | ||
| 252 | // PUSH/POP reg | ||
| 253 | const opc: u8 = switch (tag) { | ||
| 254 | .push => 0x50, | ||
| 255 | .pop => 0x58, | ||
| 256 | else => unreachable, | ||
| 257 | }; | ||
| 258 | |||
| 259 | const regs = emit.mir.instructions.items(.data)[inst].regs_to_push_or_pop; | ||
| 260 | if (tag == .push) { | ||
| 261 | for (callee_preserved_regs) |reg, i| { | ||
| 262 | if ((regs >> @intCast(u5, i)) & 1 == 0) continue; | ||
| 263 | const encoder = try Encoder.init(emit.code, 2); | ||
| 264 | encoder.rex(.{ | ||
| 265 | .b = reg.isExtended(), | ||
| 266 | }); | ||
| 267 | encoder.opcode_withReg(opc, reg.lowId()); | ||
| 268 | } | ||
| 269 | } else { | ||
| 270 | // pop in the reverse direction | ||
| 271 | var i = callee_preserved_regs.len; | ||
| 272 | while (i > 0) : (i -= 1) { | ||
| 273 | const reg = callee_preserved_regs[i - 1]; | ||
| 274 | if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue; | ||
| 275 | const encoder = try Encoder.init(emit.code, 2); | ||
| 276 | encoder.rex(.{ | ||
| 277 | .b = reg.isExtended(), | ||
| 278 | }); | ||
| 279 | encoder.opcode_withReg(opc, reg.lowId()); | ||
| 280 | } | ||
| 281 | } | ||
| 282 | } | ||
| 247 | 283 | ||
| 248 | fn mirJmpCall(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { | 284 | fn mirJmpCall(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { |
| 249 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 285 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
src/arch/x86_64/Mir.zig+16-1| ... | @@ -264,8 +264,21 @@ pub const Inst = struct { | ... | @@ -264,8 +264,21 @@ pub const Inst = struct { |
| 264 | 264 | ||
| 265 | /// arg debug info | 265 | /// arg debug info |
| 266 | arg_dbg_info, | 266 | arg_dbg_info, |
| 267 | }; | ||
| 268 | 267 | ||
| 268 | /// push registers from the callee_preserved_regs | ||
| 269 | /// data is the bitfield of which regs to push | ||
| 270 | /// for example on x86_64, the callee_preserved_regs are [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; }; | ||
| 271 | /// so to push rcx and r8 one would make data 0b00000000_00000000_00000000_00001001 (the first and fourth bits are set) | ||
| 272 | /// ops is unused | ||
| 273 | push_regs_from_callee_preserved_regs, | ||
| 274 | |||
| 275 | /// pop registers from the callee_preserved_regs | ||
| 276 | /// data is the bitfield of which regs to pop | ||
| 277 | /// for example on x86_64, the callee_preserved_regs are [_]Register{ .rcx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; }; | ||
| 278 | /// so to pop rcx and r8 one would make data 0b00000000_00000000_00000000_00001001 (the first and fourth bits are set) | ||
| 279 | /// ops is unused | ||
| 280 | pop_regs_from_callee_preserved_regs, | ||
| 281 | }; | ||
| 269 | /// The position of an MIR instruction within the `Mir` instructions array. | 282 | /// The position of an MIR instruction within the `Mir` instructions array. |
| 270 | pub const Index = u32; | 283 | pub const Index = u32; |
| 271 | 284 | ||
| ... | @@ -284,6 +297,8 @@ pub const Inst = struct { | ... | @@ -284,6 +297,8 @@ pub const Inst = struct { |
| 284 | got_entry: u32, | 297 | got_entry: u32, |
| 285 | /// Index into `extra`. Meaning of what can be found there is context-dependent. | 298 | /// Index into `extra`. Meaning of what can be found there is context-dependent. |
| 286 | payload: u32, | 299 | payload: u32, |
| 300 | /// A bitfield of which callee_preserved_regs to push | ||
| 301 | regs_to_push_or_pop: u32, | ||
| 287 | }; | 302 | }; |
| 288 | 303 | ||
| 289 | // Make sure we don't accidentally make instructions bigger than expected. | 304 | // Make sure we don't accidentally make instructions bigger than expected. |
src/arch/x86_64/bits.zig+14-11| ... | @@ -84,15 +84,11 @@ pub const Register = enum(u7) { | ... | @@ -84,15 +84,11 @@ pub const Register = enum(u7) { |
| 84 | /// Returns the index into `callee_preserved_regs`. | 84 | /// Returns the index into `callee_preserved_regs`. |
| 85 | pub fn allocIndex(self: Register) ?u4 { | 85 | pub fn allocIndex(self: Register) ?u4 { |
| 86 | return switch (self) { | 86 | return switch (self) { |
| 87 | .rax, .eax, .ax, .al => 0, | 87 | .rbx, .ebx, .bx, .bl => 0, |
| 88 | .rcx, .ecx, .cx, .cl => 1, | 88 | .r12, .r12d, .r12w, .r12b => 1, |
| 89 | .rdx, .edx, .dx, .dl => 2, | 89 | .r13, .r13d, .r13w, .r13b => 2, |
| 90 | .rsi, .esi, .si => 3, | 90 | .r14, .r14d, .r14w, .r14b => 3, |
| 91 | .rdi, .edi, .di => 4, | 91 | .r15, .r15d, .r15w, .r15b => 4, |
| 92 | .r8, .r8d, .r8w, .r8b => 5, | ||
| 93 | .r9, .r9d, .r9w, .r9b => 6, | ||
| 94 | .r10, .r10d, .r10w, .r10b => 7, | ||
| 95 | .r11, .r11d, .r11w, .r11b => 8, | ||
| 96 | else => null, | 92 | else => null, |
| 97 | }; | 93 | }; |
| 98 | } | 94 | } |
| ... | @@ -144,8 +140,15 @@ pub const Register = enum(u7) { | ... | @@ -144,8 +140,15 @@ pub const Register = enum(u7) { |
| 144 | 140 | ||
| 145 | // zig fmt: on | 141 | // zig fmt: on |
| 146 | 142 | ||
| 147 | /// These registers belong to the called function. | 143 | /// These registers need to be preserved (saved on the stack) and restored by the callee before getting clobbered |
| 148 | pub const callee_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; | 144 | /// and when the callee returns. |
| 145 | /// Note that .rsp and .rbp also belong to this set, however, we never expect to use them | ||
| 146 | /// for anything else but stack offset tracking therefore we exclude them from this set. | ||
| 147 | pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 }; | ||
| 148 | /// These registers need to be preserved (saved on the stack) and restored by the caller before | ||
| 149 | /// the caller relinquishes control to a subroutine via call instruction (or similar). | ||
| 150 | /// In other words, these registers are free to use by the callee. | ||
| 151 | pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; | ||
| 149 | pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; | 152 | pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; |
| 150 | pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx }; | 153 | pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx }; |
| 151 | 154 |
src/link/Elf.zig+2-2| ... | @@ -2604,12 +2604,12 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo | ... | @@ -2604,12 +2604,12 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo |
| 2604 | // DW.AT.name, DW.FORM.string | 2604 | // DW.AT.name, DW.FORM.string |
| 2605 | try dbg_info_buffer.writer().print("{}\x00", .{ty}); | 2605 | try dbg_info_buffer.writer().print("{}\x00", .{ty}); |
| 2606 | } else { | 2606 | } else { |
| 2607 | log.err("TODO implement .debug_info for type '{}'", .{ty}); | 2607 | log.debug("TODO implement .debug_info for type '{}'", .{ty}); |
| 2608 | try dbg_info_buffer.append(abbrev_pad1); | 2608 | try dbg_info_buffer.append(abbrev_pad1); |
| 2609 | } | 2609 | } |
| 2610 | }, | 2610 | }, |
| 2611 | else => { | 2611 | else => { |
| 2612 | log.err("TODO implement .debug_info for type '{}'", .{ty}); | 2612 | log.debug("TODO implement .debug_info for type '{}'", .{ty}); |
| 2613 | try dbg_info_buffer.append(abbrev_pad1); | 2613 | try dbg_info_buffer.append(abbrev_pad1); |
| 2614 | }, | 2614 | }, |
| 2615 | } | 2615 | } |
test/cases.zig+32| ... | @@ -1819,4 +1819,36 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -1819,4 +1819,36 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1819 | ":2:28: error: cannot set address space of local variable 'foo'", | 1819 | ":2:28: error: cannot set address space of local variable 'foo'", |
| 1820 | }); | 1820 | }); |
| 1821 | } | 1821 | } |
| 1822 | { | ||
| 1823 | var case = ctx.exe("issue 10138: callee preserved regs working", linux_x64); | ||
| 1824 | case.addCompareOutput( | ||
| 1825 | \\pub fn main() void { | ||
| 1826 | \\ const fd = open(); | ||
| 1827 | \\ _ = write(fd, "a", 1); | ||
| 1828 | \\ _ = close(fd); | ||
| 1829 | \\} | ||
| 1830 | \\ | ||
| 1831 | \\fn open() usize { | ||
| 1832 | \\ return 42; | ||
| 1833 | \\} | ||
| 1834 | \\ | ||
| 1835 | \\fn write(fd: usize, a: [*]const u8, len: usize) usize { | ||
| 1836 | \\ return syscall4(.WRITE, fd, @ptrToInt(a), len); | ||
| 1837 | \\} | ||
| 1838 | \\ | ||
| 1839 | \\fn syscall4(n: enum { WRITE }, a: usize, b: usize, c: usize) usize { | ||
| 1840 | \\ _ = n; | ||
| 1841 | \\ _ = a; | ||
| 1842 | \\ _ = b; | ||
| 1843 | \\ _ = c; | ||
| 1844 | \\ return 23; | ||
| 1845 | \\} | ||
| 1846 | \\ | ||
| 1847 | \\fn close(fd: usize) usize { | ||
| 1848 | \\ if (fd != 42) | ||
| 1849 | \\ unreachable; | ||
| 1850 | \\ return 0; | ||
| 1851 | \\} | ||
| 1852 | , ""); | ||
| 1853 | } | ||
| 1822 | } | 1854 | } |