1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;
6const math = std.math;
7const maxInt = std.math.maxInt;
8const minInt = std.math.minInt;
9const native_endian = builtin.target.cpu.arch.endian();
10
11test "@bitCast iX -> uX (32, 64)" {
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
13
14 const bit_values = [_]usize{ 32, 64 };
15
16 inline for (bit_values) |bits| {
17 try testBitCast(bits);
18 try comptime testBitCast(bits);
19 }
20}
21
22test "@bitCast iX -> uX (8, 16, 128)" {
23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
26 const bit_values = [_]usize{ 8, 16, 128 };
27
28 inline for (bit_values) |bits| {
29 try testBitCast(bits);
30 try comptime testBitCast(bits);
31 }
32}
33
34test "@bitCast iX -> uX exotic integers" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
38 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
39
40 const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 };
41
42 inline for (bit_values) |bits| {
43 try testBitCast(bits);
44 try comptime testBitCast(bits);
45 }
46}
47
48fn testBitCast(comptime N: usize) !void {
49 const iN = @Int(.signed, N);
50 const uN = @Int(.unsigned, N);
51
52 try expect(conv_iN(N, -1) == maxInt(uN));
53 try expect(conv_uN(N, maxInt(uN)) == -1);
54
55 try expect(conv_iN(N, maxInt(iN)) == maxInt(iN));
56 try expect(conv_uN(N, maxInt(iN)) == maxInt(iN));
57
58 try expect(conv_uN(N, 1 << (N - 1)) == minInt(iN));
59 try expect(conv_iN(N, minInt(iN)) == (1 << (N - 1)));
60
61 try expect(conv_uN(N, 0) == 0);
62 try expect(conv_iN(N, 0) == 0);
63
64 if (N > 24) {
65 try expect(conv_uN(N, 0xf23456) == 0xf23456);
66 }
67}
68
69fn conv_iN(comptime N: usize, x: @Int(.signed, N)) @Int(.unsigned, N) {
70 return @as(@Int(.unsigned, N), @bitCast(x));
71}
72
73fn conv_uN(comptime N: usize, x: @Int(.unsigned, N)) @Int(.signed, N) {
74 return @as(@Int(.signed, N), @bitCast(x));
75}
76
77test "nested bitcast" {
78 const S = struct {
79 fn moo(x: isize) !void {
80 try expect(@as(isize, @intCast(42)) == x);
81 }
82
83 fn foo(x: isize) !void {
84 try @This().moo(
85 @as(isize, @bitCast(if (x != 0) @as(usize, @bitCast(x)) else @as(usize, @bitCast(x)))),
86 );
87 }
88 };
89
90 try S.foo(42);
91 try comptime S.foo(42);
92}
93
94// issue #3010: compiler segfault
95test "bitcast literal [4]u8 param to u32" {
96 const ip = @as(u32, @bitCast([_]u8{ 255, 255, 255, 255 }));
97 try expect(ip == maxInt(u32));
98}
99
100test "bitcast generates a temporary value" {
101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
102
103 var y: u16 = 0x55AA;
104 _ = &y;
105 const x: u16 = @bitCast(@as([2]u8, @bitCast(y)));
106 try expect(y == x);
107}
108
109test "@bitCast packed structs at runtime and comptime" {
110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
114
115 const Full = packed struct {
116 number: u16,
117 };
118 const Divided = packed struct {
119 half1: u8,
120 quarter3: u4,
121 quarter4: u4,
122 };
123 const S = struct {
124 fn doTheTest() !void {
125 var full = Full{ .number = 0x1234 };
126 _ = &full;
127 const two_halves: Divided = @bitCast(full);
128 try expect(two_halves.half1 == 0x34);
129 try expect(two_halves.quarter3 == 0x2);
130 try expect(two_halves.quarter4 == 0x1);
131 }
132 };
133 try S.doTheTest();
134 try comptime S.doTheTest();
135}
136
137test "bitcast packed struct to integer and back" {
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
139 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
141
142 const LevelUpMove = packed struct {
143 move_id: u9,
144 level: u7,
145 };
146 const S = struct {
147 fn doTheTest() !void {
148 var move = LevelUpMove{ .move_id = 1, .level = 2 };
149 _ = &move;
150 const v: u16 = @bitCast(move);
151 const back_to_a_move: LevelUpMove = @bitCast(v);
152 try expect(back_to_a_move.move_id == 1);
153 try expect(back_to_a_move.level == 2);
154 }
155 };
156 try S.doTheTest();
157 try comptime S.doTheTest();
158}
159
160test "implicit cast to error union by returning" {
161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
163
164 const S = struct {
165 fn entry() !void {
166 try expect((func(-1) catch unreachable) == maxInt(u64));
167 }
168 pub fn func(sz: i64) anyerror!u64 {
169 return @as(u64, @bitCast(sz));
170 }
171 };
172 try S.entry();
173 try comptime S.entry();
174}
175
176test "bitcast packed struct literal to byte" {
177 const Foo = packed struct {
178 value: u8,
179 };
180 const casted = @as(u8, @bitCast(Foo{ .value = 0xF }));
181 try expect(casted == 0xf);
182}
183
184test "comptime bitcast used in expression has the correct type" {
185 const Foo = packed struct {
186 value: u8,
187 };
188 try expect(@as(u8, @bitCast(Foo{ .value = 0xF })) == 0xf);
189}
190
191test "bitcast passed as tuple element" {
192 const S = struct {
193 fn foo(args: anytype) !void {
194 comptime assert(@TypeOf(args[0]) == f32);
195 try expect(args[0] == 12.34);
196 }
197 };
198 try S.foo(.{@as(f32, @bitCast(@as(u32, 0x414570A4)))});
199}
200
201test "triple level result location with bitcast sandwich passed as tuple element" {
202 const S = struct {
203 fn foo(args: anytype) !void {
204 comptime assert(@TypeOf(args[0]) == f64);
205 try expect(args[0] > 12.33 and args[0] < 12.35);
206 }
207 };
208 try S.foo(.{@as(f64, @as(f32, @bitCast(@as(u32, 0x414570A4))))});
209}
210
211test "@bitCast packed struct of floats" {
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
215 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
216 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
217
218 const Foo = packed struct {
219 a: f16 = 0,
220 b: f32 = 1,
221 c: f64 = 2,
222 d: f128 = 3,
223 };
224
225 const Foo2 = packed struct {
226 a: f16 = 0,
227 b: f32 = 1,
228 c: f64 = 2,
229 d: f128 = 3,
230 };
231
232 const S = struct {
233 fn doTheTest() !void {
234 var foo = Foo{};
235 _ = &foo;
236 const v: Foo2 = @bitCast(foo);
237 try expect(v.a == foo.a);
238 try expect(v.b == foo.b);
239 try expect(v.c == foo.c);
240 try expect(v.d == foo.d);
241 }
242 };
243 try S.doTheTest();
244 try comptime S.doTheTest();
245}
246
247test "comptime @bitCast packed struct to int and back" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
253
254 const S = packed struct {
255 void: void = {},
256 uint: u8 = 13,
257 uint_bit_aligned: u3 = 2,
258 iint_pos: i4 = 1,
259 iint_neg4: i3 = -4,
260 iint_neg2: i3 = -2,
261 float: f32 = 3.14,
262 @"enum": enum(u2) { A, B = 1, C, D } = .B,
263 };
264 const Int = @typeInfo(S).@"struct".backing_integer.?;
265
266 // S -> Int
267 var s: S = .{};
268 _ = &s;
269 try expectEqual(@as(Int, @bitCast(s)), comptime @as(Int, @bitCast(S{})));
270
271 // Int -> S
272 var i: Int = 0;
273 _ = &i;
274 const rt_cast = @as(S, @bitCast(i));
275 const ct_cast = comptime @as(S, @bitCast(@as(Int, 0)));
276 inline for (@typeInfo(S).@"struct".field_names) |field_name| {
277 try expectEqual(@field(rt_cast, field_name), @field(ct_cast, field_name));
278 }
279}
280
281test "bitcast vector to integer and back" {
282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
284 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
285 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
286
287 var vec: @Vector(16, bool) = @splat(true);
288 vec[1] = false;
289
290 const int: u16 = @bitCast(vec);
291 try expect(int == 0b1111_1111_1111_1101);
292
293 const vec_again: @Vector(16, bool) = @bitCast(int);
294 try expect(vec_again[0]);
295 try expect(!vec_again[1]);
296 try expect(vec_again[2]);
297 try expect(vec_again[3]);
298 try expect(vec_again[4]);
299 try expect(vec_again[5]);
300 try expect(vec_again[6]);
301 try expect(vec_again[7]);
302 try expect(vec_again[8]);
303 try expect(vec_again[9]);
304 try expect(vec_again[10]);
305 try expect(vec_again[11]);
306 try expect(vec_again[12]);
307 try expect(vec_again[13]);
308 try expect(vec_again[14]);
309 try expect(vec_again[15]);
310
311 const int_again: u16 = @bitCast(vec_again);
312 try expect(int_again == 0b1111_1111_1111_1101);
313}
314
315fn bitCastWrapper16(x: f16) u16 {
316 return @as(u16, @bitCast(x));
317}
318fn bitCastWrapper32(x: f32) u32 {
319 return @as(u32, @bitCast(x));
320}
321fn bitCastWrapper64(x: f64) u64 {
322 return @as(u64, @bitCast(x));
323}
324fn bitCastWrapper128(x: f128) u128 {
325 return @as(u128, @bitCast(x));
326}
327test "bitcast nan float does not modify signaling bit" {
328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
329 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
330 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
331 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
332 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
333
334 const snan_u16: u16 = 0x7D00;
335 const snan_u32: u32 = 0x7FA00000;
336 const snan_u64: u64 = 0x7FF4000000000000;
337 const snan_u128: u128 = 0x7FFF4000000000000000000000000000;
338
339 // 16 bit
340 const snan_f16_const = math.snan(f16);
341 try expectEqual(snan_u16, @as(u16, @bitCast(snan_f16_const)));
342 try expectEqual(snan_u16, bitCastWrapper16(snan_f16_const));
343
344 var snan_f16_var = math.snan(f16);
345 _ = &snan_f16_var;
346 try expectEqual(snan_u16, @as(u16, @bitCast(snan_f16_var)));
347 try expectEqual(snan_u16, bitCastWrapper16(snan_f16_var));
348
349 // 32 bit
350 const snan_f32_const = math.snan(f32);
351 try expectEqual(snan_u32, @as(u32, @bitCast(snan_f32_const)));
352 try expectEqual(snan_u32, bitCastWrapper32(snan_f32_const));
353
354 var snan_f32_var = math.snan(f32);
355 _ = &snan_f32_var;
356 try expectEqual(snan_u32, @as(u32, @bitCast(snan_f32_var)));
357 try expectEqual(snan_u32, bitCastWrapper32(snan_f32_var));
358
359 // 64 bit
360 const snan_f64_const = math.snan(f64);
361 try expectEqual(snan_u64, @as(u64, @bitCast(snan_f64_const)));
362 try expectEqual(snan_u64, bitCastWrapper64(snan_f64_const));
363
364 var snan_f64_var = math.snan(f64);
365 _ = &snan_f64_var;
366 try expectEqual(snan_u64, @as(u64, @bitCast(snan_f64_var)));
367 try expectEqual(snan_u64, bitCastWrapper64(snan_f64_var));
368
369 // 128 bit
370 const snan_f128_const = math.snan(f128);
371 try expectEqual(snan_u128, @as(u128, @bitCast(snan_f128_const)));
372 try expectEqual(snan_u128, bitCastWrapper128(snan_f128_const));
373
374 var snan_f128_var = math.snan(f128);
375 _ = &snan_f128_var;
376 try expectEqual(snan_u128, @as(u128, @bitCast(snan_f128_var)));
377 try expectEqual(snan_u128, bitCastWrapper128(snan_f128_var));
378}
379
380test "@bitCast of packed struct of bools all true" {
381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
383 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
384 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
385
386 const P = packed struct {
387 b0: bool,
388 b1: bool,
389 b2: bool,
390 b3: bool,
391 };
392 var p = std.mem.zeroes(P);
393 p.b0 = true;
394 p.b1 = true;
395 p.b2 = true;
396 p.b3 = true;
397 try expect(@as(u8, @as(u4, @bitCast(p))) == 15);
398}
399
400test "@bitCast of packed struct of bools all false" {
401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
403 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
404
405 const P = packed struct {
406 b0: bool,
407 b1: bool,
408 b2: bool,
409 b3: bool,
410 };
411 var p = std.mem.zeroes(P);
412 p.b0 = false;
413 p.b1 = false;
414 p.b2 = false;
415 p.b3 = false;
416 try expect(@as(u8, @as(u4, @bitCast(p))) == 0);
417}
418
419test "@bitCast of packed struct with void field to integer" {
420 const S = packed struct(u8) {
421 v: void,
422 x: u8,
423
424 fn doTheTest(x: u8) !void {
425 // Intentionally using `@as` to avoid RLS which masks the bug
426 const foo = @as(@This(), .{ .v = {}, .x = x });
427 const as_int: u8 = @bitCast(foo);
428 try expect(as_int == x);
429 }
430 };
431 try S.doTheTest(123);
432 try comptime S.doTheTest(123);
433}
434
435test "@bitCast of packed struct with void field and multiple integers" {
436 const S = packed struct {
437 x: u8,
438 v: void,
439 y: u8,
440
441 fn doTheTest(x: u8, y: u8) !void {
442 const foo = @as(@This(), .{ .x = x, .v = {}, .y = y });
443 const as_int: u16 = @bitCast(foo);
444 try expect(as_int == @as(u16, y) << 8 | x);
445 }
446 };
447 try S.doTheTest(123, 45);
448 try comptime S.doTheTest(123, 45);
449}
450
451test "@bitCast vector to array with different element size" {
452 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
453
454 const static = struct {
455 fn doTheTest(v: @Vector(4, u5)) !void {
456 const result: [5]u4 = @bitCast(v);
457 // See the definition of `v` in the test proper for these values.
458 try expect(result[0] == 0b0010);
459 try expect(result[1] == 0b1110);
460 try expect(result[2] == 0b0101);
461 try expect(result[3] == 0b0110);
462 try expect(result[4] == 0b0000);
463 }
464 };
465 // The strange digit groupings here are to indicate how this maps to `expected` above.
466 const v: @Vector(4, u5) = .{
467 0b0_0010,
468 0b01_111,
469 0b110_01,
470 0b0000_0,
471 };
472 try static.doTheTest(v);
473 try comptime static.doTheTest(v);
474}
475
476test "@bitCast packed struct to array of bits" {
477 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
478
479 const S = packed struct(u16) {
480 foo: u5,
481 bar: i7,
482 baz: u3,
483 qux: bool,
484 fn doTheTest(val: @This(), comptime Bits: type) !void {
485 const bits: Bits = @bitCast(val);
486
487 // foo
488 try expect(bits[0] == 1);
489 try expect(bits[1] == 0);
490 try expect(bits[2] == 0);
491 try expect(bits[3] == 1);
492 try expect(bits[4] == 0);
493 // bar
494 try expect(bits[5] == 0);
495 try expect(bits[6] == 1);
496 try expect(bits[7] == 1);
497 try expect(bits[8] == 1);
498 try expect(bits[9] == 1);
499 try expect(bits[10] == 1);
500 try expect(bits[11] == 1);
501 // baz
502 try expect(bits[12] == 0);
503 try expect(bits[13] == 1);
504 try expect(bits[14] == 0);
505 // qux
506 try expect(bits[15] == 1);
507 }
508 };
509
510 const val: S = .{
511 .foo = 0b01001,
512 .bar = -2,
513 .baz = 0b010,
514 .qux = true,
515 };
516
517 try val.doTheTest(@Vector(16, u1));
518 try val.doTheTest([16]u1);
519
520 try comptime val.doTheTest(@Vector(16, u1));
521 try comptime val.doTheTest([16]u1);
522}
523
524test "@bitCast nested arrays of vectors" {
525 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
526
527 const Src = [2][2]@Vector(4, u5);
528 const Dest = [5]@Vector(2, u8);
529
530 // The strange digit groupings here are to indicate how this maps to the output.
531 const src: Src = .{ .{
532 .{ 0b00011, 0b00_100, 0b11100, 0b0010_1 },
533 .{ 0b1_0110, 0b11011, 0b101_10, 0b10101 },
534 }, .{
535 .{ 0b10101, 0b00_001, 0b01011, 0b0001_0 },
536 .{ 0b0_0001, 0b01111, 0b111_10, 0b00001 },
537 } };
538
539 const expected: Dest = .{
540 .{ 0b10000011, 0b11110000 },
541 .{ 0b01100010, 0b10110111 },
542 .{ 0b10101101, 0b00110101 },
543 .{ 0b00101100, 0b00010001 },
544 .{ 0b10011110, 0b00001111 },
545 };
546
547 const static = struct {
548 fn doTheTest(src_arg: Src) !void {
549 const actual: Dest = @bitCast(src_arg);
550 for (actual, expected) |actual_vec, expected_vec| {
551 try expect(actual_vec[0] == expected_vec[0]);
552 try expect(actual_vec[1] == expected_vec[1]);
553 }
554 }
555 };
556
557 try static.doTheTest(src);
558 try comptime static.doTheTest(src);
559}
560
561test "@bitCast nested arrays of bool to scalar" {
562 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
563
564 const static = struct {
565 fn doTheTest(src: [4][4]bool) !void {
566 const result: u16 = @bitCast(src);
567 try expect(result == 0b1100_0101_1010_0011);
568 }
569 };
570 const src: [4][4]bool = .{
571 .{ true, true, false, false }, // 0b0011
572 .{ false, true, false, true }, // 0b1010
573 .{ true, false, true, false }, // 0b0101
574 .{ false, false, true, true }, // 0b1100
575 };
576 try static.doTheTest(src);
577 try comptime static.doTheTest(src);
578}
579
580test "@bitCast deeply nested arrays to scalar" {
581 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
582
583 const static = struct {
584 fn doTheTest(src: [2][1][3][5]u4) !void {
585 const signed: i120 = @bitCast(src);
586 try expect(signed < 0); // top nibble is 0x8 so sign bit is 1
587 const unsigned: u120 = @bitCast(src);
588 try expect(unsigned == 0x8873B_5BF6F_F4020_0E7AC_1EFED_40F51);
589 try expect(@as(i120, @bitCast(unsigned)) == signed);
590 try expect(@as(u120, @bitCast(signed)) == unsigned);
591 }
592 };
593 const src: [2][1][3][5]u4 = .{ .{.{
594 .{ 0x1, 0x5, 0xF, 0x0, 0x4 },
595 .{ 0xD, 0xE, 0xF, 0xE, 0x1 },
596 .{ 0xC, 0xA, 0x7, 0xE, 0x0 },
597 }}, .{.{
598 .{ 0x0, 0x2, 0x0, 0x4, 0xF },
599 .{ 0xF, 0x6, 0xF, 0xB, 0x5 },
600 .{ 0xB, 0x3, 0x7, 0x8, 0x8 },
601 }} };
602 try static.doTheTest(src);
603 try comptime static.doTheTest(src);
604}