| 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,11 +32,6 @@ const abi = @import("abi.zig"); |
| 32 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | 32 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 33 | const errUnionErrorOffset = codegen.errUnionErrorOffset; | 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 | const Condition = bits.Condition; | 35 | const Condition = bits.Condition; |
| 41 | const RegisterManager = abi.RegisterManager; | 36 | const RegisterManager = abi.RegisterManager; |
| 42 | const RegisterLock = RegisterManager.RegisterLock; | 37 | const RegisterLock = RegisterManager.RegisterLock; |
| ... | @@ -448,10 +443,11 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -448,10 +443,11 @@ fn gen(self: *Self) InnerError!void { |
| 448 | 443 | ||
| 449 | // Create list of registers to save in the prologue. | 444 | // Create list of registers to save in the prologue. |
| 450 | // TODO handle register classes | 445 | // TODO handle register classes |
| 451 | var reg_list: Mir.RegisterList(Register, &callee_preserved_regs) = .{}; | 446 | var reg_list = Mir.RegisterList{}; |
| 452 | inline for (callee_preserved_regs) |reg| { | 447 | const callee_preserved_regs = abi.getCalleePreservedRegs(self.target.*); |
| 448 | for (callee_preserved_regs) |reg| { | ||
| 453 | if (self.register_manager.isRegAllocated(reg)) { | 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 | const saved_regs_stack_space: u32 = reg_list.count() * 8; | 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,7 +3919,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3923 | 3919 | ||
| 3924 | try self.spillEflagsIfOccupied(); | 3920 | try self.spillEflagsIfOccupied(); |
| 3925 | 3921 | ||
| 3926 | for (caller_preserved_regs) |reg| { | 3922 | for (abi.getCallerPreservedRegs(self.target.*)) |reg| { |
| 3927 | try self.register_manager.getReg(reg, null); | 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,7 +7136,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7140 | assert(ret_ty.isError()); | 7136 | assert(ret_ty.isError()); |
| 7141 | result.return_value = .{ .immediate = 0 }; | 7137 | result.return_value = .{ .immediate = 0 }; |
| 7142 | } else if (ret_ty_size <= 8) { | 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 | result.return_value = .{ .register = aliased_reg }; | 7140 | result.return_value = .{ .register = aliased_reg }; |
| 7145 | } else { | 7141 | } else { |
| 7146 | // We simply make the return MCValue a stack offset. However, the actual value | 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,7 +7183,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7187 | else => false, | 7183 | else => false, |
| 7188 | }; | 7184 | }; |
| 7189 | if (pass_in_reg) { | 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 | try by_reg.putNoClobber(i, next_int_reg); | 7187 | try by_reg.putNoClobber(i, next_int_reg); |
| 7192 | next_int_reg += 1; | 7188 | next_int_reg += 1; |
| 7193 | } | 7189 | } |
| ... | @@ -7210,7 +7206,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -7210,7 +7206,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7210 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 7206 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 7211 | const param_align = @intCast(u32, ty.abiAlignment(self.target.*)); | 7207 | const param_align = @intCast(u32, ty.abiAlignment(self.target.*)); |
| 7212 | if (by_reg.get(i)) |int_reg| { | 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 | result.args[i] = .{ .register = aliased_reg }; | 7210 | result.args[i] = .{ .register = aliased_reg }; |
| 7215 | next_int_reg += 1; | 7211 | next_int_reg += 1; |
| 7216 | } else { | 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,10 +283,11 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerErro |
| 283 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); | 283 | const ops = emit.mir.instructions.items(.ops)[inst].decode(); |
| 284 | const payload = emit.mir.instructions.items(.data)[inst].payload; | 284 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| 285 | const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data; | 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 | var disp: i32 = -@intCast(i32, save_reg_list.stack_end); | 286 | var disp: i32 = -@intCast(i32, save_reg_list.stack_end); |
| 288 | inline for (abi.callee_preserved_regs) |reg| { | 287 | const reg_list = Mir.RegisterList.fromInt(save_reg_list.register_list); |
| 289 | if (reg_list.isSet(reg)) { | 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 | switch (tag) { | 291 | switch (tag) { |
| 291 | .push => try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ | 292 | .push => try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ |
| 292 | .disp = @bitCast(u32, disp), | 293 | .disp = @bitCast(u32, disp), |
src/arch/x86_64/Mir.zig+31-34| ... | @@ -461,46 +461,43 @@ pub const Inst = struct { | ... | @@ -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 { | 464 | pub const RegisterList = struct { |
| 465 | assert(registers.len <= @bitSizeOf(u32)); | 465 | bitset: BitSet = BitSet.initEmpty(), |
| 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 | } | ||
| 478 | 466 | ||
| 479 | pub fn push(self: *Self, reg: Reg) void { | 467 | const BitSet = IntegerBitSet(@ctz(@as(u32, 0))); |
| 480 | const index = getIndexForReg(reg); | 468 | const Self = @This(); |
| 481 | self.bitset.set(index); | ||
| 482 | } | ||
| 483 | 469 | ||
| 484 | pub fn isSet(self: Self, reg: Reg) bool { | 470 | fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt { |
| 485 | const index = getIndexForReg(reg); | 471 | for (registers) |cpreg, i| { |
| 486 | return self.bitset.isSet(index); | 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 { | 477 | pub fn push(self: *Self, registers: []const Register, reg: Register) void { |
| 490 | return self.bitset.mask; | 478 | const index = getIndexForReg(registers, reg); |
| 491 | } | 479 | self.bitset.set(index); |
| 480 | } | ||
| 492 | 481 | ||
| 493 | pub fn fromInt(mask: u32) Self { | 482 | pub fn isSet(self: Self, registers: []const Register, reg: Register) bool { |
| 494 | return .{ | 483 | const index = getIndexForReg(registers, reg); |
| 495 | .bitset = RegBitSet{ .mask = @intCast(RegBitSet.MaskInt, mask) }, | 484 | return self.bitset.isSet(index); |
| 496 | }; | 485 | } |
| 497 | } | ||
| 498 | 486 | ||
| 499 | pub fn count(self: Self) u32 { | 487 | pub fn asInt(self: Self) u32 { |
| 500 | return @intCast(u32, self.bitset.count()); | 488 | return self.bitset.mask; |
| 501 | } | 489 | } |
| 502 | }; | 490 | |
| 503 | } | 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 | pub const SaveRegisterList = struct { | 502 | pub const SaveRegisterList = struct { |
| 506 | /// Use `RegisterList` to populate. | 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,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 | 395 | pub const SysV = struct { |
| 396 | /// for anything else but stack offset tracking therefore we exclude them from this set. | 396 | /// Note that .rsp and .rbp also belong to this set, however, we never expect to use them |
| 397 | pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 }; | 397 | /// for anything else but stack offset tracking therefore we exclude them from this set. |
| 398 | /// These registers need to be preserved (saved on the stack) and restored by the caller before | 398 | pub const callee_preserved_regs = [_]Register{ .rbx, .r12, .r13, .r14, .r15 }; |
| 399 | /// the caller relinquishes control to a subroutine via call instruction (or similar). | 399 | /// These registers need to be preserved (saved on the stack) and restored by the caller before |
| 400 | /// In other words, these registers are free to use by the callee. | 400 | /// the caller relinquishes control to a subroutine via call instruction (or similar). |
| 401 | pub const caller_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8, .r9, .r10, .r11 }; | 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_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; |
| 404 | pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx }; | 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 | const sse_avx_regs = [_]Register{ | 452 | const sse_avx_regs = [_]Register{ |
| 407 | .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7, | 453 | .ymm0, .ymm1, .ymm2, .ymm3, .ymm4, .ymm5, .ymm6, .ymm7, |
| 408 | .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15, | 454 | .ymm8, .ymm9, .ymm10, .ymm11, .ymm12, .ymm13, .ymm14, .ymm15, |
| 409 | }; | 455 | }; |
| 410 | const allocatable_registers = callee_preserved_regs ++ caller_preserved_regs ++ sse_avx_regs; | 456 | const allocatable_regs = gp_regs ++ sse_avx_regs; |
| 411 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers); | 457 | pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_regs); |
| 412 | 458 | ||
| 413 | // Register classes | 459 | // Register classes |
| 414 | const RegisterBitSet = RegisterManager.RegisterBitSet; | 460 | const RegisterBitSet = RegisterManager.RegisterBitSet; |
| ... | @@ -417,15 +463,15 @@ pub const RegisterClass = struct { | ... | @@ -417,15 +463,15 @@ pub const RegisterClass = struct { |
| 417 | var set = RegisterBitSet.initEmpty(); | 463 | var set = RegisterBitSet.initEmpty(); |
| 418 | set.setRangeValue(.{ | 464 | set.setRangeValue(.{ |
| 419 | .start = 0, | 465 | .start = 0, |
| 420 | .end = caller_preserved_regs.len + callee_preserved_regs.len, | 466 | .end = gp_regs.len, |
| 421 | }, true); | 467 | }, true); |
| 422 | break :blk set; | 468 | break :blk set; |
| 423 | }; | 469 | }; |
| 424 | pub const sse: RegisterBitSet = blk: { | 470 | pub const sse: RegisterBitSet = blk: { |
| 425 | var set = RegisterBitSet.initEmpty(); | 471 | var set = RegisterBitSet.initEmpty(); |
| 426 | set.setRangeValue(.{ | 472 | set.setRangeValue(.{ |
| 427 | .start = caller_preserved_regs.len + callee_preserved_regs.len, | 473 | .start = gp_regs.len, |
| 428 | .end = allocatable_registers.len, | 474 | .end = allocatable_regs.len, |
| 429 | }, true); | 475 | }, true); |
| 430 | break :blk set; | 476 | break :blk set; |
| 431 | }; | 477 | }; |