diff --git a/doc/langref.html.in b/doc/langref.html.in index 3ab279ff12..895a3c56ea 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -2515,13 +2515,14 @@ test "null terminated array" { {#header_open|Vectors#}

- A vector is a group of booleans, {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on - in parallel using SIMD instructions. Vector types are created with the builtin function {#link|@Type#}, - or using the shorthand function {#syntax#}std.meta.Vector{#endsyntax#}. + A vector is a group of booleans, {#link|Integers#}, {#link|Floats#}, or + {#link|Pointers#} which are operated on in parallel, using SIMD instructions if possible. + Vector types are created with the builtin function {#link|@Vector#}.

- Vectors support the same builtin operators as their underlying base types. These operations are performed - element-wise, and return a vector of the same length as the input vectors. This includes: + Vectors support the same builtin operators as their underlying base types. + These operations are performed element-wise, and return a vector of the same length + as the input vectors. This includes:

- It is prohibited to use a math operator on a mixture of scalars (individual numbers) and vectors. - Zig provides the {#link|@splat#} builtin to easily convert from scalars to vectors, and it supports {#link|@reduce#} - and array indexing syntax to convert from vectors to scalars. Vectors also support assignment to and from - fixed-length arrays with comptime known length. + It is prohibited to use a math operator on a mixture of scalars (individual numbers) + and vectors. Zig provides the {#link|@splat#} builtin to easily convert from scalars + to vectors, and it supports {#link|@reduce#} and array indexing syntax to convert + from vectors to scalars. Vectors also support assignment to and from fixed-length + arrays with comptime known length.

For rearranging elements within and between vectors, Zig provides the {#link|@shuffle#} and {#link|@select#} functions. @@ -2550,16 +2552,14 @@ test "null terminated array" {

{#code_begin|test|vector_example#} const std = @import("std"); -const Vector = std.meta.Vector; const expectEqual = std.testing.expectEqual; test "Basic vector usage" { - // Vectors have a compile-time known length and base type, - // and can be assigned to using array literal syntax - const a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; - const b: Vector(4, i32) = [_]i32{ 5, 6, 7, 8 }; + // Vectors have a compile-time known length and base type. + const a = @Vector(4, i32){ 1, 2, 3, 4 }; + const b = @Vector(4, i32){ 5, 6, 7, 8 }; - // Math operations take place element-wise + // Math operations take place element-wise. const c = a + b; // Individual vector elements can be accessed using array indexing syntax. @@ -2572,19 +2572,19 @@ test "Basic vector usage" { test "Conversion between vectors, arrays, and slices" { // Vectors and fixed-length arrays can be automatically assigned back and forth var arr1: [4]f32 = [_]f32{ 1.1, 3.2, 4.5, 5.6 }; - var vec: Vector(4, f32) = arr1; + var vec: @Vector(4, f32) = arr1; var arr2: [4]f32 = vec; try expectEqual(arr1, arr2); // You can also assign from a slice with comptime-known length to a vector using .* - const vec2: Vector(2, f32) = arr1[1..3].*; + const vec2: @Vector(2, f32) = arr1[1..3].*; var slice: []const f32 = &arr1; var offset: u32 = 1; // To extract a comptime-known length from a runtime-known offset, // first extract a new slice from the starting offset, then an array of // comptime known length - const vec3: Vector(2, f32) = slice[offset..][0..2].*; + const vec3: @Vector(2, f32) = slice[offset..][0..2].*; try expectEqual(slice[offset], vec2[0]); try expectEqual(slice[offset + 1], vec2[1]); try expectEqual(vec2, vec3); @@ -9084,7 +9084,7 @@ pub const PrefetchOptions = struct { {#header_close#} {#header_open|@select#} -
{#syntax#}@select(comptime T: type, pred: std.meta.Vector(len, bool), a: std.meta.Vector(len, T), b: std.meta.Vector(len, T)) std.meta.Vector(len, T){#endsyntax#}
+
{#syntax#}@select(comptime T: type, pred: @Vector(len, bool), a: @Vector(len, T), b: @Vector(len, T)) @Vector(len, T){#endsyntax#}

Selects values element-wise from {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} based on {#syntax#}pred{#endsyntax#}. If {#syntax#}pred[i]{#endsyntax#} is {#syntax#}true{#endsyntax#}, the corresponding element in the result will be {#syntax#}a[i]{#endsyntax#} and otherwise {#syntax#}b[i]{#endsyntax#}.

@@ -9252,7 +9252,7 @@ test "@setRuntimeSafety" { {#header_close#} {#header_open|@shuffle#} -
{#syntax#}@shuffle(comptime E: type, a: std.meta.Vector(a_len, E), b: std.meta.Vector(b_len, E), comptime mask: std.meta.Vector(mask_len, i32)) std.meta.Vector(mask_len, E){#endsyntax#}
+
{#syntax#}@shuffle(comptime E: type, a: @Vector(a_len, E), b: @Vector(b_len, E), comptime mask: @Vector(mask_len, i32)) @Vector(mask_len, E){#endsyntax#}

Constructs a new {#link|vector|Vectors#} by selecting elements from {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} based on {#syntax#}mask{#endsyntax#}. @@ -9287,22 +9287,21 @@ test "@setRuntimeSafety" {

{#code_begin|test|vector_shuffle#} const std = @import("std"); -const Vector = std.meta.Vector; const expect = std.testing.expect; test "vector @shuffle" { - const a: Vector(7, u8) = [_]u8{ 'o', 'l', 'h', 'e', 'r', 'z', 'w' }; - const b: Vector(4, u8) = [_]u8{ 'w', 'd', '!', 'x' }; + const a = @Vector(7, u8){ 'o', 'l', 'h', 'e', 'r', 'z', 'w' }; + const b = @Vector(4, u8){ 'w', 'd', '!', 'x' }; // To shuffle within a single vector, pass undefined as the second argument. // Notice that we can re-order, duplicate, or omit elements of the input vector - const mask1: Vector(5, i32) = [_]i32{ 2, 3, 1, 1, 0 }; - const res1: Vector(5, u8) = @shuffle(u8, a, undefined, mask1); + const mask1 = @Vector(5, i32){ 2, 3, 1, 1, 0 }; + const res1: @Vector(5, u8) = @shuffle(u8, a, undefined, mask1); try expect(std.mem.eql(u8, &@as([5]u8, res1), "hello")); // Combining two vectors - const mask2: Vector(6, i32) = [_]i32{ -1, 0, 4, 1, -2, -3 }; - const res2: Vector(6, u8) = @shuffle(u8, a, b, mask2); + const mask2 = @Vector(6, i32){ -1, 0, 4, 1, -2, -3 }; + const res2: @Vector(6, u8) = @shuffle(u8, a, b, mask2); try expect(std.mem.eql(u8, &@as([6]u8, res2), "world!")); } {#code_end#} @@ -9329,7 +9328,7 @@ test "vector @shuffle" { {#header_close#} {#header_open|@splat#} -
{#syntax#}@splat(comptime len: u32, scalar: anytype) std.meta.Vector(len, @TypeOf(scalar)){#endsyntax#}
+
{#syntax#}@splat(comptime len: u32, scalar: anytype) @Vector(len, @TypeOf(scalar)){#endsyntax#}

Produces a vector of length {#syntax#}len{#endsyntax#} where each element is the value {#syntax#}scalar{#endsyntax#}: @@ -9341,7 +9340,7 @@ const expect = std.testing.expect; test "vector @splat" { const scalar: u32 = 5; const result = @splat(4, scalar); - comptime try expect(@TypeOf(result) == std.meta.Vector(4, u32)); + comptime try expect(@TypeOf(result) == @Vector(4, u32)); try expect(std.mem.eql(u32, &@as([4]u32, result), &[_]u32{ 5, 5, 5, 5 })); } {#code_end#} @@ -9381,10 +9380,10 @@ const std = @import("std"); const expect = std.testing.expect; test "vector @reduce" { - const value: std.meta.Vector(4, i32) = [_]i32{ 1, -1, 1, -1 }; + const value = @Vector(4, i32){ 1, -1, 1, -1 }; const result = value > @splat(4, @as(i32, 0)); // result is { true, false, true, false }; - comptime try expect(@TypeOf(result) == std.meta.Vector(4, bool)); + comptime try expect(@TypeOf(result) == @Vector(4, bool)); const is_all_true = @reduce(.And, result); comptime try expect(@TypeOf(is_all_true) == bool); try expect(is_all_true == false); @@ -9743,6 +9742,12 @@ fn foo(comptime T: type, ptr: *T) T { {#syntax#}@unionInit{#endsyntax#} forwards its {#link|result location|Result Location Semantics#} to {#syntax#}init_expr{#endsyntax#}.

{#header_close#} + + + {#header_open|@Vector#} +
{#syntax#}@Vector(len: comptime_int, Element: type) type{#endsyntax#}
+

Creates {#link|Vectors#}.

+ {#header_close#} {#header_close#} {#header_open|Build Mode#} diff --git a/lib/std/math/round.zig b/lib/std/math/round.zig index 7e1ee1ebd1..c948431a35 100644 --- a/lib/std/math/round.zig +++ b/lib/std/math/round.zig @@ -20,6 +20,10 @@ pub fn round(x: anytype) @TypeOf(x) { f32 => round32(x), f64 => round64(x), f128 => round128(x), + + // TODO this is not correct for some targets + c_longdouble => @floatCast(c_longdouble, round128(x)), + else => @compileError("round not implemented for " ++ @typeName(T)), }; } diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 3f3144f0d1..7be06e0fd1 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -930,6 +930,7 @@ test "std.meta.Float" { try testing.expectEqual(f128, Float(128)); } +/// Deprecated. Use `@Vector`. pub fn Vector(comptime len: u32, comptime child: type) type { return @Type(.{ .Vector = .{ diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index 7d967492e9..53eb8fa352 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -421,7 +421,7 @@ pub fn MultiArrayList(comptime S: type) type { } fn capacityInBytes(capacity: usize) usize { - const sizes_vector: std.meta.Vector(sizes.bytes.len, usize) = sizes.bytes; + const sizes_vector: @Vector(sizes.bytes.len, usize) = sizes.bytes; const capacity_vector = @splat(sizes.bytes.len, capacity); return @reduce(.Add, capacity_vector * sizes_vector); } diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index db1c56c536..326ca3a8a0 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -98,6 +98,7 @@ comptime { @export(round, .{ .name = "round", .linkage = .Strong }); @export(roundf, .{ .name = "roundf", .linkage = .Strong }); + @export(roundl, .{ .name = "roundl", .linkage = .Strong }); @export(fmin, .{ .name = "fmin", .linkage = .Strong }); @export(fminf, .{ .name = "fminf", .linkage = .Strong }); @@ -575,11 +576,18 @@ fn fabsf(a: f32) callconv(.C) f32 { return math.fabs(a); } +fn roundf(a: f32) callconv(.C) f32 { + return math.round(a); +} + fn round(a: f64) callconv(.C) f64 { return math.round(a); } -fn roundf(a: f32) callconv(.C) f32 { +fn roundl(a: c_longdouble) callconv(.C) c_longdouble { + if (!long_double_is_f128) { + @panic("TODO implement this"); + } return math.round(a); } diff --git a/src/Sema.zig b/src/Sema.zig index 1a760be4ef..99519cd562 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4195,7 +4195,15 @@ fn zirDbgVar( const str_op = sema.code.instructions.items(.data)[inst].str_op; const operand = sema.resolveInst(str_op.operand); const operand_ty = sema.typeOf(operand); - if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty))) return; + switch (air_tag) { + .dbg_var_ptr => { + if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty.childType()))) return; + }, + .dbg_var_val => { + if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty))) return; + }, + else => unreachable, + } const name = str_op.getStr(sema.code); // Add the name to the AIR. @@ -13268,7 +13276,7 @@ fn checkFloatType( ty: Type, ) CompileError!void { switch (ty.zigTypeTag()) { - .ComptimeFloat, .Float => {}, + .ComptimeInt, .ComptimeFloat, .Float => {}, else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty}), } } @@ -17169,10 +17177,25 @@ fn storePtr2( return; } + // TODO do the same thing for anon structs as for tuples above. + + // Detect if we are storing an array operand to a bitcasted vector pointer. + // If so, we instead reach through the bitcasted pointer to the vector pointer, + // bitcast the array operand to a vector, and then lower this as a store of + // a vector value to a vector pointer. This generally results in better code, + // as well as working around an LLVM bug: + // https://github.com/ziglang/zig/issues/11154 + if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { + const vector_ty = sema.typeOf(vector_ptr).childType(); + const vector = try sema.coerce(block, vector_ty, uncasted_operand, operand_src); + try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store); + return; + } + const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src); + const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { - const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand); const operand_val = maybe_operand_val orelse { try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); break :rs operand_src; @@ -17195,6 +17218,39 @@ fn storePtr2( _ = try block.addBinOp(air_tag, ptr, operand); } +/// Traverse an arbitrary number of bitcasted pointers and return the underyling vector +/// pointer. Only if the final element type matches the vector element type, and the +/// lengths match. +fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref { + const array_ty = sema.typeOf(ptr).childType(); + if (array_ty.zigTypeTag() != .Array) return null; + var ptr_inst = Air.refToIndex(ptr) orelse return null; + const air_datas = sema.air_instructions.items(.data); + const air_tags = sema.air_instructions.items(.tag); + const prev_ptr = while (air_tags[ptr_inst] == .bitcast) { + const prev_ptr = air_datas[ptr_inst].ty_op.operand; + const prev_ptr_ty = sema.typeOf(prev_ptr); + const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) { + .single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data, + .pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type, + else => return null, + }; + if (prev_ptr_child_ty.zigTypeTag() == .Vector) break prev_ptr; + ptr_inst = Air.refToIndex(prev_ptr) orelse return null; + } else return null; + + // We have a pointer-to-array and a pointer-to-vector. If the elements and + // lengths match, return the result. + const vector_ty = sema.typeOf(prev_ptr).childType(); + if (array_ty.childType().eql(vector_ty.childType()) and + array_ty.arrayLen() == vector_ty.vectorLen()) + { + return prev_ptr; + } else { + return null; + } +} + /// Call when you have Value objects rather than Air instructions, and you want to /// assert the store must be done at comptime. fn storePtrVal( diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index c1c7ac06f0..42e94a3528 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3709,10 +3709,11 @@ pub const FuncGen = struct { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.air.typeOf(ty_op.operand); const dest_ty = self.air.typeOfIndex(inst); const dest_llvm_ty = try self.dg.llvmType(dest_ty); - if (dest_ty.isSignedInt()) { + if (operand_ty.isSignedInt()) { return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); } else { return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); @@ -3984,13 +3985,14 @@ pub const FuncGen = struct { const pl_op = self.air.instructions.items(.data)[inst].pl_op; const operand = try self.resolveInst(pl_op.operand); const name = self.air.nullTerminatedString(pl_op.payload); + const ptr_ty = self.air.typeOf(pl_op.operand); const di_local_var = dib.createAutoVariable( self.di_scope.?, name.ptr, self.di_file.?, self.prev_dbg_line, - try self.dg.lowerDebugType(self.air.typeOf(pl_op.operand)), + try self.dg.lowerDebugType(ptr_ty.childType()), true, // always preserve 0, // flags ); diff --git a/src/type.zig b/src/type.zig index 30c8838109..10f0b0325d 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2573,15 +2573,14 @@ pub const Type = extern union { .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1, .array, .vector => { const payload = self.cast(Payload.Array).?.data; - const elem_size = @maximum(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); + const elem_size = payload.elem_type.abiSize(target); + assert(elem_size >= payload.elem_type.abiAlignment(target)); return payload.len * elem_size; }, .array_sentinel => { const payload = self.castTag(.array_sentinel).?.data; - const elem_size = std.math.max( - payload.elem_type.abiAlignment(target), - payload.elem_type.abiSize(target), - ); + const elem_size = payload.elem_type.abiSize(target); + assert(elem_size >= payload.elem_type.abiAlignment(target)); return (payload.len + 1) * elem_size; }, .i16, .u16 => return 2, diff --git a/src/value.zig b/src/value.zig index 9117ef78df..6ab3adba36 100644 --- a/src/value.zig +++ b/src/value.zig @@ -3931,15 +3931,12 @@ pub const Value = extern union { }, 80 => { if (true) { - @panic("TODO implement compiler_rt fabs for f80"); + @panic("TODO implement compiler_rt fabs for f80 (__fabsx)"); } const f = val.toFloat(f80); return Value.Tag.float_80.create(arena, @fabs(f)); }, 128 => { - if (true) { - @panic("TODO implement compiler_rt fabs for f128"); - } const f = val.toFloat(f128); return Value.Tag.float_128.create(arena, @fabs(f)); }, @@ -3963,15 +3960,12 @@ pub const Value = extern union { }, 80 => { if (true) { - @panic("TODO implement compiler_rt floor for f80"); + @panic("TODO implement compiler_rt floor for f80 (__floorx)"); } const f = val.toFloat(f80); return Value.Tag.float_80.create(arena, @floor(f)); }, 128 => { - if (true) { - @panic("TODO implement compiler_rt floor for f128"); - } const f = val.toFloat(f128); return Value.Tag.float_128.create(arena, @floor(f)); }, @@ -4001,9 +3995,6 @@ pub const Value = extern union { return Value.Tag.float_80.create(arena, @ceil(f)); }, 128 => { - if (true) { - @panic("TODO implement compiler_rt ceil for f128"); - } const f = val.toFloat(f128); return Value.Tag.float_128.create(arena, @ceil(f)); }, @@ -4033,9 +4024,6 @@ pub const Value = extern union { return Value.Tag.float_80.create(arena, @round(f)); }, 128 => { - if (true) { - @panic("TODO implement compiler_rt round for f128"); - } const f = val.toFloat(f128); return Value.Tag.float_128.create(arena, @round(f)); }, @@ -4065,9 +4053,6 @@ pub const Value = extern union { return Value.Tag.float_80.create(arena, @trunc(f)); }, 128 => { - if (true) { - @panic("TODO implement compiler_rt trunc for f128"); - } const f = val.toFloat(f128); return Value.Tag.float_128.create(arena, @trunc(f)); }, diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 1f92a0214f..69e64b8973 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -95,8 +95,29 @@ test "comptime_int @intToFloat" { } } +test "@intToFloat" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + try testIntToFloat(-2); + } + + fn testIntToFloat(k: i32) !void { + const f = @intToFloat(f32, k); + const i = @floatToInt(i32, f); + try expect(i == k); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + test "@floatToInt" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -1007,8 +1028,6 @@ test "peer type resolve array pointer and unknown pointer" { } test "comptime float casts" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - const a = @intToFloat(comptime_float, 1); try expect(a == 1); try expect(@TypeOf(a) == comptime_float); diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index d82637b24d..424677ea1c 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -333,7 +333,6 @@ fn testLog() !void { } test "@log with vectors" { - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -343,15 +342,19 @@ test "@log with vectors" { { var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; var result = @log(v); - try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon)); - try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon)); + try expect(@log(@as(f32, 1.1)) == result[0]); + try expect(@log(@as(f32, 2.2)) == result[1]); try expect(@log(@as(f32, 0.3)) == result[2]); - try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon)); + try expect(@log(@as(f32, 0.4)) == result[3]); } } test "@log2" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO comptime try testLog2(); try testLog2(); @@ -368,15 +371,19 @@ fn testLog2() !void { { var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; var result = @log2(v); - try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon)); - try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon)); - try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon)); - try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon)); + try expect(@log2(@as(f32, 1.1)) == result[0]); + try expect(@log2(@as(f32, 2.2)) == result[1]); + try expect(@log2(@as(f32, 0.3)) == result[2]); + try expect(@log2(@as(f32, 0.4)) == result[3]); } } test "@log10" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO comptime try testLog10(); try testLog10(); @@ -393,10 +400,10 @@ fn testLog10() !void { { var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; var result = @log10(v); - try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon)); - try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon)); - try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon)); - try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon)); + try expect(@log10(@as(f32, 1.1)) == result[0]); + try expect(@log10(@as(f32, 2.2)) == result[1]); + try expect(@log10(@as(f32, 0.3)) == result[2]); + try expect(@log10(@as(f32, 0.4)) == result[3]); } } @@ -537,7 +544,71 @@ fn testTrunc() !void { } } -test "negation" { +test "negation f16" { + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + if (builtin.os.tag == .freebsd) { + // TODO file issue to track this failure + return error.SkipZigTest; + } + + const S = struct { + fn doTheTest() !void { + var a: f16 = 1; + a = -a; + try expect(a == -1); + a = -a; + try expect(a == 1); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "negation f32" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + var a: f32 = 1; + a = -a; + try expect(a == -1); + a = -a; + try expect(a == 1); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "negation f64" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + var a: f64 = 1; + a = -a; + try expect(a == -1); + a = -a; + try expect(a == 1); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "negation f80" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO if (builtin.os.tag == .freebsd) { @@ -547,11 +618,37 @@ test "negation" { const S = struct { fn doTheTest() !void { - inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| { - var a: T = 1; - a = -a; - try expect(a == -1); - } + var a: f80 = 1; + a = -a; + try expect(a == -1); + a = -a; + try expect(a == 1); + } + }; + + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "negation f128" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + + if (builtin.os.tag == .freebsd) { + // TODO file issue to track this failure + return error.SkipZigTest; + } + + const S = struct { + fn doTheTest() !void { + var a: f128 = 1; + a = -a; + try expect(a == -1); + a = -a; + try expect(a == 1); } }; @@ -583,7 +680,13 @@ test "float literal at compile time not lossy" { } test "f128 at compile time is lossy" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend != .stage1) { + // this one is happening because we represent comptime-known f128 integers with + // Value.Tag.bigint and only convert to f128 representation if it stops being an + // integer. Is this something we want? need to have a lang spec discussion on this + // topic. + return error.SkipZigTest; // TODO + } try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index c6fc43e38c..31dd6d09f3 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -6,7 +6,6 @@ const expectEqualSlices = std.testing.expectEqualSlices; const maxInt = std.math.maxInt; const minInt = std.math.minInt; const mem = std.mem; -const has_f80_rt = builtin.cpu.arch == .x86_64; test "assignment operators" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -1046,12 +1045,14 @@ fn testSqrt(comptime T: type, x: T) !void { } test "@fabs" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testFabs(f128, 12.0); comptime try testFabs(f128, 12.0); - if (has_f80_rt) try testFabs(f80, 12.0); - // comptime try testFabs(f80, 12.0); try testFabs(f64, 12.0); comptime try testFabs(f64, 12.0); try testFabs(f32, 12.0); @@ -1065,20 +1066,25 @@ test "@fabs" { comptime try expectEqual(x, z); } +test "@fabs f80" { + if (true) { + // https://github.com/ziglang/zig/issues/11030 + return error.SkipZigTest; + } + + try testFabs(f80, 12.0); + comptime try testFabs(f80, 12.0); +} + fn testFabs(comptime T: type, x: T) !void { const y = -x; const z = @fabs(y); - try expectEqual(x, z); + try expect(x == z); } test "@floor" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - // FIXME: Generates a floorl function call - // testFloor(f128, 12.0); - comptime try testFloor(f128, 12.0); - // try testFloor(f80, 12.0); - comptime try testFloor(f80, 12.0); try testFloor(f64, 12.0); comptime try testFloor(f64, 12.0); try testFloor(f32, 12.0); @@ -1089,23 +1095,39 @@ test "@floor" { const x = 14.0; const y = x + 0.7; const z = @floor(y); - comptime try expectEqual(x, z); + comptime try expect(x == z); +} + +test "@floor f80" { + if (true) { + // https://github.com/ziglang/zig/issues/11030 + return error.SkipZigTest; + } + try testFloor(f80, 12.0); + comptime try testFloor(f80, 12.0); +} + +test "@floor f128" { + if (builtin.zig_backend == .stage1) { + // Fails because it incorrectly lowers to a floorl function call. + return error.SkipZigTest; + } + + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + testFloor(f128, 12.0); + comptime try testFloor(f128, 12.0); } fn testFloor(comptime T: type, x: T) !void { const y = x + 0.6; const z = @floor(y); - try expectEqual(x, z); + try expect(x == z); } test "@ceil" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - // FIXME: Generates a ceill function call - //testCeil(f128, 12.0); - comptime try testCeil(f128, 12.0); - // try testCeil(f80, 12.0); - comptime try testCeil(f80, 12.0); try testCeil(f64, 12.0); comptime try testCeil(f64, 12.0); try testCeil(f32, 12.0); @@ -1116,29 +1138,40 @@ test "@ceil" { const x = 14.0; const y = x - 0.7; const z = @ceil(y); - comptime try expectEqual(x, z); + comptime try expect(x == z); +} + +test "@ceil f80" { + if (true) { + // https://github.com/ziglang/zig/issues/11030 + return error.SkipZigTest; + } + + try testCeil(f80, 12.0); + comptime try testCeil(f80, 12.0); +} + +test "@ceil f128" { + if (builtin.zig_backend == .stage1) { + // Fails because it incorrectly lowers to a ceill function call. + return error.SkipZigTest; + } + + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + testCeil(f128, 12.0); + comptime try testCeil(f128, 12.0); } fn testCeil(comptime T: type, x: T) !void { const y = x - 0.8; const z = @ceil(y); - try expectEqual(x, z); + try expect(x == z); } test "@trunc" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - // FIXME: Generates a truncl function call - //testTrunc(f128, 12.0); - comptime try testTrunc(f128, 12.0); - // try testTrunc(f80, 12.0); - // comptime try testTrunc(f80, 12.0); - comptime { - const x: f80 = 12.0; - const y = x + 0.8; - const z = @trunc(y); - try expectEqual(x, z); - } try testTrunc(f64, 12.0); comptime try testTrunc(f64, 12.0); try testTrunc(f32, 12.0); @@ -1149,31 +1182,54 @@ test "@trunc" { const x = 14.0; const y = x + 0.7; const z = @trunc(y); - comptime try expectEqual(x, z); + comptime try expect(x == z); +} + +test "@trunc f80" { + if (true) { + // https://github.com/ziglang/zig/issues/11030 + return error.SkipZigTest; + } + + try testTrunc(f80, 12.0); + comptime try testTrunc(f80, 12.0); + comptime { + const x: f80 = 12.0; + const y = x + 0.8; + const z = @trunc(y); + try expect(x == z); + } +} + +test "@trunc f128" { + if (builtin.zig_backend == .stage1) { + // Fails because it incorrectly lowers to a truncl function call. + return error.SkipZigTest; + } + + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + testTrunc(f128, 12.0); + comptime try testTrunc(f128, 12.0); } fn testTrunc(comptime T: type, x: T) !void { { const y = x + 0.8; const z = @trunc(y); - try expectEqual(x, z); + try expect(x == z); } { const y = -x - 0.8; const z = @trunc(y); - try expectEqual(-x, z); + try expect(-x == z); } } test "@round" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - // FIXME: Generates a roundl function call - //testRound(f128, 12.0); - comptime try testRound(f128, 12.0); - // try testRound(f80, 12.0); - comptime try testRound(f80, 12.0); try testRound(f64, 12.0); comptime try testRound(f64, 12.0); try testRound(f32, 12.0); @@ -1184,13 +1240,35 @@ test "@round" { const x = 14.0; const y = x + 0.4; const z = @round(y); - comptime try expectEqual(x, z); + comptime try expect(x == z); +} + +test "@round f80" { + if (true) { + // https://github.com/ziglang/zig/issues/11030 + return error.SkipZigTest; + } + + try testRound(f80, 12.0); + comptime try testRound(f80, 12.0); +} + +test "@round f128" { + if (builtin.zig_backend == .stage1) { + // Fails because it incorrectly lowers to a roundl function call. + return error.SkipZigTest; + } + + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + + testRound(f128, 12.0); + comptime try testRound(f128, 12.0); } fn testRound(comptime T: type, x: T) !void { const y = x - 0.5; const z = @round(y); - try expectEqual(x, z); + try expect(x == z); } test "vector integer addition" { @@ -1225,10 +1303,15 @@ test "NaN comparison" { comptime try testNanEqNan(f32); comptime try testNanEqNan(f64); comptime try testNanEqNan(f128); +} - // TODO https://github.com/ziglang/zig/issues/11030 - // try testNanEqNan(f80); - // comptime try testNanEqNan(f80); +test "NaN comparison f80" { + if (true) { + // https://github.com/ziglang/zig/issues/11030 + return error.SkipZigTest; + } + try testNanEqNan(f80); + comptime try testNanEqNan(f80); } fn testNanEqNan(comptime F: type) !void { diff --git a/test/cases.zig b/test/cases.zig index a65baeeef6..942119f780 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -16,5 +16,6 @@ pub fn addCases(ctx: *TestContext) !void { try @import("stage2/riscv64.zig").addCases(ctx); try @import("stage2/plan9.zig").addCases(ctx); try @import("stage2/x86_64.zig").addCases(ctx); - try @import("stage2/nvptx.zig").addCases(ctx); + // https://github.com/ziglang/zig/issues/10968 + //try @import("stage2/nvptx.zig").addCases(ctx); }