| ... | ... | @@ -3986,7 +3986,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 3986 | 3986 | .eflags => unreachable, |
| 3987 | 3987 | .register_overflow => unreachable, |
| 3988 | 3988 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| 3989 | | .ptr_stack_offset, .stack_offset => |off| { |
| 3989 | .stack_offset => |off| { |
| 3990 | 3990 | if (abi_size > 8) { |
| 3991 | 3991 | return self.fail("TODO implement {} for stack dst with large ABI", .{mir_tag}); |
| 3992 | 3992 | } |
| ... | ... | @@ -3996,20 +3996,13 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 3996 | 3996 | .disp = -off, |
| 3997 | 3997 | })); |
| 3998 | 3998 | }, |
| 3999 | .ptr_stack_offset => unreachable, |
| 3999 | 4000 | .memory, .linker_load => { |
| 4000 | 4001 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); |
| 4001 | 4002 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 4002 | 4003 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 4003 | 4004 | |
| 4004 | 4005 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, dst_mcv); |
| 4005 | | |
| 4006 | | // To get the actual address of the value we want to modify we have to go through the GOT |
| 4007 | | try self.asmRegisterMemory( |
| 4008 | | .mov, |
| 4009 | | addr_reg, |
| 4010 | | Memory.sib(.qword, .{ .base = addr_reg }), |
| 4011 | | ); |
| 4012 | | |
| 4013 | 4006 | try self.asmMemory( |
| 4014 | 4007 | mir_tag, |
| 4015 | 4008 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), |
| ... | ... | @@ -4454,7 +4447,7 @@ fn genBinOp( |
| 4454 | 4447 | |
| 4455 | 4448 | else => false, |
| 4456 | 4449 | }; |
| 4457 | | const needs_reg_dst = switch (tag) { |
| 4450 | const dst_mem_ok = switch (tag) { |
| 4458 | 4451 | .add, |
| 4459 | 4452 | .addwrap, |
| 4460 | 4453 | .sub, |
| ... | ... | @@ -4464,9 +4457,9 @@ fn genBinOp( |
| 4464 | 4457 | .div_exact, |
| 4465 | 4458 | .div_trunc, |
| 4466 | 4459 | .div_floor, |
| 4467 | | => lhs_ty.isRuntimeFloat(), |
| 4460 | => !lhs_ty.isRuntimeFloat(), |
| 4468 | 4461 | |
| 4469 | | else => false, |
| 4462 | else => true, |
| 4470 | 4463 | }; |
| 4471 | 4464 | |
| 4472 | 4465 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| ... | ... | @@ -4482,18 +4475,21 @@ fn genBinOp( |
| 4482 | 4475 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4483 | 4476 | |
| 4484 | 4477 | var flipped: bool = false; |
| 4485 | | const dst_mcv: MCValue = blk: { |
| 4478 | const dst_mcv: MCValue = dst: { |
| 4486 | 4479 | if (maybe_inst) |inst| { |
| 4487 | | if ((!needs_reg_dst or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) { |
| 4488 | | break :blk lhs; |
| 4480 | if ((dst_mem_ok or lhs.isRegister()) and self.reuseOperand(inst, lhs_air, 0, lhs)) { |
| 4481 | break :dst lhs; |
| 4489 | 4482 | } |
| 4490 | | if (is_commutative and (!needs_reg_dst or rhs.isRegister()) and self.reuseOperand(inst, rhs_air, 1, rhs)) { |
| 4483 | if (is_commutative and (dst_mem_ok or rhs.isRegister()) and |
| 4484 | self.reuseOperand(inst, rhs_air, 1, rhs)) |
| 4485 | { |
| 4491 | 4486 | flipped = true; |
| 4492 | | break :blk rhs; |
| 4487 | break :dst rhs; |
| 4493 | 4488 | } |
| 4494 | | break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs); |
| 4495 | 4489 | } |
| 4496 | | break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) }; |
| 4490 | const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true); |
| 4491 | try self.setRegOrMem(lhs_ty, dst_mcv, lhs); |
| 4492 | break :dst dst_mcv; |
| 4497 | 4493 | }; |
| 4498 | 4494 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 4499 | 4495 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | ... | @@ -4501,17 +4497,7 @@ fn genBinOp( |
| 4501 | 4497 | }; |
| 4502 | 4498 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 4503 | 4499 | |
| 4504 | | const src_mcv: MCValue = blk: { |
| 4505 | | const mcv = if (flipped) lhs else rhs; |
| 4506 | | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; |
| 4507 | | break :blk MCValue{ .register = try self.copyToTmpRegister(rhs_ty, mcv) }; |
| 4508 | | }; |
| 4509 | | const src_mcv_lock: ?RegisterLock = switch (src_mcv) { |
| 4510 | | .register => |reg| self.register_manager.lockReg(reg), |
| 4511 | | else => null, |
| 4512 | | }; |
| 4513 | | defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 4514 | | |
| 4500 | const src_mcv = if (flipped) lhs else rhs; |
| 4515 | 4501 | switch (tag) { |
| 4516 | 4502 | .add, |
| 4517 | 4503 | .addwrap, |
| ... | ... | @@ -4573,14 +4559,18 @@ fn genBinOp( |
| 4573 | 4559 | .ptr_add, |
| 4574 | 4560 | .ptr_sub, |
| 4575 | 4561 | => { |
| 4576 | | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 4562 | const tmp_reg = try self.copyToTmpRegister(rhs_ty, src_mcv); |
| 4563 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| 4564 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 4565 | defer self.register_manager.unlockReg(tmp_lock); |
| 4566 | |
| 4567 | const elem_size = lhs_ty.elemType2().abiSize(self.target.*); |
| 4568 | try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size }); |
| 4569 | try self.genBinOpMir(switch (tag) { |
| 4577 | 4570 | .ptr_add => .add, |
| 4578 | 4571 | .ptr_sub => .sub, |
| 4579 | 4572 | else => unreachable, |
| 4580 | | }; |
| 4581 | | const elem_size = lhs_ty.elemType2().abiSize(self.target.*); |
| 4582 | | try self.genIntMulComplexOpMir(rhs_ty, src_mcv, .{ .immediate = elem_size }); |
| 4583 | | try self.genBinOpMir(mir_tag, lhs_ty, dst_mcv, src_mcv); |
| 4573 | }, lhs_ty, dst_mcv, tmp_mcv); |
| 4584 | 4574 | }, |
| 4585 | 4575 | |
| 4586 | 4576 | .bool_or, |
| ... | ... | @@ -4657,16 +4647,8 @@ fn genBinOp( |
| 4657 | 4647 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); |
| 4658 | 4648 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 4659 | 4649 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 4660 | | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv); |
| 4661 | | |
| 4662 | | // To get the actual address of the value we want to modify we |
| 4663 | | // we have to go through the GOT |
| 4664 | | try self.asmRegisterMemory( |
| 4665 | | .mov, |
| 4666 | | addr_reg, |
| 4667 | | Memory.sib(.qword, .{ .base = addr_reg }), |
| 4668 | | ); |
| 4669 | 4650 | |
| 4651 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, mat_src_mcv); |
| 4670 | 4652 | try self.asmCmovccRegisterMemory( |
| 4671 | 4653 | registerAlias(tmp_reg, abi_size), |
| 4672 | 4654 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = addr_reg }), |
| ... | ... | @@ -4706,6 +4688,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4706 | 4688 | .eflags => unreachable, |
| 4707 | 4689 | .register_overflow => unreachable, |
| 4708 | 4690 | .register => |dst_reg| { |
| 4691 | const dst_alias = registerAlias(dst_reg, abi_size); |
| 4709 | 4692 | switch (src_mcv) { |
| 4710 | 4693 | .none => unreachable, |
| 4711 | 4694 | .undef => unreachable, |
| ... | ... | @@ -4728,41 +4711,47 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4728 | 4711 | }, |
| 4729 | 4712 | else => try self.asmRegisterRegister( |
| 4730 | 4713 | mir_tag, |
| 4731 | | registerAlias(dst_reg, abi_size), |
| 4714 | dst_alias, |
| 4732 | 4715 | registerAlias(src_reg, abi_size), |
| 4733 | 4716 | ), |
| 4734 | 4717 | }, |
| 4735 | 4718 | .immediate => |imm| { |
| 4736 | 4719 | switch (self.regBitSize(ty)) { |
| 4737 | | 8, 16, 32 => { |
| 4738 | | try self.asmRegisterImmediate( |
| 4739 | | mir_tag, |
| 4740 | | registerAlias(dst_reg, abi_size), |
| 4720 | 8 => try self.asmRegisterImmediate( |
| 4721 | mir_tag, |
| 4722 | dst_alias, |
| 4723 | if (math.cast(i8, @bitCast(i64, imm))) |small| |
| 4724 | Immediate.s(small) |
| 4725 | else |
| 4726 | Immediate.u(@intCast(u8, imm)), |
| 4727 | ), |
| 4728 | 16 => try self.asmRegisterImmediate( |
| 4729 | mir_tag, |
| 4730 | dst_alias, |
| 4731 | if (math.cast(i16, @bitCast(i64, imm))) |small| |
| 4732 | Immediate.s(small) |
| 4733 | else |
| 4734 | Immediate.u(@intCast(u16, imm)), |
| 4735 | ), |
| 4736 | 32 => try self.asmRegisterImmediate( |
| 4737 | mir_tag, |
| 4738 | dst_alias, |
| 4739 | if (math.cast(i32, @bitCast(i64, imm))) |small| |
| 4740 | Immediate.s(small) |
| 4741 | else |
| 4741 | 4742 | Immediate.u(@intCast(u32, imm)), |
| 4742 | | ); |
| 4743 | | }, |
| 4744 | | 64 => { |
| 4745 | | if (math.cast(i32, @bitCast(i64, imm))) |small| { |
| 4746 | | try self.asmRegisterImmediate( |
| 4747 | | mir_tag, |
| 4748 | | registerAlias(dst_reg, abi_size), |
| 4749 | | Immediate.s(small), |
| 4750 | | ); |
| 4751 | | } else { |
| 4752 | | try self.asmRegisterRegister( |
| 4753 | | mir_tag, |
| 4754 | | registerAlias(dst_reg, abi_size), |
| 4755 | | registerAlias(try self.copyToTmpRegister(ty, src_mcv), abi_size), |
| 4756 | | ); |
| 4757 | | } |
| 4758 | | }, |
| 4759 | | else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}), |
| 4743 | ), |
| 4744 | 64 => if (math.cast(i32, @bitCast(i64, imm))) |small| |
| 4745 | try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small)) |
| 4746 | else |
| 4747 | try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias( |
| 4748 | try self.copyToTmpRegister(ty, src_mcv), |
| 4749 | abi_size, |
| 4750 | )), |
| 4751 | else => unreachable, |
| 4760 | 4752 | } |
| 4761 | 4753 | }, |
| 4762 | | .memory, |
| 4763 | | .linker_load, |
| 4764 | | .eflags, |
| 4765 | | => { |
| 4754 | .memory, .linker_load, .eflags => { |
| 4766 | 4755 | assert(abi_size <= 8); |
| 4767 | 4756 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 4768 | 4757 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -4779,7 +4768,27 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4779 | 4768 | }, |
| 4780 | 4769 | } |
| 4781 | 4770 | }, |
| 4782 | | .ptr_stack_offset, .stack_offset => |dst_off| { |
| 4771 | .memory, .linker_load, .stack_offset => { |
| 4772 | const dst: ?struct { |
| 4773 | addr_reg: Register, |
| 4774 | addr_lock: RegisterLock, |
| 4775 | } = switch (dst_mcv) { |
| 4776 | else => unreachable, |
| 4777 | .memory, .linker_load => dst: { |
| 4778 | const dst_addr_reg = try self.register_manager.allocReg(null, gp); |
| 4779 | const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| 4780 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| 4781 | |
| 4782 | try self.loadMemPtrIntoRegister(dst_addr_reg, Type.usize, dst_mcv); |
| 4783 | break :dst .{ |
| 4784 | .addr_reg = dst_addr_reg, |
| 4785 | .addr_lock = dst_addr_lock, |
| 4786 | }; |
| 4787 | }, |
| 4788 | .stack_offset => null, |
| 4789 | }; |
| 4790 | defer if (dst) |lock| self.register_manager.unlockReg(lock.addr_lock); |
| 4791 | |
| 4783 | 4792 | const src: ?struct { |
| 4784 | 4793 | limb_reg: Register, |
| 4785 | 4794 | limb_lock: RegisterLock, |
| ... | ... | @@ -4787,7 +4796,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4787 | 4796 | addr_lock: RegisterLock, |
| 4788 | 4797 | } = switch (src_mcv) { |
| 4789 | 4798 | else => null, |
| 4790 | | .memory, .linker_load => addr: { |
| 4799 | .memory, .linker_load => src: { |
| 4791 | 4800 | const src_limb_reg = try self.register_manager.allocReg(null, gp); |
| 4792 | 4801 | const src_limb_lock = self.register_manager.lockRegAssumeUnused(src_limb_reg); |
| 4793 | 4802 | errdefer self.register_manager.unlockReg(src_limb_lock); |
| ... | ... | @@ -4797,15 +4806,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4797 | 4806 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 4798 | 4807 | |
| 4799 | 4808 | try self.loadMemPtrIntoRegister(src_addr_reg, Type.usize, src_mcv); |
| 4800 | | // To get the actual address of the value we want to modify we |
| 4801 | | // we have to go through the GOT |
| 4802 | | try self.asmRegisterMemory( |
| 4803 | | .mov, |
| 4804 | | src_addr_reg, |
| 4805 | | Memory.sib(.qword, .{ .base = src_addr_reg }), |
| 4806 | | ); |
| 4807 | | |
| 4808 | | break :addr .{ |
| 4809 | break :src .{ |
| 4809 | 4810 | .addr_reg = src_addr_reg, |
| 4810 | 4811 | .addr_lock = src_addr_lock, |
| 4811 | 4812 | .limb_reg = src_limb_reg, |
| ... | ... | @@ -4831,7 +4832,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4831 | 4832 | 0 => mir_tag, |
| 4832 | 4833 | else => switch (mir_tag) { |
| 4833 | 4834 | .add => .adc, |
| 4834 | | .sub => .sbb, |
| 4835 | .sub, .cmp => .sbb, |
| 4835 | 4836 | .@"or", .@"and", .xor => mir_tag, |
| 4836 | 4837 | else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{ |
| 4837 | 4838 | @tagName(mir_tag), |
| ... | ... | @@ -4840,7 +4841,14 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4840 | 4841 | }; |
| 4841 | 4842 | const dst_limb_mem = Memory.sib( |
| 4842 | 4843 | Memory.PtrSize.fromSize(limb_abi_size), |
| 4843 | | .{ .base = .rbp, .disp = off - dst_off }, |
| 4844 | switch (dst_mcv) { |
| 4845 | else => unreachable, |
| 4846 | .stack_offset => |dst_off| .{ |
| 4847 | .base = .rbp, |
| 4848 | .disp = off - dst_off, |
| 4849 | }, |
| 4850 | .memory, .linker_load => .{ .base = dst.?.addr_reg, .disp = off }, |
| 4851 | }, |
| 4844 | 4852 | ); |
| 4845 | 4853 | switch (src_mcv) { |
| 4846 | 4854 | .none => unreachable, |
| ... | ... | @@ -4861,34 +4869,45 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4861 | 4869 | .unsigned => 0, |
| 4862 | 4870 | }; |
| 4863 | 4871 | switch (self.regBitSize(limb_ty)) { |
| 4864 | | 8, 16, 32 => { |
| 4872 | 8 => try self.asmMemoryImmediate( |
| 4873 | mir_limb_tag, |
| 4874 | dst_limb_mem, |
| 4875 | if (math.cast(i8, @bitCast(i64, imm))) |small| |
| 4876 | Immediate.s(small) |
| 4877 | else |
| 4878 | Immediate.u(@intCast(u8, imm)), |
| 4879 | ), |
| 4880 | 16 => try self.asmMemoryImmediate( |
| 4881 | mir_limb_tag, |
| 4882 | dst_limb_mem, |
| 4883 | if (math.cast(i16, @bitCast(i64, imm))) |small| |
| 4884 | Immediate.s(small) |
| 4885 | else |
| 4886 | Immediate.u(@intCast(u16, imm)), |
| 4887 | ), |
| 4888 | 32 => try self.asmMemoryImmediate( |
| 4889 | mir_limb_tag, |
| 4890 | dst_limb_mem, |
| 4891 | if (math.cast(i32, @bitCast(i64, imm))) |small| |
| 4892 | Immediate.s(small) |
| 4893 | else |
| 4894 | Immediate.u(@intCast(u32, imm)), |
| 4895 | ), |
| 4896 | 64 => if (math.cast(i32, @bitCast(i64, imm))) |small| |
| 4865 | 4897 | try self.asmMemoryImmediate( |
| 4866 | 4898 | mir_limb_tag, |
| 4867 | 4899 | dst_limb_mem, |
| 4868 | | if (math.cast(i32, @bitCast(i64, imm))) |small| |
| 4869 | | Immediate.s(small) |
| 4870 | | else |
| 4871 | | Immediate.u(@intCast(u32, imm)), |
| 4872 | | ); |
| 4873 | | }, |
| 4874 | | 64 => { |
| 4875 | | if (math.cast(i32, @bitCast(i64, imm))) |small| { |
| 4876 | | try self.asmMemoryImmediate( |
| 4877 | | mir_limb_tag, |
| 4878 | | dst_limb_mem, |
| 4879 | | Immediate.s(small), |
| 4880 | | ); |
| 4881 | | } else { |
| 4882 | | try self.asmMemoryRegister( |
| 4883 | | mir_limb_tag, |
| 4884 | | dst_limb_mem, |
| 4885 | | registerAlias( |
| 4886 | | try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }), |
| 4887 | | limb_abi_size, |
| 4888 | | ), |
| 4889 | | ); |
| 4890 | | } |
| 4891 | | }, |
| 4900 | Immediate.s(small), |
| 4901 | ) |
| 4902 | else |
| 4903 | try self.asmMemoryRegister( |
| 4904 | mir_limb_tag, |
| 4905 | dst_limb_mem, |
| 4906 | registerAlias( |
| 4907 | try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }), |
| 4908 | limb_abi_size, |
| 4909 | ), |
| 4910 | ), |
| 4892 | 4911 | else => unreachable, |
| 4893 | 4912 | } |
| 4894 | 4913 | }, |
| ... | ... | @@ -4930,12 +4949,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 4930 | 4949 | } |
| 4931 | 4950 | } |
| 4932 | 4951 | }, |
| 4933 | | .memory => { |
| 4934 | | return self.fail("TODO implement x86 genBinOpMir destination memory", .{}); |
| 4935 | | }, |
| 4936 | | .linker_load => { |
| 4937 | | return self.fail("TODO implement x86 genBinOpMir destination symbol at index", .{}); |
| 4938 | | }, |
| 4952 | .ptr_stack_offset => unreachable, |
| 4939 | 4953 | } |
| 4940 | 4954 | } |
| 4941 | 4955 | |
| ... | ... | @@ -5452,79 +5466,61 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5452 | 5466 | |
| 5453 | 5467 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 5454 | 5468 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5469 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 5470 | const ty = self.air.typeOf(bin_op.lhs); |
| 5471 | const ty_abi_size = ty.abiSize(self.target.*); |
| 5472 | const can_reuse = ty_abi_size <= 8; |
| 5455 | 5473 | |
| 5456 | | if (self.liveness.isUnused(inst)) { |
| 5457 | | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5458 | | } |
| 5459 | | |
| 5460 | | const ty = self.air.typeOf(bin_op.lhs); |
| 5461 | | const abi_size = ty.abiSize(self.target.*); |
| 5462 | | if (abi_size > 8) return self.fail("TODO implement cmp for large values", .{}); |
| 5463 | | |
| 5464 | | const signedness: std.builtin.Signedness = blk: { |
| 5465 | | // For non-int types, we treat the values as unsigned |
| 5466 | | if (ty.zigTypeTag() != .Int) break :blk .unsigned; |
| 5467 | | |
| 5468 | | // Otherwise, we take the signedness of the actual int |
| 5469 | | break :blk ty.intInfo(self.target.*).signedness; |
| 5470 | | }; |
| 5471 | | |
| 5472 | | try self.spillEflagsIfOccupied(); |
| 5473 | | self.eflags_inst = inst; |
| 5474 | try self.spillEflagsIfOccupied(); |
| 5475 | self.eflags_inst = inst; |
| 5474 | 5476 | |
| 5475 | | const result: MCValue = result: { |
| 5476 | | // There are 2 operands, destination and source. |
| 5477 | | // Either one, but not both, can be a memory operand. |
| 5478 | | // Source operand can be an immediate, 8 bits or 32 bits. |
| 5479 | | // TODO look into reusing the operand |
| 5480 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 5481 | | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 5477 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 5478 | const lhs_lock = switch (lhs_mcv) { |
| 5482 | 5479 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5483 | 5480 | else => null, |
| 5484 | 5481 | }; |
| 5485 | 5482 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5486 | 5483 | |
| 5487 | | const dst_reg = try self.copyToTmpRegister(ty, lhs); |
| 5488 | | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 5489 | | defer self.register_manager.unlockReg(dst_reg_lock); |
| 5490 | | |
| 5491 | | const dst_mcv = MCValue{ .register = dst_reg }; |
| 5492 | | |
| 5493 | | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 5494 | | // This instruction supports only signed 32-bit immediates at most. |
| 5495 | | const src_mcv: MCValue = blk: { |
| 5496 | | switch (rhs_ty.zigTypeTag()) { |
| 5497 | | .Float => { |
| 5498 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 5499 | | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 5500 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5501 | | else => null, |
| 5502 | | }; |
| 5503 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5504 | | const src_reg = try self.copyToTmpRegister(rhs_ty, rhs); |
| 5505 | | break :blk MCValue{ .register = src_reg }; |
| 5506 | | }, |
| 5507 | | else => break :blk try self.limitImmediateType(bin_op.rhs, i32), |
| 5508 | | } |
| 5484 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 5485 | const rhs_lock = switch (rhs_mcv) { |
| 5486 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 5487 | else => null, |
| 5509 | 5488 | }; |
| 5510 | | const src_lock: ?RegisterLock = switch (src_mcv) { |
| 5489 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 5490 | |
| 5491 | const dst_mem_ok = !ty.isRuntimeFloat(); |
| 5492 | var flipped = false; |
| 5493 | const dst_mcv: MCValue = if (can_reuse and !lhs_mcv.isImmediate() and |
| 5494 | (dst_mem_ok or lhs_mcv.isRegister()) and self.liveness.operandDies(inst, 0)) |
| 5495 | lhs_mcv |
| 5496 | else if (can_reuse and !rhs_mcv.isImmediate() and |
| 5497 | (dst_mem_ok or rhs_mcv.isRegister()) and self.liveness.operandDies(inst, 1)) |
| 5498 | dst: { |
| 5499 | flipped = true; |
| 5500 | break :dst rhs_mcv; |
| 5501 | } else if (dst_mem_ok) dst: { |
| 5502 | const dst_mcv = try self.allocTempRegOrMem(ty, true); |
| 5503 | try self.setRegOrMem(ty, dst_mcv, lhs_mcv); |
| 5504 | break :dst dst_mcv; |
| 5505 | } else .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) }; |
| 5506 | const dst_lock = switch (dst_mcv) { |
| 5511 | 5507 | .register => |reg| self.register_manager.lockReg(reg), |
| 5512 | 5508 | else => null, |
| 5513 | 5509 | }; |
| 5514 | | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 5510 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5515 | 5511 | |
| 5512 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 5516 | 5513 | try self.genBinOpMir(switch (ty.tag()) { |
| 5517 | 5514 | else => .cmp, |
| 5518 | 5515 | .f32 => .ucomiss, |
| 5519 | 5516 | .f64 => .ucomisd, |
| 5520 | 5517 | }, ty, dst_mcv, src_mcv); |
| 5521 | 5518 | |
| 5522 | | break :result switch (signedness) { |
| 5523 | | .signed => MCValue{ .eflags = Condition.fromCompareOperatorSigned(op) }, |
| 5524 | | .unsigned => MCValue{ .eflags = Condition.fromCompareOperatorUnsigned(op) }, |
| 5519 | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; |
| 5520 | break :result .{ |
| 5521 | .eflags = Condition.fromCompareOperator(signedness, if (flipped) op.reverse() else op), |
| 5525 | 5522 | }; |
| 5526 | 5523 | }; |
| 5527 | | |
| 5528 | 5524 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 5529 | 5525 | } |
| 5530 | 5526 | |
| ... | ... | @@ -5785,13 +5781,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5785 | 5781 | |
| 5786 | 5782 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv); |
| 5787 | 5783 | |
| 5788 | | // To get the actual address of the value we want to modify we have to go through the GOT |
| 5789 | | try self.asmRegisterMemory( |
| 5790 | | .mov, |
| 5791 | | addr_reg, |
| 5792 | | Memory.sib(.qword, .{ .base = addr_reg }), |
| 5793 | | ); |
| 5794 | | |
| 5795 | 5784 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); |
| 5796 | 5785 | try self.asmMemoryImmediate(.cmp, Memory.sib( |
| 5797 | 5786 | Memory.PtrSize.fromSize(some_abi_size), |
| ... | ... | @@ -6803,22 +6792,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 6803 | 6792 | }, |
| 6804 | 6793 | } |
| 6805 | 6794 | }, |
| 6806 | | .memory, .linker_load => { |
| 6807 | | if (abi_size <= 8) { |
| 6808 | | const reg = try self.copyToTmpRegister(ty, mcv); |
| 6809 | | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 6810 | | } |
| 6811 | | |
| 6812 | | try self.genInlineMemcpy(.{ .stack_offset = stack_offset }, mcv, .{ .immediate = abi_size }, opts); |
| 6813 | | }, |
| 6814 | | .ptr_stack_offset => { |
| 6815 | | const reg = try self.copyToTmpRegister(ty, mcv); |
| 6816 | | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }, opts); |
| 6817 | | }, |
| 6818 | | .stack_offset => |off| { |
| 6819 | | if (stack_offset == off) { |
| 6820 | | // Copy stack variable to itself; nothing to do. |
| 6821 | | return; |
| 6795 | .memory, .linker_load, .stack_offset, .ptr_stack_offset => { |
| 6796 | switch (mcv) { |
| 6797 | else => unreachable, |
| 6798 | .memory, .linker_load, .ptr_stack_offset => {}, |
| 6799 | .stack_offset => |src_off| if (stack_offset == src_off) { |
| 6800 | // Copy stack variable to itself; nothing to do. |
| 6801 | return; |
| 6802 | }, |
| 6822 | 6803 | } |
| 6823 | 6804 | |
| 6824 | 6805 | if (abi_size <= 8) { |
| ... | ... | @@ -7096,69 +7077,38 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7096 | 7077 | |
| 7097 | 7078 | try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size)); |
| 7098 | 7079 | }, |
| 7099 | | .linker_load => { |
| 7100 | | switch (ty.zigTypeTag()) { |
| 7101 | | .Float => { |
| 7102 | | const base_reg = try self.register_manager.allocReg(null, gp); |
| 7103 | | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); |
| 7104 | | |
| 7105 | | if (intrinsicsAllowed(self.target.*, ty)) { |
| 7106 | | const tag: Mir.Inst.Tag = switch (ty.tag()) { |
| 7107 | | .f32 => .movss, |
| 7108 | | .f64 => .movsd, |
| 7109 | | else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}), |
| 7110 | | }; |
| 7111 | | const ptr_size: Memory.PtrSize = switch (ty.tag()) { |
| 7112 | | .f32 => .dword, |
| 7113 | | .f64 => .qword, |
| 7114 | | else => unreachable, |
| 7115 | | }; |
| 7116 | | return self.asmRegisterMemory( |
| 7117 | | tag, |
| 7118 | | reg.to128(), |
| 7119 | | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), |
| 7120 | | ); |
| 7121 | | } |
| 7122 | | |
| 7123 | | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); |
| 7124 | | }, |
| 7125 | | else => { |
| 7126 | | try self.loadMemPtrIntoRegister(reg, Type.usize, mcv); |
| 7127 | | try self.asmRegisterMemory( |
| 7128 | | .mov, |
| 7129 | | registerAlias(reg, abi_size), |
| 7130 | | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), |
| 7131 | | ); |
| 7132 | | }, |
| 7133 | | } |
| 7134 | | }, |
| 7135 | | .memory => |x| switch (ty.zigTypeTag()) { |
| 7080 | .memory, .linker_load => switch (ty.zigTypeTag()) { |
| 7136 | 7081 | .Float => { |
| 7137 | 7082 | const base_reg = try self.register_manager.allocReg(null, gp); |
| 7138 | 7083 | try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv); |
| 7139 | 7084 | |
| 7140 | 7085 | if (intrinsicsAllowed(self.target.*, ty)) { |
| 7141 | | const tag: Mir.Inst.Tag = switch (ty.tag()) { |
| 7142 | | .f32 => .movss, |
| 7143 | | .f64 => .movsd, |
| 7144 | | else => return self.fail("TODO genSetReg from memory for {}", .{ty.fmtDebug()}), |
| 7145 | | }; |
| 7146 | | const ptr_size: Memory.PtrSize = switch (ty.tag()) { |
| 7147 | | .f32 => .dword, |
| 7148 | | .f64 => .qword, |
| 7149 | | else => unreachable, |
| 7150 | | }; |
| 7151 | 7086 | return self.asmRegisterMemory( |
| 7152 | | tag, |
| 7087 | switch (ty.tag()) { |
| 7088 | .f32 => .movss, |
| 7089 | .f64 => .movsd, |
| 7090 | else => return self.fail("TODO genSetReg from memory for {}", .{ |
| 7091 | ty.fmt(self.bin_file.options.module.?), |
| 7092 | }), |
| 7093 | }, |
| 7153 | 7094 | reg.to128(), |
| 7154 | | Memory.sib(ptr_size, .{ .base = base_reg.to64() }), |
| 7095 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg.to64() }), |
| 7155 | 7096 | ); |
| 7156 | 7097 | } |
| 7157 | 7098 | |
| 7158 | 7099 | return self.fail("TODO genSetReg from memory for float with no intrinsics", .{}); |
| 7159 | 7100 | }, |
| 7160 | | else => { |
| 7161 | | if (x <= math.maxInt(i32)) { |
| 7101 | else => switch (mcv) { |
| 7102 | else => unreachable, |
| 7103 | .linker_load => { |
| 7104 | try self.loadMemPtrIntoRegister(reg, Type.usize, mcv); |
| 7105 | try self.asmRegisterMemory( |
| 7106 | .mov, |
| 7107 | registerAlias(reg, abi_size), |
| 7108 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), |
| 7109 | ); |
| 7110 | }, |
| 7111 | .memory => |x| if (x <= math.maxInt(i32)) { |
| 7162 | 7112 | try self.asmRegisterMemory( |
| 7163 | 7113 | .mov, |
| 7164 | 7114 | registerAlias(reg, abi_size), |
| ... | ... | @@ -7185,7 +7135,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7185 | 7135 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }), |
| 7186 | 7136 | ); |
| 7187 | 7137 | } |
| 7188 | | } |
| 7138 | }, |
| 7189 | 7139 | }, |
| 7190 | 7140 | }, |
| 7191 | 7141 | .stack_offset => |off| { |
| ... | ... | @@ -7226,15 +7176,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 7226 | 7176 | .{ty.fmtDebug()}, |
| 7227 | 7177 | ), |
| 7228 | 7178 | }; |
| 7229 | | const ptr_size: Memory.PtrSize = switch (ty.tag()) { |
| 7230 | | .f32 => .dword, |
| 7231 | | .f64 => .qword, |
| 7232 | | else => unreachable, |
| 7233 | | }; |
| 7234 | | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib(ptr_size, .{ |
| 7235 | | .base = .rbp, |
| 7236 | | .disp = -off, |
| 7237 | | })); |
| 7179 | return self.asmRegisterMemory(tag, reg.to128(), Memory.sib( |
| 7180 | Memory.PtrSize.fromSize(abi_size), |
| 7181 | .{ .base = .rbp, .disp = -off }, |
| 7182 | )); |
| 7238 | 7183 | } |
| 7239 | 7184 | return self.fail("TODO genSetReg from stack offset for float with no intrinsics", .{}); |
| 7240 | 7185 | }, |