authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-15 23:07:40+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-15 23:07:40+02:00
loge00b5daa1fda95a58cce42016d158e283e23d130
treec2f38d273769a935cf07a2a662ee78bdc9dede0c
parentc32f7a451356817091f874a97c78dd9abb9468fe
parent773def30c24f739647112e8221fdf398b5ef12e7

Merge pull request 'stage2-wasm: finish bigint support' (#31784) from pavelverigo/zig:wasm-bigint-finish into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31784 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

19 files changed, 2304 insertions(+), 339 deletions(-)

lib/compiler_rt/divmodei4.zig+40-17
......@@ -10,29 +10,30 @@ const symbol = @import("../compiler_rt.zig").symbol;
1010comptime {
1111 symbol(&__divei4, "__divei4");
1212 symbol(&__modei4, "__modei4");
13 symbol(&__divei5, "__divei5");
14 symbol(&__modei5, "__modei5");
1315}
1416
15inline fn limb(x: []u32, i: usize) *u32 {
16 return if (endian == .little) &x[i] else &x[x.len - 1 - i];
17inline fn limb(i: usize, len: usize) usize {
18 return if (endian == .little) i else len - 1 - i;
1719}
1820
19inline fn neg(x: []u32) void {
21inline fn neg(out: []u32, in: []const u32) void {
2022 var ov: u1 = 1;
21 for (0..x.len) |limb_index| {
22 const l = limb(x, limb_index);
23 l.*, ov = @addWithOverflow(~l.*, ov);
23 for (0..in.len) |limb_index| {
24 const new, ov = @addWithOverflow(~in[limb(limb_index, in.len)], ov);
25 out[limb(limb_index, out.len)] = new;
2426 }
2527}
2628
27/// Mutates the arguments!
28fn divmod(q: ?[]u32, r: ?[]u32, u: []u32, v: []u32) !void {
29 const u_sign: i32 = @bitCast(u[u.len - 1]);
30 const v_sign: i32 = @bitCast(v[v.len - 1]);
31 if (u_sign < 0) neg(u);
32 if (v_sign < 0) neg(v);
33 try @call(.always_inline, udivmod, .{ q, r, u, v });
34 if (q) |x| if (u_sign ^ v_sign < 0) neg(x);
35 if (r) |x| if (u_sign < 0) neg(x);
29fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32, tu: []u32, tv: []u32) !void {
30 const u_sign: i32 = @bitCast(u[limb(u.len - 1, u.len)]);
31 const v_sign: i32 = @bitCast(v[limb(v.len - 1, v.len)]);
32 if (u_sign < 0) neg(tu, u);
33 if (v_sign < 0) neg(tv, v);
34 try @call(.always_inline, udivmod, .{ q, r, if (u_sign < 0) tu else u, if (v_sign < 0) tv else v });
35 if (q) |x| if (u_sign ^ v_sign < 0) neg(x, x);
36 if (r) |x| if (u_sign < 0) neg(x, x);
3637}
3738
3839pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
......@@ -41,7 +42,7 @@ pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) vo
4142 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
4243 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
4344 const v: []u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
44 @call(.always_inline, divmod, .{ q, null, u, v }) catch unreachable;
45 @call(.always_inline, divmod, .{ q, null, u, v, u, v }) catch unreachable;
4546}
4647
4748pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
......@@ -50,5 +51,27 @@ pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) vo
5051 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
5152 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
5253 const v: []u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
53 @call(.always_inline, divmod, .{ null, r, u, v }) catch unreachable;
54 @call(.always_inline, divmod, .{ null, r, u, v, u, v }) catch unreachable;
55}
56
57pub fn __divei5(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, t_p: [*]u8, bits: usize) callconv(.c) void {
58 @setRuntimeSafety(compiler_rt.test_safety);
59 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
60 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
61 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
62 const v: []const u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
63 const tu: []u32 = @ptrCast(@alignCast(t_p[0..byte_size]));
64 const tv: []u32 = @ptrCast(@alignCast(t_p[byte_size..][0..byte_size]));
65 @call(.always_inline, divmod, .{ q, null, u, v, tu, tv }) catch unreachable;
66}
67
68pub fn __modei5(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, t_p: [*]u8, bits: usize) callconv(.c) void {
69 @setRuntimeSafety(compiler_rt.test_safety);
70 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
71 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
72 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
73 const v: []const u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
74 const tu: []u32 = @ptrCast(@alignCast(t_p[0..byte_size]));
75 const tv: []u32 = @ptrCast(@alignCast(t_p[byte_size..][0..byte_size]));
76 @call(.always_inline, divmod, .{ null, r, u, v, tu, tv }) catch unreachable;
5477}
lib/compiler_rt/limb64.zig+875-15
......@@ -7,6 +7,7 @@ const divCeil = std.math.divCeil;
77
88const builtin = @import("builtin");
99const compiler_rt = @import("../compiler_rt.zig");
10const symbol = @import("../compiler_rt.zig").symbol;
1011
1112const endian = builtin.cpu.arch.endian();
1213
......@@ -24,10 +25,44 @@ inline fn limbSet(limbs: []u64, i: usize, value: u64) void {
2425 }
2526}
2627
27fn limbCount(bits: u16) u16 {
28fn usedLimbCount(bits: u16) u16 {
2829 return divCeil(u16, bits, 64) catch unreachable;
2930}
3031
32fn limbCount(bits: u16) u16 {
33 return @divExact(std.zig.target.intByteSize(&builtin.target, bits), 8);
34}
35
36fn varLimbs(ptr: [*]u64, bits: u16) []u64 {
37 const limb_cnt = usedLimbCount(bits);
38 const true_limb_cnt = limbCount(bits);
39 return switch (endian) {
40 .little => ptr[0..limb_cnt],
41 .big => ptr[true_limb_cnt - limb_cnt .. true_limb_cnt],
42 };
43}
44
45fn constLimbs(ptr: [*]const u64, bits: u16) []const u64 {
46 const limb_cnt = usedLimbCount(bits);
47 const true_limb_cnt = limbCount(bits);
48 return switch (endian) {
49 .little => ptr[0..limb_cnt],
50 .big => ptr[true_limb_cnt - limb_cnt .. true_limb_cnt],
51 };
52}
53
54fn fixLastLimb(out_ptr: [*]u64, is_signed: bool, bits: u16) void {
55 const limb_cnt = usedLimbCount(bits);
56 const true_limb_cnt = limbCount(bits);
57 if (limb_cnt == true_limb_cnt) return;
58 const true_out = out_ptr[0..true_limb_cnt];
59
60 const sign: u64 = if (!is_signed or @as(i64, @bitCast(true_out[limb_cnt - 1])) >= 0) 0 else ~@as(u64, 0);
61 for (limb_cnt..true_limb_cnt) |i| {
62 true_out[i] = sign;
63 }
64}
65
3166fn Limbs(T: type) type {
3267 const int_info = @typeInfo(T).int;
3368 const limb_cnt = comptime limbCount(int_info.bits);
......@@ -55,14 +90,14 @@ fn limbWrap(limb: u64, is_signed: bool, bits: u16) u64 {
5590}
5691
5792comptime {
58 @export(&__addo_limb64, .{ .name = "__addo_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
93 symbol(&__addo_limb64, "__addo_limb64");
5994}
6095
6196fn __addo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
62 const limb_cnt = limbCount(bits);
63 const out = out_ptr[0..limb_cnt];
64 const a = a_ptr[0..limb_cnt];
65 const b = b_ptr[0..limb_cnt];
97 const limb_cnt = usedLimbCount(bits);
98 const out = varLimbs(out_ptr, bits);
99 const a = constLimbs(a_ptr, bits);
100 const b = constLimbs(b_ptr, bits);
66101
67102 var carry: u1 = 0;
68103 var i: usize = 0;
......@@ -91,11 +126,13 @@ fn __addo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_s
91126
92127 if (bits % 64 == 0) {
93128 limbSet(out, i, limb);
129 fixLastLimb(out_ptr, is_signed, bits);
94130 return carry != 0;
95131 } else {
96132 assert(carry == 0);
97133 const wrapped_limb = limbWrap(limb, is_signed, bits);
98134 limbSet(out, i, wrapped_limb);
135 fixLastLimb(out_ptr, is_signed, bits);
99136 return wrapped_limb != limb;
100137 }
101138}
......@@ -124,17 +161,20 @@ test __addo_limb64 {
124161 try test__addo_limb64(i64, maxInt(i64), 1, .{ minInt(i64), true });
125162 try test__addo_limb64(i65, maxInt(i65), 1, .{ minInt(i65), true });
126163 try test__addo_limb64(i255, -3, 2, .{ -1, false });
164
165 try test__addo_limb64(u150, maxInt(u150), 2, .{ 1, true });
166 try test__addo_limb64(i150, -3, 2, .{ -1, false });
127167}
128168
129169comptime {
130 @export(&__subo_limb64, .{ .name = "__subo_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
170 symbol(&__subo_limb64, "__subo_limb64");
131171}
132172
133173fn __subo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
134 const limb_cnt = limbCount(bits);
135 const out = out_ptr[0..limb_cnt];
136 const a = a_ptr[0..limb_cnt];
137 const b = b_ptr[0..limb_cnt];
174 const limb_cnt = usedLimbCount(bits);
175 const out = varLimbs(out_ptr, bits);
176 const a = constLimbs(a_ptr, bits);
177 const b = constLimbs(b_ptr, bits);
138178
139179 var borrow: u1 = 0;
140180 var i: usize = 0;
......@@ -163,10 +203,12 @@ fn __subo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_s
163203
164204 if (bits % 64 == 0) {
165205 limbSet(out, i, limb);
206 fixLastLimb(out_ptr, is_signed, bits);
166207 return borrow != 0;
167208 } else {
168209 const wrapped_limb = limbWrap(limb, is_signed, bits);
169210 limbSet(out, i, wrapped_limb);
211 fixLastLimb(out_ptr, is_signed, bits);
170212 return borrow != 0 or wrapped_limb != limb;
171213 }
172214}
......@@ -195,19 +237,22 @@ test __subo_limb64 {
195237 try test__subo_limb64(i64, minInt(i64), 1, .{ maxInt(i64), true });
196238 try test__subo_limb64(i65, minInt(i65), 1, .{ maxInt(i65), true });
197239 try test__subo_limb64(i255, -1, 2, .{ -3, false });
240
241 try test__subo_limb64(u150, 2, maxInt(u150), .{ 3, true });
242 try test__subo_limb64(i150, -3, 2, .{ -5, false });
198243}
199244
200245comptime {
201 @export(&__cmp_limb64, .{ .name = "__cmp_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
246 symbol(&__cmp_limb64, "__cmp_limb64");
202247}
203248
204249// a < b -> -1
205250// a == b -> 0
206251// a > b -> 1
207252fn __cmp_limb64(a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) i8 {
208 const limb_cnt = limbCount(bits);
209 const a = a_ptr[0..limb_cnt];
210 const b = b_ptr[0..limb_cnt];
253 const limb_cnt = usedLimbCount(bits);
254 const a = constLimbs(a_ptr, bits);
255 const b = constLimbs(b_ptr, bits);
211256
212257 var i: usize = 0;
213258 if (is_signed) {
......@@ -263,4 +308,819 @@ test __cmp_limb64 {
263308 try test__cmp_limb64(i255, -3, 2, -1);
264309 try test__cmp_limb64(i255, -5, -5, 0);
265310 try test__cmp_limb64(i255, 2, -3, 1);
311
312 try test__cmp_limb64(u150, maxInt(u150) - 5, maxInt(u150) - 5, 0);
313 try test__cmp_limb64(i150, minInt(i150), -5, -1);
314}
315
316comptime {
317 symbol(&__and_limb64, "__and_limb64");
318}
319
320fn __and_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
321 const limb_cnt = limbCount(bits);
322 const out = out_ptr[0..limb_cnt];
323 const a = a_ptr[0..limb_cnt];
324 const b = b_ptr[0..limb_cnt];
325
326 var i: usize = 0;
327 while (i < limb_cnt) : (i += 1) {
328 limbSet(out, i, limbGet(a, i) & limbGet(b, i));
329 }
330}
331
332fn test__and_limb64(comptime T: type, a: T, b: T, expected: T) !void {
333 const int_info = @typeInfo(T).int;
334
335 var a_limbs = asLimbs(a);
336 var b_limbs = asLimbs(b);
337 var out: Limbs(T) = undefined;
338 __and_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
339
340 const expected_limbs = asLimbs(expected);
341 try testing.expectEqual(expected_limbs, out);
342}
343
344test __and_limb64 {
345 try test__and_limb64(u64, 1, 2, 0);
346 try test__and_limb64(u64, maxInt(u64), 2, 2);
347 try test__and_limb64(u65, maxInt(u65), 2, 2);
348 try test__and_limb64(u255, maxInt(u255), 7, 7);
349
350 try test__and_limb64(i64, 1, 2, 0);
351 try test__and_limb64(i64, -1, 2, 2);
352 try test__and_limb64(i65, minInt(i65), -1, minInt(i65));
353 try test__and_limb64(i255, -1, 2, 2);
354
355 try test__and_limb64(u150, maxInt(u150), 7, 7);
356 try test__and_limb64(i150, -2, 3, 2);
357}
358
359comptime {
360 symbol(&__or_limb64, "__or_limb64");
361}
362
363fn __or_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
364 const limb_cnt = limbCount(bits);
365 const out = out_ptr[0..limb_cnt];
366 const a = a_ptr[0..limb_cnt];
367 const b = b_ptr[0..limb_cnt];
368
369 var i: usize = 0;
370 while (i < limb_cnt) : (i += 1) {
371 limbSet(out, i, limbGet(a, i) | limbGet(b, i));
372 }
373}
374
375fn test__or_limb64(comptime T: type, a: T, b: T, expected: T) !void {
376 const int_info = @typeInfo(T).int;
377
378 var a_limbs = asLimbs(a);
379 var b_limbs = asLimbs(b);
380 var out: Limbs(T) = undefined;
381 __or_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
382
383 const expected_limbs = asLimbs(expected);
384 try testing.expectEqual(expected_limbs, out);
385}
386
387test __or_limb64 {
388 try test__or_limb64(u64, 1, 2, 3);
389 try test__or_limb64(u64, maxInt(u64), 2, maxInt(u64));
390 try test__or_limb64(u65, maxInt(u65), 2, maxInt(u65));
391 try test__or_limb64(u255, 1, 2, 3);
392
393 try test__or_limb64(i64, 1, 2, 3);
394 try test__or_limb64(i64, -1, 2, -1);
395 try test__or_limb64(i65, minInt(i65), 1, minInt(i65) + 1);
396 try test__or_limb64(i255, -3, 2, -1);
397
398 try test__or_limb64(u150, maxInt(u150) - 1, 3, maxInt(u150));
399 try test__or_limb64(i150, -2, 3, -1);
400}
401
402comptime {
403 symbol(&__xor_limb64, "__xor_limb64");
404}
405
406fn __xor_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
407 const limb_cnt = limbCount(bits);
408 const out = out_ptr[0..limb_cnt];
409 const a = a_ptr[0..limb_cnt];
410 const b = b_ptr[0..limb_cnt];
411
412 var i: usize = 0;
413 while (i < limb_cnt) : (i += 1) {
414 limbSet(out, i, limbGet(a, i) ^ limbGet(b, i));
415 }
416}
417
418fn test__xor_limb64(comptime T: type, a: T, b: T, expected: T) !void {
419 const int_info = @typeInfo(T).int;
420
421 var a_limbs = asLimbs(a);
422 var b_limbs = asLimbs(b);
423 var out: Limbs(T) = undefined;
424 __xor_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
425
426 const expected_limbs = asLimbs(expected);
427 try testing.expectEqual(expected_limbs, out);
428}
429
430test __xor_limb64 {
431 try test__xor_limb64(u64, 1, 2, 3);
432 try test__xor_limb64(u64, 3, 2, 1);
433 try test__xor_limb64(u65, maxInt(u65), 2, maxInt(u65) - 2);
434 try test__xor_limb64(u255, 7, 3, 4);
435
436 try test__xor_limb64(i64, 3, 2, 1);
437 try test__xor_limb64(i64, -1, 2, -3);
438 try test__xor_limb64(i65, minInt(i65), -1, maxInt(i65));
439 try test__xor_limb64(i255, -3, 2, -1);
440
441 try test__xor_limb64(u150, maxInt(u150) - 1, 3, maxInt(u150) - 2);
442 try test__xor_limb64(i150, -2, 3, -3);
443}
444
445comptime {
446 symbol(&__not_limb64, "__not_limb64");
447}
448
449fn __not_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
450 const limb_cnt = usedLimbCount(bits);
451 const out = varLimbs(out_ptr, bits);
452 const a = constLimbs(a_ptr, bits);
453
454 var i: usize = 0;
455 while (i < limb_cnt - 1) : (i += 1) {
456 limbSet(out, i, ~limbGet(a, i));
457 }
458
459 var limb: u64 = ~limbGet(a, i);
460 if (!is_signed and bits % 64 != 0) {
461 limb = limbWrap(limb, is_signed, bits);
462 }
463 limbSet(out, i, limb);
464 fixLastLimb(out_ptr, is_signed, bits);
465}
466
467fn test__not_limb64(comptime T: type, a: T, expected: T) !void {
468 const int_info = @typeInfo(T).int;
469 const is_signed = int_info.signedness == .signed;
470
471 var a_limbs = asLimbs(a);
472 var out: Limbs(T) = undefined;
473 __not_limb64(&out, &a_limbs, is_signed, int_info.bits);
474
475 const expected_limbs = asLimbs(expected);
476 try testing.expectEqual(expected_limbs, out);
477}
478
479test __not_limb64 {
480 try test__not_limb64(u64, 1, maxInt(u64) - 1);
481 try test__not_limb64(u64, 3, maxInt(u64) - 3);
482 try test__not_limb64(u65, maxInt(u65), 0);
483 try test__not_limb64(u255, 7, maxInt(u255) - 7);
484
485 try test__not_limb64(i64, 3, -4);
486 try test__not_limb64(i64, -1, 0);
487 try test__not_limb64(i65, minInt(i65), maxInt(i65));
488 try test__not_limb64(i255, -3, 2);
489
490 try test__not_limb64(u150, maxInt(u150), 0);
491 try test__not_limb64(i150, maxInt(i150), minInt(i150));
492}
493
494comptime {
495 symbol(&__shlo_limb64, "__shlo_limb64");
496}
497
498fn __shlo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) bool {
499 const limb_cnt = usedLimbCount(bits);
500 const out = varLimbs(out_ptr, bits);
501 const a = constLimbs(a_ptr, bits);
502
503 assert(shift < bits);
504
505 const limb_shift = shift / 64;
506 const bit_shift = shift % 64;
507
508 var carry: u64 = 0;
509 var i: usize = 0;
510 while (i < limb_cnt - 1) : (i += 1) {
511 if (i < limb_shift) {
512 limbSet(out, i, 0);
513 } else {
514 const limb = limbGet(a, i - limb_shift);
515 limbSet(out, i, (limb << @intCast(bit_shift)) | carry);
516 carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
517 }
518 }
519
520 const limb = limbGet(a, i - limb_shift);
521 const raw_last = (limb << @intCast(bit_shift)) | carry;
522 carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
523
524 const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
525 limbSet(out, i, last);
526
527 const sign_extend: u64 = if (is_signed and (last >> 63) == 1) ~@as(u64, 0) else 0;
528 const expected_carry: u64 = if (bit_shift == 0) 0 else sign_extend >> @intCast(64 - bit_shift);
529
530 var overflow = carry != expected_carry;
531 if (bits % 64 != 0) {
532 overflow = overflow or raw_last != last;
533 }
534
535 var j = limb_cnt - limb_shift;
536 while (j < limb_cnt) : (j += 1) {
537 overflow = overflow or limbGet(a, j) != sign_extend;
538 }
539
540 fixLastLimb(out_ptr, is_signed, bits);
541 return overflow;
542}
543
544fn test__shlo_limb64(comptime T: type, a: T, shift: u16, expected: struct { T, bool }) !void {
545 const int_info = @typeInfo(T).int;
546 const is_signed = int_info.signedness == .signed;
547
548 var a_limbs = asLimbs(a);
549 var out: Limbs(T) = undefined;
550 const overflow = __shlo_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
551
552 const expected_limbs = asLimbs(expected[0]);
553 try testing.expectEqual(expected_limbs, out);
554 try testing.expectEqual(expected[1], overflow);
555}
556
557test __shlo_limb64 {
558 try test__shlo_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF00, true });
559 try test__shlo_limb64(u64, 0x8000_0000_0000_0001, 63, .{ 0x8000_0000_0000_0000, true });
560 try test__shlo_limb64(u65, 1, 64, .{ 0x1_0000_0000_0000_0000, false });
561 try test__shlo_limb64(u65, 0x1_0000_0000_0000_0000, 1, .{ 0, true });
562 try test__shlo_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
563 try test__shlo_limb64(u255, maxInt(u255), 1, .{ maxInt(u255) - 1, true });
564 try test__shlo_limb64(u633, 1 << 299, 333, .{ 1 << 632, false });
565 try test__shlo_limb64(u633, 1 << 300, 333, .{ 0, true });
566 try test__shlo_limb64(u633, 1 << 298, 333, .{ 1 << 631, false });
567
568 try test__shlo_limb64(i64, -2, 1, .{ -4, false });
569 try test__shlo_limb64(i64, minInt(i64), 1, .{ 0, true });
570 try test__shlo_limb64(i64, minInt(i64), 63, .{ 0, true });
571 try test__shlo_limb64(i65, minInt(i63), 1, .{ minInt(i64), false });
572 try test__shlo_limb64(i65, -1, 17, .{ -1 << 17, false });
573 try test__shlo_limb64(i65, -3, 64, .{ -1 << 64, true });
574 try test__shlo_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ -0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
575 try test__shlo_limb64(i255, -3, 1, .{ -6, false });
576 try test__shlo_limb64(i633, 1 << 298, 333, .{ 1 << 631, false });
577 try test__shlo_limb64(i633, 1 << 299, 333, .{ minInt(i633), true });
578 try test__shlo_limb64(i633, 1 << 300, 333, .{ 0, true });
579 try test__shlo_limb64(i633, 1 << 297, 333, .{ 1 << 630, false });
580 try test__shlo_limb64(i633, -1 << 299, 333, .{ -1 << 632, false });
581 try test__shlo_limb64(i633, -1 << 300, 333, .{ 0, true });
582 try test__shlo_limb64(i633, -1 << 298, 333, .{ -1 << 631, false });
583
584 try test__shlo_limb64(u150, maxInt(u150), 1, .{ maxInt(u150) - 1, true });
585 try test__shlo_limb64(i150, -3, 1, .{ -6, false });
586}
587
588comptime {
589 symbol(&__shr_limb64, "__shr_limb64");
590}
591
592fn __shr_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) void {
593 const limb_cnt = usedLimbCount(bits);
594 const out = varLimbs(out_ptr, bits);
595 const a = constLimbs(a_ptr, bits);
596
597 assert(shift < bits);
598
599 const limb_shift = shift / 64;
600 const bit_shift = shift % 64;
601
602 const ms = limbGet(a, limb_cnt - 1);
603 const sign_extend: u64 = if (is_signed and (ms >> 63) == 1) ~@as(u64, 0) else 0;
604
605 var carry: u64 = if (bit_shift != 0) (sign_extend << @intCast(64 - bit_shift)) else 0;
606 var i: usize = 0;
607 while (i < limb_cnt) : (i += 1) {
608 const j = limb_cnt - 1 - i;
609 if (i < limb_shift) {
610 limbSet(out, j, sign_extend);
611 } else {
612 const limb = limbGet(a, j + limb_shift);
613 limbSet(out, j, (limb >> @intCast(bit_shift)) | carry);
614 carry = if (bit_shift != 0) (limb << @intCast(64 - bit_shift)) else 0;
615 }
616 }
617
618 fixLastLimb(out_ptr, is_signed, bits);
619}
620
621fn test__shr_limb64(comptime T: type, a: T, shift: u16, expected: T) !void {
622 const int_info = @typeInfo(T).int;
623 const is_signed = int_info.signedness == .signed;
624
625 var a_limbs = asLimbs(a);
626 var out: Limbs(T) = undefined;
627 __shr_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
628
629 const expected_limbs = asLimbs(expected);
630 try testing.expectEqual(expected_limbs, out);
631}
632
633test __shr_limb64 {
634 try test__shr_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF);
635 try test__shr_limb64(u64, 0x8000_0000_0000_0001, 63, 1);
636 try test__shr_limb64(u65, 0x1_0000_0000_0000_0000, 64, 1);
637 try test__shr_limb64(u65, 0x1_0000_0000_0000_0001, 1, 0x0_8000_0000_0000_0000);
638 try test__shr_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
639 try test__shr_limb64(u255, maxInt(u255), 1, maxInt(u254));
640 try test__shr_limb64(u633, 1 << 333, 333, 1);
641 try test__shr_limb64(u633, 1 << 334, 333, 2);
642 try test__shr_limb64(u633, 1 << 332, 333, 0);
643
644 try test__shr_limb64(i64, -2, 1, -1);
645 try test__shr_limb64(i64, minInt(i64), 63, -1);
646 try test__shr_limb64(i65, minInt(i65), 1, minInt(i65) | (1 << 63));
647 try test__shr_limb64(i65, -1, 17, -1);
648 try test__shr_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, -0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
649 try test__shr_limb64(i255, -3, 1, -2);
650 try test__shr_limb64(i633, 1 << 333, 333, 1);
651 try test__shr_limb64(i633, 1 << 334, 333, 2);
652 try test__shr_limb64(i633, 1 << 332, 333, 0);
653 try test__shr_limb64(i633, -1 << 333, 333, -1);
654 try test__shr_limb64(i633, -1 << 334, 333, -2);
655 try test__shr_limb64(i633, -1 << 332, 333, -1);
656
657 try test__shr_limb64(u150, maxInt(u150), 1, maxInt(u149));
658 try test__shr_limb64(i150, -3, 1, -2);
659}
660
661comptime {
662 symbol(&__clz_limb64, "__clz_limb64");
663}
664
665fn __clz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
666 const limb_cnt = usedLimbCount(bits);
667 const a = constLimbs(a_ptr, bits);
668
669 var res: u16 = 0;
670 var i: usize = 0;
671
672 if (bits % 64 != 0) {
673 const limb = limbGet(a, limb_cnt - 1);
674 if (limb == 0) {
675 res += bits % 64;
676 } else {
677 return @clz(limb << @intCast(64 - bits % 64));
678 }
679 i += 1;
680 }
681
682 while (i < limb_cnt) : (i += 1) {
683 const j = limb_cnt - 1 - i;
684 const limb = limbGet(a, j);
685 if (limb == 0) {
686 res += 64;
687 } else {
688 res += @clz(limb);
689 break;
690 }
691 }
692
693 return res;
694}
695
696fn test__clz_limb64(comptime T: type, a: T, expected: u16) !void {
697 const int_info = @typeInfo(T).int;
698
699 var a_limbs = asLimbs(a);
700 const out = __clz_limb64(&a_limbs, int_info.bits);
701
702 try testing.expectEqual(expected, out);
703}
704
705test __clz_limb64 {
706 try test__clz_limb64(u64, 0, 64);
707 try test__clz_limb64(u65, 1 << 64, 0);
708 try test__clz_limb64(u65, 1 << 9, 55);
709 try test__clz_limb64(u128, 1 << 31, 96);
710 try test__clz_limb64(u255, 1 << 62, 192);
711
712 try test__clz_limb64(i64, -1, 0);
713 try test__clz_limb64(i65, minInt(i65), 0);
714 try test__clz_limb64(i65, 1 << 32, 32);
715 try test__clz_limb64(i128, 0, 128);
716 try test__clz_limb64(i255, 1 << 130, 124);
717
718 try test__clz_limb64(u150, 1 << 31, 118);
719 try test__clz_limb64(i150, maxInt(u65) - 1, 85);
720}
721
722comptime {
723 symbol(&__ctz_limb64, "__ctz_limb64");
724}
725
726fn __ctz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
727 const limb_cnt = usedLimbCount(bits);
728 const a = constLimbs(a_ptr, bits);
729
730 var res: u16 = 0;
731 var i: usize = 0;
732 while (i < limb_cnt - 1) : (i += 1) {
733 const limb = limbGet(a, i);
734 if (limb == 0) {
735 res += 64;
736 } else {
737 res += @ctz(limb);
738 return res;
739 }
740 }
741
742 const limb = limbGet(a, i);
743 if (bits % 64 != 0 and limb == 0) {
744 res += bits % 64;
745 } else {
746 res += @ctz(limb);
747 }
748
749 return res;
750}
751
752fn test__ctz_limb64(comptime T: type, a: T, expected: u16) !void {
753 const int_info = @typeInfo(T).int;
754
755 var a_limbs = asLimbs(a);
756 const out = __ctz_limb64(&a_limbs, int_info.bits);
757
758 try testing.expectEqual(expected, out);
759}
760
761test __ctz_limb64 {
762 try test__ctz_limb64(u64, 1 << 17, 17);
763 try test__ctz_limb64(u65, 1 << 64, 64);
764 try test__ctz_limb64(u65, 0, 65);
765 try test__ctz_limb64(u128, 1 << 100, 100);
766 try test__ctz_limb64(u255, 1 << 200, 200);
767
768 try test__ctz_limb64(i64, -1 << 9, 9);
769 try test__ctz_limb64(i65, minInt(i65), 64);
770 try test__ctz_limb64(i65, 0, 65);
771 try test__ctz_limb64(i128, -1 << 73, 73);
772 try test__ctz_limb64(i255, 1 << 130, 130);
773
774 try test__ctz_limb64(u150, 1 << 101, 101);
775 try test__ctz_limb64(i150, -1 << 74, 74);
776}
777
778comptime {
779 symbol(&__popcount_limb64, "__popcount_limb64");
780}
781
782fn __popcount_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
783 const limb_cnt = usedLimbCount(bits);
784 const a = constLimbs(a_ptr, bits);
785
786 var res: u16 = 0;
787 var i: usize = 0;
788 while (i < limb_cnt - 1) : (i += 1) {
789 res += @popCount(limbGet(a, i));
790 }
791
792 var limb = limbGet(a, i);
793 if (bits % 64 != 0) {
794 limb <<= @intCast(64 - bits % 64);
795 }
796 res += @popCount(limb);
797
798 return res;
799}
800
801fn test__popcount_limb64(comptime T: type, a: T, expected: u16) !void {
802 const int_info = @typeInfo(T).int;
803
804 var a_limbs = asLimbs(a);
805 const out = __popcount_limb64(&a_limbs, int_info.bits);
806
807 try testing.expectEqual(expected, out);
808}
809
810test __popcount_limb64 {
811 try test__popcount_limb64(u64, 0xF0F0_0000_0000_0001, 9);
812 try test__popcount_limb64(u65, 1 << 64, 1);
813 try test__popcount_limb64(u65, maxInt(u65), 65);
814 try test__popcount_limb64(u128, (1 << 100) | (1 << 5) | 1, 3);
815 try test__popcount_limb64(u255, maxInt(u255), 255);
816
817 try test__popcount_limb64(i64, -1, 64);
818 try test__popcount_limb64(i65, minInt(i65), 1);
819 try test__popcount_limb64(i65, -1, 65);
820 try test__popcount_limb64(i128, -1 << 7, 121);
821 try test__popcount_limb64(i255, -1 << 200, 55);
822
823 try test__popcount_limb64(u150, (1 << 149) | (1 << 65) | 1, 3);
824 try test__popcount_limb64(i150, -1 << 7, 143);
825}
826
827comptime {
828 symbol(&__bitreverse_limb64, "__bitreverse_limb64");
829}
830
831fn __bitreverse_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
832 const limb_cnt = usedLimbCount(bits);
833 const out = varLimbs(out_ptr, bits);
834 const a = constLimbs(a_ptr, bits);
835
836 var i: usize = 0;
837 while (i < limb_cnt) : (i += 1) {
838 const j = limb_cnt - 1 - i;
839 limbSet(out, j, @bitReverse(limbGet(a, i)));
840 }
841
842 if (bits % 64 != 0) {
843 __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
844 }
845 fixLastLimb(out_ptr, is_signed, bits);
846}
847
848fn test__bitreverse_limb64(comptime T: type, a: T, expected: T) !void {
849 const int_info = @typeInfo(T).int;
850 const is_signed = int_info.signedness == .signed;
851
852 var a_limbs = asLimbs(a);
853 var out: Limbs(T) = undefined;
854 __bitreverse_limb64(&out, &a_limbs, is_signed, int_info.bits);
855
856 const expected_limbs = asLimbs(expected);
857 try testing.expectEqual(expected_limbs, out);
858}
859
860test __bitreverse_limb64 {
861 try test__bitreverse_limb64(u64, 1 << 7, 1 << 56);
862 try test__bitreverse_limb64(u65, 1 << 64, 1);
863 try test__bitreverse_limb64(u65, 1 << 9, 1 << 55);
864 try test__bitreverse_limb64(u128, 1 << 100, 1 << 27);
865 try test__bitreverse_limb64(u255, 1 << 200, 1 << 54);
866
867 try test__bitreverse_limb64(i64, -1, -1);
868 try test__bitreverse_limb64(i65, 1 << 32, 1 << 32);
869 try test__bitreverse_limb64(i65, minInt(i65), 1);
870 try test__bitreverse_limb64(i128, 1 << 63, 1 << 64);
871 try test__bitreverse_limb64(i255, 1 << 130, 1 << 124);
872
873 try test__bitreverse_limb64(u150, 1 << 9, 1 << 140);
874 try test__bitreverse_limb64(i150, minInt(i150), 1);
875}
876
877comptime {
878 symbol(&__byteswap_limb64, "__byteswap_limb64");
879}
880
881fn __byteswap_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
882 const limb_cnt = usedLimbCount(bits);
883 const out = varLimbs(out_ptr, bits);
884 const a = constLimbs(a_ptr, bits);
885
886 assert(bits % 8 == 0);
887
888 var i: usize = 0;
889 while (i < limb_cnt) : (i += 1) {
890 const j = limb_cnt - 1 - i;
891 limbSet(out, j, @byteSwap(limbGet(a, i)));
892 }
893
894 if (bits % 64 != 0) {
895 __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
896 }
897 fixLastLimb(out_ptr, is_signed, bits);
898}
899
900fn test__byteswap_limb64(comptime T: type, a: T, expected: T) !void {
901 const int_info = @typeInfo(T).int;
902 const is_signed = int_info.signedness == .signed;
903
904 var a_limbs = asLimbs(a);
905 var out: Limbs(T) = undefined;
906 __byteswap_limb64(&out, &a_limbs, is_signed, int_info.bits);
907
908 const expected_limbs = asLimbs(expected);
909 try testing.expectEqual(expected_limbs, out);
910}
911
912test __byteswap_limb64 {
913 try test__byteswap_limb64(u64, 0x0123_4567_89AB_CDEF, 0xEFCD_AB89_6745_2301);
914 try test__byteswap_limb64(u72, 0x01_23_45_67_89_AB_CD_EF_11, 0x11_EF_CD_AB_89_67_45_23_01);
915 try test__byteswap_limb64(u128, 1 << 72, 1 << 48);
916 try test__byteswap_limb64(u248, 1, 1 << 240);
917 try test__byteswap_limb64(u256, 1 << 120, 1 << 128);
918
919 try test__byteswap_limb64(i64, minInt(i64), 128);
920 try test__byteswap_limb64(i72, 1, 1 << 64);
921 try test__byteswap_limb64(i72, -1, -1);
922 try test__byteswap_limb64(i128, 1 << 56, 1 << 64);
923 try test__byteswap_limb64(i248, minInt(i248), 128);
924
925 try test__byteswap_limb64(u152, 1, 1 << 144);
926 try test__byteswap_limb64(i152, 1 << 56, 1 << 88);
927}
928
929comptime {
930 symbol(&__mulo_limb64, "__mulo_limb64");
931}
932
933inline fn add3(x: *[3]u64, start: usize, v0: u64) void {
934 var i = start;
935 var v = v0;
936 while (i < 3) : (i += 1) {
937 const s = @addWithOverflow(x[i], v);
938 x[i] = s[0];
939 if (s[1] == 0) break;
940 v = 1;
941 }
942}
943
944fn mulwide(a: u64, b: u64) [2]u64 {
945 const muldXi = @import("mulXi3.zig").muldXi;
946 const limbs: [2]u64 = @bitCast(muldXi(u64, a, b));
947 return switch (endian) {
948 .little => limbs,
949 .big => .{ limbs[1], limbs[0] },
950 };
951}
952
953fn __mulo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
954 const limb_cnt = usedLimbCount(bits);
955
956 const out = varLimbs(out_ptr, bits);
957 const a = constLimbs(a_ptr, bits);
958 const b = constLimbs(b_ptr, bits);
959
960 @memset(out, 0);
961
962 const all_ones = ~@as(u64, 0);
963 const a_neg = is_signed and ((limbGet(a, limb_cnt - 1) >> 63) != 0);
964 const b_neg = is_signed and ((limbGet(b, limb_cnt - 1) >> 63) != 0);
965
966 var carry: [3]u64 = @splat(0);
967 var hi_zero = true;
968 var hi_ones = true;
969 var hi_borrow: u1 = 0;
970 var raw_last: u64 = 0;
971
972 var k: usize = 0;
973 while (k < 2 * limb_cnt) : (k += 1) {
974 var acc = carry;
975
976 var i: usize = if (k < limb_cnt) 0 else k - (limb_cnt - 1);
977 while (i < limb_cnt and i <= k) : (i += 1) {
978 const j = k - i;
979 if (j >= limb_cnt) continue;
980
981 const p = mulwide(limbGet(a, i), limbGet(b, j));
982 add3(&acc, 0, p[0]);
983 add3(&acc, 1, p[1]);
984 }
985
986 var limb = acc[0];
987 if (k < limb_cnt) {
988 limbSet(out, k, limb);
989 if (k == limb_cnt - 1) raw_last = limb;
990 } else {
991 if (is_signed) {
992 const h = k - limb_cnt;
993
994 const s0 = @subWithOverflow(limb, if (a_neg) limbGet(b, h) else 0);
995 const s1 = @subWithOverflow(s0[0], if (b_neg) limbGet(a, h) else 0);
996 const s2 = @subWithOverflow(s1[0], hi_borrow);
997
998 limb = s2[0];
999 hi_borrow = @intFromBool(s0[1] != 0 or s1[1] != 0 or s2[1] != 0);
1000 }
1001
1002 hi_zero = hi_zero and limb == 0;
1003 hi_ones = hi_ones and limb == all_ones;
1004 }
1005
1006 carry = .{ acc[1], acc[2], 0 };
1007 }
1008
1009 const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
1010 if (bits % 64 != 0) {
1011 limbSet(out, limb_cnt - 1, last);
1012 }
1013
1014 fixLastLimb(out_ptr, is_signed, bits);
1015
1016 if (!is_signed) {
1017 return !hi_zero or raw_last != last;
1018 }
1019
1020 const sign_extend: u64 = if ((last >> 63) == 1) all_ones else 0;
1021 return (raw_last != last) or if (sign_extend == 0) !hi_zero else !hi_ones;
1022}
1023
1024fn test__mulo_limb64(comptime T: type, a: T, b: T, expected: struct { T, bool }) !void {
1025 const int_info = @typeInfo(T).int;
1026 const is_signed = int_info.signedness == .signed;
1027
1028 var a_limbs = asLimbs(a);
1029 var b_limbs = asLimbs(b);
1030 var out: Limbs(T) = undefined;
1031 const overflow = __mulo_limb64(&out, &a_limbs, &b_limbs, is_signed, int_info.bits);
1032
1033 const expected_limbs = asLimbs(expected[0]);
1034 try testing.expectEqual(expected_limbs, out);
1035 try testing.expectEqual(expected[1], overflow);
1036}
1037
1038test __mulo_limb64 {
1039 try test__mulo_limb64(u64, 3, 5, .{ 15, false });
1040 try test__mulo_limb64(u64, maxInt(u64), 2, .{ maxInt(u64) - 1, true });
1041 try test__mulo_limb64(u65, 1 << 32, 1 << 32, .{ 1 << 64, false });
1042 try test__mulo_limb64(u65, 1 << 64, 2, .{ 0, true });
1043 try test__mulo_limb64(u128, 1 << 80, 1 << 40, .{ 1 << 120, false });
1044 try test__mulo_limb64(u128, 1 << 100, 1 << 40, .{ 0, true });
1045 try test__mulo_limb64(u255, 7, 9, .{ 63, false });
1046 try test__mulo_limb64(u255, maxInt(u255), 2, .{ maxInt(u255) - 1, true });
1047
1048 try test__mulo_limb64(i64, -3, 2, .{ -6, false });
1049 try test__mulo_limb64(i64, maxInt(i64), 2, .{ -2, true });
1050 try test__mulo_limb64(i65, 1 << 63, 2, .{ minInt(i65), true });
1051 try test__mulo_limb64(i65, -1 << 32, 1 << 16, .{ -1 << 48, false });
1052 try test__mulo_limb64(i128, 1 << 100, 1 << 27, .{ minInt(i128), true });
1053 try test__mulo_limb64(i128, -1 << 80, 1 << 40, .{ -1 << 120, false });
1054 try test__mulo_limb64(i255, -3, 2, .{ -6, false });
1055 try test__mulo_limb64(i255, maxInt(i255), 2, .{ -2, true });
1056
1057 try test__mulo_limb64(u200, 0, maxInt(u200), .{ 0, false });
1058 try test__mulo_limb64(u200, 1, maxInt(u200), .{ maxInt(u200), false });
1059 try test__mulo_limb64(u200, 1 << 100, 1 << 99, .{ 1 << 199, false });
1060 try test__mulo_limb64(u200, 1 << 100, 1 << 100, .{ 0, true });
1061 try test__mulo_limb64(u200, maxInt(u200), maxInt(u200), .{ 1, true });
1062
1063 try test__mulo_limb64(i200, 0, -1, .{ 0, false });
1064 try test__mulo_limb64(i200, -1, -1, .{ 1, false });
1065 try test__mulo_limb64(i200, -1, minInt(i200), .{ minInt(i200), true });
1066 try test__mulo_limb64(i200, maxInt(i200), 2, .{ -2, true });
1067 try test__mulo_limb64(i200, 1 << 100, 1 << 98, .{ 1 << 198, false });
1068 try test__mulo_limb64(i200, 1 << 100, 1 << 99, .{ minInt(i200), true });
1069 try test__mulo_limb64(i200, maxInt(i200), maxInt(i200), .{ 1, true });
1070 try test__mulo_limb64(i200, minInt(i200), minInt(i200), .{ 0, true });
1071
1072 try test__mulo_limb64(u150, maxInt(u150), 2, .{ maxInt(u150) - 1, true });
1073 try test__mulo_limb64(i150, maxInt(i150), 2, .{ -2, true });
1074}
1075
1076comptime {
1077 symbol(&__abs_limb64, "__abs_limb64");
1078}
1079
1080fn __abs_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, bits: u16) callconv(.c) void {
1081 const limb_cnt = limbCount(bits);
1082 const out = out_ptr[0..limb_cnt];
1083 const a = a_ptr[0..limb_cnt];
1084
1085 const ms = limbGet(a, limb_cnt - 1);
1086 if ((ms >> 63) == 0) {
1087 @memcpy(out, a);
1088 return;
1089 }
1090
1091 var carry: u1 = 1;
1092 var i: usize = 0;
1093 while (i < limb_cnt) : (i += 1) {
1094 const s = @addWithOverflow(~limbGet(a, i), carry);
1095 limbSet(out, i, s[0]);
1096 carry = s[1];
1097 }
1098}
1099
1100fn test__abs_limb64(comptime T: type, a: T, expected: @Int(.unsigned, @typeInfo(T).int.bits)) !void {
1101 const int_info = @typeInfo(T).int;
1102 comptime assert(int_info.signedness == .signed);
1103
1104 var a_limbs = asLimbs(a);
1105 var out: Limbs(@TypeOf(expected)) = undefined;
1106 __abs_limb64(&out, &a_limbs, int_info.bits);
1107
1108 const expected_limbs = asLimbs(expected);
1109 try testing.expectEqual(expected_limbs, out);
1110}
1111
1112test __abs_limb64 {
1113 try test__abs_limb64(i64, 0, 0);
1114 try test__abs_limb64(i64, -1, 1);
1115 try test__abs_limb64(i64, minInt(i64), 1 << 63);
1116 try test__abs_limb64(i65, -1, 1);
1117 try test__abs_limb64(i65, minInt(i65), 1 << 64);
1118 try test__abs_limb64(i65, maxInt(i65), maxInt(i65));
1119 try test__abs_limb64(i128, -1 << 80, 1 << 80);
1120 try test__abs_limb64(i128, 1 << 64, 1 << 64);
1121 try test__abs_limb64(i200, -1 << 198, 1 << 198);
1122 try test__abs_limb64(i255, -5, 5);
1123 try test__abs_limb64(i255, minInt(i255), 1 << 254);
1124
1125 try test__abs_limb64(i150, -40, 40);
2661126}
lib/compiler_rt/mulXi3.zig+1-1
......@@ -63,7 +63,7 @@ fn DoubleInt(comptime T: type) type {
6363 };
6464}
6565
66fn muldXi(comptime T: type, a: T, b: T) DoubleInt(T) {
66pub fn muldXi(comptime T: type, a: T, b: T) DoubleInt(T) {
6767 const DT = DoubleInt(T);
6868 const word_t = compiler_rt.HalveInt(DT, false);
6969 const bits_in_word_2 = @sizeOf(T) * 8 / 2;
lib/compiler_rt/udivmodei4.zig+28
......@@ -13,6 +13,8 @@ const max_limbs = std.math.divCeil(usize, 65535, 32) catch unreachable; // max s
1313comptime {
1414 symbol(&__udivei4, "__udivei4");
1515 symbol(&__umodei4, "__umodei4");
16 symbol(&__udivei5, "__udivei5");
17 symbol(&__umodei5, "__umodei5");
1618}
1719
1820/// Get the value of a limb.
......@@ -132,6 +134,32 @@ pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca
132134 @call(.always_inline, divmod, .{ null, r, u, v }) catch unreachable;
133135}
134136
137pub fn __udivei5(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, t_p: [*]u8, bits: usize) callconv(.c) void {
138 @setRuntimeSafety(compiler_rt.test_safety);
139 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
140 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
141 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
142 const v: []const u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
143 const tu: []u32 = @ptrCast(@alignCast(t_p[0..byte_size]));
144 _ = tu;
145 const tv: []u32 = @ptrCast(@alignCast(t_p[byte_size..][0..byte_size]));
146 _ = tv;
147 @call(.always_inline, divmod, .{ q, null, u, v }) catch unreachable;
148}
149
150pub fn __umodei5(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, t_p: [*]u8, bits: usize) callconv(.c) void {
151 @setRuntimeSafety(compiler_rt.test_safety);
152 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
153 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
154 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
155 const v: []const u32 = @ptrCast(@alignCast(v_p[0..byte_size]));
156 const tu: []u32 = @ptrCast(@alignCast(t_p[0..byte_size]));
157 _ = tu;
158 const tv: []u32 = @ptrCast(@alignCast(t_p[byte_size..][0..byte_size]));
159 _ = tv;
160 @call(.always_inline, divmod, .{ null, r, u, v }) catch unreachable;
161}
162
135163test "__udivei4/__umodei4" {
136164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
137165 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
src/codegen/wasm/CodeGen.zig+472-221
......@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33const Allocator = std.mem.Allocator;
44const assert = std.debug.assert;
55const testing = std.testing;
6const math = std.math;
67const mem = std.mem;
78const log = std.log.scoped(.codegen);
89
......@@ -1324,6 +1325,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
13241325 .mod,
13251326 .max,
13261327 .min,
1328 .div_exact,
13271329 .div_trunc,
13281330 .div_floor,
13291331 => |tag| {
......@@ -1349,6 +1351,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
13491351 .mod => try cg.floatMod(float_ty, lhs, rhs),
13501352 .max => try cg.floatMax(float_ty, lhs, rhs),
13511353 .min => try cg.floatMin(float_ty, lhs, rhs),
1354 .div_exact => try cg.floatDiv(float_ty, lhs, rhs),
13521355 .div_trunc => try cg.floatDivTrunc(float_ty, lhs, rhs),
13531356 .div_floor => try cg.floatDivFloor(float_ty, lhs, rhs),
13541357 else => unreachable,
......@@ -1366,6 +1369,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
13661369 .mod => try cg.intMod(int_ty, lhs, rhs),
13671370 .max => try cg.intMax(int_ty, lhs, rhs),
13681371 .min => try cg.intMin(int_ty, lhs, rhs),
1372 .div_exact => try cg.intDiv(int_ty, lhs, rhs),
13691373 .div_trunc => try cg.intDiv(int_ty, lhs, rhs),
13701374 .div_floor => try cg.intDivFloor(int_ty, lhs, rhs),
13711375 else => unreachable,
......@@ -1389,19 +1393,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
13891393 const result = try cg.floatDiv(.fromType(cg, ty), lhs, rhs);
13901394 try cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
13911395 },
1392 .div_exact => {
1393 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
1394 const lhs = try cg.resolveInst(bin_op.lhs);
1395 const rhs = try cg.resolveInst(bin_op.rhs);
1396 const ty = cg.typeOfIndex(inst);
1397
1398 if (ty.zigTypeTag(zcu) == .vector) {
1399 return cg.fail("TODO: implement AIR op: div_exact for vectors", .{});
1400 }
1401
1402 const result = try cg.intDiv(.fromType(cg, ty), lhs, rhs);
1403 try cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
1404 },
14051396 .abs => {
14061397 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
14071398 const operand = try cg.resolveInst(ty_op.operand);
......@@ -2363,6 +2354,15 @@ const IntType = struct {
23632354 }
23642355};
23652356
2357fn intBackingBits(cg: *CodeGen, bits: u16) u16 {
2358 return switch (bits) {
2359 0 => unreachable,
2360 1...32 => 32,
2361 33...64 => 64,
2362 else => std.zig.target.intByteSize(cg.target, bits) * 8,
2363 };
2364}
2365
23662366fn intAdd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue {
23672367 switch (ty.bits) {
23682368 0 => unreachable,
......@@ -2486,7 +2486,19 @@ fn intMul(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
24862486 return .stack;
24872487 },
24882488 65...128 => return cg.callIntrinsic(.__multi3, &.{ .i128_type, .i128_type }, Type.i128, &.{ lhs, rhs }),
2489 else => return cg.fail("TODO: Support intMul for integer bitsize: {d}", .{ty.bits}),
2489 else => {
2490 const result = try cg.allocInt(ty);
2491
2492 try cg.lowerToStack(result);
2493 try cg.lowerToStack(lhs);
2494 try cg.lowerToStack(rhs);
2495 try cg.addImm32(@intFromBool(ty.is_signed));
2496 try cg.addImm32(ty.bits);
2497 try cg.addCallIntrinsic(.__mulo_limb64);
2498 try cg.addTag(.drop);
2499
2500 return result;
2501 },
24902502 }
24912503}
24922504
......@@ -2512,7 +2524,28 @@ fn intDiv(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
25122524 return cg.callIntrinsic(.__udivti3, &.{ .i128_type, .i128_type }, Type.i128, &.{ lhs, rhs });
25132525 }
25142526 },
2515 else => return cg.fail("TODO: Support intDiv for integer bitsize: {d}", .{ty.bits}),
2527 else => {
2528 const result = try cg.allocInt(ty);
2529 const bits = cg.intBackingBits(ty.bits);
2530 var tmp = try cg.allocInt(.{ .is_signed = false, .bits = bits * 2 });
2531 if (ty.is_signed) {
2532 _ = try cg.callIntrinsic(
2533 .__divei5,
2534 &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type },
2535 .void,
2536 &.{ result, lhs, rhs, tmp, .{ .imm32 = ty.bits } },
2537 );
2538 } else {
2539 _ = try cg.callIntrinsic(
2540 .__udivei5,
2541 &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type },
2542 .void,
2543 &.{ result, lhs, rhs, tmp, .{ .imm32 = ty.bits } },
2544 );
2545 }
2546 tmp.free(cg);
2547 return result;
2548 },
25162549 }
25172550}
25182551
......@@ -2564,7 +2597,22 @@ fn intDivFloor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!W
25642597 try cg.addTag(.i64_sub);
25652598 return .stack;
25662599 },
2567 else => return cg.fail("TODO: Support intDivFloor for signed integer bitsize: {d}", .{ty.bits}),
2600 else => {
2601 const q = try cg.intDiv(ty, lhs, rhs);
2602
2603 const zero = try cg.intZeroValue(ty);
2604
2605 const r = try cg.intRem(ty, lhs, rhs);
2606 _ = try cg.intCmp(ty, .neq, r, zero);
2607
2608 const sign_xor = try cg.intXor(ty, lhs, rhs);
2609 _ = try cg.intCmp(ty, .lt, sign_xor, zero);
2610 var adjust = try (try cg.intAnd(.u32, .stack, .stack)).toLocal(cg, Type.u32);
2611
2612 const adjust_bigint = try cg.intCast(ty, .u32, adjust);
2613 adjust.free(cg);
2614 return try cg.intSub(ty, q, adjust_bigint);
2615 },
25682616 }
25692617}
25702618
......@@ -2590,7 +2638,28 @@ fn intRem(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
25902638 return cg.callIntrinsic(.__umodti3, &.{ .i128_type, .i128_type }, Type.i128, &.{ lhs, rhs });
25912639 }
25922640 },
2593 else => return cg.fail("TODO: Support intRem for integer bitsize: {d}", .{ty.bits}),
2641 else => {
2642 const result = try cg.allocInt(ty);
2643 const bits = cg.intBackingBits(ty.bits);
2644 var tmp = try cg.allocInt(.{ .is_signed = false, .bits = bits * 2 });
2645 if (ty.is_signed) {
2646 _ = try cg.callIntrinsic(
2647 .__modei5,
2648 &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type },
2649 .void,
2650 &.{ result, lhs, rhs, tmp, .{ .imm32 = ty.bits } },
2651 );
2652 } else {
2653 _ = try cg.callIntrinsic(
2654 .__umodei5,
2655 &.{ .usize_type, .usize_type, .usize_type, .usize_type, .usize_type },
2656 .void,
2657 &.{ result, lhs, rhs, tmp, .{ .imm32 = ty.bits } },
2658 );
2659 }
2660 tmp.free(cg);
2661 return result;
2662 },
25942663 }
25952664}
25962665
......@@ -2635,7 +2704,17 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
26352704
26362705 return result;
26372706 },
2638 else => return cg.fail("TODO: Support intAnd for integer bitsize: {d}", .{ty.bits}),
2707 else => {
2708 const result = try cg.allocInt(ty);
2709
2710 try cg.lowerToStack(result);
2711 try cg.lowerToStack(lhs);
2712 try cg.lowerToStack(rhs);
2713 try cg.addImm32(ty.bits);
2714 try cg.addCallIntrinsic(.__and_limb64);
2715
2716 return result;
2717 },
26392718 }
26402719}
26412720
......@@ -2669,7 +2748,17 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
26692748
26702749 return result;
26712750 },
2672 else => return cg.fail("TODO: Support intOr for integer bitsize: {d}", .{ty.bits}),
2751 else => {
2752 const result = try cg.allocInt(ty);
2753
2754 try cg.lowerToStack(result);
2755 try cg.lowerToStack(lhs);
2756 try cg.lowerToStack(rhs);
2757 try cg.addImm32(ty.bits);
2758 try cg.addCallIntrinsic(.__or_limb64);
2759
2760 return result;
2761 },
26732762 }
26742763}
26752764
......@@ -2703,7 +2792,17 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
27032792
27042793 return result;
27052794 },
2706 else => return cg.fail("TODO: Support intXor for integer bitsize: {d}", .{ty.bits}),
2795 else => {
2796 const result = try cg.allocInt(ty);
2797
2798 try cg.lowerToStack(result);
2799 try cg.lowerToStack(lhs);
2800 try cg.lowerToStack(rhs);
2801 try cg.addImm32(ty.bits);
2802 try cg.addCallIntrinsic(.__xor_limb64);
2803
2804 return result;
2805 },
27072806 }
27082807}
27092808
......@@ -2761,11 +2860,22 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
27612860
27622861 return result;
27632862 },
2764 else => return cg.fail("TODO: Support intNot for integer bitsize: {d}", .{ty.bits}),
2863 else => {
2864 const result = try cg.allocInt(ty);
2865
2866 try cg.lowerToStack(result);
2867 try cg.lowerToStack(operand);
2868 try cg.addImm32(@intFromBool(ty.is_signed));
2869 try cg.addImm32(ty.bits);
2870 try cg.addCallIntrinsic(.__not_limb64);
2871
2872 return result;
2873 },
27652874 }
27662875}
27672876
27682877// rhs is a shift count, pointing to i32 value
2878// does not perform wrapping, padding bits does not satisfy invariant
27692879fn intShl(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue {
27702880 switch (ty.bits) {
27712881 0 => unreachable,
......@@ -2783,7 +2893,19 @@ fn intShl(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
27832893 return .stack;
27842894 },
27852895 65...128 => return cg.callIntrinsic(.__ashlti3, &.{ .i128_type, .i32_type }, Type.i128, &.{ lhs, rhs }),
2786 else => return cg.fail("TODO: Support intShl for integer bitsize: {d}", .{ty.bits}),
2896 else => {
2897 const result = try cg.allocInt(ty);
2898
2899 try cg.lowerToStack(result);
2900 try cg.lowerToStack(lhs);
2901 try cg.lowerToStack(rhs);
2902 try cg.addImm32(@intFromBool(ty.is_signed));
2903 try cg.addImm32(ty.bits);
2904 try cg.addCallIntrinsic(.__shlo_limb64);
2905 try cg.addTag(.drop);
2906
2907 return result;
2908 },
27872909 }
27882910}
27892911
......@@ -2811,7 +2933,18 @@ fn intShr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
28112933 return cg.callIntrinsic(.__lshrti3, &.{ .i128_type, .i32_type }, Type.i128, &.{ lhs, rhs });
28122934 }
28132935 },
2814 else => return cg.fail("TODO: Support intShr for integer bitsize: {d}", .{ty.bits}),
2936 else => {
2937 const result = try cg.allocInt(ty);
2938
2939 try cg.lowerToStack(result);
2940 try cg.lowerToStack(lhs);
2941 try cg.lowerToStack(rhs);
2942 try cg.addImm32(@intFromBool(ty.is_signed));
2943 try cg.addImm32(ty.bits);
2944 try cg.addCallIntrinsic(.__shr_limb64);
2945
2946 return result;
2947 },
28152948 }
28162949}
28172950
......@@ -2871,7 +3004,16 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
28713004 const b = try cg.intSub(u128_ty, a, mask);
28723005 return b;
28733006 },
2874 else => return cg.fail("TODO: Support intAbs for integer bitsize: {d}", .{ty.bits}),
3007 else => {
3008 const result = try cg.allocInt(ty);
3009
3010 try cg.lowerToStack(result);
3011 try cg.lowerToStack(operand);
3012 try cg.addImm32(ty.bits);
3013 try cg.addCallIntrinsic(.__abs_limb64);
3014
3015 return result;
3016 },
28753017 }
28763018}
28773019
......@@ -2938,7 +3080,13 @@ fn intClz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
29383080 try cg.addTag(.i32_wrap_i64);
29393081 return .stack;
29403082 },
2941 else => return cg.fail("TODO: Support intClz for integer bitsize: {d}", .{ty.bits}),
3083 else => {
3084 try cg.lowerToStack(operand);
3085 try cg.addImm32(ty.bits);
3086 try cg.addCallIntrinsic(.__clz_limb64);
3087
3088 return .stack;
3089 },
29423090 }
29433091}
29443092
......@@ -2984,7 +3132,13 @@ fn intCtz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
29843132 try cg.addTag(.i32_wrap_i64);
29853133 return .stack;
29863134 },
2987 else => return cg.fail("TODO: Support intCtz for integer bitsize: {d}", .{ty.bits}),
3135 else => {
3136 try cg.lowerToStack(operand);
3137 try cg.addImm32(ty.bits);
3138 try cg.addCallIntrinsic(.__ctz_limb64);
3139
3140 return .stack;
3141 },
29883142 }
29893143}
29903144
......@@ -3024,7 +3178,13 @@ fn intPopCount(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
30243178 try cg.addTag(.i32_wrap_i64);
30253179 return .stack;
30263180 },
3027 else => return cg.fail("TODO: Support intPopCount for integer bitsize: {d}", .{ty.bits}),
3181 else => {
3182 try cg.lowerToStack(operand);
3183 try cg.addImm32(ty.bits);
3184 try cg.addCallIntrinsic(.__popcount_limb64);
3185
3186 return .stack;
3187 },
30283188 }
30293189}
30303190
......@@ -3083,7 +3243,17 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
30833243 return tmp;
30843244 }
30853245 },
3086 else => return cg.fail("TODO: Support intBitReverse for integer bitsize: {d}", .{ty.bits}),
3246 else => {
3247 const result = try cg.allocInt(ty);
3248
3249 try cg.lowerToStack(result);
3250 try cg.lowerToStack(operand);
3251 try cg.addImm32(@intFromBool(ty.is_signed));
3252 try cg.addImm32(ty.bits);
3253 try cg.addCallIntrinsic(.__bitreverse_limb64);
3254
3255 return result;
3256 },
30873257 }
30883258}
30893259
......@@ -3111,35 +3281,48 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
31113281 return cg.intShr(ty, intrin_ret, .{ .imm32 = 64 - ty.bits });
31123282 },
31133283 65...128 => {
3114 const tmp = try cg.allocStack(Type.u128);
3284 const result = try cg.allocStack(Type.u128);
31153285
3116 const low = try cg.load(operand, Type.u64, 0);
3117 const high = try cg.load(operand, Type.u64, 8);
3286 try cg.emitWValue(result);
31183287
3288 const low = try cg.load(operand, Type.u64, 0);
31193289 const swap_low = try cg.callIntrinsic(
31203290 .__bswapdi2,
31213291 &.{.u64_type},
31223292 Type.u64,
31233293 &.{low},
31243294 );
3295 try cg.store(.stack, swap_low, Type.u64, result.offset() + 8);
3296
3297 try cg.emitWValue(result);
3298
3299 const high = try cg.load(operand, Type.u64, 8);
31253300 const swap_high = try cg.callIntrinsic(
31263301 .__bswapdi2,
31273302 &.{.u64_type},
31283303 Type.u64,
31293304 &.{high},
31303305 );
3131
3132 try cg.store(tmp, swap_low, Type.u64, tmp.offset() + 8);
3133 try cg.store(tmp, swap_high, Type.u64, tmp.offset());
3306 try cg.store(.stack, swap_high, Type.u64, result.offset());
31343307
31353308 if (ty.bits < 128) {
31363309 const shift_ty: IntType = .{ .is_signed = ty.is_signed, .bits = 128 };
3137 return cg.intShr(shift_ty, tmp, .{ .imm32 = 128 - ty.bits });
3310 return cg.intShr(shift_ty, result, .{ .imm32 = 128 - ty.bits });
31383311 } else {
3139 return tmp;
3312 return result;
31403313 }
31413314 },
3142 else => return cg.fail("TODO: Support intByteSwap for integer bitsize: {d}", .{ty.bits}),
3315 else => {
3316 const result = try cg.allocInt(ty);
3317
3318 try cg.lowerToStack(result);
3319 try cg.lowerToStack(operand);
3320 try cg.addImm32(@intFromBool(ty.is_signed));
3321 try cg.addImm32(ty.bits);
3322 try cg.addCallIntrinsic(.__byteswap_limb64);
3323
3324 return result;
3325 },
31433326 }
31443327}
31453328
......@@ -3197,7 +3380,49 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
31973380 return result;
31983381 },
31993382 128 => return operand,
3200 else => return cg.fail("TODO: Support intWrap for integer bitsize: {d}", .{ty.bits}),
3383 else => {
3384 const bits = cg.intBackingBits(ty.bits);
3385 if (ty.bits == bits) return operand;
3386
3387 const result = try cg.allocInt(ty);
3388
3389 const used_len = (math.divCeil(u16, ty.bits, 64) catch unreachable) * 8;
3390
3391 if (ty.bits % 64 != 0) {
3392 try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 });
3393 const pad = 64 - ty.bits % 64;
3394
3395 try cg.emitWValue(result);
3396 _ = try cg.load(operand, Type.u64, used_len - 8);
3397 if (ty.is_signed) {
3398 try cg.addImm64(pad);
3399 try cg.addTag(.i64_shl);
3400 try cg.addImm64(pad);
3401 try cg.addTag(.i64_shr_s);
3402 } else {
3403 try cg.addImm64(~@as(u64, 0) >> @intCast(pad));
3404 try cg.addTag(.i64_and);
3405 }
3406 try cg.store(.stack, .stack, Type.u64, result.offset() + used_len - 8);
3407 } else {
3408 try cg.memcpy(result, operand, .{ .imm32 = used_len });
3409 }
3410
3411 const full_len = @divExact(bits, 8);
3412 if (used_len + 8 == full_len) { // last limb needs sign extended
3413 try cg.emitWValue(result);
3414 if (ty.is_signed) {
3415 _ = try cg.load(result, Type.u64, used_len - 8);
3416 try cg.addImm64(63);
3417 try cg.addTag(.i64_shr_s);
3418 } else {
3419 try cg.addImm64(0);
3420 }
3421 try cg.store(.stack, .stack, Type.u64, result.offset() + used_len);
3422 }
3423
3424 return result;
3425 },
32013426 }
32023427}
32033428
......@@ -3214,8 +3439,8 @@ fn intMaxValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue {
32143439 } else {
32153440 return .{ .imm64 = ~@as(u64, 0) >> @intCast(64 - int_ty.bits) };
32163441 }
3217 } else {
3218 const result = try cg.allocStack(Type.u128);
3442 } else if (int_ty.bits <= 128) {
3443 const result = try cg.allocInt(int_ty);
32193444 try cg.store(result, .{ .imm64 = ~@as(u64, 0) }, Type.u64, 0);
32203445
32213446 if (int_ty.is_signed) {
......@@ -3223,6 +3448,24 @@ fn intMaxValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue {
32233448 } else {
32243449 try cg.store(result, .{ .imm64 = ~@as(u64, 0) >> @intCast(128 - int_ty.bits) }, Type.u64, 8);
32253450 }
3451 return result;
3452 } else {
3453 const result = try cg.allocInt(int_ty);
3454 const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8);
3455 const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8;
3456
3457 try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0xFF });
3458
3459 if (int_ty.is_signed) {
3460 try cg.store(result, .{ .imm64 = (~@as(u64, 0) >> @intCast(used_len * 8 - int_ty.bits)) >> 1 }, Type.u64, used_len - 8);
3461 } else {
3462 try cg.store(result, .{ .imm64 = ~@as(u64, 0) >> @intCast(used_len * 8 - int_ty.bits) }, Type.u64, used_len - 8);
3463 }
3464
3465 if (used_len + 8 == full_len) {
3466 try cg.store(result, .{ .imm64 = 0 }, Type.u64, full_len - 8);
3467 }
3468
32263469 return result;
32273470 }
32283471}
......@@ -3235,10 +3478,23 @@ fn intMinValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue {
32353478 return .{ .imm32 = ~@as(u32, 0) << @intCast(int_ty.bits - 1) };
32363479 } else if (int_ty.bits <= 64) {
32373480 return .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - 1) };
3238 } else {
3239 const result = try cg.allocStack(Type.u128);
3481 } else if (int_ty.bits <= 128) {
3482 const result = try cg.allocInt(int_ty);
32403483 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 0);
32413484 try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - 65) }, Type.u64, 8);
3485 return result;
3486 } else {
3487 const result = try cg.allocInt(int_ty);
3488 const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8);
3489 const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8;
3490
3491 try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0 });
3492 try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - (used_len - 8) * 8 - 1) }, Type.u64, used_len - 8);
3493
3494 if (used_len + 8 == full_len) {
3495 try cg.store(result, .{ .imm64 = ~@as(u64, 0) }, Type.u64, full_len - 8);
3496 }
3497
32423498 return result;
32433499 }
32443500}
......@@ -3256,20 +3512,20 @@ fn intAddSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError
32563512 defer rhs_is_neg.free(cg);
32573513 const min_val = try cg.intMinValue(int_ty);
32583514
3259 try cg.emitWValue(min_val);
3260 try cg.emitWValue(max_val);
3515 try cg.lowerToStack(min_val);
3516 try cg.lowerToStack(max_val);
32613517 try cg.emitWValue(rhs_is_neg);
32623518 try cg.addTag(.select);
32633519
3264 try cg.emitWValue(op_val);
3520 try cg.lowerToStack(op_val);
32653521 const overflow_cmp = try cg.intCmp(int_ty, .lt, op_val, lhs);
32663522 const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp);
32673523 try cg.emitWValue(is_overflow);
32683524 try cg.addTag(.select);
32693525 return .stack;
32703526 } else {
3271 try cg.emitWValue(max_val);
3272 try cg.emitWValue(op_val);
3527 try cg.lowerToStack(max_val);
3528 try cg.lowerToStack(op_val);
32733529
32743530 const is_overflow = try cg.intCmp(int_ty, .lt, op_val, lhs);
32753531 try cg.emitWValue(is_overflow);
......@@ -3290,12 +3546,12 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError
32903546 const max_val = try cg.intMaxValue(int_ty);
32913547 const min_val = try cg.intMinValue(int_ty);
32923548
3293 try cg.emitWValue(max_val);
3294 try cg.emitWValue(min_val);
3549 try cg.lowerToStack(max_val);
3550 try cg.lowerToStack(min_val);
32953551 try cg.emitWValue(rhs_is_neg);
32963552 try cg.addTag(.select);
32973553
3298 try cg.emitWValue(op_val);
3554 try cg.lowerToStack(op_val);
32993555 const overflow_cmp = try cg.intCmp(int_ty, .gt, op_val, lhs);
33003556 const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp);
33013557 try cg.emitWValue(is_overflow);
......@@ -3304,8 +3560,8 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError
33043560 } else {
33053561 const zero = try cg.intZeroValue(int_ty);
33063562
3307 try cg.emitWValue(zero);
3308 try cg.emitWValue(op_val);
3563 try cg.lowerToStack(zero);
3564 try cg.lowerToStack(op_val);
33093565 const is_overflow = try cg.intCmp(int_ty, .lt, lhs, rhs);
33103566 try cg.emitWValue(is_overflow);
33113567 try cg.addTag(.select);
......@@ -3314,43 +3570,6 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError
33143570}
33153571
33163572fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue {
3317 // Remove when > 128 int ops will be implemented in backend
3318 if (int_ty.bits == 128) {
3319 if (!int_ty.is_signed) {
3320 return cg.fail("TODO: mul_sat for unsigned 128-bit integers", .{});
3321 }
3322
3323 const overflow_ret = try cg.allocStack(Type.i32);
3324 const ret = try cg.callIntrinsic(
3325 .__muloti4,
3326 &[_]InternPool.Index{ .i128_type, .i128_type, .usize_type },
3327 Type.i128,
3328 &.{ lhs, rhs, overflow_ret },
3329 );
3330 try cg.lowerToStack(ret);
3331
3332 const xor = try cg.intXor(int_ty, lhs, rhs);
3333 const sign_v = try cg.intShr(int_ty, xor, .{ .imm32 = 127 });
3334
3335 // xor ~@as(u127, 0)
3336 try cg.emitWValue(sign_v);
3337 const lsb = try cg.load(sign_v, Type.u64, 0);
3338 _ = try cg.intXor(.u64, lsb, .{ .imm64 = ~@as(u64, 0) });
3339 try cg.store(.stack, .stack, Type.u64, sign_v.offset());
3340
3341 try cg.emitWValue(sign_v);
3342 const msb = try cg.load(sign_v, Type.u64, 8);
3343 _ = try cg.intXor(.u64, msb, .{ .imm64 = ~@as(u64, 0) >> 1 });
3344 try cg.store(.stack, .stack, Type.u64, sign_v.offset() + 8);
3345
3346 try cg.lowerToStack(sign_v);
3347 _ = try cg.load(overflow_ret, Type.i32, 0);
3348 try cg.addTag(.i32_eqz);
3349 try cg.addTag(.select);
3350
3351 return .stack;
3352 }
3353
33543573 const ext_ty: IntType = .{ .is_signed = int_ty.is_signed, .bits = int_ty.bits * 2 };
33553574
33563575 const lhs_ext = try cg.intCast(ext_ty, int_ty, lhs);
......@@ -3366,10 +3585,10 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError
33663585 if (int_ty.is_signed) {
33673586 const min_val = try cg.intMinValue(int_ty);
33683587
3369 try cg.emitWValue(min_val);
3588 try cg.lowerToStack(min_val);
33703589
3371 try cg.emitWValue(max_val);
3372 try cg.emitWValue(op_val);
3590 try cg.lowerToStack(max_val);
3591 try cg.lowerToStack(op_val);
33733592 const max_ext = try cg.intCast(ext_ty, int_ty, max_val);
33743593 const ov_pos = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext);
33753594 try cg.emitWValue(ov_pos);
......@@ -3377,12 +3596,12 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError
33773596
33783597 const min_ext = try cg.intCast(ext_ty, int_ty, min_val);
33793598 const ov_neg = try cg.intCmp(ext_ty, .gt, min_ext, mul_ext);
3380 try cg.emitWValue(ov_neg);
3599 try cg.lowerToStack(ov_neg);
33813600 try cg.addTag(.select);
33823601 return .stack;
33833602 } else {
3384 try cg.emitWValue(max_val);
3385 try cg.emitWValue(op_val);
3603 try cg.lowerToStack(max_val);
3604 try cg.lowerToStack(op_val);
33863605 const max_ext = try cg.intCast(ext_ty, int_ty, max_val);
33873606 const is_overflow = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext);
33883607 try cg.emitWValue(is_overflow);
......@@ -3405,20 +3624,20 @@ fn intShlSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError
34053624 const zero = try cg.intZeroValue(int_ty);
34063625 const min_val = try cg.intMinValue(int_ty);
34073626
3408 try cg.emitWValue(min_val);
3409 try cg.emitWValue(max_val);
3627 try cg.lowerToStack(min_val);
3628 try cg.lowerToStack(max_val);
34103629 const lhs_is_neg = try cg.intCmp(int_ty, .lt, lhs, zero);
34113630 try cg.emitWValue(lhs_is_neg);
34123631 try cg.addTag(.select);
34133632
3414 try cg.emitWValue(op_val);
3633 try cg.lowerToStack(op_val);
34153634 const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs);
34163635 try cg.emitWValue(is_overflow);
34173636 try cg.addTag(.select);
34183637 return .stack;
34193638 } else {
3420 try cg.emitWValue(max_val);
3421 try cg.emitWValue(op_val);
3639 try cg.lowerToStack(max_val);
3640 try cg.lowerToStack(op_val);
34223641 const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs);
34233642 try cg.emitWValue(is_overflow);
34243643 try cg.addTag(.select);
......@@ -3432,12 +3651,17 @@ fn intZeroValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue {
34323651 1...32 => return .{ .imm32 = 0 },
34333652 33...64 => return .{ .imm64 = 0 },
34343653 65...128 => {
3435 const result = try cg.allocStack(Type.u128);
3654 const result = try cg.allocInt(int_ty);
34363655 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 0);
34373656 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 8);
34383657 return result;
34393658 },
3440 else => return cg.fail("TODO: Implement intZeroValue for integer bitsize: {d}", .{int_ty.bits}),
3659 else => {
3660 const result = try cg.allocInt(int_ty);
3661 const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8);
3662 try cg.memset(Type.u8, result, .{ .imm32 = full_len }, .{ .imm32 = 0 });
3663 return result;
3664 },
34413665 }
34423666}
34433667
......@@ -3561,68 +3785,6 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner
35613785 _ = try cg.intCmp(new_ty, .neq, res_upcast, bin_op);
35623786 try cg.addLocal(.local_set, overflow_bit.local.value);
35633787 break :blk res_tmp;
3564 } else if (int_ty.bits == 128 and !int_ty.is_signed) blk: {
3565 var lhs_lsb = try (try cg.load(lhs, Type.u64, 0)).toLocal(cg, Type.u64);
3566 defer lhs_lsb.free(cg);
3567 var lhs_msb = try (try cg.load(lhs, Type.u64, 8)).toLocal(cg, Type.u64);
3568 defer lhs_msb.free(cg);
3569 var rhs_lsb = try (try cg.load(rhs, Type.u64, 0)).toLocal(cg, Type.u64);
3570 defer rhs_lsb.free(cg);
3571 var rhs_msb = try (try cg.load(rhs, Type.u64, 8)).toLocal(cg, Type.u64);
3572 defer rhs_msb.free(cg);
3573
3574 const zero: WValue = .{ .imm64 = 0 };
3575
3576 const cross_1 = try cg.callIntrinsic(
3577 .__multi3,
3578 &[_]InternPool.Index{.i64_type} ** 4,
3579 Type.i128,
3580 &.{ lhs_msb, zero, rhs_lsb, zero },
3581 );
3582 const cross_2 = try cg.callIntrinsic(
3583 .__multi3,
3584 &[_]InternPool.Index{.i64_type} ** 4,
3585 Type.i128,
3586 &.{ rhs_msb, zero, lhs_lsb, zero },
3587 );
3588 const mul_lsb = try cg.callIntrinsic(
3589 .__multi3,
3590 &[_]InternPool.Index{.i64_type} ** 4,
3591 Type.i128,
3592 &.{ rhs_lsb, zero, lhs_lsb, zero },
3593 );
3594
3595 const rhs_msb_not_zero = try cg.intCmp(.u64, .neq, rhs_msb, zero);
3596 const lhs_msb_not_zero = try cg.intCmp(.u64, .neq, lhs_msb, zero);
3597 const both_msb_not_zero = try cg.intAnd(.u32, rhs_msb_not_zero, lhs_msb_not_zero);
3598
3599 const cross_1_msb = try cg.load(cross_1, .u64, 8);
3600 const cross_1_msb_not_zero = try cg.intCmp(.u64, .neq, cross_1_msb, zero);
3601 const cond_1 = try cg.intOr(.u32, both_msb_not_zero, cross_1_msb_not_zero);
3602
3603 const cross_2_msb = try cg.load(cross_2, Type.u64, 8);
3604 const cross_2_msb_not_zero = try cg.intCmp(.u64, .neq, cross_2_msb, zero);
3605 const cond_2 = try cg.intOr(.u32, cond_1, cross_2_msb_not_zero);
3606
3607 const cross_1_lsb = try cg.load(cross_1, Type.u64, 0);
3608 const cross_2_lsb = try cg.load(cross_2, Type.u64, 0);
3609 const cross_add = try cg.intAdd(.u64, cross_1_lsb, cross_2_lsb);
3610
3611 var mul_lsb_msb = try (try cg.load(mul_lsb, Type.u64, 8)).toLocal(cg, Type.u64);
3612 defer mul_lsb_msb.free(cg);
3613 var all_add = try (try cg.intAdd(.u64, cross_add, mul_lsb_msb)).toLocal(cg, Type.u64);
3614 defer all_add.free(cg);
3615 const add_overflow = try cg.intCmp(.u64, .lt, all_add, mul_lsb_msb);
3616
3617 _ = try cg.intOr(.u32, cond_2, add_overflow);
3618 try cg.addLocal(.local_set, overflow_bit.local.value);
3619
3620 const tmp_result = try cg.allocStack(Type.u128);
3621 try cg.emitWValue(tmp_result);
3622 const mul_lsb_lsb = try cg.load(mul_lsb, Type.u64, 0);
3623 try cg.store(.stack, mul_lsb_lsb, Type.u64, tmp_result.offset());
3624 try cg.store(tmp_result, all_add, Type.u64, 8);
3625 break :blk tmp_result;
36263788 } else if (int_ty.bits == 128 and int_ty.is_signed) blk: {
36273789 const overflow_ret = try cg.allocStack(Type.i32);
36283790 const res = try cg.callIntrinsic(
......@@ -3634,44 +3796,53 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner
36343796 _ = try cg.load(overflow_ret, Type.i32, 0);
36353797 try cg.addLocal(.local_set, overflow_bit.local.value);
36363798 break :blk res;
3637 } else return cg.fail("TODO: intMulOverflow for bitsize {d}", .{int_ty.bits});
3799 } else {
3800 const result = try cg.allocInt(int_ty);
3801
3802 try cg.lowerToStack(result);
3803 try cg.lowerToStack(lhs);
3804 try cg.lowerToStack(rhs);
3805 try cg.addImm32(@intFromBool(int_ty.is_signed));
3806 try cg.addImm32(int_ty.bits);
3807 try cg.addCallIntrinsic(.__mulo_limb64);
3808
3809 return .{ .result = result, .ov = .stack };
3810 };
36383811
36393812 return .{ .result = result_val, .ov = .{ .local = overflow_bit.local } };
36403813}
36413814
3642fn intShlOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult {
3643 switch (int_ty.bits) {
3815fn intShlOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult {
3816 switch (ty.bits) {
36443817 0 => unreachable,
36453818 1...128 => {
3646 const raw_shl = try cg.intShl(int_ty, lhs, rhs);
3647 const wrapped_shl = try cg.intWrap(int_ty, raw_shl);
3648 const shl_tmp = try cg.toLocalInt(wrapped_shl, int_ty);
3819 const raw_shl = try cg.intShl(ty, lhs, rhs);
3820 const wrapped_shl = try cg.intWrap(ty, raw_shl);
3821 const shl_tmp = try cg.toLocalInt(wrapped_shl, ty);
36493822
3650 const shr = try cg.intShr(int_ty, shl_tmp, rhs);
3651 const overflow_bit = try cg.intCmp(int_ty, .neq, shr, lhs);
3823 const shr = try cg.intShr(ty, shl_tmp, rhs);
3824 const overflow_bit = try cg.intCmp(ty, .neq, shr, lhs);
36523825
36533826 return .{ .result = shl_tmp, .ov = overflow_bit };
36543827 },
3655 else => return cg.fail("TODO: Support intShlOverflow for integer bitsize: {d}", .{int_ty.bits}),
3828 else => {
3829 const result = try cg.allocInt(ty);
3830
3831 try cg.lowerToStack(result);
3832 try cg.lowerToStack(lhs);
3833 try cg.lowerToStack(rhs);
3834 try cg.addImm32(@intFromBool(ty.is_signed));
3835 try cg.addImm32(ty.bits);
3836 try cg.addCallIntrinsic(.__shlo_limb64);
3837
3838 return .{ .result = result, .ov = .stack };
3839 },
36563840 }
36573841}
36583842
36593843fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) InnerError!WValue {
3660 const src_bits: u16 = switch (src_ty.bits) {
3661 0 => unreachable,
3662 1...32 => 32,
3663 33...64 => 64,
3664 65...128 => 128,
3665 else => unreachable,
3666 };
3667
3668 const dest_bits: u16 = switch (dest_ty.bits) {
3669 0 => unreachable,
3670 1...32 => 32,
3671 33...64 => 64,
3672 65...128 => 128,
3673 else => unreachable,
3674 };
3844 const src_bits: u16 = cg.intBackingBits(src_ty.bits);
3845 const dest_bits: u16 = cg.intBackingBits(dest_ty.bits);
36753846
36763847 if (src_bits == dest_bits) {
36773848 return operand;
......@@ -3683,34 +3854,78 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn
36833854 return .stack;
36843855 } else if (src_bits == 32 and dest_bits == 64) {
36853856 try cg.emitWValue(operand);
3686 try cg.addTag(if (dest_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
3857 try cg.addTag(if (src_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
36873858 return .stack;
3688 } else if (dest_bits == 128) {
3689 const stack_ptr = try cg.allocStack(Type.u128);
3690 try cg.emitWValue(stack_ptr);
3859 } else if (dest_bits >= 128) {
3860 const result = try cg.allocInt(dest_ty);
36913861
3692 const lhs = if (src_bits == 32) blk: {
3693 const sign_ty: IntType = .{ .is_signed = dest_ty.is_signed, .bits = 64 };
3694 break :blk try (try cg.intCast(sign_ty, src_ty, operand)).toLocal(cg, Type.u64);
3695 } else operand;
3862 const dest_len = dest_bits / 8;
36963863
3697 try cg.store(.stack, lhs, Type.u64, stack_ptr.offset());
3698
3699 if (dest_ty.is_signed) {
3700 try cg.emitWValue(stack_ptr);
3701 const shr = try cg.intShr(IntType.i64, lhs, .{ .imm32 = 63 });
3702 try cg.store(.stack, shr, Type.u64, 8 + stack_ptr.offset());
3864 if (dest_bits <= src_bits) {
3865 assert(src_bits >= 128);
3866 try cg.memcpy(result, operand, .{ .imm32 = dest_len });
37033867 } else {
3704 try cg.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8);
3705 }
3868 var src_len: u32 = undefined;
3869 if (src_bits == 32) {
3870 try cg.emitWValue(result);
3871 try cg.emitWValue(operand);
3872 try cg.addTag(if (src_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
3873 try cg.store(.stack, .stack, Type.u64, result.offset());
3874 src_len = 8;
3875 } else if (src_bits == 64) {
3876 try cg.emitWValue(result);
3877 try cg.emitWValue(operand);
3878 try cg.store(.stack, .stack, Type.u64, result.offset());
3879 src_len = 8;
3880 } else {
3881 src_len = src_bits / 8;
3882 try cg.memcpy(result, operand, .{ .imm32 = src_len });
3883 }
37063884
3707 if (src_bits == 32) {
3708 var tmp_lhs = lhs;
3709 tmp_lhs.free(cg);
3885 if (dest_bits == 128) {
3886 if (src_ty.is_signed) {
3887 try cg.emitWValue(result);
3888 if (src_bits == 32) {
3889 try cg.emitWValue(operand);
3890 try cg.addTag(if (dest_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
3891 } else if (src_bits == 64) {
3892 try cg.emitWValue(operand);
3893 } else unreachable;
3894 const shr = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 });
3895 try cg.store(.stack, shr, Type.u64, 8 + result.offset());
3896 } else {
3897 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 8);
3898 }
3899 } else {
3900 var pad = result;
3901 pad.stack_offset.value += src_len;
3902 const memset_len = dest_len - src_len;
3903 if (src_ty.is_signed) {
3904 if (src_bits == 32) {
3905 try cg.emitWValue(operand);
3906 _ = try cg.intShr(IntType.i32, .stack, .{ .imm32 = 31 });
3907 } else if (src_bits == 64) {
3908 try cg.emitWValue(operand);
3909 _ = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 });
3910 try cg.addTag(.i32_wrap_i64);
3911 } else {
3912 _ = try cg.load(operand, Type.u64, src_len - 8);
3913 _ = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 });
3914 try cg.addTag(.i32_wrap_i64);
3915 }
3916 var sign_byte = try @as(WValue, .stack).toLocal(cg, Type.u32);
3917 try cg.memset(Type.u8, pad, .{ .imm32 = memset_len }, sign_byte);
3918 sign_byte.free(cg);
3919 } else {
3920 try cg.memset(Type.u8, pad, .{ .imm32 = memset_len }, .{ .imm32 = 0 });
3921 }
3922 }
37103923 }
37113924
3712 return stack_ptr;
3925 return result;
37133926 } else {
3927 assert(dest_bits <= 64);
3928 assert(src_bits >= 128);
37143929 const load_ty = if (dest_bits == 32) Type.u32 else Type.u64;
37153930 return cg.load(operand, load_ty, 0);
37163931 }
......@@ -3719,13 +3934,7 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn
37193934fn intTrunc(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) InnerError!WValue {
37203935 var result = try cg.intCast(dest_ty, src_ty, operand);
37213936
3722 const dest_wasm_bits: u16 = switch (dest_ty.bits) {
3723 0 => unreachable,
3724 1...32 => 32,
3725 33...64 => 64,
3726 65...128 => 128,
3727 else => return cg.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{dest_ty.bits}),
3728 };
3937 const dest_wasm_bits = cg.intBackingBits(dest_ty.bits);
37293938
37303939 if (dest_wasm_bits != dest_ty.bits) {
37313940 result = try cg.intWrap(dest_ty, result);
......@@ -4275,7 +4484,34 @@ fn intFromFloat(cg: *CodeGen, dest_ty: IntType, src_ty: FloatType, operand: WVal
42754484 return cg.callIntrinsic(intrinsic, &.{.f128_type}, Type.u128, &.{operand});
42764485 },
42774486 },
4278 else => return cg.fail("TODO: Support intFromFloat for integer bitsize: {d}", .{dest_ty.bits}),
4487 else => {
4488 const result = try cg.allocInt(dest_ty);
4489
4490 switch (src_ty) {
4491 .f16 => {
4492 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixhfei else .__fixunshfei;
4493 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f16_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4494 },
4495 .f32 => {
4496 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixsfei else .__fixunssfei;
4497 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f32_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4498 },
4499 .f64 => {
4500 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixdfei else .__fixunsdfei;
4501 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f64_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4502 },
4503 .f80 => {
4504 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixxfei else .__fixunsxfei;
4505 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f80_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4506 },
4507 .f128 => {
4508 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixtfei else .__fixunstfei;
4509 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f128_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4510 },
4511 }
4512
4513 return result;
4514 },
42794515 }
42804516}
42814517
......@@ -4295,7 +4531,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
42954531 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattihf else .__floatuntihf;
42964532 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f16, &.{operand});
42974533 },
4298 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 16-bit float", .{src_ty.bits}),
4534 else => {
4535 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateihf else .__floatuneihf;
4536 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f16, &.{ operand, .{ .imm32 = src_ty.bits } });
4537 },
42994538 },
43004539 .f32 => switch (src_ty.bits) {
43014540 0 => unreachable,
......@@ -4313,7 +4552,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
43134552 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattisf else .__floatuntisf;
43144553 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f32, &.{operand});
43154554 },
4316 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 32-bit float", .{src_ty.bits}),
4555 else => {
4556 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateisf else .__floatuneisf;
4557 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f32, &.{ operand, .{ .imm32 = src_ty.bits } });
4558 },
43174559 },
43184560 .f64 => switch (src_ty.bits) {
43194561 0 => unreachable,
......@@ -4331,7 +4573,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
43314573 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattidf else .__floatuntidf;
43324574 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f64, &.{operand});
43334575 },
4334 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 64-bit float", .{src_ty.bits}),
4576 else => {
4577 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateidf else .__floatuneidf;
4578 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f64, &.{ operand, .{ .imm32 = src_ty.bits } });
4579 },
43354580 },
43364581 .f80 => switch (src_ty.bits) {
43374582 0 => unreachable,
......@@ -4347,7 +4592,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
43474592 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattixf else .__floatuntixf;
43484593 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f80, &.{operand});
43494594 },
4350 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 80-bit float", .{src_ty.bits}),
4595 else => {
4596 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateixf else .__floatuneixf;
4597 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f80, &.{ operand, .{ .imm32 = src_ty.bits } });
4598 },
43514599 },
43524600 .f128 => switch (src_ty.bits) {
43534601 0 => unreachable,
......@@ -4363,7 +4611,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
43634611 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattitf else .__floatuntitf;
43644612 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f128, &.{operand});
43654613 },
4366 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 128-bit float", .{src_ty.bits}),
4614 else => {
4615 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateitf else .__floatuneitf;
4616 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f128, &.{ operand, .{ .imm32 = src_ty.bits } });
4617 },
43674618 },
43684619 }
43694620}
src/codegen/wasm/Mir.zig+37
......@@ -825,6 +825,7 @@ pub const Intrinsic = enum(u32) {
825825 __ceilx,
826826 __cosh,
827827 __cosx,
828 __divei5,
828829 __divhf3,
829830 __divtf3,
830831 __divti3,
......@@ -846,33 +847,43 @@ pub const Intrinsic = enum(u32) {
846847 __fabsh,
847848 __fabsx,
848849 __fixdfdi,
850 __fixdfei,
849851 __fixdfsi,
850852 __fixdfti,
851853 __fixhfdi,
854 __fixhfei,
852855 __fixhfsi,
853856 __fixhfti,
854857 __fixsfdi,
858 __fixsfei,
855859 __fixsfsi,
856860 __fixsfti,
857861 __fixtfdi,
862 __fixtfei,
858863 __fixtfsi,
859864 __fixtfti,
860865 __fixunsdfdi,
866 __fixunsdfei,
861867 __fixunsdfsi,
862868 __fixunsdfti,
863869 __fixunshfdi,
870 __fixunshfei,
864871 __fixunshfsi,
865872 __fixunshfti,
866873 __fixunssfdi,
874 __fixunssfei,
867875 __fixunssfsi,
868876 __fixunssfti,
869877 __fixunstfdi,
878 __fixunstfei,
870879 __fixunstfsi,
871880 __fixunstfti,
872881 __fixunsxfdi,
882 __fixunsxfei,
873883 __fixunsxfsi,
874884 __fixunsxfti,
875885 __fixxfdi,
886 __fixxfei,
876887 __fixxfsi,
877888 __fixxfti,
878889 __floatdidf,
......@@ -880,6 +891,11 @@ pub const Intrinsic = enum(u32) {
880891 __floatdisf,
881892 __floatditf,
882893 __floatdixf,
894 __floateidf,
895 __floateihf,
896 __floateisf,
897 __floateitf,
898 __floateixf,
883899 __floatsidf,
884900 __floatsihf,
885901 __floatsisf,
......@@ -895,6 +911,11 @@ pub const Intrinsic = enum(u32) {
895911 __floatundisf,
896912 __floatunditf,
897913 __floatundixf,
914 __floatuneidf,
915 __floatuneihf,
916 __floatuneisf,
917 __floatuneitf,
918 __floatuneixf,
898919 __floatunsidf,
899920 __floatunsihf,
900921 __floatunsisf,
......@@ -930,6 +951,7 @@ pub const Intrinsic = enum(u32) {
930951 __lshrti3,
931952 __lttf2,
932953 __ltxf2,
954 __modei5,
933955 __modti3,
934956 __mulhf3,
935957 __mulodi4,
......@@ -960,7 +982,9 @@ pub const Intrinsic = enum(u32) {
960982 __truncxfdf2,
961983 __truncxfhf2,
962984 __truncxfsf2,
985 __udivei5,
963986 __udivti3,
987 __umodei5,
964988 __umodti3,
965989 ceilq,
966990 cos,
......@@ -1007,4 +1031,17 @@ pub const Intrinsic = enum(u32) {
10071031 __addo_limb64,
10081032 __subo_limb64,
10091033 __cmp_limb64,
1034 __and_limb64,
1035 __or_limb64,
1036 __xor_limb64,
1037 __not_limb64,
1038 __shlo_limb64,
1039 __shr_limb64,
1040 __clz_limb64,
1041 __ctz_limb64,
1042 __popcount_limb64,
1043 __bitreverse_limb64,
1044 __byteswap_limb64,
1045 __mulo_limb64,
1046 __abs_limb64,
10101047};
test/behavior/bit_shifting.zig-1
......@@ -151,7 +151,6 @@ test "Saturating Shift Left" {
151151 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
152152 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
153153 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
154 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
155154
156155 const S = struct {
157156 fn shlSat(x: anytype, y: std.math.Log2Int(@TypeOf(x))) @TypeOf(x) {
test/behavior/bitcast.zig-4
......@@ -35,7 +35,6 @@ test "@bitCast iX -> uX (8, 16, 128)" {
3535
3636test "@bitCast iX -> uX exotic integers" {
3737 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
3938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4140 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -80,7 +79,6 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe
8079
8180test "bitcast uX to bytes" {
8281 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8684 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -296,7 +294,6 @@ test "triple level result location with bitcast sandwich passed as tuple element
296294
297295test "@bitCast packed struct of floats" {
298296 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
300297 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
301298 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
302299 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -334,7 +331,6 @@ test "@bitCast packed struct of floats" {
334331
335332test "comptime @bitCast packed struct to int and back" {
336333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
338334 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
339335 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
340336 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/byteswap.zig-1
......@@ -42,7 +42,6 @@ test "@byteSwap exotic integers" {
4242 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
4444 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
4645
4746 const ByteSwapIntTest = struct {
4847 fn run() !void {
test/behavior/cast.zig+50
......@@ -126,6 +126,56 @@ test "@floatFromInt" {
126126 try comptime S.doTheTest();
127127}
128128
129fn testIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
130 try expect(@as(I, @intFromFloat(f)) == i);
131}
132
133test "@intFromFloat > 128 bits" {
134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
137
138 try testIntFromFloat(f16, 1024, u140, 1024);
139 try testIntFromFloat(f16, -1024, i140, -1024);
140
141 try testIntFromFloat(f32, 1 << 24, u140, 1 << 24);
142 try testIntFromFloat(f32, -1 << 24, i140, -1 << 24);
143
144 try testIntFromFloat(f64, 1 << 53, u200, 1 << 53);
145 try testIntFromFloat(f64, -1 << 53, i200, -1 << 53);
146
147 try testIntFromFloat(f80, 1 << 63, u200, 1 << 63);
148 try testIntFromFloat(f80, -1 << 63, i200, -1 << 63);
149
150 try testIntFromFloat(f128, 1 << 100, u200, 1 << 100);
151 try testIntFromFloat(f128, -1 << 100, i200, -1 << 100);
152}
153
154fn testFloatFromInt(comptime I: type, i: I, comptime F: type, expected: F) !void {
155 try expect(@as(F, @floatFromInt(i)) == expected);
156}
157
158test "@floatFromInt > 128 bits" {
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
162
163 try testFloatFromInt(u140, 1024, f16, 1024);
164 try testFloatFromInt(i140, -1024, f16, -1024);
165
166 try testFloatFromInt(u140, 1 << 24, f32, 1 << 24);
167 try testFloatFromInt(i140, -1 << 24, f32, -1 << 24);
168
169 try testFloatFromInt(u200, 1 << 53, f64, 1 << 53);
170 try testFloatFromInt(i200, -1 << 53, f64, -1 << 53);
171
172 try testFloatFromInt(u200, 1 << 63, f80, 1 << 63);
173 try testFloatFromInt(i200, -1 << 63, f80, -1 << 63);
174
175 try testFloatFromInt(u200, 1 << 100, f128, 1 << 100);
176 try testFloatFromInt(i200, -1 << 100, f128, -1 << 100);
177}
178
129179test "@floatFromInt(f80)" {
130180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131181 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/cast_int.zig+78
......@@ -3,6 +3,7 @@ const std = @import("std");
33const expect = std.testing.expect;
44const expectEqual = std.testing.expectEqual;
55const maxInt = std.math.maxInt;
6const minInt = std.math.minInt;
67
78test "@intCast i32 to u7" {
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -136,6 +137,83 @@ test "coerce non byte-sized integers accross 32bits boundary" {
136137 }
137138}
138139
140fn testIntCast(comptime S: type, a: S, comptime D: type, expected: D) !void {
141 const actual: D = @intCast(a);
142 try expect(actual == expected);
143}
144
145test "@intCast <= 64 bits" {
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
147
148 try testIntCast(i32, minInt(i32), i64, minInt(i32));
149 try testIntCast(i32, maxInt(i32), i64, maxInt(i32));
150 try testIntCast(u32, maxInt(u32), u64, maxInt(u32));
151 try testIntCast(u32, maxInt(i32), i64, maxInt(i32));
152 try testIntCast(u32, maxInt(u32), i64, maxInt(u32));
153
154 try testIntCast(i32, 0, u32, 0);
155 try testIntCast(i32, maxInt(i32), u32, maxInt(i32));
156 try testIntCast(i64, 0, u64, 0);
157 try testIntCast(i64, maxInt(i64), u64, maxInt(i64));
158
159 try testIntCast(u32, 0, i32, 0);
160 try testIntCast(u32, maxInt(i32), i32, maxInt(i32));
161 try testIntCast(u64, 0, i64, 0);
162 try testIntCast(u64, maxInt(i64), i64, maxInt(i64));
163
164 try testIntCast(i64, minInt(i32), i32, minInt(i32));
165 try testIntCast(i64, maxInt(i32), i32, maxInt(i32));
166 try testIntCast(u64, maxInt(u32), u32, maxInt(u32));
167 try testIntCast(i64, maxInt(u32), u32, maxInt(u32));
168}
169
170test "@intCast > 128 bits" {
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
172 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
173
174 try testIntCast(u8, 123, u140, 123);
175 try testIntCast(u64, 1 << 63, u140, 1 << 63);
176 try testIntCast(u127, maxInt(u127), u140, maxInt(u127));
177 try testIntCast(i8, -42, i140, -42);
178 try testIntCast(i64, minInt(i64), i140, minInt(i64));
179 try testIntCast(i127, maxInt(i127), i140, maxInt(i127));
180 try testIntCast(u127, 1 << 100, i140, 1 << 100);
181 try testIntCast(i127, 1 << 100, u140, 1 << 100);
182
183 try testIntCast(u140, 0, u128, 0);
184 try testIntCast(u140, 1 << 100, u128, 1 << 100);
185 try testIntCast(u140, maxInt(u128), u128, maxInt(u128));
186 try testIntCast(i140, -1, i128, -1);
187 try testIntCast(i140, minInt(i128), i128, minInt(i128));
188 try testIntCast(i140, maxInt(i128), i128, maxInt(i128));
189 try testIntCast(u140, 1 << 100, i128, 1 << 100);
190 try testIntCast(i140, 1 << 100, u128, 1 << 100);
191
192 try testIntCast(u16, 255, u256, 255);
193 try testIntCast(u128, 1 << 127, u256, 1 << 127);
194 try testIntCast(i16, -7, i256, -7);
195 try testIntCast(i128, minInt(i128), i256, minInt(i128));
196 try testIntCast(u128, maxInt(i128), i256, maxInt(i128));
197 try testIntCast(i128, 1 << 100, u256, 1 << 100);
198
199 try testIntCast(u256, 1 << 139, u140, 1 << 139);
200 try testIntCast(u256, maxInt(u140), u140, maxInt(u140));
201 try testIntCast(i256, -1, i140, -1);
202 try testIntCast(i256, minInt(i140), i140, minInt(i140));
203 try testIntCast(i256, maxInt(i140), i140, maxInt(i140));
204 try testIntCast(u256, 1 << 120, i140, 1 << 120);
205 try testIntCast(i256, 1 << 120, u140, 1 << 120);
206
207 try testIntCast(i257, maxInt(i256), i256, maxInt(i256));
208 try testIntCast(i257, minInt(i256), i256, minInt(i256));
209 try testIntCast(u257, maxInt(u256), u256, maxInt(u256));
210 try testIntCast(u257, 1 << 255, u256, 1 << 255);
211
212 try testIntCast(u32, maxInt(u32), i255, maxInt(u32));
213 try testIntCast(u64, maxInt(u64), i255, maxInt(u64));
214 try testIntCast(u128, maxInt(u128), i255, maxInt(u128));
215}
216
139217const Piece = packed struct {
140218 color: Color,
141219 type: Type,
test/behavior/eval.zig-1
......@@ -511,7 +511,6 @@ var foo_contents = Foo{ .name = "a" };
511511const foo_ref = &foo_contents;
512512
513513test "runtime 128 bit integer division" {
514 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
515514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
517516 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/math.zig+573-9
......@@ -61,17 +61,17 @@ fn assertFalse(b: bool) !void {
6161 try expect(!b);
6262}
6363
64test "@clz" {
64test "@clz small" {
6565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6767 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6868 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
6969
70 try testClz();
71 try comptime testClz();
70 try testClzSmall();
71 try comptime testClzSmall();
7272}
7373
74fn testClz() !void {
74fn testClzSmall() !void {
7575 try expect(testOneClz(u8, 0b10001010) == 0);
7676 try expect(testOneClz(u8, 0b00001010) == 4);
7777 try expect(testOneClz(u8, 0b00011010) == 3);
......@@ -142,17 +142,17 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
142142 try expect(@reduce(.And, a == b));
143143}
144144
145test "@ctz" {
145test "@ctz small" {
146146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
147147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148148 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
149149 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
150150
151 try testCtz();
152 try comptime testCtz();
151 try testCtzSmall();
152 try comptime testCtzSmall();
153153}
154154
155fn testCtz() !void {
155fn testCtzSmall() !void {
156156 try expect(testOneCtz(u8, 0b10100000) == 5);
157157 try expect(testOneCtz(u8, 0b10001010) == 1);
158158 try expect(testOneCtz(u8, 0b00000000) == 8);
......@@ -1119,10 +1119,38 @@ test "@mulWithOverflow bitsize 128 bits" {
11191119 try testMulWithOverflow(i128, -1 << 63, -1 << 64, -1 << 127, 1);
11201120}
11211121
1122test "@mulWithOverflow > 128 bits" {
1123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1124 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1125
1126 try testMulWithOverflow(u140, 0, maxInt(u140), 0, 0);
1127 try testMulWithOverflow(u140, 1, maxInt(u140), maxInt(u140), 0);
1128 try testMulWithOverflow(u140, 1 << 70, 1 << 69, 1 << 139, 0);
1129 try testMulWithOverflow(u140, 1 << 70, 1 << 70, 0, 1);
1130
1131 try testMulWithOverflow(u200, 1 << 100, 1 << 99, 1 << 199, 0);
1132 try testMulWithOverflow(u200, 1 << 100, 1 << 100, 0, 1);
1133 try testMulWithOverflow(u200, maxInt(u200), maxInt(u200), 1, 1);
1134 try testMulWithOverflow(u200, maxInt(u200) - 1, 2, maxInt(u200) - 3, 1);
1135
1136 try testMulWithOverflow(i140, 0, -1, 0, 0);
1137 try testMulWithOverflow(i140, -1, -1, 1, 0);
1138 try testMulWithOverflow(i140, 1 << 69, 1 << 69, 1 << 138, 0);
1139 try testMulWithOverflow(i140, 1 << 69, 1 << 70, minInt(i140), 1);
1140 try testMulWithOverflow(i140, -1 << 70, 1 << 20, -1 << 90, 0);
1141 try testMulWithOverflow(i140, minInt(i140), -1, minInt(i140), 1);
1142
1143 try testMulWithOverflow(i200, 1 << 100, 1 << 98, 1 << 198, 0);
1144 try testMulWithOverflow(i200, 1 << 100, 1 << 99, minInt(i200), 1);
1145 try testMulWithOverflow(i200, -1 << 120, 1 << 30, -1 << 150, 0);
1146 try testMulWithOverflow(i200, minInt(i200), minInt(i200), 0, 1);
1147 try testMulWithOverflow(i200, maxInt(i200), 2, -2, 1);
1148 try testMulWithOverflow(i200, maxInt(i200), maxInt(i200), 1, 1);
1149}
1150
11221151test "@mulWithOverflow bitsize 256 bits" {
11231152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11241153 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
11261154 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11271155 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11281156
......@@ -1317,6 +1345,542 @@ test "@shlWithOverflow > 64 bits" {
13171345 try testShlWithOverflow(i128, 0x0100_0000_0000_0000_0000000000000000, 9, 0, 1);
13181346}
13191347
1348test "@shlWithOverflow > 128 bits" {
1349 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1350 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1351
1352 try testShlWithOverflow(u140, 1 << 100, 20, 1 << 120, 0);
1353 try testShlWithOverflow(u140, 1 << 100, 40, 0, 1);
1354 try testShlWithOverflow(u140, 3, 138, (1 << 139) | (1 << 138), 0);
1355 try testShlWithOverflow(u140, 7, 138, (1 << 139) | (1 << 138), 1);
1356
1357 try testShlWithOverflow(u256, 1 << 200, 40, 1 << 240, 0);
1358 try testShlWithOverflow(u256, 1 << 200, 55, 1 << 255, 0);
1359 try testShlWithOverflow(u256, 1 << 200, 56, 0, 1);
1360 try testShlWithOverflow(u256, maxInt(u256), 1, maxInt(u256) - 1, 1);
1361
1362 try testShlWithOverflow(i140, 1 << 100, 20, 1 << 120, 0);
1363 try testShlWithOverflow(i140, 1 << 100, 39, minInt(i140), 1);
1364 try testShlWithOverflow(i140, -1 << 20, 10, -1 << 30, 0);
1365 try testShlWithOverflow(i140, minInt(i140), 1, 0, 1);
1366
1367 try testShlWithOverflow(i256, 1 << 200, 30, 1 << 230, 0);
1368 try testShlWithOverflow(i256, 1 << 200, 55, minInt(i256), 1);
1369 try testShlWithOverflow(i256, -1 << 120, 40, -1 << 160, 0);
1370 try testShlWithOverflow(i256, minInt(i256), 1, 0, 1);
1371}
1372
1373fn testAnd(comptime T: type, a: T, b: T, expected: T) !void {
1374 try expect((a & b) == expected);
1375}
1376
1377test "and > 128 bits" {
1378 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1379 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1380
1381 try testAnd(u140, (1 << 139) | (1 << 70) | 0xaa, (1 << 139) | (1 << 69) | 0xcc, (1 << 139) | 0x88);
1382 try testAnd(u140, maxInt(u140), 1 << 100, 1 << 100);
1383 try testAnd(u140, 0, maxInt(u140), 0);
1384 try testAnd(u140, (1 << 80) | (1 << 17) | 1, (1 << 17) | (1 << 9) | 1, (1 << 17) | 1);
1385
1386 try testAnd(u256, maxInt(u256), (1 << 255) | (1 << 200) | 7, (1 << 255) | (1 << 200) | 7);
1387 try testAnd(u256, (1 << 255) | (1 << 5), (1 << 254) | (1 << 5), 1 << 5);
1388 try testAnd(u256, (1 << 130) | (1 << 64) | (1 << 2), (1 << 130) | (1 << 63) | (1 << 2), (1 << 130) | (1 << 2));
1389 try testAnd(u256, 0, 1 << 200, 0);
1390
1391 try testAnd(i140, -1, 1 << 17, 1 << 17);
1392 try testAnd(i140, minInt(i140), -1, minInt(i140));
1393 try testAnd(i140, -1 << 40, (1 << 100) | (1 << 80) | (1 << 40), (1 << 100) | (1 << 80) | (1 << 40));
1394 try testAnd(i140, 0, maxInt(i140), 0);
1395
1396 try testAnd(i256, -1, 1 << 200, 1 << 200);
1397 try testAnd(i256, minInt(i256), maxInt(i256), 0);
1398 try testAnd(i256, -1 << 130, -1 << 129, -1 << 130);
1399 try testAnd(i256, minInt(i256), -1 << 10, minInt(i256));
1400}
1401
1402fn testOr(comptime T: type, a: T, b: T, expected: T) !void {
1403 try expect((a | b) == expected);
1404}
1405
1406test "or > 128 bits" {
1407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1408 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1409
1410 try testOr(u140, 0, 1 << 139, 1 << 139);
1411 try testOr(u140, (1 << 70) | 0xa, (1 << 69) | 0x5, (1 << 70) | (1 << 69) | 0xf);
1412 try testOr(u140, maxInt(u140), 0, maxInt(u140));
1413 try testOr(u140, (1 << 17) | (1 << 3), (1 << 17) | (1 << 1), (1 << 17) | 0xa);
1414
1415 try testOr(u256, 0, 1 << 255, 1 << 255);
1416 try testOr(u256, (1 << 200) | 0x30, (1 << 199) | 0x0f, (1 << 200) | (1 << 199) | 0x3f);
1417 try testOr(u256, maxInt(u256), 1 << 17, maxInt(u256));
1418 try testOr(u256, 1 << 130, 1 << 64, (1 << 130) | (1 << 64));
1419
1420 try testOr(i140, -1, 0, -1);
1421 try testOr(i140, minInt(i140), 1, minInt(i140) + 1);
1422 try testOr(i140, -1 << 40, (1 << 5) | 1, (-1 << 40) | 0x21);
1423 try testOr(i140, 0, maxInt(i140), maxInt(i140));
1424
1425 try testOr(i256, -1, 1 << 200, -1);
1426 try testOr(i256, minInt(i256), 1 << 17, minInt(i256) | (1 << 17));
1427 try testOr(i256, -1 << 130, 0xff, (-1 << 130) | 0xff);
1428 try testOr(i256, 0, maxInt(i256), maxInt(i256));
1429}
1430
1431fn testXor(comptime T: type, a: T, b: T, expected: T) !void {
1432 try expect((a ^ b) == expected);
1433}
1434
1435test "xor > 128 bits" {
1436 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1437 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1438
1439 try testXor(u140, 0, maxInt(u140), maxInt(u140));
1440 try testXor(u140, 1 << 139, 1 << 139, 0);
1441 try testXor(u140, (1 << 70) | 0xa, (1 << 69) | 0x5, (1 << 70) | (1 << 69) | 0xf);
1442 try testXor(u140, maxInt(u140), 1 << 100, maxInt(u140) ^ (1 << 100));
1443
1444 try testXor(u256, 0, maxInt(u256), maxInt(u256));
1445 try testXor(u256, 1 << 255, 1 << 255, 0);
1446 try testXor(u256, (1 << 200) | (1 << 5), (1 << 199) | (1 << 5), (1 << 200) | (1 << 199));
1447 try testXor(u256, maxInt(u256), 1 << 17, maxInt(u256) ^ (1 << 17));
1448
1449 try testXor(i140, -1, -1, 0);
1450 try testXor(i140, -1, 0, -1);
1451 try testXor(i140, minInt(i140), -1, maxInt(i140));
1452 try testXor(i140, -1 << 40, -1 << 39, 1 << 39);
1453
1454 try testXor(i256, -1, -1, 0);
1455 try testXor(i256, -1, 0, -1);
1456 try testXor(i256, minInt(i256), -1, maxInt(i256));
1457 try testXor(i256, -1 << 130, -1 << 129, 1 << 129);
1458}
1459
1460fn testNot(comptime T: type, a: T, expected: T) !void {
1461 try expect((~a) == expected);
1462}
1463
1464test "not > 128 bits" {
1465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1466 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1467
1468 try testNot(u140, 0, maxInt(u140));
1469 try testNot(u140, maxInt(u140), 0);
1470 try testNot(u140, 1 << 139, maxInt(u140) ^ (1 << 139));
1471 try testNot(u140, (1 << 17) | 1, maxInt(u140) ^ ((1 << 17) | 1));
1472
1473 try testNot(u256, 0, maxInt(u256));
1474 try testNot(u256, maxInt(u256), 0);
1475 try testNot(u256, 1 << 255, maxInt(u256) ^ (1 << 255));
1476 try testNot(u256, (1 << 200) | (1 << 5), maxInt(u256) ^ ((1 << 200) | (1 << 5)));
1477
1478 try testNot(i140, -1, 0);
1479 try testNot(i140, 0, -1);
1480 try testNot(i140, minInt(i140), maxInt(i140));
1481 try testNot(i140, -1 << 10, (1 << 10) - 1);
1482
1483 try testNot(i256, -1, 0);
1484 try testNot(i256, 0, -1);
1485 try testNot(i256, minInt(i256), maxInt(i256));
1486 try testNot(i256, -1 << 200, (1 << 200) - 1);
1487}
1488
1489fn testShl(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {
1490 try expect((a << b) == expected);
1491}
1492
1493test "shl > 128 bits" {
1494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1495 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1496
1497 try testShl(u140, 1 << 5, 10, 1 << 15);
1498 try testShl(u140, 3, 138, (1 << 139) | (1 << 138));
1499 try testShl(u140, 1 << 139, 1, 0);
1500 try testShl(u140, (1 << 70) | 1, 3, (1 << 73) | 8);
1501
1502 try testShl(u256, 1 << 200, 20, 1 << 220);
1503 try testShl(u256, 1 << 255, 1, 0);
1504 try testShl(u256, (1 << 128) | 5, 7, (1 << 135) | 0x280);
1505 try testShl(u256, maxInt(u256), 1, maxInt(u256) - 1);
1506
1507 try testShl(i140, 1 << 20, 5, 1 << 25);
1508 try testShl(i140, -1, 7, -128);
1509 try testShl(i140, minInt(i140), 1, 0);
1510 try testShl(i140, -1 << 10, 5, -1 << 15);
1511
1512 try testShl(i256, 1 << 200, 30, 1 << 230);
1513 try testShl(i256, -1, 200, -1 << 200);
1514 try testShl(i256, minInt(i256), 1, 0);
1515 try testShl(i256, -1 << 100, 50, -1 << 150);
1516}
1517
1518fn testShr(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {
1519 try expect((a >> b) == expected);
1520}
1521
1522test "shr > 128 bits" {
1523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1524 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1525
1526 try testShr(u140, 1 << 139, 39, 1 << 100);
1527 try testShr(u140, (1 << 70) | 8, 3, (1 << 67) | 1);
1528 try testShr(u140, 1, 1, 0);
1529 try testShr(u140, maxInt(u140), 139, 1);
1530
1531 try testShr(u256, 1 << 255, 55, 1 << 200);
1532 try testShr(u256, (1 << 200) | (1 << 7), 7, (1 << 193) | 1);
1533 try testShr(u256, 1, 1, 0);
1534 try testShr(u256, maxInt(u256), 255, 1);
1535
1536 try testShr(i140, -1, 17, -1);
1537 try testShr(i140, minInt(i140), 1, minInt(i140) >> 1);
1538 try testShr(i140, -1 << 80, 40, -1 << 40);
1539 try testShr(i140, -5, 1, -3);
1540
1541 try testShr(i256, -1, 200, -1);
1542 try testShr(i256, minInt(i256), 1, minInt(i256) >> 1);
1543 try testShr(i256, -1 << 180, 80, -1 << 100);
1544 try testShr(i256, -5, 1, -3);
1545}
1546
1547fn testClz(comptime T: type, a: T, expected: u16) !void {
1548 try expect(@clz(a) == expected);
1549}
1550
1551test "@clz > 128 bits" {
1552 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1553 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1554
1555 try testClz(u140, 0, 140);
1556 try testClz(u140, 1 << 139, 0);
1557 try testClz(u140, 1 << 70, 69);
1558 try testClz(u140, maxInt(u140), 0);
1559
1560 try testClz(u256, 0, 256);
1561 try testClz(u256, 1 << 255, 0);
1562 try testClz(u256, 1 << 200, 55);
1563 try testClz(u256, 1, 255);
1564
1565 try testClz(i140, -1, 0);
1566 try testClz(i140, minInt(i140), 0);
1567 try testClz(i140, 1 << 70, 69);
1568 try testClz(i140, 0, 140);
1569
1570 try testClz(i256, -1, 0);
1571 try testClz(i256, minInt(i256), 0);
1572 try testClz(i256, 1 << 200, 55);
1573 try testClz(i256, 0, 256);
1574}
1575
1576fn testCtz(comptime T: type, a: T, expected: u16) !void {
1577 try expect(@ctz(a) == expected);
1578}
1579
1580test "@ctz > 128 bits" {
1581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1582 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1583
1584 try testCtz(u140, 0, 140);
1585 try testCtz(u140, 1 << 139, 139);
1586 try testCtz(u140, 1 << 70, 70);
1587 try testCtz(u140, maxInt(u140), 0);
1588
1589 try testCtz(u256, 0, 256);
1590 try testCtz(u256, 1 << 255, 255);
1591 try testCtz(u256, 1 << 200, 200);
1592 try testCtz(u256, 3 << 5, 5);
1593
1594 try testCtz(i140, -1, 0);
1595 try testCtz(i140, minInt(i140), 139);
1596 try testCtz(i140, 0, 140);
1597 try testCtz(i140, -1 << 70, 70);
1598
1599 try testCtz(i256, -1, 0);
1600 try testCtz(i256, minInt(i256), 255);
1601 try testCtz(i256, 0, 256);
1602 try testCtz(i256, -1 << 200, 200);
1603}
1604
1605fn testPopCount(comptime T: type, a: T, expected: u16) !void {
1606 try expect(@popCount(a) == expected);
1607}
1608
1609test "@popCount > 128 bits" {
1610 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1611 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1612
1613 try testPopCount(u140, 0, 0);
1614 try testPopCount(u140, maxInt(u140), 140);
1615 try testPopCount(u140, (1 << 139) | (1 << 70) | 1, 3);
1616 try testPopCount(u140, (1 << 5) - 1, 5);
1617
1618 try testPopCount(u256, 0, 0);
1619 try testPopCount(u256, maxInt(u256), 256);
1620 try testPopCount(u256, (1 << 255) | (1 << 200) | (1 << 17) | (1 << 3), 4);
1621 try testPopCount(u256, (1 << 64) - 1, 64);
1622
1623 try testPopCount(i140, -1, 140);
1624 try testPopCount(i140, minInt(i140), 1);
1625 try testPopCount(i140, 0, 0);
1626 try testPopCount(i140, -1 << 70, 70);
1627
1628 try testPopCount(i256, -1, 256);
1629 try testPopCount(i256, minInt(i256), 1);
1630 try testPopCount(i256, 0, 0);
1631 try testPopCount(i256, -1 << 200, 56);
1632}
1633
1634fn testBitReverse(comptime T: type, a: T, expected: T) !void {
1635 try expect(@bitReverse(a) == expected);
1636}
1637
1638test "@bitReverse > 128 bits" {
1639 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1640 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1641
1642 try testBitReverse(u140, 1 << 139, 1);
1643 try testBitReverse(u140, 1 << 70, 1 << 69);
1644 try testBitReverse(u140, 0, 0);
1645 try testBitReverse(u140, maxInt(u140), maxInt(u140));
1646
1647 try testBitReverse(u256, 1 << 255, 1);
1648 try testBitReverse(u256, 1 << 200, 1 << 55);
1649 try testBitReverse(u256, 0, 0);
1650 try testBitReverse(u256, maxInt(u256), maxInt(u256));
1651
1652 try testBitReverse(i140, -1, -1);
1653 try testBitReverse(i140, minInt(i140), 1);
1654 try testBitReverse(i140, 1 << 70, 1 << 69);
1655 try testBitReverse(i140, 0, 0);
1656
1657 try testBitReverse(i256, -1, -1);
1658 try testBitReverse(i256, minInt(i256), 1);
1659 try testBitReverse(i256, 1 << 200, 1 << 55);
1660 try testBitReverse(i256, 0, 0);
1661}
1662
1663fn testByteSwap(comptime T: type, a: T, expected: T) !void {
1664 try expect(@byteSwap(a) == expected);
1665}
1666
1667test "@byteSwap > 128 bits" {
1668 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1669 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1670
1671 try testByteSwap(u144, 1 << 136, 1);
1672 try testByteSwap(u144, 1, 1 << 136);
1673 try testByteSwap(u144, 0, 0);
1674 try testByteSwap(u144, maxInt(u144), maxInt(u144));
1675
1676 try testByteSwap(u256, 1 << 248, 1);
1677 try testByteSwap(u256, 1 << 120, 1 << 128);
1678 try testByteSwap(u256, 1, 1 << 248);
1679 try testByteSwap(u256, maxInt(u256), maxInt(u256));
1680
1681 try testByteSwap(i144, -1, -1);
1682 try testByteSwap(i144, minInt(i144), 128);
1683 try testByteSwap(i144, 1, 1 << 136);
1684 try testByteSwap(i144, 1 << 64, 1 << 72);
1685
1686 try testByteSwap(i256, -1, -1);
1687 try testByteSwap(i256, minInt(i256), 128);
1688 try testByteSwap(i256, 1, 1 << 248);
1689 try testByteSwap(i256, 1 << 120, 1 << 128);
1690}
1691
1692fn testMax(comptime T: type, a: T, b: T, expected: T) !void {
1693 try expect(@max(a, b) == expected);
1694}
1695
1696test "@max > 128 bits" {
1697 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1698 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1699
1700 try testMax(u140, 0, maxInt(u140), maxInt(u140));
1701 try testMax(u140, 1 << 139, 1 << 138, 1 << 139);
1702 try testMax(u140, (1 << 100) + 7, (1 << 100) + 3, (1 << 100) + 7);
1703 try testMax(u140, maxInt(u140) - 1, maxInt(u140), maxInt(u140));
1704
1705 try testMax(u200, 1 << 199, 1 << 198, 1 << 199);
1706 try testMax(u200, (1 << 150) + (1 << 17), (1 << 150) + (1 << 18), (1 << 150) + (1 << 18));
1707 try testMax(u200, 0, 1 << 123, 1 << 123);
1708 try testMax(u200, maxInt(u200), maxInt(u200) - 1, maxInt(u200));
1709
1710 try testMax(i140, -1, 0, 0);
1711 try testMax(i140, minInt(i140), maxInt(i140), maxInt(i140));
1712 try testMax(i140, -1 << 70, -1 << 69, -1 << 69);
1713 try testMax(i140, (1 << 100) - 1, 1 << 100, 1 << 100);
1714
1715 try testMax(i200, -1, minInt(i200), -1);
1716 try testMax(i200, -1 << 150, -1 << 149, -1 << 149);
1717 try testMax(i200, 1 << 198, (1 << 198) - 1, 1 << 198);
1718 try testMax(i200, maxInt(i200), 0, maxInt(i200));
1719}
1720
1721fn testMin(comptime T: type, a: T, b: T, expected: T) !void {
1722 try expect(@min(a, b) == expected);
1723}
1724
1725test "@min > 128 bits" {
1726 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1727 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1728
1729 try testMin(u140, 0, maxInt(u140), 0);
1730 try testMin(u140, 1 << 139, 1 << 138, 1 << 138);
1731 try testMin(u140, (1 << 100) + 7, (1 << 100) + 3, (1 << 100) + 3);
1732 try testMin(u140, maxInt(u140) - 1, maxInt(u140), maxInt(u140) - 1);
1733
1734 try testMin(u200, 1 << 199, 1 << 198, 1 << 198);
1735 try testMin(u200, (1 << 150) + (1 << 17), (1 << 150) + (1 << 18), (1 << 150) + (1 << 17));
1736 try testMin(u200, 0, 1 << 123, 0);
1737 try testMin(u200, maxInt(u200), maxInt(u200) - 1, maxInt(u200) - 1);
1738
1739 try testMin(i140, -1, 0, -1);
1740 try testMin(i140, minInt(i140), maxInt(i140), minInt(i140));
1741 try testMin(i140, -1 << 70, -1 << 69, -1 << 70);
1742 try testMin(i140, (1 << 100) - 1, 1 << 100, (1 << 100) - 1);
1743
1744 try testMin(i200, -1, minInt(i200), minInt(i200));
1745 try testMin(i200, -1 << 150, -1 << 149, -1 << 150);
1746 try testMin(i200, 1 << 198, (1 << 198) - 1, (1 << 198) - 1);
1747 try testMin(i200, maxInt(i200), 0, 0);
1748}
1749
1750fn testAbs(comptime T: type, a: T, expected: anytype) !void {
1751 try expect(@abs(a) == expected);
1752}
1753
1754test "@abs > 128 bits" {
1755 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1756 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1757
1758 try testAbs(u140, 0, 0);
1759 try testAbs(u140, 1 << 139, 1 << 139);
1760 try testAbs(u200, 123456789, 123456789);
1761 try testAbs(u200, maxInt(u200), maxInt(u200));
1762
1763 try testAbs(i140, 0, 0);
1764 try testAbs(i140, 1, 1);
1765 try testAbs(i140, -1, 1);
1766 try testAbs(i140, minInt(i140), 1 << 139);
1767
1768 try testAbs(i200, 1 << 198, 1 << 198);
1769 try testAbs(i200, -1 << 198, 1 << 198);
1770 try testAbs(i200, maxInt(i200), maxInt(i200));
1771 try testAbs(i200, minInt(i200), 1 << 199);
1772}
1773
1774fn testRem(comptime T: type, numerator: T, denominator: T, expected: T) !void {
1775 try expect(@rem(numerator, denominator) == expected);
1776}
1777
1778test "@rem > 128 bits" {
1779 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1780 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1781
1782 try testRem(u140, 0, maxInt(u140), 0);
1783 try testRem(u140, maxInt(u140), maxInt(u140), 0);
1784 try testRem(u140, maxInt(u140), 2, 1);
1785 try testRem(u140, (1 << 139) + 5, 1 << 70, 5);
1786 try testRem(u140, (1 << 100) + (1 << 50) + 7, 1 << 50, 7);
1787 try testRem(u200, 123, 1 << 100, 123);
1788 try testRem(u200, 1 << 120, 1 << 60, 0);
1789 try testRem(u200, maxInt(u200), 1 << 100, (1 << 100) - 1);
1790
1791 try testRem(i140, 0, maxInt(i140), 0);
1792 try testRem(i140, maxInt(i140), maxInt(i140), 0);
1793 try testRem(i140, -((1 << 100) + 1), 1 << 50, -1);
1794 try testRem(i140, (1 << 100) + 1, -(1 << 50), 1);
1795 try testRem(i140, -((1 << 100) + 1), -(1 << 50), -1);
1796 try testRem(i200, minInt(i200), 1, 0);
1797 try testRem(i200, minInt(i200), -2, 0);
1798 try testRem(i200, maxInt(i200), 2, 1);
1799}
1800
1801fn testMod(comptime T: type, numerator: T, denominator: T, expected: T) !void {
1802 try expect(@mod(numerator, denominator) == expected);
1803}
1804
1805test "@mod > 128 bits" {
1806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1807 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1808
1809 try testMod(u140, 0, maxInt(u140), 0);
1810 try testMod(u140, maxInt(u140), maxInt(u140), 0);
1811 try testMod(u140, maxInt(u140), 2, 1);
1812 try testMod(u140, (1 << 139) + 5, 1 << 70, 5);
1813 try testMod(u140, (1 << 100) + (1 << 50) + 7, 1 << 50, 7);
1814 try testMod(u200, 123, 1 << 100, 123);
1815 try testMod(u200, 1 << 120, 1 << 60, 0);
1816 try testMod(u200, maxInt(u200), 1 << 100, (1 << 100) - 1);
1817
1818 try testMod(i140, 0, maxInt(i140), 0);
1819 try testMod(i140, maxInt(i140), maxInt(i140), 0);
1820 try testMod(i140, -((1 << 100) + 1), 1 << 50, (1 << 50) - 1);
1821 try testMod(i140, (1 << 100) + 1, -(1 << 50), -(1 << 50) + 1);
1822 try testMod(i140, -((1 << 100) + 1), -(1 << 50), -1);
1823 try testMod(i200, minInt(i200), 1, 0);
1824 try testMod(i200, minInt(i200), -2, 0);
1825 try testMod(i200, maxInt(i200), 2, 1);
1826}
1827
1828fn testDivFloor(comptime T: type, numerator: T, denominator: T, expected: T) !void {
1829 try expect(@divFloor(numerator, denominator) == expected);
1830}
1831
1832test "@divFloor > 128 bits" {
1833 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1834 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1835
1836 try testDivFloor(u140, 0, maxInt(u140), 0);
1837 try testDivFloor(u140, maxInt(u140), maxInt(u140), 1);
1838 try testDivFloor(u140, maxInt(u140), 2, maxInt(u140) >> 1);
1839 try testDivFloor(u140, (1 << 139) + 5, 1 << 70, 1 << 69);
1840 try testDivFloor(u140, (1 << 100) + (1 << 50) + 7, 1 << 50, (1 << 50) + 1);
1841 try testDivFloor(u200, 123, 1 << 100, 0);
1842 try testDivFloor(u200, 1 << 120, 1 << 60, 1 << 60);
1843 try testDivFloor(u200, maxInt(u200), 1 << 100, (1 << 100) - 1);
1844
1845 try testDivFloor(i140, 0, maxInt(i140), 0);
1846 try testDivFloor(i140, maxInt(i140), maxInt(i140), 1);
1847 try testDivFloor(i140, -((1 << 100) + 1), 1 << 50, -(1 << 50) - 1);
1848 try testDivFloor(i140, (1 << 100) + 1, -(1 << 50), -(1 << 50) - 1);
1849 try testDivFloor(i140, -((1 << 100) + 1), -(1 << 50), 1 << 50);
1850 try testDivFloor(i200, -3, 2, -2);
1851 try testDivFloor(i200, minInt(i200), 1, minInt(i200));
1852 try testDivFloor(i200, minInt(i200), -2, 1 << 198);
1853 try testDivFloor(i200, maxInt(i200), 2, (1 << 198) - 1);
1854}
1855
1856fn testDivTrunc(comptime T: type, numerator: T, denominator: T, expected: T) !void {
1857 try expect(@divTrunc(numerator, denominator) == expected);
1858}
1859
1860test "@divTrunc > 128 bits" {
1861 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1862 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1863
1864 try testDivTrunc(u140, 0, maxInt(u140), 0);
1865 try testDivTrunc(u140, maxInt(u140), maxInt(u140), 1);
1866 try testDivTrunc(u140, maxInt(u140), 2, maxInt(u140) >> 1);
1867 try testDivTrunc(u140, (1 << 139) + 5, 1 << 70, 1 << 69);
1868 try testDivTrunc(u140, (1 << 100) + (1 << 50) + 7, 1 << 50, (1 << 50) + 1);
1869 try testDivTrunc(u200, 123, 1 << 100, 0);
1870 try testDivTrunc(u200, 1 << 120, 1 << 60, 1 << 60);
1871 try testDivTrunc(u200, maxInt(u200), 1 << 100, (1 << 100) - 1);
1872
1873 try testDivTrunc(i140, 0, maxInt(i140), 0);
1874 try testDivTrunc(i140, maxInt(i140), maxInt(i140), 1);
1875 try testDivTrunc(i140, -((1 << 100) + 1), 1 << 50, -(1 << 50));
1876 try testDivTrunc(i140, (1 << 100) + 1, -(1 << 50), -(1 << 50));
1877 try testDivTrunc(i140, -((1 << 100) + 1), -(1 << 50), 1 << 50);
1878 try testDivTrunc(i200, -3, 2, -1);
1879 try testDivTrunc(i200, minInt(i200), 1, minInt(i200));
1880 try testDivTrunc(i200, minInt(i200), -2, 1 << 198);
1881 try testDivTrunc(i200, maxInt(i200), 2, (1 << 198) - 1);
1882}
1883
13201884test "overflow arithmetic with u0 values" {
13211885 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13221886
test/behavior/packed-struct.zig-2
......@@ -582,7 +582,6 @@ test "packed struct fields modification" {
582582
583583test "nested packed struct field access test" {
584584 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
585 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
586585 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
587586 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
588587 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -736,7 +735,6 @@ test "nested packed struct at non-zero offset 2" {
736735 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
737736 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738737 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
739 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
740738 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
741739 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
742740
test/behavior/saturating_arithmetic.zig+104-62
......@@ -4,6 +4,14 @@ const minInt = std.math.minInt;
44const maxInt = std.math.maxInt;
55const expect = std.testing.expect;
66
7fn testSatAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void {
8 try expect((lhs +| rhs) == expected);
9
10 var x = lhs;
11 x +|= rhs;
12 try expect(x == expected);
13}
14
715test "saturating add" {
816 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
917 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -28,32 +36,23 @@ test "saturating add" {
2836 try testSatAdd(u2, 3, 2, 3);
2937 try testSatAdd(u3, 7, 1, 7);
3038 }
31
32 fn testSatAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void {
33 try expect((lhs +| rhs) == expected);
34
35 var x = lhs;
36 x +|= rhs;
37 try expect(x == expected);
38 }
3939 };
4040
4141 try S.doTheTest();
4242 try comptime S.doTheTest();
4343
44 try comptime S.testSatAdd(comptime_int, 0, 0, 0);
45 try comptime S.testSatAdd(comptime_int, -1, 1, 0);
46 try comptime S.testSatAdd(comptime_int, 3, 2, 5);
47 try comptime S.testSatAdd(comptime_int, -3, -2, -5);
48 try comptime S.testSatAdd(comptime_int, 3, -2, 1);
49 try comptime S.testSatAdd(comptime_int, -3, 2, -1);
50 try comptime S.testSatAdd(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 1119305249183743626545271163355074748512);
51 try comptime S.testSatAdd(comptime_int, 7, -593423721213448152027139550640105366508, -593423721213448152027139550640105366501);
44 try comptime testSatAdd(comptime_int, 0, 0, 0);
45 try comptime testSatAdd(comptime_int, -1, 1, 0);
46 try comptime testSatAdd(comptime_int, 3, 2, 5);
47 try comptime testSatAdd(comptime_int, -3, -2, -5);
48 try comptime testSatAdd(comptime_int, 3, -2, 1);
49 try comptime testSatAdd(comptime_int, -3, 2, -1);
50 try comptime testSatAdd(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 1119305249183743626545271163355074748512);
51 try comptime testSatAdd(comptime_int, 7, -593423721213448152027139550640105366508, -593423721213448152027139550640105366501);
5252}
5353
5454test "saturating add 128bit" {
5555 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
5756 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5857 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5958 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -65,19 +64,20 @@ test "saturating add 128bit" {
6564 try testSatAdd(i128, minInt(i128), maxInt(i128), -1);
6665 try testSatAdd(u128, maxInt(u128), 1, maxInt(u128));
6766 }
68 fn testSatAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void {
69 try expect((lhs +| rhs) == expected);
70
71 var x = lhs;
72 x +|= rhs;
73 try expect(x == expected);
74 }
7567 };
7668
7769 try S.doTheTest();
7870 try comptime S.doTheTest();
7971}
8072
73fn testSatSub(comptime T: type, lhs: T, rhs: T, expected: T) !void {
74 try expect((lhs -| rhs) == expected);
75
76 var x = lhs;
77 x -|= rhs;
78 try expect(x == expected);
79}
80
8181test "saturating subtraction" {
8282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -101,32 +101,23 @@ test "saturating subtraction" {
101101 try testSatSub(u8, 10, 3, 7);
102102 try testSatSub(u8, 0, 255, 0);
103103 }
104
105 fn testSatSub(comptime T: type, lhs: T, rhs: T, expected: T) !void {
106 try expect((lhs -| rhs) == expected);
107
108 var x = lhs;
109 x -|= rhs;
110 try expect(x == expected);
111 }
112104 };
113105
114106 try S.doTheTest();
115107 try comptime S.doTheTest();
116108
117 try comptime S.testSatSub(comptime_int, 0, 0, 0);
118 try comptime S.testSatSub(comptime_int, 1, 1, 0);
119 try comptime S.testSatSub(comptime_int, 3, 2, 1);
120 try comptime S.testSatSub(comptime_int, -3, -2, -1);
121 try comptime S.testSatSub(comptime_int, 3, -2, 5);
122 try comptime S.testSatSub(comptime_int, -3, 2, -5);
123 try comptime S.testSatSub(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 182846383813587550256162760261375991602);
124 try comptime S.testSatSub(comptime_int, 7, -593423721213448152027139550640105366508, 593423721213448152027139550640105366515);
109 try comptime testSatSub(comptime_int, 0, 0, 0);
110 try comptime testSatSub(comptime_int, 1, 1, 0);
111 try comptime testSatSub(comptime_int, 3, 2, 1);
112 try comptime testSatSub(comptime_int, -3, -2, -1);
113 try comptime testSatSub(comptime_int, 3, -2, 5);
114 try comptime testSatSub(comptime_int, -3, 2, -5);
115 try comptime testSatSub(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 182846383813587550256162760261375991602);
116 try comptime testSatSub(comptime_int, 7, -593423721213448152027139550640105366508, 593423721213448152027139550640105366515);
125117}
126118
127119test "saturating subtraction 128bit" {
128120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
130121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131122 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132123 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -138,14 +129,6 @@ test "saturating subtraction 128bit" {
138129 try testSatSub(i128, minInt(i128), -maxInt(i128), -1);
139130 try testSatSub(u128, 0, maxInt(u128), 0);
140131 }
141
142 fn testSatSub(comptime T: type, lhs: T, rhs: T, expected: T) !void {
143 try expect((lhs -| rhs) == expected);
144
145 var x = lhs;
146 x -|= rhs;
147 try expect(x == expected);
148 }
149132 };
150133
151134 try S.doTheTest();
......@@ -257,7 +240,6 @@ test "saturating mul i64, i128" {
257240
258241test "saturating multiplication" {
259242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
261243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262244 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
263245 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -294,6 +276,14 @@ test "saturating multiplication" {
294276 try comptime testSatMul(comptime_int, 7, -593423721213448152027139550640105366508, -4153966048494137064189976854480737565556);
295277}
296278
279fn testSatShl(comptime Lhs: type, lhs: Lhs, comptime Rhs: type, rhs: Rhs, expected: Lhs) !void {
280 try expect((lhs <<| rhs) == expected);
281
282 var x = lhs;
283 x <<|= rhs;
284 try expect(x == expected);
285}
286
297287test "saturating shift-left" {
298288 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299289 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -320,23 +310,15 @@ test "saturating shift-left" {
320310 try testSatShl(u8, 0, u4, 8, 0);
321311 try testSatShl(u8, 3, u4, 8, maxInt(u8));
322312 }
323
324 fn testSatShl(comptime Lhs: type, lhs: Lhs, comptime Rhs: type, rhs: Rhs, expected: Lhs) !void {
325 try expect((lhs <<| rhs) == expected);
326
327 var x = lhs;
328 x <<|= rhs;
329 try expect(x == expected);
330 }
331313 };
332314
333315 try S.doTheTest();
334316 try comptime S.doTheTest();
335317
336 try comptime S.testSatShl(comptime_int, 0, comptime_int, 0, 0);
337 try comptime S.testSatShl(comptime_int, 1, comptime_int, 2, 4);
338 try comptime S.testSatShl(comptime_int, 13, comptime_int, 150, 18554220005177478453757717602843436772975706112);
339 try comptime S.testSatShl(comptime_int, -582769, comptime_int, 180, -893090893854873184096635538665358532628308979495815656505344);
318 try comptime testSatShl(comptime_int, 0, comptime_int, 0, 0);
319 try comptime testSatShl(comptime_int, 1, comptime_int, 2, 4);
320 try comptime testSatShl(comptime_int, 13, comptime_int, 150, 18554220005177478453757717602843436772975706112);
321 try comptime testSatShl(comptime_int, -582769, comptime_int, 180, -893090893854873184096635538665358532628308979495815656505344);
340322}
341323
342324test "saturating shift-left large rhs" {
......@@ -386,3 +368,63 @@ test "saturating shl uses the LHS type" {
386368
387369 try expect((1 <<| @as(u8, 200)) == 1606938044258990275541962092341162602522202993782792835301376);
388370}
371
372test "sat add > 128 bits" {
373 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
374 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
375
376 try testSatAdd(u140, 0, 0, 0);
377 try testSatAdd(u140, maxInt(u140), 1, maxInt(u140));
378 try testSatAdd(u200, 1 << 150, 1 << 20, (1 << 150) + (1 << 20));
379 try testSatAdd(u200, maxInt(u200), maxInt(u200), maxInt(u200));
380
381 try testSatAdd(i140, minInt(i140), -1, minInt(i140));
382 try testSatAdd(i140, maxInt(i140), 1, maxInt(i140));
383 try testSatAdd(i200, -1 << 150, 1 << 149, -1 << 149);
384 try testSatAdd(i200, maxInt(i200), maxInt(i200), maxInt(i200));
385}
386
387test "sat sub > 128 bits" {
388 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
389 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
390
391 try testSatSub(u140, 0, 1, 0);
392 try testSatSub(u140, maxInt(u140), maxInt(u140), 0);
393 try testSatSub(u200, 1 << 150, 1 << 20, (1 << 150) - (1 << 20));
394 try testSatSub(u200, maxInt(u200), 0, maxInt(u200));
395
396 try testSatSub(i140, minInt(i140), 1, minInt(i140));
397 try testSatSub(i140, maxInt(i140), -1, maxInt(i140));
398 try testSatSub(i200, -1 << 150, 1 << 149, -3 << 149);
399 try testSatSub(i200, 0, minInt(i200), maxInt(i200));
400}
401
402test "sat mul > 128 bits" {
403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
404 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
405
406 try testSatMul(u140, 0, maxInt(u140), 0);
407 try testSatMul(u140, 1 << 70, 1 << 69, 1 << 139);
408 try testSatMul(u200, maxInt(u200), 2, maxInt(u200));
409 try testSatMul(u200, maxInt(u200) - 1, 1, maxInt(u200) - 1);
410
411 try testSatMul(i140, -1, maxInt(i140), -maxInt(i140));
412 try testSatMul(i140, minInt(i140), -1, maxInt(i140));
413 try testSatMul(i200, 1 << 100, 1 << 99, maxInt(i200));
414 try testSatMul(i200, -1 << 150, 1 << 30, -1 << 180);
415}
416
417test "sat shl > 128 bits" {
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
420
421 try testSatShl(u140, 0, u8, 17, 0);
422 try testSatShl(u140, 1 << 100, u8, 20, 1 << 120);
423 try testSatShl(u200, maxInt(u200), u8, 1, maxInt(u200));
424 try testSatShl(u200, 1 << 199, u8, 1, maxInt(u200));
425
426 try testSatShl(i140, 0, u8, 17, 0);
427 try testSatShl(i140, 1 << 100, u8, 38, 1 << 138);
428 try testSatShl(i140, 1 << 100, u8, 39, maxInt(i140));
429 try testSatShl(i200, minInt(i200) + 1, u8, 1, minInt(i200));
430}
test/behavior/struct.zig-1
......@@ -540,7 +540,6 @@ test "zero-bit field in packed struct" {
540540test "packed struct with non-ABI-aligned field" {
541541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
542542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
543 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
544543 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
545544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
546545 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/switch.zig-2
......@@ -1457,8 +1457,6 @@ test "switch on nested packed containers" {
14571457}
14581458
14591459test "switch on large types" {
1460 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1461
14621460 const S = struct {
14631461 fn doTheTest(a: u128, b: i500) !void {
14641462 switch (a) {
test/behavior/switch_loop.zig-2
......@@ -566,8 +566,6 @@ test "switch loop with packed unions with OPV" {
566566}
567567
568568test "switch loop on large types" {
569 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
570
571569 const S = struct {
572570 fn doTheTest(a: u128, b: i500) !void {
573571 label: switch (a) {
test/behavior/truncate.zig+46
......@@ -1,4 +1,7 @@
11const std = @import("std");
2const math = std.math;
3const maxInt = math.maxInt;
4const minInt = math.minInt;
25const builtin = @import("builtin");
36const assert = std.debug.assert;
47const expect = std.testing.expect;
......@@ -64,6 +67,49 @@ test "truncate on comptime integer" {
6467 try expect(w == 0);
6568}
6669
70fn testTruncate(comptime S: type, a: S, comptime D: type, expected: D) !void {
71 const actual: D = @truncate(a);
72 try expect(actual == expected);
73}
74
75test "@truncate > 128 bits" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
78
79 try testTruncate(u140, 0, u128, 0);
80 try testTruncate(u140, maxInt(u140), u128, maxInt(u128));
81 try testTruncate(u140, 1 << 139, u128, 0);
82 try testTruncate(u140, (1 << 139) | (1 << 64) | 0x55, u128, (1 << 64) | 0x55);
83 try testTruncate(u140, (1 << 100) | (1 << 63), u128, (1 << 100) | (1 << 63));
84 try testTruncate(u140, (1 << 130) | 0xabcd, u16, 0xabcd);
85
86 try testTruncate(u256, 1 << 200, u128, 0);
87 try testTruncate(u256, (1 << 200) | (1 << 127) | 1, u128, (1 << 127) | 1);
88 try testTruncate(u256, maxInt(u256), u128, maxInt(u128));
89 try testTruncate(u256, (1 << 255) | (1 << 128) | 0x1234_5678_9abc_def0, u64, 0x1234_5678_9abc_def0);
90 try testTruncate(u256, (1 << 250) | (1 << 32), u32, 0);
91 try testTruncate(u256, (1 << 129) | (1 << 63), u64, 1 << 63);
92
93 try testTruncate(i140, 0, i128, 0);
94 try testTruncate(i140, -1, i128, -1);
95 try testTruncate(i140, -2, i8, -2);
96 try testTruncate(i140, -1 << 80, i64, 0);
97 try testTruncate(i140, (-1 << 80) | 0x1234, i16, 0x1234);
98 try testTruncate(i140, minInt(i140), i128, 0);
99 try testTruncate(i140, maxInt(i140), i128, -1);
100 try testTruncate(i140, (1 << 127) - 1, i128, maxInt(i128));
101
102 try testTruncate(i256, -1, i128, -1);
103 try testTruncate(i256, minInt(i256), i128, 0);
104 try testTruncate(i256, (-1 << 128) | maxInt(i128), i128, maxInt(i128));
105 try testTruncate(i256, (-1 << 200) | (1 << 127), i128, minInt(i128));
106 try testTruncate(i256, -255, i8, 1);
107 try testTruncate(i256, (-1 << 64) | 0x1234_5678, i32, 0x1234_5678);
108
109 try testTruncate(i257, maxInt(i257), i256, -1);
110 try testTruncate(u257, maxInt(u257), u256, maxInt(u256));
111}
112
67113test "truncate on vectors" {
68114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69115 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;