authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-30 00:02:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-30 00:02:00-07:00
log6bc6e47b1582a4538078c8f4e9b3dae386854d07
tree3919cd49e8cfe2772c4028f0b056f47040651494
parent54454fd0102af8b25dbc85751d37fd265380d920

stage2: lower float negation explicitly

Rather than lowering float negation as `0.0 - x`. * Add AIR instruction for float negation. * Add compiler-rt functions for f128, f80 negation closes #11853

25 files changed, 237 insertions(+), 57 deletions(-)

CMakeLists.txt+5-2
......@@ -608,7 +608,6 @@ set(ZIG_STAGE2_SOURCES
608608 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multf3.zig"
609609 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig"
610610 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulxf3.zig"
611 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXf2.zig"
612611 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXi2.zig"
613612 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig"
614613 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/os_version_check.zig"
......@@ -623,11 +622,15 @@ set(ZIG_STAGE2_SOURCES
623622 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sincos.zig"
624623 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/sqrt.zig"
625624 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/stack_probe.zig"
626 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig"
627625 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subo.zig"
628626 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subsf3.zig"
627 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subdf3.zig"
629628 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subtf3.zig"
630629 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/subxf3.zig"
630 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negsf2.zig"
631 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negdf2.zig"
632 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negtf2.zig"
633 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negxf2.zig"
631634 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/tan.zig"
632635 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trig.zig"
633636 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/trunc.zig"
lib/compiler_rt.zig+8-4
......@@ -4,12 +4,13 @@ comptime {
44 _ = @import("compiler_rt/atomics.zig");
55
66 _ = @import("compiler_rt/addf3.zig");
7 _ = @import("compiler_rt/adddf3.zig");
87 _ = @import("compiler_rt/addsf3.zig");
8 _ = @import("compiler_rt/adddf3.zig");
99 _ = @import("compiler_rt/addtf3.zig");
1010 _ = @import("compiler_rt/addxf3.zig");
11 _ = @import("compiler_rt/subdf3.zig");
11
1212 _ = @import("compiler_rt/subsf3.zig");
13 _ = @import("compiler_rt/subdf3.zig");
1314 _ = @import("compiler_rt/subtf3.zig");
1415 _ = @import("compiler_rt/subxf3.zig");
1516
......@@ -19,6 +20,11 @@ comptime {
1920 _ = @import("compiler_rt/multf3.zig");
2021 _ = @import("compiler_rt/mulxf3.zig");
2122
23 _ = @import("compiler_rt/negsf2.zig");
24 _ = @import("compiler_rt/negdf2.zig");
25 _ = @import("compiler_rt/negtf2.zig");
26 _ = @import("compiler_rt/negxf2.zig");
27
2228 _ = @import("compiler_rt/comparef.zig");
2329 _ = @import("compiler_rt/cmpsf2.zig");
2430 _ = @import("compiler_rt/cmpdf2.zig");
......@@ -172,8 +178,6 @@ comptime {
172178 _ = @import("compiler_rt/mulo.zig");
173179 _ = @import("compiler_rt/cmp.zig");
174180
175 _ = @import("compiler_rt/negXf2.zig");
176
177181 _ = @import("compiler_rt/os_version_check.zig");
178182 _ = @import("compiler_rt/emutls.zig");
179183 _ = @import("compiler_rt/arm.zig");
lib/compiler_rt/common.zig+12
......@@ -188,3 +188,15 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn
188188 significand.* <<= @intCast(std.math.Log2Int(Z), shift);
189189 return @as(i32, 1) - shift;
190190}
191
192pub inline fn fneg(a: anytype) @TypeOf(a) {
193 const F = @TypeOf(a);
194 const bits = @typeInfo(F).Float.bits;
195 const U = @Type(.{ .Int = .{
196 .signedness = .unsigned,
197 .bits = bits,
198 } });
199 const sign_bit_mask = @as(U, 1) << (bits - 1);
200 const negated = @bitCast(U, a) ^ sign_bit_mask;
201 return @bitCast(F, negated);
202}
lib/compiler_rt/negXf2.zig deleted-42
......@@ -1,42 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const common = @import("common.zig");
4
5pub const panic = common.panic;
6
7comptime {
8 if (common.want_aeabi) {
9 @export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = common.linkage });
10 @export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = common.linkage });
11 } else {
12 @export(__negsf2, .{ .name = "__negsf2", .linkage = common.linkage });
13 @export(__negdf2, .{ .name = "__negdf2", .linkage = common.linkage });
14 }
15}
16
17pub fn __negsf2(a: f32) callconv(.C) f32 {
18 return negXf2(f32, a);
19}
20
21fn __aeabi_fneg(a: f32) callconv(.AAPCS) f32 {
22 return negXf2(f32, a);
23}
24
25pub fn __negdf2(a: f64) callconv(.C) f64 {
26 return negXf2(f64, a);
27}
28
29fn __aeabi_dneg(a: f64) callconv(.AAPCS) f64 {
30 return negXf2(f64, a);
31}
32
33inline fn negXf2(comptime T: type, a: T) T {
34 const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
35
36 const significandBits = std.math.floatMantissaBits(T);
37 const exponentBits = std.math.floatExponentBits(T);
38
39 const signBit = (@as(Z, 1) << (significandBits + exponentBits));
40
41 return @bitCast(T, @bitCast(Z, a) ^ signBit);
42}
lib/compiler_rt/negdf2.zig created+19
......@@ -0,0 +1,19 @@
1const common = @import("./common.zig");
2
3pub const panic = common.panic;
4
5comptime {
6 if (common.want_aeabi) {
7 @export(__aeabi_dneg, .{ .name = "__aeabi_dneg", .linkage = common.linkage });
8 } else {
9 @export(__negdf2, .{ .name = "__negdf2", .linkage = common.linkage });
10 }
11}
12
13fn __negdf2(a: f64) callconv(.C) f64 {
14 return common.fneg(a);
15}
16
17fn __aeabi_dneg(a: f64) callconv(.AAPCS) f64 {
18 return common.fneg(a);
19}
lib/compiler_rt/negsf2.zig created+19
......@@ -0,0 +1,19 @@
1const common = @import("./common.zig");
2
3pub const panic = common.panic;
4
5comptime {
6 if (common.want_aeabi) {
7 @export(__aeabi_fneg, .{ .name = "__aeabi_fneg", .linkage = common.linkage });
8 } else {
9 @export(__negsf2, .{ .name = "__negsf2", .linkage = common.linkage });
10 }
11}
12
13fn __negsf2(a: f32) callconv(.C) f32 {
14 return common.fneg(a);
15}
16
17fn __aeabi_fneg(a: f32) callconv(.AAPCS) f32 {
18 return common.fneg(a);
19}
lib/compiler_rt/negtf2.zig created+11
......@@ -0,0 +1,11 @@
1const common = @import("./common.zig");
2
3pub const panic = common.panic;
4
5comptime {
6 @export(__negtf2, .{ .name = "__negtf2", .linkage = common.linkage });
7}
8
9fn __negtf2(a: f128) callconv(.C) f128 {
10 return common.fneg(a);
11}
lib/compiler_rt/negxf2.zig created+11
......@@ -0,0 +1,11 @@
1const common = @import("./common.zig");
2
3pub const panic = common.panic;
4
5comptime {
6 @export(__negxf2, .{ .name = "__negxf2", .linkage = common.linkage });
7}
8
9fn __negxf2(a: f80) callconv(.C) f80 {
10 return common.fneg(a);
11}
lib/std/fmt.zig-2
......@@ -2225,7 +2225,6 @@ test "float.scientific.precision" {
22252225}
22262226
22272227test "float.special" {
2228 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
22292228 try expectFmt("f64: nan", "f64: {}", .{math.nan_f64});
22302229 // negative nan is not defined by IEE 754,
22312230 // and ARM thus normalizes it to positive nan
......@@ -2237,7 +2236,6 @@ test "float.special" {
22372236}
22382237
22392238test "float.hexadecimal.special" {
2240 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
22412239 try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64});
22422240 // negative nan is not defined by IEE 754,
22432241 // and ARM thus normalizes it to positive nan
lib/std/math/copysign.zig-1
......@@ -13,7 +13,6 @@ pub fn copysign(magnitude: anytype, sign: @TypeOf(magnitude)) @TypeOf(magnitude)
1313}
1414
1515test "math.copysign" {
16 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
1716 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
1817 try expect(copysign(@as(T, 1.0), @as(T, 1.0)) == 1.0);
1918 try expect(copysign(@as(T, 2.0), @as(T, -2.0)) == -2.0);
lib/std/math/signbit.zig-1
......@@ -10,7 +10,6 @@ pub fn signbit(x: anytype) bool {
1010}
1111
1212test "math.signbit" {
13 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
1413 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
1514 try expect(!signbit(@as(T, 0.0)));
1615 try expect(!signbit(@as(T, 1.0)));
src/Air.zig+6
......@@ -288,6 +288,11 @@ pub const Inst = struct {
288288 /// Rounds a floating pointer number to the nearest integer towards zero.
289289 /// Uses the `un_op` field.
290290 trunc_float,
291 /// Float negation. This affects the sign of zero, inf, and NaN, which is impossible
292 /// to do with sub. Integers are not allowed and must be represented with sub with
293 /// LHS of zero.
294 /// Uses the `un_op` field.
295 neg,
291296
292297 /// `<`. Result type is always bool.
293298 /// Uses the `bin_op` field.
......@@ -970,6 +975,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
970975 .ceil,
971976 .round,
972977 .trunc_float,
978 .neg,
973979 => return air.typeOf(datas[inst].un_op),
974980
975981 .cmp_lt,
src/Liveness.zig+2
......@@ -287,6 +287,7 @@ pub fn categorizeOperand(
287287 .ceil,
288288 .round,
289289 .trunc_float,
290 .neg,
290291 .cmp_lt_errors_len,
291292 => {
292293 const o = air_datas[inst].un_op;
......@@ -834,6 +835,7 @@ fn analyzeInst(
834835 .ceil,
835836 .round,
836837 .trunc_float,
838 .neg,
837839 .cmp_lt_errors_len,
838840 .set_err_return_trace,
839841 => {
src/Sema.zig+3-1
......@@ -10070,12 +10070,14 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1007010070 }
1007110071
1007210072 if (rhs_scalar_ty.isAnyFloat()) {
10073 // We handle comptime negation here to ensure negative zero is represented in the bits.
10073 // We handle float negation here to ensure negative zero is represented in the bits.
1007410074 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
1007510075 if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty);
1007610076 const target = sema.mod.getTarget();
1007710077 return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
1007810078 }
10079 try sema.requireRuntimeBlock(block, rhs_src);
10080 return block.addUnOp(.neg, rhs);
1007910081 }
1008010082
1008110083 const lhs = if (rhs_ty.zigTypeTag() == .Vector)
src/arch/aarch64/CodeGen.zig+2-1
......@@ -582,7 +582,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
582582 .floor,
583583 .ceil,
584584 .round,
585 .trunc_float
585 .trunc_float,
586 .neg,
586587 => try self.airUnaryMath(inst),
587588
588589 .add_with_overflow => try self.airOverflow(inst),
src/arch/arm/CodeGen.zig+1
......@@ -596,6 +596,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
596596 .ceil,
597597 .round,
598598 .trunc_float,
599 .neg,
599600 => try self.airUnaryMath(inst),
600601
601602 .add_with_overflow => try self.airOverflow(inst),
src/arch/riscv64/CodeGen.zig+1
......@@ -516,6 +516,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
516516 .ceil,
517517 .round,
518518 .trunc_float,
519 .neg,
519520 => try self.airUnaryMath(inst),
520521
521522 .add_with_overflow => try self.airAddWithOverflow(inst),
src/arch/sparc64/CodeGen.zig+1
......@@ -529,6 +529,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
529529 .ceil,
530530 .round,
531531 .trunc_float,
532 .neg,
532533 => @panic("TODO try self.airUnaryMath(inst)"),
533534
534535 .add_with_overflow => try self.airAddSubWithOverflow(inst),
src/arch/wasm/CodeGen.zig+1
......@@ -1607,6 +1607,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16071607 .log10,
16081608 .fabs,
16091609 .round,
1610 .neg,
16101611
16111612 .cmpxchg_weak,
16121613 .cmpxchg_strong,
src/arch/x86_64/CodeGen.zig+1
......@@ -605,6 +605,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
605605 .ceil,
606606 .round,
607607 .trunc_float,
608 .neg,
608609 => try self.airUnaryMath(inst),
609610
610611 .add_with_overflow => try self.airAddSubShlWithOverflow(inst),
src/codegen/c.zig+16
......@@ -1755,6 +1755,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17551755 .mul_sat => try airSatOp(f, inst, "muls_"),
17561756 .shl_sat => try airSatOp(f, inst, "shls_"),
17571757
1758 .neg => try airNeg(f, inst),
1759
17581760 .sqrt,
17591761 .sin,
17601762 .cos,
......@@ -4098,6 +4100,20 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
40984100 return local;
40994101}
41004102
4103fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue {
4104 if (f.liveness.isUnused(inst)) return CValue.none;
4105
4106 const un_op = f.air.instructions.items(.data)[inst].un_op;
4107 const writer = f.object.writer();
4108 const inst_ty = f.air.typeOfIndex(inst);
4109 const operand = try f.resolveInst(un_op);
4110 const local = try f.allocLocal(inst_ty, .Const);
4111 try writer.writeAll("-");
4112 try f.writeCValue(writer, operand);
4113 try writer.writeAll(";\n");
4114 return local;
4115}
4116
41014117fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
41024118 if (f.liveness.isUnused(inst)) return CValue.none;
41034119 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
src/codegen/llvm.zig+11-3
......@@ -4019,6 +4019,7 @@ pub const FuncGen = struct {
40194019 .ceil => try self.airUnaryOp(inst, .ceil),
40204020 .round => try self.airUnaryOp(inst, .round),
40214021 .trunc_float => try self.airUnaryOp(inst, .trunc),
4022 .neg => try self.airUnaryOp(inst, .neg),
40224023
40234024 .cmp_eq => try self.airCmp(inst, .eq),
40244025 .cmp_gt => try self.airCmp(inst, .gt),
......@@ -6545,13 +6546,14 @@ pub const FuncGen = struct {
65456546 fabs,
65466547 floor,
65476548 fma,
6549 fmax,
6550 fmin,
6551 fmod,
65486552 log,
65496553 log10,
65506554 log2,
6551 fmax,
6552 fmin,
65536555 mul,
6554 fmod,
6556 neg,
65556557 round,
65566558 sin,
65576559 sqrt,
......@@ -6584,6 +6586,7 @@ pub const FuncGen = struct {
65846586 var fn_name_buf: [64]u8 = undefined;
65856587 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
65866588 // Some operations are dedicated LLVM instructions, not available as intrinsics
6589 .neg => return self.builder.buildFNeg(params[0], ""),
65876590 .add => return self.builder.buildFAdd(params[0], params[1], ""),
65886591 .sub => return self.builder.buildFSub(params[0], params[1], ""),
65896592 .mul => return self.builder.buildFMul(params[0], params[1], ""),
......@@ -6595,6 +6598,11 @@ pub const FuncGen = struct {
65956598 } else b: {
65966599 const float_bits = scalar_ty.floatBits(target);
65976600 break :b switch (op) {
6601 .neg => FloatOpStrat{
6602 .libc = std.fmt.bufPrintZ(&fn_name_buf, "__neg{s}f2", .{
6603 compilerRtFloatAbbrev(float_bits),
6604 }) catch unreachable,
6605 },
65986606 .add, .sub, .div, .mul => FloatOpStrat{
65996607 .libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{
66006608 @tagName(op), compilerRtFloatAbbrev(float_bits),
src/codegen/llvm/bindings.zig+3
......@@ -549,6 +549,9 @@ pub const Builder = opaque {
549549 pub const buildFSub = LLVMBuildFSub;
550550 extern fn LLVMBuildFSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
551551
552 pub const buildFNeg = LLVMBuildFNeg;
553 extern fn LLVMBuildFNeg(*const Builder, V: *const Value, Name: [*:0]const u8) *const Value;
554
552555 pub const buildSub = LLVMBuildSub;
553556 extern fn LLVMBuildSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
554557
src/print_air.zig+1
......@@ -168,6 +168,7 @@ const Writer = struct {
168168 .ceil,
169169 .round,
170170 .trunc_float,
171 .neg,
171172 .cmp_lt_errors_len,
172173 .set_err_return_trace,
173174 => try w.writeUnOp(s, inst),
test/behavior/floatop.zig+103
......@@ -574,6 +574,7 @@ test "negation f32" {
574574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
575575 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
576576 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
577 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
577578
578579 const S = struct {
579580 fn doTheTest() !void {
......@@ -593,6 +594,8 @@ test "negation f64" {
593594 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
594595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
595596 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
597 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
598 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
596599
597600 const S = struct {
598601 fn doTheTest() !void {
......@@ -707,3 +710,103 @@ test "comptime_float zero divided by zero produces zero" {
707710
708711 try expect((0.0 / 0.0) == 0.0);
709712}
713
714test "nan negation f16" {
715 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
716 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
717 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
718 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
719 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
720
721 const nan_comptime = comptime math.nan(f16);
722 const neg_nan_comptime = -nan_comptime;
723
724 var nan_runtime = math.nan(f16);
725 const neg_nan_runtime = -nan_runtime;
726
727 try expect(!math.signbit(nan_runtime));
728 try expect(math.signbit(neg_nan_runtime));
729
730 try expect(!math.signbit(nan_comptime));
731 try expect(math.signbit(neg_nan_comptime));
732}
733
734test "nan negation f32" {
735 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
736 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
737 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
738 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
739 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
740
741 const nan_comptime = comptime math.nan(f32);
742 const neg_nan_comptime = -nan_comptime;
743
744 var nan_runtime = math.nan(f32);
745 const neg_nan_runtime = -nan_runtime;
746
747 try expect(!math.signbit(nan_runtime));
748 try expect(math.signbit(neg_nan_runtime));
749
750 try expect(!math.signbit(nan_comptime));
751 try expect(math.signbit(neg_nan_comptime));
752}
753
754test "nan negation f64" {
755 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
756 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
758 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
760
761 const nan_comptime = comptime math.nan(f64);
762 const neg_nan_comptime = -nan_comptime;
763
764 var nan_runtime = math.nan(f64);
765 const neg_nan_runtime = -nan_runtime;
766
767 try expect(!math.signbit(nan_runtime));
768 try expect(math.signbit(neg_nan_runtime));
769
770 try expect(!math.signbit(nan_comptime));
771 try expect(math.signbit(neg_nan_comptime));
772}
773
774test "nan negation f128" {
775 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
776 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
778 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
779 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
780
781 const nan_comptime = comptime math.nan(f128);
782 const neg_nan_comptime = -nan_comptime;
783
784 var nan_runtime = math.nan(f128);
785 const neg_nan_runtime = -nan_runtime;
786
787 try expect(!math.signbit(nan_runtime));
788 try expect(math.signbit(neg_nan_runtime));
789
790 try expect(!math.signbit(nan_comptime));
791 try expect(math.signbit(neg_nan_comptime));
792}
793
794test "nan negation f80" {
795 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
796 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
797 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
798 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
799 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
800
801 const nan_comptime = comptime math.nan(f80);
802 const neg_nan_comptime = -nan_comptime;
803
804 var nan_runtime = math.nan(f80);
805 const neg_nan_runtime = -nan_runtime;
806
807 try expect(!math.signbit(nan_runtime));
808 try expect(math.signbit(neg_nan_runtime));
809
810 try expect(!math.signbit(nan_comptime));
811 try expect(math.signbit(neg_nan_comptime));
812}