Mask numbers within a range with Vectors

I want to be able to apply a SIMD operation to numbers within a range (i.e. 4 < n < 11). I got it working with the following code, but from it I have two questions:

  1. Is there a way to and two vectors of bools without bit casting to an integer as shown in the code?
  2. Is there a better way of creating such a range mask with vectors in Zig?
const std = @import("std");
const simd = std.simd;

pub fn main() !void {
    const vec_len = simd.suggestVectorLength(u8) orelse unreachable;
    const BitVec = @Vector(vec_len, u1);
    const ByteVec = @Vector(vec_len, u8);
    const Int = std.meta.Int(.unsigned, vec_len);

    const array = [_]u8{ 1, 10, 3, 4, 5, 6, 2, 1, 9, 10, 11, 12, 8, 14, 15, 16, 17, 18, 19, 20 };
    const v1: ByteVec = array[0..][0..vec_len].*;

    const fours: ByteVec = @splat(4);
    const gt_four = v1 > fours;

    const elevens: ByteVec = @splat(11);
    const lt_eleven = v1 < elevens;

    // Can't do this
    // const in_range = gt_four and lt_eleven;

    // So have to do this
    const gt_four_int: Int = @bitCast(gt_four);
    const lt_eleven_int: Int = @bitCast(lt_eleven);
    const in_range_int: Int = gt_four_int & lt_eleven_int;
    const in_range_bits: BitVec = @bitCast(in_range_int);

    const twos: ByteVec = @splat(2);
    const masked: ByteVec = in_range_bits * twos;
    const added: ByteVec = v1 + masked;

    std.debug.print("{any}\n", .{added});
}
error: expected type 'bool', found '@Vector(20, bool)'
    const in_range: BoolVec = gt_four and lt_eleven;
                              ^~~~~~~

:cry: `and` cannot operate on vectors of bool despite the manual claiming otherwise · Issue #14306 · ziglang/zig · GitHub

1 Like

Just read the thread. Hmmm, seems like a deep rabbit hole to me. I think the option of allowing bitwise ops on vectors of bools would be a good alternative then.

// NOTE: Not valid Zig code (yet?)

// So this
const in_range_bits: BitVec = gt_four & lt_eleven;

// would result in the same vector as all this:
const gt_four_int: Int = @bitCast(gt_four);
const lt_eleven_int: Int = @bitCast(lt_eleven);
const in_range_int: Int = gt_four_int & lt_eleven_int;
const in_range_bits: BitVec = @bitCast(in_range_int);
2 Likes

Exactly, it seems the problem have to do with and shortcut, that does not evaluate the second argument if the first is true.
For now, u1 instead of bool, @intFromBool to initialize u1 from bool, and bitwise operations is a workaround.

1 Like