authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-23 16:34:38+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-25 23:51:04+01:00
log05c5bb9edd51e73c0d4a2619817fbff73b82f230
tree2c27073cd2dbd58a0e0a4a55a877c2a81eda86ce
parentef7eff393912cae322fbc755536bc060c0166b94

stage2: populate debug info for args passed on stack

* implement cond_br when MCValue is a stack offset * implement passing compare flags and immediate on stack

2 files changed, 148 insertions(+), 103 deletions(-)

src/arch/x86_64/CodeGen.zig+124-100
...@@ -2506,6 +2506,70 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {...@@ -2506,6 +2506,70 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
2506 return self.finishAirBookkeeping();2506 return self.finishAirBookkeeping();
2507}2507}
25082508
2509fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
2510 const abi_size = ty.abiSize(self.target.*);
2511 switch (mcv) {
2512 .compare_flags_unsigned,
2513 .compare_flags_signed,
2514 => |cmp_op| {
2515 // Here we map the opposites since the jump is to the false branch.
2516 const flags: u2 = switch (cmp_op) {
2517 .gte => 0b10,
2518 .gt => 0b11,
2519 .neq => 0b01,
2520 .lt => 0b00,
2521 .lte => 0b01,
2522 .eq => 0b00,
2523 };
2524 const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq)
2525 .cond_jmp_eq_ne
2526 else if (mcv == .compare_flags_unsigned)
2527 Mir.Inst.Tag.cond_jmp_above_below
2528 else
2529 Mir.Inst.Tag.cond_jmp_greater_less;
2530 return self.addInst(.{
2531 .tag = tag,
2532 .ops = (Mir.Ops{
2533 .flags = flags,
2534 }).encode(),
2535 .data = .{ .inst = undefined },
2536 });
2537 },
2538 .register => |reg| {
2539 _ = try self.addInst(.{
2540 .tag = .@"test",
2541 .ops = (Mir.Ops{
2542 .reg1 = reg,
2543 .flags = 0b00,
2544 }).encode(),
2545 .data = .{ .imm = 1 },
2546 });
2547 return self.addInst(.{
2548 .tag = .cond_jmp_eq_ne,
2549 .ops = (Mir.Ops{
2550 .flags = 0b01,
2551 }).encode(),
2552 .data = .{ .inst = undefined },
2553 });
2554 },
2555 .immediate => {
2556 if (abi_size <= 8) {
2557 const reg = try self.copyToTmpRegister(ty, mcv);
2558 return self.genCondBrMir(ty, .{ .register = reg });
2559 }
2560 return self.fail("TODO implement condbr when condition is immediate larger than 4 bytes", .{});
2561 },
2562 .stack_offset => {
2563 if (abi_size <= 8) {
2564 const reg = try self.copyToTmpRegister(ty, mcv);
2565 return self.genCondBrMir(ty, .{ .register = reg });
2566 }
2567 return self.fail("TODO implement condbr when condition is stack offset with abi larger than 8 bytes", .{});
2568 },
2569 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}),
2570 }
2571}
2572
2509fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {2573fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2510 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2574 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2511 const cond = try self.resolveInst(pl_op.operand);2575 const cond = try self.resolveInst(pl_op.operand);
...@@ -2515,97 +2579,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2515,97 +2579,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2515 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];2579 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
2516 const liveness_condbr = self.liveness.getCondBr(inst);2580 const liveness_condbr = self.liveness.getCondBr(inst);
25172581
2518 const reloc: Mir.Inst.Index = reloc: {2582 const reloc = try self.genCondBrMir(cond_ty, cond);
2519 switch (cond) {
2520 .compare_flags_signed => |cmp_op| {
2521 // Here we map the opposites since the jump is to the false branch.
2522 const flags: u2 = switch (cmp_op) {
2523 .gte => 0b10,
2524 .gt => 0b11,
2525 .neq => 0b01,
2526 .lt => 0b00,
2527 .lte => 0b01,
2528 .eq => 0b00,
2529 };
2530 const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq)
2531 .cond_jmp_eq_ne
2532 else
2533 .cond_jmp_greater_less;
2534 const reloc = try self.addInst(.{
2535 .tag = tag,
2536 .ops = (Mir.Ops{
2537 .flags = flags,
2538 }).encode(),
2539 .data = .{ .inst = undefined },
2540 });
2541 break :reloc reloc;
2542 },
2543 .compare_flags_unsigned => |cmp_op| {
2544 // Here we map the opposites since the jump is to the false branch.
2545 const flags: u2 = switch (cmp_op) {
2546 .gte => 0b10,
2547 .gt => 0b11,
2548 .neq => 0b01,
2549 .lt => 0b00,
2550 .lte => 0b01,
2551 .eq => 0b00,
2552 };
2553 const tag: Mir.Inst.Tag = if (cmp_op == .neq or cmp_op == .eq)
2554 .cond_jmp_eq_ne
2555 else
2556 .cond_jmp_above_below;
2557 const reloc = try self.addInst(.{
2558 .tag = tag,
2559 .ops = (Mir.Ops{
2560 .flags = flags,
2561 }).encode(),
2562 .data = .{ .inst = undefined },
2563 });
2564 break :reloc reloc;
2565 },
2566 .register => |reg| {
2567 _ = try self.addInst(.{
2568 .tag = .@"test",
2569 .ops = (Mir.Ops{
2570 .reg1 = reg,
2571 .flags = 0b00,
2572 }).encode(),
2573 .data = .{ .imm = 1 },
2574 });
2575 const reloc = try self.addInst(.{
2576 .tag = .cond_jmp_eq_ne,
2577 .ops = (Mir.Ops{
2578 .flags = 0b01,
2579 }).encode(),
2580 .data = .{ .inst = undefined },
2581 });
2582 break :reloc reloc;
2583 },
2584 .immediate => |imm| {
2585 if (cond_ty.abiSize(self.target.*) <= 4) {
2586 const reg = try self.copyToTmpRegister(cond_ty, .{ .immediate = imm });
2587 _ = try self.addInst(.{
2588 .tag = .@"test",
2589 .ops = (Mir.Ops{
2590 .reg1 = reg,
2591 .flags = 0b00,
2592 }).encode(),
2593 .data = .{ .imm = 1 },
2594 });
2595 const reloc = try self.addInst(.{
2596 .tag = .cond_jmp_eq_ne,
2597 .ops = (Mir.Ops{
2598 .flags = 0b01,
2599 }).encode(),
2600 .data = .{ .inst = undefined },
2601 });
2602 break :reloc reloc;
2603 }
2604 return self.fail("TODO implement condbr when condition is immediate larger than 4 bytes", .{});
2605 },
2606 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(cond)}),
2607 }
2608 };
26092583
2610 // Capture the state of register and stack allocation state so that we can revert to it.2584 // Capture the state of register and stack allocation state so that we can revert to it.
2611 const parent_next_stack_offset = self.next_stack_offset;2585 const parent_next_stack_offset = self.next_stack_offset;
...@@ -3158,6 +3132,53 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3158,6 +3132,53 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3158 .dead => unreachable,3132 .dead => unreachable,
3159 .ptr_embedded_in_code => unreachable,3133 .ptr_embedded_in_code => unreachable,
3160 .unreach, .none => return,3134 .unreach, .none => return,
3135 .compare_flags_unsigned,
3136 .compare_flags_signed,
3137 => {
3138 const reg = try self.copyToTmpRegister(ty, mcv);
3139 return self.genSetStackArg(ty, stack_offset, .{ .register = reg });
3140 },
3141 .immediate => |imm| {
3142 const off = stack_offset + @intCast(i32, abi_size);
3143 switch (abi_size) {
3144 1, 2, 4 => {
3145 // We have a positive stack offset value but we want a twos complement negative
3146 // offset from rbp, which is at the top of the stack frame.
3147 // mov [rbp+offset], immediate
3148 const payload = try self.addExtra(Mir.ImmPair{
3149 .dest_off = @bitCast(u32, -off),
3150 .operand = @truncate(u32, imm),
3151 });
3152 _ = try self.addInst(.{
3153 .tag = .mov_mem_imm,
3154 .ops = (Mir.Ops{
3155 .reg1 = .rsp,
3156 .flags = switch (abi_size) {
3157 1 => 0b00,
3158 2 => 0b01,
3159 4 => 0b10,
3160 else => unreachable,
3161 },
3162 }).encode(),
3163 .data = .{ .payload = payload },
3164 });
3165 },
3166 8 => {
3167 const reg = try self.copyToTmpRegister(ty, mcv);
3168 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3169 },
3170 else => return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}),
3171 }
3172 },
3173 .memory,
3174 .embedded_in_code,
3175 => {
3176 if (abi_size <= 8) {
3177 const reg = try self.copyToTmpRegister(ty, mcv);
3178 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3179 }
3180 return self.fail("TODO implement memcpy for setting args on stack from {}", .{mcv});
3181 },
3161 .register => |reg| {3182 .register => |reg| {
3162 _ = try self.addInst(.{3183 _ = try self.addInst(.{
3163 .tag = .mov,3184 .tag = .mov,
...@@ -3227,13 +3248,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3227,13 +3248,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3227 else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }),3248 else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }),
3228 }3249 }
3229 },3250 },
3230 .compare_flags_unsigned => |op| {3251 .compare_flags_unsigned,
3231 _ = op;3252 .compare_flags_signed,
3232 return self.fail("TODO implement set stack variable with compare flags value (unsigned)", .{});3253 => {
3233 },3254 const reg = try self.copyToTmpRegister(ty, mcv);
3234 .compare_flags_signed => |op| {3255 return self.genSetStack(ty, stack_offset, .{ .register = reg });
3235 _ = op;
3236 return self.fail("TODO implement set stack variable with compare flags value (signed)", .{});
3237 },3256 },
3238 .immediate => |x_big| {3257 .immediate => |x_big| {
3239 const abi_size = ty.abiSize(self.target.*);3258 const abi_size = ty.abiSize(self.target.*);
...@@ -3321,7 +3340,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3321,7 +3340,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3321 .data = .{ .imm = @bitCast(u32, -adj_off) },3340 .data = .{ .imm = @bitCast(u32, -adj_off) },
3322 });3341 });
3323 },3342 },
3324 .memory, .embedded_in_code => {3343 .memory,
3344 .embedded_in_code,
3345 => {
3325 if (ty.abiSize(self.target.*) <= 8) {3346 if (ty.abiSize(self.target.*) <= 8) {
3326 const reg = try self.copyToTmpRegister(ty, mcv);3347 const reg = try self.copyToTmpRegister(ty, mcv);
3327 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3348 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
...@@ -3605,7 +3626,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3605,7 +3626,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3605 .compare_flags_signed,3626 .compare_flags_signed,
3606 => |op| {3627 => |op| {
3607 const tag: Mir.Inst.Tag = switch (op) {3628 const tag: Mir.Inst.Tag = switch (op) {
3608 .gte, .gt, .lt, .lte => .cond_set_byte_above_below,3629 .gte, .gt, .lt, .lte => if (mcv == .compare_flags_unsigned)
3630 Mir.Inst.Tag.cond_set_byte_above_below
3631 else
3632 Mir.Inst.Tag.cond_set_byte_greater_less,
3609 .eq, .neq => .cond_set_byte_eq_ne,3633 .eq, .neq => .cond_set_byte_eq_ne,
3610 };3634 };
3611 const flags: u2 = switch (op) {3635 const flags: u2 = switch (op) {
src/arch/x86_64/Emit.zig+24-3
...@@ -841,15 +841,16 @@ fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -841,15 +841,16 @@ fn mirArgDbgInfo(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
841 const payload = emit.mir.instructions.items(.data)[inst].payload;841 const payload = emit.mir.instructions.items(.data)[inst].payload;
842 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;842 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;
843 const mcv = emit.mir.function.args[arg_dbg_info.arg_index];843 const mcv = emit.mir.function.args[arg_dbg_info.arg_index];
844 try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv);844 try emit.genArgDbgInfo(arg_dbg_info.air_inst, mcv, arg_dbg_info.arg_index);
845}845}
846846
847fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {847fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
848 const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;848 const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;
849 const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;849 const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;
850 const name = zir.nullTerminatedString(ty_str.str);850 const name = zir.nullTerminatedString(ty_str.str);
851 const name_with_null = name.ptr[0 .. name.len + 1];851 const name_with_null = name.ptr[0 .. name.len + 1];
852 const ty = emit.mir.function.air.getRefType(ty_str.ty);852 const ty = emit.mir.function.air.getRefType(ty_str.ty);
853 const abi_size = ty.abiSize(emit.bin_file.options.target);
853854
854 switch (mcv) {855 switch (mcv) {
855 .register => |reg| {856 .register => |reg| {
...@@ -871,7 +872,27 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {...@@ -871,7 +872,27 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {
871 },872 },
872 .stack_offset => {873 .stack_offset => {
873 switch (emit.debug_output) {874 switch (emit.debug_output) {
874 .dwarf => {},875 .dwarf => |dbg_out| {
876 // we add here +16 like we do in airArg in CodeGen since we refer directly to
877 // rbp as the start of function frame minus 8 bytes for caller's rbp preserved in the
878 // prologue, and 8 bytes for return address.
879 // TODO we need to make this more generic if we don't use rbp as the frame pointer
880 // for example when -fomit-frame-pointer is set.
881 const disp = @intCast(i32, arg_index * abi_size + 16);
882 try dbg_out.dbg_info.ensureUnusedCapacity(8);
883 dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter);
884 const fixup = dbg_out.dbg_info.items.len;
885 dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
886 1, // we will backpatch it after we encode the displacement in LEB128
887 DW.OP.breg6, // .rbp TODO handle -fomit-frame-pointer
888 });
889 leb128.writeILEB128(dbg_out.dbg_info.writer(), disp) catch unreachable;
890 dbg_out.dbg_info.items[fixup] += @intCast(u8, dbg_out.dbg_info.items.len - fixup - 2);
891 try dbg_out.dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
892 try emit.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
893 dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
894
895 },
875 .plan9 => {},896 .plan9 => {},
876 .none => {},897 .none => {},
877 }898 }