| ... | ... | @@ -886,7 +886,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 886 | 886 | assert(reg.to64() == reg_mcv.register.to64()); |
| 887 | 887 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 888 | 888 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 889 | | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, .rbp, reg_mcv); |
| 889 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); |
| 890 | 890 | } |
| 891 | 891 | |
| 892 | 892 | /// Copies a value to a register without tracking the register. The register is not considered |
| ... | ... | @@ -1196,8 +1196,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1196 | 1196 | const len_ty = self.air.typeOf(bin_op.rhs); |
| 1197 | 1197 | |
| 1198 | 1198 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 1199 | | try self.genSetStack(ptr_ty, stack_offset, .rbp, ptr); |
| 1200 | | try self.genSetStack(len_ty, stack_offset - 8, .rbp, len); |
| 1199 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); |
| 1200 | try self.genSetStack(len_ty, stack_offset - 8, len, .{}); |
| 1201 | 1201 | const result = MCValue{ .stack_offset = stack_offset }; |
| 1202 | 1202 | |
| 1203 | 1203 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | ... | @@ -1797,24 +1797,47 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1797 | 1797 | /// T to E!T |
| 1798 | 1798 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1799 | 1799 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1800 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1801 | | .dead |
| 1802 | | else |
| 1803 | | return self.fail("TODO implement wrap errunion payload for {}", .{self.target.cpu.arch}); |
| 1804 | | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1800 | if (self.liveness.isUnused(inst)) { |
| 1801 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1802 | } |
| 1803 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 1804 | const error_ty = error_union_ty.errorUnionSet(); |
| 1805 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1806 | const operand = try self.resolveInst(ty_op.operand); |
| 1807 | assert(payload_ty.hasRuntimeBits()); |
| 1808 | |
| 1809 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 1810 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| 1811 | const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*)); |
| 1812 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| 1813 | try self.genSetStack(error_ty, stack_offset, .{ .immediate = 0 }, .{}); |
| 1814 | try self.genSetStack(payload_ty, stack_offset - @intCast(i32, err_abi_size), operand, .{}); |
| 1815 | |
| 1816 | return self.finishAir(inst, .{ .stack_offset = stack_offset }, .{ ty_op.operand, .none, .none }); |
| 1805 | 1817 | } |
| 1806 | 1818 | |
| 1807 | 1819 | /// E to E!T |
| 1808 | 1820 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1809 | 1821 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1810 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1811 | | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 1812 | | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1813 | | const mcv = try self.resolveInst(ty_op.operand); |
| 1814 | | if (!payload_ty.hasRuntimeBits()) break :result mcv; |
| 1815 | | |
| 1816 | | return self.fail("TODO implement wrap errunion error for non-empty payloads", .{}); |
| 1822 | if (self.liveness.isUnused(inst)) { |
| 1823 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1824 | } |
| 1825 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 1826 | const error_ty = error_union_ty.errorUnionSet(); |
| 1827 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1828 | const err = try self.resolveInst(ty_op.operand); |
| 1829 | const result: MCValue = result: { |
| 1830 | if (!payload_ty.hasRuntimeBits()) break :result err; |
| 1831 | |
| 1832 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 1833 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| 1834 | const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*)); |
| 1835 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| 1836 | try self.genSetStack(error_ty, stack_offset, err, .{}); |
| 1837 | try self.genSetStack(payload_ty, stack_offset - @intCast(i32, err_abi_size), .undef, .{}); |
| 1838 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1817 | 1839 | }; |
| 1840 | |
| 1818 | 1841 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1819 | 1842 | } |
| 1820 | 1843 | |
| ... | ... | @@ -1974,7 +1997,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1974 | 1997 | @intCast(u32, array_ty.abiSize(self.target.*)), |
| 1975 | 1998 | array_ty.abiAlignment(self.target.*), |
| 1976 | 1999 | )); |
| 1977 | | try self.genSetStack(array_ty, off, .rbp, array); |
| 2000 | try self.genSetStack(array_ty, off, array, .{}); |
| 1978 | 2001 | break :inner off; |
| 1979 | 2002 | }, |
| 1980 | 2003 | .stack_offset => |off| { |
| ... | ... | @@ -2207,7 +2230,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2207 | 2230 | if (abi_size <= 8) { |
| 2208 | 2231 | const tmp_reg = try self.register_manager.allocReg(null); |
| 2209 | 2232 | try self.load(.{ .register = tmp_reg }, ptr, ptr_ty); |
| 2210 | | return self.genSetStack(elem_ty, off, .rbp, MCValue{ .register = tmp_reg }); |
| 2233 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{}); |
| 2211 | 2234 | } |
| 2212 | 2235 | |
| 2213 | 2236 | try self.genInlineMemcpy(off, elem_ty, ptr, .{}); |
| ... | ... | @@ -2305,7 +2328,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2305 | 2328 | try self.store(.{ .register = reg }, value, ptr_ty, value_ty); |
| 2306 | 2329 | }, |
| 2307 | 2330 | .ptr_stack_offset => |off| { |
| 2308 | | try self.genSetStack(value_ty, off, .rbp, value); |
| 2331 | try self.genSetStack(value_ty, off, value, .{}); |
| 2309 | 2332 | }, |
| 2310 | 2333 | .ptr_embedded_in_code => |off| { |
| 2311 | 2334 | try self.setRegOrMem(value_ty, .{ .embedded_in_code = off }, value); |
| ... | ... | @@ -2779,7 +2802,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2779 | 2802 | |
| 2780 | 2803 | switch (src_mcv) { |
| 2781 | 2804 | .none => unreachable, |
| 2782 | | .undef => return self.genSetStack(dst_ty, off, .rbp, .undef), |
| 2805 | .undef => return self.genSetStack(dst_ty, off, .undef, .{}), |
| 2783 | 2806 | .dead, .unreach => unreachable, |
| 2784 | 2807 | .ptr_stack_offset => unreachable, |
| 2785 | 2808 | .ptr_embedded_in_code => unreachable, |
| ... | ... | @@ -2922,7 +2945,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2922 | 2945 | .stack_offset => |off| { |
| 2923 | 2946 | switch (src_mcv) { |
| 2924 | 2947 | .none => unreachable, |
| 2925 | | .undef => return self.genSetStack(dst_ty, off, .rbp, .undef), |
| 2948 | .undef => return self.genSetStack(dst_ty, off, .undef, .{}), |
| 2926 | 2949 | .dead, .unreach => unreachable, |
| 2927 | 2950 | .ptr_stack_offset => unreachable, |
| 2928 | 2951 | .ptr_embedded_in_code => unreachable, |
| ... | ... | @@ -2940,7 +2963,7 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2940 | 2963 | .data = undefined, |
| 2941 | 2964 | }); |
| 2942 | 2965 | // copy dst_reg back out |
| 2943 | | return self.genSetStack(dst_ty, off, .rbp, MCValue{ .register = dst_reg }); |
| 2966 | return self.genSetStack(dst_ty, off, MCValue{ .register = dst_reg }, .{}); |
| 2944 | 2967 | }, |
| 2945 | 2968 | .immediate => |imm| { |
| 2946 | 2969 | _ = imm; |
| ... | ... | @@ -3279,7 +3302,10 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 3279 | 3302 | }).encode(), |
| 3280 | 3303 | .data = undefined, |
| 3281 | 3304 | }); |
| 3282 | | try self.genSetStack(ret_ty, 0, reg, operand); |
| 3305 | try self.genSetStack(ret_ty, 0, operand, .{ |
| 3306 | .source_stack_base = .rbp, |
| 3307 | .dest_stack_base = reg, |
| 3308 | }); |
| 3283 | 3309 | }, |
| 3284 | 3310 | else => { |
| 3285 | 3311 | try self.setRegOrMem(ret_ty, self.ret_mcv, operand); |
| ... | ... | @@ -4179,7 +4205,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| 4179 | 4205 | .none => return, |
| 4180 | 4206 | .immediate => unreachable, |
| 4181 | 4207 | .register => |reg| return self.genSetReg(ty, reg, val), |
| 4182 | | .stack_offset => |off| return self.genSetStack(ty, off, .rbp, val), |
| 4208 | .stack_offset => |off| return self.genSetStack(ty, off, val, .{}), |
| 4183 | 4209 | .memory => { |
| 4184 | 4210 | return self.fail("TODO implement setRegOrMem for memory", .{}); |
| 4185 | 4211 | }, |
| ... | ... | @@ -4200,7 +4226,9 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 4200 | 4226 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4201 | 4227 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 4202 | 4228 | } |
| 4203 | | try self.genInlineMemset(stack_offset, .rsp, ty, .{ .immediate = 0xaa }); |
| 4229 | try self.genInlineMemset(stack_offset, ty, .{ .immediate = 0xaa }, .{ |
| 4230 | .dest_stack_base = .rsp, |
| 4231 | }); |
| 4204 | 4232 | }, |
| 4205 | 4233 | .compare_flags_unsigned, |
| 4206 | 4234 | .compare_flags_signed, |
| ... | ... | @@ -4289,7 +4317,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 4289 | 4317 | } |
| 4290 | 4318 | } |
| 4291 | 4319 | |
| 4292 | | fn genSetStack(self: *Self, ty: Type, stack_offset: i32, base_reg: Register, mcv: MCValue) InnerError!void { |
| 4320 | fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: InlineMemcpyOpts) InnerError!void { |
| 4293 | 4321 | const abi_size = ty.abiSize(self.target.*); |
| 4294 | 4322 | switch (mcv) { |
| 4295 | 4323 | .dead => unreachable, |
| ... | ... | @@ -4300,20 +4328,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, base_reg: Register, mcv |
| 4300 | 4328 | return; // The already existing value will do just fine. |
| 4301 | 4329 | // TODO Upgrade this to a memset call when we have that available. |
| 4302 | 4330 | switch (ty.abiSize(self.target.*)) { |
| 4303 | | 1 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaa }), |
| 4304 | | 2 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaa }), |
| 4305 | | 4 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaaaaaa }), |
| 4306 | | 8 => return self.genSetStack(ty, stack_offset, base_reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }), |
| 4307 | | else => return self.genInlineMemset(stack_offset, base_reg, ty, .{ .immediate = 0xaa }), |
| 4331 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }, opts), |
| 4332 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }, opts), |
| 4333 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }, opts), |
| 4334 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts), |
| 4335 | else => return self.genInlineMemset(stack_offset, ty, .{ .immediate = 0xaa }, opts), |
| 4308 | 4336 | } |
| 4309 | 4337 | }, |
| 4310 | 4338 | .compare_flags_unsigned, |
| 4311 | 4339 | .compare_flags_signed, |
| 4312 | 4340 | => { |
| 4313 | 4341 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4314 | | return self.genSetStack(ty, stack_offset, base_reg, .{ .register = reg }); |
| 4342 | return self.genSetStack(ty, stack_offset, .{ .register = reg }, opts); |
| 4315 | 4343 | }, |
| 4316 | 4344 | .immediate => |x_big| { |
| 4345 | const base_reg = opts.dest_stack_base orelse .rbp; |
| 4317 | 4346 | switch (abi_size) { |
| 4318 | 4347 | 1, 2, 4 => { |
| 4319 | 4348 | const payload = try self.addExtra(Mir.ImmPair{ |
| ... | ... | @@ -4376,6 +4405,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, base_reg: Register, mcv |
| 4376 | 4405 | return self.fail("stack offset too large", .{}); |
| 4377 | 4406 | } |
| 4378 | 4407 | |
| 4408 | const base_reg = opts.dest_stack_base orelse .rbp; |
| 4379 | 4409 | const is_power_of_two = (abi_size % 2) == 0; |
| 4380 | 4410 | if (!is_power_of_two) { |
| 4381 | 4411 | self.register_manager.freezeRegs(&.{reg}); |
| ... | ... | @@ -4431,17 +4461,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, base_reg: Register, mcv |
| 4431 | 4461 | => { |
| 4432 | 4462 | if (abi_size <= 8) { |
| 4433 | 4463 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4434 | | return self.genSetStack(ty, stack_offset, base_reg, MCValue{ .register = reg }); |
| 4464 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 4435 | 4465 | } |
| 4436 | 4466 | |
| 4437 | | try self.genInlineMemcpy(stack_offset, ty, mcv, .{ |
| 4438 | | .source_stack_base = base_reg, |
| 4439 | | .dest_stack_base = base_reg, |
| 4440 | | }); |
| 4467 | try self.genInlineMemcpy(stack_offset, ty, mcv, opts); |
| 4441 | 4468 | }, |
| 4442 | 4469 | .ptr_stack_offset => { |
| 4443 | 4470 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4444 | | return self.genSetStack(ty, stack_offset, base_reg, MCValue{ .register = reg }); |
| 4471 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 4445 | 4472 | }, |
| 4446 | 4473 | .stack_offset => |off| { |
| 4447 | 4474 | if (stack_offset == off) { |
| ... | ... | @@ -4451,13 +4478,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, base_reg: Register, mcv |
| 4451 | 4478 | |
| 4452 | 4479 | if (abi_size <= 8) { |
| 4453 | 4480 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4454 | | return self.genSetStack(ty, stack_offset, base_reg, MCValue{ .register = reg }); |
| 4481 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 4455 | 4482 | } |
| 4456 | 4483 | |
| 4457 | | try self.genInlineMemcpy(stack_offset, ty, mcv, .{ |
| 4458 | | .source_stack_base = base_reg, |
| 4459 | | .dest_stack_base = base_reg, |
| 4460 | | }); |
| 4484 | try self.genInlineMemcpy(stack_offset, ty, mcv, opts); |
| 4461 | 4485 | }, |
| 4462 | 4486 | } |
| 4463 | 4487 | } |
| ... | ... | @@ -4627,9 +4651,9 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: |
| 4627 | 4651 | fn genInlineMemset( |
| 4628 | 4652 | self: *Self, |
| 4629 | 4653 | stack_offset: i32, |
| 4630 | | stack_register: Register, |
| 4631 | 4654 | ty: Type, |
| 4632 | 4655 | value: MCValue, |
| 4656 | opts: InlineMemcpyOpts, |
| 4633 | 4657 | ) InnerError!void { |
| 4634 | 4658 | try self.register_manager.getReg(.rax, null); |
| 4635 | 4659 | |
| ... | ... | @@ -4694,7 +4718,7 @@ fn genInlineMemset( |
| 4694 | 4718 | _ = try self.addInst(.{ |
| 4695 | 4719 | .tag = .mov_mem_index_imm, |
| 4696 | 4720 | .ops = (Mir.Ops{ |
| 4697 | | .reg1 = stack_register.to64(), |
| 4721 | .reg1 = opts.dest_stack_base orelse .rbp, |
| 4698 | 4722 | }).encode(), |
| 4699 | 4723 | .data = .{ .payload = payload }, |
| 4700 | 4724 | }); |
| ... | ... | @@ -5026,8 +5050,8 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5026 | 5050 | const array_len = array_ty.arrayLenIncludingSentinel(); |
| 5027 | 5051 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 5028 | 5052 | const stack_offset = @intCast(i32, try self.allocMem(inst, 16, 16)); |
| 5029 | | try self.genSetStack(ptr_ty, stack_offset, .rbp, ptr); |
| 5030 | | try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .rbp, .{ .immediate = array_len }); |
| 5053 | try self.genSetStack(ptr_ty, stack_offset, ptr, .{}); |
| 5054 | try self.genSetStack(Type.initTag(.u64), stack_offset - 8, .{ .immediate = array_len }, .{}); |
| 5031 | 5055 | break :blk .{ .stack_offset = stack_offset }; |
| 5032 | 5056 | }; |
| 5033 | 5057 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |