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 }