authorgravatar for misha@farberbrodsky.comMichael Farber Brodsky <misha@farberbrodsky.com> 2026-08-08 10:21:31+02:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-08 10:21:31+02:00
log637504176bd3b9a2374fc9f7f2e759ead35ac9b5
treee8056df2b7e94d46b8c72f9b7150479e8019f91d
parent02c49f2911674a93be7591f3d9b47bd087c0586d

Sema: handle OPV types in `zirSelect` and `analyzeShuffle`

Fixes: https://codeberg.org/ziglang/zig/issues/35969 Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35996 Reviewed-by: mlugg <mlugg@mlugg.co.uk>

3 files changed, 40 insertions(+), 1 deletions(-)

src/Sema.zig+6-1
...@@ -23547,7 +23547,9 @@ fn analyzeShuffle(...@@ -23547,7 +23547,9 @@ fn analyzeShuffle(
23547 // `InternPool.Index` values using the known operands.23547 // `InternPool.Index` values using the known operands.
23548 for (mask_shuffle_two, mask_ip_index) |in, *out| {23548 for (mask_shuffle_two, mask_ip_index) |in, *out| {
23549 const val: Value = switch (in.unwrap()) {23549 const val: Value = switch (in.unwrap()) {
23550 .undef => try pt.undefValue(elem_ty),23550 // Special case zero bit types: there is no undefined value for OPV elements.
23551 // Only affects the case where `!a_rt and !b_rt` since `a_coerced` and `b_coerced`'s types are also OPV for OPV elements.
23552 .undef => try elem_ty.onePossibleValue(pt) orelse try pt.undefValue(elem_ty),
23551 .a_elem => |idx| try maybe_a_val.?.elemValue(pt, idx),23553 .a_elem => |idx| try maybe_a_val.?.elemValue(pt, idx),
23552 .b_elem => |idx| try maybe_b_val.?.elemValue(pt, idx),23554 .b_elem => |idx| try maybe_b_val.?.elemValue(pt, idx),
23553 };23555 };
...@@ -23596,6 +23598,9 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C...@@ -23596,6 +23598,9 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
23596 const a = try sema.coerce(block, vec_ty, sema.resolveInst(extra.a), a_src);23598 const a = try sema.coerce(block, vec_ty, sema.resolveInst(extra.a), a_src);
23597 const b = try sema.coerce(block, vec_ty, sema.resolveInst(extra.b), b_src);23599 const b = try sema.coerce(block, vec_ty, sema.resolveInst(extra.b), b_src);
2359823600
23601 // special case zero bit types
23602 if (try vec_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
23603
23599 const maybe_pred = sema.resolveValue(pred);23604 const maybe_pred = sema.resolveValue(pred);
23600 const maybe_a = sema.resolveValue(a);23605 const maybe_a = sema.resolveValue(a);
23601 const maybe_b = sema.resolveValue(b);23606 const maybe_b = sema.resolveValue(b);
test/behavior/select.zig+14
...@@ -31,6 +31,20 @@ fn selectVectors() !void {...@@ -31,6 +31,20 @@ fn selectVectors() !void {
31 _ = .{ &x, &y, &z };31 _ = .{ &x, &y, &z };
32 const xyz = @select(f32, x, y, z);32 const xyz = @select(f32, x, y, z);
33 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));33 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));
34
35 var vec_u0: @Vector(4, u0) = @splat(0);
36 var mask_u0 = @Vector(4, bool){ true, false, true, false };
37 var mask_empty = @Vector(0, i32){};
38 var vec_empty = @Vector(0, i32){};
39 _ = .{ &vec_u0, &mask_u0, &mask_empty, &vec_empty };
40 const sel_u0 = @select(u0, mask_u0, vec_u0, vec_u0);
41 const sel_u0_undefined = @select(u0, mask_u0, undefined, undefined);
42 comptime if (sel_u0[0] != 0) unreachable;
43 comptime if (sel_u0_undefined[1] != 0) unreachable;
44 const sel_empty = @select(i32, mask_empty, vec_empty, vec_empty);
45 const sel_empty_undefined = @select(i32, @Vector(0, bool){}, undefined, undefined);
46 comptime if (@as(u0, @bitCast(sel_empty)) != 0) unreachable;
47 comptime if (@as(u0, @bitCast(sel_empty_undefined)) != 0) unreachable;
34}48}
3549
36test "@select arrays" {50test "@select arrays" {
test/behavior/shuffle.zig+20
...@@ -170,3 +170,23 @@ test "@shuffle bool 2" {...@@ -170,3 +170,23 @@ test "@shuffle bool 2" {
170 try S.doTheTest();170 try S.doTheTest();
171 try comptime S.doTheTest();171 try comptime S.doTheTest();
172}172}
173
174test "@shuffle u0" {
175 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
176 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
180
181 const S = struct {
182 fn doTheTest() !void {
183 var v: @Vector(4, u0) = @splat(0);
184 const mask = @Vector(4, i32){ undefined, 0, -1, 3 };
185 _ = .{ &v, &mask };
186 const res = @shuffle(u0, v, v, mask);
187 comptime if (!std.mem.eql(u0, &@as([4]u0, res), &[4]u0{ 0, 0, 0, 0 })) unreachable;
188 }
189 };
190 try S.doTheTest();
191 try comptime S.doTheTest();
192}