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 {...@@ -9421,14 +9421,17 @@ fn doTheTest() !void {
9421 Supports {#link|Floats#} and {#link|Vectors#} of floats.9421 Supports {#link|Floats#} and {#link|Vectors#} of floats.
9422 </p>9422 </p>
9423 {#header_close#}9423 {#header_close#}
9424 {#header_open|@fabs#}9424 {#header_open|@abs#}
9425 <pre>{#syntax#}@fabs(value: anytype) @TypeOf(value){#endsyntax#}</pre>9425 <pre>{#syntax#}@abs(value: anytype) anytype{#endsyntax#}</pre>
9426 <p>9426 <p>
9427 Returns the absolute value of a floating point number. Uses a dedicated hardware instruction9427 Returns the absolute value of an integer or a floating point number. Uses a dedicated hardware instruction
9428 when available.9428 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.
9429 </p>9432 </p>
9430 <p>9433 <p>
9431 Supports {#link|Floats#} and {#link|Vectors#} of floats.9434 Supports {#link|Floats#}, {#link|Integers#} and {#link|Vectors#} of floats or integers.
9432 </p>9435 </p>
9433 {#header_close#}9436 {#header_close#}
9434 {#header_open|@floor#}9437 {#header_open|@floor#}
lib/compiler_rt/divc3.zig+1-2
...@@ -3,7 +3,6 @@ const isNan = std.math.isNan;...@@ -3,7 +3,6 @@ const isNan = std.math.isNan;
3const isInf = std.math.isInf;3const isInf = std.math.isInf;
4const scalbn = std.math.scalbn;4const scalbn = std.math.scalbn;
5const ilogb = std.math.ilogb;5const ilogb = std.math.ilogb;
6const fabs = std.math.fabs;
7const maxInt = std.math.maxInt;6const maxInt = std.math.maxInt;
8const minInt = std.math.minInt;7const minInt = std.math.minInt;
9const isFinite = std.math.isFinite;8const 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) {...@@ -16,7 +15,7 @@ pub inline fn divc3(comptime T: type, a: T, b: T, c_in: T, d_in: T) Complex(T) {
16 var d = d_in;15 var d = d_in;
1716
18 // logbw used to prevent under/over-flow17 // 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)));
20 const logbw_finite = logbw != maxInt(i32) and logbw != minInt(i32);19 const logbw_finite = logbw != maxInt(i32) and logbw != minInt(i32);
21 const ilogbw = if (logbw_finite) b: {20 const ilogbw = if (logbw_finite) b: {
22 c = scalbn(c, -logbw);21 c = scalbn(c, -logbw);
lib/compiler_rt/divxf3_test.zig+3-3
...@@ -30,9 +30,9 @@ fn test__divxf3(a: f80, b: f80) !void {...@@ -30,9 +30,9 @@ fn test__divxf3(a: f80, b: f80) !void {
30 const x_minus_eps: f80 = @bitCast((@as(u80, @bitCast(x)) - 1) | integerBit);30 const x_minus_eps: f80 = @bitCast((@as(u80, @bitCast(x)) - 1) | integerBit);
3131
32 // Make sure result is more accurate than the adjacent floats32 // Make sure result is more accurate than the adjacent floats
33 const err_x = @fabs(@mulAdd(f80, x, b, -a));33 const err_x = @abs(@mulAdd(f80, x, b, -a));
34 const err_x_plus_eps = @fabs(@mulAdd(f80, x_plus_eps, b, -a));34 const err_x_plus_eps = @abs(@mulAdd(f80, x_plus_eps, b, -a));
35 const err_x_minus_eps = @fabs(@mulAdd(f80, x_minus_eps, b, -a));35 const err_x_minus_eps = @abs(@mulAdd(f80, x_minus_eps, b, -a));
3636
37 try testing.expect(err_x_minus_eps > err_x);37 try testing.expect(err_x_minus_eps > err_x);
38 try testing.expect(err_x_plus_eps > err_x);38 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 {...@@ -18,7 +18,7 @@ pub fn floatFromInt(comptime T: type, x: anytype) T {
18 const max_exp = exp_bias;18 const max_exp = exp_bias;
1919
20 // Sign20 // 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;
22 const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0;22 const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0;
23 var result: uT = sign_bit;23 var result: uT = sign_bit;
2424
lib/std/Build/Step/ConfigHeader.zig+1-1
...@@ -539,7 +539,7 @@ fn replace_variables(...@@ -539,7 +539,7 @@ fn replace_variables(
539 .int => |i| {539 .int => |i| {
540 const buf = try std.fmt.allocPrint(allocator, "{s}{}{s}", .{ beginline, i, endline });540 const buf = try std.fmt.allocPrint(allocator, "{s}{}{s}", .{ beginline, i, endline });
541 const isNegative = i < 0;541 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;
543 last_index = start_index + @intFromBool(isNegative) + digits + 1;543 last_index = start_index + @intFromBool(isNegative) + digits + 1;
544544
545 allocator.free(content_buf);545 allocator.free(content_buf);
lib/std/dwarf/expressions.zig+1-1
...@@ -520,7 +520,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {...@@ -520,7 +520,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type {
520 if (self.stack.items.len == 0) return error.InvalidExpression;520 if (self.stack.items.len == 0) return error.InvalidExpression;
521 const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());521 const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
522 self.stack.items[self.stack.items.len - 1] = .{522 self.stack.items[self.stack.items.len - 1] = .{
523 .generic = std.math.absCast(value),523 .generic = @abs(value),
524 };524 };
525 },525 },
526 OP.@"and" => {526 OP.@"and" => {
lib/std/fmt.zig+1-1
...@@ -1413,7 +1413,7 @@ pub fn formatInt(...@@ -1413,7 +1413,7 @@ pub fn formatInt(
1413 const min_int_bits = comptime @max(value_info.bits, 8);1413 const min_int_bits = comptime @max(value_info.bits, 8);
1414 const MinInt = std.meta.Int(.unsigned, min_int_bits);1414 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);
1417 // The worst case in terms of space needed is base 2, plus 1 for the sign1417 // The worst case in terms of space needed is base 2, plus 1 for the sign
1418 var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined;1418 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 {...@@ -81,7 +81,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
8181
82 pub fn seekBy(self: *Self, amt: i64) SeekError!void {82 pub fn seekBy(self: *Self, amt: i64) SeekError!void {
83 if (amt < 0) {83 if (amt < 0) {
84 const abs_amt = std.math.absCast(amt);84 const abs_amt = @abs(amt);
85 const abs_amt_usize = std.math.cast(usize, abs_amt) orelse std.math.maxInt(usize);85 const abs_amt_usize = std.math.cast(usize, abs_amt) orelse std.math.maxInt(usize);
86 if (abs_amt_usize > self.pos) {86 if (abs_amt_usize > self.pos) {
87 self.pos = 0;87 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 {...@@ -130,7 +130,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool {
130 if (isNan(x) or isNan(y))130 if (isNan(x) or isNan(y))
131 return false;131 return false;
132132
133 return @fabs(x - y) <= tolerance;133 return @abs(x - y) <= tolerance;
134}134}
135135
136/// Performs an approximate comparison of two floating point values `x` and `y`.136/// 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 {...@@ -158,7 +158,7 @@ pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool {
158 if (isNan(x) or isNan(y))158 if (isNan(x) or isNan(y))
159 return false;159 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;
162}162}
163163
164test "approxEqAbs and approxEqRel" {164test "approxEqAbs and approxEqRel" {
...@@ -466,7 +466,7 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {...@@ -466,7 +466,7 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
466/// Shifts left. Overflowed bits are truncated.466/// Shifts left. Overflowed bits are truncated.
467/// A negative shift amount results in a right shift.467/// A negative shift amount results in a right shift.
468pub fn shl(comptime T: type, a: T, shift_amt: anytype) T {468pub 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
471 const casted_shift_amt = blk: {471 const casted_shift_amt = blk: {
472 if (@typeInfo(T) == .Vector) {472 if (@typeInfo(T) == .Vector) {
...@@ -510,7 +510,7 @@ test "shl" {...@@ -510,7 +510,7 @@ test "shl" {
510/// Shifts right. Overflowed bits are truncated.510/// Shifts right. Overflowed bits are truncated.
511/// A negative shift amount results in a left shift.511/// A negative shift amount results in a left shift.
512pub fn shr(comptime T: type, a: T, shift_amt: anytype) T {512pub 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
515 const casted_shift_amt = blk: {515 const casted_shift_amt = blk: {
516 if (@typeInfo(T) == .Vector) {516 if (@typeInfo(T) == .Vector) {
...@@ -740,52 +740,6 @@ fn testOverflow() !void {...@@ -740,52 +740,6 @@ fn testOverflow() !void {
740 try testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);740 try testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000);
741}741}
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
789/// Divide numerator by denominator, rounding toward zero. Returns an743/// Divide numerator by denominator, rounding toward zero. Returns an
790/// error on overflow or when denominator is zero.744/// error on overflow or when denominator is zero.
791pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {745pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T {
...@@ -968,50 +922,6 @@ fn testRem() !void {...@@ -968,50 +922,6 @@ fn testRem() !void {
968 try testing.expectError(error.DivisionByZero, rem(f32, 10, 0));922 try testing.expectError(error.DivisionByZero, rem(f32, 10, 0));
969}923}
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
1015/// Returns the negation of the integer parameter.925/// Returns the negation of the integer parameter.
1016/// Result is a signed integer.926/// Result is a signed integer.
1017pub fn negateCast(x: anytype) !std.meta.Int(.signed, @bitSizeOf(@TypeOf(x))) {927pub 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 {...@@ -60,7 +60,7 @@ fn asin32(x: f32) f32 {
60 }60 }
6161
62 // 1 > |x| >= 0.562 // 1 > |x| >= 0.5
63 const z = (1 - @fabs(x)) * 0.5;63 const z = (1 - @abs(x)) * 0.5;
64 const s = @sqrt(z);64 const s = @sqrt(z);
65 const fx = pio2 - 2 * (s + s * r32(z));65 const fx = pio2 - 2 * (s + s * r32(z));
6666
...@@ -119,7 +119,7 @@ fn asin64(x: f64) f64 {...@@ -119,7 +119,7 @@ fn asin64(x: f64) f64 {
119 }119 }
120120
121 // 1 > |x| >= 0.5121 // 1 > |x| >= 0.5
122 const z = (1 - @fabs(x)) * 0.5;122 const z = (1 - @abs(x)) * 0.5;
123 const s = @sqrt(z);123 const s = @sqrt(z);
124 const r = r64(z);124 const r = r64(z);
125 var fx: f64 = undefined;125 var fx: f64 = undefined;
lib/std/math/atan.zig+2-2
...@@ -73,7 +73,7 @@ fn atan32(x_: f32) f32 {...@@ -73,7 +73,7 @@ fn atan32(x_: f32) f32 {
73 }73 }
74 id = null;74 id = null;
75 } else {75 } else {
76 x = @fabs(x);76 x = @abs(x);
77 // |x| < 1.187577 // |x| < 1.1875
78 if (ix < 0x3F980000) {78 if (ix < 0x3F980000) {
79 // 7/16 <= |x| < 11/1679 // 7/16 <= |x| < 11/16
...@@ -171,7 +171,7 @@ fn atan64(x_: f64) f64 {...@@ -171,7 +171,7 @@ fn atan64(x_: f64) f64 {
171 }171 }
172 id = null;172 id = null;
173 } else {173 } else {
174 x = @fabs(x);174 x = @abs(x);
175 // |x| < 1.1875175 // |x| < 1.1875
176 if (ix < 0x3FF30000) {176 if (ix < 0x3FF30000) {
177 // 7/16 <= |x| < 11/16177 // 7/16 <= |x| < 11/16
lib/std/math/atan2.zig+2-2
...@@ -108,7 +108,7 @@ fn atan2_32(y: f32, x: f32) f32 {...@@ -108,7 +108,7 @@ fn atan2_32(y: f32, x: f32) f32 {
108 if ((m & 2) != 0 and iy + (26 << 23) < ix) {108 if ((m & 2) != 0 and iy + (26 << 23) < ix) {
109 break :z 0.0;109 break :z 0.0;
110 } else {110 } else {
111 break :z math.atan(@fabs(y / x));111 break :z math.atan(@abs(y / x));
112 }112 }
113 };113 };
114114
...@@ -198,7 +198,7 @@ fn atan2_64(y: f64, x: f64) f64 {...@@ -198,7 +198,7 @@ fn atan2_64(y: f64, x: f64) f64 {
198 if ((m & 2) != 0 and iy +% (64 << 20) < ix) {198 if ((m & 2) != 0 and iy +% (64 << 20) < ix) {
199 break :z 0.0;199 break :z 0.0;
200 } else {200 } else {
201 break :z math.atan(@fabs(y / x));201 break :z math.atan(@abs(y / x));
202 }202 }
203 };203 };
204204
lib/std/math/big/int.zig+3-3
...@@ -29,7 +29,7 @@ pub fn calcLimbLen(scalar: anytype) usize {...@@ -29,7 +29,7 @@ pub fn calcLimbLen(scalar: anytype) usize {
29 return 1;29 return 1;
30 }30 }
3131
32 const w_value = std.math.absCast(scalar);32 const w_value = @abs(scalar);
33 return @as(usize, @intCast(@divFloor(@as(Limb, @intCast(math.log2(w_value))), limb_bits) + 1));33 return @as(usize, @intCast(@divFloor(@as(Limb, @intCast(math.log2(w_value))), limb_bits) + 1));
34}34}
3535
...@@ -240,7 +240,7 @@ pub const Mutable = struct {...@@ -240,7 +240,7 @@ pub const Mutable = struct {
240240
241 switch (@typeInfo(T)) {241 switch (@typeInfo(T)) {
242 .Int => |info| {242 .Int => |info| {
243 var w_value = std.math.absCast(value);243 var w_value = @abs(value);
244244
245 if (info.bits <= limb_bits) {245 if (info.bits <= limb_bits) {
246 self.limbs[0] = w_value;246 self.limbs[0] = w_value;
...@@ -255,7 +255,7 @@ pub const Mutable = struct {...@@ -255,7 +255,7 @@ pub const Mutable = struct {
255 }255 }
256 },256 },
257 .ComptimeInt => {257 .ComptimeInt => {
258 comptime var w_value = std.math.absCast(value);258 comptime var w_value = @abs(value);
259259
260 if (w_value <= maxInt(Limb)) {260 if (w_value <= maxInt(Limb)) {
261 self.limbs[0] = w_value;261 self.limbs[0] = w_value;
lib/std/math/complex/cosh.zig+4-4
...@@ -44,12 +44,12 @@ fn cosh32(z: Complex(f32)) Complex(f32) {...@@ -44,12 +44,12 @@ fn cosh32(z: Complex(f32)) Complex(f32) {
44 // |x|>= 9, so cosh(x) ~= exp(|x|)44 // |x|>= 9, so cosh(x) ~= exp(|x|)
45 if (ix < 0x42b17218) {45 if (ix < 0x42b17218) {
46 // x < 88.7: exp(|x|) won't overflow46 // x < 88.7: exp(|x|) won't overflow
47 const h = @exp(@fabs(x)) * 0.5;47 const h = @exp(@abs(x)) * 0.5;
48 return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y));48 return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y));
49 }49 }
50 // x < 192.7: scale to avoid overflow50 // x < 192.7: scale to avoid overflow
51 else if (ix < 0x4340b1e7) {51 else if (ix < 0x4340b1e7) {
52 const v = Complex(f32).init(@fabs(x), y);52 const v = Complex(f32).init(@abs(x), y);
53 const r = ldexp_cexp(v, -1);53 const r = ldexp_cexp(v, -1);
54 return Complex(f32).init(r.re, r.im * math.copysign(@as(f32, 1.0), x));54 return Complex(f32).init(r.re, r.im * math.copysign(@as(f32, 1.0), x));
55 }55 }
...@@ -112,12 +112,12 @@ fn cosh64(z: Complex(f64)) Complex(f64) {...@@ -112,12 +112,12 @@ fn cosh64(z: Complex(f64)) Complex(f64) {
112 // |x|>= 22, so cosh(x) ~= exp(|x|)112 // |x|>= 22, so cosh(x) ~= exp(|x|)
113 if (ix < 0x40862e42) {113 if (ix < 0x40862e42) {
114 // x < 710: exp(|x|) won't overflow114 // x < 710: exp(|x|) won't overflow
115 const h = @exp(@fabs(x)) * 0.5;115 const h = @exp(@abs(x)) * 0.5;
116 return Complex(f64).init(h * @cos(y), math.copysign(h, x) * @sin(y));116 return Complex(f64).init(h * @cos(y), math.copysign(h, x) * @sin(y));
117 }117 }
118 // x < 1455: scale to avoid overflow118 // x < 1455: scale to avoid overflow
119 else if (ix < 0x4096bbaa) {119 else if (ix < 0x4096bbaa) {
120 const v = Complex(f64).init(@fabs(x), y);120 const v = Complex(f64).init(@abs(x), y);
121 const r = ldexp_cexp(v, -1);121 const r = ldexp_cexp(v, -1);
122 return Complex(f64).init(r.re, r.im * math.copysign(@as(f64, 1.0), x));122 return Complex(f64).init(r.re, r.im * math.copysign(@as(f64, 1.0), x));
123 }123 }
lib/std/math/complex/sinh.zig+4-4
...@@ -44,12 +44,12 @@ fn sinh32(z: Complex(f32)) Complex(f32) {...@@ -44,12 +44,12 @@ fn sinh32(z: Complex(f32)) Complex(f32) {
44 // |x|>= 9, so cosh(x) ~= exp(|x|)44 // |x|>= 9, so cosh(x) ~= exp(|x|)
45 if (ix < 0x42b17218) {45 if (ix < 0x42b17218) {
46 // x < 88.7: exp(|x|) won't overflow46 // x < 88.7: exp(|x|) won't overflow
47 const h = @exp(@fabs(x)) * 0.5;47 const h = @exp(@abs(x)) * 0.5;
48 return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y));48 return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y));
49 }49 }
50 // x < 192.7: scale to avoid overflow50 // x < 192.7: scale to avoid overflow
51 else if (ix < 0x4340b1e7) {51 else if (ix < 0x4340b1e7) {
52 const v = Complex(f32).init(@fabs(x), y);52 const v = Complex(f32).init(@abs(x), y);
53 const r = ldexp_cexp(v, -1);53 const r = ldexp_cexp(v, -1);
54 return Complex(f32).init(r.re * math.copysign(@as(f32, 1.0), x), r.im);54 return Complex(f32).init(r.re * math.copysign(@as(f32, 1.0), x), r.im);
55 }55 }
...@@ -111,12 +111,12 @@ fn sinh64(z: Complex(f64)) Complex(f64) {...@@ -111,12 +111,12 @@ fn sinh64(z: Complex(f64)) Complex(f64) {
111 // |x|>= 22, so cosh(x) ~= exp(|x|)111 // |x|>= 22, so cosh(x) ~= exp(|x|)
112 if (ix < 0x40862e42) {112 if (ix < 0x40862e42) {
113 // x < 710: exp(|x|) won't overflow113 // x < 710: exp(|x|) won't overflow
114 const h = @exp(@fabs(x)) * 0.5;114 const h = @exp(@abs(x)) * 0.5;
115 return Complex(f64).init(math.copysign(h, x) * @cos(y), h * @sin(y));115 return Complex(f64).init(math.copysign(h, x) * @cos(y), h * @sin(y));
116 }116 }
117 // x < 1455: scale to avoid overflow117 // x < 1455: scale to avoid overflow
118 else if (ix < 0x4096bbaa) {118 else if (ix < 0x4096bbaa) {
119 const v = Complex(f64).init(@fabs(x), y);119 const v = Complex(f64).init(@abs(x), y);
120 const r = ldexp_cexp(v, -1);120 const r = ldexp_cexp(v, -1);
121 return Complex(f64).init(r.re * math.copysign(@as(f64, 1.0), x), r.im);121 return Complex(f64).init(r.re * math.copysign(@as(f64, 1.0), x), r.im);
122 }122 }
lib/std/math/complex/sqrt.zig+5-5
...@@ -43,7 +43,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {...@@ -43,7 +43,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {
43 // sqrt(-inf + i nan) = nan +- inf i43 // sqrt(-inf + i nan) = nan +- inf i
44 // sqrt(-inf + iy) = 0 + inf i44 // sqrt(-inf + iy) = 0 + inf i
45 if (math.signbit(x)) {45 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));
47 } else {47 } else {
48 return Complex(f32).init(x, math.copysign(y - y, y));48 return Complex(f32).init(x, math.copysign(y - y, y));
49 }49 }
...@@ -64,7 +64,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {...@@ -64,7 +64,7 @@ fn sqrt32(z: Complex(f32)) Complex(f32) {
64 } else {64 } else {
65 const t = @sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5);65 const t = @sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5);
66 return Complex(f32).init(66 return Complex(f32).init(
67 @as(f32, @floatCast(@fabs(y) / (2.0 * t))),67 @as(f32, @floatCast(@abs(y) / (2.0 * t))),
68 @as(f32, @floatCast(math.copysign(t, y))),68 @as(f32, @floatCast(math.copysign(t, y))),
69 );69 );
70 }70 }
...@@ -94,7 +94,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {...@@ -94,7 +94,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
94 // sqrt(-inf + i nan) = nan +- inf i94 // sqrt(-inf + i nan) = nan +- inf i
95 // sqrt(-inf + iy) = 0 + inf i95 // sqrt(-inf + iy) = 0 + inf i
96 if (math.signbit(x)) {96 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));
98 } else {98 } else {
99 return Complex(f64).init(x, math.copysign(y - y, y));99 return Complex(f64).init(x, math.copysign(y - y, y));
100 }100 }
...@@ -104,7 +104,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {...@@ -104,7 +104,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
104104
105 // scale to avoid overflow105 // scale to avoid overflow
106 var scale = false;106 var scale = false;
107 if (@fabs(x) >= threshold or @fabs(y) >= threshold) {107 if (@abs(x) >= threshold or @abs(y) >= threshold) {
108 x *= 0.25;108 x *= 0.25;
109 y *= 0.25;109 y *= 0.25;
110 scale = true;110 scale = true;
...@@ -116,7 +116,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {...@@ -116,7 +116,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) {
116 result = Complex(f64).init(t, y / (2.0 * t));116 result = Complex(f64).init(t, y / (2.0 * t));
117 } else {117 } else {
118 const t = @sqrt((-x + math.hypot(f64, x, y)) * 0.5);118 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));
120 }120 }
121121
122 if (scale) {122 if (scale) {
lib/std/math/complex/tanh.zig+2-2
...@@ -44,7 +44,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) {...@@ -44,7 +44,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) {
4444
45 // x >= 1145 // x >= 11
46 if (ix >= 0x41300000) {46 if (ix >= 0x41300000) {
47 const exp_mx = @exp(-@fabs(x));47 const exp_mx = @exp(-@abs(x));
48 return Complex(f32).init(math.copysign(@as(f32, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx);48 return Complex(f32).init(math.copysign(@as(f32, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx);
49 }49 }
5050
...@@ -87,7 +87,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) {...@@ -87,7 +87,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) {
8787
88 // x >= 2288 // x >= 22
89 if (ix >= 0x40360000) {89 if (ix >= 0x40360000) {
90 const exp_mx = @exp(-@fabs(x));90 const exp_mx = @exp(-@abs(x));
91 return Complex(f64).init(math.copysign(@as(f64, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx);91 return Complex(f64).init(math.copysign(@as(f64, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx);
92 }92 }
9393
lib/std/math/pow.zig+2-2
...@@ -82,7 +82,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {...@@ -82,7 +82,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
82 }82 }
83 // pow(x, +inf) = +0 for |x| < 183 // pow(x, +inf) = +0 for |x| < 1
84 // pow(x, -inf) = +0 for |x| > 184 // 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)) {
86 return 0;86 return 0;
87 }87 }
88 // pow(x, -inf) = +inf for |x| < 188 // pow(x, -inf) = +inf for |x| < 1
...@@ -115,7 +115,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {...@@ -115,7 +115,7 @@ pub fn pow(comptime T: type, x: T, y: T) T {
115 return 1 / @sqrt(x);115 return 1 / @sqrt(x);
116 }116 }
117117
118 const r1 = math.modf(@fabs(y));118 const r1 = math.modf(@abs(y));
119 var yi = r1.ipart;119 var yi = r1.ipart;
120 var yf = r1.fpart;120 var yf = r1.fpart;
121121
lib/std/meta.zig+2-2
...@@ -1104,6 +1104,6 @@ pub fn isError(error_union: anytype) bool {...@@ -1104,6 +1104,6 @@ pub fn isError(error_union: anytype) bool {
1104}1104}
11051105
1106test "isError" {1106test "isError" {
1107 try std.testing.expect(isError(math.absInt(@as(i8, -128))));1107 try std.testing.expect(isError(math.divTrunc(u8, 5, 0)));
1108 try std.testing.expect(!isError(math.absInt(@as(i8, -127))));1108 try std.testing.expect(!isError(math.divTrunc(u8, 5, 5)));
1109}1109}
lib/std/rand/ziggurat.zig+1-1
...@@ -33,7 +33,7 @@ pub fn next_f64(random: Random, comptime tables: ZigTable) f64 {...@@ -33,7 +33,7 @@ pub fn next_f64(random: Random, comptime tables: ZigTable) f64 {
33 };33 };
3434
35 const x = u * tables.x[i];35 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
38 // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i])38 // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i])
39 if (test_x < tables.x[i + 1]) {39 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 {...@@ -88,13 +88,19 @@ pub inline fn __builtin_log10f(val: f32) f32 {
8888
89// Standard C Library bug: The absolute value of the most negative integer remains negative.89// Standard C Library bug: The absolute value of the most negative integer remains negative.
90pub inline fn __builtin_abs(val: c_int) c_int {90pub 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));
92}98}
93pub inline fn __builtin_fabs(val: f64) f64 {99pub inline fn __builtin_fabs(val: f64) f64 {
94 return @fabs(val);100 return @abs(val);
95}101}
96pub inline fn __builtin_fabsf(val: f32) f32 {102pub inline fn __builtin_fabsf(val: f32) f32 {
97 return @fabs(val);103 return @abs(val);
98}104}
99105
100pub inline fn __builtin_floor(val: f64) f64 {106pub inline fn __builtin_floor(val: f64) f64 {
lib/std/zig/render.zig+2
...@@ -1503,6 +1503,8 @@ fn renderBuiltinCall(...@@ -1503,6 +1503,8 @@ fn renderBuiltinCall(
1503 try ais.writer().writeAll("@ptrFromInt");1503 try ais.writer().writeAll("@ptrFromInt");
1504 } else if (mem.eql(u8, slice, "@ptrToInt")) {1504 } else if (mem.eql(u8, slice, "@ptrToInt")) {
1505 try ais.writer().writeAll("@intFromPtr");1505 try ais.writer().writeAll("@intFromPtr");
1506 } else if (mem.eql(u8, slice, "@fabs")) {
1507 try ais.writer().writeAll("@abs");
1506 } else {1508 } else {
1507 try renderToken(ais, tree, builtin_token, .none); // @name1509 try renderToken(ais, tree, builtin_token, .none); // @name
1508 }1510 }
lib/zig.h+41
...@@ -946,6 +946,24 @@ typedef unsigned long zig_Builtin64;...@@ -946,6 +946,24 @@ typedef unsigned long zig_Builtin64;
946typedef unsigned long long zig_Builtin64;946typedef unsigned long long zig_Builtin64;
947#endif947#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
949static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) {967static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) {
950 return zig_wrap_u8(val >> (8 - bits), bits);968 return zig_wrap_u8(val >> (8 - bits), bits);
951}969}
...@@ -1141,6 +1159,24 @@ zig_builtin_clz(16)...@@ -1141,6 +1159,24 @@ zig_builtin_clz(16)
1141zig_builtin_clz(32)1159zig_builtin_clz(32)
1142zig_builtin_clz(64)1160zig_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
1144/* ======================== 128-bit Integer Support ========================= */1180/* ======================== 128-bit Integer Support ========================= */
11451181
1146#if !defined(zig_has_int128)1182#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) {...@@ -1466,6 +1502,11 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1466 return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);1502 return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);
1467}1503}
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
1469#if zig_has_int1281510#if zig_has_int128
14701511
1471static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {1512static 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 {...@@ -356,9 +356,10 @@ pub const Inst = struct {
356 /// Base 10 logarithm of a floating point number.356 /// Base 10 logarithm of a floating point number.
357 /// Uses the `un_op` field.357 /// Uses the `un_op` field.
358 log10,358 log10,
359 /// Aboslute value of a floating point number.359 /// Aboslute value of an integer, floating point number or vector.
360 /// Uses the `un_op` field.360 /// Result type is always unsigned if the operand is an integer.
361 fabs,361 /// Uses the `ty_op` field.
362 abs,
362 /// Floor: rounds a floating pointer number down to the nearest integer.363 /// Floor: rounds a floating pointer number down to the nearest integer.
363 /// Uses the `un_op` field.364 /// Uses the `un_op` field.
364 floor,365 floor,
...@@ -1279,7 +1280,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1279,7 +1280,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1279 .log,1280 .log,
1280 .log2,1281 .log2,
1281 .log10,1282 .log10,
1282 .fabs,
1283 .floor,1283 .floor,
1284 .ceil,1284 .ceil,
1285 .round,1285 .round,
...@@ -1384,6 +1384,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1384,6 +1384,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1384 .addrspace_cast,1384 .addrspace_cast,
1385 .c_va_arg,1385 .c_va_arg,
1386 .c_va_copy,1386 .c_va_copy,
1387 .abs,
1387 => return air.getRefType(datas[inst].ty_op.ty),1388 => return air.getRefType(datas[inst].ty_op.ty),
13881389
1389 .loop,1390 .loop,
...@@ -1697,7 +1698,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -1697,7 +1698,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1697 .log,1698 .log,
1698 .log2,1699 .log2,
1699 .log10,1700 .log10,
1700 .fabs,1701 .abs,
1701 .floor,1702 .floor,
1702 .ceil,1703 .ceil,
1703 .round,1704 .round,
src/AstGen.zig+2-2
...@@ -2601,7 +2601,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2601,7 +2601,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2601 .log,2601 .log,
2602 .log2,2602 .log2,
2603 .log10,2603 .log10,
2604 .fabs,2604 .abs,
2605 .floor,2605 .floor,
2606 .ceil,2606 .ceil,
2607 .trunc,2607 .trunc,
...@@ -8385,7 +8385,7 @@ fn builtinCall(...@@ -8385,7 +8385,7 @@ fn builtinCall(
8385 .log => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log),8385 .log => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log),
8386 .log2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log2),8386 .log2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log2),
8387 .log10 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log10),8387 .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),
8389 .floor => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .floor),8389 .floor => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .floor),
8390 .ceil => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ceil),8390 .ceil => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ceil),
8391 .trunc => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .trunc),8391 .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....@@ -929,7 +929,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
929 .log,929 .log,
930 .log2,930 .log2,
931 .log10,931 .log10,
932 .fabs,932 .abs,
933 .floor,933 .floor,
934 .ceil,934 .ceil,
935 .trunc,935 .trunc,
src/Autodoc.zig+1-1
...@@ -1669,7 +1669,7 @@ fn walkInstruction(...@@ -1669,7 +1669,7 @@ fn walkInstruction(
1669 .log,1669 .log,
1670 .log2,1670 .log2,
1671 .log10,1671 .log10,
1672 .fabs,1672 .abs,
1673 .floor,1673 .floor,
1674 .ceil,1674 .ceil,
1675 .trunc,1675 .trunc,
src/BuiltinFn.zig+3-3
...@@ -102,7 +102,7 @@ pub const Tag = enum {...@@ -102,7 +102,7 @@ pub const Tag = enum {
102 log,102 log,
103 log2,103 log2,
104 log10,104 log10,
105 fabs,105 abs,
106 floor,106 floor,
107 ceil,107 ceil,
108 trunc,108 trunc,
...@@ -874,9 +874,9 @@ pub const list = list: {...@@ -874,9 +874,9 @@ pub const list = list: {
874 },874 },
875 },875 },
876 .{876 .{
877 "@fabs",877 "@abs",
878 .{878 .{
879 .tag = .fabs,879 .tag = .abs,
880 .param_count = 1,880 .param_count = 1,
881 },881 },
882 },882 },
src/Liveness.zig+2-2
...@@ -384,6 +384,7 @@ pub fn categorizeOperand(...@@ -384,6 +384,7 @@ pub fn categorizeOperand(
384 .addrspace_cast,384 .addrspace_cast,
385 .c_va_arg,385 .c_va_arg,
386 .c_va_copy,386 .c_va_copy,
387 .abs,
387 => {388 => {
388 const o = air_datas[inst].ty_op;389 const o = air_datas[inst].ty_op;
389 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);390 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
...@@ -420,7 +421,6 @@ pub fn categorizeOperand(...@@ -420,7 +421,6 @@ pub fn categorizeOperand(
420 .log,421 .log,
421 .log2,422 .log2,
422 .log10,423 .log10,
423 .fabs,
424 .floor,424 .floor,
425 .ceil,425 .ceil,
426 .round,426 .round,
...@@ -1027,6 +1027,7 @@ fn analyzeInst(...@@ -1027,6 +1027,7 @@ fn analyzeInst(
1027 .addrspace_cast,1027 .addrspace_cast,
1028 .c_va_arg,1028 .c_va_arg,
1029 .c_va_copy,1029 .c_va_copy,
1030 .abs,
1030 => {1031 => {
1031 const o = inst_datas[inst].ty_op;1032 const o = inst_datas[inst].ty_op;
1032 return analyzeOperands(a, pass, data, inst, .{ o.operand, .none, .none });1033 return analyzeOperands(a, pass, data, inst, .{ o.operand, .none, .none });
...@@ -1054,7 +1055,6 @@ fn analyzeInst(...@@ -1054,7 +1055,6 @@ fn analyzeInst(
1054 .log,1055 .log,
1055 .log2,1056 .log2,
1056 .log10,1057 .log10,
1057 .fabs,
1058 .floor,1058 .floor,
1059 .ceil,1059 .ceil,
1060 .round,1060 .round,
src/Liveness/Verify.zig+1-1
...@@ -110,6 +110,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -110,6 +110,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
110 .addrspace_cast,110 .addrspace_cast,
111 .c_va_arg,111 .c_va_arg,
112 .c_va_copy,112 .c_va_copy,
113 .abs,
113 => {114 => {
114 const ty_op = data[inst].ty_op;115 const ty_op = data[inst].ty_op;
115 try self.verifyInstOperands(inst, .{ ty_op.operand, .none, .none });116 try self.verifyInstOperands(inst, .{ ty_op.operand, .none, .none });
...@@ -136,7 +137,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -136,7 +137,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
136 .log,137 .log,
137 .log2,138 .log2,
138 .log10,139 .log10,
139 .fabs,
140 .floor,140 .floor,
141 .ceil,141 .ceil,
142 .round,142 .round,
src/Sema.zig+77-50
...@@ -1156,6 +1156,7 @@ fn analyzeBodyInner(...@@ -1156,6 +1156,7 @@ fn analyzeBodyInner(
1156 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),1156 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
1157 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),1157 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
1158 .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount),1158 .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount),
1159 .abs => try sema.zirAbs(block, inst),
11591160
1160 .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),1161 .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
1161 .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin),1162 .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
...@@ -1166,7 +1167,6 @@ fn analyzeBodyInner(...@@ -1166,7 +1167,6 @@ fn analyzeBodyInner(
1166 .log => try sema.zirUnaryMath(block, inst, .log, Value.log),1167 .log => try sema.zirUnaryMath(block, inst, .log, Value.log),
1167 .log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2),1168 .log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2),
1168 .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),1169 .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),
1169 .fabs => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs),
1170 .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),1170 .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),
1171 .ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),1171 .ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),
1172 .round => try sema.zirUnaryMath(block, inst, .round, Value.round),1172 .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...@@ -20178,6 +20178,69 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
20178 return block.addUnOp(.error_name, operand);20178 return block.addUnOp(.error_name, operand);
20179}20179}
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
20181fn zirUnaryMath(20244fn zirUnaryMath(
20182 sema: *Sema,20245 sema: *Sema,
20183 block: *Block,20246 block: *Block,
...@@ -20193,58 +20256,22 @@ fn zirUnaryMath(...@@ -20193,58 +20256,22 @@ fn zirUnaryMath(
20193 const operand = try sema.resolveInst(inst_data.operand);20256 const operand = try sema.resolveInst(inst_data.operand);
20194 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };20257 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20195 const operand_ty = sema.typeOf(operand);20258 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)) {
20198 .ComptimeFloat, .Float => {},20262 .ComptimeFloat, .Float => {},
20199 .Vector => {20263 else => return sema.fail(
20200 const scalar_ty = operand_ty.scalarType(mod);20264 block,
20201 switch (scalar_ty.zigTypeTag(mod)) {20265 operand_src,
20202 .ComptimeFloat, .Float => {},20266 "expected vector of floats or float type, found '{}'",
20203 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}),20267 .{operand_ty.fmt(sema.mod)},
20204 }20268 ),
20205 },
20206 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}),
20207 }20269 }
2020820270
20209 switch (operand_ty.zigTypeTag(mod)) {20271 return (try sema.maybeConstantUnaryMath(operand, operand_ty, eval)) orelse {
20210 .Vector => {20272 try sema.requireRuntimeBlock(block, operand_src, null);
20211 const scalar_ty = operand_ty.scalarType(mod);20273 return block.addUnOp(air_tag, operand);
20212 const vec_len = operand_ty.vectorLen(mod);20274 };
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 }
20248}20275}
2024920276
20250fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {20277fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -37503,7 +37530,7 @@ fn float128IntPartToBigInt(...@@ -37503,7 +37530,7 @@ fn float128IntPartToBigInt(
37503 float: f128,37530 float: f128,
37504) !std.math.big.int.Managed {37531) !std.math.big.int.Managed {
37505 const is_negative = std.math.signbit(float);37532 const is_negative = std.math.signbit(float);
37506 const floored = @floor(@fabs(float));37533 const floored = @floor(@abs(float));
3750737534
37508 var rational = try std.math.big.Rational.init(arena);37535 var rational = try std.math.big.Rational.init(arena);
37509 defer rational.q.deinit();37536 defer rational.q.deinit();
src/Zir.zig+5-5
...@@ -846,8 +846,8 @@ pub const Inst = struct {...@@ -846,8 +846,8 @@ pub const Inst = struct {
846 log2,846 log2,
847 /// Implement builtin `@log10`. Uses `un_node`.847 /// Implement builtin `@log10`. Uses `un_node`.
848 log10,848 log10,
849 /// Implement builtin `@fabs`. Uses `un_node`.849 /// Implement builtin `@abs`. Uses `un_node`.
850 fabs,850 abs,
851 /// Implement builtin `@floor`. Uses `un_node`.851 /// Implement builtin `@floor`. Uses `un_node`.
852 floor,852 floor,
853 /// Implement builtin `@ceil`. Uses `un_node`.853 /// Implement builtin `@ceil`. Uses `un_node`.
...@@ -1198,7 +1198,7 @@ pub const Inst = struct {...@@ -1198,7 +1198,7 @@ pub const Inst = struct {
1198 .log,1198 .log,
1199 .log2,1199 .log2,
1200 .log10,1200 .log10,
1201 .fabs,1201 .abs,
1202 .floor,1202 .floor,
1203 .ceil,1203 .ceil,
1204 .trunc,1204 .trunc,
...@@ -1493,7 +1493,7 @@ pub const Inst = struct {...@@ -1493,7 +1493,7 @@ pub const Inst = struct {
1493 .log,1493 .log,
1494 .log2,1494 .log2,
1495 .log10,1495 .log10,
1496 .fabs,1496 .abs,
1497 .floor,1497 .floor,
1498 .ceil,1498 .ceil,
1499 .trunc,1499 .trunc,
...@@ -1756,7 +1756,7 @@ pub const Inst = struct {...@@ -1756,7 +1756,7 @@ pub const Inst = struct {
1756 .log = .un_node,1756 .log = .un_node,
1757 .log2 = .un_node,1757 .log2 = .un_node,
1758 .log10 = .un_node,1758 .log10 = .un_node,
1759 .fabs = .un_node,1759 .abs = .un_node,
1760 .floor = .un_node,1760 .floor = .un_node,
1761 .ceil = .un_node,1761 .ceil = .un_node,
1762 .trunc = .un_node,1762 .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 {...@@ -713,7 +713,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
713 .log,713 .log,
714 .log2,714 .log2,
715 .log10,715 .log10,
716 .fabs,
717 .floor,716 .floor,
718 .ceil,717 .ceil,
719 .round,718 .round,
...@@ -788,6 +787,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -788,6 +787,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
788 .clz => try self.airClz(inst),787 .clz => try self.airClz(inst),
789 .ctz => try self.airCtz(inst),788 .ctz => try self.airCtz(inst),
790 .popcount => try self.airPopcount(inst),789 .popcount => try self.airPopcount(inst),
790 .abs => try self.airAbs(inst),
791 .byte_swap => try self.airByteSwap(inst),791 .byte_swap => try self.airByteSwap(inst),
792 .bit_reverse => try self.airBitReverse(inst),792 .bit_reverse => try self.airBitReverse(inst),
793 .tag_name => try self.airTagName(inst),793 .tag_name => try self.airTagName(inst),
...@@ -3550,6 +3550,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -3550,6 +3550,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
3550 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3550 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3551}3551}
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
3553fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {3559fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
3554 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3560 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 airByteSwap for {}", .{self.target.cpu.arch});3561 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 {...@@ -699,7 +699,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
699 .log,699 .log,
700 .log2,700 .log2,
701 .log10,701 .log10,
702 .fabs,
703 .floor,702 .floor,
704 .ceil,703 .ceil,
705 .round,704 .round,
...@@ -774,6 +773,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -774,6 +773,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
774 .clz => try self.airClz(inst),773 .clz => try self.airClz(inst),
775 .ctz => try self.airCtz(inst),774 .ctz => try self.airCtz(inst),
776 .popcount => try self.airPopcount(inst),775 .popcount => try self.airPopcount(inst),
776 .abs => try self.airAbs(inst),
777 .byte_swap => try self.airByteSwap(inst),777 .byte_swap => try self.airByteSwap(inst),
778 .bit_reverse => try self.airBitReverse(inst),778 .bit_reverse => try self.airBitReverse(inst),
779 .tag_name => try self.airTagName(inst),779 .tag_name => try self.airTagName(inst),
...@@ -2591,6 +2591,13 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -2591,6 +2591,13 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
2591 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2591 // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2592}2592}
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
2594fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {2601fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
2595 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2602 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2596 _ = ty_op;2603 _ = ty_op;
src/arch/riscv64/CodeGen.zig+7-1
...@@ -523,7 +523,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -523,7 +523,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
523 .log,523 .log,
524 .log2,524 .log2,
525 .log10,525 .log10,
526 .fabs,
527 .floor,526 .floor,
528 .ceil,527 .ceil,
529 .round,528 .round,
...@@ -607,6 +606,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -607,6 +606,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
607 .clz => try self.airClz(inst),606 .clz => try self.airClz(inst),
608 .ctz => try self.airCtz(inst),607 .ctz => try self.airCtz(inst),
609 .popcount => try self.airPopcount(inst),608 .popcount => try self.airPopcount(inst),
609 .abs => try self.airAbs(inst),
610 .byte_swap => try self.airByteSwap(inst),610 .byte_swap => try self.airByteSwap(inst),
611 .bit_reverse => try self.airBitReverse(inst),611 .bit_reverse => try self.airBitReverse(inst),
612 .tag_name => try self.airTagName(inst),612 .tag_name => try self.airTagName(inst),
...@@ -1447,6 +1447,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {...@@ -1447,6 +1447,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void {
1447 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1447 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1448}1448}
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
1450fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {1456fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
1451 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1457 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 airByteSwap for {}", .{self.target.cpu.arch});1458 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 {...@@ -543,7 +543,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
543 .log,543 .log,
544 .log2,544 .log2,
545 .log10,545 .log10,
546 .fabs,546 .abs,
547 .floor,547 .floor,
548 .ceil,548 .ceil,
549 .round,549 .round,
src/arch/wasm/CodeGen.zig+78-1
...@@ -1866,13 +1866,14 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1866,13 +1866,14 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1866 .log => func.airUnaryFloatOp(inst, .log),1866 .log => func.airUnaryFloatOp(inst, .log),
1867 .log2 => func.airUnaryFloatOp(inst, .log2),1867 .log2 => func.airUnaryFloatOp(inst, .log2),
1868 .log10 => func.airUnaryFloatOp(inst, .log10),1868 .log10 => func.airUnaryFloatOp(inst, .log10),
1869 .fabs => func.airUnaryFloatOp(inst, .fabs),
1870 .floor => func.airUnaryFloatOp(inst, .floor),1869 .floor => func.airUnaryFloatOp(inst, .floor),
1871 .ceil => func.airUnaryFloatOp(inst, .ceil),1870 .ceil => func.airUnaryFloatOp(inst, .ceil),
1872 .round => func.airUnaryFloatOp(inst, .round),1871 .round => func.airUnaryFloatOp(inst, .round),
1873 .trunc_float => func.airUnaryFloatOp(inst, .trunc),1872 .trunc_float => func.airUnaryFloatOp(inst, .trunc),
1874 .neg => func.airUnaryFloatOp(inst, .neg),1873 .neg => func.airUnaryFloatOp(inst, .neg),
18751874
1875 .abs => func.airAbs(inst),
1876
1876 .add_with_overflow => func.airAddSubWithOverflow(inst, .add),1877 .add_with_overflow => func.airAddSubWithOverflow(inst, .add),
1877 .sub_with_overflow => func.airAddSubWithOverflow(inst, .sub),1878 .sub_with_overflow => func.airAddSubWithOverflow(inst, .sub),
1878 .shl_with_overflow => func.airShlWithOverflow(inst),1879 .shl_with_overflow => func.airShlWithOverflow(inst),
...@@ -2786,6 +2787,82 @@ const FloatOp = enum {...@@ -2786,6 +2787,82 @@ const FloatOp = enum {
2786 }2787 }
2787};2788};
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
2789fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {2866fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void {
2790 const un_op = func.air.instructions.items(.data)[inst].un_op;2867 const un_op = func.air.instructions.items(.data)[inst].un_op;
2791 const operand = try func.resolveInst(un_op);2868 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 {...@@ -1809,11 +1809,13 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1809 .round,1809 .round,
1810 => try self.airUnaryMath(inst),1810 => try self.airUnaryMath(inst),
18111811
1812 .floor => try self.airRound(inst, 0b1_0_01),1812 .floor => try self.airRound(inst, 0b1_0_01),
1813 .ceil => try self.airRound(inst, 0b1_0_10),1813 .ceil => try self.airRound(inst, 0b1_0_10),
1814 .trunc_float => try self.airRound(inst, 0b1_0_11),1814 .trunc_float => try self.airRound(inst, 0b1_0_11),
1815 .sqrt => try self.airSqrt(inst),1815 .sqrt => try self.airSqrt(inst),
1816 .neg, .fabs => try self.airFloatSign(inst),1816 .neg => try self.airFloatSign(inst),
1817
1818 .abs => try self.airAbs(inst),
18171819
1818 .add_with_overflow => try self.airAddSubWithOverflow(inst),1820 .add_with_overflow => try self.airAddSubWithOverflow(inst),
1819 .sub_with_overflow => try self.airAddSubWithOverflow(inst),1821 .sub_with_overflow => try self.airAddSubWithOverflow(inst),
...@@ -4885,28 +4887,26 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {...@@ -4885,28 +4887,26 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void {
4885 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });4887 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
4886}4888}
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 {
4889 const mod = self.bin_file.options.module.?;4891 const mod = self.bin_file.options.module.?;
4890 const tag = self.air.instructions.items(.tag)[inst];4892 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);
4893 const abi_size: u32 = switch (ty.abiSize(mod)) {4893 const abi_size: u32 = switch (ty.abiSize(mod)) {
4894 1...16 => 16,4894 1...16 => 16,
4895 17...32 => 32,4895 17...32 => 32,
4896 else => return self.fail("TODO implement airFloatSign for {}", .{4896 else => return self.fail("TODO implement floatSign for {}", .{
4897 ty.fmt(mod),4897 ty.fmt(mod),
4898 }),4898 }),
4899 };4899 };
4900 const scalar_bits = ty.scalarType(mod).floatBits(self.target.*);4900 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 {}", .{
4902 ty.fmt(mod),4902 ty.fmt(mod),
4903 });4903 });
49044904
4905 const src_mcv = try self.resolveInst(un_op);4905 const src_mcv = try self.resolveInst(operand);
4906 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;4906 const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
4907 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);4907 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))
4910 src_mcv4910 src_mcv
4911 else if (self.hasFeature(.avx))4911 else if (self.hasFeature(.avx))
4912 .{ .register = try self.register_manager.allocReg(inst, sse) }4912 .{ .register = try self.register_manager.allocReg(inst, sse) }
...@@ -4923,7 +4923,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {...@@ -4923,7 +4923,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
49234923
4924 const sign_val = switch (tag) {4924 const sign_val = switch (tag) {
4925 .neg => try vec_ty.minInt(mod, vec_ty),4925 .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),
4927 else => unreachable,4927 else => unreachable,
4928 };4928 };
49294929
...@@ -4939,24 +4939,24 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {...@@ -4939,24 +4939,24 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
4939 switch (scalar_bits) {4939 switch (scalar_bits) {
4940 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {4940 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {
4941 .neg => .{ .vp_, .xor },4941 .neg => .{ .vp_, .xor },
4942 .fabs => .{ .vp_, .@"and" },4942 .abs => .{ .vp_, .@"and" },
4943 else => unreachable,4943 else => unreachable,
4944 } else switch (tag) {4944 } else switch (tag) {
4945 .neg => .{ .v_ps, .xor },4945 .neg => .{ .v_ps, .xor },
4946 .fabs => .{ .v_ps, .@"and" },4946 .abs => .{ .v_ps, .@"and" },
4947 else => unreachable,4947 else => unreachable,
4948 },4948 },
4949 32 => switch (tag) {4949 32 => switch (tag) {
4950 .neg => .{ .v_ps, .xor },4950 .neg => .{ .v_ps, .xor },
4951 .fabs => .{ .v_ps, .@"and" },4951 .abs => .{ .v_ps, .@"and" },
4952 else => unreachable,4952 else => unreachable,
4953 },4953 },
4954 64 => switch (tag) {4954 64 => switch (tag) {
4955 .neg => .{ .v_pd, .xor },4955 .neg => .{ .v_pd, .xor },
4956 .fabs => .{ .v_pd, .@"and" },4956 .abs => .{ .v_pd, .@"and" },
4957 else => unreachable,4957 else => unreachable,
4958 },4958 },
4959 80 => return self.fail("TODO implement airFloatSign for {}", .{4959 80 => return self.fail("TODO implement floatSign for {}", .{
4960 ty.fmt(self.bin_file.options.module.?),4960 ty.fmt(self.bin_file.options.module.?),
4961 }),4961 }),
4962 else => unreachable,4962 else => unreachable,
...@@ -4971,20 +4971,20 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {...@@ -4971,20 +4971,20 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
4971 switch (scalar_bits) {4971 switch (scalar_bits) {
4972 16, 128 => switch (tag) {4972 16, 128 => switch (tag) {
4973 .neg => .{ .p_, .xor },4973 .neg => .{ .p_, .xor },
4974 .fabs => .{ .p_, .@"and" },4974 .abs => .{ .p_, .@"and" },
4975 else => unreachable,4975 else => unreachable,
4976 },4976 },
4977 32 => switch (tag) {4977 32 => switch (tag) {
4978 .neg => .{ ._ps, .xor },4978 .neg => .{ ._ps, .xor },
4979 .fabs => .{ ._ps, .@"and" },4979 .abs => .{ ._ps, .@"and" },
4980 else => unreachable,4980 else => unreachable,
4981 },4981 },
4982 64 => switch (tag) {4982 64 => switch (tag) {
4983 .neg => .{ ._pd, .xor },4983 .neg => .{ ._pd, .xor },
4984 .fabs => .{ ._pd, .@"and" },4984 .abs => .{ ._pd, .@"and" },
4985 else => unreachable,4985 else => unreachable,
4986 },4986 },
4987 80 => return self.fail("TODO implement airFloatSign for {}", .{4987 80 => return self.fail("TODO implement floatSign for {}", .{
4988 ty.fmt(self.bin_file.options.module.?),4988 ty.fmt(self.bin_file.options.module.?),
4989 }),4989 }),
4990 else => unreachable,4990 else => unreachable,
...@@ -4992,7 +4992,14 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {...@@ -4992,7 +4992,14 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
4992 registerAlias(dst_reg, abi_size),4992 registerAlias(dst_reg, abi_size),
4993 sign_mem,4993 sign_mem,
4994 );4994 );
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);
4996}5003}
49975004
4998fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void {5005fn 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...@@ -5082,6 +5089,52 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4
5082 }5089 }
5083}5090}
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
5085fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {5138fn airSqrt(self: *Self, inst: Air.Inst.Index) !void {
5086 const mod = self.bin_file.options.module.?;5139 const mod = self.bin_file.options.module.?;
5087 const un_op = self.air.instructions.items(.data)[inst].un_op;5140 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 {...@@ -105,7 +105,7 @@ pub const Instruction = struct {
105 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});105 try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)});
106 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{106 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
107 @as(u8, if (rip.disp < 0) '-' else '+'),107 @as(u8, if (rip.disp < 0) '-' else '+'),
108 std.math.absCast(rip.disp),108 @abs(rip.disp),
109 });109 });
110 try writer.writeByte(']');110 try writer.writeByte(']');
111 },111 },
...@@ -140,7 +140,7 @@ pub const Instruction = struct {...@@ -140,7 +140,7 @@ pub const Instruction = struct {
140 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})140 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
141 else if (sib.disp < 0)141 else if (sib.disp < 0)
142 try writer.writeByte('-');142 try writer.writeByte('-');
143 try writer.print("0x{x}", .{std.math.absCast(sib.disp)});143 try writer.print("0x{x}", .{@abs(sib.disp)});
144 any = true;144 any = true;
145 }145 }
146146
src/codegen/c.zig+32-10
...@@ -2912,6 +2912,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2912,6 +2912,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2912 },2912 },
2913 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none),2913 .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none),
2914 .mod => try airBinBuiltinCall(f, inst, "mod", .none),2914 .mod => try airBinBuiltinCall(f, inst, "mod", .none),
2915 .abs => try airAbs(f, inst),
29152916
2916 .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits),2917 .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits),
2917 .sub_wrap => try airBinBuiltinCall(f, inst, "subw", .bits),2918 .sub_wrap => try airBinBuiltinCall(f, inst, "subw", .bits),
...@@ -2931,7 +2932,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2931,7 +2932,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2931 .log => try airUnFloatOp(f, inst, "log"),2932 .log => try airUnFloatOp(f, inst, "log"),
2932 .log2 => try airUnFloatOp(f, inst, "log2"),2933 .log2 => try airUnFloatOp(f, inst, "log2"),
2933 .log10 => try airUnFloatOp(f, inst, "log10"),2934 .log10 => try airUnFloatOp(f, inst, "log10"),
2934 .fabs => try airUnFloatOp(f, inst, "fabs"),
2935 .floor => try airUnFloatOp(f, inst, "floor"),2935 .floor => try airUnFloatOp(f, inst, "floor"),
2936 .ceil => try airUnFloatOp(f, inst, "ceil"),2936 .ceil => try airUnFloatOp(f, inst, "ceil"),
2937 .round => try airUnFloatOp(f, inst, "round"),2937 .round => try airUnFloatOp(f, inst, "round"),
...@@ -7076,23 +7076,35 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7076,23 +7076,35 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
7076 return local;7076 return local;
7077}7077}
70787078
7079fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {7079fn airAbs(f: *Function, inst: Air.Inst.Index) !CValue {
7080 const mod = f.object.dg.module;7080 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);7086 switch (scalar_ty.zigTypeTag(mod)) {
7084 try reap(f, inst, &.{un_op});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);7097fn unFloatOp(f: *Function, inst: Air.Inst.Index, operand: CValue, ty: Type, operation: []const u8) !CValue {
7087 const inst_scalar_ty = inst_ty.scalarType(mod);7098 const mod = f.object.dg.module;
7099 const scalar_ty = ty.scalarType(mod);
70887100
7089 const writer = f.object.writer();7101 const writer = f.object.writer();
7090 const local = try f.allocLocal(inst, inst_ty);7102 const local = try f.allocLocal(inst, ty);
7091 const v = try Vectorize.start(f, inst, writer, inst_ty);7103 const v = try Vectorize.start(f, inst, writer, ty);
7092 try f.writeCValue(writer, local, .Other);7104 try f.writeCValue(writer, local, .Other);
7093 try v.elem(f, writer);7105 try v.elem(f, writer);
7094 try writer.writeAll(" = zig_libc_name_");7106 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);
7096 try writer.writeByte('(');7108 try writer.writeByte('(');
7097 try writer.writeAll(operation);7109 try writer.writeAll(operation);
7098 try writer.writeAll(")(");7110 try writer.writeAll(")(");
...@@ -7104,6 +7116,16 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal...@@ -7104,6 +7116,16 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
7104 return local;7116 return local;
7105}7117}
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
7107fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {7129fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
7108 const mod = f.object.dg.module;7130 const mod = f.object.dg.module;
7109 const bin_op = f.air.instructions.items(.data)[inst].bin_op;7131 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 {...@@ -4729,6 +4729,7 @@ pub const FuncGen = struct {
4729 .div_exact => try self.airDivExact(inst, .normal),4729 .div_exact => try self.airDivExact(inst, .normal),
4730 .rem => try self.airRem(inst, .normal),4730 .rem => try self.airRem(inst, .normal),
4731 .mod => try self.airMod(inst, .normal),4731 .mod => try self.airMod(inst, .normal),
4732 .abs => try self.airAbs(inst),
4732 .ptr_add => try self.airPtrAdd(inst),4733 .ptr_add => try self.airPtrAdd(inst),
4733 .ptr_sub => try self.airPtrSub(inst),4734 .ptr_sub => try self.airPtrSub(inst),
4734 .shl => try self.airShl(inst),4735 .shl => try self.airShl(inst),
...@@ -4766,7 +4767,6 @@ pub const FuncGen = struct {...@@ -4766,7 +4767,6 @@ pub const FuncGen = struct {
4766 .log => try self.airUnaryOp(inst, .log),4767 .log => try self.airUnaryOp(inst, .log),
4767 .log2 => try self.airUnaryOp(inst, .log2),4768 .log2 => try self.airUnaryOp(inst, .log2),
4768 .log10 => try self.airUnaryOp(inst, .log10),4769 .log10 => try self.airUnaryOp(inst, .log10),
4769 .fabs => try self.airUnaryOp(inst, .fabs),
4770 .floor => try self.airUnaryOp(inst, .floor),4770 .floor => try self.airUnaryOp(inst, .floor),
4771 .ceil => try self.airUnaryOp(inst, .ceil),4771 .ceil => try self.airUnaryOp(inst, .ceil),
4772 .round => try self.airUnaryOp(inst, .round),4772 .round => try self.airUnaryOp(inst, .round),
...@@ -8237,6 +8237,28 @@ pub const FuncGen = struct {...@@ -8237,6 +8237,28 @@ pub const FuncGen = struct {
8237 else if (is_signed_int) .ashr else .lshr, lhs, casted_rhs, "");8237 else if (is_signed_int) .ashr else .lshr, lhs, casted_rhs, "");
8238 }8238 }
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
8240 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {8262 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8241 const o = self.dg.object;8263 const o = self.dg.object;
8242 const mod = o.module;8264 const mod = o.module;
src/print_air.zig+1-1
...@@ -188,7 +188,7 @@ const Writer = struct {...@@ -188,7 +188,7 @@ const Writer = struct {
188 .log,188 .log,
189 .log2,189 .log2,
190 .log10,190 .log10,
191 .fabs,191 .abs,
192 .floor,192 .floor,
193 .ceil,193 .ceil,
194 .round,194 .round,
src/print_zir.zig+1-1
...@@ -262,7 +262,7 @@ const Writer = struct {...@@ -262,7 +262,7 @@ const Writer = struct {
262 .log,262 .log,
263 .log2,263 .log2,
264 .log10,264 .log10,
265 .fabs,265 .abs,
266 .floor,266 .floor,
267 .ceil,267 .ceil,
268 .trunc,268 .trunc,
src/type.zig+11
...@@ -3197,6 +3197,17 @@ pub const Type = struct {...@@ -3197,6 +3197,17 @@ pub const Type = struct {
3197 };3197 };
3198 }3198 }
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
3200 pub const @"u1": Type = .{ .ip_index = .u1_type };3211 pub const @"u1": Type = .{ .ip_index = .u1_type };
3201 pub const @"u8": Type = .{ .ip_index = .u8_type };3212 pub const @"u8": Type = .{ .ip_index = .u8_type };
3202 pub const @"u16": Type = .{ .ip_index = .u16_type };3213 pub const @"u16": Type = .{ .ip_index = .u16_type };
src/value.zig+40-21
...@@ -1993,7 +1993,7 @@ pub const Value = struct {...@@ -1993,7 +1993,7 @@ pub const Value = struct {
1993 return 1;1993 return 1;
1994 }1994 }
19951995
1996 const w_value = @fabs(scalar);1996 const w_value = @abs(scalar);
1997 return @divFloor(@as(std.math.big.Limb, @intFromFloat(std.math.log2(w_value))), @typeInfo(std.math.big.Limb).Int.bits) + 1;1997 return @divFloor(@as(std.math.big.Limb, @intFromFloat(std.math.log2(w_value))), @typeInfo(std.math.big.Limb).Int.bits) + 1;
1998 }1998 }
19991999
...@@ -3710,36 +3710,55 @@ pub const Value = struct {...@@ -3710,36 +3710,55 @@ pub const Value = struct {
3710 } })).toValue();3710 } })).toValue();
3711 }3711 }
37123712
3713 pub fn fabs(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value {3713 pub fn abs(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
3714 if (float_type.zigTypeTag(mod) == .Vector) {3714 if (ty.zigTypeTag(mod) == .Vector) {
3715 const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod));3715 const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod));
3716 const scalar_ty = float_type.scalarType(mod);3716 const scalar_ty = ty.scalarType(mod);
3717 for (result_data, 0..) |*scalar, i| {3717 for (result_data, 0..) |*scalar, i| {
3718 const elem_val = try val.elemValue(mod, i);3718 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);
3720 }3720 }
3721 return (try mod.intern(.{ .aggregate = .{3721 return (try mod.intern(.{ .aggregate = .{
3722 .ty = float_type.toIntern(),3722 .ty = ty.toIntern(),
3723 .storage = .{ .elems = result_data },3723 .storage = .{ .elems = result_data },
3724 } })).toValue();3724 } })).toValue();
3725 }3725 }
3726 return fabsScalar(val, float_type, mod);3726 return absScalar(val, ty, mod, arena);
3727 }3727 }
37283728
3729 pub fn fabsScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value {3729 pub fn absScalar(val: Value, ty: Type, mod: *Module, arena: Allocator) Allocator.Error!Value {
3730 const target = mod.getTarget();3730 switch (ty.zigTypeTag(mod)) {
3731 const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) {3731 .Int => {
3732 16 => .{ .f16 = @fabs(val.toFloat(f16, mod)) },3732 var buffer: Value.BigIntSpace = undefined;
3733 32 => .{ .f32 = @fabs(val.toFloat(f32, mod)) },3733 var operand_bigint = try val.toBigInt(&buffer, mod).toManaged(arena);
3734 64 => .{ .f64 = @fabs(val.toFloat(f64, mod)) },3734 operand_bigint.abs();
3735 80 => .{ .f80 = @fabs(val.toFloat(f80, mod)) },3735
3736 128 => .{ .f128 = @fabs(val.toFloat(f128, mod)) },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 },
3737 else => unreachable,3760 else => unreachable,
3738 };3761 }
3739 return (try mod.intern(.{ .float = .{
3740 .ty = float_type.toIntern(),
3741 .storage = storage,
3742 } })).toValue();
3743 }3762 }
37443763
3745 pub fn floor(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value {3764 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;...@@ -946,6 +946,24 @@ typedef unsigned long zig_Builtin64;
946typedef unsigned long long zig_Builtin64;946typedef unsigned long long zig_Builtin64;
947#endif947#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
949static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) {967static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) {
950 return zig_wrap_u8(val >> (8 - bits), bits);968 return zig_wrap_u8(val >> (8 - bits), bits);
951}969}
...@@ -1141,6 +1159,24 @@ zig_builtin_clz(16)...@@ -1141,6 +1159,24 @@ zig_builtin_clz(16)
1141zig_builtin_clz(32)1159zig_builtin_clz(32)
1142zig_builtin_clz(64)1160zig_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
1144/* ======================== 128-bit Integer Support ========================= */1180/* ======================== 128-bit Integer Support ========================= */
11451181
1146#if !defined(zig_has_int128)1182#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) {...@@ -1466,6 +1502,11 @@ static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1466 return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);1502 return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);
1467}1503}
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
1469#if zig_has_int1281510#if zig_has_int128
14701511
1471static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {1512static 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 {...@@ -237,6 +237,7 @@ test {
237 _ = @import("behavior/void.zig");237 _ = @import("behavior/void.zig");
238 _ = @import("behavior/while.zig");238 _ = @import("behavior/while.zig");
239 _ = @import("behavior/widening.zig");239 _ = @import("behavior/widening.zig");
240 _ = @import("behavior/abs.zig");
240241
241 if (builtin.cpu.arch == .wasm32) {242 if (builtin.cpu.arch == .wasm32) {
242 _ = @import("behavior/wasm.zig");243 _ = @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 {...@@ -523,7 +523,7 @@ fn testLog10WithVectors() !void {
523 try expect(@log10(@as(f32, 0.4)) == result[3]);523 try expect(@log10(@as(f32, 0.4)) == result[3]);
524}524}
525525
526test "@fabs" {526test "@abs" {
527 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO527 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -533,24 +533,24 @@ test "@fabs" {...@@ -533,24 +533,24 @@ test "@fabs" {
533}533}
534534
535fn testFabs() !void {535fn testFabs() !void {
536 try expect(@fabs(@as(f16, -2.5)) == 2.5);536 try expect(@abs(@as(f16, -2.5)) == 2.5);
537 try expect(@fabs(@as(f16, 2.5)) == 2.5);537 try expect(@abs(@as(f16, 2.5)) == 2.5);
538 try expect(@fabs(@as(f32, -2.5)) == 2.5);538 try expect(@abs(@as(f32, -2.5)) == 2.5);
539 try expect(@fabs(@as(f32, 2.5)) == 2.5);539 try expect(@abs(@as(f32, 2.5)) == 2.5);
540 try expect(@fabs(@as(f64, -2.5)) == 2.5);540 try expect(@abs(@as(f64, -2.5)) == 2.5);
541 try expect(@fabs(@as(f64, 2.5)) == 2.5);541 try expect(@abs(@as(f64, 2.5)) == 2.5);
542542
543 // TODO test f128, and c_longdouble543 // TODO test f128, and c_longdouble
544 // https://github.com/ziglang/zig/issues/4026544 // https://github.com/ziglang/zig/issues/4026
545 // {545 // {
546 // var a: f80 = -2.5;546 // var a: f80 = -2.5;
547 // var b: f80 = 2.5;547 // var b: f80 = 2.5;
548 // try expect(@fabs(a) == 2.5);548 // try expect(@abs(a) == 2.5);
549 // try expect(@fabs(b) == 2.5);549 // try expect(@abs(b) == 2.5);
550 // }550 // }
551}551}
552552
553test "@fabs with vectors" {553test "@abs with vectors" {
554 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO554 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
556 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO556 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -562,14 +562,15 @@ test "@fabs with vectors" {...@@ -562,14 +562,15 @@ test "@fabs with vectors" {
562562
563fn testFabsWithVectors() !void {563fn testFabsWithVectors() !void {
564 var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };564 var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
565 var result = @fabs(v);565 var result = @abs(v);
566 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));566 try expect(math.approxEqAbs(f32, @abs(@as(f32, 1.1)), result[0], epsilon));
567 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));567 try expect(math.approxEqAbs(f32, @abs(@as(f32, -2.2)), result[1], epsilon));
568 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));568 try expect(math.approxEqAbs(f32, @abs(@as(f32, 0.3)), result[2], epsilon));
569 try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));569 try expect(math.approxEqAbs(f32, @abs(@as(f32, -0.4)), result[3], epsilon));
570}570}
571571
572test "another, possibly redundant, @fabs test" {572test "another, possibly redundant, @abs test" {
573 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
574 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO575 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
575 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO576 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -587,11 +588,12 @@ test "another, possibly redundant, @fabs test" {...@@ -587,11 +588,12 @@ test "another, possibly redundant, @fabs test" {
587588
588 const x = 14.0;589 const x = 14.0;
589 const y = -x;590 const y = -x;
590 const z = @fabs(y);591 const z = @abs(y);
591 try comptime std.testing.expectEqual(x, z);592 try comptime std.testing.expectEqual(x, z);
592}593}
593594
594test "@fabs f80" {595test "@abs f80" {
596 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO597 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
596 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO598 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
597 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO599 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -604,11 +606,12 @@ test "@fabs f80" {...@@ -604,11 +606,12 @@ test "@fabs f80" {
604606
605fn testFabsLegacy(comptime T: type, x: T) !void {607fn testFabsLegacy(comptime T: type, x: T) !void {
606 const y = -x;608 const y = -x;
607 const z = @fabs(y);609 const z = @abs(y);
608 try expect(x == z);610 try expect(x == z);
609}611}
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
612 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
614 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO617 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" {...@@ -617,23 +620,23 @@ test "a third @fabs test, surely there should not be three fabs tests" {
617620
618 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {621 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
619 // normals622 // normals
620 try expect(@fabs(@as(T, 1.0)) == 1.0);623 try expect(@abs(@as(T, 1.0)) == 1.0);
621 try expect(@fabs(@as(T, -1.0)) == 1.0);624 try expect(@abs(@as(T, -1.0)) == 1.0);
622 try expect(@fabs(math.floatMin(T)) == math.floatMin(T));625 try expect(@abs(math.floatMin(T)) == math.floatMin(T));
623 try expect(@fabs(-math.floatMin(T)) == math.floatMin(T));626 try expect(@abs(-math.floatMin(T)) == math.floatMin(T));
624 try expect(@fabs(math.floatMax(T)) == math.floatMax(T));627 try expect(@abs(math.floatMax(T)) == math.floatMax(T));
625 try expect(@fabs(-math.floatMax(T)) == math.floatMax(T));628 try expect(@abs(-math.floatMax(T)) == math.floatMax(T));
626629
627 // subnormals630 // subnormals
628 try expect(@fabs(@as(T, 0.0)) == 0.0);631 try expect(@abs(@as(T, 0.0)) == 0.0);
629 try expect(@fabs(@as(T, -0.0)) == 0.0);632 try expect(@abs(@as(T, -0.0)) == 0.0);
630 try expect(@fabs(math.floatTrueMin(T)) == math.floatTrueMin(T));633 try expect(@abs(math.floatTrueMin(T)) == math.floatTrueMin(T));
631 try expect(@fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T));634 try expect(@abs(-math.floatTrueMin(T)) == math.floatTrueMin(T));
632635
633 // non-finite numbers636 // non-finite numbers
634 try expect(math.isPositiveInf(@fabs(math.inf(T))));637 try expect(math.isPositiveInf(@abs(math.inf(T))));
635 try expect(math.isPositiveInf(@fabs(-math.inf(T))));638 try expect(math.isPositiveInf(@abs(-math.inf(T))));
636 try expect(math.isNan(@fabs(math.nan(T))));639 try expect(math.isNan(@abs(math.nan(T))));
637 }640 }
638}641}
639642
test/behavior/math.zig+3-3
...@@ -1391,7 +1391,7 @@ fn frem(comptime T: type) !void {...@@ -1391,7 +1391,7 @@ fn frem(comptime T: type) !void {
1391}1391}
13921392
1393fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {1393fn 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);
1395}1395}
13961396
1397test "float modulo division using @mod" {1397test "float modulo division using @mod" {
...@@ -1434,7 +1434,7 @@ fn fmod(comptime T: type) !void {...@@ -1434,7 +1434,7 @@ fn fmod(comptime T: type) !void {
1434}1434}
14351435
1436fn fmodOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {1436fn 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);
1438}1438}
14391439
1440test "@round" {1440test "@round" {
...@@ -1627,7 +1627,7 @@ fn testAbsFloat() !void {...@@ -1627,7 +1627,7 @@ fn testAbsFloat() !void {
1627 try testAbsFloatOne(10.05, 10.05);1627 try testAbsFloatOne(10.05, 10.05);
1628}1628}
1629fn testAbsFloatOne(in: f32, out: f32) !void {1629fn 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));
1631}1631}
16321632
1633test "mod lazy values" {1633test "mod lazy values" {