| author | |
| committer | |
| log | a19e6adbf90771890ecdbb52d6dafab1943e4cc4 |
| tree | 1361fa3ca3a41172b80dfd26fc7ee00700a0f4e5 |
| parent | aac4c1d3b225ff4cd7138d9aae599c9540c7f04e |
4 files changed, 103 insertions(+), 63 deletions(-)
src/arch/x86_64/CodeGen.zig+8-12| ... | ... | @@ -32,11 +32,6 @@ const abi = @import("abi.zig"); |
| 32 | 32 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 33 | 33 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| 34 | 34 | |
| 35 | const callee_preserved_regs = abi.callee_preserved_regs; | |
| 36 | const caller_preserved_regs = abi.caller_preserved_regs; | |
| 37 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; | |
| 38 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | |
| 39 | ||
| 40 | 35 | const Condition = bits.Condition; |
| 41 | 36 | const RegisterManager = abi.RegisterManager; |
| 42 | 37 | const RegisterLock = RegisterManager.RegisterLock; |
| ... | ... | @@ -448,10 +443,11 @@ fn gen(self: *Self) InnerError!void { |
| 448 | 443 | |
| 449 | 444 | // Create list of registers to save in the prologue. |
| 450 | 445 | // 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| { | |
| 453 | 449 | if (self.register_manager.isRegAllocated(reg)) { |
| 454 | reg_list.push(reg); | |
| 450 | reg_list.push(callee_preserved_regs, reg); | |
| 455 | 451 | } |
| 456 | 452 | } |
| 457 | 453 | 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. |
| 3923 | 3919 | |
| 3924 | 3920 | try self.spillEflagsIfOccupied(); |
| 3925 | 3921 | |
| 3926 | for (caller_preserved_regs) |reg| { | |
| 3922 | for (abi.getCallerPreservedRegs(self.target.*)) |reg| { | |
| 3927 | 3923 | try self.register_manager.getReg(reg, null); |
| 3928 | 3924 | } |
| 3929 | 3925 | |
| ... | ... | @@ -7140,7 +7136,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7140 | 7136 | assert(ret_ty.isError()); |
| 7141 | 7137 | result.return_value = .{ .immediate = 0 }; |
| 7142 | 7138 | } 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); | |
| 7144 | 7140 | result.return_value = .{ .register = aliased_reg }; |
| 7145 | 7141 | } else { |
| 7146 | 7142 | // 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 { |
| 7187 | 7183 | else => false, |
| 7188 | 7184 | }; |
| 7189 | 7185 | 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; | |
| 7191 | 7187 | try by_reg.putNoClobber(i, next_int_reg); |
| 7192 | 7188 | next_int_reg += 1; |
| 7193 | 7189 | } |
| ... | ... | @@ -7210,7 +7206,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7210 | 7206 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 7211 | 7207 | const param_align = @intCast(u32, ty.abiAlignment(self.target.*)); |
| 7212 | 7208 | 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); | |
| 7214 | 7210 | result.args[i] = .{ .register = aliased_reg }; |
| 7215 | 7211 | next_int_reg += 1; |
| 7216 | 7212 | } else { |
src/arch/x86_64/Emit.zig+4-3| ... | ... | @@ -283,10 +283,11 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerErro |
| 283 | 283 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 284 | 284 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| 285 | 285 | 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); | |
| 287 | 286 | 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)) { | |
| 290 | 291 | switch (tag) { |
| 291 | 292 | .push => try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ |
| 292 | 293 | .disp = @bitCast(u32, disp), |
src/arch/x86_64/Mir.zig+31-34| ... | ... | @@ -461,46 +461,43 @@ pub const Inst = struct { |
| 461 | 461 | } |
| 462 | 462 | }; |
| 463 | 463 | |
| 464 | pub 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 | } | |
| 464 | pub const RegisterList = struct { | |
| 465 | bitset: BitSet = BitSet.initEmpty(), | |
| 478 | 466 | |
| 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(); | |
| 483 | 469 | |
| 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); | |
| 487 | 473 | } |
| 474 | unreachable; // register not in input register list! | |
| 475 | } | |
| 488 | 476 | |
| 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 | } | |
| 492 | 481 | |
| 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 | } | |
| 498 | 486 | |
| 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 | }; | |
| 504 | 501 | |
| 505 | 502 | pub const SaveRegisterList = struct { |
| 506 | 503 | /// 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 { |
| 392 | 392 | } |
| 393 | 393 | } |
| 394 | 394 | |
| 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. | |
| 397 | pub 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. | |
| 401 | pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; | |
| 395 | pub 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 }; | |
| 402 | 403 | |
| 403 | pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; | |
| 404 | pub 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 | ||
| 408 | pub 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 }; | |
| 405 | 416 | |
| 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 | ||
| 421 | pub 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 | ||
| 428 | pub 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 | ||
| 435 | pub 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 | ||
| 442 | pub 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 | ||
| 449 | const gp_regs = [_]Register{ | |
| 450 | .rax, .rbx, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11, .r12, .r13, .r14, .r15, | |
| 451 | }; | |
| 406 | 452 | const sse_avx_regs = [_]Register{ |
| 407 | 453 | .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7, |
| 408 | 454 | .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15, |
| 409 | 455 | }; |
| 410 | const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ sse_avx_regs; | |
| 411 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); | |
| 456 | const allocatable_regs = gp_regs ++ sse_avx_regs; | |
| 457 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_regs); | |
| 412 | 458 | |
| 413 | 459 | // Register classes |
| 414 | 460 | const RegisterBitSet = RegisterManager.RegisterBitSet; |
| ... | ... | @@ -417,15 +463,15 @@ pub const RegisterClass = struct { |
| 417 | 463 | var set = RegisterBitSet.initEmpty(); |
| 418 | 464 | set.setRangeValue(.{ |
| 419 | 465 | .start = 0, |
| 420 | .end = caller_preserved_regs.len + callee_preserved_regs.len, | |
| 466 | .end = gp_regs.len, | |
| 421 | 467 | }, true); |
| 422 | 468 | break :blk set; |
| 423 | 469 | }; |
| 424 | 470 | pub const sse: RegisterBitSet = blk: { |
| 425 | 471 | var set = RegisterBitSet.initEmpty(); |
| 426 | 472 | 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, | |
| 429 | 475 | }, true); |
| 430 | 476 | break :blk set; |
| 431 | 477 | }; |