authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-05 10:48:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-05 10:48:22-07:00
logfc40d2372335e69be175972ffabb55bc7fb77230
tree184daa7845a95f54da0c8c5c6ffba0feffa01b6c
parent7a27f0d80c5ce9d596b2b43699e131ab387e1317
parent9d409233b2c62e1d24635165ac6b3b7686ffd5e4

Merge remote-tracking branch 'origin/master' into stage2-whole-file-astgen

Conflicts: * build.zig * lib/std/array_list.zig * lib/std/c/ast.zig * lib/std/c/parse.zig * lib/std/os/bits/linux.zig

54 files changed, 7625 insertions(+), 2956 deletions(-)

build.zig+25-21
...@@ -36,7 +36,7 @@ pub fn build(b: *Builder) !void {...@@ -36,7 +36,7 @@ pub fn build(b: *Builder) !void {
36 const docs_step = b.step("docs", "Build documentation");36 const docs_step = b.step("docs", "Build documentation");
37 docs_step.dependOn(&docgen_cmd.step);37 docs_step.dependOn(&docgen_cmd.step);
3838
39 const test_step = b.step("test", "Run all the tests");39 const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
4040
41 var test_stage2 = b.addTest("src/test.zig");41 var test_stage2 = b.addTest("src/test.zig");
42 test_stage2.setBuildMode(mode);42 test_stage2.setBuildMode(mode);
...@@ -99,7 +99,7 @@ pub fn build(b: *Builder) !void {...@@ -99,7 +99,7 @@ pub fn build(b: *Builder) !void {
99 exe.install();99 exe.install();
100 exe.setBuildMode(mode);100 exe.setBuildMode(mode);
101 exe.setTarget(target);101 exe.setTarget(target);
102 test_step.dependOn(&exe.step);102 toolchain_step.dependOn(&exe.step);
103 b.default_step.dependOn(&exe.step);103 b.default_step.dependOn(&exe.step);
104104
105 exe.addBuildOption(u32, "mem_leak_frames", mem_leak_frames);105 exe.addBuildOption(u32, "mem_leak_frames", mem_leak_frames);
...@@ -244,7 +244,7 @@ pub fn build(b: *Builder) !void {...@@ -244,7 +244,7 @@ pub fn build(b: *Builder) !void {
244 const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");244 const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
245 test_stage2_step.dependOn(&test_stage2.step);245 test_stage2_step.dependOn(&test_stage2.step);
246 if (!skip_stage2_tests) {246 if (!skip_stage2_tests) {
247 test_step.dependOn(test_stage2_step);247 toolchain_step.dependOn(test_stage2_step);
248 }248 }
249249
250 var chosen_modes: [4]builtin.Mode = undefined;250 var chosen_modes: [4]builtin.Mode = undefined;
...@@ -268,33 +268,37 @@ pub fn build(b: *Builder) !void {...@@ -268,33 +268,37 @@ pub fn build(b: *Builder) !void {
268 const modes = chosen_modes[0..chosen_mode_index];268 const modes = chosen_modes[0..chosen_mode_index];
269269
270 // run stage1 `zig fmt` on this build.zig file just to make sure it works270 // run stage1 `zig fmt` on this build.zig file just to make sure it works
271 test_step.dependOn(&fmt_build_zig.step);271 toolchain_step.dependOn(&fmt_build_zig.step);
272 const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");272 const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
273 fmt_step.dependOn(&fmt_build_zig.step);273 fmt_step.dependOn(&fmt_build_zig.step);
274274
275 // TODO for the moment, skip wasm32-wasi until bugs are sorted out.275 // TODO for the moment, skip wasm32-wasi until bugs are sorted out.
276 test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));276 toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
277277
278 test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));278 toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
279279 toolchain_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/c.zig", "minilibc", "Run the mini libc tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
280 test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));280
281 test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/c.zig", "minilibc", "Run the mini libc tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));281 toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
282282 toolchain_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
283 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));283 toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
284 test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));284 toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes));
285 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));285 toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
286 test_step.dependOn(tests.addCliTests(b, test_filter, modes));286 toolchain_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
287 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));287 toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter));
288 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
289 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
290 if (!skip_run_translated_c) {288 if (!skip_run_translated_c) {
291 test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));289 toolchain_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
292 }290 }
293 // tests for this feature are disabled until we have the self-hosted compiler available291 // tests for this feature are disabled until we have the self-hosted compiler available
294 // test_step.dependOn(tests.addGenHTests(b, test_filter));292 // toolchain_step.dependOn(tests.addGenHTests(b, test_filter));
295 if (!skip_compile_errors) {293 if (!skip_compile_errors) {
296 test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));294 toolchain_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
297 }295 }
296
297 const std_step = tests.addPkgTests(b, test_filter, "lib/std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir);
298
299 const test_step = b.step("test", "Run all the tests");
300 test_step.dependOn(toolchain_step);
301 test_step.dependOn(std_step);
298 test_step.dependOn(docs_step);302 test_step.dependOn(docs_step);
299}303}
300304
ci/azure/linux_script+3-1
...@@ -65,7 +65,9 @@ make $JOBS install...@@ -65,7 +65,9 @@ make $JOBS install
65cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"65cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"
66make $JOBS install66make $JOBS install
6767
68release/bin/zig build test -Denable-qemu -Denable-wasmtime68for step in test-toolchain test-std docs; do
69 release/bin/zig build $step -Denable-qemu -Denable-wasmtime
70done
6971
70# Look for HTML errors.72# Look for HTML errors.
71tidy -qe ../zig-cache/langref.html73tidy -qe ../zig-cache/langref.html
ci/azure/macos_script+4-2
...@@ -18,7 +18,7 @@ tar xf "$CACHE_BASENAME.tar.xz"...@@ -18,7 +18,7 @@ tar xf "$CACHE_BASENAME.tar.xz"
1818
19ZIG="$PREFIX/bin/zig"19ZIG="$PREFIX/bin/zig"
20NATIVE_LIBC_TXT="$HOME/native_libc.txt"20NATIVE_LIBC_TXT="$HOME/native_libc.txt"
21$ZIG libc > "$NATIVE_LIBC_TXT"21$ZIG libc >"$NATIVE_LIBC_TXT"
22export ZIG_LIBC="$NATIVE_LIBC_TXT"22export ZIG_LIBC="$NATIVE_LIBC_TXT"
23export CC="$ZIG cc"23export CC="$ZIG cc"
24export CXX="$ZIG c++"24export CXX="$ZIG c++"
...@@ -55,7 +55,9 @@ make $JOBS install...@@ -55,7 +55,9 @@ make $JOBS install
55cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" -DZIG_TARGET_MCPU="x86_64_v2"55cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" -DZIG_TARGET_MCPU="x86_64_v2"
56make $JOBS install56make $JOBS install
5757
58release/bin/zig build test58for step in test-toolchain test-std docs; do
59 release/bin/zig build $step
60done
5961
60if [ "${BUILD_REASON}" != "PullRequest" ]; then62if [ "${BUILD_REASON}" != "PullRequest" ]; then
61 mv ../LICENSE release/63 mv ../LICENSE release/
ci/azure/windows_msvc_script.bat+1-13
...@@ -26,20 +26,8 @@ cd %ZIGBUILDDIR%...@@ -26,20 +26,8 @@ cd %ZIGBUILDDIR%
26cmake.exe .. -Thost=x64 -G"Visual Studio 16 2019" -A x64 "-DCMAKE_INSTALL_PREFIX=%ZIGINSTALLDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release -DZIG_OMIT_STAGE2=ON || exit /b26cmake.exe .. -Thost=x64 -G"Visual Studio 16 2019" -A x64 "-DCMAKE_INSTALL_PREFIX=%ZIGINSTALLDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release -DZIG_OMIT_STAGE2=ON || exit /b
27msbuild /maxcpucount /p:Configuration=Release INSTALL.vcxproj || exit /b27msbuild /maxcpucount /p:Configuration=Release INSTALL.vcxproj || exit /b
2828
29"%ZIGINSTALLDIR%\bin\zig.exe" build test-behavior -Dskip-non-native || exit /b29"%ZIGINSTALLDIR%\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests || exit /b
30REM Disabled to prevent OOM
31REM "%ZIGINSTALLDIR%\bin\zig.exe" build test-stage2 -Dskip-non-native || exit /b
32"%ZIGINSTALLDIR%\bin\zig.exe" build test-fmt -Dskip-non-native || exit /b
33"%ZIGINSTALLDIR%\bin\zig.exe" build test-std -Dskip-non-native || exit /b30"%ZIGINSTALLDIR%\bin\zig.exe" build test-std -Dskip-non-native || exit /b
34"%ZIGINSTALLDIR%\bin\zig.exe" build test-compiler-rt -Dskip-non-native || exit /b
35"%ZIGINSTALLDIR%\bin\zig.exe" build test-compare-output -Dskip-non-native || exit /b
36"%ZIGINSTALLDIR%\bin\zig.exe" build test-standalone -Dskip-non-native || exit /b
37"%ZIGINSTALLDIR%\bin\zig.exe" build test-stack-traces -Dskip-non-native || exit /b
38"%ZIGINSTALLDIR%\bin\zig.exe" build test-cli -Dskip-non-native || exit /b
39"%ZIGINSTALLDIR%\bin\zig.exe" build test-asm-link -Dskip-non-native || exit /b
40"%ZIGINSTALLDIR%\bin\zig.exe" build test-runtime-safety -Dskip-non-native || exit /b
41"%ZIGINSTALLDIR%\bin\zig.exe" build test-translate-c -Dskip-non-native || exit /b
42"%ZIGINSTALLDIR%\bin\zig.exe" build test-run-translated-c -Dskip-non-native || exit /b
43"%ZIGINSTALLDIR%\bin\zig.exe" build docs || exit /b31"%ZIGINSTALLDIR%\bin\zig.exe" build docs || exit /b
4432
45set "PATH=%CD:~0,2%\msys64\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem"33set "PATH=%CD:~0,2%\msys64\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem"
ci/srht/freebsd_script+1-1
...@@ -4,7 +4,7 @@ set -x...@@ -4,7 +4,7 @@ set -x
4set -e4set -e
55
6sudo pkg update -fq6sudo pkg update -fq
7sudo pkg install -y cmake py37-s3cmd wget curl jq samurai7sudo pkg install -y cmake py38-s3cmd wget curl jq samurai
88
9ZIGDIR="$(pwd)"9ZIGDIR="$(pwd)"
10CACHE_BASENAME="zig+llvm+lld+clang-x86_64-freebsd-gnu-0.8.0-dev.1939+5a3ea9bec"10CACHE_BASENAME="zig+llvm+lld+clang-x86_64-freebsd-gnu-0.8.0-dev.1939+5a3ea9bec"
lib/std/Thread.zig+23-4
...@@ -68,11 +68,30 @@ else switch (std.Target.current.os.tag) {...@@ -68,11 +68,30 @@ else switch (std.Target.current.os.tag) {
68};68};
6969
70/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").70/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").
71pub fn spinLoopHint() void {71pub fn spinLoopHint() callconv(.Inline) void {
72 switch (std.Target.current.cpu.arch) {72 switch (std.Target.current.cpu.arch) {
73 .i386, .x86_64 => asm volatile ("pause" ::: "memory"),73 .i386, .x86_64 => {
74 .arm, .aarch64 => asm volatile ("yield" ::: "memory"),74 asm volatile ("pause" ::: "memory");
75 else => {},75 },
76 .arm, .armeb, .thumb, .thumbeb => {
77 // `yield` was introduced in v6k but are also available on v6m.
78 const can_yield = comptime std.Target.arm.featureSetHasAny(std.Target.current.cpu.features, .{ .has_v6k, .has_v6m });
79 if (can_yield) asm volatile ("yield" ::: "memory")
80 // Fallback.
81 else asm volatile ("" ::: "memory");
82 },
83 .aarch64, .aarch64_be, .aarch64_32 => {
84 asm volatile ("isb" ::: "memory");
85 },
86 .powerpc64, .powerpc64le => {
87 // No-op that serves as `yield` hint.
88 asm volatile ("or 27, 27, 27" ::: "memory");
89 },
90 else => {
91 // Do nothing but prevent the compiler from optimizing away the
92 // spinning loop.
93 asm volatile ("" ::: "memory");
94 },
76 }95 }
77}96}
7897
lib/std/array_list.zig+55-29
...@@ -50,7 +50,6 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -50,7 +50,6 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
50 allocator: *Allocator,50 allocator: *Allocator,
5151
52 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;52 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
53 pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T;
5453
55 /// Deinitialize with `deinit` or use `toOwnedSlice`.54 /// Deinitialize with `deinit` or use `toOwnedSlice`.
56 pub fn init(allocator: *Allocator) Self {55 pub fn init(allocator: *Allocator) Self {
...@@ -141,7 +140,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -141,7 +140,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
141140
142 /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.141 /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.
143 /// This operation is O(N).142 /// This operation is O(N).
144 pub fn insertSlice(self: *Self, i: usize, items: SliceConst) !void {143 pub fn insertSlice(self: *Self, i: usize, items: []const T) !void {
145 try self.ensureUnusedCapacity(items.len);144 try self.ensureUnusedCapacity(items.len);
146 self.items.len += items.len;145 self.items.len += items.len;
147146
...@@ -153,7 +152,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -153,7 +152,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
153 /// Grows list if `len < new_items.len`.152 /// Grows list if `len < new_items.len`.
154 /// Shrinks list if `len > new_items.len`.153 /// Shrinks list if `len > new_items.len`.
155 /// Invalidates pointers if this ArrayList is resized.154 /// Invalidates pointers if this ArrayList is resized.
156 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: SliceConst) !void {155 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) !void {
157 const after_range = start + len;156 const after_range = start + len;
158 const range = self.items[start..after_range];157 const range = self.items[start..after_range];
159158
...@@ -220,14 +219,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -220,14 +219,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
220219
221 /// Append the slice of items to the list. Allocates more220 /// Append the slice of items to the list. Allocates more
222 /// memory as necessary.221 /// memory as necessary.
223 pub fn appendSlice(self: *Self, items: SliceConst) !void {222 pub fn appendSlice(self: *Self, items: []const T) !void {
224 try self.ensureUnusedCapacity(items.len);223 try self.ensureUnusedCapacity(items.len);
225 self.appendSliceAssumeCapacity(items);224 self.appendSliceAssumeCapacity(items);
226 }225 }
227226
228 /// Append the slice of items to the list, asserting the capacity is already227 /// Append the slice of items to the list, asserting the capacity is already
229 /// enough to store the new items. **Does not** invalidate pointers.228 /// enough to store the new items. **Does not** invalidate pointers.
230 pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void {229 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
231 const oldlen = self.items.len;230 const oldlen = self.items.len;
232 const newlen = self.items.len + items.len;231 const newlen = self.items.len + items.len;
233 self.items.len = newlen;232 self.items.len = newlen;
...@@ -438,7 +437,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -438,7 +437,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
438 capacity: usize = 0,437 capacity: usize = 0,
439438
440 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;439 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
441 pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T;
442440
443 /// Initialize with capacity to hold at least num elements.441 /// Initialize with capacity to hold at least num elements.
444 /// Deinitialize with `deinit` or use `toOwnedSlice`.442 /// Deinitialize with `deinit` or use `toOwnedSlice`.
...@@ -492,7 +490,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -492,7 +490,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
492 /// Insert slice `items` at index `i`. Moves `list[i .. list.len]` to490 /// Insert slice `items` at index `i`. Moves `list[i .. list.len]` to
493 /// higher indicices make room.491 /// higher indicices make room.
494 /// This operation is O(N).492 /// This operation is O(N).
495 pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: SliceConst) !void {493 pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: []const T) !void {
496 try self.ensureUnusedCapacity(allocator, items.len);494 try self.ensureUnusedCapacity(allocator, items.len);
497 self.items.len += items.len;495 self.items.len += items.len;
498496
...@@ -504,7 +502,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -504,7 +502,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
504 /// Grows list if `len < new_items.len`.502 /// Grows list if `len < new_items.len`.
505 /// Shrinks list if `len > new_items.len`503 /// Shrinks list if `len > new_items.len`
506 /// Invalidates pointers if this ArrayList is resized.504 /// Invalidates pointers if this ArrayList is resized.
507 pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: SliceConst) !void {505 pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: []const T) !void {
508 var managed = self.toManaged(allocator);506 var managed = self.toManaged(allocator);
509 try managed.replaceRange(start, len, new_items);507 try managed.replaceRange(start, len, new_items);
510 self.* = managed.toUnmanaged();508 self.* = managed.toUnmanaged();
...@@ -552,14 +550,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -552,14 +550,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
552550
553 /// Append the slice of items to the list. Allocates more551 /// Append the slice of items to the list. Allocates more
554 /// memory as necessary.552 /// memory as necessary.
555 pub fn appendSlice(self: *Self, allocator: *Allocator, items: SliceConst) !void {553 pub fn appendSlice(self: *Self, allocator: *Allocator, items: []const T) !void {
556 try self.ensureUnusedCapacity(allocator, items.len);554 try self.ensureUnusedCapacity(allocator, items.len);
557 self.appendSliceAssumeCapacity(items);555 self.appendSliceAssumeCapacity(items);
558 }556 }
559557
560 /// Append the slice of items to the list, asserting the capacity is enough558 /// Append the slice of items to the list, asserting the capacity is enough
561 /// to store the new items.559 /// to store the new items.
562 pub fn appendSliceAssumeCapacity(self: *Self, items: SliceConst) void {560 pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void {
563 const oldlen = self.items.len;561 const oldlen = self.items.len;
564 const newlen = self.items.len + items.len;562 const newlen = self.items.len + items.len;
565563
...@@ -1150,15 +1148,31 @@ test "std.ArrayList/ArrayListUnmanaged: ArrayList(T) of struct T" {...@@ -1150,15 +1148,31 @@ test "std.ArrayList/ArrayListUnmanaged: ArrayList(T) of struct T" {
1150 }1148 }
1151}1149}
11521150
1153test "std.ArrayList(u8) implements writer" {1151test "std.ArrayList(u8)/ArrayListAligned implements writer" {
1154 var buffer = ArrayList(u8).init(std.testing.allocator);1152 const a = testing.allocator;
1155 defer buffer.deinit();1153
1154 {
1155 var buffer = ArrayList(u8).init(a);
1156 defer buffer.deinit();
1157
1158 const x: i32 = 42;
1159 const y: i32 = 1234;
1160 try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });
11561161
1157 const x: i32 = 42;1162 testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
1158 const y: i32 = 1234;1163 }
1159 try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });1164 {
1165 var list = ArrayListAligned(u8, 2).init(a);
1166 defer list.deinit();
11601167
1161 testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);1168 const writer = list.writer();
1169 try writer.writeAll("a");
1170 try writer.writeAll("bc");
1171 try writer.writeAll("d");
1172 try writer.writeAll("efg");
1173
1174 testing.expectEqualSlices(u8, list.items, "abcdefg");
1175 }
1162}1176}
11631177
1164test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMemory" {1178test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMemory" {
...@@ -1189,18 +1203,6 @@ test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMe...@@ -1189,18 +1203,6 @@ test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMe
1189 }1203 }
1190}1204}
11911205
1192test "std.ArrayList.writer" {
1193 var list = ArrayList(u8).init(std.testing.allocator);
1194 defer list.deinit();
1195
1196 const writer = list.writer();
1197 try writer.writeAll("a");
1198 try writer.writeAll("bc");
1199 try writer.writeAll("d");
1200 try writer.writeAll("efg");
1201 testing.expectEqualSlices(u8, list.items, "abcdefg");
1202}
1203
1204test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" {1206test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" {
1205 const a = std.testing.allocator;1207 const a = std.testing.allocator;
1206 {1208 {
...@@ -1248,3 +1250,27 @@ test "std.ArrayList/ArrayListUnmanaged.toOwnedSliceSentinel" {...@@ -1248,3 +1250,27 @@ test "std.ArrayList/ArrayListUnmanaged.toOwnedSliceSentinel" {
1248 testing.expectEqualStrings(result, mem.spanZ(result.ptr));1250 testing.expectEqualStrings(result, mem.spanZ(result.ptr));
1249 }1251 }
1250}1252}
1253
1254test "ArrayListAligned/ArrayListAlignedUnmanaged accepts unaligned slices" {
1255 const a = testing.allocator;
1256 {
1257 var list = std.ArrayListAligned(u8, 8).init(a);
1258 defer list.deinit();
1259
1260 try list.appendSlice(&.{ 0, 1, 2, 3 });
1261 try list.insertSlice(2, &.{ 4, 5, 6, 7 });
1262 try list.replaceRange(1, 3, &.{ 8, 9 });
1263
1264 testing.expectEqualSlices(u8, list.items, &.{ 0, 8, 9, 6, 7, 2, 3 });
1265 }
1266 {
1267 var list = std.ArrayListAlignedUnmanaged(u8, 8){};
1268 defer list.deinit(a);
1269
1270 try list.appendSlice(a, &.{ 0, 1, 2, 3 });
1271 try list.insertSlice(a, 2, &.{ 4, 5, 6, 7 });
1272 try list.replaceRange(a, 1, 3, &.{ 8, 9 });
1273
1274 testing.expectEqualSlices(u8, list.items, &.{ 0, 8, 9, 6, 7, 2, 3 });
1275 }
1276}
lib/std/build/run.zig+7
...@@ -191,6 +191,13 @@ pub const RunStep = struct {...@@ -191,6 +191,13 @@ pub const RunStep = struct {
191 child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);191 child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);
192 child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);192 child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);
193193
194 if (self.builder.verbose) {
195 for (argv) |arg| {
196 warn("{s} ", .{arg});
197 }
198 warn("\n", .{});
199 }
200
194 child.spawn() catch |err| {201 child.spawn() catch |err| {
195 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });202 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
196 return err;203 return err;
lib/std/builtin.zig+1-1
...@@ -166,7 +166,7 @@ pub const CallingConvention = enum {...@@ -166,7 +166,7 @@ pub const CallingConvention = enum {
166 APCS,166 APCS,
167 AAPCS,167 AAPCS,
168 AAPCSVFP,168 AAPCSVFP,
169 SysV169 SysV,
170};170};
171171
172/// This data structure is used by the Zig language code generation and172/// This data structure is used by the Zig language code generation and
lib/std/c.zig-2
...@@ -10,8 +10,6 @@ const page_size = std.mem.page_size;...@@ -10,8 +10,6 @@ const page_size = std.mem.page_size;
10pub const tokenizer = @import("c/tokenizer.zig");10pub const tokenizer = @import("c/tokenizer.zig");
11pub const Token = tokenizer.Token;11pub const Token = tokenizer.Token;
12pub const Tokenizer = tokenizer.Tokenizer;12pub const Tokenizer = tokenizer.Tokenizer;
13pub const parse = @import("c/parse.zig").parse;
14pub const ast = @import("c/ast.zig");
15pub const builtins = @import("c/builtins.zig");13pub const builtins = @import("c/builtins.zig");
1614
17test {15test {
lib/std/c/ast.zig deleted-678
...@@ -1,678 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7const ArrayList = std.ArrayList;
8const Token = std.c.Token;
9const Source = std.c.tokenizer.Source;
10
11pub const TokenIndex = usize;
12
13pub const Tree = struct {
14 tokens: []Token,
15 sources: []Source,
16 root_node: *Node.Root,
17 arena_state: std.heap.ArenaAllocator.State,
18 gpa: *mem.Allocator,
19 msgs: []Msg,
20
21 pub fn deinit(self: *Tree) void {
22 self.arena_state.promote(self.gpa).deinit();
23 }
24
25 pub fn tokenSlice(tree: *Tree, token: TokenIndex) []const u8 {
26 return tree.tokens.at(token).slice();
27 }
28
29 pub fn tokenEql(tree: *Tree, a: TokenIndex, b: TokenIndex) bool {
30 const atok = tree.tokens.at(a);
31 const btok = tree.tokens.at(b);
32 return atok.eql(btok.*);
33 }
34};
35
36pub const Msg = struct {
37 kind: enum {
38 Error,
39 Warning,
40 Note,
41 },
42 inner: Error,
43};
44
45pub const Error = union(enum) {
46 InvalidToken: SingleTokenError("invalid token '{}'"),
47 ExpectedToken: ExpectedToken,
48 ExpectedExpr: SingleTokenError("expected expression, found '{}'"),
49 ExpectedTypeName: SingleTokenError("expected type name, found '{}'"),
50 ExpectedFnBody: SingleTokenError("expected function body, found '{}'"),
51 ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"),
52 ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"),
53 ExpectedEnumField: SingleTokenError("expected enum field, found '{}'"),
54 ExpectedType: SingleTokenError("expected enum field, found '{}'"),
55 InvalidTypeSpecifier: InvalidTypeSpecifier,
56 InvalidStorageClass: SingleTokenError("invalid storage class, found '{}'"),
57 InvalidDeclarator: SimpleError("invalid declarator"),
58 DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"),
59 DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"),
60 MustUseKwToRefer: MustUseKwToRefer,
61 FnSpecOnNonFn: SingleTokenError("function specifier '{}' on non function"),
62 NothingDeclared: SimpleError("declaration doesn't declare anything"),
63 QualifierIgnored: SingleTokenError("qualifier '{}' ignored"),
64
65 pub fn render(self: *const Error, tree: *Tree, stream: anytype) !void {
66 switch (self.*) {
67 .InvalidToken => |*x| return x.render(tree, stream),
68 .ExpectedToken => |*x| return x.render(tree, stream),
69 .ExpectedExpr => |*x| return x.render(tree, stream),
70 .ExpectedTypeName => |*x| return x.render(tree, stream),
71 .ExpectedDeclarator => |*x| return x.render(tree, stream),
72 .ExpectedFnBody => |*x| return x.render(tree, stream),
73 .ExpectedInitializer => |*x| return x.render(tree, stream),
74 .ExpectedEnumField => |*x| return x.render(tree, stream),
75 .ExpectedType => |*x| return x.render(tree, stream),
76 .InvalidTypeSpecifier => |*x| return x.render(tree, stream),
77 .InvalidStorageClass => |*x| return x.render(tree, stream),
78 .InvalidDeclarator => |*x| return x.render(tree, stream),
79 .DuplicateQualifier => |*x| return x.render(tree, stream),
80 .DuplicateSpecifier => |*x| return x.render(tree, stream),
81 .MustUseKwToRefer => |*x| return x.render(tree, stream),
82 .FnSpecOnNonFn => |*x| return x.render(tree, stream),
83 .NothingDeclared => |*x| return x.render(tree, stream),
84 .QualifierIgnored => |*x| return x.render(tree, stream),
85 }
86 }
87
88 pub fn loc(self: *const Error) TokenIndex {
89 switch (self.*) {
90 .InvalidToken => |x| return x.token,
91 .ExpectedToken => |x| return x.token,
92 .ExpectedExpr => |x| return x.token,
93 .ExpectedTypeName => |x| return x.token,
94 .ExpectedDeclarator => |x| return x.token,
95 .ExpectedFnBody => |x| return x.token,
96 .ExpectedInitializer => |x| return x.token,
97 .ExpectedEnumField => |x| return x.token,
98 .ExpectedType => |*x| return x.token,
99 .InvalidTypeSpecifier => |x| return x.token,
100 .InvalidStorageClass => |x| return x.token,
101 .InvalidDeclarator => |x| return x.token,
102 .DuplicateQualifier => |x| return x.token,
103 .DuplicateSpecifier => |x| return x.token,
104 .MustUseKwToRefer => |*x| return x.name,
105 .FnSpecOnNonFn => |*x| return x.name,
106 .NothingDeclared => |*x| return x.name,
107 .QualifierIgnored => |*x| return x.name,
108 }
109 }
110
111 pub const ExpectedToken = struct {
112 token: TokenIndex,
113 expected_id: std.meta.Tag(Token.Id),
114
115 pub fn render(self: *const ExpectedToken, tree: *Tree, stream: anytype) !void {
116 const found_token = tree.tokens.at(self.token);
117 if (found_token.id == .Invalid) {
118 return stream.print("expected '{s}', found invalid bytes", .{self.expected_id.symbol()});
119 } else {
120 const token_name = found_token.id.symbol();
121 return stream.print("expected '{s}', found '{s}'", .{ self.expected_id.symbol(), token_name });
122 }
123 }
124 };
125
126 pub const InvalidTypeSpecifier = struct {
127 token: TokenIndex,
128 type_spec: *Node.TypeSpec,
129
130 pub fn render(self: *const ExpectedToken, tree: *Tree, stream: anytype) !void {
131 try stream.write("invalid type specifier '");
132 try type_spec.spec.print(tree, stream);
133 const token_name = tree.tokens.at(self.token).id.symbol();
134 return stream.print("{s}'", .{token_name});
135 }
136 };
137
138 pub const MustUseKwToRefer = struct {
139 kw: TokenIndex,
140 name: TokenIndex,
141
142 pub fn render(self: *const ExpectedToken, tree: *Tree, stream: anytype) !void {
143 return stream.print("must use '{s}' tag to refer to type '{s}'", .{ tree.slice(kw), tree.slice(name) });
144 }
145 };
146
147 fn SingleTokenError(comptime msg: []const u8) type {
148 return struct {
149 token: TokenIndex,
150
151 pub fn render(self: *const @This(), tree: *Tree, stream: anytype) !void {
152 const actual_token = tree.tokens.at(self.token);
153 return stream.print(msg, .{actual_token.id.symbol()});
154 }
155 };
156 }
157
158 fn SimpleError(comptime msg: []const u8) type {
159 return struct {
160 const ThisError = @This();
161
162 token: TokenIndex,
163
164 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: anytype) !void {
165 return stream.write(msg);
166 }
167 };
168 }
169};
170
171pub const Type = struct {
172 pub const TypeList = ArrayList(*Type);
173
174 @"const": bool = false,
175 atomic: bool = false,
176 @"volatile": bool = false,
177 restrict: bool = false,
178
179 id: union(enum) {
180 Int: struct {
181 id: Id,
182 is_signed: bool,
183
184 pub const Id = enum {
185 Char,
186 Short,
187 Int,
188 Long,
189 LongLong,
190 };
191 },
192 Float: struct {
193 id: Id,
194
195 pub const Id = enum {
196 Float,
197 Double,
198 LongDouble,
199 };
200 },
201 Pointer: *Type,
202 Function: struct {
203 return_type: *Type,
204 param_types: TypeList,
205 },
206 Typedef: *Type,
207 Record: *Node.RecordType,
208 Enum: *Node.EnumType,
209
210 /// Special case for macro parameters that can be any type.
211 /// Only present if `retain_macros == true`.
212 Macro,
213 },
214};
215
216pub const Node = struct {
217 id: Id,
218
219 pub const Id = enum {
220 Root,
221 EnumField,
222 RecordField,
223 RecordDeclarator,
224 JumpStmt,
225 ExprStmt,
226 LabeledStmt,
227 CompoundStmt,
228 IfStmt,
229 SwitchStmt,
230 WhileStmt,
231 DoStmt,
232 ForStmt,
233 StaticAssert,
234 Declarator,
235 Pointer,
236 FnDecl,
237 Typedef,
238 VarDecl,
239 };
240
241 pub const Root = struct {
242 base: Node = Node{ .id = .Root },
243 decls: DeclList,
244 eof: TokenIndex,
245
246 pub const DeclList = ArrayList(*Node);
247 };
248
249 pub const DeclSpec = struct {
250 storage_class: union(enum) {
251 Auto: TokenIndex,
252 Extern: TokenIndex,
253 Register: TokenIndex,
254 Static: TokenIndex,
255 Typedef: TokenIndex,
256 None,
257 } = .None,
258 thread_local: ?TokenIndex = null,
259 type_spec: TypeSpec = TypeSpec{},
260 fn_spec: union(enum) {
261 Inline: TokenIndex,
262 Noreturn: TokenIndex,
263 None,
264 } = .None,
265 align_spec: ?struct {
266 alignas: TokenIndex,
267 expr: *Node,
268 rparen: TokenIndex,
269 } = null,
270 };
271
272 pub const TypeSpec = struct {
273 qual: TypeQual = TypeQual{},
274 spec: union(enum) {
275 /// error or default to int
276 None,
277 Void: TokenIndex,
278 Char: struct {
279 sign: ?TokenIndex = null,
280 char: TokenIndex,
281 },
282 Short: struct {
283 sign: ?TokenIndex = null,
284 short: TokenIndex = null,
285 int: ?TokenIndex = null,
286 },
287 Int: struct {
288 sign: ?TokenIndex = null,
289 int: ?TokenIndex = null,
290 },
291 Long: struct {
292 sign: ?TokenIndex = null,
293 long: TokenIndex,
294 longlong: ?TokenIndex = null,
295 int: ?TokenIndex = null,
296 },
297 Float: struct {
298 float: TokenIndex,
299 complex: ?TokenIndex = null,
300 },
301 Double: struct {
302 long: ?TokenIndex = null,
303 double: ?TokenIndex,
304 complex: ?TokenIndex = null,
305 },
306 Bool: TokenIndex,
307 Atomic: struct {
308 atomic: TokenIndex,
309 typename: *Node,
310 rparen: TokenIndex,
311 },
312 Enum: *EnumType,
313 Record: *RecordType,
314 Typedef: struct {
315 sym: TokenIndex,
316 sym_type: *Type,
317 },
318
319 pub fn print(self: *@This(), self: *const @This(), tree: *Tree, stream: anytype) !void {
320 switch (self.spec) {
321 .None => unreachable,
322 .Void => |index| try stream.write(tree.slice(index)),
323 .Char => |char| {
324 if (char.sign) |s| {
325 try stream.write(tree.slice(s));
326 try stream.writeByte(' ');
327 }
328 try stream.write(tree.slice(char.char));
329 },
330 .Short => |short| {
331 if (short.sign) |s| {
332 try stream.write(tree.slice(s));
333 try stream.writeByte(' ');
334 }
335 try stream.write(tree.slice(short.short));
336 if (short.int) |i| {
337 try stream.writeByte(' ');
338 try stream.write(tree.slice(i));
339 }
340 },
341 .Int => |int| {
342 if (int.sign) |s| {
343 try stream.write(tree.slice(s));
344 try stream.writeByte(' ');
345 }
346 if (int.int) |i| {
347 try stream.writeByte(' ');
348 try stream.write(tree.slice(i));
349 }
350 },
351 .Long => |long| {
352 if (long.sign) |s| {
353 try stream.write(tree.slice(s));
354 try stream.writeByte(' ');
355 }
356 try stream.write(tree.slice(long.long));
357 if (long.longlong) |l| {
358 try stream.writeByte(' ');
359 try stream.write(tree.slice(l));
360 }
361 if (long.int) |i| {
362 try stream.writeByte(' ');
363 try stream.write(tree.slice(i));
364 }
365 },
366 .Float => |float| {
367 try stream.write(tree.slice(float.float));
368 if (float.complex) |c| {
369 try stream.writeByte(' ');
370 try stream.write(tree.slice(c));
371 }
372 },
373 .Double => |double| {
374 if (double.long) |l| {
375 try stream.write(tree.slice(l));
376 try stream.writeByte(' ');
377 }
378 try stream.write(tree.slice(double.double));
379 if (double.complex) |c| {
380 try stream.writeByte(' ');
381 try stream.write(tree.slice(c));
382 }
383 },
384 .Bool => |index| try stream.write(tree.slice(index)),
385 .Typedef => |typedef| try stream.write(tree.slice(typedef.sym)),
386 else => try stream.print("TODO print {}", self.spec),
387 }
388 }
389 } = .None,
390 };
391
392 pub const EnumType = struct {
393 tok: TokenIndex,
394 name: ?TokenIndex,
395 body: ?struct {
396 lbrace: TokenIndex,
397
398 /// always EnumField
399 fields: FieldList,
400 rbrace: TokenIndex,
401 },
402
403 pub const FieldList = Root.DeclList;
404 };
405
406 pub const EnumField = struct {
407 base: Node = Node{ .id = .EnumField },
408 name: TokenIndex,
409 value: ?*Node,
410 };
411
412 pub const RecordType = struct {
413 tok: TokenIndex,
414 kind: enum {
415 Struct,
416 Union,
417 },
418 name: ?TokenIndex,
419 body: ?struct {
420 lbrace: TokenIndex,
421
422 /// RecordField or StaticAssert
423 fields: FieldList,
424 rbrace: TokenIndex,
425 },
426
427 pub const FieldList = Root.DeclList;
428 };
429
430 pub const RecordField = struct {
431 base: Node = Node{ .id = .RecordField },
432 type_spec: TypeSpec,
433 declarators: DeclaratorList,
434 semicolon: TokenIndex,
435
436 pub const DeclaratorList = Root.DeclList;
437 };
438
439 pub const RecordDeclarator = struct {
440 base: Node = Node{ .id = .RecordDeclarator },
441 declarator: ?*Declarator,
442 bit_field_expr: ?*Expr,
443 };
444
445 pub const TypeQual = struct {
446 @"const": ?TokenIndex = null,
447 atomic: ?TokenIndex = null,
448 @"volatile": ?TokenIndex = null,
449 restrict: ?TokenIndex = null,
450 };
451
452 pub const JumpStmt = struct {
453 base: Node = Node{ .id = .JumpStmt },
454 ltoken: TokenIndex,
455 kind: union(enum) {
456 Break,
457 Continue,
458 Return: ?*Node,
459 Goto: TokenIndex,
460 },
461 semicolon: TokenIndex,
462 };
463
464 pub const ExprStmt = struct {
465 base: Node = Node{ .id = .ExprStmt },
466 expr: ?*Expr,
467 semicolon: TokenIndex,
468 };
469
470 pub const LabeledStmt = struct {
471 base: Node = Node{ .id = .LabeledStmt },
472 kind: union(enum) {
473 Label: TokenIndex,
474 Case: TokenIndex,
475 Default: TokenIndex,
476 },
477 stmt: *Node,
478 };
479
480 pub const CompoundStmt = struct {
481 base: Node = Node{ .id = .CompoundStmt },
482 lbrace: TokenIndex,
483 statements: StmtList,
484 rbrace: TokenIndex,
485
486 pub const StmtList = Root.DeclList;
487 };
488
489 pub const IfStmt = struct {
490 base: Node = Node{ .id = .IfStmt },
491 @"if": TokenIndex,
492 cond: *Node,
493 body: *Node,
494 @"else": ?struct {
495 tok: TokenIndex,
496 body: *Node,
497 },
498 };
499
500 pub const SwitchStmt = struct {
501 base: Node = Node{ .id = .SwitchStmt },
502 @"switch": TokenIndex,
503 expr: *Expr,
504 rparen: TokenIndex,
505 stmt: *Node,
506 };
507
508 pub const WhileStmt = struct {
509 base: Node = Node{ .id = .WhileStmt },
510 @"while": TokenIndex,
511 cond: *Expr,
512 rparen: TokenIndex,
513 body: *Node,
514 };
515
516 pub const DoStmt = struct {
517 base: Node = Node{ .id = .DoStmt },
518 do: TokenIndex,
519 body: *Node,
520 @"while": TokenIndex,
521 cond: *Expr,
522 semicolon: TokenIndex,
523 };
524
525 pub const ForStmt = struct {
526 base: Node = Node{ .id = .ForStmt },
527 @"for": TokenIndex,
528 init: ?*Node,
529 cond: ?*Expr,
530 semicolon: TokenIndex,
531 incr: ?*Expr,
532 rparen: TokenIndex,
533 body: *Node,
534 };
535
536 pub const StaticAssert = struct {
537 base: Node = Node{ .id = .StaticAssert },
538 assert: TokenIndex,
539 expr: *Node,
540 semicolon: TokenIndex,
541 };
542
543 pub const Declarator = struct {
544 base: Node = Node{ .id = .Declarator },
545 pointer: ?*Pointer,
546 prefix: union(enum) {
547 None,
548 Identifer: TokenIndex,
549 Complex: struct {
550 lparen: TokenIndex,
551 inner: *Node,
552 rparen: TokenIndex,
553 },
554 },
555 suffix: union(enum) {
556 None,
557 Fn: struct {
558 lparen: TokenIndex,
559 params: Params,
560 rparen: TokenIndex,
561 },
562 Array: Arrays,
563 },
564
565 pub const Arrays = ArrayList(*Array);
566 pub const Params = ArrayList(*Param);
567 };
568
569 pub const Array = struct {
570 lbracket: TokenIndex,
571 inner: union(enum) {
572 Inferred,
573 Unspecified: TokenIndex,
574 Variable: struct {
575 asterisk: ?TokenIndex,
576 static: ?TokenIndex,
577 qual: TypeQual,
578 expr: *Expr,
579 },
580 },
581 rbracket: TokenIndex,
582 };
583
584 pub const Pointer = struct {
585 base: Node = Node{ .id = .Pointer },
586 asterisk: TokenIndex,
587 qual: TypeQual,
588 pointer: ?*Pointer,
589 };
590
591 pub const Param = struct {
592 kind: union(enum) {
593 Variable,
594 Old: TokenIndex,
595 Normal: struct {
596 decl_spec: *DeclSpec,
597 declarator: *Node,
598 },
599 },
600 };
601
602 pub const FnDecl = struct {
603 base: Node = Node{ .id = .FnDecl },
604 decl_spec: DeclSpec,
605 declarator: *Declarator,
606 old_decls: OldDeclList,
607 body: ?*CompoundStmt,
608
609 pub const OldDeclList = ArrayList(*Node);
610 };
611
612 pub const Typedef = struct {
613 base: Node = Node{ .id = .Typedef },
614 decl_spec: DeclSpec,
615 declarators: DeclaratorList,
616 semicolon: TokenIndex,
617
618 pub const DeclaratorList = Root.DeclList;
619 };
620
621 pub const VarDecl = struct {
622 base: Node = Node{ .id = .VarDecl },
623 decl_spec: DeclSpec,
624 initializers: Initializers,
625 semicolon: TokenIndex,
626
627 pub const Initializers = Root.DeclList;
628 };
629
630 pub const Initialized = struct {
631 base: Node = Node{ .id = Initialized },
632 declarator: *Declarator,
633 eq: TokenIndex,
634 init: Initializer,
635 };
636
637 pub const Initializer = union(enum) {
638 list: struct {
639 initializers: List,
640 rbrace: TokenIndex,
641 },
642 expr: *Expr,
643
644 pub const List = ArrayList(*Initializer);
645 };
646
647 pub const Macro = struct {
648 base: Node = Node{ .id = Macro },
649 kind: union(enum) {
650 Undef: []const u8,
651 Fn: struct {
652 params: []const []const u8,
653 expr: *Expr,
654 },
655 Expr: *Expr,
656 },
657 };
658};
659
660pub const Expr = struct {
661 id: Id,
662 ty: *Type,
663 value: union(enum) {
664 None,
665 },
666
667 pub const Id = enum {
668 Infix,
669 Literal,
670 };
671
672 pub const Infix = struct {
673 base: Expr = Expr{ .id = .Infix },
674 lhs: *Expr,
675 op_token: TokenIndex,
676 rhs: *Expr,
677 };
678};
lib/std/c/parse.zig deleted-1434
...@@ -1,1434 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7const mem = std.mem;
8const assert = std.debug.assert;
9const Allocator = std.mem.Allocator;
10const ast = std.c.ast;
11const Node = ast.Node;
12const Type = ast.Type;
13const Tree = ast.Tree;
14const TokenIndex = ast.TokenIndex;
15const Token = std.c.Token;
16const TokenIterator = ast.Tree.TokenList.Iterator;
17
18pub const Error = error{ParseError} || Allocator.Error;
19
20pub const Options = struct {
21 // /// Keep simple macros unexpanded and add the definitions to the ast
22 // retain_macros: bool = false,
23 /// Warning or error
24 warn_as_err: union(enum) {
25 /// All warnings are warnings
26 None,
27
28 /// Some warnings are errors
29 Some: []std.meta.Tag(ast.Error),
30
31 /// All warnings are errors
32 All,
33 } = .All,
34};
35
36/// Result should be freed with tree.deinit() when there are
37/// no more references to any of the tokens or nodes.
38pub fn parse(allocator: *Allocator, source: []const u8, options: Options) !*Tree {
39 const tree = blk: {
40 // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists
41 // from being initialized with a pointer to this `arena`, which is created on
42 // the stack. Following code should instead refer to `&tree.arena_allocator`, a
43 // pointer to data which lives safely on the heap and will outlive `parse`.
44 var arena = std.heap.ArenaAllocator.init(allocator);
45 errdefer arena.deinit();
46 const tree = try arena.allocator.create(ast.Tree);
47 tree.* = .{
48 .root_node = undefined,
49 .arena_allocator = arena,
50 .tokens = undefined,
51 .sources = undefined,
52 };
53 break :blk tree;
54 };
55 errdefer tree.deinit();
56 const arena = &tree.arena_allocator.allocator;
57
58 tree.tokens = ast.Tree.TokenList.init(arena);
59 tree.sources = ast.Tree.SourceList.init(arena);
60
61 var tokenizer = std.zig.Tokenizer.init(source);
62 while (true) {
63 const tree_token = try tree.tokens.addOne();
64 tree_token.* = tokenizer.next();
65 if (tree_token.id == .Eof) break;
66 }
67 // TODO preprocess here
68 var it = tree.tokens.iterator(0);
69
70 while (true) {
71 const tok = it.peek().?.id;
72 switch (id) {
73 .LineComment,
74 .MultiLineComment,
75 => {
76 _ = it.next();
77 },
78 else => break,
79 }
80 }
81
82 var parse_arena = std.heap.ArenaAllocator.init(allocator);
83 defer parse_arena.deinit();
84
85 var parser = Parser{
86 .scopes = Parser.SymbolList.init(allocator),
87 .arena = &parse_arena.allocator,
88 .it = &it,
89 .tree = tree,
90 .options = options,
91 };
92 defer parser.symbols.deinit();
93
94 tree.root_node = try parser.root();
95 return tree;
96}
97
98const Parser = struct {
99 arena: *Allocator,
100 it: *TokenIterator,
101 tree: *Tree,
102
103 arena: *Allocator,
104 scopes: ScopeList,
105 options: Options,
106
107 const ScopeList = std.SegmentedLists(Scope);
108 const SymbolList = std.SegmentedLists(Symbol);
109
110 const Scope = struct {
111 kind: ScopeKind,
112 syms: SymbolList,
113 };
114
115 const Symbol = struct {
116 name: []const u8,
117 ty: *Type,
118 };
119
120 const ScopeKind = enum {
121 Block,
122 Loop,
123 Root,
124 Switch,
125 };
126
127 fn pushScope(parser: *Parser, kind: ScopeKind) !void {
128 const new = try parser.scopes.addOne();
129 new.* = .{
130 .kind = kind,
131 .syms = SymbolList.init(parser.arena),
132 };
133 }
134
135 fn popScope(parser: *Parser, len: usize) void {
136 _ = parser.scopes.pop();
137 }
138
139 fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Symbol {
140 const name = parser.tree.tokenSlice(tok);
141 var scope_it = parser.scopes.iterator(parser.scopes.len);
142 while (scope_it.prev()) |scope| {
143 var sym_it = scope.syms.iterator(scope.syms.len);
144 while (sym_it.prev()) |sym| {
145 if (mem.eql(u8, sym.name, name)) {
146 return sym;
147 }
148 }
149 }
150 return null;
151 }
152
153 fn declareSymbol(parser: *Parser, type_spec: Node.TypeSpec, dr: *Node.Declarator) Error!void {
154 return; // TODO
155 }
156
157 /// Root <- ExternalDeclaration* eof
158 fn root(parser: *Parser) Allocator.Error!*Node.Root {
159 try parser.pushScope(.Root);
160 defer parser.popScope();
161 const node = try parser.arena.create(Node.Root);
162 node.* = .{
163 .decls = Node.Root.DeclList.init(parser.arena),
164 .eof = undefined,
165 };
166 while (parser.externalDeclarations() catch |e| switch (e) {
167 error.OutOfMemory => return error.OutOfMemory,
168 error.ParseError => return node,
169 }) |decl| {
170 try node.decls.push(decl);
171 }
172 node.eof = parser.eatToken(.Eof) orelse return node;
173 return node;
174 }
175
176 /// ExternalDeclaration
177 /// <- DeclSpec Declarator OldStyleDecl* CompoundStmt
178 /// / Declaration
179 /// OldStyleDecl <- DeclSpec Declarator (COMMA Declarator)* SEMICOLON
180 fn externalDeclarations(parser: *Parser) !?*Node {
181 return parser.declarationExtra(false);
182 }
183
184 /// Declaration
185 /// <- DeclSpec DeclInit SEMICOLON
186 /// / StaticAssert
187 /// DeclInit <- Declarator (EQUAL Initializer)? (COMMA Declarator (EQUAL Initializer)?)*
188 fn declaration(parser: *Parser) !?*Node {
189 return parser.declarationExtra(true);
190 }
191
192 fn declarationExtra(parser: *Parser, local: bool) !?*Node {
193 if (try parser.staticAssert()) |decl| return decl;
194 const begin = parser.it.index + 1;
195 var ds = Node.DeclSpec{};
196 const got_ds = try parser.declSpec(&ds);
197 if (local and !got_ds) {
198 // not a declaration
199 return null;
200 }
201 switch (ds.storage_class) {
202 .Auto, .Register => |tok| return parser.err(.{
203 .InvalidStorageClass = .{ .token = tok },
204 }),
205 .Typedef => {
206 const node = try parser.arena.create(Node.Typedef);
207 node.* = .{
208 .decl_spec = ds,
209 .declarators = Node.Typedef.DeclaratorList.init(parser.arena),
210 .semicolon = undefined,
211 };
212 while (true) {
213 const dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
214 .ExpectedDeclarator = .{ .token = parser.it.index },
215 }));
216 try parser.declareSymbol(ds.type_spec, dr);
217 try node.declarators.push(&dr.base);
218 if (parser.eatToken(.Comma)) |_| {} else break;
219 }
220 return &node.base;
221 },
222 else => {},
223 }
224 var first_dr = try parser.declarator(.Must);
225 if (first_dr != null and declaratorIsFunction(first_dr.?)) {
226 // TODO typedeffed fn proto-only
227 const dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
228 try parser.declareSymbol(ds.type_spec, dr);
229 var old_decls = Node.FnDecl.OldDeclList.init(parser.arena);
230 const body = if (parser.eatToken(.Semicolon)) |_|
231 null
232 else blk: {
233 if (local) {
234 // TODO nested function warning
235 }
236 // TODO first_dr.is_old
237 // while (true) {
238 // var old_ds = Node.DeclSpec{};
239 // if (!(try parser.declSpec(&old_ds))) {
240 // // not old decl
241 // break;
242 // }
243 // var old_dr = (try parser.declarator(.Must));
244 // // if (old_dr == null)
245 // // try parser.err(.{
246 // // .NoParamName = .{ .token = parser.it.index },
247 // // });
248 // // try old_decls.push(decl);
249 // }
250 const body_node = (try parser.compoundStmt()) orelse return parser.err(.{
251 .ExpectedFnBody = .{ .token = parser.it.index },
252 });
253 break :blk @fieldParentPtr(Node.CompoundStmt, "base", body_node);
254 };
255
256 const node = try parser.arena.create(Node.FnDecl);
257 node.* = .{
258 .decl_spec = ds,
259 .declarator = dr,
260 .old_decls = old_decls,
261 .body = body,
262 };
263 return &node.base;
264 } else {
265 switch (ds.fn_spec) {
266 .Inline, .Noreturn => |tok| return parser.err(.{
267 .FnSpecOnNonFn = .{ .token = tok },
268 }),
269 else => {},
270 }
271 // TODO threadlocal without static or extern on local variable
272 const node = try parser.arena.create(Node.VarDecl);
273 node.* = .{
274 .decl_spec = ds,
275 .initializers = Node.VarDecl.Initializers.init(parser.arena),
276 .semicolon = undefined,
277 };
278 if (first_dr == null) {
279 node.semicolon = try parser.expectToken(.Semicolon);
280 const ok = switch (ds.type_spec.spec) {
281 .Enum => |e| e.name != null,
282 .Record => |r| r.name != null,
283 else => false,
284 };
285 const q = ds.type_spec.qual;
286 if (!ok)
287 try parser.warn(.{
288 .NothingDeclared = .{ .token = begin },
289 })
290 else if (q.@"const" orelse q.atomic orelse q.@"volatile" orelse q.restrict) |tok|
291 try parser.warn(.{
292 .QualifierIgnored = .{ .token = tok },
293 });
294 return &node.base;
295 }
296 var dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
297 while (true) {
298 try parser.declareSymbol(ds.type_spec, dr);
299 if (parser.eatToken(.Equal)) |tok| {
300 try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{
301 .ExpectedInitializer = .{ .token = parser.it.index },
302 }));
303 } else try node.initializers.push(&dr.base);
304 if (parser.eatToken(.Comma) != null) break;
305 dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
306 .ExpectedDeclarator = .{ .token = parser.it.index },
307 }));
308 }
309 node.semicolon = try parser.expectToken(.Semicolon);
310 return &node.base;
311 }
312 }
313
314 fn declaratorIsFunction(node: *Node) bool {
315 if (node.id != .Declarator) return false;
316 assert(node.id == .Declarator);
317 const dr = @fieldParentPtr(Node.Declarator, "base", node);
318 if (dr.suffix != .Fn) return false;
319 switch (dr.prefix) {
320 .None, .Identifer => return true,
321 .Complex => |inner| {
322 var inner_node = inner.inner;
323 while (true) {
324 if (inner_node.id != .Declarator) return false;
325 assert(inner_node.id == .Declarator);
326 const inner_dr = @fieldParentPtr(Node.Declarator, "base", inner_node);
327 if (inner_dr.pointer != null) return false;
328 switch (inner_dr.prefix) {
329 .None, .Identifer => return true,
330 .Complex => |c| inner_node = c.inner,
331 }
332 }
333 },
334 }
335 }
336
337 /// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON
338 fn staticAssert(parser: *Parser) !?*Node {
339 const tok = parser.eatToken(.Keyword_static_assert) orelse return null;
340 _ = try parser.expectToken(.LParen);
341 const const_expr = (try parser.constExpr()) orelse parser.err(.{
342 .ExpectedExpr = .{ .token = parser.it.index },
343 });
344 _ = try parser.expectToken(.Comma);
345 const str = try parser.expectToken(.StringLiteral);
346 _ = try parser.expectToken(.RParen);
347 const node = try parser.arena.create(Node.StaticAssert);
348 node.* = .{
349 .assert = tok,
350 .expr = const_expr,
351 .semicolon = try parser.expectToken(.Semicolon),
352 };
353 return &node.base;
354 }
355
356 /// DeclSpec <- (StorageClassSpec / TypeSpec / FnSpec / AlignSpec)*
357 /// returns true if any tokens were consumed
358 fn declSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
359 var got = false;
360 while ((try parser.storageClassSpec(ds)) or (try parser.typeSpec(&ds.type_spec)) or (try parser.fnSpec(ds)) or (try parser.alignSpec(ds))) {
361 got = true;
362 }
363 return got;
364 }
365
366 /// StorageClassSpec
367 /// <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register
368 fn storageClassSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
369 blk: {
370 if (parser.eatToken(.Keyword_typedef)) |tok| {
371 if (ds.storage_class != .None or ds.thread_local != null)
372 break :blk;
373 ds.storage_class = .{ .Typedef = tok };
374 } else if (parser.eatToken(.Keyword_extern)) |tok| {
375 if (ds.storage_class != .None)
376 break :blk;
377 ds.storage_class = .{ .Extern = tok };
378 } else if (parser.eatToken(.Keyword_static)) |tok| {
379 if (ds.storage_class != .None)
380 break :blk;
381 ds.storage_class = .{ .Static = tok };
382 } else if (parser.eatToken(.Keyword_thread_local)) |tok| {
383 switch (ds.storage_class) {
384 .None, .Extern, .Static => {},
385 else => break :blk,
386 }
387 ds.thread_local = tok;
388 } else if (parser.eatToken(.Keyword_auto)) |tok| {
389 if (ds.storage_class != .None or ds.thread_local != null)
390 break :blk;
391 ds.storage_class = .{ .Auto = tok };
392 } else if (parser.eatToken(.Keyword_register)) |tok| {
393 if (ds.storage_class != .None or ds.thread_local != null)
394 break :blk;
395 ds.storage_class = .{ .Register = tok };
396 } else return false;
397 return true;
398 }
399 try parser.warn(.{
400 .DuplicateSpecifier = .{ .token = parser.it.index },
401 });
402 return true;
403 }
404
405 /// TypeSpec
406 /// <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double
407 /// / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary /
408 /// / Keyword_atomic LPAREN TypeName RPAREN
409 /// / EnumSpec
410 /// / RecordSpec
411 /// / IDENTIFIER // typedef name
412 /// / TypeQual
413 fn typeSpec(parser: *Parser, type_spec: *Node.TypeSpec) !bool {
414 blk: {
415 if (parser.eatToken(.Keyword_void)) |tok| {
416 if (type_spec.spec != .None)
417 break :blk;
418 type_spec.spec = .{ .Void = tok };
419 } else if (parser.eatToken(.Keyword_char)) |tok| {
420 switch (type_spec.spec) {
421 .None => {
422 type_spec.spec = .{
423 .Char = .{
424 .char = tok,
425 },
426 };
427 },
428 .Int => |int| {
429 if (int.int != null)
430 break :blk;
431 type_spec.spec = .{
432 .Char = .{
433 .char = tok,
434 .sign = int.sign,
435 },
436 };
437 },
438 else => break :blk,
439 }
440 } else if (parser.eatToken(.Keyword_short)) |tok| {
441 switch (type_spec.spec) {
442 .None => {
443 type_spec.spec = .{
444 .Short = .{
445 .short = tok,
446 },
447 };
448 },
449 .Int => |int| {
450 if (int.int != null)
451 break :blk;
452 type_spec.spec = .{
453 .Short = .{
454 .short = tok,
455 .sign = int.sign,
456 },
457 };
458 },
459 else => break :blk,
460 }
461 } else if (parser.eatToken(.Keyword_long)) |tok| {
462 switch (type_spec.spec) {
463 .None => {
464 type_spec.spec = .{
465 .Long = .{
466 .long = tok,
467 },
468 };
469 },
470 .Int => |int| {
471 type_spec.spec = .{
472 .Long = .{
473 .long = tok,
474 .sign = int.sign,
475 .int = int.int,
476 },
477 };
478 },
479 .Long => |*long| {
480 if (long.longlong != null)
481 break :blk;
482 long.longlong = tok;
483 },
484 .Double => |*double| {
485 if (double.long != null)
486 break :blk;
487 double.long = tok;
488 },
489 else => break :blk,
490 }
491 } else if (parser.eatToken(.Keyword_int)) |tok| {
492 switch (type_spec.spec) {
493 .None => {
494 type_spec.spec = .{
495 .Int = .{
496 .int = tok,
497 },
498 };
499 },
500 .Short => |*short| {
501 if (short.int != null)
502 break :blk;
503 short.int = tok;
504 },
505 .Int => |*int| {
506 if (int.int != null)
507 break :blk;
508 int.int = tok;
509 },
510 .Long => |*long| {
511 if (long.int != null)
512 break :blk;
513 long.int = tok;
514 },
515 else => break :blk,
516 }
517 } else if (parser.eatToken(.Keyword_signed) orelse parser.eatToken(.Keyword_unsigned)) |tok| {
518 switch (type_spec.spec) {
519 .None => {
520 type_spec.spec = .{
521 .Int = .{
522 .sign = tok,
523 },
524 };
525 },
526 .Char => |*char| {
527 if (char.sign != null)
528 break :blk;
529 char.sign = tok;
530 },
531 .Short => |*short| {
532 if (short.sign != null)
533 break :blk;
534 short.sign = tok;
535 },
536 .Int => |*int| {
537 if (int.sign != null)
538 break :blk;
539 int.sign = tok;
540 },
541 .Long => |*long| {
542 if (long.sign != null)
543 break :blk;
544 long.sign = tok;
545 },
546 else => break :blk,
547 }
548 } else if (parser.eatToken(.Keyword_float)) |tok| {
549 if (type_spec.spec != .None)
550 break :blk;
551 type_spec.spec = .{
552 .Float = .{
553 .float = tok,
554 },
555 };
556 } else if (parser.eatToken(.Keyword_double)) |tok| {
557 if (type_spec.spec != .None)
558 break :blk;
559 type_spec.spec = .{
560 .Double = .{
561 .double = tok,
562 },
563 };
564 } else if (parser.eatToken(.Keyword_complex)) |tok| {
565 switch (type_spec.spec) {
566 .None => {
567 type_spec.spec = .{
568 .Double = .{
569 .complex = tok,
570 .double = null,
571 },
572 };
573 },
574 .Float => |*float| {
575 if (float.complex != null)
576 break :blk;
577 float.complex = tok;
578 },
579 .Double => |*double| {
580 if (double.complex != null)
581 break :blk;
582 double.complex = tok;
583 },
584 else => break :blk,
585 }
586 } else if (parser.eatToken(.Keyword_bool)) |tok| {
587 if (type_spec.spec != .None)
588 break :blk;
589 type_spec.spec = .{ .Bool = tok };
590 } else if (parser.eatToken(.Keyword_atomic)) |tok| {
591 // might be _Atomic qualifier
592 if (parser.eatToken(.LParen)) |_| {
593 if (type_spec.spec != .None)
594 break :blk;
595 const name = (try parser.typeName()) orelse return parser.err(.{
596 .ExpectedTypeName = .{ .token = parser.it.index },
597 });
598 type_spec.spec.Atomic = .{
599 .atomic = tok,
600 .typename = name,
601 .rparen = try parser.expectToken(.RParen),
602 };
603 } else {
604 parser.putBackToken(tok);
605 }
606 } else if (parser.eatToken(.Keyword_enum)) |tok| {
607 if (type_spec.spec != .None)
608 break :blk;
609 type_spec.spec.Enum = try parser.enumSpec(tok);
610 } else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| {
611 if (type_spec.spec != .None)
612 break :blk;
613 type_spec.spec.Record = try parser.recordSpec(tok);
614 } else if (parser.eatToken(.Identifier)) |tok| {
615 const ty = parser.getSymbol(tok) orelse {
616 parser.putBackToken(tok);
617 return false;
618 };
619 switch (ty.id) {
620 .Enum => |e| inner: {
621 if (e.name) |some|
622 if (!parser.tree.tokenEql(some, tok))
623 break :inner;
624 return parser.err(.{
625 .MustUseKwToRefer = .{ .kw = e.tok, .name = tok },
626 });
627 },
628 .Record => |r| inner: {
629 if (r.name) |some|
630 if (!parser.tree.tokenEql(some, tok))
631 break :inner;
632 return parser.err(.{
633 .MustUseKwToRefer = .{
634 .kw = r.tok,
635 .name = tok,
636 },
637 });
638 },
639 .Typedef => {
640 type_spec.spec = .{
641 .Typedef = .{
642 .sym = tok,
643 .sym_type = ty,
644 },
645 };
646 return true;
647 },
648 else => {},
649 }
650 parser.putBackToken(tok);
651 return false;
652 }
653 return parser.typeQual(&type_spec.qual);
654 }
655 return parser.err(.{
656 .InvalidTypeSpecifier = .{
657 .token = parser.it.index,
658 .type_spec = type_spec,
659 },
660 });
661 }
662
663 /// TypeQual <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic
664 fn typeQual(parser: *Parser, qual: *Node.TypeQual) !bool {
665 blk: {
666 if (parser.eatToken(.Keyword_const)) |tok| {
667 if (qual.@"const" != null)
668 break :blk;
669 qual.@"const" = tok;
670 } else if (parser.eatToken(.Keyword_restrict)) |tok| {
671 if (qual.atomic != null)
672 break :blk;
673 qual.atomic = tok;
674 } else if (parser.eatToken(.Keyword_volatile)) |tok| {
675 if (qual.@"volatile" != null)
676 break :blk;
677 qual.@"volatile" = tok;
678 } else if (parser.eatToken(.Keyword_atomic)) |tok| {
679 if (qual.atomic != null)
680 break :blk;
681 qual.atomic = tok;
682 } else return false;
683 return true;
684 }
685 try parser.warn(.{
686 .DuplicateQualifier = .{ .token = parser.it.index },
687 });
688 return true;
689 }
690
691 /// FnSpec <- Keyword_inline / Keyword_noreturn
692 fn fnSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
693 blk: {
694 if (parser.eatToken(.Keyword_inline)) |tok| {
695 if (ds.fn_spec != .None)
696 break :blk;
697 ds.fn_spec = .{ .Inline = tok };
698 } else if (parser.eatToken(.Keyword_noreturn)) |tok| {
699 if (ds.fn_spec != .None)
700 break :blk;
701 ds.fn_spec = .{ .Noreturn = tok };
702 } else return false;
703 return true;
704 }
705 try parser.warn(.{
706 .DuplicateSpecifier = .{ .token = parser.it.index },
707 });
708 return true;
709 }
710
711 /// AlignSpec <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN
712 fn alignSpec(parser: *Parser, ds: *Node.DeclSpec) !bool {
713 if (parser.eatToken(.Keyword_alignas)) |tok| {
714 _ = try parser.expectToken(.LParen);
715 const node = (try parser.typeName()) orelse (try parser.constExpr()) orelse parser.err(.{
716 .ExpectedExpr = .{ .token = parser.it.index },
717 });
718 if (ds.align_spec != null) {
719 try parser.warn(.{
720 .DuplicateSpecifier = .{ .token = parser.it.index },
721 });
722 }
723 ds.align_spec = .{
724 .alignas = tok,
725 .expr = node,
726 .rparen = try parser.expectToken(.RParen),
727 };
728 return true;
729 }
730 return false;
731 }
732
733 /// EnumSpec <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)?
734 fn enumSpec(parser: *Parser, tok: TokenIndex) !*Node.EnumType {
735 const node = try parser.arena.create(Node.EnumType);
736 const name = parser.eatToken(.Identifier);
737 node.* = .{
738 .tok = tok,
739 .name = name,
740 .body = null,
741 };
742 const ty = try parser.arena.create(Type);
743 ty.* = .{
744 .id = .{
745 .Enum = node,
746 },
747 };
748 if (name) |some|
749 try parser.symbols.append(.{
750 .name = parser.tree.tokenSlice(some),
751 .ty = ty,
752 });
753 if (parser.eatToken(.LBrace)) |lbrace| {
754 var fields = Node.EnumType.FieldList.init(parser.arena);
755 try fields.push((try parser.enumField()) orelse return parser.err(.{
756 .ExpectedEnumField = .{ .token = parser.it.index },
757 }));
758 while (parser.eatToken(.Comma)) |_| {
759 try fields.push((try parser.enumField()) orelse break);
760 }
761 node.body = .{
762 .lbrace = lbrace,
763 .fields = fields,
764 .rbrace = try parser.expectToken(.RBrace),
765 };
766 }
767 return node;
768 }
769
770 /// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA?
771 fn enumField(parser: *Parser) !?*Node {
772 const name = parser.eatToken(.Identifier) orelse return null;
773 const node = try parser.arena.create(Node.EnumField);
774 node.* = .{
775 .name = name,
776 .value = null,
777 };
778 if (parser.eatToken(.Equal)) |eq| {
779 node.value = (try parser.constExpr()) orelse parser.err(.{
780 .ExpectedExpr = .{ .token = parser.it.index },
781 });
782 }
783 return &node.base;
784 }
785
786 /// RecordSpec <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)?
787 fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType {
788 const node = try parser.arena.create(Node.RecordType);
789 const name = parser.eatToken(.Identifier);
790 const is_struct = parser.tree.tokenSlice(tok)[0] == 's';
791 node.* = .{
792 .tok = tok,
793 .kind = if (is_struct) .Struct else .Union,
794 .name = name,
795 .body = null,
796 };
797 const ty = try parser.arena.create(Type);
798 ty.* = .{
799 .id = .{
800 .Record = node,
801 },
802 };
803 if (name) |some|
804 try parser.symbols.append(.{
805 .name = parser.tree.tokenSlice(some),
806 .ty = ty,
807 });
808 if (parser.eatToken(.LBrace)) |lbrace| {
809 try parser.pushScope(.Block);
810 defer parser.popScope();
811 var fields = Node.RecordType.FieldList.init(parser.arena);
812 while (true) {
813 if (parser.eatToken(.RBrace)) |rbrace| {
814 node.body = .{
815 .lbrace = lbrace,
816 .fields = fields,
817 .rbrace = rbrace,
818 };
819 break;
820 }
821 try fields.push(try parser.recordField());
822 }
823 }
824 return node;
825 }
826
827 /// RecordField
828 /// <- TypeSpec* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON
829 /// \ StaticAssert
830 fn recordField(parser: *Parser) Error!*Node {
831 if (try parser.staticAssert()) |decl| return decl;
832 var got = false;
833 var type_spec = Node.TypeSpec{};
834 while (try parser.typeSpec(&type_spec)) got = true;
835 if (!got)
836 return parser.err(.{
837 .ExpectedType = .{ .token = parser.it.index },
838 });
839 const node = try parser.arena.create(Node.RecordField);
840 node.* = .{
841 .type_spec = type_spec,
842 .declarators = Node.RecordField.DeclaratorList.init(parser.arena),
843 .semicolon = undefined,
844 };
845 while (true) {
846 const rdr = try parser.recordDeclarator();
847 try parser.declareSymbol(type_spec, rdr.declarator);
848 try node.declarators.push(&rdr.base);
849 if (parser.eatToken(.Comma)) |_| {} else break;
850 }
851
852 node.semicolon = try parser.expectToken(.Semicolon);
853 return &node.base;
854 }
855
856 /// TypeName <- TypeSpec* AbstractDeclarator?
857 fn typeName(parser: *Parser) Error!?*Node {
858 @panic("TODO");
859 }
860
861 /// RecordDeclarator <- Declarator? (COLON ConstExpr)?
862 fn recordDeclarator(parser: *Parser) Error!*Node.RecordDeclarator {
863 @panic("TODO");
864 }
865
866 /// Pointer <- ASTERISK TypeQual* Pointer?
867 fn pointer(parser: *Parser) Error!?*Node.Pointer {
868 const asterisk = parser.eatToken(.Asterisk) orelse return null;
869 const node = try parser.arena.create(Node.Pointer);
870 node.* = .{
871 .asterisk = asterisk,
872 .qual = .{},
873 .pointer = null,
874 };
875 while (try parser.typeQual(&node.qual)) {}
876 node.pointer = try parser.pointer();
877 return node;
878 }
879
880 const Named = enum {
881 Must,
882 Allowed,
883 Forbidden,
884 };
885
886 /// Declarator <- Pointer? DeclaratorSuffix
887 /// DeclaratorPrefix
888 /// <- IDENTIFIER // if named != .Forbidden
889 /// / LPAREN Declarator RPAREN
890 /// / (none) // if named != .Must
891 /// DeclaratorSuffix
892 /// <- DeclaratorPrefix (LBRACKET ArrayDeclarator? RBRACKET)*
893 /// / DeclaratorPrefix LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN
894 fn declarator(parser: *Parser, named: Named) Error!?*Node {
895 const ptr = try parser.pointer();
896 var node: *Node.Declarator = undefined;
897 var inner_fn = false;
898
899 // TODO sizof(int (int))
900 // prefix
901 if (parser.eatToken(.LParen)) |lparen| {
902 const inner = (try parser.declarator(named)) orelse return parser.err(.{
903 .ExpectedDeclarator = .{ .token = lparen + 1 },
904 });
905 inner_fn = declaratorIsFunction(inner);
906 node = try parser.arena.create(Node.Declarator);
907 node.* = .{
908 .pointer = ptr,
909 .prefix = .{
910 .Complex = .{
911 .lparen = lparen,
912 .inner = inner,
913 .rparen = try parser.expectToken(.RParen),
914 },
915 },
916 .suffix = .None,
917 };
918 } else if (named != .Forbidden) {
919 if (parser.eatToken(.Identifier)) |tok| {
920 node = try parser.arena.create(Node.Declarator);
921 node.* = .{
922 .pointer = ptr,
923 .prefix = .{ .Identifer = tok },
924 .suffix = .None,
925 };
926 } else if (named == .Must) {
927 return parser.err(.{
928 .ExpectedToken = .{ .token = parser.it.index, .expected_id = .Identifier },
929 });
930 } else {
931 if (ptr) |some|
932 return &some.base;
933 return null;
934 }
935 } else {
936 node = try parser.arena.create(Node.Declarator);
937 node.* = .{
938 .pointer = ptr,
939 .prefix = .None,
940 .suffix = .None,
941 };
942 }
943 // suffix
944 if (parser.eatToken(.LParen)) |lparen| {
945 if (inner_fn)
946 return parser.err(.{
947 .InvalidDeclarator = .{ .token = lparen },
948 });
949 node.suffix = .{
950 .Fn = .{
951 .lparen = lparen,
952 .params = Node.Declarator.Params.init(parser.arena),
953 .rparen = undefined,
954 },
955 };
956 try parser.paramDecl(node);
957 node.suffix.Fn.rparen = try parser.expectToken(.RParen);
958 } else if (parser.eatToken(.LBracket)) |tok| {
959 if (inner_fn)
960 return parser.err(.{
961 .InvalidDeclarator = .{ .token = tok },
962 });
963 node.suffix = .{ .Array = Node.Declarator.Arrays.init(parser.arena) };
964 var lbrace = tok;
965 while (true) {
966 try node.suffix.Array.push(try parser.arrayDeclarator(lbrace));
967 if (parser.eatToken(.LBracket)) |t| lbrace = t else break;
968 }
969 }
970 if (parser.eatToken(.LParen) orelse parser.eatToken(.LBracket)) |tok|
971 return parser.err(.{
972 .InvalidDeclarator = .{ .token = tok },
973 });
974 return &node.base;
975 }
976
977 /// ArrayDeclarator
978 /// <- ASTERISK
979 /// / Keyword_static TypeQual* AssignmentExpr
980 /// / TypeQual+ (ASTERISK / Keyword_static AssignmentExpr)
981 /// / TypeQual+ AssignmentExpr?
982 /// / AssignmentExpr
983 fn arrayDeclarator(parser: *Parser, lbracket: TokenIndex) !*Node.Array {
984 const arr = try parser.arena.create(Node.Array);
985 arr.* = .{
986 .lbracket = lbracket,
987 .inner = .Inferred,
988 .rbracket = undefined,
989 };
990 if (parser.eatToken(.Asterisk)) |tok| {
991 arr.inner = .{ .Unspecified = tok };
992 } else {
993 // TODO
994 }
995 arr.rbracket = try parser.expectToken(.RBracket);
996 return arr;
997 }
998
999 /// Params <- ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?
1000 /// ParamDecl <- DeclSpec (Declarator / AbstractDeclarator)
1001 fn paramDecl(parser: *Parser, dr: *Node.Declarator) !void {
1002 var old_style = false;
1003 while (true) {
1004 var ds = Node.DeclSpec{};
1005 if (try parser.declSpec(&ds)) {
1006 //TODO
1007 // TODO try parser.declareSymbol(ds.type_spec, dr);
1008 } else if (parser.eatToken(.Identifier)) |tok| {
1009 old_style = true;
1010 } else if (parser.eatToken(.Ellipsis)) |tok| {
1011 // TODO
1012 }
1013 }
1014 }
1015
1016 /// Expr <- AssignmentExpr (COMMA Expr)*
1017 fn expr(parser: *Parser) Error!?*Expr {
1018 @panic("TODO");
1019 }
1020
1021 /// AssignmentExpr
1022 /// <- ConditionalExpr // TODO recursive?
1023 /// / UnaryExpr (EQUAL / ASTERISKEQUAL / SLASHEQUAL / PERCENTEQUAL / PLUSEQUAL / MINUSEQUA /
1024 /// / ANGLEBRACKETANGLEBRACKETLEFTEQUAL / ANGLEBRACKETANGLEBRACKETRIGHTEQUAL /
1025 /// / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL) AssignmentExpr
1026 fn assignmentExpr(parser: *Parser) !?*Expr {
1027 @panic("TODO");
1028 }
1029
1030 /// ConstExpr <- ConditionalExpr
1031 fn constExpr(parser: *Parser) Error!?*Expr {
1032 const start = parser.it.index;
1033 const expression = try parser.conditionalExpr();
1034 if (expression != null and expression.?.value == .None)
1035 return parser.err(.{
1036 .ConsExpr = start,
1037 });
1038 return expression;
1039 }
1040
1041 /// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)?
1042 fn conditionalExpr(parser: *Parser) Error!?*Expr {
1043 @panic("TODO");
1044 }
1045
1046 /// LogicalOrExpr <- LogicalAndExpr (PIPEPIPE LogicalOrExpr)*
1047 fn logicalOrExpr(parser: *Parser) !*Node {
1048 const lhs = (try parser.logicalAndExpr()) orelse return null;
1049 }
1050
1051 /// LogicalAndExpr <- BinOrExpr (AMPERSANDAMPERSAND LogicalAndExpr)*
1052 fn logicalAndExpr(parser: *Parser) !*Node {
1053 @panic("TODO");
1054 }
1055
1056 /// BinOrExpr <- BinXorExpr (PIPE BinOrExpr)*
1057 fn binOrExpr(parser: *Parser) !*Node {
1058 @panic("TODO");
1059 }
1060
1061 /// BinXorExpr <- BinAndExpr (CARET BinXorExpr)*
1062 fn binXorExpr(parser: *Parser) !*Node {
1063 @panic("TODO");
1064 }
1065
1066 /// BinAndExpr <- EqualityExpr (AMPERSAND BinAndExpr)*
1067 fn binAndExpr(parser: *Parser) !*Node {
1068 @panic("TODO");
1069 }
1070
1071 /// EqualityExpr <- ComparisionExpr ((EQUALEQUAL / BANGEQUAL) EqualityExpr)*
1072 fn equalityExpr(parser: *Parser) !*Node {
1073 @panic("TODO");
1074 }
1075
1076 /// ComparisionExpr <- ShiftExpr (ANGLEBRACKETLEFT / ANGLEBRACKETLEFTEQUAL /ANGLEBRACKETRIGHT / ANGLEBRACKETRIGHTEQUAL) ComparisionExpr)*
1077 fn comparisionExpr(parser: *Parser) !*Node {
1078 @panic("TODO");
1079 }
1080
1081 /// ShiftExpr <- AdditiveExpr (ANGLEBRACKETANGLEBRACKETLEFT / ANGLEBRACKETANGLEBRACKETRIGHT) ShiftExpr)*
1082 fn shiftExpr(parser: *Parser) !*Node {
1083 @panic("TODO");
1084 }
1085
1086 /// AdditiveExpr <- MultiplicativeExpr (PLUS / MINUS) AdditiveExpr)*
1087 fn additiveExpr(parser: *Parser) !*Node {
1088 @panic("TODO");
1089 }
1090
1091 /// MultiplicativeExpr <- UnaryExpr (ASTERISK / SLASH / PERCENT) MultiplicativeExpr)*
1092 fn multiplicativeExpr(parser: *Parser) !*Node {
1093 @panic("TODO");
1094 }
1095
1096 /// UnaryExpr
1097 /// <- LPAREN TypeName RPAREN UnaryExpr
1098 /// / Keyword_sizeof LAPERN TypeName RPAREN
1099 /// / Keyword_sizeof UnaryExpr
1100 /// / Keyword_alignof LAPERN TypeName RPAREN
1101 /// / (AMPERSAND / ASTERISK / PLUS / PLUSPLUS / MINUS / MINUSMINUS / TILDE / BANG) UnaryExpr
1102 /// / PrimaryExpr PostFixExpr*
1103 fn unaryExpr(parser: *Parser) !*Node {
1104 @panic("TODO");
1105 }
1106
1107 /// PrimaryExpr
1108 /// <- IDENTIFIER
1109 /// / INTEGERLITERAL / FLOATLITERAL / STRINGLITERAL / CHARLITERAL
1110 /// / LPAREN Expr RPAREN
1111 /// / Keyword_generic LPAREN AssignmentExpr (COMMA Generic)+ RPAREN
1112 fn primaryExpr(parser: *Parser) !*Node {
1113 @panic("TODO");
1114 }
1115
1116 /// Generic
1117 /// <- TypeName COLON AssignmentExpr
1118 /// / Keyword_default COLON AssignmentExpr
1119 fn generic(parser: *Parser) !*Node {
1120 @panic("TODO");
1121 }
1122
1123 /// PostFixExpr
1124 /// <- LPAREN TypeName RPAREN LBRACE Initializers RBRACE
1125 /// / LBRACKET Expr RBRACKET
1126 /// / LPAREN (AssignmentExpr (COMMA AssignmentExpr)*)? RPAREN
1127 /// / (PERIOD / ARROW) IDENTIFIER
1128 /// / (PLUSPLUS / MINUSMINUS)
1129 fn postFixExpr(parser: *Parser) !*Node {
1130 @panic("TODO");
1131 }
1132
1133 /// Initializers <- ((Designator+ EQUAL)? Initializer COMMA)* (Designator+ EQUAL)? Initializer COMMA?
1134 fn initializers(parser: *Parser) !*Node {
1135 @panic("TODO");
1136 }
1137
1138 /// Initializer
1139 /// <- LBRACE Initializers RBRACE
1140 /// / AssignmentExpr
1141 fn initializer(parser: *Parser, dr: *Node.Declarator) Error!?*Node {
1142 @panic("TODO");
1143 }
1144
1145 /// Designator
1146 /// <- LBRACKET ConstExpr RBRACKET
1147 /// / PERIOD IDENTIFIER
1148 fn designator(parser: *Parser) !*Node {
1149 @panic("TODO");
1150 }
1151
1152 /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE
1153 fn compoundStmt(parser: *Parser) Error!?*Node {
1154 const lbrace = parser.eatToken(.LBrace) orelse return null;
1155 try parser.pushScope(.Block);
1156 defer parser.popScope();
1157 const body_node = try parser.arena.create(Node.CompoundStmt);
1158 body_node.* = .{
1159 .lbrace = lbrace,
1160 .statements = Node.CompoundStmt.StmtList.init(parser.arena),
1161 .rbrace = undefined,
1162 };
1163 while (true) {
1164 if (parser.eatToken(.RBRACE)) |rbrace| {
1165 body_node.rbrace = rbrace;
1166 break;
1167 }
1168 try body_node.statements.push((try parser.declaration()) orelse (try parser.stmt()));
1169 }
1170 return &body_node.base;
1171 }
1172
1173 /// Stmt
1174 /// <- CompoundStmt
1175 /// / Keyword_if LPAREN Expr RPAREN Stmt (Keyword_ELSE Stmt)?
1176 /// / Keyword_switch LPAREN Expr RPAREN Stmt
1177 /// / Keyword_while LPAREN Expr RPAREN Stmt
1178 /// / Keyword_do statement Keyword_while LPAREN Expr RPAREN SEMICOLON
1179 /// / Keyword_for LPAREN (Declaration / ExprStmt) ExprStmt Expr? RPAREN Stmt
1180 /// / Keyword_default COLON Stmt
1181 /// / Keyword_case ConstExpr COLON Stmt
1182 /// / Keyword_goto IDENTIFIER SEMICOLON
1183 /// / Keyword_continue SEMICOLON
1184 /// / Keyword_break SEMICOLON
1185 /// / Keyword_return Expr? SEMICOLON
1186 /// / IDENTIFIER COLON Stmt
1187 /// / ExprStmt
1188 fn stmt(parser: *Parser) Error!*Node {
1189 if (try parser.compoundStmt()) |node| return node;
1190 if (parser.eatToken(.Keyword_if)) |tok| {
1191 const node = try parser.arena.create(Node.IfStmt);
1192 _ = try parser.expectToken(.LParen);
1193 node.* = .{
1194 .@"if" = tok,
1195 .cond = (try parser.expr()) orelse return parser.err(.{
1196 .ExpectedExpr = .{ .token = parser.it.index },
1197 }),
1198 .body = undefined,
1199 .@"else" = null,
1200 };
1201 _ = try parser.expectToken(.RParen);
1202 node.body = try parser.stmt();
1203 if (parser.eatToken(.Keyword_else)) |else_tok| {
1204 node.@"else" = .{
1205 .tok = else_tok,
1206 .body = try parser.stmt(),
1207 };
1208 }
1209 return &node.base;
1210 }
1211 if (parser.eatToken(.Keyword_while)) |tok| {
1212 try parser.pushScope(.Loop);
1213 defer parser.popScope();
1214 _ = try parser.expectToken(.LParen);
1215 const cond = (try parser.expr()) orelse return parser.err(.{
1216 .ExpectedExpr = .{ .token = parser.it.index },
1217 });
1218 const rparen = try parser.expectToken(.RParen);
1219 const node = try parser.arena.create(Node.WhileStmt);
1220 node.* = .{
1221 .@"while" = tok,
1222 .cond = cond,
1223 .rparen = rparen,
1224 .body = try parser.stmt(),
1225 .semicolon = try parser.expectToken(.Semicolon),
1226 };
1227 return &node.base;
1228 }
1229 if (parser.eatToken(.Keyword_do)) |tok| {
1230 try parser.pushScope(.Loop);
1231 defer parser.popScope();
1232 const body = try parser.stmt();
1233 _ = try parser.expectToken(.LParen);
1234 const cond = (try parser.expr()) orelse return parser.err(.{
1235 .ExpectedExpr = .{ .token = parser.it.index },
1236 });
1237 _ = try parser.expectToken(.RParen);
1238 const node = try parser.arena.create(Node.DoStmt);
1239 node.* = .{
1240 .do = tok,
1241 .body = body,
1242 .cond = cond,
1243 .@"while" = @"while",
1244 .semicolon = try parser.expectToken(.Semicolon),
1245 };
1246 return &node.base;
1247 }
1248 if (parser.eatToken(.Keyword_for)) |tok| {
1249 try parser.pushScope(.Loop);
1250 defer parser.popScope();
1251 _ = try parser.expectToken(.LParen);
1252 const init = if (try parser.declaration()) |decl| blk: {
1253 // TODO disallow storage class other than auto and register
1254 break :blk decl;
1255 } else try parser.exprStmt();
1256 const cond = try parser.expr();
1257 const semicolon = try parser.expectToken(.Semicolon);
1258 const incr = try parser.expr();
1259 const rparen = try parser.expectToken(.RParen);
1260 const node = try parser.arena.create(Node.ForStmt);
1261 node.* = .{
1262 .@"for" = tok,
1263 .init = init,
1264 .cond = cond,
1265 .semicolon = semicolon,
1266 .incr = incr,
1267 .rparen = rparen,
1268 .body = try parser.stmt(),
1269 };
1270 return &node.base;
1271 }
1272 if (parser.eatToken(.Keyword_switch)) |tok| {
1273 try parser.pushScope(.Switch);
1274 defer parser.popScope();
1275 _ = try parser.expectToken(.LParen);
1276 const switch_expr = try parser.exprStmt();
1277 const rparen = try parser.expectToken(.RParen);
1278 const node = try parser.arena.create(Node.SwitchStmt);
1279 node.* = .{
1280 .@"switch" = tok,
1281 .expr = switch_expr,
1282 .rparen = rparen,
1283 .body = try parser.stmt(),
1284 };
1285 return &node.base;
1286 }
1287 if (parser.eatToken(.Keyword_default)) |tok| {
1288 _ = try parser.expectToken(.Colon);
1289 const node = try parser.arena.create(Node.LabeledStmt);
1290 node.* = .{
1291 .kind = .{ .Default = tok },
1292 .stmt = try parser.stmt(),
1293 };
1294 return &node.base;
1295 }
1296 if (parser.eatToken(.Keyword_case)) |tok| {
1297 _ = try parser.expectToken(.Colon);
1298 const node = try parser.arena.create(Node.LabeledStmt);
1299 node.* = .{
1300 .kind = .{ .Case = tok },
1301 .stmt = try parser.stmt(),
1302 };
1303 return &node.base;
1304 }
1305 if (parser.eatToken(.Keyword_goto)) |tok| {
1306 const node = try parser.arena.create(Node.JumpStmt);
1307 node.* = .{
1308 .ltoken = tok,
1309 .kind = .{ .Goto = tok },
1310 .semicolon = try parser.expectToken(.Semicolon),
1311 };
1312 return &node.base;
1313 }
1314 if (parser.eatToken(.Keyword_continue)) |tok| {
1315 const node = try parser.arena.create(Node.JumpStmt);
1316 node.* = .{
1317 .ltoken = tok,
1318 .kind = .Continue,
1319 .semicolon = try parser.expectToken(.Semicolon),
1320 };
1321 return &node.base;
1322 }
1323 if (parser.eatToken(.Keyword_break)) |tok| {
1324 const node = try parser.arena.create(Node.JumpStmt);
1325 node.* = .{
1326 .ltoken = tok,
1327 .kind = .Break,
1328 .semicolon = try parser.expectToken(.Semicolon),
1329 };
1330 return &node.base;
1331 }
1332 if (parser.eatToken(.Keyword_return)) |tok| {
1333 const node = try parser.arena.create(Node.JumpStmt);
1334 node.* = .{
1335 .ltoken = tok,
1336 .kind = .{ .Return = try parser.expr() },
1337 .semicolon = try parser.expectToken(.Semicolon),
1338 };
1339 return &node.base;
1340 }
1341 if (parser.eatToken(.Identifier)) |tok| {
1342 if (parser.eatToken(.Colon)) |_| {
1343 const node = try parser.arena.create(Node.LabeledStmt);
1344 node.* = .{
1345 .kind = .{ .Label = tok },
1346 .stmt = try parser.stmt(),
1347 };
1348 return &node.base;
1349 }
1350 parser.putBackToken(tok);
1351 }
1352 return parser.exprStmt();
1353 }
1354
1355 /// ExprStmt <- Expr? SEMICOLON
1356 fn exprStmt(parser: *Parser) !*Node {
1357 const node = try parser.arena.create(Node.ExprStmt);
1358 node.* = .{
1359 .expr = try parser.expr(),
1360 .semicolon = try parser.expectToken(.Semicolon),
1361 };
1362 return &node.base;
1363 }
1364
1365 fn eatToken(parser: *Parser, id: std.meta.Tag(Token.Id)) ?TokenIndex {
1366 while (true) {
1367 switch ((parser.it.next() orelse return null).id) {
1368 .LineComment, .MultiLineComment, .Nl => continue,
1369 else => |next_id| if (next_id == id) {
1370 return parser.it.index;
1371 } else {
1372 _ = parser.it.prev();
1373 return null;
1374 },
1375 }
1376 }
1377 }
1378
1379 fn expectToken(parser: *Parser, id: std.meta.Tag(Token.Id)) Error!TokenIndex {
1380 while (true) {
1381 switch ((parser.it.next() orelse return error.ParseError).id) {
1382 .LineComment, .MultiLineComment, .Nl => continue,
1383 else => |next_id| if (next_id != id) {
1384 return parser.err(.{
1385 .ExpectedToken = .{ .token = parser.it.index, .expected_id = id },
1386 });
1387 } else {
1388 return parser.it.index;
1389 },
1390 }
1391 }
1392 }
1393
1394 fn putBackToken(parser: *Parser, putting_back: TokenIndex) void {
1395 while (true) {
1396 const prev_tok = parser.it.next() orelse return;
1397 switch (prev_tok.id) {
1398 .LineComment, .MultiLineComment, .Nl => continue,
1399 else => {
1400 assert(parser.it.list.at(putting_back) == prev_tok);
1401 return;
1402 },
1403 }
1404 }
1405 }
1406
1407 fn err(parser: *Parser, msg: ast.Error) Error {
1408 try parser.tree.msgs.push(.{
1409 .kind = .Error,
1410 .inner = msg,
1411 });
1412 return error.ParseError;
1413 }
1414
1415 fn warn(parser: *Parser, msg: ast.Error) Error!void {
1416 const is_warning = switch (parser.options.warn_as_err) {
1417 .None => true,
1418 .Some => |list| for (list) |item| (if (item == msg) break false) else true,
1419 .All => false,
1420 };
1421 try parser.tree.msgs.push(.{
1422 .kind = if (is_warning) .Warning else .Error,
1423 .inner = msg,
1424 });
1425 if (!is_warning) return error.ParseError;
1426 }
1427
1428 fn note(parser: *Parser, msg: ast.Error) Error!void {
1429 try parser.tree.msgs.push(.{
1430 .kind = .Note,
1431 .inner = msg,
1432 });
1433 }
1434};
lib/std/compress/deflate.zig+2-4
...@@ -662,14 +662,12 @@ test "lengths overflow" {...@@ -662,14 +662,12 @@ test "lengths overflow" {
662 // malformed final dynamic block, tries to write 321 code lengths (MAXCODES is 316)662 // malformed final dynamic block, tries to write 321 code lengths (MAXCODES is 316)
663 // f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6663 // f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6
664 // 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11664 // 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11
665 const stream = [_]u8{665 const stream = [_]u8{ 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110 };
666 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110
667 };
668666
669 const reader = std.io.fixedBufferStream(&stream).reader();667 const reader = std.io.fixedBufferStream(&stream).reader();
670 var window: [0x8000]u8 = undefined;668 var window: [0x8000]u8 = undefined;
671 var inflate = inflateStream(reader, &window);669 var inflate = inflateStream(reader, &window);
672670
673 var buf: [1]u8 = undefined;671 var buf: [1]u8 = undefined;
674 std.testing.expectError(error.InvalidLength, inflate.read(&buf)); 672 std.testing.expectError(error.InvalidLength, inflate.read(&buf));
675}673}
lib/std/crypto.zig+1
...@@ -67,6 +67,7 @@ pub const dh = struct {...@@ -67,6 +67,7 @@ pub const dh = struct {
67pub const ecc = struct {67pub const ecc = struct {
68 pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;68 pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
69 pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;69 pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
70 pub const P256 = @import("crypto/pcurves/p256.zig").P256;
70 pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;71 pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
71};72};
7273
lib/std/crypto/pcurves/common.zig created+284
...@@ -0,0 +1,284 @@
1const std = @import("std");
2const builtin = std.builtin;
3const crypto = std.crypto;
4const debug = std.debug;
5const mem = std.mem;
6const meta = std.meta;
7
8const NonCanonicalError = crypto.errors.NonCanonicalError;
9const NotSquareError = crypto.errors.NotSquareError;
10
11/// Parameters to create a finite field type.
12pub const FieldParams = struct {
13 fiat: type,
14 field_order: comptime_int,
15 field_bits: comptime_int,
16 saturated_bits: comptime_int,
17 encoded_length: comptime_int,
18};
19
20/// A field element, internally stored in Montgomery domain.
21pub fn Field(comptime params: FieldParams) type {
22 const fiat = params.fiat;
23 const Limbs = fiat.Limbs;
24
25 return struct {
26 const Fe = @This();
27
28 limbs: Limbs,
29
30 /// Field size.
31 pub const field_order = params.field_order;
32
33 /// Number of bits to represent the set of all elements.
34 pub const field_bits = params.field_bits;
35
36 /// Number of bits that can be saturated without overflowing.
37 pub const saturated_bits = params.saturated_bits;
38
39 /// Number of bytes required to encode an element.
40 pub const encoded_length = params.encoded_length;
41
42 /// Zero.
43 pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) };
44
45 /// One.
46 pub const one = comptime one: {
47 var fe: Fe = undefined;
48 fiat.setOne(&fe.limbs);
49 break :one fe;
50 };
51
52 /// Reject non-canonical encodings of an element.
53 pub fn rejectNonCanonical(s_: [encoded_length]u8, endian: builtin.Endian) NonCanonicalError!void {
54 var s = if (endian == .Little) s_ else orderSwap(s_);
55 const field_order_s = comptime fos: {
56 var fos: [encoded_length]u8 = undefined;
57 mem.writeIntLittle(std.meta.Int(.unsigned, encoded_length * 8), &fos, field_order);
58 break :fos fos;
59 };
60 if (crypto.utils.timingSafeCompare(u8, &s, &field_order_s, .Little) != .lt) {
61 return error.NonCanonical;
62 }
63 }
64
65 /// Swap the endianness of an encoded element.
66 pub fn orderSwap(s: [encoded_length]u8) [encoded_length]u8 {
67 var t = s;
68 for (s) |x, i| t[t.len - 1 - i] = x;
69 return t;
70 }
71
72 /// Unpack a field element.
73 pub fn fromBytes(s_: [encoded_length]u8, endian: builtin.Endian) NonCanonicalError!Fe {
74 var s = if (endian == .Little) s_ else orderSwap(s_);
75 try rejectNonCanonical(s, .Little);
76 var limbs_z: Limbs = undefined;
77 fiat.fromBytes(&limbs_z, s);
78 var limbs: Limbs = undefined;
79 fiat.toMontgomery(&limbs, limbs_z);
80 return Fe{ .limbs = limbs };
81 }
82
83 /// Pack a field element.
84 pub fn toBytes(fe: Fe, endian: builtin.Endian) [encoded_length]u8 {
85 var limbs_z: Limbs = undefined;
86 fiat.fromMontgomery(&limbs_z, fe.limbs);
87 var s: [encoded_length]u8 = undefined;
88 fiat.toBytes(&s, limbs_z);
89 return if (endian == .Little) s else orderSwap(s);
90 }
91
92 /// Element as an integer.
93 pub const IntRepr = meta.Int(.unsigned, params.field_bits);
94
95 /// Create a field element from an integer.
96 pub fn fromInt(comptime x: IntRepr) NonCanonicalError!Fe {
97 var s: [encoded_length]u8 = undefined;
98 mem.writeIntLittle(IntRepr, &s, x);
99 return fromBytes(s, .Little);
100 }
101
102 /// Return the field element as an integer.
103 pub fn toInt(fe: Fe) IntRepr {
104 const s = fe.toBytes(.Little);
105 return mem.readIntLittle(IntRepr, &s);
106 }
107
108 /// Return true if the field element is zero.
109 pub fn isZero(fe: Fe) bool {
110 var z: @TypeOf(fe.limbs[0]) = undefined;
111 fiat.nonzero(&z, fe.limbs);
112 return z == 0;
113 }
114
115 /// Return true if both field elements are equivalent.
116 pub fn equivalent(a: Fe, b: Fe) bool {
117 return a.sub(b).isZero();
118 }
119
120 /// Return true if the element is odd.
121 pub fn isOdd(fe: Fe) bool {
122 const s = fe.toBytes(.Little);
123 return @truncate(u1, s[0]) != 0;
124 }
125
126 /// Conditonally replace a field element with `a` if `c` is positive.
127 pub fn cMov(fe: *Fe, a: Fe, c: u1) void {
128 fiat.selectznz(&fe.limbs, c, fe.limbs, a.limbs);
129 }
130
131 /// Add field elements.
132 pub fn add(a: Fe, b: Fe) Fe {
133 var fe: Fe = undefined;
134 fiat.add(&fe.limbs, a.limbs, b.limbs);
135 return fe;
136 }
137
138 /// Subtract field elements.
139 pub fn sub(a: Fe, b: Fe) Fe {
140 var fe: Fe = undefined;
141 fiat.sub(&fe.limbs, a.limbs, b.limbs);
142 return fe;
143 }
144
145 /// Double a field element.
146 pub fn dbl(a: Fe) Fe {
147 var fe: Fe = undefined;
148 fiat.add(&fe.limbs, a.limbs, a.limbs);
149 return fe;
150 }
151
152 /// Multiply field elements.
153 pub fn mul(a: Fe, b: Fe) Fe {
154 var fe: Fe = undefined;
155 fiat.mul(&fe.limbs, a.limbs, b.limbs);
156 return fe;
157 }
158
159 /// Square a field element.
160 pub fn sq(a: Fe) Fe {
161 var fe: Fe = undefined;
162 fiat.square(&fe.limbs, a.limbs);
163 return fe;
164 }
165
166 /// Square a field element n times.
167 fn sqn(a: Fe, comptime n: comptime_int) Fe {
168 var i: usize = 0;
169 var fe = a;
170 while (i < n) : (i += 1) {
171 fe = fe.sq();
172 }
173 return fe;
174 }
175
176 /// Compute a^n.
177 pub fn pow(a: Fe, comptime T: type, comptime n: T) Fe {
178 var fe = one;
179 var x: T = n;
180 var t = a;
181 while (true) {
182 if (@truncate(u1, x) != 0) fe = fe.mul(t);
183 x >>= 1;
184 if (x == 0) break;
185 t = t.sq();
186 }
187 return fe;
188 }
189
190 /// Negate a field element.
191 pub fn neg(a: Fe) Fe {
192 var fe: Fe = undefined;
193 fiat.opp(&fe.limbs, a.limbs);
194 return fe;
195 }
196
197 /// Return the inverse of a field element, or 0 if a=0.
198 // Field inversion from https://eprint.iacr.org/2021/549.pdf
199 pub fn invert(a: Fe) Fe {
200 const iterations = (49 * field_bits + 57) / 17;
201 const Word = @TypeOf(a.limbs[0]);
202 const XLimbs = [a.limbs.len + 1]Word;
203
204 var d: Word = 1;
205 var f: XLimbs = undefined;
206 fiat.msat(&f);
207
208 var g: XLimbs = undefined;
209 fiat.fromMontgomery(g[0..a.limbs.len], a.limbs);
210 g[g.len - 1] = 0;
211
212 var r: Limbs = undefined;
213 fiat.setOne(&r);
214 var v = mem.zeroes(Limbs);
215
216 var precomp: Limbs = undefined;
217 fiat.divstepPrecomp(&precomp);
218
219 var out1: Word = undefined;
220 var out2: XLimbs = undefined;
221 var out3: XLimbs = undefined;
222 var out4: Limbs = undefined;
223 var out5: Limbs = undefined;
224
225 var i: usize = 0;
226 while (i < iterations - iterations % 2) : (i += 2) {
227 fiat.divstep(&out1, &out2, &out3, &out4, &out5, d, f, g, v, r);
228 fiat.divstep(&d, &f, &g, &v, &r, out1, out2, out3, out4, out5);
229 }
230 if (iterations % 2 != 0) {
231 fiat.divstep(&out1, &out2, &out3, &out4, &out5, d, f, g, v, r);
232 mem.copy(Word, &v, &out4);
233 mem.copy(Word, &f, &out2);
234 }
235 var v_opp: Limbs = undefined;
236 fiat.opp(&v_opp, v);
237 fiat.selectznz(&v, @truncate(u1, f[f.len - 1] >> (meta.bitCount(Word) - 1)), v, v_opp);
238 var fe: Fe = undefined;
239 fiat.mul(&fe.limbs, v, precomp);
240 return fe;
241 }
242
243 /// Return true if the field element is a square.
244 pub fn isSquare(x2: Fe) bool {
245 if (field_order == 115792089210356248762697446949407573530086143415290314195533631308867097853951) {
246 const t110 = x2.mul(x2.sq()).sq();
247 const t111 = x2.mul(t110);
248 const t111111 = t111.mul(x2.mul(t110).sqn(3));
249 const x15 = t111111.sqn(6).mul(t111111).sqn(3).mul(t111);
250 const x16 = x15.sq().mul(x2);
251 const x53 = x16.sqn(16).mul(x16).sqn(15);
252 const x47 = x15.mul(x53);
253 const ls = x47.mul(((x53.sqn(17).mul(x2)).sqn(143).mul(x47)).sqn(47)).sq().mul(x2);
254 return ls.equivalent(Fe.one);
255 } else {
256 const ls = x2.pow(std.meta.Int(.unsigned, field_bits), (field_order - 1) / 2); // Legendre symbol
257 return ls.equivalent(Fe.one);
258 }
259 }
260
261 // x=x2^((field_order+1)/4) w/ field order=3 (mod 4).
262 fn uncheckedSqrt(x2: Fe) Fe {
263 comptime debug.assert(field_order % 4 == 3);
264 if (field_order == 115792089210356248762697446949407573530086143415290314195533631308867097853951) {
265 const t11 = x2.mul(x2.sq());
266 const t1111 = t11.mul(t11.sqn(2));
267 const t11111111 = t1111.mul(t1111.sqn(4));
268 const x16 = t11111111.sqn(8).mul(t11111111);
269 return x16.sqn(16).mul(x16).sqn(32).mul(x2).sqn(96).mul(x2).sqn(94);
270 } else {
271 return x2.pow(std.meta.Int(.unsigned, field_bits), (field_order + 1) / 4);
272 }
273 }
274
275 /// Compute the square root of `x2`, returning `error.NotSquare` if `x2` was not a square.
276 pub fn sqrt(x2: Fe) NotSquareError!Fe {
277 const x = x2.uncheckedSqrt();
278 if (x.sq().equivalent(x2)) {
279 return x;
280 }
281 return error.NotSquare;
282 }
283 };
284}
lib/std/crypto/pcurves/p256.zig created+412
...@@ -0,0 +1,412 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("std");
8const builtin = std.builtin;
9const crypto = std.crypto;
10const mem = std.mem;
11const meta = std.meta;
12
13const EncodingError = crypto.errors.EncodingError;
14const IdentityElementError = crypto.errors.IdentityElementError;
15const NonCanonicalError = crypto.errors.NonCanonicalError;
16const NotSquareError = crypto.errors.NotSquareError;
17
18/// Group operations over P256.
19pub const P256 = struct {
20 /// The underlying prime field.
21 pub const Fe = @import("p256/field.zig").Fe;
22 /// Field arithmetic mod the order of the main subgroup.
23 pub const scalar = @import("p256/scalar.zig");
24
25 x: Fe,
26 y: Fe,
27 z: Fe = Fe.one,
28
29 is_base: bool = false,
30
31 /// The P256 base point.
32 pub const basePoint = P256{
33 .x = try Fe.fromInt(48439561293906451759052585252797914202762949526041747995844080717082404635286),
34 .y = try Fe.fromInt(36134250956749795798585127919587881956611106672985015071877198253568414405109),
35 .z = Fe.one,
36 .is_base = true,
37 };
38
39 /// The P256 neutral element.
40 pub const identityElement = P256{ .x = Fe.zero, .y = Fe.one, .z = Fe.zero };
41
42 pub const B = try Fe.fromInt(41058363725152142129326129780047268409114441015993725554835256314039467401291);
43
44 /// Reject the neutral element.
45 pub fn rejectIdentity(p: P256) IdentityElementError!void {
46 if (p.x.isZero()) {
47 return error.IdentityElement;
48 }
49 }
50
51 /// Create a point from affine coordinates after checking that they match the curve equation.
52 pub fn fromAffineCoordinates(x: Fe, y: Fe) EncodingError!P256 {
53 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
54 const yy = y.sq();
55 if (!x3AxB.equivalent(yy)) {
56 return error.InvalidEncoding;
57 }
58 const p: P256 = .{ .x = x, .y = y, .z = Fe.one };
59 return p;
60 }
61
62 /// Create a point from serialized affine coordinates.
63 pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: builtin.Endian) (NonCanonicalError || EncodingError)!P256 {
64 const x = try Fe.fromBytes(xs, endian);
65 const y = try Fe.fromBytes(ys, endian);
66 return fromAffineCoordinates(x, y);
67 }
68
69 /// Recover the Y coordinate from the X coordinate.
70 pub fn recoverY(x: Fe, is_odd: bool) NotSquareError!Fe {
71 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
72 var y = try x3AxB.sqrt();
73 const yn = y.neg();
74 y.cMov(yn, @boolToInt(is_odd) ^ @boolToInt(y.isOdd()));
75 return y;
76 }
77
78 /// Deserialize a SEC1-encoded point.
79 pub fn fromSec1(s: []const u8) (EncodingError || NotSquareError || NonCanonicalError)!P256 {
80 if (s.len < 1) return error.InvalidEncoding;
81 const encoding_type = s[0];
82 const encoded = s[1..];
83 switch (encoding_type) {
84 0 => {
85 if (encoded.len != 0) return error.InvalidEncoding;
86 return P256.identityElement;
87 },
88 2, 3 => {
89 if (encoded.len != 32) return error.InvalidEncoding;
90 const x = try Fe.fromBytes(encoded[0..32].*, .Big);
91 const y_is_odd = (encoding_type == 3);
92 const y = try recoverY(x, y_is_odd);
93 return P256{ .x = x, .y = y };
94 },
95 4 => {
96 if (encoded.len != 64) return error.InvalidEncoding;
97 const x = try Fe.fromBytes(encoded[0..32].*, .Big);
98 const y = try Fe.fromBytes(encoded[32..64].*, .Big);
99 return P256.fromAffineCoordinates(x, y);
100 },
101 else => return error.InvalidEncoding,
102 }
103 }
104
105 /// Serialize a point using the compressed SEC-1 format.
106 pub fn toCompressedSec1(p: P256) [33]u8 {
107 var out: [33]u8 = undefined;
108 const xy = p.affineCoordinates();
109 out[0] = if (xy.y.isOdd()) 3 else 2;
110 mem.copy(u8, out[1..], &xy.x.toBytes(.Big));
111 return out;
112 }
113
114 /// Serialize a point using the uncompressed SEC-1 format.
115 pub fn toUncompressedSec1(p: P256) [65]u8 {
116 var out: [65]u8 = undefined;
117 out[0] = 4;
118 const xy = p.affineCoordinates();
119 mem.copy(u8, out[1..33], &xy.x.toBytes(.Big));
120 mem.copy(u8, out[33..65], &xy.y.toBytes(.Big));
121 return out;
122 }
123
124 /// Return a random point.
125 pub fn random() P256 {
126 const n = scalar.random(.Little);
127 return basePoint.mul(n, .Little) catch unreachable;
128 }
129
130 /// Flip the sign of the X coordinate.
131 pub fn neg(p: P256) P256 {
132 return .{ .x = p.x, .y = p.y.neg(), .z = p.z };
133 }
134
135 /// Double a P256 point.
136 // Algorithm 6 from https://eprint.iacr.org/2015/1060.pdf
137 pub fn dbl(p: P256) P256 {
138 var t0 = p.x.sq();
139 var t1 = p.y.sq();
140 var t2 = p.z.sq();
141 var t3 = p.x.mul(p.y);
142 t3 = t3.dbl();
143 var Z3 = p.x.mul(p.z);
144 Z3 = Z3.add(Z3);
145 var Y3 = B.mul(t2);
146 Y3 = Y3.sub(Z3);
147 var X3 = Y3.dbl();
148 Y3 = X3.add(Y3);
149 X3 = t1.sub(Y3);
150 Y3 = t1.add(Y3);
151 Y3 = X3.mul(Y3);
152 X3 = X3.mul(t3);
153 t3 = t2.dbl();
154 t2 = t2.add(t3);
155 Z3 = B.mul(Z3);
156 Z3 = Z3.sub(t2);
157 Z3 = Z3.sub(t0);
158 t3 = Z3.dbl();
159 Z3 = Z3.add(t3);
160 t3 = t0.dbl();
161 t0 = t3.add(t0);
162 t0 = t0.sub(t2);
163 t0 = t0.mul(Z3);
164 Y3 = Y3.add(t0);
165 t0 = p.y.mul(p.z);
166 t0 = t0.dbl();
167 Z3 = t0.mul(Z3);
168 X3 = X3.sub(Z3);
169 Z3 = t0.mul(t1);
170 Z3 = Z3.dbl().dbl();
171 return .{
172 .x = X3,
173 .y = Y3,
174 .z = Z3,
175 };
176 }
177
178 /// Add P256 points, the second being specified using affine coordinates.
179 // Algorithm 5 from https://eprint.iacr.org/2015/1060.pdf
180 pub fn addMixed(p: P256, q: struct { x: Fe, y: Fe }) P256 {
181 var t0 = p.x.mul(q.x);
182 var t1 = p.y.mul(q.y);
183 var t3 = q.x.add(q.y);
184 var t4 = p.x.add(p.y);
185 t3 = t3.mul(t4);
186 t4 = t0.add(t1);
187 t3 = t3.sub(t4);
188 t4 = q.y.mul(p.z);
189 t4 = t4.add(p.y);
190 var Y3 = q.x.mul(p.z);
191 Y3 = Y3.add(p.x);
192 var Z3 = B.mul(p.z);
193 var X3 = Y3.sub(Z3);
194 Z3 = X3.dbl();
195 X3 = X3.add(Z3);
196 Z3 = t1.sub(X3);
197 X3 = t1.dbl();
198 Y3 = B.mul(Y3);
199 t1 = p.z.add(p.z);
200 var t2 = t1.add(p.z);
201 Y3 = Y3.sub(t2);
202 Y3 = Y3.sub(t0);
203 t1 = Y3.dbl();
204 Y3 = t1.add(Y3);
205 t1 = t0.dbl();
206 t0 = t1.add(t0);
207 t0 = t0.sub(t2);
208 t1 = t4.mul(Y3);
209 t2 = t0.mul(Y3);
210 Y3 = X3.mul(Z3);
211 Y3 = Y3.add(t2);
212 X3 = t3.mul(X3);
213 X3 = X3.sub(t1);
214 Z3 = t4.mul(Z3);
215 t1 = t3.mul(t0);
216 Z3 = Z3.add(t1);
217 return .{
218 .x = X3,
219 .y = Y3,
220 .z = Z3,
221 };
222 }
223
224 // Add P256 points.
225 // Algorithm 4 from https://eprint.iacr.org/2015/1060.pdf
226 pub fn add(p: P256, q: P256) P256 {
227 var t0 = p.x.mul(q.x);
228 var t1 = p.y.mul(q.y);
229 var t2 = p.z.mul(q.z);
230 var t3 = p.x.add(p.y);
231 var t4 = q.x.add(q.y);
232 t3 = t3.mul(t4);
233 t4 = t0.add(t1);
234 t3 = t3.sub(t4);
235 t4 = p.y.add(p.z);
236 var X3 = q.y.add(q.z);
237 t4 = t4.mul(X3);
238 X3 = t1.add(t2);
239 t4 = t4.sub(X3);
240 X3 = p.x.add(p.z);
241 var Y3 = q.x.add(q.z);
242 X3 = X3.mul(Y3);
243 Y3 = t0.add(t2);
244 Y3 = X3.sub(Y3);
245 var Z3 = B.mul(t2);
246 X3 = Y3.sub(Z3);
247 Z3 = X3.dbl();
248 X3 = X3.add(Z3);
249 Z3 = t1.sub(X3);
250 X3 = t1.add(X3);
251 Y3 = B.mul(Y3);
252 t1 = t2.dbl();
253 t2 = t1.add(t2);
254 Y3 = Y3.sub(t2);
255 Y3 = Y3.sub(t0);
256 t1 = Y3.dbl();
257 Y3 = t1.add(Y3);
258 t1 = t0.dbl();
259 t0 = t1.add(t0);
260 t0 = t0.sub(t2);
261 t1 = t4.mul(Y3);
262 t2 = t0.mul(Y3);
263 Y3 = X3.mul(Z3);
264 Y3 = Y3.add(t2);
265 X3 = t3.mul(X3);
266 X3 = X3.sub(t1);
267 Z3 = t4.mul(Z3);
268 t1 = t3.mul(t0);
269 Z3 = Z3.add(t1);
270 return .{
271 .x = X3,
272 .y = Y3,
273 .z = Z3,
274 };
275 }
276
277 // Subtract P256 points.
278 pub fn sub(p: P256, q: P256) P256 {
279 return p.add(q.neg());
280 }
281
282 /// Return affine coordinates.
283 pub fn affineCoordinates(p: P256) struct { x: Fe, y: Fe } {
284 const zinv = p.z.invert();
285 const ret = .{
286 .x = p.x.mul(zinv),
287 .y = p.y.mul(zinv),
288 };
289 return ret;
290 }
291
292 /// Return true if both coordinate sets represent the same point.
293 pub fn equivalent(a: P256, b: P256) bool {
294 if (a.sub(b).rejectIdentity()) {
295 return false;
296 } else |_| {
297 return true;
298 }
299 }
300
301 fn cMov(p: *P256, a: P256, c: u1) void {
302 p.x.cMov(a.x, c);
303 p.y.cMov(a.y, c);
304 p.z.cMov(a.z, c);
305 }
306
307 fn pcSelect(comptime n: usize, pc: [n]P256, b: u8) P256 {
308 var t = P256.identityElement;
309 comptime var i: u8 = 1;
310 inline while (i < pc.len) : (i += 1) {
311 t.cMov(pc[i], @truncate(u1, (@as(usize, b ^ i) -% 1) >> 8));
312 }
313 return t;
314 }
315
316 fn slide(s: [32]u8) [2 * 32 + 1]i8 {
317 var e: [2 * 32 + 1]i8 = undefined;
318 for (s) |x, i| {
319 e[i * 2 + 0] = @as(i8, @truncate(u4, x));
320 e[i * 2 + 1] = @as(i8, @truncate(u4, x >> 4));
321 }
322 // Now, e[0..63] is between 0 and 15, e[63] is between 0 and 7
323 var carry: i8 = 0;
324 for (e[0..64]) |*x| {
325 x.* += carry;
326 carry = (x.* + 8) >> 4;
327 x.* -= carry * 16;
328 std.debug.assert(x.* >= -8 and x.* <= 8);
329 }
330 e[64] = carry;
331 // Now, e[*] is between -8 and 8, including e[64]
332 std.debug.assert(carry >= -8 and carry <= 8);
333 return e;
334 }
335
336 fn pcMul(pc: [9]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {
337 std.debug.assert(vartime);
338 const e = slide(s);
339 var q = P256.identityElement;
340 var pos = e.len - 1;
341 while (true) : (pos -= 1) {
342 const slot = e[pos];
343 if (slot > 0) {
344 q = q.add(pc[@intCast(usize, slot)]);
345 } else if (slot < 0) {
346 q = q.sub(pc[@intCast(usize, -slot)]);
347 }
348 if (pos == 0) break;
349 q = q.dbl().dbl().dbl().dbl();
350 }
351 try q.rejectIdentity();
352 return q;
353 }
354
355 fn pcMul16(pc: [16]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {
356 var q = P256.identityElement;
357 var pos: usize = 252;
358 while (true) : (pos -= 4) {
359 const slot = @truncate(u4, (s[pos >> 3] >> @truncate(u3, pos)));
360 if (vartime) {
361 if (slot != 0) {
362 q = q.add(pc[slot]);
363 }
364 } else {
365 q = q.add(pcSelect(16, pc, slot));
366 }
367 if (pos == 0) break;
368 q = q.dbl().dbl().dbl().dbl();
369 }
370 try q.rejectIdentity();
371 return q;
372 }
373
374 fn precompute(p: P256, comptime count: usize) [1 + count]P256 {
375 var pc: [1 + count]P256 = undefined;
376 pc[0] = P256.identityElement;
377 pc[1] = p;
378 var i: usize = 2;
379 while (i <= count) : (i += 1) {
380 pc[i] = if (i % 2 == 0) pc[i / 2].dbl() else pc[i - 1].add(p);
381 }
382 return pc;
383 }
384
385 /// Multiply an elliptic curve point by a scalar.
386 /// Return error.IdentityElement if the result is the identity element.
387 pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
388 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
389 const pc = if (p.is_base) precompute(P256.basePoint, 15) else pc: {
390 try p.rejectIdentity();
391 const xpc = precompute(p, 15);
392 break :pc xpc;
393 };
394 return pcMul16(pc, s, false);
395 }
396
397 /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME*
398 /// This can be used for signature verification.
399 pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
400 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
401 const pc = if (p.is_base) precompute(P256.basePoint, 8) else pc: {
402 try p.rejectIdentity();
403 const xpc = precompute(p, 8);
404 break :pc xpc;
405 };
406 return pcMul(pc, s, true);
407 }
408};
409
410test "p256" {
411 _ = @import("tests.zig");
412}
lib/std/crypto/pcurves/p256/field.zig created+18
...@@ -0,0 +1,18 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("std");
8const common = @import("../common.zig");
9
10const Field = common.Field;
11
12pub const Fe = Field(.{
13 .fiat = @import("p256_64.zig"),
14 .field_order = 115792089210356248762697446949407573530086143415290314195533631308867097853951,
15 .field_bits = 256,
16 .saturated_bits = 255,
17 .encoded_length = 32,
18});
lib/std/crypto/pcurves/p256/p256_64.zig created+1812
...@@ -0,0 +1,1812 @@
1// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --no-prefix-fiat --package-name p256 '' 64 '2^256 - 2^224 + 2^192 + 2^96 - 1' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp
2// curve description (via package name): p256
3// machine_wordsize = 64 (from "64")
4// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp
5// m = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff (from "2^256 - 2^224 + 2^192 + 2^96 - 1")
6//
7// NOTE: In addition to the bounds specified above each function, all
8// functions synthesized for this Montgomery arithmetic require the
9// input to be strictly less than the prime modulus (m), and also
10// require the input to be in the unique saturated representation.
11// All functions also ensure that these two properties are true of
12// return values.
13//
14// Computed values:
15// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
16// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
17// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
18// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
19
20const std = @import("std");
21const cast = std.meta.cast;
22const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels
23
24pub const Limbs = [4]u64;
25
26/// The function addcarryxU64 is an addition with carry.
27/// Postconditions:
28/// out1 = (arg1 + arg2 + arg3) mod 2^64
29/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
30///
31/// Input Bounds:
32/// arg1: [0x0 ~> 0x1]
33/// arg2: [0x0 ~> 0xffffffffffffffff]
34/// arg3: [0x0 ~> 0xffffffffffffffff]
35/// Output Bounds:
36/// out1: [0x0 ~> 0xffffffffffffffff]
37/// out2: [0x0 ~> 0x1]
38fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
39 @setRuntimeSafety(mode == .Debug);
40
41 var t: u64 = undefined;
42 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
43 const carry2 = @addWithOverflow(u64, t, arg1, out1);
44 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
45}
46
47/// The function subborrowxU64 is a subtraction with borrow.
48/// Postconditions:
49/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
50/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
51///
52/// Input Bounds:
53/// arg1: [0x0 ~> 0x1]
54/// arg2: [0x0 ~> 0xffffffffffffffff]
55/// arg3: [0x0 ~> 0xffffffffffffffff]
56/// Output Bounds:
57/// out1: [0x0 ~> 0xffffffffffffffff]
58/// out2: [0x0 ~> 0x1]
59fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
60 @setRuntimeSafety(mode == .Debug);
61
62 var t: u64 = undefined;
63 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
64 const carry2 = @subWithOverflow(u64, t, arg1, out1);
65 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
66}
67
68/// The function mulxU64 is a multiplication, returning the full double-width result.
69/// Postconditions:
70/// out1 = (arg1 * arg2) mod 2^64
71/// out2 = ⌊arg1 * arg2 / 2^64⌋
72///
73/// Input Bounds:
74/// arg1: [0x0 ~> 0xffffffffffffffff]
75/// arg2: [0x0 ~> 0xffffffffffffffff]
76/// Output Bounds:
77/// out1: [0x0 ~> 0xffffffffffffffff]
78/// out2: [0x0 ~> 0xffffffffffffffff]
79fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) callconv(.Inline) void {
80 @setRuntimeSafety(mode == .Debug);
81
82 const x = @as(u128, arg1) * @as(u128, arg2);
83 out1.* = @truncate(u64, x);
84 out2.* = @truncate(u64, x >> 64);
85}
86
87/// The function cmovznzU64 is a single-word conditional move.
88/// Postconditions:
89/// out1 = (if arg1 = 0 then arg2 else arg3)
90///
91/// Input Bounds:
92/// arg1: [0x0 ~> 0x1]
93/// arg2: [0x0 ~> 0xffffffffffffffff]
94/// arg3: [0x0 ~> 0xffffffffffffffff]
95/// Output Bounds:
96/// out1: [0x0 ~> 0xffffffffffffffff]
97fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
98 @setRuntimeSafety(mode == .Debug);
99
100 const mask = 0 -% @as(u64, arg1);
101 out1.* = (mask & arg3) | ((~mask) & arg2);
102}
103
104/// The function mul multiplies two field elements in the Montgomery domain.
105/// Preconditions:
106/// 0 ≤ eval arg1 < m
107/// 0 ≤ eval arg2 < m
108/// Postconditions:
109/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
110/// 0 ≤ eval out1 < m
111///
112/// Input Bounds:
113/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
114/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
115/// Output Bounds:
116/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
117pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
118 @setRuntimeSafety(mode == .Debug);
119
120 const x1 = (arg1[1]);
121 const x2 = (arg1[2]);
122 const x3 = (arg1[3]);
123 const x4 = (arg1[0]);
124 var x5: u64 = undefined;
125 var x6: u64 = undefined;
126 mulxU64(&x5, &x6, x4, (arg2[3]));
127 var x7: u64 = undefined;
128 var x8: u64 = undefined;
129 mulxU64(&x7, &x8, x4, (arg2[2]));
130 var x9: u64 = undefined;
131 var x10: u64 = undefined;
132 mulxU64(&x9, &x10, x4, (arg2[1]));
133 var x11: u64 = undefined;
134 var x12: u64 = undefined;
135 mulxU64(&x11, &x12, x4, (arg2[0]));
136 var x13: u64 = undefined;
137 var x14: u1 = undefined;
138 addcarryxU64(&x13, &x14, 0x0, x12, x9);
139 var x15: u64 = undefined;
140 var x16: u1 = undefined;
141 addcarryxU64(&x15, &x16, x14, x10, x7);
142 var x17: u64 = undefined;
143 var x18: u1 = undefined;
144 addcarryxU64(&x17, &x18, x16, x8, x5);
145 const x19 = (cast(u64, x18) + x6);
146 var x20: u64 = undefined;
147 var x21: u64 = undefined;
148 mulxU64(&x20, &x21, x11, 0xffffffff00000001);
149 var x22: u64 = undefined;
150 var x23: u64 = undefined;
151 mulxU64(&x22, &x23, x11, 0xffffffff);
152 var x24: u64 = undefined;
153 var x25: u64 = undefined;
154 mulxU64(&x24, &x25, x11, 0xffffffffffffffff);
155 var x26: u64 = undefined;
156 var x27: u1 = undefined;
157 addcarryxU64(&x26, &x27, 0x0, x25, x22);
158 const x28 = (cast(u64, x27) + x23);
159 var x29: u64 = undefined;
160 var x30: u1 = undefined;
161 addcarryxU64(&x29, &x30, 0x0, x11, x24);
162 var x31: u64 = undefined;
163 var x32: u1 = undefined;
164 addcarryxU64(&x31, &x32, x30, x13, x26);
165 var x33: u64 = undefined;
166 var x34: u1 = undefined;
167 addcarryxU64(&x33, &x34, x32, x15, x28);
168 var x35: u64 = undefined;
169 var x36: u1 = undefined;
170 addcarryxU64(&x35, &x36, x34, x17, x20);
171 var x37: u64 = undefined;
172 var x38: u1 = undefined;
173 addcarryxU64(&x37, &x38, x36, x19, x21);
174 var x39: u64 = undefined;
175 var x40: u64 = undefined;
176 mulxU64(&x39, &x40, x1, (arg2[3]));
177 var x41: u64 = undefined;
178 var x42: u64 = undefined;
179 mulxU64(&x41, &x42, x1, (arg2[2]));
180 var x43: u64 = undefined;
181 var x44: u64 = undefined;
182 mulxU64(&x43, &x44, x1, (arg2[1]));
183 var x45: u64 = undefined;
184 var x46: u64 = undefined;
185 mulxU64(&x45, &x46, x1, (arg2[0]));
186 var x47: u64 = undefined;
187 var x48: u1 = undefined;
188 addcarryxU64(&x47, &x48, 0x0, x46, x43);
189 var x49: u64 = undefined;
190 var x50: u1 = undefined;
191 addcarryxU64(&x49, &x50, x48, x44, x41);
192 var x51: u64 = undefined;
193 var x52: u1 = undefined;
194 addcarryxU64(&x51, &x52, x50, x42, x39);
195 const x53 = (cast(u64, x52) + x40);
196 var x54: u64 = undefined;
197 var x55: u1 = undefined;
198 addcarryxU64(&x54, &x55, 0x0, x31, x45);
199 var x56: u64 = undefined;
200 var x57: u1 = undefined;
201 addcarryxU64(&x56, &x57, x55, x33, x47);
202 var x58: u64 = undefined;
203 var x59: u1 = undefined;
204 addcarryxU64(&x58, &x59, x57, x35, x49);
205 var x60: u64 = undefined;
206 var x61: u1 = undefined;
207 addcarryxU64(&x60, &x61, x59, x37, x51);
208 var x62: u64 = undefined;
209 var x63: u1 = undefined;
210 addcarryxU64(&x62, &x63, x61, cast(u64, x38), x53);
211 var x64: u64 = undefined;
212 var x65: u64 = undefined;
213 mulxU64(&x64, &x65, x54, 0xffffffff00000001);
214 var x66: u64 = undefined;
215 var x67: u64 = undefined;
216 mulxU64(&x66, &x67, x54, 0xffffffff);
217 var x68: u64 = undefined;
218 var x69: u64 = undefined;
219 mulxU64(&x68, &x69, x54, 0xffffffffffffffff);
220 var x70: u64 = undefined;
221 var x71: u1 = undefined;
222 addcarryxU64(&x70, &x71, 0x0, x69, x66);
223 const x72 = (cast(u64, x71) + x67);
224 var x73: u64 = undefined;
225 var x74: u1 = undefined;
226 addcarryxU64(&x73, &x74, 0x0, x54, x68);
227 var x75: u64 = undefined;
228 var x76: u1 = undefined;
229 addcarryxU64(&x75, &x76, x74, x56, x70);
230 var x77: u64 = undefined;
231 var x78: u1 = undefined;
232 addcarryxU64(&x77, &x78, x76, x58, x72);
233 var x79: u64 = undefined;
234 var x80: u1 = undefined;
235 addcarryxU64(&x79, &x80, x78, x60, x64);
236 var x81: u64 = undefined;
237 var x82: u1 = undefined;
238 addcarryxU64(&x81, &x82, x80, x62, x65);
239 const x83 = (cast(u64, x82) + cast(u64, x63));
240 var x84: u64 = undefined;
241 var x85: u64 = undefined;
242 mulxU64(&x84, &x85, x2, (arg2[3]));
243 var x86: u64 = undefined;
244 var x87: u64 = undefined;
245 mulxU64(&x86, &x87, x2, (arg2[2]));
246 var x88: u64 = undefined;
247 var x89: u64 = undefined;
248 mulxU64(&x88, &x89, x2, (arg2[1]));
249 var x90: u64 = undefined;
250 var x91: u64 = undefined;
251 mulxU64(&x90, &x91, x2, (arg2[0]));
252 var x92: u64 = undefined;
253 var x93: u1 = undefined;
254 addcarryxU64(&x92, &x93, 0x0, x91, x88);
255 var x94: u64 = undefined;
256 var x95: u1 = undefined;
257 addcarryxU64(&x94, &x95, x93, x89, x86);
258 var x96: u64 = undefined;
259 var x97: u1 = undefined;
260 addcarryxU64(&x96, &x97, x95, x87, x84);
261 const x98 = (cast(u64, x97) + x85);
262 var x99: u64 = undefined;
263 var x100: u1 = undefined;
264 addcarryxU64(&x99, &x100, 0x0, x75, x90);
265 var x101: u64 = undefined;
266 var x102: u1 = undefined;
267 addcarryxU64(&x101, &x102, x100, x77, x92);
268 var x103: u64 = undefined;
269 var x104: u1 = undefined;
270 addcarryxU64(&x103, &x104, x102, x79, x94);
271 var x105: u64 = undefined;
272 var x106: u1 = undefined;
273 addcarryxU64(&x105, &x106, x104, x81, x96);
274 var x107: u64 = undefined;
275 var x108: u1 = undefined;
276 addcarryxU64(&x107, &x108, x106, x83, x98);
277 var x109: u64 = undefined;
278 var x110: u64 = undefined;
279 mulxU64(&x109, &x110, x99, 0xffffffff00000001);
280 var x111: u64 = undefined;
281 var x112: u64 = undefined;
282 mulxU64(&x111, &x112, x99, 0xffffffff);
283 var x113: u64 = undefined;
284 var x114: u64 = undefined;
285 mulxU64(&x113, &x114, x99, 0xffffffffffffffff);
286 var x115: u64 = undefined;
287 var x116: u1 = undefined;
288 addcarryxU64(&x115, &x116, 0x0, x114, x111);
289 const x117 = (cast(u64, x116) + x112);
290 var x118: u64 = undefined;
291 var x119: u1 = undefined;
292 addcarryxU64(&x118, &x119, 0x0, x99, x113);
293 var x120: u64 = undefined;
294 var x121: u1 = undefined;
295 addcarryxU64(&x120, &x121, x119, x101, x115);
296 var x122: u64 = undefined;
297 var x123: u1 = undefined;
298 addcarryxU64(&x122, &x123, x121, x103, x117);
299 var x124: u64 = undefined;
300 var x125: u1 = undefined;
301 addcarryxU64(&x124, &x125, x123, x105, x109);
302 var x126: u64 = undefined;
303 var x127: u1 = undefined;
304 addcarryxU64(&x126, &x127, x125, x107, x110);
305 const x128 = (cast(u64, x127) + cast(u64, x108));
306 var x129: u64 = undefined;
307 var x130: u64 = undefined;
308 mulxU64(&x129, &x130, x3, (arg2[3]));
309 var x131: u64 = undefined;
310 var x132: u64 = undefined;
311 mulxU64(&x131, &x132, x3, (arg2[2]));
312 var x133: u64 = undefined;
313 var x134: u64 = undefined;
314 mulxU64(&x133, &x134, x3, (arg2[1]));
315 var x135: u64 = undefined;
316 var x136: u64 = undefined;
317 mulxU64(&x135, &x136, x3, (arg2[0]));
318 var x137: u64 = undefined;
319 var x138: u1 = undefined;
320 addcarryxU64(&x137, &x138, 0x0, x136, x133);
321 var x139: u64 = undefined;
322 var x140: u1 = undefined;
323 addcarryxU64(&x139, &x140, x138, x134, x131);
324 var x141: u64 = undefined;
325 var x142: u1 = undefined;
326 addcarryxU64(&x141, &x142, x140, x132, x129);
327 const x143 = (cast(u64, x142) + x130);
328 var x144: u64 = undefined;
329 var x145: u1 = undefined;
330 addcarryxU64(&x144, &x145, 0x0, x120, x135);
331 var x146: u64 = undefined;
332 var x147: u1 = undefined;
333 addcarryxU64(&x146, &x147, x145, x122, x137);
334 var x148: u64 = undefined;
335 var x149: u1 = undefined;
336 addcarryxU64(&x148, &x149, x147, x124, x139);
337 var x150: u64 = undefined;
338 var x151: u1 = undefined;
339 addcarryxU64(&x150, &x151, x149, x126, x141);
340 var x152: u64 = undefined;
341 var x153: u1 = undefined;
342 addcarryxU64(&x152, &x153, x151, x128, x143);
343 var x154: u64 = undefined;
344 var x155: u64 = undefined;
345 mulxU64(&x154, &x155, x144, 0xffffffff00000001);
346 var x156: u64 = undefined;
347 var x157: u64 = undefined;
348 mulxU64(&x156, &x157, x144, 0xffffffff);
349 var x158: u64 = undefined;
350 var x159: u64 = undefined;
351 mulxU64(&x158, &x159, x144, 0xffffffffffffffff);
352 var x160: u64 = undefined;
353 var x161: u1 = undefined;
354 addcarryxU64(&x160, &x161, 0x0, x159, x156);
355 const x162 = (cast(u64, x161) + x157);
356 var x163: u64 = undefined;
357 var x164: u1 = undefined;
358 addcarryxU64(&x163, &x164, 0x0, x144, x158);
359 var x165: u64 = undefined;
360 var x166: u1 = undefined;
361 addcarryxU64(&x165, &x166, x164, x146, x160);
362 var x167: u64 = undefined;
363 var x168: u1 = undefined;
364 addcarryxU64(&x167, &x168, x166, x148, x162);
365 var x169: u64 = undefined;
366 var x170: u1 = undefined;
367 addcarryxU64(&x169, &x170, x168, x150, x154);
368 var x171: u64 = undefined;
369 var x172: u1 = undefined;
370 addcarryxU64(&x171, &x172, x170, x152, x155);
371 const x173 = (cast(u64, x172) + cast(u64, x153));
372 var x174: u64 = undefined;
373 var x175: u1 = undefined;
374 subborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff);
375 var x176: u64 = undefined;
376 var x177: u1 = undefined;
377 subborrowxU64(&x176, &x177, x175, x167, 0xffffffff);
378 var x178: u64 = undefined;
379 var x179: u1 = undefined;
380 subborrowxU64(&x178, &x179, x177, x169, cast(u64, 0x0));
381 var x180: u64 = undefined;
382 var x181: u1 = undefined;
383 subborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001);
384 var x182: u64 = undefined;
385 var x183: u1 = undefined;
386 subborrowxU64(&x182, &x183, x181, x173, cast(u64, 0x0));
387 var x184: u64 = undefined;
388 cmovznzU64(&x184, x183, x174, x165);
389 var x185: u64 = undefined;
390 cmovznzU64(&x185, x183, x176, x167);
391 var x186: u64 = undefined;
392 cmovznzU64(&x186, x183, x178, x169);
393 var x187: u64 = undefined;
394 cmovznzU64(&x187, x183, x180, x171);
395 out1[0] = x184;
396 out1[1] = x185;
397 out1[2] = x186;
398 out1[3] = x187;
399}
400
401/// The function square squares a field element in the Montgomery domain.
402/// Preconditions:
403/// 0 ≤ eval arg1 < m
404/// Postconditions:
405/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
406/// 0 ≤ eval out1 < m
407///
408/// Input Bounds:
409/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
410/// Output Bounds:
411/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
412pub fn square(out1: *[4]u64, arg1: [4]u64) void {
413 @setRuntimeSafety(mode == .Debug);
414
415 const x1 = (arg1[1]);
416 const x2 = (arg1[2]);
417 const x3 = (arg1[3]);
418 const x4 = (arg1[0]);
419 var x5: u64 = undefined;
420 var x6: u64 = undefined;
421 mulxU64(&x5, &x6, x4, (arg1[3]));
422 var x7: u64 = undefined;
423 var x8: u64 = undefined;
424 mulxU64(&x7, &x8, x4, (arg1[2]));
425 var x9: u64 = undefined;
426 var x10: u64 = undefined;
427 mulxU64(&x9, &x10, x4, (arg1[1]));
428 var x11: u64 = undefined;
429 var x12: u64 = undefined;
430 mulxU64(&x11, &x12, x4, (arg1[0]));
431 var x13: u64 = undefined;
432 var x14: u1 = undefined;
433 addcarryxU64(&x13, &x14, 0x0, x12, x9);
434 var x15: u64 = undefined;
435 var x16: u1 = undefined;
436 addcarryxU64(&x15, &x16, x14, x10, x7);
437 var x17: u64 = undefined;
438 var x18: u1 = undefined;
439 addcarryxU64(&x17, &x18, x16, x8, x5);
440 const x19 = (cast(u64, x18) + x6);
441 var x20: u64 = undefined;
442 var x21: u64 = undefined;
443 mulxU64(&x20, &x21, x11, 0xffffffff00000001);
444 var x22: u64 = undefined;
445 var x23: u64 = undefined;
446 mulxU64(&x22, &x23, x11, 0xffffffff);
447 var x24: u64 = undefined;
448 var x25: u64 = undefined;
449 mulxU64(&x24, &x25, x11, 0xffffffffffffffff);
450 var x26: u64 = undefined;
451 var x27: u1 = undefined;
452 addcarryxU64(&x26, &x27, 0x0, x25, x22);
453 const x28 = (cast(u64, x27) + x23);
454 var x29: u64 = undefined;
455 var x30: u1 = undefined;
456 addcarryxU64(&x29, &x30, 0x0, x11, x24);
457 var x31: u64 = undefined;
458 var x32: u1 = undefined;
459 addcarryxU64(&x31, &x32, x30, x13, x26);
460 var x33: u64 = undefined;
461 var x34: u1 = undefined;
462 addcarryxU64(&x33, &x34, x32, x15, x28);
463 var x35: u64 = undefined;
464 var x36: u1 = undefined;
465 addcarryxU64(&x35, &x36, x34, x17, x20);
466 var x37: u64 = undefined;
467 var x38: u1 = undefined;
468 addcarryxU64(&x37, &x38, x36, x19, x21);
469 var x39: u64 = undefined;
470 var x40: u64 = undefined;
471 mulxU64(&x39, &x40, x1, (arg1[3]));
472 var x41: u64 = undefined;
473 var x42: u64 = undefined;
474 mulxU64(&x41, &x42, x1, (arg1[2]));
475 var x43: u64 = undefined;
476 var x44: u64 = undefined;
477 mulxU64(&x43, &x44, x1, (arg1[1]));
478 var x45: u64 = undefined;
479 var x46: u64 = undefined;
480 mulxU64(&x45, &x46, x1, (arg1[0]));
481 var x47: u64 = undefined;
482 var x48: u1 = undefined;
483 addcarryxU64(&x47, &x48, 0x0, x46, x43);
484 var x49: u64 = undefined;
485 var x50: u1 = undefined;
486 addcarryxU64(&x49, &x50, x48, x44, x41);
487 var x51: u64 = undefined;
488 var x52: u1 = undefined;
489 addcarryxU64(&x51, &x52, x50, x42, x39);
490 const x53 = (cast(u64, x52) + x40);
491 var x54: u64 = undefined;
492 var x55: u1 = undefined;
493 addcarryxU64(&x54, &x55, 0x0, x31, x45);
494 var x56: u64 = undefined;
495 var x57: u1 = undefined;
496 addcarryxU64(&x56, &x57, x55, x33, x47);
497 var x58: u64 = undefined;
498 var x59: u1 = undefined;
499 addcarryxU64(&x58, &x59, x57, x35, x49);
500 var x60: u64 = undefined;
501 var x61: u1 = undefined;
502 addcarryxU64(&x60, &x61, x59, x37, x51);
503 var x62: u64 = undefined;
504 var x63: u1 = undefined;
505 addcarryxU64(&x62, &x63, x61, cast(u64, x38), x53);
506 var x64: u64 = undefined;
507 var x65: u64 = undefined;
508 mulxU64(&x64, &x65, x54, 0xffffffff00000001);
509 var x66: u64 = undefined;
510 var x67: u64 = undefined;
511 mulxU64(&x66, &x67, x54, 0xffffffff);
512 var x68: u64 = undefined;
513 var x69: u64 = undefined;
514 mulxU64(&x68, &x69, x54, 0xffffffffffffffff);
515 var x70: u64 = undefined;
516 var x71: u1 = undefined;
517 addcarryxU64(&x70, &x71, 0x0, x69, x66);
518 const x72 = (cast(u64, x71) + x67);
519 var x73: u64 = undefined;
520 var x74: u1 = undefined;
521 addcarryxU64(&x73, &x74, 0x0, x54, x68);
522 var x75: u64 = undefined;
523 var x76: u1 = undefined;
524 addcarryxU64(&x75, &x76, x74, x56, x70);
525 var x77: u64 = undefined;
526 var x78: u1 = undefined;
527 addcarryxU64(&x77, &x78, x76, x58, x72);
528 var x79: u64 = undefined;
529 var x80: u1 = undefined;
530 addcarryxU64(&x79, &x80, x78, x60, x64);
531 var x81: u64 = undefined;
532 var x82: u1 = undefined;
533 addcarryxU64(&x81, &x82, x80, x62, x65);
534 const x83 = (cast(u64, x82) + cast(u64, x63));
535 var x84: u64 = undefined;
536 var x85: u64 = undefined;
537 mulxU64(&x84, &x85, x2, (arg1[3]));
538 var x86: u64 = undefined;
539 var x87: u64 = undefined;
540 mulxU64(&x86, &x87, x2, (arg1[2]));
541 var x88: u64 = undefined;
542 var x89: u64 = undefined;
543 mulxU64(&x88, &x89, x2, (arg1[1]));
544 var x90: u64 = undefined;
545 var x91: u64 = undefined;
546 mulxU64(&x90, &x91, x2, (arg1[0]));
547 var x92: u64 = undefined;
548 var x93: u1 = undefined;
549 addcarryxU64(&x92, &x93, 0x0, x91, x88);
550 var x94: u64 = undefined;
551 var x95: u1 = undefined;
552 addcarryxU64(&x94, &x95, x93, x89, x86);
553 var x96: u64 = undefined;
554 var x97: u1 = undefined;
555 addcarryxU64(&x96, &x97, x95, x87, x84);
556 const x98 = (cast(u64, x97) + x85);
557 var x99: u64 = undefined;
558 var x100: u1 = undefined;
559 addcarryxU64(&x99, &x100, 0x0, x75, x90);
560 var x101: u64 = undefined;
561 var x102: u1 = undefined;
562 addcarryxU64(&x101, &x102, x100, x77, x92);
563 var x103: u64 = undefined;
564 var x104: u1 = undefined;
565 addcarryxU64(&x103, &x104, x102, x79, x94);
566 var x105: u64 = undefined;
567 var x106: u1 = undefined;
568 addcarryxU64(&x105, &x106, x104, x81, x96);
569 var x107: u64 = undefined;
570 var x108: u1 = undefined;
571 addcarryxU64(&x107, &x108, x106, x83, x98);
572 var x109: u64 = undefined;
573 var x110: u64 = undefined;
574 mulxU64(&x109, &x110, x99, 0xffffffff00000001);
575 var x111: u64 = undefined;
576 var x112: u64 = undefined;
577 mulxU64(&x111, &x112, x99, 0xffffffff);
578 var x113: u64 = undefined;
579 var x114: u64 = undefined;
580 mulxU64(&x113, &x114, x99, 0xffffffffffffffff);
581 var x115: u64 = undefined;
582 var x116: u1 = undefined;
583 addcarryxU64(&x115, &x116, 0x0, x114, x111);
584 const x117 = (cast(u64, x116) + x112);
585 var x118: u64 = undefined;
586 var x119: u1 = undefined;
587 addcarryxU64(&x118, &x119, 0x0, x99, x113);
588 var x120: u64 = undefined;
589 var x121: u1 = undefined;
590 addcarryxU64(&x120, &x121, x119, x101, x115);
591 var x122: u64 = undefined;
592 var x123: u1 = undefined;
593 addcarryxU64(&x122, &x123, x121, x103, x117);
594 var x124: u64 = undefined;
595 var x125: u1 = undefined;
596 addcarryxU64(&x124, &x125, x123, x105, x109);
597 var x126: u64 = undefined;
598 var x127: u1 = undefined;
599 addcarryxU64(&x126, &x127, x125, x107, x110);
600 const x128 = (cast(u64, x127) + cast(u64, x108));
601 var x129: u64 = undefined;
602 var x130: u64 = undefined;
603 mulxU64(&x129, &x130, x3, (arg1[3]));
604 var x131: u64 = undefined;
605 var x132: u64 = undefined;
606 mulxU64(&x131, &x132, x3, (arg1[2]));
607 var x133: u64 = undefined;
608 var x134: u64 = undefined;
609 mulxU64(&x133, &x134, x3, (arg1[1]));
610 var x135: u64 = undefined;
611 var x136: u64 = undefined;
612 mulxU64(&x135, &x136, x3, (arg1[0]));
613 var x137: u64 = undefined;
614 var x138: u1 = undefined;
615 addcarryxU64(&x137, &x138, 0x0, x136, x133);
616 var x139: u64 = undefined;
617 var x140: u1 = undefined;
618 addcarryxU64(&x139, &x140, x138, x134, x131);
619 var x141: u64 = undefined;
620 var x142: u1 = undefined;
621 addcarryxU64(&x141, &x142, x140, x132, x129);
622 const x143 = (cast(u64, x142) + x130);
623 var x144: u64 = undefined;
624 var x145: u1 = undefined;
625 addcarryxU64(&x144, &x145, 0x0, x120, x135);
626 var x146: u64 = undefined;
627 var x147: u1 = undefined;
628 addcarryxU64(&x146, &x147, x145, x122, x137);
629 var x148: u64 = undefined;
630 var x149: u1 = undefined;
631 addcarryxU64(&x148, &x149, x147, x124, x139);
632 var x150: u64 = undefined;
633 var x151: u1 = undefined;
634 addcarryxU64(&x150, &x151, x149, x126, x141);
635 var x152: u64 = undefined;
636 var x153: u1 = undefined;
637 addcarryxU64(&x152, &x153, x151, x128, x143);
638 var x154: u64 = undefined;
639 var x155: u64 = undefined;
640 mulxU64(&x154, &x155, x144, 0xffffffff00000001);
641 var x156: u64 = undefined;
642 var x157: u64 = undefined;
643 mulxU64(&x156, &x157, x144, 0xffffffff);
644 var x158: u64 = undefined;
645 var x159: u64 = undefined;
646 mulxU64(&x158, &x159, x144, 0xffffffffffffffff);
647 var x160: u64 = undefined;
648 var x161: u1 = undefined;
649 addcarryxU64(&x160, &x161, 0x0, x159, x156);
650 const x162 = (cast(u64, x161) + x157);
651 var x163: u64 = undefined;
652 var x164: u1 = undefined;
653 addcarryxU64(&x163, &x164, 0x0, x144, x158);
654 var x165: u64 = undefined;
655 var x166: u1 = undefined;
656 addcarryxU64(&x165, &x166, x164, x146, x160);
657 var x167: u64 = undefined;
658 var x168: u1 = undefined;
659 addcarryxU64(&x167, &x168, x166, x148, x162);
660 var x169: u64 = undefined;
661 var x170: u1 = undefined;
662 addcarryxU64(&x169, &x170, x168, x150, x154);
663 var x171: u64 = undefined;
664 var x172: u1 = undefined;
665 addcarryxU64(&x171, &x172, x170, x152, x155);
666 const x173 = (cast(u64, x172) + cast(u64, x153));
667 var x174: u64 = undefined;
668 var x175: u1 = undefined;
669 subborrowxU64(&x174, &x175, 0x0, x165, 0xffffffffffffffff);
670 var x176: u64 = undefined;
671 var x177: u1 = undefined;
672 subborrowxU64(&x176, &x177, x175, x167, 0xffffffff);
673 var x178: u64 = undefined;
674 var x179: u1 = undefined;
675 subborrowxU64(&x178, &x179, x177, x169, cast(u64, 0x0));
676 var x180: u64 = undefined;
677 var x181: u1 = undefined;
678 subborrowxU64(&x180, &x181, x179, x171, 0xffffffff00000001);
679 var x182: u64 = undefined;
680 var x183: u1 = undefined;
681 subborrowxU64(&x182, &x183, x181, x173, cast(u64, 0x0));
682 var x184: u64 = undefined;
683 cmovznzU64(&x184, x183, x174, x165);
684 var x185: u64 = undefined;
685 cmovznzU64(&x185, x183, x176, x167);
686 var x186: u64 = undefined;
687 cmovznzU64(&x186, x183, x178, x169);
688 var x187: u64 = undefined;
689 cmovznzU64(&x187, x183, x180, x171);
690 out1[0] = x184;
691 out1[1] = x185;
692 out1[2] = x186;
693 out1[3] = x187;
694}
695
696/// The function add adds two field elements in the Montgomery domain.
697/// Preconditions:
698/// 0 ≤ eval arg1 < m
699/// 0 ≤ eval arg2 < m
700/// Postconditions:
701/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
702/// 0 ≤ eval out1 < m
703///
704/// Input Bounds:
705/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
706/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
707/// Output Bounds:
708/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
709pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
710 @setRuntimeSafety(mode == .Debug);
711
712 var x1: u64 = undefined;
713 var x2: u1 = undefined;
714 addcarryxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
715 var x3: u64 = undefined;
716 var x4: u1 = undefined;
717 addcarryxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
718 var x5: u64 = undefined;
719 var x6: u1 = undefined;
720 addcarryxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
721 var x7: u64 = undefined;
722 var x8: u1 = undefined;
723 addcarryxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
724 var x9: u64 = undefined;
725 var x10: u1 = undefined;
726 subborrowxU64(&x9, &x10, 0x0, x1, 0xffffffffffffffff);
727 var x11: u64 = undefined;
728 var x12: u1 = undefined;
729 subborrowxU64(&x11, &x12, x10, x3, 0xffffffff);
730 var x13: u64 = undefined;
731 var x14: u1 = undefined;
732 subborrowxU64(&x13, &x14, x12, x5, cast(u64, 0x0));
733 var x15: u64 = undefined;
734 var x16: u1 = undefined;
735 subborrowxU64(&x15, &x16, x14, x7, 0xffffffff00000001);
736 var x17: u64 = undefined;
737 var x18: u1 = undefined;
738 subborrowxU64(&x17, &x18, x16, cast(u64, x8), cast(u64, 0x0));
739 var x19: u64 = undefined;
740 cmovznzU64(&x19, x18, x9, x1);
741 var x20: u64 = undefined;
742 cmovznzU64(&x20, x18, x11, x3);
743 var x21: u64 = undefined;
744 cmovznzU64(&x21, x18, x13, x5);
745 var x22: u64 = undefined;
746 cmovznzU64(&x22, x18, x15, x7);
747 out1[0] = x19;
748 out1[1] = x20;
749 out1[2] = x21;
750 out1[3] = x22;
751}
752
753/// The function sub subtracts two field elements in the Montgomery domain.
754/// Preconditions:
755/// 0 ≤ eval arg1 < m
756/// 0 ≤ eval arg2 < m
757/// Postconditions:
758/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
759/// 0 ≤ eval out1 < m
760///
761/// Input Bounds:
762/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
763/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
764/// Output Bounds:
765/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
766pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
767 @setRuntimeSafety(mode == .Debug);
768
769 var x1: u64 = undefined;
770 var x2: u1 = undefined;
771 subborrowxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
772 var x3: u64 = undefined;
773 var x4: u1 = undefined;
774 subborrowxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
775 var x5: u64 = undefined;
776 var x6: u1 = undefined;
777 subborrowxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
778 var x7: u64 = undefined;
779 var x8: u1 = undefined;
780 subborrowxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
781 var x9: u64 = undefined;
782 cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
783 var x10: u64 = undefined;
784 var x11: u1 = undefined;
785 addcarryxU64(&x10, &x11, 0x0, x1, x9);
786 var x12: u64 = undefined;
787 var x13: u1 = undefined;
788 addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff));
789 var x14: u64 = undefined;
790 var x15: u1 = undefined;
791 addcarryxU64(&x14, &x15, x13, x5, cast(u64, 0x0));
792 var x16: u64 = undefined;
793 var x17: u1 = undefined;
794 addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001));
795 out1[0] = x10;
796 out1[1] = x12;
797 out1[2] = x14;
798 out1[3] = x16;
799}
800
801/// The function opp negates a field element in the Montgomery domain.
802/// Preconditions:
803/// 0 ≤ eval arg1 < m
804/// Postconditions:
805/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
806/// 0 ≤ eval out1 < m
807///
808/// Input Bounds:
809/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
810/// Output Bounds:
811/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
812pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
813 @setRuntimeSafety(mode == .Debug);
814
815 var x1: u64 = undefined;
816 var x2: u1 = undefined;
817 subborrowxU64(&x1, &x2, 0x0, cast(u64, 0x0), (arg1[0]));
818 var x3: u64 = undefined;
819 var x4: u1 = undefined;
820 subborrowxU64(&x3, &x4, x2, cast(u64, 0x0), (arg1[1]));
821 var x5: u64 = undefined;
822 var x6: u1 = undefined;
823 subborrowxU64(&x5, &x6, x4, cast(u64, 0x0), (arg1[2]));
824 var x7: u64 = undefined;
825 var x8: u1 = undefined;
826 subborrowxU64(&x7, &x8, x6, cast(u64, 0x0), (arg1[3]));
827 var x9: u64 = undefined;
828 cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
829 var x10: u64 = undefined;
830 var x11: u1 = undefined;
831 addcarryxU64(&x10, &x11, 0x0, x1, x9);
832 var x12: u64 = undefined;
833 var x13: u1 = undefined;
834 addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xffffffff));
835 var x14: u64 = undefined;
836 var x15: u1 = undefined;
837 addcarryxU64(&x14, &x15, x13, x5, cast(u64, 0x0));
838 var x16: u64 = undefined;
839 var x17: u1 = undefined;
840 addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000001));
841 out1[0] = x10;
842 out1[1] = x12;
843 out1[2] = x14;
844 out1[3] = x16;
845}
846
847/// The function fromMontgomery translates a field element out of the Montgomery domain.
848/// Preconditions:
849/// 0 ≤ eval arg1 < m
850/// Postconditions:
851/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
852/// 0 ≤ eval out1 < m
853///
854/// Input Bounds:
855/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
856/// Output Bounds:
857/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
858pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
859 @setRuntimeSafety(mode == .Debug);
860
861 const x1 = (arg1[0]);
862 var x2: u64 = undefined;
863 var x3: u64 = undefined;
864 mulxU64(&x2, &x3, x1, 0xffffffff00000001);
865 var x4: u64 = undefined;
866 var x5: u64 = undefined;
867 mulxU64(&x4, &x5, x1, 0xffffffff);
868 var x6: u64 = undefined;
869 var x7: u64 = undefined;
870 mulxU64(&x6, &x7, x1, 0xffffffffffffffff);
871 var x8: u64 = undefined;
872 var x9: u1 = undefined;
873 addcarryxU64(&x8, &x9, 0x0, x7, x4);
874 var x10: u64 = undefined;
875 var x11: u1 = undefined;
876 addcarryxU64(&x10, &x11, 0x0, x1, x6);
877 var x12: u64 = undefined;
878 var x13: u1 = undefined;
879 addcarryxU64(&x12, &x13, x11, cast(u64, 0x0), x8);
880 var x14: u64 = undefined;
881 var x15: u1 = undefined;
882 addcarryxU64(&x14, &x15, 0x0, x12, (arg1[1]));
883 var x16: u64 = undefined;
884 var x17: u64 = undefined;
885 mulxU64(&x16, &x17, x14, 0xffffffff00000001);
886 var x18: u64 = undefined;
887 var x19: u64 = undefined;
888 mulxU64(&x18, &x19, x14, 0xffffffff);
889 var x20: u64 = undefined;
890 var x21: u64 = undefined;
891 mulxU64(&x20, &x21, x14, 0xffffffffffffffff);
892 var x22: u64 = undefined;
893 var x23: u1 = undefined;
894 addcarryxU64(&x22, &x23, 0x0, x21, x18);
895 var x24: u64 = undefined;
896 var x25: u1 = undefined;
897 addcarryxU64(&x24, &x25, 0x0, x14, x20);
898 var x26: u64 = undefined;
899 var x27: u1 = undefined;
900 addcarryxU64(&x26, &x27, x25, (cast(u64, x15) + (cast(u64, x13) + (cast(u64, x9) + x5))), x22);
901 var x28: u64 = undefined;
902 var x29: u1 = undefined;
903 addcarryxU64(&x28, &x29, x27, x2, (cast(u64, x23) + x19));
904 var x30: u64 = undefined;
905 var x31: u1 = undefined;
906 addcarryxU64(&x30, &x31, x29, x3, x16);
907 var x32: u64 = undefined;
908 var x33: u1 = undefined;
909 addcarryxU64(&x32, &x33, 0x0, x26, (arg1[2]));
910 var x34: u64 = undefined;
911 var x35: u1 = undefined;
912 addcarryxU64(&x34, &x35, x33, x28, cast(u64, 0x0));
913 var x36: u64 = undefined;
914 var x37: u1 = undefined;
915 addcarryxU64(&x36, &x37, x35, x30, cast(u64, 0x0));
916 var x38: u64 = undefined;
917 var x39: u64 = undefined;
918 mulxU64(&x38, &x39, x32, 0xffffffff00000001);
919 var x40: u64 = undefined;
920 var x41: u64 = undefined;
921 mulxU64(&x40, &x41, x32, 0xffffffff);
922 var x42: u64 = undefined;
923 var x43: u64 = undefined;
924 mulxU64(&x42, &x43, x32, 0xffffffffffffffff);
925 var x44: u64 = undefined;
926 var x45: u1 = undefined;
927 addcarryxU64(&x44, &x45, 0x0, x43, x40);
928 var x46: u64 = undefined;
929 var x47: u1 = undefined;
930 addcarryxU64(&x46, &x47, 0x0, x32, x42);
931 var x48: u64 = undefined;
932 var x49: u1 = undefined;
933 addcarryxU64(&x48, &x49, x47, x34, x44);
934 var x50: u64 = undefined;
935 var x51: u1 = undefined;
936 addcarryxU64(&x50, &x51, x49, x36, (cast(u64, x45) + x41));
937 var x52: u64 = undefined;
938 var x53: u1 = undefined;
939 addcarryxU64(&x52, &x53, x51, (cast(u64, x37) + (cast(u64, x31) + x17)), x38);
940 var x54: u64 = undefined;
941 var x55: u1 = undefined;
942 addcarryxU64(&x54, &x55, 0x0, x48, (arg1[3]));
943 var x56: u64 = undefined;
944 var x57: u1 = undefined;
945 addcarryxU64(&x56, &x57, x55, x50, cast(u64, 0x0));
946 var x58: u64 = undefined;
947 var x59: u1 = undefined;
948 addcarryxU64(&x58, &x59, x57, x52, cast(u64, 0x0));
949 var x60: u64 = undefined;
950 var x61: u64 = undefined;
951 mulxU64(&x60, &x61, x54, 0xffffffff00000001);
952 var x62: u64 = undefined;
953 var x63: u64 = undefined;
954 mulxU64(&x62, &x63, x54, 0xffffffff);
955 var x64: u64 = undefined;
956 var x65: u64 = undefined;
957 mulxU64(&x64, &x65, x54, 0xffffffffffffffff);
958 var x66: u64 = undefined;
959 var x67: u1 = undefined;
960 addcarryxU64(&x66, &x67, 0x0, x65, x62);
961 var x68: u64 = undefined;
962 var x69: u1 = undefined;
963 addcarryxU64(&x68, &x69, 0x0, x54, x64);
964 var x70: u64 = undefined;
965 var x71: u1 = undefined;
966 addcarryxU64(&x70, &x71, x69, x56, x66);
967 var x72: u64 = undefined;
968 var x73: u1 = undefined;
969 addcarryxU64(&x72, &x73, x71, x58, (cast(u64, x67) + x63));
970 var x74: u64 = undefined;
971 var x75: u1 = undefined;
972 addcarryxU64(&x74, &x75, x73, (cast(u64, x59) + (cast(u64, x53) + x39)), x60);
973 const x76 = (cast(u64, x75) + x61);
974 var x77: u64 = undefined;
975 var x78: u1 = undefined;
976 subborrowxU64(&x77, &x78, 0x0, x70, 0xffffffffffffffff);
977 var x79: u64 = undefined;
978 var x80: u1 = undefined;
979 subborrowxU64(&x79, &x80, x78, x72, 0xffffffff);
980 var x81: u64 = undefined;
981 var x82: u1 = undefined;
982 subborrowxU64(&x81, &x82, x80, x74, cast(u64, 0x0));
983 var x83: u64 = undefined;
984 var x84: u1 = undefined;
985 subborrowxU64(&x83, &x84, x82, x76, 0xffffffff00000001);
986 var x85: u64 = undefined;
987 var x86: u1 = undefined;
988 subborrowxU64(&x85, &x86, x84, cast(u64, 0x0), cast(u64, 0x0));
989 var x87: u64 = undefined;
990 cmovznzU64(&x87, x86, x77, x70);
991 var x88: u64 = undefined;
992 cmovznzU64(&x88, x86, x79, x72);
993 var x89: u64 = undefined;
994 cmovznzU64(&x89, x86, x81, x74);
995 var x90: u64 = undefined;
996 cmovznzU64(&x90, x86, x83, x76);
997 out1[0] = x87;
998 out1[1] = x88;
999 out1[2] = x89;
1000 out1[3] = x90;
1001}
1002
1003/// The function toMontgomery translates a field element into the Montgomery domain.
1004/// Preconditions:
1005/// 0 ≤ eval arg1 < m
1006/// Postconditions:
1007/// eval (from_montgomery out1) mod m = eval arg1 mod m
1008/// 0 ≤ eval out1 < m
1009///
1010/// Input Bounds:
1011/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1012/// Output Bounds:
1013/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1014pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1015 @setRuntimeSafety(mode == .Debug);
1016
1017 const x1 = (arg1[1]);
1018 const x2 = (arg1[2]);
1019 const x3 = (arg1[3]);
1020 const x4 = (arg1[0]);
1021 var x5: u64 = undefined;
1022 var x6: u64 = undefined;
1023 mulxU64(&x5, &x6, x4, 0x4fffffffd);
1024 var x7: u64 = undefined;
1025 var x8: u64 = undefined;
1026 mulxU64(&x7, &x8, x4, 0xfffffffffffffffe);
1027 var x9: u64 = undefined;
1028 var x10: u64 = undefined;
1029 mulxU64(&x9, &x10, x4, 0xfffffffbffffffff);
1030 var x11: u64 = undefined;
1031 var x12: u64 = undefined;
1032 mulxU64(&x11, &x12, x4, 0x3);
1033 var x13: u64 = undefined;
1034 var x14: u1 = undefined;
1035 addcarryxU64(&x13, &x14, 0x0, x12, x9);
1036 var x15: u64 = undefined;
1037 var x16: u1 = undefined;
1038 addcarryxU64(&x15, &x16, x14, x10, x7);
1039 var x17: u64 = undefined;
1040 var x18: u1 = undefined;
1041 addcarryxU64(&x17, &x18, x16, x8, x5);
1042 var x19: u64 = undefined;
1043 var x20: u64 = undefined;
1044 mulxU64(&x19, &x20, x11, 0xffffffff00000001);
1045 var x21: u64 = undefined;
1046 var x22: u64 = undefined;
1047 mulxU64(&x21, &x22, x11, 0xffffffff);
1048 var x23: u64 = undefined;
1049 var x24: u64 = undefined;
1050 mulxU64(&x23, &x24, x11, 0xffffffffffffffff);
1051 var x25: u64 = undefined;
1052 var x26: u1 = undefined;
1053 addcarryxU64(&x25, &x26, 0x0, x24, x21);
1054 var x27: u64 = undefined;
1055 var x28: u1 = undefined;
1056 addcarryxU64(&x27, &x28, 0x0, x11, x23);
1057 var x29: u64 = undefined;
1058 var x30: u1 = undefined;
1059 addcarryxU64(&x29, &x30, x28, x13, x25);
1060 var x31: u64 = undefined;
1061 var x32: u1 = undefined;
1062 addcarryxU64(&x31, &x32, x30, x15, (cast(u64, x26) + x22));
1063 var x33: u64 = undefined;
1064 var x34: u1 = undefined;
1065 addcarryxU64(&x33, &x34, x32, x17, x19);
1066 var x35: u64 = undefined;
1067 var x36: u1 = undefined;
1068 addcarryxU64(&x35, &x36, x34, (cast(u64, x18) + x6), x20);
1069 var x37: u64 = undefined;
1070 var x38: u64 = undefined;
1071 mulxU64(&x37, &x38, x1, 0x4fffffffd);
1072 var x39: u64 = undefined;
1073 var x40: u64 = undefined;
1074 mulxU64(&x39, &x40, x1, 0xfffffffffffffffe);
1075 var x41: u64 = undefined;
1076 var x42: u64 = undefined;
1077 mulxU64(&x41, &x42, x1, 0xfffffffbffffffff);
1078 var x43: u64 = undefined;
1079 var x44: u64 = undefined;
1080 mulxU64(&x43, &x44, x1, 0x3);
1081 var x45: u64 = undefined;
1082 var x46: u1 = undefined;
1083 addcarryxU64(&x45, &x46, 0x0, x44, x41);
1084 var x47: u64 = undefined;
1085 var x48: u1 = undefined;
1086 addcarryxU64(&x47, &x48, x46, x42, x39);
1087 var x49: u64 = undefined;
1088 var x50: u1 = undefined;
1089 addcarryxU64(&x49, &x50, x48, x40, x37);
1090 var x51: u64 = undefined;
1091 var x52: u1 = undefined;
1092 addcarryxU64(&x51, &x52, 0x0, x29, x43);
1093 var x53: u64 = undefined;
1094 var x54: u1 = undefined;
1095 addcarryxU64(&x53, &x54, x52, x31, x45);
1096 var x55: u64 = undefined;
1097 var x56: u1 = undefined;
1098 addcarryxU64(&x55, &x56, x54, x33, x47);
1099 var x57: u64 = undefined;
1100 var x58: u1 = undefined;
1101 addcarryxU64(&x57, &x58, x56, x35, x49);
1102 var x59: u64 = undefined;
1103 var x60: u64 = undefined;
1104 mulxU64(&x59, &x60, x51, 0xffffffff00000001);
1105 var x61: u64 = undefined;
1106 var x62: u64 = undefined;
1107 mulxU64(&x61, &x62, x51, 0xffffffff);
1108 var x63: u64 = undefined;
1109 var x64: u64 = undefined;
1110 mulxU64(&x63, &x64, x51, 0xffffffffffffffff);
1111 var x65: u64 = undefined;
1112 var x66: u1 = undefined;
1113 addcarryxU64(&x65, &x66, 0x0, x64, x61);
1114 var x67: u64 = undefined;
1115 var x68: u1 = undefined;
1116 addcarryxU64(&x67, &x68, 0x0, x51, x63);
1117 var x69: u64 = undefined;
1118 var x70: u1 = undefined;
1119 addcarryxU64(&x69, &x70, x68, x53, x65);
1120 var x71: u64 = undefined;
1121 var x72: u1 = undefined;
1122 addcarryxU64(&x71, &x72, x70, x55, (cast(u64, x66) + x62));
1123 var x73: u64 = undefined;
1124 var x74: u1 = undefined;
1125 addcarryxU64(&x73, &x74, x72, x57, x59);
1126 var x75: u64 = undefined;
1127 var x76: u1 = undefined;
1128 addcarryxU64(&x75, &x76, x74, ((cast(u64, x58) + cast(u64, x36)) + (cast(u64, x50) + x38)), x60);
1129 var x77: u64 = undefined;
1130 var x78: u64 = undefined;
1131 mulxU64(&x77, &x78, x2, 0x4fffffffd);
1132 var x79: u64 = undefined;
1133 var x80: u64 = undefined;
1134 mulxU64(&x79, &x80, x2, 0xfffffffffffffffe);
1135 var x81: u64 = undefined;
1136 var x82: u64 = undefined;
1137 mulxU64(&x81, &x82, x2, 0xfffffffbffffffff);
1138 var x83: u64 = undefined;
1139 var x84: u64 = undefined;
1140 mulxU64(&x83, &x84, x2, 0x3);
1141 var x85: u64 = undefined;
1142 var x86: u1 = undefined;
1143 addcarryxU64(&x85, &x86, 0x0, x84, x81);
1144 var x87: u64 = undefined;
1145 var x88: u1 = undefined;
1146 addcarryxU64(&x87, &x88, x86, x82, x79);
1147 var x89: u64 = undefined;
1148 var x90: u1 = undefined;
1149 addcarryxU64(&x89, &x90, x88, x80, x77);
1150 var x91: u64 = undefined;
1151 var x92: u1 = undefined;
1152 addcarryxU64(&x91, &x92, 0x0, x69, x83);
1153 var x93: u64 = undefined;
1154 var x94: u1 = undefined;
1155 addcarryxU64(&x93, &x94, x92, x71, x85);
1156 var x95: u64 = undefined;
1157 var x96: u1 = undefined;
1158 addcarryxU64(&x95, &x96, x94, x73, x87);
1159 var x97: u64 = undefined;
1160 var x98: u1 = undefined;
1161 addcarryxU64(&x97, &x98, x96, x75, x89);
1162 var x99: u64 = undefined;
1163 var x100: u64 = undefined;
1164 mulxU64(&x99, &x100, x91, 0xffffffff00000001);
1165 var x101: u64 = undefined;
1166 var x102: u64 = undefined;
1167 mulxU64(&x101, &x102, x91, 0xffffffff);
1168 var x103: u64 = undefined;
1169 var x104: u64 = undefined;
1170 mulxU64(&x103, &x104, x91, 0xffffffffffffffff);
1171 var x105: u64 = undefined;
1172 var x106: u1 = undefined;
1173 addcarryxU64(&x105, &x106, 0x0, x104, x101);
1174 var x107: u64 = undefined;
1175 var x108: u1 = undefined;
1176 addcarryxU64(&x107, &x108, 0x0, x91, x103);
1177 var x109: u64 = undefined;
1178 var x110: u1 = undefined;
1179 addcarryxU64(&x109, &x110, x108, x93, x105);
1180 var x111: u64 = undefined;
1181 var x112: u1 = undefined;
1182 addcarryxU64(&x111, &x112, x110, x95, (cast(u64, x106) + x102));
1183 var x113: u64 = undefined;
1184 var x114: u1 = undefined;
1185 addcarryxU64(&x113, &x114, x112, x97, x99);
1186 var x115: u64 = undefined;
1187 var x116: u1 = undefined;
1188 addcarryxU64(&x115, &x116, x114, ((cast(u64, x98) + cast(u64, x76)) + (cast(u64, x90) + x78)), x100);
1189 var x117: u64 = undefined;
1190 var x118: u64 = undefined;
1191 mulxU64(&x117, &x118, x3, 0x4fffffffd);
1192 var x119: u64 = undefined;
1193 var x120: u64 = undefined;
1194 mulxU64(&x119, &x120, x3, 0xfffffffffffffffe);
1195 var x121: u64 = undefined;
1196 var x122: u64 = undefined;
1197 mulxU64(&x121, &x122, x3, 0xfffffffbffffffff);
1198 var x123: u64 = undefined;
1199 var x124: u64 = undefined;
1200 mulxU64(&x123, &x124, x3, 0x3);
1201 var x125: u64 = undefined;
1202 var x126: u1 = undefined;
1203 addcarryxU64(&x125, &x126, 0x0, x124, x121);
1204 var x127: u64 = undefined;
1205 var x128: u1 = undefined;
1206 addcarryxU64(&x127, &x128, x126, x122, x119);
1207 var x129: u64 = undefined;
1208 var x130: u1 = undefined;
1209 addcarryxU64(&x129, &x130, x128, x120, x117);
1210 var x131: u64 = undefined;
1211 var x132: u1 = undefined;
1212 addcarryxU64(&x131, &x132, 0x0, x109, x123);
1213 var x133: u64 = undefined;
1214 var x134: u1 = undefined;
1215 addcarryxU64(&x133, &x134, x132, x111, x125);
1216 var x135: u64 = undefined;
1217 var x136: u1 = undefined;
1218 addcarryxU64(&x135, &x136, x134, x113, x127);
1219 var x137: u64 = undefined;
1220 var x138: u1 = undefined;
1221 addcarryxU64(&x137, &x138, x136, x115, x129);
1222 var x139: u64 = undefined;
1223 var x140: u64 = undefined;
1224 mulxU64(&x139, &x140, x131, 0xffffffff00000001);
1225 var x141: u64 = undefined;
1226 var x142: u64 = undefined;
1227 mulxU64(&x141, &x142, x131, 0xffffffff);
1228 var x143: u64 = undefined;
1229 var x144: u64 = undefined;
1230 mulxU64(&x143, &x144, x131, 0xffffffffffffffff);
1231 var x145: u64 = undefined;
1232 var x146: u1 = undefined;
1233 addcarryxU64(&x145, &x146, 0x0, x144, x141);
1234 var x147: u64 = undefined;
1235 var x148: u1 = undefined;
1236 addcarryxU64(&x147, &x148, 0x0, x131, x143);
1237 var x149: u64 = undefined;
1238 var x150: u1 = undefined;
1239 addcarryxU64(&x149, &x150, x148, x133, x145);
1240 var x151: u64 = undefined;
1241 var x152: u1 = undefined;
1242 addcarryxU64(&x151, &x152, x150, x135, (cast(u64, x146) + x142));
1243 var x153: u64 = undefined;
1244 var x154: u1 = undefined;
1245 addcarryxU64(&x153, &x154, x152, x137, x139);
1246 var x155: u64 = undefined;
1247 var x156: u1 = undefined;
1248 addcarryxU64(&x155, &x156, x154, ((cast(u64, x138) + cast(u64, x116)) + (cast(u64, x130) + x118)), x140);
1249 var x157: u64 = undefined;
1250 var x158: u1 = undefined;
1251 subborrowxU64(&x157, &x158, 0x0, x149, 0xffffffffffffffff);
1252 var x159: u64 = undefined;
1253 var x160: u1 = undefined;
1254 subborrowxU64(&x159, &x160, x158, x151, 0xffffffff);
1255 var x161: u64 = undefined;
1256 var x162: u1 = undefined;
1257 subborrowxU64(&x161, &x162, x160, x153, cast(u64, 0x0));
1258 var x163: u64 = undefined;
1259 var x164: u1 = undefined;
1260 subborrowxU64(&x163, &x164, x162, x155, 0xffffffff00000001);
1261 var x165: u64 = undefined;
1262 var x166: u1 = undefined;
1263 subborrowxU64(&x165, &x166, x164, cast(u64, x156), cast(u64, 0x0));
1264 var x167: u64 = undefined;
1265 cmovznzU64(&x167, x166, x157, x149);
1266 var x168: u64 = undefined;
1267 cmovznzU64(&x168, x166, x159, x151);
1268 var x169: u64 = undefined;
1269 cmovznzU64(&x169, x166, x161, x153);
1270 var x170: u64 = undefined;
1271 cmovznzU64(&x170, x166, x163, x155);
1272 out1[0] = x167;
1273 out1[1] = x168;
1274 out1[2] = x169;
1275 out1[3] = x170;
1276}
1277
1278/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
1279/// Preconditions:
1280/// 0 ≤ eval arg1 < m
1281/// Postconditions:
1282/// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0
1283///
1284/// Input Bounds:
1285/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1286/// Output Bounds:
1287/// out1: [0x0 ~> 0xffffffffffffffff]
1288pub fn nonzero(out1: *u64, arg1: [4]u64) void {
1289 @setRuntimeSafety(mode == .Debug);
1290
1291 const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3]))));
1292 out1.* = x1;
1293}
1294
1295/// The function selectznz is a multi-limb conditional select.
1296/// Postconditions:
1297/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
1298///
1299/// Input Bounds:
1300/// arg1: [0x0 ~> 0x1]
1301/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1302/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1303/// Output Bounds:
1304/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1305pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
1306 @setRuntimeSafety(mode == .Debug);
1307
1308 var x1: u64 = undefined;
1309 cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0]));
1310 var x2: u64 = undefined;
1311 cmovznzU64(&x2, arg1, (arg2[1]), (arg3[1]));
1312 var x3: u64 = undefined;
1313 cmovznzU64(&x3, arg1, (arg2[2]), (arg3[2]));
1314 var x4: u64 = undefined;
1315 cmovznzU64(&x4, arg1, (arg2[3]), (arg3[3]));
1316 out1[0] = x1;
1317 out1[1] = x2;
1318 out1[2] = x3;
1319 out1[3] = x4;
1320}
1321
1322/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
1323/// Preconditions:
1324/// 0 ≤ eval arg1 < m
1325/// Postconditions:
1326/// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
1327///
1328/// Input Bounds:
1329/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1330/// Output Bounds:
1331/// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
1332pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
1333 @setRuntimeSafety(mode == .Debug);
1334
1335 const x1 = (arg1[3]);
1336 const x2 = (arg1[2]);
1337 const x3 = (arg1[1]);
1338 const x4 = (arg1[0]);
1339 const x5 = cast(u8, (x4 & cast(u64, 0xff)));
1340 const x6 = (x4 >> 8);
1341 const x7 = cast(u8, (x6 & cast(u64, 0xff)));
1342 const x8 = (x6 >> 8);
1343 const x9 = cast(u8, (x8 & cast(u64, 0xff)));
1344 const x10 = (x8 >> 8);
1345 const x11 = cast(u8, (x10 & cast(u64, 0xff)));
1346 const x12 = (x10 >> 8);
1347 const x13 = cast(u8, (x12 & cast(u64, 0xff)));
1348 const x14 = (x12 >> 8);
1349 const x15 = cast(u8, (x14 & cast(u64, 0xff)));
1350 const x16 = (x14 >> 8);
1351 const x17 = cast(u8, (x16 & cast(u64, 0xff)));
1352 const x18 = cast(u8, (x16 >> 8));
1353 const x19 = cast(u8, (x3 & cast(u64, 0xff)));
1354 const x20 = (x3 >> 8);
1355 const x21 = cast(u8, (x20 & cast(u64, 0xff)));
1356 const x22 = (x20 >> 8);
1357 const x23 = cast(u8, (x22 & cast(u64, 0xff)));
1358 const x24 = (x22 >> 8);
1359 const x25 = cast(u8, (x24 & cast(u64, 0xff)));
1360 const x26 = (x24 >> 8);
1361 const x27 = cast(u8, (x26 & cast(u64, 0xff)));
1362 const x28 = (x26 >> 8);
1363 const x29 = cast(u8, (x28 & cast(u64, 0xff)));
1364 const x30 = (x28 >> 8);
1365 const x31 = cast(u8, (x30 & cast(u64, 0xff)));
1366 const x32 = cast(u8, (x30 >> 8));
1367 const x33 = cast(u8, (x2 & cast(u64, 0xff)));
1368 const x34 = (x2 >> 8);
1369 const x35 = cast(u8, (x34 & cast(u64, 0xff)));
1370 const x36 = (x34 >> 8);
1371 const x37 = cast(u8, (x36 & cast(u64, 0xff)));
1372 const x38 = (x36 >> 8);
1373 const x39 = cast(u8, (x38 & cast(u64, 0xff)));
1374 const x40 = (x38 >> 8);
1375 const x41 = cast(u8, (x40 & cast(u64, 0xff)));
1376 const x42 = (x40 >> 8);
1377 const x43 = cast(u8, (x42 & cast(u64, 0xff)));
1378 const x44 = (x42 >> 8);
1379 const x45 = cast(u8, (x44 & cast(u64, 0xff)));
1380 const x46 = cast(u8, (x44 >> 8));
1381 const x47 = cast(u8, (x1 & cast(u64, 0xff)));
1382 const x48 = (x1 >> 8);
1383 const x49 = cast(u8, (x48 & cast(u64, 0xff)));
1384 const x50 = (x48 >> 8);
1385 const x51 = cast(u8, (x50 & cast(u64, 0xff)));
1386 const x52 = (x50 >> 8);
1387 const x53 = cast(u8, (x52 & cast(u64, 0xff)));
1388 const x54 = (x52 >> 8);
1389 const x55 = cast(u8, (x54 & cast(u64, 0xff)));
1390 const x56 = (x54 >> 8);
1391 const x57 = cast(u8, (x56 & cast(u64, 0xff)));
1392 const x58 = (x56 >> 8);
1393 const x59 = cast(u8, (x58 & cast(u64, 0xff)));
1394 const x60 = cast(u8, (x58 >> 8));
1395 out1[0] = x5;
1396 out1[1] = x7;
1397 out1[2] = x9;
1398 out1[3] = x11;
1399 out1[4] = x13;
1400 out1[5] = x15;
1401 out1[6] = x17;
1402 out1[7] = x18;
1403 out1[8] = x19;
1404 out1[9] = x21;
1405 out1[10] = x23;
1406 out1[11] = x25;
1407 out1[12] = x27;
1408 out1[13] = x29;
1409 out1[14] = x31;
1410 out1[15] = x32;
1411 out1[16] = x33;
1412 out1[17] = x35;
1413 out1[18] = x37;
1414 out1[19] = x39;
1415 out1[20] = x41;
1416 out1[21] = x43;
1417 out1[22] = x45;
1418 out1[23] = x46;
1419 out1[24] = x47;
1420 out1[25] = x49;
1421 out1[26] = x51;
1422 out1[27] = x53;
1423 out1[28] = x55;
1424 out1[29] = x57;
1425 out1[30] = x59;
1426 out1[31] = x60;
1427}
1428
1429/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
1430/// Preconditions:
1431/// 0 ≤ bytes_eval arg1 < m
1432/// Postconditions:
1433/// eval out1 mod m = bytes_eval arg1 mod m
1434/// 0 ≤ eval out1 < m
1435///
1436/// Input Bounds:
1437/// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
1438/// Output Bounds:
1439/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1440pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
1441 @setRuntimeSafety(mode == .Debug);
1442
1443 const x1 = (cast(u64, (arg1[31])) << 56);
1444 const x2 = (cast(u64, (arg1[30])) << 48);
1445 const x3 = (cast(u64, (arg1[29])) << 40);
1446 const x4 = (cast(u64, (arg1[28])) << 32);
1447 const x5 = (cast(u64, (arg1[27])) << 24);
1448 const x6 = (cast(u64, (arg1[26])) << 16);
1449 const x7 = (cast(u64, (arg1[25])) << 8);
1450 const x8 = (arg1[24]);
1451 const x9 = (cast(u64, (arg1[23])) << 56);
1452 const x10 = (cast(u64, (arg1[22])) << 48);
1453 const x11 = (cast(u64, (arg1[21])) << 40);
1454 const x12 = (cast(u64, (arg1[20])) << 32);
1455 const x13 = (cast(u64, (arg1[19])) << 24);
1456 const x14 = (cast(u64, (arg1[18])) << 16);
1457 const x15 = (cast(u64, (arg1[17])) << 8);
1458 const x16 = (arg1[16]);
1459 const x17 = (cast(u64, (arg1[15])) << 56);
1460 const x18 = (cast(u64, (arg1[14])) << 48);
1461 const x19 = (cast(u64, (arg1[13])) << 40);
1462 const x20 = (cast(u64, (arg1[12])) << 32);
1463 const x21 = (cast(u64, (arg1[11])) << 24);
1464 const x22 = (cast(u64, (arg1[10])) << 16);
1465 const x23 = (cast(u64, (arg1[9])) << 8);
1466 const x24 = (arg1[8]);
1467 const x25 = (cast(u64, (arg1[7])) << 56);
1468 const x26 = (cast(u64, (arg1[6])) << 48);
1469 const x27 = (cast(u64, (arg1[5])) << 40);
1470 const x28 = (cast(u64, (arg1[4])) << 32);
1471 const x29 = (cast(u64, (arg1[3])) << 24);
1472 const x30 = (cast(u64, (arg1[2])) << 16);
1473 const x31 = (cast(u64, (arg1[1])) << 8);
1474 const x32 = (arg1[0]);
1475 const x33 = (x31 + cast(u64, x32));
1476 const x34 = (x30 + x33);
1477 const x35 = (x29 + x34);
1478 const x36 = (x28 + x35);
1479 const x37 = (x27 + x36);
1480 const x38 = (x26 + x37);
1481 const x39 = (x25 + x38);
1482 const x40 = (x23 + cast(u64, x24));
1483 const x41 = (x22 + x40);
1484 const x42 = (x21 + x41);
1485 const x43 = (x20 + x42);
1486 const x44 = (x19 + x43);
1487 const x45 = (x18 + x44);
1488 const x46 = (x17 + x45);
1489 const x47 = (x15 + cast(u64, x16));
1490 const x48 = (x14 + x47);
1491 const x49 = (x13 + x48);
1492 const x50 = (x12 + x49);
1493 const x51 = (x11 + x50);
1494 const x52 = (x10 + x51);
1495 const x53 = (x9 + x52);
1496 const x54 = (x7 + cast(u64, x8));
1497 const x55 = (x6 + x54);
1498 const x56 = (x5 + x55);
1499 const x57 = (x4 + x56);
1500 const x58 = (x3 + x57);
1501 const x59 = (x2 + x58);
1502 const x60 = (x1 + x59);
1503 out1[0] = x39;
1504 out1[1] = x46;
1505 out1[2] = x53;
1506 out1[3] = x60;
1507}
1508
1509/// The function setOne returns the field element one in the Montgomery domain.
1510/// Postconditions:
1511/// eval (from_montgomery out1) mod m = 1 mod m
1512/// 0 ≤ eval out1 < m
1513///
1514/// Input Bounds:
1515/// Output Bounds:
1516/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1517pub fn setOne(out1: *[4]u64) void {
1518 @setRuntimeSafety(mode == .Debug);
1519
1520 out1[0] = cast(u64, 0x1);
1521 out1[1] = 0xffffffff00000000;
1522 out1[2] = 0xffffffffffffffff;
1523 out1[3] = 0xfffffffe;
1524}
1525
1526/// The function msat returns the saturated representation of the prime modulus.
1527/// Postconditions:
1528/// twos_complement_eval out1 = m
1529/// 0 ≤ eval out1 < m
1530///
1531/// Input Bounds:
1532/// Output Bounds:
1533/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1534pub fn msat(out1: *[5]u64) void {
1535 @setRuntimeSafety(mode == .Debug);
1536
1537 out1[0] = 0xffffffffffffffff;
1538 out1[1] = 0xffffffff;
1539 out1[2] = cast(u64, 0x0);
1540 out1[3] = 0xffffffff00000001;
1541 out1[4] = cast(u64, 0x0);
1542}
1543
1544/// The function divstep computes a divstep.
1545/// Preconditions:
1546/// 0 ≤ eval arg4 < m
1547/// 0 ≤ eval arg5 < m
1548/// Postconditions:
1549/// out1 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then 1 - arg1 else 1 + arg1)
1550/// twos_complement_eval out2 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then twos_complement_eval arg3 else twos_complement_eval arg2)
1551/// twos_complement_eval out3 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then ⌊(twos_complement_eval arg3 - twos_complement_eval arg2) / 2⌋ else ⌊(twos_complement_eval arg3 + (twos_complement_eval arg3 mod 2) * twos_complement_eval arg2) / 2⌋)
1552/// eval (from_montgomery out4) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (2 * eval (from_montgomery arg5)) mod m else (2 * eval (from_montgomery arg4)) mod m)
1553/// eval (from_montgomery out5) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (eval (from_montgomery arg4) - eval (from_montgomery arg4)) mod m else (eval (from_montgomery arg5) + (twos_complement_eval arg3 mod 2) * eval (from_montgomery arg4)) mod m)
1554/// 0 ≤ eval out5 < m
1555/// 0 ≤ eval out5 < m
1556/// 0 ≤ eval out2 < m
1557/// 0 ≤ eval out3 < m
1558///
1559/// Input Bounds:
1560/// arg1: [0x0 ~> 0xffffffffffffffff]
1561/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1562/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1563/// arg4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1564/// arg5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1565/// Output Bounds:
1566/// out1: [0x0 ~> 0xffffffffffffffff]
1567/// out2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1568/// out3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1569/// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1570/// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1571pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void {
1572 @setRuntimeSafety(mode == .Debug);
1573
1574 var x1: u64 = undefined;
1575 var x2: u1 = undefined;
1576 addcarryxU64(&x1, &x2, 0x0, (~arg1), cast(u64, 0x1));
1577 const x3 = (cast(u1, (x1 >> 63)) & cast(u1, ((arg3[0]) & cast(u64, 0x1))));
1578 var x4: u64 = undefined;
1579 var x5: u1 = undefined;
1580 addcarryxU64(&x4, &x5, 0x0, (~arg1), cast(u64, 0x1));
1581 var x6: u64 = undefined;
1582 cmovznzU64(&x6, x3, arg1, x4);
1583 var x7: u64 = undefined;
1584 cmovznzU64(&x7, x3, (arg2[0]), (arg3[0]));
1585 var x8: u64 = undefined;
1586 cmovznzU64(&x8, x3, (arg2[1]), (arg3[1]));
1587 var x9: u64 = undefined;
1588 cmovznzU64(&x9, x3, (arg2[2]), (arg3[2]));
1589 var x10: u64 = undefined;
1590 cmovznzU64(&x10, x3, (arg2[3]), (arg3[3]));
1591 var x11: u64 = undefined;
1592 cmovznzU64(&x11, x3, (arg2[4]), (arg3[4]));
1593 var x12: u64 = undefined;
1594 var x13: u1 = undefined;
1595 addcarryxU64(&x12, &x13, 0x0, cast(u64, 0x1), (~(arg2[0])));
1596 var x14: u64 = undefined;
1597 var x15: u1 = undefined;
1598 addcarryxU64(&x14, &x15, x13, cast(u64, 0x0), (~(arg2[1])));
1599 var x16: u64 = undefined;
1600 var x17: u1 = undefined;
1601 addcarryxU64(&x16, &x17, x15, cast(u64, 0x0), (~(arg2[2])));
1602 var x18: u64 = undefined;
1603 var x19: u1 = undefined;
1604 addcarryxU64(&x18, &x19, x17, cast(u64, 0x0), (~(arg2[3])));
1605 var x20: u64 = undefined;
1606 var x21: u1 = undefined;
1607 addcarryxU64(&x20, &x21, x19, cast(u64, 0x0), (~(arg2[4])));
1608 var x22: u64 = undefined;
1609 cmovznzU64(&x22, x3, (arg3[0]), x12);
1610 var x23: u64 = undefined;
1611 cmovznzU64(&x23, x3, (arg3[1]), x14);
1612 var x24: u64 = undefined;
1613 cmovznzU64(&x24, x3, (arg3[2]), x16);
1614 var x25: u64 = undefined;
1615 cmovznzU64(&x25, x3, (arg3[3]), x18);
1616 var x26: u64 = undefined;
1617 cmovznzU64(&x26, x3, (arg3[4]), x20);
1618 var x27: u64 = undefined;
1619 cmovznzU64(&x27, x3, (arg4[0]), (arg5[0]));
1620 var x28: u64 = undefined;
1621 cmovznzU64(&x28, x3, (arg4[1]), (arg5[1]));
1622 var x29: u64 = undefined;
1623 cmovznzU64(&x29, x3, (arg4[2]), (arg5[2]));
1624 var x30: u64 = undefined;
1625 cmovznzU64(&x30, x3, (arg4[3]), (arg5[3]));
1626 var x31: u64 = undefined;
1627 var x32: u1 = undefined;
1628 addcarryxU64(&x31, &x32, 0x0, x27, x27);
1629 var x33: u64 = undefined;
1630 var x34: u1 = undefined;
1631 addcarryxU64(&x33, &x34, x32, x28, x28);
1632 var x35: u64 = undefined;
1633 var x36: u1 = undefined;
1634 addcarryxU64(&x35, &x36, x34, x29, x29);
1635 var x37: u64 = undefined;
1636 var x38: u1 = undefined;
1637 addcarryxU64(&x37, &x38, x36, x30, x30);
1638 var x39: u64 = undefined;
1639 var x40: u1 = undefined;
1640 subborrowxU64(&x39, &x40, 0x0, x31, 0xffffffffffffffff);
1641 var x41: u64 = undefined;
1642 var x42: u1 = undefined;
1643 subborrowxU64(&x41, &x42, x40, x33, 0xffffffff);
1644 var x43: u64 = undefined;
1645 var x44: u1 = undefined;
1646 subborrowxU64(&x43, &x44, x42, x35, cast(u64, 0x0));
1647 var x45: u64 = undefined;
1648 var x46: u1 = undefined;
1649 subborrowxU64(&x45, &x46, x44, x37, 0xffffffff00000001);
1650 var x47: u64 = undefined;
1651 var x48: u1 = undefined;
1652 subborrowxU64(&x47, &x48, x46, cast(u64, x38), cast(u64, 0x0));
1653 const x49 = (arg4[3]);
1654 const x50 = (arg4[2]);
1655 const x51 = (arg4[1]);
1656 const x52 = (arg4[0]);
1657 var x53: u64 = undefined;
1658 var x54: u1 = undefined;
1659 subborrowxU64(&x53, &x54, 0x0, cast(u64, 0x0), x52);
1660 var x55: u64 = undefined;
1661 var x56: u1 = undefined;
1662 subborrowxU64(&x55, &x56, x54, cast(u64, 0x0), x51);
1663 var x57: u64 = undefined;
1664 var x58: u1 = undefined;
1665 subborrowxU64(&x57, &x58, x56, cast(u64, 0x0), x50);
1666 var x59: u64 = undefined;
1667 var x60: u1 = undefined;
1668 subborrowxU64(&x59, &x60, x58, cast(u64, 0x0), x49);
1669 var x61: u64 = undefined;
1670 cmovznzU64(&x61, x60, cast(u64, 0x0), 0xffffffffffffffff);
1671 var x62: u64 = undefined;
1672 var x63: u1 = undefined;
1673 addcarryxU64(&x62, &x63, 0x0, x53, x61);
1674 var x64: u64 = undefined;
1675 var x65: u1 = undefined;
1676 addcarryxU64(&x64, &x65, x63, x55, (x61 & 0xffffffff));
1677 var x66: u64 = undefined;
1678 var x67: u1 = undefined;
1679 addcarryxU64(&x66, &x67, x65, x57, cast(u64, 0x0));
1680 var x68: u64 = undefined;
1681 var x69: u1 = undefined;
1682 addcarryxU64(&x68, &x69, x67, x59, (x61 & 0xffffffff00000001));
1683 var x70: u64 = undefined;
1684 cmovznzU64(&x70, x3, (arg5[0]), x62);
1685 var x71: u64 = undefined;
1686 cmovznzU64(&x71, x3, (arg5[1]), x64);
1687 var x72: u64 = undefined;
1688 cmovznzU64(&x72, x3, (arg5[2]), x66);
1689 var x73: u64 = undefined;
1690 cmovznzU64(&x73, x3, (arg5[3]), x68);
1691 const x74 = cast(u1, (x22 & cast(u64, 0x1)));
1692 var x75: u64 = undefined;
1693 cmovznzU64(&x75, x74, cast(u64, 0x0), x7);
1694 var x76: u64 = undefined;
1695 cmovznzU64(&x76, x74, cast(u64, 0x0), x8);
1696 var x77: u64 = undefined;
1697 cmovznzU64(&x77, x74, cast(u64, 0x0), x9);
1698 var x78: u64 = undefined;
1699 cmovznzU64(&x78, x74, cast(u64, 0x0), x10);
1700 var x79: u64 = undefined;
1701 cmovznzU64(&x79, x74, cast(u64, 0x0), x11);
1702 var x80: u64 = undefined;
1703 var x81: u1 = undefined;
1704 addcarryxU64(&x80, &x81, 0x0, x22, x75);
1705 var x82: u64 = undefined;
1706 var x83: u1 = undefined;
1707 addcarryxU64(&x82, &x83, x81, x23, x76);
1708 var x84: u64 = undefined;
1709 var x85: u1 = undefined;
1710 addcarryxU64(&x84, &x85, x83, x24, x77);
1711 var x86: u64 = undefined;
1712 var x87: u1 = undefined;
1713 addcarryxU64(&x86, &x87, x85, x25, x78);
1714 var x88: u64 = undefined;
1715 var x89: u1 = undefined;
1716 addcarryxU64(&x88, &x89, x87, x26, x79);
1717 var x90: u64 = undefined;
1718 cmovznzU64(&x90, x74, cast(u64, 0x0), x27);
1719 var x91: u64 = undefined;
1720 cmovznzU64(&x91, x74, cast(u64, 0x0), x28);
1721 var x92: u64 = undefined;
1722 cmovznzU64(&x92, x74, cast(u64, 0x0), x29);
1723 var x93: u64 = undefined;
1724 cmovznzU64(&x93, x74, cast(u64, 0x0), x30);
1725 var x94: u64 = undefined;
1726 var x95: u1 = undefined;
1727 addcarryxU64(&x94, &x95, 0x0, x70, x90);
1728 var x96: u64 = undefined;
1729 var x97: u1 = undefined;
1730 addcarryxU64(&x96, &x97, x95, x71, x91);
1731 var x98: u64 = undefined;
1732 var x99: u1 = undefined;
1733 addcarryxU64(&x98, &x99, x97, x72, x92);
1734 var x100: u64 = undefined;
1735 var x101: u1 = undefined;
1736 addcarryxU64(&x100, &x101, x99, x73, x93);
1737 var x102: u64 = undefined;
1738 var x103: u1 = undefined;
1739 subborrowxU64(&x102, &x103, 0x0, x94, 0xffffffffffffffff);
1740 var x104: u64 = undefined;
1741 var x105: u1 = undefined;
1742 subborrowxU64(&x104, &x105, x103, x96, 0xffffffff);
1743 var x106: u64 = undefined;
1744 var x107: u1 = undefined;
1745 subborrowxU64(&x106, &x107, x105, x98, cast(u64, 0x0));
1746 var x108: u64 = undefined;
1747 var x109: u1 = undefined;
1748 subborrowxU64(&x108, &x109, x107, x100, 0xffffffff00000001);
1749 var x110: u64 = undefined;
1750 var x111: u1 = undefined;
1751 subborrowxU64(&x110, &x111, x109, cast(u64, x101), cast(u64, 0x0));
1752 var x112: u64 = undefined;
1753 var x113: u1 = undefined;
1754 addcarryxU64(&x112, &x113, 0x0, x6, cast(u64, 0x1));
1755 const x114 = ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff));
1756 const x115 = ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff));
1757 const x116 = ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff));
1758 const x117 = ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff));
1759 const x118 = ((x88 & 0x8000000000000000) | (x88 >> 1));
1760 var x119: u64 = undefined;
1761 cmovznzU64(&x119, x48, x39, x31);
1762 var x120: u64 = undefined;
1763 cmovznzU64(&x120, x48, x41, x33);
1764 var x121: u64 = undefined;
1765 cmovznzU64(&x121, x48, x43, x35);
1766 var x122: u64 = undefined;
1767 cmovznzU64(&x122, x48, x45, x37);
1768 var x123: u64 = undefined;
1769 cmovznzU64(&x123, x111, x102, x94);
1770 var x124: u64 = undefined;
1771 cmovznzU64(&x124, x111, x104, x96);
1772 var x125: u64 = undefined;
1773 cmovznzU64(&x125, x111, x106, x98);
1774 var x126: u64 = undefined;
1775 cmovznzU64(&x126, x111, x108, x100);
1776 out1.* = x112;
1777 out2[0] = x7;
1778 out2[1] = x8;
1779 out2[2] = x9;
1780 out2[3] = x10;
1781 out2[4] = x11;
1782 out3[0] = x114;
1783 out3[1] = x115;
1784 out3[2] = x116;
1785 out3[3] = x117;
1786 out3[4] = x118;
1787 out4[0] = x119;
1788 out4[1] = x120;
1789 out4[2] = x121;
1790 out4[3] = x122;
1791 out5[0] = x123;
1792 out5[1] = x124;
1793 out5[2] = x125;
1794 out5[3] = x126;
1795}
1796
1797/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
1798/// Postconditions:
1799/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if (log2 m) + 1 < 46 then ⌊(49 * ((log2 m) + 1) + 80) / 17⌋ else ⌊(49 * ((log2 m) + 1) + 57) / 17⌋)
1800/// 0 ≤ eval out1 < m
1801///
1802/// Input Bounds:
1803/// Output Bounds:
1804/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1805pub fn divstepPrecomp(out1: *[4]u64) void {
1806 @setRuntimeSafety(mode == .Debug);
1807
1808 out1[0] = 0x67ffffffb8000000;
1809 out1[1] = 0xc000000038000000;
1810 out1[2] = 0xd80000007fffffff;
1811 out1[3] = 0x2fffffffffffffff;
1812}
lib/std/crypto/pcurves/p256/p256_scalar_64.zig created+2016
...@@ -0,0 +1,2016 @@
1// Autogenerated: './src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --no-prefix-fiat --package-name p256-scalar '' 64 115792089210356248762697446949407573529996955224135760342422259061068512044369
2// curve description (via package name): p256-scalar
3// machine_wordsize = 64 (from "64")
4// requested operations: (all)
5// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "115792089210356248762697446949407573529996955224135760342422259061068512044369")
6//
7// NOTE: In addition to the bounds specified above each function, all
8// functions synthesized for this Montgomery arithmetic require the
9// input to be strictly less than the prime modulus (m), and also
10// require the input to be in the unique saturated representation.
11// All functions also ensure that these two properties are true of
12// return values.
13//
14// Computed values:
15// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
16// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
17// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
18// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
19
20const std = @import("std");
21const cast = std.meta.cast;
22const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels
23
24pub const Limbs = [4]u64;
25
26/// The function addcarryxU64 is an addition with carry.
27/// Postconditions:
28/// out1 = (arg1 + arg2 + arg3) mod 2^64
29/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
30///
31/// Input Bounds:
32/// arg1: [0x0 ~> 0x1]
33/// arg2: [0x0 ~> 0xffffffffffffffff]
34/// arg3: [0x0 ~> 0xffffffffffffffff]
35/// Output Bounds:
36/// out1: [0x0 ~> 0xffffffffffffffff]
37/// out2: [0x0 ~> 0x1]
38fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
39 @setRuntimeSafety(mode == .Debug);
40
41 var t: u64 = undefined;
42 const carry1 = @addWithOverflow(u64, arg2, arg3, &t);
43 const carry2 = @addWithOverflow(u64, t, arg1, out1);
44 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
45}
46
47/// The function subborrowxU64 is a subtraction with borrow.
48/// Postconditions:
49/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
50/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
51///
52/// Input Bounds:
53/// arg1: [0x0 ~> 0x1]
54/// arg2: [0x0 ~> 0xffffffffffffffff]
55/// arg3: [0x0 ~> 0xffffffffffffffff]
56/// Output Bounds:
57/// out1: [0x0 ~> 0xffffffffffffffff]
58/// out2: [0x0 ~> 0x1]
59fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
60 @setRuntimeSafety(mode == .Debug);
61
62 var t: u64 = undefined;
63 const carry1 = @subWithOverflow(u64, arg2, arg3, &t);
64 const carry2 = @subWithOverflow(u64, t, arg1, out1);
65 out2.* = @boolToInt(carry1) | @boolToInt(carry2);
66}
67
68/// The function mulxU64 is a multiplication, returning the full double-width result.
69/// Postconditions:
70/// out1 = (arg1 * arg2) mod 2^64
71/// out2 = ⌊arg1 * arg2 / 2^64⌋
72///
73/// Input Bounds:
74/// arg1: [0x0 ~> 0xffffffffffffffff]
75/// arg2: [0x0 ~> 0xffffffffffffffff]
76/// Output Bounds:
77/// out1: [0x0 ~> 0xffffffffffffffff]
78/// out2: [0x0 ~> 0xffffffffffffffff]
79fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) callconv(.Inline) void {
80 @setRuntimeSafety(mode == .Debug);
81
82 const x = @as(u128, arg1) * @as(u128, arg2);
83 out1.* = @truncate(u64, x);
84 out2.* = @truncate(u64, x >> 64);
85}
86
87/// The function cmovznzU64 is a single-word conditional move.
88/// Postconditions:
89/// out1 = (if arg1 = 0 then arg2 else arg3)
90///
91/// Input Bounds:
92/// arg1: [0x0 ~> 0x1]
93/// arg2: [0x0 ~> 0xffffffffffffffff]
94/// arg3: [0x0 ~> 0xffffffffffffffff]
95/// Output Bounds:
96/// out1: [0x0 ~> 0xffffffffffffffff]
97fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) callconv(.Inline) void {
98 @setRuntimeSafety(mode == .Debug);
99
100 const mask = 0 -% @as(u64, arg1);
101 out1.* = (mask & arg3) | ((~mask) & arg2);
102}
103
104/// The function mul multiplies two field elements in the Montgomery domain.
105/// Preconditions:
106/// 0 ≤ eval arg1 < m
107/// 0 ≤ eval arg2 < m
108/// Postconditions:
109/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
110/// 0 ≤ eval out1 < m
111///
112/// Input Bounds:
113/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
114/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
115/// Output Bounds:
116/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
117pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
118 @setRuntimeSafety(mode == .Debug);
119
120 const x1 = (arg1[1]);
121 const x2 = (arg1[2]);
122 const x3 = (arg1[3]);
123 const x4 = (arg1[0]);
124 var x5: u64 = undefined;
125 var x6: u64 = undefined;
126 mulxU64(&x5, &x6, x4, (arg2[3]));
127 var x7: u64 = undefined;
128 var x8: u64 = undefined;
129 mulxU64(&x7, &x8, x4, (arg2[2]));
130 var x9: u64 = undefined;
131 var x10: u64 = undefined;
132 mulxU64(&x9, &x10, x4, (arg2[1]));
133 var x11: u64 = undefined;
134 var x12: u64 = undefined;
135 mulxU64(&x11, &x12, x4, (arg2[0]));
136 var x13: u64 = undefined;
137 var x14: u1 = undefined;
138 addcarryxU64(&x13, &x14, 0x0, x12, x9);
139 var x15: u64 = undefined;
140 var x16: u1 = undefined;
141 addcarryxU64(&x15, &x16, x14, x10, x7);
142 var x17: u64 = undefined;
143 var x18: u1 = undefined;
144 addcarryxU64(&x17, &x18, x16, x8, x5);
145 const x19 = (cast(u64, x18) + x6);
146 var x20: u64 = undefined;
147 var x21: u64 = undefined;
148 mulxU64(&x20, &x21, x11, 0xccd1c8aaee00bc4f);
149 var x22: u64 = undefined;
150 var x23: u64 = undefined;
151 mulxU64(&x22, &x23, x20, 0xffffffff00000000);
152 var x24: u64 = undefined;
153 var x25: u64 = undefined;
154 mulxU64(&x24, &x25, x20, 0xffffffffffffffff);
155 var x26: u64 = undefined;
156 var x27: u64 = undefined;
157 mulxU64(&x26, &x27, x20, 0xbce6faada7179e84);
158 var x28: u64 = undefined;
159 var x29: u64 = undefined;
160 mulxU64(&x28, &x29, x20, 0xf3b9cac2fc632551);
161 var x30: u64 = undefined;
162 var x31: u1 = undefined;
163 addcarryxU64(&x30, &x31, 0x0, x29, x26);
164 var x32: u64 = undefined;
165 var x33: u1 = undefined;
166 addcarryxU64(&x32, &x33, x31, x27, x24);
167 var x34: u64 = undefined;
168 var x35: u1 = undefined;
169 addcarryxU64(&x34, &x35, x33, x25, x22);
170 const x36 = (cast(u64, x35) + x23);
171 var x37: u64 = undefined;
172 var x38: u1 = undefined;
173 addcarryxU64(&x37, &x38, 0x0, x11, x28);
174 var x39: u64 = undefined;
175 var x40: u1 = undefined;
176 addcarryxU64(&x39, &x40, x38, x13, x30);
177 var x41: u64 = undefined;
178 var x42: u1 = undefined;
179 addcarryxU64(&x41, &x42, x40, x15, x32);
180 var x43: u64 = undefined;
181 var x44: u1 = undefined;
182 addcarryxU64(&x43, &x44, x42, x17, x34);
183 var x45: u64 = undefined;
184 var x46: u1 = undefined;
185 addcarryxU64(&x45, &x46, x44, x19, x36);
186 var x47: u64 = undefined;
187 var x48: u64 = undefined;
188 mulxU64(&x47, &x48, x1, (arg2[3]));
189 var x49: u64 = undefined;
190 var x50: u64 = undefined;
191 mulxU64(&x49, &x50, x1, (arg2[2]));
192 var x51: u64 = undefined;
193 var x52: u64 = undefined;
194 mulxU64(&x51, &x52, x1, (arg2[1]));
195 var x53: u64 = undefined;
196 var x54: u64 = undefined;
197 mulxU64(&x53, &x54, x1, (arg2[0]));
198 var x55: u64 = undefined;
199 var x56: u1 = undefined;
200 addcarryxU64(&x55, &x56, 0x0, x54, x51);
201 var x57: u64 = undefined;
202 var x58: u1 = undefined;
203 addcarryxU64(&x57, &x58, x56, x52, x49);
204 var x59: u64 = undefined;
205 var x60: u1 = undefined;
206 addcarryxU64(&x59, &x60, x58, x50, x47);
207 const x61 = (cast(u64, x60) + x48);
208 var x62: u64 = undefined;
209 var x63: u1 = undefined;
210 addcarryxU64(&x62, &x63, 0x0, x39, x53);
211 var x64: u64 = undefined;
212 var x65: u1 = undefined;
213 addcarryxU64(&x64, &x65, x63, x41, x55);
214 var x66: u64 = undefined;
215 var x67: u1 = undefined;
216 addcarryxU64(&x66, &x67, x65, x43, x57);
217 var x68: u64 = undefined;
218 var x69: u1 = undefined;
219 addcarryxU64(&x68, &x69, x67, x45, x59);
220 var x70: u64 = undefined;
221 var x71: u1 = undefined;
222 addcarryxU64(&x70, &x71, x69, cast(u64, x46), x61);
223 var x72: u64 = undefined;
224 var x73: u64 = undefined;
225 mulxU64(&x72, &x73, x62, 0xccd1c8aaee00bc4f);
226 var x74: u64 = undefined;
227 var x75: u64 = undefined;
228 mulxU64(&x74, &x75, x72, 0xffffffff00000000);
229 var x76: u64 = undefined;
230 var x77: u64 = undefined;
231 mulxU64(&x76, &x77, x72, 0xffffffffffffffff);
232 var x78: u64 = undefined;
233 var x79: u64 = undefined;
234 mulxU64(&x78, &x79, x72, 0xbce6faada7179e84);
235 var x80: u64 = undefined;
236 var x81: u64 = undefined;
237 mulxU64(&x80, &x81, x72, 0xf3b9cac2fc632551);
238 var x82: u64 = undefined;
239 var x83: u1 = undefined;
240 addcarryxU64(&x82, &x83, 0x0, x81, x78);
241 var x84: u64 = undefined;
242 var x85: u1 = undefined;
243 addcarryxU64(&x84, &x85, x83, x79, x76);
244 var x86: u64 = undefined;
245 var x87: u1 = undefined;
246 addcarryxU64(&x86, &x87, x85, x77, x74);
247 const x88 = (cast(u64, x87) + x75);
248 var x89: u64 = undefined;
249 var x90: u1 = undefined;
250 addcarryxU64(&x89, &x90, 0x0, x62, x80);
251 var x91: u64 = undefined;
252 var x92: u1 = undefined;
253 addcarryxU64(&x91, &x92, x90, x64, x82);
254 var x93: u64 = undefined;
255 var x94: u1 = undefined;
256 addcarryxU64(&x93, &x94, x92, x66, x84);
257 var x95: u64 = undefined;
258 var x96: u1 = undefined;
259 addcarryxU64(&x95, &x96, x94, x68, x86);
260 var x97: u64 = undefined;
261 var x98: u1 = undefined;
262 addcarryxU64(&x97, &x98, x96, x70, x88);
263 const x99 = (cast(u64, x98) + cast(u64, x71));
264 var x100: u64 = undefined;
265 var x101: u64 = undefined;
266 mulxU64(&x100, &x101, x2, (arg2[3]));
267 var x102: u64 = undefined;
268 var x103: u64 = undefined;
269 mulxU64(&x102, &x103, x2, (arg2[2]));
270 var x104: u64 = undefined;
271 var x105: u64 = undefined;
272 mulxU64(&x104, &x105, x2, (arg2[1]));
273 var x106: u64 = undefined;
274 var x107: u64 = undefined;
275 mulxU64(&x106, &x107, x2, (arg2[0]));
276 var x108: u64 = undefined;
277 var x109: u1 = undefined;
278 addcarryxU64(&x108, &x109, 0x0, x107, x104);
279 var x110: u64 = undefined;
280 var x111: u1 = undefined;
281 addcarryxU64(&x110, &x111, x109, x105, x102);
282 var x112: u64 = undefined;
283 var x113: u1 = undefined;
284 addcarryxU64(&x112, &x113, x111, x103, x100);
285 const x114 = (cast(u64, x113) + x101);
286 var x115: u64 = undefined;
287 var x116: u1 = undefined;
288 addcarryxU64(&x115, &x116, 0x0, x91, x106);
289 var x117: u64 = undefined;
290 var x118: u1 = undefined;
291 addcarryxU64(&x117, &x118, x116, x93, x108);
292 var x119: u64 = undefined;
293 var x120: u1 = undefined;
294 addcarryxU64(&x119, &x120, x118, x95, x110);
295 var x121: u64 = undefined;
296 var x122: u1 = undefined;
297 addcarryxU64(&x121, &x122, x120, x97, x112);
298 var x123: u64 = undefined;
299 var x124: u1 = undefined;
300 addcarryxU64(&x123, &x124, x122, x99, x114);
301 var x125: u64 = undefined;
302 var x126: u64 = undefined;
303 mulxU64(&x125, &x126, x115, 0xccd1c8aaee00bc4f);
304 var x127: u64 = undefined;
305 var x128: u64 = undefined;
306 mulxU64(&x127, &x128, x125, 0xffffffff00000000);
307 var x129: u64 = undefined;
308 var x130: u64 = undefined;
309 mulxU64(&x129, &x130, x125, 0xffffffffffffffff);
310 var x131: u64 = undefined;
311 var x132: u64 = undefined;
312 mulxU64(&x131, &x132, x125, 0xbce6faada7179e84);
313 var x133: u64 = undefined;
314 var x134: u64 = undefined;
315 mulxU64(&x133, &x134, x125, 0xf3b9cac2fc632551);
316 var x135: u64 = undefined;
317 var x136: u1 = undefined;
318 addcarryxU64(&x135, &x136, 0x0, x134, x131);
319 var x137: u64 = undefined;
320 var x138: u1 = undefined;
321 addcarryxU64(&x137, &x138, x136, x132, x129);
322 var x139: u64 = undefined;
323 var x140: u1 = undefined;
324 addcarryxU64(&x139, &x140, x138, x130, x127);
325 const x141 = (cast(u64, x140) + x128);
326 var x142: u64 = undefined;
327 var x143: u1 = undefined;
328 addcarryxU64(&x142, &x143, 0x0, x115, x133);
329 var x144: u64 = undefined;
330 var x145: u1 = undefined;
331 addcarryxU64(&x144, &x145, x143, x117, x135);
332 var x146: u64 = undefined;
333 var x147: u1 = undefined;
334 addcarryxU64(&x146, &x147, x145, x119, x137);
335 var x148: u64 = undefined;
336 var x149: u1 = undefined;
337 addcarryxU64(&x148, &x149, x147, x121, x139);
338 var x150: u64 = undefined;
339 var x151: u1 = undefined;
340 addcarryxU64(&x150, &x151, x149, x123, x141);
341 const x152 = (cast(u64, x151) + cast(u64, x124));
342 var x153: u64 = undefined;
343 var x154: u64 = undefined;
344 mulxU64(&x153, &x154, x3, (arg2[3]));
345 var x155: u64 = undefined;
346 var x156: u64 = undefined;
347 mulxU64(&x155, &x156, x3, (arg2[2]));
348 var x157: u64 = undefined;
349 var x158: u64 = undefined;
350 mulxU64(&x157, &x158, x3, (arg2[1]));
351 var x159: u64 = undefined;
352 var x160: u64 = undefined;
353 mulxU64(&x159, &x160, x3, (arg2[0]));
354 var x161: u64 = undefined;
355 var x162: u1 = undefined;
356 addcarryxU64(&x161, &x162, 0x0, x160, x157);
357 var x163: u64 = undefined;
358 var x164: u1 = undefined;
359 addcarryxU64(&x163, &x164, x162, x158, x155);
360 var x165: u64 = undefined;
361 var x166: u1 = undefined;
362 addcarryxU64(&x165, &x166, x164, x156, x153);
363 const x167 = (cast(u64, x166) + x154);
364 var x168: u64 = undefined;
365 var x169: u1 = undefined;
366 addcarryxU64(&x168, &x169, 0x0, x144, x159);
367 var x170: u64 = undefined;
368 var x171: u1 = undefined;
369 addcarryxU64(&x170, &x171, x169, x146, x161);
370 var x172: u64 = undefined;
371 var x173: u1 = undefined;
372 addcarryxU64(&x172, &x173, x171, x148, x163);
373 var x174: u64 = undefined;
374 var x175: u1 = undefined;
375 addcarryxU64(&x174, &x175, x173, x150, x165);
376 var x176: u64 = undefined;
377 var x177: u1 = undefined;
378 addcarryxU64(&x176, &x177, x175, x152, x167);
379 var x178: u64 = undefined;
380 var x179: u64 = undefined;
381 mulxU64(&x178, &x179, x168, 0xccd1c8aaee00bc4f);
382 var x180: u64 = undefined;
383 var x181: u64 = undefined;
384 mulxU64(&x180, &x181, x178, 0xffffffff00000000);
385 var x182: u64 = undefined;
386 var x183: u64 = undefined;
387 mulxU64(&x182, &x183, x178, 0xffffffffffffffff);
388 var x184: u64 = undefined;
389 var x185: u64 = undefined;
390 mulxU64(&x184, &x185, x178, 0xbce6faada7179e84);
391 var x186: u64 = undefined;
392 var x187: u64 = undefined;
393 mulxU64(&x186, &x187, x178, 0xf3b9cac2fc632551);
394 var x188: u64 = undefined;
395 var x189: u1 = undefined;
396 addcarryxU64(&x188, &x189, 0x0, x187, x184);
397 var x190: u64 = undefined;
398 var x191: u1 = undefined;
399 addcarryxU64(&x190, &x191, x189, x185, x182);
400 var x192: u64 = undefined;
401 var x193: u1 = undefined;
402 addcarryxU64(&x192, &x193, x191, x183, x180);
403 const x194 = (cast(u64, x193) + x181);
404 var x195: u64 = undefined;
405 var x196: u1 = undefined;
406 addcarryxU64(&x195, &x196, 0x0, x168, x186);
407 var x197: u64 = undefined;
408 var x198: u1 = undefined;
409 addcarryxU64(&x197, &x198, x196, x170, x188);
410 var x199: u64 = undefined;
411 var x200: u1 = undefined;
412 addcarryxU64(&x199, &x200, x198, x172, x190);
413 var x201: u64 = undefined;
414 var x202: u1 = undefined;
415 addcarryxU64(&x201, &x202, x200, x174, x192);
416 var x203: u64 = undefined;
417 var x204: u1 = undefined;
418 addcarryxU64(&x203, &x204, x202, x176, x194);
419 const x205 = (cast(u64, x204) + cast(u64, x177));
420 var x206: u64 = undefined;
421 var x207: u1 = undefined;
422 subborrowxU64(&x206, &x207, 0x0, x197, 0xf3b9cac2fc632551);
423 var x208: u64 = undefined;
424 var x209: u1 = undefined;
425 subborrowxU64(&x208, &x209, x207, x199, 0xbce6faada7179e84);
426 var x210: u64 = undefined;
427 var x211: u1 = undefined;
428 subborrowxU64(&x210, &x211, x209, x201, 0xffffffffffffffff);
429 var x212: u64 = undefined;
430 var x213: u1 = undefined;
431 subborrowxU64(&x212, &x213, x211, x203, 0xffffffff00000000);
432 var x214: u64 = undefined;
433 var x215: u1 = undefined;
434 subborrowxU64(&x214, &x215, x213, x205, cast(u64, 0x0));
435 var x216: u64 = undefined;
436 cmovznzU64(&x216, x215, x206, x197);
437 var x217: u64 = undefined;
438 cmovznzU64(&x217, x215, x208, x199);
439 var x218: u64 = undefined;
440 cmovznzU64(&x218, x215, x210, x201);
441 var x219: u64 = undefined;
442 cmovznzU64(&x219, x215, x212, x203);
443 out1[0] = x216;
444 out1[1] = x217;
445 out1[2] = x218;
446 out1[3] = x219;
447}
448
449/// The function square squares a field element in the Montgomery domain.
450/// Preconditions:
451/// 0 ≤ eval arg1 < m
452/// Postconditions:
453/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
454/// 0 ≤ eval out1 < m
455///
456/// Input Bounds:
457/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
458/// Output Bounds:
459/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
460pub fn square(out1: *[4]u64, arg1: [4]u64) void {
461 @setRuntimeSafety(mode == .Debug);
462
463 const x1 = (arg1[1]);
464 const x2 = (arg1[2]);
465 const x3 = (arg1[3]);
466 const x4 = (arg1[0]);
467 var x5: u64 = undefined;
468 var x6: u64 = undefined;
469 mulxU64(&x5, &x6, x4, (arg1[3]));
470 var x7: u64 = undefined;
471 var x8: u64 = undefined;
472 mulxU64(&x7, &x8, x4, (arg1[2]));
473 var x9: u64 = undefined;
474 var x10: u64 = undefined;
475 mulxU64(&x9, &x10, x4, (arg1[1]));
476 var x11: u64 = undefined;
477 var x12: u64 = undefined;
478 mulxU64(&x11, &x12, x4, (arg1[0]));
479 var x13: u64 = undefined;
480 var x14: u1 = undefined;
481 addcarryxU64(&x13, &x14, 0x0, x12, x9);
482 var x15: u64 = undefined;
483 var x16: u1 = undefined;
484 addcarryxU64(&x15, &x16, x14, x10, x7);
485 var x17: u64 = undefined;
486 var x18: u1 = undefined;
487 addcarryxU64(&x17, &x18, x16, x8, x5);
488 const x19 = (cast(u64, x18) + x6);
489 var x20: u64 = undefined;
490 var x21: u64 = undefined;
491 mulxU64(&x20, &x21, x11, 0xccd1c8aaee00bc4f);
492 var x22: u64 = undefined;
493 var x23: u64 = undefined;
494 mulxU64(&x22, &x23, x20, 0xffffffff00000000);
495 var x24: u64 = undefined;
496 var x25: u64 = undefined;
497 mulxU64(&x24, &x25, x20, 0xffffffffffffffff);
498 var x26: u64 = undefined;
499 var x27: u64 = undefined;
500 mulxU64(&x26, &x27, x20, 0xbce6faada7179e84);
501 var x28: u64 = undefined;
502 var x29: u64 = undefined;
503 mulxU64(&x28, &x29, x20, 0xf3b9cac2fc632551);
504 var x30: u64 = undefined;
505 var x31: u1 = undefined;
506 addcarryxU64(&x30, &x31, 0x0, x29, x26);
507 var x32: u64 = undefined;
508 var x33: u1 = undefined;
509 addcarryxU64(&x32, &x33, x31, x27, x24);
510 var x34: u64 = undefined;
511 var x35: u1 = undefined;
512 addcarryxU64(&x34, &x35, x33, x25, x22);
513 const x36 = (cast(u64, x35) + x23);
514 var x37: u64 = undefined;
515 var x38: u1 = undefined;
516 addcarryxU64(&x37, &x38, 0x0, x11, x28);
517 var x39: u64 = undefined;
518 var x40: u1 = undefined;
519 addcarryxU64(&x39, &x40, x38, x13, x30);
520 var x41: u64 = undefined;
521 var x42: u1 = undefined;
522 addcarryxU64(&x41, &x42, x40, x15, x32);
523 var x43: u64 = undefined;
524 var x44: u1 = undefined;
525 addcarryxU64(&x43, &x44, x42, x17, x34);
526 var x45: u64 = undefined;
527 var x46: u1 = undefined;
528 addcarryxU64(&x45, &x46, x44, x19, x36);
529 var x47: u64 = undefined;
530 var x48: u64 = undefined;
531 mulxU64(&x47, &x48, x1, (arg1[3]));
532 var x49: u64 = undefined;
533 var x50: u64 = undefined;
534 mulxU64(&x49, &x50, x1, (arg1[2]));
535 var x51: u64 = undefined;
536 var x52: u64 = undefined;
537 mulxU64(&x51, &x52, x1, (arg1[1]));
538 var x53: u64 = undefined;
539 var x54: u64 = undefined;
540 mulxU64(&x53, &x54, x1, (arg1[0]));
541 var x55: u64 = undefined;
542 var x56: u1 = undefined;
543 addcarryxU64(&x55, &x56, 0x0, x54, x51);
544 var x57: u64 = undefined;
545 var x58: u1 = undefined;
546 addcarryxU64(&x57, &x58, x56, x52, x49);
547 var x59: u64 = undefined;
548 var x60: u1 = undefined;
549 addcarryxU64(&x59, &x60, x58, x50, x47);
550 const x61 = (cast(u64, x60) + x48);
551 var x62: u64 = undefined;
552 var x63: u1 = undefined;
553 addcarryxU64(&x62, &x63, 0x0, x39, x53);
554 var x64: u64 = undefined;
555 var x65: u1 = undefined;
556 addcarryxU64(&x64, &x65, x63, x41, x55);
557 var x66: u64 = undefined;
558 var x67: u1 = undefined;
559 addcarryxU64(&x66, &x67, x65, x43, x57);
560 var x68: u64 = undefined;
561 var x69: u1 = undefined;
562 addcarryxU64(&x68, &x69, x67, x45, x59);
563 var x70: u64 = undefined;
564 var x71: u1 = undefined;
565 addcarryxU64(&x70, &x71, x69, cast(u64, x46), x61);
566 var x72: u64 = undefined;
567 var x73: u64 = undefined;
568 mulxU64(&x72, &x73, x62, 0xccd1c8aaee00bc4f);
569 var x74: u64 = undefined;
570 var x75: u64 = undefined;
571 mulxU64(&x74, &x75, x72, 0xffffffff00000000);
572 var x76: u64 = undefined;
573 var x77: u64 = undefined;
574 mulxU64(&x76, &x77, x72, 0xffffffffffffffff);
575 var x78: u64 = undefined;
576 var x79: u64 = undefined;
577 mulxU64(&x78, &x79, x72, 0xbce6faada7179e84);
578 var x80: u64 = undefined;
579 var x81: u64 = undefined;
580 mulxU64(&x80, &x81, x72, 0xf3b9cac2fc632551);
581 var x82: u64 = undefined;
582 var x83: u1 = undefined;
583 addcarryxU64(&x82, &x83, 0x0, x81, x78);
584 var x84: u64 = undefined;
585 var x85: u1 = undefined;
586 addcarryxU64(&x84, &x85, x83, x79, x76);
587 var x86: u64 = undefined;
588 var x87: u1 = undefined;
589 addcarryxU64(&x86, &x87, x85, x77, x74);
590 const x88 = (cast(u64, x87) + x75);
591 var x89: u64 = undefined;
592 var x90: u1 = undefined;
593 addcarryxU64(&x89, &x90, 0x0, x62, x80);
594 var x91: u64 = undefined;
595 var x92: u1 = undefined;
596 addcarryxU64(&x91, &x92, x90, x64, x82);
597 var x93: u64 = undefined;
598 var x94: u1 = undefined;
599 addcarryxU64(&x93, &x94, x92, x66, x84);
600 var x95: u64 = undefined;
601 var x96: u1 = undefined;
602 addcarryxU64(&x95, &x96, x94, x68, x86);
603 var x97: u64 = undefined;
604 var x98: u1 = undefined;
605 addcarryxU64(&x97, &x98, x96, x70, x88);
606 const x99 = (cast(u64, x98) + cast(u64, x71));
607 var x100: u64 = undefined;
608 var x101: u64 = undefined;
609 mulxU64(&x100, &x101, x2, (arg1[3]));
610 var x102: u64 = undefined;
611 var x103: u64 = undefined;
612 mulxU64(&x102, &x103, x2, (arg1[2]));
613 var x104: u64 = undefined;
614 var x105: u64 = undefined;
615 mulxU64(&x104, &x105, x2, (arg1[1]));
616 var x106: u64 = undefined;
617 var x107: u64 = undefined;
618 mulxU64(&x106, &x107, x2, (arg1[0]));
619 var x108: u64 = undefined;
620 var x109: u1 = undefined;
621 addcarryxU64(&x108, &x109, 0x0, x107, x104);
622 var x110: u64 = undefined;
623 var x111: u1 = undefined;
624 addcarryxU64(&x110, &x111, x109, x105, x102);
625 var x112: u64 = undefined;
626 var x113: u1 = undefined;
627 addcarryxU64(&x112, &x113, x111, x103, x100);
628 const x114 = (cast(u64, x113) + x101);
629 var x115: u64 = undefined;
630 var x116: u1 = undefined;
631 addcarryxU64(&x115, &x116, 0x0, x91, x106);
632 var x117: u64 = undefined;
633 var x118: u1 = undefined;
634 addcarryxU64(&x117, &x118, x116, x93, x108);
635 var x119: u64 = undefined;
636 var x120: u1 = undefined;
637 addcarryxU64(&x119, &x120, x118, x95, x110);
638 var x121: u64 = undefined;
639 var x122: u1 = undefined;
640 addcarryxU64(&x121, &x122, x120, x97, x112);
641 var x123: u64 = undefined;
642 var x124: u1 = undefined;
643 addcarryxU64(&x123, &x124, x122, x99, x114);
644 var x125: u64 = undefined;
645 var x126: u64 = undefined;
646 mulxU64(&x125, &x126, x115, 0xccd1c8aaee00bc4f);
647 var x127: u64 = undefined;
648 var x128: u64 = undefined;
649 mulxU64(&x127, &x128, x125, 0xffffffff00000000);
650 var x129: u64 = undefined;
651 var x130: u64 = undefined;
652 mulxU64(&x129, &x130, x125, 0xffffffffffffffff);
653 var x131: u64 = undefined;
654 var x132: u64 = undefined;
655 mulxU64(&x131, &x132, x125, 0xbce6faada7179e84);
656 var x133: u64 = undefined;
657 var x134: u64 = undefined;
658 mulxU64(&x133, &x134, x125, 0xf3b9cac2fc632551);
659 var x135: u64 = undefined;
660 var x136: u1 = undefined;
661 addcarryxU64(&x135, &x136, 0x0, x134, x131);
662 var x137: u64 = undefined;
663 var x138: u1 = undefined;
664 addcarryxU64(&x137, &x138, x136, x132, x129);
665 var x139: u64 = undefined;
666 var x140: u1 = undefined;
667 addcarryxU64(&x139, &x140, x138, x130, x127);
668 const x141 = (cast(u64, x140) + x128);
669 var x142: u64 = undefined;
670 var x143: u1 = undefined;
671 addcarryxU64(&x142, &x143, 0x0, x115, x133);
672 var x144: u64 = undefined;
673 var x145: u1 = undefined;
674 addcarryxU64(&x144, &x145, x143, x117, x135);
675 var x146: u64 = undefined;
676 var x147: u1 = undefined;
677 addcarryxU64(&x146, &x147, x145, x119, x137);
678 var x148: u64 = undefined;
679 var x149: u1 = undefined;
680 addcarryxU64(&x148, &x149, x147, x121, x139);
681 var x150: u64 = undefined;
682 var x151: u1 = undefined;
683 addcarryxU64(&x150, &x151, x149, x123, x141);
684 const x152 = (cast(u64, x151) + cast(u64, x124));
685 var x153: u64 = undefined;
686 var x154: u64 = undefined;
687 mulxU64(&x153, &x154, x3, (arg1[3]));
688 var x155: u64 = undefined;
689 var x156: u64 = undefined;
690 mulxU64(&x155, &x156, x3, (arg1[2]));
691 var x157: u64 = undefined;
692 var x158: u64 = undefined;
693 mulxU64(&x157, &x158, x3, (arg1[1]));
694 var x159: u64 = undefined;
695 var x160: u64 = undefined;
696 mulxU64(&x159, &x160, x3, (arg1[0]));
697 var x161: u64 = undefined;
698 var x162: u1 = undefined;
699 addcarryxU64(&x161, &x162, 0x0, x160, x157);
700 var x163: u64 = undefined;
701 var x164: u1 = undefined;
702 addcarryxU64(&x163, &x164, x162, x158, x155);
703 var x165: u64 = undefined;
704 var x166: u1 = undefined;
705 addcarryxU64(&x165, &x166, x164, x156, x153);
706 const x167 = (cast(u64, x166) + x154);
707 var x168: u64 = undefined;
708 var x169: u1 = undefined;
709 addcarryxU64(&x168, &x169, 0x0, x144, x159);
710 var x170: u64 = undefined;
711 var x171: u1 = undefined;
712 addcarryxU64(&x170, &x171, x169, x146, x161);
713 var x172: u64 = undefined;
714 var x173: u1 = undefined;
715 addcarryxU64(&x172, &x173, x171, x148, x163);
716 var x174: u64 = undefined;
717 var x175: u1 = undefined;
718 addcarryxU64(&x174, &x175, x173, x150, x165);
719 var x176: u64 = undefined;
720 var x177: u1 = undefined;
721 addcarryxU64(&x176, &x177, x175, x152, x167);
722 var x178: u64 = undefined;
723 var x179: u64 = undefined;
724 mulxU64(&x178, &x179, x168, 0xccd1c8aaee00bc4f);
725 var x180: u64 = undefined;
726 var x181: u64 = undefined;
727 mulxU64(&x180, &x181, x178, 0xffffffff00000000);
728 var x182: u64 = undefined;
729 var x183: u64 = undefined;
730 mulxU64(&x182, &x183, x178, 0xffffffffffffffff);
731 var x184: u64 = undefined;
732 var x185: u64 = undefined;
733 mulxU64(&x184, &x185, x178, 0xbce6faada7179e84);
734 var x186: u64 = undefined;
735 var x187: u64 = undefined;
736 mulxU64(&x186, &x187, x178, 0xf3b9cac2fc632551);
737 var x188: u64 = undefined;
738 var x189: u1 = undefined;
739 addcarryxU64(&x188, &x189, 0x0, x187, x184);
740 var x190: u64 = undefined;
741 var x191: u1 = undefined;
742 addcarryxU64(&x190, &x191, x189, x185, x182);
743 var x192: u64 = undefined;
744 var x193: u1 = undefined;
745 addcarryxU64(&x192, &x193, x191, x183, x180);
746 const x194 = (cast(u64, x193) + x181);
747 var x195: u64 = undefined;
748 var x196: u1 = undefined;
749 addcarryxU64(&x195, &x196, 0x0, x168, x186);
750 var x197: u64 = undefined;
751 var x198: u1 = undefined;
752 addcarryxU64(&x197, &x198, x196, x170, x188);
753 var x199: u64 = undefined;
754 var x200: u1 = undefined;
755 addcarryxU64(&x199, &x200, x198, x172, x190);
756 var x201: u64 = undefined;
757 var x202: u1 = undefined;
758 addcarryxU64(&x201, &x202, x200, x174, x192);
759 var x203: u64 = undefined;
760 var x204: u1 = undefined;
761 addcarryxU64(&x203, &x204, x202, x176, x194);
762 const x205 = (cast(u64, x204) + cast(u64, x177));
763 var x206: u64 = undefined;
764 var x207: u1 = undefined;
765 subborrowxU64(&x206, &x207, 0x0, x197, 0xf3b9cac2fc632551);
766 var x208: u64 = undefined;
767 var x209: u1 = undefined;
768 subborrowxU64(&x208, &x209, x207, x199, 0xbce6faada7179e84);
769 var x210: u64 = undefined;
770 var x211: u1 = undefined;
771 subborrowxU64(&x210, &x211, x209, x201, 0xffffffffffffffff);
772 var x212: u64 = undefined;
773 var x213: u1 = undefined;
774 subborrowxU64(&x212, &x213, x211, x203, 0xffffffff00000000);
775 var x214: u64 = undefined;
776 var x215: u1 = undefined;
777 subborrowxU64(&x214, &x215, x213, x205, cast(u64, 0x0));
778 var x216: u64 = undefined;
779 cmovznzU64(&x216, x215, x206, x197);
780 var x217: u64 = undefined;
781 cmovznzU64(&x217, x215, x208, x199);
782 var x218: u64 = undefined;
783 cmovznzU64(&x218, x215, x210, x201);
784 var x219: u64 = undefined;
785 cmovznzU64(&x219, x215, x212, x203);
786 out1[0] = x216;
787 out1[1] = x217;
788 out1[2] = x218;
789 out1[3] = x219;
790}
791
792/// The function add adds two field elements in the Montgomery domain.
793/// Preconditions:
794/// 0 ≤ eval arg1 < m
795/// 0 ≤ eval arg2 < m
796/// Postconditions:
797/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
798/// 0 ≤ eval out1 < m
799///
800/// Input Bounds:
801/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
802/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
803/// Output Bounds:
804/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
805pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
806 @setRuntimeSafety(mode == .Debug);
807
808 var x1: u64 = undefined;
809 var x2: u1 = undefined;
810 addcarryxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
811 var x3: u64 = undefined;
812 var x4: u1 = undefined;
813 addcarryxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
814 var x5: u64 = undefined;
815 var x6: u1 = undefined;
816 addcarryxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
817 var x7: u64 = undefined;
818 var x8: u1 = undefined;
819 addcarryxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
820 var x9: u64 = undefined;
821 var x10: u1 = undefined;
822 subborrowxU64(&x9, &x10, 0x0, x1, 0xf3b9cac2fc632551);
823 var x11: u64 = undefined;
824 var x12: u1 = undefined;
825 subborrowxU64(&x11, &x12, x10, x3, 0xbce6faada7179e84);
826 var x13: u64 = undefined;
827 var x14: u1 = undefined;
828 subborrowxU64(&x13, &x14, x12, x5, 0xffffffffffffffff);
829 var x15: u64 = undefined;
830 var x16: u1 = undefined;
831 subborrowxU64(&x15, &x16, x14, x7, 0xffffffff00000000);
832 var x17: u64 = undefined;
833 var x18: u1 = undefined;
834 subborrowxU64(&x17, &x18, x16, cast(u64, x8), cast(u64, 0x0));
835 var x19: u64 = undefined;
836 cmovznzU64(&x19, x18, x9, x1);
837 var x20: u64 = undefined;
838 cmovznzU64(&x20, x18, x11, x3);
839 var x21: u64 = undefined;
840 cmovznzU64(&x21, x18, x13, x5);
841 var x22: u64 = undefined;
842 cmovznzU64(&x22, x18, x15, x7);
843 out1[0] = x19;
844 out1[1] = x20;
845 out1[2] = x21;
846 out1[3] = x22;
847}
848
849/// The function sub subtracts two field elements in the Montgomery domain.
850/// Preconditions:
851/// 0 ≤ eval arg1 < m
852/// 0 ≤ eval arg2 < m
853/// Postconditions:
854/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
855/// 0 ≤ eval out1 < m
856///
857/// Input Bounds:
858/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
859/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
860/// Output Bounds:
861/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
862pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
863 @setRuntimeSafety(mode == .Debug);
864
865 var x1: u64 = undefined;
866 var x2: u1 = undefined;
867 subborrowxU64(&x1, &x2, 0x0, (arg1[0]), (arg2[0]));
868 var x3: u64 = undefined;
869 var x4: u1 = undefined;
870 subborrowxU64(&x3, &x4, x2, (arg1[1]), (arg2[1]));
871 var x5: u64 = undefined;
872 var x6: u1 = undefined;
873 subborrowxU64(&x5, &x6, x4, (arg1[2]), (arg2[2]));
874 var x7: u64 = undefined;
875 var x8: u1 = undefined;
876 subborrowxU64(&x7, &x8, x6, (arg1[3]), (arg2[3]));
877 var x9: u64 = undefined;
878 cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
879 var x10: u64 = undefined;
880 var x11: u1 = undefined;
881 addcarryxU64(&x10, &x11, 0x0, x1, (x9 & 0xf3b9cac2fc632551));
882 var x12: u64 = undefined;
883 var x13: u1 = undefined;
884 addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xbce6faada7179e84));
885 var x14: u64 = undefined;
886 var x15: u1 = undefined;
887 addcarryxU64(&x14, &x15, x13, x5, x9);
888 var x16: u64 = undefined;
889 var x17: u1 = undefined;
890 addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000000));
891 out1[0] = x10;
892 out1[1] = x12;
893 out1[2] = x14;
894 out1[3] = x16;
895}
896
897/// The function opp negates a field element in the Montgomery domain.
898/// Preconditions:
899/// 0 ≤ eval arg1 < m
900/// Postconditions:
901/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
902/// 0 ≤ eval out1 < m
903///
904/// Input Bounds:
905/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
906/// Output Bounds:
907/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
908pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
909 @setRuntimeSafety(mode == .Debug);
910
911 var x1: u64 = undefined;
912 var x2: u1 = undefined;
913 subborrowxU64(&x1, &x2, 0x0, cast(u64, 0x0), (arg1[0]));
914 var x3: u64 = undefined;
915 var x4: u1 = undefined;
916 subborrowxU64(&x3, &x4, x2, cast(u64, 0x0), (arg1[1]));
917 var x5: u64 = undefined;
918 var x6: u1 = undefined;
919 subborrowxU64(&x5, &x6, x4, cast(u64, 0x0), (arg1[2]));
920 var x7: u64 = undefined;
921 var x8: u1 = undefined;
922 subborrowxU64(&x7, &x8, x6, cast(u64, 0x0), (arg1[3]));
923 var x9: u64 = undefined;
924 cmovznzU64(&x9, x8, cast(u64, 0x0), 0xffffffffffffffff);
925 var x10: u64 = undefined;
926 var x11: u1 = undefined;
927 addcarryxU64(&x10, &x11, 0x0, x1, (x9 & 0xf3b9cac2fc632551));
928 var x12: u64 = undefined;
929 var x13: u1 = undefined;
930 addcarryxU64(&x12, &x13, x11, x3, (x9 & 0xbce6faada7179e84));
931 var x14: u64 = undefined;
932 var x15: u1 = undefined;
933 addcarryxU64(&x14, &x15, x13, x5, x9);
934 var x16: u64 = undefined;
935 var x17: u1 = undefined;
936 addcarryxU64(&x16, &x17, x15, x7, (x9 & 0xffffffff00000000));
937 out1[0] = x10;
938 out1[1] = x12;
939 out1[2] = x14;
940 out1[3] = x16;
941}
942
943/// The function fromMontgomery translates a field element out of the Montgomery domain.
944/// Preconditions:
945/// 0 ≤ eval arg1 < m
946/// Postconditions:
947/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
948/// 0 ≤ eval out1 < m
949///
950/// Input Bounds:
951/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
952/// Output Bounds:
953/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
954pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
955 @setRuntimeSafety(mode == .Debug);
956
957 const x1 = (arg1[0]);
958 var x2: u64 = undefined;
959 var x3: u64 = undefined;
960 mulxU64(&x2, &x3, x1, 0xccd1c8aaee00bc4f);
961 var x4: u64 = undefined;
962 var x5: u64 = undefined;
963 mulxU64(&x4, &x5, x2, 0xffffffff00000000);
964 var x6: u64 = undefined;
965 var x7: u64 = undefined;
966 mulxU64(&x6, &x7, x2, 0xffffffffffffffff);
967 var x8: u64 = undefined;
968 var x9: u64 = undefined;
969 mulxU64(&x8, &x9, x2, 0xbce6faada7179e84);
970 var x10: u64 = undefined;
971 var x11: u64 = undefined;
972 mulxU64(&x10, &x11, x2, 0xf3b9cac2fc632551);
973 var x12: u64 = undefined;
974 var x13: u1 = undefined;
975 addcarryxU64(&x12, &x13, 0x0, x11, x8);
976 var x14: u64 = undefined;
977 var x15: u1 = undefined;
978 addcarryxU64(&x14, &x15, x13, x9, x6);
979 var x16: u64 = undefined;
980 var x17: u1 = undefined;
981 addcarryxU64(&x16, &x17, x15, x7, x4);
982 var x18: u64 = undefined;
983 var x19: u1 = undefined;
984 addcarryxU64(&x18, &x19, 0x0, x1, x10);
985 var x20: u64 = undefined;
986 var x21: u1 = undefined;
987 addcarryxU64(&x20, &x21, x19, cast(u64, 0x0), x12);
988 var x22: u64 = undefined;
989 var x23: u1 = undefined;
990 addcarryxU64(&x22, &x23, x21, cast(u64, 0x0), x14);
991 var x24: u64 = undefined;
992 var x25: u1 = undefined;
993 addcarryxU64(&x24, &x25, x23, cast(u64, 0x0), x16);
994 var x26: u64 = undefined;
995 var x27: u1 = undefined;
996 addcarryxU64(&x26, &x27, 0x0, x20, (arg1[1]));
997 var x28: u64 = undefined;
998 var x29: u1 = undefined;
999 addcarryxU64(&x28, &x29, x27, x22, cast(u64, 0x0));
1000 var x30: u64 = undefined;
1001 var x31: u1 = undefined;
1002 addcarryxU64(&x30, &x31, x29, x24, cast(u64, 0x0));
1003 var x32: u64 = undefined;
1004 var x33: u64 = undefined;
1005 mulxU64(&x32, &x33, x26, 0xccd1c8aaee00bc4f);
1006 var x34: u64 = undefined;
1007 var x35: u64 = undefined;
1008 mulxU64(&x34, &x35, x32, 0xffffffff00000000);
1009 var x36: u64 = undefined;
1010 var x37: u64 = undefined;
1011 mulxU64(&x36, &x37, x32, 0xffffffffffffffff);
1012 var x38: u64 = undefined;
1013 var x39: u64 = undefined;
1014 mulxU64(&x38, &x39, x32, 0xbce6faada7179e84);
1015 var x40: u64 = undefined;
1016 var x41: u64 = undefined;
1017 mulxU64(&x40, &x41, x32, 0xf3b9cac2fc632551);
1018 var x42: u64 = undefined;
1019 var x43: u1 = undefined;
1020 addcarryxU64(&x42, &x43, 0x0, x41, x38);
1021 var x44: u64 = undefined;
1022 var x45: u1 = undefined;
1023 addcarryxU64(&x44, &x45, x43, x39, x36);
1024 var x46: u64 = undefined;
1025 var x47: u1 = undefined;
1026 addcarryxU64(&x46, &x47, x45, x37, x34);
1027 var x48: u64 = undefined;
1028 var x49: u1 = undefined;
1029 addcarryxU64(&x48, &x49, 0x0, x26, x40);
1030 var x50: u64 = undefined;
1031 var x51: u1 = undefined;
1032 addcarryxU64(&x50, &x51, x49, x28, x42);
1033 var x52: u64 = undefined;
1034 var x53: u1 = undefined;
1035 addcarryxU64(&x52, &x53, x51, x30, x44);
1036 var x54: u64 = undefined;
1037 var x55: u1 = undefined;
1038 addcarryxU64(&x54, &x55, x53, (cast(u64, x31) + (cast(u64, x25) + (cast(u64, x17) + x5))), x46);
1039 var x56: u64 = undefined;
1040 var x57: u1 = undefined;
1041 addcarryxU64(&x56, &x57, 0x0, x50, (arg1[2]));
1042 var x58: u64 = undefined;
1043 var x59: u1 = undefined;
1044 addcarryxU64(&x58, &x59, x57, x52, cast(u64, 0x0));
1045 var x60: u64 = undefined;
1046 var x61: u1 = undefined;
1047 addcarryxU64(&x60, &x61, x59, x54, cast(u64, 0x0));
1048 var x62: u64 = undefined;
1049 var x63: u64 = undefined;
1050 mulxU64(&x62, &x63, x56, 0xccd1c8aaee00bc4f);
1051 var x64: u64 = undefined;
1052 var x65: u64 = undefined;
1053 mulxU64(&x64, &x65, x62, 0xffffffff00000000);
1054 var x66: u64 = undefined;
1055 var x67: u64 = undefined;
1056 mulxU64(&x66, &x67, x62, 0xffffffffffffffff);
1057 var x68: u64 = undefined;
1058 var x69: u64 = undefined;
1059 mulxU64(&x68, &x69, x62, 0xbce6faada7179e84);
1060 var x70: u64 = undefined;
1061 var x71: u64 = undefined;
1062 mulxU64(&x70, &x71, x62, 0xf3b9cac2fc632551);
1063 var x72: u64 = undefined;
1064 var x73: u1 = undefined;
1065 addcarryxU64(&x72, &x73, 0x0, x71, x68);
1066 var x74: u64 = undefined;
1067 var x75: u1 = undefined;
1068 addcarryxU64(&x74, &x75, x73, x69, x66);
1069 var x76: u64 = undefined;
1070 var x77: u1 = undefined;
1071 addcarryxU64(&x76, &x77, x75, x67, x64);
1072 var x78: u64 = undefined;
1073 var x79: u1 = undefined;
1074 addcarryxU64(&x78, &x79, 0x0, x56, x70);
1075 var x80: u64 = undefined;
1076 var x81: u1 = undefined;
1077 addcarryxU64(&x80, &x81, x79, x58, x72);
1078 var x82: u64 = undefined;
1079 var x83: u1 = undefined;
1080 addcarryxU64(&x82, &x83, x81, x60, x74);
1081 var x84: u64 = undefined;
1082 var x85: u1 = undefined;
1083 addcarryxU64(&x84, &x85, x83, (cast(u64, x61) + (cast(u64, x55) + (cast(u64, x47) + x35))), x76);
1084 var x86: u64 = undefined;
1085 var x87: u1 = undefined;
1086 addcarryxU64(&x86, &x87, 0x0, x80, (arg1[3]));
1087 var x88: u64 = undefined;
1088 var x89: u1 = undefined;
1089 addcarryxU64(&x88, &x89, x87, x82, cast(u64, 0x0));
1090 var x90: u64 = undefined;
1091 var x91: u1 = undefined;
1092 addcarryxU64(&x90, &x91, x89, x84, cast(u64, 0x0));
1093 var x92: u64 = undefined;
1094 var x93: u64 = undefined;
1095 mulxU64(&x92, &x93, x86, 0xccd1c8aaee00bc4f);
1096 var x94: u64 = undefined;
1097 var x95: u64 = undefined;
1098 mulxU64(&x94, &x95, x92, 0xffffffff00000000);
1099 var x96: u64 = undefined;
1100 var x97: u64 = undefined;
1101 mulxU64(&x96, &x97, x92, 0xffffffffffffffff);
1102 var x98: u64 = undefined;
1103 var x99: u64 = undefined;
1104 mulxU64(&x98, &x99, x92, 0xbce6faada7179e84);
1105 var x100: u64 = undefined;
1106 var x101: u64 = undefined;
1107 mulxU64(&x100, &x101, x92, 0xf3b9cac2fc632551);
1108 var x102: u64 = undefined;
1109 var x103: u1 = undefined;
1110 addcarryxU64(&x102, &x103, 0x0, x101, x98);
1111 var x104: u64 = undefined;
1112 var x105: u1 = undefined;
1113 addcarryxU64(&x104, &x105, x103, x99, x96);
1114 var x106: u64 = undefined;
1115 var x107: u1 = undefined;
1116 addcarryxU64(&x106, &x107, x105, x97, x94);
1117 var x108: u64 = undefined;
1118 var x109: u1 = undefined;
1119 addcarryxU64(&x108, &x109, 0x0, x86, x100);
1120 var x110: u64 = undefined;
1121 var x111: u1 = undefined;
1122 addcarryxU64(&x110, &x111, x109, x88, x102);
1123 var x112: u64 = undefined;
1124 var x113: u1 = undefined;
1125 addcarryxU64(&x112, &x113, x111, x90, x104);
1126 var x114: u64 = undefined;
1127 var x115: u1 = undefined;
1128 addcarryxU64(&x114, &x115, x113, (cast(u64, x91) + (cast(u64, x85) + (cast(u64, x77) + x65))), x106);
1129 const x116 = (cast(u64, x115) + (cast(u64, x107) + x95));
1130 var x117: u64 = undefined;
1131 var x118: u1 = undefined;
1132 subborrowxU64(&x117, &x118, 0x0, x110, 0xf3b9cac2fc632551);
1133 var x119: u64 = undefined;
1134 var x120: u1 = undefined;
1135 subborrowxU64(&x119, &x120, x118, x112, 0xbce6faada7179e84);
1136 var x121: u64 = undefined;
1137 var x122: u1 = undefined;
1138 subborrowxU64(&x121, &x122, x120, x114, 0xffffffffffffffff);
1139 var x123: u64 = undefined;
1140 var x124: u1 = undefined;
1141 subborrowxU64(&x123, &x124, x122, x116, 0xffffffff00000000);
1142 var x125: u64 = undefined;
1143 var x126: u1 = undefined;
1144 subborrowxU64(&x125, &x126, x124, cast(u64, 0x0), cast(u64, 0x0));
1145 var x127: u64 = undefined;
1146 cmovznzU64(&x127, x126, x117, x110);
1147 var x128: u64 = undefined;
1148 cmovznzU64(&x128, x126, x119, x112);
1149 var x129: u64 = undefined;
1150 cmovznzU64(&x129, x126, x121, x114);
1151 var x130: u64 = undefined;
1152 cmovznzU64(&x130, x126, x123, x116);
1153 out1[0] = x127;
1154 out1[1] = x128;
1155 out1[2] = x129;
1156 out1[3] = x130;
1157}
1158
1159/// The function toMontgomery translates a field element into the Montgomery domain.
1160/// Preconditions:
1161/// 0 ≤ eval arg1 < m
1162/// Postconditions:
1163/// eval (from_montgomery out1) mod m = eval arg1 mod m
1164/// 0 ≤ eval out1 < m
1165///
1166/// Input Bounds:
1167/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1168/// Output Bounds:
1169/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1170pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1171 @setRuntimeSafety(mode == .Debug);
1172
1173 const x1 = (arg1[1]);
1174 const x2 = (arg1[2]);
1175 const x3 = (arg1[3]);
1176 const x4 = (arg1[0]);
1177 var x5: u64 = undefined;
1178 var x6: u64 = undefined;
1179 mulxU64(&x5, &x6, x4, 0x66e12d94f3d95620);
1180 var x7: u64 = undefined;
1181 var x8: u64 = undefined;
1182 mulxU64(&x7, &x8, x4, 0x2845b2392b6bec59);
1183 var x9: u64 = undefined;
1184 var x10: u64 = undefined;
1185 mulxU64(&x9, &x10, x4, 0x4699799c49bd6fa6);
1186 var x11: u64 = undefined;
1187 var x12: u64 = undefined;
1188 mulxU64(&x11, &x12, x4, 0x83244c95be79eea2);
1189 var x13: u64 = undefined;
1190 var x14: u1 = undefined;
1191 addcarryxU64(&x13, &x14, 0x0, x12, x9);
1192 var x15: u64 = undefined;
1193 var x16: u1 = undefined;
1194 addcarryxU64(&x15, &x16, x14, x10, x7);
1195 var x17: u64 = undefined;
1196 var x18: u1 = undefined;
1197 addcarryxU64(&x17, &x18, x16, x8, x5);
1198 var x19: u64 = undefined;
1199 var x20: u64 = undefined;
1200 mulxU64(&x19, &x20, x11, 0xccd1c8aaee00bc4f);
1201 var x21: u64 = undefined;
1202 var x22: u64 = undefined;
1203 mulxU64(&x21, &x22, x19, 0xffffffff00000000);
1204 var x23: u64 = undefined;
1205 var x24: u64 = undefined;
1206 mulxU64(&x23, &x24, x19, 0xffffffffffffffff);
1207 var x25: u64 = undefined;
1208 var x26: u64 = undefined;
1209 mulxU64(&x25, &x26, x19, 0xbce6faada7179e84);
1210 var x27: u64 = undefined;
1211 var x28: u64 = undefined;
1212 mulxU64(&x27, &x28, x19, 0xf3b9cac2fc632551);
1213 var x29: u64 = undefined;
1214 var x30: u1 = undefined;
1215 addcarryxU64(&x29, &x30, 0x0, x28, x25);
1216 var x31: u64 = undefined;
1217 var x32: u1 = undefined;
1218 addcarryxU64(&x31, &x32, x30, x26, x23);
1219 var x33: u64 = undefined;
1220 var x34: u1 = undefined;
1221 addcarryxU64(&x33, &x34, x32, x24, x21);
1222 var x35: u64 = undefined;
1223 var x36: u1 = undefined;
1224 addcarryxU64(&x35, &x36, 0x0, x11, x27);
1225 var x37: u64 = undefined;
1226 var x38: u1 = undefined;
1227 addcarryxU64(&x37, &x38, x36, x13, x29);
1228 var x39: u64 = undefined;
1229 var x40: u1 = undefined;
1230 addcarryxU64(&x39, &x40, x38, x15, x31);
1231 var x41: u64 = undefined;
1232 var x42: u1 = undefined;
1233 addcarryxU64(&x41, &x42, x40, x17, x33);
1234 var x43: u64 = undefined;
1235 var x44: u1 = undefined;
1236 addcarryxU64(&x43, &x44, x42, (cast(u64, x18) + x6), (cast(u64, x34) + x22));
1237 var x45: u64 = undefined;
1238 var x46: u64 = undefined;
1239 mulxU64(&x45, &x46, x1, 0x66e12d94f3d95620);
1240 var x47: u64 = undefined;
1241 var x48: u64 = undefined;
1242 mulxU64(&x47, &x48, x1, 0x2845b2392b6bec59);
1243 var x49: u64 = undefined;
1244 var x50: u64 = undefined;
1245 mulxU64(&x49, &x50, x1, 0x4699799c49bd6fa6);
1246 var x51: u64 = undefined;
1247 var x52: u64 = undefined;
1248 mulxU64(&x51, &x52, x1, 0x83244c95be79eea2);
1249 var x53: u64 = undefined;
1250 var x54: u1 = undefined;
1251 addcarryxU64(&x53, &x54, 0x0, x52, x49);
1252 var x55: u64 = undefined;
1253 var x56: u1 = undefined;
1254 addcarryxU64(&x55, &x56, x54, x50, x47);
1255 var x57: u64 = undefined;
1256 var x58: u1 = undefined;
1257 addcarryxU64(&x57, &x58, x56, x48, x45);
1258 var x59: u64 = undefined;
1259 var x60: u1 = undefined;
1260 addcarryxU64(&x59, &x60, 0x0, x37, x51);
1261 var x61: u64 = undefined;
1262 var x62: u1 = undefined;
1263 addcarryxU64(&x61, &x62, x60, x39, x53);
1264 var x63: u64 = undefined;
1265 var x64: u1 = undefined;
1266 addcarryxU64(&x63, &x64, x62, x41, x55);
1267 var x65: u64 = undefined;
1268 var x66: u1 = undefined;
1269 addcarryxU64(&x65, &x66, x64, x43, x57);
1270 var x67: u64 = undefined;
1271 var x68: u64 = undefined;
1272 mulxU64(&x67, &x68, x59, 0xccd1c8aaee00bc4f);
1273 var x69: u64 = undefined;
1274 var x70: u64 = undefined;
1275 mulxU64(&x69, &x70, x67, 0xffffffff00000000);
1276 var x71: u64 = undefined;
1277 var x72: u64 = undefined;
1278 mulxU64(&x71, &x72, x67, 0xffffffffffffffff);
1279 var x73: u64 = undefined;
1280 var x74: u64 = undefined;
1281 mulxU64(&x73, &x74, x67, 0xbce6faada7179e84);
1282 var x75: u64 = undefined;
1283 var x76: u64 = undefined;
1284 mulxU64(&x75, &x76, x67, 0xf3b9cac2fc632551);
1285 var x77: u64 = undefined;
1286 var x78: u1 = undefined;
1287 addcarryxU64(&x77, &x78, 0x0, x76, x73);
1288 var x79: u64 = undefined;
1289 var x80: u1 = undefined;
1290 addcarryxU64(&x79, &x80, x78, x74, x71);
1291 var x81: u64 = undefined;
1292 var x82: u1 = undefined;
1293 addcarryxU64(&x81, &x82, x80, x72, x69);
1294 var x83: u64 = undefined;
1295 var x84: u1 = undefined;
1296 addcarryxU64(&x83, &x84, 0x0, x59, x75);
1297 var x85: u64 = undefined;
1298 var x86: u1 = undefined;
1299 addcarryxU64(&x85, &x86, x84, x61, x77);
1300 var x87: u64 = undefined;
1301 var x88: u1 = undefined;
1302 addcarryxU64(&x87, &x88, x86, x63, x79);
1303 var x89: u64 = undefined;
1304 var x90: u1 = undefined;
1305 addcarryxU64(&x89, &x90, x88, x65, x81);
1306 var x91: u64 = undefined;
1307 var x92: u1 = undefined;
1308 addcarryxU64(&x91, &x92, x90, ((cast(u64, x66) + cast(u64, x44)) + (cast(u64, x58) + x46)), (cast(u64, x82) + x70));
1309 var x93: u64 = undefined;
1310 var x94: u64 = undefined;
1311 mulxU64(&x93, &x94, x2, 0x66e12d94f3d95620);
1312 var x95: u64 = undefined;
1313 var x96: u64 = undefined;
1314 mulxU64(&x95, &x96, x2, 0x2845b2392b6bec59);
1315 var x97: u64 = undefined;
1316 var x98: u64 = undefined;
1317 mulxU64(&x97, &x98, x2, 0x4699799c49bd6fa6);
1318 var x99: u64 = undefined;
1319 var x100: u64 = undefined;
1320 mulxU64(&x99, &x100, x2, 0x83244c95be79eea2);
1321 var x101: u64 = undefined;
1322 var x102: u1 = undefined;
1323 addcarryxU64(&x101, &x102, 0x0, x100, x97);
1324 var x103: u64 = undefined;
1325 var x104: u1 = undefined;
1326 addcarryxU64(&x103, &x104, x102, x98, x95);
1327 var x105: u64 = undefined;
1328 var x106: u1 = undefined;
1329 addcarryxU64(&x105, &x106, x104, x96, x93);
1330 var x107: u64 = undefined;
1331 var x108: u1 = undefined;
1332 addcarryxU64(&x107, &x108, 0x0, x85, x99);
1333 var x109: u64 = undefined;
1334 var x110: u1 = undefined;
1335 addcarryxU64(&x109, &x110, x108, x87, x101);
1336 var x111: u64 = undefined;
1337 var x112: u1 = undefined;
1338 addcarryxU64(&x111, &x112, x110, x89, x103);
1339 var x113: u64 = undefined;
1340 var x114: u1 = undefined;
1341 addcarryxU64(&x113, &x114, x112, x91, x105);
1342 var x115: u64 = undefined;
1343 var x116: u64 = undefined;
1344 mulxU64(&x115, &x116, x107, 0xccd1c8aaee00bc4f);
1345 var x117: u64 = undefined;
1346 var x118: u64 = undefined;
1347 mulxU64(&x117, &x118, x115, 0xffffffff00000000);
1348 var x119: u64 = undefined;
1349 var x120: u64 = undefined;
1350 mulxU64(&x119, &x120, x115, 0xffffffffffffffff);
1351 var x121: u64 = undefined;
1352 var x122: u64 = undefined;
1353 mulxU64(&x121, &x122, x115, 0xbce6faada7179e84);
1354 var x123: u64 = undefined;
1355 var x124: u64 = undefined;
1356 mulxU64(&x123, &x124, x115, 0xf3b9cac2fc632551);
1357 var x125: u64 = undefined;
1358 var x126: u1 = undefined;
1359 addcarryxU64(&x125, &x126, 0x0, x124, x121);
1360 var x127: u64 = undefined;
1361 var x128: u1 = undefined;
1362 addcarryxU64(&x127, &x128, x126, x122, x119);
1363 var x129: u64 = undefined;
1364 var x130: u1 = undefined;
1365 addcarryxU64(&x129, &x130, x128, x120, x117);
1366 var x131: u64 = undefined;
1367 var x132: u1 = undefined;
1368 addcarryxU64(&x131, &x132, 0x0, x107, x123);
1369 var x133: u64 = undefined;
1370 var x134: u1 = undefined;
1371 addcarryxU64(&x133, &x134, x132, x109, x125);
1372 var x135: u64 = undefined;
1373 var x136: u1 = undefined;
1374 addcarryxU64(&x135, &x136, x134, x111, x127);
1375 var x137: u64 = undefined;
1376 var x138: u1 = undefined;
1377 addcarryxU64(&x137, &x138, x136, x113, x129);
1378 var x139: u64 = undefined;
1379 var x140: u1 = undefined;
1380 addcarryxU64(&x139, &x140, x138, ((cast(u64, x114) + cast(u64, x92)) + (cast(u64, x106) + x94)), (cast(u64, x130) + x118));
1381 var x141: u64 = undefined;
1382 var x142: u64 = undefined;
1383 mulxU64(&x141, &x142, x3, 0x66e12d94f3d95620);
1384 var x143: u64 = undefined;
1385 var x144: u64 = undefined;
1386 mulxU64(&x143, &x144, x3, 0x2845b2392b6bec59);
1387 var x145: u64 = undefined;
1388 var x146: u64 = undefined;
1389 mulxU64(&x145, &x146, x3, 0x4699799c49bd6fa6);
1390 var x147: u64 = undefined;
1391 var x148: u64 = undefined;
1392 mulxU64(&x147, &x148, x3, 0x83244c95be79eea2);
1393 var x149: u64 = undefined;
1394 var x150: u1 = undefined;
1395 addcarryxU64(&x149, &x150, 0x0, x148, x145);
1396 var x151: u64 = undefined;
1397 var x152: u1 = undefined;
1398 addcarryxU64(&x151, &x152, x150, x146, x143);
1399 var x153: u64 = undefined;
1400 var x154: u1 = undefined;
1401 addcarryxU64(&x153, &x154, x152, x144, x141);
1402 var x155: u64 = undefined;
1403 var x156: u1 = undefined;
1404 addcarryxU64(&x155, &x156, 0x0, x133, x147);
1405 var x157: u64 = undefined;
1406 var x158: u1 = undefined;
1407 addcarryxU64(&x157, &x158, x156, x135, x149);
1408 var x159: u64 = undefined;
1409 var x160: u1 = undefined;
1410 addcarryxU64(&x159, &x160, x158, x137, x151);
1411 var x161: u64 = undefined;
1412 var x162: u1 = undefined;
1413 addcarryxU64(&x161, &x162, x160, x139, x153);
1414 var x163: u64 = undefined;
1415 var x164: u64 = undefined;
1416 mulxU64(&x163, &x164, x155, 0xccd1c8aaee00bc4f);
1417 var x165: u64 = undefined;
1418 var x166: u64 = undefined;
1419 mulxU64(&x165, &x166, x163, 0xffffffff00000000);
1420 var x167: u64 = undefined;
1421 var x168: u64 = undefined;
1422 mulxU64(&x167, &x168, x163, 0xffffffffffffffff);
1423 var x169: u64 = undefined;
1424 var x170: u64 = undefined;
1425 mulxU64(&x169, &x170, x163, 0xbce6faada7179e84);
1426 var x171: u64 = undefined;
1427 var x172: u64 = undefined;
1428 mulxU64(&x171, &x172, x163, 0xf3b9cac2fc632551);
1429 var x173: u64 = undefined;
1430 var x174: u1 = undefined;
1431 addcarryxU64(&x173, &x174, 0x0, x172, x169);
1432 var x175: u64 = undefined;
1433 var x176: u1 = undefined;
1434 addcarryxU64(&x175, &x176, x174, x170, x167);
1435 var x177: u64 = undefined;
1436 var x178: u1 = undefined;
1437 addcarryxU64(&x177, &x178, x176, x168, x165);
1438 var x179: u64 = undefined;
1439 var x180: u1 = undefined;
1440 addcarryxU64(&x179, &x180, 0x0, x155, x171);
1441 var x181: u64 = undefined;
1442 var x182: u1 = undefined;
1443 addcarryxU64(&x181, &x182, x180, x157, x173);
1444 var x183: u64 = undefined;
1445 var x184: u1 = undefined;
1446 addcarryxU64(&x183, &x184, x182, x159, x175);
1447 var x185: u64 = undefined;
1448 var x186: u1 = undefined;
1449 addcarryxU64(&x185, &x186, x184, x161, x177);
1450 var x187: u64 = undefined;
1451 var x188: u1 = undefined;
1452 addcarryxU64(&x187, &x188, x186, ((cast(u64, x162) + cast(u64, x140)) + (cast(u64, x154) + x142)), (cast(u64, x178) + x166));
1453 var x189: u64 = undefined;
1454 var x190: u1 = undefined;
1455 subborrowxU64(&x189, &x190, 0x0, x181, 0xf3b9cac2fc632551);
1456 var x191: u64 = undefined;
1457 var x192: u1 = undefined;
1458 subborrowxU64(&x191, &x192, x190, x183, 0xbce6faada7179e84);
1459 var x193: u64 = undefined;
1460 var x194: u1 = undefined;
1461 subborrowxU64(&x193, &x194, x192, x185, 0xffffffffffffffff);
1462 var x195: u64 = undefined;
1463 var x196: u1 = undefined;
1464 subborrowxU64(&x195, &x196, x194, x187, 0xffffffff00000000);
1465 var x197: u64 = undefined;
1466 var x198: u1 = undefined;
1467 subborrowxU64(&x197, &x198, x196, cast(u64, x188), cast(u64, 0x0));
1468 var x199: u64 = undefined;
1469 cmovznzU64(&x199, x198, x189, x181);
1470 var x200: u64 = undefined;
1471 cmovznzU64(&x200, x198, x191, x183);
1472 var x201: u64 = undefined;
1473 cmovznzU64(&x201, x198, x193, x185);
1474 var x202: u64 = undefined;
1475 cmovznzU64(&x202, x198, x195, x187);
1476 out1[0] = x199;
1477 out1[1] = x200;
1478 out1[2] = x201;
1479 out1[3] = x202;
1480}
1481
1482/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
1483/// Preconditions:
1484/// 0 ≤ eval arg1 < m
1485/// Postconditions:
1486/// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0
1487///
1488/// Input Bounds:
1489/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1490/// Output Bounds:
1491/// out1: [0x0 ~> 0xffffffffffffffff]
1492pub fn nonzero(out1: *u64, arg1: [4]u64) void {
1493 @setRuntimeSafety(mode == .Debug);
1494
1495 const x1 = ((arg1[0]) | ((arg1[1]) | ((arg1[2]) | (arg1[3]))));
1496 out1.* = x1;
1497}
1498
1499/// The function selectznz is a multi-limb conditional select.
1500/// Postconditions:
1501/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
1502///
1503/// Input Bounds:
1504/// arg1: [0x0 ~> 0x1]
1505/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1506/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1507/// Output Bounds:
1508/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1509pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
1510 @setRuntimeSafety(mode == .Debug);
1511
1512 var x1: u64 = undefined;
1513 cmovznzU64(&x1, arg1, (arg2[0]), (arg3[0]));
1514 var x2: u64 = undefined;
1515 cmovznzU64(&x2, arg1, (arg2[1]), (arg3[1]));
1516 var x3: u64 = undefined;
1517 cmovznzU64(&x3, arg1, (arg2[2]), (arg3[2]));
1518 var x4: u64 = undefined;
1519 cmovznzU64(&x4, arg1, (arg2[3]), (arg3[3]));
1520 out1[0] = x1;
1521 out1[1] = x2;
1522 out1[2] = x3;
1523 out1[3] = x4;
1524}
1525
1526/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
1527/// Preconditions:
1528/// 0 ≤ eval arg1 < m
1529/// Postconditions:
1530/// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
1531///
1532/// Input Bounds:
1533/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1534/// Output Bounds:
1535/// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
1536pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
1537 @setRuntimeSafety(mode == .Debug);
1538
1539 const x1 = (arg1[3]);
1540 const x2 = (arg1[2]);
1541 const x3 = (arg1[1]);
1542 const x4 = (arg1[0]);
1543 const x5 = cast(u8, (x4 & cast(u64, 0xff)));
1544 const x6 = (x4 >> 8);
1545 const x7 = cast(u8, (x6 & cast(u64, 0xff)));
1546 const x8 = (x6 >> 8);
1547 const x9 = cast(u8, (x8 & cast(u64, 0xff)));
1548 const x10 = (x8 >> 8);
1549 const x11 = cast(u8, (x10 & cast(u64, 0xff)));
1550 const x12 = (x10 >> 8);
1551 const x13 = cast(u8, (x12 & cast(u64, 0xff)));
1552 const x14 = (x12 >> 8);
1553 const x15 = cast(u8, (x14 & cast(u64, 0xff)));
1554 const x16 = (x14 >> 8);
1555 const x17 = cast(u8, (x16 & cast(u64, 0xff)));
1556 const x18 = cast(u8, (x16 >> 8));
1557 const x19 = cast(u8, (x3 & cast(u64, 0xff)));
1558 const x20 = (x3 >> 8);
1559 const x21 = cast(u8, (x20 & cast(u64, 0xff)));
1560 const x22 = (x20 >> 8);
1561 const x23 = cast(u8, (x22 & cast(u64, 0xff)));
1562 const x24 = (x22 >> 8);
1563 const x25 = cast(u8, (x24 & cast(u64, 0xff)));
1564 const x26 = (x24 >> 8);
1565 const x27 = cast(u8, (x26 & cast(u64, 0xff)));
1566 const x28 = (x26 >> 8);
1567 const x29 = cast(u8, (x28 & cast(u64, 0xff)));
1568 const x30 = (x28 >> 8);
1569 const x31 = cast(u8, (x30 & cast(u64, 0xff)));
1570 const x32 = cast(u8, (x30 >> 8));
1571 const x33 = cast(u8, (x2 & cast(u64, 0xff)));
1572 const x34 = (x2 >> 8);
1573 const x35 = cast(u8, (x34 & cast(u64, 0xff)));
1574 const x36 = (x34 >> 8);
1575 const x37 = cast(u8, (x36 & cast(u64, 0xff)));
1576 const x38 = (x36 >> 8);
1577 const x39 = cast(u8, (x38 & cast(u64, 0xff)));
1578 const x40 = (x38 >> 8);
1579 const x41 = cast(u8, (x40 & cast(u64, 0xff)));
1580 const x42 = (x40 >> 8);
1581 const x43 = cast(u8, (x42 & cast(u64, 0xff)));
1582 const x44 = (x42 >> 8);
1583 const x45 = cast(u8, (x44 & cast(u64, 0xff)));
1584 const x46 = cast(u8, (x44 >> 8));
1585 const x47 = cast(u8, (x1 & cast(u64, 0xff)));
1586 const x48 = (x1 >> 8);
1587 const x49 = cast(u8, (x48 & cast(u64, 0xff)));
1588 const x50 = (x48 >> 8);
1589 const x51 = cast(u8, (x50 & cast(u64, 0xff)));
1590 const x52 = (x50 >> 8);
1591 const x53 = cast(u8, (x52 & cast(u64, 0xff)));
1592 const x54 = (x52 >> 8);
1593 const x55 = cast(u8, (x54 & cast(u64, 0xff)));
1594 const x56 = (x54 >> 8);
1595 const x57 = cast(u8, (x56 & cast(u64, 0xff)));
1596 const x58 = (x56 >> 8);
1597 const x59 = cast(u8, (x58 & cast(u64, 0xff)));
1598 const x60 = cast(u8, (x58 >> 8));
1599 out1[0] = x5;
1600 out1[1] = x7;
1601 out1[2] = x9;
1602 out1[3] = x11;
1603 out1[4] = x13;
1604 out1[5] = x15;
1605 out1[6] = x17;
1606 out1[7] = x18;
1607 out1[8] = x19;
1608 out1[9] = x21;
1609 out1[10] = x23;
1610 out1[11] = x25;
1611 out1[12] = x27;
1612 out1[13] = x29;
1613 out1[14] = x31;
1614 out1[15] = x32;
1615 out1[16] = x33;
1616 out1[17] = x35;
1617 out1[18] = x37;
1618 out1[19] = x39;
1619 out1[20] = x41;
1620 out1[21] = x43;
1621 out1[22] = x45;
1622 out1[23] = x46;
1623 out1[24] = x47;
1624 out1[25] = x49;
1625 out1[26] = x51;
1626 out1[27] = x53;
1627 out1[28] = x55;
1628 out1[29] = x57;
1629 out1[30] = x59;
1630 out1[31] = x60;
1631}
1632
1633/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
1634/// Preconditions:
1635/// 0 ≤ bytes_eval arg1 < m
1636/// Postconditions:
1637/// eval out1 mod m = bytes_eval arg1 mod m
1638/// 0 ≤ eval out1 < m
1639///
1640/// Input Bounds:
1641/// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
1642/// Output Bounds:
1643/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1644pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
1645 @setRuntimeSafety(mode == .Debug);
1646
1647 const x1 = (cast(u64, (arg1[31])) << 56);
1648 const x2 = (cast(u64, (arg1[30])) << 48);
1649 const x3 = (cast(u64, (arg1[29])) << 40);
1650 const x4 = (cast(u64, (arg1[28])) << 32);
1651 const x5 = (cast(u64, (arg1[27])) << 24);
1652 const x6 = (cast(u64, (arg1[26])) << 16);
1653 const x7 = (cast(u64, (arg1[25])) << 8);
1654 const x8 = (arg1[24]);
1655 const x9 = (cast(u64, (arg1[23])) << 56);
1656 const x10 = (cast(u64, (arg1[22])) << 48);
1657 const x11 = (cast(u64, (arg1[21])) << 40);
1658 const x12 = (cast(u64, (arg1[20])) << 32);
1659 const x13 = (cast(u64, (arg1[19])) << 24);
1660 const x14 = (cast(u64, (arg1[18])) << 16);
1661 const x15 = (cast(u64, (arg1[17])) << 8);
1662 const x16 = (arg1[16]);
1663 const x17 = (cast(u64, (arg1[15])) << 56);
1664 const x18 = (cast(u64, (arg1[14])) << 48);
1665 const x19 = (cast(u64, (arg1[13])) << 40);
1666 const x20 = (cast(u64, (arg1[12])) << 32);
1667 const x21 = (cast(u64, (arg1[11])) << 24);
1668 const x22 = (cast(u64, (arg1[10])) << 16);
1669 const x23 = (cast(u64, (arg1[9])) << 8);
1670 const x24 = (arg1[8]);
1671 const x25 = (cast(u64, (arg1[7])) << 56);
1672 const x26 = (cast(u64, (arg1[6])) << 48);
1673 const x27 = (cast(u64, (arg1[5])) << 40);
1674 const x28 = (cast(u64, (arg1[4])) << 32);
1675 const x29 = (cast(u64, (arg1[3])) << 24);
1676 const x30 = (cast(u64, (arg1[2])) << 16);
1677 const x31 = (cast(u64, (arg1[1])) << 8);
1678 const x32 = (arg1[0]);
1679 const x33 = (x31 + cast(u64, x32));
1680 const x34 = (x30 + x33);
1681 const x35 = (x29 + x34);
1682 const x36 = (x28 + x35);
1683 const x37 = (x27 + x36);
1684 const x38 = (x26 + x37);
1685 const x39 = (x25 + x38);
1686 const x40 = (x23 + cast(u64, x24));
1687 const x41 = (x22 + x40);
1688 const x42 = (x21 + x41);
1689 const x43 = (x20 + x42);
1690 const x44 = (x19 + x43);
1691 const x45 = (x18 + x44);
1692 const x46 = (x17 + x45);
1693 const x47 = (x15 + cast(u64, x16));
1694 const x48 = (x14 + x47);
1695 const x49 = (x13 + x48);
1696 const x50 = (x12 + x49);
1697 const x51 = (x11 + x50);
1698 const x52 = (x10 + x51);
1699 const x53 = (x9 + x52);
1700 const x54 = (x7 + cast(u64, x8));
1701 const x55 = (x6 + x54);
1702 const x56 = (x5 + x55);
1703 const x57 = (x4 + x56);
1704 const x58 = (x3 + x57);
1705 const x59 = (x2 + x58);
1706 const x60 = (x1 + x59);
1707 out1[0] = x39;
1708 out1[1] = x46;
1709 out1[2] = x53;
1710 out1[3] = x60;
1711}
1712
1713/// The function setOne returns the field element one in the Montgomery domain.
1714/// Postconditions:
1715/// eval (from_montgomery out1) mod m = 1 mod m
1716/// 0 ≤ eval out1 < m
1717///
1718/// Input Bounds:
1719/// Output Bounds:
1720/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1721pub fn setOne(out1: *[4]u64) void {
1722 @setRuntimeSafety(mode == .Debug);
1723
1724 out1[0] = 0xc46353d039cdaaf;
1725 out1[1] = 0x4319055258e8617b;
1726 out1[2] = cast(u64, 0x0);
1727 out1[3] = 0xffffffff;
1728}
1729
1730/// The function msat returns the saturated representation of the prime modulus.
1731/// Postconditions:
1732/// twos_complement_eval out1 = m
1733/// 0 ≤ eval out1 < m
1734///
1735/// Input Bounds:
1736/// Output Bounds:
1737/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1738pub fn msat(out1: *[5]u64) void {
1739 @setRuntimeSafety(mode == .Debug);
1740
1741 out1[0] = 0xf3b9cac2fc632551;
1742 out1[1] = 0xbce6faada7179e84;
1743 out1[2] = 0xffffffffffffffff;
1744 out1[3] = 0xffffffff00000000;
1745 out1[4] = cast(u64, 0x0);
1746}
1747
1748/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
1749/// Postconditions:
1750/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if (log2 m) + 1 < 46 then ⌊(49 * ((log2 m) + 1) + 80) / 17⌋ else ⌊(49 * ((log2 m) + 1) + 57) / 17⌋)
1751/// 0 ≤ eval out1 < m
1752///
1753/// Input Bounds:
1754/// Output Bounds:
1755/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1756pub fn divstepPrecomp(out1: *[4]u64) void {
1757 @setRuntimeSafety(mode == .Debug);
1758
1759 out1[0] = 0xd739262fb7fcfbb5;
1760 out1[1] = 0x8ac6f75d20074414;
1761 out1[2] = 0xc67428bfb5e3c256;
1762 out1[3] = 0x444962f2eda7aedf;
1763}
1764
1765/// The function divstep computes a divstep.
1766/// Preconditions:
1767/// 0 ≤ eval arg4 < m
1768/// 0 ≤ eval arg5 < m
1769/// Postconditions:
1770/// out1 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then 1 - arg1 else 1 + arg1)
1771/// twos_complement_eval out2 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then twos_complement_eval arg3 else twos_complement_eval arg2)
1772/// twos_complement_eval out3 = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then ⌊(twos_complement_eval arg3 - twos_complement_eval arg2) / 2⌋ else ⌊(twos_complement_eval arg3 + (twos_complement_eval arg3 mod 2) * twos_complement_eval arg2) / 2⌋)
1773/// eval (from_montgomery out4) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (2 * eval (from_montgomery arg5)) mod m else (2 * eval (from_montgomery arg4)) mod m)
1774/// eval (from_montgomery out5) mod m = (if 0 < arg1 ∧ (twos_complement_eval arg3) is odd then (eval (from_montgomery arg4) - eval (from_montgomery arg4)) mod m else (eval (from_montgomery arg5) + (twos_complement_eval arg3 mod 2) * eval (from_montgomery arg4)) mod m)
1775/// 0 ≤ eval out5 < m
1776/// 0 ≤ eval out5 < m
1777/// 0 ≤ eval out2 < m
1778/// 0 ≤ eval out3 < m
1779///
1780/// Input Bounds:
1781/// arg1: [0x0 ~> 0xffffffffffffffff]
1782/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1783/// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1784/// arg4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1785/// arg5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1786/// Output Bounds:
1787/// out1: [0x0 ~> 0xffffffffffffffff]
1788/// out2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1789/// out3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1790/// out4: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1791/// out5: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1792pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[4]u64, arg1: u64, arg2: [5]u64, arg3: [5]u64, arg4: [4]u64, arg5: [4]u64) void {
1793 @setRuntimeSafety(mode == .Debug);
1794
1795 var x1: u64 = undefined;
1796 var x2: u1 = undefined;
1797 addcarryxU64(&x1, &x2, 0x0, (~arg1), cast(u64, 0x1));
1798 const x3 = (cast(u1, (x1 >> 63)) & cast(u1, ((arg3[0]) & cast(u64, 0x1))));
1799 var x4: u64 = undefined;
1800 var x5: u1 = undefined;
1801 addcarryxU64(&x4, &x5, 0x0, (~arg1), cast(u64, 0x1));
1802 var x6: u64 = undefined;
1803 cmovznzU64(&x6, x3, arg1, x4);
1804 var x7: u64 = undefined;
1805 cmovznzU64(&x7, x3, (arg2[0]), (arg3[0]));
1806 var x8: u64 = undefined;
1807 cmovznzU64(&x8, x3, (arg2[1]), (arg3[1]));
1808 var x9: u64 = undefined;
1809 cmovznzU64(&x9, x3, (arg2[2]), (arg3[2]));
1810 var x10: u64 = undefined;
1811 cmovznzU64(&x10, x3, (arg2[3]), (arg3[3]));
1812 var x11: u64 = undefined;
1813 cmovznzU64(&x11, x3, (arg2[4]), (arg3[4]));
1814 var x12: u64 = undefined;
1815 var x13: u1 = undefined;
1816 addcarryxU64(&x12, &x13, 0x0, cast(u64, 0x1), (~(arg2[0])));
1817 var x14: u64 = undefined;
1818 var x15: u1 = undefined;
1819 addcarryxU64(&x14, &x15, x13, cast(u64, 0x0), (~(arg2[1])));
1820 var x16: u64 = undefined;
1821 var x17: u1 = undefined;
1822 addcarryxU64(&x16, &x17, x15, cast(u64, 0x0), (~(arg2[2])));
1823 var x18: u64 = undefined;
1824 var x19: u1 = undefined;
1825 addcarryxU64(&x18, &x19, x17, cast(u64, 0x0), (~(arg2[3])));
1826 var x20: u64 = undefined;
1827 var x21: u1 = undefined;
1828 addcarryxU64(&x20, &x21, x19, cast(u64, 0x0), (~(arg2[4])));
1829 var x22: u64 = undefined;
1830 cmovznzU64(&x22, x3, (arg3[0]), x12);
1831 var x23: u64 = undefined;
1832 cmovznzU64(&x23, x3, (arg3[1]), x14);
1833 var x24: u64 = undefined;
1834 cmovznzU64(&x24, x3, (arg3[2]), x16);
1835 var x25: u64 = undefined;
1836 cmovznzU64(&x25, x3, (arg3[3]), x18);
1837 var x26: u64 = undefined;
1838 cmovznzU64(&x26, x3, (arg3[4]), x20);
1839 var x27: u64 = undefined;
1840 cmovznzU64(&x27, x3, (arg4[0]), (arg5[0]));
1841 var x28: u64 = undefined;
1842 cmovznzU64(&x28, x3, (arg4[1]), (arg5[1]));
1843 var x29: u64 = undefined;
1844 cmovznzU64(&x29, x3, (arg4[2]), (arg5[2]));
1845 var x30: u64 = undefined;
1846 cmovznzU64(&x30, x3, (arg4[3]), (arg5[3]));
1847 var x31: u64 = undefined;
1848 var x32: u1 = undefined;
1849 addcarryxU64(&x31, &x32, 0x0, x27, x27);
1850 var x33: u64 = undefined;
1851 var x34: u1 = undefined;
1852 addcarryxU64(&x33, &x34, x32, x28, x28);
1853 var x35: u64 = undefined;
1854 var x36: u1 = undefined;
1855 addcarryxU64(&x35, &x36, x34, x29, x29);
1856 var x37: u64 = undefined;
1857 var x38: u1 = undefined;
1858 addcarryxU64(&x37, &x38, x36, x30, x30);
1859 var x39: u64 = undefined;
1860 var x40: u1 = undefined;
1861 subborrowxU64(&x39, &x40, 0x0, x31, 0xf3b9cac2fc632551);
1862 var x41: u64 = undefined;
1863 var x42: u1 = undefined;
1864 subborrowxU64(&x41, &x42, x40, x33, 0xbce6faada7179e84);
1865 var x43: u64 = undefined;
1866 var x44: u1 = undefined;
1867 subborrowxU64(&x43, &x44, x42, x35, 0xffffffffffffffff);
1868 var x45: u64 = undefined;
1869 var x46: u1 = undefined;
1870 subborrowxU64(&x45, &x46, x44, x37, 0xffffffff00000000);
1871 var x47: u64 = undefined;
1872 var x48: u1 = undefined;
1873 subborrowxU64(&x47, &x48, x46, cast(u64, x38), cast(u64, 0x0));
1874 const x49 = (arg4[3]);
1875 const x50 = (arg4[2]);
1876 const x51 = (arg4[1]);
1877 const x52 = (arg4[0]);
1878 var x53: u64 = undefined;
1879 var x54: u1 = undefined;
1880 subborrowxU64(&x53, &x54, 0x0, cast(u64, 0x0), x52);
1881 var x55: u64 = undefined;
1882 var x56: u1 = undefined;
1883 subborrowxU64(&x55, &x56, x54, cast(u64, 0x0), x51);
1884 var x57: u64 = undefined;
1885 var x58: u1 = undefined;
1886 subborrowxU64(&x57, &x58, x56, cast(u64, 0x0), x50);
1887 var x59: u64 = undefined;
1888 var x60: u1 = undefined;
1889 subborrowxU64(&x59, &x60, x58, cast(u64, 0x0), x49);
1890 var x61: u64 = undefined;
1891 cmovznzU64(&x61, x60, cast(u64, 0x0), 0xffffffffffffffff);
1892 var x62: u64 = undefined;
1893 var x63: u1 = undefined;
1894 addcarryxU64(&x62, &x63, 0x0, x53, (x61 & 0xf3b9cac2fc632551));
1895 var x64: u64 = undefined;
1896 var x65: u1 = undefined;
1897 addcarryxU64(&x64, &x65, x63, x55, (x61 & 0xbce6faada7179e84));
1898 var x66: u64 = undefined;
1899 var x67: u1 = undefined;
1900 addcarryxU64(&x66, &x67, x65, x57, x61);
1901 var x68: u64 = undefined;
1902 var x69: u1 = undefined;
1903 addcarryxU64(&x68, &x69, x67, x59, (x61 & 0xffffffff00000000));
1904 var x70: u64 = undefined;
1905 cmovznzU64(&x70, x3, (arg5[0]), x62);
1906 var x71: u64 = undefined;
1907 cmovznzU64(&x71, x3, (arg5[1]), x64);
1908 var x72: u64 = undefined;
1909 cmovznzU64(&x72, x3, (arg5[2]), x66);
1910 var x73: u64 = undefined;
1911 cmovznzU64(&x73, x3, (arg5[3]), x68);
1912 const x74 = cast(u1, (x22 & cast(u64, 0x1)));
1913 var x75: u64 = undefined;
1914 cmovznzU64(&x75, x74, cast(u64, 0x0), x7);
1915 var x76: u64 = undefined;
1916 cmovznzU64(&x76, x74, cast(u64, 0x0), x8);
1917 var x77: u64 = undefined;
1918 cmovznzU64(&x77, x74, cast(u64, 0x0), x9);
1919 var x78: u64 = undefined;
1920 cmovznzU64(&x78, x74, cast(u64, 0x0), x10);
1921 var x79: u64 = undefined;
1922 cmovznzU64(&x79, x74, cast(u64, 0x0), x11);
1923 var x80: u64 = undefined;
1924 var x81: u1 = undefined;
1925 addcarryxU64(&x80, &x81, 0x0, x22, x75);
1926 var x82: u64 = undefined;
1927 var x83: u1 = undefined;
1928 addcarryxU64(&x82, &x83, x81, x23, x76);
1929 var x84: u64 = undefined;
1930 var x85: u1 = undefined;
1931 addcarryxU64(&x84, &x85, x83, x24, x77);
1932 var x86: u64 = undefined;
1933 var x87: u1 = undefined;
1934 addcarryxU64(&x86, &x87, x85, x25, x78);
1935 var x88: u64 = undefined;
1936 var x89: u1 = undefined;
1937 addcarryxU64(&x88, &x89, x87, x26, x79);
1938 var x90: u64 = undefined;
1939 cmovznzU64(&x90, x74, cast(u64, 0x0), x27);
1940 var x91: u64 = undefined;
1941 cmovznzU64(&x91, x74, cast(u64, 0x0), x28);
1942 var x92: u64 = undefined;
1943 cmovznzU64(&x92, x74, cast(u64, 0x0), x29);
1944 var x93: u64 = undefined;
1945 cmovznzU64(&x93, x74, cast(u64, 0x0), x30);
1946 var x94: u64 = undefined;
1947 var x95: u1 = undefined;
1948 addcarryxU64(&x94, &x95, 0x0, x70, x90);
1949 var x96: u64 = undefined;
1950 var x97: u1 = undefined;
1951 addcarryxU64(&x96, &x97, x95, x71, x91);
1952 var x98: u64 = undefined;
1953 var x99: u1 = undefined;
1954 addcarryxU64(&x98, &x99, x97, x72, x92);
1955 var x100: u64 = undefined;
1956 var x101: u1 = undefined;
1957 addcarryxU64(&x100, &x101, x99, x73, x93);
1958 var x102: u64 = undefined;
1959 var x103: u1 = undefined;
1960 subborrowxU64(&x102, &x103, 0x0, x94, 0xf3b9cac2fc632551);
1961 var x104: u64 = undefined;
1962 var x105: u1 = undefined;
1963 subborrowxU64(&x104, &x105, x103, x96, 0xbce6faada7179e84);
1964 var x106: u64 = undefined;
1965 var x107: u1 = undefined;
1966 subborrowxU64(&x106, &x107, x105, x98, 0xffffffffffffffff);
1967 var x108: u64 = undefined;
1968 var x109: u1 = undefined;
1969 subborrowxU64(&x108, &x109, x107, x100, 0xffffffff00000000);
1970 var x110: u64 = undefined;
1971 var x111: u1 = undefined;
1972 subborrowxU64(&x110, &x111, x109, cast(u64, x101), cast(u64, 0x0));
1973 var x112: u64 = undefined;
1974 var x113: u1 = undefined;
1975 addcarryxU64(&x112, &x113, 0x0, x6, cast(u64, 0x1));
1976 const x114 = ((x80 >> 1) | ((x82 << 63) & 0xffffffffffffffff));
1977 const x115 = ((x82 >> 1) | ((x84 << 63) & 0xffffffffffffffff));
1978 const x116 = ((x84 >> 1) | ((x86 << 63) & 0xffffffffffffffff));
1979 const x117 = ((x86 >> 1) | ((x88 << 63) & 0xffffffffffffffff));
1980 const x118 = ((x88 & 0x8000000000000000) | (x88 >> 1));
1981 var x119: u64 = undefined;
1982 cmovznzU64(&x119, x48, x39, x31);
1983 var x120: u64 = undefined;
1984 cmovznzU64(&x120, x48, x41, x33);
1985 var x121: u64 = undefined;
1986 cmovznzU64(&x121, x48, x43, x35);
1987 var x122: u64 = undefined;
1988 cmovznzU64(&x122, x48, x45, x37);
1989 var x123: u64 = undefined;
1990 cmovznzU64(&x123, x111, x102, x94);
1991 var x124: u64 = undefined;
1992 cmovznzU64(&x124, x111, x104, x96);
1993 var x125: u64 = undefined;
1994 cmovznzU64(&x125, x111, x106, x98);
1995 var x126: u64 = undefined;
1996 cmovznzU64(&x126, x111, x108, x100);
1997 out1.* = x112;
1998 out2[0] = x7;
1999 out2[1] = x8;
2000 out2[2] = x9;
2001 out2[3] = x10;
2002 out2[4] = x11;
2003 out3[0] = x114;
2004 out3[1] = x115;
2005 out3[2] = x116;
2006 out3[3] = x117;
2007 out3[4] = x118;
2008 out4[0] = x119;
2009 out4[1] = x120;
2010 out4[2] = x121;
2011 out4[3] = x122;
2012 out5[0] = x123;
2013 out5[1] = x124;
2014 out5[2] = x125;
2015 out5[3] = x126;
2016}
lib/std/crypto/pcurves/p256/scalar.zig created+231
...@@ -0,0 +1,231 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("std");
8const builtin = std.builtin;
9const common = @import("../common.zig");
10const crypto = std.crypto;
11const debug = std.debug;
12const math = std.math;
13const mem = std.mem;
14
15const Field = common.Field;
16
17const NonCanonicalError = std.crypto.errors.NonCanonicalError;
18const NotSquareError = std.crypto.errors.NotSquareError;
19
20/// Number of bytes required to encode a scalar.
21pub const encoded_length = 32;
22
23/// A compressed scalar, in canonical form.
24pub const CompressedScalar = [encoded_length]u8;
25
26const Fe = Field(.{
27 .fiat = @import("p256_scalar_64.zig"),
28 .field_order = 115792089210356248762697446949407573529996955224135760342422259061068512044369,
29 .field_bits = 256,
30 .saturated_bits = 255,
31 .encoded_length = encoded_length,
32});
33
34/// Reject a scalar whose encoding is not canonical.
35pub fn rejectNonCanonical(s: CompressedScalar, endian: builtin.Endian) NonCanonicalError!void {
36 return Fe.rejectNonCanonical(s, endian);
37}
38
39/// Reduce a 48-bytes scalar to the field size.
40pub fn reduce48(s: [48]u8, endian: builtin.Endian) CompressedScalar {
41 return Scalar.fromBytes48(s, endian).toBytes(endian);
42}
43
44/// Reduce a 64-bytes scalar to the field size.
45pub fn reduce64(s: [64]u8, endian: builtin.Endian) CompressedScalar {
46 return ScalarDouble.fromBytes64(s, endian).toBytes(endian);
47}
48
49/// Return a*b (mod L)
50pub fn mul(a: CompressedScalar, b: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
51 return (try Scalar.fromBytes(a, endian)).mul(try Scalar.fromBytes(b, endian)).toBytes(endian);
52}
53
54/// Return a*b+c (mod L)
55pub fn mulAdd(a: CompressedScalar, b: CompressedScalar, c: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
56 return (try Scalar.fromBytes(a, endian)).mul(try Scalar.fromBytes(b, endian)).add(try Scalar.fromBytes(c, endian)).toBytes(endian);
57}
58
59/// Return a+b (mod L)
60pub fn add(a: CompressedScalar, b: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
61 return (try Scalar.fromBytes(a, endian)).add(try Scalar.fromBytes(b, endian)).toBytes(endian);
62}
63
64/// Return -s (mod L)
65pub fn neg(s: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
66 return (try Scalar.fromBytes(a, endian)).neg().toBytes(endian);
67}
68
69/// Return (a-b) (mod L)
70pub fn sub(a: CompressedScalar, b: CompressedScalar, endian: builtin.Endian) NonCanonicalError!CompressedScalar {
71 return (try Scalar.fromBytes(a, endian)).sub(try Scalar.fromBytes(b.endian)).toBytes(endian);
72}
73
74/// Return a random scalar
75pub fn random(endian: builtin.Endian) CompressedScalar {
76 return Scalar.random().toBytes(endian);
77}
78
79/// A scalar in unpacked representation.
80pub const Scalar = struct {
81 fe: Fe,
82
83 /// Zero.
84 pub const zero = Scalar{ .fe = Fe.zero };
85
86 /// One.
87 pub const one = Scalar{ .fe = Fe.one };
88
89 /// Unpack a serialized representation of a scalar.
90 pub fn fromBytes(s: CompressedScalar, endian: builtin.Endian) NonCanonicalError!Scalar {
91 return Scalar{ .fe = try Fe.fromBytes(s, endian) };
92 }
93
94 /// Reduce a 384 bit input to the field size.
95 pub fn fromBytes48(s: [48]u8, endian: builtin.Endian) Scalar {
96 const t = ScalarDouble.fromBytes(384, s, endian);
97 return t.reduce(384);
98 }
99
100 /// Reduce a 512 bit input to the field size.
101 pub fn fromBytes64(s: [64]u8, endian: builtin.Endian) Scalar {
102 const t = ScalarDouble.fromBytes(512, s, endian);
103 return t.reduce(512);
104 }
105
106 /// Pack a scalar into bytes.
107 pub fn toBytes(n: Scalar, endian: builtin.Endian) CompressedScalar {
108 return n.fe.toBytes(endian);
109 }
110
111 /// Return true if the scalar is zero..
112 pub fn isZero(n: Scalar) bool {
113 return n.fe.isZero();
114 }
115
116 /// Return true if a and b are equivalent.
117 pub fn equivalent(a: Scalar, b: Scalar) bool {
118 return a.fe.equivalent(b.fe);
119 }
120
121 /// Compute x+y (mod L)
122 pub fn add(x: Scalar, y: Scalar) Scalar {
123 return Scalar{ .fe = x.fe().add(y.fe) };
124 }
125
126 /// Compute x-y (mod L)
127 pub fn sub(x: Scalar, y: Scalar) Scalar {
128 return Scalar{ .fe = x.fe().sub(y.fe) };
129 }
130
131 /// Compute 2n (mod L)
132 pub fn dbl(n: Scalar) Scalar {
133 return Scalar{ .fe = n.fe.dbl() };
134 }
135
136 /// Compute x*y (mod L)
137 pub fn mul(x: Scalar, y: Scalar) Scalar {
138 return Scalar{ .fe = x.fe().mul(y.fe) };
139 }
140
141 /// Compute x^2 (mod L)
142 pub fn sq(n: Scalar) Scalar {
143 return Scalar{ .fe = n.fe.sq() };
144 }
145
146 /// Compute x^n (mod L)
147 pub fn pow(a: Scalar, comptime T: type, comptime n: T) Scalar {
148 return Scalar{ .fe = a.fe.pow(n) };
149 }
150
151 /// Compute -x (mod L)
152 pub fn neg(n: Scalar) Scalar {
153 return Scalar{ .fe = n.fe.neg() };
154 }
155
156 /// Compute x^-1 (mod L)
157 pub fn invert(n: Scalar) Scalar {
158 return Scalar{ .fe = n.fe.invert() };
159 }
160
161 /// Return true if n is a quadratic residue mod L.
162 pub fn isSquare(n: Scalar) Scalar {
163 return n.fe.isSquare();
164 }
165
166 /// Return the square root of L, or NotSquare if there isn't any solutions.
167 pub fn sqrt(n: Scalar) NotSquareError!Scalar {
168 return Scalar{ .fe = try n.fe.sqrt() };
169 }
170
171 /// Return a random scalar < L.
172 pub fn random() Scalar {
173 var s: [48]u8 = undefined;
174 while (true) {
175 crypto.random.bytes(&s);
176 const n = Scalar.fromBytes48(s, .Little);
177 if (!n.isZero()) {
178 return n;
179 }
180 }
181 }
182};
183
184const ScalarDouble = struct {
185 x1: Fe,
186 x2: Fe,
187 x3: Fe,
188
189 fn fromBytes(comptime bits: usize, s_: [bits / 8]u8, endian: builtin.Endian) ScalarDouble {
190 debug.assert(bits > 0 and bits <= 512 and bits >= Fe.saturated_bits and bits <= Fe.saturated_bits * 3);
191
192 var s = s_;
193 if (endian == .Big) {
194 for (s_) |x, i| s[s.len - 1 - i] = x;
195 }
196 var t = ScalarDouble{ .x1 = undefined, .x2 = Fe.zero, .x3 = Fe.zero };
197 {
198 var b = [_]u8{0} ** encoded_length;
199 const len = math.min(s.len, 24);
200 mem.copy(u8, b[0..len], s[0..len]);
201 t.x1 = Fe.fromBytes(b, .Little) catch unreachable;
202 }
203 if (s_.len >= 24) {
204 var b = [_]u8{0} ** encoded_length;
205 const len = math.min(s.len - 24, 24);
206 mem.copy(u8, b[0..len], s[24..][0..len]);
207 t.x2 = Fe.fromBytes(b, .Little) catch unreachable;
208 }
209 if (s_.len >= 48) {
210 var b = [_]u8{0} ** encoded_length;
211 const len = s.len - 48;
212 mem.copy(u8, b[0..len], s[48..][0..len]);
213 t.x3 = Fe.fromBytes(b, .Little) catch unreachable;
214 }
215 return t;
216 }
217
218 fn reduce(expanded: ScalarDouble, comptime bits: usize) Scalar {
219 debug.assert(bits > 0 and bits <= Fe.saturated_bits * 3 and bits <= 512);
220 var fe = expanded.x1;
221 if (bits >= 192) {
222 const st1 = Fe.fromInt(1 << 192) catch unreachable;
223 fe = fe.add(expanded.x2.mul(st1));
224 if (bits >= 384) {
225 const st2 = st1.sq();
226 fe = fe.add(expanded.x3.mul(st2));
227 }
228 }
229 return Scalar{ .fe = fe };
230 }
231};
lib/std/crypto/pcurves/tests.zig created+103
...@@ -0,0 +1,103 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("std");
8const fmt = std.fmt;
9const testing = std.testing;
10
11const P256 = @import("p256.zig").P256;
12
13test "p256 ECDH key exchange" {
14 const dha = P256.scalar.random(.Little);
15 const dhb = P256.scalar.random(.Little);
16 const dhA = try P256.basePoint.mul(dha, .Little);
17 const dhB = try P256.basePoint.mul(dhb, .Little);
18 const shareda = try dhA.mul(dhb, .Little);
19 const sharedb = try dhB.mul(dha, .Little);
20 testing.expect(shareda.equivalent(sharedb));
21}
22
23test "p256 point from affine coordinates" {
24 const xh = "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296";
25 const yh = "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5";
26 var xs: [32]u8 = undefined;
27 _ = try fmt.hexToBytes(&xs, xh);
28 var ys: [32]u8 = undefined;
29 _ = try fmt.hexToBytes(&ys, yh);
30 var p = try P256.fromSerializedAffineCoordinates(xs, ys, .Big);
31 testing.expect(p.equivalent(P256.basePoint));
32}
33
34test "p256 test vectors" {
35 const expected = [_][]const u8{
36 "0000000000000000000000000000000000000000000000000000000000000000",
37 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
38 "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
39 "5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c",
40 "e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
41 "51590b7a515140d2d784c85608668fdfef8c82fd1f5be52421554a0dc3d033ed",
42 "b01a172a76a4602c92d3242cb897dde3024c740debb215b4c6b0aae93c2291a9",
43 "8e533b6fa0bf7b4625bb30667c01fb607ef9f8b8a80fef5b300628703187b2a3",
44 "62d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393",
45 "ea68d7b6fedf0b71878938d51d71f8729e0acb8c2c6df8b3d79e8a4b90949ee0",
46 };
47 var p = P256.identityElement;
48 for (expected) |xh| {
49 const x = p.affineCoordinates().x;
50 p = p.add(P256.basePoint);
51 var xs: [32]u8 = undefined;
52 _ = try fmt.hexToBytes(&xs, xh);
53 testing.expectEqualSlices(u8, &x.toBytes(.Big), &xs);
54 }
55}
56
57test "p256 test vectors - doubling" {
58 const expected = [_][]const u8{
59 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
60 "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
61 "e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
62 "62d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393",
63 };
64 var p = P256.basePoint;
65 for (expected) |xh| {
66 const x = p.affineCoordinates().x;
67 p = p.dbl();
68 var xs: [32]u8 = undefined;
69 _ = try fmt.hexToBytes(&xs, xh);
70 testing.expectEqualSlices(u8, &x.toBytes(.Big), &xs);
71 }
72}
73
74test "p256 compressed sec1 encoding/decoding" {
75 const p = P256.random();
76 const s = p.toCompressedSec1();
77 const q = try P256.fromSec1(&s);
78 testing.expect(p.equivalent(q));
79}
80
81test "p256 uncompressed sec1 encoding/decoding" {
82 const p = P256.random();
83 const s = p.toUncompressedSec1();
84 const q = try P256.fromSec1(&s);
85 testing.expect(p.equivalent(q));
86}
87
88test "p256 public key is the neutral element" {
89 const n = P256.scalar.Scalar.zero.toBytes(.Little);
90 const p = P256.random();
91 testing.expectError(error.IdentityElement, p.mul(n, .Little));
92}
93
94test "p256 public key is the neutral element (public verification)" {
95 const n = P256.scalar.Scalar.zero.toBytes(.Little);
96 const p = P256.random();
97 testing.expectError(error.IdentityElement, p.mulPublic(n, .Little));
98}
99
100test "p256 field element non-canonical encoding" {
101 const s = [_]u8{0xff} ** 32;
102 testing.expectError(error.NonCanonical, P256.Fe.fromBytes(s, .Little));
103}
lib/std/fmt.zig+159
...@@ -696,6 +696,11 @@ fn formatFloatValue(...@@ -696,6 +696,11 @@ fn formatFloatValue(
696 error.NoSpaceLeft => unreachable,696 error.NoSpaceLeft => unreachable,
697 else => |e| return e,697 else => |e| return e,
698 };698 };
699 } else if (comptime std.mem.eql(u8, fmt, "x")) {
700 formatFloatHexadecimal(value, options, buf_stream.writer()) catch |err| switch (err) {
701 error.NoSpaceLeft => unreachable,
702 else => |e| return e,
703 };
699 } else {704 } else {
700 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");705 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
701 }706 }
...@@ -1023,6 +1028,112 @@ pub fn formatFloatScientific(...@@ -1023,6 +1028,112 @@ pub fn formatFloatScientific(
1023 }1028 }
1024}1029}
10251030
1031pub fn formatFloatHexadecimal(
1032 value: anytype,
1033 options: FormatOptions,
1034 writer: anytype,
1035) !void {
1036 if (math.signbit(value)) {
1037 try writer.writeByte('-');
1038 }
1039 if (math.isNan(value)) {
1040 return writer.writeAll("nan");
1041 }
1042 if (math.isInf(value)) {
1043 return writer.writeAll("inf");
1044 }
1045
1046 const T = @TypeOf(value);
1047 const TU = std.meta.Int(.unsigned, std.meta.bitCount(T));
1048
1049 const mantissa_bits = math.floatMantissaBits(T);
1050 const exponent_bits = math.floatExponentBits(T);
1051 const mantissa_mask = (1 << mantissa_bits) - 1;
1052 const exponent_mask = (1 << exponent_bits) - 1;
1053 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
1054
1055 const as_bits = @bitCast(TU, value);
1056 var mantissa = as_bits & mantissa_mask;
1057 var exponent: i32 = @truncate(u16, (as_bits >> mantissa_bits) & exponent_mask);
1058
1059 const is_denormal = exponent == 0 and mantissa != 0;
1060 const is_zero = exponent == 0 and mantissa == 0;
1061
1062 if (is_zero) {
1063 // Handle this case here to simplify the logic below.
1064 try writer.writeAll("0x0");
1065 if (options.precision) |precision| {
1066 if (precision > 0) {
1067 try writer.writeAll(".");
1068 try writer.writeByteNTimes('0', precision);
1069 }
1070 } else {
1071 try writer.writeAll(".0");
1072 }
1073 try writer.writeAll("p0");
1074 return;
1075 }
1076
1077 if (is_denormal) {
1078 // Adjust the exponent for printing.
1079 exponent += 1;
1080 } else {
1081 // Add the implicit 1.
1082 mantissa |= 1 << mantissa_bits;
1083 }
1084
1085 // Fill in zeroes to round the mantissa width to a multiple of 4.
1086 if (T == f16) mantissa <<= 2 else if (T == f32) mantissa <<= 1;
1087
1088 const mantissa_digits = (mantissa_bits + 3) / 4;
1089
1090 if (options.precision) |precision| {
1091 // Round if needed.
1092 if (precision < mantissa_digits) {
1093 // We always have at least 4 extra bits.
1094 var extra_bits = (mantissa_digits - precision) * 4;
1095 // The result LSB is the Guard bit, we need two more (Round and
1096 // Sticky) to round the value.
1097 while (extra_bits > 2) {
1098 mantissa = (mantissa >> 1) | (mantissa & 1);
1099 extra_bits -= 1;
1100 }
1101 // Round to nearest, tie to even.
1102 mantissa |= @boolToInt(mantissa & 0b100 != 0);
1103 mantissa += 1;
1104 // Drop the excess bits.
1105 mantissa >>= 2;
1106 // Restore the alignment.
1107 mantissa <<= @intCast(math.Log2Int(TU), (mantissa_digits - precision) * 4);
1108
1109 const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0;
1110 // Prefer a normalized result in case of overflow.
1111 if (overflow) {
1112 mantissa >>= 1;
1113 exponent += 1;
1114 }
1115 }
1116 }
1117
1118 // +1 for the decimal part.
1119 var buf: [1 + mantissa_digits]u8 = undefined;
1120 const N = formatIntBuf(&buf, mantissa, 16, false, .{ .fill = '0', .width = 1 + mantissa_digits });
1121
1122 try writer.writeAll("0x");
1123 try writer.writeByte(buf[0]);
1124 if (options.precision != @as(usize, 0))
1125 try writer.writeAll(".");
1126 const trimmed = mem.trimRight(u8, buf[1..], "0");
1127 try writer.writeAll(trimmed);
1128 // Add trailing zeros if explicitly requested.
1129 if (options.precision) |precision| if (precision > 0) {
1130 if (precision > trimmed.len)
1131 try writer.writeByteNTimes('0', precision - trimmed.len);
1132 };
1133 try writer.writeAll("p");
1134 try formatInt(exponent - exponent_bias, 10, false, .{}, writer);
1135}
1136
1026/// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.1137/// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
1027/// By default floats are printed at full precision (no rounding).1138/// By default floats are printed at full precision (no rounding).
1028pub fn formatFloatDecimal(1139pub fn formatFloatDecimal(
...@@ -1917,6 +2028,54 @@ test "float.special" {...@@ -1917,6 +2028,54 @@ test "float.special" {
1917 try expectFmt("f64: -inf", "f64: {}", .{-math.inf_f64});2028 try expectFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
1918}2029}
19192030
2031test "float.hexadecimal.special" {
2032 try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64});
2033 // negative nan is not defined by IEE 754,
2034 // and ARM thus normalizes it to positive nan
2035 if (builtin.arch != builtin.Arch.arm) {
2036 try expectFmt("f64: -nan", "f64: {x}", .{-math.nan_f64});
2037 }
2038 try expectFmt("f64: inf", "f64: {x}", .{math.inf_f64});
2039 try expectFmt("f64: -inf", "f64: {x}", .{-math.inf_f64});
2040
2041 try expectFmt("f64: 0x0.0p0", "f64: {x}", .{@as(f64, 0)});
2042 try expectFmt("f64: -0x0.0p0", "f64: {x}", .{-@as(f64, 0)});
2043}
2044
2045test "float.hexadecimal" {
2046 try expectFmt("f16: 0x1.554p-2", "f16: {x}", .{@as(f16, 1.0 / 3.0)});
2047 try expectFmt("f32: 0x1.555556p-2", "f32: {x}", .{@as(f32, 1.0 / 3.0)});
2048 try expectFmt("f64: 0x1.5555555555555p-2", "f64: {x}", .{@as(f64, 1.0 / 3.0)});
2049 try expectFmt("f128: 0x1.5555555555555555555555555555p-2", "f128: {x}", .{@as(f128, 1.0 / 3.0)});
2050
2051 try expectFmt("f16: 0x1.p-14", "f16: {x}", .{@as(f16, math.f16_min)});
2052 try expectFmt("f32: 0x1.p-126", "f32: {x}", .{@as(f32, math.f32_min)});
2053 try expectFmt("f64: 0x1.p-1022", "f64: {x}", .{@as(f64, math.f64_min)});
2054 try expectFmt("f128: 0x1.p-16382", "f128: {x}", .{@as(f128, math.f128_min)});
2055
2056 try expectFmt("f16: 0x0.004p-14", "f16: {x}", .{@as(f16, math.f16_true_min)});
2057 try expectFmt("f32: 0x0.000002p-126", "f32: {x}", .{@as(f32, math.f32_true_min)});
2058 try expectFmt("f64: 0x0.0000000000001p-1022", "f64: {x}", .{@as(f64, math.f64_true_min)});
2059 try expectFmt("f128: 0x0.0000000000000000000000000001p-16382", "f128: {x}", .{@as(f128, math.f128_true_min)});
2060
2061 try expectFmt("f16: 0x1.ffcp15", "f16: {x}", .{@as(f16, math.f16_max)});
2062 try expectFmt("f32: 0x1.fffffep127", "f32: {x}", .{@as(f32, math.f32_max)});
2063 try expectFmt("f64: 0x1.fffffffffffffp1023", "f64: {x}", .{@as(f64, math.f64_max)});
2064 try expectFmt("f128: 0x1.ffffffffffffffffffffffffffffp16383", "f128: {x}", .{@as(f128, math.f128_max)});
2065}
2066
2067test "float.hexadecimal.precision" {
2068 try expectFmt("f16: 0x1.5p-2", "f16: {x:.1}", .{@as(f16, 1.0 / 3.0)});
2069 try expectFmt("f32: 0x1.555p-2", "f32: {x:.3}", .{@as(f32, 1.0 / 3.0)});
2070 try expectFmt("f64: 0x1.55555p-2", "f64: {x:.5}", .{@as(f64, 1.0 / 3.0)});
2071 try expectFmt("f128: 0x1.5555555p-2", "f128: {x:.7}", .{@as(f128, 1.0 / 3.0)});
2072
2073 try expectFmt("f16: 0x1.00000p0", "f16: {x:.5}", .{@as(f16, 1.0)});
2074 try expectFmt("f32: 0x1.00000p0", "f32: {x:.5}", .{@as(f32, 1.0)});
2075 try expectFmt("f64: 0x1.00000p0", "f64: {x:.5}", .{@as(f64, 1.0)});
2076 try expectFmt("f128: 0x1.00000p0", "f128: {x:.5}", .{@as(f128, 1.0)});
2077}
2078
1920test "float.decimal" {2079test "float.decimal" {
1921 try expectFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});2080 try expectFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
1922 try expectFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});2081 try expectFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
lib/std/math/copysign.zig+18
...@@ -20,6 +20,7 @@ pub fn copysign(comptime T: type, x: T, y: T) T {...@@ -20,6 +20,7 @@ pub fn copysign(comptime T: type, x: T, y: T) T {
20 f16 => copysign16(x, y),20 f16 => copysign16(x, y),
21 f32 => copysign32(x, y),21 f32 => copysign32(x, y),
22 f64 => copysign64(x, y),22 f64 => copysign64(x, y),
23 f128 => copysign128(x, y),
23 else => @compileError("copysign not implemented for " ++ @typeName(T)),24 else => @compileError("copysign not implemented for " ++ @typeName(T)),
24 };25 };
25}26}
...@@ -51,10 +52,20 @@ fn copysign64(x: f64, y: f64) f64 {...@@ -51,10 +52,20 @@ fn copysign64(x: f64, y: f64) f64 {
51 return @bitCast(f64, h1 | h2);52 return @bitCast(f64, h1 | h2);
52}53}
5354
55fn copysign128(x: f128, y: f128) f128 {
56 const ux = @bitCast(u128, x);
57 const uy = @bitCast(u128, y);
58
59 const h1 = ux & (maxInt(u128) / 2);
60 const h2 = uy & (@as(u128, 1) << 127);
61 return @bitCast(f128, h1 | h2);
62}
63
54test "math.copysign" {64test "math.copysign" {
55 expect(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0));65 expect(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0));
56 expect(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));66 expect(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));
57 expect(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));67 expect(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));
68 expect(copysign(f128, 1.0, 1.0) == copysign128(1.0, 1.0));
58}69}
5970
60test "math.copysign16" {71test "math.copysign16" {
...@@ -77,3 +88,10 @@ test "math.copysign64" {...@@ -77,3 +88,10 @@ test "math.copysign64" {
77 expect(copysign64(-5.0, -1.0) == -5.0);88 expect(copysign64(-5.0, -1.0) == -5.0);
78 expect(copysign64(-5.0, 1.0) == 5.0);89 expect(copysign64(-5.0, 1.0) == 5.0);
79}90}
91
92test "math.copysign128" {
93 expect(copysign128(5.0, 1.0) == 5.0);
94 expect(copysign128(5.0, -1.0) == -5.0);
95 expect(copysign128(-5.0, -1.0) == -5.0);
96 expect(copysign128(-5.0, 1.0) == 5.0);
97}
lib/std/math/isfinite.zig+18
...@@ -24,6 +24,10 @@ pub fn isFinite(x: anytype) bool {...@@ -24,6 +24,10 @@ pub fn isFinite(x: anytype) bool {
24 const bits = @bitCast(u64, x);24 const bits = @bitCast(u64, x);
25 return bits & (maxInt(u64) >> 1) < (0x7FF << 52);25 return bits & (maxInt(u64) >> 1) < (0x7FF << 52);
26 },26 },
27 f128 => {
28 const bits = @bitCast(u128, x);
29 return bits & (maxInt(u128) >> 1) < (0x7FFF << 112);
30 },
27 else => {31 else => {
28 @compileError("isFinite not implemented for " ++ @typeName(T));32 @compileError("isFinite not implemented for " ++ @typeName(T));
29 },33 },
...@@ -37,10 +41,24 @@ test "math.isFinite" {...@@ -37,10 +41,24 @@ test "math.isFinite" {
37 expect(isFinite(@as(f32, -0.0)));41 expect(isFinite(@as(f32, -0.0)));
38 expect(isFinite(@as(f64, 0.0)));42 expect(isFinite(@as(f64, 0.0)));
39 expect(isFinite(@as(f64, -0.0)));43 expect(isFinite(@as(f64, -0.0)));
44 expect(isFinite(@as(f128, 0.0)));
45 expect(isFinite(@as(f128, -0.0)));
46
40 expect(!isFinite(math.inf(f16)));47 expect(!isFinite(math.inf(f16)));
41 expect(!isFinite(-math.inf(f16)));48 expect(!isFinite(-math.inf(f16)));
42 expect(!isFinite(math.inf(f32)));49 expect(!isFinite(math.inf(f32)));
43 expect(!isFinite(-math.inf(f32)));50 expect(!isFinite(-math.inf(f32)));
44 expect(!isFinite(math.inf(f64)));51 expect(!isFinite(math.inf(f64)));
45 expect(!isFinite(-math.inf(f64)));52 expect(!isFinite(-math.inf(f64)));
53 expect(!isFinite(math.inf(f128)));
54 expect(!isFinite(-math.inf(f128)));
55
56 expect(!isFinite(math.nan(f16)));
57 expect(!isFinite(-math.nan(f16)));
58 expect(!isFinite(math.nan(f32)));
59 expect(!isFinite(-math.nan(f32)));
60 expect(!isFinite(math.nan(f64)));
61 expect(!isFinite(-math.nan(f64)));
62 expect(!isFinite(math.nan(f128)));
63 expect(!isFinite(-math.nan(f128)));
46}64}
lib/std/math/signbit.zig+12
...@@ -14,6 +14,7 @@ pub fn signbit(x: anytype) bool {...@@ -14,6 +14,7 @@ pub fn signbit(x: anytype) bool {
14 f16 => signbit16(x),14 f16 => signbit16(x),
15 f32 => signbit32(x),15 f32 => signbit32(x),
16 f64 => signbit64(x),16 f64 => signbit64(x),
17 f128 => signbit128(x),
17 else => @compileError("signbit not implemented for " ++ @typeName(T)),18 else => @compileError("signbit not implemented for " ++ @typeName(T)),
18 };19 };
19}20}
...@@ -33,10 +34,16 @@ fn signbit64(x: f64) bool {...@@ -33,10 +34,16 @@ fn signbit64(x: f64) bool {
33 return bits >> 63 != 0;34 return bits >> 63 != 0;
34}35}
3536
37fn signbit128(x: f128) bool {
38 const bits = @bitCast(u128, x);
39 return bits >> 127 != 0;
40}
41
36test "math.signbit" {42test "math.signbit" {
37 expect(signbit(@as(f16, 4.0)) == signbit16(4.0));43 expect(signbit(@as(f16, 4.0)) == signbit16(4.0));
38 expect(signbit(@as(f32, 4.0)) == signbit32(4.0));44 expect(signbit(@as(f32, 4.0)) == signbit32(4.0));
39 expect(signbit(@as(f64, 4.0)) == signbit64(4.0));45 expect(signbit(@as(f64, 4.0)) == signbit64(4.0));
46 expect(signbit(@as(f128, 4.0)) == signbit128(4.0));
40}47}
4148
42test "math.signbit16" {49test "math.signbit16" {
...@@ -53,3 +60,8 @@ test "math.signbit64" {...@@ -53,3 +60,8 @@ test "math.signbit64" {
53 expect(!signbit64(4.0));60 expect(!signbit64(4.0));
54 expect(signbit64(-3.0));61 expect(signbit64(-3.0));
55}62}
63
64test "math.signbit128" {
65 expect(!signbit128(4.0));
66 expect(signbit128(-3.0));
67}
lib/std/os/bits/darwin.zig+7
...@@ -832,6 +832,13 @@ pub const SO_RCVTIMEO = 0x1006;...@@ -832,6 +832,13 @@ pub const SO_RCVTIMEO = 0x1006;
832pub const SO_ERROR = 0x1007;832pub const SO_ERROR = 0x1007;
833pub const SO_TYPE = 0x1008;833pub const SO_TYPE = 0x1008;
834834
835pub const SO_NREAD = 0x1020;
836pub const SO_NKE = 0x1021;
837pub const SO_NOSIGPIPE = 0x1022;
838pub const SO_NOADDRERR = 0x1023;
839pub const SO_NWRITE = 0x1024;
840pub const SO_REUSESHAREUID = 0x1025;
841
835fn wstatus(x: u32) u32 {842fn wstatus(x: u32) u32 {
836 return x & 0o177;843 return x & 0o177;
837}844}
lib/std/os/bits/linux.zig+109-39
...@@ -5,11 +5,12 @@...@@ -5,11 +5,12 @@
5// and substantial portions of the software.5// and substantial portions of the software.
6const std = @import("../../std.zig");6const std = @import("../../std.zig");
7const maxInt = std.math.maxInt;7const maxInt = std.math.maxInt;
8const arch = std.Target.current.cpu.arch;8const arch = @import("builtin").target.cpu.arch;
9usingnamespace @import("../bits.zig");9usingnamespace @import("../bits.zig");
1010
11pub usingnamespace switch (arch) {11pub usingnamespace switch (arch) {
12 .mips, .mipsel => @import("linux/errno-mips.zig"),12 .mips, .mipsel => @import("linux/errno-mips.zig"),
13 .sparc, .sparcel, .sparcv9 => @import("linux/errno-sparc.zig"),
13 else => @import("linux/errno-generic.zig"),14 else => @import("linux/errno-generic.zig"),
14};15};
1516
...@@ -31,6 +32,7 @@ pub usingnamespace @import("linux/prctl.zig");...@@ -31,6 +32,7 @@ pub usingnamespace @import("linux/prctl.zig");
31pub usingnamespace @import("linux/securebits.zig");32pub usingnamespace @import("linux/securebits.zig");
3233
33const is_mips = arch.isMIPS();34const is_mips = arch.isMIPS();
35const is_ppc = arch.isPPC();
34const is_ppc64 = arch.isPPC64();36const is_ppc64 = arch.isPPC64();
35const is_sparc = arch.isSPARC();37const is_sparc = arch.isSPARC();
3638
...@@ -247,40 +249,78 @@ else...@@ -247,40 +249,78 @@ else
247 pub const SIG_SETMASK = 2;249 pub const SIG_SETMASK = 2;
248 };250 };
249251
250pub const SIGHUP = 1;252pub usingnamespace if (is_sparc) struct {
251pub const SIGINT = 2;253 pub const SIGHUP = 1;
252pub const SIGQUIT = 3;254 pub const SIGINT = 2;
253pub const SIGILL = 4;255 pub const SIGQUIT = 3;
254pub const SIGTRAP = 5;256 pub const SIGILL = 4;
255pub const SIGABRT = 6;257 pub const SIGTRAP = 5;
256pub const SIGIOT = SIGABRT;258 pub const SIGABRT = 6;
257pub const SIGBUS = 7;259 pub const SIGEMT = 7;
258pub const SIGFPE = 8;260 pub const SIGFPE = 8;
259pub const SIGKILL = 9;261 pub const SIGKILL = 9;
260pub const SIGUSR1 = 10;262 pub const SIGBUS = 10;
261pub const SIGSEGV = 11;263 pub const SIGSEGV = 11;
262pub const SIGUSR2 = 12;264 pub const SIGSYS = 12;
263pub const SIGPIPE = 13;265 pub const SIGPIPE = 13;
264pub const SIGALRM = 14;266 pub const SIGALRM = 14;
265pub const SIGTERM = 15;267 pub const SIGTERM = 15;
266pub const SIGSTKFLT = 16;268 pub const SIGURG = 16;
267pub const SIGCHLD = 17;269 pub const SIGSTOP = 17;
268pub const SIGCONT = 18;270 pub const SIGTSTP = 18;
269pub const SIGSTOP = 19;271 pub const SIGCONT = 19;
270pub const SIGTSTP = 20;272 pub const SIGCHLD = 20;
271pub const SIGTTIN = 21;273 pub const SIGTTIN = 21;
272pub const SIGTTOU = 22;274 pub const SIGTTOU = 22;
273pub const SIGURG = 23;275 pub const SIGPOLL = 23;
274pub const SIGXCPU = 24;276 pub const SIGXCPU = 24;
275pub const SIGXFSZ = 25;277 pub const SIGXFSZ = 25;
276pub const SIGVTALRM = 26;278 pub const SIGVTALRM = 26;
277pub const SIGPROF = 27;279 pub const SIGPROF = 27;
278pub const SIGWINCH = 28;280 pub const SIGWINCH = 28;
279pub const SIGIO = 29;281 pub const SIGLOST = 29;
280pub const SIGPOLL = 29;282 pub const SIGUSR1 = 30;
281pub const SIGPWR = 30;283 pub const SIGUSR2 = 31;
282pub const SIGSYS = 31;284 pub const SIGIOT = SIGABRT;
283pub const SIGUNUSED = SIGSYS;285 pub const SIGCLD = SIGCHLD;
286 pub const SIGPWR = SIGLOST;
287 pub const SIGIO = SIGPOLL;
288} else struct {
289 pub const SIGHUP = 1;
290 pub const SIGINT = 2;
291 pub const SIGQUIT = 3;
292 pub const SIGILL = 4;
293 pub const SIGTRAP = 5;
294 pub const SIGABRT = 6;
295 pub const SIGIOT = SIGABRT;
296 pub const SIGBUS = 7;
297 pub const SIGFPE = 8;
298 pub const SIGKILL = 9;
299 pub const SIGUSR1 = 10;
300 pub const SIGSEGV = 11;
301 pub const SIGUSR2 = 12;
302 pub const SIGPIPE = 13;
303 pub const SIGALRM = 14;
304 pub const SIGTERM = 15;
305 pub const SIGSTKFLT = 16;
306 pub const SIGCHLD = 17;
307 pub const SIGCONT = 18;
308 pub const SIGSTOP = 19;
309 pub const SIGTSTP = 20;
310 pub const SIGTTIN = 21;
311 pub const SIGTTOU = 22;
312 pub const SIGURG = 23;
313 pub const SIGXCPU = 24;
314 pub const SIGXFSZ = 25;
315 pub const SIGVTALRM = 26;
316 pub const SIGPROF = 27;
317 pub const SIGWINCH = 28;
318 pub const SIGIO = 29;
319 pub const SIGPOLL = 29;
320 pub const SIGPWR = 30;
321 pub const SIGSYS = 31;
322 pub const SIGUNUSED = SIGSYS;
323};
284324
285pub const O_RDONLY = 0o0;325pub const O_RDONLY = 0o0;
286pub const O_WRONLY = 0o1;326pub const O_WRONLY = 0o1;
...@@ -419,7 +459,39 @@ pub const AF_QIPCRTR = PF_QIPCRTR;...@@ -419,7 +459,39 @@ pub const AF_QIPCRTR = PF_QIPCRTR;
419pub const AF_SMC = PF_SMC;459pub const AF_SMC = PF_SMC;
420pub const AF_MAX = PF_MAX;460pub const AF_MAX = PF_MAX;
421461
422pub usingnamespace if (!is_mips)462pub usingnamespace if (is_mips)
463 struct {}
464else if (is_ppc or is_ppc64)
465 struct {
466 pub const SO_DEBUG = 1;
467 pub const SO_REUSEADDR = 2;
468 pub const SO_TYPE = 3;
469 pub const SO_ERROR = 4;
470 pub const SO_DONTROUTE = 5;
471 pub const SO_BROADCAST = 6;
472 pub const SO_SNDBUF = 7;
473 pub const SO_RCVBUF = 8;
474 pub const SO_KEEPALIVE = 9;
475 pub const SO_OOBINLINE = 10;
476 pub const SO_NO_CHECK = 11;
477 pub const SO_PRIORITY = 12;
478 pub const SO_LINGER = 13;
479 pub const SO_BSDCOMPAT = 14;
480 pub const SO_REUSEPORT = 15;
481 pub const SO_RCVLOWAT = 16;
482 pub const SO_SNDLOWAT = 17;
483 pub const SO_RCVTIMEO = 18;
484 pub const SO_SNDTIMEO = 19;
485 pub const SO_PASSCRED = 20;
486 pub const SO_PEERCRED = 21;
487 pub const SO_ACCEPTCONN = 30;
488 pub const SO_PEERSEC = 31;
489 pub const SO_SNDBUFFORCE = 32;
490 pub const SO_RCVBUFFORCE = 33;
491 pub const SO_PROTOCOL = 38;
492 pub const SO_DOMAIN = 39;
493 }
494else
423 struct {495 struct {
424 pub const SO_DEBUG = 1;496 pub const SO_DEBUG = 1;
425 pub const SO_REUSEADDR = 2;497 pub const SO_REUSEADDR = 2;
...@@ -448,9 +520,7 @@ pub usingnamespace if (!is_mips)...@@ -448,9 +520,7 @@ pub usingnamespace if (!is_mips)
448 pub const SO_RCVBUFFORCE = 33;520 pub const SO_RCVBUFFORCE = 33;
449 pub const SO_PROTOCOL = 38;521 pub const SO_PROTOCOL = 38;
450 pub const SO_DOMAIN = 39;522 pub const SO_DOMAIN = 39;
451 }523 };
452else
453 struct {};
454524
455pub const SO_SECURITY_AUTHENTICATION = 22;525pub const SO_SECURITY_AUTHENTICATION = 22;
456pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;526pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
lib/std/os/bits/linux/arm64.zig+1
...@@ -9,6 +9,7 @@...@@ -9,6 +9,7 @@
9const std = @import("../../../std.zig");9const std = @import("../../../std.zig");
10const linux = std.os.linux;10const linux = std.os.linux;
11const socklen_t = linux.socklen_t;11const socklen_t = linux.socklen_t;
12const sockaddr = linux.sockaddr;
12const iovec = linux.iovec;13const iovec = linux.iovec;
13const iovec_const = linux.iovec_const;14const iovec_const = linux.iovec_const;
14const uid_t = linux.uid_t;15const uid_t = linux.uid_t;
lib/std/os/bits/linux/errno-mips.zig+4
...@@ -3,6 +3,9 @@...@@ -3,6 +3,9 @@
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
6
7// These are MIPS ABI compatible.
8
6pub const EPERM = 1;9pub const EPERM = 1;
7pub const ENOENT = 2;10pub const ENOENT = 2;
8pub const ESRCH = 3;11pub const ESRCH = 3;
...@@ -37,6 +40,7 @@ pub const EMLINK = 31;...@@ -37,6 +40,7 @@ pub const EMLINK = 31;
37pub const EPIPE = 32;40pub const EPIPE = 32;
38pub const EDOM = 33;41pub const EDOM = 33;
39pub const ERANGE = 34;42pub const ERANGE = 34;
43
40pub const ENOMSG = 35;44pub const ENOMSG = 35;
41pub const EIDRM = 36;45pub const EIDRM = 36;
42pub const ECHRNG = 37;46pub const ECHRNG = 37;
lib/std/os/bits/linux/errno-sparc.zig created+144
...@@ -0,0 +1,144 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7// These match the SunOS error numbering scheme.
8
9pub const EPERM = 1;
10pub const ENOENT = 2;
11pub const ESRCH = 3;
12pub const EINTR = 4;
13pub const EIO = 5;
14pub const ENXIO = 6;
15pub const E2BIG = 7;
16pub const ENOEXEC = 8;
17pub const EBADF = 9;
18pub const ECHILD = 10;
19pub const EAGAIN = 11;
20pub const ENOMEM = 12;
21pub const EACCES = 13;
22pub const EFAULT = 14;
23pub const ENOTBLK = 15;
24pub const EBUSY = 16;
25pub const EEXIST = 17;
26pub const EXDEV = 18;
27pub const ENODEV = 19;
28pub const ENOTDIR = 20;
29pub const EISDIR = 21;
30pub const EINVAL = 22;
31pub const ENFILE = 23;
32pub const EMFILE = 24;
33pub const ENOTTY = 25;
34pub const ETXTBSY = 26;
35pub const EFBIG = 27;
36pub const ENOSPC = 28;
37pub const ESPIPE = 29;
38pub const EROFS = 30;
39pub const EMLINK = 31;
40pub const EPIPE = 32;
41pub const EDOM = 33;
42pub const ERANGE = 34;
43
44pub const EWOULDBLOCK = EAGAIN;
45pub const EINPROGRESS = 36;
46pub const EALREADY = 37;
47pub const ENOTSOCK = 38;
48pub const EDESTADDRREQ = 39;
49pub const EMSGSIZE = 40;
50pub const EPROTOTYPE = 41;
51pub const ENOPROTOOPT = 42;
52pub const EPROTONOSUPPORT = 43;
53pub const ESOCKTNOSUPPORT = 44;
54pub const EOPNOTSUPP = 45;
55pub const EPFNOSUPPORT = 46;
56pub const EAFNOSUPPORT = 47;
57pub const EADDRINUSE = 48;
58pub const EADDRNOTAVAIL = 49;
59pub const ENETDOWN = 50;
60pub const ENETUNREACH = 51;
61pub const ENETRESET = 52;
62pub const ECONNABORTED = 53;
63pub const ECONNRESET = 54;
64pub const ENOBUFS = 55;
65pub const EISCONN = 56;
66pub const ENOTCONN = 57;
67pub const ESHUTDOWN = 58;
68pub const ETOOMANYREFS = 59;
69pub const ETIMEDOUT = 60;
70pub const ECONNREFUSED = 61;
71pub const ELOOP = 62;
72pub const ENAMETOOLONG = 63;
73pub const EHOSTDOWN = 64;
74pub const EHOSTUNREACH = 65;
75pub const ENOTEMPTY = 66;
76pub const EPROCLIM = 67;
77pub const EUSERS = 68;
78pub const EDQUOT = 69;
79pub const ESTALE = 70;
80pub const EREMOTE = 71;
81pub const ENOSTR = 72;
82pub const ETIME = 73;
83pub const ENOSR = 74;
84pub const ENOMSG = 75;
85pub const EBADMSG = 76;
86pub const EIDRM = 77;
87pub const EDEADLK = 78;
88pub const ENOLCK = 79;
89pub const ENONET = 80;
90pub const ERREMOTE = 81;
91pub const ENOLINK = 82;
92pub const EADV = 83;
93pub const ESRMNT = 84;
94pub const ECOMM = 85;
95pub const EPROTO = 86;
96pub const EMULTIHOP = 87;
97pub const EDOTDOT = 88;
98pub const EREMCHG = 89;
99pub const ENOSYS = 90;
100pub const ESTRPIPE = 91;
101pub const EOVERFLOW = 92;
102pub const EBADFD = 93;
103pub const ECHRNG = 94;
104pub const EL2NSYNC = 95;
105pub const EL3HLT = 96;
106pub const EL3RST = 97;
107pub const ELNRNG = 98;
108pub const EUNATCH = 99;
109pub const ENOCSI = 100;
110pub const EL2HLT = 101;
111pub const EBADE = 102;
112pub const EBADR = 103;
113pub const EXFULL = 104;
114pub const ENOANO = 105;
115pub const EBADRQC = 106;
116pub const EBADSLT = 107;
117pub const EDEADLOCK = 108;
118pub const EBFONT = 109;
119pub const ELIBEXEC = 110;
120pub const ENODATA = 111;
121pub const ELIBBAD = 112;
122pub const ENOPKG = 113;
123pub const ELIBACC = 114;
124pub const ENOTUNIQ = 115;
125pub const ERESTART = 116;
126pub const EUCLEAN = 117;
127pub const ENOTNAM = 118;
128pub const ENAVAIL = 119;
129pub const EISNAM = 120;
130pub const EREMOTEIO = 121;
131pub const EILSEQ = 122;
132pub const ELIBMAX = 123;
133pub const ELIBSCN = 124;
134pub const ENOMEDIUM = 125;
135pub const EMEDIUMTYPE = 126;
136pub const ECANCELED = 127;
137pub const ENOKEY = 128;
138pub const EKEYEXPIRED = 129;
139pub const EKEYREVOKED = 130;
140pub const EKEYREJECTED = 131;
141pub const EOWNERDEAD = 132;
142pub const ENOTRECOVERABLE = 133;
143pub const ERFKILL = 134;
144pub const EHWPOISON = 135;
lib/std/os/bits/linux/riscv64.zig+5
...@@ -376,6 +376,11 @@ pub const timespec = extern struct {...@@ -376,6 +376,11 @@ pub const timespec = extern struct {
376 tv_nsec: isize,376 tv_nsec: isize,
377};377};
378378
379pub const timeval = extern struct {
380 tv_sec: time_t,
381 tv_usec: i64,
382};
383
379pub const Flock = extern struct {384pub const Flock = extern struct {
380 l_type: i16,385 l_type: i16,
381 l_whence: i16,386 l_whence: i16,
lib/std/os/bits/windows.zig+5
...@@ -22,6 +22,11 @@ pub const timespec = extern struct {...@@ -22,6 +22,11 @@ pub const timespec = extern struct {
22 tv_nsec: c_long,22 tv_nsec: c_long,
23};23};
2424
25pub const timeval = extern struct {
26 tv_sec: c_long,
27 tv_usec: c_long,
28};
29
25pub const sig_atomic_t = c_int;30pub const sig_atomic_t = c_int;
2631
27/// maximum signal number + 132/// maximum signal number + 1
lib/std/os/linux.zig+9-5
...@@ -387,7 +387,7 @@ pub fn symlinkat(existing: [*:0]const u8, newfd: i32, newpath: [*:0]const u8) us...@@ -387,7 +387,7 @@ pub fn symlinkat(existing: [*:0]const u8, newfd: i32, newpath: [*:0]const u8) us
387}387}
388388
389pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {389pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
390 if (@hasField(SYS, "pread64")) {390 if (@hasField(SYS, "pread64") and usize_bits < 64) {
391 const offset_halves = splitValue64(offset);391 const offset_halves = splitValue64(offset);
392 if (require_aligned_register_pair) {392 if (require_aligned_register_pair) {
393 return syscall6(393 return syscall6(
...@@ -410,8 +410,10 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {...@@ -410,8 +410,10 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
410 );410 );
411 }411 }
412 } else {412 } else {
413 // Some architectures (eg. 64bit SPARC) pread is called pread64.
414 const S = if (!@hasField(SYS, "pread") and @hasField(SYS, "pread64")) .pread64 else .pread;
413 return syscall4(415 return syscall4(
414 .pread,416 S,
415 @bitCast(usize, @as(isize, fd)),417 @bitCast(usize, @as(isize, fd)),
416 @ptrToInt(buf),418 @ptrToInt(buf),
417 count,419 count,
...@@ -451,7 +453,7 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {...@@ -451,7 +453,7 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
451}453}
452454
453pub fn ftruncate(fd: i32, length: u64) usize {455pub fn ftruncate(fd: i32, length: u64) usize {
454 if (@hasField(SYS, "ftruncate64")) {456 if (@hasField(SYS, "ftruncate64") and usize_bits < 64) {
455 const length_halves = splitValue64(length);457 const length_halves = splitValue64(length);
456 if (require_aligned_register_pair) {458 if (require_aligned_register_pair) {
457 return syscall4(459 return syscall4(
...@@ -479,7 +481,7 @@ pub fn ftruncate(fd: i32, length: u64) usize {...@@ -479,7 +481,7 @@ pub fn ftruncate(fd: i32, length: u64) usize {
479}481}
480482
481pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {483pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {
482 if (@hasField(SYS, "pwrite64")) {484 if (@hasField(SYS, "pwrite64") and usize_bits < 64) {
483 const offset_halves = splitValue64(offset);485 const offset_halves = splitValue64(offset);
484486
485 if (require_aligned_register_pair) {487 if (require_aligned_register_pair) {
...@@ -503,8 +505,10 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {...@@ -503,8 +505,10 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {
503 );505 );
504 }506 }
505 } else {507 } else {
508 // Some architectures (eg. 64bit SPARC) pwrite is called pwrite64.
509 const S = if (!@hasField(SYS, "pwrite") and @hasField(SYS, "pwrite64")) .pwrite64 else .pwrite;
506 return syscall4(510 return syscall4(
507 .pwrite,511 S,
508 @bitCast(usize, @as(isize, fd)),512 @bitCast(usize, @as(isize, fd)),
509 @ptrToInt(buf),513 @ptrToInt(buf),
510 count,514 count,
lib/std/special/c.zig+7-6
...@@ -617,23 +617,24 @@ fn clone() callconv(.Naked) void {...@@ -617,23 +617,24 @@ fn clone() callconv(.Naked) void {
617 \\ # Shuffle the arguments617 \\ # Shuffle the arguments
618 \\ mov 217, %%g1618 \\ mov 217, %%g1
619 \\ mov %%i2, %%o0619 \\ mov %%i2, %%o0
620 \\ sub %%i1, 2047, %%o1620 \\ # Add some extra space for the initial frame
621 \\ sub %%i1, 176 + 2047, %%o1
621 \\ mov %%i4, %%o2622 \\ mov %%i4, %%o2
622 \\ mov %%i5, %%o3623 \\ mov %%i5, %%o3
623 \\ ldx [%%fp + 192 - 2*8 + 2047], %%o4624 \\ ldx [%%fp + 0x8af], %%o4
624 \\ t 0x6d625 \\ t 0x6d
625 \\ bcs,pn %%xcc, 2f626 \\ bcs,pn %%xcc, 2f
626 \\ nop627 \\ nop
627 \\ # sparc64 returns the child pid in o0 and a flag telling628 \\ # The child pid is returned in o0 while o1 tells if this
628 \\ # whether the process is the child in o1629 \\ # process is # the child (=1) or the parent (=0).
629 \\ brnz %%o1, 1f630 \\ brnz %%o1, 1f
630 \\ nop631 \\ nop
631 \\ # This is the parent process, return the child pid632 \\ # Parent process, return the child pid
632 \\ mov %%o0, %%i0633 \\ mov %%o0, %%i0
633 \\ ret634 \\ ret
634 \\ restore635 \\ restore
635 \\1:636 \\1:
636 \\ # This is the child process637 \\ # Child process, call func(arg)
637 \\ mov %%g0, %%fp638 \\ mov %%g0, %%fp
638 \\ call %%g2639 \\ call %%g2
639 \\ mov %%g3, %%o0640 \\ mov %%g3, %%o0
lib/std/target/aarch64.zig+18
...@@ -1621,6 +1621,16 @@ pub const cpu = struct {...@@ -1621,6 +1621,16 @@ pub const cpu = struct {
1621 .apple_a7,1621 .apple_a7,
1622 }),1622 }),
1623 };1623 };
1624 pub const emag = CpuModel{
1625 .name = "emag",
1626 .llvm_name = null,
1627 .features = featureSet(&[_]Feature{
1628 .crc,
1629 .crypto,
1630 .perfmon,
1631 .v8a,
1632 }),
1633 };
1624 pub const exynos_m1 = CpuModel{1634 pub const exynos_m1 = CpuModel{
1625 .name = "exynos_m1",1635 .name = "exynos_m1",
1626 .llvm_name = null,1636 .llvm_name = null,
...@@ -1867,4 +1877,12 @@ pub const cpu = struct {...@@ -1867,4 +1877,12 @@ pub const cpu = struct {
1867 .v8_2a,1877 .v8_2a,
1868 }),1878 }),
1869 };1879 };
1880 pub const xgene1 = CpuModel{
1881 .name = "xgene1",
1882 .llvm_name = null,
1883 .features = featureSet(&[_]Feature{
1884 .perfmon,
1885 .v8a,
1886 }),
1887 };
1870};1888};
lib/std/x.zig+23-1
...@@ -1 +1,23 @@...@@ -1 +1,23 @@
1pub const os = @import("x/os/os.zig");1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("std.zig");
8
9pub const os = struct {
10 pub const Socket = @import("x/os/Socket.zig");
11 pub usingnamespace @import("x/os/net.zig");
12};
13
14pub const net = struct {
15 pub const ip = @import("x/net/ip.zig");
16 pub const tcp = @import("x/net/tcp.zig");
17};
18
19test {
20 inline for (.{ os, net }) |module| {
21 std.testing.refAllDecls(module);
22 }
23}
lib/std/x/net/ip.zig created+61
...@@ -0,0 +1,61 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../std.zig");
8
9const fmt = std.fmt;
10
11const IPv4 = std.x.os.IPv4;
12const IPv6 = std.x.os.IPv6;
13const Socket = std.x.os.Socket;
14
15/// A generic IP abstraction.
16const ip = @This();
17
18/// A union of all eligible types of IP addresses.
19pub const Address = union(enum) {
20 ipv4: IPv4.Address,
21 ipv6: IPv6.Address,
22
23 /// Instantiate a new address with a IPv4 host and port.
24 pub fn initIPv4(host: IPv4, port: u16) Address {
25 return .{ .ipv4 = .{ .host = host, .port = port } };
26 }
27
28 /// Instantiate a new address with a IPv6 host and port.
29 pub fn initIPv6(host: IPv6, port: u16) Address {
30 return .{ .ipv6 = .{ .host = host, .port = port } };
31 }
32
33 /// Re-interpret a generic socket address into an IP address.
34 pub fn from(address: Socket.Address) ip.Address {
35 return switch (address) {
36 .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
37 .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
38 };
39 }
40
41 /// Re-interpret an IP address into a generic socket address.
42 pub fn into(self: ip.Address) Socket.Address {
43 return switch (self) {
44 .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
45 .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
46 };
47 }
48
49 /// Implements the `std.fmt.format` API.
50 pub fn format(
51 self: ip.Address,
52 comptime layout: []const u8,
53 opts: fmt.FormatOptions,
54 writer: anytype,
55 ) !void {
56 switch (self) {
57 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
58 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
59 }
60 }
61};
lib/std/x/net/tcp.zig created+352
...@@ -0,0 +1,352 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../std.zig");
8
9const os = std.os;
10const ip = std.x.net.ip;
11
12const fmt = std.fmt;
13const mem = std.mem;
14const builtin = std.builtin;
15const testing = std.testing;
16
17const IPv4 = std.x.os.IPv4;
18const IPv6 = std.x.os.IPv6;
19const Socket = std.x.os.Socket;
20
21/// A generic TCP socket abstraction.
22const tcp = @This();
23
24/// A TCP client-address pair.
25pub const Connection = struct {
26 client: tcp.Client,
27 address: ip.Address,
28
29 /// Enclose a TCP client and address into a client-address pair.
30 pub fn from(conn: Socket.Connection) tcp.Connection {
31 return .{
32 .client = tcp.Client.from(conn.socket),
33 .address = ip.Address.from(conn.address),
34 };
35 }
36
37 /// Unravel a TCP client-address pair into a socket-address pair.
38 pub fn into(self: tcp.Connection) Socket.Connection {
39 return .{
40 .socket = self.client.socket,
41 .address = self.address.into(),
42 };
43 }
44
45 /// Closes the underlying client of the connection.
46 pub fn deinit(self: tcp.Connection) void {
47 self.client.deinit();
48 }
49};
50
51/// Possible domains that a TCP client/listener may operate over.
52pub const Domain = extern enum(u16) {
53 ip = os.AF_INET,
54 ipv6 = os.AF_INET6,
55};
56
57/// A TCP client.
58pub const Client = struct {
59 socket: Socket,
60
61 /// Opens a new client.
62 pub fn init(domain: tcp.Domain, flags: u32) !Client {
63 return Client{
64 .socket = try Socket.init(
65 @enumToInt(domain),
66 os.SOCK_STREAM | flags,
67 os.IPPROTO_TCP,
68 ),
69 };
70 }
71
72 /// Enclose a TCP client over an existing socket.
73 pub fn from(socket: Socket) Client {
74 return Client{ .socket = socket };
75 }
76
77 /// Closes the client.
78 pub fn deinit(self: Client) void {
79 self.socket.deinit();
80 }
81
82 /// Shutdown either the read side, write side, or all sides of the client's underlying socket.
83 pub fn shutdown(self: Client, how: os.ShutdownHow) !void {
84 return self.socket.shutdown(how);
85 }
86
87 /// Have the client attempt to the connect to an address.
88 pub fn connect(self: Client, address: ip.Address) !void {
89 return self.socket.connect(address.into());
90 }
91
92 /// Read data from the socket into the buffer provided. It returns the
93 /// number of bytes read into the buffer provided.
94 pub fn read(self: Client, buf: []u8) !usize {
95 return self.socket.read(buf);
96 }
97
98 /// Read data from the socket into the buffer provided with a set of flags
99 /// specified. It returns the number of bytes read into the buffer provided.
100 pub fn recv(self: Client, buf: []u8, flags: u32) !usize {
101 return self.socket.recv(buf, flags);
102 }
103
104 /// Write a buffer of data provided to the socket. It returns the number
105 /// of bytes that are written to the socket.
106 pub fn write(self: Client, buf: []const u8) !usize {
107 return self.socket.write(buf);
108 }
109
110 /// Writes multiple I/O vectors to the socket. It returns the number
111 /// of bytes that are written to the socket.
112 pub fn writev(self: Client, buffers: []const os.iovec_const) !usize {
113 return self.socket.writev(buffers);
114 }
115
116 /// Write a buffer of data provided to the socket with a set of flags specified.
117 /// It returns the number of bytes that are written to the socket.
118 pub fn send(self: Client, buf: []const u8, flags: u32) !usize {
119 return self.socket.send(buf, flags);
120 }
121
122 /// Writes multiple I/O vectors with a prepended message header to the socket
123 /// with a set of flags specified. It returns the number of bytes that are
124 /// written to the socket.
125 pub fn sendmsg(self: Client, msg: os.msghdr_const, flags: u32) !usize {
126 return self.socket.sendmsg(msg, flags);
127 }
128
129 /// Query and return the latest cached error on the client's underlying socket.
130 pub fn getError(self: Client) !void {
131 return self.socket.getError();
132 }
133
134 /// Query the read buffer size of the client's underlying socket.
135 pub fn getReadBufferSize(self: Client) !u32 {
136 return self.socket.getReadBufferSize();
137 }
138
139 /// Query the write buffer size of the client's underlying socket.
140 pub fn getWriteBufferSize(self: Client) !u32 {
141 return self.socket.getWriteBufferSize();
142 }
143
144 /// Query the address that the client's socket is locally bounded to.
145 pub fn getLocalAddress(self: Client) !ip.Address {
146 return ip.Address.from(try self.socket.getLocalAddress());
147 }
148
149 /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if
150 /// the host does not support sockets disabling Nagle's algorithm.
151 pub fn setNoDelay(self: Client, enabled: bool) !void {
152 if (comptime @hasDecl(os, "TCP_NODELAY")) {
153 const bytes = mem.asBytes(&@as(usize, @boolToInt(enabled)));
154 return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_NODELAY, bytes);
155 }
156 return error.UnsupportedSocketOption;
157 }
158
159 /// Set the write buffer size of the socket.
160 pub fn setWriteBufferSize(self: Client, size: u32) !void {
161 return self.socket.setWriteBufferSize(size);
162 }
163
164 /// Set the read buffer size of the socket.
165 pub fn setReadBufferSize(self: Client, size: u32) !void {
166 return self.socket.setReadBufferSize(size);
167 }
168
169 /// Set a timeout on the socket that is to occur if no messages are successfully written
170 /// to its bound destination after a specified number of milliseconds. A subsequent write
171 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
172 pub fn setWriteTimeout(self: Client, milliseconds: usize) !void {
173 return self.socket.setWriteTimeout(milliseconds);
174 }
175
176 /// Set a timeout on the socket that is to occur if no messages are successfully read
177 /// from its bound destination after a specified number of milliseconds. A subsequent
178 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
179 /// exceeded.
180 pub fn setReadTimeout(self: Client, milliseconds: usize) !void {
181 return self.socket.setReadTimeout(milliseconds);
182 }
183};
184
185/// A TCP listener.
186pub const Listener = struct {
187 socket: Socket,
188
189 /// Opens a new listener.
190 pub fn init(domain: tcp.Domain, flags: u32) !Listener {
191 return Listener{
192 .socket = try Socket.init(
193 @enumToInt(domain),
194 os.SOCK_STREAM | flags,
195 os.IPPROTO_TCP,
196 ),
197 };
198 }
199
200 /// Closes the listener.
201 pub fn deinit(self: Listener) void {
202 self.socket.deinit();
203 }
204
205 /// Shuts down the underlying listener's socket. The next subsequent call, or
206 /// a current pending call to accept() after shutdown is called will return
207 /// an error.
208 pub fn shutdown(self: Listener) !void {
209 return self.socket.shutdown(.recv);
210 }
211
212 /// Binds the listener's socket to an address.
213 pub fn bind(self: Listener, address: ip.Address) !void {
214 return self.socket.bind(address.into());
215 }
216
217 /// Start listening for incoming connections.
218 pub fn listen(self: Listener, max_backlog_size: u31) !void {
219 return self.socket.listen(max_backlog_size);
220 }
221
222 /// Accept a pending incoming connection queued to the kernel backlog
223 /// of the listener's socket.
224 pub fn accept(self: Listener, flags: u32) !tcp.Connection {
225 return tcp.Connection.from(try self.socket.accept(flags));
226 }
227
228 /// Query and return the latest cached error on the listener's underlying socket.
229 pub fn getError(self: Client) !void {
230 return self.socket.getError();
231 }
232
233 /// Query the address that the listener's socket is locally bounded to.
234 pub fn getLocalAddress(self: Listener) !ip.Address {
235 return ip.Address.from(try self.socket.getLocalAddress());
236 }
237
238 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
239 /// the host does not support sockets listening the same address.
240 pub fn setReuseAddress(self: Listener, enabled: bool) !void {
241 return self.socket.setReuseAddress(enabled);
242 }
243
244 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
245 /// the host does not supports sockets listening on the same port.
246 pub fn setReusePort(self: Listener, enabled: bool) !void {
247 return self.socket.setReusePort(enabled);
248 }
249
250 /// Enables TCP Fast Open (RFC 7413) on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not
251 /// support TCP Fast Open.
252 pub fn setFastOpen(self: Listener, enabled: bool) !void {
253 if (comptime @hasDecl(os, "TCP_FASTOPEN")) {
254 return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(usize, @boolToInt(enabled))));
255 }
256 return error.UnsupportedSocketOption;
257 }
258
259 /// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns
260 /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
261 pub fn setQuickACK(self: Listener, enabled: bool) !void {
262 if (comptime @hasDecl(os, "TCP_QUICKACK")) {
263 return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(usize, @boolToInt(enabled))));
264 }
265 return error.UnsupportedSocketOption;
266 }
267
268 /// Set a timeout on the listener that is to occur if no new incoming connections come in
269 /// after a specified number of milliseconds. A subsequent accept call to the listener
270 /// will thereafter return `error.WouldBlock` should the timeout be exceeded.
271 pub fn setAcceptTimeout(self: Listener, milliseconds: usize) !void {
272 return self.socket.setReadTimeout(milliseconds);
273 }
274};
275
276test "tcp: create client/listener pair" {
277 if (builtin.os.tag == .wasi) return error.SkipZigTest;
278
279 const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
280 defer listener.deinit();
281
282 try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
283 try listener.listen(128);
284
285 var binded_address = try listener.getLocalAddress();
286 switch (binded_address) {
287 .ipv4 => |*ipv4| ipv4.host = IPv4.localhost,
288 .ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
289 }
290
291 const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC);
292 defer client.deinit();
293
294 try client.connect(binded_address);
295
296 const conn = try listener.accept(os.SOCK_CLOEXEC);
297 defer conn.deinit();
298}
299
300test "tcp/client: set read timeout of 1 millisecond on blocking client" {
301 if (builtin.os.tag == .wasi) return error.SkipZigTest;
302
303 const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
304 defer listener.deinit();
305
306 try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
307 try listener.listen(128);
308
309 var binded_address = try listener.getLocalAddress();
310 switch (binded_address) {
311 .ipv4 => |*ipv4| ipv4.host = IPv4.localhost,
312 .ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
313 }
314
315 const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC);
316 defer client.deinit();
317
318 try client.connect(binded_address);
319 try client.setReadTimeout(1);
320
321 const conn = try listener.accept(os.SOCK_CLOEXEC);
322 defer conn.deinit();
323
324 var buf: [1]u8 = undefined;
325 testing.expectError(error.WouldBlock, client.read(&buf));
326}
327
328test "tcp/listener: bind to unspecified ipv4 address" {
329 if (builtin.os.tag == .wasi) return error.SkipZigTest;
330
331 const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
332 defer listener.deinit();
333
334 try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
335 try listener.listen(128);
336
337 const address = try listener.getLocalAddress();
338 testing.expect(address == .ipv4);
339}
340
341test "tcp/listener: bind to unspecified ipv6 address" {
342 if (builtin.os.tag == .wasi) return error.SkipZigTest;
343
344 const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC);
345 defer listener.deinit();
346
347 try listener.bind(ip.Address.initIPv6(IPv6.unspecified, 0));
348 try listener.listen(128);
349
350 const address = try listener.getLocalAddress();
351 testing.expect(address == .ipv6);
352}
lib/std/x/os/Socket.zig+115-96
...@@ -1,18 +1,110 @@...@@ -1,18 +1,110 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
1const std = @import("../../std.zig");7const std = @import("../../std.zig");
8const net = @import("net.zig");
29
3const os = std.os;10const os = std.os;
11const fmt = std.fmt;
4const mem = std.mem;12const mem = std.mem;
5const net = std.net;
6const time = std.time;13const time = std.time;
7const builtin = std.builtin;
8const testing = std.testing;
914
15/// A generic socket abstraction.
10const Socket = @This();16const Socket = @This();
1117
12/// A socket-address pair.18/// A socket-address pair.
13pub const Connection = struct {19pub const Connection = struct {
14 socket: Socket,20 socket: Socket,
15 address: net.Address,21 address: Socket.Address,
22
23 /// Enclose a socket and address into a socket-address pair.
24 pub fn from(socket: Socket, address: Socket.Address) Socket.Connection {
25 return .{ .socket = socket, .address = address };
26 }
27};
28
29/// A generic socket address abstraction. It is safe to directly access and modify
30/// the fields of a `Socket.Address`.
31pub const Address = union(enum) {
32 ipv4: net.IPv4.Address,
33 ipv6: net.IPv6.Address,
34
35 /// Instantiate a new address with a IPv4 host and port.
36 pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address {
37 return .{ .ipv4 = .{ .host = host, .port = port } };
38 }
39
40 /// Instantiate a new address with a IPv6 host and port.
41 pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address {
42 return .{ .ipv6 = .{ .host = host, .port = port } };
43 }
44
45 /// Parses a `sockaddr` into a generic socket address.
46 pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address {
47 switch (address.family) {
48 os.AF_INET => {
49 const info = @ptrCast(*const os.sockaddr_in, address);
50 const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
51 const port = mem.bigToNative(u16, info.port);
52 return Socket.Address.initIPv4(host, port);
53 },
54 os.AF_INET6 => {
55 const info = @ptrCast(*const os.sockaddr_in6, address);
56 const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
57 const port = mem.bigToNative(u16, info.port);
58 return Socket.Address.initIPv6(host, port);
59 },
60 else => unreachable,
61 }
62 }
63
64 /// Encodes a generic socket address into an extern union that may be reliably
65 /// casted into a `sockaddr` which may be passed into socket syscalls.
66 pub fn toNative(self: Socket.Address) extern union {
67 ipv4: os.sockaddr_in,
68 ipv6: os.sockaddr_in6,
69 } {
70 return switch (self) {
71 .ipv4 => |address| .{
72 .ipv4 = .{
73 .addr = @bitCast(u32, address.host.octets),
74 .port = mem.nativeToBig(u16, address.port),
75 },
76 },
77 .ipv6 => |address| .{
78 .ipv6 = .{
79 .addr = address.host.octets,
80 .port = mem.nativeToBig(u16, address.port),
81 .scope_id = address.host.scope_id,
82 .flowinfo = 0,
83 },
84 },
85 };
86 }
87
88 /// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
89 pub fn getNativeSize(self: Socket.Address) u32 {
90 return switch (self) {
91 .ipv4 => @sizeOf(os.sockaddr_in),
92 .ipv6 => @sizeOf(os.sockaddr_in6),
93 };
94 }
95
96 /// Implements the `std.fmt.format` API.
97 pub fn format(
98 self: Socket.Address,
99 comptime layout: []const u8,
100 opts: fmt.FormatOptions,
101 writer: anytype,
102 ) !void {
103 switch (self) {
104 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
105 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
106 }
107 }
16};108};
17109
18/// The underlying handle of a socket.110/// The underlying handle of a socket.
...@@ -23,19 +115,24 @@ pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {...@@ -23,19 +115,24 @@ pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
23 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };115 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
24}116}
25117
118/// Enclose a socket abstraction over an existing socket file descriptor.
119pub fn from(fd: os.socket_t) Socket {
120 return Socket{ .fd = fd };
121}
122
26/// Closes the socket.123/// Closes the socket.
27pub fn deinit(self: Socket) void {124pub fn deinit(self: Socket) void {
28 os.closeSocket(self.fd);125 os.closeSocket(self.fd);
29}126}
30127
31/// Shutdown either the read side, or write side, or the entirety of a socket.128/// Shutdown either the read side, write side, or all side of the socket.
32pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {129pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
33 return os.shutdown(self.fd, how);130 return os.shutdown(self.fd, how);
34}131}
35132
36/// Binds the socket to an address.133/// Binds the socket to an address.
37pub fn bind(self: Socket, address: net.Address) !void {134pub fn bind(self: Socket, address: Socket.Address) !void {
38 return os.bind(self.fd, &address.any, address.getOsSockLen());135 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
39}136}
40137
41/// Start listening for incoming connections on the socket.138/// Start listening for incoming connections on the socket.
...@@ -44,8 +141,8 @@ pub fn listen(self: Socket, max_backlog_size: u31) !void {...@@ -44,8 +141,8 @@ pub fn listen(self: Socket, max_backlog_size: u31) !void {
44}141}
45142
46/// Have the socket attempt to the connect to an address.143/// Have the socket attempt to the connect to an address.
47pub fn connect(self: Socket, address: net.Address) !void {144pub fn connect(self: Socket, address: Socket.Address) !void {
48 return os.connect(self.fd, &address.any, address.getOsSockLen());145 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
49}146}
50147
51/// Accept a pending incoming connection queued to the kernel backlog148/// Accept a pending incoming connection queued to the kernel backlog
...@@ -54,12 +151,10 @@ pub fn accept(self: Socket, flags: u32) !Socket.Connection {...@@ -54,12 +151,10 @@ pub fn accept(self: Socket, flags: u32) !Socket.Connection {
54 var address: os.sockaddr = undefined;151 var address: os.sockaddr = undefined;
55 var address_len: u32 = @sizeOf(os.sockaddr);152 var address_len: u32 = @sizeOf(os.sockaddr);
56153
57 const fd = try os.accept(self.fd, &address, &address_len, flags);154 const socket = Socket{ .fd = try os.accept(self.fd, &address, &address_len, flags) };
155 const socket_address = Socket.Address.fromNative(@alignCast(4, &address));
58156
59 return Connection{157 return Socket.Connection.from(socket, socket_address);
60 .socket = Socket{ .fd = fd },
61 .address = net.Address.initPosix(@alignCast(4, &address)),
62 };
63}158}
64159
65/// Read data from the socket into the buffer provided. It returns the160/// Read data from the socket into the buffer provided. It returns the
...@@ -100,11 +195,11 @@ pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize {...@@ -100,11 +195,11 @@ pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
100}195}
101196
102/// Query the address that the socket is locally bounded to.197/// Query the address that the socket is locally bounded to.
103pub fn getLocalAddress(self: Socket) !net.Address {198pub fn getLocalAddress(self: Socket) !Socket.Address {
104 var address: os.sockaddr = undefined;199 var address: os.sockaddr = undefined;
105 var address_len: u32 = @sizeOf(os.sockaddr);200 var address_len: u32 = @sizeOf(os.sockaddr);
106 try os.getsockname(self.fd, &address, &address_len);201 try os.getsockname(self.fd, &address, &address_len);
107 return net.Address.initPosix(@alignCast(4, &address));202 return Socket.Address.fromNative(@alignCast(4, &address));
108}203}
109204
110/// Query and return the latest cached error on the socket.205/// Query and return the latest cached error on the socket.
...@@ -164,33 +259,6 @@ pub fn setReusePort(self: Socket, enabled: bool) !void {...@@ -164,33 +259,6 @@ pub fn setReusePort(self: Socket, enabled: bool) !void {
164 return error.UnsupportedSocketOption;259 return error.UnsupportedSocketOption;
165}260}
166261
167/// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not support
168/// sockets disabling Nagle's algorithm.
169pub fn setNoDelay(self: Socket, enabled: bool) !void {
170 if (comptime @hasDecl(os, "TCP_NODELAY")) {
171 return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_NODELAY, mem.asBytes(&@as(usize, @boolToInt(enabled))));
172 }
173 return error.UnsupportedSocketOption;
174}
175
176/// Enables TCP Fast Open (RFC 7413) on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not
177/// support TCP Fast Open.
178pub fn setFastOpen(self: Socket, enabled: bool) !void {
179 if (comptime @hasDecl(os, "TCP_FASTOPEN")) {
180 return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(usize, @boolToInt(enabled))));
181 }
182 return error.UnsupportedSocketOption;
183}
184
185/// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns
186/// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
187pub fn setQuickACK(self: Socket, enabled: bool) !void {
188 if (comptime @hasDecl(os, "TCP_QUICKACK")) {
189 return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(usize, @boolToInt(enabled))));
190 }
191 return error.UnsupportedSocketOption;
192}
193
194/// Set the write buffer size of the socket.262/// Set the write buffer size of the socket.
195pub fn setWriteBufferSize(self: Socket, size: u32) !void {263pub fn setWriteBufferSize(self: Socket, size: u32) !void {
196 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));264 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
...@@ -206,8 +274,8 @@ pub fn setReadBufferSize(self: Socket, size: u32) !void {...@@ -206,8 +274,8 @@ pub fn setReadBufferSize(self: Socket, size: u32) !void {
206/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.274/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
207pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {275pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
208 const timeout = os.timeval{276 const timeout = os.timeval{
209 .tv_sec = @intCast(isize, milliseconds / time.ms_per_s),277 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
210 .tv_usec = @intCast(isize, (milliseconds % time.ms_per_s) * time.us_per_ms),278 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
211 };279 };
212280
213 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));281 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
...@@ -219,58 +287,9 @@ pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {...@@ -219,58 +287,9 @@ pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
219/// exceeded.287/// exceeded.
220pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {288pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
221 const timeout = os.timeval{289 const timeout = os.timeval{
222 .tv_sec = @intCast(isize, milliseconds / time.ms_per_s),290 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
223 .tv_usec = @intCast(isize, (milliseconds % time.ms_per_s) * time.us_per_ms),291 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
224 };292 };
225293
226 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));294 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
227}295}
228
229test {
230 testing.refAllDecls(@This());
231}
232
233test "socket/linux: set read timeout of 1 millisecond on blocking socket" {
234 if (builtin.os.tag != .linux) return error.SkipZigTest;
235
236 const a = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
237 defer a.deinit();
238
239 try a.bind(net.Address.initIp4([_]u8{ 0, 0, 0, 0 }, 0));
240 try a.listen(128);
241
242 const binded_address = try a.getLocalAddress();
243
244 const b = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
245 defer b.deinit();
246
247 try b.connect(binded_address);
248 try b.setReadTimeout(1);
249
250 const ab = try a.accept(os.SOCK_CLOEXEC);
251 defer ab.socket.deinit();
252
253 var buf: [1]u8 = undefined;
254 testing.expectError(error.WouldBlock, b.read(&buf));
255}
256
257test "socket/linux: create non-blocking socket pair" {
258 if (builtin.os.tag != .linux) return error.SkipZigTest;
259
260 const a = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_NONBLOCK | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
261 defer a.deinit();
262
263 try a.bind(net.Address.initIp4([_]u8{ 0, 0, 0, 0 }, 0));
264 try a.listen(128);
265
266 const binded_address = try a.getLocalAddress();
267
268 const b = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_NONBLOCK | os.SOCK_CLOEXEC, os.IPPROTO_TCP);
269 defer b.deinit();
270
271 testing.expectError(error.WouldBlock, b.connect(binded_address));
272 try b.getError();
273
274 const ab = try a.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
275 defer ab.socket.deinit();
276}
lib/std/x/os/net.zig created+567
...@@ -0,0 +1,567 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../std.zig");
8
9const os = std.os;
10const fmt = std.fmt;
11const mem = std.mem;
12const math = std.math;
13const builtin = std.builtin;
14const testing = std.testing;
15
16/// Resolves a network interface name into a scope/zone ID. It returns
17/// an error if either resolution fails, or if the interface name is
18/// too long.
19pub fn resolveScopeID(name: []const u8) !u32 {
20 if (comptime @hasDecl(os, "IFNAMESIZE")) {
21 if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong;
22
23 const fd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM, 0);
24 defer os.closeSocket(fd);
25
26 var f: os.ifreq = undefined;
27 mem.copy(u8, &f.ifrn.name, name);
28 f.ifrn.name[name.len] = 0;
29
30 try os.ioctl_SIOCGIFINDEX(fd, &f);
31
32 return @bitCast(u32, f.ifru.ivalue);
33 }
34 return error.Unsupported;
35}
36
37/// An IPv4 address comprised of 4 bytes.
38pub const IPv4 = extern struct {
39 /// A IPv4 host-port pair.
40 pub const Address = extern struct {
41 host: IPv4,
42 port: u16,
43 };
44
45 /// Octets of a IPv4 address designating the local host.
46 pub const localhost_octets = [_]u8{ 127, 0, 0, 1 };
47
48 /// The IPv4 address of the local host.
49 pub const localhost: IPv4 = .{ .octets = localhost_octets };
50
51 /// Octets of an unspecified IPv4 address.
52 pub const unspecified_octets = [_]u8{0} ** 4;
53
54 /// An unspecified IPv4 address.
55 pub const unspecified: IPv4 = .{ .octets = unspecified_octets };
56
57 /// Octets of a broadcast IPv4 address.
58 pub const broadcast_octets = [_]u8{255} ** 4;
59
60 /// An IPv4 broadcast address.
61 pub const broadcast: IPv4 = .{ .octets = broadcast_octets };
62
63 /// The prefix octet pattern of a link-local IPv4 address.
64 pub const link_local_prefix = [_]u8{ 169, 254 };
65
66 /// The prefix octet patterns of IPv4 addresses intended for
67 /// documentation.
68 pub const documentation_prefixes = [_][]const u8{
69 &[_]u8{ 192, 0, 2 },
70 &[_]u8{ 198, 51, 100 },
71 &[_]u8{ 203, 0, 113 },
72 };
73
74 octets: [4]u8,
75
76 /// Returns whether or not the two addresses are equal to, less than, or
77 /// greater than each other.
78 pub fn cmp(self: IPv4, other: IPv4) math.Order {
79 return mem.order(u8, &self.octets, &other.octets);
80 }
81
82 /// Returns true if both addresses are semantically equivalent.
83 pub fn eql(self: IPv4, other: IPv4) bool {
84 return mem.eql(u8, &self.octets, &other.octets);
85 }
86
87 /// Returns true if the address is a loopback address.
88 pub fn isLoopback(self: IPv4) bool {
89 return self.octets[0] == 127;
90 }
91
92 /// Returns true if the address is an unspecified IPv4 address.
93 pub fn isUnspecified(self: IPv4) bool {
94 return mem.eql(u8, &self.octets, &unspecified_octets);
95 }
96
97 /// Returns true if the address is a private IPv4 address.
98 pub fn isPrivate(self: IPv4) bool {
99 return self.octets[0] == 10 or
100 (self.octets[0] == 172 and self.octets[1] >= 16 and self.octets[1] <= 31) or
101 (self.octets[0] == 192 and self.octets[1] == 168);
102 }
103
104 /// Returns true if the address is a link-local IPv4 address.
105 pub fn isLinkLocal(self: IPv4) bool {
106 return mem.startsWith(u8, &self.octets, &link_local_prefix);
107 }
108
109 /// Returns true if the address is a multicast IPv4 address.
110 pub fn isMulticast(self: IPv4) bool {
111 return self.octets[0] >= 224 and self.octets[0] <= 239;
112 }
113
114 /// Returns true if the address is a IPv4 broadcast address.
115 pub fn isBroadcast(self: IPv4) bool {
116 return mem.eql(u8, &self.octets, &broadcast_octets);
117 }
118
119 /// Returns true if the address is in a range designated for documentation. Refer
120 /// to IETF RFC 5737 for more details.
121 pub fn isDocumentation(self: IPv4) bool {
122 inline for (documentation_prefixes) |prefix| {
123 if (mem.startsWith(u8, &self.octets, prefix)) {
124 return true;
125 }
126 }
127 return false;
128 }
129
130 /// Implements the `std.fmt.format` API.
131 pub fn format(
132 self: IPv4,
133 comptime layout: []const u8,
134 opts: fmt.FormatOptions,
135 writer: anytype,
136 ) !void {
137 if (comptime layout.len != 0 and layout[0] != 's') {
138 @compileError("Unsupported format specifier for IPv4 type '" ++ layout ++ "'.");
139 }
140
141 try fmt.format(writer, "{}.{}.{}.{}", .{
142 self.octets[0],
143 self.octets[1],
144 self.octets[2],
145 self.octets[3],
146 });
147 }
148
149 /// Set of possible errors that may encountered when parsing an IPv4
150 /// address.
151 pub const ParseError = error{
152 UnexpectedEndOfOctet,
153 TooManyOctets,
154 OctetOverflow,
155 UnexpectedToken,
156 IncompleteAddress,
157 };
158
159 /// Parses an arbitrary IPv4 address.
160 pub fn parse(buf: []const u8) ParseError!IPv4 {
161 var octets: [4]u8 = undefined;
162 var octet: u8 = 0;
163
164 var index: u8 = 0;
165 var saw_any_digits: bool = false;
166
167 for (buf) |c| {
168 switch (c) {
169 '.' => {
170 if (!saw_any_digits) return error.UnexpectedEndOfOctet;
171 if (index == 3) return error.TooManyOctets;
172 octets[index] = octet;
173 index += 1;
174 octet = 0;
175 saw_any_digits = false;
176 },
177 '0'...'9' => {
178 saw_any_digits = true;
179 octet = math.mul(u8, octet, 10) catch return error.OctetOverflow;
180 octet = math.add(u8, octet, c - '0') catch return error.OctetOverflow;
181 },
182 else => return error.UnexpectedToken,
183 }
184 }
185
186 if (index == 3 and saw_any_digits) {
187 octets[index] = octet;
188 return IPv4{ .octets = octets };
189 }
190
191 return error.IncompleteAddress;
192 }
193
194 /// Maps the address to its IPv6 equivalent. In most cases, you would
195 /// want to map the address to its IPv6 equivalent rather than directly
196 /// re-interpreting the address.
197 pub fn mapToIPv6(self: IPv4) IPv6 {
198 var octets: [16]u8 = undefined;
199 mem.copy(u8, octets[0..12], &IPv6.v4_mapped_prefix);
200 mem.copy(u8, octets[12..], &self.octets);
201 return IPv6{ .octets = octets, .scope_id = IPv6.no_scope_id };
202 }
203
204 /// Directly re-interprets the address to its IPv6 equivalent. In most
205 /// cases, you would want to map the address to its IPv6 equivalent rather
206 /// than directly re-interpreting the address.
207 pub fn toIPv6(self: IPv4) IPv6 {
208 var octets: [16]u8 = undefined;
209 mem.set(u8, octets[0..12], 0);
210 mem.copy(u8, octets[12..], &self.octets);
211 return IPv6{ .octets = octets, .scope_id = IPv6.no_scope_id };
212 }
213};
214
215/// An IPv6 address comprised of 16 bytes for an address, and 4 bytes
216/// for a scope ID; cumulatively summing to 20 bytes in total.
217pub const IPv6 = extern struct {
218 /// A IPv6 host-port pair.
219 pub const Address = extern struct {
220 host: IPv6,
221 port: u16,
222 };
223
224 /// Octets of a IPv6 address designating the local host.
225 pub const localhost_octets = [_]u8{0} ** 15 ++ [_]u8{0x01};
226
227 /// The IPv6 address of the local host.
228 pub const localhost: IPv6 = .{
229 .octets = localhost_octets,
230 .scope_id = no_scope_id,
231 };
232
233 /// Octets of an unspecified IPv6 address.
234 pub const unspecified_octets = [_]u8{0} ** 16;
235
236 /// An unspecified IPv6 address.
237 pub const unspecified: IPv6 = .{
238 .octets = unspecified_octets,
239 .scope_id = no_scope_id,
240 };
241
242 /// The prefix of a IPv6 address that is mapped to a IPv4 address.
243 pub const v4_mapped_prefix = [_]u8{0} ** 10 ++ [_]u8{0xFF} ** 2;
244
245 /// A marker value used to designate an IPv6 address with no
246 /// associated scope ID.
247 pub const no_scope_id = math.maxInt(u32);
248
249 octets: [16]u8,
250 scope_id: u32,
251
252 /// Returns whether or not the two addresses are equal to, less than, or
253 /// greater than each other.
254 pub fn cmp(self: IPv6, other: IPv6) math.Order {
255 return switch (mem.order(u8, self.octets, other.octets)) {
256 .eq => math.order(self.scope_id, other.scope_id),
257 else => |order| order,
258 };
259 }
260
261 /// Returns true if both addresses are semantically equivalent.
262 pub fn eql(self: IPv6, other: IPv6) bool {
263 return self.scope_id == other.scope_id and mem.eql(u8, &self.octets, &other.octets);
264 }
265
266 /// Returns true if the address is an unspecified IPv6 address.
267 pub fn isUnspecified(self: IPv6) bool {
268 return mem.eql(u8, &self.octets, &unspecified_octets);
269 }
270
271 /// Returns true if the address is a loopback address.
272 pub fn isLoopback(self: IPv6) bool {
273 return mem.eql(u8, self.octets[0..3], &[_]u8{ 0, 0, 0 }) and
274 mem.eql(u8, self.octets[12..], &[_]u8{ 0, 0, 0, 1 });
275 }
276
277 /// Returns true if the address maps to an IPv4 address.
278 pub fn mapsToIPv4(self: IPv6) bool {
279 return mem.startsWith(u8, &self.octets, &v4_mapped_prefix);
280 }
281
282 /// Returns an IPv4 address representative of the address should
283 /// it the address be mapped to an IPv4 address. It returns null
284 /// otherwise.
285 pub fn toIPv4(self: IPv6) ?IPv4 {
286 if (!self.mapsToIPv4()) return null;
287 return IPv4{ .octets = self.octets[12..][0..4].* };
288 }
289
290 /// Returns true if the address is a multicast IPv6 address.
291 pub fn isMulticast(self: IPv6) bool {
292 return self.octets[0] == 0xFF;
293 }
294
295 /// Returns true if the address is a unicast link local IPv6 address.
296 pub fn isLinkLocal(self: IPv6) bool {
297 return self.octets[0] == 0xFE and self.octets[1] & 0xC0 == 0x80;
298 }
299
300 /// Returns true if the address is a deprecated unicast site local
301 /// IPv6 address. Refer to IETF RFC 3879 for more details as to
302 /// why they are deprecated.
303 pub fn isSiteLocal(self: IPv6) bool {
304 return self.octets[0] == 0xFE and self.octets[1] & 0xC0 == 0xC0;
305 }
306
307 /// IPv6 multicast address scopes.
308 pub const Scope = enum(u8) {
309 interface = 1,
310 link = 2,
311 realm = 3,
312 admin = 4,
313 site = 5,
314 organization = 8,
315 global = 14,
316 unknown = 0xFF,
317 };
318
319 /// Returns the multicast scope of the address.
320 pub fn scope(self: IPv6) Scope {
321 if (!self.isMulticast()) return .unknown;
322
323 return switch (self.octets[0] & 0x0F) {
324 1 => .interface,
325 2 => .link,
326 3 => .realm,
327 4 => .admin,
328 5 => .site,
329 8 => .organization,
330 14 => .global,
331 else => .unknown,
332 };
333 }
334
335 /// Implements the `std.fmt.format` API. Specifying 'x' or 's' formats the
336 /// address lower-cased octets, while specifying 'X' or 'S' formats the
337 /// address using upper-cased ASCII octets.
338 ///
339 /// The default specifier is 'x'.
340 pub fn format(
341 self: IPv6,
342 comptime layout: []const u8,
343 opts: fmt.FormatOptions,
344 writer: anytype,
345 ) !void {
346 comptime const specifier = &[_]u8{if (layout.len == 0) 'x' else switch (layout[0]) {
347 'x', 'X' => |specifier| specifier,
348 's' => 'x',
349 'S' => 'X',
350 else => @compileError("Unsupported format specifier for IPv6 type '" ++ layout ++ "'."),
351 }};
352
353 if (mem.startsWith(u8, &self.octets, &v4_mapped_prefix)) {
354 return fmt.format(writer, "::{" ++ specifier ++ "}{" ++ specifier ++ "}:{}.{}.{}.{}", .{
355 0xFF,
356 0xFF,
357 self.octets[12],
358 self.octets[13],
359 self.octets[14],
360 self.octets[15],
361 });
362 }
363
364 const zero_span = span: {
365 var i: usize = 0;
366 while (i < self.octets.len) : (i += 2) {
367 if (self.octets[i] == 0 and self.octets[i + 1] == 0) break;
368 } else break :span .{ .from = 0, .to = 0 };
369
370 const from = i;
371
372 while (i < self.octets.len) : (i += 2) {
373 if (self.octets[i] != 0 or self.octets[i + 1] != 0) break;
374 }
375
376 break :span .{ .from = from, .to = i };
377 };
378
379 var i: usize = 0;
380 while (i != 16) : (i += 2) {
381 if (zero_span.from != zero_span.to and i == zero_span.from) {
382 try writer.writeAll("::");
383 } else if (i >= zero_span.from and i < zero_span.to) {} else {
384 if (i != 0 and i != zero_span.to) try writer.writeAll(":");
385
386 const val = @as(u16, self.octets[i]) << 8 | self.octets[i + 1];
387 try fmt.formatIntValue(val, specifier, .{}, writer);
388 }
389 }
390
391 if (self.scope_id != no_scope_id and self.scope_id != 0) {
392 try fmt.format(writer, "%{d}", .{self.scope_id});
393 }
394 }
395
396 /// Set of possible errors that may encountered when parsing an IPv6
397 /// address.
398 pub const ParseError = error{
399 MalformedV4Mapping,
400 BadScopeID,
401 } || IPv4.ParseError;
402
403 /// Parses an arbitrary IPv6 address, including link-local addresses.
404 pub fn parse(buf: []const u8) ParseError!IPv6 {
405 if (mem.lastIndexOfScalar(u8, buf, '%')) |index| {
406 const ip_slice = buf[0..index];
407 const scope_id_slice = buf[index + 1 ..];
408
409 if (scope_id_slice.len == 0) return error.BadScopeID;
410
411 const scope_id: u32 = switch (scope_id_slice[0]) {
412 '0'...'9' => fmt.parseInt(u32, scope_id_slice, 10),
413 else => resolveScopeID(scope_id_slice),
414 } catch return error.BadScopeID;
415
416 return parseWithScopeID(ip_slice, scope_id);
417 }
418
419 return parseWithScopeID(buf, no_scope_id);
420 }
421
422 /// Parses an IPv6 address with a pre-specified scope ID. Presumes
423 /// that the address is not a link-local address.
424 pub fn parseWithScopeID(buf: []const u8, scope_id: u32) ParseError!IPv6 {
425 var octets: [16]u8 = undefined;
426 var octet: u16 = 0;
427 var tail: [16]u8 = undefined;
428
429 var out: []u8 = &octets;
430 var index: u8 = 0;
431
432 var saw_any_digits: bool = false;
433 var abbrv: bool = false;
434
435 for (buf) |c, i| {
436 switch (c) {
437 ':' => {
438 if (!saw_any_digits) {
439 if (abbrv) return error.UnexpectedToken;
440 if (i != 0) abbrv = true;
441 mem.set(u8, out[index..], 0);
442 out = &tail;
443 index = 0;
444 continue;
445 }
446 if (index == 14) return error.TooManyOctets;
447
448 out[index] = @truncate(u8, octet >> 8);
449 index += 1;
450 out[index] = @truncate(u8, octet);
451 index += 1;
452
453 octet = 0;
454 saw_any_digits = false;
455 },
456 '.' => {
457 if (!abbrv or out[0] != 0xFF and out[1] != 0xFF) {
458 return error.MalformedV4Mapping;
459 }
460 const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1;
461 const v4 = try IPv4.parse(buf[start_index..]);
462 octets[10] = 0xFF;
463 octets[11] = 0xFF;
464 mem.copy(u8, octets[12..], &v4.octets);
465
466 return IPv6{ .octets = octets, .scope_id = scope_id };
467 },
468 else => {
469 saw_any_digits = true;
470 const digit = fmt.charToDigit(c, 16) catch return error.UnexpectedToken;
471 octet = math.mul(u16, octet, 16) catch return error.OctetOverflow;
472 octet = math.add(u16, octet, digit) catch return error.OctetOverflow;
473 },
474 }
475 }
476
477 if (!saw_any_digits and !abbrv) {
478 return error.IncompleteAddress;
479 }
480
481 if (index == 14) {
482 out[14] = @truncate(u8, octet >> 8);
483 out[15] = @truncate(u8, octet);
484 } else {
485 out[index] = @truncate(u8, octet >> 8);
486 index += 1;
487 out[index] = @truncate(u8, octet);
488 index += 1;
489 mem.copy(u8, octets[16 - index ..], out[0..index]);
490 }
491
492 return IPv6{ .octets = octets, .scope_id = scope_id };
493 }
494};
495
496test {
497 testing.refAllDecls(@This());
498}
499
500test "ip: convert to and from ipv6" {
501 try testing.expectFmt("::7f00:1", "{}", .{IPv4.localhost.toIPv6()});
502 testing.expect(!IPv4.localhost.toIPv6().mapsToIPv4());
503
504 try testing.expectFmt("::ffff:127.0.0.1", "{}", .{IPv4.localhost.mapToIPv6()});
505 testing.expect(IPv4.localhost.mapToIPv6().mapsToIPv4());
506
507 testing.expect(IPv4.localhost.toIPv6().toIPv4() == null);
508 try testing.expectFmt("127.0.0.1", "{}", .{IPv4.localhost.mapToIPv6().toIPv4()});
509}
510
511test "ipv4: parse & format" {
512 const cases = [_][]const u8{
513 "0.0.0.0",
514 "255.255.255.255",
515 "1.2.3.4",
516 "123.255.0.91",
517 "127.0.0.1",
518 };
519
520 for (cases) |case| {
521 try testing.expectFmt(case, "{}", .{try IPv4.parse(case)});
522 }
523}
524
525test "ipv6: parse & format" {
526 const inputs = [_][]const u8{
527 "FF01:0:0:0:0:0:0:FB",
528 "FF01::Fb",
529 "::1",
530 "::",
531 "2001:db8::",
532 "::1234:5678",
533 "2001:db8::1234:5678",
534 "::ffff:123.5.123.5",
535 };
536
537 const outputs = [_][]const u8{
538 "ff01::fb",
539 "ff01::fb",
540 "::1",
541 "::",
542 "2001:db8::",
543 "::1234:5678",
544 "2001:db8::1234:5678",
545 "::ffff:123.5.123.5",
546 };
547
548 for (inputs) |input, i| {
549 try testing.expectFmt(outputs[i], "{}", .{try IPv6.parse(input)});
550 }
551}
552
553test "ipv6: parse & format addresses with scope ids" {
554 if (!@hasDecl(os, "IFNAMESIZE")) return error.SkipZigTest;
555
556 const inputs = [_][]const u8{
557 "FF01::FB%lo",
558 };
559
560 const outputs = [_][]const u8{
561 "ff01::fb%1",
562 };
563
564 for (inputs) |input, i| {
565 try testing.expectFmt(outputs[i], "{}", .{try IPv6.parse(input)});
566 }
567}
lib/std/x/os/os.zig deleted-9
...@@ -1,9 +0,0 @@
1const std = @import("../../std.zig");
2
3const testing = std.testing;
4
5pub const Socket = @import("Socket.zig");
6
7test {
8 testing.refAllDecls(@This());
9}
lib/std/zig/ast.zig+13-7
...@@ -1979,20 +1979,26 @@ pub const Tree = struct {...@@ -1979,20 +1979,26 @@ pub const Tree = struct {
1979 // asm ("foo" :: [_] "" (y) : "a", "b");1979 // asm ("foo" :: [_] "" (y) : "a", "b");
1980 const last_input = result.inputs[result.inputs.len - 1];1980 const last_input = result.inputs[result.inputs.len - 1];
1981 const rparen = tree.lastToken(last_input);1981 const rparen = tree.lastToken(last_input);
1982 if (token_tags[rparen + 1] == .colon and1982 var i = rparen + 1;
1983 token_tags[rparen + 2] == .string_literal)1983 // Allow a (useless) comma right after the closing parenthesis.
1984 if (token_tags[i] == .comma) i += 1;
1985 if (token_tags[i] == .colon and
1986 token_tags[i + 1] == .string_literal)
1984 {1987 {
1985 result.first_clobber = rparen + 2;1988 result.first_clobber = i + 1;
1986 }1989 }
1987 } else {1990 } else {
1988 // asm ("foo" : [_] "" (x) :: "a", "b");1991 // asm ("foo" : [_] "" (x) :: "a", "b");
1989 const last_output = result.outputs[result.outputs.len - 1];1992 const last_output = result.outputs[result.outputs.len - 1];
1990 const rparen = tree.lastToken(last_output);1993 const rparen = tree.lastToken(last_output);
1991 if (token_tags[rparen + 1] == .colon and1994 var i = rparen + 1;
1992 token_tags[rparen + 2] == .colon and1995 // Allow a (useless) comma right after the closing parenthesis.
1993 token_tags[rparen + 3] == .string_literal)1996 if (token_tags[i] == .comma) i += 1;
1997 if (token_tags[i] == .colon and
1998 token_tags[i + 1] == .colon and
1999 token_tags[i + 2] == .string_literal)
1994 {2000 {
1995 result.first_clobber = rparen + 3;2001 result.first_clobber = i + 2;
1996 }2002 }
1997 }2003 }
19982004
lib/std/zig/parser_test.zig+32
...@@ -4,6 +4,38 @@...@@ -4,6 +4,38 @@
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
66
7test "zig fmt: preserves clobbers in inline asm with stray comma" {
8 try testTransform(
9 \\fn foo() void {
10 \\ asm volatile (""
11 \\ : [_] "" (-> type),
12 \\ :
13 \\ : "clobber"
14 \\ );
15 \\ asm volatile (""
16 \\ :
17 \\ : [_] "" (type),
18 \\ : "clobber"
19 \\ );
20 \\}
21 \\
22 ,
23 \\fn foo() void {
24 \\ asm volatile (""
25 \\ : [_] "" (-> type)
26 \\ :
27 \\ : "clobber"
28 \\ );
29 \\ asm volatile (""
30 \\ :
31 \\ : [_] "" (type)
32 \\ : "clobber"
33 \\ );
34 \\}
35 \\
36 );
37}
38
7test "zig fmt: respect line breaks in struct field value declaration" {39test "zig fmt: respect line breaks in struct field value declaration" {
8 try testCanonical(40 try testCanonical(
9 \\const Foo = struct {41 \\const Foo = struct {
lib/std/zig/system/linux.zig+276-7
...@@ -53,7 +53,7 @@ const SparcCpuinfoImpl = struct {...@@ -53,7 +53,7 @@ const SparcCpuinfoImpl = struct {
53 // At the moment we only support 64bit SPARC systems.53 // At the moment we only support 64bit SPARC systems.
54 assert(self.is_64bit);54 assert(self.is_64bit);
5555
56 const model = self.model orelse Target.Cpu.Model.generic(arch);56 const model = self.model orelse return null;
57 return Target.Cpu{57 return Target.Cpu{
58 .arch = arch,58 .arch = arch,
59 .model = model,59 .model = model,
...@@ -65,7 +65,7 @@ const SparcCpuinfoImpl = struct {...@@ -65,7 +65,7 @@ const SparcCpuinfoImpl = struct {
65const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);65const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);
6666
67test "cpuinfo: SPARC" {67test "cpuinfo: SPARC" {
68 try testParser(SparcCpuinfoParser, &Target.sparc.cpu.niagara2,68 try testParser(SparcCpuinfoParser, .sparcv9, &Target.sparc.cpu.niagara2,
69 \\cpu : UltraSparc T2 (Niagara2)69 \\cpu : UltraSparc T2 (Niagara2)
70 \\fpu : UltraSparc T2 integrated FPU70 \\fpu : UltraSparc T2 integrated FPU
71 \\pmu : niagara271 \\pmu : niagara2
...@@ -119,7 +119,7 @@ const PowerpcCpuinfoImpl = struct {...@@ -119,7 +119,7 @@ const PowerpcCpuinfoImpl = struct {
119 }119 }
120120
121 fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {121 fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
122 const model = self.model orelse Target.Cpu.Model.generic(arch);122 const model = self.model orelse return null;
123 return Target.Cpu{123 return Target.Cpu{
124 .arch = arch,124 .arch = arch,
125 .model = model,125 .model = model,
...@@ -131,13 +131,13 @@ const PowerpcCpuinfoImpl = struct {...@@ -131,13 +131,13 @@ const PowerpcCpuinfoImpl = struct {
131const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl);131const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl);
132132
133test "cpuinfo: PowerPC" {133test "cpuinfo: PowerPC" {
134 try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.@"970",134 try testParser(PowerpcCpuinfoParser, .powerpc, &Target.powerpc.cpu.@"970",
135 \\processor : 0135 \\processor : 0
136 \\cpu : PPC970MP, altivec supported136 \\cpu : PPC970MP, altivec supported
137 \\clock : 1250.000000MHz137 \\clock : 1250.000000MHz
138 \\revision : 1.1 (pvr 0044 0101)138 \\revision : 1.1 (pvr 0044 0101)
139 );139 );
140 try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.pwr8,140 try testParser(PowerpcCpuinfoParser, .powerpc64le, &Target.powerpc.cpu.pwr8,
141 \\processor : 0141 \\processor : 0
142 \\cpu : POWER8 (raw), altivec supported142 \\cpu : POWER8 (raw), altivec supported
143 \\clock : 2926.000000MHz143 \\clock : 2926.000000MHz
...@@ -145,9 +145,275 @@ test "cpuinfo: PowerPC" {...@@ -145,9 +145,275 @@ test "cpuinfo: PowerPC" {
145 );145 );
146}146}
147147
148fn testParser(parser: anytype, expected_model: *const Target.Cpu.Model, input: []const u8) !void {148const ArmCpuinfoImpl = struct {
149 cores: [4]CoreInfo = undefined,
150 core_no: usize = 0,
151 have_fields: usize = 0,
152
153 const CoreInfo = struct {
154 architecture: u8 = 0,
155 implementer: u8 = 0,
156 variant: u8 = 0,
157 part: u16 = 0,
158 is_really_v6: bool = false,
159 };
160
161 const cpu_models = struct {
162 // Shorthands to simplify the tables below.
163 const A32 = Target.arm.cpu;
164 const A64 = Target.aarch64.cpu;
165
166 const E = struct {
167 part: u16,
168 variant: ?u8 = null, // null if matches any variant
169 m32: ?*const Target.Cpu.Model = null,
170 m64: ?*const Target.Cpu.Model = null,
171 };
172
173 // implementer = 0x41
174 const ARM = [_]E{
175 E{ .part = 0x926, .m32 = &A32.arm926ej_s, .m64 = null },
176 E{ .part = 0xb02, .m32 = &A32.mpcore, .m64 = null },
177 E{ .part = 0xb36, .m32 = &A32.arm1136j_s, .m64 = null },
178 E{ .part = 0xb56, .m32 = &A32.arm1156t2_s, .m64 = null },
179 E{ .part = 0xb76, .m32 = &A32.arm1176jz_s, .m64 = null },
180 E{ .part = 0xc05, .m32 = &A32.cortex_a5, .m64 = null },
181 E{ .part = 0xc07, .m32 = &A32.cortex_a7, .m64 = null },
182 E{ .part = 0xc08, .m32 = &A32.cortex_a8, .m64 = null },
183 E{ .part = 0xc09, .m32 = &A32.cortex_a9, .m64 = null },
184 E{ .part = 0xc0d, .m32 = &A32.cortex_a17, .m64 = null },
185 E{ .part = 0xc0f, .m32 = &A32.cortex_a15, .m64 = null },
186 E{ .part = 0xc0e, .m32 = &A32.cortex_a17, .m64 = null },
187 E{ .part = 0xc14, .m32 = &A32.cortex_r4, .m64 = null },
188 E{ .part = 0xc15, .m32 = &A32.cortex_r5, .m64 = null },
189 E{ .part = 0xc17, .m32 = &A32.cortex_r7, .m64 = null },
190 E{ .part = 0xc18, .m32 = &A32.cortex_r8, .m64 = null },
191 E{ .part = 0xc20, .m32 = &A32.cortex_m0, .m64 = null },
192 E{ .part = 0xc21, .m32 = &A32.cortex_m1, .m64 = null },
193 E{ .part = 0xc23, .m32 = &A32.cortex_m3, .m64 = null },
194 E{ .part = 0xc24, .m32 = &A32.cortex_m4, .m64 = null },
195 E{ .part = 0xc27, .m32 = &A32.cortex_m7, .m64 = null },
196 E{ .part = 0xc60, .m32 = &A32.cortex_m0plus, .m64 = null },
197 E{ .part = 0xd01, .m32 = &A32.cortex_a32, .m64 = null },
198 E{ .part = 0xd03, .m32 = &A32.cortex_a53, .m64 = &A64.cortex_a53 },
199 E{ .part = 0xd04, .m32 = &A32.cortex_a35, .m64 = &A64.cortex_a35 },
200 E{ .part = 0xd05, .m32 = &A32.cortex_a55, .m64 = &A64.cortex_a55 },
201 E{ .part = 0xd07, .m32 = &A32.cortex_a57, .m64 = &A64.cortex_a57 },
202 E{ .part = 0xd08, .m32 = &A32.cortex_a72, .m64 = &A64.cortex_a72 },
203 E{ .part = 0xd09, .m32 = &A32.cortex_a73, .m64 = &A64.cortex_a73 },
204 E{ .part = 0xd0a, .m32 = &A32.cortex_a75, .m64 = &A64.cortex_a75 },
205 E{ .part = 0xd0b, .m32 = &A32.cortex_a76, .m64 = &A64.cortex_a76 },
206 E{ .part = 0xd0c, .m32 = &A32.neoverse_n1, .m64 = null },
207 E{ .part = 0xd0d, .m32 = &A32.cortex_a77, .m64 = &A64.cortex_a77 },
208 E{ .part = 0xd13, .m32 = &A32.cortex_r52, .m64 = null },
209 E{ .part = 0xd20, .m32 = &A32.cortex_m23, .m64 = null },
210 E{ .part = 0xd21, .m32 = &A32.cortex_m33, .m64 = null },
211 E{ .part = 0xd41, .m32 = &A32.cortex_a78, .m64 = &A64.cortex_a78 },
212 E{ .part = 0xd4b, .m32 = &A32.cortex_a78c, .m64 = &A64.cortex_a78c },
213 E{ .part = 0xd44, .m32 = &A32.cortex_x1, .m64 = &A64.cortex_x1 },
214 E{ .part = 0xd02, .m64 = &A64.cortex_a34 },
215 E{ .part = 0xd06, .m64 = &A64.cortex_a65 },
216 E{ .part = 0xd43, .m64 = &A64.cortex_a65ae },
217 };
218 // implementer = 0x42
219 const Broadcom = [_]E{
220 E{ .part = 0x516, .m64 = &A64.thunderx2t99 },
221 };
222 // implementer = 0x43
223 const Cavium = [_]E{
224 E{ .part = 0x0a0, .m64 = &A64.thunderx },
225 E{ .part = 0x0a2, .m64 = &A64.thunderxt81 },
226 E{ .part = 0x0a3, .m64 = &A64.thunderxt83 },
227 E{ .part = 0x0a1, .m64 = &A64.thunderxt88 },
228 E{ .part = 0x0af, .m64 = &A64.thunderx2t99 },
229 };
230 // implementer = 0x46
231 const Fujitsu = [_]E{
232 E{ .part = 0x001, .m64 = &A64.a64fx },
233 };
234 // implementer = 0x48
235 const HiSilicon = [_]E{
236 E{ .part = 0xd01, .m64 = &A64.tsv110 },
237 };
238 // implementer = 0x4e
239 const Nvidia = [_]E{
240 E{ .part = 0x004, .m64 = &A64.carmel },
241 };
242 // implementer = 0x50
243 const Ampere = [_]E{
244 E{ .part = 0x000, .variant = 3, .m64 = &A64.emag },
245 E{ .part = 0x000, .m64 = &A64.xgene1 },
246 };
247 // implementer = 0x51
248 const Qualcomm = [_]E{
249 E{ .part = 0x06f, .m32 = &A32.krait },
250 E{ .part = 0x201, .m64 = &A64.kryo, .m32 = &A64.kryo },
251 E{ .part = 0x205, .m64 = &A64.kryo, .m32 = &A64.kryo },
252 E{ .part = 0x211, .m64 = &A64.kryo, .m32 = &A64.kryo },
253 E{ .part = 0x800, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
254 E{ .part = 0x801, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
255 E{ .part = 0x802, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
256 E{ .part = 0x803, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
257 E{ .part = 0x804, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
258 E{ .part = 0x805, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
259 E{ .part = 0xc00, .m64 = &A64.falkor },
260 E{ .part = 0xc01, .m64 = &A64.saphira },
261 };
262
263 fn isKnown(core: CoreInfo, is_64bit: bool) ?*const Target.Cpu.Model {
264 const models = switch (core.implementer) {
265 0x41 => &ARM,
266 0x42 => &Broadcom,
267 0x43 => &Cavium,
268 0x46 => &Fujitsu,
269 0x48 => &HiSilicon,
270 0x50 => &Ampere,
271 0x51 => &Qualcomm,
272 else => return null,
273 };
274
275 for (models) |model| {
276 if (model.part == core.part and
277 (model.variant == null or model.variant.? == core.variant))
278 return if (is_64bit) model.m64 else model.m32;
279 }
280
281 return null;
282 }
283 };
284
285 fn addOne(self: *ArmCpuinfoImpl) void {
286 if (self.have_fields == 4 and self.core_no < self.cores.len) {
287 if (self.core_no > 0) {
288 // Deduplicate the core info.
289 for (self.cores[0..self.core_no]) |it| {
290 if (std.meta.eql(it, self.cores[self.core_no]))
291 return;
292 }
293 }
294 self.core_no += 1;
295 }
296 }
297
298 fn line_hook(self: *ArmCpuinfoImpl, key: []const u8, value: []const u8) !bool {
299 const info = &self.cores[self.core_no];
300
301 if (mem.eql(u8, key, "processor")) {
302 // Handle both old-style and new-style cpuinfo formats.
303 // The former prints a sequence of "processor: N" lines for each
304 // core and then the info for the core that's executing this code(!)
305 // while the latter prints the infos for each core right after the
306 // "processor" key.
307 self.have_fields = 0;
308 self.cores[self.core_no] = .{};
309 } else if (mem.eql(u8, key, "CPU implementer")) {
310 info.implementer = try fmt.parseInt(u8, value, 0);
311 self.have_fields += 1;
312 } else if (mem.eql(u8, key, "CPU architecture")) {
313 // "AArch64" on older kernels.
314 info.architecture = if (mem.startsWith(u8, value, "AArch64"))
315 8
316 else
317 try fmt.parseInt(u8, value, 0);
318 self.have_fields += 1;
319 } else if (mem.eql(u8, key, "CPU variant")) {
320 info.variant = try fmt.parseInt(u8, value, 0);
321 self.have_fields += 1;
322 } else if (mem.eql(u8, key, "CPU part")) {
323 info.part = try fmt.parseInt(u16, value, 0);
324 self.have_fields += 1;
325 } else if (mem.eql(u8, key, "model name")) {
326 // ARMv6 cores report "CPU architecture" equal to 7.
327 if (mem.indexOf(u8, value, "(v6l)")) |_| {
328 info.is_really_v6 = true;
329 }
330 } else if (mem.eql(u8, key, "CPU revision")) {
331 // This field is always the last one for each CPU section.
332 _ = self.addOne();
333 }
334
335 return true;
336 }
337
338 fn finalize(self: *ArmCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
339 if (self.core_no == 0) return null;
340
341 const is_64bit = switch (arch) {
342 .aarch64, .aarch64_be, .aarch64_32 => true,
343 else => false,
344 };
345
346 var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined;
347 for (self.cores[0..self.core_no]) |core, i| {
348 known_models[i] = cpu_models.isKnown(core, is_64bit);
349 }
350
351 // XXX We pick the first core on big.LITTLE systems, hopefully the
352 // LITTLE one.
353 const model = known_models[0] orelse return null;
354 return Target.Cpu{
355 .arch = arch,
356 .model = model,
357 .features = model.features,
358 };
359 }
360};
361
362const ArmCpuinfoParser = CpuinfoParser(ArmCpuinfoImpl);
363
364test "cpuinfo: ARM" {
365 try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.arm1176jz_s,
366 \\processor : 0
367 \\model name : ARMv6-compatible processor rev 7 (v6l)
368 \\BogoMIPS : 997.08
369 \\Features : half thumb fastmult vfp edsp java tls
370 \\CPU implementer : 0x41
371 \\CPU architecture: 7
372 \\CPU variant : 0x0
373 \\CPU part : 0xb76
374 \\CPU revision : 7
375 );
376 try testParser(ArmCpuinfoParser, .arm, &Target.arm.cpu.cortex_a7,
377 \\processor : 0
378 \\model name : ARMv7 Processor rev 3 (v7l)
379 \\BogoMIPS : 18.00
380 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
381 \\CPU implementer : 0x41
382 \\CPU architecture: 7
383 \\CPU variant : 0x0
384 \\CPU part : 0xc07
385 \\CPU revision : 3
386 \\
387 \\processor : 4
388 \\model name : ARMv7 Processor rev 3 (v7l)
389 \\BogoMIPS : 90.00
390 \\Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
391 \\CPU implementer : 0x41
392 \\CPU architecture: 7
393 \\CPU variant : 0x2
394 \\CPU part : 0xc0f
395 \\CPU revision : 3
396 );
397 try testParser(ArmCpuinfoParser, .aarch64, &Target.aarch64.cpu.cortex_a72,
398 \\processor : 0
399 \\BogoMIPS : 108.00
400 \\Features : fp asimd evtstrm crc32 cpuid
401 \\CPU implementer : 0x41
402 \\CPU architecture: 8
403 \\CPU variant : 0x0
404 \\CPU part : 0xd08
405 \\CPU revision : 3
406 );
407}
408
409fn testParser(
410 parser: anytype,
411 arch: Target.Cpu.Arch,
412 expected_model: *const Target.Cpu.Model,
413 input: []const u8,
414) !void {
149 var fbs = io.fixedBufferStream(input);415 var fbs = io.fixedBufferStream(input);
150 const result = try parser.parse(.powerpc, fbs.reader());416 const result = try parser.parse(arch, fbs.reader());
151 testing.expectEqual(expected_model, result.?.model);417 testing.expectEqual(expected_model, result.?.model);
152 testing.expect(expected_model.features.eql(result.?.features));418 testing.expect(expected_model.features.eql(result.?.features));
153}419}
...@@ -186,6 +452,9 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {...@@ -186,6 +452,9 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
186452
187 const current_arch = std.Target.current.cpu.arch;453 const current_arch = std.Target.current.cpu.arch;
188 switch (current_arch) {454 switch (current_arch) {
455 .arm, .armeb, .thumb, .thumbeb, .aarch64, .aarch64_be, .aarch64_32 => {
456 return ArmCpuinfoParser.parse(current_arch, f.reader()) catch null;
457 },
189 .sparcv9 => {458 .sparcv9 => {
190 return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null;459 return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null;
191 },460 },
src/Compilation.zig-1
...@@ -239,7 +239,6 @@ pub const CObject = struct {...@@ -239,7 +239,6 @@ pub const CObject = struct {
239 pub fn destroy(em: *ErrorMsg, gpa: *Allocator) void {239 pub fn destroy(em: *ErrorMsg, gpa: *Allocator) void {
240 gpa.free(em.msg);240 gpa.free(em.msg);
241 gpa.destroy(em);241 gpa.destroy(em);
242 em.* = undefined;
243 }242 }
244 };243 };
245244
src/link/MachO/Object.zig+80-98
...@@ -43,17 +43,13 @@ dwarf_debug_str_index: ?u16 = null,...@@ -43,17 +43,13 @@ dwarf_debug_str_index: ?u16 = null,
43dwarf_debug_line_index: ?u16 = null,43dwarf_debug_line_index: ?u16 = null,
44dwarf_debug_ranges_index: ?u16 = null,44dwarf_debug_ranges_index: ?u16 = null,
4545
46symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},46symbols: std.ArrayListUnmanaged(*Symbol) = .{},
47strtab: std.ArrayListUnmanaged(u8) = .{},47initializers: std.ArrayListUnmanaged(*Symbol) = .{},
48data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
4849
49locals: std.StringArrayHashMapUnmanaged(Symbol) = .{},
50stabs: std.ArrayListUnmanaged(Stab) = .{},
51tu_path: ?[]const u8 = null,50tu_path: ?[]const u8 = null,
52tu_mtime: ?u64 = null,51tu_mtime: ?u64 = null,
5352
54initializers: std.ArrayListUnmanaged(CppStatic) = .{},
55data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
56
57pub const Section = struct {53pub const Section = struct {
58 inner: macho.section_64,54 inner: macho.section_64,
59 code: []u8,55 code: []u8,
...@@ -71,23 +67,6 @@ pub const Section = struct {...@@ -71,23 +67,6 @@ pub const Section = struct {
71 }67 }
72};68};
7369
74const CppStatic = struct {
75 symbol: u32,
76 target_addr: u64,
77};
78
79const Stab = struct {
80 tag: Tag,
81 symbol: u32,
82 size: ?u64 = null,
83
84 const Tag = enum {
85 function,
86 global,
87 static,
88 };
89};
90
91const DebugInfo = struct {70const DebugInfo = struct {
92 inner: dwarf.DwarfInfo,71 inner: dwarf.DwarfInfo,
93 debug_info: []u8,72 debug_info: []u8,
...@@ -169,14 +148,12 @@ pub fn deinit(self: *Object) void {...@@ -169,14 +148,12 @@ pub fn deinit(self: *Object) void {
169 }148 }
170 self.sections.deinit(self.allocator);149 self.sections.deinit(self.allocator);
171150
172 for (self.locals.items()) |*entry| {151 for (self.symbols.items) |sym| {
173 entry.value.deinit(self.allocator);152 sym.deinit(self.allocator);
153 self.allocator.destroy(sym);
174 }154 }
175 self.locals.deinit(self.allocator);155 self.symbols.deinit(self.allocator);
176156
177 self.symtab.deinit(self.allocator);
178 self.strtab.deinit(self.allocator);
179 self.stabs.deinit(self.allocator);
180 self.data_in_code_entries.deinit(self.allocator);157 self.data_in_code_entries.deinit(self.allocator);
181 self.initializers.deinit(self.allocator);158 self.initializers.deinit(self.allocator);
182159
...@@ -222,9 +199,9 @@ pub fn parse(self: *Object) !void {...@@ -222,9 +199,9 @@ pub fn parse(self: *Object) !void {
222 }199 }
223200
224 try self.readLoadCommands(reader);201 try self.readLoadCommands(reader);
202 try self.parseSymbols();
225 try self.parseSections();203 try self.parseSections();
226 if (self.symtab_cmd_index != null) try self.parseSymtab();204 try self.parseDataInCode();
227 if (self.data_in_code_cmd_index != null) try self.readDataInCode();
228 try self.parseInitializers();205 try self.parseInitializers();
229 try self.parseDebugInfo();206 try self.parseDebugInfo();
230}207}
...@@ -298,9 +275,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {...@@ -298,9 +275,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
298}275}
299276
300pub fn parseSections(self: *Object) !void {277pub fn parseSections(self: *Object) !void {
301 log.debug("parsing sections in {s}", .{self.name.?});
302 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;278 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
303279
280 log.debug("parsing sections in {s}", .{self.name.?});
281
304 try self.sections.ensureCapacity(self.allocator, seg.sections.items.len);282 try self.sections.ensureCapacity(self.allocator, seg.sections.items.len);
305283
306 for (seg.sections.items) |sect| {284 for (seg.sections.items) |sect| {
...@@ -327,6 +305,7 @@ pub fn parseSections(self: *Object) !void {...@@ -327,6 +305,7 @@ pub fn parseSections(self: *Object) !void {
327 self.arch.?,305 self.arch.?,
328 section.code,306 section.code,
329 mem.bytesAsSlice(macho.relocation_info, raw_relocs),307 mem.bytesAsSlice(macho.relocation_info, raw_relocs),
308 self.symbols.items,
330 );309 );
331 }310 }
332311
...@@ -344,60 +323,70 @@ pub fn parseInitializers(self: *Object) !void {...@@ -344,60 +323,70 @@ pub fn parseInitializers(self: *Object) !void {
344 const relocs = section.relocs orelse unreachable;323 const relocs = section.relocs orelse unreachable;
345 try self.initializers.ensureCapacity(self.allocator, relocs.len);324 try self.initializers.ensureCapacity(self.allocator, relocs.len);
346 for (relocs) |rel| {325 for (relocs) |rel| {
347 self.initializers.appendAssumeCapacity(.{326 self.initializers.appendAssumeCapacity(rel.target.symbol);
348 .symbol = rel.target.symbol,
349 .target_addr = undefined,
350 });
351 }327 }
352328
353 mem.reverse(CppStatic, self.initializers.items);329 mem.reverse(*Symbol, self.initializers.items);
354
355 for (self.initializers.items) |initializer| {
356 const sym = self.symtab.items[initializer.symbol];
357 const sym_name = self.getString(sym.n_strx);
358 log.debug(" | {s}", .{sym_name});
359 }
360}330}
361331
362pub fn parseSymtab(self: *Object) !void {332pub fn parseSymbols(self: *Object) !void {
363 const symtab_cmd = self.load_commands.items[self.symtab_cmd_index.?].Symtab;333 const index = self.symtab_cmd_index orelse return;
334 const symtab_cmd = self.load_commands.items[index].Symtab;
364335
365 var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);336 var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
366 defer self.allocator.free(symtab);337 defer self.allocator.free(symtab);
367
368 _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff);338 _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff);
369 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));339 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
370 try self.symtab.appendSlice(self.allocator, slice);
371340
372 var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);341 var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);
373 defer self.allocator.free(strtab);342 defer self.allocator.free(strtab);
374
375 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);343 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);
376 try self.strtab.appendSlice(self.allocator, strtab);
377344
378 for (self.symtab.items) |sym, sym_id| {345 for (slice) |sym| {
379 if (Symbol.isStab(sym) or Symbol.isUndef(sym)) continue;346 if (Symbol.isStab(sym)) {
347 log.err("TODO handle stabs embedded within object files", .{});
348 return error.HandleStabsInObjects;
349 }
380350
381 const sym_name = self.getString(sym.n_strx);351 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
382 const tag: Symbol.Tag = tag: {352 const name = try self.allocator.dupe(u8, sym_name);
383 if (Symbol.isLocal(sym)) {353
384 if (self.arch.? == .aarch64 and mem.startsWith(u8, sym_name, "l")) continue;354 const symbol: *Symbol = symbol: {
385 break :tag .local;355 if (Symbol.isSect(sym)) {
386 }356 const linkage: Symbol.Regular.Linkage = linkage: {
387 if (Symbol.isWeakDef(sym)) {357 if (!Symbol.isExt(sym)) break :linkage .translation_unit;
388 break :tag .weak;358 if (Symbol.isWeakDef(sym) or Symbol.isPext(sym)) break :linkage .linkage_unit;
359 break :linkage .global;
360 };
361 const regular = try self.allocator.create(Symbol.Regular);
362 errdefer self.allocator.destroy(regular);
363 regular.* = .{
364 .base = .{
365 .@"type" = .regular,
366 .name = name,
367 },
368 .linkage = linkage,
369 .address = sym.n_value,
370 .section = sym.n_sect - 1,
371 .weak_ref = Symbol.isWeakRef(sym),
372 .file = self,
373 };
374 break :symbol &regular.base;
389 }375 }
390 break :tag .strong;376
377 const undef = try self.allocator.create(Symbol.Unresolved);
378 errdefer self.allocator.destroy(undef);
379 undef.* = .{
380 .base = .{
381 .@"type" = .unresolved,
382 .name = name,
383 },
384 .file = self,
385 };
386 break :symbol &undef.base;
391 };387 };
392 const name = try self.allocator.dupe(u8, sym_name);
393388
394 try self.locals.putNoClobber(self.allocator, name, .{389 try self.symbols.append(self.allocator, symbol);
395 .tag = tag,
396 .name = name,
397 .address = 0,
398 .section = 0,
399 .index = @intCast(u32, sym_id),
400 });
401 }390 }
402}391}
403392
...@@ -429,38 +418,31 @@ pub fn parseDebugInfo(self: *Object) !void {...@@ -429,38 +418,31 @@ pub fn parseDebugInfo(self: *Object) !void {
429 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));418 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
430 };419 };
431420
432 for (self.locals.items()) |entry, index| {421 for (self.symbols.items) |sym| {
433 const local = entry.value;422 if (sym.cast(Symbol.Regular)) |reg| {
434 const source_sym = self.symtab.items[local.index.?];423 const size: u64 = blk: for (debug_info.inner.func_list.items) |func| {
435 const size = blk: for (debug_info.inner.func_list.items) |func| {424 if (func.pc_range) |range| {
436 if (func.pc_range) |range| {425 if (reg.address >= range.start and reg.address < range.end) {
437 if (source_sym.n_value >= range.start and source_sym.n_value < range.end) {426 break :blk range.end - range.start;
438 break :blk range.end - range.start;427 }
439 }428 }
440 }429 } else 0;
441 } else null;430
442 const tag: Stab.Tag = tag: {431 reg.stab = .{
443 if (size != null) break :tag .function;432 .kind = kind: {
444 switch (local.tag) {433 if (size > 0) break :kind .function;
445 .weak, .strong => break :tag .global,434 switch (reg.linkage) {
446 else => break :tag .static,435 .translation_unit => break :kind .static,
447 }436 else => break :kind .global,
448 };437 }
449438 },
450 try self.stabs.append(self.allocator, .{439 .size = size,
451 .tag = tag,440 };
452 .size = size,441 }
453 .symbol = @intCast(u32, index),
454 });
455 }442 }
456}443}
457444
458pub fn getString(self: *const Object, str_off: u32) []const u8 {445fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
459 assert(str_off < self.strtab.items.len);
460 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off));
461}
462
463pub fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
464 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;446 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
465 const sect = seg.sections.items[index];447 const sect = seg.sections.items[index];
466 var buffer = try allocator.alloc(u8, sect.size);448 var buffer = try allocator.alloc(u8, sect.size);
...@@ -468,7 +450,7 @@ pub fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {...@@ -468,7 +450,7 @@ pub fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
468 return buffer;450 return buffer;
469}451}
470452
471pub fn readDataInCode(self: *Object) !void {453pub fn parseDataInCode(self: *Object) !void {
472 const index = self.data_in_code_cmd_index orelse return;454 const index = self.data_in_code_cmd_index orelse return;
473 const data_in_code = self.load_commands.items[index].LinkeditData;455 const data_in_code = self.load_commands.items[index].LinkeditData;
474456
src/link/MachO/Symbol.zig+101-30
...@@ -2,31 +2,113 @@ const Symbol = @This();...@@ -2,31 +2,113 @@ const Symbol = @This();
22
3const std = @import("std");3const std = @import("std");
4const macho = std.macho;4const macho = std.macho;
5const mem = std.mem;
56
6const Allocator = std.mem.Allocator;7const Allocator = mem.Allocator;
8const Object = @import("Object.zig");
79
8pub const Tag = enum {10pub const Type = enum {
9 local,11 regular,
10 weak,12 proxy,
11 strong,13 unresolved,
12 import,
13 undef,
14};14};
1515
16tag: Tag,16/// Symbol type.
17@"type": Type,
18
19/// Symbol name. Owned slice.
17name: []u8,20name: []u8,
18address: u64,
19section: u8,
2021
21/// Index of file where to locate this symbol.22/// Alias of.
22/// Depending on context, this is either an object file, or a dylib.23alias: ?*Symbol = null,
23file: ?u16 = null,24
25/// Index in GOT table for indirection.
26got_index: ?u32 = null,
27
28/// Index in stubs table for late binding.
29stubs_index: ?u32 = null,
30
31pub const Regular = struct {
32 base: Symbol,
33
34 /// Linkage type.
35 linkage: Linkage,
36
37 /// Symbol address.
38 address: u64,
39
40 /// Section ID where the symbol resides.
41 section: u8,
42
43 /// Whether the symbol is a weak ref.
44 weak_ref: bool,
45
46 /// File where to locate this symbol.
47 file: *Object,
48
49 /// Debug stab if defined.
50 stab: ?struct {
51 /// Stab kind
52 kind: enum {
53 function,
54 global,
55 static,
56 },
57
58 /// Size of the stab.
59 size: u64,
60 } = null,
61
62 pub const base_type: Symbol.Type = .regular;
63
64 pub const Linkage = enum {
65 translation_unit,
66 linkage_unit,
67 global,
68 };
69
70 pub fn isTemp(regular: *Regular) bool {
71 if (regular.linkage == .translation_unit) {
72 return mem.startsWith(u8, regular.base.name, "l") or mem.startsWith(u8, regular.base.name, "L");
73 }
74 return false;
75 }
76};
77
78pub const Proxy = struct {
79 base: Symbol,
80
81 /// Dylib ordinal.
82 dylib: u16,
83
84 pub const base_type: Symbol.Type = .proxy;
85};
86
87pub const Unresolved = struct {
88 base: Symbol,
89
90 /// File where this symbol was referenced.
91 file: *Object,
2492
25/// Index of this symbol within the file's symbol table.93 pub const base_type: Symbol.Type = .unresolved;
26index: ?u32 = null,94};
2795
28pub fn deinit(self: *Symbol, allocator: *Allocator) void {96pub fn deinit(base: *Symbol, allocator: *Allocator) void {
29 allocator.free(self.name);97 allocator.free(base.name);
98}
99
100pub fn cast(base: *Symbol, comptime T: type) ?*T {
101 if (base.@"type" != T.base_type) {
102 return null;
103 }
104 return @fieldParentPtr(T, "base", base);
105}
106
107pub fn getTopmostAlias(base: *Symbol) *Symbol {
108 if (base.alias) |alias| {
109 return alias.getTopmostAlias();
110 }
111 return base;
30}112}
31113
32pub fn isStab(sym: macho.nlist_64) bool {114pub fn isStab(sym: macho.nlist_64) bool {
...@@ -55,17 +137,6 @@ pub fn isWeakDef(sym: macho.nlist_64) bool {...@@ -55,17 +137,6 @@ pub fn isWeakDef(sym: macho.nlist_64) bool {
55 return (sym.n_desc & macho.N_WEAK_DEF) != 0;137 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
56}138}
57139
58/// Symbol is local if it is defined and not an extern.140pub fn isWeakRef(sym: macho.nlist_64) bool {
59pub fn isLocal(sym: macho.nlist_64) bool {141 return (sym.n_desc & macho.N_WEAK_REF) != 0;
60 return isSect(sym) and !isExt(sym);
61}
62
63/// Symbol is global if it is defined and an extern.
64pub fn isGlobal(sym: macho.nlist_64) bool {
65 return isSect(sym) and isExt(sym);
66}
67
68/// Symbol is undefined if it is not defined and an extern.
69pub fn isUndef(sym: macho.nlist_64) bool {
70 return isUndf(sym) and isExt(sym);
71}142}
src/link/MachO/Zld.zig+423-449
...@@ -29,8 +29,8 @@ page_size: ?u16 = null,...@@ -29,8 +29,8 @@ page_size: ?u16 = null,
29file: ?fs.File = null,29file: ?fs.File = null,
30out_path: ?[]const u8 = null,30out_path: ?[]const u8 = null,
3131
32objects: std.ArrayListUnmanaged(Object) = .{},32objects: std.ArrayListUnmanaged(*Object) = .{},
33archives: std.ArrayListUnmanaged(Archive) = .{},33archives: std.ArrayListUnmanaged(*Archive) = .{},
3434
35load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},35load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
3636
...@@ -58,6 +58,7 @@ stubs_section_index: ?u16 = null,...@@ -58,6 +58,7 @@ stubs_section_index: ?u16 = null,
58stub_helper_section_index: ?u16 = null,58stub_helper_section_index: ?u16 = null,
59text_const_section_index: ?u16 = null,59text_const_section_index: ?u16 = null,
60cstring_section_index: ?u16 = null,60cstring_section_index: ?u16 = null,
61ustring_section_index: ?u16 = null,
6162
62// __DATA_CONST segment sections63// __DATA_CONST segment sections
63got_section_index: ?u16 = null,64got_section_index: ?u16 = null,
...@@ -74,30 +75,23 @@ data_section_index: ?u16 = null,...@@ -74,30 +75,23 @@ data_section_index: ?u16 = null,
74bss_section_index: ?u16 = null,75bss_section_index: ?u16 = null,
75common_section_index: ?u16 = null,76common_section_index: ?u16 = null,
7677
77symtab: std.StringArrayHashMapUnmanaged(Symbol) = .{},78globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
79imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
80unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
81
78strtab: std.ArrayListUnmanaged(u8) = .{},82strtab: std.ArrayListUnmanaged(u8) = .{},
79strtab_dir: std.StringHashMapUnmanaged(u32) = .{},83strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
8084
81threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},85threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
82local_rebases: std.ArrayListUnmanaged(Pointer) = .{},86local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
83stubs: std.StringArrayHashMapUnmanaged(u32) = .{},87stubs: std.ArrayListUnmanaged(*Symbol) = .{},
84got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},88got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
8589
86stub_helper_stubs_start_off: ?u64 = null,90stub_helper_stubs_start_off: ?u64 = null,
8791
88mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},92mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
89unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},93unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
9094
91const GotEntry = struct {
92 tag: enum {
93 local,
94 import,
95 },
96 index: u32,
97 target_addr: u64,
98 file: u16,
99};
100
101const MappingKey = struct {95const MappingKey = struct {
102 object_id: u16,96 object_id: u16,
103 source_sect_id: u16,97 source_sect_id: u16,
...@@ -124,15 +118,7 @@ pub fn init(allocator: *Allocator) Zld {...@@ -124,15 +118,7 @@ pub fn init(allocator: *Allocator) Zld {
124pub fn deinit(self: *Zld) void {118pub fn deinit(self: *Zld) void {
125 self.threadlocal_offsets.deinit(self.allocator);119 self.threadlocal_offsets.deinit(self.allocator);
126 self.local_rebases.deinit(self.allocator);120 self.local_rebases.deinit(self.allocator);
127
128 for (self.stubs.items()) |entry| {
129 self.allocator.free(entry.key);
130 }
131 self.stubs.deinit(self.allocator);121 self.stubs.deinit(self.allocator);
132
133 for (self.got_entries.items()) |entry| {
134 self.allocator.free(entry.key);
135 }
136 self.got_entries.deinit(self.allocator);122 self.got_entries.deinit(self.allocator);
137123
138 for (self.load_commands.items) |*lc| {124 for (self.load_commands.items) |*lc| {
...@@ -140,23 +126,22 @@ pub fn deinit(self: *Zld) void {...@@ -140,23 +126,22 @@ pub fn deinit(self: *Zld) void {
140 }126 }
141 self.load_commands.deinit(self.allocator);127 self.load_commands.deinit(self.allocator);
142128
143 for (self.objects.items) |*object| {129 for (self.objects.items) |object| {
144 object.deinit();130 object.deinit();
131 self.allocator.destroy(object);
145 }132 }
146 self.objects.deinit(self.allocator);133 self.objects.deinit(self.allocator);
147134
148 for (self.archives.items) |*archive| {135 for (self.archives.items) |archive| {
149 archive.deinit();136 archive.deinit();
137 self.allocator.destroy(archive);
150 }138 }
151 self.archives.deinit(self.allocator);139 self.archives.deinit(self.allocator);
152140
153 self.mappings.deinit(self.allocator);141 self.mappings.deinit(self.allocator);
154 self.unhandled_sections.deinit(self.allocator);142 self.unhandled_sections.deinit(self.allocator);
155143
156 for (self.symtab.items()) |*entry| {144 self.globals.deinit(self.allocator);
157 entry.value.deinit(self.allocator);
158 }
159 self.symtab.deinit(self.allocator);
160 self.strtab.deinit(self.allocator);145 self.strtab.deinit(self.allocator);
161146
162 {147 {
...@@ -224,10 +209,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {...@@ -224,10 +209,6 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
224 try self.allocateDataSegment();209 try self.allocateDataSegment();
225 self.allocateLinkeditSegment();210 self.allocateLinkeditSegment();
226 try self.allocateSymbols();211 try self.allocateSymbols();
227 try self.allocateStubsAndGotEntries();
228 try self.allocateCppStatics();
229 try self.writeStubHelperCommon();
230 try self.resolveRelocsAndWriteSections();
231 try self.flush();212 try self.flush();
232}213}
233214
...@@ -291,7 +272,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -291,7 +272,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
291 for (classified.items) |input| {272 for (classified.items) |input| {
292 switch (input.kind) {273 switch (input.kind) {
293 .object => {274 .object => {
294 var object = Object.init(self.allocator);275 const object = try self.allocator.create(Object);
276 errdefer self.allocator.destroy(object);
277
278 object.* = Object.init(self.allocator);
295 object.arch = self.arch.?;279 object.arch = self.arch.?;
296 object.name = try self.allocator.dupe(u8, input.name);280 object.name = try self.allocator.dupe(u8, input.name);
297 object.file = input.file;281 object.file = input.file;
...@@ -299,7 +283,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -299,7 +283,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
299 try self.objects.append(self.allocator, object);283 try self.objects.append(self.allocator, object);
300 },284 },
301 .archive => {285 .archive => {
302 var archive = Archive.init(self.allocator);286 const archive = try self.allocator.create(Archive);
287 errdefer self.allocator.destroy(archive);
288
289 archive.* = Archive.init(self.allocator);
303 archive.arch = self.arch.?;290 archive.arch = self.arch.?;
304 archive.name = try self.allocator.dupe(u8, input.name);291 archive.name = try self.allocator.dupe(u8, input.name);
305 archive.file = input.file;292 archive.file = input.file;
...@@ -367,23 +354,43 @@ fn updateMetadata(self: *Zld) !void {...@@ -367,23 +354,43 @@ fn updateMetadata(self: *Zld) !void {
367 switch (flags) {354 switch (flags) {
368 macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {355 macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
369 if (mem.eql(u8, segname, "__TEXT")) {356 if (mem.eql(u8, segname, "__TEXT")) {
370 if (self.text_const_section_index != null) continue;357 if (mem.eql(u8, sectname, "__ustring")) {
371358 if (self.ustring_section_index != null) continue;
372 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);359
373 try text_seg.addSection(self.allocator, .{360 self.ustring_section_index = @intCast(u16, text_seg.sections.items.len);
374 .sectname = makeStaticString("__const"),361 try text_seg.addSection(self.allocator, .{
375 .segname = makeStaticString("__TEXT"),362 .sectname = makeStaticString("__ustring"),
376 .addr = 0,363 .segname = makeStaticString("__TEXT"),
377 .size = 0,364 .addr = 0,
378 .offset = 0,365 .size = 0,
379 .@"align" = 0,366 .offset = 0,
380 .reloff = 0,367 .@"align" = 0,
381 .nreloc = 0,368 .reloff = 0,
382 .flags = macho.S_REGULAR,369 .nreloc = 0,
383 .reserved1 = 0,370 .flags = macho.S_REGULAR,
384 .reserved2 = 0,371 .reserved1 = 0,
385 .reserved3 = 0,372 .reserved2 = 0,
386 });373 .reserved3 = 0,
374 });
375 } else {
376 if (self.text_const_section_index != null) continue;
377
378 self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
379 try text_seg.addSection(self.allocator, .{
380 .sectname = makeStaticString("__const"),
381 .segname = makeStaticString("__TEXT"),
382 .addr = 0,
383 .size = 0,
384 .offset = 0,
385 .@"align" = 0,
386 .reloff = 0,
387 .nreloc = 0,
388 .flags = macho.S_REGULAR,
389 .reserved1 = 0,
390 .reserved2 = 0,
391 .reserved3 = 0,
392 });
393 }
387 } else if (mem.eql(u8, segname, "__DATA")) {394 } else if (mem.eql(u8, segname, "__DATA")) {
388 if (!mem.eql(u8, sectname, "__const")) continue;395 if (!mem.eql(u8, sectname, "__const")) continue;
389 if (self.data_const_section_index != null) continue;396 if (self.data_const_section_index != null) continue;
...@@ -599,6 +606,50 @@ fn updateMetadata(self: *Zld) !void {...@@ -599,6 +606,50 @@ fn updateMetadata(self: *Zld) !void {
599 }, 0);606 }, 0);
600 }607 }
601 }608 }
609
610 tlv_align: {
611 const has_tlv =
612 self.tlv_section_index != null or
613 self.tlv_data_section_index != null or
614 self.tlv_bss_section_index != null;
615
616 if (!has_tlv) break :tlv_align;
617
618 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
619
620 if (self.tlv_section_index) |index| {
621 const sect = &seg.sections.items[index];
622 sect.@"align" = 3; // __thread_vars is always 8byte aligned
623 }
624
625 // Apparently __tlv_data and __tlv_bss need to have matching alignment, so fix it up.
626 // <rdar://problem/24221680> All __thread_data and __thread_bss sections must have same alignment
627 // https://github.com/apple-opensource/ld64/blob/e28c028b20af187a16a7161d89e91868a450cadc/src/ld/ld.cpp#L1172
628 const data_align: u32 = data: {
629 if (self.tlv_data_section_index) |index| {
630 const sect = &seg.sections.items[index];
631 break :data sect.@"align";
632 }
633 break :tlv_align;
634 };
635 const bss_align: u32 = bss: {
636 if (self.tlv_bss_section_index) |index| {
637 const sect = &seg.sections.items[index];
638 break :bss sect.@"align";
639 }
640 break :tlv_align;
641 };
642 const max_align = math.max(data_align, bss_align);
643
644 if (self.tlv_data_section_index) |index| {
645 const sect = &seg.sections.items[index];
646 sect.@"align" = max_align;
647 }
648 if (self.tlv_bss_section_index) |index| {
649 const sect = &seg.sections.items[index];
650 sect.@"align" = max_align;
651 }
652 }
602}653}
603654
604const MatchingSection = struct {655const MatchingSection = struct {
...@@ -674,10 +725,17 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {...@@ -674,10 +725,17 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
674 },725 },
675 macho.S_REGULAR => {726 macho.S_REGULAR => {
676 if (mem.eql(u8, segname, "__TEXT")) {727 if (mem.eql(u8, segname, "__TEXT")) {
677 break :blk .{728 if (mem.eql(u8, sectname, "__ustring")) {
678 .seg = self.text_segment_cmd_index.?,729 break :blk .{
679 .sect = self.text_const_section_index.?,730 .seg = self.text_segment_cmd_index.?,
680 };731 .sect = self.ustring_section_index.?,
732 };
733 } else {
734 break :blk .{
735 .seg = self.text_segment_cmd_index.?,
736 .sect = self.text_const_section_index.?,
737 };
738 }
681 } else if (mem.eql(u8, segname, "__DATA")) {739 } else if (mem.eql(u8, segname, "__DATA")) {
682 if (mem.eql(u8, sectname, "__data")) {740 if (mem.eql(u8, sectname, "__data")) {
683 break :blk .{741 break :blk .{
...@@ -723,6 +781,7 @@ fn sortSections(self: *Zld) !void {...@@ -723,6 +781,7 @@ fn sortSections(self: *Zld) !void {
723 &self.stub_helper_section_index,781 &self.stub_helper_section_index,
724 &self.text_const_section_index,782 &self.text_const_section_index,
725 &self.cstring_section_index,783 &self.cstring_section_index,
784 &self.ustring_section_index,
726 };785 };
727 for (indices) |maybe_index| {786 for (indices) |maybe_index| {
728 const new_index: u16 = if (maybe_index.*) |index| blk: {787 const new_index: u16 = if (maybe_index.*) |index| blk: {
...@@ -805,7 +864,7 @@ fn sortSections(self: *Zld) !void {...@@ -805,7 +864,7 @@ fn sortSections(self: *Zld) !void {
805864
806fn allocateTextSegment(self: *Zld) !void {865fn allocateTextSegment(self: *Zld) !void {
807 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;866 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
808 const nstubs = @intCast(u32, self.stubs.items().len);867 const nstubs = @intCast(u32, self.stubs.items.len);
809868
810 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;869 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
811 seg.inner.fileoff = 0;870 seg.inner.fileoff = 0;
...@@ -856,7 +915,7 @@ fn allocateTextSegment(self: *Zld) !void {...@@ -856,7 +915,7 @@ fn allocateTextSegment(self: *Zld) !void {
856915
857fn allocateDataConstSegment(self: *Zld) !void {916fn allocateDataConstSegment(self: *Zld) !void {
858 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;917 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
859 const nentries = @intCast(u32, self.got_entries.items().len);918 const nentries = @intCast(u32, self.got_entries.items.len);
860919
861 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;920 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
862 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;921 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
...@@ -871,7 +930,7 @@ fn allocateDataConstSegment(self: *Zld) !void {...@@ -871,7 +930,7 @@ fn allocateDataConstSegment(self: *Zld) !void {
871930
872fn allocateDataSegment(self: *Zld) !void {931fn allocateDataSegment(self: *Zld) !void {
873 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;932 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
874 const nstubs = @intCast(u32, self.stubs.items().len);933 const nstubs = @intCast(u32, self.stubs.items.len);
875934
876 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;935 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
877 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;936 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
...@@ -914,95 +973,46 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {...@@ -914,95 +973,46 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
914}973}
915974
916fn allocateSymbols(self: *Zld) !void {975fn allocateSymbols(self: *Zld) !void {
917 for (self.objects.items) |*object, object_id| {976 for (self.objects.items) |object, object_id| {
918 for (object.locals.items()) |*entry| {977 for (object.symbols.items) |sym| {
919 const source_sym = object.symtab.items[entry.value.index.?];978 const reg = sym.cast(Symbol.Regular) orelse continue;
920 const source_sect_id = source_sym.n_sect - 1;
921979
922 // TODO I am more and more convinced we should store the mapping as part of the Object struct.980 // TODO I am more and more convinced we should store the mapping as part of the Object struct.
923 const target_mapping = self.mappings.get(.{981 const target_mapping = self.mappings.get(.{
924 .object_id = @intCast(u16, object_id),982 .object_id = @intCast(u16, object_id),
925 .source_sect_id = source_sect_id,983 .source_sect_id = reg.section,
926 }) orelse {984 }) orelse {
927 if (self.unhandled_sections.get(.{985 if (self.unhandled_sections.get(.{
928 .object_id = @intCast(u16, object_id),986 .object_id = @intCast(u16, object_id),
929 .source_sect_id = source_sect_id,987 .source_sect_id = reg.section,
930 }) != null) continue;988 }) != null) continue;
931989
932 log.err("section not mapped for symbol '{s}'", .{entry.value.name});990 log.err("section not mapped for symbol '{s}'", .{sym.name});
933 return error.SectionNotMappedForSymbol;991 return error.SectionNotMappedForSymbol;
934 };992 };
935993
936 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;994 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
937 const source_sect = source_seg.sections.items[source_sect_id];995 const source_sect = source_seg.sections.items[reg.section];
938 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;996 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
939 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];997 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
940 const target_addr = target_sect.addr + target_mapping.offset;998 const target_addr = target_sect.addr + target_mapping.offset;
941 const n_value = source_sym.n_value - source_sect.addr + target_addr;999 const address = reg.address - source_sect.addr + target_addr;
9421000
943 log.debug("resolving local symbol '{s}' at 0x{x}", .{ entry.value.name, n_value });1001 log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address });
9441002
945 // TODO there might be a more generic way of doing this.1003 // TODO there might be a more generic way of doing this.
946 var n_sect: u8 = 0;1004 var section: u8 = 0;
947 for (self.load_commands.items) |cmd, cmd_id| {1005 for (self.load_commands.items) |cmd, cmd_id| {
948 if (cmd != .Segment) break;1006 if (cmd != .Segment) break;
949 if (cmd_id == target_mapping.target_seg_id) {1007 if (cmd_id == target_mapping.target_seg_id) {
950 n_sect += @intCast(u8, target_mapping.target_sect_id) + 1;1008 section += @intCast(u8, target_mapping.target_sect_id) + 1;
951 break;1009 break;
952 }1010 }
953 n_sect += @intCast(u8, cmd.Segment.sections.items.len);1011 section += @intCast(u8, cmd.Segment.sections.items.len);
954 }
955
956 entry.value.address = n_value;
957 entry.value.section = n_sect;
958 }
959 }
960
961 for (self.symtab.items()) |*entry| {
962 if (entry.value.tag == .import) continue;
963
964 const object_id = entry.value.file orelse unreachable;
965 const object = self.objects.items[object_id];
966 const local = object.locals.get(entry.key) orelse unreachable;
967
968 log.debug("resolving {} symbol '{s}' at 0x{x}", .{ entry.value.tag, entry.key, local.address });
969
970 entry.value.address = local.address;
971 entry.value.section = local.section;
972 }
973}
974
975fn allocateStubsAndGotEntries(self: *Zld) !void {
976 for (self.got_entries.items()) |*entry| {
977 if (entry.value.tag == .import) continue;
978
979 const object = self.objects.items[entry.value.file];
980 entry.value.target_addr = target_addr: {
981 if (object.locals.get(entry.key)) |local| {
982 break :target_addr local.address;
983 }1012 }
984 const global = self.symtab.get(entry.key) orelse unreachable;
985 break :target_addr global.address;
986 };
987
988 log.debug("resolving GOT entry '{s}' at 0x{x}", .{
989 entry.key,
990 entry.value.target_addr,
991 });
992 }
993}
9941013
995fn allocateCppStatics(self: *Zld) !void {1014 reg.address = address;
996 for (self.objects.items) |*object| {1015 reg.section = section;
997 for (object.initializers.items) |*initializer| {
998 const sym = object.symtab.items[initializer.symbol];
999 const sym_name = object.getString(sym.n_strx);
1000 initializer.target_addr = object.locals.get(sym_name).?.address;
1001
1002 log.debug("resolving C++ initializer '{s}' at 0x{x}", .{
1003 sym_name,
1004 initializer.target_addr,
1005 });
1006 }1016 }
1007 }1017 }
1008}1018}
...@@ -1037,8 +1047,8 @@ fn writeStubHelperCommon(self: *Zld) !void {...@@ -1037,8 +1047,8 @@ fn writeStubHelperCommon(self: *Zld) !void {
1037 code[9] = 0xff;1047 code[9] = 0xff;
1038 code[10] = 0x25;1048 code[10] = 0x25;
1039 {1049 {
1040 const dyld_stub_binder = self.got_entries.get("dyld_stub_binder").?;1050 const dyld_stub_binder = self.imports.get("dyld_stub_binder").?;
1041 const addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64));1051 const addr = (got.addr + dyld_stub_binder.got_index.? * @sizeOf(u64));
1042 const displacement = try math.cast(u32, addr - stub_helper.addr - code_size);1052 const displacement = try math.cast(u32, addr - stub_helper.addr - code_size);
1043 mem.writeIntLittle(u32, code[11..], displacement);1053 mem.writeIntLittle(u32, code[11..], displacement);
1044 }1054 }
...@@ -1081,9 +1091,9 @@ fn writeStubHelperCommon(self: *Zld) !void {...@@ -1081,9 +1091,9 @@ fn writeStubHelperCommon(self: *Zld) !void {
1081 code[10] = 0xbf;1091 code[10] = 0xbf;
1082 code[11] = 0xa9;1092 code[11] = 0xa9;
1083 binder_blk_outer: {1093 binder_blk_outer: {
1084 const dyld_stub_binder = self.got_entries.get("dyld_stub_binder").?;1094 const dyld_stub_binder = self.imports.get("dyld_stub_binder").?;
1085 const this_addr = stub_helper.addr + 3 * @sizeOf(u32);1095 const this_addr = stub_helper.addr + 3 * @sizeOf(u32);
1086 const target_addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64));1096 const target_addr = (got.addr + dyld_stub_binder.got_index.? * @sizeOf(u64));
1087 binder_blk: {1097 binder_blk: {
1088 const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk;1098 const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk;
1089 const literal = math.cast(u18, displacement) catch |_| break :binder_blk;1099 const literal = math.cast(u18, displacement) catch |_| break :binder_blk;
...@@ -1134,8 +1144,9 @@ fn writeStubHelperCommon(self: *Zld) !void {...@@ -1134,8 +1144,9 @@ fn writeStubHelperCommon(self: *Zld) !void {
1134 }1144 }
1135 };1145 };
11361146
1137 for (self.stubs.items()) |entry| {1147 for (self.stubs.items) |sym| {
1138 const index = entry.value;1148 // TODO weak bound pointers
1149 const index = sym.stubs_index orelse unreachable;
1139 try self.writeLazySymbolPointer(index);1150 try self.writeLazySymbolPointer(index);
1140 try self.writeStub(index);1151 try self.writeStub(index);
1141 try self.writeStubInStubHelper(index);1152 try self.writeStubInStubHelper(index);
...@@ -1274,145 +1285,154 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {...@@ -1274,145 +1285,154 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {
1274 try self.file.?.pwriteAll(code, stub_off);1285 try self.file.?.pwriteAll(code, stub_off);
1275}1286}
12761287
1277fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {1288fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
1278 const object = self.objects.items[object_id];
1279 log.debug("resolving symbols in '{s}'", .{object.name});1289 log.debug("resolving symbols in '{s}'", .{object.name});
12801290
1281 for (object.symtab.items) |sym, sym_id| {1291 for (object.symbols.items) |sym| {
1282 if (Symbol.isLocal(sym)) {1292 if (sym.cast(Symbol.Regular)) |reg| {
1283 // If symbol is local to CU, we don't put it in the global symbol table.1293 if (reg.linkage == .translation_unit) continue; // Symbol local to TU.
1284 continue;1294
1285 } else if (Symbol.isGlobal(sym)) {1295 if (self.unresolved.swapRemove(sym.name)) |entry| {
1286 const sym_name = object.getString(sym.n_strx);1296 // Create link to the global.
1287 const is_weak = Symbol.isWeakDef(sym) or Symbol.isPext(sym);1297 entry.value.alias = sym;
1288 const global = self.symtab.getEntry(sym_name) orelse {1298 }
1299 const entry = self.globals.getEntry(sym.name) orelse {
1289 // Put new global symbol into the symbol table.1300 // Put new global symbol into the symbol table.
1290 const name = try self.allocator.dupe(u8, sym_name);1301 try self.globals.putNoClobber(self.allocator, sym.name, sym);
1291 try self.symtab.putNoClobber(self.allocator, name, .{
1292 .tag = if (is_weak) .weak else .strong,
1293 .name = name,
1294 .address = 0,
1295 .section = 0,
1296 .file = object_id,
1297 .index = @intCast(u32, sym_id),
1298 });
1299 continue;1302 continue;
1300 };1303 };
13011304 const g_sym = entry.value;
1302 switch (global.value.tag) {1305 const g_reg = g_sym.cast(Symbol.Regular) orelse unreachable;
1303 .weak => {1306
1304 if (is_weak) continue; // Nothing to do for weak symbol.1307 switch (g_reg.linkage) {
1308 .translation_unit => unreachable,
1309 .linkage_unit => {
1310 if (reg.linkage == .linkage_unit) {
1311 // Create link to the first encountered linkage_unit symbol.
1312 sym.alias = g_sym;
1313 continue;
1314 }
1305 },1315 },
1306 .strong => {1316 .global => {
1307 if (!is_weak) {1317 if (reg.linkage == .global) {
1308 log.debug("strong symbol '{s}' defined multiple times", .{sym_name});1318 log.debug("symbol '{s}' defined multiple times", .{reg.base.name});
1309 return error.MultipleSymbolDefinitions;1319 return error.MultipleSymbolDefinitions;
1310 }1320 }
1321 sym.alias = g_sym;
1311 continue;1322 continue;
1312 },1323 },
1313 else => {},
1314 }1324 }
13151325
1316 global.value.tag = if (is_weak) .weak else .strong;1326 g_sym.alias = sym;
1317 global.value.file = object_id;1327 entry.value = sym;
1318 global.value.index = @intCast(u32, sym_id);1328 } else if (sym.cast(Symbol.Unresolved)) |und| {
1319 } else if (Symbol.isUndef(sym)) {1329 if (self.globals.get(sym.name)) |g_sym| {
1320 const sym_name = object.getString(sym.n_strx);1330 sym.alias = g_sym;
1321 if (self.symtab.contains(sym_name)) continue; // Nothing to do if we already found a definition.1331 continue;
13221332 }
1323 const name = try self.allocator.dupe(u8, sym_name);1333 if (self.unresolved.get(sym.name)) |u_sym| {
1324 try self.symtab.putNoClobber(self.allocator, name, .{1334 sym.alias = u_sym;
1325 .tag = .undef,1335 continue;
1326 .name = name,1336 }
1327 .address = 0,1337 try self.unresolved.putNoClobber(self.allocator, sym.name, sym);
1328 .section = 0,
1329 });
1330 } else unreachable;1338 } else unreachable;
1331 }1339 }
1332}1340}
13331341
1334fn resolveSymbols(self: *Zld) !void {1342fn resolveSymbols(self: *Zld) !void {
1335 // First pass, resolve symbols in provided objects.1343 // First pass, resolve symbols in provided objects.
1336 for (self.objects.items) |object, object_id| {1344 for (self.objects.items) |object| {
1337 try self.resolveSymbolsInObject(@intCast(u16, object_id));1345 try self.resolveSymbolsInObject(object);
1338 }1346 }
13391347
1340 // Second pass, resolve symbols in static libraries.1348 // Second pass, resolve symbols in static libraries.
1341 var next_sym: usize = 0;1349 var next_sym: usize = 0;
1342 var nsyms: usize = self.symtab.items().len;1350 while (true) {
1343 while (next_sym < nsyms) : (next_sym += 1) {1351 if (next_sym == self.unresolved.count()) break;
1344 const sym = self.symtab.items()[next_sym];
1345 if (sym.value.tag != .undef) continue;
13461352
1347 const sym_name = sym.value.name;1353 const entry = self.unresolved.items()[next_sym];
1354 const sym = entry.value;
1355
1356 var reset: bool = false;
1348 for (self.archives.items) |archive| {1357 for (self.archives.items) |archive| {
1349 // Check if the entry exists in a static archive.1358 // Check if the entry exists in a static archive.
1350 const offsets = archive.toc.get(sym_name) orelse {1359 const offsets = archive.toc.get(sym.name) orelse {
1351 // No hit.1360 // No hit.
1352 continue;1361 continue;
1353 };1362 };
1354 assert(offsets.items.len > 0);1363 assert(offsets.items.len > 0);
13551364
1356 const object = try archive.parseObject(offsets.items[0]);1365 const object = try self.allocator.create(Object);
1357 const object_id = @intCast(u16, self.objects.items.len);1366 errdefer self.allocator.destroy(object);
1367
1368 object.* = try archive.parseObject(offsets.items[0]);
1358 try self.objects.append(self.allocator, object);1369 try self.objects.append(self.allocator, object);
1359 try self.resolveSymbolsInObject(object_id);1370 try self.resolveSymbolsInObject(object);
13601371
1361 nsyms = self.symtab.items().len;1372 reset = true;
1362 break;1373 break;
1363 }1374 }
1375
1376 if (reset) {
1377 next_sym = 0;
1378 } else {
1379 next_sym += 1;
1380 }
1364 }1381 }
13651382
1366 // Third pass, resolve symbols in dynamic libraries.1383 // Third pass, resolve symbols in dynamic libraries.
1367 // TODO Implement libSystem as a hard-coded library, or ship with1384 // TODO Implement libSystem as a hard-coded library, or ship with
1368 // a libSystem.B.tbd definition file?1385 // a libSystem.B.tbd definition file?
1369 for (self.symtab.items()) |*entry| {1386 try self.imports.ensureCapacity(self.allocator, self.unresolved.count());
1370 if (entry.value.tag != .undef) continue;1387 for (self.unresolved.items()) |entry| {
1388 const proxy = try self.allocator.create(Symbol.Proxy);
1389 errdefer self.allocator.destroy(proxy);
1390
1391 proxy.* = .{
1392 .base = .{
1393 .@"type" = .proxy,
1394 .name = try self.allocator.dupe(u8, entry.key),
1395 },
1396 .dylib = 0,
1397 };
13711398
1372 entry.value.tag = .import;1399 self.imports.putAssumeCapacityNoClobber(proxy.base.name, &proxy.base);
1373 entry.value.file = 0;1400 entry.value.alias = &proxy.base;
1374 }1401 }
1402 self.unresolved.clearAndFree(self.allocator);
13751403
1376 // If there are any undefs left, flag an error.1404 // If there are any undefs left, flag an error.
1377 var has_unresolved = false;1405 if (self.unresolved.count() > 0) {
1378 for (self.symtab.items()) |entry| {1406 for (self.unresolved.items()) |entry| {
1379 if (entry.value.tag != .undef) continue;1407 log.err("undefined reference to symbol '{s}'", .{entry.key});
13801408 log.err(" | referenced in {s}", .{
1381 has_unresolved = true;1409 entry.value.cast(Symbol.Unresolved).?.file.name.?,
1382 log.err("undefined reference to symbol '{s}'", .{entry.value.name});1410 });
1383 }1411 }
1384 if (has_unresolved) {
1385 return error.UndefinedSymbolReference;1412 return error.UndefinedSymbolReference;
1386 }1413 }
13871414
1388 // Finally put dyld_stub_binder as an Import1415 // Finally put dyld_stub_binder as an Import
1389 var name = try self.allocator.dupe(u8, "dyld_stub_binder");1416 const dyld_stub_binder = try self.allocator.create(Symbol.Proxy);
1390 try self.symtab.putNoClobber(self.allocator, name, .{1417 errdefer self.allocator.destroy(dyld_stub_binder);
1391 .tag = .import,
1392 .name = name,
1393 .address = 0,
1394 .section = 0,
1395 .file = 0,
1396 });
13971418
1398 {1419 dyld_stub_binder.* = .{
1399 log.debug("symtab", .{});1420 .base = .{
1400 for (self.symtab.items()) |sym| {1421 .@"type" = .proxy,
1401 switch (sym.value.tag) {1422 .name = try self.allocator.dupe(u8, "dyld_stub_binder"),
1402 .weak, .strong => {1423 },
1403 log.debug(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? });1424 .dylib = 0,
1404 },1425 };
1405 .import => {1426
1406 log.debug(" | {s} => libSystem.B.dylib", .{sym.key});1427 try self.imports.putNoClobber(
1407 },1428 self.allocator,
1408 else => unreachable,1429 dyld_stub_binder.base.name,
1409 }1430 &dyld_stub_binder.base,
1410 }1431 );
1411 }
1412}1432}
14131433
1414fn resolveStubsAndGotEntries(self: *Zld) !void {1434fn resolveStubsAndGotEntries(self: *Zld) !void {
1415 for (self.objects.items) |object, object_id| {1435 for (self.objects.items) |object| {
1416 log.debug("resolving stubs and got entries from {s}", .{object.name});1436 log.debug("resolving stubs and got entries from {s}", .{object.name});
14171437
1418 for (object.sections.items) |sect| {1438 for (object.sections.items) |sect| {
...@@ -1421,42 +1441,32 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {...@@ -1421,42 +1441,32 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
1421 switch (rel.@"type") {1441 switch (rel.@"type") {
1422 .unsigned => continue,1442 .unsigned => continue,
1423 .got_page, .got_page_off, .got_load, .got => {1443 .got_page, .got_page_off, .got_load, .got => {
1424 const sym = object.symtab.items[rel.target.symbol];1444 const sym = rel.target.symbol.getTopmostAlias();
1425 const sym_name = object.getString(sym.n_strx);1445 if (sym.got_index != null) continue;
1426
1427 if (self.got_entries.contains(sym_name)) continue;
1428
1429 // TODO clean this up
1430 const is_import = self.symtab.get(sym_name).?.tag == .import;
1431 var name = try self.allocator.dupe(u8, sym_name);
1432 const index = @intCast(u32, self.got_entries.items().len);
1433 try self.got_entries.putNoClobber(self.allocator, name, .{
1434 .tag = if (is_import) .import else .local,
1435 .index = index,
1436 .target_addr = 0,
1437 .file = if (is_import) 0 else @intCast(u16, object_id),
1438 });
14391446
1440 log.debug(" | found GOT entry {s}: {}", .{ sym_name, self.got_entries.get(sym_name) });1447 const index = @intCast(u32, self.got_entries.items.len);
1448 sym.got_index = index;
1449 try self.got_entries.append(self.allocator, sym);
1450
1451 log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym });
1441 },1452 },
1442 else => {1453 else => {
1443 if (rel.target != .symbol) continue;1454 if (rel.target != .symbol) continue;
14441455
1445 const sym = object.symtab.items[rel.target.symbol];1456 const sym = rel.target.symbol.getTopmostAlias();
1446 const sym_name = object.getString(sym.n_strx);1457 assert(sym.@"type" != .unresolved);
1447
1448 if (!Symbol.isUndef(sym)) continue;
1449
1450 const in_globals = self.symtab.get(sym_name) orelse unreachable;
14511458
1452 if (in_globals.tag != .import) continue;1459 if (sym.stubs_index != null) continue;
1453 if (self.stubs.contains(sym_name)) continue;1460 if (sym.@"type" != .proxy) continue;
1461 // if (sym.cast(Symbol.Regular)) |reg| {
1462 // if (!reg.weak_ref) continue;
1463 // }
14541464
1455 var name = try self.allocator.dupe(u8, sym_name);1465 const index = @intCast(u32, self.stubs.items.len);
1456 const index = @intCast(u32, self.stubs.items().len);1466 sym.stubs_index = index;
1457 try self.stubs.putNoClobber(self.allocator, name, index);1467 try self.stubs.append(self.allocator, sym);
14581468
1459 log.debug(" | found stub {s}: {}", .{ sym_name, self.stubs.get(sym_name) });1469 log.debug(" | found stub {s}: {*}", .{ sym.name, sym });
1460 },1470 },
1461 }1471 }
1462 }1472 }
...@@ -1464,16 +1474,12 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {...@@ -1464,16 +1474,12 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
1464 }1474 }
14651475
1466 // Finally, put dyld_stub_binder as the final GOT entry1476 // Finally, put dyld_stub_binder as the final GOT entry
1467 var name = try self.allocator.dupe(u8, "dyld_stub_binder");1477 const sym = self.imports.get("dyld_stub_binder") orelse unreachable;
1468 const index = @intCast(u32, self.got_entries.items().len);1478 const index = @intCast(u32, self.got_entries.items.len);
1469 try self.got_entries.putNoClobber(self.allocator, name, .{1479 sym.got_index = index;
1470 .tag = .import,1480 try self.got_entries.append(self.allocator, sym);
1471 .index = index,
1472 .target_addr = 0,
1473 .file = 0,
1474 });
14751481
1476 log.debug(" | found GOT entry dyld_stub_binder: {}", .{self.got_entries.get("dyld_stub_binder")});1482 log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym });
1477}1483}
14781484
1479fn resolveRelocsAndWriteSections(self: *Zld) !void {1485fn resolveRelocsAndWriteSections(self: *Zld) !void {
...@@ -1547,11 +1553,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1547,11 +1553,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1547 // TLV is handled via a separate offset mechanism.1553 // TLV is handled via a separate offset mechanism.
1548 // Calculate the offset to the initializer.1554 // Calculate the offset to the initializer.
1549 if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {1555 if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
1550 const sym = object.symtab.items[rel.target.symbol];
1551 const sym_name = object.getString(sym.n_strx);
1552
1553 // TODO we don't want to save offset to tlv_bootstrap1556 // TODO we don't want to save offset to tlv_bootstrap
1554 if (mem.eql(u8, sym_name, "__tlv_bootstrap")) break :tlv;1557 if (mem.eql(u8, rel.target.symbol.name, "__tlv_bootstrap")) break :tlv;
15551558
1556 const base_addr = blk: {1559 const base_addr = blk: {
1557 if (self.tlv_data_section_index) |index| {1560 if (self.tlv_data_section_index) |index| {
...@@ -1570,10 +1573,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1570,10 +1573,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1570 .got_page, .got_page_off, .got_load, .got => {1573 .got_page, .got_page_off, .got_load, .got => {
1571 const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;1574 const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1572 const got = dc_seg.sections.items[self.got_section_index.?];1575 const got = dc_seg.sections.items[self.got_section_index.?];
1573 const sym = object.symtab.items[rel.target.symbol];1576 const final = rel.target.symbol.getTopmostAlias();
1574 const sym_name = object.getString(sym.n_strx);1577 args.target_addr = got.addr + final.got_index.? * @sizeOf(u64);
1575 const entry = self.got_entries.get(sym_name) orelse unreachable;
1576 args.target_addr = got.addr + entry.index * @sizeOf(u64);
1577 },1578 },
1578 else => |tt| {1579 else => |tt| {
1579 if (tt == .signed and rel.target == .section) {1580 if (tt == .signed and rel.target == .section) {
...@@ -1620,58 +1621,27 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1620,58 +1621,27 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1620}1621}
16211622
1622fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) !u64 {1623fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) !u64 {
1623 const object = self.objects.items[object_id];
1624 const target_addr = blk: {1624 const target_addr = blk: {
1625 switch (target) {1625 switch (target) {
1626 .symbol => |sym_id| {1626 .symbol => |sym| {
1627 const sym = object.symtab.items[sym_id];1627 const final = sym.getTopmostAlias();
1628 const sym_name = object.getString(sym.n_strx);1628 if (final.cast(Symbol.Regular)) |reg| {
16291629 log.debug(" | regular '{s}'", .{sym.name});
1630 if (Symbol.isSect(sym)) {1630 break :blk reg.address;
1631 log.debug(" | local symbol '{s}'", .{sym_name});1631 } else if (final.cast(Symbol.Proxy)) |proxy| {
1632 if (object.locals.get(sym_name)) |local| {1632 if (mem.eql(u8, sym.name, "__tlv_bootstrap")) {
1633 break :blk local.address;1633 log.debug(" | symbol '__tlv_bootstrap'", .{});
1634 }1634 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1635 // For temp locals, i.e., symbols prefixed with l... we relocate1635 const tlv = segment.sections.items[self.tlv_section_index.?];
1636 // based on section addressing.1636 break :blk tlv.addr;
1637 const source_sect_id = sym.n_sect - 1;
1638 const target_mapping = self.mappings.get(.{
1639 .object_id = object_id,
1640 .source_sect_id = source_sect_id,
1641 }) orelse unreachable;
1642
1643 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
1644 const source_sect = source_seg.sections.items[source_sect_id];
1645 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
1646 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1647 const target_addr = target_sect.addr + target_mapping.offset;
1648 break :blk sym.n_value - source_sect.addr + target_addr;
1649 } else if (self.symtab.get(sym_name)) |global| {
1650 switch (global.tag) {
1651 .weak, .strong => {
1652 log.debug(" | global symbol '{s}'", .{sym_name});
1653 break :blk global.address;
1654 },
1655 .import => {
1656 if (self.stubs.get(sym_name)) |index| {
1657 log.debug(" | symbol stub '{s}'", .{sym_name});
1658 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1659 const stubs = segment.sections.items[self.stubs_section_index.?];
1660 break :blk stubs.addr + index * stubs.reserved2;
1661 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
1662 log.debug(" | symbol '__tlv_bootstrap'", .{});
1663 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1664 const tlv = segment.sections.items[self.tlv_section_index.?];
1665 break :blk tlv.addr;
1666 } else {
1667 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1668 return error.FailedToResolveRelocationTarget;
1669 }
1670 },
1671 else => unreachable,
1672 }1637 }
1638
1639 log.debug(" | symbol stub '{s}'", .{sym.name});
1640 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1641 const stubs = segment.sections.items[self.stubs_section_index.?];
1642 break :blk stubs.addr + proxy.base.stubs_index.? * stubs.reserved2;
1673 } else {1643 } else {
1674 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});1644 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym.name});
1675 return error.FailedToResolveRelocationTarget;1645 return error.FailedToResolveRelocationTarget;
1676 }1646 }
1677 },1647 },
...@@ -2091,6 +2061,9 @@ fn populateMetadata(self: *Zld) !void {...@@ -2091,6 +2061,9 @@ fn populateMetadata(self: *Zld) !void {
2091}2061}
20922062
2093fn flush(self: *Zld) !void {2063fn flush(self: *Zld) !void {
2064 try self.writeStubHelperCommon();
2065 try self.resolveRelocsAndWriteSections();
2066
2094 if (self.common_section_index) |index| {2067 if (self.common_section_index) |index| {
2095 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;2068 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2096 const sect = &seg.sections.items[index];2069 const sect = &seg.sections.items[index];
...@@ -2136,10 +2109,10 @@ fn flush(self: *Zld) !void {...@@ -2136,10 +2109,10 @@ fn flush(self: *Zld) !void {
2136 var initializers = std.ArrayList(u64).init(self.allocator);2109 var initializers = std.ArrayList(u64).init(self.allocator);
2137 defer initializers.deinit();2110 defer initializers.deinit();
21382111
2139 // TODO sort the initializers globally
2140 for (self.objects.items) |object| {2112 for (self.objects.items) |object| {
2141 for (object.initializers.items) |initializer| {2113 for (object.initializers.items) |initializer| {
2142 try initializers.append(initializer.target_addr);2114 const address = initializer.cast(Symbol.Regular).?.address;
2115 try initializers.append(address);
2143 }2116 }
2144 }2117 }
21452118
...@@ -2193,14 +2166,15 @@ fn writeGotEntries(self: *Zld) !void {...@@ -2193,14 +2166,15 @@ fn writeGotEntries(self: *Zld) !void {
2193 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;2166 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2194 const sect = seg.sections.items[self.got_section_index.?];2167 const sect = seg.sections.items[self.got_section_index.?];
21952168
2196 var buffer = try self.allocator.alloc(u8, self.got_entries.items().len * @sizeOf(u64));2169 var buffer = try self.allocator.alloc(u8, self.got_entries.items.len * @sizeOf(u64));
2197 defer self.allocator.free(buffer);2170 defer self.allocator.free(buffer);
21982171
2199 var stream = std.io.fixedBufferStream(buffer);2172 var stream = std.io.fixedBufferStream(buffer);
2200 var writer = stream.writer();2173 var writer = stream.writer();
22012174
2202 for (self.got_entries.items()) |entry| {2175 for (self.got_entries.items) |sym| {
2203 try writer.writeIntLittle(u64, entry.value.target_addr);2176 const address: u64 = if (sym.cast(Symbol.Regular)) |reg| reg.address else 0;
2177 try writer.writeIntLittle(u64, address);
2204 }2178 }
22052179
2206 log.debug("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len });2180 log.debug("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len });
...@@ -2213,7 +2187,8 @@ fn setEntryPoint(self: *Zld) !void {...@@ -2213,7 +2187,8 @@ fn setEntryPoint(self: *Zld) !void {
2213 // entrypoint. For now, assume default of `_main`.2187 // entrypoint. For now, assume default of `_main`.
2214 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2188 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2215 const text = seg.sections.items[self.text_section_index.?];2189 const text = seg.sections.items[self.text_section_index.?];
2216 const entry_sym = self.symtab.get("_main") orelse return error.MissingMainEntrypoint;2190 const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint;
2191 const entry_sym = sym.cast(Symbol.Regular) orelse unreachable;
2217 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;2192 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;
2218 ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr);2193 ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr);
2219}2194}
...@@ -2226,24 +2201,21 @@ fn writeRebaseInfoTable(self: *Zld) !void {...@@ -2226,24 +2201,21 @@ fn writeRebaseInfoTable(self: *Zld) !void {
2226 pointers.appendSliceAssumeCapacity(self.local_rebases.items);2201 pointers.appendSliceAssumeCapacity(self.local_rebases.items);
22272202
2228 if (self.got_section_index) |idx| {2203 if (self.got_section_index) |idx| {
2229 // TODO this should be cleaned up!
2230 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;2204 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2231 const sect = seg.sections.items[idx];2205 const sect = seg.sections.items[idx];
2232 const base_offset = sect.addr - seg.inner.vmaddr;2206 const base_offset = sect.addr - seg.inner.vmaddr;
2233 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);2207 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
22342208
2235 for (self.got_entries.items()) |entry| {2209 for (self.got_entries.items) |sym| {
2236 if (entry.value.tag == .import) continue;2210 if (sym.@"type" == .proxy) continue;
2237
2238 try pointers.append(.{2211 try pointers.append(.{
2239 .offset = base_offset + entry.value.index * @sizeOf(u64),2212 .offset = base_offset + sym.got_index.? * @sizeOf(u64),
2240 .segment_id = segment_id,2213 .segment_id = segment_id,
2241 });2214 });
2242 }2215 }
2243 }2216 }
22442217
2245 if (self.mod_init_func_section_index) |idx| {2218 if (self.mod_init_func_section_index) |idx| {
2246 // TODO audit and investigate this.
2247 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;2219 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2248 const sect = seg.sections.items[idx];2220 const sect = seg.sections.items[idx];
2249 const base_offset = sect.addr - seg.inner.vmaddr;2221 const base_offset = sect.addr - seg.inner.vmaddr;
...@@ -2267,10 +2239,10 @@ fn writeRebaseInfoTable(self: *Zld) !void {...@@ -2267,10 +2239,10 @@ fn writeRebaseInfoTable(self: *Zld) !void {
2267 const base_offset = sect.addr - seg.inner.vmaddr;2239 const base_offset = sect.addr - seg.inner.vmaddr;
2268 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);2240 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
22692241
2270 try pointers.ensureCapacity(pointers.items.len + self.stubs.items().len);2242 try pointers.ensureCapacity(pointers.items.len + self.stubs.items.len);
2271 for (self.stubs.items()) |entry| {2243 for (self.stubs.items) |sym| {
2272 pointers.appendAssumeCapacity(.{2244 pointers.appendAssumeCapacity(.{
2273 .offset = base_offset + entry.value * @sizeOf(u64),2245 .offset = base_offset + sym.stubs_index.? * @sizeOf(u64),
2274 .segment_id = segment_id,2246 .segment_id = segment_id,
2275 });2247 });
2276 }2248 }
...@@ -2306,21 +2278,16 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2306,21 +2278,16 @@ fn writeBindInfoTable(self: *Zld) !void {
2306 const base_offset = sect.addr - seg.inner.vmaddr;2278 const base_offset = sect.addr - seg.inner.vmaddr;
2307 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);2279 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
23082280
2309 for (self.got_entries.items()) |entry| {2281 for (self.got_entries.items) |sym| {
2310 if (entry.value.tag == .local) continue;2282 if (sym.cast(Symbol.Proxy)) |proxy| {
23112283 const dylib_ordinal = proxy.dylib + 1;
2312 const dylib_ordinal = dylib_ordinal: {2284 try pointers.append(.{
2313 const sym = self.symtab.get(entry.key) orelse continue; // local indirection2285 .offset = base_offset + proxy.base.got_index.? * @sizeOf(u64),
2314 if (sym.tag != .import) continue; // local indirection2286 .segment_id = segment_id,
2315 break :dylib_ordinal sym.file.? + 1;2287 .dylib_ordinal = dylib_ordinal,
2316 };2288 .name = proxy.base.name,
23172289 });
2318 try pointers.append(.{2290 }
2319 .offset = base_offset + entry.value.index * @sizeOf(u64),
2320 .segment_id = segment_id,
2321 .dylib_ordinal = dylib_ordinal,
2322 .name = entry.key,
2323 });
2324 }2291 }
2325 }2292 }
23262293
...@@ -2330,14 +2297,15 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2330,14 +2297,15 @@ fn writeBindInfoTable(self: *Zld) !void {
2330 const base_offset = sect.addr - seg.inner.vmaddr;2297 const base_offset = sect.addr - seg.inner.vmaddr;
2331 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);2298 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
23322299
2333 const sym = self.symtab.get("__tlv_bootstrap") orelse unreachable;2300 const sym = self.imports.get("__tlv_bootstrap") orelse unreachable;
2334 const dylib_ordinal = sym.file.? + 1;2301 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
2302 const dylib_ordinal = proxy.dylib + 1;
23352303
2336 try pointers.append(.{2304 try pointers.append(.{
2337 .offset = base_offset,2305 .offset = base_offset,
2338 .segment_id = segment_id,2306 .segment_id = segment_id,
2339 .dylib_ordinal = dylib_ordinal,2307 .dylib_ordinal = dylib_ordinal,
2340 .name = "__tlv_bootstrap",2308 .name = proxy.base.name,
2341 });2309 });
2342 }2310 }
23432311
...@@ -2369,20 +2337,16 @@ fn writeLazyBindInfoTable(self: *Zld) !void {...@@ -2369,20 +2337,16 @@ fn writeLazyBindInfoTable(self: *Zld) !void {
2369 const base_offset = sect.addr - seg.inner.vmaddr;2337 const base_offset = sect.addr - seg.inner.vmaddr;
2370 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);2338 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
23712339
2372 try pointers.ensureCapacity(self.stubs.items().len);2340 try pointers.ensureCapacity(self.stubs.items.len);
2373
2374 for (self.stubs.items()) |entry| {
2375 const dylib_ordinal = dylib_ordinal: {
2376 const sym = self.symtab.get(entry.key) orelse unreachable;
2377 assert(sym.tag == .import);
2378 break :dylib_ordinal sym.file.? + 1;
2379 };
23802341
2342 for (self.stubs.items) |sym| {
2343 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
2344 const dylib_ordinal = proxy.dylib + 1;
2381 pointers.appendAssumeCapacity(.{2345 pointers.appendAssumeCapacity(.{
2382 .offset = base_offset + entry.value * @sizeOf(u64),2346 .offset = base_offset + sym.stubs_index.? * @sizeOf(u64),
2383 .segment_id = segment_id,2347 .segment_id = segment_id,
2384 .dylib_ordinal = dylib_ordinal,2348 .dylib_ordinal = dylib_ordinal,
2385 .name = entry.key,2349 .name = sym.name,
2386 });2350 });
2387 }2351 }
2388 }2352 }
...@@ -2451,7 +2415,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {...@@ -2451,7 +2415,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
2451 else => {},2415 else => {},
2452 }2416 }
2453 }2417 }
2454 assert(self.stubs.items().len <= offsets.items.len);2418 assert(self.stubs.items.len <= offsets.items.len);
24552419
2456 const stub_size: u4 = switch (self.arch.?) {2420 const stub_size: u4 = switch (self.arch.?) {
2457 .x86_64 => 10,2421 .x86_64 => 10,
...@@ -2464,9 +2428,10 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {...@@ -2464,9 +2428,10 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
2464 else => unreachable,2428 else => unreachable,
2465 };2429 };
2466 var buf: [@sizeOf(u32)]u8 = undefined;2430 var buf: [@sizeOf(u32)]u8 = undefined;
2467 for (self.stubs.items()) |entry| {2431 for (self.stubs.items) |sym| {
2468 const placeholder_off = self.stub_helper_stubs_start_off.? + entry.value * stub_size + off;2432 const index = sym.stubs_index orelse unreachable;
2469 mem.writeIntLittle(u32, &buf, offsets.items[entry.value]);2433 const placeholder_off = self.stub_helper_stubs_start_off.? + index * stub_size + off;
2434 mem.writeIntLittle(u32, &buf, offsets.items[index]);
2470 try self.file.?.pwriteAll(&buf, placeholder_off);2435 try self.file.?.pwriteAll(&buf, placeholder_off);
2471 }2436 }
2472}2437}
...@@ -2478,12 +2443,13 @@ fn writeExportInfo(self: *Zld) !void {...@@ -2478,12 +2443,13 @@ fn writeExportInfo(self: *Zld) !void {
2478 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2443 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
24792444
2480 // TODO export items for dylibs2445 // TODO export items for dylibs
2481 const sym = self.symtab.get("_main") orelse return error.MissingMainEntrypoint;2446 const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint;
2482 assert(sym.address >= text_segment.inner.vmaddr);2447 const reg = sym.cast(Symbol.Regular) orelse unreachable;
2448 assert(reg.address >= text_segment.inner.vmaddr);
24832449
2484 try trie.put(.{2450 try trie.put(.{
2485 .name = "_main",2451 .name = sym.name,
2486 .vmaddr_offset = sym.address - text_segment.inner.vmaddr,2452 .vmaddr_offset = reg.address - text_segment.inner.vmaddr,
2487 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,2453 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
2488 });2454 });
24892455
...@@ -2511,7 +2477,7 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2511,7 +2477,7 @@ fn writeDebugInfo(self: *Zld) !void {
2511 var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);2477 var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);
2512 defer stabs.deinit();2478 defer stabs.deinit();
25132479
2514 for (self.objects.items) |object, object_id| {2480 for (self.objects.items) |object| {
2515 const tu_path = object.tu_path orelse continue;2481 const tu_path = object.tu_path orelse continue;
2516 const tu_mtime = object.tu_mtime orelse continue;2482 const tu_mtime = object.tu_mtime orelse continue;
2517 const dirname = std.fs.path.dirname(tu_path) orelse "./";2483 const dirname = std.fs.path.dirname(tu_path) orelse "./";
...@@ -2540,39 +2506,42 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2540,39 +2506,42 @@ fn writeDebugInfo(self: *Zld) !void {
2540 .n_value = 0, //tu_mtime, TODO figure out why precalculated mtime value doesn't work2506 .n_value = 0, //tu_mtime, TODO figure out why precalculated mtime value doesn't work
2541 });2507 });
25422508
2543 for (object.stabs.items) |stab| {2509 for (object.symbols.items) |sym| {
2544 const entry = object.locals.items()[stab.symbol];2510 if (sym.@"type" != .regular) continue;
2545 const sym = entry.value;2511 const reg = sym.cast(Symbol.Regular) orelse unreachable;
25462512
2547 switch (stab.tag) {2513 if (reg.isTemp() or reg.stab == null) continue;
2514 const stab = reg.stab orelse unreachable;
2515
2516 switch (stab.kind) {
2548 .function => {2517 .function => {
2549 try stabs.append(.{2518 try stabs.append(.{
2550 .n_strx = 0,2519 .n_strx = 0,
2551 .n_type = macho.N_BNSYM,2520 .n_type = macho.N_BNSYM,
2552 .n_sect = sym.section,2521 .n_sect = reg.section,
2553 .n_desc = 0,2522 .n_desc = 0,
2554 .n_value = sym.address,2523 .n_value = reg.address,
2555 });2524 });
2556 try stabs.append(.{2525 try stabs.append(.{
2557 .n_strx = try self.makeString(sym.name),2526 .n_strx = try self.makeString(sym.name),
2558 .n_type = macho.N_FUN,2527 .n_type = macho.N_FUN,
2559 .n_sect = sym.section,2528 .n_sect = reg.section,
2560 .n_desc = 0,2529 .n_desc = 0,
2561 .n_value = sym.address,2530 .n_value = reg.address,
2562 });2531 });
2563 try stabs.append(.{2532 try stabs.append(.{
2564 .n_strx = 0,2533 .n_strx = 0,
2565 .n_type = macho.N_FUN,2534 .n_type = macho.N_FUN,
2566 .n_sect = 0,2535 .n_sect = 0,
2567 .n_desc = 0,2536 .n_desc = 0,
2568 .n_value = stab.size.?,2537 .n_value = stab.size,
2569 });2538 });
2570 try stabs.append(.{2539 try stabs.append(.{
2571 .n_strx = 0,2540 .n_strx = 0,
2572 .n_type = macho.N_ENSYM,2541 .n_type = macho.N_ENSYM,
2573 .n_sect = sym.section,2542 .n_sect = reg.section,
2574 .n_desc = 0,2543 .n_desc = 0,
2575 .n_value = stab.size.?,2544 .n_value = stab.size,
2576 });2545 });
2577 },2546 },
2578 .global => {2547 .global => {
...@@ -2588,9 +2557,9 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2588,9 +2557,9 @@ fn writeDebugInfo(self: *Zld) !void {
2588 try stabs.append(.{2557 try stabs.append(.{
2589 .n_strx = try self.makeString(sym.name),2558 .n_strx = try self.makeString(sym.name),
2590 .n_type = macho.N_STSYM,2559 .n_type = macho.N_STSYM,
2591 .n_sect = sym.section,2560 .n_sect = reg.section,
2592 .n_desc = 0,2561 .n_desc = 0,
2593 .n_value = sym.address,2562 .n_value = reg.address,
2594 });2563 });
2595 },2564 },
2596 }2565 }
...@@ -2626,27 +2595,6 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2626,27 +2595,6 @@ fn writeDebugInfo(self: *Zld) !void {
2626 dysymtab.nlocalsym = symtab.nsyms;2595 dysymtab.nlocalsym = symtab.nsyms;
2627}2596}
26282597
2629fn populateStringTable(self: *Zld) !void {
2630 for (self.objects.items) |*object| {
2631 for (object.symtab.items) |*sym| {
2632 switch (sym.tag) {
2633 .undef, .import => continue,
2634 else => {},
2635 }
2636 const sym_name = object.getString(sym.inner.n_strx);
2637 const n_strx = try self.makeString(sym_name);
2638 sym.inner.n_strx = n_strx;
2639 }
2640 }
2641
2642 for (self.symtab.items()) |*entry| {
2643 if (entry.value.tag != .import) continue;
2644
2645 const n_strx = try self.makeString(entry.key);
2646 entry.value.inner.n_strx = n_strx;
2647 }
2648}
2649
2650fn writeSymbolTable(self: *Zld) !void {2598fn writeSymbolTable(self: *Zld) !void {
2651 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2599 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2652 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2600 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
...@@ -2654,56 +2602,52 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2654,56 +2602,52 @@ fn writeSymbolTable(self: *Zld) !void {
2654 var locals = std.ArrayList(macho.nlist_64).init(self.allocator);2602 var locals = std.ArrayList(macho.nlist_64).init(self.allocator);
2655 defer locals.deinit();2603 defer locals.deinit();
26562604
2605 var exports = std.ArrayList(macho.nlist_64).init(self.allocator);
2606 defer exports.deinit();
2607
2657 for (self.objects.items) |object| {2608 for (self.objects.items) |object| {
2658 for (object.locals.items()) |entry| {2609 for (object.symbols.items) |sym| {
2659 const sym = entry.value;2610 const final = sym.getTopmostAlias();
2660 if (sym.tag != .local) continue;2611 if (final.@"type" != .regular) continue;
26612612
2662 try locals.append(.{2613 const reg = final.cast(Symbol.Regular) orelse unreachable;
2663 .n_strx = try self.makeString(sym.name),2614 if (reg.isTemp()) continue;
2664 .n_type = macho.N_SECT,2615
2665 .n_sect = sym.section,2616 switch (reg.linkage) {
2666 .n_desc = 0,2617 .translation_unit => {
2667 .n_value = sym.address,2618 try locals.append(.{
2668 });2619 .n_strx = try self.makeString(sym.name),
2620 .n_type = macho.N_SECT,
2621 .n_sect = reg.section,
2622 .n_desc = 0,
2623 .n_value = reg.address,
2624 });
2625 },
2626 else => {
2627 try exports.append(.{
2628 .n_strx = try self.makeString(sym.name),
2629 .n_type = macho.N_SECT | macho.N_EXT,
2630 .n_sect = reg.section,
2631 .n_desc = 0,
2632 .n_value = reg.address,
2633 });
2634 },
2635 }
2669 }2636 }
2670 }2637 }
26712638
2672 var exports = std.ArrayList(macho.nlist_64).init(self.allocator);
2673 defer exports.deinit();
2674
2675 var undefs = std.ArrayList(macho.nlist_64).init(self.allocator);2639 var undefs = std.ArrayList(macho.nlist_64).init(self.allocator);
2676 defer undefs.deinit();2640 defer undefs.deinit();
26772641
2678 var undefs_ids = std.StringHashMap(u32).init(self.allocator);2642 for (self.imports.items()) |entry| {
2679 defer undefs_ids.deinit();
2680
2681 var undef_id: u32 = 0;
2682 for (self.symtab.items()) |entry| {
2683 const sym = entry.value;2643 const sym = entry.value;
2684 switch (sym.tag) {2644 try undefs.append(.{
2685 .weak, .strong => {2645 .n_strx = try self.makeString(sym.name),
2686 try exports.append(.{2646 .n_type = macho.N_UNDF | macho.N_EXT,
2687 .n_strx = try self.makeString(sym.name),2647 .n_sect = 0,
2688 .n_type = macho.N_SECT | macho.N_EXT,2648 .n_desc = macho.N_SYMBOL_RESOLVER | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
2689 .n_sect = sym.section,2649 .n_value = 0,
2690 .n_desc = 0,2650 });
2691 .n_value = sym.address,
2692 });
2693 },
2694 .import => {
2695 try undefs.append(.{
2696 .n_strx = try self.makeString(sym.name),
2697 .n_type = macho.N_UNDF | macho.N_EXT,
2698 .n_sect = 0,
2699 .n_desc = macho.N_SYMBOL_RESOLVER | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
2700 .n_value = 0,
2701 });
2702 try undefs_ids.putNoClobber(sym.name, undef_id);
2703 undef_id += 1;
2704 },
2705 else => unreachable,
2706 }
2707 }2651 }
27082652
2709 const nlocals = locals.items.len;2653 const nlocals = locals.items.len;
...@@ -2743,8 +2687,8 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2743,8 +2687,8 @@ fn writeSymbolTable(self: *Zld) !void {
2743 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;2687 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2744 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];2688 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
27452689
2746 const nstubs = @intCast(u32, self.stubs.items().len);2690 const nstubs = @intCast(u32, self.stubs.items.len);
2747 const ngot_entries = @intCast(u32, self.got_entries.items().len);2691 const ngot_entries = @intCast(u32, self.got_entries.items.len);
27482692
2749 dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);2693 dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
2750 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;2694 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
...@@ -2764,25 +2708,25 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2764,25 +2708,25 @@ fn writeSymbolTable(self: *Zld) !void {
2764 var writer = stream.writer();2708 var writer = stream.writer();
27652709
2766 stubs.reserved1 = 0;2710 stubs.reserved1 = 0;
2767 for (self.stubs.items()) |entry| {2711 for (self.stubs.items) |sym| {
2768 const id = undefs_ids.get(entry.key) orelse unreachable;2712 const id = self.imports.getIndex(sym.name) orelse unreachable;
2769 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);2713 try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id));
2770 }2714 }
27712715
2772 got.reserved1 = nstubs;2716 got.reserved1 = nstubs;
2773 for (self.got_entries.items()) |entry| {2717 for (self.got_entries.items) |sym| {
2774 if (entry.value.tag == .import) {2718 if (sym.@"type" == .proxy) {
2775 const id = undefs_ids.get(entry.key) orelse unreachable;2719 const id = self.imports.getIndex(sym.name) orelse unreachable;
2776 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);2720 try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id));
2777 } else {2721 } else {
2778 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);2722 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
2779 }2723 }
2780 }2724 }
27812725
2782 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;2726 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
2783 for (self.stubs.items()) |entry| {2727 for (self.stubs.items) |sym| {
2784 const id = undefs_ids.get(entry.key) orelse unreachable;2728 const id = self.imports.getIndex(sym.name) orelse unreachable;
2785 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);2729 try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id));
2786 }2730 }
27872731
2788 try self.file.?.pwriteAll(buf, dysymtab.indirectsymoff);2732 try self.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
...@@ -2979,3 +2923,33 @@ pub fn parseName(name: *const [16]u8) []const u8 {...@@ -2979,3 +2923,33 @@ pub fn parseName(name: *const [16]u8) []const u8 {
2979 const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;2923 const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
2980 return name[0..len];2924 return name[0..len];
2981}2925}
2926
2927fn printSymbols(self: *Zld) void {
2928 log.debug("globals", .{});
2929 for (self.globals.items()) |entry| {
2930 const sym = entry.value.cast(Symbol.Regular) orelse unreachable;
2931 log.debug(" | {s} @ {*}", .{ sym.base.name, entry.value });
2932 log.debug(" => alias of {*}", .{sym.base.alias});
2933 log.debug(" => linkage {s}", .{sym.linkage});
2934 log.debug(" => defined in {s}", .{sym.file.name.?});
2935 }
2936 for (self.objects.items) |object| {
2937 log.debug("locals in {s}", .{object.name.?});
2938 for (object.symbols.items) |sym| {
2939 log.debug(" | {s} @ {*}", .{ sym.name, sym });
2940 log.debug(" => alias of {*}", .{sym.alias});
2941 if (sym.cast(Symbol.Regular)) |reg| {
2942 log.debug(" => linkage {s}", .{reg.linkage});
2943 } else {
2944 log.debug(" => unresolved", .{});
2945 }
2946 }
2947 }
2948 log.debug("proxies", .{});
2949 for (self.imports.items()) |entry| {
2950 const sym = entry.value.cast(Symbol.Proxy) orelse unreachable;
2951 log.debug(" | {s} @ {*}", .{ sym.base.name, entry.value });
2952 log.debug(" => alias of {*}", .{sym.base.alias});
2953 log.debug(" => defined in libSystem.B.dylib", .{});
2954 }
2955}
src/link/MachO/reloc.zig+7-3
...@@ -10,6 +10,7 @@ const aarch64 = @import("reloc/aarch64.zig");...@@ -10,6 +10,7 @@ const aarch64 = @import("reloc/aarch64.zig");
10const x86_64 = @import("reloc/x86_64.zig");10const x86_64 = @import("reloc/x86_64.zig");
1111
12const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
13const Symbol = @import("Symbol.zig");
1314
14pub const Relocation = struct {15pub const Relocation = struct {
15 @"type": Type,16 @"type": Type,
...@@ -75,12 +76,12 @@ pub const Relocation = struct {...@@ -75,12 +76,12 @@ pub const Relocation = struct {
75 };76 };
7677
77 pub const Target = union(enum) {78 pub const Target = union(enum) {
78 symbol: u32,79 symbol: *Symbol,
79 section: u16,80 section: u16,
8081
81 pub fn from_reloc(reloc: macho.relocation_info) Target {82 pub fn from_reloc(reloc: macho.relocation_info, symbols: []*Symbol) Target {
82 return if (reloc.r_extern == 1) .{83 return if (reloc.r_extern == 1) .{
83 .symbol = reloc.r_symbolnum,84 .symbol = symbols[reloc.r_symbolnum],
84 } else .{85 } else .{
85 .section = @intCast(u16, reloc.r_symbolnum - 1),86 .section = @intCast(u16, reloc.r_symbolnum - 1),
86 };87 };
...@@ -136,6 +137,7 @@ pub fn parse(...@@ -136,6 +137,7 @@ pub fn parse(
136 arch: std.Target.Cpu.Arch,137 arch: std.Target.Cpu.Arch,
137 code: []u8,138 code: []u8,
138 relocs: []const macho.relocation_info,139 relocs: []const macho.relocation_info,
140 symbols: []*Symbol,
139) ![]*Relocation {141) ![]*Relocation {
140 var it = RelocIterator{142 var it = RelocIterator{
141 .buffer = relocs,143 .buffer = relocs,
...@@ -148,6 +150,7 @@ pub fn parse(...@@ -148,6 +150,7 @@ pub fn parse(
148 .it = &it,150 .it = &it,
149 .code = code,151 .code = code,
150 .parsed = std.ArrayList(*Relocation).init(allocator),152 .parsed = std.ArrayList(*Relocation).init(allocator),
153 .symbols = symbols,
151 };154 };
152 defer parser.deinit();155 defer parser.deinit();
153 try parser.parse();156 try parser.parse();
...@@ -160,6 +163,7 @@ pub fn parse(...@@ -160,6 +163,7 @@ pub fn parse(
160 .it = &it,163 .it = &it,
161 .code = code,164 .code = code,
162 .parsed = std.ArrayList(*Relocation).init(allocator),165 .parsed = std.ArrayList(*Relocation).init(allocator),
166 .symbols = symbols,
163 };167 };
164 defer parser.deinit();168 defer parser.deinit();
165 try parser.parse();169 try parser.parse();
src/link/MachO/reloc/aarch64.zig+9-7
...@@ -10,6 +10,7 @@ const reloc = @import("../reloc.zig");...@@ -10,6 +10,7 @@ const reloc = @import("../reloc.zig");
1010
11const Allocator = mem.Allocator;11const Allocator = mem.Allocator;
12const Relocation = reloc.Relocation;12const Relocation = reloc.Relocation;
13const Symbol = @import("../Symbol.zig");
1314
14pub const Branch = struct {15pub const Branch = struct {
15 base: Relocation,16 base: Relocation,
...@@ -188,6 +189,7 @@ pub const Parser = struct {...@@ -188,6 +189,7 @@ pub const Parser = struct {
188 it: *reloc.RelocIterator,189 it: *reloc.RelocIterator,
189 code: []u8,190 code: []u8,
190 parsed: std.ArrayList(*Relocation),191 parsed: std.ArrayList(*Relocation),
192 symbols: []*Symbol,
191 addend: ?u32 = null,193 addend: ?u32 = null,
192 subtractor: ?Relocation.Target = null,194 subtractor: ?Relocation.Target = null,
193195
...@@ -273,7 +275,7 @@ pub const Parser = struct {...@@ -273,7 +275,7 @@ pub const Parser = struct {
273 var branch = try parser.allocator.create(Branch);275 var branch = try parser.allocator.create(Branch);
274 errdefer parser.allocator.destroy(branch);276 errdefer parser.allocator.destroy(branch);
275277
276 const target = Relocation.Target.from_reloc(rel);278 const target = Relocation.Target.from_reloc(rel, parser.symbols);
277279
278 branch.* = .{280 branch.* = .{
279 .base = .{281 .base = .{
...@@ -294,7 +296,7 @@ pub const Parser = struct {...@@ -294,7 +296,7 @@ pub const Parser = struct {
294 assert(rel.r_length == 2);296 assert(rel.r_length == 2);
295297
296 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);298 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
297 const target = Relocation.Target.from_reloc(rel);299 const target = Relocation.Target.from_reloc(rel, parser.symbols);
298300
299 const offset = @intCast(u32, rel.r_address);301 const offset = @intCast(u32, rel.r_address);
300 const inst = parser.code[offset..][0..4];302 const inst = parser.code[offset..][0..4];
...@@ -400,7 +402,7 @@ pub const Parser = struct {...@@ -400,7 +402,7 @@ pub const Parser = struct {
400 aarch64.Instruction.load_store_register,402 aarch64.Instruction.load_store_register,
401 ), inst) };403 ), inst) };
402 }404 }
403 const target = Relocation.Target.from_reloc(rel);405 const target = Relocation.Target.from_reloc(rel, parser.symbols);
404406
405 var page_off = try parser.allocator.create(PageOff);407 var page_off = try parser.allocator.create(PageOff);
406 errdefer parser.allocator.destroy(page_off);408 errdefer parser.allocator.destroy(page_off);
...@@ -437,7 +439,7 @@ pub const Parser = struct {...@@ -437,7 +439,7 @@ pub const Parser = struct {
437 ), inst);439 ), inst);
438 assert(parsed_inst.size == 3);440 assert(parsed_inst.size == 3);
439441
440 const target = Relocation.Target.from_reloc(rel);442 const target = Relocation.Target.from_reloc(rel, parser.symbols);
441443
442 var page_off = try parser.allocator.create(GotPageOff);444 var page_off = try parser.allocator.create(GotPageOff);
443 errdefer parser.allocator.destroy(page_off);445 errdefer parser.allocator.destroy(page_off);
...@@ -496,7 +498,7 @@ pub const Parser = struct {...@@ -496,7 +498,7 @@ pub const Parser = struct {
496 }498 }
497 };499 };
498500
499 const target = Relocation.Target.from_reloc(rel);501 const target = Relocation.Target.from_reloc(rel, parser.symbols);
500502
501 var page_off = try parser.allocator.create(TlvpPageOff);503 var page_off = try parser.allocator.create(TlvpPageOff);
502 errdefer parser.allocator.destroy(page_off);504 errdefer parser.allocator.destroy(page_off);
...@@ -531,7 +533,7 @@ pub const Parser = struct {...@@ -531,7 +533,7 @@ pub const Parser = struct {
531 assert(rel.r_pcrel == 0);533 assert(rel.r_pcrel == 0);
532 assert(parser.subtractor == null);534 assert(parser.subtractor == null);
533535
534 parser.subtractor = Relocation.Target.from_reloc(rel);536 parser.subtractor = Relocation.Target.from_reloc(rel, parser.symbols);
535537
536 // Verify SUBTRACTOR is followed by UNSIGNED.538 // Verify SUBTRACTOR is followed by UNSIGNED.
537 const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type);539 const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type);
...@@ -554,7 +556,7 @@ pub const Parser = struct {...@@ -554,7 +556,7 @@ pub const Parser = struct {
554 var unsigned = try parser.allocator.create(reloc.Unsigned);556 var unsigned = try parser.allocator.create(reloc.Unsigned);
555 errdefer parser.allocator.destroy(unsigned);557 errdefer parser.allocator.destroy(unsigned);
556558
557 const target = Relocation.Target.from_reloc(rel);559 const target = Relocation.Target.from_reloc(rel, parser.symbols);
558 const is_64bit: bool = switch (rel.r_length) {560 const is_64bit: bool = switch (rel.r_length) {
559 3 => true,561 3 => true,
560 2 => false,562 2 => false,
src/link/MachO/reloc/x86_64.zig+9-7
...@@ -9,6 +9,7 @@ const reloc = @import("../reloc.zig");...@@ -9,6 +9,7 @@ const reloc = @import("../reloc.zig");
99
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const Relocation = reloc.Relocation;11const Relocation = reloc.Relocation;
12const Symbol = @import("../Symbol.zig");
1213
13pub const Branch = struct {14pub const Branch = struct {
14 base: Relocation,15 base: Relocation,
...@@ -95,6 +96,7 @@ pub const Parser = struct {...@@ -95,6 +96,7 @@ pub const Parser = struct {
95 it: *reloc.RelocIterator,96 it: *reloc.RelocIterator,
96 code: []u8,97 code: []u8,
97 parsed: std.ArrayList(*Relocation),98 parsed: std.ArrayList(*Relocation),
99 symbols: []*Symbol,
98 subtractor: ?Relocation.Target = null,100 subtractor: ?Relocation.Target = null,
99101
100 pub fn deinit(parser: *Parser) void {102 pub fn deinit(parser: *Parser) void {
...@@ -145,7 +147,7 @@ pub const Parser = struct {...@@ -145,7 +147,7 @@ pub const Parser = struct {
145 var branch = try parser.allocator.create(Branch);147 var branch = try parser.allocator.create(Branch);
146 errdefer parser.allocator.destroy(branch);148 errdefer parser.allocator.destroy(branch);
147149
148 const target = Relocation.Target.from_reloc(rel);150 const target = Relocation.Target.from_reloc(rel, parser.symbols);
149151
150 branch.* = .{152 branch.* = .{
151 .base = .{153 .base = .{
...@@ -165,7 +167,7 @@ pub const Parser = struct {...@@ -165,7 +167,7 @@ pub const Parser = struct {
165 assert(rel.r_length == 2);167 assert(rel.r_length == 2);
166168
167 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);169 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
168 const target = Relocation.Target.from_reloc(rel);170 const target = Relocation.Target.from_reloc(rel, parser.symbols);
169 const is_extern = rel.r_extern == 1;171 const is_extern = rel.r_extern == 1;
170172
171 const offset = @intCast(u32, rel.r_address);173 const offset = @intCast(u32, rel.r_address);
...@@ -211,7 +213,7 @@ pub const Parser = struct {...@@ -211,7 +213,7 @@ pub const Parser = struct {
211213
212 const offset = @intCast(u32, rel.r_address);214 const offset = @intCast(u32, rel.r_address);
213 const inst = parser.code[offset..][0..4];215 const inst = parser.code[offset..][0..4];
214 const target = Relocation.Target.from_reloc(rel);216 const target = Relocation.Target.from_reloc(rel, parser.symbols);
215217
216 var got_load = try parser.allocator.create(GotLoad);218 var got_load = try parser.allocator.create(GotLoad);
217 errdefer parser.allocator.destroy(got_load);219 errdefer parser.allocator.destroy(got_load);
...@@ -237,7 +239,7 @@ pub const Parser = struct {...@@ -237,7 +239,7 @@ pub const Parser = struct {
237239
238 const offset = @intCast(u32, rel.r_address);240 const offset = @intCast(u32, rel.r_address);
239 const inst = parser.code[offset..][0..4];241 const inst = parser.code[offset..][0..4];
240 const target = Relocation.Target.from_reloc(rel);242 const target = Relocation.Target.from_reloc(rel, parser.symbols);
241243
242 var got = try parser.allocator.create(Got);244 var got = try parser.allocator.create(Got);
243 errdefer parser.allocator.destroy(got);245 errdefer parser.allocator.destroy(got);
...@@ -263,7 +265,7 @@ pub const Parser = struct {...@@ -263,7 +265,7 @@ pub const Parser = struct {
263265
264 const offset = @intCast(u32, rel.r_address);266 const offset = @intCast(u32, rel.r_address);
265 const inst = parser.code[offset..][0..4];267 const inst = parser.code[offset..][0..4];
266 const target = Relocation.Target.from_reloc(rel);268 const target = Relocation.Target.from_reloc(rel, parser.symbols);
267269
268 var tlv = try parser.allocator.create(Tlv);270 var tlv = try parser.allocator.create(Tlv);
269 errdefer parser.allocator.destroy(tlv);271 errdefer parser.allocator.destroy(tlv);
...@@ -288,7 +290,7 @@ pub const Parser = struct {...@@ -288,7 +290,7 @@ pub const Parser = struct {
288 assert(rel.r_pcrel == 0);290 assert(rel.r_pcrel == 0);
289 assert(parser.subtractor == null);291 assert(parser.subtractor == null);
290292
291 parser.subtractor = Relocation.Target.from_reloc(rel);293 parser.subtractor = Relocation.Target.from_reloc(rel, parser.symbols);
292294
293 // Verify SUBTRACTOR is followed by UNSIGNED.295 // Verify SUBTRACTOR is followed by UNSIGNED.
294 const next = @intToEnum(macho.reloc_type_x86_64, parser.it.peek().r_type);296 const next = @intToEnum(macho.reloc_type_x86_64, parser.it.peek().r_type);
...@@ -311,7 +313,7 @@ pub const Parser = struct {...@@ -311,7 +313,7 @@ pub const Parser = struct {
311 var unsigned = try parser.allocator.create(reloc.Unsigned);313 var unsigned = try parser.allocator.create(reloc.Unsigned);
312 errdefer parser.allocator.destroy(unsigned);314 errdefer parser.allocator.destroy(unsigned);
313315
314 const target = Relocation.Target.from_reloc(rel);316 const target = Relocation.Target.from_reloc(rel, parser.symbols);
315 const is_64bit: bool = switch (rel.r_length) {317 const is_64bit: bool = switch (rel.r_length) {
316 3 => true,318 3 => true,
317 2 => false,319 2 => false,
src/stage1/stage1.h+4-1
...@@ -56,7 +56,7 @@ enum TargetSubsystem {...@@ -56,7 +56,7 @@ enum TargetSubsystem {
5656
5757
58// ABI warning58// ABI warning
59// Synchronize with target.cpp::os_list59// Synchronize with std.Target.Os.Tag and target.cpp::os_list
60enum Os {60enum Os {
61 OsFreestanding,61 OsFreestanding,
62 OsAnanas,62 OsAnanas,
...@@ -94,6 +94,9 @@ enum Os {...@@ -94,6 +94,9 @@ enum Os {
94 OsWASI,94 OsWASI,
95 OsEmscripten,95 OsEmscripten,
96 OsUefi,96 OsUefi,
97 OsOpenCL,
98 OsGLSL450,
99 OsVulkan,
97 OsOther,100 OsOther,
98};101};
99102
src/stage1/target.cpp+16
...@@ -122,6 +122,9 @@ static const Os os_list[] = {...@@ -122,6 +122,9 @@ static const Os os_list[] = {
122 OsWASI,122 OsWASI,
123 OsEmscripten,123 OsEmscripten,
124 OsUefi,124 OsUefi,
125 OsOpenCL,
126 OsGLSL450,
127 OsVulkan,
125 OsOther,128 OsOther,
126};129};
127130
...@@ -213,6 +216,9 @@ Os target_os_enum(size_t index) {...@@ -213,6 +216,9 @@ Os target_os_enum(size_t index) {
213ZigLLVM_OSType get_llvm_os_type(Os os_type) {216ZigLLVM_OSType get_llvm_os_type(Os os_type) {
214 switch (os_type) {217 switch (os_type) {
215 case OsFreestanding:218 case OsFreestanding:
219 case OsOpenCL:
220 case OsGLSL450:
221 case OsVulkan:
216 case OsOther:222 case OsOther:
217 return ZigLLVM_UnknownOS;223 return ZigLLVM_UnknownOS;
218 case OsAnanas:224 case OsAnanas:
...@@ -330,6 +336,9 @@ const char *target_os_name(Os os_type) {...@@ -330,6 +336,9 @@ const char *target_os_name(Os os_type) {
330 case OsHurd:336 case OsHurd:
331 case OsWASI:337 case OsWASI:
332 case OsEmscripten:338 case OsEmscripten:
339 case OsOpenCL:
340 case OsGLSL450:
341 case OsVulkan:
333 return ZigLLVMGetOSTypeName(get_llvm_os_type(os_type));342 return ZigLLVMGetOSTypeName(get_llvm_os_type(os_type));
334 }343 }
335 zig_unreachable();344 zig_unreachable();
...@@ -733,6 +742,9 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {...@@ -733,6 +742,9 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
733 case OsAMDPAL:742 case OsAMDPAL:
734 case OsHermitCore:743 case OsHermitCore:
735 case OsHurd:744 case OsHurd:
745 case OsOpenCL:
746 case OsGLSL450:
747 case OsVulkan:
736 zig_panic("TODO c type size in bits for this target");748 zig_panic("TODO c type size in bits for this target");
737 }749 }
738 zig_unreachable();750 zig_unreachable();
...@@ -999,6 +1011,10 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {...@@ -999,6 +1011,10 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
999 case OsWASI:1011 case OsWASI:
1000 case OsEmscripten:1012 case OsEmscripten:
1001 return ZigLLVM_Musl;1013 return ZigLLVM_Musl;
1014 case OsOpenCL:
1015 case OsGLSL450:
1016 case OsVulkan:
1017 return ZigLLVM_UnknownEnvironment;
1002 }1018 }
1003 zig_unreachable();1019 zig_unreachable();
1004}1020}
tools/update_cpu_features.zig+22
...@@ -239,6 +239,28 @@ const llvm_targets = [_]LlvmTarget{...@@ -239,6 +239,28 @@ const llvm_targets = [_]LlvmTarget{
239 "zcz_fp",239 "zcz_fp",
240 },240 },
241 },241 },
242 .{
243 .llvm_name = null,
244 .zig_name = "xgene1",
245 .features = &.{
246 "fp_armv8",
247 "neon",
248 "perfmon",
249 "v8a",
250 },
251 },
252 .{
253 .llvm_name = null,
254 .zig_name = "emag",
255 .features = &.{
256 "crc",
257 "crypto",
258 "fp_armv8",
259 "neon",
260 "perfmon",
261 "v8a",
262 },
263 },
242 },264 },
243 },265 },
244 .{266 .{