| ... | @@ -3008,7 +3008,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3008,7 +3008,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 3008 | | 3008 | |
| 3009 | try self.genCopy(dst_ty, dst_mcv, src_mcv); | 3009 | try self.genCopy(dst_ty, dst_mcv, src_mcv); |
| 3010 | break :dst dst_mcv; | 3010 | break :dst dst_mcv; |
| 3011 | } else return self.fail("TODO implement trunc from {} to {}", .{ src_ty.fmt(mod), dst_ty.fmt(mod) }); | 3011 | } else try self.allocRegOrMem(inst, true); |
| 3012 | | 3012 | |
| 3013 | if (dst_ty.zigTypeTag(mod) == .Vector) { | 3013 | if (dst_ty.zigTypeTag(mod) == .Vector) { |
| 3014 | assert(src_ty.zigTypeTag(mod) == .Vector and dst_ty.vectorLen(mod) == src_ty.vectorLen(mod)); | 3014 | assert(src_ty.zigTypeTag(mod) == .Vector and dst_ty.vectorLen(mod) == src_ty.vectorLen(mod)); |
| ... | @@ -3429,7 +3429,10 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3429,7 +3429,10 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3429 | }; | 3429 | }; |
| 3430 | | 3430 | |
| 3431 | try self.spillEflagsIfOccupied(); | 3431 | try self.spillEflagsIfOccupied(); |
| 3432 | try self.spillRegisters(&.{ .rax, .rdx }); | 3432 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| | 3433 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx }); |
| | 3434 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| | 3435 | |
| 3433 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 3436 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 3434 | const rhs_mcv = try self.resolveInst(bin_op.rhs); | 3437 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 3435 | break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs_mcv, rhs_mcv); | 3438 | break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs_mcv, rhs_mcv); |
| ... | @@ -3685,9 +3688,9 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3685,9 +3688,9 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3685 | .{ty.fmt(mod)}, | 3688 | .{ty.fmt(mod)}, |
| 3686 | ); | 3689 | ); |
| 3687 | | 3690 | |
| 3688 | try self.spillRegisters(&.{ .rax, .rdx }); | 3691 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| 3689 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); | 3692 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx }); |
| 3690 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); | 3693 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 3691 | | 3694 | |
| 3692 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 3695 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 3693 | const lhs_lock = switch (lhs_mcv) { | 3696 | const lhs_lock = switch (lhs_mcv) { |
| ... | @@ -3950,11 +3953,154 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3950,11 +3953,154 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3950 | .Vector => return self.fail("TODO implement airMulWithOverflow for {}", .{dst_ty.fmt(mod)}), | 3953 | .Vector => return self.fail("TODO implement airMulWithOverflow for {}", .{dst_ty.fmt(mod)}), |
| 3951 | .Int => result: { | 3954 | .Int => result: { |
| 3952 | const dst_info = dst_ty.intInfo(mod); | 3955 | const dst_info = dst_ty.intInfo(mod); |
| | 3956 | if (dst_info.bits > 128 and dst_info.signedness == .unsigned) { |
| | 3957 | const slow_inc = self.hasFeature(.slow_incdec); |
| | 3958 | const abi_size: u32 = @intCast(dst_ty.abiSize(mod)); |
| | 3959 | const limb_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; |
| | 3960 | |
| | 3961 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| | 3962 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx }); |
| | 3963 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| | 3964 | |
| | 3965 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| | 3966 | try self.genInlineMemset( |
| | 3967 | dst_mcv.address(), |
| | 3968 | .{ .immediate = 0 }, |
| | 3969 | .{ .immediate = tuple_ty.abiSize(mod) }, |
| | 3970 | ); |
| | 3971 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| | 3972 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| | 3973 | |
| | 3974 | const temp_regs = try self.register_manager.allocRegs( |
| | 3975 | 4, |
| | 3976 | .{ null, null, null, null }, |
| | 3977 | abi.RegisterClass.gp, |
| | 3978 | ); |
| | 3979 | const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs); |
| | 3980 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| | 3981 | |
| | 3982 | try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[0].to32(), temp_regs[0].to32()); |
| | 3983 | |
| | 3984 | const outer_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| | 3985 | try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[1].to64(), .{ |
| | 3986 | .base = .{ .frame = rhs_mcv.load_frame.index }, |
| | 3987 | .mod = .{ .rm = .{ |
| | 3988 | .size = .qword, |
| | 3989 | .index = temp_regs[0].to64(), |
| | 3990 | .scale = .@"8", |
| | 3991 | } }, |
| | 3992 | }); |
| | 3993 | try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64()); |
| | 3994 | const skip_inner = try self.asmJccReloc(.z, undefined); |
| | 3995 | |
| | 3996 | try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[2].to32(), temp_regs[2].to32()); |
| | 3997 | try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[3].to32(), temp_regs[0].to32()); |
| | 3998 | try self.asmRegisterRegister(.{ ._, .xor }, .ecx, .ecx); |
| | 3999 | try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx); |
| | 4000 | |
| | 4001 | const inner_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| | 4002 | try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, Immediate.u(1)); |
| | 4003 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| | 4004 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| | 4005 | .mod = .{ .rm = .{ |
| | 4006 | .size = .qword, |
| | 4007 | .index = temp_regs[3].to64(), |
| | 4008 | .scale = .@"8", |
| | 4009 | .disp = @intCast(tuple_ty.structFieldOffset(0, mod)), |
| | 4010 | } }, |
| | 4011 | }, .rdx); |
| | 4012 | try self.asmSetccRegister(.c, .cl); |
| | 4013 | |
| | 4014 | try self.asmRegisterMemory(.{ ._, .mov }, .rax, .{ |
| | 4015 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| | 4016 | .mod = .{ .rm = .{ |
| | 4017 | .size = .qword, |
| | 4018 | .index = temp_regs[2].to64(), |
| | 4019 | .scale = .@"8", |
| | 4020 | } }, |
| | 4021 | }); |
| | 4022 | try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64()); |
| | 4023 | |
| | 4024 | try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, Immediate.u(1)); |
| | 4025 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| | 4026 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| | 4027 | .mod = .{ .rm = .{ |
| | 4028 | .size = .qword, |
| | 4029 | .index = temp_regs[3].to64(), |
| | 4030 | .scale = .@"8", |
| | 4031 | .disp = @intCast(tuple_ty.structFieldOffset(0, mod)), |
| | 4032 | } }, |
| | 4033 | }, .rax); |
| | 4034 | try self.asmSetccRegister(.c, .ch); |
| | 4035 | |
| | 4036 | if (slow_inc) { |
| | 4037 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), Immediate.u(1)); |
| | 4038 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), Immediate.u(1)); |
| | 4039 | } else { |
| | 4040 | try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32()); |
| | 4041 | try self.asmRegister(.{ ._, .inc }, temp_regs[3].to32()); |
| | 4042 | } |
| | 4043 | try self.asmRegisterImmediate( |
| | 4044 | .{ ._, .cmp }, |
| | 4045 | temp_regs[3].to32(), |
| | 4046 | Immediate.u(limb_len), |
| | 4047 | ); |
| | 4048 | _ = try self.asmJccReloc(.b, inner_loop); |
| | 4049 | |
| | 4050 | try self.asmRegisterRegister(.{ ._, .@"or" }, .rdx, .rcx); |
| | 4051 | const overflow = try self.asmJccReloc(.nz, undefined); |
| | 4052 | const overflow_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| | 4053 | try self.asmRegisterImmediate( |
| | 4054 | .{ ._, .cmp }, |
| | 4055 | temp_regs[2].to32(), |
| | 4056 | Immediate.u(limb_len), |
| | 4057 | ); |
| | 4058 | const no_overflow = try self.asmJccReloc(.nb, undefined); |
| | 4059 | if (slow_inc) { |
| | 4060 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), Immediate.u(1)); |
| | 4061 | } else { |
| | 4062 | try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32()); |
| | 4063 | } |
| | 4064 | try self.asmMemoryImmediate(.{ ._, .cmp }, .{ |
| | 4065 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| | 4066 | .mod = .{ .rm = .{ |
| | 4067 | .size = .qword, |
| | 4068 | .index = temp_regs[2].to64(), |
| | 4069 | .scale = .@"8", |
| | 4070 | .disp = -8, |
| | 4071 | } }, |
| | 4072 | }, Immediate.u(0)); |
| | 4073 | _ = try self.asmJccReloc(.z, overflow_loop); |
| | 4074 | try self.performReloc(overflow); |
| | 4075 | try self.asmMemoryImmediate(.{ ._, .mov }, .{ |
| | 4076 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| | 4077 | .mod = .{ .rm = .{ |
| | 4078 | .size = .byte, |
| | 4079 | .disp = @intCast(tuple_ty.structFieldOffset(1, mod)), |
| | 4080 | } }, |
| | 4081 | }, Immediate.u(1)); |
| | 4082 | try self.performReloc(no_overflow); |
| | 4083 | |
| | 4084 | try self.performReloc(skip_inner); |
| | 4085 | if (slow_inc) { |
| | 4086 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1)); |
| | 4087 | } else { |
| | 4088 | try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32()); |
| | 4089 | } |
| | 4090 | try self.asmRegisterImmediate( |
| | 4091 | .{ ._, .cmp }, |
| | 4092 | temp_regs[0].to32(), |
| | 4093 | Immediate.u(limb_len), |
| | 4094 | ); |
| | 4095 | _ = try self.asmJccReloc(.b, outer_loop); |
| | 4096 | |
| | 4097 | break :result dst_mcv; |
| | 4098 | } |
| | 4099 | |
| 3953 | const lhs_active_bits = self.activeIntBits(bin_op.lhs); | 4100 | const lhs_active_bits = self.activeIntBits(bin_op.lhs); |
| 3954 | const rhs_active_bits = self.activeIntBits(bin_op.rhs); | 4101 | const rhs_active_bits = self.activeIntBits(bin_op.rhs); |
| 3955 | const src_bits = @max(lhs_active_bits, rhs_active_bits, dst_info.bits / 2); | 4102 | const src_bits = @max(lhs_active_bits, rhs_active_bits, dst_info.bits / 2); |
| 3956 | const src_ty = try mod.intType(dst_info.signedness, src_bits); | 4103 | const src_ty = try mod.intType(dst_info.signedness, src_bits); |
| 3957 | | | |
| 3958 | if (src_bits > 64 and src_bits <= 128 and | 4104 | if (src_bits > 64 and src_bits <= 128 and |
| 3959 | dst_info.bits > 64 and dst_info.bits <= 128) switch (dst_info.signedness) { | 4105 | dst_info.bits > 64 and dst_info.bits <= 128) switch (dst_info.signedness) { |
| 3960 | .signed => { | 4106 | .signed => { |
| ... | @@ -4110,7 +4256,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4110,7 +4256,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4110 | }; | 4256 | }; |
| 4111 | | 4257 | |
| 4112 | try self.spillEflagsIfOccupied(); | 4258 | try self.spillEflagsIfOccupied(); |
| 4113 | try self.spillRegisters(&.{ .rax, .rdx }); | 4259 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| | 4260 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx }); |
| | 4261 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 4114 | | 4262 | |
| 4115 | const cc: Condition = switch (dst_info.signedness) { | 4263 | const cc: Condition = switch (dst_info.signedness) { |
| 4116 | .unsigned => .c, | 4264 | .unsigned => .c, |
| ... | @@ -8053,13 +8201,14 @@ fn genMulDivBinOp( | ... | @@ -8053,13 +8201,14 @@ fn genMulDivBinOp( |
| 8053 | const src_abi_size: u32 = @intCast(src_ty.abiSize(mod)); | 8201 | const src_abi_size: u32 = @intCast(src_ty.abiSize(mod)); |
| 8054 | | 8202 | |
| 8055 | assert(self.register_manager.isRegFree(.rax)); | 8203 | assert(self.register_manager.isRegFree(.rax)); |
| | 8204 | assert(self.register_manager.isRegFree(.rcx)); |
| 8056 | assert(self.register_manager.isRegFree(.rdx)); | 8205 | assert(self.register_manager.isRegFree(.rdx)); |
| 8057 | assert(self.eflags_inst == null); | 8206 | assert(self.eflags_inst == null); |
| 8058 | | 8207 | |
| 8059 | if (dst_abi_size == 16 and src_abi_size == 16) { | 8208 | if (dst_abi_size == 16 and src_abi_size == 16) { |
| 8060 | assert(tag == .mul or tag == .mul_wrap); | 8209 | assert(tag == .mul or tag == .mul_wrap); |
| 8061 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); | 8210 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 8062 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); | 8211 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 8063 | | 8212 | |
| 8064 | const mat_lhs_mcv = switch (lhs_mcv) { | 8213 | const mat_lhs_mcv = switch (lhs_mcv) { |
| 8065 | .load_symbol => mat_lhs_mcv: { | 8214 | .load_symbol => mat_lhs_mcv: { |
| ... | @@ -8124,10 +8273,171 @@ fn genMulDivBinOp( | ... | @@ -8124,10 +8273,171 @@ fn genMulDivBinOp( |
| 8124 | else => unreachable, | 8273 | else => unreachable, |
| 8125 | .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, | 8274 | .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, |
| 8126 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size, | 8275 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size, |
| 8127 | } or src_abi_size > 8) return self.fail( | 8276 | } or src_abi_size > 8) { |
| 8128 | "TODO implement genMulDivBinOp for {s} from {} to {}", | 8277 | const src_info = src_ty.intInfo(mod); |
| 8129 | .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) }, | 8278 | switch (tag) { |
| 8130 | ); | 8279 | .mul, .mul_wrap => { |
| | 8280 | const slow_inc = self.hasFeature(.slow_incdec); |
| | 8281 | const limb_len = std.math.divCeil(u32, src_abi_size, 8) catch unreachable; |
| | 8282 | |
| | 8283 | try self.spillRegisters(&.{ .rax, .rcx, .rdx }); |
| | 8284 | const reg_locks = self.register_manager.lockRegs(3, .{ .rax, .rcx, .rdx }); |
| | 8285 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| |
| | 8286 | self.register_manager.unlockReg(lock); |
| | 8287 | |
| | 8288 | const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false); |
| | 8289 | try self.genInlineMemset( |
| | 8290 | dst_mcv.address(), |
| | 8291 | .{ .immediate = 0 }, |
| | 8292 | .{ .immediate = src_abi_size }, |
| | 8293 | ); |
| | 8294 | |
| | 8295 | const temp_regs = try self.register_manager.allocRegs( |
| | 8296 | 4, |
| | 8297 | .{ null, null, null, null }, |
| | 8298 | abi.RegisterClass.gp, |
| | 8299 | ); |
| | 8300 | const temp_locks = self.register_manager.lockRegs(4, temp_regs); |
| | 8301 | defer for (temp_locks) |temp_lock| if (temp_lock) |lock| |
| | 8302 | self.register_manager.unlockReg(lock); |
| | 8303 | |
| | 8304 | try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[0].to32(), temp_regs[0].to32()); |
| | 8305 | |
| | 8306 | const outer_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| | 8307 | try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[1].to64(), .{ |
| | 8308 | .base = .{ .frame = rhs_mcv.load_frame.index }, |
| | 8309 | .mod = .{ .rm = .{ |
| | 8310 | .size = .qword, |
| | 8311 | .index = temp_regs[0].to64(), |
| | 8312 | .scale = .@"8", |
| | 8313 | } }, |
| | 8314 | }); |
| | 8315 | try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64()); |
| | 8316 | const skip_inner = try self.asmJccReloc(.z, undefined); |
| | 8317 | |
| | 8318 | try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[2].to32(), temp_regs[2].to32()); |
| | 8319 | try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[3].to32(), temp_regs[0].to32()); |
| | 8320 | try self.asmRegisterRegister(.{ ._, .xor }, .ecx, .ecx); |
| | 8321 | try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx); |
| | 8322 | |
| | 8323 | const inner_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| | 8324 | try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, Immediate.u(1)); |
| | 8325 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| | 8326 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| | 8327 | .mod = .{ .rm = .{ |
| | 8328 | .size = .qword, |
| | 8329 | .index = temp_regs[3].to64(), |
| | 8330 | .scale = .@"8", |
| | 8331 | } }, |
| | 8332 | }, .rdx); |
| | 8333 | try self.asmSetccRegister(.c, .cl); |
| | 8334 | |
| | 8335 | try self.asmRegisterMemory(.{ ._, .mov }, .rax, .{ |
| | 8336 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| | 8337 | .mod = .{ .rm = .{ |
| | 8338 | .size = .qword, |
| | 8339 | .index = temp_regs[2].to64(), |
| | 8340 | .scale = .@"8", |
| | 8341 | } }, |
| | 8342 | }); |
| | 8343 | try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64()); |
| | 8344 | |
| | 8345 | try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, Immediate.u(1)); |
| | 8346 | try self.asmMemoryRegister(.{ ._, .adc }, .{ |
| | 8347 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| | 8348 | .mod = .{ .rm = .{ |
| | 8349 | .size = .qword, |
| | 8350 | .index = temp_regs[3].to64(), |
| | 8351 | .scale = .@"8", |
| | 8352 | } }, |
| | 8353 | }, .rax); |
| | 8354 | try self.asmSetccRegister(.c, .ch); |
| | 8355 | |
| | 8356 | if (slow_inc) { |
| | 8357 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), Immediate.u(1)); |
| | 8358 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), Immediate.u(1)); |
| | 8359 | } else { |
| | 8360 | try self.asmRegister(.{ ._, .inc }, temp_regs[2].to32()); |
| | 8361 | try self.asmRegister(.{ ._, .inc }, temp_regs[3].to32()); |
| | 8362 | } |
| | 8363 | try self.asmRegisterImmediate( |
| | 8364 | .{ ._, .cmp }, |
| | 8365 | temp_regs[3].to32(), |
| | 8366 | Immediate.u(limb_len), |
| | 8367 | ); |
| | 8368 | _ = try self.asmJccReloc(.b, inner_loop); |
| | 8369 | |
| | 8370 | try self.performReloc(skip_inner); |
| | 8371 | if (slow_inc) { |
| | 8372 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1)); |
| | 8373 | } else { |
| | 8374 | try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32()); |
| | 8375 | } |
| | 8376 | try self.asmRegisterImmediate( |
| | 8377 | .{ ._, .cmp }, |
| | 8378 | temp_regs[0].to32(), |
| | 8379 | Immediate.u(limb_len), |
| | 8380 | ); |
| | 8381 | _ = try self.asmJccReloc(.b, outer_loop); |
| | 8382 | |
| | 8383 | return dst_mcv; |
| | 8384 | }, |
| | 8385 | .div_trunc, .div_floor, .div_exact, .rem, .mod => switch (src_info.signedness) { |
| | 8386 | .signed => {}, |
| | 8387 | .unsigned => { |
| | 8388 | const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false); |
| | 8389 | const manyptr_u32_ty = try mod.ptrType(.{ |
| | 8390 | .child = .u32_type, |
| | 8391 | .flags = .{ |
| | 8392 | .size = .Many, |
| | 8393 | }, |
| | 8394 | }); |
| | 8395 | const manyptr_const_u32_ty = try mod.ptrType(.{ |
| | 8396 | .child = .u32_type, |
| | 8397 | .flags = .{ |
| | 8398 | .size = .Many, |
| | 8399 | .is_const = true, |
| | 8400 | }, |
| | 8401 | }); |
| | 8402 | _ = try self.genCall(.{ .lib = .{ |
| | 8403 | .return_type = .void_type, |
| | 8404 | .param_types = &.{ |
| | 8405 | manyptr_u32_ty.toIntern(), |
| | 8406 | manyptr_const_u32_ty.toIntern(), |
| | 8407 | manyptr_const_u32_ty.toIntern(), |
| | 8408 | .usize_type, |
| | 8409 | }, |
| | 8410 | .callee = switch (tag) { |
| | 8411 | .div_trunc, |
| | 8412 | .div_floor, |
| | 8413 | .div_exact, |
| | 8414 | => "__udivei4", |
| | 8415 | .rem, |
| | 8416 | .mod, |
| | 8417 | => "__umodei4", |
| | 8418 | else => unreachable, |
| | 8419 | }, |
| | 8420 | } }, &.{ |
| | 8421 | manyptr_u32_ty, |
| | 8422 | manyptr_const_u32_ty, |
| | 8423 | manyptr_const_u32_ty, |
| | 8424 | Type.usize, |
| | 8425 | }, &.{ |
| | 8426 | dst_mcv.address(), |
| | 8427 | lhs_mcv.address(), |
| | 8428 | rhs_mcv.address(), |
| | 8429 | .{ .immediate = src_info.bits }, |
| | 8430 | }); |
| | 8431 | return dst_mcv; |
| | 8432 | }, |
| | 8433 | }, |
| | 8434 | else => {}, |
| | 8435 | } |
| | 8436 | return self.fail( |
| | 8437 | "TODO implement genMulDivBinOp for {s} from {} to {}", |
| | 8438 | .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) }, |
| | 8439 | ); |
| | 8440 | } |
| 8131 | const ty = if (dst_abi_size <= 8) dst_ty else src_ty; | 8441 | const ty = if (dst_abi_size <= 8) dst_ty else src_ty; |
| 8132 | const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size; | 8442 | const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size; |
| 8133 | | 8443 | |