| ... | ... | @@ -870,7 +870,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 870 | 870 | assert(reg.to64() == reg_mcv.register.to64()); |
| 871 | 871 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 872 | 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 | } |
| 875 | 875 | |
| 876 | 876 | /// 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 | 1146 | const len_ty = self.air.typeOf(bin_op.rhs); |
| 1147 | 1147 | |
| 1148 | 1148 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 1149 | | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1150 | | try self.genSetStack(len_ty, stack_offset - 8, len); |
| 1149 | try self.genSetStack(ptr_ty, stack_offset, .rbp, ptr); |
| 1150 | try self.genSetStack(len_ty, stack_offset - 8, .rbp, len); |
| 1151 | 1151 | const result = MCValue{ .stack_offset = stack_offset }; |
| 1152 | 1152 | |
| 1153 | 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 | 1856 | @intCast(u32, array_ty.abiSize(self.target.*)), |
| 1857 | 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 | 1860 | break :inner off; |
| 1861 | 1861 | }, |
| 1862 | 1862 | .stack_offset => |off| { |
| ... | ... | @@ -2089,10 +2089,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2089 | 2089 | if (abi_size <= 8) { |
| 2090 | 2090 | const tmp_reg = try self.register_manager.allocReg(null); |
| 2091 | 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 | } |
| 2094 | 2094 | |
| 2095 | | try self.genInlineMemcpy(off, .rbp, elem_ty, ptr); |
| 2095 | try self.genInlineMemcpy(off, elem_ty, ptr, .{}); |
| 2096 | 2096 | }, |
| 2097 | 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 | 2187 | try self.store(.{ .register = reg }, value, ptr_ty, value_ty); |
| 2188 | 2188 | }, |
| 2189 | 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 | 2192 | .ptr_embedded_in_code => |off| { |
| 2193 | 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 | 2661 | |
| 2662 | 2662 | switch (src_mcv) { |
| 2663 | 2663 | .none => unreachable, |
| 2664 | | .undef => return self.genSetStack(dst_ty, off, .undef), |
| 2664 | .undef => return self.genSetStack(dst_ty, off, .rbp, .undef), |
| 2665 | 2665 | .dead, .unreach => unreachable, |
| 2666 | 2666 | .ptr_stack_offset => unreachable, |
| 2667 | 2667 | .ptr_embedded_in_code => unreachable, |
| ... | ... | @@ -2804,7 +2804,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2804 | 2804 | .stack_offset => |off| { |
| 2805 | 2805 | switch (src_mcv) { |
| 2806 | 2806 | .none => unreachable, |
| 2807 | | .undef => return self.genSetStack(dst_ty, off, .undef), |
| 2807 | .undef => return self.genSetStack(dst_ty, off, .rbp, .undef), |
| 2808 | 2808 | .dead, .unreach => unreachable, |
| 2809 | 2809 | .ptr_stack_offset => unreachable, |
| 2810 | 2810 | .ptr_embedded_in_code => unreachable, |
| ... | ... | @@ -2822,7 +2822,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2822 | 2822 | .data = undefined, |
| 2823 | 2823 | }); |
| 2824 | 2824 | // 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 | 2827 | .immediate => |imm| { |
| 2828 | 2828 | _ = imm; |
| ... | ... | @@ -2920,6 +2920,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2920 | 2920 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 2921 | 2921 | defer info.deinit(self); |
| 2922 | 2922 | |
| 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 | 2935 | for (args) |arg, arg_i| { |
| 2924 | 2936 | const mc_arg = info.args[arg_i]; |
| 2925 | 2937 | const arg_ty = self.air.typeOf(arg); |
| ... | ... | @@ -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 | 3127 | else => {}, |
| 3125 | 3128 | } |
| 3126 | 3129 | break :result info.return_value; |
| ... | ... | @@ -3142,17 +3145,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 3142 | 3145 | |
| 3143 | 3146 | fn ret(self: *Self, mcv: MCValue) !void { |
| 3144 | 3147 | const ret_ty = self.fn_type.fnReturnType(); |
| 3145 | | const ret_mcv = blk: { |
| 3146 | | switch (self.ret_mcv) { |
| 3147 | | .stack_offset => |off| { |
| 3148 | | // Adjust the stack offset |
| 3149 | | const offset = @intCast(i32, self.max_end_stack) - off + 16; |
| 3150 | | break :blk MCValue{ .stack_offset = -offset }; |
| 3151 | | }, |
| 3152 | | else => break :blk self.ret_mcv, |
| 3153 | | } |
| 3154 | | }; |
| 3155 | | try self.setRegOrMem(ret_ty, ret_mcv, mcv); |
| 3148 | switch (self.ret_mcv) { |
| 3149 | .stack_offset => { |
| 3150 | try self.genSetStack(ret_ty, 0, .rdi, mcv); |
| 3151 | }, |
| 3152 | else => { |
| 3153 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 3154 | }, |
| 3155 | } |
| 3156 | 3156 | // TODO when implementing defer, this will need to jump to the appropriate defer expression. |
| 3157 | 3157 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction |
| 3158 | 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 | 3879 | .none => return, |
| 3880 | 3880 | .immediate => unreachable, |
| 3881 | 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 | 3883 | .memory => { |
| 3884 | 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 | 3955 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3956 | 3956 | } |
| 3957 | 3957 | |
| 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 | 3963 | .register => |reg| { |
| 3961 | 3964 | _ = try self.addInst(.{ |
| ... | ... | @@ -3978,12 +3981,15 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3978 | 3981 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3979 | 3982 | } |
| 3980 | 3983 | |
| 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 | } |
| 3985 | 3991 | |
| 3986 | | fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void { |
| 3992 | fn genSetStack(self: *Self, ty: Type, stack_offset: i32, base_reg: Register, mcv: MCValue) InnerError!void { |
| 3987 | 3993 | const abi_size = ty.abiSize(self.target.*); |
| 3988 | 3994 | switch (mcv) { |
| 3989 | 3995 | .dead => unreachable, |
| ... | ... | @@ -3994,18 +4000,18 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3994 | 4000 | return; // The already existing value will do just fine. |
| 3995 | 4001 | // TODO Upgrade this to a memset call when we have that available. |
| 3996 | 4002 | switch (ty.abiSize(self.target.*)) { |
| 3997 | | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 3998 | | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 3999 | | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| 4000 | | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 4001 | | else => return self.genInlineMemset(stack_offset, .rbp, ty, .{ .immediate = 0xaa }), |
| 4003 | 1 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaa }), |
| 4004 | 2 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaa }), |
| 4005 | 4 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaaaaaa }), |
| 4006 | 8 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 4007 | else => return self.genInlineMemset(stack_offset, base_reg, ty, .{ .immediate = 0xaa }), |
| 4002 | 4008 | } |
| 4003 | 4009 | }, |
| 4004 | 4010 | .compare_flags_unsigned, |
| 4005 | 4011 | .compare_flags_signed, |
| 4006 | 4012 | => { |
| 4007 | 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 | 4016 | .immediate => |x_big| { |
| 4011 | 4017 | switch (abi_size) { |
| ... | ... | @@ -4017,7 +4023,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 4017 | 4023 | _ = try self.addInst(.{ |
| 4018 | 4024 | .tag = .mov_mem_imm, |
| 4019 | 4025 | .ops = (Mir.Ops{ |
| 4020 | | .reg1 = .rbp, |
| 4026 | .reg1 = base_reg, |
| 4021 | 4027 | .flags = switch (abi_size) { |
| 4022 | 4028 | 1 => 0b00, |
| 4023 | 4029 | 2 => 0b01, |
| ... | ... | @@ -4039,7 +4045,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 4039 | 4045 | _ = try self.addInst(.{ |
| 4040 | 4046 | .tag = .mov_mem_imm, |
| 4041 | 4047 | .ops = (Mir.Ops{ |
| 4042 | | .reg1 = .rbp, |
| 4048 | .reg1 = base_reg, |
| 4043 | 4049 | .flags = 0b10, |
| 4044 | 4050 | }).encode(), |
| 4045 | 4051 | .data = .{ .payload = payload }, |
| ... | ... | @@ -4053,7 +4059,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 4053 | 4059 | _ = try self.addInst(.{ |
| 4054 | 4060 | .tag = .mov_mem_imm, |
| 4055 | 4061 | .ops = (Mir.Ops{ |
| 4056 | | .reg1 = .rbp, |
| 4062 | .reg1 = base_reg, |
| 4057 | 4063 | .flags = 0b10, |
| 4058 | 4064 | }).encode(), |
| 4059 | 4065 | .data = .{ .payload = payload }, |
| ... | ... | @@ -4085,7 +4091,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 4085 | 4091 | _ = try self.addInst(.{ |
| 4086 | 4092 | .tag = .mov, |
| 4087 | 4093 | .ops = (Mir.Ops{ |
| 4088 | | .reg1 = .rbp, |
| 4094 | .reg1 = base_reg, |
| 4089 | 4095 | .reg2 = registerAlias(tmp_reg, closest_power_of_two), |
| 4090 | 4096 | .flags = 0b10, |
| 4091 | 4097 | }).encode(), |
| ... | ... | @@ -4110,7 +4116,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 4110 | 4116 | _ = try self.addInst(.{ |
| 4111 | 4117 | .tag = .mov, |
| 4112 | 4118 | .ops = (Mir.Ops{ |
| 4113 | | .reg1 = .rbp, |
| 4119 | .reg1 = base_reg, |
| 4114 | 4120 | .reg2 = registerAlias(reg, @intCast(u32, abi_size)), |
| 4115 | 4121 | .flags = 0b10, |
| 4116 | 4122 | }).encode(), |
| ... | ... | @@ -4125,14 +4131,17 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 4125 | 4131 | => { |
| 4126 | 4132 | if (abi_size <= 8) { |
| 4127 | 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 | } |
| 4130 | 4136 | |
| 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 | 4142 | .ptr_stack_offset => { |
| 4134 | 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 | 4146 | .stack_offset => |off| { |
| 4138 | 4147 | if (stack_offset == off) { |
| ... | ... | @@ -4142,171 +4151,36 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 4142 | 4151 | |
| 4143 | 4152 | if (abi_size <= 8) { |
| 4144 | 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 | } |
| 4147 | 4156 | |
| 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 | } |
| 4152 | 4164 | |
| 4153 | | fn genInlineMemcpyTODO(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void { |
| 4165 | const InlineMemcpyOpts = struct { |
| 4166 | source_stack_base: ?Register = null, |
| 4167 | dest_stack_base: ?Register = null, |
| 4168 | }; |
| 4169 | |
| 4170 | fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: InlineMemcpyOpts) InnerError!void { |
| 4154 | 4171 | const abi_size = ty.abiSize(self.target.*); |
| 4155 | 4172 | |
| 4156 | 4173 | try self.register_manager.getReg(.rax, null); |
| 4157 | 4174 | try self.register_manager.getReg(.rcx, null); |
| 4158 | 4175 | |
| 4159 | | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp }); |
| 4160 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp }); |
| 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 | | |
| 4302 | | fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type, val: MCValue) InnerError!void { |
| 4303 | | const abi_size = ty.abiSize(self.target.*); |
| 4176 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 4177 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 4304 | 4178 | |
| 4305 | | try self.register_manager.getReg(.rax, null); |
| 4306 | | try self.register_manager.getReg(.rcx, null); |
| 4179 | if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 4180 | defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| 4307 | 4181 | |
| 4308 | | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp }); |
| 4309 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp }); |
| 4182 | if (opts.dest_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 4183 | defer if (opts.dest_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| 4310 | 4184 | |
| 4311 | 4185 | const addr_reg: Register = blk: { |
| 4312 | 4186 | switch (val) { |
| ... | ... | @@ -4322,7 +4196,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type |
| 4322 | 4196 | .tag = .lea, |
| 4323 | 4197 | .ops = (Mir.Ops{ |
| 4324 | 4198 | .reg1 = addr_reg, |
| 4325 | | .reg2 = .rbp, |
| 4199 | .reg2 = opts.source_stack_base orelse .rbp, |
| 4326 | 4200 | }).encode(), |
| 4327 | 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 | 4278 | _ = try self.addInst(.{ |
| 4405 | 4279 | .tag = .mov_scale_dst, |
| 4406 | 4280 | .ops = (Mir.Ops{ |
| 4407 | | .reg1 = stack_reg, |
| 4281 | .reg1 = opts.dest_stack_base orelse .rbp, |
| 4408 | 4282 | .reg2 = tmp_reg.to8(), |
| 4409 | 4283 | }).encode(), |
| 4410 | 4284 | .data = .{ .imm = @bitCast(u32, -stack_offset) }, |
| ... | ... | @@ -4850,8 +4724,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 4850 | 4724 | const array_len = array_ty.arrayLenIncludingSentinel(); |
| 4851 | 4725 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 4852 | 4726 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 4853 | | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 4854 | | try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len }); |
| 4727 | try self.genSetStack(ptr_ty, stack_offset, .rbp, ptr); |
| 4728 | try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .rbp, .{ .immediate = array_len }); |
| 4855 | 4729 | break :blk .{ .stack_offset = stack_offset }; |
| 4856 | 4730 | }; |
| 4857 | 4731 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -5249,10 +5123,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5249 | 5123 | const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size); |
| 5250 | 5124 | result.return_value = .{ .register = aliased_reg }; |
| 5251 | 5125 | } else { |
| 5252 | | // TODO save the stack location in `.rdi` for C ABI compatible extern calls. |
| 5253 | | const ret_ty_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 5254 | | const offset = mem.alignForwardGeneric(u32, ret_ty_size, ret_ty_align); |
| 5255 | | result.return_value = .{ .stack_offset = @intCast(i32, offset) }; |
| 5126 | // We simply make the return MCValue a stack offset. However, the actual value |
| 5127 | // for the offset will be populated later. We will also push the stack offset |
| 5128 | // value into .rdi register when we resolve the offset. |
| 5129 | result.return_value = .{ .stack_offset = 0 }; |
| 5256 | 5130 | } |
| 5257 | 5131 | } |
| 5258 | 5132 | |