From 505e720421ce4f7ed11730fe68d32e3bba711f3c Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Wed, 8 Mar 2023 17:49:52 +0100 Subject: [PATCH 1/2] sema: add peer type resolution for vectors This is consistent with how coercion for vectors work. So now you can do this: ``` var a: @Vector(2, u16) = .{1, 2}; var b: @Vector(2, u8) = .{2, 1}; const c = @min(a, b); ``` where previously you had to cast explicitly: ``` var a: @Vector(2, u16) = .{1, 2}; var b: @Vector(2, u8) = .{2, 1}; var c: @Vector(2, u16) = b; const c = @min(a, c); ``` --- src/Sema.zig | 25 +++++++++++++++++++++++++ test/behavior/vector.zig | 19 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/Sema.zig b/src/Sema.zig index 8c6e3cf05c..a33c9bee6d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -29875,6 +29875,31 @@ fn resolvePeerTypes( continue; }, .Vector => switch (chosen_ty_tag) { + .Vector => { + const chosen_len = chosen_ty.vectorLen(); + const candidate_len = candidate_ty.vectorLen(); + if (chosen_len != candidate_len) + continue; + + const chosen_child_ty = chosen_ty.childType(); + const candidate_child_ty = candidate_ty.childType(); + if (chosen_child_ty.zigTypeTag() == .Int and candidate_child_ty.zigTypeTag() == .Int) { + const chosen_info = chosen_child_ty.intInfo(target); + const candidate_info = candidate_child_ty.intInfo(target); + if (chosen_info.bits < candidate_info.bits) { + chosen = candidate; + chosen_i = candidate_i + 1; + } + continue; + } + if (chosen_child_ty.zigTypeTag() == .Float and candidate_child_ty.zigTypeTag() == .Float) { + if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) { + chosen = candidate; + chosen_i = candidate_i + 1; + } + continue; + } + }, .Array => { chosen = candidate; chosen_i = candidate_i + 1; diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 1d9d517a96..2c7be227c4 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -175,6 +175,25 @@ test "array to vector" { comptime try S.doTheTest(); } +test "peer type resolution with coercible element types" { + 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_sparc64) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + var b: @Vector(2, u8) = .{ 1, 2 }; + var a: @Vector(2, u16) = .{ 2, 1 }; + var t: bool = true; + var c = if (t) a else b; + try std.testing.expect(@TypeOf(c) == @Vector(2, u16)); + } + }; + comptime try S.doTheTest(); +} + test "tuple to vector" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO From 0606f0aa5576122204886f1a3c9530c0ce75c044 Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Wed, 8 Mar 2023 23:13:37 +0100 Subject: [PATCH 2/2] sema: fix result ptr coercion array -> vector Previously this worked for array to vector where the element type matched exactly (e.g `[4]u8` to `@Vector(4, u8)`) since that is performed with a simple `.bitcast` operation, but now it also works for types where the array is coercible to the vector type (e.g `[4]u8` to `@Vector(4, u16)`). --- src/Sema.zig | 14 ++++++++++++++ test/behavior/vector.zig | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Sema.zig b/src/Sema.zig index a33c9bee6d..61b6209a3e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2538,6 +2538,20 @@ fn coerceResultPtr( const trash_inst = trash_block.instructions.pop(); switch (air_tags[trash_inst]) { + // Array coerced to Vector where element size is not equal but coercible. + .aggregate_init => { + const ty_pl = air_datas[trash_inst].ty_pl; + const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{ + .pointee_type = try sema.analyzeAsType(block, src, ty_pl.ty), + .@"addrspace" = addr_space, + }); + + if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { + return sema.addConstant(ptr_operand_ty, ptr_val); + } else { + return sema.bitCast(block, ptr_operand_ty, new_ptr, src, null); + } + }, .bitcast => { const ty_op = air_datas[trash_inst].ty_op; const operand_ty = sema.typeOf(ty_op.operand); diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 2c7be227c4..b1c0e310fe 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -175,6 +175,25 @@ test "array to vector" { comptime try S.doTheTest(); } +test "array to vector with element type coercion" { + 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_sparc64) return error.SkipZigTest; // TODO + + const S = struct { + fn doTheTest() !void { + var foo: f16 = 3.14; + var arr32 = [4]f32{ foo, 1.5, 0.0, 0.0 }; + var vec: @Vector(4, f32) = [4]f16{ foo, 1.5, 0.0, 0.0 }; + try std.testing.expect(std.mem.eql(f32, &@as([4]f32, vec), &arr32)); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + test "peer type resolution with coercible element types" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO