| ... | ... | @@ -5263,21 +5263,29 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void { |
| 5263 | 5263 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5264 | 5264 | const ty = self.typeOf(un_op); |
| 5265 | 5265 | |
| 5266 | | const src_mcv = try self.resolveInst(un_op); |
| 5267 | | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) |
| 5268 | | src_mcv |
| 5269 | | else |
| 5270 | | try self.copyToRegisterWithInstTracking(inst, ty, src_mcv); |
| 5271 | | const dst_reg = dst_mcv.getReg().?; |
| 5272 | | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 5273 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5274 | | try self.genRound(ty, dst_reg, src_mcv, mode); |
| 5275 | | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 5266 | const result = result: { |
| 5267 | switch (try self.genRoundLibcall(ty, .{ .air_ref = un_op }, mode)) { |
| 5268 | .none => {}, |
| 5269 | else => |dst_mcv| break :result dst_mcv, |
| 5270 | } |
| 5271 | |
| 5272 | const src_mcv = try self.resolveInst(un_op); |
| 5273 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) |
| 5274 | src_mcv |
| 5275 | else |
| 5276 | try self.copyToRegisterWithInstTracking(inst, ty, src_mcv); |
| 5277 | const dst_reg = dst_mcv.getReg().?; |
| 5278 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 5279 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5280 | try self.genRound(ty, dst_reg, src_mcv, mode); |
| 5281 | break :result dst_mcv; |
| 5282 | }; |
| 5283 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 5276 | 5284 | } |
| 5277 | 5285 | |
| 5278 | | fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void { |
| 5286 | fn getRoundTag(self: *Self, ty: Type) ?Mir.Inst.FixedTag { |
| 5279 | 5287 | const mod = self.bin_file.options.module.?; |
| 5280 | | const mir_tag = @as(?Mir.Inst.FixedTag, if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) { |
| 5288 | return if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) { |
| 5281 | 5289 | .Float => switch (ty.floatBits(self.target.*)) { |
| 5282 | 5290 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, |
| 5283 | 5291 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, |
| ... | ... | @@ -5304,26 +5312,38 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro |
| 5304 | 5312 | else => null, |
| 5305 | 5313 | }, |
| 5306 | 5314 | else => unreachable, |
| 5307 | | } else null) orelse { |
| 5308 | | if (ty.zigTypeTag(mod) != .Float) |
| 5309 | | return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)}); |
| 5310 | | |
| 5311 | | var callee: ["__trunc?".len]u8 = undefined; |
| 5312 | | const res = try self.genCall(.{ .lib = .{ |
| 5313 | | .return_type = ty.toIntern(), |
| 5314 | | .param_types = &.{ty.toIntern()}, |
| 5315 | | .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{ |
| 5316 | | floatLibcAbiPrefix(ty), |
| 5317 | | switch (mode.mode) { |
| 5318 | | .down => "floor", |
| 5319 | | .up => "ceil", |
| 5320 | | .zero => "trunc", |
| 5321 | | else => unreachable, |
| 5322 | | }, |
| 5323 | | floatLibcAbiSuffix(ty), |
| 5324 | | }) catch unreachable, |
| 5325 | | } }, &.{ty}, &.{src_mcv}); |
| 5326 | | return self.genSetReg(dst_reg, ty, res); |
| 5315 | } else null; |
| 5316 | } |
| 5317 | |
| 5318 | fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MCValue { |
| 5319 | const mod = self.bin_file.options.module.?; |
| 5320 | if (self.getRoundTag(ty)) |_| return .none; |
| 5321 | |
| 5322 | if (ty.zigTypeTag(mod) != .Float) |
| 5323 | return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)}); |
| 5324 | |
| 5325 | var callee: ["__trunc?".len]u8 = undefined; |
| 5326 | return try self.genCall(.{ .lib = .{ |
| 5327 | .return_type = ty.toIntern(), |
| 5328 | .param_types = &.{ty.toIntern()}, |
| 5329 | .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{ |
| 5330 | floatLibcAbiPrefix(ty), |
| 5331 | switch (mode.mode) { |
| 5332 | .down => "floor", |
| 5333 | .up => "ceil", |
| 5334 | .zero => "trunc", |
| 5335 | else => unreachable, |
| 5336 | }, |
| 5337 | floatLibcAbiSuffix(ty), |
| 5338 | }) catch unreachable, |
| 5339 | } }, &.{ty}, &.{src_mcv}); |
| 5340 | } |
| 5341 | |
| 5342 | fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void { |
| 5343 | const mod = self.bin_file.options.module.?; |
| 5344 | const mir_tag = self.getRoundTag(ty) orelse { |
| 5345 | const result = try self.genRoundLibcall(ty, src_mcv, mode); |
| 5346 | return self.genSetReg(dst_reg, ty, result); |
| 5327 | 5347 | }; |
| 5328 | 5348 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 5329 | 5349 | const dst_alias = registerAlias(dst_reg, abi_size); |
| ... | ... | @@ -6760,11 +6780,17 @@ fn genBinOp( |
| 6760 | 6780 | else => unreachable, |
| 6761 | 6781 | }) { |
| 6762 | 6782 | var callee: ["__add?f3".len]u8 = undefined; |
| 6763 | | return self.genCall(.{ .lib = .{ |
| 6783 | const result = try self.genCall(.{ .lib = .{ |
| 6764 | 6784 | .return_type = lhs_ty.toIntern(), |
| 6765 | 6785 | .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, |
| 6766 | 6786 | .callee = switch (air_tag) { |
| 6767 | | .add, .sub, .mul, .div_float => std.fmt.bufPrint(&callee, "__{s}{c}f3", .{ |
| 6787 | .add, |
| 6788 | .sub, |
| 6789 | .mul, |
| 6790 | .div_float, |
| 6791 | .div_trunc, |
| 6792 | .div_floor, |
| 6793 | => std.fmt.bufPrint(&callee, "__{s}{c}f3", .{ |
| 6768 | 6794 | @tagName(air_tag)[0..3], |
| 6769 | 6795 | floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)), |
| 6770 | 6796 | }), |
| ... | ... | @@ -6778,6 +6804,17 @@ fn genBinOp( |
| 6778 | 6804 | }), |
| 6779 | 6805 | } catch unreachable, |
| 6780 | 6806 | } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }); |
| 6807 | return switch (air_tag) { |
| 6808 | .div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{ |
| 6809 | .mode = switch (air_tag) { |
| 6810 | .div_trunc => .zero, |
| 6811 | .div_floor => .down, |
| 6812 | else => unreachable, |
| 6813 | }, |
| 6814 | .precision = .inexact, |
| 6815 | }), |
| 6816 | else => result, |
| 6817 | }; |
| 6781 | 6818 | } |
| 6782 | 6819 | |
| 6783 | 6820 | if ((lhs_ty.scalarType(mod).isRuntimeFloat() and |
| ... | ... | @@ -7666,16 +7703,14 @@ fn genBinOp( |
| 7666 | 7703 | |
| 7667 | 7704 | switch (air_tag) { |
| 7668 | 7705 | .add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {}, |
| 7669 | | .div_trunc, .div_floor => try self.genRound( |
| 7670 | | lhs_ty, |
| 7671 | | dst_reg, |
| 7672 | | .{ .register = dst_reg }, |
| 7673 | | .{ .mode = switch (air_tag) { |
| 7706 | .div_trunc, .div_floor => try self.genRound(lhs_ty, dst_reg, .{ .register = dst_reg }, .{ |
| 7707 | .mode = switch (air_tag) { |
| 7674 | 7708 | .div_trunc => .zero, |
| 7675 | 7709 | .div_floor => .down, |
| 7676 | 7710 | else => unreachable, |
| 7677 | | }, .precision = .inexact }, |
| 7678 | | ), |
| 7711 | }, |
| 7712 | .precision = .inexact, |
| 7713 | }), |
| 7679 | 7714 | .bit_and, .bit_or, .xor => {}, |
| 7680 | 7715 | .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) { |
| 7681 | 7716 | const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size); |
| ... | ... | @@ -8673,7 +8708,10 @@ fn genCall(self: *Self, info: union(enum) { |
| 8673 | 8708 | try self.spillRegisters(&regs); |
| 8674 | 8709 | try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); |
| 8675 | 8710 | }, |
| 8676 | | .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8711 | .load_frame => { |
| 8712 | try self.genCopy(arg_ty, dst_arg, src_arg); |
| 8713 | try self.freeValue(src_arg); |
| 8714 | }, |
| 8677 | 8715 | else => unreachable, |
| 8678 | 8716 | }; |
| 8679 | 8717 | |