lib/simd/src/cast.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 pub fn bitCast(comptime D: type, value: anytype) D.Vector {
4 if (@bitSizeOf(@TypeOf(value)) / 8 != D.byte_count) {
5 @compileError("bitCast requires equal source and destination byte sizes");
6 }
7 return @bitCast(value);
8 }
9
10 pub fn resizeBitCast(comptime D: type, value: anytype) D.Vector {
11 return resize(D, value);
12 }
13
14 pub fn zeroExtendResizeBitCast(
15 comptime DTo: type,
16 comptime DFrom: type,
17 value: DFrom.Vector,
18 ) DTo.Vector {
19 return resize(DTo, value);
20 }
21
22 fn resize(comptime D: type, value: anytype) D.Vector {
23 const source_byte_count = @bitSizeOf(@TypeOf(value)) / 8;
24 const SourceBytes = [source_byte_count]u8;
25 const source: SourceBytes = @bitCast(value);
26 var target: [D.byte_count]u8 = @splat(0);
27 inline for (0..@min(source_byte_count, D.byte_count)) |index| {
28 target[index] = source[index];
29 }
30 return @bitCast(target);
31 }
32
33 test "Highway bit casts preserve every source bit" {
34 const simd = @import("root.zig");
35 const DW = simd.FixedTag(u32, 4);
36 const DB = simd.FixedTag(u8, 16);
37 const words: DW.Vector = .{ 0x0123_4567, 0x89ab_cdef, 0, 0xffff_ffff };
38 const bytes = bitCast(DB, words);
39 try std.testing.expect(@reduce(.And, bitCast(DW, bytes) == words));
40 }
41
42 test "Highway resize casts retain low-address bytes and zero extensions" {
43 const simd = @import("root.zig");
44 const D = simd.FixedTag(u16, 8);
45 const DH = simd.FixedTag(u16, 4);
46 const DT = simd.FixedTag(u16, 16);
47 const value: D.Vector = .{ 1, 2, 3, 4, 5, 6, 7, 8 };
48 try std.testing.expect(@reduce(.And, resizeBitCast(DH, value) ==
49 @as(DH.Vector, .{ 1, 2, 3, 4 })));
50 try std.testing.expect(@reduce(.And, zeroExtendResizeBitCast(DT, D, value) ==
51 @as(DT.Vector, .{ 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0 })));
52 }
53
54 test "Highway resize casts work across lane types" {
55 const simd = @import("root.zig");
56 inline for (.{ u8, i8, u16, i16, u32, i32, u64, i64, f16, f32, f64 }) |T| {
57 const D = simd.FixedTag(T, 4);
58 const DB = simd.FixedTag(u8, D.byte_count);
59 const DT = simd.FixedTag(T, 8);
60 const value: D.Vector = @splat(0);
61 try std.testing.expect(@reduce(.And, bitCast(D, bitCast(DB, value)) == value));
62 const extended = zeroExtendResizeBitCast(DT, D, value);
63 try std.testing.expect(@reduce(.And, resizeBitCast(D, extended) == value));
64 try std.testing.expect(@reduce(.And, extended == @as(DT.Vector, @splat(0))));
65 }
66 }