I need a ridiculous fast way to convert
counts: [2][6]u8,
to
bits: u12;
where each bit is set if the counts is set.
Is that possible without a loop? I tried an inline loop, but that is much much much too slow.
pub fn update_bits(self: *Material) void {
var bits: u12 = 0;
var m: u12 = 1;
inline for (0..2) |c| {
inline for (0..6) |p| {
if (self.counts[c][p] != 0) {
bits |= m;
}
m <<= 1;
}
}
self.bits = bits;
}
You could try casting the array to a @Vector(12, u8) and then use @as(u12, @bitCast(vector != zero)) where zero is a vector filled with zeroes.
2 Likes
fn foo(counts: [2][6]u8) u12 {
const vecForm: @Vector(12, u8) = @as([12]u8, @bitCast(counts));
const ok: @Vector(12, bool) = vecForm != @as(@Vector(12, u8), @splat(0));
const bitVec: @Vector(12, u12) = comptime @as(@Vector(12, u12), @splat(1)) << std.simd.iota(u12, 12);
return @reduce(.Or, @select(u12, ok, bitVec, @as(@Vector(12, u12), @splat(0))));
}
pub fn main() void {
const counts: [2][6]u8 = .{
.{0,1,0,0,0,1},
.{1,0,0,1,1,0},
};
const ans = foo(counts);
std.debug.print("{b}\n", .{ans});
}
This outputs
11001100010
Is that what you are looking for?
Also, we can do more optimizations if you guarantee that the u8 values in count will be forced to be either 1 or 0.
Semantically, this could copy the array, which would be unwanted. Feeding it to godbolt shows a pass by reference, but it’s not clear how robust that is.
Not the interesting part of your post, but perhaps worth mentioning.
1 Like
i will check that.
currently i do a “incremental” update each time a value changes, which is the fastest i could think of.
i’ll try your code