@zigc/lib 0.16.0 → 0.17.0-dev.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/c/fcntl.zig +6 -1
  2. package/c/inttypes.zig +0 -10
  3. package/c/math.zig +46 -122
  4. package/c/pthread.zig +57 -0
  5. package/c/search.zig +1 -27
  6. package/c/stdlib/drand48.zig +0 -57
  7. package/c/stdlib.zig +0 -100
  8. package/c/string.zig +20 -7
  9. package/c/strings.zig +0 -38
  10. package/c/unistd.zig +27 -26
  11. package/c/wchar.zig +10 -0
  12. package/c.zig +2 -2
  13. package/compiler/aro/aro/CodeGen.zig +5 -6
  14. package/compiler/aro/aro/Compilation.zig +17 -14
  15. package/compiler/aro/aro/Driver.zig +14 -13
  16. package/compiler/aro/aro/Parser.zig +20 -15
  17. package/compiler/aro/aro/Pragma.zig +3 -2
  18. package/compiler/aro/aro/Preprocessor.zig +9 -6
  19. package/compiler/aro/aro/pragmas/message.zig +3 -2
  20. package/compiler/aro/aro/text_literal.zig +3 -2
  21. package/compiler/aro/assembly_backend/x86_64.zig +4 -4
  22. package/compiler/build_runner.zig +0 -2
  23. package/compiler/reduce/Walk.zig +7 -7
  24. package/compiler/test_runner.zig +2 -2
  25. package/compiler/translate-c/Translator.zig +6 -2
  26. package/compiler/translate-c/main.zig +1 -1
  27. package/compiler_rt/cos.zig +0 -2
  28. package/compiler_rt/divmodei4.zig +40 -17
  29. package/compiler_rt/exp.zig +1 -6
  30. package/compiler_rt/exp2.zig +1 -6
  31. package/compiler_rt/exp_f128.zig +377 -0
  32. package/compiler_rt/fabs.zig +0 -2
  33. package/compiler_rt/fma.zig +0 -2
  34. package/compiler_rt/fmax.zig +0 -2
  35. package/compiler_rt/fmin.zig +0 -2
  36. package/compiler_rt/fmod.zig +0 -2
  37. package/compiler_rt/limb64.zig +876 -15
  38. package/compiler_rt/log.zig +0 -2
  39. package/compiler_rt/log10.zig +0 -2
  40. package/compiler_rt/log2.zig +0 -2
  41. package/compiler_rt/mulXi3.zig +1 -1
  42. package/compiler_rt/round.zig +0 -2
  43. package/compiler_rt/sin.zig +0 -2
  44. package/compiler_rt/sincos.zig +0 -2
  45. package/compiler_rt/sqrt.zig +0 -2
  46. package/compiler_rt/ssp.zig +1 -1
  47. package/compiler_rt/tan.zig +0 -2
  48. package/compiler_rt/trunc.zig +0 -2
  49. package/compiler_rt/udivmodei4.zig +28 -0
  50. package/fuzzer.zig +2 -0
  51. package/libc/musl/arch/mipsn32/syscall_arch.h +35 -32
  52. package/package.json +1 -1
  53. package/std/Build/Cache.zig +6 -6
  54. package/std/Build/Step/Compile.zig +0 -1
  55. package/std/Build/Step/Run.zig +2 -2
  56. package/std/Build/Step.zig +2 -4
  57. package/std/Build/WebServer.zig +2 -2
  58. package/std/Build.zig +0 -3
  59. package/std/Io/Dir.zig +7 -2
  60. package/std/Io/Dispatch.zig +3 -13
  61. package/std/Io/File/Writer.zig +8 -6
  62. package/std/Io/Reader.zig +8 -9
  63. package/std/Io/Semaphore.zig +112 -17
  64. package/std/Io/Terminal.zig +1 -1
  65. package/std/Io/Threaded.zig +171 -37
  66. package/std/Io/Uring.zig +13 -15
  67. package/std/Io/Writer.zig +46 -42
  68. package/std/Io/net.zig +11 -11
  69. package/std/Io.zig +90 -26
  70. package/std/SemanticVersion.zig +1 -1
  71. package/std/Target/Query.zig +2 -2
  72. package/std/Target.zig +50 -5
  73. package/std/array_hash_map.zig +9 -18
  74. package/std/builtin.zig +4 -0
  75. package/std/c/haiku.zig +3 -0
  76. package/std/c/serenity.zig +1 -6
  77. package/std/c.zig +89 -7
  78. package/std/compress/flate/Decompress.zig +2 -3
  79. package/std/compress/zstd/Decompress.zig +2 -4
  80. package/std/crypto/Certificate.zig +13 -1
  81. package/std/crypto/ascon.zig +75 -33
  82. package/std/crypto/codecs/asn1/Oid.zig +12 -1
  83. package/std/crypto/codecs/base64_hex_ct.zig +2 -4
  84. package/std/crypto/ml_kem.zig +2 -9
  85. package/std/crypto/tls/Client.zig +79 -4
  86. package/std/crypto/tls.zig +1 -1
  87. package/std/crypto.zig +1 -0
  88. package/std/debug/Pdb.zig +1 -1
  89. package/std/debug.zig +4 -3
  90. package/std/fmt.zig +8 -3
  91. package/std/fs/path.zig +6 -4
  92. package/std/heap/BufferFirstAllocator.zig +165 -0
  93. package/std/heap.zig +2 -126
  94. package/std/http/Client.zig +21 -24
  95. package/std/http.zig +3 -4
  96. package/std/json/Scanner.zig +2 -2
  97. package/std/os/emscripten.zig +1 -1
  98. package/std/os/linux/IoUring.zig +2 -0
  99. package/std/os/linux/aarch64.zig +41 -12
  100. package/std/os/linux/arc.zig +173 -0
  101. package/std/os/linux/arm.zig +41 -12
  102. package/std/os/linux/hexagon.zig +33 -11
  103. package/std/os/linux/loongarch32.zig +41 -13
  104. package/std/os/linux/loongarch64.zig +41 -12
  105. package/std/os/linux/m68k.zig +41 -13
  106. package/std/os/linux/mips.zig +67 -36
  107. package/std/os/linux/mips64.zig +60 -29
  108. package/std/os/linux/mipsn32.zig +60 -29
  109. package/std/os/linux/or1k.zig +41 -12
  110. package/std/os/linux/powerpc.zig +41 -12
  111. package/std/os/linux/powerpc64.zig +41 -12
  112. package/std/os/linux/riscv32.zig +41 -12
  113. package/std/os/linux/riscv64.zig +41 -12
  114. package/std/os/linux/s390x.zig +44 -7
  115. package/std/os/linux/sparc64.zig +83 -52
  116. package/std/os/linux/thumb.zig +52 -36
  117. package/std/os/linux/x32.zig +41 -12
  118. package/std/os/linux/x86.zig +42 -13
  119. package/std/os/linux/x86_64.zig +41 -12
  120. package/std/os/linux.zig +412 -436
  121. package/std/os/uefi/tables/boot_services.zig +9 -8
  122. package/std/os.zig +41 -0
  123. package/std/process.zig +1 -1
  124. package/std/sort.zig +3 -3
  125. package/std/zig/Ast/Render.zig +3 -3
  126. package/std/zig/AstGen.zig +44 -98
  127. package/std/zig/AstRlAnnotate.zig +0 -11
  128. package/std/zig/BuiltinFn.zig +0 -32
  129. package/std/zig/LibCInstallation.zig +4 -3
  130. package/std/zig/Parse.zig +7 -7
  131. package/std/zig/WindowsSdk.zig +13 -13
  132. package/std/zig/Zir.zig +50 -63
  133. package/std/zig/ZonGen.zig +6 -5
  134. package/std/zig/llvm/Builder.zig +12 -12
  135. package/std/zig.zig +1 -10
  136. package/std/zip.zig +5 -5
  137. package/zig.h +340 -1
  138. package/libc/mingw/math/fdiml.c +0 -24
  139. package/libc/mingw/winpthreads/spinlock.c +0 -82
  140. package/libc/musl/src/linux/tee.c +0 -8
  141. package/libc/musl/src/math/fdimf.c +0 -10
  142. package/libc/musl/src/math/fdiml.c +0 -18
  143. package/libc/musl/src/string/strdup.c +0 -10
  144. package/libc/musl/src/string/strndup.c +0 -12
  145. package/libc/musl/src/string/wcsdup.c +0 -10
  146. package/libc/musl/src/thread/pthread_spin_destroy.c +0 -6
  147. package/libc/musl/src/thread/pthread_spin_init.c +0 -6
  148. package/libc/musl/src/thread/pthread_spin_lock.c +0 -8
  149. package/libc/musl/src/thread/pthread_spin_trylock.c +0 -7
  150. package/libc/musl/src/thread/pthread_spin_unlock.c +0 -7
  151. package/libc/musl/src/unistd/dup2.c +0 -20
  152. package/libc/musl/src/unistd/dup3.c +0 -26
  153. package/libc/wasi/thread-stub/pthread_spin_lock.c +0 -8
  154. package/libc/wasi/thread-stub/pthread_spin_trylock.c +0 -8
  155. package/libc/wasi/thread-stub/pthread_spin_unlock.c +0 -7
@@ -7,6 +7,7 @@ const divCeil = std.math.divCeil;
7
7
 
8
8
  const builtin = @import("builtin");
9
9
  const compiler_rt = @import("../compiler_rt.zig");
10
+ const symbol = @import("../compiler_rt.zig").symbol;
10
11
 
11
12
  const endian = builtin.cpu.arch.endian();
12
13
 
@@ -24,10 +25,45 @@ inline fn limbSet(limbs: []u64, i: usize, value: u64) void {
24
25
  }
25
26
  }
26
27
 
27
- fn limbCount(bits: u16) u16 {
28
+ fn usedLimbCount(bits: u16) u16 {
28
29
  return divCeil(u16, bits, 64) catch unreachable;
29
30
  }
30
31
 
32
+ fn limbCount(bits: u16) u16 {
33
+ return @divExact(std.zig.target.intByteSize(&builtin.target, bits), 8);
34
+ }
35
+
36
+ fn 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
+
45
+ fn 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
+
54
+ fn 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 ms = limbGet(true_out, limb_cnt - 1);
61
+ const sign: u64 = if (!is_signed or @as(i64, @bitCast(ms)) >= 0) 0 else ~@as(u64, 0);
62
+ for (limb_cnt..true_limb_cnt) |i| {
63
+ limbSet(true_out, i, sign);
64
+ }
65
+ }
66
+
31
67
  fn Limbs(T: type) type {
32
68
  const int_info = @typeInfo(T).int;
33
69
  const limb_cnt = comptime limbCount(int_info.bits);
@@ -55,14 +91,14 @@ fn limbWrap(limb: u64, is_signed: bool, bits: u16) u64 {
55
91
  }
56
92
 
57
93
  comptime {
58
- @export(&__addo_limb64, .{ .name = "__addo_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
94
+ symbol(&__addo_limb64, "__addo_limb64");
59
95
  }
60
96
 
61
97
  fn __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];
98
+ const limb_cnt = usedLimbCount(bits);
99
+ const out = varLimbs(out_ptr, bits);
100
+ const a = constLimbs(a_ptr, bits);
101
+ const b = constLimbs(b_ptr, bits);
66
102
 
67
103
  var carry: u1 = 0;
68
104
  var i: usize = 0;
@@ -91,11 +127,13 @@ fn __addo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_s
91
127
 
92
128
  if (bits % 64 == 0) {
93
129
  limbSet(out, i, limb);
130
+ fixLastLimb(out_ptr, is_signed, bits);
94
131
  return carry != 0;
95
132
  } else {
96
133
  assert(carry == 0);
97
134
  const wrapped_limb = limbWrap(limb, is_signed, bits);
98
135
  limbSet(out, i, wrapped_limb);
136
+ fixLastLimb(out_ptr, is_signed, bits);
99
137
  return wrapped_limb != limb;
100
138
  }
101
139
  }
@@ -124,17 +162,20 @@ test __addo_limb64 {
124
162
  try test__addo_limb64(i64, maxInt(i64), 1, .{ minInt(i64), true });
125
163
  try test__addo_limb64(i65, maxInt(i65), 1, .{ minInt(i65), true });
126
164
  try test__addo_limb64(i255, -3, 2, .{ -1, false });
165
+
166
+ try test__addo_limb64(u150, maxInt(u150), 2, .{ 1, true });
167
+ try test__addo_limb64(i150, -3, 2, .{ -1, false });
127
168
  }
128
169
 
129
170
  comptime {
130
- @export(&__subo_limb64, .{ .name = "__subo_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
171
+ symbol(&__subo_limb64, "__subo_limb64");
131
172
  }
132
173
 
133
174
  fn __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];
175
+ const limb_cnt = usedLimbCount(bits);
176
+ const out = varLimbs(out_ptr, bits);
177
+ const a = constLimbs(a_ptr, bits);
178
+ const b = constLimbs(b_ptr, bits);
138
179
 
139
180
  var borrow: u1 = 0;
140
181
  var i: usize = 0;
@@ -163,10 +204,12 @@ fn __subo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_s
163
204
 
164
205
  if (bits % 64 == 0) {
165
206
  limbSet(out, i, limb);
207
+ fixLastLimb(out_ptr, is_signed, bits);
166
208
  return borrow != 0;
167
209
  } else {
168
210
  const wrapped_limb = limbWrap(limb, is_signed, bits);
169
211
  limbSet(out, i, wrapped_limb);
212
+ fixLastLimb(out_ptr, is_signed, bits);
170
213
  return borrow != 0 or wrapped_limb != limb;
171
214
  }
172
215
  }
@@ -195,19 +238,22 @@ test __subo_limb64 {
195
238
  try test__subo_limb64(i64, minInt(i64), 1, .{ maxInt(i64), true });
196
239
  try test__subo_limb64(i65, minInt(i65), 1, .{ maxInt(i65), true });
197
240
  try test__subo_limb64(i255, -1, 2, .{ -3, false });
241
+
242
+ try test__subo_limb64(u150, 2, maxInt(u150), .{ 3, true });
243
+ try test__subo_limb64(i150, -3, 2, .{ -5, false });
198
244
  }
199
245
 
200
246
  comptime {
201
- @export(&__cmp_limb64, .{ .name = "__cmp_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
247
+ symbol(&__cmp_limb64, "__cmp_limb64");
202
248
  }
203
249
 
204
250
  // a < b -> -1
205
251
  // a == b -> 0
206
252
  // a > b -> 1
207
253
  fn __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];
254
+ const limb_cnt = usedLimbCount(bits);
255
+ const a = constLimbs(a_ptr, bits);
256
+ const b = constLimbs(b_ptr, bits);
211
257
 
212
258
  var i: usize = 0;
213
259
  if (is_signed) {
@@ -263,4 +309,819 @@ test __cmp_limb64 {
263
309
  try test__cmp_limb64(i255, -3, 2, -1);
264
310
  try test__cmp_limb64(i255, -5, -5, 0);
265
311
  try test__cmp_limb64(i255, 2, -3, 1);
312
+
313
+ try test__cmp_limb64(u150, maxInt(u150) - 5, maxInt(u150) - 5, 0);
314
+ try test__cmp_limb64(i150, minInt(i150), -5, -1);
315
+ }
316
+
317
+ comptime {
318
+ symbol(&__and_limb64, "__and_limb64");
319
+ }
320
+
321
+ fn __and_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
322
+ const limb_cnt = limbCount(bits);
323
+ const out = out_ptr[0..limb_cnt];
324
+ const a = a_ptr[0..limb_cnt];
325
+ const b = b_ptr[0..limb_cnt];
326
+
327
+ var i: usize = 0;
328
+ while (i < limb_cnt) : (i += 1) {
329
+ limbSet(out, i, limbGet(a, i) & limbGet(b, i));
330
+ }
331
+ }
332
+
333
+ fn test__and_limb64(comptime T: type, a: T, b: T, expected: T) !void {
334
+ const int_info = @typeInfo(T).int;
335
+
336
+ var a_limbs = asLimbs(a);
337
+ var b_limbs = asLimbs(b);
338
+ var out: Limbs(T) = undefined;
339
+ __and_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
340
+
341
+ const expected_limbs = asLimbs(expected);
342
+ try testing.expectEqual(expected_limbs, out);
343
+ }
344
+
345
+ test __and_limb64 {
346
+ try test__and_limb64(u64, 1, 2, 0);
347
+ try test__and_limb64(u64, maxInt(u64), 2, 2);
348
+ try test__and_limb64(u65, maxInt(u65), 2, 2);
349
+ try test__and_limb64(u255, maxInt(u255), 7, 7);
350
+
351
+ try test__and_limb64(i64, 1, 2, 0);
352
+ try test__and_limb64(i64, -1, 2, 2);
353
+ try test__and_limb64(i65, minInt(i65), -1, minInt(i65));
354
+ try test__and_limb64(i255, -1, 2, 2);
355
+
356
+ try test__and_limb64(u150, maxInt(u150), 7, 7);
357
+ try test__and_limb64(i150, -2, 3, 2);
358
+ }
359
+
360
+ comptime {
361
+ symbol(&__or_limb64, "__or_limb64");
362
+ }
363
+
364
+ fn __or_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
365
+ const limb_cnt = limbCount(bits);
366
+ const out = out_ptr[0..limb_cnt];
367
+ const a = a_ptr[0..limb_cnt];
368
+ const b = b_ptr[0..limb_cnt];
369
+
370
+ var i: usize = 0;
371
+ while (i < limb_cnt) : (i += 1) {
372
+ limbSet(out, i, limbGet(a, i) | limbGet(b, i));
373
+ }
374
+ }
375
+
376
+ fn test__or_limb64(comptime T: type, a: T, b: T, expected: T) !void {
377
+ const int_info = @typeInfo(T).int;
378
+
379
+ var a_limbs = asLimbs(a);
380
+ var b_limbs = asLimbs(b);
381
+ var out: Limbs(T) = undefined;
382
+ __or_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
383
+
384
+ const expected_limbs = asLimbs(expected);
385
+ try testing.expectEqual(expected_limbs, out);
386
+ }
387
+
388
+ test __or_limb64 {
389
+ try test__or_limb64(u64, 1, 2, 3);
390
+ try test__or_limb64(u64, maxInt(u64), 2, maxInt(u64));
391
+ try test__or_limb64(u65, maxInt(u65), 2, maxInt(u65));
392
+ try test__or_limb64(u255, 1, 2, 3);
393
+
394
+ try test__or_limb64(i64, 1, 2, 3);
395
+ try test__or_limb64(i64, -1, 2, -1);
396
+ try test__or_limb64(i65, minInt(i65), 1, minInt(i65) + 1);
397
+ try test__or_limb64(i255, -3, 2, -1);
398
+
399
+ try test__or_limb64(u150, maxInt(u150) - 1, 3, maxInt(u150));
400
+ try test__or_limb64(i150, -2, 3, -1);
401
+ }
402
+
403
+ comptime {
404
+ symbol(&__xor_limb64, "__xor_limb64");
405
+ }
406
+
407
+ fn __xor_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
408
+ const limb_cnt = limbCount(bits);
409
+ const out = out_ptr[0..limb_cnt];
410
+ const a = a_ptr[0..limb_cnt];
411
+ const b = b_ptr[0..limb_cnt];
412
+
413
+ var i: usize = 0;
414
+ while (i < limb_cnt) : (i += 1) {
415
+ limbSet(out, i, limbGet(a, i) ^ limbGet(b, i));
416
+ }
417
+ }
418
+
419
+ fn test__xor_limb64(comptime T: type, a: T, b: T, expected: T) !void {
420
+ const int_info = @typeInfo(T).int;
421
+
422
+ var a_limbs = asLimbs(a);
423
+ var b_limbs = asLimbs(b);
424
+ var out: Limbs(T) = undefined;
425
+ __xor_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
426
+
427
+ const expected_limbs = asLimbs(expected);
428
+ try testing.expectEqual(expected_limbs, out);
429
+ }
430
+
431
+ test __xor_limb64 {
432
+ try test__xor_limb64(u64, 1, 2, 3);
433
+ try test__xor_limb64(u64, 3, 2, 1);
434
+ try test__xor_limb64(u65, maxInt(u65), 2, maxInt(u65) - 2);
435
+ try test__xor_limb64(u255, 7, 3, 4);
436
+
437
+ try test__xor_limb64(i64, 3, 2, 1);
438
+ try test__xor_limb64(i64, -1, 2, -3);
439
+ try test__xor_limb64(i65, minInt(i65), -1, maxInt(i65));
440
+ try test__xor_limb64(i255, -3, 2, -1);
441
+
442
+ try test__xor_limb64(u150, maxInt(u150) - 1, 3, maxInt(u150) - 2);
443
+ try test__xor_limb64(i150, -2, 3, -3);
444
+ }
445
+
446
+ comptime {
447
+ symbol(&__not_limb64, "__not_limb64");
448
+ }
449
+
450
+ fn __not_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
451
+ const limb_cnt = usedLimbCount(bits);
452
+ const out = varLimbs(out_ptr, bits);
453
+ const a = constLimbs(a_ptr, bits);
454
+
455
+ var i: usize = 0;
456
+ while (i < limb_cnt - 1) : (i += 1) {
457
+ limbSet(out, i, ~limbGet(a, i));
458
+ }
459
+
460
+ var limb: u64 = ~limbGet(a, i);
461
+ if (!is_signed and bits % 64 != 0) {
462
+ limb = limbWrap(limb, is_signed, bits);
463
+ }
464
+ limbSet(out, i, limb);
465
+ fixLastLimb(out_ptr, is_signed, bits);
466
+ }
467
+
468
+ fn test__not_limb64(comptime T: type, a: T, expected: T) !void {
469
+ const int_info = @typeInfo(T).int;
470
+ const is_signed = int_info.signedness == .signed;
471
+
472
+ var a_limbs = asLimbs(a);
473
+ var out: Limbs(T) = undefined;
474
+ __not_limb64(&out, &a_limbs, is_signed, int_info.bits);
475
+
476
+ const expected_limbs = asLimbs(expected);
477
+ try testing.expectEqual(expected_limbs, out);
478
+ }
479
+
480
+ test __not_limb64 {
481
+ try test__not_limb64(u64, 1, maxInt(u64) - 1);
482
+ try test__not_limb64(u64, 3, maxInt(u64) - 3);
483
+ try test__not_limb64(u65, maxInt(u65), 0);
484
+ try test__not_limb64(u255, 7, maxInt(u255) - 7);
485
+
486
+ try test__not_limb64(i64, 3, -4);
487
+ try test__not_limb64(i64, -1, 0);
488
+ try test__not_limb64(i65, minInt(i65), maxInt(i65));
489
+ try test__not_limb64(i255, -3, 2);
490
+
491
+ try test__not_limb64(u150, maxInt(u150), 0);
492
+ try test__not_limb64(i150, maxInt(i150), minInt(i150));
493
+ }
494
+
495
+ comptime {
496
+ symbol(&__shlo_limb64, "__shlo_limb64");
497
+ }
498
+
499
+ fn __shlo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) bool {
500
+ const limb_cnt = usedLimbCount(bits);
501
+ const out = varLimbs(out_ptr, bits);
502
+ const a = constLimbs(a_ptr, bits);
503
+
504
+ assert(shift < bits);
505
+
506
+ const limb_shift = shift / 64;
507
+ const bit_shift = shift % 64;
508
+
509
+ var carry: u64 = 0;
510
+ var i: usize = 0;
511
+ while (i < limb_cnt - 1) : (i += 1) {
512
+ if (i < limb_shift) {
513
+ limbSet(out, i, 0);
514
+ } else {
515
+ const limb = limbGet(a, i - limb_shift);
516
+ limbSet(out, i, (limb << @intCast(bit_shift)) | carry);
517
+ carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
518
+ }
519
+ }
520
+
521
+ const limb = limbGet(a, i - limb_shift);
522
+ const raw_last = (limb << @intCast(bit_shift)) | carry;
523
+ carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
524
+
525
+ const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
526
+ limbSet(out, i, last);
527
+
528
+ const sign_extend: u64 = if (is_signed and (last >> 63) == 1) ~@as(u64, 0) else 0;
529
+ const expected_carry: u64 = if (bit_shift == 0) 0 else sign_extend >> @intCast(64 - bit_shift);
530
+
531
+ var overflow = carry != expected_carry;
532
+ if (bits % 64 != 0) {
533
+ overflow = overflow or raw_last != last;
534
+ }
535
+
536
+ var j = limb_cnt - limb_shift;
537
+ while (j < limb_cnt) : (j += 1) {
538
+ overflow = overflow or limbGet(a, j) != sign_extend;
539
+ }
540
+
541
+ fixLastLimb(out_ptr, is_signed, bits);
542
+ return overflow;
543
+ }
544
+
545
+ fn test__shlo_limb64(comptime T: type, a: T, shift: u16, expected: struct { T, bool }) !void {
546
+ const int_info = @typeInfo(T).int;
547
+ const is_signed = int_info.signedness == .signed;
548
+
549
+ var a_limbs = asLimbs(a);
550
+ var out: Limbs(T) = undefined;
551
+ const overflow = __shlo_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
552
+
553
+ const expected_limbs = asLimbs(expected[0]);
554
+ try testing.expectEqual(expected_limbs, out);
555
+ try testing.expectEqual(expected[1], overflow);
556
+ }
557
+
558
+ test __shlo_limb64 {
559
+ try test__shlo_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF00, true });
560
+ try test__shlo_limb64(u64, 0x8000_0000_0000_0001, 63, .{ 0x8000_0000_0000_0000, true });
561
+ try test__shlo_limb64(u65, 1, 64, .{ 0x1_0000_0000_0000_0000, false });
562
+ try test__shlo_limb64(u65, 0x1_0000_0000_0000_0000, 1, .{ 0, true });
563
+ try test__shlo_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
564
+ try test__shlo_limb64(u255, maxInt(u255), 1, .{ maxInt(u255) - 1, true });
565
+ try test__shlo_limb64(u633, 1 << 299, 333, .{ 1 << 632, false });
566
+ try test__shlo_limb64(u633, 1 << 300, 333, .{ 0, true });
567
+ try test__shlo_limb64(u633, 1 << 298, 333, .{ 1 << 631, false });
568
+
569
+ try test__shlo_limb64(i64, -2, 1, .{ -4, false });
570
+ try test__shlo_limb64(i64, minInt(i64), 1, .{ 0, true });
571
+ try test__shlo_limb64(i64, minInt(i64), 63, .{ 0, true });
572
+ try test__shlo_limb64(i65, minInt(i63), 1, .{ minInt(i64), false });
573
+ try test__shlo_limb64(i65, -1, 17, .{ -1 << 17, false });
574
+ try test__shlo_limb64(i65, -3, 64, .{ -1 << 64, true });
575
+ try test__shlo_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ -0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
576
+ try test__shlo_limb64(i255, -3, 1, .{ -6, false });
577
+ try test__shlo_limb64(i633, 1 << 298, 333, .{ 1 << 631, false });
578
+ try test__shlo_limb64(i633, 1 << 299, 333, .{ minInt(i633), true });
579
+ try test__shlo_limb64(i633, 1 << 300, 333, .{ 0, true });
580
+ try test__shlo_limb64(i633, 1 << 297, 333, .{ 1 << 630, false });
581
+ try test__shlo_limb64(i633, -1 << 299, 333, .{ -1 << 632, false });
582
+ try test__shlo_limb64(i633, -1 << 300, 333, .{ 0, true });
583
+ try test__shlo_limb64(i633, -1 << 298, 333, .{ -1 << 631, false });
584
+
585
+ try test__shlo_limb64(u150, maxInt(u150), 1, .{ maxInt(u150) - 1, true });
586
+ try test__shlo_limb64(i150, -3, 1, .{ -6, false });
587
+ }
588
+
589
+ comptime {
590
+ symbol(&__shr_limb64, "__shr_limb64");
591
+ }
592
+
593
+ fn __shr_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) void {
594
+ const limb_cnt = usedLimbCount(bits);
595
+ const out = varLimbs(out_ptr, bits);
596
+ const a = constLimbs(a_ptr, bits);
597
+
598
+ assert(shift < bits);
599
+
600
+ const limb_shift = shift / 64;
601
+ const bit_shift = shift % 64;
602
+
603
+ const ms = limbGet(a, limb_cnt - 1);
604
+ const sign_extend: u64 = if (is_signed and (ms >> 63) == 1) ~@as(u64, 0) else 0;
605
+
606
+ var carry: u64 = if (bit_shift != 0) (sign_extend << @intCast(64 - bit_shift)) else 0;
607
+ var i: usize = 0;
608
+ while (i < limb_cnt) : (i += 1) {
609
+ const j = limb_cnt - 1 - i;
610
+ if (i < limb_shift) {
611
+ limbSet(out, j, sign_extend);
612
+ } else {
613
+ const limb = limbGet(a, j + limb_shift);
614
+ limbSet(out, j, (limb >> @intCast(bit_shift)) | carry);
615
+ carry = if (bit_shift != 0) (limb << @intCast(64 - bit_shift)) else 0;
616
+ }
617
+ }
618
+
619
+ fixLastLimb(out_ptr, is_signed, bits);
620
+ }
621
+
622
+ fn test__shr_limb64(comptime T: type, a: T, shift: u16, expected: T) !void {
623
+ const int_info = @typeInfo(T).int;
624
+ const is_signed = int_info.signedness == .signed;
625
+
626
+ var a_limbs = asLimbs(a);
627
+ var out: Limbs(T) = undefined;
628
+ __shr_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
629
+
630
+ const expected_limbs = asLimbs(expected);
631
+ try testing.expectEqual(expected_limbs, out);
632
+ }
633
+
634
+ test __shr_limb64 {
635
+ try test__shr_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF);
636
+ try test__shr_limb64(u64, 0x8000_0000_0000_0001, 63, 1);
637
+ try test__shr_limb64(u65, 0x1_0000_0000_0000_0000, 64, 1);
638
+ try test__shr_limb64(u65, 0x1_0000_0000_0000_0001, 1, 0x0_8000_0000_0000_0000);
639
+ try test__shr_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
640
+ try test__shr_limb64(u255, maxInt(u255), 1, maxInt(u254));
641
+ try test__shr_limb64(u633, 1 << 333, 333, 1);
642
+ try test__shr_limb64(u633, 1 << 334, 333, 2);
643
+ try test__shr_limb64(u633, 1 << 332, 333, 0);
644
+
645
+ try test__shr_limb64(i64, -2, 1, -1);
646
+ try test__shr_limb64(i64, minInt(i64), 63, -1);
647
+ try test__shr_limb64(i65, minInt(i65), 1, minInt(i65) | (1 << 63));
648
+ try test__shr_limb64(i65, -1, 17, -1);
649
+ try test__shr_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, -0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
650
+ try test__shr_limb64(i255, -3, 1, -2);
651
+ try test__shr_limb64(i633, 1 << 333, 333, 1);
652
+ try test__shr_limb64(i633, 1 << 334, 333, 2);
653
+ try test__shr_limb64(i633, 1 << 332, 333, 0);
654
+ try test__shr_limb64(i633, -1 << 333, 333, -1);
655
+ try test__shr_limb64(i633, -1 << 334, 333, -2);
656
+ try test__shr_limb64(i633, -1 << 332, 333, -1);
657
+
658
+ try test__shr_limb64(u150, maxInt(u150), 1, maxInt(u149));
659
+ try test__shr_limb64(i150, -3, 1, -2);
660
+ }
661
+
662
+ comptime {
663
+ symbol(&__clz_limb64, "__clz_limb64");
664
+ }
665
+
666
+ fn __clz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
667
+ const limb_cnt = usedLimbCount(bits);
668
+ const a = constLimbs(a_ptr, bits);
669
+
670
+ var res: u16 = 0;
671
+ var i: usize = 0;
672
+
673
+ if (bits % 64 != 0) {
674
+ const limb = limbGet(a, limb_cnt - 1);
675
+ if (limb == 0) {
676
+ res += bits % 64;
677
+ } else {
678
+ return @clz(limb << @intCast(64 - bits % 64));
679
+ }
680
+ i += 1;
681
+ }
682
+
683
+ while (i < limb_cnt) : (i += 1) {
684
+ const j = limb_cnt - 1 - i;
685
+ const limb = limbGet(a, j);
686
+ if (limb == 0) {
687
+ res += 64;
688
+ } else {
689
+ res += @clz(limb);
690
+ break;
691
+ }
692
+ }
693
+
694
+ return res;
695
+ }
696
+
697
+ fn test__clz_limb64(comptime T: type, a: T, expected: u16) !void {
698
+ const int_info = @typeInfo(T).int;
699
+
700
+ var a_limbs = asLimbs(a);
701
+ const out = __clz_limb64(&a_limbs, int_info.bits);
702
+
703
+ try testing.expectEqual(expected, out);
704
+ }
705
+
706
+ test __clz_limb64 {
707
+ try test__clz_limb64(u64, 0, 64);
708
+ try test__clz_limb64(u65, 1 << 64, 0);
709
+ try test__clz_limb64(u65, 1 << 9, 55);
710
+ try test__clz_limb64(u128, 1 << 31, 96);
711
+ try test__clz_limb64(u255, 1 << 62, 192);
712
+
713
+ try test__clz_limb64(i64, -1, 0);
714
+ try test__clz_limb64(i65, minInt(i65), 0);
715
+ try test__clz_limb64(i65, 1 << 32, 32);
716
+ try test__clz_limb64(i128, 0, 128);
717
+ try test__clz_limb64(i255, 1 << 130, 124);
718
+
719
+ try test__clz_limb64(u150, 1 << 31, 118);
720
+ try test__clz_limb64(i150, maxInt(u65) - 1, 85);
721
+ }
722
+
723
+ comptime {
724
+ symbol(&__ctz_limb64, "__ctz_limb64");
725
+ }
726
+
727
+ fn __ctz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
728
+ const limb_cnt = usedLimbCount(bits);
729
+ const a = constLimbs(a_ptr, bits);
730
+
731
+ var res: u16 = 0;
732
+ var i: usize = 0;
733
+ while (i < limb_cnt - 1) : (i += 1) {
734
+ const limb = limbGet(a, i);
735
+ if (limb == 0) {
736
+ res += 64;
737
+ } else {
738
+ res += @ctz(limb);
739
+ return res;
740
+ }
741
+ }
742
+
743
+ const limb = limbGet(a, i);
744
+ if (bits % 64 != 0 and limb == 0) {
745
+ res += bits % 64;
746
+ } else {
747
+ res += @ctz(limb);
748
+ }
749
+
750
+ return res;
751
+ }
752
+
753
+ fn test__ctz_limb64(comptime T: type, a: T, expected: u16) !void {
754
+ const int_info = @typeInfo(T).int;
755
+
756
+ var a_limbs = asLimbs(a);
757
+ const out = __ctz_limb64(&a_limbs, int_info.bits);
758
+
759
+ try testing.expectEqual(expected, out);
760
+ }
761
+
762
+ test __ctz_limb64 {
763
+ try test__ctz_limb64(u64, 1 << 17, 17);
764
+ try test__ctz_limb64(u65, 1 << 64, 64);
765
+ try test__ctz_limb64(u65, 0, 65);
766
+ try test__ctz_limb64(u128, 1 << 100, 100);
767
+ try test__ctz_limb64(u255, 1 << 200, 200);
768
+
769
+ try test__ctz_limb64(i64, -1 << 9, 9);
770
+ try test__ctz_limb64(i65, minInt(i65), 64);
771
+ try test__ctz_limb64(i65, 0, 65);
772
+ try test__ctz_limb64(i128, -1 << 73, 73);
773
+ try test__ctz_limb64(i255, 1 << 130, 130);
774
+
775
+ try test__ctz_limb64(u150, 1 << 101, 101);
776
+ try test__ctz_limb64(i150, -1 << 74, 74);
777
+ }
778
+
779
+ comptime {
780
+ symbol(&__popcount_limb64, "__popcount_limb64");
781
+ }
782
+
783
+ fn __popcount_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
784
+ const limb_cnt = usedLimbCount(bits);
785
+ const a = constLimbs(a_ptr, bits);
786
+
787
+ var res: u16 = 0;
788
+ var i: usize = 0;
789
+ while (i < limb_cnt - 1) : (i += 1) {
790
+ res += @popCount(limbGet(a, i));
791
+ }
792
+
793
+ var limb = limbGet(a, i);
794
+ if (bits % 64 != 0) {
795
+ limb <<= @intCast(64 - bits % 64);
796
+ }
797
+ res += @popCount(limb);
798
+
799
+ return res;
800
+ }
801
+
802
+ fn test__popcount_limb64(comptime T: type, a: T, expected: u16) !void {
803
+ const int_info = @typeInfo(T).int;
804
+
805
+ var a_limbs = asLimbs(a);
806
+ const out = __popcount_limb64(&a_limbs, int_info.bits);
807
+
808
+ try testing.expectEqual(expected, out);
809
+ }
810
+
811
+ test __popcount_limb64 {
812
+ try test__popcount_limb64(u64, 0xF0F0_0000_0000_0001, 9);
813
+ try test__popcount_limb64(u65, 1 << 64, 1);
814
+ try test__popcount_limb64(u65, maxInt(u65), 65);
815
+ try test__popcount_limb64(u128, (1 << 100) | (1 << 5) | 1, 3);
816
+ try test__popcount_limb64(u255, maxInt(u255), 255);
817
+
818
+ try test__popcount_limb64(i64, -1, 64);
819
+ try test__popcount_limb64(i65, minInt(i65), 1);
820
+ try test__popcount_limb64(i65, -1, 65);
821
+ try test__popcount_limb64(i128, -1 << 7, 121);
822
+ try test__popcount_limb64(i255, -1 << 200, 55);
823
+
824
+ try test__popcount_limb64(u150, (1 << 149) | (1 << 65) | 1, 3);
825
+ try test__popcount_limb64(i150, -1 << 7, 143);
826
+ }
827
+
828
+ comptime {
829
+ symbol(&__bitreverse_limb64, "__bitreverse_limb64");
830
+ }
831
+
832
+ fn __bitreverse_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
833
+ const limb_cnt = usedLimbCount(bits);
834
+ const out = varLimbs(out_ptr, bits);
835
+ const a = constLimbs(a_ptr, bits);
836
+
837
+ var i: usize = 0;
838
+ while (i < limb_cnt) : (i += 1) {
839
+ const j = limb_cnt - 1 - i;
840
+ limbSet(out, j, @bitReverse(limbGet(a, i)));
841
+ }
842
+
843
+ if (bits % 64 != 0) {
844
+ __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
845
+ }
846
+ fixLastLimb(out_ptr, is_signed, bits);
847
+ }
848
+
849
+ fn test__bitreverse_limb64(comptime T: type, a: T, expected: T) !void {
850
+ const int_info = @typeInfo(T).int;
851
+ const is_signed = int_info.signedness == .signed;
852
+
853
+ var a_limbs = asLimbs(a);
854
+ var out: Limbs(T) = undefined;
855
+ __bitreverse_limb64(&out, &a_limbs, is_signed, int_info.bits);
856
+
857
+ const expected_limbs = asLimbs(expected);
858
+ try testing.expectEqual(expected_limbs, out);
859
+ }
860
+
861
+ test __bitreverse_limb64 {
862
+ try test__bitreverse_limb64(u64, 1 << 7, 1 << 56);
863
+ try test__bitreverse_limb64(u65, 1 << 64, 1);
864
+ try test__bitreverse_limb64(u65, 1 << 9, 1 << 55);
865
+ try test__bitreverse_limb64(u128, 1 << 100, 1 << 27);
866
+ try test__bitreverse_limb64(u255, 1 << 200, 1 << 54);
867
+
868
+ try test__bitreverse_limb64(i64, -1, -1);
869
+ try test__bitreverse_limb64(i65, 1 << 32, 1 << 32);
870
+ try test__bitreverse_limb64(i65, minInt(i65), 1);
871
+ try test__bitreverse_limb64(i128, 1 << 63, 1 << 64);
872
+ try test__bitreverse_limb64(i255, 1 << 130, 1 << 124);
873
+
874
+ try test__bitreverse_limb64(u150, 1 << 9, 1 << 140);
875
+ try test__bitreverse_limb64(i150, minInt(i150), 1);
876
+ }
877
+
878
+ comptime {
879
+ symbol(&__byteswap_limb64, "__byteswap_limb64");
880
+ }
881
+
882
+ fn __byteswap_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
883
+ const limb_cnt = usedLimbCount(bits);
884
+ const out = varLimbs(out_ptr, bits);
885
+ const a = constLimbs(a_ptr, bits);
886
+
887
+ assert(bits % 8 == 0);
888
+
889
+ var i: usize = 0;
890
+ while (i < limb_cnt) : (i += 1) {
891
+ const j = limb_cnt - 1 - i;
892
+ limbSet(out, j, @byteSwap(limbGet(a, i)));
893
+ }
894
+
895
+ if (bits % 64 != 0) {
896
+ __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
897
+ }
898
+ fixLastLimb(out_ptr, is_signed, bits);
899
+ }
900
+
901
+ fn test__byteswap_limb64(comptime T: type, a: T, expected: T) !void {
902
+ const int_info = @typeInfo(T).int;
903
+ const is_signed = int_info.signedness == .signed;
904
+
905
+ var a_limbs = asLimbs(a);
906
+ var out: Limbs(T) = undefined;
907
+ __byteswap_limb64(&out, &a_limbs, is_signed, int_info.bits);
908
+
909
+ const expected_limbs = asLimbs(expected);
910
+ try testing.expectEqual(expected_limbs, out);
911
+ }
912
+
913
+ test __byteswap_limb64 {
914
+ try test__byteswap_limb64(u64, 0x0123_4567_89AB_CDEF, 0xEFCD_AB89_6745_2301);
915
+ try test__byteswap_limb64(u72, 0x01_23_45_67_89_AB_CD_EF_11, 0x11_EF_CD_AB_89_67_45_23_01);
916
+ try test__byteswap_limb64(u128, 1 << 72, 1 << 48);
917
+ try test__byteswap_limb64(u248, 1, 1 << 240);
918
+ try test__byteswap_limb64(u256, 1 << 120, 1 << 128);
919
+
920
+ try test__byteswap_limb64(i64, minInt(i64), 128);
921
+ try test__byteswap_limb64(i72, 1, 1 << 64);
922
+ try test__byteswap_limb64(i72, -1, -1);
923
+ try test__byteswap_limb64(i128, 1 << 56, 1 << 64);
924
+ try test__byteswap_limb64(i248, minInt(i248), 128);
925
+
926
+ try test__byteswap_limb64(u152, 1, 1 << 144);
927
+ try test__byteswap_limb64(i152, 1 << 56, 1 << 88);
928
+ }
929
+
930
+ comptime {
931
+ symbol(&__mulo_limb64, "__mulo_limb64");
932
+ }
933
+
934
+ inline fn add3(x: *[3]u64, start: usize, v0: u64) void {
935
+ var i = start;
936
+ var v = v0;
937
+ while (i < 3) : (i += 1) {
938
+ const s = @addWithOverflow(x[i], v);
939
+ x[i] = s[0];
940
+ if (s[1] == 0) break;
941
+ v = 1;
942
+ }
943
+ }
944
+
945
+ fn mulwide(a: u64, b: u64) [2]u64 {
946
+ const muldXi = @import("mulXi3.zig").muldXi;
947
+ const limbs: [2]u64 = @bitCast(muldXi(u64, a, b));
948
+ return switch (endian) {
949
+ .little => limbs,
950
+ .big => .{ limbs[1], limbs[0] },
951
+ };
952
+ }
953
+
954
+ fn __mulo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
955
+ const limb_cnt = usedLimbCount(bits);
956
+
957
+ const out = varLimbs(out_ptr, bits);
958
+ const a = constLimbs(a_ptr, bits);
959
+ const b = constLimbs(b_ptr, bits);
960
+
961
+ @memset(out, 0);
962
+
963
+ const all_ones = ~@as(u64, 0);
964
+ const a_neg = is_signed and ((limbGet(a, limb_cnt - 1) >> 63) != 0);
965
+ const b_neg = is_signed and ((limbGet(b, limb_cnt - 1) >> 63) != 0);
966
+
967
+ var carry: [3]u64 = @splat(0);
968
+ var hi_zero = true;
969
+ var hi_ones = true;
970
+ var hi_borrow: u1 = 0;
971
+ var raw_last: u64 = 0;
972
+
973
+ var k: usize = 0;
974
+ while (k < 2 * limb_cnt) : (k += 1) {
975
+ var acc = carry;
976
+
977
+ var i: usize = if (k < limb_cnt) 0 else k - (limb_cnt - 1);
978
+ while (i < limb_cnt and i <= k) : (i += 1) {
979
+ const j = k - i;
980
+ if (j >= limb_cnt) continue;
981
+
982
+ const p = mulwide(limbGet(a, i), limbGet(b, j));
983
+ add3(&acc, 0, p[0]);
984
+ add3(&acc, 1, p[1]);
985
+ }
986
+
987
+ var limb = acc[0];
988
+ if (k < limb_cnt) {
989
+ limbSet(out, k, limb);
990
+ if (k == limb_cnt - 1) raw_last = limb;
991
+ } else {
992
+ if (is_signed) {
993
+ const h = k - limb_cnt;
994
+
995
+ const s0 = @subWithOverflow(limb, if (a_neg) limbGet(b, h) else 0);
996
+ const s1 = @subWithOverflow(s0[0], if (b_neg) limbGet(a, h) else 0);
997
+ const s2 = @subWithOverflow(s1[0], hi_borrow);
998
+
999
+ limb = s2[0];
1000
+ hi_borrow = @intFromBool(s0[1] != 0 or s1[1] != 0 or s2[1] != 0);
1001
+ }
1002
+
1003
+ hi_zero = hi_zero and limb == 0;
1004
+ hi_ones = hi_ones and limb == all_ones;
1005
+ }
1006
+
1007
+ carry = .{ acc[1], acc[2], 0 };
1008
+ }
1009
+
1010
+ const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
1011
+ if (bits % 64 != 0) {
1012
+ limbSet(out, limb_cnt - 1, last);
1013
+ }
1014
+
1015
+ fixLastLimb(out_ptr, is_signed, bits);
1016
+
1017
+ if (!is_signed) {
1018
+ return !hi_zero or raw_last != last;
1019
+ }
1020
+
1021
+ const sign_extend: u64 = if ((last >> 63) == 1) all_ones else 0;
1022
+ return (raw_last != last) or if (sign_extend == 0) !hi_zero else !hi_ones;
1023
+ }
1024
+
1025
+ fn test__mulo_limb64(comptime T: type, a: T, b: T, expected: struct { T, bool }) !void {
1026
+ const int_info = @typeInfo(T).int;
1027
+ const is_signed = int_info.signedness == .signed;
1028
+
1029
+ var a_limbs = asLimbs(a);
1030
+ var b_limbs = asLimbs(b);
1031
+ var out: Limbs(T) = undefined;
1032
+ const overflow = __mulo_limb64(&out, &a_limbs, &b_limbs, is_signed, int_info.bits);
1033
+
1034
+ const expected_limbs = asLimbs(expected[0]);
1035
+ try testing.expectEqual(expected_limbs, out);
1036
+ try testing.expectEqual(expected[1], overflow);
1037
+ }
1038
+
1039
+ test __mulo_limb64 {
1040
+ try test__mulo_limb64(u64, 3, 5, .{ 15, false });
1041
+ try test__mulo_limb64(u64, maxInt(u64), 2, .{ maxInt(u64) - 1, true });
1042
+ try test__mulo_limb64(u65, 1 << 32, 1 << 32, .{ 1 << 64, false });
1043
+ try test__mulo_limb64(u65, 1 << 64, 2, .{ 0, true });
1044
+ try test__mulo_limb64(u128, 1 << 80, 1 << 40, .{ 1 << 120, false });
1045
+ try test__mulo_limb64(u128, 1 << 100, 1 << 40, .{ 0, true });
1046
+ try test__mulo_limb64(u255, 7, 9, .{ 63, false });
1047
+ try test__mulo_limb64(u255, maxInt(u255), 2, .{ maxInt(u255) - 1, true });
1048
+
1049
+ try test__mulo_limb64(i64, -3, 2, .{ -6, false });
1050
+ try test__mulo_limb64(i64, maxInt(i64), 2, .{ -2, true });
1051
+ try test__mulo_limb64(i65, 1 << 63, 2, .{ minInt(i65), true });
1052
+ try test__mulo_limb64(i65, -1 << 32, 1 << 16, .{ -1 << 48, false });
1053
+ try test__mulo_limb64(i128, 1 << 100, 1 << 27, .{ minInt(i128), true });
1054
+ try test__mulo_limb64(i128, -1 << 80, 1 << 40, .{ -1 << 120, false });
1055
+ try test__mulo_limb64(i255, -3, 2, .{ -6, false });
1056
+ try test__mulo_limb64(i255, maxInt(i255), 2, .{ -2, true });
1057
+
1058
+ try test__mulo_limb64(u200, 0, maxInt(u200), .{ 0, false });
1059
+ try test__mulo_limb64(u200, 1, maxInt(u200), .{ maxInt(u200), false });
1060
+ try test__mulo_limb64(u200, 1 << 100, 1 << 99, .{ 1 << 199, false });
1061
+ try test__mulo_limb64(u200, 1 << 100, 1 << 100, .{ 0, true });
1062
+ try test__mulo_limb64(u200, maxInt(u200), maxInt(u200), .{ 1, true });
1063
+
1064
+ try test__mulo_limb64(i200, 0, -1, .{ 0, false });
1065
+ try test__mulo_limb64(i200, -1, -1, .{ 1, false });
1066
+ try test__mulo_limb64(i200, -1, minInt(i200), .{ minInt(i200), true });
1067
+ try test__mulo_limb64(i200, maxInt(i200), 2, .{ -2, true });
1068
+ try test__mulo_limb64(i200, 1 << 100, 1 << 98, .{ 1 << 198, false });
1069
+ try test__mulo_limb64(i200, 1 << 100, 1 << 99, .{ minInt(i200), true });
1070
+ try test__mulo_limb64(i200, maxInt(i200), maxInt(i200), .{ 1, true });
1071
+ try test__mulo_limb64(i200, minInt(i200), minInt(i200), .{ 0, true });
1072
+
1073
+ try test__mulo_limb64(u150, maxInt(u150), 2, .{ maxInt(u150) - 1, true });
1074
+ try test__mulo_limb64(i150, maxInt(i150), 2, .{ -2, true });
1075
+ }
1076
+
1077
+ comptime {
1078
+ symbol(&__abs_limb64, "__abs_limb64");
1079
+ }
1080
+
1081
+ fn __abs_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, bits: u16) callconv(.c) void {
1082
+ const limb_cnt = limbCount(bits);
1083
+ const out = out_ptr[0..limb_cnt];
1084
+ const a = a_ptr[0..limb_cnt];
1085
+
1086
+ const ms = limbGet(a, limb_cnt - 1);
1087
+ if ((ms >> 63) == 0) {
1088
+ @memcpy(out, a);
1089
+ return;
1090
+ }
1091
+
1092
+ var carry: u1 = 1;
1093
+ var i: usize = 0;
1094
+ while (i < limb_cnt) : (i += 1) {
1095
+ const s = @addWithOverflow(~limbGet(a, i), carry);
1096
+ limbSet(out, i, s[0]);
1097
+ carry = s[1];
1098
+ }
1099
+ }
1100
+
1101
+ fn test__abs_limb64(comptime T: type, a: T, expected: @Int(.unsigned, @typeInfo(T).int.bits)) !void {
1102
+ const int_info = @typeInfo(T).int;
1103
+ comptime assert(int_info.signedness == .signed);
1104
+
1105
+ var a_limbs = asLimbs(a);
1106
+ var out: Limbs(@TypeOf(expected)) = undefined;
1107
+ __abs_limb64(&out, &a_limbs, int_info.bits);
1108
+
1109
+ const expected_limbs = asLimbs(expected);
1110
+ try testing.expectEqual(expected_limbs, out);
1111
+ }
1112
+
1113
+ test __abs_limb64 {
1114
+ try test__abs_limb64(i64, 0, 0);
1115
+ try test__abs_limb64(i64, -1, 1);
1116
+ try test__abs_limb64(i64, minInt(i64), 1 << 63);
1117
+ try test__abs_limb64(i65, -1, 1);
1118
+ try test__abs_limb64(i65, minInt(i65), 1 << 64);
1119
+ try test__abs_limb64(i65, maxInt(i65), maxInt(i65));
1120
+ try test__abs_limb64(i128, -1 << 80, 1 << 80);
1121
+ try test__abs_limb64(i128, 1 << 64, 1 << 64);
1122
+ try test__abs_limb64(i200, -1 << 198, 1 << 198);
1123
+ try test__abs_limb64(i255, -5, 5);
1124
+ try test__abs_limb64(i255, minInt(i255), 1 << 254);
1125
+
1126
+ try test__abs_limb64(i150, -40, 40);
266
1127
  }