authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-29 14:25:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-29 14:27:28-07:00
logf8e418c47d13189674bdf5f131c19fd811964579
tree7695c4d6ef606bae5f58c6a978b2f5642b298078
parent5e60ee41272579bc5fef3d95c59180df6ab824c1

Sema: improved comptime `%` syntax

* comptime known 0 as a numerator returns comptime 0 independent of denominator. * negative numerator and denominator are allowed when the remainder is zero because that means the modulus would be also zero. * organize math behavior tests

4 files changed, 467 insertions(+), 422 deletions(-)

src/Sema.zig+19-10
...@@ -8674,7 +8674,6 @@ fn analyzeArithmetic(...@@ -8674,7 +8674,6 @@ fn analyzeArithmetic(
8674 // For integers:8674 // For integers:
8675 // Either operand being undef is a compile error because there exists8675 // Either operand being undef is a compile error because there exists
8676 // a possible value (TODO what is it?) that would invoke illegal behavior.8676 // a possible value (TODO what is it?) that would invoke illegal behavior.
8677 // TODO: can lhs zero be handled better?
8678 // TODO: can lhs undef be handled better?8677 // TODO: can lhs undef be handled better?
8679 //8678 //
8680 // For floats:8679 // For floats:
...@@ -8690,8 +8689,8 @@ fn analyzeArithmetic(...@@ -8690,8 +8689,8 @@ fn analyzeArithmetic(
8690 if (lhs_val.isUndef()) {8689 if (lhs_val.isUndef()) {
8691 return sema.failWithUseOfUndef(block, lhs_src);8690 return sema.failWithUseOfUndef(block, lhs_src);
8692 }8691 }
8693 if (lhs_val.compareWithZero(.lt)) {8692 if (lhs_val.compareWithZero(.eq)) {
8694 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);8693 return sema.addConstant(scalar_type, Value.zero);
8695 }8694 }
8696 } else if (lhs_ty.isSignedInt()) {8695 } else if (lhs_ty.isSignedInt()) {
8697 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);8696 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
...@@ -8703,14 +8702,24 @@ fn analyzeArithmetic(...@@ -8703,14 +8702,24 @@ fn analyzeArithmetic(
8703 if (rhs_val.compareWithZero(.eq)) {8702 if (rhs_val.compareWithZero(.eq)) {
8704 return sema.failWithDivideByZero(block, rhs_src);8703 return sema.failWithDivideByZero(block, rhs_src);
8705 }8704 }
8706 if (rhs_val.compareWithZero(.lt)) {
8707 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
8708 }
8709 if (maybe_lhs_val) |lhs_val| {8705 if (maybe_lhs_val) |lhs_val| {
8710 return sema.addConstant(8706 const rem_result = try lhs_val.intRem(rhs_val, sema.arena);
8711 scalar_type,8707 // If this answer could possibly be different by doing `intMod`,
8712 try lhs_val.intRem(rhs_val, sema.arena),8708 // we must emit a compile error. Otherwise, it's OK.
8713 );8709 if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and
8710 !rem_result.compareWithZero(.eq))
8711 {
8712 const bad_src = if (lhs_val.compareWithZero(.lt))
8713 lhs_src
8714 else
8715 rhs_src;
8716 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);
8717 }
8718 if (lhs_val.compareWithZero(.lt)) {
8719 // Negative
8720 return sema.addConstant(scalar_type, Value.zero);
8721 }
8722 return sema.addConstant(scalar_type, rem_result);
8714 }8723 }
8715 break :rs .{ .src = lhs_src, .air_tag = .rem };8724 break :rs .{ .src = lhs_src, .air_tag = .rem };
8716 } else if (rhs_ty.isSignedInt()) {8725 } else if (rhs_ty.isSignedInt()) {
test/behavior.zig-1
...@@ -153,7 +153,6 @@ test {...@@ -153,7 +153,6 @@ test {
153 _ = @import("behavior/floatop_stage1.zig");153 _ = @import("behavior/floatop_stage1.zig");
154 _ = @import("behavior/fn_delegation.zig");154 _ = @import("behavior/fn_delegation.zig");
155 _ = @import("behavior/ir_block_deps.zig");155 _ = @import("behavior/ir_block_deps.zig");
156 _ = @import("behavior/math_stage1.zig");
157 _ = @import("behavior/misc.zig");156 _ = @import("behavior/misc.zig");
158 _ = @import("behavior/muladd.zig");157 _ = @import("behavior/muladd.zig");
159 _ = @import("behavior/null_stage1.zig");158 _ = @import("behavior/null_stage1.zig");
test/behavior/math.zig+448
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("std");2const std = @import("std");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
...@@ -5,6 +6,7 @@ const expectEqualSlices = std.testing.expectEqualSlices;...@@ -5,6 +6,7 @@ const expectEqualSlices = std.testing.expectEqualSlices;
5const maxInt = std.math.maxInt;6const maxInt = std.math.maxInt;
6const minInt = std.math.minInt;7const minInt = std.math.minInt;
7const mem = std.mem;8const mem = std.mem;
9const has_f80_rt = builtin.cpu.arch == .x86_64;
810
9test "assignment operators" {11test "assignment operators" {
10 var i: u32 = 0;12 var i: u32 = 0;
...@@ -612,3 +614,449 @@ test "overflow arithmetic with u0 values" {...@@ -612,3 +614,449 @@ test "overflow arithmetic with u0 values" {
612 try expect(!@shlWithOverflow(u0, 0, 0, &result));614 try expect(!@shlWithOverflow(u0, 0, 0, &result));
613 try expect(result == 0);615 try expect(result == 0);
614}616}
617
618test "allow signed integer division/remainder when values are comptime known and positive or exact" {
619 try expect(5 / 3 == 1);
620 try expect(-5 / -3 == 1);
621 try expect(-6 / 3 == -2);
622
623 try expect(5 % 3 == 2);
624 try expect(-6 % 3 == 0);
625
626 if (builtin.zig_backend != .stage1) {
627 var undef: i32 = undefined;
628 if (0 % undef != 0) {
629 @compileError("0 as numerator should return comptime zero independent of denominator");
630 }
631 }
632}
633
634test "quad hex float literal parsing accurate" {
635 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
636
637 const a: f128 = 0x1.1111222233334444555566667777p+0;
638
639 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
640 const expected: u128 = 0x3fff1111222233334444555566667777;
641 try expect(@bitCast(u128, a) == expected);
642
643 // non-normalized
644 const b: f128 = 0x11.111222233334444555566667777p-4;
645 try expect(@bitCast(u128, b) == expected);
646
647 const S = struct {
648 fn doTheTest() !void {
649 {
650 var f: f128 = 0x1.2eab345678439abcdefea56782346p+5;
651 try expect(@bitCast(u128, f) == 0x40042eab345678439abcdefea5678234);
652 }
653 {
654 var f: f128 = 0x1.edcb34a235253948765432134674fp-1;
655 try expect(@bitCast(u128, f) == 0x3ffeedcb34a235253948765432134674);
656 }
657 {
658 var f: f128 = 0x1.353e45674d89abacc3a2ebf3ff4ffp-50;
659 try expect(@bitCast(u128, f) == 0x3fcd353e45674d89abacc3a2ebf3ff50);
660 }
661 {
662 var f: f128 = 0x1.ed8764648369535adf4be3214567fp-9;
663 try expect(@bitCast(u128, f) == 0x3ff6ed8764648369535adf4be3214568);
664 }
665 const exp2ft = [_]f64{
666 0x1.6a09e667f3bcdp-1,
667 0x1.7a11473eb0187p-1,
668 0x1.8ace5422aa0dbp-1,
669 0x1.9c49182a3f090p-1,
670 0x1.ae89f995ad3adp-1,
671 0x1.c199bdd85529cp-1,
672 0x1.d5818dcfba487p-1,
673 0x1.ea4afa2a490dap-1,
674 0x1.0000000000000p+0,
675 0x1.0b5586cf9890fp+0,
676 0x1.172b83c7d517bp+0,
677 0x1.2387a6e756238p+0,
678 0x1.306fe0a31b715p+0,
679 0x1.3dea64c123422p+0,
680 0x1.4bfdad5362a27p+0,
681 0x1.5ab07dd485429p+0,
682 0x1.8p23,
683 0x1.62e430p-1,
684 0x1.ebfbe0p-3,
685 0x1.c6b348p-5,
686 0x1.3b2c9cp-7,
687 0x1.0p127,
688 -0x1.0p-149,
689 };
690
691 const answers = [_]u64{
692 0x3fe6a09e667f3bcd,
693 0x3fe7a11473eb0187,
694 0x3fe8ace5422aa0db,
695 0x3fe9c49182a3f090,
696 0x3feae89f995ad3ad,
697 0x3fec199bdd85529c,
698 0x3fed5818dcfba487,
699 0x3feea4afa2a490da,
700 0x3ff0000000000000,
701 0x3ff0b5586cf9890f,
702 0x3ff172b83c7d517b,
703 0x3ff2387a6e756238,
704 0x3ff306fe0a31b715,
705 0x3ff3dea64c123422,
706 0x3ff4bfdad5362a27,
707 0x3ff5ab07dd485429,
708 0x4168000000000000,
709 0x3fe62e4300000000,
710 0x3fcebfbe00000000,
711 0x3fac6b3480000000,
712 0x3f83b2c9c0000000,
713 0x47e0000000000000,
714 0xb6a0000000000000,
715 };
716
717 for (exp2ft) |x, i| {
718 try expect(@bitCast(u64, x) == answers[i]);
719 }
720 }
721 };
722 try S.doTheTest();
723 comptime try S.doTheTest();
724}
725
726test "truncating shift left" {
727 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
728
729 try testShlTrunc(maxInt(u16));
730 comptime try testShlTrunc(maxInt(u16));
731}
732fn testShlTrunc(x: u16) !void {
733 const shifted = x << 1;
734 try expect(shifted == 65534);
735}
736
737test "exact shift left" {
738 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
739
740 try testShlExact(0b00110101);
741 comptime try testShlExact(0b00110101);
742}
743fn testShlExact(x: u8) !void {
744 const shifted = @shlExact(x, 2);
745 try expect(shifted == 0b11010100);
746}
747
748test "exact shift right" {
749 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
750
751 try testShrExact(0b10110100);
752 comptime try testShrExact(0b10110100);
753}
754fn testShrExact(x: u8) !void {
755 const shifted = @shrExact(x, 2);
756 try expect(shifted == 0b00101101);
757}
758
759test "shift left/right on u0 operand" {
760 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
761
762 const S = struct {
763 fn doTheTest() !void {
764 var x: u0 = 0;
765 var y: u0 = 0;
766 try expectEqual(@as(u0, 0), x << 0);
767 try expectEqual(@as(u0, 0), x >> 0);
768 try expectEqual(@as(u0, 0), x << y);
769 try expectEqual(@as(u0, 0), x >> y);
770 try expectEqual(@as(u0, 0), @shlExact(x, 0));
771 try expectEqual(@as(u0, 0), @shrExact(x, 0));
772 try expectEqual(@as(u0, 0), @shlExact(x, y));
773 try expectEqual(@as(u0, 0), @shrExact(x, y));
774 }
775 };
776 try S.doTheTest();
777 comptime try S.doTheTest();
778}
779
780test "comptime float rem int" {
781 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
782
783 comptime {
784 var x = @as(f32, 1) % 2;
785 try expect(x == 1.0);
786 }
787}
788
789test "remainder division" {
790 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
791
792 comptime try remdiv(f16);
793 comptime try remdiv(f32);
794 comptime try remdiv(f64);
795 comptime try remdiv(f128);
796 try remdiv(f16);
797 try remdiv(f64);
798 try remdiv(f128);
799}
800
801fn remdiv(comptime T: type) !void {
802 try expect(@as(T, 1) == @as(T, 1) % @as(T, 2));
803 try expect(@as(T, 1) == @as(T, 7) % @as(T, 3));
804}
805
806test "@sqrt" {
807 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
808
809 try testSqrt(f64, 12.0);
810 comptime try testSqrt(f64, 12.0);
811 try testSqrt(f32, 13.0);
812 comptime try testSqrt(f32, 13.0);
813 try testSqrt(f16, 13.0);
814 comptime try testSqrt(f16, 13.0);
815
816 const x = 14.0;
817 const y = x * x;
818 const z = @sqrt(y);
819 comptime try expect(z == x);
820}
821
822fn testSqrt(comptime T: type, x: T) !void {
823 try expect(@sqrt(x * x) == x);
824}
825
826test "@fabs" {
827 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
828
829 try testFabs(f128, 12.0);
830 comptime try testFabs(f128, 12.0);
831 if (has_f80_rt) try testFabs(f80, 12.0);
832 // comptime try testFabs(f80, 12.0);
833 try testFabs(f64, 12.0);
834 comptime try testFabs(f64, 12.0);
835 try testFabs(f32, 12.0);
836 comptime try testFabs(f32, 12.0);
837 try testFabs(f16, 12.0);
838 comptime try testFabs(f16, 12.0);
839
840 const x = 14.0;
841 const y = -x;
842 const z = @fabs(y);
843 comptime try expectEqual(x, z);
844}
845
846fn testFabs(comptime T: type, x: T) !void {
847 const y = -x;
848 const z = @fabs(y);
849 try expectEqual(x, z);
850}
851
852test "@floor" {
853 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
854
855 // FIXME: Generates a floorl function call
856 // testFloor(f128, 12.0);
857 comptime try testFloor(f128, 12.0);
858 // try testFloor(f80, 12.0);
859 comptime try testFloor(f80, 12.0);
860 try testFloor(f64, 12.0);
861 comptime try testFloor(f64, 12.0);
862 try testFloor(f32, 12.0);
863 comptime try testFloor(f32, 12.0);
864 try testFloor(f16, 12.0);
865 comptime try testFloor(f16, 12.0);
866
867 const x = 14.0;
868 const y = x + 0.7;
869 const z = @floor(y);
870 comptime try expectEqual(x, z);
871}
872
873fn testFloor(comptime T: type, x: T) !void {
874 const y = x + 0.6;
875 const z = @floor(y);
876 try expectEqual(x, z);
877}
878
879test "@ceil" {
880 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
881
882 // FIXME: Generates a ceill function call
883 //testCeil(f128, 12.0);
884 comptime try testCeil(f128, 12.0);
885 // try testCeil(f80, 12.0);
886 comptime try testCeil(f80, 12.0);
887 try testCeil(f64, 12.0);
888 comptime try testCeil(f64, 12.0);
889 try testCeil(f32, 12.0);
890 comptime try testCeil(f32, 12.0);
891 try testCeil(f16, 12.0);
892 comptime try testCeil(f16, 12.0);
893
894 const x = 14.0;
895 const y = x - 0.7;
896 const z = @ceil(y);
897 comptime try expectEqual(x, z);
898}
899
900fn testCeil(comptime T: type, x: T) !void {
901 const y = x - 0.8;
902 const z = @ceil(y);
903 try expectEqual(x, z);
904}
905
906test "@trunc" {
907 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
908
909 // FIXME: Generates a truncl function call
910 //testTrunc(f128, 12.0);
911 comptime try testTrunc(f128, 12.0);
912 // try testTrunc(f80, 12.0);
913 // comptime try testTrunc(f80, 12.0);
914 comptime {
915 const x: f80 = 12.0;
916 const y = x + 0.8;
917 const z = @trunc(y);
918 try expectEqual(x, z);
919 }
920 try testTrunc(f64, 12.0);
921 comptime try testTrunc(f64, 12.0);
922 try testTrunc(f32, 12.0);
923 comptime try testTrunc(f32, 12.0);
924 try testTrunc(f16, 12.0);
925 comptime try testTrunc(f16, 12.0);
926
927 const x = 14.0;
928 const y = x + 0.7;
929 const z = @trunc(y);
930 comptime try expectEqual(x, z);
931}
932
933fn testTrunc(comptime T: type, x: T) !void {
934 {
935 const y = x + 0.8;
936 const z = @trunc(y);
937 try expectEqual(x, z);
938 }
939
940 {
941 const y = -x - 0.8;
942 const z = @trunc(y);
943 try expectEqual(-x, z);
944 }
945}
946
947test "@round" {
948 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
949
950 // FIXME: Generates a roundl function call
951 //testRound(f128, 12.0);
952 comptime try testRound(f128, 12.0);
953 // try testRound(f80, 12.0);
954 comptime try testRound(f80, 12.0);
955 try testRound(f64, 12.0);
956 comptime try testRound(f64, 12.0);
957 try testRound(f32, 12.0);
958 comptime try testRound(f32, 12.0);
959 try testRound(f16, 12.0);
960 comptime try testRound(f16, 12.0);
961
962 const x = 14.0;
963 const y = x + 0.4;
964 const z = @round(y);
965 comptime try expectEqual(x, z);
966}
967
968fn testRound(comptime T: type, x: T) !void {
969 const y = x - 0.5;
970 const z = @round(y);
971 try expectEqual(x, z);
972}
973
974test "vector integer addition" {
975 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
976
977 const S = struct {
978 fn doTheTest() !void {
979 var a: std.meta.Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };
980 var b: std.meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
981 var result = a + b;
982 var result_array: [4]i32 = result;
983 const expected = [_]i32{ 6, 8, 10, 12 };
984 try expectEqualSlices(i32, &expected, &result_array);
985 }
986 };
987 try S.doTheTest();
988 comptime try S.doTheTest();
989}
990
991test "NaN comparison" {
992 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
993
994 try testNanEqNan(f16);
995 try testNanEqNan(f32);
996 try testNanEqNan(f64);
997 try testNanEqNan(f128);
998 if (has_f80_rt) try testNanEqNan(f80);
999 comptime try testNanEqNan(f16);
1000 comptime try testNanEqNan(f32);
1001 comptime try testNanEqNan(f64);
1002 comptime try testNanEqNan(f128);
1003 // comptime try testNanEqNan(f80);
1004}
1005
1006fn testNanEqNan(comptime F: type) !void {
1007 var nan1 = std.math.nan(F);
1008 var nan2 = std.math.nan(F);
1009 try expect(nan1 != nan2);
1010 try expect(!(nan1 == nan2));
1011 try expect(!(nan1 > nan2));
1012 try expect(!(nan1 >= nan2));
1013 try expect(!(nan1 < nan2));
1014 try expect(!(nan1 <= nan2));
1015}
1016
1017test "vector comparison" {
1018 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1019
1020 const S = struct {
1021 fn doTheTest() !void {
1022 var a: std.meta.Vector(6, i32) = [_]i32{ 1, 3, -1, 5, 7, 9 };
1023 var b: std.meta.Vector(6, i32) = [_]i32{ -1, 3, 0, 6, 10, -10 };
1024 try expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{ false, false, true, true, true, false }));
1025 try expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{ false, true, true, true, true, false }));
1026 try expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{ false, true, false, false, false, false }));
1027 try expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{ true, false, true, true, true, true }));
1028 try expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{ true, false, false, false, false, true }));
1029 try expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{ true, true, false, false, false, true }));
1030 }
1031 };
1032 try S.doTheTest();
1033 comptime try S.doTheTest();
1034}
1035
1036test "compare undefined literal with comptime_int" {
1037 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1038
1039 var x = undefined == 1;
1040 // x is now undefined with type bool
1041 x = true;
1042 try expect(x);
1043}
1044
1045test "signed zeros are represented properly" {
1046 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1047
1048 const S = struct {
1049 fn doTheTest() !void {
1050 inline for ([_]type{ f16, f32, f64, f128 }) |T| {
1051 const ST = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
1052 var as_fp_val = -@as(T, 0.0);
1053 var as_uint_val = @bitCast(ST, as_fp_val);
1054 // Ensure the sign bit is set.
1055 try expect(as_uint_val >> (@typeInfo(T).Float.bits - 1) == 1);
1056 }
1057 }
1058 };
1059
1060 try S.doTheTest();
1061 comptime try S.doTheTest();
1062}
test/behavior/math_stage1.zig deleted-411
...@@ -1,411 +0,0 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
4const expectEqualSlices = std.testing.expectEqualSlices;
5const maxInt = std.math.maxInt;
6const minInt = std.math.minInt;
7const mem = std.mem;
8const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
9
10test "allow signed integer division/remainder when values are comptime known and positive or exact" {
11 try expect(5 / 3 == 1);
12 try expect(-5 / -3 == 1);
13 try expect(-6 / 3 == -2);
14
15 try expect(5 % 3 == 2);
16 try expect(-6 % 3 == 0);
17}
18
19test "quad hex float literal parsing accurate" {
20 const a: f128 = 0x1.1111222233334444555566667777p+0;
21
22 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
23 const expected: u128 = 0x3fff1111222233334444555566667777;
24 try expect(@bitCast(u128, a) == expected);
25
26 // non-normalized
27 const b: f128 = 0x11.111222233334444555566667777p-4;
28 try expect(@bitCast(u128, b) == expected);
29
30 const S = struct {
31 fn doTheTest() !void {
32 {
33 var f: f128 = 0x1.2eab345678439abcdefea56782346p+5;
34 try expect(@bitCast(u128, f) == 0x40042eab345678439abcdefea5678234);
35 }
36 {
37 var f: f128 = 0x1.edcb34a235253948765432134674fp-1;
38 try expect(@bitCast(u128, f) == 0x3ffeedcb34a235253948765432134674);
39 }
40 {
41 var f: f128 = 0x1.353e45674d89abacc3a2ebf3ff4ffp-50;
42 try expect(@bitCast(u128, f) == 0x3fcd353e45674d89abacc3a2ebf3ff50);
43 }
44 {
45 var f: f128 = 0x1.ed8764648369535adf4be3214567fp-9;
46 try expect(@bitCast(u128, f) == 0x3ff6ed8764648369535adf4be3214568);
47 }
48 const exp2ft = [_]f64{
49 0x1.6a09e667f3bcdp-1,
50 0x1.7a11473eb0187p-1,
51 0x1.8ace5422aa0dbp-1,
52 0x1.9c49182a3f090p-1,
53 0x1.ae89f995ad3adp-1,
54 0x1.c199bdd85529cp-1,
55 0x1.d5818dcfba487p-1,
56 0x1.ea4afa2a490dap-1,
57 0x1.0000000000000p+0,
58 0x1.0b5586cf9890fp+0,
59 0x1.172b83c7d517bp+0,
60 0x1.2387a6e756238p+0,
61 0x1.306fe0a31b715p+0,
62 0x1.3dea64c123422p+0,
63 0x1.4bfdad5362a27p+0,
64 0x1.5ab07dd485429p+0,
65 0x1.8p23,
66 0x1.62e430p-1,
67 0x1.ebfbe0p-3,
68 0x1.c6b348p-5,
69 0x1.3b2c9cp-7,
70 0x1.0p127,
71 -0x1.0p-149,
72 };
73
74 const answers = [_]u64{
75 0x3fe6a09e667f3bcd,
76 0x3fe7a11473eb0187,
77 0x3fe8ace5422aa0db,
78 0x3fe9c49182a3f090,
79 0x3feae89f995ad3ad,
80 0x3fec199bdd85529c,
81 0x3fed5818dcfba487,
82 0x3feea4afa2a490da,
83 0x3ff0000000000000,
84 0x3ff0b5586cf9890f,
85 0x3ff172b83c7d517b,
86 0x3ff2387a6e756238,
87 0x3ff306fe0a31b715,
88 0x3ff3dea64c123422,
89 0x3ff4bfdad5362a27,
90 0x3ff5ab07dd485429,
91 0x4168000000000000,
92 0x3fe62e4300000000,
93 0x3fcebfbe00000000,
94 0x3fac6b3480000000,
95 0x3f83b2c9c0000000,
96 0x47e0000000000000,
97 0xb6a0000000000000,
98 };
99
100 for (exp2ft) |x, i| {
101 try expect(@bitCast(u64, x) == answers[i]);
102 }
103 }
104 };
105 try S.doTheTest();
106 comptime try S.doTheTest();
107}
108
109test "truncating shift left" {
110 try testShlTrunc(maxInt(u16));
111 comptime try testShlTrunc(maxInt(u16));
112}
113fn testShlTrunc(x: u16) !void {
114 const shifted = x << 1;
115 try expect(shifted == 65534);
116}
117
118test "exact shift left" {
119 try testShlExact(0b00110101);
120 comptime try testShlExact(0b00110101);
121}
122fn testShlExact(x: u8) !void {
123 const shifted = @shlExact(x, 2);
124 try expect(shifted == 0b11010100);
125}
126
127test "exact shift right" {
128 try testShrExact(0b10110100);
129 comptime try testShrExact(0b10110100);
130}
131fn testShrExact(x: u8) !void {
132 const shifted = @shrExact(x, 2);
133 try expect(shifted == 0b00101101);
134}
135
136test "shift left/right on u0 operand" {
137 const S = struct {
138 fn doTheTest() !void {
139 var x: u0 = 0;
140 var y: u0 = 0;
141 try expectEqual(@as(u0, 0), x << 0);
142 try expectEqual(@as(u0, 0), x >> 0);
143 try expectEqual(@as(u0, 0), x << y);
144 try expectEqual(@as(u0, 0), x >> y);
145 try expectEqual(@as(u0, 0), @shlExact(x, 0));
146 try expectEqual(@as(u0, 0), @shrExact(x, 0));
147 try expectEqual(@as(u0, 0), @shlExact(x, y));
148 try expectEqual(@as(u0, 0), @shrExact(x, y));
149 }
150 };
151 try S.doTheTest();
152 comptime try S.doTheTest();
153}
154
155test "comptime float rem int" {
156 comptime {
157 var x = @as(f32, 1) % 2;
158 try expect(x == 1.0);
159 }
160}
161
162test "remainder division" {
163 comptime try remdiv(f16);
164 comptime try remdiv(f32);
165 comptime try remdiv(f64);
166 comptime try remdiv(f128);
167 try remdiv(f16);
168 try remdiv(f64);
169 try remdiv(f128);
170}
171
172fn remdiv(comptime T: type) !void {
173 try expect(@as(T, 1) == @as(T, 1) % @as(T, 2));
174 try expect(@as(T, 1) == @as(T, 7) % @as(T, 3));
175}
176
177test "@sqrt" {
178 try testSqrt(f64, 12.0);
179 comptime try testSqrt(f64, 12.0);
180 try testSqrt(f32, 13.0);
181 comptime try testSqrt(f32, 13.0);
182 try testSqrt(f16, 13.0);
183 comptime try testSqrt(f16, 13.0);
184
185 const x = 14.0;
186 const y = x * x;
187 const z = @sqrt(y);
188 comptime try expect(z == x);
189}
190
191fn testSqrt(comptime T: type, x: T) !void {
192 try expect(@sqrt(x * x) == x);
193}
194
195test "@fabs" {
196 try testFabs(f128, 12.0);
197 comptime try testFabs(f128, 12.0);
198 if (has_f80_rt) try testFabs(f80, 12.0);
199 // comptime try testFabs(f80, 12.0);
200 try testFabs(f64, 12.0);
201 comptime try testFabs(f64, 12.0);
202 try testFabs(f32, 12.0);
203 comptime try testFabs(f32, 12.0);
204 try testFabs(f16, 12.0);
205 comptime try testFabs(f16, 12.0);
206
207 const x = 14.0;
208 const y = -x;
209 const z = @fabs(y);
210 comptime try expectEqual(x, z);
211}
212
213fn testFabs(comptime T: type, x: T) !void {
214 const y = -x;
215 const z = @fabs(y);
216 try expectEqual(x, z);
217}
218
219test "@floor" {
220 // FIXME: Generates a floorl function call
221 // testFloor(f128, 12.0);
222 comptime try testFloor(f128, 12.0);
223 // try testFloor(f80, 12.0);
224 comptime try testFloor(f80, 12.0);
225 try testFloor(f64, 12.0);
226 comptime try testFloor(f64, 12.0);
227 try testFloor(f32, 12.0);
228 comptime try testFloor(f32, 12.0);
229 try testFloor(f16, 12.0);
230 comptime try testFloor(f16, 12.0);
231
232 const x = 14.0;
233 const y = x + 0.7;
234 const z = @floor(y);
235 comptime try expectEqual(x, z);
236}
237
238fn testFloor(comptime T: type, x: T) !void {
239 const y = x + 0.6;
240 const z = @floor(y);
241 try expectEqual(x, z);
242}
243
244test "@ceil" {
245 // FIXME: Generates a ceill function call
246 //testCeil(f128, 12.0);
247 comptime try testCeil(f128, 12.0);
248 // try testCeil(f80, 12.0);
249 comptime try testCeil(f80, 12.0);
250 try testCeil(f64, 12.0);
251 comptime try testCeil(f64, 12.0);
252 try testCeil(f32, 12.0);
253 comptime try testCeil(f32, 12.0);
254 try testCeil(f16, 12.0);
255 comptime try testCeil(f16, 12.0);
256
257 const x = 14.0;
258 const y = x - 0.7;
259 const z = @ceil(y);
260 comptime try expectEqual(x, z);
261}
262
263fn testCeil(comptime T: type, x: T) !void {
264 const y = x - 0.8;
265 const z = @ceil(y);
266 try expectEqual(x, z);
267}
268
269test "@trunc" {
270 // FIXME: Generates a truncl function call
271 //testTrunc(f128, 12.0);
272 comptime try testTrunc(f128, 12.0);
273 // try testTrunc(f80, 12.0);
274 // comptime try testTrunc(f80, 12.0);
275 comptime {
276 const x: f80 = 12.0;
277 const y = x + 0.8;
278 const z = @trunc(y);
279 try expectEqual(x, z);
280 }
281 try testTrunc(f64, 12.0);
282 comptime try testTrunc(f64, 12.0);
283 try testTrunc(f32, 12.0);
284 comptime try testTrunc(f32, 12.0);
285 try testTrunc(f16, 12.0);
286 comptime try testTrunc(f16, 12.0);
287
288 const x = 14.0;
289 const y = x + 0.7;
290 const z = @trunc(y);
291 comptime try expectEqual(x, z);
292}
293
294fn testTrunc(comptime T: type, x: T) !void {
295 {
296 const y = x + 0.8;
297 const z = @trunc(y);
298 try expectEqual(x, z);
299 }
300
301 {
302 const y = -x - 0.8;
303 const z = @trunc(y);
304 try expectEqual(-x, z);
305 }
306}
307
308test "@round" {
309 // FIXME: Generates a roundl function call
310 //testRound(f128, 12.0);
311 comptime try testRound(f128, 12.0);
312 // try testRound(f80, 12.0);
313 comptime try testRound(f80, 12.0);
314 try testRound(f64, 12.0);
315 comptime try testRound(f64, 12.0);
316 try testRound(f32, 12.0);
317 comptime try testRound(f32, 12.0);
318 try testRound(f16, 12.0);
319 comptime try testRound(f16, 12.0);
320
321 const x = 14.0;
322 const y = x + 0.4;
323 const z = @round(y);
324 comptime try expectEqual(x, z);
325}
326
327fn testRound(comptime T: type, x: T) !void {
328 const y = x - 0.5;
329 const z = @round(y);
330 try expectEqual(x, z);
331}
332
333test "vector integer addition" {
334 const S = struct {
335 fn doTheTest() !void {
336 var a: std.meta.Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };
337 var b: std.meta.Vector(4, i32) = [_]i32{ 5, 6, 7, 8 };
338 var result = a + b;
339 var result_array: [4]i32 = result;
340 const expected = [_]i32{ 6, 8, 10, 12 };
341 try expectEqualSlices(i32, &expected, &result_array);
342 }
343 };
344 try S.doTheTest();
345 comptime try S.doTheTest();
346}
347
348test "NaN comparison" {
349 try testNanEqNan(f16);
350 try testNanEqNan(f32);
351 try testNanEqNan(f64);
352 try testNanEqNan(f128);
353 if (has_f80_rt) try testNanEqNan(f80);
354 comptime try testNanEqNan(f16);
355 comptime try testNanEqNan(f32);
356 comptime try testNanEqNan(f64);
357 comptime try testNanEqNan(f128);
358 // comptime try testNanEqNan(f80);
359}
360
361fn testNanEqNan(comptime F: type) !void {
362 var nan1 = std.math.nan(F);
363 var nan2 = std.math.nan(F);
364 try expect(nan1 != nan2);
365 try expect(!(nan1 == nan2));
366 try expect(!(nan1 > nan2));
367 try expect(!(nan1 >= nan2));
368 try expect(!(nan1 < nan2));
369 try expect(!(nan1 <= nan2));
370}
371
372test "vector comparison" {
373 const S = struct {
374 fn doTheTest() !void {
375 var a: std.meta.Vector(6, i32) = [_]i32{ 1, 3, -1, 5, 7, 9 };
376 var b: std.meta.Vector(6, i32) = [_]i32{ -1, 3, 0, 6, 10, -10 };
377 try expect(mem.eql(bool, &@as([6]bool, a < b), &[_]bool{ false, false, true, true, true, false }));
378 try expect(mem.eql(bool, &@as([6]bool, a <= b), &[_]bool{ false, true, true, true, true, false }));
379 try expect(mem.eql(bool, &@as([6]bool, a == b), &[_]bool{ false, true, false, false, false, false }));
380 try expect(mem.eql(bool, &@as([6]bool, a != b), &[_]bool{ true, false, true, true, true, true }));
381 try expect(mem.eql(bool, &@as([6]bool, a > b), &[_]bool{ true, false, false, false, false, true }));
382 try expect(mem.eql(bool, &@as([6]bool, a >= b), &[_]bool{ true, true, false, false, false, true }));
383 }
384 };
385 try S.doTheTest();
386 comptime try S.doTheTest();
387}
388
389test "compare undefined literal with comptime_int" {
390 var x = undefined == 1;
391 // x is now undefined with type bool
392 x = true;
393 try expect(x);
394}
395
396test "signed zeros are represented properly" {
397 const S = struct {
398 fn doTheTest() !void {
399 inline for ([_]type{ f16, f32, f64, f128 }) |T| {
400 const ST = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
401 var as_fp_val = -@as(T, 0.0);
402 var as_uint_val = @bitCast(ST, as_fp_val);
403 // Ensure the sign bit is set.
404 try expect(as_uint_val >> (@typeInfo(T).Float.bits - 1) == 1);
405 }
406 }
407 };
408
409 try S.doTheTest();
410 comptime try S.doTheTest();
411}