authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-22 21:58:26-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-23 22:42:18-04:00
logfbe8c8938b4efef12a2aa992eec3c947e5f65e70
treee15909e1094233b6da95344e2dc5ffd44c82e920
parentfe93332ba26b0cb8ca6ecce0b2c605d49a02ca87

x86_64: implement `@mod` for floating-point types


3 files changed, 187 insertions(+), 69 deletions(-)

lib/std/math.zig+2-2
...@@ -903,12 +903,12 @@ pub fn mod(comptime T: type, numerator: T, denominator: T) !T {...@@ -903,12 +903,12 @@ pub fn mod(comptime T: type, numerator: T, denominator: T) !T {
903}903}
904904
905test "mod" {905test "mod" {
906 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
907
906 try testMod();908 try testMod();
907 try comptime testMod();909 try comptime testMod();
908}910}
909fn testMod() !void {911fn testMod() !void {
910 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
911
912 try testing.expect((mod(i32, -5, 3) catch unreachable) == 1);912 try testing.expect((mod(i32, -5, 3) catch unreachable) == 1);
913 try testing.expect((mod(i32, 5, 3) catch unreachable) == 2);913 try testing.expect((mod(i32, 5, 3) catch unreachable) == 2);
914 try testing.expectError(error.NegativeDenominator, mod(i32, 10, -1));914 try testing.expectError(error.NegativeDenominator, mod(i32, 10, -1));
src/arch/x86_64/CodeGen.zig+183-65
...@@ -2745,11 +2745,11 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -2745,11 +2745,11 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
2745 },2745 },
2746 else => unreachable,2746 else => unreachable,
2747 }) {2747 }) {
2748 var callee: ["__trunc?f?f2".len]u8 = undefined;2748 var callee_buf: ["__trunc?f?f2".len]u8 = undefined;
2749 break :result try self.genCall(.{ .lib = .{2749 break :result try self.genCall(.{ .lib = .{
2750 .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(),2750 .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(),
2751 .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()},2751 .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()},
2752 .callee = std.fmt.bufPrint(&callee, "__trunc{c}f{c}f2", .{2752 .callee = std.fmt.bufPrint(&callee_buf, "__trunc{c}f{c}f2", .{
2753 floatCompilerRtAbiName(src_bits),2753 floatCompilerRtAbiName(src_bits),
2754 floatCompilerRtAbiName(dst_bits),2754 floatCompilerRtAbiName(dst_bits),
2755 }) catch unreachable,2755 }) catch unreachable,
...@@ -2777,7 +2777,7 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {...@@ -2777,7 +2777,7 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void {
2777 .{ .v_, .cvtps2ph },2777 .{ .v_, .cvtps2ph },
2778 dst_reg,2778 dst_reg,
2779 mat_src_reg.to128(),2779 mat_src_reg.to128(),
2780 Immediate.u(0b1_00),2780 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
2781 );2781 );
2782 },2782 },
2783 else => unreachable,2783 else => unreachable,
...@@ -2844,11 +2844,11 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {...@@ -2844,11 +2844,11 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
2844 },2844 },
2845 else => unreachable,2845 else => unreachable,
2846 }) {2846 }) {
2847 var callee: ["__extend?f?f2".len]u8 = undefined;2847 var callee_buf: ["__extend?f?f2".len]u8 = undefined;
2848 break :result try self.genCall(.{ .lib = .{2848 break :result try self.genCall(.{ .lib = .{
2849 .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(),2849 .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(),
2850 .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()},2850 .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()},
2851 .callee = std.fmt.bufPrint(&callee, "__extend{c}f{c}f2", .{2851 .callee = std.fmt.bufPrint(&callee_buf, "__extend{c}f{c}f2", .{
2852 floatCompilerRtAbiName(src_bits),2852 floatCompilerRtAbiName(src_bits),
2853 floatCompilerRtAbiName(dst_bits),2853 floatCompilerRtAbiName(dst_bits),
2854 }) catch unreachable,2854 }) catch unreachable,
...@@ -5347,7 +5347,7 @@ const RoundMode = packed struct(u5) {...@@ -5347,7 +5347,7 @@ const RoundMode = packed struct(u5) {
5347 precision: enum(u1) {5347 precision: enum(u1) {
5348 normal = 0b0,5348 normal = 0b0,
5349 inexact = 0b1,5349 inexact = 0b1,
5350 },5350 } = .normal,
5351};5351};
53525352
5353fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void {5353fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void {
...@@ -5413,11 +5413,11 @@ fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MC...@@ -5413,11 +5413,11 @@ fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MC
5413 if (ty.zigTypeTag(mod) != .Float)5413 if (ty.zigTypeTag(mod) != .Float)
5414 return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)});5414 return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)});
54155415
5416 var callee: ["__trunc?".len]u8 = undefined;5416 var callee_buf: ["__trunc?".len]u8 = undefined;
5417 return try self.genCall(.{ .lib = .{5417 return try self.genCall(.{ .lib = .{
5418 .return_type = ty.toIntern(),5418 .return_type = ty.toIntern(),
5419 .param_types = &.{ty.toIntern()},5419 .param_types = &.{ty.toIntern()},
5420 .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{5420 .callee = std.fmt.bufPrint(&callee_buf, "{s}{s}{s}", .{
5421 floatLibcAbiPrefix(ty),5421 floatLibcAbiPrefix(ty),
5422 switch (mode.mode) {5422 switch (mode.mode) {
5423 .down => "floor",5423 .down => "floor",
...@@ -5628,11 +5628,11 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5628,11 +5628,11 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5628 80, 128 => true,5628 80, 128 => true,
5629 else => unreachable,5629 else => unreachable,
5630 }) {5630 }) {
5631 var callee: ["__sqrt?".len]u8 = undefined;5631 var callee_buf: ["__sqrt?".len]u8 = undefined;
5632 break :result try self.genCall(.{ .lib = .{5632 break :result try self.genCall(.{ .lib = .{
5633 .return_type = ty.toIntern(),5633 .return_type = ty.toIntern(),
5634 .param_types = &.{ty.toIntern()},5634 .param_types = &.{ty.toIntern()},
5635 .callee = std.fmt.bufPrint(&callee, "{s}sqrt{s}", .{5635 .callee = std.fmt.bufPrint(&callee_buf, "{s}sqrt{s}", .{
5636 floatLibcAbiPrefix(ty),5636 floatLibcAbiPrefix(ty),
5637 floatLibcAbiSuffix(ty),5637 floatLibcAbiSuffix(ty),
5638 }) catch unreachable,5638 }) catch unreachable,
...@@ -5665,7 +5665,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5665,7 +5665,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5665 .{ .v_, .cvtps2ph },5665 .{ .v_, .cvtps2ph },
5666 dst_reg,5666 dst_reg,
5667 dst_reg,5667 dst_reg,
5668 Immediate.u(0b1_00),5668 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
5669 );5669 );
5670 break :result dst_mcv;5670 break :result dst_mcv;
5671 },5671 },
...@@ -5695,7 +5695,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5695,7 +5695,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5695 .{ .v_, .cvtps2ph },5695 .{ .v_, .cvtps2ph },
5696 dst_reg,5696 dst_reg,
5697 dst_reg,5697 dst_reg,
5698 Immediate.u(0b1_00),5698 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
5699 );5699 );
5700 break :result dst_mcv;5700 break :result dst_mcv;
5701 },5701 },
...@@ -5720,7 +5720,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5720,7 +5720,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5720 .{ .v_, .cvtps2ph },5720 .{ .v_, .cvtps2ph },
5721 dst_reg,5721 dst_reg,
5722 wide_reg,5722 wide_reg,
5723 Immediate.u(0b1_00),5723 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
5724 );5724 );
5725 break :result dst_mcv;5725 break :result dst_mcv;
5726 },5726 },
...@@ -5783,11 +5783,11 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5783,11 +5783,11 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5783fn airUnaryMath(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {5783fn airUnaryMath(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
5784 const un_op = self.air.instructions.items(.data)[inst].un_op;5784 const un_op = self.air.instructions.items(.data)[inst].un_op;
5785 const ty = self.typeOf(un_op);5785 const ty = self.typeOf(un_op);
5786 var callee: ["__round?".len]u8 = undefined;5786 var callee_buf: ["__round?".len]u8 = undefined;
5787 const result = try self.genCall(.{ .lib = .{5787 const result = try self.genCall(.{ .lib = .{
5788 .return_type = ty.toIntern(),5788 .return_type = ty.toIntern(),
5789 .param_types = &.{ty.toIntern()},5789 .param_types = &.{ty.toIntern()},
5790 .callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{5790 .callee = std.fmt.bufPrint(&callee_buf, "{s}{s}{s}", .{
5791 floatLibcAbiPrefix(ty),5791 floatLibcAbiPrefix(ty),
5792 switch (tag) {5792 switch (tag) {
5793 .sin,5793 .sin,
...@@ -6978,11 +6978,11 @@ fn genMulDivBinOp(...@@ -6978,11 +6978,11 @@ fn genMulDivBinOp(
6978 ),6978 ),
6979 else => {},6979 else => {},
6980 };6980 };
6981 var callee: ["__udiv?i3".len]u8 = undefined;6981 var callee_buf: ["__udiv?i3".len]u8 = undefined;
6982 return try self.genCall(.{ .lib = .{6982 return try self.genCall(.{ .lib = .{
6983 .return_type = dst_ty.toIntern(),6983 .return_type = dst_ty.toIntern(),
6984 .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },6984 .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },
6985 .callee = std.fmt.bufPrint(&callee, "__{s}{s}{c}i3", .{6985 .callee = std.fmt.bufPrint(&callee_buf, "__{s}{s}{c}i3", .{
6986 if (signed) "" else "u",6986 if (signed) "" else "u",
6987 switch (tag) {6987 switch (tag) {
6988 .div_trunc, .div_exact => "div",6988 .div_trunc, .div_exact => "div",
...@@ -7205,43 +7205,163 @@ fn genBinOp(...@@ -7205,43 +7205,163 @@ fn genBinOp(
7205 const rhs_ty = self.typeOf(rhs_air);7205 const rhs_ty = self.typeOf(rhs_air);
7206 const abi_size: u32 = @intCast(lhs_ty.abiSize(mod));7206 const abi_size: u32 = @intCast(lhs_ty.abiSize(mod));
72077207
7208 if (lhs_ty.isRuntimeFloat() and (air_tag == .rem or switch (lhs_ty.floatBits(self.target.*)) {7208 if (lhs_ty.isRuntimeFloat()) libcall: {
7209 16 => !self.hasFeature(.f16c),7209 const float_bits = lhs_ty.floatBits(self.target.*);
7210 32, 64 => false,7210 const type_needs_libcall = switch (float_bits) {
7211 80, 128 => true,7211 16 => !self.hasFeature(.f16c),
7212 else => unreachable,7212 32, 64 => false,
7213 })) {7213 80, 128 => true,
7214 var callee: ["__mod?f3".len]u8 = undefined;7214 else => unreachable,
7215 };
7216 switch (air_tag) {
7217 .rem, .mod => {},
7218 else => if (!type_needs_libcall) break :libcall,
7219 }
7220 var callee_buf: ["__mod?f3".len]u8 = undefined;
7221 const callee = switch (air_tag) {
7222 .add,
7223 .sub,
7224 .mul,
7225 .div_float,
7226 .div_trunc,
7227 .div_floor,
7228 => std.fmt.bufPrint(&callee_buf, "__{s}{c}f3", .{
7229 @tagName(air_tag)[0..3],
7230 floatCompilerRtAbiName(float_bits),
7231 }),
7232 .rem, .mod, .min, .max => std.fmt.bufPrint(&callee_buf, "{s}f{s}{s}", .{
7233 floatLibcAbiPrefix(lhs_ty),
7234 switch (air_tag) {
7235 .rem, .mod => "mod",
7236 .min => "min",
7237 .max => "max",
7238 else => unreachable,
7239 },
7240 floatLibcAbiSuffix(lhs_ty),
7241 }),
7242 else => return self.fail("TODO implement genBinOp for {s} {}", .{
7243 @tagName(air_tag), lhs_ty.fmt(mod),
7244 }),
7245 } catch unreachable;
7215 const result = try self.genCall(.{ .lib = .{7246 const result = try self.genCall(.{ .lib = .{
7216 .return_type = lhs_ty.toIntern(),7247 .return_type = lhs_ty.toIntern(),
7217 .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },7248 .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
7218 .callee = switch (air_tag) {7249 .callee = callee,
7219 .add,
7220 .sub,
7221 .mul,
7222 .div_float,
7223 .div_trunc,
7224 .div_floor,
7225 => std.fmt.bufPrint(&callee, "__{s}{c}f3", .{
7226 @tagName(air_tag)[0..3],
7227 floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)),
7228 }),
7229 .rem, .min, .max => std.fmt.bufPrint(&callee, "{s}f{s}{s}", .{
7230 floatLibcAbiPrefix(lhs_ty),
7231 switch (air_tag) {
7232 .rem => "mod",
7233 .min => "min",
7234 .max => "max",
7235 else => unreachable,
7236 },
7237 floatLibcAbiSuffix(lhs_ty),
7238 }),
7239 else => return self.fail("TODO implement genBinOp for {s} {}", .{
7240 @tagName(air_tag), lhs_ty.fmt(mod),
7241 }),
7242 } catch unreachable,
7243 } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } });7250 } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } });
7244 return switch (air_tag) {7251 return switch (air_tag) {
7252 .mod => result: {
7253 const adjusted: MCValue = if (type_needs_libcall) adjusted: {
7254 var add_callee_buf: ["__add?f3".len]u8 = undefined;
7255 break :adjusted try self.genCall(.{ .lib = .{
7256 .return_type = lhs_ty.toIntern(),
7257 .param_types = &.{
7258 lhs_ty.toIntern(),
7259 rhs_ty.toIntern(),
7260 },
7261 .callee = std.fmt.bufPrint(&add_callee_buf, "__add{c}f3", .{
7262 floatCompilerRtAbiName(float_bits),
7263 }) catch unreachable,
7264 } }, &.{ lhs_ty, rhs_ty }, &.{ result, .{ .air_ref = rhs_air } });
7265 } else switch (float_bits) {
7266 16, 32, 64 => adjusted: {
7267 const dst_reg = switch (result) {
7268 .register => |reg| reg,
7269 else => if (maybe_inst) |inst|
7270 (try self.copyToRegisterWithInstTracking(inst, lhs_ty, result)).register
7271 else
7272 try self.copyToTmpRegister(lhs_ty, result),
7273 };
7274 const dst_lock = self.register_manager.lockReg(dst_reg);
7275 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
7276
7277 const rhs_mcv = try self.resolveInst(rhs_air);
7278 const src_mcv: MCValue = if (float_bits == 16) src: {
7279 assert(self.hasFeature(.f16c));
7280 const tmp_reg = (try self.register_manager.allocReg(
7281 null,
7282 abi.RegisterClass.sse,
7283 )).to128();
7284 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7285 defer self.register_manager.unlockReg(tmp_lock);
7286
7287 if (rhs_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate(
7288 .{ .vp_w, .insr },
7289 dst_reg,
7290 dst_reg,
7291 rhs_mcv.mem(.word),
7292 Immediate.u(1),
7293 ) else try self.asmRegisterRegisterRegister(
7294 .{ .vp_, .unpcklwd },
7295 dst_reg,
7296 dst_reg,
7297 (if (rhs_mcv.isRegister())
7298 rhs_mcv.getReg().?
7299 else
7300 try self.copyToTmpRegister(rhs_ty, rhs_mcv)).to128(),
7301 );
7302 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
7303 break :src .{ .register = tmp_reg };
7304 } else rhs_mcv;
7305
7306 if (self.hasFeature(.avx)) {
7307 const mir_tag: Mir.Inst.FixedTag = switch (float_bits) {
7308 16, 32 => .{ .v_ss, .add },
7309 64 => .{ .v_sd, .add },
7310 else => unreachable,
7311 };
7312 if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory(
7313 mir_tag,
7314 dst_reg,
7315 dst_reg,
7316 src_mcv.mem(Memory.PtrSize.fromBitSize(float_bits)),
7317 ) else try self.asmRegisterRegisterRegister(
7318 mir_tag,
7319 dst_reg,
7320 dst_reg,
7321 (if (src_mcv.isRegister())
7322 src_mcv.getReg().?
7323 else
7324 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
7325 );
7326 } else {
7327 const mir_tag: Mir.Inst.FixedTag = switch (float_bits) {
7328 32 => .{ ._ss, .add },
7329 64 => .{ ._sd, .add },
7330 else => unreachable,
7331 };
7332 if (src_mcv.isMemory()) try self.asmRegisterMemory(
7333 mir_tag,
7334 dst_reg,
7335 src_mcv.mem(Memory.PtrSize.fromBitSize(float_bits)),
7336 ) else try self.asmRegisterRegister(
7337 mir_tag,
7338 dst_reg,
7339 (if (src_mcv.isRegister())
7340 src_mcv.getReg().?
7341 else
7342 try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
7343 );
7344 }
7345
7346 if (float_bits == 16) try self.asmRegisterRegisterImmediate(
7347 .{ .v_, .cvtps2ph },
7348 dst_reg,
7349 dst_reg,
7350 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
7351 );
7352 break :adjusted .{ .register = dst_reg };
7353 },
7354 80, 128 => return self.fail("TODO implement genBinOp for {s} of {}", .{
7355 @tagName(air_tag), lhs_ty.fmt(mod),
7356 }),
7357 else => unreachable,
7358 };
7359 break :result try self.genCall(.{ .lib = .{
7360 .return_type = lhs_ty.toIntern(),
7361 .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
7362 .callee = callee,
7363 } }, &.{ lhs_ty, rhs_ty }, &.{ adjusted, .{ .air_ref = rhs_air } });
7364 },
7245 .div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{7365 .div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{
7246 .mode = switch (air_tag) {7366 .mode = switch (air_tag) {
7247 .div_trunc => .zero,7367 .div_trunc => .zero,
...@@ -7263,6 +7383,7 @@ fn genBinOp(...@@ -7263,6 +7383,7 @@ fn genBinOp(
72637383
7264 const maybe_mask_reg = switch (air_tag) {7384 const maybe_mask_reg = switch (air_tag) {
7265 else => null,7385 else => null,
7386 .rem, .mod => unreachable,
7266 .max, .min => if (lhs_ty.scalarType(mod).isRuntimeFloat()) registerAlias(7387 .max, .min => if (lhs_ty.scalarType(mod).isRuntimeFloat()) registerAlias(
7267 if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: {7388 if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: {
7268 try self.register_manager.getReg(.xmm0, null);7389 try self.register_manager.getReg(.xmm0, null);
...@@ -7270,9 +7391,6 @@ fn genBinOp(...@@ -7270,9 +7391,6 @@ fn genBinOp(
7270 } else try self.register_manager.allocReg(null, abi.RegisterClass.sse),7391 } else try self.register_manager.allocReg(null, abi.RegisterClass.sse),
7271 abi_size,7392 abi_size,
7272 ) else null,7393 ) else null,
7273 .rem, .mod => return self.fail("TODO implement genBinOp for {s} {}", .{
7274 @tagName(air_tag), lhs_ty.fmt(mod),
7275 }),
7276 };7394 };
7277 const mask_lock =7395 const mask_lock =
7278 if (maybe_mask_reg) |mask_reg| self.register_manager.lockRegAssumeUnused(mask_reg) else null;7396 if (maybe_mask_reg) |mask_reg| self.register_manager.lockRegAssumeUnused(mask_reg) else null;
...@@ -7667,7 +7785,7 @@ fn genBinOp(...@@ -7667,7 +7785,7 @@ fn genBinOp(
7667 .{ .v_, .cvtps2ph },7785 .{ .v_, .cvtps2ph },
7668 dst_reg,7786 dst_reg,
7669 dst_reg,7787 dst_reg,
7670 Immediate.u(0b1_00),7788 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
7671 );7789 );
7672 return dst_mcv;7790 return dst_mcv;
7673 },7791 },
...@@ -8096,7 +8214,7 @@ fn genBinOp(...@@ -8096,7 +8214,7 @@ fn genBinOp(
8096 .{ .v_, .cvtps2ph },8214 .{ .v_, .cvtps2ph },
8097 dst_reg,8215 dst_reg,
8098 dst_reg,8216 dst_reg,
8099 Immediate.u(0b1_00),8217 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
8100 );8218 );
8101 return dst_mcv;8219 return dst_mcv;
8102 },8220 },
...@@ -8147,7 +8265,7 @@ fn genBinOp(...@@ -8147,7 +8265,7 @@ fn genBinOp(
8147 .{ .v_, .cvtps2ph },8265 .{ .v_, .cvtps2ph },
8148 dst_reg,8266 dst_reg,
8149 dst_reg,8267 dst_reg,
8150 Immediate.u(0b1_00),8268 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
8151 );8269 );
8152 return dst_mcv;8270 return dst_mcv;
8153 },8271 },
...@@ -8190,7 +8308,7 @@ fn genBinOp(...@@ -8190,7 +8308,7 @@ fn genBinOp(
8190 .{ .v_, .cvtps2ph },8308 .{ .v_, .cvtps2ph },
8191 dst_reg,8309 dst_reg,
8192 dst_reg,8310 dst_reg,
8193 Immediate.u(0b1_00),8311 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
8194 );8312 );
8195 return dst_mcv;8313 return dst_mcv;
8196 },8314 },
...@@ -8233,7 +8351,7 @@ fn genBinOp(...@@ -8233,7 +8351,7 @@ fn genBinOp(
8233 .{ .v_, .cvtps2ph },8351 .{ .v_, .cvtps2ph },
8234 dst_reg,8352 dst_reg,
8235 dst_reg.to256(),8353 dst_reg.to256(),
8236 Immediate.u(0b1_00),8354 Immediate.u(@as(u5, @bitCast(RoundMode{ .mode = .mxcsr }))),
8237 );8355 );
8238 return dst_mcv;8356 return dst_mcv;
8239 },8357 },
...@@ -9607,11 +9725,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -9607,11 +9725,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
9607 80, 128 => true,9725 80, 128 => true,
9608 else => unreachable,9726 else => unreachable,
9609 }) {9727 }) {
9610 var callee: ["__???f2".len]u8 = undefined;9728 var callee_buf: ["__???f2".len]u8 = undefined;
9611 const ret = try self.genCall(.{ .lib = .{9729 const ret = try self.genCall(.{ .lib = .{
9612 .return_type = .i32_type,9730 .return_type = .i32_type,
9613 .param_types = &.{ ty.toIntern(), ty.toIntern() },9731 .param_types = &.{ ty.toIntern(), ty.toIntern() },
9614 .callee = std.fmt.bufPrint(&callee, "__{s}{c}f2", .{9732 .callee = std.fmt.bufPrint(&callee_buf, "__{s}{c}f2", .{
9615 switch (op) {9733 switch (op) {
9616 .eq => "eq",9734 .eq => "eq",
9617 .neq => "ne",9735 .neq => "ne",
...@@ -12224,11 +12342,11 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -12224,11 +12342,11 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void {
12224 src_ty.fmt(mod), dst_ty.fmt(mod),12342 src_ty.fmt(mod), dst_ty.fmt(mod),
12225 });12343 });
1222612344
12227 var callee: ["__floatun?i?f".len]u8 = undefined;12345 var callee_buf: ["__floatun?i?f".len]u8 = undefined;
12228 break :result try self.genCall(.{ .lib = .{12346 break :result try self.genCall(.{ .lib = .{
12229 .return_type = dst_ty.toIntern(),12347 .return_type = dst_ty.toIntern(),
12230 .param_types = &.{src_ty.toIntern()},12348 .param_types = &.{src_ty.toIntern()},
12231 .callee = std.fmt.bufPrint(&callee, "__float{s}{c}i{c}f", .{12349 .callee = std.fmt.bufPrint(&callee_buf, "__float{s}{c}i{c}f", .{
12232 switch (src_signedness) {12350 switch (src_signedness) {
12233 .signed => "",12351 .signed => "",
12234 .unsigned => "un",12352 .unsigned => "un",
...@@ -12303,11 +12421,11 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -12303,11 +12421,11 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
12303 src_ty.fmt(mod), dst_ty.fmt(mod),12421 src_ty.fmt(mod), dst_ty.fmt(mod),
12304 });12422 });
1230512423
12306 var callee: ["__fixuns?f?i".len]u8 = undefined;12424 var callee_buf: ["__fixuns?f?i".len]u8 = undefined;
12307 break :result try self.genCall(.{ .lib = .{12425 break :result try self.genCall(.{ .lib = .{
12308 .return_type = dst_ty.toIntern(),12426 .return_type = dst_ty.toIntern(),
12309 .param_types = &.{src_ty.toIntern()},12427 .param_types = &.{src_ty.toIntern()},
12310 .callee = std.fmt.bufPrint(&callee, "__fix{s}{c}f{c}i", .{12428 .callee = std.fmt.bufPrint(&callee_buf, "__fix{s}{c}f{c}i", .{
12311 switch (dst_signedness) {12429 switch (dst_signedness) {
12312 .signed => "",12430 .signed => "",
12313 .unsigned => "uns",12431 .unsigned => "uns",
...@@ -13516,11 +13634,11 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {...@@ -13516,11 +13634,11 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
13516 ty.fmt(mod),13634 ty.fmt(mod),
13517 });13635 });
1351813636
13519 var callee: ["__fma?".len]u8 = undefined;13637 var callee_buf: ["__fma?".len]u8 = undefined;
13520 break :result try self.genCall(.{ .lib = .{13638 break :result try self.genCall(.{ .lib = .{
13521 .return_type = ty.toIntern(),13639 .return_type = ty.toIntern(),
13522 .param_types = &.{ ty.toIntern(), ty.toIntern(), ty.toIntern() },13640 .param_types = &.{ ty.toIntern(), ty.toIntern(), ty.toIntern() },
13523 .callee = std.fmt.bufPrint(&callee, "{s}fma{s}", .{13641 .callee = std.fmt.bufPrint(&callee_buf, "{s}fma{s}", .{
13524 floatLibcAbiPrefix(ty),13642 floatLibcAbiPrefix(ty),
13525 floatLibcAbiSuffix(ty),13643 floatLibcAbiSuffix(ty),
13526 }) catch unreachable,13644 }) catch unreachable,
test/behavior/math.zig+2-2
...@@ -1321,7 +1321,7 @@ test "remainder division" {...@@ -1321,7 +1321,7 @@ test "remainder division" {
1321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1323 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1323 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1324 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1324 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
1325 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;1325 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
13261326
1327 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {1327 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
...@@ -1401,9 +1401,9 @@ test "float modulo division using @mod" {...@@ -1401,9 +1401,9 @@ test "float modulo division using @mod" {
1401 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1401 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1404 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1404 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1406 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1405 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1406 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
14071407
1408 try comptime fmod(f16);1408 try comptime fmod(f16);
1409 try comptime fmod(f32);1409 try comptime fmod(f32);