| ... | @@ -2346,7 +2346,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2346,7 +2346,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2346 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{}); | 2346 | return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg }, .{}); |
| 2347 | } | 2347 | } |
| 2348 | | 2348 | |
| 2349 | try self.genInlineMemcpy(off, elem_ty, ptr, .{}); | 2349 | try self.genInlineMemcpy(dst_mcv, ptr, .{ .immediate = abi_size }, .{}); |
| 2350 | }, | 2350 | }, |
| 2351 | else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), | 2351 | else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), |
| 2352 | } | 2352 | } |
| ... | @@ -2392,6 +2392,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue | ... | @@ -2392,6 +2392,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue |
| 2392 | .got_load, | 2392 | .got_load, |
| 2393 | .direct_load, | 2393 | .direct_load, |
| 2394 | => |sym_index| { | 2394 | => |sym_index| { |
| | 2395 | const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*)); |
| 2395 | const flags: u2 = switch (ptr) { | 2396 | const flags: u2 = switch (ptr) { |
| 2396 | .got_load => 0b00, | 2397 | .got_load => 0b00, |
| 2397 | .direct_load => 0b01, | 2398 | .direct_load => 0b01, |
| ... | @@ -2400,7 +2401,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue | ... | @@ -2400,7 +2401,7 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue |
| 2400 | _ = try self.addInst(.{ | 2401 | _ = try self.addInst(.{ |
| 2401 | .tag = .lea_pie, | 2402 | .tag = .lea_pie, |
| 2402 | .ops = (Mir.Ops{ | 2403 | .ops = (Mir.Ops{ |
| 2403 | .reg1 = registerAlias(reg, @intCast(u32, ptr_ty.abiSize(self.target.*))), | 2404 | .reg1 = registerAlias(reg, abi_size), |
| 2404 | .flags = flags, | 2405 | .flags = flags, |
| 2405 | }).encode(), | 2406 | }).encode(), |
| 2406 | .data = .{ | 2407 | .data = .{ |
| ... | @@ -2524,7 +2525,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2524,7 +2525,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2524 | return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); | 2525 | return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); |
| 2525 | } | 2526 | } |
| 2526 | | 2527 | |
| 2527 | try self.genInlineMemcpy(0, value_ty, value, .{ | 2528 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, value, .{ .immediate = abi_size }, .{ |
| 2528 | .source_stack_base = .rbp, | 2529 | .source_stack_base = .rbp, |
| 2529 | .dest_stack_base = reg.to64(), | 2530 | .dest_stack_base = reg.to64(), |
| 2530 | }); | 2531 | }); |
| ... | @@ -3464,7 +3465,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3464,7 +3465,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3464 | .data = undefined, | 3465 | .data = undefined, |
| 3465 | }); | 3466 | }); |
| 3466 | try self.ret_backpatches.append(self.gpa, backpatch); | 3467 | try self.ret_backpatches.append(self.gpa, backpatch); |
| 3467 | try self.genInlineMemcpy(0, elem_ty, ptr, .{ | 3468 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, ptr, .{ .immediate = elem_ty.abiSize(self.target.*) }, .{ |
| 3468 | .source_stack_base = .rbp, | 3469 | .source_stack_base = .rbp, |
| 3469 | .dest_stack_base = reg, | 3470 | .dest_stack_base = reg, |
| 3470 | }); | 3471 | }); |
| ... | @@ -4412,9 +4413,12 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -4412,9 +4413,12 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 4412 | const reg = try self.copyToTmpRegister(ty, mcv); | 4413 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4413 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | 4414 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 4414 | } | 4415 | } |
| 4415 | try self.genInlineMemset(stack_offset, ty, .{ .immediate = 0xaa }, .{ | 4416 | try self.genInlineMemset( |
| 4416 | .dest_stack_base = .rsp, | 4417 | .{ .stack_offset = stack_offset }, |
| 4417 | }); | 4418 | .{ .immediate = 0xaa }, |
| | 4419 | .{ .immediate = abi_size }, |
| | 4420 | .{ .dest_stack_base = .rsp }, |
| | 4421 | ); |
| 4418 | }, | 4422 | }, |
| 4419 | .compare_flags_unsigned, | 4423 | .compare_flags_unsigned, |
| 4420 | .compare_flags_signed, | 4424 | .compare_flags_signed, |
| ... | @@ -4469,7 +4473,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -4469,7 +4473,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 4469 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | 4473 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 4470 | } | 4474 | } |
| 4471 | | 4475 | |
| 4472 | try self.genInlineMemcpy(stack_offset, ty, mcv, .{ | 4476 | try self.genInlineMemcpy(.{ .stack_offset = stack_offset }, mcv, .{ .immediate = abi_size }, .{ |
| 4473 | .source_stack_base = .rbp, | 4477 | .source_stack_base = .rbp, |
| 4474 | .dest_stack_base = .rsp, | 4478 | .dest_stack_base = .rsp, |
| 4475 | }); | 4479 | }); |
| ... | @@ -4495,7 +4499,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -4495,7 +4499,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 4495 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | 4499 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 4496 | } | 4500 | } |
| 4497 | | 4501 | |
| 4498 | try self.genInlineMemcpy(stack_offset, ty, mcv, .{ | 4502 | try self.genInlineMemcpy(.{ .stack_offset = stack_offset }, mcv, .{ .immediate = abi_size }, .{ |
| 4499 | .source_stack_base = .rbp, | 4503 | .source_stack_base = .rbp, |
| 4500 | .dest_stack_base = .rsp, | 4504 | .dest_stack_base = .rsp, |
| 4501 | }); | 4505 | }); |
| ... | @@ -4518,7 +4522,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -4518,7 +4522,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 4518 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }, opts), | 4522 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }, opts), |
| 4519 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }, opts), | 4523 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }, opts), |
| 4520 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts), | 4524 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts), |
| 4521 | else => return self.genInlineMemset(stack_offset, ty, .{ .immediate = 0xaa }, opts), | 4525 | else => |x| return self.genInlineMemset( |
| | 4526 | .{ .stack_offset = stack_offset }, |
| | 4527 | .{ .immediate = 0xaa }, |
| | 4528 | .{ .immediate = x }, |
| | 4529 | opts, |
| | 4530 | ), |
| 4522 | } | 4531 | } |
| 4523 | }, | 4532 | }, |
| 4524 | .compare_flags_unsigned, | 4533 | .compare_flags_unsigned, |
| ... | @@ -4650,7 +4659,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -4650,7 +4659,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 4650 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); | 4659 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 4651 | } | 4660 | } |
| 4652 | | 4661 | |
| 4653 | try self.genInlineMemcpy(stack_offset, ty, mcv, opts); | 4662 | try self.genInlineMemcpy(.{ .stack_offset = stack_offset }, mcv, .{ .immediate = abi_size }, opts); |
| 4654 | }, | 4663 | }, |
| 4655 | .ptr_stack_offset => { | 4664 | .ptr_stack_offset => { |
| 4656 | const reg = try self.copyToTmpRegister(ty, mcv); | 4665 | const reg = try self.copyToTmpRegister(ty, mcv); |
| ... | @@ -4667,7 +4676,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -4667,7 +4676,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 4667 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); | 4676 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 4668 | } | 4677 | } |
| 4669 | | 4678 | |
| 4670 | try self.genInlineMemcpy(stack_offset, ty, mcv, opts); | 4679 | try self.genInlineMemcpy(.{ .stack_offset = stack_offset }, mcv, .{ .immediate = abi_size }, opts); |
| 4671 | }, | 4680 | }, |
| 4672 | } | 4681 | } |
| 4673 | } | 4682 | } |
| ... | @@ -4677,9 +4686,13 @@ const InlineMemcpyOpts = struct { | ... | @@ -4677,9 +4686,13 @@ const InlineMemcpyOpts = struct { |
| 4677 | dest_stack_base: ?Register = null, | 4686 | dest_stack_base: ?Register = null, |
| 4678 | }; | 4687 | }; |
| 4679 | | 4688 | |
| 4680 | fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: InlineMemcpyOpts) InnerError!void { | 4689 | fn genInlineMemcpy( |
| 4681 | const abi_size = ty.abiSize(self.target.*); | 4690 | self: *Self, |
| 4682 | | 4691 | dst_ptr: MCValue, |
| | 4692 | src_ptr: MCValue, |
| | 4693 | len: MCValue, |
| | 4694 | opts: InlineMemcpyOpts, |
| | 4695 | ) InnerError!void { |
| 4683 | // TODO this is wrong. We should check first if any of the operands is in `.rax` or `.rcx` before | 4696 | // TODO this is wrong. We should check first if any of the operands is in `.rax` or `.rcx` before |
| 4684 | // spilling. Consolidate with other TODOs regarding register allocation mechanics. | 4697 | // spilling. Consolidate with other TODOs regarding register allocation mechanics. |
| 4685 | try self.register_manager.getReg(.rax, null); | 4698 | try self.register_manager.getReg(.rax, null); |
| ... | @@ -4694,19 +4707,55 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: | ... | @@ -4694,19 +4707,55 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: |
| 4694 | if (opts.dest_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); | 4707 | if (opts.dest_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 4695 | defer if (opts.dest_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); | 4708 | defer if (opts.dest_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| 4696 | | 4709 | |
| 4697 | const addr_reg = try self.register_manager.allocReg(null); | 4710 | const dst_addr_reg = try self.register_manager.allocReg(null); |
| 4698 | switch (val) { | 4711 | switch (dst_ptr) { |
| 4699 | .memory, | 4712 | .memory, |
| | 4713 | .got_load, |
| 4700 | .direct_load, | 4714 | .direct_load, |
| | 4715 | => { |
| | 4716 | try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr); |
| | 4717 | }, |
| | 4718 | .ptr_stack_offset, .stack_offset => |off| { |
| | 4719 | _ = try self.addInst(.{ |
| | 4720 | .tag = .lea, |
| | 4721 | .ops = (Mir.Ops{ |
| | 4722 | .reg1 = dst_addr_reg.to64(), |
| | 4723 | .reg2 = opts.dest_stack_base orelse .rbp, |
| | 4724 | }).encode(), |
| | 4725 | .data = .{ .imm = @bitCast(u32, -off) }, |
| | 4726 | }); |
| | 4727 | }, |
| | 4728 | .register => |reg| { |
| | 4729 | _ = try self.addInst(.{ |
| | 4730 | .tag = .mov, |
| | 4731 | .ops = (Mir.Ops{ |
| | 4732 | .reg1 = registerAlias(dst_addr_reg, @divExact(reg.size(), 8)), |
| | 4733 | .reg2 = reg, |
| | 4734 | }).encode(), |
| | 4735 | .data = undefined, |
| | 4736 | }); |
| | 4737 | }, |
| | 4738 | else => { |
| | 4739 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); |
| | 4740 | }, |
| | 4741 | } |
| | 4742 | |
| | 4743 | self.register_manager.freezeRegs(&.{dst_addr_reg}); |
| | 4744 | defer self.register_manager.unfreezeRegs(&.{dst_addr_reg}); |
| | 4745 | |
| | 4746 | const src_addr_reg = try self.register_manager.allocReg(null); |
| | 4747 | switch (src_ptr) { |
| | 4748 | .memory, |
| 4701 | .got_load, | 4749 | .got_load, |
| | 4750 | .direct_load, |
| 4702 | => { | 4751 | => { |
| 4703 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, val); | 4752 | try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr); |
| 4704 | }, | 4753 | }, |
| 4705 | .ptr_stack_offset, .stack_offset => |off| { | 4754 | .ptr_stack_offset, .stack_offset => |off| { |
| 4706 | _ = try self.addInst(.{ | 4755 | _ = try self.addInst(.{ |
| 4707 | .tag = .lea, | 4756 | .tag = .lea, |
| 4708 | .ops = (Mir.Ops{ | 4757 | .ops = (Mir.Ops{ |
| 4709 | .reg1 = addr_reg.to64(), | 4758 | .reg1 = src_addr_reg.to64(), |
| 4710 | .reg2 = opts.source_stack_base orelse .rbp, | 4759 | .reg2 = opts.source_stack_base orelse .rbp, |
| 4711 | }).encode(), | 4760 | }).encode(), |
| 4712 | .data = .{ .imm = @bitCast(u32, -off) }, | 4761 | .data = .{ .imm = @bitCast(u32, -off) }, |
| ... | @@ -4716,25 +4765,25 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: | ... | @@ -4716,25 +4765,25 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: |
| 4716 | _ = try self.addInst(.{ | 4765 | _ = try self.addInst(.{ |
| 4717 | .tag = .mov, | 4766 | .tag = .mov, |
| 4718 | .ops = (Mir.Ops{ | 4767 | .ops = (Mir.Ops{ |
| 4719 | .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)), | 4768 | .reg1 = registerAlias(src_addr_reg, @divExact(reg.size(), 8)), |
| 4720 | .reg2 = reg, | 4769 | .reg2 = reg, |
| 4721 | }).encode(), | 4770 | }).encode(), |
| 4722 | .data = undefined, | 4771 | .data = undefined, |
| 4723 | }); | 4772 | }); |
| 4724 | }, | 4773 | }, |
| 4725 | else => { | 4774 | else => { |
| 4726 | return self.fail("TODO implement memcpy for setting stack from {}", .{val}); | 4775 | return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr}); |
| 4727 | }, | 4776 | }, |
| 4728 | } | 4777 | } |
| 4729 | | 4778 | |
| 4730 | self.register_manager.freezeRegs(&.{addr_reg}); | 4779 | self.register_manager.freezeRegs(&.{src_addr_reg}); |
| 4731 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | 4780 | defer self.register_manager.unfreezeRegs(&.{src_addr_reg}); |
| 4732 | | 4781 | |
| 4733 | const regs = try self.register_manager.allocRegs(2, .{ null, null }); | 4782 | const regs = try self.register_manager.allocRegs(2, .{ null, null }); |
| 4734 | const count_reg = regs[0].to64(); | 4783 | const count_reg = regs[0].to64(); |
| 4735 | const tmp_reg = regs[1].to8(); | 4784 | const tmp_reg = regs[1].to8(); |
| 4736 | | 4785 | |
| 4737 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); | 4786 | try self.genSetReg(Type.usize, count_reg, len); |
| 4738 | | 4787 | |
| 4739 | // mov rcx, 0 | 4788 | // mov rcx, 0 |
| 4740 | _ = try self.addInst(.{ | 4789 | _ = try self.addInst(.{ |
| ... | @@ -4776,7 +4825,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: | ... | @@ -4776,7 +4825,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: |
| 4776 | .tag = .mov_scale_src, | 4825 | .tag = .mov_scale_src, |
| 4777 | .ops = (Mir.Ops{ | 4826 | .ops = (Mir.Ops{ |
| 4778 | .reg1 = tmp_reg.to8(), | 4827 | .reg1 = tmp_reg.to8(), |
| 4779 | .reg2 = addr_reg, | 4828 | .reg2 = src_addr_reg, |
| 4780 | }).encode(), | 4829 | }).encode(), |
| 4781 | .data = .{ .imm = 0 }, | 4830 | .data = .{ .imm = 0 }, |
| 4782 | }); | 4831 | }); |
| ... | @@ -4785,10 +4834,10 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: | ... | @@ -4785,10 +4834,10 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: |
| 4785 | _ = try self.addInst(.{ | 4834 | _ = try self.addInst(.{ |
| 4786 | .tag = .mov_scale_dst, | 4835 | .tag = .mov_scale_dst, |
| 4787 | .ops = (Mir.Ops{ | 4836 | .ops = (Mir.Ops{ |
| 4788 | .reg1 = opts.dest_stack_base orelse .rbp, | 4837 | .reg1 = dst_addr_reg, |
| 4789 | .reg2 = tmp_reg.to8(), | 4838 | .reg2 = tmp_reg.to8(), |
| 4790 | }).encode(), | 4839 | }).encode(), |
| 4791 | .data = .{ .imm = @bitCast(u32, -stack_offset) }, | 4840 | .data = .{ .imm = 0 }, |
| 4792 | }); | 4841 | }); |
| 4793 | | 4842 | |
| 4794 | // add rcx, 1 | 4843 | // add rcx, 1 |
| ... | @@ -4831,39 +4880,52 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: | ... | @@ -4831,39 +4880,52 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: |
| 4831 | | 4880 | |
| 4832 | fn genInlineMemset( | 4881 | fn genInlineMemset( |
| 4833 | self: *Self, | 4882 | self: *Self, |
| 4834 | stack_offset: i32, | 4883 | dst_ptr: MCValue, |
| 4835 | ty: Type, | | |
| 4836 | value: MCValue, | 4884 | value: MCValue, |
| | 4885 | len: MCValue, |
| 4837 | opts: InlineMemcpyOpts, | 4886 | opts: InlineMemcpyOpts, |
| 4838 | ) InnerError!void { | 4887 | ) InnerError!void { |
| 4839 | try self.register_manager.getReg(.rax, null); | 4888 | try self.register_manager.getReg(.rax, null); |
| | 4889 | self.register_manager.freezeRegs(&.{.rax}); |
| | 4890 | defer self.register_manager.unfreezeRegs(&.{.rax}); |
| 4840 | | 4891 | |
| 4841 | const abi_size = ty.abiSize(self.target.*); | 4892 | const addr_reg = try self.register_manager.allocReg(null); |
| 4842 | const negative_offset = @bitCast(u32, -stack_offset); | 4893 | switch (dst_ptr) { |
| 4843 | | 4894 | .memory, |
| 4844 | // We are actually counting `abi_size` bytes; however, we reuse the index register | 4895 | .got_load, |
| 4845 | // as both the counter and offset scaler, hence we need to subtract one from `abi_size` | 4896 | .direct_load, |
| 4846 | // and count until -1. | 4897 | => { |
| 4847 | if (abi_size > math.maxInt(i32)) { | 4898 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr); |
| 4848 | // movabs rax, abi_size - 1 | 4899 | }, |
| 4849 | const payload = try self.addExtra(Mir.Imm64.encode(abi_size - 1)); | 4900 | .ptr_stack_offset, .stack_offset => |off| { |
| 4850 | _ = try self.addInst(.{ | 4901 | _ = try self.addInst(.{ |
| 4851 | .tag = .movabs, | 4902 | .tag = .lea, |
| 4852 | .ops = (Mir.Ops{ | 4903 | .ops = (Mir.Ops{ |
| 4853 | .reg1 = .rax, | 4904 | .reg1 = addr_reg.to64(), |
| 4854 | }).encode(), | 4905 | .reg2 = opts.dest_stack_base orelse .rbp, |
| 4855 | .data = .{ .payload = payload }, | 4906 | }).encode(), |
| 4856 | }); | 4907 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 4857 | } else { | 4908 | }); |
| 4858 | // mov rax, abi_size - 1 | 4909 | }, |
| 4859 | _ = try self.addInst(.{ | 4910 | .register => |reg| { |
| 4860 | .tag = .mov, | 4911 | _ = try self.addInst(.{ |
| 4861 | .ops = (Mir.Ops{ | 4912 | .tag = .mov, |
| 4862 | .reg1 = .rax, | 4913 | .ops = (Mir.Ops{ |
| 4863 | }).encode(), | 4914 | .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)), |
| 4864 | .data = .{ .imm = @truncate(u32, abi_size - 1) }, | 4915 | .reg2 = reg, |
| 4865 | }); | 4916 | }).encode(), |
| | 4917 | .data = undefined, |
| | 4918 | }); |
| | 4919 | }, |
| | 4920 | else => { |
| | 4921 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); |
| | 4922 | }, |
| 4866 | } | 4923 | } |
| | 4924 | self.register_manager.freezeRegs(&.{addr_reg}); |
| | 4925 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| | 4926 | |
| | 4927 | try self.genSetReg(Type.usize, .rax, len); |
| | 4928 | try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); |
| 4867 | | 4929 | |
| 4868 | // loop: | 4930 | // loop: |
| 4869 | // cmp rax, -1 | 4931 | // cmp rax, -1 |
| ... | @@ -4889,13 +4951,13 @@ fn genInlineMemset( | ... | @@ -4889,13 +4951,13 @@ fn genInlineMemset( |
| 4889 | } | 4951 | } |
| 4890 | // mov byte ptr [rbp + rax + stack_offset], imm | 4952 | // mov byte ptr [rbp + rax + stack_offset], imm |
| 4891 | const payload = try self.addExtra(Mir.ImmPair{ | 4953 | const payload = try self.addExtra(Mir.ImmPair{ |
| 4892 | .dest_off = negative_offset, | 4954 | .dest_off = 0, |
| 4893 | .operand = @truncate(u32, x), | 4955 | .operand = @truncate(u32, x), |
| 4894 | }); | 4956 | }); |
| 4895 | _ = try self.addInst(.{ | 4957 | _ = try self.addInst(.{ |
| 4896 | .tag = .mov_mem_index_imm, | 4958 | .tag = .mov_mem_index_imm, |
| 4897 | .ops = (Mir.Ops{ | 4959 | .ops = (Mir.Ops{ |
| 4898 | .reg1 = opts.dest_stack_base orelse .rbp, | 4960 | .reg1 = addr_reg, |
| 4899 | }).encode(), | 4961 | }).encode(), |
| 4900 | .data = .{ .payload = payload }, | 4962 | .data = .{ .payload = payload }, |
| 4901 | }); | 4963 | }); |
| ... | @@ -5076,33 +5138,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5076,33 +5138,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5076 | .data = undefined, | 5138 | .data = undefined, |
| 5077 | }); | 5139 | }); |
| 5078 | }, | 5140 | }, |
| 5079 | .got_load, | | |
| 5080 | .direct_load, | 5141 | .direct_load, |
| 5081 | => |sym_index| { | 5142 | .got_load, |
| 5082 | const flags: u2 = switch (mcv) { | 5143 | => { |
| 5083 | .got_load => 0b00, | 5144 | try self.loadMemPtrIntoRegister(reg, Type.usize, mcv); |
| 5084 | .direct_load => 0b01, | | |
| 5085 | else => unreachable, | | |
| 5086 | }; | | |
| 5087 | _ = try self.addInst(.{ | | |
| 5088 | .tag = .lea_pie, | | |
| 5089 | .ops = (Mir.Ops{ | | |
| 5090 | .reg1 = reg, | | |
| 5091 | .flags = flags, | | |
| 5092 | }).encode(), | | |
| 5093 | .data = .{ | | |
| 5094 | .load_reloc = .{ | | |
| 5095 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | | |
| 5096 | .sym_index = sym_index, | | |
| 5097 | }, | | |
| 5098 | }, | | |
| 5099 | }); | | |
| 5100 | // MOV reg, [reg] | | |
| 5101 | _ = try self.addInst(.{ | 5145 | _ = try self.addInst(.{ |
| 5102 | .tag = .mov, | 5146 | .tag = .mov, |
| 5103 | .ops = (Mir.Ops{ | 5147 | .ops = (Mir.Ops{ |
| 5104 | .reg1 = reg, | 5148 | .reg1 = reg.to64(), |
| 5105 | .reg2 = reg, | 5149 | .reg2 = reg.to64(), |
| 5106 | .flags = 0b01, | 5150 | .flags = 0b01, |
| 5107 | }).encode(), | 5151 | }).encode(), |
| 5108 | .data = .{ .imm = 0 }, | 5152 | .data = .{ .imm = 0 }, |
| ... | @@ -5278,13 +5322,69 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr | ... | @@ -5278,13 +5322,69 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr |
| 5278 | } | 5322 | } |
| 5279 | | 5323 | |
| 5280 | fn airMemset(self: *Self, inst: Air.Inst.Index) !void { | 5324 | fn airMemset(self: *Self, inst: Air.Inst.Index) !void { |
| 5281 | _ = inst; | 5325 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5282 | return self.fail("TODO implement airMemset for {}", .{self.target.cpu.arch}); | 5326 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| | 5327 | |
| | 5328 | const dst_ptr = try self.resolveInst(pl_op.operand); |
| | 5329 | dst_ptr.freezeIfRegister(&self.register_manager); |
| | 5330 | defer dst_ptr.unfreezeIfRegister(&self.register_manager); |
| | 5331 | |
| | 5332 | const src_val = try self.resolveInst(extra.lhs); |
| | 5333 | src_val.freezeIfRegister(&self.register_manager); |
| | 5334 | defer src_val.unfreezeIfRegister(&self.register_manager); |
| | 5335 | |
| | 5336 | const len = try self.resolveInst(extra.rhs); |
| | 5337 | len.freezeIfRegister(&self.register_manager); |
| | 5338 | defer len.unfreezeIfRegister(&self.register_manager); |
| | 5339 | |
| | 5340 | try self.genInlineMemset(dst_ptr, src_val, len, .{}); |
| | 5341 | |
| | 5342 | return self.finishAir(inst, .none, .{ pl_op.operand, .none, .none }); |
| 5283 | } | 5343 | } |
| 5284 | | 5344 | |
| 5285 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | 5345 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 5286 | _ = inst; | 5346 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5287 | return self.fail("TODO implement airMemcpy for {}", .{self.target.cpu.arch}); | 5347 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| | 5348 | |
| | 5349 | const dst_ptr = try self.resolveInst(pl_op.operand); |
| | 5350 | dst_ptr.freezeIfRegister(&self.register_manager); |
| | 5351 | defer dst_ptr.unfreezeIfRegister(&self.register_manager); |
| | 5352 | |
| | 5353 | const src_ty = self.air.typeOf(extra.lhs); |
| | 5354 | const src_ptr = try self.resolveInst(extra.lhs); |
| | 5355 | src_ptr.freezeIfRegister(&self.register_manager); |
| | 5356 | defer src_ptr.unfreezeIfRegister(&self.register_manager); |
| | 5357 | |
| | 5358 | const len = try self.resolveInst(extra.rhs); |
| | 5359 | len.freezeIfRegister(&self.register_manager); |
| | 5360 | defer len.unfreezeIfRegister(&self.register_manager); |
| | 5361 | |
| | 5362 | // TODO Is this the only condition for pointer dereference for memcpy? |
| | 5363 | const src: MCValue = blk: { |
| | 5364 | switch (src_ptr) { |
| | 5365 | .got_load, .direct_load, .memory => { |
| | 5366 | const reg = try self.register_manager.allocReg(null); |
| | 5367 | try self.loadMemPtrIntoRegister(reg, src_ty, src_ptr); |
| | 5368 | _ = try self.addInst(.{ |
| | 5369 | .tag = .mov, |
| | 5370 | .ops = (Mir.Ops{ |
| | 5371 | .reg1 = reg, |
| | 5372 | .reg2 = reg, |
| | 5373 | .flags = 0b01, |
| | 5374 | }).encode(), |
| | 5375 | .data = .{ .imm = 0 }, |
| | 5376 | }); |
| | 5377 | break :blk MCValue{ .register = reg }; |
| | 5378 | }, |
| | 5379 | else => break :blk src_ptr, |
| | 5380 | } |
| | 5381 | }; |
| | 5382 | src.freezeIfRegister(&self.register_manager); |
| | 5383 | defer src.unfreezeIfRegister(&self.register_manager); |
| | 5384 | |
| | 5385 | try self.genInlineMemcpy(dst_ptr, src, len, .{}); |
| | 5386 | |
| | 5387 | return self.finishAir(inst, .none, .{ pl_op.operand, .none, .none }); |
| 5288 | } | 5388 | } |
| 5289 | | 5389 | |
| 5290 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | 5390 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |