authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-01 12:24:55+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-07 22:42:56+02:00
loga19e6adbf90771890ecdbb52d6dafab1943e4cc4
tree1361fa3ca3a41172b80dfd26fc7ee00700a0f4e5
parentaac4c1d3b225ff4cd7138d9aae599c9540c7f04e

x86_64: add support for Win64/C calling convention


4 files changed, 103 insertions(+), 63 deletions(-)

src/arch/x86_64/CodeGen.zig+8-12
......@@ -32,11 +32,6 @@ const abi = @import("abi.zig");
3232const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
3333const errUnionErrorOffset = codegen.errUnionErrorOffset;
3434
35const callee_preserved_regs = abi.callee_preserved_regs;
36const caller_preserved_regs = abi.caller_preserved_regs;
37const c_abi_int_param_regs = abi.c_abi_int_param_regs;
38const c_abi_int_return_regs = abi.c_abi_int_return_regs;
39
4035const Condition = bits.Condition;
4136const RegisterManager = abi.RegisterManager;
4237const RegisterLock = RegisterManager.RegisterLock;
......@@ -448,10 +443,11 @@ fn gen(self: *Self) InnerError!void {
448443
449444 // Create list of registers to save in the prologue.
450445 // TODO handle register classes
451 var reg_list: Mir.RegisterList(Register, &callee_preserved_regs) = .{};
452 inline for (callee_preserved_regs) |reg| {
446 var reg_list = Mir.RegisterList{};
447 const callee_preserved_regs = abi.getCalleePreservedRegs(self.target.*);
448 for (callee_preserved_regs) |reg| {
453449 if (self.register_manager.isRegAllocated(reg)) {
454 reg_list.push(reg);
450 reg_list.push(callee_preserved_regs, reg);
455451 }
456452 }
457453 const saved_regs_stack_space: u32 = reg_list.count() * 8;
......@@ -3923,7 +3919,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
39233919
39243920 try self.spillEflagsIfOccupied();
39253921
3926 for (caller_preserved_regs) |reg| {
3922 for (abi.getCallerPreservedRegs(self.target.*)) |reg| {
39273923 try self.register_manager.getReg(reg, null);
39283924 }
39293925
......@@ -7140,7 +7136,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
71407136 assert(ret_ty.isError());
71417137 result.return_value = .{ .immediate = 0 };
71427138 } else if (ret_ty_size <= 8) {
7143 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);
7139 const aliased_reg = registerAlias(abi.getCAbiIntReturnRegs(self.target.*)[0], ret_ty_size);
71447140 result.return_value = .{ .register = aliased_reg };
71457141 } else {
71467142 // We simply make the return MCValue a stack offset. However, the actual value
......@@ -7187,7 +7183,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
71877183 else => false,
71887184 };
71897185 if (pass_in_reg) {
7190 if (next_int_reg >= c_abi_int_param_regs.len) break;
7186 if (next_int_reg >= abi.getCAbiIntParamRegs(self.target.*).len) break;
71917187 try by_reg.putNoClobber(i, next_int_reg);
71927188 next_int_reg += 1;
71937189 }
......@@ -7210,7 +7206,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
72107206 const param_size = @intCast(u32, ty.abiSize(self.target.*));
72117207 const param_align = @intCast(u32, ty.abiAlignment(self.target.*));
72127208 if (by_reg.get(i)) |int_reg| {
7213 const aliased_reg = registerAlias(c_abi_int_param_regs[int_reg], param_size);
7209 const aliased_reg = registerAlias(abi.getCAbiIntParamRegs(self.target.*)[int_reg], param_size);
72147210 result.args[i] = .{ .register = aliased_reg };
72157211 next_int_reg += 1;
72167212 } else {
src/arch/x86_64/Emit.zig+4-3
......@@ -283,10 +283,11 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerErro
283283 const ops = emit.mir.instructions.items(.ops)[inst].decode();
284284 const payload = emit.mir.instructions.items(.data)[inst].payload;
285285 const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;
286 const reg_list = Mir.RegisterList(Register, &abi.callee_preserved_regs).fromInt(save_reg_list.register_list);
287286 var disp: i32 = -@intCast(i32, save_reg_list.stack_end);
288 inline for (abi.callee_preserved_regs) |reg| {
289 if (reg_list.isSet(reg)) {
287 const reg_list = Mir.RegisterList.fromInt(save_reg_list.register_list);
288 const callee_preserved_regs = abi.getCalleePreservedRegs(emit.target.*);
289 for (callee_preserved_regs) |reg| {
290 if (reg_list.isSet(callee_preserved_regs, reg)) {
290291 switch (tag) {
291292 .push => try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
292293 .disp = @bitCast(u32, disp),
src/arch/x86_64/Mir.zig+31-34
......@@ -461,46 +461,43 @@ pub const Inst = struct {
461461 }
462462};
463463
464pub fn RegisterList(comptime Reg: type, comptime registers: []const Reg) type {
465 assert(registers.len <= @bitSizeOf(u32));
466 return struct {
467 bitset: RegBitSet = RegBitSet.initEmpty(),
468
469 const RegBitSet = IntegerBitSet(registers.len);
470 const Self = @This();
471
472 fn getIndexForReg(reg: Reg) RegBitSet.MaskInt {
473 inline for (registers) |cpreg, i| {
474 if (reg.id() == cpreg.id()) return i;
475 }
476 unreachable; // register not in input register list!
477 }
464pub const RegisterList = struct {
465 bitset: BitSet = BitSet.initEmpty(),
478466
479 pub fn push(self: *Self, reg: Reg) void {
480 const index = getIndexForReg(reg);
481 self.bitset.set(index);
482 }
467 const BitSet = IntegerBitSet(@ctz(@as(u32, 0)));
468 const Self = @This();
483469
484 pub fn isSet(self: Self, reg: Reg) bool {
485 const index = getIndexForReg(reg);
486 return self.bitset.isSet(index);
470 fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt {
471 for (registers) |cpreg, i| {
472 if (reg.id() == cpreg.id()) return @intCast(u32, i);
487473 }
474 unreachable; // register not in input register list!
475 }
488476
489 pub fn asInt(self: Self) u32 {
490 return self.bitset.mask;
491 }
477 pub fn push(self: *Self, registers: []const Register, reg: Register) void {
478 const index = getIndexForReg(registers, reg);
479 self.bitset.set(index);
480 }
492481
493 pub fn fromInt(mask: u32) Self {
494 return .{
495 .bitset = RegBitSet{ .mask = @intCast(RegBitSet.MaskInt, mask) },
496 };
497 }
482 pub fn isSet(self: Self, registers: []const Register, reg: Register) bool {
483 const index = getIndexForReg(registers, reg);
484 return self.bitset.isSet(index);
485 }
498486
499 pub fn count(self: Self) u32 {
500 return @intCast(u32, self.bitset.count());
501 }
502 };
503}
487 pub fn asInt(self: Self) u32 {
488 return self.bitset.mask;
489 }
490
491 pub fn fromInt(mask: u32) Self {
492 return .{
493 .bitset = BitSet{ .mask = @intCast(BitSet.MaskInt, mask) },
494 };
495 }
496
497 pub fn count(self: Self) u32 {
498 return @intCast(u32, self.bitset.count());
499 }
500};
504501
505502pub const SaveRegisterList = struct {
506503 /// Use `RegisterList` to populate.
src/arch/x86_64/abi.zig+60-14
......@@ -392,23 +392,69 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
392392 }
393393}
394394
395/// Note that .rsp and .rbp also belong to this set, however, we never expect to use them
396/// for anything else but stack offset tracking therefore we exclude them from this set.
397pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 };
398/// These registers need to be preserved (saved on the stack) and restored by the caller before
399/// the caller relinquishes control to a subroutine via call instruction (or similar).
400/// In other words, these registers are free to use by the callee.
401pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
395pub const SysV = struct {
396 /// Note that .rsp and .rbp also belong to this set, however, we never expect to use them
397 /// for anything else but stack offset tracking therefore we exclude them from this set.
398 pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 };
399 /// These registers need to be preserved (saved on the stack) and restored by the caller before
400 /// the caller relinquishes control to a subroutine via call instruction (or similar).
401 /// In other words, these registers are free to use by the callee.
402 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 };
402403
403pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
404pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
404 pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
405 pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
406};
407
408pub const Win64 = struct {
409 /// Note that .rsp and .rbp also belong to this set, however, we never expect to use them
410 /// for anything else but stack offset tracking therefore we exclude them from this set.
411 pub const callee_preserved_regs = [_]Register{ .rbx, .rsi, .rdi, .r12, .r13, .r14, .r15 };
412 /// These registers need to be preserved (saved on the stack) and restored by the caller before
413 /// the caller relinquishes control to a subroutine via call instruction (or similar).
414 /// In other words, these registers are free to use by the callee.
415 pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .r8, .r9, .r10, .r11 };
405416
417 pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 };
418 pub const c_abi_int_return_regs = [_]Register{.rax};
419};
420
421pub fn getCalleePreservedRegs(target: Target) []const Register {
422 return switch (target.os.tag) {
423 .windows => &Win64.callee_preserved_regs,
424 else => &SysV.callee_preserved_regs,
425 };
426}
427
428pub fn getCallerPreservedRegs(target: Target) []const Register {
429 return switch (target.os.tag) {
430 .windows => &Win64.caller_preserved_regs,
431 else => &SysV.caller_preserved_regs,
432 };
433}
434
435pub fn getCAbiIntParamRegs(target: Target) []const Register {
436 return switch (target.os.tag) {
437 .windows => &Win64.c_abi_int_param_regs,
438 else => &SysV.c_abi_int_param_regs,
439 };
440}
441
442pub fn getCAbiIntReturnRegs(target: Target) []const Register {
443 return switch (target.os.tag) {
444 .windows => &Win64.c_abi_int_return_regs,
445 else => &SysV.c_abi_int_return_regs,
446 };
447}
448
449const gp_regs = [_]Register{
450 .rax, .rbx, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15,
451};
406452const sse_avx_regs = [_]Register{
407453 .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7,
408454 .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15,
409455};
410const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ sse_avx_regs;
411pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
456const allocatable_regs = gp_regs ++ sse_avx_regs;
457pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_regs);
412458
413459// Register classes
414460const RegisterBitSet = RegisterManager.RegisterBitSet;
......@@ -417,15 +463,15 @@ pub const RegisterClass = struct {
417463 var set = RegisterBitSet.initEmpty();
418464 set.setRangeValue(.{
419465 .start = 0,
420 .end = caller_preserved_regs.len + callee_preserved_regs.len,
466 .end = gp_regs.len,
421467 }, true);
422468 break :blk set;
423469 };
424470 pub const sse: RegisterBitSet = blk: {
425471 var set = RegisterBitSet.initEmpty();
426472 set.setRangeValue(.{
427 .start = caller_preserved_regs.len + callee_preserved_regs.len,
428 .end = allocatable_registers.len,
473 .start = gp_regs.len,
474 .end = allocatable_regs.len,
429475 }, true);
430476 break :blk set;
431477 };