authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-30 17:34:05-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-06-30 17:34:05-04:00
log77a334451f1329110d6c1bd07b46813cef10e97c
tree6708ceee35b9c7fc1c358696cd18a7b05d87bbf7
parentbe18459c81f831e455750e62f37dae6aeef62f1d
parentb3b96b5e288ddf3694b4a0d203c684b9b8f6b49f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11967 from ziglang/runtime-float-negation

stage2: lower float negation explicitly + modify hash/eql logic for floats

26 files changed, 278 insertions(+), 72 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+17-3
......@@ -4022,6 +4022,7 @@ pub const FuncGen = struct {
40224022 .ceil => try self.airUnaryOp(inst, .ceil),
40234023 .round => try self.airUnaryOp(inst, .round),
40244024 .trunc_float => try self.airUnaryOp(inst, .trunc),
4025 .neg => try self.airUnaryOp(inst, .neg),
40254026
40264027 .cmp_eq => try self.airCmp(inst, .eq),
40274028 .cmp_gt => try self.airCmp(inst, .gt),
......@@ -6548,13 +6549,14 @@ pub const FuncGen = struct {
65486549 fabs,
65496550 floor,
65506551 fma,
6552 fmax,
6553 fmin,
6554 fmod,
65516555 log,
65526556 log10,
65536557 log2,
6554 fmax,
6555 fmin,
65566558 mul,
6557 fmod,
6559 neg,
65586560 round,
65596561 sin,
65606562 sqrt,
......@@ -6587,6 +6589,7 @@ pub const FuncGen = struct {
65876589 var fn_name_buf: [64]u8 = undefined;
65886590 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
65896591 // Some operations are dedicated LLVM instructions, not available as intrinsics
6592 .neg => return self.builder.buildFNeg(params[0], ""),
65906593 .add => return self.builder.buildFAdd(params[0], params[1], ""),
65916594 .sub => return self.builder.buildFSub(params[0], params[1], ""),
65926595 .mul => return self.builder.buildFMul(params[0], params[1], ""),
......@@ -6598,6 +6601,17 @@ pub const FuncGen = struct {
65986601 } else b: {
65996602 const float_bits = scalar_ty.floatBits(target);
66006603 break :b switch (op) {
6604 .neg => {
6605 // In this case we can generate a softfloat negation by XORing the
6606 // bits with a constant.
6607 const int_llvm_ty = self.dg.context.intType(float_bits);
6608 const one = int_llvm_ty.constInt(1, .False);
6609 const shift_amt = int_llvm_ty.constInt(float_bits - 1, .False);
6610 const sign_mask = one.constShl(shift_amt);
6611 const bitcasted_operand = self.builder.buildBitCast(params[0], int_llvm_ty, "");
6612 const result = self.builder.buildXor(bitcasted_operand, sign_mask, "");
6613 return self.builder.buildBitCast(result, llvm_ty, "");
6614 },
66016615 .add, .sub, .div, .mul => FloatOpStrat{
66026616 .libc = std.fmt.bufPrintZ(&fn_name_buf, "__{s}{s}f3", .{
66036617 @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),
src/value.zig+35-15
......@@ -2189,12 +2189,25 @@ pub const Value = extern union {
21892189 return ty.isTupleOrAnonStruct() and ty.structFieldCount() != 0;
21902190 },
21912191 .Float => {
2192 const a_nan = a.isNan();
2193 const b_nan = b.isNan();
2194 if (a_nan or b_nan) {
2195 return a_nan and b_nan;
2192 switch (ty.floatBits(target)) {
2193 16 => return @bitCast(u16, a.toFloat(f16)) == @bitCast(u16, b.toFloat(f16)),
2194 32 => return @bitCast(u32, a.toFloat(f32)) == @bitCast(u32, b.toFloat(f32)),
2195 64 => return @bitCast(u64, a.toFloat(f64)) == @bitCast(u64, b.toFloat(f64)),
2196 80 => return @bitCast(u80, a.toFloat(f80)) == @bitCast(u80, b.toFloat(f80)),
2197 128 => return @bitCast(u128, a.toFloat(f128)) == @bitCast(u128, b.toFloat(f128)),
2198 else => unreachable,
21962199 }
2197 return order(a, b, target).compare(.eq);
2200 },
2201 .ComptimeFloat => {
2202 const a_float = a.toFloat(f128);
2203 const b_float = b.toFloat(f128);
2204
2205 const a_nan = std.math.isNan(a_float);
2206 const b_nan = std.math.isNan(b_float);
2207 if (a_nan != b_nan) return false;
2208 if (std.math.signbit(a_float) != std.math.signbit(b_float)) return false;
2209 if (a_nan) return true;
2210 return a_float == b_float;
21982211 },
21992212 .Optional => {
22002213 if (a.tag() != .opt_payload and b.tag() == .opt_payload) {
......@@ -2231,18 +2244,25 @@ pub const Value = extern union {
22312244 var buf: ToTypeBuffer = undefined;
22322245 return val.toType(&buf).hashWithHasher(hasher, mod);
22332246 },
2234 .Float, .ComptimeFloat => {
2235 // Normalize the float here because this hash must match eql semantics.
2236 // These functions are used for hash maps so we want NaN to equal itself,
2237 // and -0.0 to equal +0.0.
2247 .Float => {
2248 // For hash/eql purposes, we treat floats as their IEEE integer representation.
2249 switch (ty.floatBits(mod.getTarget())) {
2250 16 => std.hash.autoHash(hasher, @bitCast(u16, val.toFloat(f16))),
2251 32 => std.hash.autoHash(hasher, @bitCast(u32, val.toFloat(f32))),
2252 64 => std.hash.autoHash(hasher, @bitCast(u64, val.toFloat(f64))),
2253 80 => std.hash.autoHash(hasher, @bitCast(u80, val.toFloat(f80))),
2254 128 => std.hash.autoHash(hasher, @bitCast(u128, val.toFloat(f128))),
2255 else => unreachable,
2256 }
2257 },
2258 .ComptimeFloat => {
22382259 const float = val.toFloat(f128);
2239 if (std.math.isNan(float)) {
2240 std.hash.autoHash(hasher, std.math.nan_u128);
2241 } else if (float == 0.0) {
2242 var normalized_zero: f128 = 0.0;
2243 std.hash.autoHash(hasher, @bitCast(u128, normalized_zero));
2244 } else {
2260 const is_nan = std.math.isNan(float);
2261 std.hash.autoHash(hasher, is_nan);
2262 if (!is_nan) {
22452263 std.hash.autoHash(hasher, @bitCast(u128, float));
2264 } else {
2265 std.hash.autoHash(hasher, std.math.signbit(float));
22462266 }
22472267 },
22482268 .Bool, .Int, .ComptimeInt, .Pointer => switch (val.tag()) {
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}