authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-01 17:59:21+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-01 17:59:21+01:00
logad03fef71222ad4335107257451c1828fb9adc88
treec820beca9cfac30ea1ea659f2f21f63e93a16406
parentca97caab8a02813eb76388e72e2a9dab1f5fa047
parentcaa4e30ef458ee150a9ce9950293827957afb87c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11019 from ziglang/x64-air-memcpy

x64: memcpy and memset

3 files changed, 184 insertions(+), 86 deletions(-)

src/arch/x86_64/CodeGen.zig+183-83
...@@ -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 }
23482348
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 }
25262527
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 }
44714475
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 }
44974501
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 }
46524661
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 }
46694678
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};
46794688
4680fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: InlineMemcpyOpts) InnerError!void {4689fn genInlineMemcpy(
4681 const abi_size = ty.abiSize(self.target.*);4690 self: *Self,
46824691 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` before4696 // 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});
46964709
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 }
47294778
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});
47324781
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();
47364785
4737 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });4786 try self.genSetReg(Type.usize, count_reg, len);
47384787
4739 // mov rcx, 04788 // 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 });
47934842
4794 // add rcx, 14843 // 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:
48314880
4832fn genInlineMemset(4881fn 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});
48404891
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) {
48434894 .memory,
4844 // We are actually counting `abi_size` bytes; however, we reuse the index register4895 .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 - 14899 },
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 - 14909 },
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 });
48674929
4868 // loop:4930 // loop:
4869 // cmp rax, -14931 // 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], imm4952 // 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}
52795323
5280fn airMemset(self: *Self, inst: Air.Inst.Index) !void {5324fn 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}
52845344
5285fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {5345fn 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}
52895389
5290fn airTagName(self: *Self, inst: Air.Inst.Index) !void {5390fn airTagName(self: *Self, inst: Air.Inst.Index) !void {
test/behavior/basic.zig-1
...@@ -341,7 +341,6 @@ fn f2(x: bool) []const u8 {...@@ -341,7 +341,6 @@ fn f2(x: bool) []const u8 {
341test "memcpy and memset intrinsics" {341test "memcpy and memset intrinsics" {
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
344 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
345 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO344 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
346345
347 try testMemcpyMemset();346 try testMemcpyMemset();
test/behavior/struct.zig+1-2
...@@ -80,12 +80,11 @@ const StructWithNoFields = struct {...@@ -80,12 +80,11 @@ const StructWithNoFields = struct {
80const StructFoo = struct {80const StructFoo = struct {
81 a: i32,81 a: i32,
82 b: bool,82 b: bool,
83 c: f32,83 c: u64,
84};84};
8585
86test "structs" {86test "structs" {
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9089
91 var foo: StructFoo = undefined;90 var foo: StructFoo = undefined;