| ... | @@ -5263,21 +5263,29 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void { | ... | @@ -5263,21 +5263,29 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void { |
| 5263 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5263 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5264 | const ty = self.typeOf(un_op); | 5264 | const ty = self.typeOf(un_op); |
| 5265 | | 5265 | |
| 5266 | const src_mcv = try self.resolveInst(un_op); | 5266 | const result = result: { |
| 5267 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) | 5267 | switch (try self.genRoundLibcall(ty, .{ .air_ref = un_op }, mode)) { |
| 5268 | src_mcv | 5268 | .none => {}, |
| 5269 | else | 5269 | else => |dst_mcv| break :result dst_mcv, |
| 5270 | try self.copyToRegisterWithInstTracking(inst, ty, src_mcv); | 5270 | } |
| 5271 | const dst_reg = dst_mcv.getReg().?; | 5271 | |
| 5272 | const dst_lock = self.register_manager.lockReg(dst_reg); | 5272 | const src_mcv = try self.resolveInst(un_op); |
| 5273 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 5273 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) |
| 5274 | try self.genRound(ty, dst_reg, src_mcv, mode); | 5274 | src_mcv |
| 5275 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); | 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 | const mod = self.bin_file.options.module.?; | 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 | .Float => switch (ty.floatBits(self.target.*)) { | 5289 | .Float => switch (ty.floatBits(self.target.*)) { |
| 5282 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, | 5290 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, |
| 5283 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, | 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,26 +5312,38 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro |
| 5304 | else => null, | 5312 | else => null, |
| 5305 | }, | 5313 | }, |
| 5306 | else => unreachable, | 5314 | else => unreachable, |
| 5307 | } else null) orelse { | 5315 | } else null; |
| 5308 | if (ty.zigTypeTag(mod) != .Float) | 5316 | } |
| 5309 | return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)}); | 5317 | |
| 5310 | | 5318 | fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MCValue { |
| 5311 | var callee: ["__trunc?".len]u8 = undefined; | 5319 | const mod = self.bin_file.options.module.?; |
| 5312 | const res = try self.genCall(.{ .lib = .{ | 5320 | if (self.getRoundTag(ty)) |_| return .none; |
| 5313 | .return_type = ty.toIntern(), | 5321 | |
| 5314 | .param_types = &.{ty.toIntern()}, | 5322 | if (ty.zigTypeTag(mod) != .Float) |
| 5315 | .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{ | 5323 | return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)}); |
| 5316 | floatLibcAbiPrefix(ty), | 5324 | |
| 5317 | switch (mode.mode) { | 5325 | var callee: ["__trunc?".len]u8 = undefined; |
| 5318 | .down => "floor", | 5326 | return try self.genCall(.{ .lib = .{ |
| 5319 | .up => "ceil", | 5327 | .return_type = ty.toIntern(), |
| 5320 | .zero => "trunc", | 5328 | .param_types = &.{ty.toIntern()}, |
| 5321 | else => unreachable, | 5329 | .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{ |
| 5322 | }, | 5330 | floatLibcAbiPrefix(ty), |
| 5323 | floatLibcAbiSuffix(ty), | 5331 | switch (mode.mode) { |
| 5324 | }) catch unreachable, | 5332 | .down => "floor", |
| 5325 | } }, &.{ty}, &.{src_mcv}); | 5333 | .up => "ceil", |
| 5326 | return self.genSetReg(dst_reg, ty, res); | 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 | const abi_size: u32 = @intCast(ty.abiSize(mod)); | 5348 | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 5329 | const dst_alias = registerAlias(dst_reg, abi_size); | 5349 | const dst_alias = registerAlias(dst_reg, abi_size); |
| ... | @@ -6760,11 +6780,17 @@ fn genBinOp( | ... | @@ -6760,11 +6780,17 @@ fn genBinOp( |
| 6760 | else => unreachable, | 6780 | else => unreachable, |
| 6761 | }) { | 6781 | }) { |
| 6762 | var callee: ["__add?f3".len]u8 = undefined; | 6782 | var callee: ["__add?f3".len]u8 = undefined; |
| 6763 | return self.genCall(.{ .lib = .{ | 6783 | const result = try self.genCall(.{ .lib = .{ |
| 6764 | .return_type = lhs_ty.toIntern(), | 6784 | .return_type = lhs_ty.toIntern(), |
| 6765 | .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, | 6785 | .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, |
| 6766 | .callee = switch (air_tag) { | 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 | @tagName(air_tag)[0..3], | 6794 | @tagName(air_tag)[0..3], |
| 6769 | floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)), | 6795 | floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)), |
| 6770 | }), | 6796 | }), |
| ... | @@ -6778,6 +6804,17 @@ fn genBinOp( | ... | @@ -6778,6 +6804,17 @@ fn genBinOp( |
| 6778 | }), | 6804 | }), |
| 6779 | } catch unreachable, | 6805 | } catch unreachable, |
| 6780 | } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }); | 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 | if ((lhs_ty.scalarType(mod).isRuntimeFloat() and | 6820 | if ((lhs_ty.scalarType(mod).isRuntimeFloat() and |
| ... | @@ -7666,16 +7703,14 @@ fn genBinOp( | ... | @@ -7666,16 +7703,14 @@ fn genBinOp( |
| 7666 | | 7703 | |
| 7667 | switch (air_tag) { | 7704 | switch (air_tag) { |
| 7668 | .add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {}, | 7705 | .add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {}, |
| 7669 | .div_trunc, .div_floor => try self.genRound( | 7706 | .div_trunc, .div_floor => try self.genRound(lhs_ty, dst_reg, .{ .register = dst_reg }, .{ |
| 7670 | lhs_ty, | 7707 | .mode = switch (air_tag) { |
| 7671 | dst_reg, | | |
| 7672 | .{ .register = dst_reg }, | | |
| 7673 | .{ .mode = switch (air_tag) { | | |
| 7674 | .div_trunc => .zero, | 7708 | .div_trunc => .zero, |
| 7675 | .div_floor => .down, | 7709 | .div_floor => .down, |
| 7676 | else => unreachable, | 7710 | else => unreachable, |
| 7677 | }, .precision = .inexact }, | 7711 | }, |
| 7678 | ), | 7712 | .precision = .inexact, |
| | 7713 | }), |
| 7679 | .bit_and, .bit_or, .xor => {}, | 7714 | .bit_and, .bit_or, .xor => {}, |
| 7680 | .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) { | 7715 | .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) { |
| 7681 | const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size); | 7716 | const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size); |
| ... | @@ -8673,7 +8708,10 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8673,7 +8708,10 @@ fn genCall(self: *Self, info: union(enum) { |
| 8673 | try self.spillRegisters(&regs); | 8708 | try self.spillRegisters(&regs); |
| 8674 | try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); | 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 | else => unreachable, | 8715 | else => unreachable, |
| 8678 | }; | 8716 | }; |
| 8679 | | 8717 | |