authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-23 00:01:12+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-23 00:01:12+01:00
log081ce09575426086bca1164ae733e476b99a0253
treefbc6b204723691dfad10851137c7df67858d679b
parentc9ae24503dc8da2e59f46619695bf4eb863fb3ac
parent406c85f9ba056e10899feed18dae91e20942dc55
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10664 from ziglang/stage2-x86_64-refactor-air-call

stage2: refactor how we preserve callee regs and how we pass args on the stack in x86_64 backend

6 files changed, 194 insertions(+), 245 deletions(-)

src/arch/x86_64/CodeGen.zig+147-205
...@@ -43,7 +43,7 @@ err_msg: ?*ErrorMsg,...@@ -43,7 +43,7 @@ err_msg: ?*ErrorMsg,
43args: []MCValue,43args: []MCValue,
44ret_mcv: MCValue,44ret_mcv: MCValue,
45fn_type: Type,45fn_type: Type,
46arg_index: usize,46arg_index: u32,
47src_loc: Module.SrcLoc,47src_loc: Module.SrcLoc,
48stack_align: u32,48stack_align: u32,
4949
...@@ -61,8 +61,6 @@ end_di_column: u32,...@@ -61,8 +61,6 @@ end_di_column: u32,
61/// which is a relative jump, based on the address following the reloc.61/// which is a relative jump, based on the address following the reloc.
62exitlude_jump_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},62exitlude_jump_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
6363
64stack_args_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .{},
65
66/// Whenever there is a runtime branch, we push a Branch onto this stack,64/// Whenever there is a runtime branch, we push a Branch onto this stack,
67/// and pop it off when the runtime branch joins. This provides an "overlay"65/// and pop it off when the runtime branch joins. This provides an "overlay"
68/// of the table of mappings from instructions to `MCValue` from within the branch.66/// of the table of mappings from instructions to `MCValue` from within the branch.
...@@ -119,9 +117,9 @@ pub const MCValue = union(enum) {...@@ -119,9 +117,9 @@ pub const MCValue = union(enum) {
119 memory: u64,117 memory: u64,
120 /// The value is one of the stack variables.118 /// The value is one of the stack variables.
121 /// If the type is a pointer, it means the pointer address is in the stack at this offset.119 /// If the type is a pointer, it means the pointer address is in the stack at this offset.
122 stack_offset: u32,120 stack_offset: i32,
123 /// The value is a pointer to one of the stack variables (payload is stack offset).121 /// The value is a pointer to one of the stack variables (payload is stack offset).
124 ptr_stack_offset: u32,122 ptr_stack_offset: i32,
125 /// The value is in the compare flags assuming an unsigned operation,123 /// The value is in the compare flags assuming an unsigned operation,
126 /// with this operator applied on top of it.124 /// with this operator applied on top of it.
127 compare_flags_unsigned: math.CompareOperator,125 compare_flags_unsigned: math.CompareOperator,
...@@ -286,7 +284,6 @@ pub fn generate(...@@ -286,7 +284,6 @@ pub fn generate(
286 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);284 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
287 defer function.mir_instructions.deinit(bin_file.allocator);285 defer function.mir_instructions.deinit(bin_file.allocator);
288 defer function.mir_extra.deinit(bin_file.allocator);286 defer function.mir_extra.deinit(bin_file.allocator);
289 defer function.stack_args_relocs.deinit(bin_file.allocator);
290 defer if (builtin.mode == .Debug) function.mir_to_air_map.deinit();287 defer if (builtin.mode == .Debug) function.mir_to_air_map.deinit();
291288
292 var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) {289 var call_info = function.resolveCallingConventionValues(fn_type) catch |err| switch (err) {
...@@ -378,13 +375,6 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {...@@ -378,13 +375,6 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
378fn gen(self: *Self) InnerError!void {375fn gen(self: *Self) InnerError!void {
379 const cc = self.fn_type.fnCallingConvention();376 const cc = self.fn_type.fnCallingConvention();
380 if (cc != .Naked) {377 if (cc != .Naked) {
381 // push the callee_preserved_regs that were used
382 const backpatch_push_callee_preserved_regs_i = try self.addInst(.{
383 .tag = .push_regs_from_callee_preserved_regs,
384 .ops = undefined,
385 .data = .{ .regs_to_push_or_pop = undefined }, // to be backpatched
386 });
387
388 _ = try self.addInst(.{378 _ = try self.addInst(.{
389 .tag = .push,379 .tag = .push,
390 .ops = (Mir.Ops{380 .ops = (Mir.Ops{
...@@ -416,6 +406,15 @@ fn gen(self: *Self) InnerError!void {...@@ -416,6 +406,15 @@ fn gen(self: *Self) InnerError!void {
416 .data = undefined,406 .data = undefined,
417 });407 });
418408
409 // push the callee_preserved_regs that were used
410 const backpatch_push_callee_preserved_regs_i = try self.addInst(.{
411 .tag = .push_regs_from_callee_preserved_regs,
412 .ops = (Mir.Ops{
413 .reg1 = .rbp,
414 }).encode(),
415 .data = .{ .payload = undefined }, // to be backpatched
416 });
417
419 try self.genBody(self.air.getMainBody());418 try self.genBody(self.air.getMainBody());
420419
421 // TODO can single exitlude jump reloc be elided? What if it is not at the end of the code?420 // TODO can single exitlude jump reloc be elided? What if it is not at the end of the code?
...@@ -429,6 +428,33 @@ fn gen(self: *Self) InnerError!void {...@@ -429,6 +428,33 @@ fn gen(self: *Self) InnerError!void {
429 self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len);428 self.mir_instructions.items(.data)[jmp_reloc].inst = @intCast(u32, self.mir_instructions.len);
430 }429 }
431430
431 // calculate the data for callee_preserved_regs to be pushed and popped
432 const callee_preserved_regs_payload = blk: {
433 var data = Mir.RegsToPushOrPop{
434 .regs = 0,
435 .disp = mem.alignForwardGeneric(u32, self.next_stack_offset, 8),
436 };
437 inline for (callee_preserved_regs) |reg, i| {
438 if (self.register_manager.isRegAllocated(reg)) {
439 data.regs |= 1 << @intCast(u5, i);
440 self.max_end_stack += 8;
441 }
442 }
443 break :blk try self.addExtra(data);
444 };
445
446 const data = self.mir_instructions.items(.data);
447 // backpatch the push instruction
448 data[backpatch_push_callee_preserved_regs_i].payload = callee_preserved_regs_payload;
449 // pop the callee_preserved_regs
450 _ = try self.addInst(.{
451 .tag = .pop_regs_from_callee_preserved_regs,
452 .ops = (Mir.Ops{
453 .reg1 = .rbp,
454 }).encode(),
455 .data = .{ .payload = callee_preserved_regs_payload },
456 });
457
432 _ = try self.addInst(.{458 _ = try self.addInst(.{
433 .tag = .dbg_epilogue_begin,459 .tag = .dbg_epilogue_begin,
434 .ops = undefined,460 .ops = undefined,
...@@ -450,34 +476,6 @@ fn gen(self: *Self) InnerError!void {...@@ -450,34 +476,6 @@ fn gen(self: *Self) InnerError!void {
450 .data = undefined,476 .data = undefined,
451 });477 });
452478
453 // calculate the data for callee_preserved_regs to be pushed and popped
454 var callee_preserved_regs_push_data: u32 = 0x0;
455 // TODO this is required on macOS since macOS actively checks for stack alignment
456 // at every extern call site. As far as I can tell, macOS accounts for the typical
457 // function prologue first 2 instructions of:
458 // ...
459 // push rbp
460 // mov rsp, rbp
461 // ...
462 // Thus we don't need to adjust the stack for the first push instruction. However,
463 // any subsequent push of values on the stack such as when preserving registers,
464 // needs to be taken into account here.
465 var stack_adjustment: u32 = 0;
466 inline for (callee_preserved_regs) |reg, i| {
467 if (self.register_manager.isRegAllocated(reg)) {
468 callee_preserved_regs_push_data |= 1 << @intCast(u5, i);
469 stack_adjustment += @divExact(reg.size(), 8);
470 }
471 }
472 const data = self.mir_instructions.items(.data);
473 // backpatch the push instruction
474 data[backpatch_push_callee_preserved_regs_i].regs_to_push_or_pop = callee_preserved_regs_push_data;
475 // pop the callee_preserved_regs
476 _ = try self.addInst(.{
477 .tag = .pop_regs_from_callee_preserved_regs,
478 .ops = undefined,
479 .data = .{ .regs_to_push_or_pop = callee_preserved_regs_push_data },
480 });
481 _ = try self.addInst(.{479 _ = try self.addInst(.{
482 .tag = .ret,480 .tag = .ret,
483 .ops = (Mir.Ops{481 .ops = (Mir.Ops{
...@@ -487,37 +485,28 @@ fn gen(self: *Self) InnerError!void {...@@ -487,37 +485,28 @@ fn gen(self: *Self) InnerError!void {
487 });485 });
488486
489 // Adjust the stack487 // Adjust the stack
490 const stack_end = self.max_end_stack;488 if (self.max_end_stack > math.maxInt(i32)) {
491 if (stack_end > math.maxInt(i32) - stack_adjustment) {
492 return self.failSymbol("too much stack used in call parameters", .{});489 return self.failSymbol("too much stack used in call parameters", .{});
493 }490 }
494 // TODO we should reuse this mechanism to align the stack when calling any function even if491 // TODO we should reuse this mechanism to align the stack when calling any function even if
495 // we do not pass any args on the stack BUT we still push regs to stack with `push` inst.492 // we do not pass any args on the stack BUT we still push regs to stack with `push` inst.
496 const aligned_stack_end = @intCast(u32, mem.alignForward(stack_end, self.stack_align));493 const aligned_stack_end = @intCast(u32, mem.alignForward(self.max_end_stack, self.stack_align));
497 if (aligned_stack_end > 0 or (stack_adjustment > 0 and self.target.isDarwin())) {494 if (aligned_stack_end > 0) {
498 const imm = if (self.target.isDarwin()) aligned_stack_end + stack_adjustment else aligned_stack_end;
499 self.mir_instructions.set(backpatch_stack_sub, .{495 self.mir_instructions.set(backpatch_stack_sub, .{
500 .tag = .sub,496 .tag = .sub,
501 .ops = (Mir.Ops{497 .ops = (Mir.Ops{
502 .reg1 = .rsp,498 .reg1 = .rsp,
503 }).encode(),499 }).encode(),
504 .data = .{ .imm = imm },500 .data = .{ .imm = aligned_stack_end },
505 });501 });
506 self.mir_instructions.set(backpatch_stack_add, .{502 self.mir_instructions.set(backpatch_stack_add, .{
507 .tag = .add,503 .tag = .add,
508 .ops = (Mir.Ops{504 .ops = (Mir.Ops{
509 .reg1 = .rsp,505 .reg1 = .rsp,
510 }).encode(),506 }).encode(),
511 .data = .{ .imm = imm },507 .data = .{ .imm = aligned_stack_end },
512 });508 });
513 }509 }
514 while (self.stack_args_relocs.popOrNull()) |index| {
515 // TODO like above, gotta figure out the alignment shenanigans for macOS, etc.
516 const adjustment = if (self.target.isDarwin()) 2 * stack_adjustment else stack_adjustment;
517 // +16 bytes to account for saved return address of the `call` instruction and
518 // `push rbp`.
519 self.mir_instructions.items(.data)[index].imm += adjustment + aligned_stack_end + 16;
520 }
521 } else {510 } else {
522 _ = try self.addInst(.{511 _ = try self.addInst(.{
523 .tag = .dbg_prologue_end,512 .tag = .dbg_prologue_end,
...@@ -808,7 +797,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -808,7 +797,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
808 }797 }
809 }798 }
810 const stack_offset = try self.allocMem(inst, abi_size, abi_align);799 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
811 return MCValue{ .stack_offset = stack_offset };800 return MCValue{ .stack_offset = @intCast(i32, stack_offset) };
812}801}
813802
814pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {803pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
...@@ -854,12 +843,12 @@ fn copyToNewRegisterWithExceptions(...@@ -854,12 +843,12 @@ fn copyToNewRegisterWithExceptions(
854843
855fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {844fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
856 const stack_offset = try self.allocMemPtr(inst);845 const stack_offset = try self.allocMemPtr(inst);
857 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });846 return self.finishAir(inst, .{ .ptr_stack_offset = @intCast(i32, stack_offset) }, .{ .none, .none, .none });
858}847}
859848
860fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {849fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void {
861 const stack_offset = try self.allocMemPtr(inst);850 const stack_offset = try self.allocMemPtr(inst);
862 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });851 return self.finishAir(inst, .{ .ptr_stack_offset = @intCast(i32, stack_offset) }, .{ .none, .none, .none });
863}852}
864853
865fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {854fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1419,7 +1408,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1419,7 +1408,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1419 .reg1 = addr_reg.to64(),1408 .reg1 = addr_reg.to64(),
1420 .reg2 = .rbp,1409 .reg2 = .rbp,
1421 }).encode(),1410 }).encode(),
1422 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + array_abi_size)) },1411 .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, array_abi_size))) },
1423 });1412 });
1424 },1413 },
1425 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),1414 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
...@@ -1623,7 +1612,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1623,7 +1612,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1623 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });1612 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
16241613
1625 return self.genInlineMemcpy(1614 return self.genInlineMemcpy(
1626 @bitCast(u32, -@intCast(i32, off + abi_size)),1615 -(off + @intCast(i32, abi_size)),
1627 .rbp,1616 .rbp,
1628 registerAlias(addr_reg, @divExact(reg.size(), 8)),1617 registerAlias(addr_reg, @divExact(reg.size(), 8)),
1629 count_reg.to64(),1618 count_reg.to64(),
...@@ -1780,10 +1769,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -1780,10 +1769,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
1780 return if (self.liveness.isUnused(inst)) .dead else result: {1769 return if (self.liveness.isUnused(inst)) .dead else result: {
1781 const mcv = try self.resolveInst(operand);1770 const mcv = try self.resolveInst(operand);
1782 const struct_ty = self.air.typeOf(operand).childType();1771 const struct_ty = self.air.typeOf(operand).childType();
1783 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));1772 const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*));
1784 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));1773 const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*));
1785 const struct_field_ty = struct_ty.structFieldType(index);1774 const struct_field_ty = struct_ty.structFieldType(index);
1786 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));1775 const struct_field_size = @intCast(i32, struct_field_ty.abiSize(self.target.*));
17871776
1788 switch (mcv) {1777 switch (mcv) {
1789 .ptr_stack_offset => |off| {1778 .ptr_stack_offset => |off| {
...@@ -1803,10 +1792,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1803,10 +1792,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
1803 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1792 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1804 const mcv = try self.resolveInst(operand);1793 const mcv = try self.resolveInst(operand);
1805 const struct_ty = self.air.typeOf(operand);1794 const struct_ty = self.air.typeOf(operand);
1806 const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*));1795 const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*));
1807 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));1796 const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*));
1808 const struct_field_ty = struct_ty.structFieldType(index);1797 const struct_field_ty = struct_ty.structFieldType(index);
1809 const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));1798 const struct_field_size = @intCast(i32, struct_field_ty.abiSize(self.target.*));
18101799
1811 switch (mcv) {1800 switch (mcv) {
1812 .stack_offset => |off| {1801 .stack_offset => |off| {
...@@ -1970,7 +1959,7 @@ fn genBinMathOpMir(...@@ -1970,7 +1959,7 @@ fn genBinMathOpMir(
1970 return self.fail("stack offset too large", .{});1959 return self.fail("stack offset too large", .{});
1971 }1960 }
1972 const abi_size = dst_ty.abiSize(self.target.*);1961 const abi_size = dst_ty.abiSize(self.target.*);
1973 const adj_off = off + abi_size;1962 const adj_off = off + @intCast(i32, abi_size);
1974 _ = try self.addInst(.{1963 _ = try self.addInst(.{
1975 .tag = mir_tag,1964 .tag = mir_tag,
1976 .ops = (Mir.Ops{1965 .ops = (Mir.Ops{
...@@ -1978,7 +1967,7 @@ fn genBinMathOpMir(...@@ -1978,7 +1967,7 @@ fn genBinMathOpMir(
1978 .reg2 = .rbp,1967 .reg2 = .rbp,
1979 .flags = 0b01,1968 .flags = 0b01,
1980 }).encode(),1969 }).encode(),
1981 .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },1970 .data = .{ .imm = @bitCast(u32, -adj_off) },
1982 });1971 });
1983 },1972 },
1984 .compare_flags_unsigned => {1973 .compare_flags_unsigned => {
...@@ -1997,7 +1986,7 @@ fn genBinMathOpMir(...@@ -1997,7 +1986,7 @@ fn genBinMathOpMir(
1997 if (abi_size > 8) {1986 if (abi_size > 8) {
1998 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});1987 return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{});
1999 }1988 }
2000 const adj_off = off + abi_size;1989 const adj_off = off + @intCast(i32, abi_size);
20011990
2002 switch (src_mcv) {1991 switch (src_mcv) {
2003 .none => unreachable,1992 .none => unreachable,
...@@ -2013,7 +2002,7 @@ fn genBinMathOpMir(...@@ -2013,7 +2002,7 @@ fn genBinMathOpMir(
2013 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),2002 .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)),
2014 .flags = 0b10,2003 .flags = 0b10,
2015 }).encode(),2004 }).encode(),
2016 .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },2005 .data = .{ .imm = @bitCast(u32, -adj_off) },
2017 });2006 });
2018 },2007 },
2019 .immediate => |imm| {2008 .immediate => |imm| {
...@@ -2034,7 +2023,7 @@ fn genBinMathOpMir(...@@ -2034,7 +2023,7 @@ fn genBinMathOpMir(
2034 else => unreachable,2023 else => unreachable,
2035 };2024 };
2036 const payload = try self.addExtra(Mir.ImmPair{2025 const payload = try self.addExtra(Mir.ImmPair{
2037 .dest_off = @bitCast(u32, -@intCast(i32, adj_off)),2026 .dest_off = @bitCast(u32, -adj_off),
2038 .operand = @truncate(u32, imm),2027 .operand = @truncate(u32, imm),
2039 });2028 });
2040 _ = try self.addInst(.{2029 _ = try self.addInst(.{
...@@ -2172,7 +2161,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -2172,7 +2161,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
2172 const mcv = self.args[arg_index];2161 const mcv = self.args[arg_index];
2173 const payload = try self.addExtra(Mir.ArgDbgInfo{2162 const payload = try self.addExtra(Mir.ArgDbgInfo{
2174 .air_inst = inst,2163 .air_inst = inst,
2175 .arg_index = @truncate(u32, arg_index), // TODO can arg_index: u32?2164 .arg_index = arg_index,
2176 });2165 });
2177 _ = try self.addInst(.{2166 _ = try self.addInst(.{
2178 .tag = .arg_dbg_info,2167 .tag = .arg_dbg_info,
...@@ -2188,58 +2177,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -2188,58 +2177,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
2188 self.register_manager.getRegAssumeFree(reg.to64(), inst);2177 self.register_manager.getRegAssumeFree(reg.to64(), inst);
2189 break :blk mcv;2178 break :blk mcv;
2190 },2179 },
2191 .stack_offset => |off| {2180 .stack_offset => {
2192 const ty = self.air.typeOfIndex(inst);2181 const ty = self.air.typeOfIndex(inst);
2193 const abi_size = ty.abiSize(self.target.*);2182 const abi_size = ty.abiSize(self.target.*);
21942183 const off = @intCast(i32, (arg_index + 1) * abi_size) + 16;
2195 if (abi_size <= 8) {2184 break :blk MCValue{ .stack_offset = -off };
2196 const reg = try self.register_manager.allocReg(inst, &.{});
2197 const reloc = try self.addInst(.{
2198 .tag = .mov,
2199 .ops = (Mir.Ops{
2200 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),
2201 .reg2 = .rsp,
2202 .flags = 0b01,
2203 }).encode(),
2204 .data = .{ .imm = off },
2205 });
2206 try self.stack_args_relocs.append(self.bin_file.allocator, reloc);
2207 break :blk .{ .register = reg };
2208 }
2209
2210 // TODO copy ellision
2211 const dst_mcv = try self.allocRegOrMem(inst, false);
2212 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx });
2213 const addr_reg = regs[0];
2214 const count_reg = regs[1];
2215 const tmp_reg = regs[2];
2216
2217 try self.register_manager.getReg(.rax, null);
2218 try self.register_manager.getReg(.rcx, null);
2219
2220 const reloc = try self.addInst(.{
2221 .tag = .lea,
2222 .ops = (Mir.Ops{
2223 .reg1 = addr_reg.to64(),
2224 .reg2 = .rsp,
2225 }).encode(),
2226 .data = .{ .imm = off },
2227 });
2228 try self.stack_args_relocs.append(self.bin_file.allocator, reloc);
2229
2230 // TODO allow for abi_size to be u64
2231 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
2232 try self.genInlineMemcpy(
2233 @bitCast(u32, -@intCast(i32, dst_mcv.stack_offset + abi_size)),
2234 .rbp,
2235 addr_reg.to64(),
2236 count_reg.to64(),
2237 tmp_reg.to8(),
2238 );
2239
2240 break :blk dst_mcv;
2241 },2185 },
2242 else => unreachable,2186 else => return self.fail("TODO implement arg for {}", .{mcv}),
2243 }2187 }
2244 };2188 };
22452189
...@@ -2264,64 +2208,6 @@ fn airFence(self: *Self) !void {...@@ -2264,64 +2208,6 @@ fn airFence(self: *Self) !void {
2264 //return self.finishAirBookkeeping();2208 //return self.finishAirBookkeeping();
2265}2209}
22662210
2267fn genSetStackArg(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
2268 const abi_size = ty.abiSize(self.target.*);
2269 switch (mcv) {
2270 .dead => unreachable,
2271 .ptr_embedded_in_code => unreachable,
2272 .unreach, .none => return,
2273 .register => |reg| {
2274 _ = try self.addInst(.{
2275 .tag = .mov,
2276 .ops = (Mir.Ops{
2277 .reg1 = .rsp,
2278 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
2279 .flags = 0b10,
2280 }).encode(),
2281 .data = .{ .imm = @bitCast(u32, -@intCast(i32, stack_offset + abi_size)) },
2282 });
2283 },
2284 .ptr_stack_offset => {
2285 const reg = try self.copyToTmpRegister(ty, mcv);
2286 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
2287 },
2288 .stack_offset => |unadjusted_off| {
2289 if (abi_size <= 8) {
2290 const reg = try self.copyToTmpRegister(ty, mcv);
2291 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
2292 }
2293
2294 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx });
2295 const addr_reg = regs[0];
2296 const count_reg = regs[1];
2297 const tmp_reg = regs[2];
2298
2299 try self.register_manager.getReg(.rax, null);
2300 try self.register_manager.getReg(.rcx, null);
2301
2302 _ = try self.addInst(.{
2303 .tag = .lea,
2304 .ops = (Mir.Ops{
2305 .reg1 = addr_reg.to64(),
2306 .reg2 = .rbp,
2307 }).encode(),
2308 .data = .{ .imm = @bitCast(u32, -@intCast(i32, unadjusted_off + abi_size)) },
2309 });
2310
2311 // TODO allow for abi_size to be u64
2312 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
2313 try self.genInlineMemcpy(
2314 @bitCast(u32, -@intCast(i32, stack_offset + abi_size)),
2315 .rsp,
2316 addr_reg.to64(),
2317 count_reg.to64(),
2318 tmp_reg.to8(),
2319 );
2320 },
2321 else => return self.fail("TODO implement args on stack for {}", .{mcv}),
2322 }
2323}
2324
2325fn airCall(self: *Self, inst: Air.Inst.Index) !void {2211fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2326 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2212 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2327 const callee = pl_op.operand;2213 const callee = pl_op.operand;
...@@ -2338,12 +2224,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2338,12 +2224,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2338 var info = try self.resolveCallingConventionValues(fn_ty);2224 var info = try self.resolveCallingConventionValues(fn_ty);
2339 defer info.deinit(self);2225 defer info.deinit(self);
23402226
2341 var count: usize = info.args.len;
2342 var stack_adjustment: u32 = 0;2227 var stack_adjustment: u32 = 0;
2343 while (count > 0) : (count -= 1) {2228 for (args) |arg, arg_i| {
2344 const arg_i = count - 1;
2345 const mc_arg = info.args[arg_i];2229 const mc_arg = info.args[arg_i];
2346 const arg = args[arg_i];
2347 const arg_ty = self.air.typeOf(arg);2230 const arg_ty = self.air.typeOf(arg);
2348 const arg_mcv = try self.resolveInst(args[arg_i]);2231 const arg_mcv = try self.resolveInst(args[arg_i]);
2349 // Here we do not use setRegOrMem even though the logic is similar, because2232 // Here we do not use setRegOrMem even though the logic is similar, because
...@@ -2355,9 +2238,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2355,9 +2238,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2355 try self.genSetReg(arg_ty, reg, arg_mcv);2238 try self.genSetReg(arg_ty, reg, arg_mcv);
2356 },2239 },
2357 .stack_offset => |off| {2240 .stack_offset => |off| {
2358 const abi_size = arg_ty.abiSize(self.target.*);2241 const abi_size = @intCast(u32, arg_ty.abiSize(self.target.*));
2359 try self.genSetStackArg(arg_ty, off, arg_mcv);2242 try self.genSetStackArg(arg_ty, off, arg_mcv);
2360 stack_adjustment += @intCast(u32, abi_size);2243 stack_adjustment += abi_size;
2361 },2244 },
2362 .ptr_stack_offset => {2245 .ptr_stack_offset => {
2363 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});2246 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
...@@ -3269,7 +3152,65 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {...@@ -3269,7 +3152,65 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
3269 }3152 }
3270}3153}
32713154
3272fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {3155fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {
3156 const abi_size = ty.abiSize(self.target.*);
3157 switch (mcv) {
3158 .dead => unreachable,
3159 .ptr_embedded_in_code => unreachable,
3160 .unreach, .none => return,
3161 .register => |reg| {
3162 _ = try self.addInst(.{
3163 .tag = .mov,
3164 .ops = (Mir.Ops{
3165 .reg1 = .rsp,
3166 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
3167 .flags = 0b10,
3168 }).encode(),
3169 .data = .{ .imm = @bitCast(u32, -(stack_offset + @intCast(i32, abi_size))) },
3170 });
3171 },
3172 .ptr_stack_offset => {
3173 const reg = try self.copyToTmpRegister(ty, mcv);
3174 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3175 },
3176 .stack_offset => |unadjusted_off| {
3177 if (abi_size <= 8) {
3178 const reg = try self.copyToTmpRegister(ty, mcv);
3179 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3180 }
3181
3182 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx });
3183 const addr_reg = regs[0];
3184 const count_reg = regs[1];
3185 const tmp_reg = regs[2];
3186
3187 try self.register_manager.getReg(.rax, null);
3188 try self.register_manager.getReg(.rcx, null);
3189
3190 _ = try self.addInst(.{
3191 .tag = .lea,
3192 .ops = (Mir.Ops{
3193 .reg1 = addr_reg.to64(),
3194 .reg2 = .rbp,
3195 }).encode(),
3196 .data = .{ .imm = @bitCast(u32, -(unadjusted_off + @intCast(i32, abi_size))) },
3197 });
3198
3199 // TODO allow for abi_size to be u64
3200 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
3201 try self.genInlineMemcpy(
3202 -(stack_offset + @intCast(i32, abi_size)),
3203 .rsp,
3204 addr_reg.to64(),
3205 count_reg.to64(),
3206 tmp_reg.to8(),
3207 );
3208 },
3209 else => return self.fail("TODO implement args on stack for {}", .{mcv}),
3210 }
3211}
3212
3213fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {
3273 switch (mcv) {3214 switch (mcv) {
3274 .dead => unreachable,3215 .dead => unreachable,
3275 .ptr_embedded_in_code => unreachable,3216 .ptr_embedded_in_code => unreachable,
...@@ -3296,7 +3237,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3296,7 +3237,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3296 },3237 },
3297 .immediate => |x_big| {3238 .immediate => |x_big| {
3298 const abi_size = ty.abiSize(self.target.*);3239 const abi_size = ty.abiSize(self.target.*);
3299 const adj_off = stack_offset + abi_size;3240 const adj_off = stack_offset + @intCast(i32, abi_size);
3300 if (adj_off > 128) {3241 if (adj_off > 128) {
3301 return self.fail("TODO implement set stack variable with large stack offset", .{});3242 return self.fail("TODO implement set stack variable with large stack offset", .{});
3302 }3243 }
...@@ -3306,7 +3247,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3306,7 +3247,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3306 // offset from rbp, which is at the top of the stack frame.3247 // offset from rbp, which is at the top of the stack frame.
3307 // mov [rbp+offset], immediate3248 // mov [rbp+offset], immediate
3308 const payload = try self.addExtra(Mir.ImmPair{3249 const payload = try self.addExtra(Mir.ImmPair{
3309 .dest_off = @bitCast(u32, -@intCast(i32, adj_off)),3250 .dest_off = @bitCast(u32, -adj_off),
3310 .operand = @truncate(u32, x_big),3251 .operand = @truncate(u32, x_big),
3311 });3252 });
3312 _ = try self.addInst(.{3253 _ = try self.addInst(.{
...@@ -3326,7 +3267,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3326,7 +3267,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3326 8 => {3267 8 => {
3327 // We have a positive stack offset value but we want a twos complement negative3268 // We have a positive stack offset value but we want a twos complement negative
3328 // offset from rbp, which is at the top of the stack frame.3269 // offset from rbp, which is at the top of the stack frame.
3329 const negative_offset = -@intCast(i32, adj_off);3270 const negative_offset = -adj_off;
33303271
3331 // 64 bit write to memory would take two mov's anyways so we3272 // 64 bit write to memory would take two mov's anyways so we
3332 // insted just use two 32 bit writes to avoid register allocation3273 // insted just use two 32 bit writes to avoid register allocation
...@@ -3369,7 +3310,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3369,7 +3310,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3369 return self.fail("stack offset too large", .{});3310 return self.fail("stack offset too large", .{});
3370 }3311 }
3371 const abi_size = ty.abiSize(self.target.*);3312 const abi_size = ty.abiSize(self.target.*);
3372 const adj_off = stack_offset + abi_size;3313 const adj_off = stack_offset + @intCast(i32, abi_size);
3373 _ = try self.addInst(.{3314 _ = try self.addInst(.{
3374 .tag = .mov,3315 .tag = .mov,
3375 .ops = (Mir.Ops{3316 .ops = (Mir.Ops{
...@@ -3377,7 +3318,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3377,7 +3318,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3377 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),3318 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
3378 .flags = 0b10,3319 .flags = 0b10,
3379 }).encode(),3320 }).encode(),
3380 .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) },3321 .data = .{ .imm = @bitCast(u32, -adj_off) },
3381 });3322 });
3382 },3323 },
3383 .memory, .embedded_in_code => {3324 .memory, .embedded_in_code => {
...@@ -3403,7 +3344,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3403,7 +3344,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3403 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });3344 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
3404 }3345 }
34053346
3406 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx });3347 const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx, .rbp });
3407 const addr_reg = regs[0];3348 const addr_reg = regs[0];
3408 const count_reg = regs[1];3349 const count_reg = regs[1];
3409 const tmp_reg = regs[2];3350 const tmp_reg = regs[2];
...@@ -3417,14 +3358,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3417,14 +3358,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3417 .reg1 = addr_reg.to64(),3358 .reg1 = addr_reg.to64(),
3418 .reg2 = .rbp,3359 .reg2 = .rbp,
3419 }).encode(),3360 }).encode(),
3420 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + abi_size)) },3361 .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, abi_size))) },
3421 });3362 });
34223363
3423 // TODO allow for abi_size to be u643364 // TODO allow for abi_size to be u64
3424 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });3365 try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) });
34253366
3426 return self.genInlineMemcpy(3367 return self.genInlineMemcpy(
3427 @bitCast(u32, -@intCast(i32, stack_offset + abi_size)),3368 -(stack_offset + @intCast(i32, abi_size)),
3428 .rbp,3369 .rbp,
3429 addr_reg.to64(),3370 addr_reg.to64(),
3430 count_reg.to64(),3371 count_reg.to64(),
...@@ -3436,7 +3377,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3436,7 +3377,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
34363377
3437fn genInlineMemcpy(3378fn genInlineMemcpy(
3438 self: *Self,3379 self: *Self,
3439 stack_offset: u32,3380 stack_offset: i32,
3440 stack_reg: Register,3381 stack_reg: Register,
3441 addr_reg: Register,3382 addr_reg: Register,
3442 count_reg: Register,3383 count_reg: Register,
...@@ -3494,7 +3435,7 @@ fn genInlineMemcpy(...@@ -3494,7 +3435,7 @@ fn genInlineMemcpy(
3494 .reg1 = stack_reg,3435 .reg1 = stack_reg,
3495 .reg2 = tmp_reg.to8(),3436 .reg2 = tmp_reg.to8(),
3496 }).encode(),3437 }).encode(),
3497 .data = .{ .imm = stack_offset },3438 .data = .{ .imm = @bitCast(u32, stack_offset) },
3498 });3439 });
34993440
3500 // add rcx, 13441 // add rcx, 1
...@@ -3535,14 +3476,14 @@ fn genInlineMemcpy(...@@ -3535,14 +3476,14 @@ fn genInlineMemcpy(
3535 try self.performReloc(loop_reloc);3476 try self.performReloc(loop_reloc);
3536}3477}
35373478
3538fn genInlineMemset(self: *Self, ty: Type, stack_offset: u32, value: MCValue) InnerError!void {3479fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void {
3539 try self.register_manager.getReg(.rax, null);3480 try self.register_manager.getReg(.rax, null);
3540 const abi_size = ty.abiSize(self.target.*);3481 const abi_size = ty.abiSize(self.target.*);
3541 const adj_off = stack_offset + abi_size;3482 const adj_off = stack_offset + @intCast(i32, abi_size);
3542 if (adj_off > 128) {3483 if (adj_off > 128) {
3543 return self.fail("TODO inline memset with large stack offset", .{});3484 return self.fail("TODO inline memset with large stack offset", .{});
3544 }3485 }
3545 const negative_offset = @bitCast(u32, -@intCast(i32, adj_off));3486 const negative_offset = @bitCast(u32, -adj_off);
35463487
3547 // We are actually counting `abi_size` bytes; however, we reuse the index register3488 // We are actually counting `abi_size` bytes; however, we reuse the index register
3548 // as both the counter and offset scaler, hence we need to subtract one from `abi_size`3489 // as both the counter and offset scaler, hence we need to subtract one from `abi_size`
...@@ -3633,7 +3574,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3633,7 +3574,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3633 const ptr_abi_size = ty.abiSize(self.target.*);3574 const ptr_abi_size = ty.abiSize(self.target.*);
3634 const elem_ty = ty.childType();3575 const elem_ty = ty.childType();
3635 const elem_abi_size = elem_ty.abiSize(self.target.*);3576 const elem_abi_size = elem_ty.abiSize(self.target.*);
3636 const off = unadjusted_off + elem_abi_size;3577 const off = unadjusted_off + @intCast(i32, elem_abi_size);
3637 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {3578 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
3638 return self.fail("stack offset too large", .{});3579 return self.fail("stack offset too large", .{});
3639 }3580 }
...@@ -3643,7 +3584,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3643,7 +3584,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3643 .reg1 = registerAlias(reg, @intCast(u32, ptr_abi_size)),3584 .reg1 = registerAlias(reg, @intCast(u32, ptr_abi_size)),
3644 .reg2 = .rbp,3585 .reg2 = .rbp,
3645 }).encode(),3586 }).encode(),
3646 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },3587 .data = .{ .imm = @bitCast(u32, -off) },
3647 });3588 });
3648 },3589 },
3649 .ptr_embedded_in_code => unreachable,3590 .ptr_embedded_in_code => unreachable,
...@@ -3830,7 +3771,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3830,7 +3771,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3830 },3771 },
3831 .stack_offset => |unadjusted_off| {3772 .stack_offset => |unadjusted_off| {
3832 const abi_size = ty.abiSize(self.target.*);3773 const abi_size = ty.abiSize(self.target.*);
3833 const off = unadjusted_off + abi_size;3774 const off = unadjusted_off + @intCast(i32, abi_size);
3834 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {3775 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
3835 return self.fail("stack offset too large", .{});3776 return self.fail("stack offset too large", .{});
3836 }3777 }
...@@ -3841,7 +3782,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -3841,7 +3782,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
3841 .reg2 = .rbp,3782 .reg2 = .rbp,
3842 .flags = 0b01,3783 .flags = 0b01,
3843 }).encode(),3784 }).encode(),
3844 .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) },3785 .data = .{ .imm = @bitCast(u32, -off) },
3845 });3786 });
3846 },3787 },
3847 }3788 }
...@@ -3866,7 +3807,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -3866,7 +3807,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
3866 const array_ty = ptr_ty.childType();3807 const array_ty = ptr_ty.childType();
3867 const array_len = array_ty.arrayLenIncludingSentinel();3808 const array_len = array_ty.arrayLenIncludingSentinel();
3868 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {3809 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
3869 const stack_offset = try self.allocMem(inst, 16, 16);3810 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
3870 try self.genSetStack(ptr_ty, stack_offset + 8, ptr);3811 try self.genSetStack(ptr_ty, stack_offset + 8, ptr);
3871 try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len });3812 try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len });
3872 break :blk .{ .stack_offset = stack_offset };3813 break :blk .{ .stack_offset = stack_offset };
...@@ -4247,6 +4188,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4247,6 +4188,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4247 var next_stack_offset: u32 = 0;4188 var next_stack_offset: u32 = 0;
4248 var count: usize = param_types.len;4189 var count: usize = param_types.len;
4249 while (count > 0) : (count -= 1) {4190 while (count > 0) : (count -= 1) {
4191 // for (param_types) |ty, i| {
4250 const i = count - 1;4192 const i = count - 1;
4251 const ty = param_types[i];4193 const ty = param_types[i];
4252 if (!ty.hasCodeGenBits()) {4194 if (!ty.hasCodeGenBits()) {
...@@ -4265,7 +4207,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4265,7 +4207,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4265 // such as ptr and len of slices as separate registers.4207 // such as ptr and len of slices as separate registers.
4266 // TODO: also we need to honor the C ABI for relevant types rather than passing on4208 // TODO: also we need to honor the C ABI for relevant types rather than passing on
4267 // the stack here.4209 // the stack here.
4268 result.args[i] = .{ .stack_offset = next_stack_offset };4210 result.args[i] = .{ .stack_offset = @intCast(i32, next_stack_offset) };
4269 next_stack_offset += param_size;4211 next_stack_offset += param_size;
4270 }4212 }
4271 }4213 }
src/arch/x86_64/Emit.zig+19-17
...@@ -251,23 +251,25 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -251,23 +251,25 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
251 }251 }
252}252}
253fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {253fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
254 const callee_preserved_regs = bits.callee_preserved_regs;254 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
255 const regs = emit.mir.instructions.items(.data)[inst].regs_to_push_or_pop;255 const payload = emit.mir.instructions.items(.data)[inst].payload;
256 if (tag == .push) {256 const data = emit.mir.extraData(Mir.RegsToPushOrPop, payload).data;
257 for (callee_preserved_regs) |reg, i| {257 const regs = data.regs;
258 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;258 var disp: u32 = data.disp + 8;
259 lowerToOEnc(.push, reg, emit.code) catch |err|259 for (bits.callee_preserved_regs) |reg, i| {
260 return emit.failWithLoweringError(err);260 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
261 }261 if (tag == .push) {
262 } else {262 lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
263 // pop in the reverse direction263 .disp = @bitCast(u32, -@intCast(i32, disp)),
264 var i = callee_preserved_regs.len;264 .base = ops.reg1,
265 while (i > 0) : (i -= 1) {265 }), reg.to64(), emit.code) catch |err| return emit.failWithLoweringError(err);
266 const reg = callee_preserved_regs[i - 1];266 } else {
267 if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue;267 lowerToRmEnc(.mov, reg.to64(), RegisterOrMemory.mem(.qword_ptr, .{
268 lowerToOEnc(.pop, reg, emit.code) catch |err|268 .disp = @bitCast(u32, -@intCast(i32, disp)),
269 return emit.failWithLoweringError(err);269 .base = ops.reg1,
270 }), emit.code) catch |err| return emit.failWithLoweringError(err);
270 }271 }
272 disp += 8;
271 }273 }
272}274}
273275
...@@ -1603,7 +1605,7 @@ fn lowerToRmEnc(...@@ -1603,7 +1605,7 @@ fn lowerToRmEnc(
1603 if (reg.size() != src_reg.size()) {1605 if (reg.size() != src_reg.size()) {
1604 return error.OperandSizeMismatch;1606 return error.OperandSizeMismatch;
1605 }1607 }
1606 const encoder = try Encoder.init(code, 3);1608 const encoder = try Encoder.init(code, 4);
1607 encoder.rex(.{1609 encoder.rex(.{
1608 .w = setRexWRegister(reg) or setRexWRegister(src_reg),1610 .w = setRexWRegister(reg) or setRexWRegister(src_reg),
1609 .r = reg.isExtended(),1611 .r = reg.isExtended(),
src/arch/x86_64/Mir.zig+5-2
...@@ -333,8 +333,6 @@ pub const Inst = struct {...@@ -333,8 +333,6 @@ pub const Inst = struct {
333 got_entry: u32,333 got_entry: u32,
334 /// Index into `extra`. Meaning of what can be found there is context-dependent.334 /// Index into `extra`. Meaning of what can be found there is context-dependent.
335 payload: u32,335 payload: u32,
336 /// A bitfield of which callee_preserved_regs to push
337 regs_to_push_or_pop: u32,
338 };336 };
339337
340 // Make sure we don't accidentally make instructions bigger than expected.338 // Make sure we don't accidentally make instructions bigger than expected.
...@@ -346,6 +344,11 @@ pub const Inst = struct {...@@ -346,6 +344,11 @@ pub const Inst = struct {
346 }344 }
347};345};
348346
347pub const RegsToPushOrPop = struct {
348 regs: u32,
349 disp: u32,
350};
351
349pub const ImmPair = struct {352pub const ImmPair = struct {
350 dest_off: u32,353 dest_off: u32,
351 operand: u32,354 operand: u32,
src/arch/x86_64/PrintMir.zig+21-19
...@@ -180,26 +180,28 @@ fn mirPushPop(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: a...@@ -180,26 +180,28 @@ fn mirPushPop(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: a
180 try w.writeByte('\n');180 try w.writeByte('\n');
181}181}
182fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {182fn mirPushPopRegsFromCalleePreservedRegs(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void {
183 const callee_preserved_regs = bits.callee_preserved_regs;183 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
184 // PUSH/POP reg184 const payload = print.mir.instructions.items(.data)[inst].payload;
185185 const data = print.mir.extraData(Mir.RegsToPushOrPop, payload).data;
186 const regs = print.mir.instructions.items(.data)[inst].regs_to_push_or_pop;186 const regs = data.regs;
187 if (regs == 0) return w.writeAll("push/pop no regs from callee_preserved_regs\n");187 var disp: u32 = data.disp + 8;
188 if (tag == .push) {188 if (regs == 0) return w.writeAll("no regs from callee_preserved_regs\n");
189 try w.writeAll("push ");189 for (bits.callee_preserved_regs) |reg, i| {
190 for (callee_preserved_regs) |reg, i| {190 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;
191 if ((regs >> @intCast(u5, i)) & 1 == 0) continue;191 if (tag == .push) {
192 try w.print("{s}, ", .{@tagName(reg)});192 try w.print("mov qword ptr [{s} + {d}], {s}", .{
193 }193 @tagName(ops.reg1),
194 } else {194 @bitCast(u32, -@intCast(i32, disp)),
195 // pop in the reverse direction195 @tagName(reg.to64()),
196 var i = callee_preserved_regs.len;196 });
197 try w.writeAll("pop ");197 } else {
198 while (i > 0) : (i -= 1) {198 try w.print("mov {s}, qword ptr [{s} + {d}]", .{
199 if ((regs >> @intCast(u5, i - 1)) & 1 == 0) continue;199 @tagName(reg.to64()),
200 const reg = callee_preserved_regs[i - 1];200 @tagName(ops.reg1),
201 try w.print("{s}, ", .{@tagName(reg)});201 @bitCast(u32, -@intCast(i32, disp)),
202 });
202 }203 }
204 disp += 8;
203 }205 }
204 try w.writeByte('\n');206 try w.writeByte('\n');
205}207}
src/link/Elf.zig+1-1
...@@ -2118,7 +2118,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl...@@ -2118,7 +2118,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl
2118 const sym = self.local_symbols.items[big_block.local_sym_index];2118 const sym = self.local_symbols.items[big_block.local_sym_index];
2119 const capacity = big_block.capacity(self.*);2119 const capacity = big_block.capacity(self.*);
2120 const ideal_capacity = padToIdeal(capacity);2120 const ideal_capacity = padToIdeal(capacity);
2121 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;2121 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;
2122 const capacity_end_vaddr = sym.st_value + capacity;2122 const capacity_end_vaddr = sym.st_value + capacity;
2123 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;2123 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;
2124 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);2124 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
src/link/MachO.zig+1-1
...@@ -5064,7 +5064,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m...@@ -5064,7 +5064,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
5064 const sym = self.locals.items[big_atom.local_sym_index];5064 const sym = self.locals.items[big_atom.local_sym_index];
5065 const capacity = big_atom.capacity(self.*);5065 const capacity = big_atom.capacity(self.*);
5066 const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;5066 const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;
5067 const ideal_capacity_end_vaddr = sym.n_value + ideal_capacity;5067 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
5068 const capacity_end_vaddr = sym.n_value + capacity;5068 const capacity_end_vaddr = sym.n_value + capacity;
5069 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;5069 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
5070 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);5070 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);