authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-20 13:51:13+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-22 21:56:34+01:00
log630da643c664591846c295d75277475ca1801d75
tree636bee53f5a374f2970c6d3022bfa3e5ff9fcb5b
parent478f7700533097b92820dafd3003af6320fd3c85

x64: pass pointer to stack for return value in .rdi register


1 files changed, 82 insertions(+), 208 deletions(-)

src/arch/x86_64/CodeGen.zig+82-208
...@@ -870,7 +870,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -870,7 +870,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
870 assert(reg.to64() == reg_mcv.register.to64());870 assert(reg.to64() == reg_mcv.register.to64());
871 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];871 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
872 try branch.inst_table.put(self.gpa, inst, stack_mcv);872 try branch.inst_table.put(self.gpa, inst, stack_mcv);
873 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);873 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, .rbp, reg_mcv);
874}874}
875875
876/// Copies a value to a register without tracking the register. The register is not considered876/// Copies a value to a register without tracking the register. The register is not considered
...@@ -1146,8 +1146,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1146,8 +1146,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1146 const len_ty = self.air.typeOf(bin_op.rhs);1146 const len_ty = self.air.typeOf(bin_op.rhs);
11471147
1148 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));1148 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
1149 try self.genSetStack(ptr_ty, stack_offset, ptr);1149 try self.genSetStack(ptr_ty, stack_offset, .rbp, ptr);
1150 try self.genSetStack(len_ty, stack_offset - 8, len);1150 try self.genSetStack(len_ty, stack_offset - 8, .rbp, len);
1151 const result = MCValue{ .stack_offset = stack_offset };1151 const result = MCValue{ .stack_offset = stack_offset };
11521152
1153 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1153 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -1856,7 +1856,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1856,7 +1856,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1856 @intCast(u32, array_ty.abiSize(self.target.*)),1856 @intCast(u32, array_ty.abiSize(self.target.*)),
1857 array_ty.abiAlignment(self.target.*),1857 array_ty.abiAlignment(self.target.*),
1858 ));1858 ));
1859 try self.genSetStack(array_ty, off, array);1859 try self.genSetStack(array_ty, off, .rbp, array);
1860 break :inner off;1860 break :inner off;
1861 },1861 },
1862 .stack_offset => |off| {1862 .stack_offset => |off| {
...@@ -2089,10 +2089,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2089,10 +2089,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2089 if (abi_size <= 8) {2089 if (abi_size <= 8) {
2090 const tmp_reg = try self.register_manager.allocReg(null);2090 const tmp_reg = try self.register_manager.allocReg(null);
2091 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);2091 try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
2092 return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });2092 return self.genSetStack(elem_ty, off, .rbp, MCValue{ .register = tmp_reg });
2093 }2093 }
20942094
2095 try self.genInlineMemcpy(off, .rbp, elem_ty, ptr);2095 try self.genInlineMemcpy(off, elem_ty, ptr, .{});
2096 },2096 },
2097 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),2097 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
2098 }2098 }
...@@ -2187,7 +2187,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2187,7 +2187,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2187 try self.store(.{ .register = reg }, value, ptr_ty, value_ty);2187 try self.store(.{ .register = reg }, value, ptr_ty, value_ty);
2188 },2188 },
2189 .ptr_stack_offset => |off| {2189 .ptr_stack_offset => |off| {
2190 try self.genSetStack(value_ty, off, value);2190 try self.genSetStack(value_ty, off, .rbp, value);
2191 },2191 },
2192 .ptr_embedded_in_code => |off| {2192 .ptr_embedded_in_code => |off| {
2193 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);2193 try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value);
...@@ -2661,7 +2661,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC...@@ -2661,7 +2661,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
26612661
2662 switch (src_mcv) {2662 switch (src_mcv) {
2663 .none => unreachable,2663 .none => unreachable,
2664 .undef => return self.genSetStack(dst_ty, off, .undef),2664 .undef => return self.genSetStack(dst_ty, off, .rbp, .undef),
2665 .dead, .unreach => unreachable,2665 .dead, .unreach => unreachable,
2666 .ptr_stack_offset => unreachable,2666 .ptr_stack_offset => unreachable,
2667 .ptr_embedded_in_code => unreachable,2667 .ptr_embedded_in_code => unreachable,
...@@ -2804,7 +2804,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !...@@ -2804,7 +2804,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
2804 .stack_offset => |off| {2804 .stack_offset => |off| {
2805 switch (src_mcv) {2805 switch (src_mcv) {
2806 .none => unreachable,2806 .none => unreachable,
2807 .undef => return self.genSetStack(dst_ty, off, .undef),2807 .undef => return self.genSetStack(dst_ty, off, .rbp, .undef),
2808 .dead, .unreach => unreachable,2808 .dead, .unreach => unreachable,
2809 .ptr_stack_offset => unreachable,2809 .ptr_stack_offset => unreachable,
2810 .ptr_embedded_in_code => unreachable,2810 .ptr_embedded_in_code => unreachable,
...@@ -2822,7 +2822,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !...@@ -2822,7 +2822,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
2822 .data = undefined,2822 .data = undefined,
2823 });2823 });
2824 // copy dst_reg back out2824 // copy dst_reg back out
2825 return self.genSetStack(dst_ty, off, MCValue{ .register = dst_reg });2825 return self.genSetStack(dst_ty, off, .rbp, MCValue{ .register = dst_reg });
2826 },2826 },
2827 .immediate => |imm| {2827 .immediate => |imm| {
2828 _ = imm;2828 _ = imm;
...@@ -2920,6 +2920,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2920,6 +2920,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2920 var info = try self.resolveCallingConventionValues(fn_ty);2920 var info = try self.resolveCallingConventionValues(fn_ty);
2921 defer info.deinit(self);2921 defer info.deinit(self);
29222922
2923 if (info.return_value == .stack_offset) {
2924 const ret_ty = fn_ty.fnReturnType();
2925 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
2926 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
2927 const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align));
2928
2929 try self.register_manager.getReg(.rdi, inst);
2930 try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset });
2931
2932 info.return_value.stack_offset = stack_offset;
2933 }
2934
2923 for (args) |arg, arg_i| {2935 for (args) |arg, arg_i| {
2924 const mc_arg = info.args[arg_i];2936 const mc_arg = info.args[arg_i];
2925 const arg_ty = self.air.typeOf(arg);2937 const arg_ty = self.air.typeOf(arg);
...@@ -3112,15 +3124,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -3112,15 +3124,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
3112 );3124 );
3113 }3125 }
3114 },3126 },
3115 .stack_offset => {
3116 // TODO what a waste...
3117 const ret_ty = fn_ty.fnReturnType();
3118 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3119 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3120 const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align));
3121 try self.genInlineMemcpyTODO(stack_offset, .rbp, ret_ty, info.return_value);
3122 break :result MCValue{ .stack_offset = stack_offset };
3123 },
3124 else => {},3127 else => {},
3125 }3128 }
3126 break :result info.return_value;3129 break :result info.return_value;
...@@ -3142,17 +3145,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -3142,17 +3145,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
31423145
3143fn ret(self: *Self, mcv: MCValue) !void {3146fn ret(self: *Self, mcv: MCValue) !void {
3144 const ret_ty = self.fn_type.fnReturnType();3147 const ret_ty = self.fn_type.fnReturnType();
3145 const ret_mcv = blk: {3148 switch (self.ret_mcv) {
3146 switch (self.ret_mcv) {3149 .stack_offset => {
3147 .stack_offset => |off| {3150 try self.genSetStack(ret_ty, 0, .rdi, mcv);
3148 // Adjust the stack offset3151 },
3149 const offset = @intCast(i32, self.max_end_stack) - off + 16;3152 else => {
3150 break :blk MCValue{ .stack_offset = -offset };3153 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
3151 },3154 },
3152 else => break :blk self.ret_mcv,3155 }
3153 }
3154 };
3155 try self.setRegOrMem(ret_ty, ret_mcv, mcv);
3156 // TODO when implementing defer, this will need to jump to the appropriate defer expression.3156 // TODO when implementing defer, this will need to jump to the appropriate defer expression.
3157 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction3157 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
3158 // which is available if the jump is 127 bytes or less forward.3158 // which is available if the jump is 127 bytes or less forward.
...@@ -3879,7 +3879,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {...@@ -3879,7 +3879,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
3879 .none => return,3879 .none => return,
3880 .immediate => unreachable,3880 .immediate => unreachable,
3881 .register => |reg| return self.genSetReg(ty, reg, val),3881 .register => |reg| return self.genSetReg(ty, reg, val),
3882 .stack_offset => |off| return self.genSetStack(ty, off, val),3882 .stack_offset => |off| return self.genSetStack(ty, off, .rbp, val),
3883 .memory => {3883 .memory => {
3884 return self.fail("TODO implement setRegOrMem for memory", .{});3884 return self.fail("TODO implement setRegOrMem for memory", .{});
3885 },3885 },
...@@ -3955,7 +3955,10 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3955,7 +3955,10 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3955 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });3955 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3956 }3956 }
39573957
3958 try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv);3958 try self.genInlineMemcpy(stack_offset, ty, mcv, .{
3959 .source_stack_base = .rbp,
3960 .dest_stack_base = .rsp,
3961 });
3959 },3962 },
3960 .register => |reg| {3963 .register => |reg| {
3961 _ = try self.addInst(.{3964 _ = try self.addInst(.{
...@@ -3978,12 +3981,15 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE...@@ -3978,12 +3981,15 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
3978 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });3981 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3979 }3982 }
39803983
3981 try self.genInlineMemcpy(stack_offset, .rsp, ty, mcv);3984 try self.genInlineMemcpy(stack_offset, ty, mcv, .{
3985 .source_stack_base = .rbp,
3986 .dest_stack_base = .rsp,
3987 });
3982 },3988 },
3983 }3989 }
3984}3990}
39853991
3986fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void {3992fn genSetStack(self: *Self, ty: Type, stack_offset: i32, base_reg: Register, mcv: MCValue) InnerError!void {
3987 const abi_size = ty.abiSize(self.target.*);3993 const abi_size = ty.abiSize(self.target.*);
3988 switch (mcv) {3994 switch (mcv) {
3989 .dead => unreachable,3995 .dead => unreachable,
...@@ -3994,18 +4000,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -3994,18 +4000,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
3994 return; // The already existing value will do just fine.4000 return; // The already existing value will do just fine.
3995 // TODO Upgrade this to a memset call when we have that available.4001 // TODO Upgrade this to a memset call when we have that available.
3996 switch (ty.abiSize(self.target.*)) {4002 switch (ty.abiSize(self.target.*)) {
3997 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),4003 1 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaa }),
3998 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),4004 2 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaa }),
3999 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),4005 4 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaaaaaa }),
4000 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),4006 8 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
4001 else => return self.genInlineMemset(stack_offset, .rbp, ty, .{ .immediate = 0xaa }),4007 else => return self.genInlineMemset(stack_offset, base_reg, ty, .{ .immediate = 0xaa }),
4002 }4008 }
4003 },4009 },
4004 .compare_flags_unsigned,4010 .compare_flags_unsigned,
4005 .compare_flags_signed,4011 .compare_flags_signed,
4006 => {4012 => {
4007 const reg = try self.copyToTmpRegister(ty, mcv);4013 const reg = try self.copyToTmpRegister(ty, mcv);
4008 return self.genSetStack(ty, stack_offset, .{ .register = reg });4014 return self.genSetStack(ty, stack_offset, base_reg, .{ .register = reg });
4009 },4015 },
4010 .immediate => |x_big| {4016 .immediate => |x_big| {
4011 switch (abi_size) {4017 switch (abi_size) {
...@@ -4017,7 +4023,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -4017,7 +4023,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
4017 _ = try self.addInst(.{4023 _ = try self.addInst(.{
4018 .tag = .mov_mem_imm,4024 .tag = .mov_mem_imm,
4019 .ops = (Mir.Ops{4025 .ops = (Mir.Ops{
4020 .reg1 = .rbp,4026 .reg1 = base_reg,
4021 .flags = switch (abi_size) {4027 .flags = switch (abi_size) {
4022 1 => 0b00,4028 1 => 0b00,
4023 2 => 0b01,4029 2 => 0b01,
...@@ -4039,7 +4045,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -4039,7 +4045,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
4039 _ = try self.addInst(.{4045 _ = try self.addInst(.{
4040 .tag = .mov_mem_imm,4046 .tag = .mov_mem_imm,
4041 .ops = (Mir.Ops{4047 .ops = (Mir.Ops{
4042 .reg1 = .rbp,4048 .reg1 = base_reg,
4043 .flags = 0b10,4049 .flags = 0b10,
4044 }).encode(),4050 }).encode(),
4045 .data = .{ .payload = payload },4051 .data = .{ .payload = payload },
...@@ -4053,7 +4059,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -4053,7 +4059,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
4053 _ = try self.addInst(.{4059 _ = try self.addInst(.{
4054 .tag = .mov_mem_imm,4060 .tag = .mov_mem_imm,
4055 .ops = (Mir.Ops{4061 .ops = (Mir.Ops{
4056 .reg1 = .rbp,4062 .reg1 = base_reg,
4057 .flags = 0b10,4063 .flags = 0b10,
4058 }).encode(),4064 }).encode(),
4059 .data = .{ .payload = payload },4065 .data = .{ .payload = payload },
...@@ -4085,7 +4091,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -4085,7 +4091,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
4085 _ = try self.addInst(.{4091 _ = try self.addInst(.{
4086 .tag = .mov,4092 .tag = .mov,
4087 .ops = (Mir.Ops{4093 .ops = (Mir.Ops{
4088 .reg1 = .rbp,4094 .reg1 = base_reg,
4089 .reg2 = registerAlias(tmp_reg, closest_power_of_two),4095 .reg2 = registerAlias(tmp_reg, closest_power_of_two),
4090 .flags = 0b10,4096 .flags = 0b10,
4091 }).encode(),4097 }).encode(),
...@@ -4110,7 +4116,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -4110,7 +4116,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
4110 _ = try self.addInst(.{4116 _ = try self.addInst(.{
4111 .tag = .mov,4117 .tag = .mov,
4112 .ops = (Mir.Ops{4118 .ops = (Mir.Ops{
4113 .reg1 = .rbp,4119 .reg1 = base_reg,
4114 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),4120 .reg2 = registerAlias(reg, @intCast(u32, abi_size)),
4115 .flags = 0b10,4121 .flags = 0b10,
4116 }).encode(),4122 }).encode(),
...@@ -4125,14 +4131,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -4125,14 +4131,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
4125 => {4131 => {
4126 if (abi_size <= 8) {4132 if (abi_size <= 8) {
4127 const reg = try self.copyToTmpRegister(ty, mcv);4133 const reg = try self.copyToTmpRegister(ty, mcv);
4128 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });4134 return self.genSetStack(ty, stack_offset, base_reg, MCValue{ .register = reg });
4129 }4135 }
41304136
4131 try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv);4137 try self.genInlineMemcpy(stack_offset, ty, mcv, .{
4138 .source_stack_base = base_reg,
4139 .dest_stack_base = base_reg,
4140 });
4132 },4141 },
4133 .ptr_stack_offset => {4142 .ptr_stack_offset => {
4134 const reg = try self.copyToTmpRegister(ty, mcv);4143 const reg = try self.copyToTmpRegister(ty, mcv);
4135 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });4144 return self.genSetStack(ty, stack_offset, base_reg, MCValue{ .register = reg });
4136 },4145 },
4137 .stack_offset => |off| {4146 .stack_offset => |off| {
4138 if (stack_offset == off) {4147 if (stack_offset == off) {
...@@ -4142,171 +4151,36 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro...@@ -4142,171 +4151,36 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
41424151
4143 if (abi_size <= 8) {4152 if (abi_size <= 8) {
4144 const reg = try self.copyToTmpRegister(ty, mcv);4153 const reg = try self.copyToTmpRegister(ty, mcv);
4145 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });4154 return self.genSetStack(ty, stack_offset, base_reg, MCValue{ .register = reg });
4146 }4155 }
41474156
4148 try self.genInlineMemcpy(stack_offset, .rbp, ty, mcv);4157 try self.genInlineMemcpy(stack_offset, ty, mcv, .{
4158 .source_stack_base = base_reg,
4159 .dest_stack_base = base_reg,
4160 });
4149 },4161 },
4150 }4162 }
4151}4163}
41524164
4153fn genInlineMemcpyTODO(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void {4165const InlineMemcpyOpts = struct {
4166 source_stack_base: ?Register = null,
4167 dest_stack_base: ?Register = null,
4168};
4169
4170fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: InlineMemcpyOpts) InnerError!void {
4154 const abi_size = ty.abiSize(self.target.*);4171 const abi_size = ty.abiSize(self.target.*);
41554172
4156 try self.register_manager.getReg(.rax, null);4173 try self.register_manager.getReg(.rax, null);
4157 try self.register_manager.getReg(.rcx, null);4174 try self.register_manager.getReg(.rcx, null);
41584175
4159 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });4176 self.register_manager.freezeRegs(&.{ .rax, .rcx });
4160 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });4177 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
4161
4162 const addr_reg: Register = blk: {
4163 switch (val) {
4164 .memory,
4165 .direct_load,
4166 .got_load,
4167 => {
4168 break :blk try self.loadMemPtrIntoRegister(Type.usize, val);
4169 },
4170 .stack_offset => |off| {
4171 const addr_reg = (try self.register_manager.allocReg(null)).to64();
4172 _ = try self.addInst(.{
4173 .tag = .lea,
4174 .ops = (Mir.Ops{
4175 .reg1 = addr_reg,
4176 .reg2 = .rsp,
4177 }).encode(),
4178 .data = .{ .imm = @bitCast(u32, -off) },
4179 });
4180 break :blk addr_reg;
4181 },
4182 .register => |reg| {
4183 const addr_reg = try self.register_manager.allocReg(null);
4184 _ = try self.addInst(.{
4185 .tag = .mov,
4186 .ops = (Mir.Ops{
4187 .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)),
4188 .reg2 = reg,
4189 }).encode(),
4190 .data = undefined,
4191 });
4192 break :blk addr_reg.to64();
4193 },
4194 else => {
4195 return self.fail("TODO implement memcpy for setting stack from {}", .{val});
4196 },
4197 }
4198 };
4199
4200 self.register_manager.freezeRegs(&.{addr_reg});
4201 defer self.register_manager.unfreezeRegs(&.{addr_reg});
4202
4203 const regs = try self.register_manager.allocRegs(2, .{ null, null });
4204 const count_reg = regs[0].to64();
4205 const tmp_reg = regs[1].to8();
4206
4207 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
4208
4209 // mov rcx, 0
4210 _ = try self.addInst(.{
4211 .tag = .mov,
4212 .ops = (Mir.Ops{
4213 .reg1 = .rcx,
4214 }).encode(),
4215 .data = .{ .imm = 0 },
4216 });
4217
4218 // mov rax, 0
4219 _ = try self.addInst(.{
4220 .tag = .mov,
4221 .ops = (Mir.Ops{
4222 .reg1 = .rax,
4223 }).encode(),
4224 .data = .{ .imm = 0 },
4225 });
4226
4227 // loop:
4228 // cmp count, 0
4229 const loop_start = try self.addInst(.{
4230 .tag = .cmp,
4231 .ops = (Mir.Ops{
4232 .reg1 = count_reg,
4233 }).encode(),
4234 .data = .{ .imm = 0 },
4235 });
4236
4237 // je end
4238 const loop_reloc = try self.addInst(.{
4239 .tag = .cond_jmp_eq_ne,
4240 .ops = (Mir.Ops{ .flags = 0b01 }).encode(),
4241 .data = .{ .inst = undefined },
4242 });
4243
4244 // mov tmp, [addr + rcx]
4245 _ = try self.addInst(.{
4246 .tag = .mov_scale_src,
4247 .ops = (Mir.Ops{
4248 .reg1 = tmp_reg.to8(),
4249 .reg2 = addr_reg,
4250 }).encode(),
4251 .data = .{ .imm = 0 },
4252 });
4253
4254 // mov [stack_offset + rax], tmp
4255 _ = try self.addInst(.{
4256 .tag = .mov_scale_dst,
4257 .ops = (Mir.Ops{
4258 .reg1 = stack_reg,
4259 .reg2 = tmp_reg.to8(),
4260 }).encode(),
4261 .data = .{ .imm = @bitCast(u32, -stack_offset) },
4262 });
4263
4264 // add rcx, 1
4265 _ = try self.addInst(.{
4266 .tag = .add,
4267 .ops = (Mir.Ops{
4268 .reg1 = .rcx,
4269 }).encode(),
4270 .data = .{ .imm = 1 },
4271 });
4272
4273 // add rax, 1
4274 _ = try self.addInst(.{
4275 .tag = .add,
4276 .ops = (Mir.Ops{
4277 .reg1 = .rax,
4278 }).encode(),
4279 .data = .{ .imm = 1 },
4280 });
4281
4282 // sub count, 1
4283 _ = try self.addInst(.{
4284 .tag = .sub,
4285 .ops = (Mir.Ops{
4286 .reg1 = count_reg,
4287 }).encode(),
4288 .data = .{ .imm = 1 },
4289 });
4290
4291 // jmp loop
4292 _ = try self.addInst(.{
4293 .tag = .jmp,
4294 .ops = (Mir.Ops{ .flags = 0b00 }).encode(),
4295 .data = .{ .inst = loop_start },
4296 });
4297
4298 // end:
4299 try self.performReloc(loop_reloc);
4300}
4301
4302fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void {
4303 const abi_size = ty.abiSize(self.target.*);
43044178
4305 try self.register_manager.getReg(.rax, null);4179 if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg});
4306 try self.register_manager.getReg(.rcx, null);4180 defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg});
43074181
4308 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });4182 if (opts.dest_stack_base) |reg| self.register_manager.freezeRegs(&.{reg});
4309 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });4183 defer if (opts.dest_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg});
43104184
4311 const addr_reg: Register = blk: {4185 const addr_reg: Register = blk: {
4312 switch (val) {4186 switch (val) {
...@@ -4322,7 +4196,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type...@@ -4322,7 +4196,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type
4322 .tag = .lea,4196 .tag = .lea,
4323 .ops = (Mir.Ops{4197 .ops = (Mir.Ops{
4324 .reg1 = addr_reg,4198 .reg1 = addr_reg,
4325 .reg2 = .rbp,4199 .reg2 = opts.source_stack_base orelse .rbp,
4326 }).encode(),4200 }).encode(),
4327 .data = .{ .imm = @bitCast(u32, -off) },4201 .data = .{ .imm = @bitCast(u32, -off) },
4328 });4202 });
...@@ -4404,7 +4278,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type...@@ -4404,7 +4278,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type
4404 _ = try self.addInst(.{4278 _ = try self.addInst(.{
4405 .tag = .mov_scale_dst,4279 .tag = .mov_scale_dst,
4406 .ops = (Mir.Ops{4280 .ops = (Mir.Ops{
4407 .reg1 = stack_reg,4281 .reg1 = opts.dest_stack_base orelse .rbp,
4408 .reg2 = tmp_reg.to8(),4282 .reg2 = tmp_reg.to8(),
4409 }).encode(),4283 }).encode(),
4410 .data = .{ .imm = @bitCast(u32, -stack_offset) },4284 .data = .{ .imm = @bitCast(u32, -stack_offset) },
...@@ -4850,8 +4724,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -4850,8 +4724,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void {
4850 const array_len = array_ty.arrayLenIncludingSentinel();4724 const array_len = array_ty.arrayLenIncludingSentinel();
4851 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {4725 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
4852 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));4726 const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16));
4853 try self.genSetStack(ptr_ty, stack_offset, ptr);4727 try self.genSetStack(ptr_ty, stack_offset, .rbp, ptr);
4854 try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len });4728 try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .rbp, .{ .immediate = array_len });
4855 break :blk .{ .stack_offset = stack_offset };4729 break :blk .{ .stack_offset = stack_offset };
4856 };4730 };
4857 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4731 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -5249,10 +5123,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5249,10 +5123,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5249 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);5123 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);
5250 result.return_value = .{ .register = aliased_reg };5124 result.return_value = .{ .register = aliased_reg };
5251 } else {5125 } else {
5252 // TODO save the stack location in `.rdi` for C ABI compatible extern calls.5126 // We simply make the return MCValue a stack offset. However, the actual value
5253 const ret_ty_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));5127 // for the offset will be populated later. We will also push the stack offset
5254 const offset = mem.alignForwardGeneric(u32, ret_ty_size, ret_ty_align);5128 // value into .rdi register when we resolve the offset.
5255 result.return_value = .{ .stack_offset = @intCast(i32, offset) };5129 result.return_value = .{ .stack_offset = 0 };
5256 }5130 }
5257 }5131 }
52585132