authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-11-12 20:00:59-05:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-19 09:38:36+01:00
log8fc3a707a44368f3f5c0ded0cc1b7080bf056761
tree78d6cb00f5a872dd537b44cc35debb6d7f51544d
parentf950d763a160d7ee333dde75ff61c9ac6597c803

x86_64/Emit: implement restoring callee_preserved_registers


3 files changed, 75 insertions(+), 1 deletions(-)

src/arch/x86_64/CodeGen.zig+23
......@@ -349,6 +349,13 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
349349fn gen(self: *Self) InnerError!void {
350350 const cc = self.fn_type.fnCallingConvention();
351351 if (cc != .Naked) {
352 // push the callee_preserved_regs that were used
353 const backpatch_push_callee_preserved_regs_i = try self.addInst(.{
354 .tag = .push_regs_from_callee_preserved_regs,
355 .ops = undefined,
356 .data = .{ .regs_to_push_or_pop = undefined }, // to be backpatched
357 });
358
352359 _ = try self.addInst(.{
353360 .tag = .push,
354361 .ops = (Mir.Ops{
......@@ -423,6 +430,22 @@ fn gen(self: *Self) InnerError!void {
423430 }).encode(),
424431 .data = undefined,
425432 });
433 // calculate the data for callee_preserved_regs to be pushed and popped
434 var callee_preserved_regs_push_data: u32 = 0x0;
435 inline for (callee_preserved_regs) |reg, i| {
436 if (self.register_manager.isRegAllocated(reg)) {
437 callee_preserved_regs_push_data |= 1 << @intCast(u5, i);
438 }
439 }
440 const data = self.mir_instructions.items(.data);
441 // backpatch the push instruction
442 data[backpatch_push_callee_preserved_regs_i].regs_to_push_or_pop = callee_preserved_regs_push_data;
443 // pop the callee_preserved_regs
444 _ = try self.addInst(.{
445 .tag = .pop_regs_from_callee_preserved_regs,
446 .ops = undefined,
447 .data = .{ .regs_to_push_or_pop = callee_preserved_regs_push_data },
448 });
426449 _ = try self.addInst(.{
427450 .tag = .ret,
428451 .ops = (Mir.Ops{
src/arch/x86_64/Emit.zig+36
......@@ -142,6 +142,9 @@ pub fn emitMir(emit: *Emit) InnerError!void {
142142 .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),
143143 .arg_dbg_info => try emit.mirArgDbgInfo(inst),
144144
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
145148 else => {
146149 return emit.fail("Implement MIR->Isel lowering for x86_64 for pseudo-inst: {s}", .{tag});
147150 },
......@@ -244,6 +247,39 @@ fn mirPushPop(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!v
244247 0b11 => unreachable,
245248 }
246249}
250fn 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}
247283
248284fn mirJmpCall(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
249285 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 {
264264
265265 /// arg debug info
266266 arg_dbg_info,
267 };
268267
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 };
269282 /// The position of an MIR instruction within the `Mir` instructions array.
270283 pub const Index = u32;
271284
......@@ -284,6 +297,8 @@ pub const Inst = struct {
284297 got_entry: u32,
285298 /// Index into `extra`. Meaning of what can be found there is context-dependent.
286299 payload: u32,
300 /// A bitfield of which callee_preserved_regs to push
301 regs_to_push_or_pop: u32,
287302 };
288303
289304 // Make sure we don't accidentally make instructions bigger than expected.