| ... | @@ -4413,9 +4413,12 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -4413,9 +4413,12 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 4413 | const reg = try self.copyToTmpRegister(ty, mcv); | 4413 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4414 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | 4414 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 4415 | } | 4415 | } |
| 4416 | try self.genInlineMemset(stack_offset, ty, .{ .immediate = 0xaa }, .{ | 4416 | try self.genInlineMemset( |
| 4417 | .dest_stack_base = .rsp, | 4417 | .{ .stack_offset = stack_offset }, |
| 4418 | }); | 4418 | .{ .immediate = 0xaa }, |
| | 4419 | .{ .immediate = abi_size }, |
| | 4420 | .{ .dest_stack_base = .rsp }, |
| | 4421 | ); |
| 4419 | }, | 4422 | }, |
| 4420 | .compare_flags_unsigned, | 4423 | .compare_flags_unsigned, |
| 4421 | .compare_flags_signed, | 4424 | .compare_flags_signed, |
| ... | @@ -4519,7 +4522,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -4519,7 +4522,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 4519 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }, opts), | 4522 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }, opts), |
| 4520 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }, opts), | 4523 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }, opts), |
| 4521 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts), | 4524 | 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }, opts), |
| 4522 | 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 | ), |
| 4523 | } | 4531 | } |
| 4524 | }, | 4532 | }, |
| 4525 | .compare_flags_unsigned, | 4533 | .compare_flags_unsigned, |
| ... | @@ -4701,8 +4709,8 @@ fn genInlineMemcpy( | ... | @@ -4701,8 +4709,8 @@ fn genInlineMemcpy( |
| 4701 | | 4709 | |
| 4702 | const dst_addr_reg = try self.register_manager.allocReg(null); | 4710 | const dst_addr_reg = try self.register_manager.allocReg(null); |
| 4703 | switch (dst_ptr) { | 4711 | switch (dst_ptr) { |
| 4704 | .got_load => unreachable, | | |
| 4705 | .memory, | 4712 | .memory, |
| | 4713 | .got_load, |
| 4706 | .direct_load, | 4714 | .direct_load, |
| 4707 | => { | 4715 | => { |
| 4708 | try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr); | 4716 | try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_ptr); |
| ... | @@ -4737,8 +4745,8 @@ fn genInlineMemcpy( | ... | @@ -4737,8 +4745,8 @@ fn genInlineMemcpy( |
| 4737 | | 4745 | |
| 4738 | const src_addr_reg = try self.register_manager.allocReg(null); | 4746 | const src_addr_reg = try self.register_manager.allocReg(null); |
| 4739 | switch (src_ptr) { | 4747 | switch (src_ptr) { |
| 4740 | .got_load => unreachable, | | |
| 4741 | .memory, | 4748 | .memory, |
| | 4749 | .got_load, |
| 4742 | .direct_load, | 4750 | .direct_load, |
| 4743 | => { | 4751 | => { |
| 4744 | try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr); | 4752 | try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_ptr); |
| ... | @@ -4872,39 +4880,52 @@ fn genInlineMemcpy( | ... | @@ -4872,39 +4880,52 @@ fn genInlineMemcpy( |
| 4872 | | 4880 | |
| 4873 | fn genInlineMemset( | 4881 | fn genInlineMemset( |
| 4874 | self: *Self, | 4882 | self: *Self, |
| 4875 | stack_offset: i32, | 4883 | dst_ptr: MCValue, |
| 4876 | ty: Type, | | |
| 4877 | value: MCValue, | 4884 | value: MCValue, |
| | 4885 | len: MCValue, |
| 4878 | opts: InlineMemcpyOpts, | 4886 | opts: InlineMemcpyOpts, |
| 4879 | ) InnerError!void { | 4887 | ) InnerError!void { |
| 4880 | 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}); |
| 4881 | | 4891 | |
| 4882 | const abi_size = ty.abiSize(self.target.*); | 4892 | const addr_reg = try self.register_manager.allocReg(null); |
| 4883 | const negative_offset = @bitCast(u32, -stack_offset); | 4893 | switch (dst_ptr) { |
| 4884 | | 4894 | .memory, |
| 4885 | // We are actually counting `abi_size` bytes; however, we reuse the index register | 4895 | .got_load, |
| 4886 | // as both the counter and offset scaler, hence we need to subtract one from `abi_size` | 4896 | .direct_load, |
| 4887 | // and count until -1. | 4897 | => { |
| 4888 | if (abi_size > math.maxInt(i32)) { | 4898 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_ptr); |
| 4889 | // movabs rax, abi_size - 1 | 4899 | }, |
| 4890 | const payload = try self.addExtra(Mir.Imm64.encode(abi_size - 1)); | 4900 | .ptr_stack_offset, .stack_offset => |off| { |
| 4891 | _ = try self.addInst(.{ | 4901 | _ = try self.addInst(.{ |
| 4892 | .tag = .movabs, | 4902 | .tag = .lea, |
| 4893 | .ops = (Mir.Ops{ | 4903 | .ops = (Mir.Ops{ |
| 4894 | .reg1 = .rax, | 4904 | .reg1 = addr_reg.to64(), |
| 4895 | }).encode(), | 4905 | .reg2 = opts.dest_stack_base orelse .rbp, |
| 4896 | .data = .{ .payload = payload }, | 4906 | }).encode(), |
| 4897 | }); | 4907 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 4898 | } else { | 4908 | }); |
| 4899 | // mov rax, abi_size - 1 | 4909 | }, |
| 4900 | _ = try self.addInst(.{ | 4910 | .register => |reg| { |
| 4901 | .tag = .mov, | 4911 | _ = try self.addInst(.{ |
| 4902 | .ops = (Mir.Ops{ | 4912 | .tag = .mov, |
| 4903 | .reg1 = .rax, | 4913 | .ops = (Mir.Ops{ |
| 4904 | }).encode(), | 4914 | .reg1 = registerAlias(addr_reg, @divExact(reg.size(), 8)), |
| 4905 | .data = .{ .imm = @truncate(u32, abi_size - 1) }, | 4915 | .reg2 = reg, |
| 4906 | }); | 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 | }, |
| 4907 | } | 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 }); |
| 4908 | | 4929 | |
| 4909 | // loop: | 4930 | // loop: |
| 4910 | // cmp rax, -1 | 4931 | // cmp rax, -1 |
| ... | @@ -4930,13 +4951,13 @@ fn genInlineMemset( | ... | @@ -4930,13 +4951,13 @@ fn genInlineMemset( |
| 4930 | } | 4951 | } |
| 4931 | // mov byte ptr [rbp + rax + stack_offset], imm | 4952 | // mov byte ptr [rbp + rax + stack_offset], imm |
| 4932 | const payload = try self.addExtra(Mir.ImmPair{ | 4953 | const payload = try self.addExtra(Mir.ImmPair{ |
| 4933 | .dest_off = negative_offset, | 4954 | .dest_off = 0, |
| 4934 | .operand = @truncate(u32, x), | 4955 | .operand = @truncate(u32, x), |
| 4935 | }); | 4956 | }); |
| 4936 | _ = try self.addInst(.{ | 4957 | _ = try self.addInst(.{ |
| 4937 | .tag = .mov_mem_index_imm, | 4958 | .tag = .mov_mem_index_imm, |
| 4938 | .ops = (Mir.Ops{ | 4959 | .ops = (Mir.Ops{ |
| 4939 | .reg1 = opts.dest_stack_base orelse .rbp, | 4960 | .reg1 = addr_reg, |
| 4940 | }).encode(), | 4961 | }).encode(), |
| 4941 | .data = .{ .payload = payload }, | 4962 | .data = .{ .payload = payload }, |
| 4942 | }); | 4963 | }); |
| ... | @@ -5301,8 +5322,24 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr | ... | @@ -5301,8 +5322,24 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr |
| 5301 | } | 5322 | } |
| 5302 | | 5323 | |
| 5303 | fn airMemset(self: *Self, inst: Air.Inst.Index) !void { | 5324 | fn airMemset(self: *Self, inst: Air.Inst.Index) !void { |
| 5304 | _ = inst; | 5325 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5305 | 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 }); |
| 5306 | } | 5343 | } |
| 5307 | | 5344 | |
| 5308 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | 5345 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -5313,6 +5350,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5313,6 +5350,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 5313 | dst_ptr.freezeIfRegister(&self.register_manager); | 5350 | dst_ptr.freezeIfRegister(&self.register_manager); |
| 5314 | defer dst_ptr.unfreezeIfRegister(&self.register_manager); | 5351 | defer dst_ptr.unfreezeIfRegister(&self.register_manager); |
| 5315 | | 5352 | |
| | 5353 | const src_ty = self.air.typeOf(extra.lhs); |
| 5316 | const src_ptr = try self.resolveInst(extra.lhs); | 5354 | const src_ptr = try self.resolveInst(extra.lhs); |
| 5317 | src_ptr.freezeIfRegister(&self.register_manager); | 5355 | src_ptr.freezeIfRegister(&self.register_manager); |
| 5318 | defer src_ptr.unfreezeIfRegister(&self.register_manager); | 5356 | defer src_ptr.unfreezeIfRegister(&self.register_manager); |
| ... | @@ -5321,8 +5359,30 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5321,8 +5359,30 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 5321 | len.freezeIfRegister(&self.register_manager); | 5359 | len.freezeIfRegister(&self.register_manager); |
| 5322 | defer len.unfreezeIfRegister(&self.register_manager); | 5360 | defer len.unfreezeIfRegister(&self.register_manager); |
| 5323 | | 5361 | |
| 5324 | log.warn("dst_ptr = {}, src_ptr = {}, len = {}", .{ dst_ptr, src_ptr, len }); | 5362 | // TODO Is this the only condition for pointer dereference for memcpy? |
| 5325 | try self.genInlineMemcpy(dst_ptr, src_ptr, len, .{}); | 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, .{}); |
| 5326 | | 5386 | |
| 5327 | return self.finishAir(inst, .none, .{ pl_op.operand, .none, .none }); | 5387 | return self.finishAir(inst, .none, .{ pl_op.operand, .none, .none }); |
| 5328 | } | 5388 | } |