mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
x86_64: hack around silent f80 miscompilations
The x87 kind sucks.
This commit is contained in:
parent
b19fd485b1
commit
24c67992e0
@ -5263,21 +5263,29 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void {
|
|||||||
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
const un_op = self.air.instructions.items(.data)[inst].un_op;
|
||||||
const ty = self.typeOf(un_op);
|
const ty = self.typeOf(un_op);
|
||||||
|
|
||||||
const src_mcv = try self.resolveInst(un_op);
|
const result = result: {
|
||||||
const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
|
switch (try self.genRoundLibcall(ty, .{ .air_ref = un_op }, mode)) {
|
||||||
src_mcv
|
.none => {},
|
||||||
else
|
else => |dst_mcv| break :result dst_mcv,
|
||||||
try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
|
}
|
||||||
const dst_reg = dst_mcv.getReg().?;
|
|
||||||
const dst_lock = self.register_manager.lockReg(dst_reg);
|
const src_mcv = try self.resolveInst(un_op);
|
||||||
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
|
const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
|
||||||
try self.genRound(ty, dst_reg, src_mcv, mode);
|
src_mcv
|
||||||
return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
|
else
|
||||||
|
try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
|
||||||
|
const dst_reg = dst_mcv.getReg().?;
|
||||||
|
const dst_lock = self.register_manager.lockReg(dst_reg);
|
||||||
|
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
|
||||||
|
try self.genRound(ty, dst_reg, src_mcv, mode);
|
||||||
|
break :result dst_mcv;
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ un_op, .none, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void {
|
fn getRoundTag(self: *Self, ty: Type) ?Mir.Inst.FixedTag {
|
||||||
const mod = self.bin_file.options.module.?;
|
const mod = self.bin_file.options.module.?;
|
||||||
const mir_tag = @as(?Mir.Inst.FixedTag, if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) {
|
return if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) {
|
||||||
.Float => switch (ty.floatBits(self.target.*)) {
|
.Float => switch (ty.floatBits(self.target.*)) {
|
||||||
32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
|
32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
|
||||||
64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
|
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
|
|||||||
else => null,
|
else => null,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
} else null) orelse {
|
} else null;
|
||||||
if (ty.zigTypeTag(mod) != .Float)
|
}
|
||||||
return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)});
|
|
||||||
|
|
||||||
var callee: ["__trunc?".len]u8 = undefined;
|
fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MCValue {
|
||||||
const res = try self.genCall(.{ .lib = .{
|
const mod = self.bin_file.options.module.?;
|
||||||
.return_type = ty.toIntern(),
|
if (self.getRoundTag(ty)) |_| return .none;
|
||||||
.param_types = &.{ty.toIntern()},
|
|
||||||
.callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{
|
if (ty.zigTypeTag(mod) != .Float)
|
||||||
floatLibcAbiPrefix(ty),
|
return self.fail("TODO implement genRound for {}", .{ty.fmt(mod)});
|
||||||
switch (mode.mode) {
|
|
||||||
.down => "floor",
|
var callee: ["__trunc?".len]u8 = undefined;
|
||||||
.up => "ceil",
|
return try self.genCall(.{ .lib = .{
|
||||||
.zero => "trunc",
|
.return_type = ty.toIntern(),
|
||||||
else => unreachable,
|
.param_types = &.{ty.toIntern()},
|
||||||
},
|
.callee = std.fmt.bufPrint(&callee, "{s}{s}{s}", .{
|
||||||
floatLibcAbiSuffix(ty),
|
floatLibcAbiPrefix(ty),
|
||||||
}) catch unreachable,
|
switch (mode.mode) {
|
||||||
} }, &.{ty}, &.{src_mcv});
|
.down => "floor",
|
||||||
return self.genSetReg(dst_reg, ty, res);
|
.up => "ceil",
|
||||||
|
.zero => "trunc",
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
floatLibcAbiSuffix(ty),
|
||||||
|
}) catch unreachable,
|
||||||
|
} }, &.{ty}, &.{src_mcv});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void {
|
||||||
|
const mod = self.bin_file.options.module.?;
|
||||||
|
const mir_tag = self.getRoundTag(ty) orelse {
|
||||||
|
const result = try self.genRoundLibcall(ty, src_mcv, mode);
|
||||||
|
return self.genSetReg(dst_reg, ty, result);
|
||||||
};
|
};
|
||||||
const abi_size: u32 = @intCast(ty.abiSize(mod));
|
const abi_size: u32 = @intCast(ty.abiSize(mod));
|
||||||
const dst_alias = registerAlias(dst_reg, abi_size);
|
const dst_alias = registerAlias(dst_reg, abi_size);
|
||||||
@ -6760,11 +6780,17 @@ fn genBinOp(
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
}) {
|
}) {
|
||||||
var callee: ["__add?f3".len]u8 = undefined;
|
var callee: ["__add?f3".len]u8 = undefined;
|
||||||
return self.genCall(.{ .lib = .{
|
const result = try self.genCall(.{ .lib = .{
|
||||||
.return_type = lhs_ty.toIntern(),
|
.return_type = lhs_ty.toIntern(),
|
||||||
.param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
|
.param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
|
||||||
.callee = switch (air_tag) {
|
.callee = switch (air_tag) {
|
||||||
.add, .sub, .mul, .div_float => std.fmt.bufPrint(&callee, "__{s}{c}f3", .{
|
.add,
|
||||||
|
.sub,
|
||||||
|
.mul,
|
||||||
|
.div_float,
|
||||||
|
.div_trunc,
|
||||||
|
.div_floor,
|
||||||
|
=> std.fmt.bufPrint(&callee, "__{s}{c}f3", .{
|
||||||
@tagName(air_tag)[0..3],
|
@tagName(air_tag)[0..3],
|
||||||
floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)),
|
floatCompilerRtAbiName(lhs_ty.floatBits(self.target.*)),
|
||||||
}),
|
}),
|
||||||
@ -6778,6 +6804,17 @@ fn genBinOp(
|
|||||||
}),
|
}),
|
||||||
} catch unreachable,
|
} catch unreachable,
|
||||||
} }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } });
|
} }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } });
|
||||||
|
return switch (air_tag) {
|
||||||
|
.div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{
|
||||||
|
.mode = switch (air_tag) {
|
||||||
|
.div_trunc => .zero,
|
||||||
|
.div_floor => .down,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.precision = .inexact,
|
||||||
|
}),
|
||||||
|
else => result,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((lhs_ty.scalarType(mod).isRuntimeFloat() and
|
if ((lhs_ty.scalarType(mod).isRuntimeFloat() and
|
||||||
@ -7666,16 +7703,14 @@ fn genBinOp(
|
|||||||
|
|
||||||
switch (air_tag) {
|
switch (air_tag) {
|
||||||
.add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {},
|
.add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {},
|
||||||
.div_trunc, .div_floor => try self.genRound(
|
.div_trunc, .div_floor => try self.genRound(lhs_ty, dst_reg, .{ .register = dst_reg }, .{
|
||||||
lhs_ty,
|
.mode = switch (air_tag) {
|
||||||
dst_reg,
|
|
||||||
.{ .register = dst_reg },
|
|
||||||
.{ .mode = switch (air_tag) {
|
|
||||||
.div_trunc => .zero,
|
.div_trunc => .zero,
|
||||||
.div_floor => .down,
|
.div_floor => .down,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}, .precision = .inexact },
|
},
|
||||||
),
|
.precision = .inexact,
|
||||||
|
}),
|
||||||
.bit_and, .bit_or, .xor => {},
|
.bit_and, .bit_or, .xor => {},
|
||||||
.max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) {
|
.max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) {
|
||||||
const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size);
|
const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size);
|
||||||
@ -8673,7 +8708,10 @@ fn genCall(self: *Self, info: union(enum) {
|
|||||||
try self.spillRegisters(®s);
|
try self.spillRegisters(®s);
|
||||||
try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs));
|
try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs));
|
||||||
},
|
},
|
||||||
.load_frame => try self.genCopy(arg_ty, dst_arg, src_arg),
|
.load_frame => {
|
||||||
|
try self.genCopy(arg_ty, dst_arg, src_arg);
|
||||||
|
try self.freeValue(src_arg);
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1029,7 +1029,7 @@ test "@floor f80/f128/c_longdouble" {
|
|||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
|
||||||
|
|
||||||
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
|
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
|
||||||
// https://github.com/ziglang/zig/issues/12602
|
// https://github.com/ziglang/zig/issues/12602
|
||||||
@ -1111,7 +1111,7 @@ test "@ceil f80/f128/c_longdouble" {
|
|||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
|
||||||
|
|
||||||
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
|
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
|
||||||
// https://github.com/ziglang/zig/issues/12602
|
// https://github.com/ziglang/zig/issues/12602
|
||||||
@ -1203,7 +1203,7 @@ test "@trunc f80/f128/c_longdouble" {
|
|||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
|
||||||
|
|
||||||
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
|
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
|
||||||
// https://github.com/ziglang/zig/issues/12602
|
// https://github.com/ziglang/zig/issues/12602
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user