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 {
25062506 return self.finishAirBookkeeping();
25072507}
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
25092573fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
25102574 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
25112575 const cond = try self.resolveInst(pl_op.operand);
......@@ -2515,97 +2579,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
25152579 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
25162580 const liveness_condbr = self.liveness.getCondBr(inst);
25172581
2518 const reloc: Mir.Inst.Index = reloc: {
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 };
2582 const reloc = try self.genCondBrMir(cond_ty, cond);
26092583
26102584 // Capture the state of register and stack allocation state so that we can revert to it.
26112585 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
31583132 .dead => unreachable,
31593133 .ptr_embedded_in_code => unreachable,
31603134 .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 },
31613182 .register => |reg| {
31623183 _ = try self.addInst(.{
31633184 .tag = .mov,
......@@ -3227,13 +3248,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
32273248 else => return self.genInlineMemset(ty, stack_offset, .{ .immediate = 0xaa }),
32283249 }
32293250 },
3230 .compare_flags_unsigned => |op| {
3231 _ = op;
3232 return self.fail("TODO implement set stack variable with compare flags value (unsigned)", .{});
3233 },
3234 .compare_flags_signed => |op| {
3235 _ = op;
3236 return self.fail("TODO implement set stack variable with compare flags value (signed)", .{});
3251 .compare_flags_unsigned,
3252 .compare_flags_signed,
3253 => {
3254 const reg = try self.copyToTmpRegister(ty, mcv);
3255 return self.genSetStack(ty, stack_offset, .{ .register = reg });
32373256 },
32383257 .immediate => |x_big| {
32393258 const abi_size = ty.abiSize(self.target.*);
......@@ -3321,7 +3340,9 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
33213340 .data = .{ .imm = @bitCast(u32, -adj_off) },
33223341 });
33233342 },
3324 .memory, .embedded_in_code => {
3343 .memory,
3344 .embedded_in_code,
3345 => {
33253346 if (ty.abiSize(self.target.*) <= 8) {
33263347 const reg = try self.copyToTmpRegister(ty, mcv);
33273348 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
36053626 .compare_flags_signed,
36063627 => |op| {
36073628 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,
36093633 .eq, .neq => .cond_set_byte_eq_ne,
36103634 };
36113635 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 {
841841 const payload = emit.mir.instructions.items(.data)[inst].payload;
842842 const arg_dbg_info = emit.mir.extraData(Mir.ArgDbgInfo, payload).data;
843843 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);
845845}
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 {
848848 const ty_str = emit.mir.function.air.instructions.items(.data)[inst].ty_str;
849849 const zir = &emit.mir.function.mod_fn.owner_decl.getFileScope().zir;
850850 const name = zir.nullTerminatedString(ty_str.str);
851851 const name_with_null = name.ptr[0 .. name.len + 1];
852852 const ty = emit.mir.function.air.getRefType(ty_str.ty);
853 const abi_size = ty.abiSize(emit.bin_file.options.target);
853854
854855 switch (mcv) {
855856 .register => |reg| {
......@@ -871,7 +872,27 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {
871872 },
872873 .stack_offset => {
873874 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 },
875896 .plan9 => {},
876897 .none => {},
877898 }