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