authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-27 17:25:19-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-27 17:25:19-07:00
log937138cb90ae9327b0f7a932910c8d6080984f5c
tree458e4beacf025609f843d2db1188f5b9bd8488d5
parentab3ac1e6701431ae7dea99b23852e36b369d6b87
parent9763573ebb4f05eaa1c0bd5598f8dd6aee20ae9c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17248 from antlilja/abs

Replace @fabs builtin with new @abs builtin

51 files changed, 937 insertions(+), 309 deletions(-)

doc/langref.html.in+7-4
......@@ -9421,14 +9421,17 @@ fn doTheTest() !void {
94219421 Supports {#link|Floats#} and {#link|Vectors#} of floats.
94229422 </p>
94239423 {#header_close#}
9424 {#header_open|@fabs#}
9425 <pre>{#syntax#}@fabs(value: anytype) @TypeOf(value){#endsyntax#}</pre>
9424 {#header_open|@abs#}
9425 <pre>{#syntax#}@abs(value: anytype) anytype{#endsyntax#}</pre>
94269426 <p>
9427 Returns the absolute value of a floating point number. Uses a dedicated hardware instruction
9427 Returns the absolute value of an integer or a floating point number. Uses a dedicated hardware instruction
94289428 when available.
9429
9430 The return type is always an unsigned integer of the same bit width as the operand if the operand is an integer.
9431 Unsigned integer operands are supported. The builtin cannot overflow for signed integer operands.
94299432 </p>
94309433 <p>
9431 Supports {#link|Floats#} and {#link|Vectors#} of floats.
9434 Supports {#link|Floats#}, {#link|Integers#} and {#link|Vectors#} of floats or integers.
94329435 </p>
94339436 {#header_close#}
94349437 {#header_open|@floor#}
lib/compiler_rt/divc3.zig+1-2
......@@ -3,7 +3,6 @@ const isNan = std.math.isNan;
33const isInf = std.math.isInf;
44const scalbn = std.math.scalbn;
55const ilogb = std.math.ilogb;
6const fabs = std.math.fabs;
76const maxInt = std.math.maxInt;
87const minInt = std.math.minInt;
98const isFinite = std.math.isFinite;
......@@ -16,7 +15,7 @@ pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) {
1615 var d = d_in;
1716
1817 // logbw used to prevent under/over-flow
19 const logbw = ilogb(@max(fabs(c), fabs(d)));
18 const logbw = ilogb(@max(@abs(c), @abs(d)));
2019 const logbw_finite = logbw != maxInt(i32) and logbw != minInt(i32);
2120 const ilogbw = if (logbw_finite) b: {
2221 c = scalbn(c, -logbw);
lib/compiler_rt/divxf3_test.zig+3-3
......@@ -30,9 +30,9 @@ fn test__divxf3(a: f80, b: f80) !void {
3030 const x_minus_eps: f80 = @bitCast((@as(u80, @bitCast(x)) - 1) | integerBit);
3131
3232 // Make sure result is more accurate than the adjacent floats
33 const err_x = @fabs(@mulAdd(f80, x, b, -a));
34 const err_x_plus_eps = @fabs(@mulAdd(f80, x_plus_eps, b, -a));
35 const err_x_minus_eps = @fabs(@mulAdd(f80, x_minus_eps, b, -a));
33 const err_x = @abs(@mulAdd(f80, x, b, -a));
34 const err_x_plus_eps = @abs(@mulAdd(f80, x_plus_eps, b, -a));
35 const err_x_minus_eps = @abs(@mulAdd(f80, x_minus_eps, b, -a));
3636
3737 try testing.expect(err_x_minus_eps > err_x);
3838 try testing.expect(err_x_plus_eps > err_x);
lib/compiler_rt/float_from_int.zig+1-1
......@@ -18,7 +18,7 @@ pub fn floatFromInt(comptime T: type, x: anytype) T {
1818 const max_exp = exp_bias;
1919
2020 // Sign
21 var abs_val = math.absCast(x);
21 var abs_val = if (@TypeOf(x) == comptime_int or @typeInfo(@TypeOf(x)).Int.signedness == .signed) @abs(x) else x;
2222 const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0;
2323 var result: uT = sign_bit;
2424
lib/std/Build/Step/ConfigHeader.zig+1-1
......@@ -539,7 +539,7 @@ fn replace_variables(
539539 .int => |i| {
540540 const buf = try std.fmt.allocPrint(allocator, "{s}{}{s}", .{ beginline, i, endline });
541541 const isNegative = i < 0;
542 const digits = (if (0 < i) std.math.log10(std.math.absCast(i)) else 0) + 1;
542 const digits = (if (0 < i) std.math.log10(@abs(i)) else 0) + 1;
543543 last_index = start_index + @intFromBool(isNegative) + digits + 1;
544544
545545 allocator.free(content_buf);
lib/std/dwarf/expressions.zig+1-1
......@@ -520,7 +520,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
520520 if (self.stack.items.len == 0) return error.InvalidExpression;
521521 const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
522522 self.stack.items[self.stack.items.len - 1] = .{
523 .generic = std.math.absCast(value),
523 .generic = @abs(value),
524524 };
525525 },
526526 OP.@"and" => {
lib/std/fmt.zig+1-1
......@@ -1413,7 +1413,7 @@ pub fn formatInt(
14131413 const min_int_bits = comptime @max(value_info.bits, 8);
14141414 const MinInt = std.meta.Int(.unsigned, min_int_bits);
14151415
1416 const abs_value = math.absCast(int_value);
1416 const abs_value = @abs(int_value);
14171417 // The worst case in terms of space needed is base 2, plus 1 for the sign
14181418 var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined;
14191419
lib/std/io/fixed_buffer_stream.zig+1-1
......@@ -81,7 +81,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
8181
8282 pub fn seekBy(self: *Self, amt: i64) SeekError!void {
8383 if (amt < 0) {
84 const abs_amt = std.math.absCast(amt);
84 const abs_amt = @abs(amt);
8585 const abs_amt_usize = std.math.cast(usize, abs_amt) orelse std.math.maxInt(usize);
8686 if (abs_amt_usize > self.pos) {
8787 self.pos = 0;
lib/std/math.zig+4-94
......@@ -130,7 +130,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool {
130130 if (isNan(x) or isNan(y))
131131 return false;
132132
133 return @fabs(x - y) <= tolerance;
133 return @abs(x - y) <= tolerance;
134134}
135135
136136/// Performs an approximate comparison of two floating point values `x` and `y`.
......@@ -158,7 +158,7 @@ pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool {
158158 if (isNan(x) or isNan(y))
159159 return false;
160160
161 return @fabs(x - y) <= @max(@fabs(x), @fabs(y)) * tolerance;
161 return @abs(x - y) <= @max(@abs(x), @abs(y)) * tolerance;
162162}
163163
164164test "approxEqAbs and approxEqRel" {
......@@ -466,7 +466,7 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
466466/// Shifts left. Overflowed bits are truncated.
467467/// A negative shift amount results in a right shift.
468468pub fn shl(comptime T: type, a: T, shift_amt: anytype) T {
469 const abs_shift_amt = absCast(shift_amt);
469 const abs_shift_amt = @abs(shift_amt);
470470
471471 const casted_shift_amt = blk: {
472472 if (@typeInfo(T) == .Vector) {
......@@ -510,7 +510,7 @@ test "shl" {
510510/// Shifts right. Overflowed bits are truncated.
511511/// A negative shift amount results in a left shift.
512512pub fn shr(comptime T: type, a: T, shift_amt: anytype) T {
513 const abs_shift_amt = absCast(shift_amt);
513 const abs_shift_amt = @abs(shift_amt);
514514
515515 const casted_shift_amt = blk: {
516516 if (@typeInfo(T) == .Vector) {
......@@ -740,52 +740,6 @@ fn testOverflow() !void {
740740 try testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
741741}
742742
743/// Returns the absolute value of x, where x is a value of a signed integer type.
744/// Does not convert and returns a value of a signed integer type.
745/// Use `absCast` if you want to convert the result and get an unsigned type.
746/// Use `@fabs` if you need the absolute value of a floating point value.
747pub fn absInt(x: anytype) !@TypeOf(x) {
748 const T = @TypeOf(x);
749 return switch (@typeInfo(T)) {
750 .Int => |info| {
751 comptime assert(info.signedness == .signed); // must pass a signed integer to absInt
752 if (x == minInt(T)) {
753 return error.Overflow;
754 } else {
755 @setRuntimeSafety(false);
756 return if (x < 0) -x else x;
757 }
758 },
759 .Vector => |vinfo| blk: {
760 switch (@typeInfo(vinfo.child)) {
761 .Int => |info| {
762 comptime assert(info.signedness == .signed); // must pass a signed integer to absInt
763 if (@reduce(.Or, x == @as(T, @splat(minInt(vinfo.child))))) {
764 return error.Overflow;
765 }
766 const zero: T = @splat(0);
767 break :blk @select(vinfo.child, x > zero, x, -x);
768 },
769 else => @compileError("Expected vector of ints, found " ++ @typeName(T)),
770 }
771 },
772 else => @compileError("Expected an int or vector, found " ++ @typeName(T)),
773 };
774}
775
776test "absInt" {
777 try testAbsInt();
778 try comptime testAbsInt();
779}
780fn testAbsInt() !void {
781 try testing.expect((absInt(@as(i32, -10)) catch unreachable) == 10);
782 try testing.expect((absInt(@as(i32, 10)) catch unreachable) == 10);
783 try testing.expectEqual(@Vector(3, i32){ 10, 10, 0 }, (absInt(@Vector(3, i32){ -10, 10, 0 }) catch unreachable));
784
785 try testing.expectError(error.Overflow, absInt(@as(i32, minInt(i32))));
786 try testing.expectError(error.Overflow, absInt(@Vector(3, i32){ 10, -10, minInt(i32) }));
787}
788
789743/// Divide numerator by denominator, rounding toward zero. Returns an
790744/// error on overflow or when denominator is zero.
791745pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
......@@ -968,50 +922,6 @@ fn testRem() !void {
968922 try testing.expectError(error.DivisionByZero, rem(f32, 10, 0));
969923}
970924
971/// Returns the absolute value of a floating point number.
972/// Uses a dedicated hardware instruction when available.
973/// This is the same as calling the builtin @fabs
974pub inline fn fabs(value: anytype) @TypeOf(value) {
975 return @fabs(value);
976}
977
978/// Returns the absolute value of the integer parameter.
979/// Converts result type to unsigned if needed and returns a value of an unsigned integer type.
980/// Use `absInt` if you want to keep your integer type signed.
981pub fn absCast(x: anytype) switch (@typeInfo(@TypeOf(x))) {
982 .ComptimeInt => comptime_int,
983 .Int => |int_info| std.meta.Int(.unsigned, int_info.bits),
984 else => @compileError("absCast only accepts integers"),
985} {
986 switch (@typeInfo(@TypeOf(x))) {
987 .ComptimeInt => {
988 if (x < 0) {
989 return -x;
990 } else {
991 return x;
992 }
993 },
994 .Int => |int_info| {
995 if (int_info.signedness == .unsigned) return x;
996 const Uint = std.meta.Int(.unsigned, int_info.bits);
997 if (x < 0) {
998 return ~@as(Uint, @bitCast(x +% -1));
999 } else {
1000 return @as(Uint, @intCast(x));
1001 }
1002 },
1003 else => unreachable,
1004 }
1005}
1006
1007test "absCast" {
1008 try testing.expectEqual(@as(u1, 1), absCast(@as(i1, -1)));
1009 try testing.expectEqual(@as(u32, 999), absCast(@as(i32, -999)));
1010 try testing.expectEqual(@as(u32, 999), absCast(@as(i32, 999)));
1011 try testing.expectEqual(@as(u32, -minInt(i32)), absCast(@as(i32, minInt(i32))));
1012 try testing.expectEqual(999, absCast(-999));
1013}
1014
1015925/// Returns the negation of the integer parameter.
1016926/// Result is a signed integer.
1017927pub fn negateCast(x: anytype) !std.meta.Int(.signed, @bitSizeOf(@TypeOf(x))) {
lib/std/math/asin.zig+2-2
......@@ -60,7 +60,7 @@ fn asin32(x: f32) f32 {
6060 }
6161
6262 // 1 > |x| >= 0.5
63 const z = (1 - @fabs(x)) * 0.5;
63 const z = (1 - @abs(x)) * 0.5;
6464 const s = @sqrt(z);
6565 const fx = pio2 - 2 * (s + s * r32(z));
6666
......@@ -119,7 +119,7 @@ fn asin64(x: f64) f64 {
119119 }
120120
121121 // 1 > |x| >= 0.5
122 const z = (1 - @fabs(x)) * 0.5;
122 const z = (1 - @abs(x)) * 0.5;
123123 const s = @sqrt(z);
124124 const r = r64(z);
125125 var fx: f64 = undefined;
lib/std/math/atan.zig+2-2
......@@ -73,7 +73,7 @@ fn atan32(x_: f32) f32 {
7373 }
7474 id = null;
7575 } else {
76 x = @fabs(x);
76 x = @abs(x);
7777 // |x| < 1.1875
7878 if (ix < 0x3F980000) {
7979 // 7/16 <= |x| < 11/16
......@@ -171,7 +171,7 @@ fn atan64(x_: f64) f64 {
171171 }
172172 id = null;
173173 } else {
174 x = @fabs(x);
174 x = @abs(x);
175175 // |x| < 1.1875
176176 if (ix < 0x3FF30000) {
177177 // 7/16 <= |x| < 11/16
lib/std/math/atan2.zig+2-2
......@@ -108,7 +108,7 @@ fn atan2_32(y: f32, x: f32) f32 {
108108 if ((m & 2) != 0 and iy + (26 << 23) < ix) {
109109 break :z 0.0;
110110 } else {
111 break :z math.atan(@fabs(y / x));
111 break :z math.atan(@abs(y / x));
112112 }
113113 };
114114
......@@ -198,7 +198,7 @@ fn atan2_64(y: f64, x: f64) f64 {
198198 if ((m & 2) != 0 and iy +% (64 << 20) < ix) {
199199 break :z 0.0;
200200 } else {
201 break :z math.atan(@fabs(y / x));
201 break :z math.atan(@abs(y / x));
202202 }
203203 };
204204
lib/std/math/big/int.zig+3-3
......@@ -29,7 +29,7 @@ pub fn calcLimbLen(scalar: anytype) usize {
2929 return 1;
3030 }
3131
32 const w_value = std.math.absCast(scalar);
32 const w_value = @abs(scalar);
3333 return @as(usize, @intCast(@divFloor(@as(Limb, @intCast(math.log2(w_value))), limb_bits) + 1));
3434}
3535
......@@ -240,7 +240,7 @@ pub const Mutable = struct {
240240
241241 switch (@typeInfo(T)) {
242242 .Int => |info| {
243 var w_value = std.math.absCast(value);
243 var w_value = @abs(value);
244244
245245 if (info.bits <= limb_bits) {
246246 self.limbs[0] = w_value;
......@@ -255,7 +255,7 @@ pub const Mutable = struct {
255255 }
256256 },
257257 .ComptimeInt => {
258 comptime var w_value = std.math.absCast(value);
258 comptime var w_value = @abs(value);
259259
260260 if (w_value <= maxInt(Limb)) {
261261 self.limbs[0] = w_value;
lib/std/math/complex/cosh.zig+4-4
......@@ -44,12 +44,12 @@ fn cosh32(z: Complex(f32)) Complex(f32) {
4444 // |x|>= 9, so cosh(x) ~= exp(|x|)
4545 if (ix < 0x42b17218) {
4646 // x < 88.7: exp(|x|) won't overflow
47 const h = @exp(@fabs(x)) * 0.5;
47 const h = @exp(@abs(x)) * 0.5;
4848 return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y));
4949 }
5050 // x < 192.7: scale to avoid overflow
5151 else if (ix < 0x4340b1e7) {
52 const v = Complex(f32).init(@fabs(x), y);
52 const v = Complex(f32).init(@abs(x), y);
5353 const r = ldexp_cexp(v, -1);
5454 return Complex(f32).init(r.re, r.im * math.copysign(@as(f32, 1.0), x));
5555 }
......@@ -112,12 +112,12 @@ fn cosh64(z: Complex(f64)) Complex(f64) {
112112 // |x|>= 22, so cosh(x) ~= exp(|x|)
113113 if (ix < 0x40862e42) {
114114 // x < 710: exp(|x|) won't overflow
115 const h = @exp(@fabs(x)) * 0.5;
115 const h = @exp(@abs(x)) * 0.5;
116116 return Complex(f64).init(h * @cos(y), math.copysign(h, x) * @sin(y));
117117 }
118118 // x < 1455: scale to avoid overflow
119119 else if (ix < 0x4096bbaa) {
120 const v = Complex(f64).init(@fabs(x), y);
120 const v = Complex(f64).init(@abs(x), y);
121121 const r = ldexp_cexp(v, -1);
122122 return Complex(f64).init(r.re, r.im * math.copysign(@as(f64, 1.0), x));
123123 }
lib/std/math/complex/sinh.zig+4-4
......@@ -44,12 +44,12 @@ fn sinh32(z: Complex(f32)) Complex(f32) {
4444 // |x|>= 9, so cosh(x) ~= exp(|x|)
4545 if (ix < 0x42b17218) {
4646 // x < 88.7: exp(|x|) won't overflow
47 const h = @exp(@fabs(x)) * 0.5;
47 const h = @exp(@abs(x)) * 0.5;
4848 return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y));
4949 }
5050 // x < 192.7: scale to avoid overflow
5151 else if (ix < 0x4340b1e7) {
52 const v = Complex(f32).init(@fabs(x), y);
52 const v = Complex(f32).init(@abs(x), y);
5353 const r = ldexp_cexp(v, -1);
5454 return Complex(f32).init(r.re * math.copysign(@as(f32, 1.0), x), r.im);
5555 }
......@@ -111,12 +111,12 @@ fn sinh64(z: Complex(f64)) Complex(f64) {
111111 // |x|>= 22, so cosh(x) ~= exp(|x|)
112112 if (ix < 0x40862e42) {
113113 // x < 710: exp(|x|) won't overflow
114 const h = @exp(@fabs(x)) * 0.5;
114 const h = @exp(@abs(x)) * 0.5;
115115 return Complex(f64).init(math.copysign(h, x) * @cos(y), h * @sin(y));
116116 }
117117 // x < 1455: scale to avoid overflow
118118 else if (ix < 0x4096bbaa) {
119 const v = Complex(f64).init(@fabs(x), y);
119 const v = Complex(f64).init(@abs(x), y);
120120 const r = ldexp_cexp(v, -1);
121121 return Complex(f64).init(r.re * math.copysign(@as(f64, 1.0), x), r.im);
122122 }
lib/std/math/complex/sqrt.zig+5-5
......@@ -43,7 +43,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {
4343 // sqrt(-inf + i nan) = nan +- inf i
4444 // sqrt(-inf + iy) = 0 + inf i
4545 if (math.signbit(x)) {
46 return Complex(f32).init(@fabs(x - y), math.copysign(x, y));
46 return Complex(f32).init(@abs(x - y), math.copysign(x, y));
4747 } else {
4848 return Complex(f32).init(x, math.copysign(y - y, y));
4949 }
......@@ -64,7 +64,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {
6464 } else {
6565 const t = @sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5);
6666 return Complex(f32).init(
67 @as(f32, @floatCast(@fabs(y) / (2.0 * t))),
67 @as(f32, @floatCast(@abs(y) / (2.0 * t))),
6868 @as(f32, @floatCast(math.copysign(t, y))),
6969 );
7070 }
......@@ -94,7 +94,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
9494 // sqrt(-inf + i nan) = nan +- inf i
9595 // sqrt(-inf + iy) = 0 + inf i
9696 if (math.signbit(x)) {
97 return Complex(f64).init(@fabs(x - y), math.copysign(x, y));
97 return Complex(f64).init(@abs(x - y), math.copysign(x, y));
9898 } else {
9999 return Complex(f64).init(x, math.copysign(y - y, y));
100100 }
......@@ -104,7 +104,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
104104
105105 // scale to avoid overflow
106106 var scale = false;
107 if (@fabs(x) >= threshold or @fabs(y) >= threshold) {
107 if (@abs(x) >= threshold or @abs(y) >= threshold) {
108108 x *= 0.25;
109109 y *= 0.25;
110110 scale = true;
......@@ -116,7 +116,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
116116 result = Complex(f64).init(t, y / (2.0 * t));
117117 } else {
118118 const t = @sqrt((-x + math.hypot(f64, x, y)) * 0.5);
119 result = Complex(f64).init(@fabs(y) / (2.0 * t), math.copysign(t, y));
119 result = Complex(f64).init(@abs(y) / (2.0 * t), math.copysign(t, y));
120120 }
121121
122122 if (scale) {
lib/std/math/complex/tanh.zig+2-2
......@@ -44,7 +44,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) {
4444
4545 // x >= 11
4646 if (ix >= 0x41300000) {
47 const exp_mx = @exp(-@fabs(x));
47 const exp_mx = @exp(-@abs(x));
4848 return Complex(f32).init(math.copysign(@as(f32, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx);
4949 }
5050
......@@ -87,7 +87,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) {
8787
8888 // x >= 22
8989 if (ix >= 0x40360000) {
90 const exp_mx = @exp(-@fabs(x));
90 const exp_mx = @exp(-@abs(x));
9191 return Complex(f64).init(math.copysign(@as(f64, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx);
9292 }
9393
lib/std/math/pow.zig+2-2
......@@ -82,7 +82,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
8282 }
8383 // pow(x, +inf) = +0 for |x| < 1
8484 // pow(x, -inf) = +0 for |x| > 1
85 else if ((@fabs(x) < 1) == math.isPositiveInf(y)) {
85 else if ((@abs(x) < 1) == math.isPositiveInf(y)) {
8686 return 0;
8787 }
8888 // pow(x, -inf) = +inf for |x| < 1
......@@ -115,7 +115,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
115115 return 1 / @sqrt(x);
116116 }
117117
118 const r1 = math.modf(@fabs(y));
118 const r1 = math.modf(@abs(y));
119119 var yi = r1.ipart;
120120 var yf = r1.fpart;
121121
lib/std/meta.zig+2-2
......@@ -1104,6 +1104,6 @@ pub fn isError(error_union: anytype) bool {
11041104}
11051105
11061106test "isError" {
1107 try std.testing.expect(isError(math.absInt(@as(i8, -128))));
1108 try std.testing.expect(!isError(math.absInt(@as(i8, -127))));
1107 try std.testing.expect(isError(math.divTrunc(u8, 5, 0)));
1108 try std.testing.expect(!isError(math.divTrunc(u8, 5, 5)));
11091109}
lib/std/rand/ziggurat.zig+1-1
......@@ -33,7 +33,7 @@ pub fn next_f64(random: Random, comptime tables: ZigTable) f64 {
3333 };
3434
3535 const x = u * tables.x[i];
36 const test_x = if (tables.is_symmetric) @fabs(x) else x;
36 const test_x = if (tables.is_symmetric) @abs(x) else x;
3737
3838 // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i])
3939 if (test_x < tables.x[i + 1]) {
lib/std/zig/c_builtins.zig+9-3
......@@ -88,13 +88,19 @@ pub inline fn __builtin_log10f(val: f32) f32 {
8888
8989// Standard C Library bug: The absolute value of the most negative integer remains negative.
9090pub inline fn __builtin_abs(val: c_int) c_int {
91 return std.math.absInt(val) catch std.math.minInt(c_int);
91 return if (val == std.math.minInt(c_int)) val else @intCast(@abs(val));
92}
93pub inline fn __builtin_labs(val: c_long) c_long {
94 return if (val == std.math.minInt(c_long)) val else @intCast(@abs(val));
95}
96pub inline fn __builtin_llabs(val: c_longlong) c_longlong {
97 return if (val == std.math.minInt(c_longlong)) val else @intCast(@abs(val));
9298}
9399pub inline fn __builtin_fabs(val: f64) f64 {
94 return @fabs(val);
100 return @abs(val);
95101}
96102pub inline fn __builtin_fabsf(val: f32) f32 {
97 return @fabs(val);
103 return @abs(val);
98104}
99105
100106pub inline fn __builtin_floor(val: f64) f64 {
lib/std/zig/render.zig+2
......@@ -1503,6 +1503,8 @@ fn renderBuiltinCall(
15031503 try ais.writer().writeAll("@ptrFromInt");
15041504 } else if (mem.eql(u8, slice, "@ptrToInt")) {
15051505 try ais.writer().writeAll("@intFromPtr");
1506 } else if (mem.eql(u8, slice, "@fabs")) {
1507 try ais.writer().writeAll("@abs");
15061508 } else {
15071509 try renderToken(ais, tree, builtin_token, .none); // @name
15081510 }
lib/zig.h+41
......@@ -946,6 +946,24 @@ typedef unsigned long zig_Builtin64;
946946typedef unsigned long long zig_Builtin64;
947947#endif
948948
949#define zig_builtin8_rev(name, val) __builtin_##name(val)
950
951#define zig_builtin16_rev(name, val) __builtin_##name(val)
952
953#if INT_MIN <= INT32_MIN
954#define zig_builtin32_rev(name, val) __builtin_##name(val)
955#elif LONG_MIN <= INT32_MIN
956#define zig_builtin32_rev(name, val) __builtin_l##name(val)
957#endif
958
959#if INT_MIN <= INT64_MIN
960#define zig_builtin64_rev(name, val) __builtin_##name(val)
961#elif LONG_MIN <= INT64_MIN
962#define zig_builtin64_rev(name, val) __builtin_l##name(val)
963#elif LLONG_MIN <= INT64_MIN
964#define zig_builtin64_rev(name, val) __builtin_ll##name(val)
965#endif
966
949967static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) {
950968 return zig_wrap_u8(val >> (8 - bits), bits);
951969}
......@@ -1141,6 +1159,24 @@ zig_builtin_clz(16)
11411159zig_builtin_clz(32)
11421160zig_builtin_clz(64)
11431161
1162#if zig_has_builtin(abs) || defined(zig_gnuc)
1163#define zig_builtin_abs(w) \
1164 static inline int##w##_t zig_abs_i##w(int##w##_t val) { \
1165 return zig_builtin##w##_rev(abs, val); \
1166 }
1167#else
1168#define zig_builtin_abs(w) \
1169 static inline int##w##_t zig_abs_i##w(int##w##_t val) { \
1170 if (val == INT##w##_MIN) return val; \
1171 int##w##_t tmp = val >> (w - 1); \
1172 return (val ^ tmp) - tmp; \
1173 }
1174#endif
1175zig_builtin_abs(8)
1176zig_builtin_abs(16)
1177zig_builtin_abs(32)
1178zig_builtin_abs(64)
1179
11441180/* ======================== 128-bit Integer Support ========================= */
11451181
11461182#if !defined(zig_has_int128)
......@@ -1466,6 +1502,11 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
14661502 return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);
14671503}
14681504
1505static inline zig_u128 zig_abs_i128(zig_i128 val) {
1506 zig_i128 tmp = zig_shr_i128(val, 127);
1507 return zig_bitCast_u128(zig_sub_i128(zig_xor_i128(val, tmp), tmp));
1508}
1509
14691510#if zig_has_int128
14701511
14711512static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
src/Air.zig+6-5
......@@ -356,9 +356,10 @@ pub const Inst = struct {
356356 /// Base 10 logarithm of a floating point number.
357357 /// Uses the `un_op` field.
358358 log10,
359 /// Aboslute value of a floating point number.
360 /// Uses the `un_op` field.
361 fabs,
359 /// Aboslute value of an integer, floating point number or vector.
360 /// Result type is always unsigned if the operand is an integer.
361 /// Uses the `ty_op` field.
362 abs,
362363 /// Floor: rounds a floating pointer number down to the nearest integer.
363364 /// Uses the `un_op` field.
364365 floor,
......@@ -1279,7 +1280,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
12791280 .log,
12801281 .log2,
12811282 .log10,
1282 .fabs,
12831283 .floor,
12841284 .ceil,
12851285 .round,
......@@ -1384,6 +1384,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
13841384 .addrspace_cast,
13851385 .c_va_arg,
13861386 .c_va_copy,
1387 .abs,
13871388 => return air.getRefType(datas[inst].ty_op.ty),
13881389
13891390 .loop,
......@@ -1697,7 +1698,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
16971698 .log,
16981699 .log2,
16991700 .log10,
1700 .fabs,
1701 .abs,
17011702 .floor,
17021703 .ceil,
17031704 .round,
src/AstGen.zig+2-2
......@@ -2601,7 +2601,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
26012601 .log,
26022602 .log2,
26032603 .log10,
2604 .fabs,
2604 .abs,
26052605 .floor,
26062606 .ceil,
26072607 .trunc,
......@@ -8385,7 +8385,7 @@ fn builtinCall(
83858385 .log => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log),
83868386 .log2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log2),
83878387 .log10 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log10),
8388 .fabs => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .fabs),
8388 .abs => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .abs),
83898389 .floor => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .floor),
83908390 .ceil => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ceil),
83918391 .trunc => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .trunc),
src/AstRlAnnotate.zig+1-1
......@@ -929,7 +929,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
929929 .log,
930930 .log2,
931931 .log10,
932 .fabs,
932 .abs,
933933 .floor,
934934 .ceil,
935935 .trunc,
src/Autodoc.zig+1-1
......@@ -1669,7 +1669,7 @@ fn walkInstruction(
16691669 .log,
16701670 .log2,
16711671 .log10,
1672 .fabs,
1672 .abs,
16731673 .floor,
16741674 .ceil,
16751675 .trunc,
src/BuiltinFn.zig+3-3
......@@ -102,7 +102,7 @@ pub const Tag = enum {
102102 log,
103103 log2,
104104 log10,
105 fabs,
105 abs,
106106 floor,
107107 ceil,
108108 trunc,
......@@ -874,9 +874,9 @@ pub const list = list: {
874874 },
875875 },
876876 .{
877 "@fabs",
877 "@abs",
878878 .{
879 .tag = .fabs,
879 .tag = .abs,
880880 .param_count = 1,
881881 },
882882 },
src/Liveness.zig+2-2
......@@ -384,6 +384,7 @@ pub fn categorizeOperand(
384384 .addrspace_cast,
385385 .c_va_arg,
386386 .c_va_copy,
387 .abs,
387388 => {
388389 const o = air_datas[inst].ty_op;
389390 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
......@@ -420,7 +421,6 @@ pub fn categorizeOperand(
420421 .log,
421422 .log2,
422423 .log10,
423 .fabs,
424424 .floor,
425425 .ceil,
426426 .round,
......@@ -1027,6 +1027,7 @@ fn analyzeInst(
10271027 .addrspace_cast,
10281028 .c_va_arg,
10291029 .c_va_copy,
1030 .abs,
10301031 => {
10311032 const o = inst_datas[inst].ty_op;
10321033 return analyzeOperands(a, pass, data, inst, .{ o.operand, .none, .none });
......@@ -1054,7 +1055,6 @@ fn analyzeInst(
10541055 .log,
10551056 .log2,
10561057 .log10,
1057 .fabs,
10581058 .floor,
10591059 .ceil,
10601060 .round,
src/Liveness/Verify.zig+1-1
......@@ -110,6 +110,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
110110 .addrspace_cast,
111111 .c_va_arg,
112112 .c_va_copy,
113 .abs,
113114 => {
114115 const ty_op = data[inst].ty_op;
115116 try self.verifyInstOperands(inst, .{ ty_op.operand, .none, .none });
......@@ -136,7 +137,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
136137 .log,
137138 .log2,
138139 .log10,
139 .fabs,
140140 .floor,
141141 .ceil,
142142 .round,
src/Sema.zig+77-50
......@@ -1156,6 +1156,7 @@ fn analyzeBodyInner(
11561156 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
11571157 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
11581158 .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount),
1159 .abs => try sema.zirAbs(block, inst),
11591160
11601161 .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
11611162 .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
......@@ -1166,7 +1167,6 @@ fn analyzeBodyInner(
11661167 .log => try sema.zirUnaryMath(block, inst, .log, Value.log),
11671168 .log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2),
11681169 .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),
1169 .fabs => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs),
11701170 .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),
11711171 .ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),
11721172 .round => try sema.zirUnaryMath(block, inst, .round, Value.round),
......@@ -20178,6 +20178,69 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2017820178 return block.addUnOp(.error_name, operand);
2017920179}
2018020180
20181fn zirAbs(
20182 sema: *Sema,
20183 block: *Block,
20184 inst: Zir.Inst.Index,
20185) CompileError!Air.Inst.Ref {
20186 const mod = sema.mod;
20187 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
20188 const operand = try sema.resolveInst(inst_data.operand);
20189 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20190 const operand_ty = sema.typeOf(operand);
20191 const scalar_ty = operand_ty.scalarType(mod);
20192
20193 const result_ty = switch (scalar_ty.zigTypeTag(mod)) {
20194 .ComptimeFloat, .Float, .ComptimeInt => operand_ty,
20195 .Int => if (scalar_ty.isSignedInt(mod)) try operand_ty.toUnsigned(mod) else return operand,
20196 else => return sema.fail(
20197 block,
20198 operand_src,
20199 "expected integer, float, or vector of either integers or floats, found '{}'",
20200 .{operand_ty.fmt(mod)},
20201 ),
20202 };
20203
20204 return (try sema.maybeConstantUnaryMath(operand, result_ty, Value.abs)) orelse {
20205 try sema.requireRuntimeBlock(block, operand_src, null);
20206 return block.addTyOp(.abs, result_ty, operand);
20207 };
20208}
20209
20210fn maybeConstantUnaryMath(
20211 sema: *Sema,
20212 operand: Air.Inst.Ref,
20213 result_ty: Type,
20214 comptime eval: fn (Value, Type, Allocator, *Module) Allocator.Error!Value,
20215) CompileError!?Air.Inst.Ref {
20216 const mod = sema.mod;
20217 switch (result_ty.zigTypeTag(mod)) {
20218 .Vector => if (try sema.resolveMaybeUndefVal(operand)) |val| {
20219 const scalar_ty = result_ty.scalarType(mod);
20220 const vec_len = result_ty.vectorLen(mod);
20221 if (val.isUndef(mod))
20222 return try mod.undefRef(result_ty);
20223
20224 const elems = try sema.arena.alloc(InternPool.Index, vec_len);
20225 for (elems, 0..) |*elem, i| {
20226 const elem_val = try val.elemValue(sema.mod, i);
20227 elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod);
20228 }
20229 return Air.internedToRef((try mod.intern(.{ .aggregate = .{
20230 .ty = result_ty.toIntern(),
20231 .storage = .{ .elems = elems },
20232 } })));
20233 },
20234 else => if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
20235 if (operand_val.isUndef(mod))
20236 return try mod.undefRef(result_ty);
20237 const result_val = try eval(operand_val, result_ty, sema.arena, sema.mod);
20238 return Air.internedToRef(result_val.toIntern());
20239 },
20240 }
20241 return null;
20242}
20243
2018120244fn zirUnaryMath(
2018220245 sema: *Sema,
2018320246 block: *Block,
......@@ -20193,58 +20256,22 @@ fn zirUnaryMath(
2019320256 const operand = try sema.resolveInst(inst_data.operand);
2019420257 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2019520258 const operand_ty = sema.typeOf(operand);
20259 const scalar_ty = operand_ty.scalarType(mod);
2019620260
20197 switch (operand_ty.zigTypeTag(mod)) {
20261 switch (scalar_ty.zigTypeTag(mod)) {
2019820262 .ComptimeFloat, .Float => {},
20199 .Vector => {
20200 const scalar_ty = operand_ty.scalarType(mod);
20201 switch (scalar_ty.zigTypeTag(mod)) {
20202 .ComptimeFloat, .Float => {},
20203 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}),
20204 }
20205 },
20206 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}),
20263 else => return sema.fail(
20264 block,
20265 operand_src,
20266 "expected vector of floats or float type, found '{}'",
20267 .{operand_ty.fmt(sema.mod)},
20268 ),
2020720269 }
2020820270
20209 switch (operand_ty.zigTypeTag(mod)) {
20210 .Vector => {
20211 const scalar_ty = operand_ty.scalarType(mod);
20212 const vec_len = operand_ty.vectorLen(mod);
20213 const result_ty = try mod.vectorType(.{
20214 .len = vec_len,
20215 .child = scalar_ty.toIntern(),
20216 });
20217 if (try sema.resolveMaybeUndefVal(operand)) |val| {
20218 if (val.isUndef(mod))
20219 return mod.undefRef(result_ty);
20220
20221 const elems = try sema.arena.alloc(InternPool.Index, vec_len);
20222 for (elems, 0..) |*elem, i| {
20223 const elem_val = try val.elemValue(sema.mod, i);
20224 elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod);
20225 }
20226 return Air.internedToRef((try mod.intern(.{ .aggregate = .{
20227 .ty = result_ty.toIntern(),
20228 .storage = .{ .elems = elems },
20229 } })));
20230 }
20231
20232 try sema.requireRuntimeBlock(block, operand_src, null);
20233 return block.addUnOp(air_tag, operand);
20234 },
20235 .ComptimeFloat, .Float => {
20236 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
20237 if (operand_val.isUndef(mod))
20238 return mod.undefRef(operand_ty);
20239 const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod);
20240 return Air.internedToRef(result_val.toIntern());
20241 }
20242
20243 try sema.requireRuntimeBlock(block, operand_src, null);
20244 return block.addUnOp(air_tag, operand);
20245 },
20246 else => unreachable,
20247 }
20271 return (try sema.maybeConstantUnaryMath(operand, operand_ty, eval)) orelse {
20272 try sema.requireRuntimeBlock(block, operand_src, null);
20273 return block.addUnOp(air_tag, operand);
20274 };
2024820275}
2024920276
2025020277fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -37503,7 +37530,7 @@ fn float128IntPartToBigInt(
3750337530 float: f128,
3750437531) !std.math.big.int.Managed {
3750537532 const is_negative = std.math.signbit(float);
37506 const floored = @floor(@fabs(float));
37533 const floored = @floor(@abs(float));
3750737534
3750837535 var rational = try std.math.big.Rational.init(arena);
3750937536 defer rational.q.deinit();
src/Zir.zig+5-5
......@@ -846,8 +846,8 @@ pub const Inst = struct {
846846 log2,
847847 /// Implement builtin `@log10`. Uses `un_node`.
848848 log10,
849 /// Implement builtin `@fabs`. Uses `un_node`.
850 fabs,
849 /// Implement builtin `@abs`. Uses `un_node`.
850 abs,
851851 /// Implement builtin `@floor`. Uses `un_node`.
852852 floor,
853853 /// Implement builtin `@ceil`. Uses `un_node`.
......@@ -1198,7 +1198,7 @@ pub const Inst = struct {
11981198 .log,
11991199 .log2,
12001200 .log10,
1201 .fabs,
1201 .abs,
12021202 .floor,
12031203 .ceil,
12041204 .trunc,
......@@ -1493,7 +1493,7 @@ pub const Inst = struct {
14931493 .log,
14941494 .log2,
14951495 .log10,
1496 .fabs,
1496 .abs,
14971497 .floor,
14981498 .ceil,
14991499 .trunc,
......@@ -1756,7 +1756,7 @@ pub const Inst = struct {
17561756 .log = .un_node,
17571757 .log2 = .un_node,
17581758 .log10 = .un_node,
1759 .fabs = .un_node,
1759 .abs = .un_node,
17601760 .floor = .un_node,
17611761 .ceil = .un_node,
17621762 .trunc = .un_node,
src/arch/aarch64/CodeGen.zig+7-1
......@@ -713,7 +713,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
713713 .log,
714714 .log2,
715715 .log10,
716 .fabs,
717716 .floor,
718717 .ceil,
719718 .round,
......@@ -788,6 +787,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
788787 .clz => try self.airClz(inst),
789788 .ctz => try self.airCtz(inst),
790789 .popcount => try self.airPopcount(inst),
790 .abs => try self.airAbs(inst),
791791 .byte_swap => try self.airByteSwap(inst),
792792 .bit_reverse => try self.airBitReverse(inst),
793793 .tag_name => try self.airTagName(inst),
......@@ -3550,6 +3550,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
35503550 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
35513551}
35523552
3553fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
3554 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3555 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airAbs for {}", .{self.target.cpu.arch});
3556 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3557}
3558
35533559fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
35543560 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
35553561 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch});
src/arch/arm/CodeGen.zig+8-1
......@@ -699,7 +699,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
699699 .log,
700700 .log2,
701701 .log10,
702 .fabs,
703702 .floor,
704703 .ceil,
705704 .round,
......@@ -774,6 +773,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
774773 .clz => try self.airClz(inst),
775774 .ctz => try self.airCtz(inst),
776775 .popcount => try self.airPopcount(inst),
776 .abs => try self.airAbs(inst),
777777 .byte_swap => try self.airByteSwap(inst),
778778 .bit_reverse => try self.airBitReverse(inst),
779779 .tag_name => try self.airTagName(inst),
......@@ -2591,6 +2591,13 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
25912591 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
25922592}
25932593
2594fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
2595 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2596 _ = ty_op;
2597 return self.fail("TODO implement airAbs for {}", .{self.target.cpu.arch});
2598 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2599}
2600
25942601fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
25952602 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
25962603 _ = ty_op;
src/arch/riscv64/CodeGen.zig+7-1
......@@ -523,7 +523,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
523523 .log,
524524 .log2,
525525 .log10,
526 .fabs,
527526 .floor,
528527 .ceil,
529528 .round,
......@@ -607,6 +606,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
607606 .clz => try self.airClz(inst),
608607 .ctz => try self.airCtz(inst),
609608 .popcount => try self.airPopcount(inst),
609 .abs => try self.airAbs(inst),
610610 .byte_swap => try self.airByteSwap(inst),
611611 .bit_reverse => try self.airBitReverse(inst),
612612 .tag_name => try self.airTagName(inst),
......@@ -1447,6 +1447,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
14471447 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
14481448}
14491449
1450fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
1451 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1452 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airAbs for {}", .{self.target.cpu.arch});
1453 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1454}
1455
14501456fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
14511457 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
14521458 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airByteSwap for {}", .{self.target.cpu.arch});
src/arch/sparc64/CodeGen.zig+1-1
......@@ -543,7 +543,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
543543 .log,
544544 .log2,
545545 .log10,
546 .fabs,
546 .abs,
547547 .floor,
548548 .ceil,
549549 .round,
src/arch/wasm/CodeGen.zig+78-1
......@@ -1866,13 +1866,14 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18661866 .log => func.airUnaryFloatOp(inst, .log),
18671867 .log2 => func.airUnaryFloatOp(inst, .log2),
18681868 .log10 => func.airUnaryFloatOp(inst, .log10),
1869 .fabs => func.airUnaryFloatOp(inst, .fabs),
18701869 .floor => func.airUnaryFloatOp(inst, .floor),
18711870 .ceil => func.airUnaryFloatOp(inst, .ceil),
18721871 .round => func.airUnaryFloatOp(inst, .round),
18731872 .trunc_float => func.airUnaryFloatOp(inst, .trunc),
18741873 .neg => func.airUnaryFloatOp(inst, .neg),
18751874
1875 .abs => func.airAbs(inst),
1876
18761877 .add_with_overflow => func.airAddSubWithOverflow(inst, .add),
18771878 .sub_with_overflow => func.airAddSubWithOverflow(inst, .sub),
18781879 .shl_with_overflow => func.airShlWithOverflow(inst),
......@@ -2786,6 +2787,82 @@ const FloatOp = enum {
27862787 }
27872788};
27882789
2790fn airAbs(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2791 const mod = func.bin_file.base.options.module.?;
2792 const ty_op = func.air.instructions.items(.data)[inst].ty_op;
2793 const operand = try func.resolveInst(ty_op.operand);
2794 const ty = func.typeOf(ty_op.operand);
2795 const scalar_ty = ty.scalarType(mod);
2796
2797 switch (scalar_ty.zigTypeTag(mod)) {
2798 .Int => if (ty.zigTypeTag(mod) == .Vector) {
2799 return func.fail("TODO implement airAbs for {}", .{ty.fmt(mod)});
2800 } else {
2801 const int_bits = ty.intInfo(mod).bits;
2802 const wasm_bits = toWasmBits(int_bits) orelse {
2803 return func.fail("TODO: airAbs for signed integers larger than '{d}' bits", .{int_bits});
2804 };
2805
2806 const op = try operand.toLocal(func, ty);
2807
2808 try func.emitWValue(op);
2809 switch (wasm_bits) {
2810 32 => {
2811 if (wasm_bits != int_bits) {
2812 try func.addImm32(wasm_bits - int_bits);
2813 try func.addTag(.i32_shl);
2814 }
2815 try func.addImm32(31);
2816 try func.addTag(.i32_shr_s);
2817
2818 const tmp = try func.allocLocal(ty);
2819 try func.addLabel(.local_tee, tmp.local.value);
2820
2821 try func.emitWValue(op);
2822 try func.addTag(.i32_xor);
2823 try func.emitWValue(tmp);
2824 try func.addTag(.i32_sub);
2825
2826 if (int_bits != wasm_bits) {
2827 try func.emitWValue(WValue{ .imm32 = (@as(u32, 1) << @intCast(int_bits)) - 1 });
2828 try func.addTag(.i32_and);
2829 }
2830 },
2831 64 => {
2832 if (wasm_bits != int_bits) {
2833 try func.addImm64(wasm_bits - int_bits);
2834 try func.addTag(.i64_shl);
2835 }
2836 try func.addImm64(63);
2837 try func.addTag(.i64_shr_s);
2838
2839 const tmp = try func.allocLocal(ty);
2840 try func.addLabel(.local_tee, tmp.local.value);
2841
2842 try func.emitWValue(op);
2843 try func.addTag(.i64_xor);
2844 try func.emitWValue(tmp);
2845 try func.addTag(.i64_sub);
2846
2847 if (int_bits != wasm_bits) {
2848 try func.emitWValue(WValue{ .imm64 = (@as(u64, 1) << @intCast(int_bits)) - 1 });
2849 try func.addTag(.i64_and);
2850 }
2851 },
2852 else => return func.fail("TODO: Implement airAbs for {}", .{ty.fmt(mod)}),
2853 }
2854
2855 const result = try (WValue{ .stack = {} }).toLocal(func, ty);
2856 func.finishAir(inst, result, &.{ty_op.operand});
2857 },
2858 .Float => {
2859 const result = try (try func.floatOp(.fabs, ty, &.{operand})).toLocal(func, ty);
2860 func.finishAir(inst, result, &.{ty_op.operand});
2861 },
2862 else => unreachable,
2863 }
2864}
2865
27892866fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {
27902867 const un_op = func.air.instructions.items(.data)[inst].un_op;
27912868 const operand = try func.resolveInst(un_op);
src/arch/x86_64/CodeGen.zig+75-22
......@@ -1809,11 +1809,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
18091809 .round,
18101810 => try self.airUnaryMath(inst),
18111811
1812 .floor => try self.airRound(inst, 0b1_0_01),
1813 .ceil => try self.airRound(inst, 0b1_0_10),
1812 .floor => try self.airRound(inst, 0b1_0_01),
1813 .ceil => try self.airRound(inst, 0b1_0_10),
18141814 .trunc_float => try self.airRound(inst, 0b1_0_11),
1815 .sqrt => try self.airSqrt(inst),
1816 .neg, .fabs => try self.airFloatSign(inst),
1815 .sqrt => try self.airSqrt(inst),
1816 .neg => try self.airFloatSign(inst),
1817
1818 .abs => try self.airAbs(inst),
18171819
18181820 .add_with_overflow => try self.airAddSubWithOverflow(inst),
18191821 .sub_with_overflow => try self.airAddSubWithOverflow(inst),
......@@ -4885,28 +4887,26 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
48854887 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
48864888}
48874889
4888fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
4890fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void {
48894891 const mod = self.bin_file.options.module.?;
48904892 const tag = self.air.instructions.items(.tag)[inst];
4891 const un_op = self.air.instructions.items(.data)[inst].un_op;
4892 const ty = self.typeOf(un_op);
48934893 const abi_size: u32 = switch (ty.abiSize(mod)) {
48944894 1...16 => 16,
48954895 17...32 => 32,
4896 else => return self.fail("TODO implement airFloatSign for {}", .{
4896 else => return self.fail("TODO implement floatSign for {}", .{
48974897 ty.fmt(mod),
48984898 }),
48994899 };
49004900 const scalar_bits = ty.scalarType(mod).floatBits(self.target.*);
4901 if (scalar_bits == 80) return self.fail("TODO implement airFloatSign for {}", .{
4901 if (scalar_bits == 80) return self.fail("TODO implement floatSign for {}", .{
49024902 ty.fmt(mod),
49034903 });
49044904
4905 const src_mcv = try self.resolveInst(un_op);
4905 const src_mcv = try self.resolveInst(operand);
49064906 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
49074907 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
49084908
4909 const dst_mcv: MCValue = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
4909 const dst_mcv: MCValue = if (src_mcv.isRegister() and self.reuseOperand(inst, operand, 0, src_mcv))
49104910 src_mcv
49114911 else if (self.hasFeature(.avx))
49124912 .{ .register = try self.register_manager.allocReg(inst, sse) }
......@@ -4923,7 +4923,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
49234923
49244924 const sign_val = switch (tag) {
49254925 .neg => try vec_ty.minInt(mod, vec_ty),
4926 .fabs => try vec_ty.maxInt(mod, vec_ty),
4926 .abs => try vec_ty.maxInt(mod, vec_ty),
49274927 else => unreachable,
49284928 };
49294929
......@@ -4939,24 +4939,24 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
49394939 switch (scalar_bits) {
49404940 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {
49414941 .neg => .{ .vp_, .xor },
4942 .fabs => .{ .vp_, .@"and" },
4942 .abs => .{ .vp_, .@"and" },
49434943 else => unreachable,
49444944 } else switch (tag) {
49454945 .neg => .{ .v_ps, .xor },
4946 .fabs => .{ .v_ps, .@"and" },
4946 .abs => .{ .v_ps, .@"and" },
49474947 else => unreachable,
49484948 },
49494949 32 => switch (tag) {
49504950 .neg => .{ .v_ps, .xor },
4951 .fabs => .{ .v_ps, .@"and" },
4951 .abs => .{ .v_ps, .@"and" },
49524952 else => unreachable,
49534953 },
49544954 64 => switch (tag) {
49554955 .neg => .{ .v_pd, .xor },
4956 .fabs => .{ .v_pd, .@"and" },
4956 .abs => .{ .v_pd, .@"and" },
49574957 else => unreachable,
49584958 },
4959 80 => return self.fail("TODO implement airFloatSign for {}", .{
4959 80 => return self.fail("TODO implement floatSign for {}", .{
49604960 ty.fmt(self.bin_file.options.module.?),
49614961 }),
49624962 else => unreachable,
......@@ -4971,20 +4971,20 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
49714971 switch (scalar_bits) {
49724972 16, 128 => switch (tag) {
49734973 .neg => .{ .p_, .xor },
4974 .fabs => .{ .p_, .@"and" },
4974 .abs => .{ .p_, .@"and" },
49754975 else => unreachable,
49764976 },
49774977 32 => switch (tag) {
49784978 .neg => .{ ._ps, .xor },
4979 .fabs => .{ ._ps, .@"and" },
4979 .abs => .{ ._ps, .@"and" },
49804980 else => unreachable,
49814981 },
49824982 64 => switch (tag) {
49834983 .neg => .{ ._pd, .xor },
4984 .fabs => .{ ._pd, .@"and" },
4984 .abs => .{ ._pd, .@"and" },
49854985 else => unreachable,
49864986 },
4987 80 => return self.fail("TODO implement airFloatSign for {}", .{
4987 80 => return self.fail("TODO implement floatSign for {}", .{
49884988 ty.fmt(self.bin_file.options.module.?),
49894989 }),
49904990 else => unreachable,
......@@ -4992,7 +4992,14 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
49924992 registerAlias(dst_reg, abi_size),
49934993 sign_mem,
49944994 );
4995 return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
4995 return self.finishAir(inst, dst_mcv, .{ operand, .none, .none });
4996}
4997
4998fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
4999 const un_op = self.air.instructions.items(.data)[inst].un_op;
5000 const ty = self.typeOf(un_op);
5001
5002 return self.floatSign(inst, un_op, ty);
49965003}
49975004
49985005fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {
......@@ -5082,6 +5089,52 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
50825089 }
50835090}
50845091
5092fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
5093 const mod = self.bin_file.options.module.?;
5094 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5095 const ty = self.typeOf(ty_op.operand);
5096 const scalar_ty = ty.scalarType(mod);
5097
5098 switch (scalar_ty.zigTypeTag(mod)) {
5099 .Int => if (ty.zigTypeTag(mod) == .Vector) {
5100 return self.fail("TODO implement airAbs for {}", .{ty.fmt(mod)});
5101 } else {
5102 if (ty.abiSize(mod) > 8) {
5103 return self.fail("TODO implement abs for integer abi sizes larger than 8", .{});
5104 }
5105 const src_mcv = try self.resolveInst(ty_op.operand);
5106 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5107
5108 try self.genUnOpMir(.{ ._, .neg }, ty, dst_mcv);
5109
5110 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);
5111 switch (src_mcv) {
5112 .register => |val_reg| try self.asmCmovccRegisterRegister(
5113 registerAlias(dst_mcv.register, cmov_abi_size),
5114 registerAlias(val_reg, cmov_abi_size),
5115 .l,
5116 ),
5117 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
5118 registerAlias(dst_mcv.register, cmov_abi_size),
5119 src_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
5120 .l,
5121 ),
5122 else => {
5123 const val_reg = try self.copyToTmpRegister(ty, src_mcv);
5124 try self.asmCmovccRegisterRegister(
5125 registerAlias(dst_mcv.register, cmov_abi_size),
5126 registerAlias(val_reg, cmov_abi_size),
5127 .l,
5128 );
5129 },
5130 }
5131 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
5132 },
5133 .Float => return self.floatSign(inst, ty_op.operand, ty),
5134 else => unreachable,
5135 }
5136}
5137
50855138fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
50865139 const mod = self.bin_file.options.module.?;
50875140 const un_op = self.air.instructions.items(.data)[inst].un_op;
src/arch/x86_64/encoder.zig+2-2
......@@ -105,7 +105,7 @@ pub const Instruction = struct {
105105 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
106106 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
107107 @as(u8, if (rip.disp < 0) '-' else '+'),
108 std.math.absCast(rip.disp),
108 @abs(rip.disp),
109109 });
110110 try writer.writeByte(']');
111111 },
......@@ -140,7 +140,7 @@ pub const Instruction = struct {
140140 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
141141 else if (sib.disp < 0)
142142 try writer.writeByte('-');
143 try writer.print("0x{x}", .{std.math.absCast(sib.disp)});
143 try writer.print("0x{x}", .{@abs(sib.disp)});
144144 any = true;
145145 }
146146
src/codegen/c.zig+32-10
......@@ -2912,6 +2912,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
29122912 },
29132913 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none),
29142914 .mod => try airBinBuiltinCall(f, inst, "mod", .none),
2915 .abs => try airAbs(f, inst),
29152916
29162917 .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits),
29172918 .sub_wrap => try airBinBuiltinCall(f, inst, "subw", .bits),
......@@ -2931,7 +2932,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
29312932 .log => try airUnFloatOp(f, inst, "log"),
29322933 .log2 => try airUnFloatOp(f, inst, "log2"),
29332934 .log10 => try airUnFloatOp(f, inst, "log10"),
2934 .fabs => try airUnFloatOp(f, inst, "fabs"),
29352935 .floor => try airUnFloatOp(f, inst, "floor"),
29362936 .ceil => try airUnFloatOp(f, inst, "ceil"),
29372937 .round => try airUnFloatOp(f, inst, "round"),
......@@ -7076,23 +7076,35 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
70767076 return local;
70777077}
70787078
7079fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
7079fn airAbs(f: *Function, inst: Air.Inst.Index) !CValue {
70807080 const mod = f.object.dg.module;
7081 const un_op = f.air.instructions.items(.data)[inst].un_op;
7081 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
7082 const operand = try f.resolveInst(ty_op.operand);
7083 const ty = f.typeOf(ty_op.operand);
7084 const scalar_ty = ty.scalarType(mod);
70827085
7083 const operand = try f.resolveInst(un_op);
7084 try reap(f, inst, &.{un_op});
7086 switch (scalar_ty.zigTypeTag(mod)) {
7087 .Int => if (ty.zigTypeTag(mod) == .Vector) {
7088 return f.fail("TODO implement airAbs for '{}'", .{ty.fmt(mod)});
7089 } else {
7090 return airUnBuiltinCall(f, inst, "abs", .none);
7091 },
7092 .Float => return unFloatOp(f, inst, operand, ty, "fabs"),
7093 else => unreachable,
7094 }
7095}
70857096
7086 const inst_ty = f.typeOfIndex(inst);
7087 const inst_scalar_ty = inst_ty.scalarType(mod);
7097fn unFloatOp(f: *Function, inst: Air.Inst.Index, operand: CValue, ty: Type, operation: []const u8) !CValue {
7098 const mod = f.object.dg.module;
7099 const scalar_ty = ty.scalarType(mod);
70887100
70897101 const writer = f.object.writer();
7090 const local = try f.allocLocal(inst, inst_ty);
7091 const v = try Vectorize.start(f, inst, writer, inst_ty);
7102 const local = try f.allocLocal(inst, ty);
7103 const v = try Vectorize.start(f, inst, writer, ty);
70927104 try f.writeCValue(writer, local, .Other);
70937105 try v.elem(f, writer);
70947106 try writer.writeAll(" = zig_libc_name_");
7095 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty);
7107 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
70967108 try writer.writeByte('(');
70977109 try writer.writeAll(operation);
70987110 try writer.writeAll(")(");
......@@ -7104,6 +7116,16 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
71047116 return local;
71057117}
71067118
7119fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
7120 const un_op = f.air.instructions.items(.data)[inst].un_op;
7121
7122 const operand = try f.resolveInst(un_op);
7123 try reap(f, inst, &.{un_op});
7124
7125 const inst_ty = f.typeOfIndex(inst);
7126 return unFloatOp(f, inst, operand, inst_ty, operation);
7127}
7128
71077129fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
71087130 const mod = f.object.dg.module;
71097131 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
src/codegen/llvm.zig+23-1
......@@ -4729,6 +4729,7 @@ pub const FuncGen = struct {
47294729 .div_exact => try self.airDivExact(inst, .normal),
47304730 .rem => try self.airRem(inst, .normal),
47314731 .mod => try self.airMod(inst, .normal),
4732 .abs => try self.airAbs(inst),
47324733 .ptr_add => try self.airPtrAdd(inst),
47334734 .ptr_sub => try self.airPtrSub(inst),
47344735 .shl => try self.airShl(inst),
......@@ -4766,7 +4767,6 @@ pub const FuncGen = struct {
47664767 .log => try self.airUnaryOp(inst, .log),
47674768 .log2 => try self.airUnaryOp(inst, .log2),
47684769 .log10 => try self.airUnaryOp(inst, .log10),
4769 .fabs => try self.airUnaryOp(inst, .fabs),
47704770 .floor => try self.airUnaryOp(inst, .floor),
47714771 .ceil => try self.airUnaryOp(inst, .ceil),
47724772 .round => try self.airUnaryOp(inst, .round),
......@@ -8237,6 +8237,28 @@ pub const FuncGen = struct {
82378237 else if (is_signed_int) .ashr else .lshr, lhs, casted_rhs, "");
82388238 }
82398239
8240 fn airAbs(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8241 const o = self.dg.object;
8242 const mod = o.module;
8243 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8244 const operand = try self.resolveInst(ty_op.operand);
8245 const operand_ty = self.typeOf(ty_op.operand);
8246 const scalar_ty = operand_ty.scalarType(mod);
8247
8248 switch (scalar_ty.zigTypeTag(mod)) {
8249 .Int => return self.wip.callIntrinsic(
8250 .normal,
8251 .none,
8252 .abs,
8253 &.{try o.lowerType(operand_ty)},
8254 &.{ operand, try o.builder.intValue(.i1, 0) },
8255 "",
8256 ),
8257 .Float => return self.buildFloatOp(.fabs, .normal, operand_ty, 1, .{operand}),
8258 else => unreachable,
8259 }
8260 }
8261
82408262 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
82418263 const o = self.dg.object;
82428264 const mod = o.module;
src/print_air.zig+1-1
......@@ -188,7 +188,7 @@ const Writer = struct {
188188 .log,
189189 .log2,
190190 .log10,
191 .fabs,
191 .abs,
192192 .floor,
193193 .ceil,
194194 .round,
src/print_zir.zig+1-1
......@@ -262,7 +262,7 @@ const Writer = struct {
262262 .log,
263263 .log2,
264264 .log10,
265 .fabs,
265 .abs,
266266 .floor,
267267 .ceil,
268268 .trunc,
src/type.zig+11
......@@ -3197,6 +3197,17 @@ pub const Type = struct {
31973197 };
31983198 }
31993199
3200 pub fn toUnsigned(ty: Type, mod: *Module) !Type {
3201 return switch (ty.zigTypeTag(mod)) {
3202 .Int => mod.intType(.unsigned, ty.intInfo(mod).bits),
3203 .Vector => try mod.vectorType(.{
3204 .len = ty.vectorLen(mod),
3205 .child = (try ty.childType(mod).toUnsigned(mod)).toIntern(),
3206 }),
3207 else => unreachable,
3208 };
3209 }
3210
32003211 pub const @"u1": Type = .{ .ip_index = .u1_type };
32013212 pub const @"u8": Type = .{ .ip_index = .u8_type };
32023213 pub const @"u16": Type = .{ .ip_index = .u16_type };
src/value.zig+40-21
......@@ -1993,7 +1993,7 @@ pub const Value = struct {
19931993 return 1;
19941994 }
19951995
1996 const w_value = @fabs(scalar);
1996 const w_value = @abs(scalar);
19971997 return @divFloor(@as(std.math.big.Limb, @intFromFloat(std.math.log2(w_value))), @typeInfo(std.math.big.Limb).Int.bits) + 1;
19981998 }
19991999
......@@ -3710,36 +3710,55 @@ pub const Value = struct {
37103710 } })).toValue();
37113711 }
37123712
3713 pub fn fabs(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value {
3714 if (float_type.zigTypeTag(mod) == .Vector) {
3715 const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod));
3716 const scalar_ty = float_type.scalarType(mod);
3713 pub fn abs(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
3714 if (ty.zigTypeTag(mod) == .Vector) {
3715 const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod));
3716 const scalar_ty = ty.scalarType(mod);
37173717 for (result_data, 0..) |*scalar, i| {
37183718 const elem_val = try val.elemValue(mod, i);
3719 scalar.* = try (try fabsScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod);
3719 scalar.* = try (try absScalar(elem_val, scalar_ty, mod, arena)).intern(scalar_ty, mod);
37203720 }
37213721 return (try mod.intern(.{ .aggregate = .{
3722 .ty = float_type.toIntern(),
3722 .ty = ty.toIntern(),
37233723 .storage = .{ .elems = result_data },
37243724 } })).toValue();
37253725 }
3726 return fabsScalar(val, float_type, mod);
3726 return absScalar(val, ty, mod, arena);
37273727 }
37283728
3729 pub fn fabsScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value {
3730 const target = mod.getTarget();
3731 const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) {
3732 16 => .{ .f16 = @fabs(val.toFloat(f16, mod)) },
3733 32 => .{ .f32 = @fabs(val.toFloat(f32, mod)) },
3734 64 => .{ .f64 = @fabs(val.toFloat(f64, mod)) },
3735 80 => .{ .f80 = @fabs(val.toFloat(f80, mod)) },
3736 128 => .{ .f128 = @fabs(val.toFloat(f128, mod)) },
3729 pub fn absScalar(val: Value, ty: Type, mod: *Module, arena: Allocator) Allocator.Error!Value {
3730 switch (ty.zigTypeTag(mod)) {
3731 .Int => {
3732 var buffer: Value.BigIntSpace = undefined;
3733 var operand_bigint = try val.toBigInt(&buffer, mod).toManaged(arena);
3734 operand_bigint.abs();
3735
3736 return mod.intValue_big(try ty.toUnsigned(mod), operand_bigint.toConst());
3737 },
3738 .ComptimeInt => {
3739 var buffer: Value.BigIntSpace = undefined;
3740 var operand_bigint = try val.toBigInt(&buffer, mod).toManaged(arena);
3741 operand_bigint.abs();
3742
3743 return mod.intValue_big(ty, operand_bigint.toConst());
3744 },
3745 .ComptimeFloat, .Float => {
3746 const target = mod.getTarget();
3747 const storage: InternPool.Key.Float.Storage = switch (ty.floatBits(target)) {
3748 16 => .{ .f16 = @abs(val.toFloat(f16, mod)) },
3749 32 => .{ .f32 = @abs(val.toFloat(f32, mod)) },
3750 64 => .{ .f64 = @abs(val.toFloat(f64, mod)) },
3751 80 => .{ .f80 = @abs(val.toFloat(f80, mod)) },
3752 128 => .{ .f128 = @abs(val.toFloat(f128, mod)) },
3753 else => unreachable,
3754 };
3755 return (try mod.intern(.{ .float = .{
3756 .ty = ty.toIntern(),
3757 .storage = storage,
3758 } })).toValue();
3759 },
37373760 else => unreachable,
3738 };
3739 return (try mod.intern(.{ .float = .{
3740 .ty = float_type.toIntern(),
3741 .storage = storage,
3742 } })).toValue();
3761 }
37433762 }
37443763
37453764 pub fn floor(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value {
stage1/zig.h+41
......@@ -946,6 +946,24 @@ typedef unsigned long zig_Builtin64;
946946typedef unsigned long long zig_Builtin64;
947947#endif
948948
949#define zig_builtin8_rev(name, val) __builtin_##name(val)
950
951#define zig_builtin16_rev(name, val) __builtin_##name(val)
952
953#if INT_MIN <= INT32_MIN
954#define zig_builtin32_rev(name, val) __builtin_##name(val)
955#elif LONG_MIN <= INT32_MIN
956#define zig_builtin32_rev(name, val) __builtin_l##name(val)
957#endif
958
959#if INT_MIN <= INT64_MIN
960#define zig_builtin64_rev(name, val) __builtin_##name(val)
961#elif LONG_MIN <= INT64_MIN
962#define zig_builtin64_rev(name, val) __builtin_l##name(val)
963#elif LLONG_MIN <= INT64_MIN
964#define zig_builtin64_rev(name, val) __builtin_ll##name(val)
965#endif
966
949967static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) {
950968 return zig_wrap_u8(val >> (8 - bits), bits);
951969}
......@@ -1141,6 +1159,24 @@ zig_builtin_clz(16)
11411159zig_builtin_clz(32)
11421160zig_builtin_clz(64)
11431161
1162#if zig_has_builtin(abs) || defined(zig_gnuc)
1163#define zig_builtin_abs(w) \
1164 static inline int##w##_t zig_abs_i##w(int##w##_t val) { \
1165 return zig_builtin##w##_rev(abs, val); \
1166 }
1167#else
1168#define zig_builtin_abs(w) \
1169 static inline int##w##_t zig_abs_i##w(int##w##_t val) { \
1170 if (val == INT##w##_MIN) return val; \
1171 int##w##_t tmp = val >> (w - 1); \
1172 return (val ^ tmp) - tmp; \
1173 }
1174#endif
1175zig_builtin_abs(8)
1176zig_builtin_abs(16)
1177zig_builtin_abs(32)
1178zig_builtin_abs(64)
1179
11441180/* ======================== 128-bit Integer Support ========================= */
11451181
11461182#if !defined(zig_has_int128)
......@@ -1466,6 +1502,11 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
14661502 return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);
14671503}
14681504
1505static inline zig_u128 zig_abs_i128(zig_i128 val) {
1506 zig_i128 tmp = zig_shr_i128(val, 127);
1507 return zig_bitCast_u128(zig_sub_i128(zig_xor_i128(val, tmp), tmp));
1508}
1509
14691510#if zig_has_int128
14701511
14711512static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
stage1/zig1.wasm
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
test/behavior.zig+1
......@@ -237,6 +237,7 @@ test {
237237 _ = @import("behavior/void.zig");
238238 _ = @import("behavior/while.zig");
239239 _ = @import("behavior/widening.zig");
240 _ = @import("behavior/abs.zig");
240241
241242 if (builtin.cpu.arch == .wasm32) {
242243 _ = @import("behavior/wasm.zig");
test/behavior/abs.zig created+371
......@@ -0,0 +1,371 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4
5test "@abs integers" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11
12 try comptime testAbsIntegers();
13 try testAbsIntegers();
14}
15
16fn testAbsIntegers() !void {
17 {
18 var x: i32 = -1000;
19 try expect(@abs(x) == 1000);
20 }
21 {
22 var x: i32 = 0;
23 try expect(@abs(x) == 0);
24 }
25 {
26 var x: i32 = 1000;
27 try expect(@abs(x) == 1000);
28 }
29 {
30 var x: i64 = std.math.minInt(i64);
31 try expect(@abs(x) == @as(u64, -std.math.minInt(i64)));
32 }
33 {
34 var x: i5 = -1;
35 try expect(@abs(x) == 1);
36 }
37 {
38 var x: i5 = -5;
39 try expect(@abs(x) == 5);
40 }
41 comptime {
42 try expect(@abs(@as(i2, -2)) == 2);
43 }
44}
45
46test "@abs unsigned integers" {
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
52
53 try comptime testAbsUnsignedIntegers();
54 try testAbsUnsignedIntegers();
55}
56
57fn testAbsUnsignedIntegers() !void {
58 {
59 var x: u32 = 1000;
60 try expect(@abs(x) == 1000);
61 }
62 {
63 var x: u32 = 0;
64 try expect(@abs(x) == 0);
65 }
66 {
67 var x: u32 = 1000;
68 try expect(@abs(x) == 1000);
69 }
70 {
71 var x: u5 = 1;
72 try expect(@abs(x) == 1);
73 }
74 {
75 var x: u5 = 5;
76 try expect(@abs(x) == 5);
77 }
78 comptime {
79 try expect(@abs(@as(u2, 2)) == 2);
80 }
81}
82
83test "@abs floats" {
84 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
89
90 try comptime testAbsFloats(f16);
91 if (builtin.zig_backend != .stage2_x86_64) try testAbsFloats(f16);
92 try comptime testAbsFloats(f32);
93 try testAbsFloats(f32);
94 try comptime testAbsFloats(f64);
95 try testAbsFloats(f64);
96 try comptime testAbsFloats(f80);
97 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);
98 try comptime testAbsFloats(f128);
99 if (builtin.zig_backend != .stage2_x86_64 and builtin.zig_backend != .stage2_wasm) try testAbsFloats(f128);
100}
101
102fn testAbsFloats(comptime T: type) !void {
103 {
104 var x: T = -2.62;
105 try expect(@abs(x) == 2.62);
106 }
107 {
108 var x: T = 2.62;
109 try expect(@abs(x) == 2.62);
110 }
111 {
112 var x: T = 0.0;
113 try expect(@abs(x) == 0.0);
114 }
115 {
116 var x: T = -std.math.pi;
117 try expect(@abs(x) == std.math.pi);
118 }
119
120 {
121 var x: T = -std.math.inf(T);
122 try expect(@abs(x) == std.math.inf(T));
123 }
124 {
125 var x: T = std.math.inf(T);
126 try expect(@abs(x) == std.math.inf(T));
127 }
128 comptime {
129 try expect(@abs(@as(T, -std.math.e)) == std.math.e);
130 }
131}
132
133test "@abs int vectors" {
134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
142
143 try comptime testAbsIntVectors(1);
144 try testAbsIntVectors(1);
145 try comptime testAbsIntVectors(2);
146 try testAbsIntVectors(2);
147 try comptime testAbsIntVectors(3);
148 try testAbsIntVectors(3);
149 try comptime testAbsIntVectors(4);
150 try testAbsIntVectors(4);
151 try comptime testAbsIntVectors(8);
152 try testAbsIntVectors(8);
153 try comptime testAbsIntVectors(16);
154 try testAbsIntVectors(16);
155 try comptime testAbsIntVectors(17);
156 try testAbsIntVectors(17);
157}
158
159fn testAbsIntVectors(comptime len: comptime_int) !void {
160 const I32 = @Vector(len, i32);
161 const U32 = @Vector(len, u32);
162 const I64 = @Vector(len, i64);
163 const U64 = @Vector(len, u64);
164 {
165 var x: I32 = @splat(-10);
166 var y: U32 = @splat(10);
167 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
168 }
169 {
170 var x: I32 = @splat(10);
171 var y: U32 = @splat(10);
172 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
173 }
174 {
175 var x: I32 = @splat(0);
176 var y: U32 = @splat(0);
177 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
178 }
179 {
180 var x: I64 = @splat(-10);
181 var y: U64 = @splat(10);
182 try expect(std.mem.eql(u64, &@as([len]u64, y), &@as([len]u64, @abs(x))));
183 }
184 {
185 var x: I64 = @splat(std.math.minInt(i64));
186 var y: U64 = @splat(-std.math.minInt(i64));
187 try expect(std.mem.eql(u64, &@as([len]u64, y), &@as([len]u64, @abs(x))));
188 }
189 {
190 var x = std.simd.repeat(len, @Vector(4, i32){ -2, 5, std.math.minInt(i32), -7 });
191 var y = std.simd.repeat(len, @Vector(4, u32){ 2, 5, -std.math.minInt(i32), 7 });
192 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
193 }
194}
195
196test "@abs unsigned int vectors" {
197 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
198 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
199 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
201 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
205
206 try comptime testAbsUnsignedIntVectors(1);
207 try testAbsUnsignedIntVectors(1);
208 try comptime testAbsUnsignedIntVectors(2);
209 try testAbsUnsignedIntVectors(2);
210 try comptime testAbsUnsignedIntVectors(3);
211 try testAbsUnsignedIntVectors(3);
212 try comptime testAbsUnsignedIntVectors(4);
213 try testAbsUnsignedIntVectors(4);
214 try comptime testAbsUnsignedIntVectors(8);
215 try testAbsUnsignedIntVectors(8);
216 try comptime testAbsUnsignedIntVectors(16);
217 try testAbsUnsignedIntVectors(16);
218 try comptime testAbsUnsignedIntVectors(17);
219 try testAbsUnsignedIntVectors(17);
220}
221
222fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {
223 const U32 = @Vector(len, u32);
224 const U64 = @Vector(len, u64);
225 {
226 var x: U32 = @splat(10);
227 var y: U32 = @splat(10);
228 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
229 }
230 {
231 var x: U32 = @splat(10);
232 var y: U32 = @splat(10);
233 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
234 }
235 {
236 var x: U32 = @splat(0);
237 var y: U32 = @splat(0);
238 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
239 }
240 {
241 var x: U64 = @splat(10);
242 var y: U64 = @splat(10);
243 try expect(std.mem.eql(u64, &@as([len]u64, y), &@as([len]u64, @abs(x))));
244 }
245 {
246 var x = std.simd.repeat(len, @Vector(3, u32){ 2, 5, 7 });
247 var y = std.simd.repeat(len, @Vector(3, u32){ 2, 5, 7 });
248 try expect(std.mem.eql(u32, &@as([len]u32, y), &@as([len]u32, @abs(x))));
249 }
250}
251
252test "@abs float vectors" {
253 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
254 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
258 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
261
262 // https://github.com/ziglang/zig/issues/12827
263 if (builtin.zig_backend == .stage2_llvm and
264 builtin.os.tag == .macos and
265 builtin.target.cpu.arch == .x86_64) return error.SkipZigTest;
266
267 @setEvalBranchQuota(2000);
268 try comptime testAbsFloatVectors(f16, 1);
269 try testAbsFloatVectors(f16, 1);
270 try comptime testAbsFloatVectors(f16, 2);
271 try testAbsFloatVectors(f16, 2);
272 try comptime testAbsFloatVectors(f16, 3);
273 try testAbsFloatVectors(f16, 3);
274 try comptime testAbsFloatVectors(f16, 4);
275 try testAbsFloatVectors(f16, 4);
276 try comptime testAbsFloatVectors(f16, 8);
277 try testAbsFloatVectors(f16, 8);
278 try comptime testAbsFloatVectors(f16, 16);
279 try testAbsFloatVectors(f16, 16);
280 try comptime testAbsFloatVectors(f16, 17);
281
282 try testAbsFloatVectors(f32, 17);
283 try comptime testAbsFloatVectors(f32, 1);
284 try testAbsFloatVectors(f32, 1);
285 try comptime testAbsFloatVectors(f32, 2);
286 try testAbsFloatVectors(f32, 2);
287 try comptime testAbsFloatVectors(f32, 3);
288 try testAbsFloatVectors(f32, 3);
289 try comptime testAbsFloatVectors(f32, 4);
290 try testAbsFloatVectors(f32, 4);
291 try comptime testAbsFloatVectors(f32, 8);
292 try testAbsFloatVectors(f32, 8);
293 try comptime testAbsFloatVectors(f32, 16);
294 try testAbsFloatVectors(f32, 16);
295 try comptime testAbsFloatVectors(f32, 17);
296 try testAbsFloatVectors(f32, 17);
297
298 try comptime testAbsFloatVectors(f64, 1);
299 try testAbsFloatVectors(f64, 1);
300 try comptime testAbsFloatVectors(f64, 2);
301 try testAbsFloatVectors(f64, 2);
302 try comptime testAbsFloatVectors(f64, 3);
303 try testAbsFloatVectors(f64, 3);
304 try comptime testAbsFloatVectors(f64, 4);
305 try testAbsFloatVectors(f64, 4);
306 try comptime testAbsFloatVectors(f64, 8);
307 try testAbsFloatVectors(f64, 8);
308 try comptime testAbsFloatVectors(f64, 16);
309 try testAbsFloatVectors(f64, 16);
310 try comptime testAbsFloatVectors(f64, 17);
311 try testAbsFloatVectors(f64, 17);
312
313 try comptime testAbsFloatVectors(f80, 1);
314 try testAbsFloatVectors(f80, 1);
315 try comptime testAbsFloatVectors(f80, 2);
316 try testAbsFloatVectors(f80, 2);
317 try comptime testAbsFloatVectors(f80, 3);
318 try testAbsFloatVectors(f80, 3);
319 try comptime testAbsFloatVectors(f80, 4);
320 try testAbsFloatVectors(f80, 4);
321 try comptime testAbsFloatVectors(f80, 8);
322 try testAbsFloatVectors(f80, 8);
323 try comptime testAbsFloatVectors(f80, 16);
324 try testAbsFloatVectors(f80, 16);
325 try comptime testAbsFloatVectors(f80, 17);
326 try testAbsFloatVectors(f80, 17);
327
328 try comptime testAbsFloatVectors(f128, 1);
329 try testAbsFloatVectors(f128, 1);
330 try comptime testAbsFloatVectors(f128, 2);
331 try testAbsFloatVectors(f128, 2);
332 try comptime testAbsFloatVectors(f128, 3);
333 try testAbsFloatVectors(f128, 3);
334 try comptime testAbsFloatVectors(f128, 4);
335 try testAbsFloatVectors(f128, 4);
336 try comptime testAbsFloatVectors(f128, 8);
337 try testAbsFloatVectors(f128, 8);
338 try comptime testAbsFloatVectors(f128, 16);
339 try testAbsFloatVectors(f128, 16);
340 try comptime testAbsFloatVectors(f128, 17);
341 try testAbsFloatVectors(f128, 17);
342}
343
344fn testAbsFloatVectors(comptime T: type, comptime len: comptime_int) !void {
345 const V = @Vector(len, T);
346 {
347 var x: V = @splat(-7.5);
348 var y: V = @splat(7.5);
349 try expect(std.mem.eql(T, &@as([len]T, y), &@as([len]T, @abs(x))));
350 }
351 {
352 var x: V = @splat(7.5);
353 var y: V = @splat(7.5);
354 try expect(std.mem.eql(T, &@as([len]T, y), &@as([len]T, @abs(x))));
355 }
356 {
357 var x: V = @splat(0.0);
358 var y: V = @splat(0.0);
359 try expect(std.mem.eql(T, &@as([len]T, y), &@as([len]T, @abs(x))));
360 }
361 {
362 var x: V = @splat(-std.math.pi);
363 var y: V = @splat(std.math.pi);
364 try expect(std.mem.eql(T, &@as([len]T, y), &@as([len]T, @abs(x))));
365 }
366 {
367 var x: V = @splat(std.math.pi);
368 var y: V = @splat(std.math.pi);
369 try expect(std.mem.eql(T, &@as([len]T, y), &@as([len]T, @abs(x))));
370 }
371}
test/behavior/floatop.zig+36-33
......@@ -523,7 +523,7 @@ fn testLog10WithVectors() !void {
523523 try expect(@log10(@as(f32, 0.4)) == result[3]);
524524}
525525
526test "@fabs" {
526test "@abs" {
527527 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
528528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -533,24 +533,24 @@ test "@fabs" {
533533}
534534
535535fn testFabs() !void {
536 try expect(@fabs(@as(f16, -2.5)) == 2.5);
537 try expect(@fabs(@as(f16, 2.5)) == 2.5);
538 try expect(@fabs(@as(f32, -2.5)) == 2.5);
539 try expect(@fabs(@as(f32, 2.5)) == 2.5);
540 try expect(@fabs(@as(f64, -2.5)) == 2.5);
541 try expect(@fabs(@as(f64, 2.5)) == 2.5);
536 try expect(@abs(@as(f16, -2.5)) == 2.5);
537 try expect(@abs(@as(f16, 2.5)) == 2.5);
538 try expect(@abs(@as(f32, -2.5)) == 2.5);
539 try expect(@abs(@as(f32, 2.5)) == 2.5);
540 try expect(@abs(@as(f64, -2.5)) == 2.5);
541 try expect(@abs(@as(f64, 2.5)) == 2.5);
542542
543543 // TODO test f128, and c_longdouble
544544 // https://github.com/ziglang/zig/issues/4026
545545 // {
546546 // var a: f80 = -2.5;
547547 // var b: f80 = 2.5;
548 // try expect(@fabs(a) == 2.5);
549 // try expect(@fabs(b) == 2.5);
548 // try expect(@abs(a) == 2.5);
549 // try expect(@abs(b) == 2.5);
550550 // }
551551}
552552
553test "@fabs with vectors" {
553test "@abs with vectors" {
554554 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
555555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
556556 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -562,14 +562,15 @@ test "@fabs with vectors" {
562562
563563fn testFabsWithVectors() !void {
564564 var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
565 var result = @fabs(v);
566 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
567 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
568 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));
569 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));
565 var result = @abs(v);
566 try expect(math.approxEqAbs(f32, @abs(@as(f32, 1.1)), result[0], epsilon));
567 try expect(math.approxEqAbs(f32, @abs(@as(f32, -2.2)), result[1], epsilon));
568 try expect(math.approxEqAbs(f32, @abs(@as(f32, 0.3)), result[2], epsilon));
569 try expect(math.approxEqAbs(f32, @abs(@as(f32, -0.4)), result[3], epsilon));
570570}
571571
572test "another, possibly redundant, @fabs test" {
572test "another, possibly redundant, @abs test" {
573 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
573574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
574575 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
575576 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -587,11 +588,12 @@ test "another, possibly redundant, @fabs test" {
587588
588589 const x = 14.0;
589590 const y = -x;
590 const z = @fabs(y);
591 const z = @abs(y);
591592 try comptime std.testing.expectEqual(x, z);
592593}
593594
594test "@fabs f80" {
595test "@abs f80" {
596 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
595597 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
596598 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
597599 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -604,11 +606,12 @@ test "@fabs f80" {
604606
605607fn testFabsLegacy(comptime T: type, x: T) !void {
606608 const y = -x;
607 const z = @fabs(y);
609 const z = @abs(y);
608610 try expect(x == z);
609611}
610612
611test "a third @fabs test, surely there should not be three fabs tests" {
613test "a third @abs test, surely there should not be three fabs tests" {
614 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
612615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
613616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
614617 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -617,23 +620,23 @@ test "a third @fabs test, surely there should not be three fabs tests" {
617620
618621 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
619622 // normals
620 try expect(@fabs(@as(T, 1.0)) == 1.0);
621 try expect(@fabs(@as(T, -1.0)) == 1.0);
622 try expect(@fabs(math.floatMin(T)) == math.floatMin(T));
623 try expect(@fabs(-math.floatMin(T)) == math.floatMin(T));
624 try expect(@fabs(math.floatMax(T)) == math.floatMax(T));
625 try expect(@fabs(-math.floatMax(T)) == math.floatMax(T));
623 try expect(@abs(@as(T, 1.0)) == 1.0);
624 try expect(@abs(@as(T, -1.0)) == 1.0);
625 try expect(@abs(math.floatMin(T)) == math.floatMin(T));
626 try expect(@abs(-math.floatMin(T)) == math.floatMin(T));
627 try expect(@abs(math.floatMax(T)) == math.floatMax(T));
628 try expect(@abs(-math.floatMax(T)) == math.floatMax(T));
626629
627630 // subnormals
628 try expect(@fabs(@as(T, 0.0)) == 0.0);
629 try expect(@fabs(@as(T, -0.0)) == 0.0);
630 try expect(@fabs(math.floatTrueMin(T)) == math.floatTrueMin(T));
631 try expect(@fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T));
631 try expect(@abs(@as(T, 0.0)) == 0.0);
632 try expect(@abs(@as(T, -0.0)) == 0.0);
633 try expect(@abs(math.floatTrueMin(T)) == math.floatTrueMin(T));
634 try expect(@abs(-math.floatTrueMin(T)) == math.floatTrueMin(T));
632635
633636 // non-finite numbers
634 try expect(math.isPositiveInf(@fabs(math.inf(T))));
635 try expect(math.isPositiveInf(@fabs(-math.inf(T))));
636 try expect(math.isNan(@fabs(math.nan(T))));
637 try expect(math.isPositiveInf(@abs(math.inf(T))));
638 try expect(math.isPositiveInf(@abs(-math.inf(T))));
639 try expect(math.isNan(@abs(math.nan(T))));
637640 }
638641}
639642
test/behavior/math.zig+3-3
......@@ -1391,7 +1391,7 @@ fn frem(comptime T: type) !void {
13911391}
13921392
13931393fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {
1394 try expect(@fabs(@rem(a, b) - c) < epsilon);
1394 try expect(@abs(@rem(a, b) - c) < epsilon);
13951395}
13961396
13971397test "float modulo division using @mod" {
......@@ -1434,7 +1434,7 @@ fn fmod(comptime T: type) !void {
14341434}
14351435
14361436fn fmodOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {
1437 try expect(@fabs(@mod(@as(T, a), @as(T, b)) - @as(T, c)) < epsilon);
1437 try expect(@abs(@mod(@as(T, a), @as(T, b)) - @as(T, c)) < epsilon);
14381438}
14391439
14401440test "@round" {
......@@ -1627,7 +1627,7 @@ fn testAbsFloat() !void {
16271627 try testAbsFloatOne(10.05, 10.05);
16281628}
16291629fn testAbsFloatOne(in: f32, out: f32) !void {
1630 try expect(@fabs(@as(f32, in)) == @as(f32, out));
1630 try expect(@abs(@as(f32, in)) == @as(f32, out));
16311631}
16321632
16331633test "mod lazy values" {