| author | |
| committer | |
| log | 8fc3a707a44368f3f5c0ded0cc1b7080bf056761 |
| tree | 78d6cb00f5a872dd537b44cc35debb6d7f51544d |
| parent | f950d763a160d7ee333dde75ff61c9ac6597c803 |
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 { |
| 349 | 349 | fn gen(self: *Self) InnerError!void { |
| 350 | 350 | const cc = self.fn_type.fnCallingConvention(); |
| 351 | 351 | 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 | ||
| 352 | 359 | _ = try self.addInst(.{ |
| 353 | 360 | .tag = .push, |
| 354 | 361 | .ops = (Mir.Ops{ |
| ... | ... | @@ -423,6 +430,22 @@ fn gen(self: *Self) InnerError!void { |
| 423 | 430 | }).encode(), |
| 424 | 431 | .data = undefined, |
| 425 | 432 | }); |
| 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 | }); | |
| 426 | 449 | _ = try self.addInst(.{ |
| 427 | 450 | .tag = .ret, |
| 428 | 451 | .ops = (Mir.Ops{ |
src/arch/x86_64/Emit.zig+36| ... | ... | @@ -142,6 +142,9 @@ pub fn emitMir(emit: *Emit) InnerError!void { |
| 142 | 142 | .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst), |
| 143 | 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 | 148 | else => { |
| 146 | 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 | 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 | 284 | fn mirJmpCall(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { |
| 249 | 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 | 264 | |
| 265 | 265 | /// arg debug info |
| 266 | 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 | 282 | /// The position of an MIR instruction within the `Mir` instructions array. |
| 270 | 283 | pub const Index = u32; |
| 271 | 284 | |
| ... | ... | @@ -284,6 +297,8 @@ pub const Inst = struct { |
| 284 | 297 | got_entry: u32, |
| 285 | 298 | /// Index into `extra`. Meaning of what can be found there is context-dependent. |
| 286 | 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 | 304 | // Make sure we don't accidentally make instructions bigger than expected. |