| author | |
| committer | |
| log | 937138cb90ae9327b0f7a932910c8d6080984f5c |
| tree | 458e4beacf025609f843d2db1188f5b9bd8488d5 |
| parent | ab3ac1e6701431ae7dea99b23852e36b369d6b87 |
| parent | 9763573ebb4f05eaa1c0bd5598f8dd6aee20ae9c |
| signature |
Replace @fabs builtin with new @abs builtin51 files changed, 937 insertions(+), 309 deletions(-)
doc/langref.html.in+7-4| ... | ... | @@ -9421,14 +9421,17 @@ fn doTheTest() !void { |
| 9421 | 9421 | Supports {#link|Floats#} and {#link|Vectors#} of floats. |
| 9422 | 9422 | </p> |
| 9423 | 9423 | {#header_close#} |
| 9424 | {#header_open|@fabs#} | |
| 9425 | <pre>{#syntax#}@fabs(value: anytype) @TypeOf(value){#endsyntax#}</pre> | |
| 9424 | {#header_open|@abs#} | |
| 9425 | <pre>{#syntax#}@abs(value: anytype) anytype{#endsyntax#}</pre> | |
| 9426 | 9426 | <p> |
| 9427 | Returns the absolute value of a floating point number. Uses a dedicated hardware instruction | |
| 9427 | Returns the absolute value of an integer or a floating point number. Uses a dedicated hardware instruction | |
| 9428 | 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 | 9432 | </p> |
| 9430 | 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 | 9435 | </p> |
| 9433 | 9436 | {#header_close#} |
| 9434 | 9437 | {#header_open|@floor#} |
lib/compiler_rt/divc3.zig+1-2| ... | ... | @@ -3,7 +3,6 @@ const isNan = std.math.isNan; |
| 3 | 3 | const isInf = std.math.isInf; |
| 4 | 4 | const scalbn = std.math.scalbn; |
| 5 | 5 | const ilogb = std.math.ilogb; |
| 6 | const fabs = std.math.fabs; | |
| 7 | 6 | const maxInt = std.math.maxInt; |
| 8 | 7 | const minInt = std.math.minInt; |
| 9 | 8 | const 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 | 15 | var d = d_in; |
| 17 | 16 | |
| 18 | 17 | // 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 | 19 | const logbw_finite = logbw != maxInt(i32) and logbw != minInt(i32); |
| 21 | 20 | const ilogbw = if (logbw_finite) b: { |
| 22 | 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 | 30 | const x_minus_eps: f80 = @bitCast((@as(u80, @bitCast(x)) - 1) | integerBit); |
| 31 | 31 | |
| 32 | 32 | // Make sure result is more accurate than the adjacent floats |
| 33 | const err_x = @fabs(@mulAdd(f80, x, b, -a)); | |
| 34 | const err_x_plus_eps = @fabs(@mulAdd(f80, x_plus_eps, b, -a)); | |
| 35 | const err_x_minus_eps = @fabs(@mulAdd(f80, x_minus_eps, b, -a)); | |
| 33 | const err_x = @abs(@mulAdd(f80, x, b, -a)); | |
| 34 | const err_x_plus_eps = @abs(@mulAdd(f80, x_plus_eps, b, -a)); | |
| 35 | const err_x_minus_eps = @abs(@mulAdd(f80, x_minus_eps, b, -a)); | |
| 36 | 36 | |
| 37 | 37 | try testing.expect(err_x_minus_eps > err_x); |
| 38 | 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 | 18 | const max_exp = exp_bias; |
| 19 | 19 | |
| 20 | 20 | // 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 | 22 | const sign_bit = if (x < 0) @as(uT, 1) << (float_bits - 1) else 0; |
| 23 | 23 | var result: uT = sign_bit; |
| 24 | 24 |
lib/std/Build/Step/ConfigHeader.zig+1-1| ... | ... | @@ -539,7 +539,7 @@ fn replace_variables( |
| 539 | 539 | .int => |i| { |
| 540 | 540 | const buf = try std.fmt.allocPrint(allocator, "{s}{}{s}", .{ beginline, i, endline }); |
| 541 | 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 | 543 | last_index = start_index + @intFromBool(isNegative) + digits + 1; |
| 544 | 544 | |
| 545 | 545 | allocator.free(content_buf); |
lib/std/dwarf/expressions.zig+1-1| ... | ... | @@ -520,7 +520,7 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 520 | 520 | if (self.stack.items.len == 0) return error.InvalidExpression; |
| 521 | 521 | const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral()); |
| 522 | 522 | self.stack.items[self.stack.items.len - 1] = .{ |
| 523 | .generic = std.math.absCast(value), | |
| 523 | .generic = @abs(value), | |
| 524 | 524 | }; |
| 525 | 525 | }, |
| 526 | 526 | OP.@"and" => { |
lib/std/fmt.zig+1-1| ... | ... | @@ -1413,7 +1413,7 @@ pub fn formatInt( |
| 1413 | 1413 | const min_int_bits = comptime @max(value_info.bits, 8); |
| 1414 | 1414 | const MinInt = std.meta.Int(.unsigned, min_int_bits); |
| 1415 | 1415 | |
| 1416 | const abs_value = math.absCast(int_value); | |
| 1416 | const abs_value = @abs(int_value); | |
| 1417 | 1417 | // The worst case in terms of space needed is base 2, plus 1 for the sign |
| 1418 | 1418 | var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined; |
| 1419 | 1419 |
lib/std/io/fixed_buffer_stream.zig+1-1| ... | ... | @@ -81,7 +81,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type { |
| 81 | 81 | |
| 82 | 82 | pub fn seekBy(self: *Self, amt: i64) SeekError!void { |
| 83 | 83 | if (amt < 0) { |
| 84 | const abs_amt = std.math.absCast(amt); | |
| 84 | const abs_amt = @abs(amt); | |
| 85 | 85 | const abs_amt_usize = std.math.cast(usize, abs_amt) orelse std.math.maxInt(usize); |
| 86 | 86 | if (abs_amt_usize > self.pos) { |
| 87 | 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 | 130 | if (isNan(x) or isNan(y)) |
| 131 | 131 | return false; |
| 132 | 132 | |
| 133 | return @fabs(x - y) <= tolerance; | |
| 133 | return @abs(x - y) <= tolerance; | |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | 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 | 158 | if (isNan(x) or isNan(y)) |
| 159 | 159 | return false; |
| 160 | 160 | |
| 161 | return @fabs(x - y) <= @max(@fabs(x), @fabs(y)) * tolerance; | |
| 161 | return @abs(x - y) <= @max(@abs(x), @abs(y)) * tolerance; | |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | 164 | test "approxEqAbs and approxEqRel" { |
| ... | ... | @@ -466,7 +466,7 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { |
| 466 | 466 | /// Shifts left. Overflowed bits are truncated. |
| 467 | 467 | /// A negative shift amount results in a right shift. |
| 468 | 468 | pub 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); | |
| 470 | 470 | |
| 471 | 471 | const casted_shift_amt = blk: { |
| 472 | 472 | if (@typeInfo(T) == .Vector) { |
| ... | ... | @@ -510,7 +510,7 @@ test "shl" { |
| 510 | 510 | /// Shifts right. Overflowed bits are truncated. |
| 511 | 511 | /// A negative shift amount results in a left shift. |
| 512 | 512 | pub 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); | |
| 514 | 514 | |
| 515 | 515 | const casted_shift_amt = blk: { |
| 516 | 516 | if (@typeInfo(T) == .Vector) { |
| ... | ... | @@ -740,52 +740,6 @@ fn testOverflow() !void { |
| 740 | 740 | try testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000); |
| 741 | 741 | } |
| 742 | 742 | |
| 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. | |
| 747 | pub 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 | ||
| 776 | test "absInt" { | |
| 777 | try testAbsInt(); | |
| 778 | try comptime testAbsInt(); | |
| 779 | } | |
| 780 | fn 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 | 743 | /// Divide numerator by denominator, rounding toward zero. Returns an |
| 790 | 744 | /// error on overflow or when denominator is zero. |
| 791 | 745 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { |
| ... | ... | @@ -968,50 +922,6 @@ fn testRem() !void { |
| 968 | 922 | try testing.expectError(error.DivisionByZero, rem(f32, 10, 0)); |
| 969 | 923 | } |
| 970 | 924 | |
| 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 | |
| 974 | pub 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. | |
| 981 | pub 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 | ||
| 1007 | test "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 | 925 | /// Returns the negation of the integer parameter. |
| 1016 | 926 | /// Result is a signed integer. |
| 1017 | 927 | pub 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 | 60 | } |
| 61 | 61 | |
| 62 | 62 | // 1 > |x| >= 0.5 |
| 63 | const z = (1 - @fabs(x)) * 0.5; | |
| 63 | const z = (1 - @abs(x)) * 0.5; | |
| 64 | 64 | const s = @sqrt(z); |
| 65 | 65 | const fx = pio2 - 2 * (s + s * r32(z)); |
| 66 | 66 | |
| ... | ... | @@ -119,7 +119,7 @@ fn asin64(x: f64) f64 { |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | 121 | // 1 > |x| >= 0.5 |
| 122 | const z = (1 - @fabs(x)) * 0.5; | |
| 122 | const z = (1 - @abs(x)) * 0.5; | |
| 123 | 123 | const s = @sqrt(z); |
| 124 | 124 | const r = r64(z); |
| 125 | 125 | var fx: f64 = undefined; |
lib/std/math/atan.zig+2-2| ... | ... | @@ -73,7 +73,7 @@ fn atan32(x_: f32) f32 { |
| 73 | 73 | } |
| 74 | 74 | id = null; |
| 75 | 75 | } else { |
| 76 | x = @fabs(x); | |
| 76 | x = @abs(x); | |
| 77 | 77 | // |x| < 1.1875 |
| 78 | 78 | if (ix < 0x3F980000) { |
| 79 | 79 | // 7/16 <= |x| < 11/16 |
| ... | ... | @@ -171,7 +171,7 @@ fn atan64(x_: f64) f64 { |
| 171 | 171 | } |
| 172 | 172 | id = null; |
| 173 | 173 | } else { |
| 174 | x = @fabs(x); | |
| 174 | x = @abs(x); | |
| 175 | 175 | // |x| < 1.1875 |
| 176 | 176 | if (ix < 0x3FF30000) { |
| 177 | 177 | // 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 | 108 | if ((m & 2) != 0 and iy + (26 << 23) < ix) { |
| 109 | 109 | break :z 0.0; |
| 110 | 110 | } else { |
| 111 | break :z math.atan(@fabs(y / x)); | |
| 111 | break :z math.atan(@abs(y / x)); | |
| 112 | 112 | } |
| 113 | 113 | }; |
| 114 | 114 | |
| ... | ... | @@ -198,7 +198,7 @@ fn atan2_64(y: f64, x: f64) f64 { |
| 198 | 198 | if ((m & 2) != 0 and iy +% (64 << 20) < ix) { |
| 199 | 199 | break :z 0.0; |
| 200 | 200 | } else { |
| 201 | break :z math.atan(@fabs(y / x)); | |
| 201 | break :z math.atan(@abs(y / x)); | |
| 202 | 202 | } |
| 203 | 203 | }; |
| 204 | 204 |
lib/std/math/big/int.zig+3-3| ... | ... | @@ -29,7 +29,7 @@ pub fn calcLimbLen(scalar: anytype) usize { |
| 29 | 29 | return 1; |
| 30 | 30 | } |
| 31 | 31 | |
| 32 | const w_value = std.math.absCast(scalar); | |
| 32 | const w_value = @abs(scalar); | |
| 33 | 33 | return @as(usize, @intCast(@divFloor(@as(Limb, @intCast(math.log2(w_value))), limb_bits) + 1)); |
| 34 | 34 | } |
| 35 | 35 | |
| ... | ... | @@ -240,7 +240,7 @@ pub const Mutable = struct { |
| 240 | 240 | |
| 241 | 241 | switch (@typeInfo(T)) { |
| 242 | 242 | .Int => |info| { |
| 243 | var w_value = std.math.absCast(value); | |
| 243 | var w_value = @abs(value); | |
| 244 | 244 | |
| 245 | 245 | if (info.bits <= limb_bits) { |
| 246 | 246 | self.limbs[0] = w_value; |
| ... | ... | @@ -255,7 +255,7 @@ pub const Mutable = struct { |
| 255 | 255 | } |
| 256 | 256 | }, |
| 257 | 257 | .ComptimeInt => { |
| 258 | comptime var w_value = std.math.absCast(value); | |
| 258 | comptime var w_value = @abs(value); | |
| 259 | 259 | |
| 260 | 260 | if (w_value <= maxInt(Limb)) { |
| 261 | 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 | 44 | // |x|>= 9, so cosh(x) ~= exp(|x|) |
| 45 | 45 | if (ix < 0x42b17218) { |
| 46 | 46 | // 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 | 48 | return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y)); |
| 49 | 49 | } |
| 50 | 50 | // x < 192.7: scale to avoid overflow |
| 51 | 51 | else if (ix < 0x4340b1e7) { |
| 52 | const v = Complex(f32).init(@fabs(x), y); | |
| 52 | const v = Complex(f32).init(@abs(x), y); | |
| 53 | 53 | const r = ldexp_cexp(v, -1); |
| 54 | 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 | 112 | // |x|>= 22, so cosh(x) ~= exp(|x|) |
| 113 | 113 | if (ix < 0x40862e42) { |
| 114 | 114 | // x < 710: exp(|x|) won't overflow |
| 115 | const h = @exp(@fabs(x)) * 0.5; | |
| 115 | const h = @exp(@abs(x)) * 0.5; | |
| 116 | 116 | return Complex(f64).init(h * @cos(y), math.copysign(h, x) * @sin(y)); |
| 117 | 117 | } |
| 118 | 118 | // x < 1455: scale to avoid overflow |
| 119 | 119 | else if (ix < 0x4096bbaa) { |
| 120 | const v = Complex(f64).init(@fabs(x), y); | |
| 120 | const v = Complex(f64).init(@abs(x), y); | |
| 121 | 121 | const r = ldexp_cexp(v, -1); |
| 122 | 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 | 44 | // |x|>= 9, so cosh(x) ~= exp(|x|) |
| 45 | 45 | if (ix < 0x42b17218) { |
| 46 | 46 | // 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 | 48 | return Complex(f32).init(math.copysign(h, x) * @cos(y), h * @sin(y)); |
| 49 | 49 | } |
| 50 | 50 | // x < 192.7: scale to avoid overflow |
| 51 | 51 | else if (ix < 0x4340b1e7) { |
| 52 | const v = Complex(f32).init(@fabs(x), y); | |
| 52 | const v = Complex(f32).init(@abs(x), y); | |
| 53 | 53 | const r = ldexp_cexp(v, -1); |
| 54 | 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 | 111 | // |x|>= 22, so cosh(x) ~= exp(|x|) |
| 112 | 112 | if (ix < 0x40862e42) { |
| 113 | 113 | // x < 710: exp(|x|) won't overflow |
| 114 | const h = @exp(@fabs(x)) * 0.5; | |
| 114 | const h = @exp(@abs(x)) * 0.5; | |
| 115 | 115 | return Complex(f64).init(math.copysign(h, x) * @cos(y), h * @sin(y)); |
| 116 | 116 | } |
| 117 | 117 | // x < 1455: scale to avoid overflow |
| 118 | 118 | else if (ix < 0x4096bbaa) { |
| 119 | const v = Complex(f64).init(@fabs(x), y); | |
| 119 | const v = Complex(f64).init(@abs(x), y); | |
| 120 | 120 | const r = ldexp_cexp(v, -1); |
| 121 | 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 | 43 | // sqrt(-inf + i nan) = nan +- inf i |
| 44 | 44 | // sqrt(-inf + iy) = 0 + inf i |
| 45 | 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 | 47 | } else { |
| 48 | 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 | 64 | } else { |
| 65 | 65 | const t = @sqrt((-dx + math.hypot(f64, dx, dy)) * 0.5); |
| 66 | 66 | return Complex(f32).init( |
| 67 | @as(f32, @floatCast(@fabs(y) / (2.0 * t))), | |
| 67 | @as(f32, @floatCast(@abs(y) / (2.0 * t))), | |
| 68 | 68 | @as(f32, @floatCast(math.copysign(t, y))), |
| 69 | 69 | ); |
| 70 | 70 | } |
| ... | ... | @@ -94,7 +94,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) { |
| 94 | 94 | // sqrt(-inf + i nan) = nan +- inf i |
| 95 | 95 | // sqrt(-inf + iy) = 0 + inf i |
| 96 | 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 | 98 | } else { |
| 99 | 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 | 104 | |
| 105 | 105 | // scale to avoid overflow |
| 106 | 106 | var scale = false; |
| 107 | if (@fabs(x) >= threshold or @fabs(y) >= threshold) { | |
| 107 | if (@abs(x) >= threshold or @abs(y) >= threshold) { | |
| 108 | 108 | x *= 0.25; |
| 109 | 109 | y *= 0.25; |
| 110 | 110 | scale = true; |
| ... | ... | @@ -116,7 +116,7 @@ fn sqrt64(z: Complex(f64)) Complex(f64) { |
| 116 | 116 | result = Complex(f64).init(t, y / (2.0 * t)); |
| 117 | 117 | } else { |
| 118 | 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 | } |
| 121 | 121 | |
| 122 | 122 | if (scale) { |
lib/std/math/complex/tanh.zig+2-2| ... | ... | @@ -44,7 +44,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) { |
| 44 | 44 | |
| 45 | 45 | // x >= 11 |
| 46 | 46 | if (ix >= 0x41300000) { |
| 47 | const exp_mx = @exp(-@fabs(x)); | |
| 47 | const exp_mx = @exp(-@abs(x)); | |
| 48 | 48 | return Complex(f32).init(math.copysign(@as(f32, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx); |
| 49 | 49 | } |
| 50 | 50 | |
| ... | ... | @@ -87,7 +87,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) { |
| 87 | 87 | |
| 88 | 88 | // x >= 22 |
| 89 | 89 | if (ix >= 0x40360000) { |
| 90 | const exp_mx = @exp(-@fabs(x)); | |
| 90 | const exp_mx = @exp(-@abs(x)); | |
| 91 | 91 | return Complex(f64).init(math.copysign(@as(f64, 1.0), x), 4 * @sin(y) * @cos(y) * exp_mx * exp_mx); |
| 92 | 92 | } |
| 93 | 93 |
lib/std/math/pow.zig+2-2| ... | ... | @@ -82,7 +82,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 82 | 82 | } |
| 83 | 83 | // pow(x, +inf) = +0 for |x| < 1 |
| 84 | 84 | // 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 | 86 | return 0; |
| 87 | 87 | } |
| 88 | 88 | // pow(x, -inf) = +inf for |x| < 1 |
| ... | ... | @@ -115,7 +115,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 115 | 115 | return 1 / @sqrt(x); |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | const r1 = math.modf(@fabs(y)); | |
| 118 | const r1 = math.modf(@abs(y)); | |
| 119 | 119 | var yi = r1.ipart; |
| 120 | 120 | var yf = r1.fpart; |
| 121 | 121 |
lib/std/meta.zig+2-2| ... | ... | @@ -1104,6 +1104,6 @@ pub fn isError(error_union: anytype) bool { |
| 1104 | 1104 | } |
| 1105 | 1105 | |
| 1106 | 1106 | test "isError" { |
| 1107 | try std.testing.expect(isError(math.absInt(@as(i8, -128)))); | |
| 1108 | try std.testing.expect(!isError(math.absInt(@as(i8, -127)))); | |
| 1107 | try std.testing.expect(isError(math.divTrunc(u8, 5, 0))); | |
| 1108 | try std.testing.expect(!isError(math.divTrunc(u8, 5, 5))); | |
| 1109 | 1109 | } |
lib/std/rand/ziggurat.zig+1-1| ... | ... | @@ -33,7 +33,7 @@ pub fn next_f64(random: Random, comptime tables: ZigTable) f64 { |
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | 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; | |
| 37 | 37 | |
| 38 | 38 | // equivalent to |u| < tables.x[i+1] / tables.x[i] (or u < tables.x[i+1] / tables.x[i]) |
| 39 | 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 | 88 | |
| 89 | 89 | // Standard C Library bug: The absolute value of the most negative integer remains negative. |
| 90 | 90 | pub 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 | } | |
| 93 | pub inline fn __builtin_labs(val: c_long) c_long { | |
| 94 | return if (val == std.math.minInt(c_long)) val else @intCast(@abs(val)); | |
| 95 | } | |
| 96 | pub 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 | } |
| 93 | 99 | pub inline fn __builtin_fabs(val: f64) f64 { |
| 94 | return @fabs(val); | |
| 100 | return @abs(val); | |
| 95 | 101 | } |
| 96 | 102 | pub inline fn __builtin_fabsf(val: f32) f32 { |
| 97 | return @fabs(val); | |
| 103 | return @abs(val); | |
| 98 | 104 | } |
| 99 | 105 | |
| 100 | 106 | pub inline fn __builtin_floor(val: f64) f64 { |
lib/std/zig/render.zig+2| ... | ... | @@ -1503,6 +1503,8 @@ fn renderBuiltinCall( |
| 1503 | 1503 | try ais.writer().writeAll("@ptrFromInt"); |
| 1504 | 1504 | } else if (mem.eql(u8, slice, "@ptrToInt")) { |
| 1505 | 1505 | try ais.writer().writeAll("@intFromPtr"); |
| 1506 | } else if (mem.eql(u8, slice, "@fabs")) { | |
| 1507 | try ais.writer().writeAll("@abs"); | |
| 1506 | 1508 | } else { |
| 1507 | 1509 | try renderToken(ais, tree, builtin_token, .none); // @name |
| 1508 | 1510 | } |
lib/zig.h+41| ... | ... | @@ -946,6 +946,24 @@ typedef unsigned long zig_Builtin64; |
| 946 | 946 | typedef unsigned long long zig_Builtin64; |
| 947 | 947 | #endif |
| 948 | 948 | |
| 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 | ||
| 949 | 967 | static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) { |
| 950 | 968 | return zig_wrap_u8(val >> (8 - bits), bits); |
| 951 | 969 | } |
| ... | ... | @@ -1141,6 +1159,24 @@ zig_builtin_clz(16) |
| 1141 | 1159 | zig_builtin_clz(32) |
| 1142 | 1160 | zig_builtin_clz(64) |
| 1143 | 1161 | |
| 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 | |
| 1175 | zig_builtin_abs(8) | |
| 1176 | zig_builtin_abs(16) | |
| 1177 | zig_builtin_abs(32) | |
| 1178 | zig_builtin_abs(64) | |
| 1179 | ||
| 1144 | 1180 | /* ======================== 128-bit Integer Support ========================= */ |
| 1145 | 1181 | |
| 1146 | 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 | 1502 | return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); |
| 1467 | 1503 | } |
| 1468 | 1504 | |
| 1505 | static 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 | 1510 | #if zig_has_int128 |
| 1470 | 1511 | |
| 1471 | 1512 | static 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 | 356 | /// Base 10 logarithm of a floating point number. |
| 357 | 357 | /// Uses the `un_op` field. |
| 358 | 358 | log10, |
| 359 | /// Aboslute value of a floating point number. | |
| 360 | /// Uses the `un_op` field. | |
| 361 | fabs, | |
| 359 | /// Aboslute value of an integer, floating point number or vector. | |
| 360 | /// Result type is always unsigned if the operand is an integer. | |
| 361 | /// Uses the `ty_op` field. | |
| 362 | abs, | |
| 362 | 363 | /// Floor: rounds a floating pointer number down to the nearest integer. |
| 363 | 364 | /// Uses the `un_op` field. |
| 364 | 365 | floor, |
| ... | ... | @@ -1279,7 +1280,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) |
| 1279 | 1280 | .log, |
| 1280 | 1281 | .log2, |
| 1281 | 1282 | .log10, |
| 1282 | .fabs, | |
| 1283 | 1283 | .floor, |
| 1284 | 1284 | .ceil, |
| 1285 | 1285 | .round, |
| ... | ... | @@ -1384,6 +1384,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) |
| 1384 | 1384 | .addrspace_cast, |
| 1385 | 1385 | .c_va_arg, |
| 1386 | 1386 | .c_va_copy, |
| 1387 | .abs, | |
| 1387 | 1388 | => return air.getRefType(datas[inst].ty_op.ty), |
| 1388 | 1389 | |
| 1389 | 1390 | .loop, |
| ... | ... | @@ -1697,7 +1698,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { |
| 1697 | 1698 | .log, |
| 1698 | 1699 | .log2, |
| 1699 | 1700 | .log10, |
| 1700 | .fabs, | |
| 1701 | .abs, | |
| 1701 | 1702 | .floor, |
| 1702 | 1703 | .ceil, |
| 1703 | 1704 | .round, |
src/AstGen.zig+2-2| ... | ... | @@ -2601,7 +2601,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2601 | 2601 | .log, |
| 2602 | 2602 | .log2, |
| 2603 | 2603 | .log10, |
| 2604 | .fabs, | |
| 2604 | .abs, | |
| 2605 | 2605 | .floor, |
| 2606 | 2606 | .ceil, |
| 2607 | 2607 | .trunc, |
| ... | ... | @@ -8385,7 +8385,7 @@ fn builtinCall( |
| 8385 | 8385 | .log => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log), |
| 8386 | 8386 | .log2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log2), |
| 8387 | 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 | 8389 | .floor => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .floor), |
| 8390 | 8390 | .ceil => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ceil), |
| 8391 | 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 | 929 | .log, |
| 930 | 930 | .log2, |
| 931 | 931 | .log10, |
| 932 | .fabs, | |
| 932 | .abs, | |
| 933 | 933 | .floor, |
| 934 | 934 | .ceil, |
| 935 | 935 | .trunc, |
src/Autodoc.zig+1-1| ... | ... | @@ -1669,7 +1669,7 @@ fn walkInstruction( |
| 1669 | 1669 | .log, |
| 1670 | 1670 | .log2, |
| 1671 | 1671 | .log10, |
| 1672 | .fabs, | |
| 1672 | .abs, | |
| 1673 | 1673 | .floor, |
| 1674 | 1674 | .ceil, |
| 1675 | 1675 | .trunc, |
src/BuiltinFn.zig+3-3| ... | ... | @@ -102,7 +102,7 @@ pub const Tag = enum { |
| 102 | 102 | log, |
| 103 | 103 | log2, |
| 104 | 104 | log10, |
| 105 | fabs, | |
| 105 | abs, | |
| 106 | 106 | floor, |
| 107 | 107 | ceil, |
| 108 | 108 | trunc, |
| ... | ... | @@ -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 | 880 | .param_count = 1, |
| 881 | 881 | }, |
| 882 | 882 | }, |
src/Liveness.zig+2-2| ... | ... | @@ -384,6 +384,7 @@ pub fn categorizeOperand( |
| 384 | 384 | .addrspace_cast, |
| 385 | 385 | .c_va_arg, |
| 386 | 386 | .c_va_copy, |
| 387 | .abs, | |
| 387 | 388 | => { |
| 388 | 389 | const o = air_datas[inst].ty_op; |
| 389 | 390 | if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); |
| ... | ... | @@ -420,7 +421,6 @@ pub fn categorizeOperand( |
| 420 | 421 | .log, |
| 421 | 422 | .log2, |
| 422 | 423 | .log10, |
| 423 | .fabs, | |
| 424 | 424 | .floor, |
| 425 | 425 | .ceil, |
| 426 | 426 | .round, |
| ... | ... | @@ -1027,6 +1027,7 @@ fn analyzeInst( |
| 1027 | 1027 | .addrspace_cast, |
| 1028 | 1028 | .c_va_arg, |
| 1029 | 1029 | .c_va_copy, |
| 1030 | .abs, | |
| 1030 | 1031 | => { |
| 1031 | 1032 | const o = inst_datas[inst].ty_op; |
| 1032 | 1033 | return analyzeOperands(a, pass, data, inst, .{ o.operand, .none, .none }); |
| ... | ... | @@ -1054,7 +1055,6 @@ fn analyzeInst( |
| 1054 | 1055 | .log, |
| 1055 | 1056 | .log2, |
| 1056 | 1057 | .log10, |
| 1057 | .fabs, | |
| 1058 | 1058 | .floor, |
| 1059 | 1059 | .ceil, |
| 1060 | 1060 | .round, |
src/Liveness/Verify.zig+1-1| ... | ... | @@ -110,6 +110,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 110 | 110 | .addrspace_cast, |
| 111 | 111 | .c_va_arg, |
| 112 | 112 | .c_va_copy, |
| 113 | .abs, | |
| 113 | 114 | => { |
| 114 | 115 | const ty_op = data[inst].ty_op; |
| 115 | 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 | 137 | .log, |
| 137 | 138 | .log2, |
| 138 | 139 | .log10, |
| 139 | .fabs, | |
| 140 | 140 | .floor, |
| 141 | 141 | .ceil, |
| 142 | 142 | .round, |
src/Sema.zig+77-50| ... | ... | @@ -1156,6 +1156,7 @@ fn analyzeBodyInner( |
| 1156 | 1156 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), |
| 1157 | 1157 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), |
| 1158 | 1158 | .pop_count => try sema.zirBitCount(block, inst, .popcount, Value.popCount), |
| 1159 | .abs => try sema.zirAbs(block, inst), | |
| 1159 | 1160 | |
| 1160 | 1161 | .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt), |
| 1161 | 1162 | .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin), |
| ... | ... | @@ -1166,7 +1167,6 @@ fn analyzeBodyInner( |
| 1166 | 1167 | .log => try sema.zirUnaryMath(block, inst, .log, Value.log), |
| 1167 | 1168 | .log2 => try sema.zirUnaryMath(block, inst, .log2, Value.log2), |
| 1168 | 1169 | .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10), |
| 1169 | .fabs => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs), | |
| 1170 | 1170 | .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor), |
| 1171 | 1171 | .ceil => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil), |
| 1172 | 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 | 20178 | return block.addUnOp(.error_name, operand); |
| 20179 | 20179 | } |
| 20180 | 20180 | |
| 20181 | fn 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 | ||
| 20210 | fn 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 | ||
| 20181 | 20244 | fn zirUnaryMath( |
| 20182 | 20245 | sema: *Sema, |
| 20183 | 20246 | block: *Block, |
| ... | ... | @@ -20193,58 +20256,22 @@ fn zirUnaryMath( |
| 20193 | 20256 | const operand = try sema.resolveInst(inst_data.operand); |
| 20194 | 20257 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20195 | 20258 | const operand_ty = sema.typeOf(operand); |
| 20259 | const scalar_ty = operand_ty.scalarType(mod); | |
| 20196 | 20260 | |
| 20197 | switch (operand_ty.zigTypeTag(mod)) { | |
| 20261 | switch (scalar_ty.zigTypeTag(mod)) { | |
| 20198 | 20262 | .ComptimeFloat, .Float => {}, |
| 20199 | .Vector => { | |
| 20200 | const scalar_ty = operand_ty.scalarType(mod); | |
| 20201 | switch (scalar_ty.zigTypeTag(mod)) { | |
| 20202 | .ComptimeFloat, .Float => {}, | |
| 20203 | else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}), | |
| 20204 | } | |
| 20205 | }, | |
| 20206 | else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}), | |
| 20263 | else => return sema.fail( | |
| 20264 | block, | |
| 20265 | operand_src, | |
| 20266 | "expected vector of floats or float type, found '{}'", | |
| 20267 | .{operand_ty.fmt(sema.mod)}, | |
| 20268 | ), | |
| 20207 | 20269 | } |
| 20208 | 20270 | |
| 20209 | switch (operand_ty.zigTypeTag(mod)) { | |
| 20210 | .Vector => { | |
| 20211 | const scalar_ty = operand_ty.scalarType(mod); | |
| 20212 | const vec_len = operand_ty.vectorLen(mod); | |
| 20213 | const result_ty = try mod.vectorType(.{ | |
| 20214 | .len = vec_len, | |
| 20215 | .child = scalar_ty.toIntern(), | |
| 20216 | }); | |
| 20217 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | |
| 20218 | if (val.isUndef(mod)) | |
| 20219 | return mod.undefRef(result_ty); | |
| 20220 | ||
| 20221 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); | |
| 20222 | for (elems, 0..) |*elem, i| { | |
| 20223 | const elem_val = try val.elemValue(sema.mod, i); | |
| 20224 | elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod); | |
| 20225 | } | |
| 20226 | return Air.internedToRef((try mod.intern(.{ .aggregate = .{ | |
| 20227 | .ty = result_ty.toIntern(), | |
| 20228 | .storage = .{ .elems = elems }, | |
| 20229 | } }))); | |
| 20230 | } | |
| 20231 | ||
| 20232 | try sema.requireRuntimeBlock(block, operand_src, null); | |
| 20233 | return block.addUnOp(air_tag, operand); | |
| 20234 | }, | |
| 20235 | .ComptimeFloat, .Float => { | |
| 20236 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | |
| 20237 | if (operand_val.isUndef(mod)) | |
| 20238 | return mod.undefRef(operand_ty); | |
| 20239 | const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod); | |
| 20240 | return Air.internedToRef(result_val.toIntern()); | |
| 20241 | } | |
| 20242 | ||
| 20243 | try sema.requireRuntimeBlock(block, operand_src, null); | |
| 20244 | return block.addUnOp(air_tag, operand); | |
| 20245 | }, | |
| 20246 | else => unreachable, | |
| 20247 | } | |
| 20271 | return (try sema.maybeConstantUnaryMath(operand, operand_ty, eval)) orelse { | |
| 20272 | try sema.requireRuntimeBlock(block, operand_src, null); | |
| 20273 | return block.addUnOp(air_tag, operand); | |
| 20274 | }; | |
| 20248 | 20275 | } |
| 20249 | 20276 | |
| 20250 | 20277 | fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -37503,7 +37530,7 @@ fn float128IntPartToBigInt( |
| 37503 | 37530 | float: f128, |
| 37504 | 37531 | ) !std.math.big.int.Managed { |
| 37505 | 37532 | const is_negative = std.math.signbit(float); |
| 37506 | const floored = @floor(@fabs(float)); | |
| 37533 | const floored = @floor(@abs(float)); | |
| 37507 | 37534 | |
| 37508 | 37535 | var rational = try std.math.big.Rational.init(arena); |
| 37509 | 37536 | defer rational.q.deinit(); |
src/Zir.zig+5-5| ... | ... | @@ -846,8 +846,8 @@ pub const Inst = struct { |
| 846 | 846 | log2, |
| 847 | 847 | /// Implement builtin `@log10`. Uses `un_node`. |
| 848 | 848 | log10, |
| 849 | /// Implement builtin `@fabs`. Uses `un_node`. | |
| 850 | fabs, | |
| 849 | /// Implement builtin `@abs`. Uses `un_node`. | |
| 850 | abs, | |
| 851 | 851 | /// Implement builtin `@floor`. Uses `un_node`. |
| 852 | 852 | floor, |
| 853 | 853 | /// Implement builtin `@ceil`. Uses `un_node`. |
| ... | ... | @@ -1198,7 +1198,7 @@ pub const Inst = struct { |
| 1198 | 1198 | .log, |
| 1199 | 1199 | .log2, |
| 1200 | 1200 | .log10, |
| 1201 | .fabs, | |
| 1201 | .abs, | |
| 1202 | 1202 | .floor, |
| 1203 | 1203 | .ceil, |
| 1204 | 1204 | .trunc, |
| ... | ... | @@ -1493,7 +1493,7 @@ pub const Inst = struct { |
| 1493 | 1493 | .log, |
| 1494 | 1494 | .log2, |
| 1495 | 1495 | .log10, |
| 1496 | .fabs, | |
| 1496 | .abs, | |
| 1497 | 1497 | .floor, |
| 1498 | 1498 | .ceil, |
| 1499 | 1499 | .trunc, |
| ... | ... | @@ -1756,7 +1756,7 @@ pub const Inst = struct { |
| 1756 | 1756 | .log = .un_node, |
| 1757 | 1757 | .log2 = .un_node, |
| 1758 | 1758 | .log10 = .un_node, |
| 1759 | .fabs = .un_node, | |
| 1759 | .abs = .un_node, | |
| 1760 | 1760 | .floor = .un_node, |
| 1761 | 1761 | .ceil = .un_node, |
| 1762 | 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 | 713 | .log, |
| 714 | 714 | .log2, |
| 715 | 715 | .log10, |
| 716 | .fabs, | |
| 717 | 716 | .floor, |
| 718 | 717 | .ceil, |
| 719 | 718 | .round, |
| ... | ... | @@ -788,6 +787,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 788 | 787 | .clz => try self.airClz(inst), |
| 789 | 788 | .ctz => try self.airCtz(inst), |
| 790 | 789 | .popcount => try self.airPopcount(inst), |
| 790 | .abs => try self.airAbs(inst), | |
| 791 | 791 | .byte_swap => try self.airByteSwap(inst), |
| 792 | 792 | .bit_reverse => try self.airBitReverse(inst), |
| 793 | 793 | .tag_name => try self.airTagName(inst), |
| ... | ... | @@ -3550,6 +3550,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 3550 | 3550 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3551 | 3551 | } |
| 3552 | 3552 | |
| 3553 | fn 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 | ||
| 3553 | 3559 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 3554 | 3560 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3555 | 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 | 699 | .log, |
| 700 | 700 | .log2, |
| 701 | 701 | .log10, |
| 702 | .fabs, | |
| 703 | 702 | .floor, |
| 704 | 703 | .ceil, |
| 705 | 704 | .round, |
| ... | ... | @@ -774,6 +773,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 774 | 773 | .clz => try self.airClz(inst), |
| 775 | 774 | .ctz => try self.airCtz(inst), |
| 776 | 775 | .popcount => try self.airPopcount(inst), |
| 776 | .abs => try self.airAbs(inst), | |
| 777 | 777 | .byte_swap => try self.airByteSwap(inst), |
| 778 | 778 | .bit_reverse => try self.airBitReverse(inst), |
| 779 | 779 | .tag_name => try self.airTagName(inst), |
| ... | ... | @@ -2591,6 +2591,13 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 2591 | 2591 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2592 | 2592 | } |
| 2593 | 2593 | |
| 2594 | fn 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 | ||
| 2594 | 2601 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 2595 | 2602 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2596 | 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 | 523 | .log, |
| 524 | 524 | .log2, |
| 525 | 525 | .log10, |
| 526 | .fabs, | |
| 527 | 526 | .floor, |
| 528 | 527 | .ceil, |
| 529 | 528 | .round, |
| ... | ... | @@ -607,6 +606,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 607 | 606 | .clz => try self.airClz(inst), |
| 608 | 607 | .ctz => try self.airCtz(inst), |
| 609 | 608 | .popcount => try self.airPopcount(inst), |
| 609 | .abs => try self.airAbs(inst), | |
| 610 | 610 | .byte_swap => try self.airByteSwap(inst), |
| 611 | 611 | .bit_reverse => try self.airBitReverse(inst), |
| 612 | 612 | .tag_name => try self.airTagName(inst), |
| ... | ... | @@ -1447,6 +1447,12 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 1447 | 1447 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1448 | 1448 | } |
| 1449 | 1449 | |
| 1450 | fn 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 | ||
| 1450 | 1456 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 1451 | 1457 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1452 | 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 | 543 | .log, |
| 544 | 544 | .log2, |
| 545 | 545 | .log10, |
| 546 | .fabs, | |
| 546 | .abs, | |
| 547 | 547 | .floor, |
| 548 | 548 | .ceil, |
| 549 | 549 | .round, |
src/arch/wasm/CodeGen.zig+78-1| ... | ... | @@ -1866,13 +1866,14 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1866 | 1866 | .log => func.airUnaryFloatOp(inst, .log), |
| 1867 | 1867 | .log2 => func.airUnaryFloatOp(inst, .log2), |
| 1868 | 1868 | .log10 => func.airUnaryFloatOp(inst, .log10), |
| 1869 | .fabs => func.airUnaryFloatOp(inst, .fabs), | |
| 1870 | 1869 | .floor => func.airUnaryFloatOp(inst, .floor), |
| 1871 | 1870 | .ceil => func.airUnaryFloatOp(inst, .ceil), |
| 1872 | 1871 | .round => func.airUnaryFloatOp(inst, .round), |
| 1873 | 1872 | .trunc_float => func.airUnaryFloatOp(inst, .trunc), |
| 1874 | 1873 | .neg => func.airUnaryFloatOp(inst, .neg), |
| 1875 | 1874 | |
| 1875 | .abs => func.airAbs(inst), | |
| 1876 | ||
| 1876 | 1877 | .add_with_overflow => func.airAddSubWithOverflow(inst, .add), |
| 1877 | 1878 | .sub_with_overflow => func.airAddSubWithOverflow(inst, .sub), |
| 1878 | 1879 | .shl_with_overflow => func.airShlWithOverflow(inst), |
| ... | ... | @@ -2786,6 +2787,82 @@ const FloatOp = enum { |
| 2786 | 2787 | } |
| 2787 | 2788 | }; |
| 2788 | 2789 | |
| 2790 | fn 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 | ||
| 2789 | 2866 | fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void { |
| 2790 | 2867 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 2791 | 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 | 1809 | .round, |
| 1810 | 1810 | => try self.airUnaryMath(inst), |
| 1811 | 1811 | |
| 1812 | .floor => try self.airRound(inst, 0b1_0_01), | |
| 1813 | .ceil => try self.airRound(inst, 0b1_0_10), | |
| 1812 | .floor => try self.airRound(inst, 0b1_0_01), | |
| 1813 | .ceil => try self.airRound(inst, 0b1_0_10), | |
| 1814 | 1814 | .trunc_float => try self.airRound(inst, 0b1_0_11), |
| 1815 | .sqrt => try self.airSqrt(inst), | |
| 1816 | .neg, .fabs => try self.airFloatSign(inst), | |
| 1815 | .sqrt => try self.airSqrt(inst), | |
| 1816 | .neg => try self.airFloatSign(inst), | |
| 1817 | ||
| 1818 | .abs => try self.airAbs(inst), | |
| 1817 | 1819 | |
| 1818 | 1820 | .add_with_overflow => try self.airAddSubWithOverflow(inst), |
| 1819 | 1821 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), |
| ... | ... | @@ -4885,28 +4887,26 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 4885 | 4887 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 4886 | 4888 | } |
| 4887 | 4889 | |
| 4888 | fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { | |
| 4890 | fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void { | |
| 4889 | 4891 | const mod = self.bin_file.options.module.?; |
| 4890 | 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 | 4893 | const abi_size: u32 = switch (ty.abiSize(mod)) { |
| 4894 | 4894 | 1...16 => 16, |
| 4895 | 4895 | 17...32 => 32, |
| 4896 | else => return self.fail("TODO implement airFloatSign for {}", .{ | |
| 4896 | else => return self.fail("TODO implement floatSign for {}", .{ | |
| 4897 | 4897 | ty.fmt(mod), |
| 4898 | 4898 | }), |
| 4899 | 4899 | }; |
| 4900 | 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 | 4902 | ty.fmt(mod), |
| 4903 | 4903 | }); |
| 4904 | 4904 | |
| 4905 | const src_mcv = try self.resolveInst(un_op); | |
| 4905 | const src_mcv = try self.resolveInst(operand); | |
| 4906 | 4906 | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 4907 | 4907 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 4908 | 4908 | |
| 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 | 4910 | src_mcv |
| 4911 | 4911 | else if (self.hasFeature(.avx)) |
| 4912 | 4912 | .{ .register = try self.register_manager.allocReg(inst, sse) } |
| ... | ... | @@ -4923,7 +4923,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4923 | 4923 | |
| 4924 | 4924 | const sign_val = switch (tag) { |
| 4925 | 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 | 4927 | else => unreachable, |
| 4928 | 4928 | }; |
| 4929 | 4929 | |
| ... | ... | @@ -4939,24 +4939,24 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4939 | 4939 | switch (scalar_bits) { |
| 4940 | 4940 | 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) { |
| 4941 | 4941 | .neg => .{ .vp_, .xor }, |
| 4942 | .fabs => .{ .vp_, .@"and" }, | |
| 4942 | .abs => .{ .vp_, .@"and" }, | |
| 4943 | 4943 | else => unreachable, |
| 4944 | 4944 | } else switch (tag) { |
| 4945 | 4945 | .neg => .{ .v_ps, .xor }, |
| 4946 | .fabs => .{ .v_ps, .@"and" }, | |
| 4946 | .abs => .{ .v_ps, .@"and" }, | |
| 4947 | 4947 | else => unreachable, |
| 4948 | 4948 | }, |
| 4949 | 4949 | 32 => switch (tag) { |
| 4950 | 4950 | .neg => .{ .v_ps, .xor }, |
| 4951 | .fabs => .{ .v_ps, .@"and" }, | |
| 4951 | .abs => .{ .v_ps, .@"and" }, | |
| 4952 | 4952 | else => unreachable, |
| 4953 | 4953 | }, |
| 4954 | 4954 | 64 => switch (tag) { |
| 4955 | 4955 | .neg => .{ .v_pd, .xor }, |
| 4956 | .fabs => .{ .v_pd, .@"and" }, | |
| 4956 | .abs => .{ .v_pd, .@"and" }, | |
| 4957 | 4957 | else => unreachable, |
| 4958 | 4958 | }, |
| 4959 | 80 => return self.fail("TODO implement airFloatSign for {}", .{ | |
| 4959 | 80 => return self.fail("TODO implement floatSign for {}", .{ | |
| 4960 | 4960 | ty.fmt(self.bin_file.options.module.?), |
| 4961 | 4961 | }), |
| 4962 | 4962 | else => unreachable, |
| ... | ... | @@ -4971,20 +4971,20 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4971 | 4971 | switch (scalar_bits) { |
| 4972 | 4972 | 16, 128 => switch (tag) { |
| 4973 | 4973 | .neg => .{ .p_, .xor }, |
| 4974 | .fabs => .{ .p_, .@"and" }, | |
| 4974 | .abs => .{ .p_, .@"and" }, | |
| 4975 | 4975 | else => unreachable, |
| 4976 | 4976 | }, |
| 4977 | 4977 | 32 => switch (tag) { |
| 4978 | 4978 | .neg => .{ ._ps, .xor }, |
| 4979 | .fabs => .{ ._ps, .@"and" }, | |
| 4979 | .abs => .{ ._ps, .@"and" }, | |
| 4980 | 4980 | else => unreachable, |
| 4981 | 4981 | }, |
| 4982 | 4982 | 64 => switch (tag) { |
| 4983 | 4983 | .neg => .{ ._pd, .xor }, |
| 4984 | .fabs => .{ ._pd, .@"and" }, | |
| 4984 | .abs => .{ ._pd, .@"and" }, | |
| 4985 | 4985 | else => unreachable, |
| 4986 | 4986 | }, |
| 4987 | 80 => return self.fail("TODO implement airFloatSign for {}", .{ | |
| 4987 | 80 => return self.fail("TODO implement floatSign for {}", .{ | |
| 4988 | 4988 | ty.fmt(self.bin_file.options.module.?), |
| 4989 | 4989 | }), |
| 4990 | 4990 | else => unreachable, |
| ... | ... | @@ -4992,7 +4992,14 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4992 | 4992 | registerAlias(dst_reg, abi_size), |
| 4993 | 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 | ||
| 4998 | fn 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 | } |
| 4997 | 5004 | |
| 4998 | 5005 | fn 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 | 5089 | } |
| 5083 | 5090 | } |
| 5084 | 5091 | |
| 5092 | fn 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 | ||
| 5085 | 5138 | fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5086 | 5139 | const mod = self.bin_file.options.module.?; |
| 5087 | 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 | 105 | try writer.print("{s} ptr [rip", .{@tagName(rip.ptr_size)}); |
| 106 | 106 | if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{ |
| 107 | 107 | @as(u8, if (rip.disp < 0) '-' else '+'), |
| 108 | std.math.absCast(rip.disp), | |
| 108 | @abs(rip.disp), | |
| 109 | 109 | }); |
| 110 | 110 | try writer.writeByte(']'); |
| 111 | 111 | }, |
| ... | ... | @@ -140,7 +140,7 @@ pub const Instruction = struct { |
| 140 | 140 | try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')}) |
| 141 | 141 | else if (sib.disp < 0) |
| 142 | 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 | 144 | any = true; |
| 145 | 145 | } |
| 146 | 146 |
src/codegen/c.zig+32-10| ... | ... | @@ -2912,6 +2912,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2912 | 2912 | }, |
| 2913 | 2913 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none), |
| 2914 | 2914 | .mod => try airBinBuiltinCall(f, inst, "mod", .none), |
| 2915 | .abs => try airAbs(f, inst), | |
| 2915 | 2916 | |
| 2916 | 2917 | .add_wrap => try airBinBuiltinCall(f, inst, "addw", .bits), |
| 2917 | 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 | 2932 | .log => try airUnFloatOp(f, inst, "log"), |
| 2932 | 2933 | .log2 => try airUnFloatOp(f, inst, "log2"), |
| 2933 | 2934 | .log10 => try airUnFloatOp(f, inst, "log10"), |
| 2934 | .fabs => try airUnFloatOp(f, inst, "fabs"), | |
| 2935 | 2935 | .floor => try airUnFloatOp(f, inst, "floor"), |
| 2936 | 2936 | .ceil => try airUnFloatOp(f, inst, "ceil"), |
| 2937 | 2937 | .round => try airUnFloatOp(f, inst, "round"), |
| ... | ... | @@ -7076,23 +7076,35 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7076 | 7076 | return local; |
| 7077 | 7077 | } |
| 7078 | 7078 | |
| 7079 | fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { | |
| 7079 | fn airAbs(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 7080 | 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); | |
| 7082 | 7085 | |
| 7083 | const operand = try f.resolveInst(un_op); | |
| 7084 | try reap(f, inst, &.{un_op}); | |
| 7086 | switch (scalar_ty.zigTypeTag(mod)) { | |
| 7087 | .Int => if (ty.zigTypeTag(mod) == .Vector) { | |
| 7088 | return f.fail("TODO implement airAbs for '{}'", .{ty.fmt(mod)}); | |
| 7089 | } else { | |
| 7090 | return airUnBuiltinCall(f, inst, "abs", .none); | |
| 7091 | }, | |
| 7092 | .Float => return unFloatOp(f, inst, operand, ty, "fabs"), | |
| 7093 | else => unreachable, | |
| 7094 | } | |
| 7095 | } | |
| 7085 | 7096 | |
| 7086 | const inst_ty = f.typeOfIndex(inst); | |
| 7087 | const inst_scalar_ty = inst_ty.scalarType(mod); | |
| 7097 | fn unFloatOp(f: *Function, inst: Air.Inst.Index, operand: CValue, ty: Type, operation: []const u8) !CValue { | |
| 7098 | const mod = f.object.dg.module; | |
| 7099 | const scalar_ty = ty.scalarType(mod); | |
| 7088 | 7100 | |
| 7089 | 7101 | const writer = f.object.writer(); |
| 7090 | const local = try f.allocLocal(inst, inst_ty); | |
| 7091 | const v = try Vectorize.start(f, inst, writer, inst_ty); | |
| 7102 | const local = try f.allocLocal(inst, ty); | |
| 7103 | const v = try Vectorize.start(f, inst, writer, ty); | |
| 7092 | 7104 | try f.writeCValue(writer, local, .Other); |
| 7093 | 7105 | try v.elem(f, writer); |
| 7094 | 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 | 7108 | try writer.writeByte('('); |
| 7097 | 7109 | try writer.writeAll(operation); |
| 7098 | 7110 | try writer.writeAll(")("); |
| ... | ... | @@ -7104,6 +7116,16 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal |
| 7104 | 7116 | return local; |
| 7105 | 7117 | } |
| 7106 | 7118 | |
| 7119 | fn 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 | ||
| 7107 | 7129 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 7108 | 7130 | const mod = f.object.dg.module; |
| 7109 | 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 | 4729 | .div_exact => try self.airDivExact(inst, .normal), |
| 4730 | 4730 | .rem => try self.airRem(inst, .normal), |
| 4731 | 4731 | .mod => try self.airMod(inst, .normal), |
| 4732 | .abs => try self.airAbs(inst), | |
| 4732 | 4733 | .ptr_add => try self.airPtrAdd(inst), |
| 4733 | 4734 | .ptr_sub => try self.airPtrSub(inst), |
| 4734 | 4735 | .shl => try self.airShl(inst), |
| ... | ... | @@ -4766,7 +4767,6 @@ pub const FuncGen = struct { |
| 4766 | 4767 | .log => try self.airUnaryOp(inst, .log), |
| 4767 | 4768 | .log2 => try self.airUnaryOp(inst, .log2), |
| 4768 | 4769 | .log10 => try self.airUnaryOp(inst, .log10), |
| 4769 | .fabs => try self.airUnaryOp(inst, .fabs), | |
| 4770 | 4770 | .floor => try self.airUnaryOp(inst, .floor), |
| 4771 | 4771 | .ceil => try self.airUnaryOp(inst, .ceil), |
| 4772 | 4772 | .round => try self.airUnaryOp(inst, .round), |
| ... | ... | @@ -8237,6 +8237,28 @@ pub const FuncGen = struct { |
| 8237 | 8237 | else if (is_signed_int) .ashr else .lshr, lhs, casted_rhs, ""); |
| 8238 | 8238 | } |
| 8239 | 8239 | |
| 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 | 8262 | fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 8241 | 8263 | const o = self.dg.object; |
| 8242 | 8264 | const mod = o.module; |
src/print_air.zig+1-1| ... | ... | @@ -188,7 +188,7 @@ const Writer = struct { |
| 188 | 188 | .log, |
| 189 | 189 | .log2, |
| 190 | 190 | .log10, |
| 191 | .fabs, | |
| 191 | .abs, | |
| 192 | 192 | .floor, |
| 193 | 193 | .ceil, |
| 194 | 194 | .round, |
src/print_zir.zig+1-1| ... | ... | @@ -262,7 +262,7 @@ const Writer = struct { |
| 262 | 262 | .log, |
| 263 | 263 | .log2, |
| 264 | 264 | .log10, |
| 265 | .fabs, | |
| 265 | .abs, | |
| 266 | 266 | .floor, |
| 267 | 267 | .ceil, |
| 268 | 268 | .trunc, |
src/type.zig+11| ... | ... | @@ -3197,6 +3197,17 @@ pub const Type = struct { |
| 3197 | 3197 | }; |
| 3198 | 3198 | } |
| 3199 | 3199 | |
| 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 | 3211 | pub const @"u1": Type = .{ .ip_index = .u1_type }; |
| 3201 | 3212 | pub const @"u8": Type = .{ .ip_index = .u8_type }; |
| 3202 | 3213 | pub const @"u16": Type = .{ .ip_index = .u16_type }; |
src/value.zig+40-21| ... | ... | @@ -1993,7 +1993,7 @@ pub const Value = struct { |
| 1993 | 1993 | return 1; |
| 1994 | 1994 | } |
| 1995 | 1995 | |
| 1996 | const w_value = @fabs(scalar); | |
| 1996 | const w_value = @abs(scalar); | |
| 1997 | 1997 | return @divFloor(@as(std.math.big.Limb, @intFromFloat(std.math.log2(w_value))), @typeInfo(std.math.big.Limb).Int.bits) + 1; |
| 1998 | 1998 | } |
| 1999 | 1999 | |
| ... | ... | @@ -3710,36 +3710,55 @@ pub const Value = struct { |
| 3710 | 3710 | } })).toValue(); |
| 3711 | 3711 | } |
| 3712 | 3712 | |
| 3713 | pub fn fabs(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | |
| 3714 | if (float_type.zigTypeTag(mod) == .Vector) { | |
| 3715 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | |
| 3716 | const scalar_ty = float_type.scalarType(mod); | |
| 3713 | pub fn abs(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | |
| 3714 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 3715 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); | |
| 3716 | const scalar_ty = ty.scalarType(mod); | |
| 3717 | 3717 | for (result_data, 0..) |*scalar, i| { |
| 3718 | 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 | 3721 | return (try mod.intern(.{ .aggregate = .{ |
| 3722 | .ty = float_type.toIntern(), | |
| 3722 | .ty = ty.toIntern(), | |
| 3723 | 3723 | .storage = .{ .elems = result_data }, |
| 3724 | 3724 | } })).toValue(); |
| 3725 | 3725 | } |
| 3726 | return fabsScalar(val, float_type, mod); | |
| 3726 | return absScalar(val, ty, mod, arena); | |
| 3727 | 3727 | } |
| 3728 | 3728 | |
| 3729 | pub fn fabsScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { | |
| 3730 | const target = mod.getTarget(); | |
| 3731 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | |
| 3732 | 16 => .{ .f16 = @fabs(val.toFloat(f16, mod)) }, | |
| 3733 | 32 => .{ .f32 = @fabs(val.toFloat(f32, mod)) }, | |
| 3734 | 64 => .{ .f64 = @fabs(val.toFloat(f64, mod)) }, | |
| 3735 | 80 => .{ .f80 = @fabs(val.toFloat(f80, mod)) }, | |
| 3736 | 128 => .{ .f128 = @fabs(val.toFloat(f128, mod)) }, | |
| 3729 | pub fn absScalar(val: Value, ty: Type, mod: *Module, arena: Allocator) Allocator.Error!Value { | |
| 3730 | switch (ty.zigTypeTag(mod)) { | |
| 3731 | .Int => { | |
| 3732 | var buffer: Value.BigIntSpace = undefined; | |
| 3733 | var operand_bigint = try val.toBigInt(&buffer, mod).toManaged(arena); | |
| 3734 | operand_bigint.abs(); | |
| 3735 | ||
| 3736 | return mod.intValue_big(try ty.toUnsigned(mod), operand_bigint.toConst()); | |
| 3737 | }, | |
| 3738 | .ComptimeInt => { | |
| 3739 | var buffer: Value.BigIntSpace = undefined; | |
| 3740 | var operand_bigint = try val.toBigInt(&buffer, mod).toManaged(arena); | |
| 3741 | operand_bigint.abs(); | |
| 3742 | ||
| 3743 | return mod.intValue_big(ty, operand_bigint.toConst()); | |
| 3744 | }, | |
| 3745 | .ComptimeFloat, .Float => { | |
| 3746 | const target = mod.getTarget(); | |
| 3747 | const storage: InternPool.Key.Float.Storage = switch (ty.floatBits(target)) { | |
| 3748 | 16 => .{ .f16 = @abs(val.toFloat(f16, mod)) }, | |
| 3749 | 32 => .{ .f32 = @abs(val.toFloat(f32, mod)) }, | |
| 3750 | 64 => .{ .f64 = @abs(val.toFloat(f64, mod)) }, | |
| 3751 | 80 => .{ .f80 = @abs(val.toFloat(f80, mod)) }, | |
| 3752 | 128 => .{ .f128 = @abs(val.toFloat(f128, mod)) }, | |
| 3753 | else => unreachable, | |
| 3754 | }; | |
| 3755 | return (try mod.intern(.{ .float = .{ | |
| 3756 | .ty = ty.toIntern(), | |
| 3757 | .storage = storage, | |
| 3758 | } })).toValue(); | |
| 3759 | }, | |
| 3737 | 3760 | else => unreachable, |
| 3738 | }; | |
| 3739 | return (try mod.intern(.{ .float = .{ | |
| 3740 | .ty = float_type.toIntern(), | |
| 3741 | .storage = storage, | |
| 3742 | } })).toValue(); | |
| 3761 | } | |
| 3743 | 3762 | } |
| 3744 | 3763 | |
| 3745 | 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 | 946 | typedef unsigned long long zig_Builtin64; |
| 947 | 947 | #endif |
| 948 | 948 | |
| 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 | ||
| 949 | 967 | static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) { |
| 950 | 968 | return zig_wrap_u8(val >> (8 - bits), bits); |
| 951 | 969 | } |
| ... | ... | @@ -1141,6 +1159,24 @@ zig_builtin_clz(16) |
| 1141 | 1159 | zig_builtin_clz(32) |
| 1142 | 1160 | zig_builtin_clz(64) |
| 1143 | 1161 | |
| 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 | |
| 1175 | zig_builtin_abs(8) | |
| 1176 | zig_builtin_abs(16) | |
| 1177 | zig_builtin_abs(32) | |
| 1178 | zig_builtin_abs(64) | |
| 1179 | ||
| 1144 | 1180 | /* ======================== 128-bit Integer Support ========================= */ |
| 1145 | 1181 | |
| 1146 | 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 | 1502 | return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); |
| 1467 | 1503 | } |
| 1468 | 1504 | |
| 1505 | static 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 | 1510 | #if zig_has_int128 |
| 1470 | 1511 | |
| 1471 | 1512 | static 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 | 237 | _ = @import("behavior/void.zig"); |
| 238 | 238 | _ = @import("behavior/while.zig"); |
| 239 | 239 | _ = @import("behavior/widening.zig"); |
| 240 | _ = @import("behavior/abs.zig"); | |
| 240 | 241 | |
| 241 | 242 | if (builtin.cpu.arch == .wasm32) { |
| 242 | 243 | _ = @import("behavior/wasm.zig"); |
test/behavior/abs.zig created+371| ... | ... | @@ -0,0 +1,371 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const expect = std.testing.expect; | |
| 4 | ||
| 5 | test "@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 | ||
| 16 | fn 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 | ||
| 46 | test "@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 | ||
| 57 | fn 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 | ||
| 83 | test "@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 | ||
| 102 | fn 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 | ||
| 133 | test "@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 | ||
| 159 | fn 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 | ||
| 196 | test "@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 | ||
| 222 | fn 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 | ||
| 252 | test "@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 | ||
| 344 | fn 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 | 523 | try expect(@log10(@as(f32, 0.4)) == result[3]); |
| 524 | 524 | } |
| 525 | 525 | |
| 526 | test "@fabs" { | |
| 526 | test "@abs" { | |
| 527 | 527 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 528 | 528 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 529 | 529 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -533,24 +533,24 @@ test "@fabs" { |
| 533 | 533 | } |
| 534 | 534 | |
| 535 | 535 | fn testFabs() !void { |
| 536 | try expect(@fabs(@as(f16, -2.5)) == 2.5); | |
| 537 | try expect(@fabs(@as(f16, 2.5)) == 2.5); | |
| 538 | try expect(@fabs(@as(f32, -2.5)) == 2.5); | |
| 539 | try expect(@fabs(@as(f32, 2.5)) == 2.5); | |
| 540 | try expect(@fabs(@as(f64, -2.5)) == 2.5); | |
| 541 | try expect(@fabs(@as(f64, 2.5)) == 2.5); | |
| 536 | try expect(@abs(@as(f16, -2.5)) == 2.5); | |
| 537 | try expect(@abs(@as(f16, 2.5)) == 2.5); | |
| 538 | try expect(@abs(@as(f32, -2.5)) == 2.5); | |
| 539 | try expect(@abs(@as(f32, 2.5)) == 2.5); | |
| 540 | try expect(@abs(@as(f64, -2.5)) == 2.5); | |
| 541 | try expect(@abs(@as(f64, 2.5)) == 2.5); | |
| 542 | 542 | |
| 543 | 543 | // TODO test f128, and c_longdouble |
| 544 | 544 | // https://github.com/ziglang/zig/issues/4026 |
| 545 | 545 | // { |
| 546 | 546 | // var a: f80 = -2.5; |
| 547 | 547 | // var b: f80 = 2.5; |
| 548 | // try expect(@fabs(a) == 2.5); | |
| 549 | // try expect(@fabs(b) == 2.5); | |
| 548 | // try expect(@abs(a) == 2.5); | |
| 549 | // try expect(@abs(b) == 2.5); | |
| 550 | 550 | // } |
| 551 | 551 | } |
| 552 | 552 | |
| 553 | test "@fabs with vectors" { | |
| 553 | test "@abs with vectors" { | |
| 554 | 554 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 555 | 555 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 556 | 556 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -562,14 +562,15 @@ test "@fabs with vectors" { |
| 562 | 562 | |
| 563 | 563 | fn testFabsWithVectors() !void { |
| 564 | 564 | var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 }; |
| 565 | var result = @fabs(v); | |
| 566 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon)); | |
| 567 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon)); | |
| 568 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon)); | |
| 569 | try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon)); | |
| 565 | var result = @abs(v); | |
| 566 | try expect(math.approxEqAbs(f32, @abs(@as(f32, 1.1)), result[0], epsilon)); | |
| 567 | try expect(math.approxEqAbs(f32, @abs(@as(f32, -2.2)), result[1], epsilon)); | |
| 568 | try expect(math.approxEqAbs(f32, @abs(@as(f32, 0.3)), result[2], epsilon)); | |
| 569 | try expect(math.approxEqAbs(f32, @abs(@as(f32, -0.4)), result[3], epsilon)); | |
| 570 | 570 | } |
| 571 | 571 | |
| 572 | test "another, possibly redundant, @fabs test" { | |
| 572 | test "another, possibly redundant, @abs test" { | |
| 573 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 573 | 574 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 574 | 575 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 575 | 576 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -587,11 +588,12 @@ test "another, possibly redundant, @fabs test" { |
| 587 | 588 | |
| 588 | 589 | const x = 14.0; |
| 589 | 590 | const y = -x; |
| 590 | const z = @fabs(y); | |
| 591 | const z = @abs(y); | |
| 591 | 592 | try comptime std.testing.expectEqual(x, z); |
| 592 | 593 | } |
| 593 | 594 | |
| 594 | test "@fabs f80" { | |
| 595 | test "@abs f80" { | |
| 596 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 595 | 597 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 596 | 598 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 597 | 599 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -604,11 +606,12 @@ test "@fabs f80" { |
| 604 | 606 | |
| 605 | 607 | fn testFabsLegacy(comptime T: type, x: T) !void { |
| 606 | 608 | const y = -x; |
| 607 | const z = @fabs(y); | |
| 609 | const z = @abs(y); | |
| 608 | 610 | try expect(x == z); |
| 609 | 611 | } |
| 610 | 612 | |
| 611 | test "a third @fabs test, surely there should not be three fabs tests" { | |
| 613 | test "a third @abs test, surely there should not be three fabs tests" { | |
| 614 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 612 | 615 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 613 | 616 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 614 | 617 | 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 | 620 | |
| 618 | 621 | inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| { |
| 619 | 622 | // normals |
| 620 | try expect(@fabs(@as(T, 1.0)) == 1.0); | |
| 621 | try expect(@fabs(@as(T, -1.0)) == 1.0); | |
| 622 | try expect(@fabs(math.floatMin(T)) == math.floatMin(T)); | |
| 623 | try expect(@fabs(-math.floatMin(T)) == math.floatMin(T)); | |
| 624 | try expect(@fabs(math.floatMax(T)) == math.floatMax(T)); | |
| 625 | try expect(@fabs(-math.floatMax(T)) == math.floatMax(T)); | |
| 623 | try expect(@abs(@as(T, 1.0)) == 1.0); | |
| 624 | try expect(@abs(@as(T, -1.0)) == 1.0); | |
| 625 | try expect(@abs(math.floatMin(T)) == math.floatMin(T)); | |
| 626 | try expect(@abs(-math.floatMin(T)) == math.floatMin(T)); | |
| 627 | try expect(@abs(math.floatMax(T)) == math.floatMax(T)); | |
| 628 | try expect(@abs(-math.floatMax(T)) == math.floatMax(T)); | |
| 626 | 629 | |
| 627 | 630 | // subnormals |
| 628 | try expect(@fabs(@as(T, 0.0)) == 0.0); | |
| 629 | try expect(@fabs(@as(T, -0.0)) == 0.0); | |
| 630 | try expect(@fabs(math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 631 | try expect(@fabs(-math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 631 | try expect(@abs(@as(T, 0.0)) == 0.0); | |
| 632 | try expect(@abs(@as(T, -0.0)) == 0.0); | |
| 633 | try expect(@abs(math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 634 | try expect(@abs(-math.floatTrueMin(T)) == math.floatTrueMin(T)); | |
| 632 | 635 | |
| 633 | 636 | // non-finite numbers |
| 634 | try expect(math.isPositiveInf(@fabs(math.inf(T)))); | |
| 635 | try expect(math.isPositiveInf(@fabs(-math.inf(T)))); | |
| 636 | try expect(math.isNan(@fabs(math.nan(T)))); | |
| 637 | try expect(math.isPositiveInf(@abs(math.inf(T)))); | |
| 638 | try expect(math.isPositiveInf(@abs(-math.inf(T)))); | |
| 639 | try expect(math.isNan(@abs(math.nan(T)))); | |
| 637 | 640 | } |
| 638 | 641 | } |
| 639 | 642 |
test/behavior/math.zig+3-3| ... | ... | @@ -1391,7 +1391,7 @@ fn frem(comptime T: type) !void { |
| 1391 | 1391 | } |
| 1392 | 1392 | |
| 1393 | 1393 | fn 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 | } |
| 1396 | 1396 | |
| 1397 | 1397 | test "float modulo division using @mod" { |
| ... | ... | @@ -1434,7 +1434,7 @@ fn fmod(comptime T: type) !void { |
| 1434 | 1434 | } |
| 1435 | 1435 | |
| 1436 | 1436 | fn 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 | } |
| 1439 | 1439 | |
| 1440 | 1440 | test "@round" { |
| ... | ... | @@ -1627,7 +1627,7 @@ fn testAbsFloat() !void { |
| 1627 | 1627 | try testAbsFloatOne(10.05, 10.05); |
| 1628 | 1628 | } |
| 1629 | 1629 | fn 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 | } |
| 1632 | 1632 | |
| 1633 | 1633 | test "mod lazy values" { |