| ... | ... | @@ -43,7 +43,7 @@ err_msg: ?*ErrorMsg, |
| 43 | 43 | args: []MCValue, |
| 44 | 44 | ret_mcv: MCValue, |
| 45 | 45 | fn_type: Type, |
| 46 | | arg_index: usize, |
| 46 | arg_index: u32, |
| 47 | 47 | src_loc: Module.SrcLoc, |
| 48 | 48 | stack_align: u32, |
| 49 | 49 | |
| ... | ... | @@ -117,9 +117,9 @@ pub const MCValue = union(enum) { |
| 117 | 117 | memory: u64, |
| 118 | 118 | /// The value is one of the stack variables. |
| 119 | 119 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 120 | | stack_offset: u32, |
| 120 | stack_offset: i32, |
| 121 | 121 | /// The value is a pointer to one of the stack variables (payload is stack offset). |
| 122 | | ptr_stack_offset: u32, |
| 122 | ptr_stack_offset: i32, |
| 123 | 123 | /// The value is in the compare flags assuming an unsigned operation, |
| 124 | 124 | /// with this operator applied on top of it. |
| 125 | 125 | compare_flags_unsigned: math.CompareOperator, |
| ... | ... | @@ -485,13 +485,12 @@ fn gen(self: *Self) InnerError!void { |
| 485 | 485 | }); |
| 486 | 486 | |
| 487 | 487 | // Adjust the stack |
| 488 | | const stack_end = self.max_end_stack; |
| 489 | | if (stack_end > math.maxInt(i32)) { |
| 488 | if (self.max_end_stack > math.maxInt(i32)) { |
| 490 | 489 | return self.failSymbol("too much stack used in call parameters", .{}); |
| 491 | 490 | } |
| 492 | 491 | // TODO we should reuse this mechanism to align the stack when calling any function even if |
| 493 | 492 | // we do not pass any args on the stack BUT we still push regs to stack with `push` inst. |
| 494 | | 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)); |
| 495 | 494 | if (aligned_stack_end > 0) { |
| 496 | 495 | self.mir_instructions.set(backpatch_stack_sub, .{ |
| 497 | 496 | .tag = .sub, |
| ... | ... | @@ -798,7 +797,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 798 | 797 | } |
| 799 | 798 | } |
| 800 | 799 | const stack_offset = try self.allocMem(inst, abi_size, abi_align); |
| 801 | | return MCValue{ .stack_offset = stack_offset }; |
| 800 | return MCValue{ .stack_offset = @intCast(i32, stack_offset) }; |
| 802 | 801 | } |
| 803 | 802 | |
| 804 | 803 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -844,12 +843,12 @@ fn copyToNewRegisterWithExceptions( |
| 844 | 843 | |
| 845 | 844 | fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 846 | 845 | const stack_offset = try self.allocMemPtr(inst); |
| 847 | | 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 }); |
| 848 | 847 | } |
| 849 | 848 | |
| 850 | 849 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 851 | 850 | const stack_offset = try self.allocMemPtr(inst); |
| 852 | | 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 }); |
| 853 | 852 | } |
| 854 | 853 | |
| 855 | 854 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1409,7 +1408,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1409 | 1408 | .reg1 = addr_reg.to64(), |
| 1410 | 1409 | .reg2 = .rbp, |
| 1411 | 1410 | }).encode(), |
| 1412 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + array_abi_size)) }, |
| 1411 | .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, array_abi_size))) }, |
| 1413 | 1412 | }); |
| 1414 | 1413 | }, |
| 1415 | 1414 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| ... | ... | @@ -1613,7 +1612,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1613 | 1612 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 1614 | 1613 | |
| 1615 | 1614 | return self.genInlineMemcpy( |
| 1616 | | @bitCast(u32, -@intCast(i32, off + abi_size)), |
| 1615 | -(off + @intCast(i32, abi_size)), |
| 1617 | 1616 | .rbp, |
| 1618 | 1617 | registerAlias(addr_reg, @divExact(reg.size(), 8)), |
| 1619 | 1618 | count_reg.to64(), |
| ... | ... | @@ -1770,10 +1769,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 1770 | 1769 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 1771 | 1770 | const mcv = try self.resolveInst(operand); |
| 1772 | 1771 | const struct_ty = self.air.typeOf(operand).childType(); |
| 1773 | | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 1774 | | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| 1772 | const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*)); |
| 1773 | const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*)); |
| 1775 | 1774 | const struct_field_ty = struct_ty.structFieldType(index); |
| 1776 | | 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.*)); |
| 1777 | 1776 | |
| 1778 | 1777 | switch (mcv) { |
| 1779 | 1778 | .ptr_stack_offset => |off| { |
| ... | ... | @@ -1793,10 +1792,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1793 | 1792 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1794 | 1793 | const mcv = try self.resolveInst(operand); |
| 1795 | 1794 | const struct_ty = self.air.typeOf(operand); |
| 1796 | | const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); |
| 1797 | | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); |
| 1795 | const struct_size = @intCast(i32, struct_ty.abiSize(self.target.*)); |
| 1796 | const struct_field_offset = @intCast(i32, struct_ty.structFieldOffset(index, self.target.*)); |
| 1798 | 1797 | const struct_field_ty = struct_ty.structFieldType(index); |
| 1799 | | 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.*)); |
| 1800 | 1799 | |
| 1801 | 1800 | switch (mcv) { |
| 1802 | 1801 | .stack_offset => |off| { |
| ... | ... | @@ -1960,7 +1959,7 @@ fn genBinMathOpMir( |
| 1960 | 1959 | return self.fail("stack offset too large", .{}); |
| 1961 | 1960 | } |
| 1962 | 1961 | const abi_size = dst_ty.abiSize(self.target.*); |
| 1963 | | const adj_off = off + abi_size; |
| 1962 | const adj_off = off + @intCast(i32, abi_size); |
| 1964 | 1963 | _ = try self.addInst(.{ |
| 1965 | 1964 | .tag = mir_tag, |
| 1966 | 1965 | .ops = (Mir.Ops{ |
| ... | ... | @@ -1968,7 +1967,7 @@ fn genBinMathOpMir( |
| 1968 | 1967 | .reg2 = .rbp, |
| 1969 | 1968 | .flags = 0b01, |
| 1970 | 1969 | }).encode(), |
| 1971 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) }, |
| 1970 | .data = .{ .imm = @bitCast(u32, -adj_off) }, |
| 1972 | 1971 | }); |
| 1973 | 1972 | }, |
| 1974 | 1973 | .compare_flags_unsigned => { |
| ... | ... | @@ -1987,7 +1986,7 @@ fn genBinMathOpMir( |
| 1987 | 1986 | if (abi_size > 8) { |
| 1988 | 1987 | return self.fail("TODO implement ADD/SUB/CMP for stack dst with large ABI", .{}); |
| 1989 | 1988 | } |
| 1990 | | const adj_off = off + abi_size; |
| 1989 | const adj_off = off + @intCast(i32, abi_size); |
| 1991 | 1990 | |
| 1992 | 1991 | switch (src_mcv) { |
| 1993 | 1992 | .none => unreachable, |
| ... | ... | @@ -2003,7 +2002,7 @@ fn genBinMathOpMir( |
| 2003 | 2002 | .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)), |
| 2004 | 2003 | .flags = 0b10, |
| 2005 | 2004 | }).encode(), |
| 2006 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) }, |
| 2005 | .data = .{ .imm = @bitCast(u32, -adj_off) }, |
| 2007 | 2006 | }); |
| 2008 | 2007 | }, |
| 2009 | 2008 | .immediate => |imm| { |
| ... | ... | @@ -2024,7 +2023,7 @@ fn genBinMathOpMir( |
| 2024 | 2023 | else => unreachable, |
| 2025 | 2024 | }; |
| 2026 | 2025 | const payload = try self.addExtra(Mir.ImmPair{ |
| 2027 | | .dest_off = @bitCast(u32, -@intCast(i32, adj_off)), |
| 2026 | .dest_off = @bitCast(u32, -adj_off), |
| 2028 | 2027 | .operand = @truncate(u32, imm), |
| 2029 | 2028 | }); |
| 2030 | 2029 | _ = try self.addInst(.{ |
| ... | ... | @@ -2162,7 +2161,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 2162 | 2161 | const mcv = self.args[arg_index]; |
| 2163 | 2162 | const payload = try self.addExtra(Mir.ArgDbgInfo{ |
| 2164 | 2163 | .air_inst = inst, |
| 2165 | | .arg_index = @truncate(u32, arg_index), // TODO can arg_index: u32? |
| 2164 | .arg_index = arg_index, |
| 2166 | 2165 | }); |
| 2167 | 2166 | _ = try self.addInst(.{ |
| 2168 | 2167 | .tag = .arg_dbg_info, |
| ... | ... | @@ -2178,56 +2177,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 2178 | 2177 | self.register_manager.getRegAssumeFree(reg.to64(), inst); |
| 2179 | 2178 | break :blk mcv; |
| 2180 | 2179 | }, |
| 2181 | | .stack_offset => |off| { |
| 2180 | .stack_offset => { |
| 2182 | 2181 | const ty = self.air.typeOfIndex(inst); |
| 2183 | 2182 | const abi_size = ty.abiSize(self.target.*); |
| 2184 | | |
| 2185 | | if (abi_size <= 8) { |
| 2186 | | const reg = try self.register_manager.allocReg(inst, &.{}); |
| 2187 | | _ = try self.addInst(.{ |
| 2188 | | .tag = .mov, |
| 2189 | | .ops = (Mir.Ops{ |
| 2190 | | .reg1 = registerAlias(reg, @intCast(u32, abi_size)), |
| 2191 | | .reg2 = .rbp, |
| 2192 | | .flags = 0b01, |
| 2193 | | }).encode(), |
| 2194 | | .data = .{ .imm = off + 16 }, |
| 2195 | | }); |
| 2196 | | break :blk .{ .register = reg }; |
| 2197 | | } |
| 2198 | | |
| 2199 | | // TODO copy ellision |
| 2200 | | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 2201 | | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx }); |
| 2202 | | const addr_reg = regs[0]; |
| 2203 | | const count_reg = regs[1]; |
| 2204 | | const tmp_reg = regs[2]; |
| 2205 | | |
| 2206 | | try self.register_manager.getReg(.rax, null); |
| 2207 | | try self.register_manager.getReg(.rcx, null); |
| 2208 | | |
| 2209 | | _ = try self.addInst(.{ |
| 2210 | | .tag = .lea, |
| 2211 | | .ops = (Mir.Ops{ |
| 2212 | | .reg1 = addr_reg.to64(), |
| 2213 | | .reg2 = .rbp, |
| 2214 | | }).encode(), |
| 2215 | | .data = .{ .imm = off + 16 }, |
| 2216 | | }); |
| 2217 | | |
| 2218 | | // TODO allow for abi_size to be u64 |
| 2219 | | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 2220 | | try self.genInlineMemcpy( |
| 2221 | | @bitCast(u32, -@intCast(i32, dst_mcv.stack_offset + abi_size)), |
| 2222 | | .rbp, |
| 2223 | | addr_reg.to64(), |
| 2224 | | count_reg.to64(), |
| 2225 | | tmp_reg.to8(), |
| 2226 | | ); |
| 2227 | | |
| 2228 | | break :blk dst_mcv; |
| 2183 | const off = @intCast(i32, (arg_index + 1) * abi_size) + 16; |
| 2184 | break :blk MCValue{ .stack_offset = -off }; |
| 2229 | 2185 | }, |
| 2230 | | else => unreachable, |
| 2186 | else => return self.fail("TODO implement arg for {}", .{mcv}), |
| 2231 | 2187 | } |
| 2232 | 2188 | }; |
| 2233 | 2189 | |
| ... | ... | @@ -2252,64 +2208,6 @@ fn airFence(self: *Self) !void { |
| 2252 | 2208 | //return self.finishAirBookkeeping(); |
| 2253 | 2209 | } |
| 2254 | 2210 | |
| 2255 | | fn genSetStackArg(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 2256 | | const abi_size = ty.abiSize(self.target.*); |
| 2257 | | switch (mcv) { |
| 2258 | | .dead => unreachable, |
| 2259 | | .ptr_embedded_in_code => unreachable, |
| 2260 | | .unreach, .none => return, |
| 2261 | | .register => |reg| { |
| 2262 | | _ = try self.addInst(.{ |
| 2263 | | .tag = .mov, |
| 2264 | | .ops = (Mir.Ops{ |
| 2265 | | .reg1 = .rsp, |
| 2266 | | .reg2 = registerAlias(reg, @intCast(u32, abi_size)), |
| 2267 | | .flags = 0b10, |
| 2268 | | }).encode(), |
| 2269 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, stack_offset + abi_size)) }, |
| 2270 | | }); |
| 2271 | | }, |
| 2272 | | .ptr_stack_offset => { |
| 2273 | | const reg = try self.copyToTmpRegister(ty, mcv); |
| 2274 | | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 2275 | | }, |
| 2276 | | .stack_offset => |unadjusted_off| { |
| 2277 | | if (abi_size <= 8) { |
| 2278 | | const reg = try self.copyToTmpRegister(ty, mcv); |
| 2279 | | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 2280 | | } |
| 2281 | | |
| 2282 | | const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{ .rax, .rcx }); |
| 2283 | | const addr_reg = regs[0]; |
| 2284 | | const count_reg = regs[1]; |
| 2285 | | const tmp_reg = regs[2]; |
| 2286 | | |
| 2287 | | try self.register_manager.getReg(.rax, null); |
| 2288 | | try self.register_manager.getReg(.rcx, null); |
| 2289 | | |
| 2290 | | _ = try self.addInst(.{ |
| 2291 | | .tag = .lea, |
| 2292 | | .ops = (Mir.Ops{ |
| 2293 | | .reg1 = addr_reg.to64(), |
| 2294 | | .reg2 = .rbp, |
| 2295 | | }).encode(), |
| 2296 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, unadjusted_off + abi_size)) }, |
| 2297 | | }); |
| 2298 | | |
| 2299 | | // TODO allow for abi_size to be u64 |
| 2300 | | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 2301 | | try self.genInlineMemcpy( |
| 2302 | | @bitCast(u32, -@intCast(i32, stack_offset + abi_size)), |
| 2303 | | .rsp, |
| 2304 | | addr_reg.to64(), |
| 2305 | | count_reg.to64(), |
| 2306 | | tmp_reg.to8(), |
| 2307 | | ); |
| 2308 | | }, |
| 2309 | | else => return self.fail("TODO implement args on stack for {}", .{mcv}), |
| 2310 | | } |
| 2311 | | } |
| 2312 | | |
| 2313 | 2211 | fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2314 | 2212 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2315 | 2213 | const callee = pl_op.operand; |
| ... | ... | @@ -2326,12 +2224,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2326 | 2224 | var info = try self.resolveCallingConventionValues(fn_ty); |
| 2327 | 2225 | defer info.deinit(self); |
| 2328 | 2226 | |
| 2329 | | var count: usize = info.args.len; |
| 2330 | 2227 | var stack_adjustment: u32 = 0; |
| 2331 | | while (count > 0) : (count -= 1) { |
| 2332 | | const arg_i = count - 1; |
| 2228 | for (args) |arg, arg_i| { |
| 2333 | 2229 | const mc_arg = info.args[arg_i]; |
| 2334 | | const arg = args[arg_i]; |
| 2335 | 2230 | const arg_ty = self.air.typeOf(arg); |
| 2336 | 2231 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 2337 | 2232 | // Here we do not use setRegOrMem even though the logic is similar, because |
| ... | ... | @@ -2343,9 +2238,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2343 | 2238 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| 2344 | 2239 | }, |
| 2345 | 2240 | .stack_offset => |off| { |
| 2346 | | const abi_size = arg_ty.abiSize(self.target.*); |
| 2241 | const abi_size = @intCast(u32, arg_ty.abiSize(self.target.*)); |
| 2347 | 2242 | try self.genSetStackArg(arg_ty, off, arg_mcv); |
| 2348 | | stack_adjustment += @intCast(u32, abi_size); |
| 2243 | stack_adjustment += abi_size; |
| 2349 | 2244 | }, |
| 2350 | 2245 | .ptr_stack_offset => { |
| 2351 | 2246 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| ... | ... | @@ -3257,7 +3152,65 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| 3257 | 3152 | } |
| 3258 | 3153 | } |
| 3259 | 3154 | |
| 3260 | | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 3155 | fn 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 | |
| 3213 | fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerError!void { |
| 3261 | 3214 | switch (mcv) { |
| 3262 | 3215 | .dead => unreachable, |
| 3263 | 3216 | .ptr_embedded_in_code => unreachable, |
| ... | ... | @@ -3284,7 +3237,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3284 | 3237 | }, |
| 3285 | 3238 | .immediate => |x_big| { |
| 3286 | 3239 | const abi_size = ty.abiSize(self.target.*); |
| 3287 | | const adj_off = stack_offset + abi_size; |
| 3240 | const adj_off = stack_offset + @intCast(i32, abi_size); |
| 3288 | 3241 | if (adj_off > 128) { |
| 3289 | 3242 | return self.fail("TODO implement set stack variable with large stack offset", .{}); |
| 3290 | 3243 | } |
| ... | ... | @@ -3294,7 +3247,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3294 | 3247 | // offset from rbp, which is at the top of the stack frame. |
| 3295 | 3248 | // mov [rbp+offset], immediate |
| 3296 | 3249 | const payload = try self.addExtra(Mir.ImmPair{ |
| 3297 | | .dest_off = @bitCast(u32, -@intCast(i32, adj_off)), |
| 3250 | .dest_off = @bitCast(u32, -adj_off), |
| 3298 | 3251 | .operand = @truncate(u32, x_big), |
| 3299 | 3252 | }); |
| 3300 | 3253 | _ = try self.addInst(.{ |
| ... | ... | @@ -3314,7 +3267,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3314 | 3267 | 8 => { |
| 3315 | 3268 | // We have a positive stack offset value but we want a twos complement negative |
| 3316 | 3269 | // offset from rbp, which is at the top of the stack frame. |
| 3317 | | const negative_offset = -@intCast(i32, adj_off); |
| 3270 | const negative_offset = -adj_off; |
| 3318 | 3271 | |
| 3319 | 3272 | // 64 bit write to memory would take two mov's anyways so we |
| 3320 | 3273 | // insted just use two 32 bit writes to avoid register allocation |
| ... | ... | @@ -3357,7 +3310,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3357 | 3310 | return self.fail("stack offset too large", .{}); |
| 3358 | 3311 | } |
| 3359 | 3312 | const abi_size = ty.abiSize(self.target.*); |
| 3360 | | const adj_off = stack_offset + abi_size; |
| 3313 | const adj_off = stack_offset + @intCast(i32, abi_size); |
| 3361 | 3314 | _ = try self.addInst(.{ |
| 3362 | 3315 | .tag = .mov, |
| 3363 | 3316 | .ops = (Mir.Ops{ |
| ... | ... | @@ -3365,7 +3318,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3365 | 3318 | .reg2 = registerAlias(reg, @intCast(u32, abi_size)), |
| 3366 | 3319 | .flags = 0b10, |
| 3367 | 3320 | }).encode(), |
| 3368 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, adj_off)) }, |
| 3321 | .data = .{ .imm = @bitCast(u32, -adj_off) }, |
| 3369 | 3322 | }); |
| 3370 | 3323 | }, |
| 3371 | 3324 | .memory, .embedded_in_code => { |
| ... | ... | @@ -3391,7 +3344,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3391 | 3344 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3392 | 3345 | } |
| 3393 | 3346 | |
| 3394 | | 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 }); |
| 3395 | 3348 | const addr_reg = regs[0]; |
| 3396 | 3349 | const count_reg = regs[1]; |
| 3397 | 3350 | const tmp_reg = regs[2]; |
| ... | ... | @@ -3405,14 +3358,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3405 | 3358 | .reg1 = addr_reg.to64(), |
| 3406 | 3359 | .reg2 = .rbp, |
| 3407 | 3360 | }).encode(), |
| 3408 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off + abi_size)) }, |
| 3361 | .data = .{ .imm = @bitCast(u32, -(off + @intCast(i32, abi_size))) }, |
| 3409 | 3362 | }); |
| 3410 | 3363 | |
| 3411 | 3364 | // TODO allow for abi_size to be u64 |
| 3412 | 3365 | try self.genSetReg(Type.initTag(.u32), count_reg, .{ .immediate = @intCast(u32, abi_size) }); |
| 3413 | 3366 | |
| 3414 | 3367 | return self.genInlineMemcpy( |
| 3415 | | @bitCast(u32, -@intCast(i32, stack_offset + abi_size)), |
| 3368 | -(stack_offset + @intCast(i32, abi_size)), |
| 3416 | 3369 | .rbp, |
| 3417 | 3370 | addr_reg.to64(), |
| 3418 | 3371 | count_reg.to64(), |
| ... | ... | @@ -3424,7 +3377,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3424 | 3377 | |
| 3425 | 3378 | fn genInlineMemcpy( |
| 3426 | 3379 | self: *Self, |
| 3427 | | stack_offset: u32, |
| 3380 | stack_offset: i32, |
| 3428 | 3381 | stack_reg: Register, |
| 3429 | 3382 | addr_reg: Register, |
| 3430 | 3383 | count_reg: Register, |
| ... | ... | @@ -3482,7 +3435,7 @@ fn genInlineMemcpy( |
| 3482 | 3435 | .reg1 = stack_reg, |
| 3483 | 3436 | .reg2 = tmp_reg.to8(), |
| 3484 | 3437 | }).encode(), |
| 3485 | | .data = .{ .imm = stack_offset }, |
| 3438 | .data = .{ .imm = @bitCast(u32, stack_offset) }, |
| 3486 | 3439 | }); |
| 3487 | 3440 | |
| 3488 | 3441 | // add rcx, 1 |
| ... | ... | @@ -3523,14 +3476,14 @@ fn genInlineMemcpy( |
| 3523 | 3476 | try self.performReloc(loop_reloc); |
| 3524 | 3477 | } |
| 3525 | 3478 | |
| 3526 | | fn genInlineMemset(self: *Self, ty: Type, stack_offset: u32, value: MCValue) InnerError!void { |
| 3479 | fn genInlineMemset(self: *Self, ty: Type, stack_offset: i32, value: MCValue) InnerError!void { |
| 3527 | 3480 | try self.register_manager.getReg(.rax, null); |
| 3528 | 3481 | const abi_size = ty.abiSize(self.target.*); |
| 3529 | | const adj_off = stack_offset + abi_size; |
| 3482 | const adj_off = stack_offset + @intCast(i32, abi_size); |
| 3530 | 3483 | if (adj_off > 128) { |
| 3531 | 3484 | return self.fail("TODO inline memset with large stack offset", .{}); |
| 3532 | 3485 | } |
| 3533 | | const negative_offset = @bitCast(u32, -@intCast(i32, adj_off)); |
| 3486 | const negative_offset = @bitCast(u32, -adj_off); |
| 3534 | 3487 | |
| 3535 | 3488 | // We are actually counting `abi_size` bytes; however, we reuse the index register |
| 3536 | 3489 | // as both the counter and offset scaler, hence we need to subtract one from `abi_size` |
| ... | ... | @@ -3621,7 +3574,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3621 | 3574 | const ptr_abi_size = ty.abiSize(self.target.*); |
| 3622 | 3575 | const elem_ty = ty.childType(); |
| 3623 | 3576 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 3624 | | const off = unadjusted_off + elem_abi_size; |
| 3577 | const off = unadjusted_off + @intCast(i32, elem_abi_size); |
| 3625 | 3578 | if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { |
| 3626 | 3579 | return self.fail("stack offset too large", .{}); |
| 3627 | 3580 | } |
| ... | ... | @@ -3631,7 +3584,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3631 | 3584 | .reg1 = registerAlias(reg, @intCast(u32, ptr_abi_size)), |
| 3632 | 3585 | .reg2 = .rbp, |
| 3633 | 3586 | }).encode(), |
| 3634 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) }, |
| 3587 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 3635 | 3588 | }); |
| 3636 | 3589 | }, |
| 3637 | 3590 | .ptr_embedded_in_code => unreachable, |
| ... | ... | @@ -3818,7 +3771,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3818 | 3771 | }, |
| 3819 | 3772 | .stack_offset => |unadjusted_off| { |
| 3820 | 3773 | const abi_size = ty.abiSize(self.target.*); |
| 3821 | | const off = unadjusted_off + abi_size; |
| 3774 | const off = unadjusted_off + @intCast(i32, abi_size); |
| 3822 | 3775 | if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) { |
| 3823 | 3776 | return self.fail("stack offset too large", .{}); |
| 3824 | 3777 | } |
| ... | ... | @@ -3829,7 +3782,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3829 | 3782 | .reg2 = .rbp, |
| 3830 | 3783 | .flags = 0b01, |
| 3831 | 3784 | }).encode(), |
| 3832 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, off)) }, |
| 3785 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 3833 | 3786 | }); |
| 3834 | 3787 | }, |
| 3835 | 3788 | } |
| ... | ... | @@ -3854,7 +3807,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 3854 | 3807 | const array_ty = ptr_ty.childType(); |
| 3855 | 3808 | const array_len = array_ty.arrayLenIncludingSentinel(); |
| 3856 | 3809 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 3857 | | const stack_offset = try self.allocMem(inst, 16, 16); |
| 3810 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 3858 | 3811 | try self.genSetStack(ptr_ty, stack_offset + 8, ptr); |
| 3859 | 3812 | try self.genSetStack(Type.initTag(.u64), stack_offset, .{ .immediate = array_len }); |
| 3860 | 3813 | break :blk .{ .stack_offset = stack_offset }; |
| ... | ... | @@ -4235,6 +4188,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4235 | 4188 | var next_stack_offset: u32 = 0; |
| 4236 | 4189 | var count: usize = param_types.len; |
| 4237 | 4190 | while (count > 0) : (count -= 1) { |
| 4191 | // for (param_types) |ty, i| { |
| 4238 | 4192 | const i = count - 1; |
| 4239 | 4193 | const ty = param_types[i]; |
| 4240 | 4194 | if (!ty.hasCodeGenBits()) { |
| ... | ... | @@ -4253,7 +4207,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 4253 | 4207 | // such as ptr and len of slices as separate registers. |
| 4254 | 4208 | // TODO: also we need to honor the C ABI for relevant types rather than passing on |
| 4255 | 4209 | // the stack here. |
| 4256 | | result.args[i] = .{ .stack_offset = next_stack_offset }; |
| 4210 | result.args[i] = .{ .stack_offset = @intCast(i32, next_stack_offset) }; |
| 4257 | 4211 | next_stack_offset += param_size; |
| 4258 | 4212 | } |
| 4259 | 4213 | } |