diff --git a/src/Sema.zig b/src/Sema.zig index 1c2c3056a5b10dd3bb5282c7ad74886d070e3efa..c10b69fea8b0d5300d33bdbaa83f390ed463d89b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -23547,7 +23547,9 @@ fn analyzeShuffle( // `InternPool.Index` values using the known operands. for (mask_shuffle_two, mask_ip_index) |in, *out| { const val: Value = switch (in.unwrap()) { - .undef => try pt.undefValue(elem_ty), + // Special case zero bit types: there is no undefined value for OPV elements. + // Only affects the case where `!a_rt and !b_rt` since `a_coerced` and `b_coerced`'s types are also OPV for OPV elements. + .undef => try elem_ty.onePossibleValue(pt) orelse try pt.undefValue(elem_ty), .a_elem => |idx| try maybe_a_val.?.elemValue(pt, idx), .b_elem => |idx| try maybe_b_val.?.elemValue(pt, idx), }; @@ -23596,6 +23598,9 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C const a = try sema.coerce(block, vec_ty, sema.resolveInst(extra.a), a_src); const b = try sema.coerce(block, vec_ty, sema.resolveInst(extra.b), b_src); + // special case zero bit types + if (try vec_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); + const maybe_pred = sema.resolveValue(pred); const maybe_a = sema.resolveValue(a); const maybe_b = sema.resolveValue(b); diff --git a/test/behavior/select.zig b/test/behavior/select.zig index f3a8eda1416e62e69db9e5d4c620c77df8070e20..0bac089d7be2db12da742b2b45b8141075805e38 100644 --- a/test/behavior/select.zig +++ b/test/behavior/select.zig @@ -31,6 +31,20 @@ fn selectVectors() !void { _ = .{ &x, &y, &z }; const xyz = @select(f32, x, y, z); try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 })); + + var vec_u0: @Vector(4, u0) = @splat(0); + var mask_u0 = @Vector(4, bool){ true, false, true, false }; + var mask_empty = @Vector(0, i32){}; + var vec_empty = @Vector(0, i32){}; + _ = .{ &vec_u0, &mask_u0, &mask_empty, &vec_empty }; + const sel_u0 = @select(u0, mask_u0, vec_u0, vec_u0); + const sel_u0_undefined = @select(u0, mask_u0, undefined, undefined); + comptime if (sel_u0[0] != 0) unreachable; + comptime if (sel_u0_undefined[1] != 0) unreachable; + const sel_empty = @select(i32, mask_empty, vec_empty, vec_empty); + const sel_empty_undefined = @select(i32, @Vector(0, bool){}, undefined, undefined); + comptime if (@as(u0, @bitCast(sel_empty)) != 0) unreachable; + comptime if (@as(u0, @bitCast(sel_empty_undefined)) != 0) unreachable; } test "@select arrays" { diff --git a/test/behavior/shuffle.zig b/test/behavior/shuffle.zig index 871852111025055a87858b65656ad15dc27062fe..e61e8f17a8d940c94b054228894bf6d799aa4c8d 100644 --- a/test/behavior/shuffle.zig +++ b/test/behavior/shuffle.zig @@ -170,3 +170,23 @@ test "@shuffle bool 2" { try S.doTheTest(); try comptime S.doTheTest(); } + +test "@shuffle u0" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = struct { + fn doTheTest() !void { + var v: @Vector(4, u0) = @splat(0); + const mask = @Vector(4, i32){ undefined, 0, -1, 3 }; + _ = .{ &v, &mask }; + const res = @shuffle(u0, v, v, mask); + comptime if (!std.mem.eql(u0, &@as([4]u0, res), &[4]u0{ 0, 0, 0, 0 })) unreachable; + } + }; + try S.doTheTest(); + try comptime S.doTheTest(); +}