@zigc/lib 0.16.0-test.1 → 0.17.0-dev.27
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.
- package/LICENSE +19 -0
- package/c/math.zig +148 -35
- package/c/stropts.zig +17 -0
- package/c.zig +1 -0
- package/compiler/aro/aro/Attribute/names.zig +604 -589
- package/compiler/aro/aro/Attribute.zig +202 -116
- package/compiler/aro/aro/Builtins/common.zig +874 -863
- package/compiler/aro/aro/Builtins/eval.zig +15 -7
- package/compiler/aro/aro/Builtins.zig +0 -1
- package/compiler/aro/aro/CodeGen.zig +3 -1
- package/compiler/aro/aro/Compilation.zig +120 -97
- package/compiler/aro/aro/Diagnostics.zig +21 -17
- package/compiler/aro/aro/Driver/GCCDetector.zig +635 -0
- package/compiler/aro/aro/Driver.zig +124 -50
- package/compiler/aro/aro/LangOpts.zig +12 -2
- package/compiler/aro/aro/Parser/Diagnostic.zig +79 -19
- package/compiler/aro/aro/Parser.zig +336 -142
- package/compiler/aro/aro/Preprocessor/Diagnostic.zig +21 -0
- package/compiler/aro/aro/Preprocessor.zig +127 -56
- package/compiler/aro/aro/Target.zig +17 -12
- package/compiler/aro/aro/Tokenizer.zig +31 -14
- package/compiler/aro/aro/Toolchain.zig +4 -7
- package/compiler/aro/aro/Tree.zig +178 -148
- package/compiler/aro/aro/TypeStore.zig +82 -24
- package/compiler/aro/aro/Value.zig +13 -17
- package/compiler/aro/aro/features.zig +1 -0
- package/compiler/aro/aro/pragmas/once.zig +0 -1
- package/compiler/aro/aro/record_layout.zig +3 -3
- package/compiler/aro/assembly_backend/x86_64.zig +3 -4
- package/compiler/aro/backend/Assembly.zig +1 -2
- package/compiler/aro/backend/Interner.zig +2 -2
- package/compiler/aro/backend/Ir.zig +100 -92
- package/compiler/aro/include/ptrcheck.h +49 -0
- package/compiler/aro/main.zig +26 -10
- package/compiler/build_runner.zig +1 -0
- package/compiler/objdump.zig +93 -0
- package/compiler/reduce.zig +5 -1
- package/compiler/resinator/compile.zig +2 -2
- package/compiler/resinator/main.zig +7 -1
- package/compiler/resinator/preprocess.zig +1 -3
- package/compiler/std-docs.zig +8 -1
- package/compiler/test_runner.zig +194 -62
- package/compiler/translate-c/MacroTranslator.zig +80 -11
- package/compiler/translate-c/PatternList.zig +1 -9
- package/compiler/translate-c/Scope.zig +43 -6
- package/compiler/translate-c/Translator.zig +364 -126
- package/compiler/translate-c/ast.zig +19 -11
- package/compiler/translate-c/main.zig +75 -16
- package/compiler_rt/cos.zig +141 -52
- package/compiler_rt/divmodei4.zig +40 -17
- package/compiler_rt/exp.zig +1 -4
- package/compiler_rt/exp2.zig +1 -4
- package/compiler_rt/exp_f128.zig +377 -0
- package/compiler_rt/limb64.zig +1126 -0
- package/compiler_rt/long_double.zig +37 -0
- package/compiler_rt/mulXi3.zig +1 -1
- package/compiler_rt/mulo.zig +6 -1
- package/compiler_rt/rem_pio2l.zig +173 -0
- package/compiler_rt/sin.zig +140 -55
- package/compiler_rt/sincos.zig +279 -72
- package/compiler_rt/ssp.zig +1 -1
- package/compiler_rt/tan.zig +118 -47
- package/compiler_rt/trig.zig +256 -6
- package/compiler_rt/udivmodei4.zig +28 -0
- package/compiler_rt.zig +2 -0
- package/fuzzer.zig +855 -307
- package/libc/musl/src/math/pow.c +343 -0
- package/package.json +1 -1
- package/std/Build/Fuzz.zig +6 -19
- package/std/Build/Module.zig +1 -1
- package/std/Build/Step/CheckObject.zig +3 -3
- package/std/Build/Step/Compile.zig +18 -0
- package/std/Build/Step/ConfigHeader.zig +49 -33
- package/std/Build/Step/InstallArtifact.zig +18 -0
- package/std/Build/Step/Run.zig +536 -87
- package/std/Build/Step/TranslateC.zig +0 -6
- package/std/Build/Step.zig +8 -15
- package/std/Build/WebServer.zig +29 -17
- package/std/Build/abi.zig +47 -11
- package/std/Build.zig +17 -14
- package/std/Io/Dispatch.zig +2 -0
- package/std/Io/File/Reader.zig +3 -1
- package/std/Io/File.zig +1 -0
- package/std/Io/Kqueue.zig +2 -2
- package/std/Io/Threaded.zig +181 -143
- package/std/Io/Uring.zig +2 -1
- package/std/Io/Writer.zig +41 -41
- package/std/Io.zig +970 -2
- package/std/Target.zig +3 -2
- package/std/Thread.zig +8 -3
- package/std/array_hash_map.zig +96 -555
- package/std/array_list.zig +22 -31
- package/std/bit_set.zig +22 -6
- package/std/builtin/assembly.zig +68 -0
- package/std/c.zig +17 -17
- package/std/compress/flate/Compress.zig +3 -3
- package/std/crypto/Certificate/Bundle.zig +15 -1
- package/std/crypto/codecs/asn1.zig +33 -18
- package/std/crypto/codecs/base64_hex_ct.zig +14 -4
- package/std/debug/Dwarf.zig +29 -9
- package/std/debug/Info.zig +4 -0
- package/std/debug/MachOFile.zig +46 -8
- package/std/debug/Pdb.zig +539 -36
- package/std/debug/SelfInfo/Elf.zig +19 -18
- package/std/debug/SelfInfo/MachO.zig +18 -7
- package/std/debug/SelfInfo/Windows.zig +138 -36
- package/std/debug.zig +179 -65
- package/std/enums.zig +25 -19
- package/std/heap/ArenaAllocator.zig +145 -154
- package/std/heap/debug_allocator.zig +7 -7
- package/std/http/Client.zig +10 -6
- package/std/http.zig +11 -9
- package/std/json/Stringify.zig +3 -3
- package/std/json/dynamic.zig +4 -4
- package/std/math/big/int.zig +16 -17
- package/std/mem/Allocator.zig +4 -5
- package/std/mem.zig +48 -0
- package/std/os/emscripten.zig +2 -18
- package/std/os/linux/arc.zig +144 -0
- package/std/os/linux.zig +21 -4
- package/std/os/windows.zig +2 -2
- package/std/pdb.zig +143 -4
- package/std/posix.zig +6 -12
- package/std/priority_dequeue.zig +13 -12
- package/std/priority_queue.zig +5 -4
- package/std/process/Child.zig +1 -1
- package/std/process/Environ.zig +1 -1
- package/std/start.zig +17 -4
- package/std/std.zig +19 -6
- package/std/testing/FailingAllocator.zig +4 -4
- package/std/testing/Smith.zig +37 -2
- package/std/zig/Ast/Render.zig +186 -458
- package/std/zig/Ast.zig +0 -4
- package/std/zig/AstGen.zig +44 -7
- package/std/zig/AstSmith.zig +2602 -0
- package/std/zig/Client.zig +8 -3
- package/std/zig/Parse.zig +83 -74
- package/std/zig/Server.zig +26 -0
- package/std/zig/Zir.zig +17 -0
- package/std/zig/c_translation/helpers.zig +14 -9
- package/std/zig/llvm/Builder.zig +107 -48
- package/std/zig/system.zig +20 -4
- package/std/zig/tokenizer.zig +2 -1
- package/std/zig.zig +6 -0
- package/compiler/aro/aro/Driver/Filesystem.zig +0 -241
- package/libc/mingw/complex/cabs.c +0 -48
- package/libc/mingw/complex/cabsf.c +0 -48
- package/libc/mingw/complex/cacos.c +0 -50
- package/libc/mingw/complex/cacosf.c +0 -50
- package/libc/mingw/complex/carg.c +0 -48
- package/libc/mingw/complex/cargf.c +0 -48
- package/libc/mingw/complex/casin.c +0 -50
- package/libc/mingw/complex/casinf.c +0 -50
- package/libc/mingw/complex/catan.c +0 -50
- package/libc/mingw/complex/catanf.c +0 -50
- package/libc/mingw/complex/ccos.c +0 -50
- package/libc/mingw/complex/ccosf.c +0 -50
- package/libc/mingw/complex/cexp.c +0 -48
- package/libc/mingw/complex/cexpf.c +0 -48
- package/libc/mingw/complex/cimag.c +0 -48
- package/libc/mingw/complex/cimagf.c +0 -48
- package/libc/mingw/complex/clog.c +0 -48
- package/libc/mingw/complex/clog10.c +0 -49
- package/libc/mingw/complex/clog10f.c +0 -49
- package/libc/mingw/complex/clogf.c +0 -48
- package/libc/mingw/complex/conj.c +0 -48
- package/libc/mingw/complex/conjf.c +0 -48
- package/libc/mingw/complex/cpow.c +0 -48
- package/libc/mingw/complex/cpowf.c +0 -48
- package/libc/mingw/complex/cproj.c +0 -48
- package/libc/mingw/complex/cprojf.c +0 -48
- package/libc/mingw/complex/creal.c +0 -48
- package/libc/mingw/complex/crealf.c +0 -48
- package/libc/mingw/complex/csin.c +0 -50
- package/libc/mingw/complex/csinf.c +0 -50
- package/libc/mingw/complex/csqrt.c +0 -48
- package/libc/mingw/complex/csqrtf.c +0 -48
- package/libc/mingw/complex/ctan.c +0 -50
- package/libc/mingw/complex/ctanf.c +0 -50
- package/libc/mingw/math/arm/s_rint.c +0 -86
- package/libc/mingw/math/arm/s_rintf.c +0 -51
- package/libc/mingw/math/arm/sincos.S +0 -30
- package/libc/mingw/math/arm-common/sincosl.c +0 -13
- package/libc/mingw/math/arm64/rint.c +0 -12
- package/libc/mingw/math/arm64/rintf.c +0 -12
- package/libc/mingw/math/arm64/sincos.S +0 -32
- package/libc/mingw/math/bsd_private_base.h +0 -148
- package/libc/mingw/math/fdiml.c +0 -24
- package/libc/mingw/math/frexpf.c +0 -13
- package/libc/mingw/math/frexpl.c +0 -71
- package/libc/mingw/math/x86/acosf.c +0 -29
- package/libc/mingw/math/x86/atanf.c +0 -23
- package/libc/mingw/math/x86/atanl.c +0 -18
- package/libc/mingw/math/x86/cos.def.h +0 -65
- package/libc/mingw/math/x86/cosl.c +0 -46
- package/libc/mingw/math/x86/cosl_internal.S +0 -55
- package/libc/mingw/math/x86/ldexp.c +0 -23
- package/libc/mingw/math/x86/scalbn.S +0 -41
- package/libc/mingw/math/x86/scalbnf.S +0 -40
- package/libc/mingw/math/x86/sin.def.h +0 -65
- package/libc/mingw/math/x86/sinl.c +0 -46
- package/libc/mingw/math/x86/sinl_internal.S +0 -58
- package/libc/mingw/math/x86/tanl.S +0 -62
- package/libc/mingw/misc/btowc.c +0 -28
- package/libc/mingw/misc/wcstof.c +0 -66
- package/libc/mingw/misc/wcstoimax.c +0 -132
- package/libc/mingw/misc/wcstoumax.c +0 -126
- package/libc/mingw/misc/wctob.c +0 -29
- package/libc/mingw/misc/winbs_uint64.c +0 -6
- package/libc/mingw/misc/winbs_ulong.c +0 -6
- package/libc/mingw/misc/winbs_ushort.c +0 -6
- package/libc/mingw/stdio/_Exit.c +0 -10
- package/libc/mingw/stdio/_findfirst64i32.c +0 -21
- package/libc/mingw/stdio/_findnext64i32.c +0 -21
- package/libc/mingw/stdio/_fstat64i32.c +0 -37
- package/libc/mingw/stdio/_stat64i32.c +0 -37
- package/libc/mingw/stdio/_wfindfirst64i32.c +0 -21
- package/libc/mingw/stdio/_wfindnext64i32.c +0 -21
- package/libc/mingw/stdio/_wstat64i32.c +0 -37
- package/libc/musl/src/legacy/isastream.c +0 -7
- package/libc/musl/src/legacy/valloc.c +0 -8
- package/libc/musl/src/math/__cosl.c +0 -96
- package/libc/musl/src/math/__sinl.c +0 -78
- package/libc/musl/src/math/__tanl.c +0 -143
- package/libc/musl/src/math/aarch64/lrint.c +0 -10
- package/libc/musl/src/math/aarch64/lrintf.c +0 -10
- package/libc/musl/src/math/aarch64/rintf.c +0 -7
- package/libc/musl/src/math/cosl.c +0 -39
- package/libc/musl/src/math/fdim.c +0 -10
- package/libc/musl/src/math/fdimf.c +0 -10
- package/libc/musl/src/math/fdiml.c +0 -18
- package/libc/musl/src/math/finite.c +0 -7
- package/libc/musl/src/math/finitef.c +0 -7
- package/libc/musl/src/math/frexp.c +0 -23
- package/libc/musl/src/math/frexpf.c +0 -23
- package/libc/musl/src/math/frexpl.c +0 -29
- package/libc/musl/src/math/i386/lrint.c +0 -8
- package/libc/musl/src/math/i386/lrintf.c +0 -8
- package/libc/musl/src/math/i386/rintf.c +0 -7
- package/libc/musl/src/math/lrint.c +0 -72
- package/libc/musl/src/math/lrintf.c +0 -8
- package/libc/musl/src/math/powerpc64/lrint.c +0 -16
- package/libc/musl/src/math/powerpc64/lrintf.c +0 -16
- package/libc/musl/src/math/rintf.c +0 -30
- package/libc/musl/src/math/s390x/rintf.c +0 -15
- package/libc/musl/src/math/sincosl.c +0 -60
- package/libc/musl/src/math/sinl.c +0 -41
- package/libc/musl/src/math/tanl.c +0 -29
- package/libc/musl/src/math/x32/lrint.s +0 -5
- package/libc/musl/src/math/x32/lrintf.s +0 -5
- package/libc/musl/src/math/x86_64/lrint.c +0 -8
- package/libc/musl/src/math/x86_64/lrintf.c +0 -8
- package/libc/wasi/libc-bottom-half/sources/reallocarray.c +0 -14
|
@@ -0,0 +1,1126 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const testing = std.testing;
|
|
3
|
+
const assert = std.debug.assert;
|
|
4
|
+
const maxInt = std.math.maxInt;
|
|
5
|
+
const minInt = std.math.minInt;
|
|
6
|
+
const divCeil = std.math.divCeil;
|
|
7
|
+
|
|
8
|
+
const builtin = @import("builtin");
|
|
9
|
+
const compiler_rt = @import("../compiler_rt.zig");
|
|
10
|
+
const symbol = @import("../compiler_rt.zig").symbol;
|
|
11
|
+
|
|
12
|
+
const endian = builtin.cpu.arch.endian();
|
|
13
|
+
|
|
14
|
+
inline fn limbGet(limbs: []const u64, i: usize) u64 {
|
|
15
|
+
return switch (endian) {
|
|
16
|
+
.little => limbs[i],
|
|
17
|
+
.big => limbs[limbs.len - 1 - i],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
inline fn limbSet(limbs: []u64, i: usize, value: u64) void {
|
|
22
|
+
switch (endian) {
|
|
23
|
+
.little => limbs[i] = value,
|
|
24
|
+
.big => limbs[limbs.len - 1 - i] = value,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fn usedLimbCount(bits: u16) u16 {
|
|
29
|
+
return divCeil(u16, bits, 64) catch unreachable;
|
|
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 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
|
+
|
|
66
|
+
fn Limbs(T: type) type {
|
|
67
|
+
const int_info = @typeInfo(T).int;
|
|
68
|
+
const limb_cnt = comptime limbCount(int_info.bits);
|
|
69
|
+
return [limb_cnt]u64;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fn asLimbs(v: anytype) Limbs(@TypeOf(v)) {
|
|
73
|
+
const T = @TypeOf(v);
|
|
74
|
+
const int_info = @typeInfo(T).int;
|
|
75
|
+
const limb_cnt = comptime limbCount(int_info.bits);
|
|
76
|
+
const ET = @Int(int_info.signedness, limb_cnt * 64);
|
|
77
|
+
return @bitCast(@as(ET, v));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fn limbWrap(limb: u64, is_signed: bool, bits: u16) u64 {
|
|
81
|
+
assert(bits % 64 != 0);
|
|
82
|
+
const pad_bits: u6 = @intCast(64 - bits % 64);
|
|
83
|
+
if (!is_signed) {
|
|
84
|
+
const s = limb << pad_bits;
|
|
85
|
+
return s >> pad_bits;
|
|
86
|
+
} else {
|
|
87
|
+
const s = @as(i64, @bitCast(limb)) << pad_bits;
|
|
88
|
+
return @bitCast(s >> pad_bits);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
comptime {
|
|
93
|
+
symbol(&__addo_limb64, "__addo_limb64");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn __addo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
|
|
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);
|
|
101
|
+
|
|
102
|
+
var carry: u1 = 0;
|
|
103
|
+
var i: usize = 0;
|
|
104
|
+
while (i < limb_cnt - 1) : (i += 1) {
|
|
105
|
+
const s1 = @addWithOverflow(limbGet(a, i), limbGet(b, i));
|
|
106
|
+
const s2 = @addWithOverflow(s1[0], carry);
|
|
107
|
+
carry = s1[1] | s2[1];
|
|
108
|
+
limbSet(out, i, s2[0]);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const limb: u64 = b: {
|
|
112
|
+
if (!is_signed) {
|
|
113
|
+
const s1 = @addWithOverflow(limbGet(a, i), limbGet(b, i));
|
|
114
|
+
const s2 = @addWithOverflow(s1[0], carry);
|
|
115
|
+
carry = s1[1] | s2[1];
|
|
116
|
+
break :b s2[0];
|
|
117
|
+
} else {
|
|
118
|
+
const as: i64 = @bitCast(limbGet(a, i));
|
|
119
|
+
const bs: i64 = @bitCast(limbGet(b, i));
|
|
120
|
+
const s1 = @addWithOverflow(as, bs);
|
|
121
|
+
const s2 = @addWithOverflow(s1[0], carry);
|
|
122
|
+
carry = s1[1] | s2[1];
|
|
123
|
+
break :b @bitCast(s2[0]);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
if (bits % 64 == 0) {
|
|
128
|
+
limbSet(out, i, limb);
|
|
129
|
+
fixLastLimb(out_ptr, is_signed, bits);
|
|
130
|
+
return carry != 0;
|
|
131
|
+
} else {
|
|
132
|
+
assert(carry == 0);
|
|
133
|
+
const wrapped_limb = limbWrap(limb, is_signed, bits);
|
|
134
|
+
limbSet(out, i, wrapped_limb);
|
|
135
|
+
fixLastLimb(out_ptr, is_signed, bits);
|
|
136
|
+
return wrapped_limb != limb;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
fn test__addo_limb64(comptime T: type, a: T, b: T, expected: struct { T, bool }) !void {
|
|
141
|
+
const int_info = @typeInfo(T).int;
|
|
142
|
+
const is_signed = int_info.signedness == .signed;
|
|
143
|
+
|
|
144
|
+
var a_limbs = asLimbs(a);
|
|
145
|
+
var b_limbs = asLimbs(b);
|
|
146
|
+
var out: Limbs(T) = undefined;
|
|
147
|
+
const overflow = __addo_limb64(&out, &a_limbs, &b_limbs, is_signed, int_info.bits);
|
|
148
|
+
|
|
149
|
+
const expected_limbs = asLimbs(expected[0]);
|
|
150
|
+
try testing.expectEqual(expected_limbs, out);
|
|
151
|
+
try testing.expectEqual(expected[1], overflow);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
test __addo_limb64 {
|
|
155
|
+
try test__addo_limb64(u64, 1, 2, .{ 3, false });
|
|
156
|
+
try test__addo_limb64(u64, maxInt(u64), 2, .{ 1, true });
|
|
157
|
+
try test__addo_limb64(u65, maxInt(u65), 2, .{ 1, true });
|
|
158
|
+
try test__addo_limb64(u255, 1, 2, .{ 3, false });
|
|
159
|
+
|
|
160
|
+
try test__addo_limb64(i64, 1, 2, .{ 3, false });
|
|
161
|
+
try test__addo_limb64(i64, maxInt(i64), 1, .{ minInt(i64), true });
|
|
162
|
+
try test__addo_limb64(i65, maxInt(i65), 1, .{ minInt(i65), true });
|
|
163
|
+
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 });
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
comptime {
|
|
170
|
+
symbol(&__subo_limb64, "__subo_limb64");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
fn __subo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
|
|
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);
|
|
178
|
+
|
|
179
|
+
var borrow: u1 = 0;
|
|
180
|
+
var i: usize = 0;
|
|
181
|
+
while (i < limb_cnt - 1) : (i += 1) {
|
|
182
|
+
const s1 = @subWithOverflow(limbGet(a, i), limbGet(b, i));
|
|
183
|
+
const s2 = @subWithOverflow(s1[0], borrow);
|
|
184
|
+
borrow = s1[1] | s2[1];
|
|
185
|
+
limbSet(out, i, s2[0]);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const limb: u64 = b: {
|
|
189
|
+
if (!is_signed) {
|
|
190
|
+
const s1 = @subWithOverflow(limbGet(a, i), limbGet(b, i));
|
|
191
|
+
const s2 = @subWithOverflow(s1[0], borrow);
|
|
192
|
+
borrow = s1[1] | s2[1];
|
|
193
|
+
break :b s2[0];
|
|
194
|
+
} else {
|
|
195
|
+
const as: i64 = @bitCast(limbGet(a, i));
|
|
196
|
+
const bs: i64 = @bitCast(limbGet(b, i));
|
|
197
|
+
const s1 = @subWithOverflow(as, bs);
|
|
198
|
+
const s2 = @subWithOverflow(s1[0], borrow);
|
|
199
|
+
borrow = s1[1] | s2[1];
|
|
200
|
+
break :b @bitCast(s2[0]);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
if (bits % 64 == 0) {
|
|
205
|
+
limbSet(out, i, limb);
|
|
206
|
+
fixLastLimb(out_ptr, is_signed, bits);
|
|
207
|
+
return borrow != 0;
|
|
208
|
+
} else {
|
|
209
|
+
const wrapped_limb = limbWrap(limb, is_signed, bits);
|
|
210
|
+
limbSet(out, i, wrapped_limb);
|
|
211
|
+
fixLastLimb(out_ptr, is_signed, bits);
|
|
212
|
+
return borrow != 0 or wrapped_limb != limb;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
fn test__subo_limb64(comptime T: type, a: T, b: T, expected: struct { T, bool }) !void {
|
|
217
|
+
const int_info = @typeInfo(T).int;
|
|
218
|
+
const is_signed = int_info.signedness == .signed;
|
|
219
|
+
|
|
220
|
+
var a_limbs = asLimbs(a);
|
|
221
|
+
var b_limbs = asLimbs(b);
|
|
222
|
+
var out: Limbs(T) = undefined;
|
|
223
|
+
const overflow = __subo_limb64(&out, &a_limbs, &b_limbs, is_signed, int_info.bits);
|
|
224
|
+
|
|
225
|
+
const expected_limbs = asLimbs(expected[0]);
|
|
226
|
+
try testing.expectEqual(expected_limbs, out);
|
|
227
|
+
try testing.expectEqual(expected[1], overflow);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
test __subo_limb64 {
|
|
231
|
+
try test__subo_limb64(u64, 3, 2, .{ 1, false });
|
|
232
|
+
try test__subo_limb64(u64, 0, 1, .{ maxInt(u64), true });
|
|
233
|
+
try test__subo_limb64(u65, 0, 1, .{ maxInt(u65), true });
|
|
234
|
+
try test__subo_limb64(u255, 3, 2, .{ 1, false });
|
|
235
|
+
|
|
236
|
+
try test__subo_limb64(i64, 1, 2, .{ -1, false });
|
|
237
|
+
try test__subo_limb64(i64, minInt(i64), 1, .{ maxInt(i64), true });
|
|
238
|
+
try test__subo_limb64(i65, minInt(i65), 1, .{ maxInt(i65), true });
|
|
239
|
+
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 });
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
comptime {
|
|
246
|
+
symbol(&__cmp_limb64, "__cmp_limb64");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// a < b -> -1
|
|
250
|
+
// a == b -> 0
|
|
251
|
+
// a > b -> 1
|
|
252
|
+
fn __cmp_limb64(a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) i8 {
|
|
253
|
+
const limb_cnt = usedLimbCount(bits);
|
|
254
|
+
const a = constLimbs(a_ptr, bits);
|
|
255
|
+
const b = constLimbs(b_ptr, bits);
|
|
256
|
+
|
|
257
|
+
var i: usize = 0;
|
|
258
|
+
if (is_signed) {
|
|
259
|
+
const sa: i64 = @bitCast(limbGet(a, limb_cnt - 1));
|
|
260
|
+
const sb: i64 = @bitCast(limbGet(b, limb_cnt - 1));
|
|
261
|
+
if (sa < sb) return -1;
|
|
262
|
+
if (sa > sb) return 1;
|
|
263
|
+
i += 1;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
while (i < limb_cnt) : (i += 1) {
|
|
267
|
+
const ai = limbGet(a, limb_cnt - 1 - i);
|
|
268
|
+
const bi = limbGet(b, limb_cnt - 1 - i);
|
|
269
|
+
if (ai < bi) return -1;
|
|
270
|
+
if (ai > bi) return 1;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
fn test__cmp_limb64(comptime T: type, a: T, b: T, expected: i8) !void {
|
|
277
|
+
const int_info = @typeInfo(T).int;
|
|
278
|
+
const is_signed = int_info.signedness == .signed;
|
|
279
|
+
|
|
280
|
+
var a_limbs = asLimbs(a);
|
|
281
|
+
var b_limbs = asLimbs(b);
|
|
282
|
+
const actual = __cmp_limb64(&a_limbs, &b_limbs, is_signed, int_info.bits);
|
|
283
|
+
|
|
284
|
+
try testing.expectEqual(expected, actual);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
test __cmp_limb64 {
|
|
288
|
+
try test__cmp_limb64(u64, 1, 2, -1);
|
|
289
|
+
try test__cmp_limb64(u64, 2, 2, 0);
|
|
290
|
+
try test__cmp_limb64(u64, 3, 2, 1);
|
|
291
|
+
|
|
292
|
+
try test__cmp_limb64(u65, 1, 2, -1);
|
|
293
|
+
try test__cmp_limb64(u65, maxInt(u65), maxInt(u65), 0);
|
|
294
|
+
try test__cmp_limb64(u65, maxInt(u65), maxInt(u65) - 1, 1);
|
|
295
|
+
|
|
296
|
+
try test__cmp_limb64(u255, 1, 2, -1);
|
|
297
|
+
try test__cmp_limb64(u255, 7, 7, 0);
|
|
298
|
+
try test__cmp_limb64(u255, maxInt(u255), maxInt(u255) - 1, 1);
|
|
299
|
+
|
|
300
|
+
try test__cmp_limb64(i64, -1, 0, -1);
|
|
301
|
+
try test__cmp_limb64(i64, 0, 0, 0);
|
|
302
|
+
try test__cmp_limb64(i64, 1, 0, 1);
|
|
303
|
+
|
|
304
|
+
try test__cmp_limb64(i65, minInt(i65), maxInt(i65), -1);
|
|
305
|
+
try test__cmp_limb64(i65, -1, -1, 0);
|
|
306
|
+
try test__cmp_limb64(i65, maxInt(i65), minInt(i65), 1);
|
|
307
|
+
|
|
308
|
+
try test__cmp_limb64(i255, -3, 2, -1);
|
|
309
|
+
try test__cmp_limb64(i255, -5, -5, 0);
|
|
310
|
+
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
|
+
|
|
316
|
+
comptime {
|
|
317
|
+
symbol(&__and_limb64, "__and_limb64");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
fn __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
|
+
|
|
332
|
+
fn 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
|
+
|
|
344
|
+
test __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
|
+
|
|
359
|
+
comptime {
|
|
360
|
+
symbol(&__or_limb64, "__or_limb64");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
fn __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
|
+
|
|
375
|
+
fn 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
|
+
|
|
387
|
+
test __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
|
+
|
|
402
|
+
comptime {
|
|
403
|
+
symbol(&__xor_limb64, "__xor_limb64");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
fn __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
|
+
|
|
418
|
+
fn 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
|
+
|
|
430
|
+
test __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
|
+
|
|
445
|
+
comptime {
|
|
446
|
+
symbol(&__not_limb64, "__not_limb64");
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
fn __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
|
+
|
|
467
|
+
fn 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
|
+
|
|
479
|
+
test __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
|
+
|
|
494
|
+
comptime {
|
|
495
|
+
symbol(&__shlo_limb64, "__shlo_limb64");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
fn __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
|
+
|
|
544
|
+
fn 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
|
+
|
|
557
|
+
test __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
|
+
|
|
588
|
+
comptime {
|
|
589
|
+
symbol(&__shr_limb64, "__shr_limb64");
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
fn __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
|
+
|
|
621
|
+
fn 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
|
+
|
|
633
|
+
test __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
|
+
|
|
661
|
+
comptime {
|
|
662
|
+
symbol(&__clz_limb64, "__clz_limb64");
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
fn __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
|
+
|
|
696
|
+
fn 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
|
+
|
|
705
|
+
test __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
|
+
|
|
722
|
+
comptime {
|
|
723
|
+
symbol(&__ctz_limb64, "__ctz_limb64");
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
fn __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
|
+
|
|
752
|
+
fn 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
|
+
|
|
761
|
+
test __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
|
+
|
|
778
|
+
comptime {
|
|
779
|
+
symbol(&__popcount_limb64, "__popcount_limb64");
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
fn __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
|
+
|
|
801
|
+
fn 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
|
+
|
|
810
|
+
test __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
|
+
|
|
827
|
+
comptime {
|
|
828
|
+
symbol(&__bitreverse_limb64, "__bitreverse_limb64");
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
fn __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
|
+
|
|
848
|
+
fn 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
|
+
|
|
860
|
+
test __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
|
+
|
|
877
|
+
comptime {
|
|
878
|
+
symbol(&__byteswap_limb64, "__byteswap_limb64");
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
fn __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
|
+
|
|
900
|
+
fn 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
|
+
|
|
912
|
+
test __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
|
+
|
|
929
|
+
comptime {
|
|
930
|
+
symbol(&__mulo_limb64, "__mulo_limb64");
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
inline 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
|
+
|
|
944
|
+
fn 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
|
+
|
|
953
|
+
fn __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
|
+
|
|
1024
|
+
fn 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
|
+
|
|
1038
|
+
test __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
|
+
|
|
1076
|
+
comptime {
|
|
1077
|
+
symbol(&__abs_limb64, "__abs_limb64");
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
fn __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
|
+
|
|
1100
|
+
fn 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
|
+
|
|
1112
|
+
test __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);
|
|
1126
|
+
}
|