authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-12 16:41:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-12 16:41:20-07:00
logc9cc09a3bfb45d93b84577238047cd69ef0a7d88
tree1686cda92ae0c5d9ae55c02e7755c55d4e6f3c18
parent71afc3088009944fcd8339ac71e69a0b77a781ab
parent40a47eae65b918866abc9d745f89d837f6a1e591

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

Conflicts: * lib/std/os/linux.zig * lib/std/os/windows/bits.zig * src/Module.zig * src/Sema.zig * test/stage2/test.zig Mainly I wanted Jakub's new macOS code for respecting stack size, since we now depend on it for debug builds able to pass one of the test cases for recursive comptime function calls with `@setEvalBranchQuota`. The conflicts were all trivial.

72 files changed, 5411 insertions(+), 1378 deletions(-)

ci/azure/linux_script+5-3
......@@ -9,7 +9,7 @@ sudo apt-get install -y cmake s3cmd tidy
99ZIGDIR="$(pwd)"
1010ARCH="$(uname -m)"
1111TARGET="$ARCH-linux-musl"
12CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.1939+5a3ea9bec"
12CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.2168+2d1196773"
1313PREFIX="$HOME/$CACHE_BASENAME"
1414MCPU="baseline"
1515JOBS="-j$(nproc)"
......@@ -25,8 +25,10 @@ wget -nv "https://ziglang.org/deps/$QEMUBASE.tar.xz"
2525tar xf "$QEMUBASE.tar.xz"
2626export PATH="$(pwd)/$QEMUBASE/bin:$PATH"
2727
28WASMTIME="wasmtime-v0.20.0-x86_64-linux"
29wget -nv "https://github.com/bytecodealliance/wasmtime/releases/download/v0.20.0/$WASMTIME.tar.xz"
28# Bump to v0.23 once this issue is resolved:
29# https://github.com/ziglang/zig/issues/8742
30WASMTIME="wasmtime-v0.22.1-x86_64-linux"
31wget -nv "https://github.com/bytecodealliance/wasmtime/releases/download/v0.22.1/$WASMTIME.tar.xz"
3032tar xf "$WASMTIME.tar.xz"
3133export PATH="$(pwd)/$WASMTIME:$PATH"
3234
ci/azure/macos_arm64_script+60-60
......@@ -3,24 +3,31 @@
33set -x
44set -e
55
6brew update && brew install s3cmd ninja gnu-tar
6brew update && brew install s3cmd
77
88ZIGDIR="$(pwd)"
9
10HOST_ARCH="x86_64"
11HOST_TARGET="$HOST_ARCH-macos-gnu"
12HOST_MCPU="baseline"
13HOST_CACHE_BASENAME="zig+llvm+lld+clang-$HOST_TARGET-0.8.0-dev.2168+2d1196773"
14HOST_PREFIX="$HOME/$HOST_CACHE_BASENAME"
15
916ARCH="aarch64"
10# {product}-{os}{sdk_version}-{arch}-{llvm_version}-{cmake_build_type}
11CACHE_HOST_BASENAME="ci-llvm-macos10.15-x86_64-12.0.0.1-release"
12CACHE_ARM64_BASENAME="ci-llvm-macos11.0-arm64-12.0.0.1-release"
13PREFIX_HOST="$HOME/$CACHE_HOST_BASENAME"
14PREFIX_ARM64="$HOME/$CACHE_ARM64_BASENAME"
17TARGET="$ARCH-macos-gnu"
18MCPU="cyclone"
19CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.2168+2d1196773"
20PREFIX="$HOME/$CACHE_BASENAME"
21
1522JOBS="-j2"
1623
17rm -rf $PREFIX
24rm -rf $HOST_PREFIX $PREFIX
1825cd $HOME
19wget -nv "https://ziglang.org/deps/$CACHE_HOST_BASENAME.tar.xz"
20wget -nv "https://ziglang.org/deps/$CACHE_ARM64_BASENAME.tar.xz"
2126
22gtar xf "$CACHE_HOST_BASENAME.tar.xz"
23gtar xf "$CACHE_ARM64_BASENAME.tar.xz"
27wget -nv "https://ziglang.org/deps/$HOST_CACHE_BASENAME.tar.xz"
28wget -nv "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"
29tar xf "$HOST_CACHE_BASENAME.tar.xz"
30tar xf "$CACHE_BASENAME.tar.xz"
2431
2532cd $ZIGDIR
2633
......@@ -30,83 +37,75 @@ git config core.abbrev 9
3037git fetch --unshallow || true
3138git fetch --tags
3239
33# Select xcode: latest version found on vmImage macOS-10.15 .
34DEVELOPER_DIR=/Applications/Xcode_12.4.app
40# Build host zig compiler in debug so that we can get the
41# current version when packaging
3542
36export ZIG_LOCAL_CACHE_DIR="$ZIGDIR/zig-cache"
37export ZIG_GLOBAL_CACHE_DIR="$ZIGDIR/zig-cache"
43ZIG="$HOST_PREFIX/bin/zig"
3844
39# Build zig for host and use `Debug` type to make builds a little faster.
45export CC="$ZIG cc -target $HOST_TARGET -mcpu=$HOST_MCPU"
46export CXX="$ZIG c++ -target $HOST_TARGET -mcpu=$HOST_MCPU"
4047
41cd $ZIGDIR
4248mkdir build.host
4349cd build.host
44cmake -G "Ninja" .. \
50cmake .. \
4551 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
46 -DCMAKE_PREFIX_PATH="$PREFIX_HOST" \
47 -DCMAKE_BUILD_TYPE="Debug" \
48 -DZIG_STATIC="OFF"
49
50# Build but do not install.
51ninja $JOBS
52 -DCMAKE_PREFIX_PATH="$HOST_PREFIX" \
53 -DCMAKE_BUILD_TYPE=Debug \
54 -DZIG_TARGET_TRIPLE="$HOST_TARGET" \
55 -DZIG_TARGET_MCPU="$HOST_MCPU" \
56 -DZIG_STATIC=ON
5257
53ZIG_EXE="$ZIGDIR/build.host/zig"
58unset CC
59unset CXX
5460
55# Build zig for arm64 target.
56# - use `Release` type for published tarballs
57# - ad-hoc codesign with linker
58# - note: apple quarantine of downloads (eg. via safari) still apply
61make $JOBS install
5962
63# Build zig compiler cross-compiled for arm64
6064cd $ZIGDIR
61mkdir build.arm64
62cd build.arm64
63cmake -G "Ninja" .. \
65
66ZIG="$ZIGDIR/build.host/release/bin/zig"
67
68export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
69export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
70
71mkdir build
72cd build
73cmake .. \
6474 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
65 -DCMAKE_PREFIX_PATH="$PREFIX_ARM64" \
66 -DCMAKE_BUILD_TYPE="Release" \
67 -DCMAKE_CROSSCOMPILING="True" \
68 -DCMAKE_SYSTEM_NAME="Darwin" \
69 -DCMAKE_C_FLAGS="-arch arm64" \
70 -DCMAKE_CXX_FLAGS="-arch arm64" \
71 -DCMAKE_EXE_LINKER_FLAGS="-lz -Xlinker -adhoc_codesign" \
72 -DZIG_USE_LLVM_CONFIG="OFF" \
73 -DZIG_EXECUTABLE="$ZIG_EXE" \
74 -DZIG_TARGET_TRIPLE="${ARCH}-macos" \
75 -DZIG_STATIC="OFF"
76
77ninja $JOBS install
78
79# Disable test because binary is foreign arch.
80#release/bin/zig build test
75 -DCMAKE_PREFIX_PATH="$PREFIX" \
76 -DCMAKE_BUILD_TYPE=Release \
77 -DZIG_TARGET_TRIPLE="$TARGET" \
78 -DZIG_TARGET_MCPU="$MCPU" \
79 -DZIG_EXECUTABLE="$ZIG" \
80 -DZIG_STATIC=ON
81
82unset CC
83unset CXX
84
85make $JOBS install
8186
8287if [ "${BUILD_REASON}" != "PullRequest" ]; then
8388 mv ../LICENSE release/
8489
8590 # We do not run test suite but still need langref.
8691 mkdir -p release/docs
87 $ZIG_EXE run ../doc/docgen.zig -- $ZIG_EXE ../doc/langref.html.in release/docs/langref.html
92 $ZIG run ../doc/docgen.zig -- $ZIG ../doc/langref.html.in release/docs/langref.html
8893
8994 # Produce the experimental std lib documentation.
9095 mkdir -p release/docs/std
91 $ZIG_EXE test ../lib/std/std.zig \
96 $ZIG test ../lib/std/std.zig \
9297 --override-lib-dir ../lib \
9398 -femit-docs=release/docs/std \
9499 -fno-emit-bin
95100
96 # Remove the unnecessary bin dir in $prefix/bin/zig
97101 mv release/bin/zig release/
98102 rmdir release/bin
99103
100 # Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
101 mv release/lib/zig release/lib2
102 rmdir release/lib
103 mv release/lib2 release/lib
104
105 VERSION=$($ZIG_EXE version)
104 VERSION=$(../build.host/release/bin/zig version)
106105 DIRNAME="zig-macos-$ARCH-$VERSION"
107106 TARBALL="$DIRNAME.tar.xz"
108 gtar cJf "$TARBALL" release/ --owner=root --sort=name --transform="s,^release,${DIRNAME},"
109 ln "$TARBALL" "$BUILD_ARTIFACTSTAGINGDIRECTORY/."
107 mv release "$DIRNAME"
108 tar cfJ "$TARBALL" "$DIRNAME"
110109
111110 mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"
112111 s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
......@@ -114,12 +113,13 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
114113 SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
115114 BYTESIZE=$(wc -c < $TARBALL)
116115
117 JSONFILE="tarball.json"
116 JSONFILE="macos-$GITBRANCH.json"
118117 touch $JSONFILE
119118 echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
120119 echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
121120 echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
122121
122 s3cmd put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE"
123123 s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"
124124
125125 # `set -x` causes these variables to be mangled.
ci/azure/macos_script+9-10
......@@ -7,21 +7,21 @@ brew update && brew install s3cmd
77
88ZIGDIR="$(pwd)"
99ARCH="x86_64"
10CACHE_BASENAME="zig+llvm+lld+clang-$ARCH-macos-gnu-0.8.0-dev.1939+5a3ea9bec"
10TARGET="$ARCH-macos-gnu"
11MCPU="baseline"
12CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.2168+2d1196773"
1113PREFIX="$HOME/$CACHE_BASENAME"
1214JOBS="-j2"
1315
1416rm -rf $PREFIX
1517cd $HOME
18
1619wget -nv "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"
1720tar xf "$CACHE_BASENAME.tar.xz"
1821
1922ZIG="$PREFIX/bin/zig"
20NATIVE_LIBC_TXT="$HOME/native_libc.txt"
21$ZIG libc >"$NATIVE_LIBC_TXT"
22export ZIG_LIBC="$NATIVE_LIBC_TXT"
23export CC="$ZIG cc"
24export CXX="$ZIG c++"
23export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
24export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
2525
2626cd $ZIGDIR
2727
......@@ -37,22 +37,21 @@ cmake .. \
3737 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
3838 -DCMAKE_PREFIX_PATH="$PREFIX" \
3939 -DCMAKE_BUILD_TYPE=Release \
40 -DZIG_TARGET_TRIPLE="$ARCH-native-gnu" \
41 -DZIG_TARGET_MCPU="baseline" \
40 -DZIG_TARGET_TRIPLE="$TARGET" \
41 -DZIG_TARGET_MCPU="$MCPU" \
4242 -DZIG_STATIC=ON
4343
4444# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
4545# so that installation and testing do not get affected by them.
4646unset CC
4747unset CXX
48unset ZIG_LIBC
4948
5049make $JOBS install
5150
5251# Here we rebuild zig but this time using the Zig binary we just now produced to
5352# build zig1.o rather than relying on the one built with stage0. See
5453# https://github.com/ziglang/zig/issues/6830 for more details.
55cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" -DZIG_TARGET_MCPU="x86_64_v2"
54cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"
5655make $JOBS install
5756
5857for step in test-toolchain test-std docs; do
ci/azure/pipelines.yml+1-7
......@@ -2,9 +2,7 @@ jobs:
22- job: BuildMacOS
33 pool:
44 vmImage: 'macOS-10.15'
5
65 timeoutInMinutes: 360
7
86 steps:
97 - task: DownloadSecureFile@1
108 inputs:
......@@ -15,9 +13,7 @@ jobs:
1513- job: BuildMacOS_arm64
1614 pool:
1715 vmImage: 'macOS-10.15'
18
19 timeoutInMinutes: 60
20
16 timeoutInMinutes: 180
2117 steps:
2218 - task: DownloadSecureFile@1
2319 inputs:
......@@ -28,9 +24,7 @@ jobs:
2824- job: BuildLinux
2925 pool:
3026 vmImage: 'ubuntu-18.04'
31
3227 timeoutInMinutes: 360
33
3428 steps:
3529 - task: DownloadSecureFile@1
3630 inputs:
lib/libc/glibc/sysdeps/i386/sysdep.h+3-2
......@@ -61,7 +61,7 @@ lose: SYSCALL_PIC_SETUP \
6161
6262# define SETUP_PIC_REG(reg) \
6363 .ifndef GET_PC_THUNK(reg); \
64 .section .gnu.linkonce.t.GET_PC_THUNK(reg),"ax",@progbits; \
64 .section .text.GET_PC_THUNK(reg),"axG",@progbits,GET_PC_THUNK(reg),comdat; \
6565 .globl GET_PC_THUNK(reg); \
6666 .hidden GET_PC_THUNK(reg); \
6767 .p2align 4; \
......@@ -97,8 +97,9 @@ GET_PC_THUNK(reg): \
9797
9898# define SETUP_PIC_REG_STR(reg) \
9999 ".ifndef " GET_PC_THUNK_STR (reg) "\n" \
100 ".section .gnu.linkonce.t." GET_PC_THUNK_STR (reg) ",\"ax\",@progbits\n" \
100 "section .text." GET_PC_THUNK_STR (reg) ",\"axG\",@progbits," \
101101 ".globl " GET_PC_THUNK_STR (reg) "\n" \
102 GET_PC_THUNK_STR (reg) ",comdat\n" \
102103 ".hidden " GET_PC_THUNK_STR (reg) "\n" \
103104 ".p2align 4\n" \
104105 ".type " GET_PC_THUNK_STR (reg) ",@function\n" \
lib/std/array_hash_map.zig+16-4
......@@ -18,11 +18,11 @@ const builtin = std.builtin;
1818const hash_map = @This();
1919
2020pub fn AutoArrayHashMap(comptime K: type, comptime V: type) type {
21 return ArrayHashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K), autoEqlIsCheap(K));
21 return ArrayHashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K), !autoEqlIsCheap(K));
2222}
2323
2424pub fn AutoArrayHashMapUnmanaged(comptime K: type, comptime V: type) type {
25 return ArrayHashMapUnmanaged(K, V, getAutoHashFn(K), getAutoEqlFn(K), autoEqlIsCheap(K));
25 return ArrayHashMapUnmanaged(K, V, getAutoHashFn(K), getAutoEqlFn(K), !autoEqlIsCheap(K));
2626}
2727
2828/// Builtin hashmap for strings as keys.
......@@ -1318,7 +1318,7 @@ test "reIndex" {
13181318 try al.append(std.testing.allocator, .{
13191319 .key = i,
13201320 .value = i * 10,
1321 .hash = hash(i),
1321 .hash = {},
13221322 });
13231323 }
13241324
......@@ -1345,7 +1345,7 @@ test "fromOwnedArrayList" {
13451345 try al.append(std.testing.allocator, .{
13461346 .key = i,
13471347 .value = i * 10,
1348 .hash = hash(i),
1348 .hash = {},
13491349 });
13501350 }
13511351
......@@ -1362,6 +1362,18 @@ test "fromOwnedArrayList" {
13621362 }
13631363}
13641364
1365test "auto store_hash" {
1366 const HasCheapEql = AutoArrayHashMap(i32, i32);
1367 const HasExpensiveEql = AutoArrayHashMap([32]i32, i32);
1368 try testing.expect(meta.fieldInfo(HasCheapEql.Entry, .hash).field_type == void);
1369 try testing.expect(meta.fieldInfo(HasExpensiveEql.Entry, .hash).field_type != void);
1370
1371 const HasCheapEqlUn = AutoArrayHashMapUnmanaged(i32, i32);
1372 const HasExpensiveEqlUn = AutoArrayHashMapUnmanaged([32]i32, i32);
1373 try testing.expect(meta.fieldInfo(HasCheapEqlUn.Entry, .hash).field_type == void);
1374 try testing.expect(meta.fieldInfo(HasExpensiveEqlUn.Entry, .hash).field_type != void);
1375}
1376
13651377pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
13661378 return struct {
13671379 fn hash(key: K) u32 {
lib/std/c.zig+6-5
......@@ -89,13 +89,13 @@ pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int;
8989pub extern "c" fn raise(sig: c_int) c_int;
9090pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
9191pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize;
92pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize;
93pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: u64) isize;
92pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: off_t) isize;
93pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: off_t) isize;
9494pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) isize;
95pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: u64) isize;
95pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize;
9696pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;
97pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize;
98pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: u64) *c_void;
97pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize;
98pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: off_t) *c_void;
9999pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
100100pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
101101pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
......@@ -151,6 +151,7 @@ pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: soc
151151pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int;
152152pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
153153pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
154pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
154155pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;
155156pub extern "c" fn accept(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t) c_int;
156157pub extern "c" fn accept4(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t, flags: c_uint) c_int;
lib/std/c/linux.zig+17-2
......@@ -63,6 +63,23 @@ pub const EAI = enum(c_int) {
6363 _,
6464};
6565
66pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
67pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
68pub extern "c" fn fstat64(fd: fd_t, buf: *libc_stat) c_int;
69pub extern "c" fn fstatat64(dirfd: fd_t, path: [*:0]const u8, stat_buf: *libc_stat, flags: u32) c_int;
70pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
71pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
72pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
73pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *c_void;
74pub extern "c" fn open64(path: [*:0]const u8, oflag: c_uint, ...) c_int;
75pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
76pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;
77pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize;
78pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: i64) isize;
79pub extern "c" fn pwritev64(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: i64) isize;
80pub extern "c" fn sendfile64(out_fd: fd_t, in_fd: fd_t, offset: ?*i64, count: usize) isize;
81pub extern "c" fn setrlimit64(resource: rlimit_resource, rlim: *const rlimit) c_int;
82
6683pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
6784pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
6885pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int;
......@@ -92,8 +109,6 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
92109
93110pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
94111
95pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
96
97112pub extern "c" fn sendfile(
98113 out_fd: fd_t,
99114 in_fd: fd_t,
lib/std/crypto/pcurves/p256.zig+48-16
......@@ -49,21 +49,26 @@ pub const P256 = struct {
4949 }
5050
5151 /// Create a point from affine coordinates after checking that they match the curve equation.
52 pub fn fromAffineCoordinates(x: Fe, y: Fe) EncodingError!P256 {
52 pub fn fromAffineCoordinates(p: AffineCoordinates) EncodingError!P256 {
53 const x = p.x;
54 const y = p.y;
5355 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
5456 const yy = y.sq();
55 if (!x3AxB.equivalent(yy)) {
57 const on_curve = @boolToInt(x3AxB.equivalent(yy));
58 const is_identity = @boolToInt(x.equivalent(AffineCoordinates.identityElement.x)) & @boolToInt(y.equivalent(AffineCoordinates.identityElement.y));
59 if ((on_curve | is_identity) == 0) {
5660 return error.InvalidEncoding;
5761 }
58 const p: P256 = .{ .x = x, .y = y, .z = Fe.one };
59 return p;
62 var ret = P256{ .x = x, .y = y, .z = Fe.one };
63 ret.z.cMov(P256.identityElement.z, is_identity);
64 return ret;
6065 }
6166
6267 /// Create a point from serialized affine coordinates.
6368 pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: builtin.Endian) (NonCanonicalError || EncodingError)!P256 {
6469 const x = try Fe.fromBytes(xs, endian);
6570 const y = try Fe.fromBytes(ys, endian);
66 return fromAffineCoordinates(x, y);
71 return fromAffineCoordinates(.{ .x = x, .y = y });
6772 }
6873
6974 /// Recover the Y coordinate from the X coordinate.
......@@ -96,7 +101,7 @@ pub const P256 = struct {
96101 if (encoded.len != 64) return error.InvalidEncoding;
97102 const x = try Fe.fromBytes(encoded[0..32].*, .Big);
98103 const y = try Fe.fromBytes(encoded[32..64].*, .Big);
99 return P256.fromAffineCoordinates(x, y);
104 return P256.fromAffineCoordinates(.{ .x = x, .y = y });
100105 },
101106 else => return error.InvalidEncoding,
102107 }
......@@ -177,7 +182,7 @@ pub const P256 = struct {
177182
178183 /// Add P256 points, the second being specified using affine coordinates.
179184 // Algorithm 5 from https://eprint.iacr.org/2015/1060.pdf
180 pub fn addMixed(p: P256, q: struct { x: Fe, y: Fe }) P256 {
185 pub fn addMixed(p: P256, q: AffineCoordinates) P256 {
181186 var t0 = p.x.mul(q.x);
182187 var t1 = p.y.mul(q.y);
183188 var t3 = q.x.add(q.y);
......@@ -194,9 +199,9 @@ pub const P256 = struct {
194199 Z3 = X3.dbl();
195200 X3 = X3.add(Z3);
196201 Z3 = t1.sub(X3);
197 X3 = t1.dbl();
202 X3 = t1.add(X3);
198203 Y3 = B.mul(Y3);
199 t1 = p.z.add(p.z);
204 t1 = p.z.dbl();
200205 var t2 = t1.add(p.z);
201206 Y3 = Y3.sub(t2);
202207 Y3 = Y3.sub(t0);
......@@ -214,14 +219,16 @@ pub const P256 = struct {
214219 Z3 = t4.mul(Z3);
215220 t1 = t3.mul(t0);
216221 Z3 = Z3.add(t1);
217 return .{
222 var ret = P256{
218223 .x = X3,
219224 .y = Y3,
220225 .z = Z3,
221226 };
227 ret.cMov(p, @boolToInt(q.x.isZero()));
228 return ret;
222229 }
223230
224 // Add P256 points.
231 /// Add P256 points.
225232 // Algorithm 4 from https://eprint.iacr.org/2015/1060.pdf
226233 pub fn add(p: P256, q: P256) P256 {
227234 var t0 = p.x.mul(q.x);
......@@ -274,18 +281,19 @@ pub const P256 = struct {
274281 };
275282 }
276283
277 // Subtract P256 points.
284 /// Subtract P256 points.
278285 pub fn sub(p: P256, q: P256) P256 {
279286 return p.add(q.neg());
280287 }
281288
282289 /// Return affine coordinates.
283 pub fn affineCoordinates(p: P256) struct { x: Fe, y: Fe } {
290 pub fn affineCoordinates(p: P256) AffineCoordinates {
284291 const zinv = p.z.invert();
285 const ret = .{
292 var ret = AffineCoordinates{
286293 .x = p.x.mul(zinv),
287294 .y = p.y.mul(zinv),
288295 };
296 ret.cMov(AffineCoordinates.identityElement, @boolToInt(p.x.isZero()));
289297 return ret;
290298 }
291299
......@@ -382,11 +390,21 @@ pub const P256 = struct {
382390 return pc;
383391 }
384392
393 const basePointPc = comptime pc: {
394 @setEvalBranchQuota(50000);
395 break :pc precompute(P256.basePoint, 15);
396 };
397
398 const basePointPc8 = comptime pc: {
399 @setEvalBranchQuota(50000);
400 break :pc precompute(P256.basePoint, 8);
401 };
402
385403 /// Multiply an elliptic curve point by a scalar.
386404 /// Return error.IdentityElement if the result is the identity element.
387405 pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
388406 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
389 const pc = if (p.is_base) precompute(P256.basePoint, 15) else pc: {
407 const pc = if (p.is_base) basePointPc else pc: {
390408 try p.rejectIdentity();
391409 const xpc = precompute(p, 15);
392410 break :pc xpc;
......@@ -398,7 +416,7 @@ pub const P256 = struct {
398416 /// This can be used for signature verification.
399417 pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
400418 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
401 const pc = if (p.is_base) precompute(P256.basePoint, 8) else pc: {
419 const pc = if (p.is_base) basePointPc8 else pc: {
402420 try p.rejectIdentity();
403421 const xpc = precompute(p, 8);
404422 break :pc xpc;
......@@ -407,6 +425,20 @@ pub const P256 = struct {
407425 }
408426};
409427
428/// A point in affine coordinates.
429pub const AffineCoordinates = struct {
430 x: P256.Fe,
431 y: P256.Fe,
432
433 /// Identity element in affine coordinates.
434 pub const identityElement = AffineCoordinates{ .x = P256.identityElement.x, .y = P256.identityElement.y };
435
436 fn cMov(p: *AffineCoordinates, a: AffineCoordinates, c: u1) void {
437 p.x.cMov(a.x, c);
438 p.y.cMov(a.y, c);
439 }
440};
441
410442test "p256" {
411443 _ = @import("tests.zig");
412444}
lib/std/crypto/pcurves/tests.zig+6
......@@ -101,3 +101,9 @@ test "p256 field element non-canonical encoding" {
101101 const s = [_]u8{0xff} ** 32;
102102 try testing.expectError(error.NonCanonical, P256.Fe.fromBytes(s, .Little));
103103}
104
105test "p256 neutral element decoding" {
106 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.zero }));
107 const p = try P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one });
108 try testing.expectError(error.IdentityElement, p.rejectIdentity());
109}
lib/std/fs/file.zig+2-2
......@@ -524,8 +524,8 @@ pub const File = struct {
524524 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
525525 /// order to handle partial reads from the underlying OS layer.
526526 /// See https://github.com/ziglang/zig/issues/7699
527 pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {
528 if (iovecs.len == 0) return;
527 pub fn preadvAll(self: File, iovecs: []os.iovec, offset: u64) PReadError!usize {
528 if (iovecs.len == 0) return 0;
529529
530530 var i: usize = 0;
531531 var off: usize = 0;
lib/std/fs/test.zig+83
......@@ -520,6 +520,89 @@ test "makePath, put some files in it, deleteTree" {
520520 }
521521}
522522
523test "writev, readv" {
524 var tmp = tmpDir(.{});
525 defer tmp.cleanup();
526
527 const line1 = "line1\n";
528 const line2 = "line2\n";
529
530 var buf1: [line1.len]u8 = undefined;
531 var buf2: [line2.len]u8 = undefined;
532 var write_vecs = [_]std.os.iovec_const{
533 .{
534 .iov_base = line1,
535 .iov_len = line1.len,
536 },
537 .{
538 .iov_base = line2,
539 .iov_len = line2.len,
540 },
541 };
542 var read_vecs = [_]std.os.iovec{
543 .{
544 .iov_base = &buf2,
545 .iov_len = buf2.len,
546 },
547 .{
548 .iov_base = &buf1,
549 .iov_len = buf1.len,
550 },
551 };
552
553 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
554 defer src_file.close();
555
556 try src_file.writevAll(&write_vecs);
557 try testing.expectEqual(@as(u64, line1.len + line2.len), try src_file.getEndPos());
558 try src_file.seekTo(0);
559 const read = try src_file.readvAll(&read_vecs);
560 try testing.expectEqual(@as(usize, line1.len + line2.len), read);
561 try testing.expectEqualStrings(&buf1, "line2\n");
562 try testing.expectEqualStrings(&buf2, "line1\n");
563}
564
565test "pwritev, preadv" {
566 var tmp = tmpDir(.{});
567 defer tmp.cleanup();
568
569 const line1 = "line1\n";
570 const line2 = "line2\n";
571
572 var buf1: [line1.len]u8 = undefined;
573 var buf2: [line2.len]u8 = undefined;
574 var write_vecs = [_]std.os.iovec_const{
575 .{
576 .iov_base = line1,
577 .iov_len = line1.len,
578 },
579 .{
580 .iov_base = line2,
581 .iov_len = line2.len,
582 },
583 };
584 var read_vecs = [_]std.os.iovec{
585 .{
586 .iov_base = &buf2,
587 .iov_len = buf2.len,
588 },
589 .{
590 .iov_base = &buf1,
591 .iov_len = buf1.len,
592 },
593 };
594
595 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
596 defer src_file.close();
597
598 try src_file.pwritevAll(&write_vecs, 16);
599 try testing.expectEqual(@as(u64, 16 + line1.len + line2.len), try src_file.getEndPos());
600 const read = try src_file.preadvAll(&read_vecs, 16);
601 try testing.expectEqual(@as(usize, line1.len + line2.len), read);
602 try testing.expectEqualStrings(&buf1, "line2\n");
603 try testing.expectEqualStrings(&buf2, "line1\n");
604}
605
523606test "access file" {
524607 if (builtin.os.tag == .wasi) return error.SkipZigTest;
525608
lib/std/json.zig+20
......@@ -1571,6 +1571,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
15711571 return error.DuplicateJSONField;
15721572 } else if (options.duplicate_field_behavior == .UseLast) {
15731573 parseFree(field.field_type, @field(r, field.name), options);
1574 fields_seen[i] = false;
15741575 }
15751576 }
15761577 if (field.is_comptime) {
......@@ -1642,6 +1643,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
16421643 switch (ptrInfo.size) {
16431644 .One => {
16441645 const r: T = try allocator.create(ptrInfo.child);
1646 errdefer allocator.destroy(r);
16451647 r.* = try parseInternal(ptrInfo.child, token, tokens, options);
16461648 return r;
16471649 },
......@@ -1988,6 +1990,24 @@ test "parse into struct with misc fields" {
19881990 try testing.expectEqual(T.Union{ .float = 100000 }, r.a_union);
19891991}
19901992
1993test "parse into struct with duplicate field" {
1994 // allow allocator to detect double frees by keeping bucket in use
1995 const ballast = try testing.allocator.alloc(u64, 1);
1996 defer testing.allocator.free(ballast);
1997
1998 const options = ParseOptions{
1999 .allocator = testing.allocator,
2000 .duplicate_field_behavior = .UseLast,
2001 };
2002 const str = "{ \"a\": 1, \"a\": 0.25 }";
2003
2004 const T1 = struct { a: *u64 };
2005 try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options));
2006
2007 const T2 = struct { a: f64 };
2008 try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options));
2009}
2010
19912011/// A non-stream JSON parser which constructs a tree of Value's.
19922012pub const Parser = struct {
19932013 allocator: *Allocator,
lib/std/mem.zig+188
......@@ -603,6 +603,7 @@ test "span" {
603603 try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null)));
604604}
605605
606/// Deprecated: use std.mem.span() or std.mem.sliceTo()
606607/// Same as `span`, except when there is both a sentinel and an array
607608/// length or slice length, scans the memory for the sentinel value
608609/// rather than using the length.
......@@ -631,6 +632,192 @@ test "spanZ" {
631632 try testing.expectEqual(@as(?[:0]u16, null), spanZ(@as(?[*:0]u16, null)));
632633}
633634
635/// Helper for the return type of sliceTo()
636fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
637 switch (@typeInfo(T)) {
638 .Optional => |optional_info| {
639 return ?SliceTo(optional_info.child, end);
640 },
641 .Pointer => |ptr_info| {
642 var new_ptr_info = ptr_info;
643 new_ptr_info.size = .Slice;
644 switch (ptr_info.size) {
645 .One => switch (@typeInfo(ptr_info.child)) {
646 .Array => |array_info| {
647 new_ptr_info.child = array_info.child;
648 // The return type must only be sentinel terminated if we are guaranteed
649 // to find the value searched for, which is only the case if it matches
650 // the sentinel of the type passed.
651 if (array_info.sentinel) |sentinel| {
652 if (end == sentinel) {
653 new_ptr_info.sentinel = end;
654 } else {
655 new_ptr_info.sentinel = null;
656 }
657 }
658 },
659 else => {},
660 },
661 .Many, .Slice => {
662 // The return type must only be sentinel terminated if we are guaranteed
663 // to find the value searched for, which is only the case if it matches
664 // the sentinel of the type passed.
665 if (ptr_info.sentinel) |sentinel| {
666 if (end == sentinel) {
667 new_ptr_info.sentinel = end;
668 } else {
669 new_ptr_info.sentinel = null;
670 }
671 }
672 },
673 .C => {
674 new_ptr_info.sentinel = end;
675 // C pointers are always allowzero, but we don't want the return type to be.
676 assert(new_ptr_info.is_allowzero);
677 new_ptr_info.is_allowzero = false;
678 },
679 }
680 return @Type(std.builtin.TypeInfo{ .Pointer = new_ptr_info });
681 },
682 else => {},
683 }
684 @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T));
685}
686
687/// Takes a pointer to an array, an array, a sentinel-terminated pointer, or a slice and
688/// iterates searching for the first occurrence of `end`, returning the scanned slice.
689/// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned.
690/// If the pointer type is sentinel terminated and `end` matches that terminator, the
691/// resulting slice is also sentinel terminated.
692/// Pointer properties such as mutability and alignment are preserved.
693/// C pointers are assumed to be non-null.
694pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) {
695 if (@typeInfo(@TypeOf(ptr)) == .Optional) {
696 const non_null = ptr orelse return null;
697 return sliceTo(non_null, end);
698 }
699 const Result = SliceTo(@TypeOf(ptr), end);
700 const length = lenSliceTo(ptr, end);
701 if (@typeInfo(Result).Pointer.sentinel) |s| {
702 return ptr[0..length :s];
703 } else {
704 return ptr[0..length];
705 }
706}
707
708test "sliceTo" {
709 try testing.expectEqualSlices(u8, "aoeu", sliceTo("aoeu", 0));
710
711 {
712 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
713 try testing.expectEqualSlices(u16, &array, sliceTo(&array, 0));
714 try testing.expectEqualSlices(u16, array[0..3], sliceTo(array[0..3], 0));
715 try testing.expectEqualSlices(u16, array[0..2], sliceTo(&array, 3));
716 try testing.expectEqualSlices(u16, array[0..2], sliceTo(array[0..3], 3));
717
718 const sentinel_ptr = @ptrCast([*:5]u16, &array);
719 try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_ptr, 3));
720 try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_ptr, 99));
721
722 const optional_sentinel_ptr = @ptrCast(?[*:5]u16, &array);
723 try testing.expectEqualSlices(u16, array[0..2], sliceTo(optional_sentinel_ptr, 3).?);
724 try testing.expectEqualSlices(u16, array[0..4], sliceTo(optional_sentinel_ptr, 99).?);
725
726 const c_ptr = @as([*c]u16, &array);
727 try testing.expectEqualSlices(u16, array[0..2], sliceTo(c_ptr, 3));
728
729 const slice: []u16 = &array;
730 try testing.expectEqualSlices(u16, array[0..2], sliceTo(slice, 3));
731 try testing.expectEqualSlices(u16, &array, sliceTo(slice, 99));
732
733 const sentinel_slice: [:5]u16 = array[0..4 :5];
734 try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_slice, 3));
735 try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_slice, 99));
736 }
737 {
738 var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
739 try testing.expectEqualSlices(u16, sentinel_array[0..2], sliceTo(&sentinel_array, 3));
740 try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 0));
741 try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 99));
742 }
743
744 try testing.expectEqual(@as(?[]u8, null), sliceTo(@as(?[]u8, null), 0));
745}
746
747/// Private helper for sliceTo(). If you want the length, use sliceTo(foo, x).len
748fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {
749 switch (@typeInfo(@TypeOf(ptr))) {
750 .Pointer => |ptr_info| switch (ptr_info.size) {
751 .One => switch (@typeInfo(ptr_info.child)) {
752 .Array => |array_info| {
753 if (array_info.sentinel) |sentinel| {
754 if (sentinel == end) {
755 return indexOfSentinel(array_info.child, end, ptr);
756 }
757 }
758 return indexOfScalar(array_info.child, ptr, end) orelse array_info.len;
759 },
760 else => {},
761 },
762 .Many => if (ptr_info.sentinel) |sentinel| {
763 // We may be looking for something other than the sentinel,
764 // but iterating past the sentinel would be a bug so we need
765 // to check for both.
766 var i: usize = 0;
767 while (ptr[i] != end and ptr[i] != sentinel) i += 1;
768 return i;
769 },
770 .C => {
771 assert(ptr != null);
772 return indexOfSentinel(ptr_info.child, end, ptr);
773 },
774 .Slice => {
775 if (ptr_info.sentinel) |sentinel| {
776 if (sentinel == end) {
777 return indexOfSentinel(ptr_info.child, sentinel, ptr);
778 }
779 }
780 return indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len;
781 },
782 },
783 else => {},
784 }
785 @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(@TypeOf(ptr)));
786}
787
788test "lenSliceTo" {
789 try testing.expect(lenSliceTo("aoeu", 0) == 4);
790
791 {
792 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
793 try testing.expectEqual(@as(usize, 5), lenSliceTo(&array, 0));
794 try testing.expectEqual(@as(usize, 3), lenSliceTo(array[0..3], 0));
795 try testing.expectEqual(@as(usize, 2), lenSliceTo(&array, 3));
796 try testing.expectEqual(@as(usize, 2), lenSliceTo(array[0..3], 3));
797
798 const sentinel_ptr = @ptrCast([*:5]u16, &array);
799 try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_ptr, 3));
800 try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_ptr, 99));
801
802 const c_ptr = @as([*c]u16, &array);
803 try testing.expectEqual(@as(usize, 2), lenSliceTo(c_ptr, 3));
804
805 const slice: []u16 = &array;
806 try testing.expectEqual(@as(usize, 2), lenSliceTo(slice, 3));
807 try testing.expectEqual(@as(usize, 5), lenSliceTo(slice, 99));
808
809 const sentinel_slice: [:5]u16 = array[0..4 :5];
810 try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_slice, 3));
811 try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_slice, 99));
812 }
813 {
814 var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
815 try testing.expectEqual(@as(usize, 2), lenSliceTo(&sentinel_array, 3));
816 try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 0));
817 try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 99));
818 }
819}
820
634821/// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer,
635822/// a slice or a tuple, and returns the length.
636823/// In the case of a sentinel-terminated array, it uses the array length.
......@@ -689,6 +876,7 @@ test "len" {
689876 }
690877}
691878
879/// Deprecated: use std.mem.len() or std.mem.sliceTo().len
692880/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
693881/// or a slice, and returns the length.
694882/// In the case of a sentinel-terminated array, it scans the array
lib/std/meta.zig+1-7
......@@ -175,13 +175,7 @@ pub fn Elem(comptime T: type) type {
175175 },
176176 .Many, .C, .Slice => return info.child,
177177 },
178 .Optional => |info| switch (@typeInfo(info.child)) {
179 .Pointer => |ptr_info| switch (ptr_info.size) {
180 .Many => return ptr_info.child,
181 else => {},
182 },
183 else => {},
184 },
178 .Optional => |info| return Elem(info.child),
185179 else => {},
186180 }
187181 @compileError("Expected pointer, slice, array or vector type, found '" ++ @typeName(T) ++ "'");
lib/std/os.zig+147-33
......@@ -497,8 +497,14 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
497497 };
498498 const adjusted_len = math.min(max_count, buf.len);
499499
500 const pread_sym = if (builtin.os.tag == .linux and builtin.link_libc)
501 system.pread64
502 else
503 system.pread;
504
505 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
500506 while (true) {
501 const rc = system.pread(fd, buf.ptr, adjusted_len, offset);
507 const rc = pread_sym(fd, buf.ptr, adjusted_len, ioffset);
502508 switch (errno(rc)) {
503509 0 => return @intCast(usize, rc),
504510 EINTR => continue,
......@@ -567,15 +573,13 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
567573 }
568574
569575 while (true) {
570 const rc = if (builtin.link_libc)
571 if (std.Target.current.os.tag == .linux)
572 system.ftruncate64(fd, @bitCast(off_t, length))
573 else
574 system.ftruncate(fd, @bitCast(off_t, length))
576 const ftruncate_sym = if (builtin.os.tag == .linux and builtin.link_libc)
577 system.ftruncate64
575578 else
576 system.ftruncate(fd, length);
579 system.ftruncate;
577580
578 switch (errno(rc)) {
581 const ilen = @bitCast(i64, length); // the OS treats this as unsigned
582 switch (errno(ftruncate_sym(fd, ilen))) {
579583 0 => return,
580584 EINTR => continue,
581585 EFBIG => return error.FileTooBig,
......@@ -637,8 +641,14 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
637641
638642 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);
639643
644 const preadv_sym = if (builtin.os.tag == .linux and builtin.link_libc)
645 system.preadv64
646 else
647 system.preadv;
648
649 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
640650 while (true) {
641 const rc = system.preadv(fd, iov.ptr, iov_count, offset);
651 const rc = preadv_sym(fd, iov.ptr, iov_count, ioffset);
642652 switch (errno(rc)) {
643653 0 => return @bitCast(usize, rc),
644654 EINTR => continue,
......@@ -895,8 +905,14 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
895905 };
896906 const adjusted_len = math.min(max_count, bytes.len);
897907
908 const pwrite_sym = if (builtin.os.tag == .linux and builtin.link_libc)
909 system.pwrite64
910 else
911 system.pwrite;
912
913 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
898914 while (true) {
899 const rc = system.pwrite(fd, bytes.ptr, adjusted_len, offset);
915 const rc = pwrite_sym(fd, bytes.ptr, adjusted_len, ioffset);
900916 switch (errno(rc)) {
901917 0 => return @intCast(usize, rc),
902918 EINTR => continue,
......@@ -977,9 +993,15 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
977993 }
978994 }
979995
996 const pwritev_sym = if (builtin.os.tag == .linux and builtin.link_libc)
997 system.pwritev64
998 else
999 system.pwritev;
1000
9801001 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);
1002 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
9811003 while (true) {
982 const rc = system.pwritev(fd, iov.ptr, iov_count, offset);
1004 const rc = pwritev_sym(fd, iov.ptr, iov_count, ioffset);
9831005 switch (errno(rc)) {
9841006 0 => return @intCast(usize, rc),
9851007 EINTR => continue,
......@@ -1068,8 +1090,14 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t
10681090 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
10691091 return openW(file_path_w.span(), flags, perm);
10701092 }
1093
1094 const open_sym = if (builtin.os.tag == .linux and builtin.link_libc)
1095 system.open64
1096 else
1097 system.open;
1098
10711099 while (true) {
1072 const rc = system.open(file_path, flags, perm);
1100 const rc = open_sym(file_path, flags, perm);
10731101 switch (errno(rc)) {
10741102 0 => return @intCast(fd_t, rc),
10751103 EINTR => continue,
......@@ -1202,8 +1230,14 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)
12021230 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
12031231 return openatW(dir_fd, file_path_w.span(), flags, mode);
12041232 }
1233
1234 const openat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
1235 system.openat64
1236 else
1237 system.openat;
1238
12051239 while (true) {
1206 const rc = system.openat(dir_fd, file_path, flags, mode);
1240 const rc = openat_sym(dir_fd, file_path, flags, mode);
12071241 switch (errno(rc)) {
12081242 0 => return @intCast(fd_t, rc),
12091243 EINTR => continue,
......@@ -2758,9 +2792,9 @@ pub const ShutdownHow = enum { recv, send, both };
27582792pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void {
27592793 if (builtin.os.tag == .windows) {
27602794 const result = windows.ws2_32.shutdown(sock, switch (how) {
2761 .recv => windows.SD_RECEIVE,
2762 .send => windows.SD_SEND,
2763 .both => windows.SD_BOTH,
2795 .recv => windows.ws2_32.SD_RECEIVE,
2796 .send => windows.ws2_32.SD_SEND,
2797 .both => windows.ws2_32.SD_BOTH,
27642798 });
27652799 if (0 != result) switch (windows.ws2_32.WSAGetLastError()) {
27662800 .WSAECONNABORTED => return error.ConnectionAborted,
......@@ -3217,6 +3251,35 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
32173251 }
32183252}
32193253
3254pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
3255 if (builtin.os.tag == .windows) {
3256 const rc = windows.getpeername(sock, addr, addrlen);
3257 if (rc == windows.ws2_32.SOCKET_ERROR) {
3258 switch (windows.ws2_32.WSAGetLastError()) {
3259 .WSANOTINITIALISED => unreachable,
3260 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3261 .WSAEFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value
3262 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
3263 .WSAEINVAL => return error.SocketNotBound,
3264 else => |err| return windows.unexpectedWSAError(err),
3265 }
3266 }
3267 return;
3268 } else {
3269 const rc = system.getpeername(sock, addr, addrlen);
3270 switch (errno(rc)) {
3271 0 => return,
3272 else => |err| return unexpectedErrno(err),
3273
3274 EBADF => unreachable, // always a race condition
3275 EFAULT => unreachable,
3276 EINVAL => unreachable, // invalid parameters
3277 ENOTSOCK => return error.FileDescriptorNotASocket,
3278 ENOBUFS => return error.SystemResources,
3279 }
3280 }
3281}
3282
32203283pub const ConnectError = error{
32213284 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
32223285 /// file, or search permission is denied for one of the directories in the path prefix.
......@@ -3408,8 +3471,13 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
34083471 @compileError("fstat is not yet implemented on Windows");
34093472 }
34103473
3411 var stat: Stat = undefined;
3412 switch (errno(system.fstat(fd, &stat))) {
3474 const fstat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
3475 system.fstat64
3476 else
3477 system.fstat;
3478
3479 var stat = mem.zeroes(Stat);
3480 switch (errno(fstat_sym(fd, &stat))) {
34133481 0 => return stat,
34143482 EINVAL => unreachable,
34153483 EBADF => unreachable, // Always a race condition.
......@@ -3459,8 +3527,13 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
34593527/// Same as `fstatat` but `pathname` is null-terminated.
34603528/// See also `fstatat`.
34613529pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
3462 var stat: Stat = undefined;
3463 switch (errno(system.fstatat(dirfd, pathname, &stat, flags))) {
3530 const fstatat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
3531 system.fstatat64
3532 else
3533 system.fstatat;
3534
3535 var stat = mem.zeroes(Stat);
3536 switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) {
34643537 0 => return stat,
34653538 EINVAL => unreachable,
34663539 EBADF => unreachable, // Always a race condition.
......@@ -3672,12 +3745,17 @@ pub fn mmap(
36723745 fd: fd_t,
36733746 offset: u64,
36743747) MMapError![]align(mem.page_size) u8 {
3748 const mmap_sym = if (builtin.os.tag == .linux and builtin.link_libc)
3749 system.mmap64
3750 else
3751 system.mmap;
3752
3753 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
3754 const rc = mmap_sym(ptr, length, prot, flags, fd, ioffset);
36753755 const err = if (builtin.link_libc) blk: {
3676 const rc = std.c.mmap(ptr, length, prot, flags, fd, offset);
36773756 if (rc != std.c.MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length];
36783757 break :blk system._errno().*;
36793758 } else blk: {
3680 const rc = system.mmap(ptr, length, prot, flags, fd, offset);
36813759 const err = errno(rc);
36823760 if (err == 0) return @intToPtr([*]align(mem.page_size) u8, rc)[0..length];
36833761 break :blk err;
......@@ -4027,8 +4105,14 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
40274105 else => |err| return unexpectedErrno(err),
40284106 }
40294107 }
4030 const ipos = @bitCast(i64, offset); // the OS treats this as unsigned
4031 switch (errno(system.lseek(fd, ipos, SEEK_SET))) {
4108
4109 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4110 system.lseek64
4111 else
4112 system.lseek;
4113
4114 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
4115 switch (errno(lseek_sym(fd, ioffset, SEEK_SET))) {
40324116 0 => return,
40334117 EBADF => unreachable, // always a race condition
40344118 EINVAL => return error.Unseekable,
......@@ -4069,7 +4153,13 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
40694153 else => |err| return unexpectedErrno(err),
40704154 }
40714155 }
4072 switch (errno(system.lseek(fd, offset, SEEK_CUR))) {
4156 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4157 system.lseek64
4158 else
4159 system.lseek;
4160
4161 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
4162 switch (errno(lseek_sym(fd, ioffset, SEEK_CUR))) {
40734163 0 => return,
40744164 EBADF => unreachable, // always a race condition
40754165 EINVAL => return error.Unseekable,
......@@ -4110,7 +4200,13 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
41104200 else => |err| return unexpectedErrno(err),
41114201 }
41124202 }
4113 switch (errno(system.lseek(fd, offset, SEEK_END))) {
4203 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4204 system.lseek64
4205 else
4206 system.lseek;
4207
4208 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
4209 switch (errno(lseek_sym(fd, ioffset, SEEK_END))) {
41144210 0 => return,
41154211 EBADF => unreachable, // always a race condition
41164212 EINVAL => return error.Unseekable,
......@@ -4151,7 +4247,12 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
41514247 else => |err| return unexpectedErrno(err),
41524248 }
41534249 }
4154 const rc = system.lseek(fd, 0, SEEK_CUR);
4250 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4251 system.lseek64
4252 else
4253 system.lseek;
4254
4255 const rc = lseek_sym(fd, 0, SEEK_CUR);
41554256 switch (errno(rc)) {
41564257 0 => return @bitCast(u64, rc),
41574258 EBADF => unreachable, // always a race condition
......@@ -5169,9 +5270,14 @@ pub fn sendfile(
51695270 // Here we match BSD behavior, making a zero count value send as many bytes as possible.
51705271 const adjusted_count = if (in_len == 0) max_count else math.min(in_len, @as(size_t, max_count));
51715272
5273 const sendfile_sym = if (builtin.link_libc)
5274 system.sendfile64
5275 else
5276 system.sendfile;
5277
51725278 while (true) {
51735279 var offset: off_t = @bitCast(off_t, in_offset);
5174 const rc = system.sendfile(out_fd, in_fd, &offset, adjusted_count);
5280 const rc = sendfile_sym(out_fd, in_fd, &offset, adjusted_count);
51755281 switch (errno(rc)) {
51765282 0 => {
51775283 const amt = @bitCast(usize, rc);
......@@ -5722,7 +5828,7 @@ pub const SetSockOptError = error{
57225828/// Set a socket's options.
57235829pub fn setsockopt(fd: socket_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {
57245830 if (builtin.os.tag == .windows) {
5725 const rc = windows.ws2_32.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len));
5831 const rc = windows.ws2_32.setsockopt(fd, @intCast(i32, level), @intCast(i32, optname), opt.ptr, @intCast(i32, opt.len));
57265832 if (rc == windows.ws2_32.SOCKET_ERROR) {
57275833 switch (windows.ws2_32.WSAGetLastError()) {
57285834 .WSANOTINITIALISED => unreachable,
......@@ -5989,9 +6095,13 @@ pub fn prctl(option: PR, args: anytype) PrctlError!u31 {
59896095pub const GetrlimitError = UnexpectedError;
59906096
59916097pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
6098 const getrlimit_sym = if (builtin.os.tag == .linux and builtin.link_libc)
6099 system.getrlimit64
6100 else
6101 system.getrlimit;
6102
59926103 var limits: rlimit = undefined;
5993 const rc = system.getrlimit(resource, &limits);
5994 switch (errno(rc)) {
6104 switch (errno(getrlimit_sym(resource, &limits))) {
59956105 0 => return limits,
59966106 EFAULT => unreachable, // bogus pointer
59976107 EINVAL => unreachable,
......@@ -6002,8 +6112,12 @@ pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
60026112pub const SetrlimitError = error{PermissionDenied} || UnexpectedError;
60036113
60046114pub fn setrlimit(resource: rlimit_resource, limits: rlimit) SetrlimitError!void {
6005 const rc = system.setrlimit(resource, &limits);
6006 switch (errno(rc)) {
6115 const setrlimit_sym = if (builtin.os.tag == .linux and builtin.link_libc)
6116 system.setrlimit64
6117 else
6118 system.setrlimit;
6119
6120 switch (errno(setrlimit_sym(resource, &limits))) {
60076121 0 => return,
60086122 EFAULT => unreachable, // bogus pointer
60096123 EINVAL => unreachable,
lib/std/os/bits/darwin.zig+42
......@@ -23,6 +23,13 @@ pub const sockaddr = extern struct {
2323 family: sa_family_t,
2424 data: [14]u8,
2525};
26pub const sockaddr_storage = extern struct {
27 len: u8,
28 family: sa_family_t,
29 __pad1: [5]u8,
30 __align: i64,
31 __pad2: [112]u8,
32};
2633pub const sockaddr_in = extern struct {
2734 len: u8 = @sizeOf(sockaddr_in),
2835 family: sa_family_t = AF_INET,
......@@ -1744,3 +1751,38 @@ pub const IOCPARM_MASK = 0x1fff;
17441751fn ior(inout: u32, group: usize, num: usize, len: usize) usize {
17451752 return (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num));
17461753}
1754
1755// CPU families mapping
1756pub const CPUFAMILY = enum(u32) {
1757 UNKNOWN = 0,
1758 POWERPC_G3 = 0xcee41549,
1759 POWERPC_G4 = 0x77c184ae,
1760 POWERPC_G5 = 0xed76d8aa,
1761 INTEL_6_13 = 0xaa33392b,
1762 INTEL_PENRYN = 0x78ea4fbc,
1763 INTEL_NEHALEM = 0x6b5a4cd2,
1764 INTEL_WESTMERE = 0x573b5eec,
1765 INTEL_SANDYBRIDGE = 0x5490b78c,
1766 INTEL_IVYBRIDGE = 0x1f65e835,
1767 INTEL_HASWELL = 0x10b282dc,
1768 INTEL_BROADWELL = 0x582ed09c,
1769 INTEL_SKYLAKE = 0x37fc219f,
1770 INTEL_KABYLAKE = 0x0f817246,
1771 ARM_9 = 0xe73283ae,
1772 ARM_11 = 0x8ff620d8,
1773 ARM_XSCALE = 0x53b005f5,
1774 ARM_12 = 0xbd1b0ae9,
1775 ARM_13 = 0x0cc90e64,
1776 ARM_14 = 0x96077ef1,
1777 ARM_15 = 0xa8511bca,
1778 ARM_SWIFT = 0x1e2d6381,
1779 ARM_CYCLONE = 0x37a09642,
1780 ARM_TYPHOON = 0x2c91a47e,
1781 ARM_TWISTER = 0x92fb37c8,
1782 ARM_HURRICANE = 0x67ceee93,
1783 ARM_MONSOON_MISTRAL = 0xe81e7ef6,
1784 ARM_VORTEX_TEMPEST = 0x07d34b9f,
1785 ARM_LIGHTNING_THUNDER = 0x462504d2,
1786 ARM_FIRESTORM_ICESTORM = 0x1b588bb3,
1787 _,
1788};
lib/std/os/bits/dragonfly.zig+9-1
......@@ -380,6 +380,14 @@ pub const sockaddr = extern struct {
380380 sa_data: [14]u8,
381381};
382382
383pub const sockaddr_storage = extern struct {
384 len: u8,
385 family: sa_family_t,
386 __pad1: [5]u8,
387 __align: i64,
388 __pad2: [112]u8,
389};
390
383391pub const Kevent = extern struct {
384392 ident: usize,
385393 filter: c_short,
......@@ -640,7 +648,7 @@ pub const socklen_t = c_uint;
640648pub const sockaddr_storage = extern struct {
641649 ss_len: u8,
642650 ss_family: sa_family_t,
643 __ss_pad1: [6]u8,
651 __ss_pad1: [5]u8,
644652 __ss_align: i64,
645653 __ss_pad2: [112]u8,
646654};
lib/std/os/bits/freebsd.zig+8
......@@ -206,6 +206,14 @@ pub const sockaddr = extern struct {
206206 data: [14]u8,
207207};
208208
209pub const sockaddr_storage = extern struct {
210 len: u8,
211 family: sa_family_t,
212 __pad1: [5]u8,
213 __align: i64,
214 __pad2: [112]u8,
215};
216
209217pub const sockaddr_in = extern struct {
210218 len: u8 = @sizeOf(sockaddr_in),
211219 family: sa_family_t = AF_INET,
lib/std/os/bits/haiku.zig+8
......@@ -239,6 +239,14 @@ pub const sockaddr = extern struct {
239239 data: [14]u8,
240240};
241241
242pub const sockaddr_storage = extern struct {
243 len: u8,
244 family: sa_family_t,
245 __pad1: [5]u8,
246 __align: i64,
247 __pad2: [112]u8,
248};
249
242250pub const sockaddr_in = extern struct {
243251 len: u8 = @sizeOf(sockaddr_in),
244252 family: sa_family_t = AF_INET,
lib/std/os/bits/linux.zig+7
......@@ -1149,6 +1149,13 @@ pub const sockaddr = extern struct {
11491149 data: [14]u8,
11501150};
11511151
1152pub const sockaddr_storage = extern struct {
1153 family: sa_family_t,
1154 __pad1: [6]u8,
1155 __align: i64,
1156 __pad2: [112]u8,
1157};
1158
11521159/// IPv4 socket address
11531160pub const sockaddr_in = extern struct {
11541161 family: sa_family_t = AF_INET,
lib/std/os/bits/netbsd.zig+8
......@@ -226,6 +226,14 @@ pub const sockaddr = extern struct {
226226 data: [14]u8,
227227};
228228
229pub const sockaddr_storage = extern struct {
230 len: u8,
231 family: sa_family_t,
232 __pad1: [5]u8,
233 __align: i64,
234 __pad2: [112]u8,
235};
236
229237pub const sockaddr_in = extern struct {
230238 len: u8 = @sizeOf(sockaddr_in),
231239 family: sa_family_t = AF_INET,
lib/std/os/bits/openbsd.zig+149-9
......@@ -246,6 +246,14 @@ pub const sockaddr = extern struct {
246246 data: [14]u8,
247247};
248248
249pub const sockaddr_storage = extern struct {
250 len: u8,
251 family: sa_family_t,
252 __pad1: [5]u8,
253 __align: i64,
254 __pad2: [112]u8,
255};
256
249257pub const sockaddr_in = extern struct {
250258 len: u8 = @sizeOf(sockaddr_in),
251259 family: sa_family_t = AF_INET,
......@@ -290,15 +298,6 @@ pub const AI_NUMERICSERV = 16;
290298/// only if any address is assigned
291299pub const AI_ADDRCONFIG = 64;
292300
293pub const CTL_KERN = 1;
294pub const CTL_DEBUG = 5;
295pub const CTL_HW = 6;
296
297pub const KERN_PROC_ARGS = 55;
298pub const KERN_PROC_ARGV = 1;
299
300pub const HW_NCPUONLINE = 25;
301
302301pub const PATH_MAX = 1024;
303302
304303pub const STDIN_FILENO = 0;
......@@ -1229,3 +1228,144 @@ pub const POLLNORM = POLLRDNORM;
12291228pub const POLLWRNORM = POLLOUT;
12301229pub const POLLRDBAND = 0x0080;
12311230pub const POLLWRBAND = 0x0100;
1231
1232// sysctl mib
1233pub const CTL_UNSPEC = 0;
1234pub const CTL_KERN = 1;
1235pub const CTL_VM = 2;
1236pub const CTL_FS = 3;
1237pub const CTL_NET = 4;
1238pub const CTL_DEBUG = 5;
1239pub const CTL_HW = 6;
1240pub const CTL_MACHDEP = 7;
1241
1242pub const CTL_DDB = 9;
1243pub const CTL_VFS = 10;
1244
1245pub const KERN_OSTYPE = 1;
1246pub const KERN_OSRELEASE = 2;
1247pub const KERN_OSREV = 3;
1248pub const KERN_VERSION = 4;
1249pub const KERN_MAXVNODES = 5;
1250pub const KERN_MAXPROC = 6;
1251pub const KERN_MAXFILES = 7;
1252pub const KERN_ARGMAX = 8;
1253pub const KERN_SECURELVL = 9;
1254pub const KERN_HOSTNAME = 10;
1255pub const KERN_HOSTID = 11;
1256pub const KERN_CLOCKRATE = 12;
1257
1258pub const KERN_PROF = 16;
1259pub const KERN_POSIX1 = 17;
1260pub const KERN_NGROUPS = 18;
1261pub const KERN_JOB_CONTROL = 19;
1262pub const KERN_SAVED_IDS = 20;
1263pub const KERN_BOOTTIME = 21;
1264pub const KERN_DOMAINNAME = 22;
1265pub const KERN_MAXPARTITIONS = 23;
1266pub const KERN_RAWPARTITION = 24;
1267pub const KERN_MAXTHREAD = 25;
1268pub const KERN_NTHREADS = 26;
1269pub const KERN_OSVERSION = 27;
1270pub const KERN_SOMAXCONN = 28;
1271pub const KERN_SOMINCONN = 29;
1272
1273pub const KERN_NOSUIDCOREDUMP = 32;
1274pub const KERN_FSYNC = 33;
1275pub const KERN_SYSVMSG = 34;
1276pub const KERN_SYSVSEM = 35;
1277pub const KERN_SYSVSHM = 36;
1278
1279pub const KERN_MSGBUFSIZE = 38;
1280pub const KERN_MALLOCSTATS = 39;
1281pub const KERN_CPTIME = 40;
1282pub const KERN_NCHSTATS = 41;
1283pub const KERN_FORKSTAT = 42;
1284pub const KERN_NSELCOLL = 43;
1285pub const KERN_TTY = 44;
1286pub const KERN_CCPU = 45;
1287pub const KERN_FSCALE = 46;
1288pub const KERN_NPROCS = 47;
1289pub const KERN_MSGBUF = 48;
1290pub const KERN_POOL = 49;
1291pub const KERN_STACKGAPRANDOM = 50;
1292pub const KERN_SYSVIPC_INFO = 51;
1293pub const KERN_ALLOWKMEM = 52;
1294pub const KERN_WITNESSWATCH = 53;
1295pub const KERN_SPLASSERT = 54;
1296pub const KERN_PROC_ARGS = 55;
1297pub const KERN_NFILES = 56;
1298pub const KERN_TTYCOUNT = 57;
1299pub const KERN_NUMVNODES = 58;
1300pub const KERN_MBSTAT = 59;
1301pub const KERN_WITNESS = 60;
1302pub const KERN_SEMINFO = 61;
1303pub const KERN_SHMINFO = 62;
1304pub const KERN_INTRCNT = 63;
1305pub const KERN_WATCHDOG = 64;
1306pub const KERN_ALLOWDT = 65;
1307pub const KERN_PROC = 66;
1308pub const KERN_MAXCLUSTERS = 67;
1309pub const KERN_EVCOUNT = 68;
1310pub const KERN_TIMECOUNTER = 69;
1311pub const KERN_MAXLOCKSPERUID = 70;
1312pub const KERN_CPTIME2 = 71;
1313pub const KERN_CACHEPCT = 72;
1314pub const KERN_FILE = 73;
1315pub const KERN_WXABORT = 74;
1316pub const KERN_CONSDEV = 75;
1317pub const KERN_NETLIVELOCKS = 76;
1318pub const KERN_POOL_DEBUG = 77;
1319pub const KERN_PROC_CWD = 78;
1320pub const KERN_PROC_NOBROADCASTKILL = 79;
1321pub const KERN_PROC_VMMAP = 80;
1322pub const KERN_GLOBAL_PTRACE = 81;
1323pub const KERN_CONSBUFSIZE = 82;
1324pub const KERN_CONSBUF = 83;
1325pub const KERN_AUDIO = 84;
1326pub const KERN_CPUSTATS = 85;
1327pub const KERN_PFSTATUS = 86;
1328pub const KERN_TIMEOUT_STATS = 87;
1329pub const KERN_UTC_OFFSET = 88;
1330pub const KERN_VIDEO = 89;
1331
1332pub const HW_MACHINE = 1;
1333pub const HW_MODEL = 2;
1334pub const HW_NCPU = 3;
1335pub const HW_BYTEORDER = 4;
1336pub const HW_PHYSMEM = 5;
1337pub const HW_USERMEM = 6;
1338pub const HW_PAGESIZE = 7;
1339pub const HW_DISKNAMES = 8;
1340pub const HW_DISKSTATS = 9;
1341pub const HW_DISKCOUNT = 10;
1342pub const HW_SENSORS = 11;
1343pub const HW_CPUSPEED = 12;
1344pub const HW_SETPERF = 13;
1345pub const HW_VENDOR = 14;
1346pub const HW_PRODUCT = 15;
1347pub const HW_VERSION = 16;
1348pub const HW_SERIALNO = 17;
1349pub const HW_UUID = 18;
1350pub const HW_PHYSMEM64 = 19;
1351pub const HW_USERMEM64 = 20;
1352pub const HW_NCPUFOUND = 21;
1353pub const HW_ALLOWPOWERDOWN = 22;
1354pub const HW_PERFPOLICY = 23;
1355pub const HW_SMT = 24;
1356pub const HW_NCPUONLINE = 25;
1357
1358pub const KERN_PROC_ALL = 0;
1359pub const KERN_PROC_PID = 1;
1360pub const KERN_PROC_PGRP = 2;
1361pub const KERN_PROC_SESSION = 3;
1362pub const KERN_PROC_TTY = 4;
1363pub const KERN_PROC_UID = 5;
1364pub const KERN_PROC_RUID = 6;
1365pub const KERN_PROC_KTHREAD = 7;
1366pub const KERN_PROC_SHOW_THREADS = 0x40000000;
1367
1368pub const KERN_PROC_ARGV = 1;
1369pub const KERN_PROC_NARGV = 2;
1370pub const KERN_PROC_ENV = 3;
1371pub const KERN_PROC_NENV = 4;
lib/std/os/bits/windows.zig+2
......@@ -321,3 +321,5 @@ pub const O_NOATIME = 0o1000000;
321321pub const O_PATH = 0o10000000;
322322pub const O_TMPFILE = 0o20200000;
323323pub const O_NDELAY = O_NONBLOCK;
324
325pub const IFNAMESIZE = 30;
lib/std/os/linux.zig+39-24
......@@ -60,15 +60,30 @@ const require_aligned_register_pair =
6060 std.Target.current.cpu.arch.isThumb();
6161
6262// Split a 64bit value into a {LSB,MSB} pair.
63fn splitValue64(val: u64) [2]u32 {
63// The LE/BE variants specify the endianness to assume.
64fn splitValueLE64(val: i64) [2]u32 {
65 const u = @bitCast(u64, val);
66 return [2]u32{
67 @truncate(u32, u),
68 @truncate(u32, u >> 32),
69 };
70}
71fn splitValueBE64(val: i64) [2]u32 {
72 return [2]u32{
73 @truncate(u32, u >> 32),
74 @truncate(u32, u),
75 };
76}
77fn splitValue64(val: i64) [2]u32 {
78 const u = @bitCast(u64, val);
6479 switch (native_endian) {
6580 .Little => return [2]u32{
66 @truncate(u32, val),
67 @truncate(u32, val >> 32),
81 @truncate(u32, u),
82 @truncate(u32, u >> 32),
6883 },
6984 .Big => return [2]u32{
70 @truncate(u32, val >> 32),
71 @truncate(u32, val),
85 @truncate(u32, u >> 32),
86 @truncate(u32, u),
7287 },
7388 }
7489}
......@@ -142,8 +157,8 @@ pub fn utimensat(dirfd: i32, path: ?[*:0]const u8, times: *const [2]timespec, fl
142157 return syscall4(.utimensat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(times), flags);
143158}
144159
145pub fn fallocate(fd: i32, mode: i32, offset: u64, length: u64) usize {
146 if (@sizeOf(usize) == 4) {
160pub fn fallocate(fd: i32, mode: i32, offset: i64, length: i64) usize {
161 if (usize_bits < 64) {
147162 const offset_halves = splitValue64(offset);
148163 const length_halves = splitValue64(length);
149164 return syscall6(
......@@ -160,8 +175,8 @@ pub fn fallocate(fd: i32, mode: i32, offset: u64, length: u64) usize {
160175 .fallocate,
161176 @bitCast(usize, @as(isize, fd)),
162177 @bitCast(usize, @as(isize, mode)),
163 offset,
164 length,
178 @bitCast(u64, offset),
179 @bitCast(u64, length),
165180 );
166181 }
167182}
......@@ -244,7 +259,7 @@ pub fn umount2(special: [*:0]const u8, flags: u32) usize {
244259 return syscall2(.umount2, @ptrToInt(special), flags);
245260}
246261
247pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: u64) usize {
262pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: i64) usize {
248263 if (@hasField(SYS, "mmap2")) {
249264 // Make sure the offset is also specified in multiples of page size
250265 if ((offset & (MMAP2_UNIT - 1)) != 0)
......@@ -257,7 +272,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
257272 prot,
258273 flags,
259274 @bitCast(usize, @as(isize, fd)),
260 @truncate(usize, offset / MMAP2_UNIT),
275 @truncate(usize, @bitCast(u64, offset) / MMAP2_UNIT),
261276 );
262277 } else {
263278 return syscall6(
......@@ -267,7 +282,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
267282 prot,
268283 flags,
269284 @bitCast(usize, @as(isize, fd)),
270 offset,
285 @bitCast(u64, offset),
271286 );
272287 }
273288}
......@@ -309,8 +324,8 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
309324 return syscall3(.read, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
310325}
311326
312pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
313 const offset_halves = splitValue64(offset);
327pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: i64) usize {
328 const offset_halves = splitValueLE64(offset);
314329 return syscall5(
315330 .preadv,
316331 @bitCast(usize, @as(isize, fd)),
......@@ -321,7 +336,7 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
321336 );
322337}
323338
324pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: u64, flags: kernel_rwf) usize {
339pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: i64, flags: kernel_rwf) usize {
325340 const offset_halves = splitValue64(offset);
326341 return syscall6(
327342 .preadv2,
......@@ -342,8 +357,8 @@ pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
342357 return syscall3(.writev, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count);
343358}
344359
345pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
346 const offset_halves = splitValue64(offset);
360pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: i64) usize {
361 const offset_halves = splitValueLE64(offset);
347362 return syscall5(
348363 .pwritev,
349364 @bitCast(usize, @as(isize, fd)),
......@@ -354,7 +369,7 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us
354369 );
355370}
356371
357pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64, flags: kernel_rwf) usize {
372pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: i64, flags: kernel_rwf) usize {
358373 const offset_halves = splitValue64(offset);
359374 return syscall6(
360375 .pwritev2,
......@@ -387,7 +402,7 @@ pub fn symlinkat(existing: [*:0]const u8, newfd: i32, newpath: [*:0]const u8) us
387402 return syscall3(.symlinkat, @ptrToInt(existing), @bitCast(usize, @as(isize, newfd)), @ptrToInt(newpath));
388403}
389404
390pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
405pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: i64) usize {
391406 if (@hasField(SYS, "pread64") and usize_bits < 64) {
392407 const offset_halves = splitValue64(offset);
393408 if (require_aligned_register_pair) {
......@@ -418,7 +433,7 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
418433 @bitCast(usize, @as(isize, fd)),
419434 @ptrToInt(buf),
420435 count,
421 offset,
436 @bitCast(u64, offset),
422437 );
423438 }
424439}
......@@ -453,7 +468,7 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
453468 return syscall3(.write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
454469}
455470
456pub fn ftruncate(fd: i32, length: u64) usize {
471pub fn ftruncate(fd: i32, length: i64) usize {
457472 if (@hasField(SYS, "ftruncate64") and usize_bits < 64) {
458473 const length_halves = splitValue64(length);
459474 if (require_aligned_register_pair) {
......@@ -476,12 +491,12 @@ pub fn ftruncate(fd: i32, length: u64) usize {
476491 return syscall2(
477492 .ftruncate,
478493 @bitCast(usize, @as(isize, fd)),
479 @truncate(usize, length),
494 @bitCast(usize, length),
480495 );
481496 }
482497}
483498
484pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {
499pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: i64) usize {
485500 if (@hasField(SYS, "pwrite64") and usize_bits < 64) {
486501 const offset_halves = splitValue64(offset);
487502
......@@ -513,7 +528,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {
513528 @bitCast(usize, @as(isize, fd)),
514529 @ptrToInt(buf),
515530 count,
516 offset,
531 @bitCast(u64, offset),
517532 );
518533 }
519534}
lib/std/os/linux/test.zig+1-1
......@@ -20,7 +20,7 @@ test "fallocate" {
2020
2121 try expect((try file.stat()).size == 0);
2222
23 const len: u64 = 65536;
23 const len: i64 = 65536;
2424 switch (linux.getErrno(linux.fallocate(file.handle, 0, 0, len))) {
2525 0 => {},
2626 linux.ENOSYS => return error.SkipZigTest,
lib/std/os/test.zig-4
......@@ -263,10 +263,6 @@ test "linkat with different directories" {
263263test "fstatat" {
264264 // enable when `fstat` and `fstatat` are implemented on Windows
265265 if (builtin.os.tag == .windows) return error.SkipZigTest;
266 if (builtin.os.tag == .freebsd and builtin.mode == .ReleaseFast) {
267 // https://github.com/ziglang/zig/issues/8538
268 return error.SkipZigTest;
269 }
270266
271267 var tmp = tmpDir(.{});
272268 defer tmp.cleanup();
lib/std/os/windows.zig+95
......@@ -389,6 +389,43 @@ pub fn GetQueuedCompletionStatus(
389389 return GetQueuedCompletionStatusResult.Normal;
390390}
391391
392pub const GetQueuedCompletionStatusError = error{
393 Aborted,
394 Cancelled,
395 EOF,
396 Timeout,
397} || std.os.UnexpectedError;
398
399pub fn GetQueuedCompletionStatusEx(
400 completion_port: HANDLE,
401 completion_port_entries: []OVERLAPPED_ENTRY,
402 timeout_ms: ?DWORD,
403 alertable: bool,
404) GetQueuedCompletionStatusError!u32 {
405 var num_entries_removed: u32 = 0;
406
407 const success = kernel32.GetQueuedCompletionStatusEx(
408 completion_port,
409 completion_port_entries.ptr,
410 @intCast(ULONG, completion_port_entries.len),
411 &num_entries_removed,
412 timeout_ms orelse INFINITE,
413 @boolToInt(alertable),
414 );
415
416 if (success == FALSE) {
417 return switch (kernel32.GetLastError()) {
418 .ABANDONED_WAIT_0 => error.Aborted,
419 .OPERATION_ABORTED => error.Cancelled,
420 .HANDLE_EOF => error.EOF,
421 .IMEOUT => error.Timeout,
422 else => |err| unexpectedError(err),
423 };
424 }
425
426 return num_entries_removed;
427}
428
392429pub fn CloseHandle(hObject: HANDLE) void {
393430 assert(ntdll.NtClose(hObject) == .SUCCESS);
394431}
......@@ -1291,6 +1328,10 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so
12911328 return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen));
12921329}
12931330
1331pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
1332 return ws2_32.getpeername(s, name, @ptrCast(*i32, namelen));
1333}
1334
12941335pub fn sendmsg(
12951336 s: ws2_32.SOCKET,
12961337 msg: *const ws2_32.WSAMSG,
......@@ -1404,6 +1445,28 @@ pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetCon
14041445 }
14051446}
14061447
1448pub fn SetConsoleCtrlHandler(handler_routine: ?HANDLER_ROUTINE, add: bool) !void {
1449 const success = kernel32.SetConsoleCtrlHandler(
1450 handler_routine,
1451 if (add) TRUE else FALSE,
1452 );
1453
1454 if (success == FALSE) {
1455 return switch (kernel32.GetLastError()) {
1456 else => |err| unexpectedError(err),
1457 };
1458 }
1459}
1460
1461pub fn SetFileCompletionNotificationModes(handle: HANDLE, flags: UCHAR) !void {
1462 const success = kernel32.SetFileCompletionNotificationModes(handle, flags);
1463 if (success == FALSE) {
1464 return switch (kernel32.GetLastError()) {
1465 else => |err| unexpectedError(err),
1466 };
1467 }
1468}
1469
14071470pub const GetEnvironmentStringsError = error{OutOfMemory};
14081471
14091472pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*:0]u16 {
......@@ -1686,6 +1749,38 @@ fn MAKELANGID(p: c_ushort, s: c_ushort) callconv(.Inline) LANGID {
16861749 return (s << 10) | p;
16871750}
16881751
1752/// Loads a Winsock extension function in runtime specified by a GUID.
1753pub fn loadWinsockExtensionFunction(comptime T: type, sock: ws2_32.SOCKET, guid: GUID) !T {
1754 var function: T = undefined;
1755 var num_bytes: DWORD = undefined;
1756
1757 const rc = ws2_32.WSAIoctl(
1758 sock,
1759 ws2_32.SIO_GET_EXTENSION_FUNCTION_POINTER,
1760 @ptrCast(*const c_void, &guid),
1761 @sizeOf(GUID),
1762 &function,
1763 @sizeOf(T),
1764 &num_bytes,
1765 null,
1766 null,
1767 );
1768
1769 if (rc == ws2_32.SOCKET_ERROR) {
1770 return switch (ws2_32.WSAGetLastError()) {
1771 .WSAEOPNOTSUPP => error.OperationNotSupported,
1772 .WSAENOTSOCK => error.FileDescriptorNotASocket,
1773 else => |err| unexpectedWSAError(err),
1774 };
1775 }
1776
1777 if (num_bytes != @sizeOf(T)) {
1778 return error.ShortRead;
1779 }
1780
1781 return function;
1782}
1783
16891784/// Call this when you made a windows DLL call or something that does SetLastError
16901785/// and you get an unexpected error.
16911786pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
lib/std/os/windows/bits.zig+11-4
......@@ -1619,10 +1619,6 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct {
16191619};
16201620pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008;
16211621
1622pub const SD_RECEIVE = 0;
1623pub const SD_SEND = 1;
1624pub const SD_BOTH = 2;
1625
16261622pub const OBJECT_INFORMATION_CLASS = enum(c_int) {
16271623 ObjectBasicInformation = 0,
16281624 ObjectNameInformation = 1,
......@@ -1642,3 +1638,14 @@ pub const SRWLOCK = usize;
16421638pub const SRWLOCK_INIT: SRWLOCK = 0;
16431639pub const CONDITION_VARIABLE = usize;
16441640pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = 0;
1641
1642pub const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 0x1;
1643pub const FILE_SKIP_SET_EVENT_ON_HANDLE = 0x2;
1644
1645pub const CTRL_C_EVENT: DWORD = 0;
1646pub const CTRL_BREAK_EVENT: DWORD = 1;
1647pub const CTRL_CLOSE_EVENT: DWORD = 2;
1648pub const CTRL_LOGOFF_EVENT: DWORD = 5;
1649pub const CTRL_SHUTDOWN_EVENT: DWORD = 6;
1650
1651pub const HANDLER_ROUTINE = fn (dwCtrlType: DWORD) callconv(.C) BOOL;
lib/std/os/windows/kernel32.zig+18
......@@ -140,6 +140,14 @@ pub extern "kernel32" fn GetOverlappedResult(hFile: HANDLE, lpOverlapped: *OVERL
140140
141141pub extern "kernel32" fn GetProcessHeap() callconv(WINAPI) ?HANDLE;
142142pub extern "kernel32" fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) callconv(WINAPI) BOOL;
143pub extern "kernel32" fn GetQueuedCompletionStatusEx(
144 CompletionPort: HANDLE,
145 lpCompletionPortEntries: [*]OVERLAPPED_ENTRY,
146 ulCount: ULONG,
147 ulNumEntriesRemoved: *ULONG,
148 dwMilliseconds: DWORD,
149 fAlertable: BOOL,
150) callconv(WINAPI) BOOL;
143151
144152pub extern "kernel32" fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) callconv(WINAPI) void;
145153pub extern "kernel32" fn GetSystemTimeAsFileTime(*FILETIME) callconv(WINAPI) void;
......@@ -197,6 +205,16 @@ pub extern "kernel32" fn RemoveDirectoryW(lpPathName: [*:0]const u16) callconv(W
197205
198206pub extern "kernel32" fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) callconv(WINAPI) BOOL;
199207
208pub extern "kernel32" fn SetConsoleCtrlHandler(
209 HandlerRoutine: ?HANDLER_ROUTINE,
210 Add: BOOL,
211) callconv(WINAPI) BOOL;
212
213pub extern "kernel32" fn SetFileCompletionNotificationModes(
214 FileHandle: HANDLE,
215 Flags: UCHAR,
216) callconv(WINAPI) BOOL;
217
200218pub extern "kernel32" fn SetFilePointerEx(
201219 in_fFile: HANDLE,
202220 in_liDistanceToMove: LARGE_INTEGER,
lib/std/os/windows/ws2_32.zig+1668-246
......@@ -7,10 +7,929 @@ usingnamespace @import("bits.zig");
77
88pub const SOCKET = *opaque {};
99pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));
10pub const SOCKET_ERROR = -1;
1110
11pub const GROUP = u32;
12pub const ADDRESS_FAMILY = u16;
13pub const WSAEVENT = HANDLE;
14
15// Microsoft use the signed c_int for this, but it should never be negative
16pub const socklen_t = u32;
17
18pub const LM_HB_Extension = 128;
19pub const LM_HB1_PnP = 1;
20pub const LM_HB1_PDA_Palmtop = 2;
21pub const LM_HB1_Computer = 4;
22pub const LM_HB1_Printer = 8;
23pub const LM_HB1_Modem = 16;
24pub const LM_HB1_Fax = 32;
25pub const LM_HB1_LANAccess = 64;
26pub const LM_HB2_Telephony = 1;
27pub const LM_HB2_FileServer = 2;
28pub const ATMPROTO_AALUSER = 0;
29pub const ATMPROTO_AAL1 = 1;
30pub const ATMPROTO_AAL2 = 2;
31pub const ATMPROTO_AAL34 = 3;
32pub const ATMPROTO_AAL5 = 5;
33pub const SAP_FIELD_ABSENT = 4294967294;
34pub const SAP_FIELD_ANY = 4294967295;
35pub const SAP_FIELD_ANY_AESA_SEL = 4294967290;
36pub const SAP_FIELD_ANY_AESA_REST = 4294967291;
37pub const ATM_E164 = 1;
38pub const ATM_NSAP = 2;
39pub const ATM_AESA = 2;
40pub const ATM_ADDR_SIZE = 20;
41pub const BLLI_L2_ISO_1745 = 1;
42pub const BLLI_L2_Q921 = 2;
43pub const BLLI_L2_X25L = 6;
44pub const BLLI_L2_X25M = 7;
45pub const BLLI_L2_ELAPB = 8;
46pub const BLLI_L2_HDLC_ARM = 9;
47pub const BLLI_L2_HDLC_NRM = 10;
48pub const BLLI_L2_HDLC_ABM = 11;
49pub const BLLI_L2_LLC = 12;
50pub const BLLI_L2_X75 = 13;
51pub const BLLI_L2_Q922 = 14;
52pub const BLLI_L2_USER_SPECIFIED = 16;
53pub const BLLI_L2_ISO_7776 = 17;
54pub const BLLI_L3_X25 = 6;
55pub const BLLI_L3_ISO_8208 = 7;
56pub const BLLI_L3_X223 = 8;
57pub const BLLI_L3_SIO_8473 = 9;
58pub const BLLI_L3_T70 = 10;
59pub const BLLI_L3_ISO_TR9577 = 11;
60pub const BLLI_L3_USER_SPECIFIED = 16;
61pub const BLLI_L3_IPI_SNAP = 128;
62pub const BLLI_L3_IPI_IP = 204;
63pub const BHLI_ISO = 0;
64pub const BHLI_UserSpecific = 1;
65pub const BHLI_HighLayerProfile = 2;
66pub const BHLI_VendorSpecificAppId = 3;
67pub const AAL5_MODE_MESSAGE = 1;
68pub const AAL5_MODE_STREAMING = 2;
69pub const AAL5_SSCS_NULL = 0;
70pub const AAL5_SSCS_SSCOP_ASSURED = 1;
71pub const AAL5_SSCS_SSCOP_NON_ASSURED = 2;
72pub const AAL5_SSCS_FRAME_RELAY = 4;
73pub const BCOB_A = 1;
74pub const BCOB_C = 3;
75pub const BCOB_X = 16;
76pub const TT_NOIND = 0;
77pub const TT_CBR = 4;
78pub const TT_VBR = 8;
79pub const TR_NOIND = 0;
80pub const TR_END_TO_END = 1;
81pub const TR_NO_END_TO_END = 2;
82pub const CLIP_NOT = 0;
83pub const CLIP_SUS = 32;
84pub const UP_P2P = 0;
85pub const UP_P2MP = 1;
86pub const BLLI_L2_MODE_NORMAL = 64;
87pub const BLLI_L2_MODE_EXT = 128;
88pub const BLLI_L3_MODE_NORMAL = 64;
89pub const BLLI_L3_MODE_EXT = 128;
90pub const BLLI_L3_PACKET_16 = 4;
91pub const BLLI_L3_PACKET_32 = 5;
92pub const BLLI_L3_PACKET_64 = 6;
93pub const BLLI_L3_PACKET_128 = 7;
94pub const BLLI_L3_PACKET_256 = 8;
95pub const BLLI_L3_PACKET_512 = 9;
96pub const BLLI_L3_PACKET_1024 = 10;
97pub const BLLI_L3_PACKET_2048 = 11;
98pub const BLLI_L3_PACKET_4096 = 12;
99pub const PI_ALLOWED = 0;
100pub const PI_RESTRICTED = 64;
101pub const PI_NUMBER_NOT_AVAILABLE = 128;
102pub const SI_USER_NOT_SCREENED = 0;
103pub const SI_USER_PASSED = 1;
104pub const SI_USER_FAILED = 2;
105pub const SI_NETWORK = 3;
106pub const CAUSE_LOC_USER = 0;
107pub const CAUSE_LOC_PRIVATE_LOCAL = 1;
108pub const CAUSE_LOC_PUBLIC_LOCAL = 2;
109pub const CAUSE_LOC_TRANSIT_NETWORK = 3;
110pub const CAUSE_LOC_PUBLIC_REMOTE = 4;
111pub const CAUSE_LOC_PRIVATE_REMOTE = 5;
112pub const CAUSE_LOC_INTERNATIONAL_NETWORK = 7;
113pub const CAUSE_LOC_BEYOND_INTERWORKING = 10;
114pub const CAUSE_UNALLOCATED_NUMBER = 1;
115pub const CAUSE_NO_ROUTE_TO_TRANSIT_NETWORK = 2;
116pub const CAUSE_NO_ROUTE_TO_DESTINATION = 3;
117pub const CAUSE_VPI_VCI_UNACCEPTABLE = 10;
118pub const CAUSE_NORMAL_CALL_CLEARING = 16;
119pub const CAUSE_USER_BUSY = 17;
120pub const CAUSE_NO_USER_RESPONDING = 18;
121pub const CAUSE_CALL_REJECTED = 21;
122pub const CAUSE_NUMBER_CHANGED = 22;
123pub const CAUSE_USER_REJECTS_CLIR = 23;
124pub const CAUSE_DESTINATION_OUT_OF_ORDER = 27;
125pub const CAUSE_INVALID_NUMBER_FORMAT = 28;
126pub const CAUSE_STATUS_ENQUIRY_RESPONSE = 30;
127pub const CAUSE_NORMAL_UNSPECIFIED = 31;
128pub const CAUSE_VPI_VCI_UNAVAILABLE = 35;
129pub const CAUSE_NETWORK_OUT_OF_ORDER = 38;
130pub const CAUSE_TEMPORARY_FAILURE = 41;
131pub const CAUSE_ACCESS_INFORMAION_DISCARDED = 43;
132pub const CAUSE_NO_VPI_VCI_AVAILABLE = 45;
133pub const CAUSE_RESOURCE_UNAVAILABLE = 47;
134pub const CAUSE_QOS_UNAVAILABLE = 49;
135pub const CAUSE_USER_CELL_RATE_UNAVAILABLE = 51;
136pub const CAUSE_BEARER_CAPABILITY_UNAUTHORIZED = 57;
137pub const CAUSE_BEARER_CAPABILITY_UNAVAILABLE = 58;
138pub const CAUSE_OPTION_UNAVAILABLE = 63;
139pub const CAUSE_BEARER_CAPABILITY_UNIMPLEMENTED = 65;
140pub const CAUSE_UNSUPPORTED_TRAFFIC_PARAMETERS = 73;
141pub const CAUSE_INVALID_CALL_REFERENCE = 81;
142pub const CAUSE_CHANNEL_NONEXISTENT = 82;
143pub const CAUSE_INCOMPATIBLE_DESTINATION = 88;
144pub const CAUSE_INVALID_ENDPOINT_REFERENCE = 89;
145pub const CAUSE_INVALID_TRANSIT_NETWORK_SELECTION = 91;
146pub const CAUSE_TOO_MANY_PENDING_ADD_PARTY = 92;
147pub const CAUSE_AAL_PARAMETERS_UNSUPPORTED = 93;
148pub const CAUSE_MANDATORY_IE_MISSING = 96;
149pub const CAUSE_UNIMPLEMENTED_MESSAGE_TYPE = 97;
150pub const CAUSE_UNIMPLEMENTED_IE = 99;
151pub const CAUSE_INVALID_IE_CONTENTS = 100;
152pub const CAUSE_INVALID_STATE_FOR_MESSAGE = 101;
153pub const CAUSE_RECOVERY_ON_TIMEOUT = 102;
154pub const CAUSE_INCORRECT_MESSAGE_LENGTH = 104;
155pub const CAUSE_PROTOCOL_ERROR = 111;
156pub const CAUSE_COND_UNKNOWN = 0;
157pub const CAUSE_COND_PERMANENT = 1;
158pub const CAUSE_COND_TRANSIENT = 2;
159pub const CAUSE_REASON_USER = 0;
160pub const CAUSE_REASON_IE_MISSING = 4;
161pub const CAUSE_REASON_IE_INSUFFICIENT = 8;
162pub const CAUSE_PU_PROVIDER = 0;
163pub const CAUSE_PU_USER = 8;
164pub const CAUSE_NA_NORMAL = 0;
165pub const CAUSE_NA_ABNORMAL = 4;
166pub const QOS_CLASS0 = 0;
167pub const QOS_CLASS1 = 1;
168pub const QOS_CLASS2 = 2;
169pub const QOS_CLASS3 = 3;
170pub const QOS_CLASS4 = 4;
171pub const TNS_TYPE_NATIONAL = 64;
172pub const TNS_PLAN_CARRIER_ID_CODE = 1;
173pub const SIO_GET_NUMBER_OF_ATM_DEVICES = 1343619073;
174pub const SIO_GET_ATM_ADDRESS = 3491102722;
175pub const SIO_ASSOCIATE_PVC = 2417360899;
176pub const SIO_GET_ATM_CONNECTION_ID = 1343619076;
177pub const RIO_MSG_DONT_NOTIFY = 1;
178pub const RIO_MSG_DEFER = 2;
179pub const RIO_MSG_WAITALL = 4;
180pub const RIO_MSG_COMMIT_ONLY = 8;
181pub const RIO_MAX_CQ_SIZE = 134217728;
182pub const RIO_CORRUPT_CQ = 4294967295;
183pub const WINDOWS_AF_IRDA = 26;
184pub const WCE_AF_IRDA = 22;
185pub const IRDA_PROTO_SOCK_STREAM = 1;
186pub const SOL_IRLMP = 255;
187pub const IRLMP_ENUMDEVICES = 16;
188pub const IRLMP_IAS_SET = 17;
189pub const IRLMP_IAS_QUERY = 18;
190pub const IRLMP_SEND_PDU_LEN = 19;
191pub const IRLMP_EXCLUSIVE_MODE = 20;
192pub const IRLMP_IRLPT_MODE = 21;
193pub const IRLMP_9WIRE_MODE = 22;
194pub const IRLMP_TINYTP_MODE = 23;
195pub const IRLMP_PARAMETERS = 24;
196pub const IRLMP_DISCOVERY_MODE = 25;
197pub const IRLMP_SHARP_MODE = 32;
198pub const IAS_ATTRIB_NO_CLASS = 16;
199pub const IAS_ATTRIB_NO_ATTRIB = 0;
200pub const IAS_ATTRIB_INT = 1;
201pub const IAS_ATTRIB_OCTETSEQ = 2;
202pub const IAS_ATTRIB_STR = 3;
203pub const IAS_MAX_USER_STRING = 256;
204pub const IAS_MAX_OCTET_STRING = 1024;
205pub const IAS_MAX_CLASSNAME = 64;
206pub const IAS_MAX_ATTRIBNAME = 256;
207pub const LmCharSetASCII = 0;
208pub const LmCharSetISO_8859_1 = 1;
209pub const LmCharSetISO_8859_2 = 2;
210pub const LmCharSetISO_8859_3 = 3;
211pub const LmCharSetISO_8859_4 = 4;
212pub const LmCharSetISO_8859_5 = 5;
213pub const LmCharSetISO_8859_6 = 6;
214pub const LmCharSetISO_8859_7 = 7;
215pub const LmCharSetISO_8859_8 = 8;
216pub const LmCharSetISO_8859_9 = 9;
217pub const LmCharSetUNICODE = 255;
218pub const LM_BAUD_1200 = 1200;
219pub const LM_BAUD_2400 = 2400;
220pub const LM_BAUD_9600 = 9600;
221pub const LM_BAUD_19200 = 19200;
222pub const LM_BAUD_38400 = 38400;
223pub const LM_BAUD_57600 = 57600;
224pub const LM_BAUD_115200 = 115200;
225pub const LM_BAUD_576K = 576000;
226pub const LM_BAUD_1152K = 1152000;
227pub const LM_BAUD_4M = 4000000;
228pub const LM_BAUD_16M = 16000000;
229pub const IPX_PTYPE = 16384;
230pub const IPX_FILTERPTYPE = 16385;
231pub const IPX_STOPFILTERPTYPE = 16387;
232pub const IPX_DSTYPE = 16386;
233pub const IPX_EXTENDED_ADDRESS = 16388;
234pub const IPX_RECVHDR = 16389;
235pub const IPX_MAXSIZE = 16390;
236pub const IPX_ADDRESS = 16391;
237pub const IPX_GETNETINFO = 16392;
238pub const IPX_GETNETINFO_NORIP = 16393;
239pub const IPX_SPXGETCONNECTIONSTATUS = 16395;
240pub const IPX_ADDRESS_NOTIFY = 16396;
241pub const IPX_MAX_ADAPTER_NUM = 16397;
242pub const IPX_RERIPNETNUMBER = 16398;
243pub const IPX_RECEIVE_BROADCAST = 16399;
244pub const IPX_IMMEDIATESPXACK = 16400;
245pub const IPPROTO_RM = 113;
246pub const MAX_MCAST_TTL = 255;
247pub const RM_OPTIONSBASE = 1000;
248pub const RM_RATE_WINDOW_SIZE = 1001;
249pub const RM_SET_MESSAGE_BOUNDARY = 1002;
250pub const RM_FLUSHCACHE = 1003;
251pub const RM_SENDER_WINDOW_ADVANCE_METHOD = 1004;
252pub const RM_SENDER_STATISTICS = 1005;
253pub const RM_LATEJOIN = 1006;
254pub const RM_SET_SEND_IF = 1007;
255pub const RM_ADD_RECEIVE_IF = 1008;
256pub const RM_DEL_RECEIVE_IF = 1009;
257pub const RM_SEND_WINDOW_ADV_RATE = 1010;
258pub const RM_USE_FEC = 1011;
259pub const RM_SET_MCAST_TTL = 1012;
260pub const RM_RECEIVER_STATISTICS = 1013;
261pub const RM_HIGH_SPEED_INTRANET_OPT = 1014;
262pub const SENDER_DEFAULT_RATE_KBITS_PER_SEC = 56;
263pub const SENDER_DEFAULT_WINDOW_ADV_PERCENTAGE = 15;
264pub const MAX_WINDOW_INCREMENT_PERCENTAGE = 25;
265pub const SENDER_DEFAULT_LATE_JOINER_PERCENTAGE = 0;
266pub const SENDER_MAX_LATE_JOINER_PERCENTAGE = 75;
267pub const BITS_PER_BYTE = 8;
268pub const LOG2_BITS_PER_BYTE = 3;
269
270pub const SOCKET_DEFAULT2_QM_POLICY = GUID.parse("{aec2ef9c-3a4d-4d3e-8842-239942e39a47}");
271pub const REAL_TIME_NOTIFICATION_CAPABILITY = GUID.parse("{6b59819a-5cae-492d-a901-2a3c2c50164f}");
272pub const REAL_TIME_NOTIFICATION_CAPABILITY_EX = GUID.parse("{6843da03-154a-4616-a508-44371295f96b}");
273pub const ASSOCIATE_NAMERES_CONTEXT = GUID.parse("{59a38b67-d4fe-46e1-ba3c-87ea74ca3049}");
274
275pub const WSAID_CONNECTEX = GUID{
276 .Data1 = 0x25a207b9,
277 .Data2 = 0xddf3,
278 .Data3 = 0x4660,
279 .Data4 = [8]u8{ 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e },
280};
281
282pub const WSAID_ACCEPTEX = GUID{
283 .Data1 = 0xb5367df1,
284 .Data2 = 0xcbac,
285 .Data3 = 0x11cf,
286 .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 },
287};
288
289pub const WSAID_GETACCEPTEXSOCKADDRS = GUID{
290 .Data1 = 0xb5367df2,
291 .Data2 = 0xcbac,
292 .Data3 = 0x11cf,
293 .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 },
294};
295
296pub const WSAID_WSARECVMSG = GUID{
297 .Data1 = 0xf689d7c8,
298 .Data2 = 0x6f1f,
299 .Data3 = 0x436b,
300 .Data4 = [8]u8{ 0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22 },
301};
302
303pub const WSAID_WSAPOLL = GUID{
304 .Data1 = 0x18C76F85,
305 .Data2 = 0xDC66,
306 .Data3 = 0x4964,
307 .Data4 = [8]u8{ 0x97, 0x2E, 0x23, 0xC2, 0x72, 0x38, 0x31, 0x2B },
308};
309
310pub const WSAID_WSASENDMSG = GUID{
311 .Data1 = 0xa441e712,
312 .Data2 = 0x754f,
313 .Data3 = 0x43ca,
314 .Data4 = [8]u8{ 0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d },
315};
316
317pub const TCP_INITIAL_RTO_DEFAULT_RTT = 0;
318pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS = 0;
319pub const SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = 1;
320pub const SOCKET_SETTINGS_ALLOW_INSECURE = 2;
321pub const SOCKET_SETTINGS_IPSEC_SKIP_FILTER_INSTANTIATION = 1;
322pub const SOCKET_SETTINGS_IPSEC_OPTIONAL_PEER_NAME_VERIFICATION = 2;
323pub const SOCKET_SETTINGS_IPSEC_ALLOW_FIRST_INBOUND_PKT_UNENCRYPTED = 4;
324pub const SOCKET_SETTINGS_IPSEC_PEER_NAME_IS_RAW_FORMAT = 8;
325pub const SOCKET_QUERY_IPSEC2_ABORT_CONNECTION_ON_FIELD_CHANGE = 1;
326pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_MM_SA_ID = 1;
327pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_QM_SA_ID = 2;
328pub const SOCKET_INFO_CONNECTION_SECURED = 1;
329pub const SOCKET_INFO_CONNECTION_ENCRYPTED = 2;
330pub const SOCKET_INFO_CONNECTION_IMPERSONATED = 4;
331pub const IN4ADDR_LOOPBACK = 16777343;
332pub const IN4ADDR_LOOPBACKPREFIX_LENGTH = 8;
333pub const IN4ADDR_LINKLOCALPREFIX_LENGTH = 16;
334pub const IN4ADDR_MULTICASTPREFIX_LENGTH = 4;
335pub const IFF_UP = 1;
336pub const IFF_BROADCAST = 2;
337pub const IFF_LOOPBACK = 4;
338pub const IFF_POINTTOPOINT = 8;
339pub const IFF_MULTICAST = 16;
340pub const IP_OPTIONS = 1;
341pub const IP_HDRINCL = 2;
342pub const IP_TOS = 3;
343pub const IP_TTL = 4;
344pub const IP_MULTICAST_IF = 9;
345pub const IP_MULTICAST_TTL = 10;
346pub const IP_MULTICAST_LOOP = 11;
347pub const IP_ADD_MEMBERSHIP = 12;
348pub const IP_DROP_MEMBERSHIP = 13;
349pub const IP_DONTFRAGMENT = 14;
350pub const IP_ADD_SOURCE_MEMBERSHIP = 15;
351pub const IP_DROP_SOURCE_MEMBERSHIP = 16;
352pub const IP_BLOCK_SOURCE = 17;
353pub const IP_UNBLOCK_SOURCE = 18;
354pub const IP_PKTINFO = 19;
355pub const IP_HOPLIMIT = 21;
356pub const IP_RECVTTL = 21;
357pub const IP_RECEIVE_BROADCAST = 22;
358pub const IP_RECVIF = 24;
359pub const IP_RECVDSTADDR = 25;
360pub const IP_IFLIST = 28;
361pub const IP_ADD_IFLIST = 29;
362pub const IP_DEL_IFLIST = 30;
363pub const IP_UNICAST_IF = 31;
364pub const IP_RTHDR = 32;
365pub const IP_GET_IFLIST = 33;
366pub const IP_RECVRTHDR = 38;
367pub const IP_TCLASS = 39;
368pub const IP_RECVTCLASS = 40;
369pub const IP_RECVTOS = 40;
370pub const IP_ORIGINAL_ARRIVAL_IF = 47;
371pub const IP_ECN = 50;
372pub const IP_PKTINFO_EX = 51;
373pub const IP_WFP_REDIRECT_RECORDS = 60;
374pub const IP_WFP_REDIRECT_CONTEXT = 70;
375pub const IP_MTU_DISCOVER = 71;
376pub const IP_MTU = 73;
377pub const IP_NRT_INTERFACE = 74;
378pub const IP_RECVERR = 75;
379pub const IP_USER_MTU = 76;
380pub const IP_UNSPECIFIED_TYPE_OF_SERVICE = -1;
381pub const IN6ADDR_LINKLOCALPREFIX_LENGTH = 64;
382pub const IN6ADDR_MULTICASTPREFIX_LENGTH = 8;
383pub const IN6ADDR_SOLICITEDNODEMULTICASTPREFIX_LENGTH = 104;
384pub const IN6ADDR_V4MAPPEDPREFIX_LENGTH = 96;
385pub const IN6ADDR_6TO4PREFIX_LENGTH = 16;
386pub const IN6ADDR_TEREDOPREFIX_LENGTH = 32;
387pub const MCAST_JOIN_GROUP = 41;
388pub const MCAST_LEAVE_GROUP = 42;
389pub const MCAST_BLOCK_SOURCE = 43;
390pub const MCAST_UNBLOCK_SOURCE = 44;
391pub const MCAST_JOIN_SOURCE_GROUP = 45;
392pub const MCAST_LEAVE_SOURCE_GROUP = 46;
393pub const IPV6_HOPOPTS = 1;
394pub const IPV6_HDRINCL = 2;
395pub const IPV6_UNICAST_HOPS = 4;
396pub const IPV6_MULTICAST_IF = 9;
397pub const IPV6_MULTICAST_HOPS = 10;
398pub const IPV6_MULTICAST_LOOP = 11;
399pub const IPV6_ADD_MEMBERSHIP = 12;
400pub const IPV6_DROP_MEMBERSHIP = 13;
401pub const IPV6_DONTFRAG = 14;
402pub const IPV6_PKTINFO = 19;
403pub const IPV6_HOPLIMIT = 21;
404pub const IPV6_PROTECTION_LEVEL = 23;
405pub const IPV6_RECVIF = 24;
406pub const IPV6_RECVDSTADDR = 25;
407pub const IPV6_CHECKSUM = 26;
408pub const IPV6_V6ONLY = 27;
409pub const IPV6_IFLIST = 28;
410pub const IPV6_ADD_IFLIST = 29;
411pub const IPV6_DEL_IFLIST = 30;
412pub const IPV6_UNICAST_IF = 31;
413pub const IPV6_RTHDR = 32;
414pub const IPV6_GET_IFLIST = 33;
415pub const IPV6_RECVRTHDR = 38;
416pub const IPV6_TCLASS = 39;
417pub const IPV6_RECVTCLASS = 40;
418pub const IPV6_ECN = 50;
419pub const IPV6_PKTINFO_EX = 51;
420pub const IPV6_WFP_REDIRECT_RECORDS = 60;
421pub const IPV6_WFP_REDIRECT_CONTEXT = 70;
422pub const IPV6_MTU_DISCOVER = 71;
423pub const IPV6_MTU = 72;
424pub const IPV6_NRT_INTERFACE = 74;
425pub const IPV6_RECVERR = 75;
426pub const IPV6_USER_MTU = 76;
427pub const IP_UNSPECIFIED_HOP_LIMIT = -1;
428pub const PROTECTION_LEVEL_UNRESTRICTED = 10;
429pub const PROTECTION_LEVEL_EDGERESTRICTED = 20;
430pub const PROTECTION_LEVEL_RESTRICTED = 30;
431pub const INET_ADDRSTRLEN = 22;
432pub const INET6_ADDRSTRLEN = 65;
433pub const TCP_OFFLOAD_NO_PREFERENCE = 0;
434pub const TCP_OFFLOAD_NOT_PREFERRED = 1;
435pub const TCP_OFFLOAD_PREFERRED = 2;
436pub const TCP_EXPEDITED_1122 = 2;
437pub const TCP_KEEPALIVE = 3;
438pub const TCP_MAXSEG = 4;
439pub const TCP_MAXRT = 5;
440pub const TCP_STDURG = 6;
441pub const TCP_NOURG = 7;
442pub const TCP_ATMARK = 8;
443pub const TCP_NOSYNRETRIES = 9;
444pub const TCP_TIMESTAMPS = 10;
445pub const TCP_OFFLOAD_PREFERENCE = 11;
446pub const TCP_CONGESTION_ALGORITHM = 12;
447pub const TCP_DELAY_FIN_ACK = 13;
448pub const TCP_MAXRTMS = 14;
449pub const TCP_FASTOPEN = 15;
450pub const TCP_KEEPCNT = 16;
451pub const TCP_KEEPINTVL = 17;
452pub const TCP_FAIL_CONNECT_ON_ICMP_ERROR = 18;
453pub const TCP_ICMP_ERROR_INFO = 19;
454pub const UDP_SEND_MSG_SIZE = 2;
455pub const UDP_RECV_MAX_COALESCED_SIZE = 3;
456pub const UDP_COALESCED_INFO = 3;
457pub const AF_UNSPEC = 0;
458pub const AF_UNIX = 1;
459pub const AF_INET = 2;
460pub const AF_IMPLINK = 3;
461pub const AF_PUP = 4;
462pub const AF_CHAOS = 5;
463pub const AF_NS = 6;
464pub const AF_ISO = 7;
465pub const AF_ECMA = 8;
466pub const AF_DATAKIT = 9;
467pub const AF_CCITT = 10;
468pub const AF_SNA = 11;
469pub const AF_DECnet = 12;
470pub const AF_DLI = 13;
471pub const AF_LAT = 14;
472pub const AF_HYLINK = 15;
473pub const AF_APPLETALK = 16;
474pub const AF_NETBIOS = 17;
475pub const AF_VOICEVIEW = 18;
476pub const AF_FIREFOX = 19;
477pub const AF_UNKNOWN1 = 20;
478pub const AF_BAN = 21;
479pub const AF_ATM = 22;
480pub const AF_INET6 = 23;
481pub const AF_CLUSTER = 24;
482pub const AF_12844 = 25;
483pub const AF_IRDA = 26;
484pub const AF_NETDES = 28;
485pub const AF_MAX = 29;
486pub const AF_TCNPROCESS = 29;
487pub const AF_TCNMESSAGE = 30;
488pub const AF_ICLFXBM = 31;
489pub const AF_LINK = 33;
490pub const AF_HYPERV = 34;
491pub const SOCK_STREAM = 1;
492pub const SOCK_DGRAM = 2;
493pub const SOCK_RAW = 3;
494pub const SOCK_RDM = 4;
495pub const SOCK_SEQPACKET = 5;
496pub const SOL_SOCKET = 65535;
497pub const SO_DEBUG = 1;
498pub const SO_ACCEPTCONN = 2;
499pub const SO_REUSEADDR = 4;
500pub const SO_KEEPALIVE = 8;
501pub const SO_DONTROUTE = 16;
502pub const SO_BROADCAST = 32;
503pub const SO_USELOOPBACK = 64;
504pub const SO_LINGER = 128;
505pub const SO_OOBINLINE = 256;
506pub const SO_SNDBUF = 4097;
507pub const SO_RCVBUF = 4098;
508pub const SO_SNDLOWAT = 4099;
509pub const SO_RCVLOWAT = 4100;
510pub const SO_SNDTIMEO = 4101;
511pub const SO_RCVTIMEO = 4102;
512pub const SO_ERROR = 4103;
513pub const SO_TYPE = 4104;
514pub const SO_BSP_STATE = 4105;
515pub const SO_GROUP_ID = 8193;
516pub const SO_GROUP_PRIORITY = 8194;
517pub const SO_MAX_MSG_SIZE = 8195;
518pub const SO_CONDITIONAL_ACCEPT = 12290;
519pub const SO_PAUSE_ACCEPT = 12291;
520pub const SO_COMPARTMENT_ID = 12292;
521pub const SO_RANDOMIZE_PORT = 12293;
522pub const SO_PORT_SCALABILITY = 12294;
523pub const SO_REUSE_UNICASTPORT = 12295;
524pub const SO_REUSE_MULTICASTPORT = 12296;
525pub const SO_ORIGINAL_DST = 12303;
526pub const WSK_SO_BASE = 16384;
527pub const TCP_NODELAY = 1;
528pub const IOC_UNIX = 0;
529pub const IOC_WS2 = 134217728;
530pub const IOC_PROTOCOL = 268435456;
531pub const IOC_VENDOR = 402653184;
532pub const SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_OUT | IOC_IN | IOC_WS2 | 6;
533pub const SIO_BSP_HANDLE = IOC_OUT | IOC_WS2 | 27;
534pub const SIO_BSP_HANDLE_SELECT = IOC_OUT | IOC_WS2 | 28;
535pub const SIO_BSP_HANDLE_POLL = IOC_OUT | IOC_WS2 | 29;
536pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34;
537pub const IPPROTO_IP = 0;
538pub const IPPORT_TCPMUX = 1;
539pub const IPPORT_ECHO = 7;
540pub const IPPORT_DISCARD = 9;
541pub const IPPORT_SYSTAT = 11;
542pub const IPPORT_DAYTIME = 13;
543pub const IPPORT_NETSTAT = 15;
544pub const IPPORT_QOTD = 17;
545pub const IPPORT_MSP = 18;
546pub const IPPORT_CHARGEN = 19;
547pub const IPPORT_FTP_DATA = 20;
548pub const IPPORT_FTP = 21;
549pub const IPPORT_TELNET = 23;
550pub const IPPORT_SMTP = 25;
551pub const IPPORT_TIMESERVER = 37;
552pub const IPPORT_NAMESERVER = 42;
553pub const IPPORT_WHOIS = 43;
554pub const IPPORT_MTP = 57;
555pub const IPPORT_TFTP = 69;
556pub const IPPORT_RJE = 77;
557pub const IPPORT_FINGER = 79;
558pub const IPPORT_TTYLINK = 87;
559pub const IPPORT_SUPDUP = 95;
560pub const IPPORT_POP3 = 110;
561pub const IPPORT_NTP = 123;
562pub const IPPORT_EPMAP = 135;
563pub const IPPORT_NETBIOS_NS = 137;
564pub const IPPORT_NETBIOS_DGM = 138;
565pub const IPPORT_NETBIOS_SSN = 139;
566pub const IPPORT_IMAP = 143;
567pub const IPPORT_SNMP = 161;
568pub const IPPORT_SNMP_TRAP = 162;
569pub const IPPORT_IMAP3 = 220;
570pub const IPPORT_LDAP = 389;
571pub const IPPORT_HTTPS = 443;
572pub const IPPORT_MICROSOFT_DS = 445;
573pub const IPPORT_EXECSERVER = 512;
574pub const IPPORT_LOGINSERVER = 513;
575pub const IPPORT_CMDSERVER = 514;
576pub const IPPORT_EFSSERVER = 520;
577pub const IPPORT_BIFFUDP = 512;
578pub const IPPORT_WHOSERVER = 513;
579pub const IPPORT_ROUTESERVER = 520;
580pub const IPPORT_RESERVED = 1024;
581pub const IPPORT_REGISTERED_MAX = 49151;
582pub const IPPORT_DYNAMIC_MIN = 49152;
583pub const IPPORT_DYNAMIC_MAX = 65535;
584pub const IN_CLASSA_NET = 4278190080;
585pub const IN_CLASSA_NSHIFT = 24;
586pub const IN_CLASSA_HOST = 16777215;
587pub const IN_CLASSA_MAX = 128;
588pub const IN_CLASSB_NET = 4294901760;
589pub const IN_CLASSB_NSHIFT = 16;
590pub const IN_CLASSB_HOST = 65535;
591pub const IN_CLASSB_MAX = 65536;
592pub const IN_CLASSC_NET = 4294967040;
593pub const IN_CLASSC_NSHIFT = 8;
594pub const IN_CLASSC_HOST = 255;
595pub const IN_CLASSD_NET = 4026531840;
596pub const IN_CLASSD_NSHIFT = 28;
597pub const IN_CLASSD_HOST = 268435455;
598pub const INADDR_LOOPBACK = 2130706433;
599pub const INADDR_NONE = 4294967295;
600pub const IOCPARM_MASK = 127;
601pub const IOC_VOID = 536870912;
602pub const IOC_OUT = 1073741824;
603pub const IOC_IN = 2147483648;
604pub const MSG_TRUNC = 256;
605pub const MSG_CTRUNC = 512;
606pub const MSG_BCAST = 1024;
607pub const MSG_MCAST = 2048;
608pub const MSG_ERRQUEUE = 4096;
609pub const AI_PASSIVE = 1;
610pub const AI_CANONNAME = 2;
611pub const AI_NUMERICHOST = 4;
612pub const AI_NUMERICSERV = 8;
613pub const AI_DNS_ONLY = 16;
614pub const AI_ALL = 256;
615pub const AI_ADDRCONFIG = 1024;
616pub const AI_V4MAPPED = 2048;
617pub const AI_NON_AUTHORITATIVE = 16384;
618pub const AI_SECURE = 32768;
619pub const AI_RETURN_PREFERRED_NAMES = 65536;
620pub const AI_FQDN = 131072;
621pub const AI_FILESERVER = 262144;
622pub const AI_DISABLE_IDN_ENCODING = 524288;
623pub const AI_EXTENDED = 2147483648;
624pub const AI_RESOLUTION_HANDLE = 1073741824;
625pub const FIONBIO = -2147195266;
626pub const ADDRINFOEX_VERSION_2 = 2;
627pub const ADDRINFOEX_VERSION_3 = 3;
628pub const ADDRINFOEX_VERSION_4 = 4;
629pub const NS_ALL = 0;
630pub const NS_SAP = 1;
631pub const NS_NDS = 2;
632pub const NS_PEER_BROWSE = 3;
633pub const NS_SLP = 5;
634pub const NS_DHCP = 6;
635pub const NS_TCPIP_LOCAL = 10;
636pub const NS_TCPIP_HOSTS = 11;
637pub const NS_DNS = 12;
638pub const NS_NETBT = 13;
639pub const NS_WINS = 14;
640pub const NS_NLA = 15;
641pub const NS_NBP = 20;
642pub const NS_MS = 30;
643pub const NS_STDA = 31;
644pub const NS_NTDS = 32;
645pub const NS_EMAIL = 37;
646pub const NS_X500 = 40;
647pub const NS_NIS = 41;
648pub const NS_NISPLUS = 42;
649pub const NS_WRQ = 50;
650pub const NS_NETDES = 60;
651pub const NI_NOFQDN = 1;
652pub const NI_NUMERICHOST = 2;
653pub const NI_NAMEREQD = 4;
654pub const NI_NUMERICSERV = 8;
655pub const NI_DGRAM = 16;
656pub const NI_MAXHOST = 1025;
657pub const NI_MAXSERV = 32;
658pub const INCL_WINSOCK_API_PROTOTYPES = 1;
659pub const INCL_WINSOCK_API_TYPEDEFS = 0;
660pub const FD_SETSIZE = 64;
661pub const IMPLINK_IP = 155;
662pub const IMPLINK_LOWEXPER = 156;
663pub const IMPLINK_HIGHEXPER = 158;
12664pub const WSADESCRIPTION_LEN = 256;
13665pub const WSASYS_STATUS_LEN = 128;
666pub const SOCKET_ERROR = -1;
667pub const FROM_PROTOCOL_INFO = -1;
668pub const SO_PROTOCOL_INFOA = 8196;
669pub const SO_PROTOCOL_INFOW = 8197;
670pub const PVD_CONFIG = 12289;
671pub const SOMAXCONN = 2147483647;
672pub const MSG_PEEK = 2;
673pub const MSG_WAITALL = 8;
674pub const MSG_PUSH_IMMEDIATE = 32;
675pub const MSG_PARTIAL = 32768;
676pub const MSG_INTERRUPT = 16;
677pub const MSG_MAXIOVLEN = 16;
678pub const MAXGETHOSTSTRUCT = 1024;
679pub const FD_READ_BIT = 0;
680pub const FD_WRITE_BIT = 1;
681pub const FD_OOB_BIT = 2;
682pub const FD_ACCEPT_BIT = 3;
683pub const FD_CONNECT_BIT = 4;
684pub const FD_CLOSE_BIT = 5;
685pub const FD_QOS_BIT = 6;
686pub const FD_GROUP_QOS_BIT = 7;
687pub const FD_ROUTING_INTERFACE_CHANGE_BIT = 8;
688pub const FD_ADDRESS_LIST_CHANGE_BIT = 9;
689pub const FD_MAX_EVENTS = 10;
690pub const CF_ACCEPT = 0;
691pub const CF_REJECT = 1;
692pub const CF_DEFER = 2;
693pub const SD_RECEIVE = 0;
694pub const SD_SEND = 1;
695pub const SD_BOTH = 2;
696pub const SG_UNCONSTRAINED_GROUP = 1;
697pub const SG_CONSTRAINED_GROUP = 2;
698pub const MAX_PROTOCOL_CHAIN = 7;
699pub const BASE_PROTOCOL = 1;
700pub const LAYERED_PROTOCOL = 0;
701pub const WSAPROTOCOL_LEN = 255;
702pub const PFL_MULTIPLE_PROTO_ENTRIES = 1;
703pub const PFL_RECOMMENDED_PROTO_ENTRY = 2;
704pub const PFL_HIDDEN = 4;
705pub const PFL_MATCHES_PROTOCOL_ZERO = 8;
706pub const PFL_NETWORKDIRECT_PROVIDER = 16;
707pub const XP1_CONNECTIONLESS = 1;
708pub const XP1_GUARANTEED_DELIVERY = 2;
709pub const XP1_GUARANTEED_ORDER = 4;
710pub const XP1_MESSAGE_ORIENTED = 8;
711pub const XP1_PSEUDO_STREAM = 16;
712pub const XP1_GRACEFUL_CLOSE = 32;
713pub const XP1_EXPEDITED_DATA = 64;
714pub const XP1_CONNECT_DATA = 128;
715pub const XP1_DISCONNECT_DATA = 256;
716pub const XP1_SUPPORT_BROADCAST = 512;
717pub const XP1_SUPPORT_MULTIPOINT = 1024;
718pub const XP1_MULTIPOINT_CONTROL_PLANE = 2048;
719pub const XP1_MULTIPOINT_DATA_PLANE = 4096;
720pub const XP1_QOS_SUPPORTED = 8192;
721pub const XP1_INTERRUPT = 16384;
722pub const XP1_UNI_SEND = 32768;
723pub const XP1_UNI_RECV = 65536;
724pub const XP1_IFS_HANDLES = 131072;
725pub const XP1_PARTIAL_MESSAGE = 262144;
726pub const XP1_SAN_SUPPORT_SDP = 524288;
727pub const BIGENDIAN = 0;
728pub const LITTLEENDIAN = 1;
729pub const SECURITY_PROTOCOL_NONE = 0;
730pub const JL_SENDER_ONLY = 1;
731pub const JL_RECEIVER_ONLY = 2;
732pub const JL_BOTH = 4;
733pub const WSA_FLAG_OVERLAPPED = 1;
734pub const WSA_FLAG_MULTIPOINT_C_ROOT = 2;
735pub const WSA_FLAG_MULTIPOINT_C_LEAF = 4;
736pub const WSA_FLAG_MULTIPOINT_D_ROOT = 8;
737pub const WSA_FLAG_MULTIPOINT_D_LEAF = 16;
738pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY = 64;
739pub const WSA_FLAG_NO_HANDLE_INHERIT = 128;
740pub const WSA_FLAG_REGISTERED_IO = 256;
741pub const TH_NETDEV = 1;
742pub const TH_TAPI = 2;
743pub const SERVICE_MULTIPLE = 1;
744pub const NS_LOCALNAME = 19;
745pub const RES_UNUSED_1 = 1;
746pub const RES_FLUSH_CACHE = 2;
747pub const RES_SERVICE = 4;
748pub const LUP_DEEP = 1;
749pub const LUP_CONTAINERS = 2;
750pub const LUP_NOCONTAINERS = 4;
751pub const LUP_NEAREST = 8;
752pub const LUP_RETURN_NAME = 16;
753pub const LUP_RETURN_TYPE = 32;
754pub const LUP_RETURN_VERSION = 64;
755pub const LUP_RETURN_COMMENT = 128;
756pub const LUP_RETURN_ADDR = 256;
757pub const LUP_RETURN_BLOB = 512;
758pub const LUP_RETURN_ALIASES = 1024;
759pub const LUP_RETURN_QUERY_STRING = 2048;
760pub const LUP_RETURN_ALL = 4080;
761pub const LUP_RES_SERVICE = 32768;
762pub const LUP_FLUSHCACHE = 4096;
763pub const LUP_FLUSHPREVIOUS = 8192;
764pub const LUP_NON_AUTHORITATIVE = 16384;
765pub const LUP_SECURE = 32768;
766pub const LUP_RETURN_PREFERRED_NAMES = 65536;
767pub const LUP_DNS_ONLY = 131072;
768pub const LUP_ADDRCONFIG = 1048576;
769pub const LUP_DUAL_ADDR = 2097152;
770pub const LUP_FILESERVER = 4194304;
771pub const LUP_DISABLE_IDN_ENCODING = 8388608;
772pub const LUP_API_ANSI = 16777216;
773pub const LUP_RESOLUTION_HANDLE = 2147483648;
774pub const RESULT_IS_ALIAS = 1;
775pub const RESULT_IS_ADDED = 16;
776pub const RESULT_IS_CHANGED = 32;
777pub const RESULT_IS_DELETED = 64;
778pub const POLLRDNORM = 256;
779pub const POLLRDBAND = 512;
780pub const POLLPRI = 1024;
781pub const POLLWRNORM = 16;
782pub const POLLWRBAND = 32;
783pub const POLLERR = 1;
784pub const POLLHUP = 2;
785pub const POLLNVAL = 4;
786pub const SO_CONNDATA = 28672;
787pub const SO_CONNOPT = 28673;
788pub const SO_DISCDATA = 28674;
789pub const SO_DISCOPT = 28675;
790pub const SO_CONNDATALEN = 28676;
791pub const SO_CONNOPTLEN = 28677;
792pub const SO_DISCDATALEN = 28678;
793pub const SO_DISCOPTLEN = 28679;
794pub const SO_OPENTYPE = 28680;
795pub const SO_SYNCHRONOUS_ALERT = 16;
796pub const SO_SYNCHRONOUS_NONALERT = 32;
797pub const SO_MAXDG = 28681;
798pub const SO_MAXPATHDG = 28682;
799pub const SO_UPDATE_ACCEPT_CONTEXT = 28683;
800pub const SO_CONNECT_TIME = 28684;
801pub const SO_UPDATE_CONNECT_CONTEXT = 28688;
802pub const TCP_BSDURGENT = 28672;
803pub const TF_DISCONNECT = 1;
804pub const TF_REUSE_SOCKET = 2;
805pub const TF_WRITE_BEHIND = 4;
806pub const TF_USE_DEFAULT_WORKER = 0;
807pub const TF_USE_SYSTEM_THREAD = 16;
808pub const TF_USE_KERNEL_APC = 32;
809pub const TP_ELEMENT_MEMORY = 1;
810pub const TP_ELEMENT_FILE = 2;
811pub const TP_ELEMENT_EOP = 4;
812pub const NLA_ALLUSERS_NETWORK = 1;
813pub const NLA_FRIENDLY_NAME = 2;
814pub const WSPDESCRIPTION_LEN = 255;
815pub const WSS_OPERATION_IN_PROGRESS = 259;
816pub const LSP_SYSTEM = 2147483648;
817pub const LSP_INSPECTOR = 1;
818pub const LSP_REDIRECTOR = 2;
819pub const LSP_PROXY = 4;
820pub const LSP_FIREWALL = 8;
821pub const LSP_INBOUND_MODIFY = 16;
822pub const LSP_OUTBOUND_MODIFY = 32;
823pub const LSP_CRYPTO_COMPRESS = 64;
824pub const LSP_LOCAL_CACHE = 128;
825pub const IPPROTO_ICMP = 1;
826pub const IPPROTO_IGMP = 2;
827pub const IPPROTO_GGP = 3;
828pub const IPPROTO_TCP = 6;
829pub const IPPROTO_PUP = 12;
830pub const IPPROTO_UDP = 17;
831pub const IPPROTO_IDP = 22;
832pub const IPPROTO_ND = 77;
833pub const IPPROTO_RAW = 255;
834pub const IPPROTO_MAX = 256;
835pub const IP_DEFAULT_MULTICAST_TTL = 1;
836pub const IP_DEFAULT_MULTICAST_LOOP = 1;
837pub const IP_MAX_MEMBERSHIPS = 20;
838pub const AF_IPX = 6;
839pub const FD_READ = 1;
840pub const FD_WRITE = 2;
841pub const FD_OOB = 4;
842pub const FD_ACCEPT = 8;
843pub const FD_CONNECT = 16;
844pub const FD_CLOSE = 32;
845pub const SERVICE_RESOURCE = 1;
846pub const SERVICE_SERVICE = 2;
847pub const SERVICE_LOCAL = 4;
848pub const SERVICE_FLAG_DEFER = 1;
849pub const SERVICE_FLAG_HARD = 2;
850pub const PROP_COMMENT = 1;
851pub const PROP_LOCALE = 2;
852pub const PROP_DISPLAY_HINT = 4;
853pub const PROP_VERSION = 8;
854pub const PROP_START_TIME = 16;
855pub const PROP_MACHINE = 32;
856pub const PROP_ADDRESSES = 256;
857pub const PROP_SD = 512;
858pub const PROP_ALL = 2147483648;
859pub const SERVICE_ADDRESS_FLAG_RPC_CN = 1;
860pub const SERVICE_ADDRESS_FLAG_RPC_DG = 2;
861pub const SERVICE_ADDRESS_FLAG_RPC_NB = 4;
862pub const NS_DEFAULT = 0;
863pub const NS_VNS = 50;
864pub const NSTYPE_HIERARCHICAL = 1;
865pub const NSTYPE_DYNAMIC = 2;
866pub const NSTYPE_ENUMERABLE = 4;
867pub const NSTYPE_WORKGROUP = 8;
868pub const XP_CONNECTIONLESS = 1;
869pub const XP_GUARANTEED_DELIVERY = 2;
870pub const XP_GUARANTEED_ORDER = 4;
871pub const XP_MESSAGE_ORIENTED = 8;
872pub const XP_PSEUDO_STREAM = 16;
873pub const XP_GRACEFUL_CLOSE = 32;
874pub const XP_EXPEDITED_DATA = 64;
875pub const XP_CONNECT_DATA = 128;
876pub const XP_DISCONNECT_DATA = 256;
877pub const XP_SUPPORTS_BROADCAST = 512;
878pub const XP_SUPPORTS_MULTICAST = 1024;
879pub const XP_BANDWIDTH_ALLOCATION = 2048;
880pub const XP_FRAGMENTATION = 4096;
881pub const XP_ENCRYPTS = 8192;
882pub const RES_SOFT_SEARCH = 1;
883pub const RES_FIND_MULTIPLE = 2;
884pub const SET_SERVICE_PARTIAL_SUCCESS = 1;
885pub const UDP_NOCHECKSUM = 1;
886pub const UDP_CHECKSUM_COVERAGE = 20;
887pub const GAI_STRERROR_BUFFER_SIZE = 1024;
888
889pub const LPCONDITIONPROC = fn (
890 lpCallerId: *WSABUF,
891 lpCallerData: *WSABUF,
892 lpSQOS: *QOS,
893 lpGQOS: *QOS,
894 lpCalleeId: *WSABUF,
895 lpCalleeData: *WSABUF,
896 g: *u32,
897 dwCallbackData: usize,
898) callconv(WINAPI) i32;
899
900pub const LPWSAOVERLAPPED_COMPLETION_ROUTINE = fn (
901 dwError: u32,
902 cbTransferred: u32,
903 lpOverlapped: *OVERLAPPED,
904 dwFlags: u32,
905) callconv(WINAPI) void;
906
907pub const FLOWSPEC = extern struct {
908 TokenRate: u32,
909 TokenBucketSize: u32,
910 PeakBandwidth: u32,
911 Latency: u32,
912 DelayVariation: u32,
913 ServiceType: u32,
914 MaxSduSize: u32,
915 MinimumPolicedSize: u32,
916};
917
918pub const QOS = extern struct {
919 SendingFlowspec: FLOWSPEC,
920 ReceivingFlowspec: FLOWSPEC,
921 ProviderSpecific: WSABUF,
922};
923
924pub const SOCKET_ADDRESS = extern struct {
925 lpSockaddr: *sockaddr,
926 iSockaddrLength: i32,
927};
928
929pub const SOCKET_ADDRESS_LIST = extern struct {
930 iAddressCount: i32,
931 Address: [1]SOCKET_ADDRESS,
932};
14933
15934pub const WSADATA = if (@sizeOf(usize) == @sizeOf(u64))
16935 extern struct {
......@@ -33,15 +952,11 @@ else
33952 lpVendorInfo: *u8,
34953 };
35954
36pub const MAX_PROTOCOL_CHAIN = 7;
37
38955pub const WSAPROTOCOLCHAIN = extern struct {
39956 ChainLen: c_int,
40957 ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD,
41958};
42959
43pub const WSAPROTOCOL_LEN = 255;
44
45960pub const WSAPROTOCOL_INFOA = extern struct {
46961 dwServiceFlags1: DWORD,
47962 dwServiceFlags2: DWORD,
......@@ -88,20 +1003,20 @@ pub const WSAPROTOCOL_INFOW = extern struct {
881003 szProtocol: [WSAPROTOCOL_LEN + 1]WCHAR,
891004};
901005
91pub const GROUP = u32;
92
93pub const SG_UNCONSTRAINED_GROUP = 0x1;
94pub const SG_CONSTRAINED_GROUP = 0x2;
1006pub const sockproto = extern struct {
1007 sp_family: u16,
1008 sp_protocol: u16,
1009};
951010
96pub const WSA_FLAG_OVERLAPPED = 0x01;
97pub const WSA_FLAG_MULTIPOINT_C_ROOT = 0x02;
98pub const WSA_FLAG_MULTIPOINT_C_LEAF = 0x04;
99pub const WSA_FLAG_MULTIPOINT_D_ROOT = 0x08;
100pub const WSA_FLAG_MULTIPOINT_D_LEAF = 0x10;
101pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY = 0x40;
102pub const WSA_FLAG_NO_HANDLE_INHERIT = 0x80;
1011pub const linger = extern struct {
1012 l_onoff: u16,
1013 l_linger: u16,
1014};
1031015
104pub const WSAEVENT = HANDLE;
1016pub const WSANETWORKEVENTS = extern struct {
1017 lNetworkEvents: i32,
1018 iErrorCode: [10]i32,
1019};
1051020
1061021pub const WSAOVERLAPPED = extern struct {
1071022 Internal: DWORD,
......@@ -111,82 +1026,9 @@ pub const WSAOVERLAPPED = extern struct {
1111026 hEvent: ?WSAEVENT,
1121027};
1131028
114pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred: DWORD, lpOverlapped: *WSAOVERLAPPED, dwFlags: DWORD) callconv(.C) void;
115
116pub const ADDRESS_FAMILY = u16;
117
118// Microsoft use the signed c_int for this, but it should never be negative
119pub const socklen_t = u32;
1029pub const addrinfo = addrinfoa;
1201030
121pub const AF_UNSPEC = 0;
122pub const AF_UNIX = 1;
123pub const AF_INET = 2;
124pub const AF_IMPLINK = 3;
125pub const AF_PUP = 4;
126pub const AF_CHAOS = 5;
127pub const AF_NS = 6;
128pub const AF_IPX = AF_NS;
129pub const AF_ISO = 7;
130pub const AF_OSI = AF_ISO;
131pub const AF_ECMA = 8;
132pub const AF_DATAKIT = 9;
133pub const AF_CCITT = 10;
134pub const AF_SNA = 11;
135pub const AF_DECnet = 12;
136pub const AF_DLI = 13;
137pub const AF_LAT = 14;
138pub const AF_HYLINK = 15;
139pub const AF_APPLETALK = 16;
140pub const AF_NETBIOS = 17;
141pub const AF_VOICEVIEW = 18;
142pub const AF_FIREFOX = 19;
143pub const AF_UNKNOWN1 = 20;
144pub const AF_BAN = 21;
145pub const AF_ATM = 22;
146pub const AF_INET6 = 23;
147pub const AF_CLUSTER = 24;
148pub const AF_12844 = 25;
149pub const AF_IRDA = 26;
150pub const AF_NETDES = 28;
151pub const AF_TCNPROCESS = 29;
152pub const AF_TCNMESSAGE = 30;
153pub const AF_ICLFXBM = 31;
154pub const AF_BTH = 32;
155pub const AF_MAX = 33;
156
157pub const SOCK_STREAM = 1;
158pub const SOCK_DGRAM = 2;
159pub const SOCK_RAW = 3;
160pub const SOCK_RDM = 4;
161pub const SOCK_SEQPACKET = 5;
162
163pub const IPPROTO_ICMP = 1;
164pub const IPPROTO_IGMP = 2;
165pub const BTHPROTO_RFCOMM = 3;
166pub const IPPROTO_TCP = 6;
167pub const IPPROTO_UDP = 17;
168pub const IPPROTO_ICMPV6 = 58;
169pub const IPPROTO_RM = 113;
170
171pub const AI_PASSIVE = 0x00001;
172pub const AI_CANONNAME = 0x00002;
173pub const AI_NUMERICHOST = 0x00004;
174pub const AI_NUMERICSERV = 0x00008;
175pub const AI_ADDRCONFIG = 0x00400;
176pub const AI_V4MAPPED = 0x00800;
177pub const AI_NON_AUTHORITATIVE = 0x04000;
178pub const AI_SECURE = 0x08000;
179pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
180pub const AI_DISABLE_IDN_ENCODING = 0x80000;
181
182pub const FIONBIO = -2147195266;
183
184pub const sockaddr = extern struct {
185 family: ADDRESS_FAMILY,
186 data: [14]u8,
187};
188
189pub const addrinfo = extern struct {
1031pub const addrinfoa = extern struct {
1901032 flags: i32,
1911033 family: i32,
1921034 socktype: i32,
......@@ -197,6 +1039,32 @@ pub const addrinfo = extern struct {
1971039 next: ?*addrinfo,
1981040};
1991041
1042pub const addrinfoexA = extern struct {
1043 ai_flags: i32,
1044 ai_family: i32,
1045 ai_socktype: i32,
1046 ai_protocol: i32,
1047 ai_addrlen: usize,
1048 ai_canonname: [*:0]u8,
1049 ai_addr: *sockaddr,
1050 ai_blob: *c_void,
1051 ai_bloblen: usize,
1052 ai_provider: *GUID,
1053 ai_next: *addrinfoexA,
1054};
1055
1056pub const sockaddr = extern struct {
1057 family: ADDRESS_FAMILY,
1058 data: [14]u8,
1059};
1060
1061pub const sockaddr_storage = extern struct {
1062 family: ADDRESS_FAMILY,
1063 __pad1: [6]u8,
1064 __align: i64,
1065 __pad2: [112]u8,
1066};
1067
2001068/// IPv4 socket address
2011069pub const sockaddr_in = extern struct {
2021070 family: ADDRESS_FAMILY = AF_INET,
......@@ -225,7 +1093,10 @@ pub const WSABUF = extern struct {
2251093 buf: [*]u8,
2261094};
2271095
228pub const WSAMSG = extern struct {
1096pub const msghdr = WSAMSG;
1097pub const msghdr_const = WSAMSG_const;
1098
1099pub const WSAMSG_const = extern struct {
2291100 name: *const sockaddr,
2301101 namelen: INT,
2311102 lpBuffers: [*]WSABUF,
......@@ -234,26 +1105,108 @@ pub const WSAMSG = extern struct {
2341105 dwFlags: DWORD,
2351106};
2361107
1108pub const WSAMSG = extern struct {
1109 name: *sockaddr,
1110 namelen: INT,
1111 lpBuffers: [*]WSABUF,
1112 dwBufferCount: DWORD,
1113 Control: WSABUF,
1114 dwFlags: DWORD,
1115};
1116
1117pub const WSAPOLLFD = pollfd;
1118
2371119pub const pollfd = extern struct {
2381120 fd: SOCKET,
2391121 events: SHORT,
2401122 revents: SHORT,
2411123};
2421124
243// Event flag definitions for WSAPoll().
1125pub const TRANSMIT_FILE_BUFFERS = extern struct {
1126 Head: *c_void,
1127 HeadLength: u32,
1128 Tail: *c_void,
1129 TailLength: u32,
1130};
1131
1132pub const LPFN_TRANSMITFILE = fn (
1133 hSocket: SOCKET,
1134 hFile: HANDLE,
1135 nNumberOfBytesToWrite: u32,
1136 nNumberOfBytesPerSend: u32,
1137 lpOverlapped: ?*OVERLAPPED,
1138 lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS,
1139 dwReserved: u32,
1140) callconv(WINAPI) BOOL;
1141
1142pub const LPFN_ACCEPTEX = fn (
1143 sListenSocket: SOCKET,
1144 sAcceptSocket: SOCKET,
1145 lpOutputBuffer: *c_void,
1146 dwReceiveDataLength: u32,
1147 dwLocalAddressLength: u32,
1148 dwRemoteAddressLength: u32,
1149 lpdwBytesReceived: *u32,
1150 lpOverlapped: *OVERLAPPED,
1151) callconv(WINAPI) BOOL;
1152
1153pub const LPFN_GETACCEPTEXSOCKADDRS = fn (
1154 lpOutputBuffer: *c_void,
1155 dwReceiveDataLength: u32,
1156 dwLocalAddressLength: u32,
1157 dwRemoteAddressLength: u32,
1158 LocalSockaddr: **sockaddr,
1159 LocalSockaddrLength: *i32,
1160 RemoteSockaddr: **sockaddr,
1161 RemoteSockaddrLength: *i32,
1162) callconv(WINAPI) void;
1163
1164pub const LPFN_WSASENDMSG = fn (
1165 s: SOCKET,
1166 lpMsg: *const WSAMSG_const,
1167 dwFlags: u32,
1168 lpNumberOfBytesSent: ?*u32,
1169 lpOverlapped: ?*OVERLAPPED,
1170 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
1171) callconv(WINAPI) i32;
2441172
245pub const POLLRDNORM = 0x0100;
246pub const POLLRDBAND = 0x0200;
247pub const POLLIN = (POLLRDNORM | POLLRDBAND);
248pub const POLLPRI = 0x0400;
1173pub const LPFN_WSARECVMSG = fn (
1174 s: SOCKET,
1175 lpMsg: *WSAMSG,
1176 lpdwNumberOfBytesRecv: ?*u32,
1177 lpOverlapped: ?*OVERLAPPED,
1178 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
1179) callconv(WINAPI) i32;
2491180
250pub const POLLWRNORM = 0x0010;
251pub const POLLOUT = (POLLWRNORM);
252pub const POLLWRBAND = 0x0020;
1181pub const LPSERVICE_CALLBACK_PROC = fn (
1182 lParam: LPARAM,
1183 hAsyncTaskHandle: HANDLE,
1184) callconv(WINAPI) void;
2531185
254pub const POLLERR = 0x0001;
255pub const POLLHUP = 0x0002;
256pub const POLLNVAL = 0x0004;
1186pub const SERVICE_ASYNC_INFO = extern struct {
1187 lpServiceCallbackProc: LPSERVICE_CALLBACK_PROC,
1188 lParam: LPARAM,
1189 hAsyncTaskHandle: HANDLE,
1190};
1191
1192pub const LPLOOKUPSERVICE_COMPLETION_ROUTINE = fn (
1193 dwError: u32,
1194 dwBytes: u32,
1195 lpOverlapped: *OVERLAPPED,
1196) callconv(WINAPI) void;
1197
1198pub const fd_set = extern struct {
1199 fd_count: u32,
1200 fd_array: [64]SOCKET,
1201};
1202
1203pub const hostent = extern struct {
1204 h_name: [*]u8,
1205 h_aliases: **i8,
1206 h_addrtype: i16,
1207 h_length: i16,
1208 h_addr_list: **i8,
1209};
2571210
2581211// https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2
2591212pub const WinsockError = enum(u16) {
......@@ -704,180 +1657,649 @@ pub const WinsockError = enum(u16) {
7041657 _,
7051658};
7061659
707/// no parameters
708const IOC_VOID = 0x80000000;
1660pub extern "ws2_32" fn accept(
1661 s: SOCKET,
1662 addr: ?*sockaddr,
1663 addrlen: ?*i32,
1664) callconv(WINAPI) SOCKET;
7091665
710/// copy out parameters
711const IOC_OUT = 0x40000000;
1666pub extern "ws2_32" fn bind(
1667 s: SOCKET,
1668 name: *const sockaddr,
1669 namelen: i32,
1670) callconv(WINAPI) i32;
7121671
713/// copy in parameters
714const IOC_IN = 0x80000000;
1672pub extern "ws2_32" fn closesocket(
1673 s: SOCKET,
1674) callconv(WINAPI) i32;
7151675
716/// The IOCTL is a generic Windows Sockets 2 IOCTL code. New IOCTL codes defined for Windows Sockets 2 will have T == 1.
717const IOC_WS2 = 0x08000000;
1676pub extern "ws2_32" fn connect(
1677 s: SOCKET,
1678 name: *const sockaddr,
1679 namelen: i32,
1680) callconv(WINAPI) i32;
7181681
719pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34;
1682pub extern "ws2_32" fn ioctlsocket(
1683 s: SOCKET,
1684 cmd: i32,
1685 argp: *u32,
1686) callconv(WINAPI) i32;
1687
1688pub extern "ws2_32" fn getpeername(
1689 s: SOCKET,
1690 name: *sockaddr,
1691 namelen: *i32,
1692) callconv(WINAPI) i32;
7201693
721pub const SOL_SOCKET = 0xffff;
722
723pub const SO_DEBUG = 0x0001;
724pub const SO_ACCEPTCONN = 0x0002;
725pub const SO_REUSEADDR = 0x0004;
726pub const SO_KEEPALIVE = 0x0008;
727pub const SO_DONTROUTE = 0x0010;
728pub const SO_BROADCAST = 0x0020;
729pub const SO_USELOOPBACK = 0x0040;
730pub const SO_LINGER = 0x0080;
731pub const SO_OOBINLINE = 0x0100;
732
733pub const SO_DONTLINGER = ~@as(u32, SO_LINGER);
734pub const SO_EXCLUSIVEADDRUSE = ~@as(u32, SO_REUSEADDR);
735
736pub const SO_SNDBUF = 0x1001;
737pub const SO_RCVBUF = 0x1002;
738pub const SO_SNDLOWAT = 0x1003;
739pub const SO_RCVLOWAT = 0x1004;
740pub const SO_SNDTIMEO = 0x1005;
741pub const SO_RCVTIMEO = 0x1006;
742pub const SO_ERROR = 0x1007;
743pub const SO_TYPE = 0x1008;
744
745pub const SO_GROUP_ID = 0x2001;
746pub const SO_GROUP_PRIORITY = 0x2002;
747pub const SO_MAX_MSG_SIZE = 0x2003;
748pub const SO_PROTOCOL_INFOA = 0x2004;
749pub const SO_PROTOCOL_INFOW = 0x2005;
750
751pub const PVD_CONFIG = 0x3001;
752pub const SO_CONDITIONAL_ACCEPT = 0x3002;
753
754pub const TCP_NODELAY = 0x0001;
1694pub extern "ws2_32" fn getsockname(
1695 s: SOCKET,
1696 name: *sockaddr,
1697 namelen: *i32,
1698) callconv(WINAPI) i32;
1699
1700pub extern "ws2_32" fn getsockopt(
1701 s: SOCKET,
1702 level: i32,
1703 optname: i32,
1704 optval: [*]u8,
1705 optlen: *i32,
1706) callconv(WINAPI) i32;
1707
1708pub extern "ws2_32" fn htonl(
1709 hostlong: u32,
1710) callconv(WINAPI) u32;
1711
1712pub extern "ws2_32" fn htons(
1713 hostshort: u16,
1714) callconv(WINAPI) u16;
1715
1716pub extern "ws2_32" fn inet_addr(
1717 cp: ?[*]const u8,
1718) callconv(WINAPI) u32;
1719
1720pub extern "ws2_32" fn listen(
1721 s: SOCKET,
1722 backlog: i32,
1723) callconv(WINAPI) i32;
1724
1725pub extern "ws2_32" fn ntohl(
1726 netlong: u32,
1727) callconv(WINAPI) u32;
1728
1729pub extern "ws2_32" fn ntohs(
1730 netshort: u16,
1731) callconv(WINAPI) u16;
1732
1733pub extern "ws2_32" fn recv(
1734 s: SOCKET,
1735 buf: [*]u8,
1736 len: i32,
1737 flags: i32,
1738) callconv(WINAPI) i32;
1739
1740pub extern "ws2_32" fn recvfrom(
1741 s: SOCKET,
1742 buf: [*]u8,
1743 len: i32,
1744 flags: i32,
1745 from: ?*sockaddr,
1746 fromlen: ?*i32,
1747) callconv(WINAPI) i32;
1748
1749pub extern "ws2_32" fn select(
1750 nfds: i32,
1751 readfds: ?*fd_set,
1752 writefds: ?*fd_set,
1753 exceptfds: ?*fd_set,
1754 timeout: ?*const timeval,
1755) callconv(WINAPI) i32;
1756
1757pub extern "ws2_32" fn send(
1758 s: SOCKET,
1759 buf: [*]const u8,
1760 len: i32,
1761 flags: u32,
1762) callconv(WINAPI) i32;
1763
1764pub extern "ws2_32" fn sendto(
1765 s: SOCKET,
1766 buf: [*]const u8,
1767 len: i32,
1768 flags: i32,
1769 to: *const sockaddr,
1770 tolen: i32,
1771) callconv(WINAPI) i32;
1772
1773pub extern "ws2_32" fn setsockopt(
1774 s: SOCKET,
1775 level: i32,
1776 optname: i32,
1777 optval: ?[*]const u8,
1778 optlen: i32,
1779) callconv(WINAPI) i32;
1780
1781pub extern "ws2_32" fn shutdown(
1782 s: SOCKET,
1783 how: i32,
1784) callconv(WINAPI) i32;
1785
1786pub extern "ws2_32" fn socket(
1787 af: i32,
1788 @"type": i32,
1789 protocol: i32,
1790) callconv(WINAPI) SOCKET;
7551791
7561792pub extern "ws2_32" fn WSAStartup(
7571793 wVersionRequired: WORD,
7581794 lpWSAData: *WSADATA,
759) callconv(WINAPI) c_int;
760pub extern "ws2_32" fn WSACleanup() callconv(WINAPI) c_int;
1795) callconv(WINAPI) i32;
1796
1797pub extern "ws2_32" fn WSACleanup() callconv(WINAPI) i32;
1798
1799pub extern "ws2_32" fn WSASetLastError(iError: i32) callconv(WINAPI) void;
1800
7611801pub extern "ws2_32" fn WSAGetLastError() callconv(WINAPI) WinsockError;
762pub extern "ws2_32" fn WSASocketA(
763 af: c_int,
764 type: c_int,
765 protocol: c_int,
766 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,
767 g: GROUP,
768 dwFlags: DWORD,
769) callconv(WINAPI) SOCKET;
770pub extern "ws2_32" fn WSASocketW(
771 af: c_int,
772 type: c_int,
773 protocol: c_int,
774 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,
775 g: GROUP,
776 dwFlags: DWORD,
777) callconv(WINAPI) SOCKET;
778pub extern "ws2_32" fn closesocket(s: SOCKET) callconv(WINAPI) c_int;
779pub extern "ws2_32" fn WSAIoctl(
1802
1803pub extern "ws2_32" fn WSAIsBlocking() callconv(WINAPI) BOOL;
1804
1805pub extern "ws2_32" fn WSAUnhookBlockingHook() callconv(WINAPI) i32;
1806
1807pub extern "ws2_32" fn WSASetBlockingHook(lpBlockFunc: FARPROC) callconv(WINAPI) FARPROC;
1808
1809pub extern "ws2_32" fn WSACancelBlockingCall() callconv(WINAPI) i32;
1810
1811pub extern "ws2_32" fn WSAAsyncGetServByName(
1812 hWnd: HWND,
1813 wMsg: u32,
1814 name: [*:0]const u8,
1815 proto: ?[*:0]const u8,
1816 buf: [*]u8,
1817 buflen: i32,
1818) callconv(WINAPI) HANDLE;
1819
1820pub extern "ws2_32" fn WSAAsyncGetServByPort(
1821 hWnd: HWND,
1822 wMsg: u32,
1823 port: i32,
1824 proto: ?[*:0]const u8,
1825 buf: [*]u8,
1826 buflen: i32,
1827) callconv(WINAPI) HANDLE;
1828
1829pub extern "ws2_32" fn WSAAsyncGetProtoByName(
1830 hWnd: HWND,
1831 wMsg: u32,
1832 name: [*:0]const u8,
1833 buf: [*]u8,
1834 buflen: i32,
1835) callconv(WINAPI) HANDLE;
1836
1837pub extern "ws2_32" fn WSAAsyncGetProtoByNumber(
1838 hWnd: HWND,
1839 wMsg: u32,
1840 number: i32,
1841 buf: [*]u8,
1842 buflen: i32,
1843) callconv(WINAPI) HANDLE;
1844
1845pub extern "ws2_32" fn WSACancelAsyncRequest(hAsyncTaskHandle: HANDLE) callconv(WINAPI) i32;
1846
1847pub extern "ws2_32" fn WSAAsyncSelect(
7801848 s: SOCKET,
781 dwIoControlCode: DWORD,
782 lpvInBuffer: ?*const c_void,
783 cbInBuffer: DWORD,
784 lpvOutBuffer: ?LPVOID,
785 cbOutBuffer: DWORD,
786 lpcbBytesReturned: LPDWORD,
787 lpOverlapped: ?*WSAOVERLAPPED,
788 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
789) callconv(WINAPI) c_int;
790pub extern "ws2_32" fn accept(
1849 hWnd: HWND,
1850 wMsg: u32,
1851 lEvent: i32,
1852) callconv(WINAPI) i32;
1853
1854pub extern "ws2_32" fn WSAAccept(
7911855 s: SOCKET,
7921856 addr: ?*sockaddr,
793 addrlen: ?*c_int,
1857 addrlen: ?*i32,
1858 lpfnCondition: ?LPCONDITIONPROC,
1859 dwCallbackData: usize,
7941860) callconv(WINAPI) SOCKET;
795pub extern "ws2_32" fn bind(
1861
1862pub extern "ws2_32" fn WSACloseEvent(hEvent: HANDLE) callconv(WINAPI) BOOL;
1863
1864pub extern "ws2_32" fn WSAConnect(
7961865 s: SOCKET,
797 addr: ?*const sockaddr,
798 addrlen: c_int,
799) callconv(WINAPI) c_int;
800pub extern "ws2_32" fn connect(
1866 name: *const sockaddr,
1867 namelen: i32,
1868 lpCallerData: ?*WSABUF,
1869 lpCalleeData: ?*WSABUF,
1870 lpSQOS: ?*QOS,
1871 lpGQOS: ?*QOS,
1872) callconv(WINAPI) i32;
1873
1874pub extern "ws2_32" fn WSAConnectByNameW(
1875 s: SOCKET,
1876 nodename: [*:0]const u16,
1877 servicename: [*:0]const u16,
1878 LocalAddressLength: ?*u32,
1879 LocalAddress: ?*sockaddr,
1880 RemoteAddressLength: ?*u32,
1881 RemoteAddress: ?*sockaddr,
1882 timeout: ?*const timeval,
1883 Reserved: *OVERLAPPED,
1884) callconv(WINAPI) BOOL;
1885
1886pub extern "ws2_32" fn WSAConnectByNameA(
1887 s: SOCKET,
1888 nodename: [*:0]const u8,
1889 servicename: [*:0]const u8,
1890 LocalAddressLength: ?*u32,
1891 LocalAddress: ?*sockaddr,
1892 RemoteAddressLength: ?*u32,
1893 RemoteAddress: ?*sockaddr,
1894 timeout: ?*const timeval,
1895 Reserved: *OVERLAPPED,
1896) callconv(WINAPI) BOOL;
1897
1898pub extern "ws2_32" fn WSAConnectByList(
1899 s: SOCKET,
1900 SocketAddress: *SOCKET_ADDRESS_LIST,
1901 LocalAddressLength: ?*u32,
1902 LocalAddress: ?*sockaddr,
1903 RemoteAddressLength: ?*u32,
1904 RemoteAddress: ?*sockaddr,
1905 timeout: ?*const timeval,
1906 Reserved: *OVERLAPPED,
1907) callconv(WINAPI) BOOL;
1908
1909pub extern "ws2_32" fn WSACreateEvent() callconv(WINAPI) HANDLE;
1910
1911pub extern "ws2_32" fn WSADuplicateSocketA(
1912 s: SOCKET,
1913 dwProcessId: u32,
1914 lpProtocolInfo: *WSAPROTOCOL_INFOA,
1915) callconv(WINAPI) i32;
1916
1917pub extern "ws2_32" fn WSADuplicateSocketW(
1918 s: SOCKET,
1919 dwProcessId: u32,
1920 lpProtocolInfo: *WSAPROTOCOL_INFOW,
1921) callconv(WINAPI) i32;
1922
1923pub extern "ws2_32" fn WSAEnumNetworkEvents(
1924 s: SOCKET,
1925 hEventObject: HANDLE,
1926 lpNetworkEvents: *WSANETWORKEVENTS,
1927) callconv(WINAPI) i32;
1928
1929pub extern "ws2_32" fn WSAEnumProtocolsA(
1930 lpiProtocols: ?*i32,
1931 lpProtocolBuffer: ?*WSAPROTOCOL_INFOA,
1932 lpdwBufferLength: *u32,
1933) callconv(WINAPI) i32;
1934
1935pub extern "ws2_32" fn WSAEnumProtocolsW(
1936 lpiProtocols: ?*i32,
1937 lpProtocolBuffer: ?*WSAPROTOCOL_INFOW,
1938 lpdwBufferLength: *u32,
1939) callconv(WINAPI) i32;
1940
1941pub extern "ws2_32" fn WSAEventSelect(
1942 s: SOCKET,
1943 hEventObject: HANDLE,
1944 lNetworkEvents: i32,
1945) callconv(WINAPI) i32;
1946
1947pub extern "ws2_32" fn WSAGetOverlappedResult(
1948 s: SOCKET,
1949 lpOverlapped: *OVERLAPPED,
1950 lpcbTransfer: *u32,
1951 fWait: BOOL,
1952 lpdwFlags: *u32,
1953) callconv(WINAPI) BOOL;
1954
1955pub extern "ws2_32" fn WSAGetQOSByName(
1956 s: SOCKET,
1957 lpQOSName: *WSABUF,
1958 lpQOS: *QOS,
1959) callconv(WINAPI) BOOL;
1960
1961pub extern "ws2_32" fn WSAHtonl(
1962 s: SOCKET,
1963 hostlong: u32,
1964 lpnetlong: *u32,
1965) callconv(WINAPI) i32;
1966
1967pub extern "ws2_32" fn WSAHtons(
1968 s: SOCKET,
1969 hostshort: u16,
1970 lpnetshort: *u16,
1971) callconv(WINAPI) i32;
1972
1973pub extern "ws2_32" fn WSAIoctl(
1974 s: SOCKET,
1975 dwIoControlCode: u32,
1976 lpvInBuffer: ?*const c_void,
1977 cbInBuffer: u32,
1978 lpvOutbuffer: ?*c_void,
1979 cbOutbuffer: u32,
1980 lpcbBytesReturned: *u32,
1981 lpOverlapped: ?*OVERLAPPED,
1982 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
1983) callconv(WINAPI) i32;
1984
1985pub extern "ws2_32" fn WSAJoinLeaf(
8011986 s: SOCKET,
8021987 name: *const sockaddr,
803 namelen: c_int,
804) callconv(WINAPI) c_int;
805pub extern "ws2_32" fn listen(
1988 namelen: i32,
1989 lpCallerdata: ?*WSABUF,
1990 lpCalleeData: ?*WSABUF,
1991 lpSQOS: ?*QOS,
1992 lpGQOS: ?*QOS,
1993 dwFlags: u32,
1994) callconv(WINAPI) SOCKET;
1995
1996pub extern "ws2_32" fn WSANtohl(
1997 s: SOCKET,
1998 netlong: u32,
1999 lphostlong: *u32,
2000) callconv(WINAPI) u32;
2001
2002pub extern "ws2_32" fn WSANtohs(
8062003 s: SOCKET,
807 backlog: c_int,
808) callconv(WINAPI) c_int;
2004 netshort: u16,
2005 lphostshort: *u16,
2006) callconv(WINAPI) i32;
2007
8092008pub extern "ws2_32" fn WSARecv(
8102009 s: SOCKET,
811 lpBuffers: [*]const WSABUF,
812 dwBufferCount: DWORD,
813 lpNumberOfBytesRecvd: ?*DWORD,
814 lpFlags: *DWORD,
815 lpOverlapped: ?*WSAOVERLAPPED,
816 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
817) callconv(WINAPI) c_int;
2010 lpBuffers: [*]WSABUF,
2011 dwBufferCouynt: u32,
2012 lpNumberOfBytesRecv: ?*u32,
2013 lpFlags: *u32,
2014 lpOverlapped: ?*OVERLAPPED,
2015 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2016) callconv(WINAPI) i32;
2017
2018pub extern "ws2_32" fn WSARecvDisconnect(
2019 s: SOCKET,
2020 lpInboundDisconnectData: ?*WSABUF,
2021) callconv(WINAPI) i32;
2022
8182023pub extern "ws2_32" fn WSARecvFrom(
8192024 s: SOCKET,
820 lpBuffers: [*]const WSABUF,
821 dwBufferCount: DWORD,
822 lpNumberOfBytesRecvd: ?*DWORD,
823 lpFlags: *DWORD,
2025 lpBuffers: [*]WSABUF,
2026 dwBuffercount: u32,
2027 lpNumberOfBytesRecvd: ?*u32,
2028 lpFlags: *u32,
8242029 lpFrom: ?*sockaddr,
825 lpFromlen: ?*socklen_t,
826 lpOverlapped: ?*WSAOVERLAPPED,
827 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
828) callconv(WINAPI) c_int;
2030 lpFromlen: ?*i32,
2031 lpOverlapped: ?*OVERLAPPED,
2032 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2033) callconv(WINAPI) i32;
2034
2035pub extern "ws2_32" fn WSAResetEvent(hEvent: HANDLE) callconv(WINAPI) i32;
2036
8292037pub extern "ws2_32" fn WSASend(
8302038 s: SOCKET,
8312039 lpBuffers: [*]WSABUF,
832 dwBufferCount: DWORD,
833 lpNumberOfBytesSent: ?*DWORD,
834 dwFlags: DWORD,
835 lpOverlapped: ?*WSAOVERLAPPED,
836 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
837) callconv(WINAPI) c_int;
2040 dwBufferCount: u32,
2041 lpNumberOfBytesSent: ?*u32,
2042 dwFlags: u32,
2043 lpOverlapped: ?*OVERLAPPED,
2044 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2045) callconv(WINAPI) i32;
2046
2047pub extern "ws2_32" fn WSASendMsg(
2048 s: SOCKET,
2049 lpMsg: *const WSAMSG_const,
2050 dwFlags: u32,
2051 lpNumberOfBytesSent: ?*u32,
2052 lpOverlapped: ?*OVERLAPPED,
2053 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2054) callconv(WINAPI) i32;
2055
2056pub extern "ws2_32" fn WSARecvMsg(
2057 s: SOCKET,
2058 lpMsg: *WSAMSG,
2059 lpdwNumberOfBytesRecv: ?*u32,
2060 lpOverlapped: ?*OVERLAPPED,
2061 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2062) callconv(WINAPI) i32;
2063
2064pub extern "ws2_32" fn WSASendDisconnect(
2065 s: SOCKET,
2066 lpOutboundDisconnectData: ?*WSABUF,
2067) callconv(WINAPI) i32;
2068
8382069pub extern "ws2_32" fn WSASendTo(
8392070 s: SOCKET,
8402071 lpBuffers: [*]WSABUF,
841 dwBufferCount: DWORD,
842 lpNumberOfBytesSent: ?*DWORD,
843 dwFlags: DWORD,
2072 dwBufferCount: u32,
2073 lpNumberOfBytesSent: ?*u32,
2074 dwFlags: u32,
8442075 lpTo: ?*const sockaddr,
845 iTolen: c_int,
846 lpOverlapped: ?*WSAOVERLAPPED,
847 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
848) callconv(WINAPI) c_int;
2076 iToLen: i32,
2077 lpOverlapped: ?*OVERLAPPED,
2078 lpCompletionRounte: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2079) callconv(WINAPI) i32;
2080
2081pub extern "ws2_32" fn WSASetEvent(
2082 hEvent: HANDLE,
2083) callconv(WINAPI) BOOL;
2084
2085pub extern "ws2_32" fn WSASocketA(
2086 af: i32,
2087 @"type": i32,
2088 protocol: i32,
2089 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,
2090 g: u32,
2091 dwFlags: u32,
2092) callconv(WINAPI) SOCKET;
2093
2094pub extern "ws2_32" fn WSASocketW(
2095 af: i32,
2096 @"type": i32,
2097 protocol: i32,
2098 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,
2099 g: u32,
2100 dwFlags: u32,
2101) callconv(WINAPI) SOCKET;
2102
2103pub extern "ws2_32" fn WSAWaitForMultipleEvents(
2104 cEvents: u32,
2105 lphEvents: [*]const HANDLE,
2106 fWaitAll: BOOL,
2107 dwTimeout: u32,
2108 fAlertable: BOOL,
2109) callconv(WINAPI) u32;
2110
2111pub extern "ws2_32" fn WSAAddressToStringA(
2112 lpsaAddress: *sockaddr,
2113 dwAddressLength: u32,
2114 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,
2115 lpszAddressString: [*]u8,
2116 lpdwAddressStringLength: *u32,
2117) callconv(WINAPI) i32;
2118
2119pub extern "ws2_32" fn WSAAddressToStringW(
2120 lpsaAddress: *sockaddr,
2121 dwAddressLength: u32,
2122 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,
2123 lpszAddressString: [*]u16,
2124 lpdwAddressStringLength: *u32,
2125) callconv(WINAPI) i32;
2126
2127pub extern "ws2_32" fn WSAStringToAddressA(
2128 AddressString: [*:0]const u8,
2129 AddressFamily: i32,
2130 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,
2131 lpAddress: *sockaddr,
2132 lpAddressLength: *i32,
2133) callconv(WINAPI) i32;
2134
2135pub extern "ws2_32" fn WSAStringToAddressW(
2136 AddressString: [*:0]const u16,
2137 AddressFamily: i32,
2138 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,
2139 lpAddrses: *sockaddr,
2140 lpAddressLength: *i32,
2141) callconv(WINAPI) i32;
2142
2143pub extern "ws2_32" fn WSAProviderConfigChange(
2144 lpNotificationHandle: *HANDLE,
2145 lpOverlapped: ?*OVERLAPPED,
2146 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2147) callconv(WINAPI) i32;
2148
8492149pub extern "ws2_32" fn WSAPoll(
850 fdArray: [*]pollfd,
851 fds: c_ulong,
852 timeout: c_int,
853) callconv(WINAPI) c_int;
2150 fdArray: [*]WSAPOLLFD,
2151 fds: u32,
2152 timeout: i32,
2153) callconv(WINAPI) i32;
2154
2155pub extern "mswsock" fn WSARecvEx(
2156 s: SOCKET,
2157 buf: [*]u8,
2158 len: i32,
2159 flags: *i32,
2160) callconv(WINAPI) i32;
2161
2162pub extern "mswsock" fn TransmitFile(
2163 hSocket: SOCKET,
2164 hFile: HANDLE,
2165 nNumberOfBytesToWrite: u32,
2166 nNumberOfBytesPerSend: u32,
2167 lpOverlapped: ?*OVERLAPPED,
2168 lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS,
2169 dwReserved: u32,
2170) callconv(WINAPI) BOOL;
2171
2172pub extern "mswsock" fn AcceptEx(
2173 sListenSocket: SOCKET,
2174 sAcceptSocket: SOCKET,
2175 lpOutputBuffer: *c_void,
2176 dwReceiveDataLength: u32,
2177 dwLocalAddressLength: u32,
2178 dwRemoteAddressLength: u32,
2179 lpdwBytesReceived: *u32,
2180 lpOverlapped: *OVERLAPPED,
2181) callconv(WINAPI) BOOL;
2182
2183pub extern "mswsock" fn GetAcceptExSockaddrs(
2184 lpOutputBuffer: *c_void,
2185 dwReceiveDataLength: u32,
2186 dwLocalAddressLength: u32,
2187 dwRemoteAddressLength: u32,
2188 LocalSockaddr: **sockaddr,
2189 LocalSockaddrLength: *i32,
2190 RemoteSockaddr: **sockaddr,
2191 RemoteSockaddrLength: *i32,
2192) callconv(WINAPI) void;
2193
2194pub extern "ws2_32" fn WSAProviderCompleteAsyncCall(
2195 hAsyncCall: HANDLE,
2196 iRetCode: i32,
2197) callconv(WINAPI) i32;
2198
2199pub extern "mswsock" fn EnumProtocolsA(
2200 lpiProtocols: ?*i32,
2201 lpProtocolBuffer: *c_void,
2202 lpdwBufferLength: *u32,
2203) callconv(WINAPI) i32;
2204
2205pub extern "mswsock" fn EnumProtocolsW(
2206 lpiProtocols: ?*i32,
2207 lpProtocolBuffer: *c_void,
2208 lpdwBufferLength: *u32,
2209) callconv(WINAPI) i32;
2210
2211pub extern "mswsock" fn GetAddressByNameA(
2212 dwNameSpace: u32,
2213 lpServiceType: *GUID,
2214 lpServiceName: ?[*:0]u8,
2215 lpiProtocols: ?*i32,
2216 dwResolution: u32,
2217 lpServiceAsyncInfo: ?*SERVICE_ASYNC_INFO,
2218 lpCsaddrBuffer: *c_void,
2219 lpAliasBuffer: ?[*:0]const u8,
2220 lpdwAliasBufferLength: *u32,
2221) callconv(WINAPI) i32;
2222
2223pub extern "mswsock" fn GetAddressByNameW(
2224 dwNameSpace: u32,
2225 lpServiceType: *GUID,
2226 lpServiceName: ?[*:0]u16,
2227 lpiProtocols: ?*i32,
2228 dwResolution: u32,
2229 lpServiceAsyncInfo: ?*SERVICE_ASYNC_INFO,
2230 lpCsaddrBuffer: *c_void,
2231 ldwBufferLEngth: *u32,
2232 lpAliasBuffer: ?[*:0]u16,
2233 lpdwAliasBufferLength: *u32,
2234) callconv(WINAPI) i32;
2235
2236pub extern "mswsock" fn GetTypeByNameA(
2237 lpServiceName: [*:0]u8,
2238 lpServiceType: *GUID,
2239) callconv(WINAPI) i32;
2240
2241pub extern "mswsock" fn GetTypeByNameW(
2242 lpServiceName: [*:0]u16,
2243 lpServiceType: *GUID,
2244) callconv(WINAPI) i32;
2245
2246pub extern "mswsock" fn GetNameByTypeA(
2247 lpServiceType: *GUID,
2248 lpServiceName: [*:0]u8,
2249 dwNameLength: u32,
2250) callconv(WINAPI) i32;
2251
2252pub extern "mswsock" fn GetNameByTypeW(
2253 lpServiceType: *GUID,
2254 lpServiceName: [*:0]u16,
2255 dwNameLength: u32,
2256) callconv(WINAPI) i32;
2257
8542258pub extern "ws2_32" fn getaddrinfo(
855 pNodeName: [*:0]const u8,
856 pServiceName: [*:0]const u8,
857 pHints: *const addrinfo,
858 ppResult: **addrinfo,
2259 pNodeName: ?[*:0]const u8,
2260 pServiceName: ?[*:0]const u8,
2261 pHints: ?*const addrinfoa,
2262 ppResult: **addrinfoa,
2263) callconv(WINAPI) i32;
2264
2265pub extern "ws2_32" fn GetAddrInfoExA(
2266 pName: ?[*:0]const u8,
2267 pServiceName: ?[*:0]const u8,
2268 dwNameSapce: u32,
2269 lpNspId: ?*GUID,
2270 hints: ?*const addrinfoexA,
2271 ppResult: **addrinfoexA,
2272 timeout: ?*timeval,
2273 lpOverlapped: ?*OVERLAPPED,
2274 lpCompletionRoutine: ?LPLOOKUPSERVICE_COMPLETION_ROUTINE,
8592275) callconv(WINAPI) i32;
2276
2277pub extern "ws2_32" fn GetAddrInfoExCancel(
2278 lpHandle: *HANDLE,
2279) callconv(WINAPI) i32;
2280
2281pub extern "ws2_32" fn GetAddrInfoExOverlappedResult(
2282 lpOverlapped: *OVERLAPPED,
2283) callconv(WINAPI) i32;
2284
8602285pub extern "ws2_32" fn freeaddrinfo(
861 pAddrInfo: *addrinfo,
2286 pAddrInfo: ?*addrinfoa,
8622287) callconv(WINAPI) void;
863pub extern "ws2_32" fn ioctlsocket(
864 s: SOCKET,
865 cmd: c_long,
866 argp: *c_ulong,
867) callconv(WINAPI) c_int;
868pub extern "ws2_32" fn getsockname(
869 s: SOCKET,
870 name: *sockaddr,
871 namelen: *c_int,
872) callconv(WINAPI) c_int;
873pub extern "ws2_32" fn setsockopt(
874 s: SOCKET,
875 level: u32,
876 optname: u32,
877 optval: ?*const c_void,
878 optlen: socklen_t,
879) callconv(WINAPI) c_int;
880pub extern "ws2_32" fn shutdown(
881 s: SOCKET,
882 how: c_int,
883) callconv(WINAPI) c_int;
2288
2289pub extern "ws2_32" fn FreeAddrInfoEx(
2290 pAddrInfoEx: ?*addrinfoexA,
2291) callconv(WINAPI) void;
2292
2293pub extern "ws2_32" fn getnameinfo(
2294 pSockaddr: *const sockaddr,
2295 SockaddrLength: i32,
2296 pNodeBuffer: ?[*]u8,
2297 NodeBufferSize: u32,
2298 pServiceBuffer: ?[*]u8,
2299 ServiceBufferName: u32,
2300 Flags: i32,
2301) callconv(WINAPI) i32;
2302
2303pub extern "IPHLPAPI" fn if_nametoindex(
2304 InterfaceName: [*:0]const u8,
2305) callconv(WINAPI) u32;
lib/std/priority_dequeue.zig+1-16
......@@ -387,17 +387,6 @@ pub fn PriorityDequeue(comptime T: type) type {
387387 return;
388388 },
389389 };
390 self.len = new_len;
391 }
392
393 /// Reduce length to `new_len`.
394 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
395 assert(new_len <= self.items.len);
396
397 // Cannot shrink to smaller than the current queue size without invalidating the heap property
398 assert(new_len >= self.len);
399
400 self.len = new_len;
401390 }
402391
403392 pub fn update(self: *Self, elem: T, new_elem: T) !void {
......@@ -836,7 +825,7 @@ test "std.PriorityDequeue: iterator while empty" {
836825 try expectEqual(it.next(), null);
837826}
838827
839test "std.PriorityDequeue: shrinkRetainingCapacity and shrinkAndFree" {
828test "std.PriorityDequeue: shrinkAndFree" {
840829 var queue = PDQ.init(testing.allocator, lessThanComparison);
841830 defer queue.deinit();
842831
......@@ -849,10 +838,6 @@ test "std.PriorityDequeue: shrinkRetainingCapacity and shrinkAndFree" {
849838 try expect(queue.capacity() >= 4);
850839 try expectEqual(@as(usize, 3), queue.len);
851840
852 queue.shrinkRetainingCapacity(3);
853 try expect(queue.capacity() >= 4);
854 try expectEqual(@as(usize, 3), queue.len);
855
856841 queue.shrinkAndFree(3);
857842 try expectEqual(@as(usize, 3), queue.capacity());
858843 try expectEqual(@as(usize, 3), queue.len);
lib/std/priority_queue.zig+1-16
......@@ -203,17 +203,6 @@ pub fn PriorityQueue(comptime T: type) type {
203203 return;
204204 },
205205 };
206 self.len = new_len;
207 }
208
209 /// Reduce length to `new_len`.
210 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
211 assert(new_len <= self.items.len);
212
213 // Cannot shrink to smaller than the current queue size without invalidating the heap property
214 assert(new_len >= self.len);
215
216 self.len = new_len;
217206 }
218207
219208 pub fn update(self: *Self, elem: T, new_elem: T) !void {
......@@ -495,7 +484,7 @@ test "std.PriorityQueue: iterator while empty" {
495484 try expectEqual(it.next(), null);
496485}
497486
498test "std.PriorityQueue: shrinkRetainingCapacity and shrinkAndFree" {
487test "std.PriorityQueue: shrinkAndFree" {
499488 var queue = PQ.init(testing.allocator, lessThan);
500489 defer queue.deinit();
501490
......@@ -508,10 +497,6 @@ test "std.PriorityQueue: shrinkRetainingCapacity and shrinkAndFree" {
508497 try expect(queue.capacity() >= 4);
509498 try expectEqual(@as(usize, 3), queue.len);
510499
511 queue.shrinkRetainingCapacity(3);
512 try expect(queue.capacity() >= 4);
513 try expectEqual(@as(usize, 3), queue.len);
514
515500 queue.shrinkAndFree(3);
516501 try expectEqual(@as(usize, 3), queue.capacity());
517502 try expectEqual(@as(usize, 3), queue.len);
lib/std/special/c.zig+2-2
......@@ -228,7 +228,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8
228228 return dest;
229229}
230230
231export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isize {
231export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) c_int {
232232 @setRuntimeSafety(false);
233233
234234 var index: usize = 0;
......@@ -253,7 +253,7 @@ test "memcmp" {
253253 try std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
254254}
255255
256export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) isize {
256export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) c_int {
257257 @setRuntimeSafety(false);
258258
259259 var index: usize = 0;
lib/std/special/test_runner.zig+7-1
......@@ -14,12 +14,15 @@ var log_err_count: usize = 0;
1414var args_buffer: [std.fs.MAX_PATH_BYTES + std.mem.page_size]u8 = undefined;
1515var args_allocator = std.heap.FixedBufferAllocator.init(&args_buffer);
1616
17pub fn main() anyerror!void {
17fn processArgs() void {
1818 const args = std.process.argsAlloc(&args_allocator.allocator) catch {
1919 @panic("Too many bytes passed over the CLI to the test runner");
2020 };
2121 std.testing.zig_exe_path = args[1];
22}
2223
24pub fn main() anyerror!void {
25 processArgs();
2326 const test_fn_list = builtin.test_functions;
2427 var ok_count: usize = 0;
2528 var skip_count: usize = 0;
......@@ -84,6 +87,9 @@ pub fn main() anyerror!void {
8487 test_node.end();
8588 progress.log("{s}... FAIL ({s})\n", .{ test_fn.name, @errorName(err) });
8689 if (progress.terminal == null) std.debug.print("FAIL ({s})\n", .{@errorName(err)});
90 if (@errorReturnTrace()) |trace| {
91 std.debug.dumpStackTrace(trace.*);
92 }
8793 },
8894 }
8995 }
lib/std/target.zig+4-4
......@@ -267,7 +267,7 @@ pub const Target = struct {
267267 .macos => return .{
268268 .semver = .{
269269 .min = .{ .major = 10, .minor = 13 },
270 .max = .{ .major = 11, .minor = 1 },
270 .max = .{ .major = 11, .minor = 2 },
271271 },
272272 },
273273 .ios => return .{
......@@ -291,19 +291,19 @@ pub const Target = struct {
291291 .netbsd => return .{
292292 .semver = .{
293293 .min = .{ .major = 8, .minor = 0 },
294 .max = .{ .major = 9, .minor = 0 },
294 .max = .{ .major = 9, .minor = 1 },
295295 },
296296 },
297297 .openbsd => return .{
298298 .semver = .{
299299 .min = .{ .major = 6, .minor = 8 },
300 .max = .{ .major = 6, .minor = 8 },
300 .max = .{ .major = 6, .minor = 9 },
301301 },
302302 },
303303 .dragonfly => return .{
304304 .semver = .{
305305 .min = .{ .major = 5, .minor = 8 },
306 .max = .{ .major = 5, .minor = 8 },
306 .max = .{ .major = 6, .minor = 0 },
307307 },
308308 },
309309
lib/std/x.zig+1-1
......@@ -7,7 +7,7 @@
77const std = @import("std.zig");
88
99pub const os = struct {
10 pub const Socket = @import("x/os/Socket.zig");
10 pub const Socket = @import("x/os/socket.zig").Socket;
1111 pub usingnamespace @import("x/os/net.zig");
1212};
1313
lib/std/x/net/tcp.zig+82-34
......@@ -6,6 +6,7 @@
66
77const std = @import("../../std.zig");
88
9const io = std.io;
910const os = std.os;
1011const ip = std.x.net.ip;
1112
......@@ -58,6 +59,28 @@ pub const Domain = enum(u16) {
5859pub const Client = struct {
5960 socket: Socket,
6061
62 /// Implements `std.io.Reader`.
63 pub const Reader = struct {
64 client: Client,
65 flags: u32,
66
67 /// Implements `readFn` for `std.io.Reader`.
68 pub fn read(self: Client.Reader, buffer: []u8) !usize {
69 return self.client.read(buffer, self.flags);
70 }
71 };
72
73 /// Implements `std.io.Writer`.
74 pub const Writer = struct {
75 client: Client,
76 flags: u32,
77
78 /// Implements `writeFn` for `std.io.Writer`.
79 pub fn write(self: Client.Writer, buffer: []const u8) !usize {
80 return self.client.write(buffer, self.flags);
81 }
82 };
83
6184 /// Opens a new client.
6285 pub fn init(domain: tcp.Domain, flags: u32) !Client {
6386 return Client{
......@@ -89,41 +112,46 @@ pub const Client = struct {
89112 return self.socket.connect(address.into());
90113 }
91114
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);
115 /// Extracts the error set of a function.
116 /// TODO: remove after Socket.{read, write} error unions are well-defined across different platforms
117 fn ErrorSetOf(comptime Function: anytype) type {
118 return @typeInfo(@typeInfo(@TypeOf(Function)).Fn.return_type.?).ErrorUnion.error_set;
96119 }
97120
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);
121 /// Wrap `tcp.Client` into `std.io.Reader`.
122 pub fn reader(self: Client, flags: u32) io.Reader(Client.Reader, ErrorSetOf(Client.Reader.read), Client.Reader.read) {
123 return .{ .context = .{ .client = self, .flags = flags } };
102124 }
103125
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);
126 /// Wrap `tcp.Client` into `std.io.Writer`.
127 pub fn writer(self: Client, flags: u32) io.Writer(Client.Writer, ErrorSetOf(Client.Writer.write), Client.Writer.write) {
128 return .{ .context = .{ .client = self, .flags = flags } };
108129 }
109130
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);
131 /// Read data from the socket into the buffer provided with a set of flags
132 /// specified. It returns the number of bytes read into the buffer provided.
133 pub fn read(self: Client, buf: []u8, flags: u32) !usize {
134 return self.socket.read(buf, flags);
114135 }
115136
116137 /// Write a buffer of data provided to the socket with a set of flags specified.
117138 /// 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);
139 pub fn write(self: Client, buf: []const u8, flags: u32) !usize {
140 return self.socket.write(buf, flags);
120141 }
121142
122143 /// Writes multiple I/O vectors with a prepended message header to the socket
123144 /// with a set of flags specified. It returns the number of bytes that are
124145 /// written to the socket.
125 pub fn sendmsg(self: Client, msg: os.msghdr_const, flags: u32) !usize {
126 return self.socket.sendmsg(msg, flags);
146 pub fn writeVectorized(self: Client, msg: os.msghdr_const, flags: u32) !usize {
147 return self.socket.writeVectorized(msg, flags);
148 }
149
150 /// Read multiple I/O vectors with a prepended message header from the socket
151 /// with a set of flags specified. It returns the number of bytes that were
152 /// read into the buffer provided.
153 pub fn readVectorized(self: Client, msg: *os.msghdr, flags: u32) !usize {
154 return self.socket.readVectorized(msg, flags);
127155 }
128156
129157 /// Query and return the latest cached error on the client's underlying socket.
......@@ -146,12 +174,41 @@ pub const Client = struct {
146174 return ip.Address.from(try self.socket.getLocalAddress());
147175 }
148176
177 /// Query the address that the socket is connected to.
178 pub fn getRemoteAddress(self: Client) !ip.Address {
179 return ip.Address.from(try self.socket.getRemoteAddress());
180 }
181
182 /// Have close() or shutdown() syscalls block until all queued messages in the client have been successfully
183 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
184 /// if the host does not support the option for a socket to linger around up until a timeout specified in
185 /// seconds.
186 pub fn setLinger(self: Client, timeout_seconds: ?u16) !void {
187 return self.socket.setLinger(timeout_seconds);
188 }
189
190 /// Have keep-alive messages be sent periodically. The timing in which keep-alive messages are sent are
191 /// dependant on operating system settings. It returns `error.UnsupportedSocketOption` if the host does
192 /// not support periodically sending keep-alive messages on connection-oriented sockets.
193 pub fn setKeepAlive(self: Client, enabled: bool) !void {
194 return self.socket.setKeepAlive(enabled);
195 }
196
149197 /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if
150198 /// the host does not support sockets disabling Nagle's algorithm.
151199 pub fn setNoDelay(self: Client, enabled: bool) !void {
152200 if (comptime @hasDecl(os, "TCP_NODELAY")) {
153201 const bytes = mem.asBytes(&@as(usize, @boolToInt(enabled)));
154 return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_NODELAY, bytes);
202 return self.socket.setOption(os.IPPROTO_TCP, os.TCP_NODELAY, bytes);
203 }
204 return error.UnsupportedSocketOption;
205 }
206
207 /// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns
208 /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
209 pub fn setQuickACK(self: Client, enabled: bool) !void {
210 if (comptime @hasDecl(os, "TCP_QUICKACK")) {
211 return self.socket.setOption(os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(u32, @boolToInt(enabled))));
155212 }
156213 return error.UnsupportedSocketOption;
157214 }
......@@ -169,7 +226,7 @@ pub const Client = struct {
169226 /// Set a timeout on the socket that is to occur if no messages are successfully written
170227 /// to its bound destination after a specified number of milliseconds. A subsequent write
171228 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
172 pub fn setWriteTimeout(self: Client, milliseconds: usize) !void {
229 pub fn setWriteTimeout(self: Client, milliseconds: u32) !void {
173230 return self.socket.setWriteTimeout(milliseconds);
174231 }
175232
......@@ -177,7 +234,7 @@ pub const Client = struct {
177234 /// from its bound destination after a specified number of milliseconds. A subsequent
178235 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
179236 /// exceeded.
180 pub fn setReadTimeout(self: Client, milliseconds: usize) !void {
237 pub fn setReadTimeout(self: Client, milliseconds: u32) !void {
181238 return self.socket.setReadTimeout(milliseconds);
182239 }
183240};
......@@ -251,16 +308,7 @@ pub const Listener = struct {
251308 /// support TCP Fast Open.
252309 pub fn setFastOpen(self: Listener, enabled: bool) !void {
253310 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))));
311 return self.socket.setOption(os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(u32, @boolToInt(enabled))));
264312 }
265313 return error.UnsupportedSocketOption;
266314 }
......@@ -322,7 +370,7 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" {
322370 defer conn.deinit();
323371
324372 var buf: [1]u8 = undefined;
325 try testing.expectError(error.WouldBlock, client.read(&buf));
373 try testing.expectError(error.WouldBlock, client.reader(0).read(&buf));
326374}
327375
328376test "tcp/listener: bind to unspecified ipv4 address" {
lib/std/x/os/Socket.zig deleted-295
......@@ -1,295 +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.
6
7const std = @import("../../std.zig");
8const net = @import("net.zig");
9
10const os = std.os;
11const fmt = std.fmt;
12const mem = std.mem;
13const time = std.time;
14
15/// A generic socket abstraction.
16const Socket = @This();
17
18/// A socket-address pair.
19pub const Connection = struct {
20 socket: Socket,
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 }
108};
109
110/// The underlying handle of a socket.
111fd: os.socket_t,
112
113/// Open a new socket.
114pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
115 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
116}
117
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
123/// Closes the socket.
124pub fn deinit(self: Socket) void {
125 os.closeSocket(self.fd);
126}
127
128/// Shutdown either the read side, write side, or all side of the socket.
129pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
130 return os.shutdown(self.fd, how);
131}
132
133/// Binds the socket to an address.
134pub fn bind(self: Socket, address: Socket.Address) !void {
135 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
136}
137
138/// Start listening for incoming connections on the socket.
139pub fn listen(self: Socket, max_backlog_size: u31) !void {
140 return os.listen(self.fd, max_backlog_size);
141}
142
143/// Have the socket attempt to the connect to an address.
144pub fn connect(self: Socket, address: Socket.Address) !void {
145 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
146}
147
148/// Accept a pending incoming connection queued to the kernel backlog
149/// of the socket.
150pub fn accept(self: Socket, flags: u32) !Socket.Connection {
151 var address: os.sockaddr = undefined;
152 var address_len: u32 = @sizeOf(os.sockaddr);
153
154 const socket = Socket{ .fd = try os.accept(self.fd, &address, &address_len, flags) };
155 const socket_address = Socket.Address.fromNative(@alignCast(4, &address));
156
157 return Socket.Connection.from(socket, socket_address);
158}
159
160/// Read data from the socket into the buffer provided. It returns the
161/// number of bytes read into the buffer provided.
162pub fn read(self: Socket, buf: []u8) !usize {
163 return os.read(self.fd, buf);
164}
165
166/// Read data from the socket into the buffer provided with a set of flags
167/// specified. It returns the number of bytes read into the buffer provided.
168pub fn recv(self: Socket, buf: []u8, flags: u32) !usize {
169 return os.recv(self.fd, buf, flags);
170}
171
172/// Write a buffer of data provided to the socket. It returns the number
173/// of bytes that are written to the socket.
174pub fn write(self: Socket, buf: []const u8) !usize {
175 return os.write(self.fd, buf);
176}
177
178/// Writes multiple I/O vectors to the socket. It returns the number
179/// of bytes that are written to the socket.
180pub fn writev(self: Socket, buffers: []const os.iovec_const) !usize {
181 return os.writev(self.fd, buffers);
182}
183
184/// Write a buffer of data provided to the socket with a set of flags specified.
185/// It returns the number of bytes that are written to the socket.
186pub fn send(self: Socket, buf: []const u8, flags: u32) !usize {
187 return os.send(self.fd, buf, flags);
188}
189
190/// Writes multiple I/O vectors with a prepended message header to the socket
191/// with a set of flags specified. It returns the number of bytes that are
192/// written to the socket.
193pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
194 return os.sendmsg(self.fd, msg, flags);
195}
196
197/// Query the address that the socket is locally bounded to.
198pub fn getLocalAddress(self: Socket) !Socket.Address {
199 var address: os.sockaddr = undefined;
200 var address_len: u32 = @sizeOf(os.sockaddr);
201 try os.getsockname(self.fd, &address, &address_len);
202 return Socket.Address.fromNative(@alignCast(4, &address));
203}
204
205/// Query and return the latest cached error on the socket.
206pub fn getError(self: Socket) !void {
207 return os.getsockoptError(self.fd);
208}
209
210/// Query the read buffer size of the socket.
211pub fn getReadBufferSize(self: Socket) !u32 {
212 var value: u32 = undefined;
213 var value_len: u32 = @sizeOf(u32);
214
215 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);
216 return switch (os.errno(rc)) {
217 0 => value,
218 os.EBADF => error.BadFileDescriptor,
219 os.EFAULT => error.InvalidAddressSpace,
220 os.EINVAL => error.InvalidSocketOption,
221 os.ENOPROTOOPT => error.UnknownSocketOption,
222 os.ENOTSOCK => error.NotASocket,
223 else => |err| os.unexpectedErrno(err),
224 };
225}
226
227/// Query the write buffer size of the socket.
228pub fn getWriteBufferSize(self: Socket) !u32 {
229 var value: u32 = undefined;
230 var value_len: u32 = @sizeOf(u32);
231
232 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len);
233 return switch (os.errno(rc)) {
234 0 => value,
235 os.EBADF => error.BadFileDescriptor,
236 os.EFAULT => error.InvalidAddressSpace,
237 os.EINVAL => error.InvalidSocketOption,
238 os.ENOPROTOOPT => error.UnknownSocketOption,
239 os.ENOTSOCK => error.NotASocket,
240 else => |err| os.unexpectedErrno(err),
241 };
242}
243
244/// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
245/// the host does not support sockets listening the same address.
246pub fn setReuseAddress(self: Socket, enabled: bool) !void {
247 if (comptime @hasDecl(os, "SO_REUSEADDR")) {
248 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(usize, @boolToInt(enabled))));
249 }
250 return error.UnsupportedSocketOption;
251}
252
253/// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
254/// the host does not supports sockets listening on the same port.
255pub fn setReusePort(self: Socket, enabled: bool) !void {
256 if (comptime @hasDecl(os, "SO_REUSEPORT")) {
257 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(usize, @boolToInt(enabled))));
258 }
259 return error.UnsupportedSocketOption;
260}
261
262/// Set the write buffer size of the socket.
263pub fn setWriteBufferSize(self: Socket, size: u32) !void {
264 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
265}
266
267/// Set the read buffer size of the socket.
268pub fn setReadBufferSize(self: Socket, size: u32) !void {
269 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));
270}
271
272/// Set a timeout on the socket that is to occur if no messages are successfully written
273/// to its bound destination after a specified number of milliseconds. A subsequent write
274/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
275pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
276 const timeout = os.timeval{
277 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
278 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
279 };
280
281 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
282}
283
284/// Set a timeout on the socket that is to occur if no messages are successfully read
285/// from its bound destination after a specified number of milliseconds. A subsequent
286/// read from the socket will thereafter return `error.WouldBlock` should the timeout be
287/// exceeded.
288pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
289 const timeout = os.timeval{
290 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
291 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
292 };
293
294 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
295}
lib/std/x/os/net.zig+9
......@@ -20,6 +20,14 @@ pub fn resolveScopeID(name: []const u8) !u32 {
2020 if (comptime @hasDecl(os, "IFNAMESIZE")) {
2121 if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong;
2222
23 if (comptime builtin.os.tag == .windows) {
24 var interface_name: [os.IFNAMESIZE]u8 = undefined;
25 mem.copy(u8, &interface_name, name);
26 interface_name[name.len] = 0;
27
28 return os.windows.ws2_32.if_nametoindex(@ptrCast([*:0]const u8, &interface_name));
29 }
30
2331 const fd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM, 0);
2432 defer os.closeSocket(fd);
2533
......@@ -31,6 +39,7 @@ pub fn resolveScopeID(name: []const u8) !u32 {
3139
3240 return @bitCast(u32, f.ifru.ivalue);
3341 }
42
3443 return error.Unsupported;
3544}
3645
lib/std/x/os/socket.zig created+123
......@@ -0,0 +1,123 @@
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");
8const net = @import("net.zig");
9
10const os = std.os;
11const fmt = std.fmt;
12const mem = std.mem;
13const time = std.time;
14const builtin = std.builtin;
15
16/// A generic, cross-platform socket abstraction.
17pub const Socket = struct {
18 /// A socket-address pair.
19 pub const Connection = struct {
20 socket: Socket,
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`.
31 pub 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 }
108 };
109
110 /// The underlying handle of a socket.
111 fd: os.socket_t,
112
113 /// Enclose a socket abstraction over an existing socket file descriptor.
114 pub fn from(fd: os.socket_t) Socket {
115 return Socket{ .fd = fd };
116 }
117
118 /// Mix in socket syscalls depending on the platform we are compiling against.
119 pub usingnamespace switch (builtin.os.tag) {
120 .windows => @import("socket_windows.zig"),
121 else => @import("socket_posix.zig"),
122 }.Mixin(Socket);
123};
lib/std/x/os/socket_posix.zig created+251
......@@ -0,0 +1,251 @@
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 mem = std.mem;
11const time = std.time;
12
13pub fn Mixin(comptime Socket: type) type {
14 return struct {
15 /// Open a new socket.
16 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
17 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
18 }
19
20 /// Closes the socket.
21 pub fn deinit(self: Socket) void {
22 os.closeSocket(self.fd);
23 }
24
25 /// Shutdown either the read side, write side, or all side of the socket.
26 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
27 return os.shutdown(self.fd, how);
28 }
29
30 /// Binds the socket to an address.
31 pub fn bind(self: Socket, address: Socket.Address) !void {
32 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
33 }
34
35 /// Start listening for incoming connections on the socket.
36 pub fn listen(self: Socket, max_backlog_size: u31) !void {
37 return os.listen(self.fd, max_backlog_size);
38 }
39
40 /// Have the socket attempt to the connect to an address.
41 pub fn connect(self: Socket, address: Socket.Address) !void {
42 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
43 }
44
45 /// Accept a pending incoming connection queued to the kernel backlog
46 /// of the socket.
47 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
48 var address: os.sockaddr_storage = undefined;
49 var address_len: u32 = @sizeOf(os.sockaddr_storage);
50
51 const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) };
52 const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
53
54 return Socket.Connection.from(socket, socket_address);
55 }
56
57 /// Read data from the socket into the buffer provided with a set of flags
58 /// specified. It returns the number of bytes read into the buffer provided.
59 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
60 return os.recv(self.fd, buf, flags);
61 }
62
63 /// Write a buffer of data provided to the socket with a set of flags specified.
64 /// It returns the number of bytes that are written to the socket.
65 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
66 return os.send(self.fd, buf, flags);
67 }
68
69 /// Writes multiple I/O vectors with a prepended message header to the socket
70 /// with a set of flags specified. It returns the number of bytes that are
71 /// written to the socket.
72 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
73 return os.sendmsg(self.fd, msg, flags);
74 }
75
76 /// Read multiple I/O vectors with a prepended message header from the socket
77 /// with a set of flags specified. It returns the number of bytes that were
78 /// read into the buffer provided.
79 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {
80 if (comptime @hasDecl(os.system, "recvmsg")) {
81 while (true) {
82 const rc = os.system.recvmsg(self.fd, msg, flags);
83 return switch (os.errno(rc)) {
84 0 => @intCast(usize, rc),
85 os.EBADF => unreachable, // always a race condition
86 os.EFAULT => unreachable,
87 os.EINVAL => unreachable,
88 os.ENOTCONN => unreachable,
89 os.ENOTSOCK => unreachable,
90 os.EINTR => continue,
91 os.EAGAIN => error.WouldBlock,
92 os.ENOMEM => error.SystemResources,
93 os.ECONNREFUSED => error.ConnectionRefused,
94 os.ECONNRESET => error.ConnectionResetByPeer,
95 else => |err| os.unexpectedErrno(err),
96 };
97 }
98 }
99 return error.NotSupported;
100 }
101
102 /// Query the address that the socket is locally bounded to.
103 pub fn getLocalAddress(self: Socket) !Socket.Address {
104 var address: os.sockaddr_storage = undefined;
105 var address_len: u32 = @sizeOf(os.sockaddr_storage);
106 try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
107 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
108 }
109
110 /// Query the address that the socket is connected to.
111 pub fn getRemoteAddress(self: Socket) !Socket.Address {
112 var address: os.sockaddr_storage = undefined;
113 var address_len: u32 = @sizeOf(os.sockaddr_storage);
114 try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
115 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
116 }
117
118 /// Query and return the latest cached error on the socket.
119 pub fn getError(self: Socket) !void {
120 return os.getsockoptError(self.fd);
121 }
122
123 /// Query the read buffer size of the socket.
124 pub fn getReadBufferSize(self: Socket) !u32 {
125 var value: u32 = undefined;
126 var value_len: u32 = @sizeOf(u32);
127
128 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);
129 return switch (os.errno(rc)) {
130 0 => value,
131 os.EBADF => error.BadFileDescriptor,
132 os.EFAULT => error.InvalidAddressSpace,
133 os.EINVAL => error.InvalidSocketOption,
134 os.ENOPROTOOPT => error.UnknownSocketOption,
135 os.ENOTSOCK => error.NotASocket,
136 else => |err| os.unexpectedErrno(err),
137 };
138 }
139
140 /// Query the write buffer size of the socket.
141 pub fn getWriteBufferSize(self: Socket) !u32 {
142 var value: u32 = undefined;
143 var value_len: u32 = @sizeOf(u32);
144
145 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len);
146 return switch (os.errno(rc)) {
147 0 => value,
148 os.EBADF => error.BadFileDescriptor,
149 os.EFAULT => error.InvalidAddressSpace,
150 os.EINVAL => error.InvalidSocketOption,
151 os.ENOPROTOOPT => error.UnknownSocketOption,
152 os.ENOTSOCK => error.NotASocket,
153 else => |err| os.unexpectedErrno(err),
154 };
155 }
156
157 /// Set a socket option.
158 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
159 return os.setsockopt(self.fd, level, code, value);
160 }
161
162 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
163 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
164 /// if the host does not support the option for a socket to linger around up until a timeout specified in
165 /// seconds.
166 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
167 if (comptime @hasDecl(os, "SO_LINGER")) {
168 const settings = extern struct {
169 l_onoff: c_int,
170 l_linger: c_int,
171 }{
172 .l_onoff = @intCast(c_int, @boolToInt(timeout_seconds != null)),
173 .l_linger = if (timeout_seconds) |seconds| @intCast(c_int, seconds) else 0,
174 };
175
176 return self.setOption(os.SOL_SOCKET, os.SO_LINGER, mem.asBytes(&settings));
177 }
178
179 return error.UnsupportedSocketOption;
180 }
181
182 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
183 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
184 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
185 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
186 if (comptime @hasDecl(os, "SO_KEEPALIVE")) {
187 return self.setOption(os.SOL_SOCKET, os.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
188 }
189 return error.UnsupportedSocketOption;
190 }
191
192 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
193 /// the host does not support sockets listening the same address.
194 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
195 if (comptime @hasDecl(os, "SO_REUSEADDR")) {
196 return self.setOption(os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));
197 }
198 return error.UnsupportedSocketOption;
199 }
200
201 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
202 /// the host does not supports sockets listening on the same port.
203 pub fn setReusePort(self: Socket, enabled: bool) !void {
204 if (comptime @hasDecl(os, "SO_REUSEPORT")) {
205 return self.setOption(os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(u32, @boolToInt(enabled))));
206 }
207 return error.UnsupportedSocketOption;
208 }
209
210 /// Set the write buffer size of the socket.
211 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
212 return self.setOption(os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
213 }
214
215 /// Set the read buffer size of the socket.
216 pub fn setReadBufferSize(self: Socket, size: u32) !void {
217 return self.setOption(os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));
218 }
219
220 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
221 /// set on a non-blocking socket.
222 ///
223 /// Set a timeout on the socket that is to occur if no messages are successfully written
224 /// to its bound destination after a specified number of milliseconds. A subsequent write
225 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
226 pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
227 const timeout = os.timeval{
228 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
229 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
230 };
231
232 return self.setOption(os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
233 }
234
235 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
236 /// set on a non-blocking socket.
237 ///
238 /// Set a timeout on the socket that is to occur if no messages are successfully read
239 /// from its bound destination after a specified number of milliseconds. A subsequent
240 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
241 /// exceeded.
242 pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
243 const timeout = os.timeval{
244 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
245 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
246 };
247
248 return self.setOption(os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
249 }
250 };
251}
lib/std/x/os/socket_windows.zig created+448
......@@ -0,0 +1,448 @@
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");
8const net = @import("net.zig");
9
10const os = std.os;
11const mem = std.mem;
12
13const windows = std.os.windows;
14const ws2_32 = windows.ws2_32;
15
16pub fn Mixin(comptime Socket: type) type {
17 return struct {
18 /// Open a new socket.
19 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
20 var filtered_socket_type = socket_type & ~@as(u32, os.SOCK_CLOEXEC);
21
22 var filtered_flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED;
23 if (socket_type & os.SOCK_CLOEXEC != 0) {
24 filtered_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
25 }
26
27 const fd = ws2_32.WSASocketW(
28 @intCast(i32, domain),
29 @intCast(i32, filtered_socket_type),
30 @intCast(i32, protocol),
31 null,
32 0,
33 filtered_flags,
34 );
35 if (fd == ws2_32.INVALID_SOCKET) {
36 return switch (ws2_32.WSAGetLastError()) {
37 .WSANOTINITIALISED => {
38 _ = try windows.WSAStartup(2, 2);
39 return Socket.init(domain, socket_type, protocol);
40 },
41 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
42 .WSAEMFILE => error.ProcessFdQuotaExceeded,
43 .WSAENOBUFS => error.SystemResources,
44 .WSAEPROTONOSUPPORT => error.ProtocolNotSupported,
45 else => |err| windows.unexpectedWSAError(err),
46 };
47 }
48
49 return Socket{ .fd = fd };
50 }
51
52 /// Closes the socket.
53 pub fn deinit(self: Socket) void {
54 _ = ws2_32.closesocket(self.fd);
55 }
56
57 /// Shutdown either the read side, write side, or all side of the socket.
58 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
59 const rc = ws2_32.shutdown(self.fd, switch (how) {
60 .recv => ws2_32.SD_RECEIVE,
61 .send => ws2_32.SD_SEND,
62 .both => ws2_32.SD_BOTH,
63 });
64 if (rc == ws2_32.SOCKET_ERROR) {
65 return switch (ws2_32.WSAGetLastError()) {
66 .WSAECONNABORTED => return error.ConnectionAborted,
67 .WSAECONNRESET => return error.ConnectionResetByPeer,
68 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
69 .WSAEINVAL => unreachable,
70 .WSAENETDOWN => return error.NetworkSubsystemFailed,
71 .WSAENOTCONN => return error.SocketNotConnected,
72 .WSAENOTSOCK => unreachable,
73 .WSANOTINITIALISED => unreachable,
74 else => |err| return windows.unexpectedWSAError(err),
75 };
76 }
77 }
78
79 /// Binds the socket to an address.
80 pub fn bind(self: Socket, address: Socket.Address) !void {
81 const rc = ws2_32.bind(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
82 if (rc == ws2_32.SOCKET_ERROR) {
83 return switch (ws2_32.WSAGetLastError()) {
84 .WSAENETDOWN => error.NetworkSubsystemFailed,
85 .WSAEACCES => error.AccessDenied,
86 .WSAEADDRINUSE => error.AddressInUse,
87 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
88 .WSAEFAULT => error.BadAddress,
89 .WSAEINPROGRESS => error.WouldBlock,
90 .WSAEINVAL => error.AlreadyBound,
91 .WSAENOBUFS => error.NoEphemeralPortsAvailable,
92 .WSAENOTSOCK => error.NotASocket,
93 else => |err| windows.unexpectedWSAError(err),
94 };
95 }
96 }
97
98 /// Start listening for incoming connections on the socket.
99 pub fn listen(self: Socket, max_backlog_size: u31) !void {
100 const rc = ws2_32.listen(self.fd, max_backlog_size);
101 if (rc == ws2_32.SOCKET_ERROR) {
102 return switch (ws2_32.WSAGetLastError()) {
103 .WSAENETDOWN => error.NetworkSubsystemFailed,
104 .WSAEADDRINUSE => error.AddressInUse,
105 .WSAEISCONN => error.AlreadyConnected,
106 .WSAEINVAL => error.SocketNotBound,
107 .WSAEMFILE, .WSAENOBUFS => error.SystemResources,
108 .WSAENOTSOCK => error.FileDescriptorNotASocket,
109 .WSAEOPNOTSUPP => error.OperationNotSupported,
110 .WSAEINPROGRESS => error.WouldBlock,
111 else => |err| windows.unexpectedWSAError(err),
112 };
113 }
114 }
115
116 /// Have the socket attempt to the connect to an address.
117 pub fn connect(self: Socket, address: Socket.Address) !void {
118 const rc = ws2_32.connect(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
119 if (rc == ws2_32.SOCKET_ERROR) {
120 return switch (ws2_32.WSAGetLastError()) {
121 .WSAEADDRINUSE => error.AddressInUse,
122 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
123 .WSAECONNREFUSED => error.ConnectionRefused,
124 .WSAETIMEDOUT => error.ConnectionTimedOut,
125 .WSAEFAULT => error.BadAddress,
126 .WSAEINVAL => error.ListeningSocket,
127 .WSAEISCONN => error.AlreadyConnected,
128 .WSAENOTSOCK => error.NotASocket,
129 .WSAEACCES => error.BroadcastNotEnabled,
130 .WSAENOBUFS => error.SystemResources,
131 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
132 .WSAEINPROGRESS, .WSAEWOULDBLOCK => error.WouldBlock,
133 .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable,
134 else => |err| windows.unexpectedWSAError(err),
135 };
136 }
137 }
138
139 /// Accept a pending incoming connection queued to the kernel backlog
140 /// of the socket.
141 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
142 var address: ws2_32.sockaddr_storage = undefined;
143 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
144
145 const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
146 if (rc == ws2_32.INVALID_SOCKET) {
147 return switch (ws2_32.WSAGetLastError()) {
148 .WSANOTINITIALISED => unreachable,
149 .WSAECONNRESET => error.ConnectionResetByPeer,
150 .WSAEFAULT => unreachable,
151 .WSAEINVAL => error.SocketNotListening,
152 .WSAEMFILE => error.ProcessFdQuotaExceeded,
153 .WSAENETDOWN => error.NetworkSubsystemFailed,
154 .WSAENOBUFS => error.FileDescriptorNotASocket,
155 .WSAEOPNOTSUPP => error.OperationNotSupported,
156 .WSAEWOULDBLOCK => error.WouldBlock,
157 else => |err| windows.unexpectedWSAError(err),
158 };
159 }
160
161 const socket = Socket.from(rc);
162 const socket_address = Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
163
164 return Socket.Connection.from(socket, socket_address);
165 }
166
167 /// Read data from the socket into the buffer provided with a set of flags
168 /// specified. It returns the number of bytes read into the buffer provided.
169 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
170 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};
171 var num_bytes: u32 = undefined;
172 var flags_ = flags;
173
174 const rc = ws2_32.WSARecv(self.fd, bufs, 1, &num_bytes, &flags_, null, null);
175 if (rc == ws2_32.SOCKET_ERROR) {
176 return switch (ws2_32.WSAGetLastError()) {
177 .WSAECONNABORTED => error.ConnectionAborted,
178 .WSAECONNRESET => error.ConnectionResetByPeer,
179 .WSAEDISCON => error.ConnectionClosedByPeer,
180 .WSAEFAULT => error.BadBuffer,
181 .WSAEINPROGRESS,
182 .WSAEWOULDBLOCK,
183 .WSA_IO_PENDING,
184 .WSAETIMEDOUT,
185 => error.WouldBlock,
186 .WSAEINTR => error.Cancelled,
187 .WSAEINVAL => error.SocketNotBound,
188 .WSAEMSGSIZE => error.MessageTooLarge,
189 .WSAENETDOWN => error.NetworkSubsystemFailed,
190 .WSAENETRESET => error.NetworkReset,
191 .WSAENOTCONN => error.SocketNotConnected,
192 .WSAENOTSOCK => error.FileDescriptorNotASocket,
193 .WSAEOPNOTSUPP => error.OperationNotSupported,
194 .WSAESHUTDOWN => error.AlreadyShutdown,
195 .WSA_OPERATION_ABORTED => error.OperationAborted,
196 else => |err| windows.unexpectedWSAError(err),
197 };
198 }
199
200 return @intCast(usize, num_bytes);
201 }
202
203 /// Write a buffer of data provided to the socket with a set of flags specified.
204 /// It returns the number of bytes that are written to the socket.
205 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
206 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = @intToPtr([*]u8, @ptrToInt(buf.ptr)) }};
207 var num_bytes: u32 = undefined;
208
209 const rc = ws2_32.WSASend(self.fd, bufs, 1, &num_bytes, flags, null, null);
210 if (rc == ws2_32.SOCKET_ERROR) {
211 return switch (ws2_32.WSAGetLastError()) {
212 .WSAECONNABORTED => error.ConnectionAborted,
213 .WSAECONNRESET => error.ConnectionResetByPeer,
214 .WSAEFAULT => error.BadBuffer,
215 .WSAEINPROGRESS,
216 .WSAEWOULDBLOCK,
217 .WSA_IO_PENDING,
218 .WSAETIMEDOUT,
219 => error.WouldBlock,
220 .WSAEINTR => error.Cancelled,
221 .WSAEINVAL => error.SocketNotBound,
222 .WSAEMSGSIZE => error.MessageTooLarge,
223 .WSAENETDOWN => error.NetworkSubsystemFailed,
224 .WSAENETRESET => error.NetworkReset,
225 .WSAENOBUFS => error.BufferDeadlock,
226 .WSAENOTCONN => error.SocketNotConnected,
227 .WSAENOTSOCK => error.FileDescriptorNotASocket,
228 .WSAEOPNOTSUPP => error.OperationNotSupported,
229 .WSAESHUTDOWN => error.AlreadyShutdown,
230 .WSA_OPERATION_ABORTED => error.OperationAborted,
231 else => |err| windows.unexpectedWSAError(err),
232 };
233 }
234
235 return @intCast(usize, num_bytes);
236 }
237
238 /// Writes multiple I/O vectors with a prepended message header to the socket
239 /// with a set of flags specified. It returns the number of bytes that are
240 /// written to the socket.
241 pub fn writeVectorized(self: Socket, msg: ws2_32.msghdr_const, flags: u32) !usize {
242 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSASENDMSG, self.fd, ws2_32.WSAID_WSASENDMSG);
243
244 var num_bytes: u32 = undefined;
245
246 const rc = call(self.fd, &msg, flags, &num_bytes, null, null);
247 if (rc == ws2_32.SOCKET_ERROR) {
248 return switch (ws2_32.WSAGetLastError()) {
249 .WSAECONNABORTED => error.ConnectionAborted,
250 .WSAECONNRESET => error.ConnectionResetByPeer,
251 .WSAEFAULT => error.BadBuffer,
252 .WSAEINPROGRESS,
253 .WSAEWOULDBLOCK,
254 .WSA_IO_PENDING,
255 .WSAETIMEDOUT,
256 => error.WouldBlock,
257 .WSAEINTR => error.Cancelled,
258 .WSAEINVAL => error.SocketNotBound,
259 .WSAEMSGSIZE => error.MessageTooLarge,
260 .WSAENETDOWN => error.NetworkSubsystemFailed,
261 .WSAENETRESET => error.NetworkReset,
262 .WSAENOBUFS => error.BufferDeadlock,
263 .WSAENOTCONN => error.SocketNotConnected,
264 .WSAENOTSOCK => error.FileDescriptorNotASocket,
265 .WSAEOPNOTSUPP => error.OperationNotSupported,
266 .WSAESHUTDOWN => error.AlreadyShutdown,
267 .WSA_OPERATION_ABORTED => error.OperationAborted,
268 else => |err| windows.unexpectedWSAError(err),
269 };
270 }
271
272 return @intCast(usize, num_bytes);
273 }
274
275 /// Read multiple I/O vectors with a prepended message header from the socket
276 /// with a set of flags specified. It returns the number of bytes that were
277 /// read into the buffer provided.
278 pub fn readVectorized(self: Socket, msg: *ws2_32.msghdr, flags: u32) !usize {
279 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSARECVMSG, self.fd, ws2_32.WSAID_WSARECVMSG);
280
281 var num_bytes: u32 = undefined;
282
283 const rc = call(self.fd, msg, &num_bytes, null, null);
284 if (rc == ws2_32.SOCKET_ERROR) {
285 return switch (ws2_32.WSAGetLastError()) {
286 .WSAECONNABORTED => error.ConnectionAborted,
287 .WSAECONNRESET => error.ConnectionResetByPeer,
288 .WSAEDISCON => error.ConnectionClosedByPeer,
289 .WSAEFAULT => error.BadBuffer,
290 .WSAEINPROGRESS,
291 .WSAEWOULDBLOCK,
292 .WSA_IO_PENDING,
293 .WSAETIMEDOUT,
294 => error.WouldBlock,
295 .WSAEINTR => error.Cancelled,
296 .WSAEINVAL => error.SocketNotBound,
297 .WSAEMSGSIZE => error.MessageTooLarge,
298 .WSAENETDOWN => error.NetworkSubsystemFailed,
299 .WSAENETRESET => error.NetworkReset,
300 .WSAENOTCONN => error.SocketNotConnected,
301 .WSAENOTSOCK => error.FileDescriptorNotASocket,
302 .WSAEOPNOTSUPP => error.OperationNotSupported,
303 .WSAESHUTDOWN => error.AlreadyShutdown,
304 .WSA_OPERATION_ABORTED => error.OperationAborted,
305 else => |err| windows.unexpectedWSAError(err),
306 };
307 }
308
309 return @intCast(usize, num_bytes);
310 }
311
312 /// Query the address that the socket is locally bounded to.
313 pub fn getLocalAddress(self: Socket) !Socket.Address {
314 var address: ws2_32.sockaddr_storage = undefined;
315 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
316
317 const rc = ws2_32.getsockname(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
318 if (rc == ws2_32.SOCKET_ERROR) {
319 return switch (ws2_32.WSAGetLastError()) {
320 .WSANOTINITIALISED => unreachable,
321 .WSAEFAULT => unreachable,
322 .WSAENETDOWN => error.NetworkSubsystemFailed,
323 .WSAENOTSOCK => error.FileDescriptorNotASocket,
324 .WSAEINVAL => error.SocketNotBound,
325 else => |err| windows.unexpectedWSAError(err),
326 };
327 }
328
329 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
330 }
331
332 /// Query the address that the socket is connected to.
333 pub fn getRemoteAddress(self: Socket) !Socket.Address {
334 var address: ws2_32.sockaddr_storage = undefined;
335 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
336
337 const rc = ws2_32.getpeername(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
338 if (rc == ws2_32.SOCKET_ERROR) {
339 return switch (ws2_32.WSAGetLastError()) {
340 .WSANOTINITIALISED => unreachable,
341 .WSAEFAULT => unreachable,
342 .WSAENETDOWN => error.NetworkSubsystemFailed,
343 .WSAENOTSOCK => error.FileDescriptorNotASocket,
344 .WSAEINVAL => error.SocketNotBound,
345 else => |err| windows.unexpectedWSAError(err),
346 };
347 }
348
349 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
350 }
351
352 /// Query and return the latest cached error on the socket.
353 pub fn getError(self: Socket) !void {
354 return {};
355 }
356
357 /// Query the read buffer size of the socket.
358 pub fn getReadBufferSize(self: Socket) !u32 {
359 return 0;
360 }
361
362 /// Query the write buffer size of the socket.
363 pub fn getWriteBufferSize(self: Socket) !u32 {
364 return 0;
365 }
366
367 /// Set a socket option.
368 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
369 const rc = ws2_32.setsockopt(self.fd, @intCast(i32, level), @intCast(i32, code), value.ptr, @intCast(i32, value.len));
370 if (rc == ws2_32.SOCKET_ERROR) {
371 return switch (ws2_32.WSAGetLastError()) {
372 .WSANOTINITIALISED => unreachable,
373 .WSAENETDOWN => return error.NetworkSubsystemFailed,
374 .WSAEFAULT => unreachable,
375 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
376 .WSAEINVAL => return error.SocketNotBound,
377 else => |err| windows.unexpectedWSAError(err),
378 };
379 }
380 }
381
382 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
383 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
384 /// if the host does not support the option for a socket to linger around up until a timeout specified in
385 /// seconds.
386 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
387 const settings = ws2_32.linger{
388 .l_onoff = @as(u16, @boolToInt(timeout_seconds != null)),
389 .l_linger = if (timeout_seconds) |seconds| seconds else 0,
390 };
391
392 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_LINGER, mem.asBytes(&settings));
393 }
394
395 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
396 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
397 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
398 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
399 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
400 }
401
402 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
403 /// the host does not support sockets listening the same address.
404 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
405 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));
406 }
407
408 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
409 /// the host does not supports sockets listening on the same port.
410 ///
411 /// TODO: verify if this truly mimicks SO_REUSEPORT behavior, or if SO_REUSE_UNICASTPORT provides the correct behavior
412 pub fn setReusePort(self: Socket, enabled: bool) !void {
413 try self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_BROADCAST, mem.asBytes(&@as(u32, @boolToInt(enabled))));
414 try self.setReuseAddress(enabled);
415 }
416
417 /// Set the write buffer size of the socket.
418 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
419 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDBUF, mem.asBytes(&size));
420 }
421
422 /// Set the read buffer size of the socket.
423 pub fn setReadBufferSize(self: Socket, size: u32) !void {
424 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVBUF, mem.asBytes(&size));
425 }
426
427 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
428 /// set on a non-blocking socket.
429 ///
430 /// Set a timeout on the socket that is to occur if no messages are successfully written
431 /// to its bound destination after a specified number of milliseconds. A subsequent write
432 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
433 pub fn setWriteTimeout(self: Socket, milliseconds: u32) !void {
434 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDTIMEO, mem.asBytes(&milliseconds));
435 }
436
437 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
438 /// set on a non-blocking socket.
439 ///
440 /// Set a timeout on the socket that is to occur if no messages are successfully read
441 /// from its bound destination after a specified number of milliseconds. A subsequent
442 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
443 /// exceeded.
444 pub fn setReadTimeout(self: Socket, milliseconds: u32) !void {
445 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVTIMEO, mem.asBytes(&milliseconds));
446 }
447 };
448}
lib/std/zig/parse.zig+1-1
......@@ -639,7 +639,7 @@ const Parser = struct {
639639 };
640640 }
641641
642 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
642 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
643643 fn parseFnProto(p: *Parser) !Node.Index {
644644 const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
645645
lib/std/zig/system.zig+80-28
......@@ -209,11 +209,6 @@ pub const NativeTargetInfo = struct {
209209
210210 dynamic_linker: DynamicLinker = DynamicLinker{},
211211
212 /// Only some architectures have CPU detection implemented. This field reveals whether
213 /// CPU detection actually occurred. When this is `true` it means that the reported
214 /// CPU is baseline only because of a missing implementation for that architecture.
215 cpu_detection_unimplemented: bool = false,
216
217212 pub const DynamicLinker = Target.DynamicLinker;
218213
219214 pub const DetectError = error{
......@@ -258,28 +253,86 @@ pub const NativeTargetInfo = struct {
258253 os.version_range.windows.max = detected_version;
259254 },
260255 .macos => try macos.detect(&os),
261 .freebsd => {
262 var osreldate: u32 = undefined;
263 var len: usize = undefined;
256 .freebsd, .netbsd, .dragonfly => {
257 const key = switch (Target.current.os.tag) {
258 .freebsd => "kern.osreldate",
259 .netbsd, .dragonfly => "kern.osrevision",
260 else => unreachable,
261 };
262 var value: u32 = undefined;
263 var len: usize = @sizeOf(@TypeOf(value));
264
265 std.os.sysctlbynameZ(key, &value, &len, null, 0) catch |err| switch (err) {
266 error.NameTooLong => unreachable, // constant, known good value
267 error.PermissionDenied => unreachable, // only when setting values,
268 error.SystemResources => unreachable, // memory already on the stack
269 error.UnknownName => unreachable, // constant, known good value
270 error.Unexpected => return error.OSVersionDetectionFail,
271 };
272
273 switch (Target.current.os.tag) {
274 .freebsd => {
275 // https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html
276 // Major * 100,000 has been convention since FreeBSD 2.2 (1997)
277 // Minor * 1(0),000 summed has been convention since FreeBSD 2.2 (1997)
278 // e.g. 492101 = 4.11-STABLE = 4.(9+2)
279 const major = value / 100_000;
280 const minor1 = value % 100_000 / 10_000; // usually 0 since 5.1
281 const minor2 = value % 10_000 / 1_000; // 0 before 5.1, minor version since
282 const patch = value % 1_000;
283 os.version_range.semver.min = .{ .major = major, .minor = minor1 + minor2, .patch = patch };
284 os.version_range.semver.max = os.version_range.semver.min;
285 },
286 .netbsd => {
287 // #define __NetBSD_Version__ MMmmrrpp00
288 //
289 // M = major version
290 // m = minor version; a minor number of 99 indicates current.
291 // r = 0 (*)
292 // p = patchlevel
293 const major = value / 100_000_000;
294 const minor = value % 100_000_000 / 1_000_000;
295 const patch = value % 10_000 / 100;
296 os.version_range.semver.min = .{ .major = major, .minor = minor, .patch = patch };
297 os.version_range.semver.max = os.version_range.semver.min;
298 },
299 .dragonfly => {
300 // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/cb2cde83771754aeef9bb3251ee48959138dec87/Makefile.inc1#L15-L17
301 // flat base10 format: Mmmmpp
302 // M = major
303 // m = minor; odd-numbers indicate current dev branch
304 // p = patch
305 const major = value / 100_000;
306 const minor = value % 100_000 / 100;
307 const patch = value % 100;
308 os.version_range.semver.min = .{ .major = major, .minor = minor, .patch = patch };
309 os.version_range.semver.max = os.version_range.semver.min;
310 },
311 else => unreachable,
312 }
313 },
314 .openbsd => {
315 const mib: [2]c_int = [_]c_int{
316 std.os.CTL_KERN,
317 std.os.KERN_OSRELEASE,
318 };
319 var buf: [64]u8 = undefined;
320 var len: usize = buf.len;
264321
265 std.os.sysctlbynameZ("kern.osreldate", &osreldate, &len, null, 0) catch |err| switch (err) {
322 std.os.sysctl(&mib, &buf, &len, null, 0) catch |err| switch (err) {
266323 error.NameTooLong => unreachable, // constant, known good value
267324 error.PermissionDenied => unreachable, // only when setting values,
268325 error.SystemResources => unreachable, // memory already on the stack
269326 error.UnknownName => unreachable, // constant, known good value
270 error.Unexpected => unreachable, // EFAULT: stack should be safe, EISDIR/ENOTDIR: constant, known good value
327 error.Unexpected => return error.OSVersionDetectionFail,
271328 };
272329
273 // https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html
274 // Major * 100,000 has been convention since FreeBSD 2.2 (1997)
275 // Minor * 1(0),000 summed has been convention since FreeBSD 2.2 (1997)
276 // e.g. 492101 = 4.11-STABLE = 4.(9+2)
277 const major = osreldate / 100_000;
278 const minor1 = osreldate % 100_000 / 10_000; // usually 0 since 5.1
279 const minor2 = osreldate % 10_000 / 1_000; // 0 before 5.1, minor version since
280 const patch = osreldate % 1_000;
281 os.version_range.semver.min = .{ .major = major, .minor = minor1 + minor2, .patch = patch };
282 os.version_range.semver.max = .{ .major = major, .minor = minor1 + minor2, .patch = patch };
330 if (std.builtin.Version.parse(buf[0 .. len - 1])) |ver| {
331 os.version_range.semver.min = ver;
332 os.version_range.semver.max = ver;
333 } else |err| {
334 return error.OSVersionDetectionFail;
335 }
283336 },
284337 else => {
285338 // Unimplemented, fall back to default version range.
......@@ -310,8 +363,6 @@ pub const NativeTargetInfo = struct {
310363 os.version_range.linux.glibc = glibc;
311364 }
312365
313 var cpu_detection_unimplemented = false;
314
315366 // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the
316367 // native CPU architecture as being different than the current target), we use this:
317368 const cpu_arch = cross_target.getCpuArch();
......@@ -325,7 +376,6 @@ pub const NativeTargetInfo = struct {
325376 Target.Cpu.baseline(cpu_arch),
326377 .explicit => |model| model.toCpu(cpu_arch),
327378 } orelse backup_cpu_detection: {
328 cpu_detection_unimplemented = true;
329379 break :backup_cpu_detection Target.Cpu.baseline(cpu_arch);
330380 };
331381 var result = try detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);
......@@ -362,7 +412,6 @@ pub const NativeTargetInfo = struct {
362412 else => {},
363413 }
364414 cross_target.updateCpuFeatures(&result.target.cpu.features);
365 result.cpu_detection_unimplemented = cpu_detection_unimplemented;
366415 return result;
367416 }
368417
......@@ -925,12 +974,15 @@ pub const NativeTargetInfo = struct {
925974 else => {},
926975 }
927976
977 switch (std.Target.current.os.tag) {
978 .linux => return linux.detectNativeCpuAndFeatures(),
979 .macos => return macos.detectNativeCpuAndFeatures(),
980 else => {},
981 }
982
928983 // This architecture does not have CPU model & feature detection yet.
929984 // See https://github.com/ziglang/zig/issues/4591
930 if (std.Target.current.os.tag != .linux)
931 return null;
932
933 return linux.detectNativeCpuAndFeatures();
985 return null;
934986 }
935987};
936988
lib/std/zig/system/macos.zig+46-5
......@@ -7,10 +7,13 @@ const std = @import("std");
77const assert = std.debug.assert;
88const mem = std.mem;
99const testing = std.testing;
10const os = std.os;
11
12const Target = std.Target;
1013
1114/// Detect macOS version.
12/// `os` is not modified in case of error.
13pub fn detect(os: *std.Target.Os) !void {
15/// `target_os` is not modified in case of error.
16pub fn detect(target_os: *Target.Os) !void {
1417 // Drop use of osproductversion sysctl because:
1518 // 1. only available 10.13.4 High Sierra and later
1619 // 2. when used from a binary built against < SDK 11.0 it returns 10.16 and masks Big Sur 11.x version
......@@ -60,8 +63,8 @@ pub fn detect(os: *std.Target.Os) !void {
6063 if (parseSystemVersion(bytes)) |ver| {
6164 // never return non-canonical `10.(16+)`
6265 if (!(ver.major == 10 and ver.minor >= 16)) {
63 os.version_range.semver.min = ver;
64 os.version_range.semver.max = ver;
66 target_os.version_range.semver.min = ver;
67 target_os.version_range.semver.max = ver;
6568 return;
6669 }
6770 continue;
......@@ -410,7 +413,7 @@ fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version)
410413/// `-syslibroot` param of the linker.
411414/// The caller needs to free the resulting path slice.
412415pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 {
413 assert(std.Target.current.isDarwin());
416 assert(Target.current.isDarwin());
414417 const argv = &[_][]const u8{ "xcrun", "--show-sdk-path" };
415418 const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });
416419 defer {
......@@ -426,3 +429,41 @@ pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 {
426429 const syslibroot = mem.trimRight(u8, result.stdout, "\r\n");
427430 return mem.dupe(allocator, u8, syslibroot);
428431}
432
433pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
434 var cpu_family: os.CPUFAMILY = undefined;
435 var len: usize = @sizeOf(os.CPUFAMILY);
436 os.sysctlbynameZ("hw.cpufamily", &cpu_family, &len, null, 0) catch |err| switch (err) {
437 error.NameTooLong => unreachable, // constant, known good value
438 error.PermissionDenied => unreachable, // only when setting values,
439 error.SystemResources => unreachable, // memory already on the stack
440 error.UnknownName => unreachable, // constant, known good value
441 error.Unexpected => unreachable, // EFAULT: stack should be safe, EISDIR/ENOTDIR: constant, known good value
442 };
443
444 const current_arch = Target.current.cpu.arch;
445 switch (current_arch) {
446 .aarch64, .aarch64_be, .aarch64_32 => {
447 const model = switch (cpu_family) {
448 .ARM_FIRESTORM_ICESTORM => &Target.aarch64.cpu.apple_a14,
449 .ARM_LIGHTNING_THUNDER => &Target.aarch64.cpu.apple_a13,
450 .ARM_VORTEX_TEMPEST => &Target.aarch64.cpu.apple_a12,
451 .ARM_MONSOON_MISTRAL => &Target.aarch64.cpu.apple_a11,
452 .ARM_HURRICANE => &Target.aarch64.cpu.apple_a10,
453 .ARM_TWISTER => &Target.aarch64.cpu.apple_a9,
454 .ARM_TYPHOON => &Target.aarch64.cpu.apple_a8,
455 .ARM_CYCLONE => &Target.aarch64.cpu.cyclone,
456 else => return null,
457 };
458
459 return Target.Cpu{
460 .arch = current_arch,
461 .model = model,
462 .features = model.features,
463 };
464 },
465 else => {},
466 }
467
468 return null;
469}
src/Cache.zig+20-1
......@@ -11,6 +11,7 @@ const testing = std.testing;
1111const mem = std.mem;
1212const fmt = std.fmt;
1313const Allocator = std.mem.Allocator;
14const Compilation = @import("Compilation.zig");
1415
1516/// Be sure to call `Manifest.deinit` after successful initialization.
1617pub fn obtain(cache: *const Cache) Manifest {
......@@ -61,7 +62,7 @@ pub const File = struct {
6162pub const HashHelper = struct {
6263 hasher: Hasher = hasher_init,
6364
64 const EmitLoc = @import("Compilation.zig").EmitLoc;
65 const EmitLoc = Compilation.EmitLoc;
6566
6667 /// Record a slice of bytes as an dependency of the process being cached
6768 pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {
......@@ -220,6 +221,24 @@ pub const Manifest = struct {
220221 return idx;
221222 }
222223
224 pub fn hashCSource(self: *Manifest, c_source: Compilation.CSourceFile) !void {
225 _ = try self.addFile(c_source.src_path, null);
226 // Hash the extra flags, with special care to call addFile for file parameters.
227 // TODO this logic can likely be improved by utilizing clang_options_data.zig.
228 const file_args = [_][]const u8{"-include"};
229 var arg_i: usize = 0;
230 while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
231 const arg = c_source.extra_flags[arg_i];
232 self.hash.addBytes(arg);
233 for (file_args) |file_arg| {
234 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
235 arg_i += 1;
236 _ = try self.addFile(c_source.extra_flags[arg_i], null);
237 }
238 }
239 }
240 }
241
223242 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
224243 self.hash.add(optional_file_path != null);
225244 const file_path = optional_file_path orelse return;
src/Compilation.zig+24-26
......@@ -942,7 +942,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
942942 arena,
943943 options.zig_lib_directory.path.?,
944944 options.target,
945 options.is_native_os,
945 options.is_native_abi,
946946 link_libc,
947947 options.libc_installation,
948948 );
......@@ -2514,23 +2514,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
25142514
25152515 man.hash.add(comp.clang_preprocessor_mode);
25162516
2517 _ = try man.addFile(c_object.src.src_path, null);
2518 {
2519 // Hash the extra flags, with special care to call addFile for file parameters.
2520 // TODO this logic can likely be improved by utilizing clang_options_data.zig.
2521 const file_args = [_][]const u8{"-include"};
2522 var arg_i: usize = 0;
2523 while (arg_i < c_object.src.extra_flags.len) : (arg_i += 1) {
2524 const arg = c_object.src.extra_flags[arg_i];
2525 man.hash.addBytes(arg);
2526 for (file_args) |file_arg| {
2527 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_object.src.extra_flags.len) {
2528 arg_i += 1;
2529 _ = try man.addFile(c_object.src.extra_flags[arg_i], null);
2530 }
2531 }
2532 }
2533 }
2517 try man.hashCSource(c_object.src);
25342518
25352519 {
25362520 const is_collision = blk: {
......@@ -2862,6 +2846,10 @@ pub fn addCCArgs(
28622846 }
28632847 }
28642848
2849 if (target.cpu.arch.isThumb()) {
2850 try argv.append("-mthumb");
2851 }
2852
28652853 if (comp.haveFramePointer()) {
28662854 try argv.append("-fno-omit-frame-pointer");
28672855 } else {
......@@ -3135,7 +3123,7 @@ fn detectLibCIncludeDirs(
31353123 arena: *Allocator,
31363124 zig_lib_dir: []const u8,
31373125 target: Target,
3138 is_native_os: bool,
3126 is_native_abi: bool,
31393127 link_libc: bool,
31403128 libc_installation: ?*const LibCInstallation,
31413129) !LibCDirs {
......@@ -3150,10 +3138,26 @@ fn detectLibCIncludeDirs(
31503138 return detectLibCFromLibCInstallation(arena, target, lci);
31513139 }
31523140
3141 if (is_native_abi) {
3142 const libc = try arena.create(LibCInstallation);
3143 libc.* = try LibCInstallation.findNative(.{ .allocator = arena });
3144 return detectLibCFromLibCInstallation(arena, target, libc);
3145 }
3146
31533147 if (target_util.canBuildLibC(target)) {
31543148 const generic_name = target_util.libCGenericName(target);
31553149 // Some architectures are handled by the same set of headers.
3156 const arch_name = if (target.abi.isMusl()) target_util.archMuslName(target.cpu.arch) else @tagName(target.cpu.arch);
3150 const arch_name = if (target.abi.isMusl())
3151 target_util.archMuslName(target.cpu.arch)
3152 else if (target.cpu.arch.isThumb())
3153 // ARM headers are valid for Thumb too.
3154 switch (target.cpu.arch) {
3155 .thumb => "arm",
3156 .thumbeb => "armeb",
3157 else => unreachable,
3158 }
3159 else
3160 @tagName(target.cpu.arch);
31573161 const os_name = @tagName(target.os.tag);
31583162 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
31593163 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
......@@ -3190,12 +3194,6 @@ fn detectLibCIncludeDirs(
31903194 };
31913195 }
31923196
3193 if (is_native_os) {
3194 const libc = try arena.create(LibCInstallation);
3195 libc.* = try LibCInstallation.findNative(.{ .allocator = arena });
3196 return detectLibCFromLibCInstallation(arena, target, libc);
3197 }
3198
31993197 return LibCDirs{
32003198 .libc_include_dir_list = &[0][]u8{},
32013199 .libc_installation = null,
src/Module.zig+60
......@@ -4151,6 +4151,33 @@ pub fn intDiv(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
41514151 }
41524152}
41534153
4154pub fn intMul(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
4155 // TODO is this a performance issue? maybe we should try the operation without
4156 // resorting to BigInt first.
4157 var lhs_space: Value.BigIntSpace = undefined;
4158 var rhs_space: Value.BigIntSpace = undefined;
4159 const lhs_bigint = lhs.toBigInt(&lhs_space);
4160 const rhs_bigint = rhs.toBigInt(&rhs_space);
4161 const limbs = try allocator.alloc(
4162 std.math.big.Limb,
4163 lhs_bigint.limbs.len + rhs_bigint.limbs.len + 1,
4164 );
4165 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
4166 var limbs_buffer = try allocator.alloc(
4167 std.math.big.Limb,
4168 std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
4169 );
4170 defer allocator.free(limbs_buffer);
4171 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, allocator);
4172 const result_limbs = result_bigint.limbs[0..result_bigint.len];
4173
4174 if (result_bigint.positive) {
4175 return Value.Tag.int_big_positive.create(allocator, result_limbs);
4176 } else {
4177 return Value.Tag.int_big_negative.create(allocator, result_limbs);
4178 }
4179}
4180
41544181pub fn floatAdd(
41554182 arena: *Allocator,
41564183 float_type: Type,
......@@ -4250,6 +4277,39 @@ pub fn floatDiv(
42504277 }
42514278}
42524279
4280pub fn floatMul(
4281 arena: *Allocator,
4282 float_type: Type,
4283 src: LazySrcLoc,
4284 lhs: Value,
4285 rhs: Value,
4286) !Value {
4287 switch (float_type.tag()) {
4288 .f16 => {
4289 @panic("TODO add __trunctfhf2 to compiler-rt");
4290 //const lhs_val = lhs.toFloat(f16);
4291 //const rhs_val = rhs.toFloat(f16);
4292 //return Value.Tag.float_16.create(arena, lhs_val * rhs_val);
4293 },
4294 .f32 => {
4295 const lhs_val = lhs.toFloat(f32);
4296 const rhs_val = rhs.toFloat(f32);
4297 return Value.Tag.float_32.create(arena, lhs_val * rhs_val);
4298 },
4299 .f64 => {
4300 const lhs_val = lhs.toFloat(f64);
4301 const rhs_val = rhs.toFloat(f64);
4302 return Value.Tag.float_64.create(arena, lhs_val * rhs_val);
4303 },
4304 .f128, .comptime_float, .c_longdouble => {
4305 const lhs_val = lhs.toFloat(f128);
4306 const rhs_val = rhs.toFloat(f128);
4307 return Value.Tag.float_128.create(arena, lhs_val * rhs_val);
4308 },
4309 else => unreachable,
4310 }
4311}
4312
42534313pub fn simplePtrType(
42544314 mod: *Module,
42554315 arena: *Allocator,
src/Sema.zig+16-4
......@@ -4606,10 +4606,15 @@ fn analyzeArithmetic(
46064606 // incase rhs is 0, simply return lhs without doing any calculations
46074607 // TODO Once division is implemented we should throw an error when dividing by 0.
46084608 if (rhs_val.compareWithZero(.eq)) {
4609 return sema.mod.constInst(sema.arena, src, .{
4610 .ty = scalar_type,
4611 .val = lhs_val,
4612 });
4609 switch (zir_tag) {
4610 .add, .addwrap, .sub, .subwrap => {
4611 return sema.mod.constInst(sema.arena, src, .{
4612 .ty = scalar_type,
4613 .val = lhs_val,
4614 });
4615 },
4616 else => {},
4617 }
46134618 }
46144619
46154620 const value = switch (zir_tag) {
......@@ -4634,6 +4639,13 @@ fn analyzeArithmetic(
46344639 try Module.floatDiv(sema.arena, scalar_type, src, lhs_val, rhs_val);
46354640 break :blk val;
46364641 },
4642 .mul => blk: {
4643 const val = if (is_int)
4644 try Module.intMul(sema.arena, lhs_val, rhs_val)
4645 else
4646 try Module.floatMul(sema.arena, scalar_type, src, lhs_val, rhs_val);
4647 break :blk val;
4648 },
46374649 else => return sema.mod.fail(&block.base, src, "TODO Implement arithmetic operand '{s}'", .{@tagName(zir_tag)}),
46384650 };
46394651
src/codegen.zig+674-239
......@@ -20,6 +20,8 @@ const build_options = @import("build_options");
2020const LazySrcLoc = Module.LazySrcLoc;
2121const RegisterManager = @import("register_manager.zig").RegisterManager;
2222
23const X8664Encoder = @import("codegen/x86_64.zig").Encoder;
24
2325/// The codegen-related data that is stored in `ir.Inst.Block` instructions.
2426pub const BlockData = struct {
2527 relocs: std.ArrayListUnmanaged(Reloc) = undefined,
......@@ -905,7 +907,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
905907 // TODO separate architectures with registers from
906908 // stack-based architectures (spu_2)
907909 if (callee_preserved_regs.len > 0) {
908 if (self.register_manager.tryAllocReg(inst)) |reg| {
910 if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
909911 return MCValue{ .register = registerAlias(reg, abi_size) };
910912 }
911913 }
......@@ -917,6 +919,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
917919
918920 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: Register, inst: *ir.Inst) !void {
919921 const stack_mcv = try self.allocRegOrMem(inst, false);
922 log.debug("spilling {*} to stack mcv {any}", .{ inst, stack_mcv });
920923 const reg_mcv = self.getResolvedInstValue(inst);
921924 assert(reg == toCanonicalReg(reg_mcv.register));
922925 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
......@@ -928,7 +931,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
928931 /// allocated. A second call to `copyToTmpRegister` may return the same register.
929932 /// This can have a side effect of spilling instructions to the stack to free up a register.
930933 fn copyToTmpRegister(self: *Self, src: LazySrcLoc, ty: Type, mcv: MCValue) !Register {
931 const reg = try self.register_manager.allocRegWithoutTracking();
934 const reg = try self.register_manager.allocRegWithoutTracking(&.{});
932935 try self.genSetReg(src, ty, reg, mcv);
933936 return reg;
934937 }
......@@ -937,7 +940,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
937940 /// `reg_owner` is the instruction that gets associated with the register in the register table.
938941 /// This can have a side effect of spilling instructions to the stack to free up a register.
939942 fn copyToNewRegister(self: *Self, reg_owner: *ir.Inst, mcv: MCValue) !MCValue {
940 const reg = try self.register_manager.allocReg(reg_owner);
943 const reg = try self.register_manager.allocReg(reg_owner, &.{});
941944 try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv);
942945 return MCValue{ .register = reg };
943946 }
......@@ -1017,7 +1020,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10171020 },
10181021 .val = Value.initTag(.bool_true),
10191022 };
1020 return try self.genX8664BinMath(&inst.base, inst.operand, &imm.base, 6, 0x30);
1023 return try self.genX8664BinMath(&inst.base, inst.operand, &imm.base);
10211024 },
10221025 .arm, .armeb => {
10231026 var imm = ir.Inst.Constant{
......@@ -1041,7 +1044,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10411044 return MCValue.dead;
10421045 switch (arch) {
10431046 .x86_64 => {
1044 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 0, 0x00);
1047 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs);
10451048 },
10461049 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .add),
10471050 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),
......@@ -1062,6 +1065,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10621065 if (inst.base.isUnused())
10631066 return MCValue.dead;
10641067 switch (arch) {
1068 .x86_64 => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
10651069 .arm, .armeb => return try self.genArmMul(&inst.base, inst.lhs, inst.rhs),
10661070 else => return self.fail(inst.base.src, "TODO implement mul for {}", .{self.target.cpu.arch}),
10671071 }
......@@ -1340,7 +1344,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13401344 return MCValue.dead;
13411345 switch (arch) {
13421346 .x86_64 => {
1343 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 5, 0x28);
1347 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs);
13441348 },
13451349 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .sub),
13461350 else => return self.fail(inst.base.src, "TODO implement sub for {}", .{self.target.cpu.arch}),
......@@ -1356,36 +1360,124 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13561360 }
13571361 }
13581362
1363 fn armOperandShouldBeRegister(self: *Self, src: LazySrcLoc, mcv: MCValue) !bool {
1364 return switch (mcv) {
1365 .none => unreachable,
1366 .undef => unreachable,
1367 .dead, .unreach => unreachable,
1368 .compare_flags_unsigned => unreachable,
1369 .compare_flags_signed => unreachable,
1370 .ptr_stack_offset => unreachable,
1371 .ptr_embedded_in_code => unreachable,
1372 .immediate => |imm| blk: {
1373 if (imm > std.math.maxInt(u32)) return self.fail(src, "TODO ARM binary arithmetic immediate larger than u32", .{});
1374
1375 // Load immediate into register if it doesn't fit
1376 // in an operand
1377 break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) == null;
1378 },
1379 .register => true,
1380 .stack_offset,
1381 .embedded_in_code,
1382 .memory,
1383 => true,
1384 };
1385 }
1386
13591387 fn genArmBinOp(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, op: ir.Inst.Tag) !MCValue {
13601388 const lhs = try self.resolveInst(op_lhs);
13611389 const rhs = try self.resolveInst(op_rhs);
13621390
1391 const lhs_is_register = lhs == .register;
1392 const rhs_is_register = rhs == .register;
1393 const lhs_should_be_register = try self.armOperandShouldBeRegister(op_lhs.src, lhs);
1394 const rhs_should_be_register = try self.armOperandShouldBeRegister(op_rhs.src, rhs);
1395 const reuse_lhs = lhs_is_register and self.reuseOperand(inst, 0, lhs);
1396 const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, 1, rhs);
1397
13631398 // Destination must be a register
13641399 var dst_mcv: MCValue = undefined;
1365 var lhs_mcv: MCValue = undefined;
1366 var rhs_mcv: MCValue = undefined;
1367 if (self.reuseOperand(inst, 0, lhs)) {
1368 // LHS is the destination
1369 // RHS is the source
1370 lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;
1371 rhs_mcv = rhs;
1372 dst_mcv = lhs_mcv;
1373 } else if (self.reuseOperand(inst, 1, rhs)) {
1374 // RHS is the destination
1375 // LHS is the source
1376 lhs_mcv = lhs;
1377 rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;
1378 dst_mcv = rhs_mcv;
1400 var lhs_mcv = lhs;
1401 var rhs_mcv = rhs;
1402 var swap_lhs_and_rhs = false;
1403
1404 // Allocate registers for operands and/or destination
1405 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1406 if (reuse_lhs) {
1407 // Allocate 0 or 1 registers
1408 if (!rhs_is_register and rhs_should_be_register) {
1409 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(op_rhs, &.{lhs.register}) };
1410 branch.inst_table.putAssumeCapacity(op_rhs, rhs_mcv);
1411 }
1412 dst_mcv = lhs;
1413 } else if (reuse_rhs) {
1414 // Allocate 0 or 1 registers
1415 if (!lhs_is_register and lhs_should_be_register) {
1416 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(op_lhs, &.{rhs.register}) };
1417 branch.inst_table.putAssumeCapacity(op_lhs, lhs_mcv);
1418 }
1419 dst_mcv = rhs;
1420
1421 swap_lhs_and_rhs = true;
13791422 } else {
1380 // TODO save 1 copy instruction by directly allocating the destination register
1381 // LHS is the destination
1382 // RHS is the source
1383 lhs_mcv = try self.copyToNewRegister(inst, lhs);
1384 rhs_mcv = rhs;
1385 dst_mcv = lhs_mcv;
1423 // Allocate 1 or 2 registers
1424 if (lhs_should_be_register and rhs_should_be_register) {
1425 if (lhs_is_register and rhs_is_register) {
1426 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{ lhs.register, rhs.register }) };
1427 } else if (lhs_is_register) {
1428 // Move RHS to register
1429 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) };
1430 rhs_mcv = dst_mcv;
1431 } else if (rhs_is_register) {
1432 // Move LHS to register
1433 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) };
1434 lhs_mcv = dst_mcv;
1435 } else {
1436 // Move LHS and RHS to register
1437 const regs = try self.register_manager.allocRegs(2, .{ inst, op_rhs }, &.{});
1438 lhs_mcv = MCValue{ .register = regs[0] };
1439 rhs_mcv = MCValue{ .register = regs[1] };
1440 dst_mcv = lhs_mcv;
1441
1442 branch.inst_table.putAssumeCapacity(op_rhs, rhs_mcv);
1443 }
1444 } else if (lhs_should_be_register) {
1445 // RHS is immediate
1446 if (lhs_is_register) {
1447 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) };
1448 } else {
1449 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
1450 lhs_mcv = dst_mcv;
1451 }
1452 } else if (rhs_should_be_register) {
1453 // LHS is immediate
1454 if (rhs_is_register) {
1455 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) };
1456 } else {
1457 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
1458 rhs_mcv = dst_mcv;
1459 }
1460
1461 swap_lhs_and_rhs = true;
1462 } else unreachable; // binary operation on two immediates
1463 }
1464
1465 // Move the operands to the newly allocated registers
1466 if (lhs_mcv == .register and !lhs_is_register) {
1467 try self.genSetReg(op_lhs.src, op_lhs.ty, lhs_mcv.register, lhs);
1468 }
1469 if (rhs_mcv == .register and !rhs_is_register) {
1470 try self.genSetReg(op_rhs.src, op_rhs.ty, rhs_mcv.register, rhs);
13861471 }
13871472
1388 try self.genArmBinOpCode(inst.src, dst_mcv.register, lhs_mcv, rhs_mcv, op);
1473 try self.genArmBinOpCode(
1474 inst.src,
1475 dst_mcv.register,
1476 lhs_mcv,
1477 rhs_mcv,
1478 swap_lhs_and_rhs,
1479 op,
1480 );
13891481 return dst_mcv;
13901482 }
13911483
......@@ -1395,11 +1487,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13951487 dst_reg: Register,
13961488 lhs_mcv: MCValue,
13971489 rhs_mcv: MCValue,
1490 swap_lhs_and_rhs: bool,
13981491 op: ir.Inst.Tag,
13991492 ) !void {
1400 assert(lhs_mcv == .register or lhs_mcv == .register);
1493 assert(lhs_mcv == .register or rhs_mcv == .register);
14011494
1402 const swap_lhs_and_rhs = rhs_mcv == .register and lhs_mcv != .register;
14031495 const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register;
14041496 const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv;
14051497
......@@ -1411,19 +1503,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14111503 .compare_flags_signed => unreachable,
14121504 .ptr_stack_offset => unreachable,
14131505 .ptr_embedded_in_code => unreachable,
1414 .immediate => |imm| blk: {
1415 if (imm > std.math.maxInt(u32)) return self.fail(src, "TODO ARM binary arithmetic immediate larger than u32", .{});
1416
1417 // Load immediate into register if it doesn't fit
1418 // as an operand
1419 break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse
1420 Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none);
1421 },
1506 .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?,
14221507 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
14231508 .stack_offset,
14241509 .embedded_in_code,
14251510 .memory,
1426 => Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none),
1511 => unreachable,
14271512 };
14281513
14291514 switch (op) {
......@@ -1485,8 +1570,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14851570 return dst_mcv;
14861571 }
14871572
1573 /// Perform "binary" operators, excluding comparisons.
1574 /// Currently, the following ops are supported:
14881575 /// ADD, SUB, XOR, OR, AND
1489 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue {
1576 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst) !MCValue {
1577 // We'll handle these ops in two steps.
1578 // 1) Prepare an output location (register or memory)
1579 // This location will be the location of the operand that dies (if one exists)
1580 // or just a temporary register (if one doesn't exist)
1581 // 2) Perform the op with the other argument
1582 // 3) Sometimes, the output location is memory but the op doesn't support it.
1583 // In this case, copy that location to a register, then perform the op to that register instead.
1584 //
1585 // TODO: make this algorithm less bad
1586
14901587 try self.code.ensureCapacity(self.code.items.len + 8);
14911588
14921589 const lhs = try self.resolveInst(op_lhs);
......@@ -1547,18 +1644,109 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
15471644 else => {},
15481645 }
15491646
1550 try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, opx, mr);
1647 // Now for step 2, we perform the actual op
1648 switch (inst.tag) {
1649 // TODO: Generate wrapping and non-wrapping versions separately
1650 .add, .addwrap => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 0, 0x00),
1651 .bool_or, .bit_or => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 1, 0x08),
1652 .bool_and, .bit_and => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 4, 0x20),
1653 .sub, .subwrap => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 5, 0x28),
1654 .xor, .not => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 6, 0x30),
1655
1656 .mul, .mulwrap => try self.genX8664Imul(inst.src, inst.ty, dst_mcv, src_mcv),
1657 else => unreachable,
1658 }
15511659
15521660 return dst_mcv;
15531661 }
15541662
1663 /// Wrap over Instruction.encodeInto to translate errors
1664 fn encodeX8664Instruction(
1665 self: *Self,
1666 src: LazySrcLoc,
1667 inst: Instruction,
1668 ) !void {
1669 inst.encodeInto(self.code) catch |err| {
1670 if (err == error.OutOfMemory)
1671 return error.OutOfMemory
1672 else
1673 return self.fail(src, "Instruction.encodeInto failed because {s}", .{@errorName(err)});
1674 };
1675 }
1676
1677 /// This function encodes a binary operation for x86_64
1678 /// intended for use with the following opcode ranges
1679 /// because they share the same structure.
1680 ///
1681 /// Thus not all binary operations can be used here
1682 /// -- multiplication needs to be done with imul,
1683 /// which doesn't have as convenient an interface.
1684 ///
1685 /// "opx"-style instructions use the opcode extension field to indicate which instruction to execute:
1686 ///
1687 /// opx = /0: add
1688 /// opx = /1: or
1689 /// opx = /2: adc
1690 /// opx = /3: sbb
1691 /// opx = /4: and
1692 /// opx = /5: sub
1693 /// opx = /6: xor
1694 /// opx = /7: cmp
1695 ///
1696 /// opcode | operand shape
1697 /// --------+----------------------
1698 /// 80 /opx | *r/m8*, imm8
1699 /// 81 /opx | *r/m16/32/64*, imm16/32
1700 /// 83 /opx | *r/m16/32/64*, imm8
1701 ///
1702 /// "mr"-style instructions use the low bits of opcode to indicate shape of instruction:
1703 ///
1704 /// mr = 00: add
1705 /// mr = 08: or
1706 /// mr = 10: adc
1707 /// mr = 18: sbb
1708 /// mr = 20: and
1709 /// mr = 28: sub
1710 /// mr = 30: xor
1711 /// mr = 38: cmp
1712 ///
1713 /// opcode | operand shape
1714 /// -------+-------------------------
1715 /// mr + 0 | *r/m8*, r8
1716 /// mr + 1 | *r/m16/32/64*, r16/32/64
1717 /// mr + 2 | *r8*, r/m8
1718 /// mr + 3 | *r16/32/64*, r/m16/32/64
1719 /// mr + 4 | *AL*, imm8
1720 /// mr + 5 | *rAX*, imm16/32
1721 ///
1722 /// TODO: rotates and shifts share the same structure, so we can potentially implement them
1723 /// at a later date with very similar code.
1724 /// They have "opx"-style instructions, but no "mr"-style instructions.
1725 ///
1726 /// opx = /0: rol,
1727 /// opx = /1: ror,
1728 /// opx = /2: rcl,
1729 /// opx = /3: rcr,
1730 /// opx = /4: shl sal,
1731 /// opx = /5: shr,
1732 /// opx = /6: sal shl,
1733 /// opx = /7: sar,
1734 ///
1735 /// opcode | operand shape
1736 /// --------+------------------
1737 /// c0 /opx | *r/m8*, imm8
1738 /// c1 /opx | *r/m16/32/64*, imm8
1739 /// d0 /opx | *r/m8*, 1
1740 /// d1 /opx | *r/m16/32/64*, 1
1741 /// d2 /opx | *r/m8*, CL (for context, CL is register 1)
1742 /// d3 /opx | *r/m16/32/64*, CL (for context, CL is register 1)
15551743 fn genX8664BinMathCode(
15561744 self: *Self,
15571745 src: LazySrcLoc,
15581746 dst_ty: Type,
15591747 dst_mcv: MCValue,
15601748 src_mcv: MCValue,
1561 opx: u8,
1749 opx: u3,
15621750 mr: u8,
15631751 ) !void {
15641752 switch (dst_mcv) {
......@@ -1577,31 +1765,85 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
15771765 .ptr_stack_offset => unreachable,
15781766 .ptr_embedded_in_code => unreachable,
15791767 .register => |src_reg| {
1580 self.rex(.{ .b = dst_reg.isExtended(), .r = src_reg.isExtended(), .w = dst_reg.size() == 64 });
1581 self.code.appendSliceAssumeCapacity(&[_]u8{ mr + 0x1, 0xC0 | (@as(u8, src_reg.id() & 0b111) << 3) | @as(u8, dst_reg.id() & 0b111) });
1768 // for register, register use mr + 1
1769 // addressing mode: *r/m16/32/64*, r16/32/64
1770 const abi_size = dst_ty.abiSize(self.target.*);
1771 const encoder = try X8664Encoder.init(self.code, 3);
1772 encoder.rex(.{
1773 .w = abi_size == 8,
1774 .r = src_reg.isExtended(),
1775 .b = dst_reg.isExtended(),
1776 });
1777 encoder.opcode_1byte(mr + 1);
1778 encoder.modRm_direct(
1779 src_reg.low_id(),
1780 dst_reg.low_id(),
1781 );
15821782 },
15831783 .immediate => |imm| {
1584 const imm32 = @intCast(u31, imm); // This case must be handled before calling genX8664BinMathCode.
1585 // 81 /opx id
1586 if (imm32 <= math.maxInt(u7)) {
1587 self.rex(.{ .b = dst_reg.isExtended(), .w = dst_reg.size() == 64 });
1588 self.code.appendSliceAssumeCapacity(&[_]u8{
1589 0x83,
1590 0xC0 | (opx << 3) | @truncate(u3, dst_reg.id()),
1591 @intCast(u8, imm32),
1784 // register, immediate use opx = 81 or 83 addressing modes:
1785 // opx = 81: r/m16/32/64, imm16/32
1786 // opx = 83: r/m16/32/64, imm8
1787 const imm32 = @intCast(i32, imm); // This case must be handled before calling genX8664BinMathCode.
1788 if (imm32 <= math.maxInt(i8)) {
1789 const abi_size = dst_ty.abiSize(self.target.*);
1790 const encoder = try X8664Encoder.init(self.code, 4);
1791 encoder.rex(.{
1792 .w = abi_size == 8,
1793 .b = dst_reg.isExtended(),
15921794 });
1795 encoder.opcode_1byte(0x83);
1796 encoder.modRm_direct(
1797 opx,
1798 dst_reg.low_id(),
1799 );
1800 encoder.imm8(@intCast(i8, imm32));
15931801 } else {
1594 self.rex(.{ .r = dst_reg.isExtended(), .w = dst_reg.size() == 64 });
1595 self.code.appendSliceAssumeCapacity(&[_]u8{
1596 0x81,
1597 0xC0 | (opx << 3) | @truncate(u3, dst_reg.id()),
1802 const abi_size = dst_ty.abiSize(self.target.*);
1803 const encoder = try X8664Encoder.init(self.code, 7);
1804 encoder.rex(.{
1805 .w = abi_size == 8,
1806 .b = dst_reg.isExtended(),
15981807 });
1599 std.mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), imm32);
1808 encoder.opcode_1byte(0x81);
1809 encoder.modRm_direct(
1810 opx,
1811 dst_reg.low_id(),
1812 );
1813 encoder.imm32(@intCast(i32, imm32));
16001814 }
16011815 },
1602 .embedded_in_code, .memory, .stack_offset => {
1816 .embedded_in_code, .memory => {
16031817 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source memory", .{});
16041818 },
1819 .stack_offset => |off| {
1820 // register, indirect use mr + 3
1821 // addressing mode: *r16/32/64*, r/m16/32/64
1822 const abi_size = dst_ty.abiSize(self.target.*);
1823 const adj_off = off + abi_size;
1824 if (off > math.maxInt(i32)) {
1825 return self.fail(src, "stack offset too large", .{});
1826 }
1827 const encoder = try X8664Encoder.init(self.code, 7);
1828 encoder.rex(.{
1829 .w = abi_size == 8,
1830 .r = dst_reg.isExtended(),
1831 });
1832 encoder.opcode_1byte(mr + 3);
1833 if (adj_off <= std.math.maxInt(i8)) {
1834 encoder.modRm_indirectDisp8(
1835 dst_reg.low_id(),
1836 Register.ebp.low_id(),
1837 );
1838 encoder.disp8(-@intCast(i8, adj_off));
1839 } else {
1840 encoder.modRm_indirectDisp32(
1841 dst_reg.low_id(),
1842 Register.ebp.low_id(),
1843 );
1844 encoder.disp32(-@intCast(i32, adj_off));
1845 }
1846 },
16051847 .compare_flags_unsigned => {
16061848 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
16071849 },
......@@ -1640,27 +1882,183 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16401882 }
16411883 }
16421884
1885 /// Performs integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv.
1886 fn genX8664Imul(
1887 self: *Self,
1888 src: LazySrcLoc,
1889 dst_ty: Type,
1890 dst_mcv: MCValue,
1891 src_mcv: MCValue,
1892 ) !void {
1893 switch (dst_mcv) {
1894 .none => unreachable,
1895 .undef => unreachable,
1896 .dead, .unreach, .immediate => unreachable,
1897 .compare_flags_unsigned => unreachable,
1898 .compare_flags_signed => unreachable,
1899 .ptr_stack_offset => unreachable,
1900 .ptr_embedded_in_code => unreachable,
1901 .register => |dst_reg| {
1902 switch (src_mcv) {
1903 .none => unreachable,
1904 .undef => try self.genSetReg(src, dst_ty, dst_reg, .undef),
1905 .dead, .unreach => unreachable,
1906 .ptr_stack_offset => unreachable,
1907 .ptr_embedded_in_code => unreachable,
1908 .register => |src_reg| {
1909 // register, register
1910 //
1911 // Use the following imul opcode
1912 // 0F AF /r: IMUL r32/64, r/m32/64
1913 const abi_size = dst_ty.abiSize(self.target.*);
1914 const encoder = try X8664Encoder.init(self.code, 4);
1915 encoder.rex(.{
1916 .w = abi_size == 8,
1917 .r = dst_reg.isExtended(),
1918 .b = src_reg.isExtended(),
1919 });
1920 encoder.opcode_2byte(0x0f, 0xaf);
1921 encoder.modRm_direct(
1922 dst_reg.low_id(),
1923 src_reg.low_id(),
1924 );
1925 },
1926 .immediate => |imm| {
1927 // register, immediate:
1928 // depends on size of immediate.
1929 //
1930 // immediate fits in i8:
1931 // 6B /r ib: IMUL r32/64, r/m32/64, imm8
1932 //
1933 // immediate fits in i32:
1934 // 69 /r id: IMUL r32/64, r/m32/64, imm32
1935 //
1936 // immediate is huge:
1937 // split into 2 instructions
1938 // 1) copy the 64 bit immediate into a tmp register
1939 // 2) perform register,register mul
1940 // 0F AF /r: IMUL r32/64, r/m32/64
1941 if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {
1942 const abi_size = dst_ty.abiSize(self.target.*);
1943 const encoder = try X8664Encoder.init(self.code, 4);
1944 encoder.rex(.{
1945 .w = abi_size == 8,
1946 .r = dst_reg.isExtended(),
1947 .b = dst_reg.isExtended(),
1948 });
1949 encoder.opcode_1byte(0x6B);
1950 encoder.modRm_direct(
1951 dst_reg.low_id(),
1952 dst_reg.low_id(),
1953 );
1954 encoder.imm8(@intCast(i8, imm));
1955 } else if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
1956 const abi_size = dst_ty.abiSize(self.target.*);
1957 const encoder = try X8664Encoder.init(self.code, 7);
1958 encoder.rex(.{
1959 .w = abi_size == 8,
1960 .r = dst_reg.isExtended(),
1961 .b = dst_reg.isExtended(),
1962 });
1963 encoder.opcode_1byte(0x69);
1964 encoder.modRm_direct(
1965 dst_reg.low_id(),
1966 dst_reg.low_id(),
1967 );
1968 encoder.imm32(@intCast(i32, imm));
1969 } else {
1970 const src_reg = try self.copyToTmpRegister(src, dst_ty, src_mcv);
1971 return self.genX8664Imul(src, dst_ty, dst_mcv, MCValue{ .register = src_reg });
1972 }
1973 },
1974 .embedded_in_code, .memory, .stack_offset => {
1975 return self.fail(src, "TODO implement x86 multiply source memory", .{});
1976 },
1977 .compare_flags_unsigned => {
1978 return self.fail(src, "TODO implement x86 multiply source compare flag (unsigned)", .{});
1979 },
1980 .compare_flags_signed => {
1981 return self.fail(src, "TODO implement x86 multiply source compare flag (signed)", .{});
1982 },
1983 }
1984 },
1985 .stack_offset => |off| {
1986 switch (src_mcv) {
1987 .none => unreachable,
1988 .undef => return self.genSetStack(src, dst_ty, off, .undef),
1989 .dead, .unreach => unreachable,
1990 .ptr_stack_offset => unreachable,
1991 .ptr_embedded_in_code => unreachable,
1992 .register => |src_reg| {
1993 // copy dst to a register
1994 const dst_reg = try self.copyToTmpRegister(src, dst_ty, dst_mcv);
1995 // multiply into dst_reg
1996 // register, register
1997 // Use the following imul opcode
1998 // 0F AF /r: IMUL r32/64, r/m32/64
1999 const abi_size = dst_ty.abiSize(self.target.*);
2000 const encoder = try X8664Encoder.init(self.code, 4);
2001 encoder.rex(.{
2002 .w = abi_size == 8,
2003 .r = dst_reg.isExtended(),
2004 .b = src_reg.isExtended(),
2005 });
2006 encoder.opcode_2byte(0x0f, 0xaf);
2007 encoder.modRm_direct(
2008 dst_reg.low_id(),
2009 src_reg.low_id(),
2010 );
2011 // copy dst_reg back out
2012 return self.genSetStack(src, dst_ty, off, MCValue{ .register = dst_reg });
2013 },
2014 .immediate => |imm| {
2015 return self.fail(src, "TODO implement x86 multiply source immediate", .{});
2016 },
2017 .embedded_in_code, .memory, .stack_offset => {
2018 return self.fail(src, "TODO implement x86 multiply source memory", .{});
2019 },
2020 .compare_flags_unsigned => {
2021 return self.fail(src, "TODO implement x86 multiply source compare flag (unsigned)", .{});
2022 },
2023 .compare_flags_signed => {
2024 return self.fail(src, "TODO implement x86 multiply source compare flag (signed)", .{});
2025 },
2026 }
2027 },
2028 .embedded_in_code, .memory => {
2029 return self.fail(src, "TODO implement x86 multiply destination memory", .{});
2030 },
2031 }
2032 }
2033
16432034 fn genX8664ModRMRegToStack(self: *Self, src: LazySrcLoc, ty: Type, off: u32, reg: Register, opcode: u8) !void {
16442035 const abi_size = ty.abiSize(self.target.*);
16452036 const adj_off = off + abi_size;
1646 try self.code.ensureCapacity(self.code.items.len + 7);
1647 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended() });
1648 const reg_id: u8 = @truncate(u3, reg.id());
1649 if (adj_off <= 128) {
2037 if (off > math.maxInt(i32)) {
2038 return self.fail(src, "stack offset too large", .{});
2039 }
2040
2041 const i_adj_off = -@intCast(i32, adj_off);
2042 const encoder = try X8664Encoder.init(self.code, 7);
2043 encoder.rex(.{
2044 .w = abi_size == 8,
2045 .r = reg.isExtended(),
2046 });
2047 encoder.opcode_1byte(opcode);
2048 if (i_adj_off < std.math.maxInt(i8)) {
16502049 // example: 48 89 55 7f mov QWORD PTR [rbp+0x7f],rdx
1651 const RM = @as(u8, 0b01_000_101) | (reg_id << 3);
1652 const negative_offset = @intCast(i8, -@intCast(i32, adj_off));
1653 const twos_comp = @bitCast(u8, negative_offset);
1654 self.code.appendSliceAssumeCapacity(&[_]u8{ opcode, RM, twos_comp });
1655 } else if (adj_off <= 2147483648) {
1656 // example: 48 89 95 80 00 00 00 mov QWORD PTR [rbp+0x80],rdx
1657 const RM = @as(u8, 0b10_000_101) | (reg_id << 3);
1658 const negative_offset = @intCast(i32, -@intCast(i33, adj_off));
1659 const twos_comp = @bitCast(u32, negative_offset);
1660 self.code.appendSliceAssumeCapacity(&[_]u8{ opcode, RM });
1661 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), twos_comp);
2050 encoder.modRm_indirectDisp8(
2051 reg.low_id(),
2052 Register.ebp.low_id(),
2053 );
2054 encoder.disp8(@intCast(i8, i_adj_off));
16622055 } else {
1663 return self.fail(src, "stack offset too large", .{});
2056 // example: 48 89 95 80 00 00 00 mov QWORD PTR [rbp+0x80],rdx
2057 encoder.modRm_indirectDisp32(
2058 reg.low_id(),
2059 Register.ebp.low_id(),
2060 );
2061 encoder.disp32(i_adj_off);
16642062 }
16652063 }
16662064
......@@ -2106,12 +2504,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21062504 log.debug("got_addr = 0x{x}", .{got_addr});
21072505 switch (arch) {
21082506 .x86_64 => {
2109 try self.genSetReg(inst.base.src, Type.initTag(.u32), .rax, .{ .memory = got_addr });
2507 try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .memory = got_addr });
21102508 // callq *%rax
2509 try self.code.ensureCapacity(self.code.items.len + 2);
21112510 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
21122511 },
21132512 .aarch64 => {
2114 try self.genSetReg(inst.base.src, Type.initTag(.u32), .x30, .{ .memory = got_addr });
2513 try self.genSetReg(inst.base.src, Type.initTag(.u64), .x30, .{ .memory = got_addr });
21152514 // blr x30
21162515 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
21172516 },
......@@ -2276,10 +2675,42 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22762675 const lhs = try self.resolveInst(inst.lhs);
22772676 const rhs = try self.resolveInst(inst.rhs);
22782677
2279 const src_mcv = rhs;
2280 const dst_mcv = if (lhs != .register) try self.copyToNewRegister(inst.lhs, lhs) else lhs;
2678 const lhs_is_register = lhs == .register;
2679 const rhs_is_register = rhs == .register;
2680 // lhs should always be a register
2681 const rhs_should_be_register = try self.armOperandShouldBeRegister(inst.rhs.src, rhs);
2682
2683 var lhs_mcv = lhs;
2684 var rhs_mcv = rhs;
2685
2686 // Allocate registers
2687 if (rhs_should_be_register) {
2688 if (!lhs_is_register and !rhs_is_register) {
2689 const regs = try self.register_manager.allocRegs(2, .{ inst.rhs, inst.lhs }, &.{});
2690 lhs_mcv = MCValue{ .register = regs[0] };
2691 rhs_mcv = MCValue{ .register = regs[1] };
2692 } else if (!rhs_is_register) {
2693 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(inst.rhs, &.{}) };
2694 }
2695 }
2696 if (!lhs_is_register) {
2697 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(inst.lhs, &.{}) };
2698 }
2699
2700 // Move the operands to the newly allocated registers
2701 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2702 if (lhs_mcv == .register and !lhs_is_register) {
2703 try self.genSetReg(inst.lhs.src, inst.lhs.ty, lhs_mcv.register, lhs);
2704 branch.inst_table.putAssumeCapacity(inst.lhs, lhs);
2705 }
2706 if (rhs_mcv == .register and !rhs_is_register) {
2707 try self.genSetReg(inst.rhs.src, inst.rhs.ty, rhs_mcv.register, rhs);
2708 branch.inst_table.putAssumeCapacity(inst.rhs, rhs);
2709 }
2710
2711 // The destination register is not present in the cmp instruction
2712 try self.genArmBinOpCode(inst.base.src, undefined, lhs_mcv, rhs_mcv, false, .cmp_eq);
22812713
2282 try self.genArmBinOpCode(inst.base.src, dst_mcv.register, dst_mcv, src_mcv, .cmp_eq);
22832714 const info = inst.lhs.ty.intInfo(self.target.*);
22842715 return switch (info.signedness) {
22852716 .signed => MCValue{ .compare_flags_signed = op },
......@@ -2335,15 +2766,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
23352766 .register => |reg| blk: {
23362767 // test reg, 1
23372768 // TODO detect al, ax, eax
2338 try self.code.ensureCapacity(self.code.items.len + 4);
2339 // TODO audit this codegen: we force w = true here to make
2340 // the value affect the big register
2341 self.rex(.{ .b = reg.isExtended(), .w = true });
2342 self.code.appendSliceAssumeCapacity(&[_]u8{
2343 0xf6,
2344 @as(u8, 0xC0) | (0 << 3) | @truncate(u3, reg.id()),
2345 0x01,
2769 const encoder = try X8664Encoder.init(self.code, 4);
2770 encoder.rex(.{
2771 // TODO audit this codegen: we force w = true here to make
2772 // the value affect the big register
2773 .w = true,
2774 .b = reg.isExtended(),
23462775 });
2776 encoder.opcode_1byte(0xf6);
2777 encoder.modRm_direct(
2778 0,
2779 reg.low_id(),
2780 );
2781 encoder.disp8(1);
23472782 break :blk 0x84;
23482783 },
23492784 else => return self.fail(inst.base.src, "TODO implement condbr {s} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
......@@ -2653,9 +3088,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26533088 switch (arch) {
26543089 .x86_64 => switch (inst.base.tag) {
26553090 // lhs AND rhs
2656 .bool_and => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 4, 0x20),
3091 .bool_and => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
26573092 // lhs OR rhs
2658 .bool_or => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 1, 0x08),
3093 .bool_or => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
26593094 else => unreachable, // Not a boolean operation
26603095 },
26613096 .arm, .armeb => switch (inst.base.tag) {
......@@ -2862,39 +3297,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
28623297 }
28633298 }
28643299
2865 /// Encodes a REX prefix as specified, and appends it to the instruction
2866 /// stream. This only modifies the instruction stream if at least one bit
2867 /// is set true, which has a few implications:
2868 ///
2869 /// * The length of the instruction buffer will be modified *if* the
2870 /// resulting REX is meaningful, but will remain the same if it is not.
2871 /// * Deliberately inserting a "meaningless REX" requires explicit usage of
2872 /// 0x40, and cannot be done via this function.
2873 /// W => 64 bit mode
2874 /// R => extension to the MODRM.reg field
2875 /// X => extension to the SIB.index field
2876 /// B => extension to the MODRM.rm field or the SIB.base field
2877 fn rex(self: *Self, arg: struct { b: bool = false, w: bool = false, x: bool = false, r: bool = false }) void {
2878 comptime assert(arch == .x86_64);
2879 // From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB.
2880 var value: u8 = 0x40;
2881 if (arg.b) {
2882 value |= 0x1;
2883 }
2884 if (arg.x) {
2885 value |= 0x2;
2886 }
2887 if (arg.r) {
2888 value |= 0x4;
2889 }
2890 if (arg.w) {
2891 value |= 0x8;
2892 }
2893 if (value != 0x40) {
2894 self.code.appendAssumeCapacity(value);
2895 }
2896 }
2897
28983300 /// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
28993301 fn setRegOrMem(self: *Self, src: LazySrcLoc, ty: Type, loc: MCValue, val: MCValue) !void {
29003302 switch (loc) {
......@@ -3442,20 +3844,25 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
34423844 }
34433845 },
34443846 .compare_flags_unsigned => |op| {
3445 try self.code.ensureCapacity(self.code.items.len + 3);
3847 const encoder = try X8664Encoder.init(self.code, 7);
34463848 // TODO audit this codegen: we force w = true here to make
34473849 // the value affect the big register
3448 self.rex(.{ .b = reg.isExtended(), .w = true });
3449 const opcode: u8 = switch (op) {
3850 encoder.rex(.{
3851 .w = true,
3852 .b = reg.isExtended(),
3853 });
3854 encoder.opcode_2byte(0x0f, switch (op) {
34503855 .gte => 0x93,
34513856 .gt => 0x97,
34523857 .neq => 0x95,
34533858 .lt => 0x92,
34543859 .lte => 0x96,
34553860 .eq => 0x94,
3456 };
3457 const id = @as(u8, reg.id() & 0b111);
3458 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x0f, opcode, 0xC0 | id });
3861 });
3862 encoder.modRm_direct(
3863 0,
3864 reg.low_id(),
3865 );
34593866 },
34603867 .compare_flags_signed => |op| {
34613868 return self.fail(src, "TODO set register with compare flags value (signed)", .{});
......@@ -3465,40 +3872,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
34653872 // register is the fastest way to zero a register.
34663873 if (x == 0) {
34673874 // The encoding for `xor r32, r32` is `0x31 /r`.
3468 // Section 3.1.1.1 of the Intel x64 Manual states that "/r indicates that the
3469 // ModR/M byte of the instruction contains a register operand and an r/m operand."
3470 //
3471 // R/M bytes are composed of two bits for the mode, then three bits for the register,
3472 // then three bits for the operand. Since we're zeroing a register, the two three-bit
3473 // values will be identical, and the mode is three (the raw register value).
3474 //
3875 const encoder = try X8664Encoder.init(self.code, 3);
3876
34753877 // If we're accessing e.g. r8d, we need to use a REX prefix before the actual operation. Since
34763878 // this is a 32-bit operation, the W flag is set to zero. X is also zero, as we're not using a SIB.
34773879 // Both R and B are set, as we're extending, in effect, the register bits *and* the operand.
3478 try self.code.ensureCapacity(self.code.items.len + 3);
3479 self.rex(.{ .r = reg.isExtended(), .b = reg.isExtended() });
3480 const id = @as(u8, reg.id() & 0b111);
3481 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x31, 0xC0 | id << 3 | id });
3880 encoder.rex(.{
3881 .r = reg.isExtended(),
3882 .b = reg.isExtended(),
3883 });
3884 encoder.opcode_1byte(0x31);
3885 // Section 3.1.1.1 of the Intel x64 Manual states that "/r indicates that the
3886 // ModR/M byte of the instruction contains a register operand and an r/m operand."
3887 encoder.modRm_direct(
3888 reg.low_id(),
3889 reg.low_id(),
3890 );
3891
34823892 return;
34833893 }
3484 if (x <= math.maxInt(u32)) {
3894 if (x <= math.maxInt(i32)) {
34853895 // Next best case: if we set the lower four bytes, the upper four will be zeroed.
34863896 //
34873897 // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM.
3488 if (reg.isExtended()) {
3489 // Just as with XORing, we need a REX prefix. This time though, we only
3490 // need the B bit set, as we're extending the opcode's register field,
3491 // and there is no Mod R/M byte.
3492 //
3493 // Thus, we need b01000001, or 0x41.
3494 try self.code.resize(self.code.items.len + 6);
3495 self.code.items[self.code.items.len - 6] = 0x41;
3496 } else {
3497 try self.code.resize(self.code.items.len + 5);
3498 }
3499 self.code.items[self.code.items.len - 5] = 0xB8 | @as(u8, reg.id() & 0b111);
3500 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
3501 mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x));
3898
3899 const encoder = try X8664Encoder.init(self.code, 6);
3900 // Just as with XORing, we need a REX prefix. This time though, we only
3901 // need the B bit set, as we're extending the opcode's register field,
3902 // and there is no Mod R/M byte.
3903 encoder.rex(.{
3904 .b = reg.isExtended(),
3905 });
3906 encoder.opcode_withReg(0xB8, reg.low_id());
3907
3908 // no ModR/M byte
3909
3910 // IMM
3911 encoder.imm32(@intCast(i32, x));
35023912 return;
35033913 }
35043914 // Worst case: we need to load the 64-bit register with the IMM. GNU's assemblers calls
......@@ -3508,79 +3918,98 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
35083918 // This encoding is, in fact, the *same* as the one used for 32-bit loads. The only
35093919 // difference is that we set REX.W before the instruction, which extends the load to
35103920 // 64-bit and uses the full bit-width of the register.
3511 //
3512 // Since we always need a REX here, let's just check if we also need to set REX.B.
3513 //
3514 // In this case, the encoding of the REX byte is 0b0100100B
3515 try self.code.ensureCapacity(self.code.items.len + 10);
3516 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended() });
3517 self.code.items.len += 9;
3518 self.code.items[self.code.items.len - 9] = 0xB8 | @as(u8, reg.id() & 0b111);
3519 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];
3520 mem.writeIntLittle(u64, imm_ptr, x);
3921 {
3922 const encoder = try X8664Encoder.init(self.code, 10);
3923 encoder.rex(.{
3924 .w = true,
3925 .b = reg.isExtended(),
3926 });
3927 encoder.opcode_withReg(0xB8, reg.low_id());
3928 encoder.imm64(x);
3929 }
35213930 },
35223931 .embedded_in_code => |code_offset| {
35233932 // We need the offset from RIP in a signed i32 twos complement.
35243933 // The instruction is 7 bytes long and RIP points to the next instruction.
3525 try self.code.ensureCapacity(self.code.items.len + 7);
3526 // 64-bit LEA is encoded as REX.W 8D /r. If the register is extended, the REX byte is modified,
3527 // but the operation size is unchanged. Since we're using a disp32, we want mode 0 and lower three
3528 // bits as five.
3529 // REX 0x8D 0b00RRR101, where RRR is the lower three bits of the id.
3530 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended() });
3531 self.code.items.len += 6;
3532 const rip = self.code.items.len;
3934
3935 // 64-bit LEA is encoded as REX.W 8D /r.
3936 const rip = self.code.items.len + 7;
35333937 const big_offset = @intCast(i64, code_offset) - @intCast(i64, rip);
35343938 const offset = @intCast(i32, big_offset);
3535 self.code.items[self.code.items.len - 6] = 0x8D;
3536 self.code.items[self.code.items.len - 5] = 0b101 | (@as(u8, reg.id() & 0b111) << 3);
3537 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
3538 mem.writeIntLittle(i32, imm_ptr, offset);
3939 const encoder = try X8664Encoder.init(self.code, 7);
3940
3941 // byte 1, always exists because w = true
3942 encoder.rex(.{
3943 .w = true,
3944 .r = reg.isExtended(),
3945 });
3946 // byte 2
3947 encoder.opcode_1byte(0x8D);
3948 // byte 3
3949 encoder.modRm_RIPDisp32(reg.low_id());
3950 // byte 4-7
3951 encoder.disp32(offset);
3952
3953 // Double check that we haven't done any math errors
3954 assert(rip == self.code.items.len);
35393955 },
35403956 .register => |src_reg| {
35413957 // If the registers are the same, nothing to do.
35423958 if (src_reg.id() == reg.id())
35433959 return;
35443960
3545 // This is a variant of 8B /r. Since we're using 64-bit moves, we require a REX.
3546 // This is thus three bytes: REX 0x8B R/M.
3547 // If the destination is extended, the R field must be 1.
3548 // If the *source* is extended, the B field must be 1.
3549 // Since the register is being accessed directly, the R/M mode is three. The reg field (the middle
3550 // three bits) contain the destination, and the R/M field (the lower three bits) contain the source.
3551 try self.code.ensureCapacity(self.code.items.len + 3);
3552 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended(), .b = src_reg.isExtended() });
3553 const R = 0xC0 | (@as(u8, reg.id() & 0b111) << 3) | @as(u8, src_reg.id() & 0b111);
3554 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, R });
3961 // This is a variant of 8B /r.
3962 const abi_size = ty.abiSize(self.target.*);
3963 const encoder = try X8664Encoder.init(self.code, 3);
3964 encoder.rex(.{
3965 .w = abi_size == 8,
3966 .r = reg.isExtended(),
3967 .b = src_reg.isExtended(),
3968 });
3969 encoder.opcode_1byte(0x8B);
3970 encoder.modRm_direct(reg.low_id(), src_reg.low_id());
35553971 },
35563972 .memory => |x| {
35573973 if (self.bin_file.options.pie) {
35583974 // RIP-relative displacement to the entry in the GOT table.
3975 const abi_size = ty.abiSize(self.target.*);
3976 const encoder = try X8664Encoder.init(self.code, 10);
3977
3978 // LEA reg, [<offset>]
3979
3980 // We encode the instruction FIRST because prefixes may or may not appear.
3981 // After we encode the instruction, we will know that the displacement bytes
3982 // for [<offset>] will be at self.code.items.len - 4.
3983 encoder.rex(.{
3984 .w = true, // force 64 bit because loading an address (to the GOT)
3985 .r = reg.isExtended(),
3986 });
3987 encoder.opcode_1byte(0x8D);
3988 encoder.modRm_RIPDisp32(reg.low_id());
3989 encoder.disp32(0);
3990
35593991 // TODO we should come up with our own, backend independent relocation types
35603992 // which each backend (Elf, MachO, etc.) would then translate into an actual
35613993 // fixup when linking.
35623994 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
35633995 try macho_file.pie_fixups.append(self.bin_file.allocator, .{
35643996 .target_addr = x,
3565 .offset = self.code.items.len + 3,
3997 .offset = self.code.items.len - 4,
35663998 .size = 4,
35673999 });
35684000 } else {
35694001 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
35704002 }
3571 try self.code.ensureCapacity(self.code.items.len + 7);
3572 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended() });
3573 self.code.appendSliceAssumeCapacity(&[_]u8{
3574 0x8D,
3575 0x05 | (@as(u8, reg.id() & 0b111) << 3),
3576 });
3577 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), 0);
35784003
3579 try self.code.ensureCapacity(self.code.items.len + 3);
3580 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended(), .r = reg.isExtended() });
3581 const RM = (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, reg.id());
3582 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, RM });
3583 } else if (x <= math.maxInt(u32)) {
4004 // MOV reg, [reg]
4005 encoder.rex(.{
4006 .w = abi_size == 8,
4007 .r = reg.isExtended(),
4008 .b = reg.isExtended(),
4009 });
4010 encoder.opcode_1byte(0x8B);
4011 encoder.modRm_indirectDisp0(reg.low_id(), reg.low_id());
4012 } else if (x <= math.maxInt(i32)) {
35844013 // Moving from memory to a register is a variant of `8B /r`.
35854014 // Since we're using 64-bit moves, we require a REX.
35864015 // This variant also requires a SIB, as it would otherwise be RIP-relative.
......@@ -3588,14 +4017,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
35884017 // The SIB must be 0x25, to indicate a disp32 with no scaled index.
35894018 // 0b00RRR100, where RRR is the lower three bits of the register ID.
35904019 // The instruction is thus eight bytes; REX 0x8B 0b00RRR100 0x25 followed by a four-byte disp32.
3591 try self.code.ensureCapacity(self.code.items.len + 8);
3592 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended() });
3593 self.code.appendSliceAssumeCapacity(&[_]u8{
3594 0x8B,
3595 0x04 | (@as(u8, reg.id() & 0b111) << 3), // R
3596 0x25,
4020 const abi_size = ty.abiSize(self.target.*);
4021 const encoder = try X8664Encoder.init(self.code, 8);
4022 encoder.rex(.{
4023 .w = abi_size == 8,
4024 .r = reg.isExtended(),
35974025 });
3598 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), @intCast(u32, x));
4026 encoder.opcode_1byte(0x8B);
4027 // effective address = [SIB]
4028 encoder.modRm_SIBDisp0(reg.low_id());
4029 // SIB = disp32
4030 encoder.sib_disp32();
4031 encoder.disp32(@intCast(i32, x));
35994032 } else {
36004033 // If this is RAX, we can use a direct load; otherwise, we need to load the address, then indirectly load
36014034 // the value.
......@@ -3603,12 +4036,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
36034036 // REX.W 0xA1 moffs64*
36044037 // moffs64* is a 64-bit offset "relative to segment base", which really just means the
36054038 // absolute address for all practical purposes.
3606 try self.code.resize(self.code.items.len + 10);
3607 // REX.W == 0x48
3608 self.code.items[self.code.items.len - 10] = 0x48;
3609 self.code.items[self.code.items.len - 9] = 0xA1;
3610 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];
3611 mem.writeIntLittle(u64, imm_ptr, x);
4039
4040 const encoder = try X8664Encoder.init(self.code, 10);
4041 encoder.rex(.{
4042 .w = true,
4043 });
4044 encoder.opcode_1byte(0xA1);
4045 encoder.writeIntLittle(u64, x);
36124046 } else {
36134047 // This requires two instructions; a move imm as used above, followed by an indirect load using the register
36144048 // as the address and the register as the destination.
......@@ -3625,40 +4059,41 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
36254059 // Now, the register contains the address of the value to load into it
36264060 // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant.
36274061 // TODO: determine whether to allow other sized registers, and if so, handle them properly.
3628 // This operation requires three bytes: REX 0x8B R/M
3629 try self.code.ensureCapacity(self.code.items.len + 3);
3630 // For this operation, we want R/M mode *zero* (use register indirectly), and the two register
3631 // values must match. Thus, it's 00ABCABC where ABC is the lower three bits of the register ID.
3632 //
3633 // Furthermore, if this is an extended register, both B and R must be set in the REX byte, as *both*
3634 // register operands need to be marked as extended.
3635 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended(), .r = reg.isExtended() });
3636 const RM = (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, reg.id());
3637 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, RM });
4062
4063 // mov reg, [reg]
4064 const abi_size = ty.abiSize(self.target.*);
4065 const encoder = try X8664Encoder.init(self.code, 3);
4066 encoder.rex(.{
4067 .w = abi_size == 8,
4068 .r = reg.isExtended(),
4069 .b = reg.isExtended(),
4070 });
4071 encoder.opcode_1byte(0x8B);
4072 encoder.modRm_indirectDisp0(reg.low_id(), reg.low_id());
36384073 }
36394074 }
36404075 },
36414076 .stack_offset => |unadjusted_off| {
3642 try self.code.ensureCapacity(self.code.items.len + 7);
3643 const size_bytes = @divExact(reg.size(), 8);
3644 const off = unadjusted_off + size_bytes;
3645 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended() });
3646 const reg_id: u8 = @truncate(u3, reg.id());
3647 if (off <= 128) {
4077 const abi_size = ty.abiSize(self.target.*);
4078 const off = unadjusted_off + abi_size;
4079 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
4080 return self.fail(src, "stack offset too large", .{});
4081 }
4082 const ioff = -@intCast(i32, off);
4083 const encoder = try X8664Encoder.init(self.code, 3);
4084 encoder.rex(.{
4085 .w = abi_size == 8,
4086 .r = reg.isExtended(),
4087 });
4088 encoder.opcode_1byte(0x8B);
4089 if (std.math.minInt(i8) <= ioff and ioff <= std.math.maxInt(i8)) {
36484090 // Example: 48 8b 4d 7f mov rcx,QWORD PTR [rbp+0x7f]
3649 const RM = @as(u8, 0b01_000_101) | (reg_id << 3);
3650 const negative_offset = @intCast(i8, -@intCast(i32, off));
3651 const twos_comp = @bitCast(u8, negative_offset);
3652 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8b, RM, twos_comp });
3653 } else if (off <= 2147483648) {
3654 // Example: 48 8b 8d 80 00 00 00 mov rcx,QWORD PTR [rbp+0x80]
3655 const RM = @as(u8, 0b10_000_101) | (reg_id << 3);
3656 const negative_offset = @intCast(i32, -@intCast(i33, off));
3657 const twos_comp = @bitCast(u32, negative_offset);
3658 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8b, RM });
3659 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), twos_comp);
4091 encoder.modRm_indirectDisp8(reg.low_id(), Register.ebp.low_id());
4092 encoder.disp8(@intCast(i8, ioff));
36604093 } else {
3661 return self.fail(src, "stack offset too large", .{});
4094 // Example: 48 8b 8d 80 00 00 00 mov rcx,QWORD PTR [rbp+0x80]
4095 encoder.modRm_indirectDisp32(reg.low_id(), Register.ebp.low_id());
4096 encoder.disp32(ioff);
36624097 }
36634098 },
36644099 },
src/codegen/x86_64.zig+497
......@@ -1,4 +1,9 @@
11const std = @import("std");
2const testing = std.testing;
3const mem = std.mem;
4const assert = std.debug.assert;
5const ArrayList = std.ArrayList;
6const Allocator = std.mem.Allocator;
27const Type = @import("../Type.zig");
38const DW = std.dwarf;
49
......@@ -68,6 +73,11 @@ pub const Register = enum(u8) {
6873 return @truncate(u4, @enumToInt(self));
6974 }
7075
76 /// Like id, but only returns the lower 3 bits.
77 pub fn low_id(self: Register) u3 {
78 return @truncate(u3, @enumToInt(self));
79 }
80
7181 /// Returns the index into `callee_preserved_regs`.
7282 pub fn allocIndex(self: Register) ?u4 {
7383 return switch (self) {
......@@ -136,6 +146,493 @@ pub const callee_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8
136146pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
137147pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
138148
149/// Encoding helper functions for x86_64 instructions
150///
151/// Many of these helpers do very little, but they can help make things
152/// slightly more readable with more descriptive field names / function names.
153///
154/// Some of them also have asserts to ensure that we aren't doing dumb things.
155/// For example, trying to use register 4 (esp) in an indirect modr/m byte is illegal,
156/// you need to encode it with an SIB byte.
157///
158/// Note that ALL of these helper functions will assume capacity,
159/// so ensure that the `code` has sufficient capacity before using them.
160/// The `init` method is the recommended way to ensure capacity.
161pub const Encoder = struct {
162 /// Non-owning reference to the code array
163 code: *ArrayList(u8),
164
165 const Self = @This();
166
167 /// Wrap `code` in Encoder to make it easier to call these helper functions
168 ///
169 /// maximum_inst_size should contain the maximum number of bytes
170 /// that the encoded instruction will take.
171 /// This is because the helper functions will assume capacity
172 /// in order to avoid bounds checking.
173 pub fn init(code: *ArrayList(u8), maximum_inst_size: u8) !Self {
174 try code.ensureCapacity(code.items.len + maximum_inst_size);
175 return Self{ .code = code };
176 }
177
178 /// Directly write a number to the code array with big endianness
179 pub fn writeIntBig(self: Self, comptime T: type, value: T) void {
180 mem.writeIntBig(
181 T,
182 self.code.addManyAsArrayAssumeCapacity(@divExact(@typeInfo(T).Int.bits, 8)),
183 value,
184 );
185 }
186
187 /// Directly write a number to the code array with little endianness
188 pub fn writeIntLittle(self: Self, comptime T: type, value: T) void {
189 mem.writeIntLittle(
190 T,
191 self.code.addManyAsArrayAssumeCapacity(@divExact(@typeInfo(T).Int.bits, 8)),
192 value,
193 );
194 }
195
196 // --------
197 // Prefixes
198 // --------
199
200 pub const LegacyPrefixes = packed struct {
201 /// LOCK
202 prefix_f0: bool = false,
203 /// REPNZ, REPNE, REP, Scalar Double-precision
204 prefix_f2: bool = false,
205 /// REPZ, REPE, REP, Scalar Single-precision
206 prefix_f3: bool = false,
207
208 /// CS segment override or Branch not taken
209 prefix_2e: bool = false,
210 /// DS segment override
211 prefix_36: bool = false,
212 /// ES segment override
213 prefix_26: bool = false,
214 /// FS segment override
215 prefix_64: bool = false,
216 /// GS segment override
217 prefix_65: bool = false,
218
219 /// Branch taken
220 prefix_3e: bool = false,
221
222 /// Operand size override (enables 16 bit operation)
223 prefix_66: bool = false,
224
225 /// Address size override (enables 16 bit address size)
226 prefix_67: bool = false,
227
228 padding: u5 = 0,
229 };
230
231 /// Encodes legacy prefixes
232 pub fn legacyPrefixes(self: Self, prefixes: LegacyPrefixes) void {
233 if (@bitCast(u16, prefixes) != 0) {
234 // Hopefully this path isn't taken very often, so we'll do it the slow way for now
235
236 // LOCK
237 if (prefixes.prefix_f0) self.code.appendAssumeCapacity(0xf0);
238 // REPNZ, REPNE, REP, Scalar Double-precision
239 if (prefixes.prefix_f2) self.code.appendAssumeCapacity(0xf2);
240 // REPZ, REPE, REP, Scalar Single-precision
241 if (prefixes.prefix_f3) self.code.appendAssumeCapacity(0xf3);
242
243 // CS segment override or Branch not taken
244 if (prefixes.prefix_2e) self.code.appendAssumeCapacity(0x2e);
245 // DS segment override
246 if (prefixes.prefix_36) self.code.appendAssumeCapacity(0x36);
247 // ES segment override
248 if (prefixes.prefix_26) self.code.appendAssumeCapacity(0x26);
249 // FS segment override
250 if (prefixes.prefix_64) self.code.appendAssumeCapacity(0x64);
251 // GS segment override
252 if (prefixes.prefix_65) self.code.appendAssumeCapacity(0x65);
253
254 // Branch taken
255 if (prefixes.prefix_3e) self.code.appendAssumeCapacity(0x3e);
256
257 // Operand size override
258 if (prefixes.prefix_66) self.code.appendAssumeCapacity(0x66);
259
260 // Address size override
261 if (prefixes.prefix_67) self.code.appendAssumeCapacity(0x67);
262 }
263 }
264
265 /// Use 16 bit operand size
266 ///
267 /// Note that this flag is overridden by REX.W, if both are present.
268 pub fn prefix16BitMode(self: Self) void {
269 self.code.appendAssumeCapacity(0x66);
270 }
271
272 /// From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB
273 pub const Rex = struct {
274 /// Wide, enables 64-bit operation
275 w: bool = false,
276 /// Extends the reg field in the ModR/M byte
277 r: bool = false,
278 /// Extends the index field in the SIB byte
279 x: bool = false,
280 /// Extends the r/m field in the ModR/M byte,
281 /// or the base field in the SIB byte,
282 /// or the reg field in the Opcode byte
283 b: bool = false,
284 };
285
286 /// Encodes a REX prefix byte given all the fields
287 ///
288 /// Use this byte whenever you need 64 bit operation,
289 /// or one of reg, index, r/m, base, or opcode-reg might be extended.
290 ///
291 /// See struct `Rex` for a description of each field.
292 ///
293 /// Does not add a prefix byte if none of the fields are set!
294 pub fn rex(self: Self, byte: Rex) void {
295 var value: u8 = 0b0100_0000;
296
297 if (byte.w) value |= 0b1000;
298 if (byte.r) value |= 0b0100;
299 if (byte.x) value |= 0b0010;
300 if (byte.b) value |= 0b0001;
301
302 if (value != 0b0100_0000) {
303 self.code.appendAssumeCapacity(value);
304 }
305 }
306
307 // ------
308 // Opcode
309 // ------
310
311 /// Encodes a 1 byte opcode
312 pub fn opcode_1byte(self: Self, opcode: u8) void {
313 self.code.appendAssumeCapacity(opcode);
314 }
315
316 /// Encodes a 2 byte opcode
317 ///
318 /// e.g. IMUL has the opcode 0x0f 0xaf, so you use
319 ///
320 /// encoder.opcode_2byte(0x0f, 0xaf);
321 pub fn opcode_2byte(self: Self, prefix: u8, opcode: u8) void {
322 self.code.appendAssumeCapacity(prefix);
323 self.code.appendAssumeCapacity(opcode);
324 }
325
326 /// Encodes a 1 byte opcode with a reg field
327 ///
328 /// Remember to add a REX prefix byte if reg is extended!
329 pub fn opcode_withReg(self: Self, opcode: u8, reg: u3) void {
330 assert(opcode & 0b111 == 0);
331 self.code.appendAssumeCapacity(opcode | reg);
332 }
333
334 // ------
335 // ModR/M
336 // ------
337
338 /// Construct a ModR/M byte given all the fields
339 ///
340 /// Remember to add a REX prefix byte if reg or rm are extended!
341 pub fn modRm(self: Self, mod: u2, reg_or_opx: u3, rm: u3) void {
342 self.code.appendAssumeCapacity(
343 @as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm,
344 );
345 }
346
347 /// Construct a ModR/M byte using direct r/m addressing
348 /// r/m effective address: r/m
349 ///
350 /// Note reg's effective address is always just reg for the ModR/M byte.
351 /// Remember to add a REX prefix byte if reg or rm are extended!
352 pub fn modRm_direct(self: Self, reg_or_opx: u3, rm: u3) void {
353 self.modRm(0b11, reg_or_opx, rm);
354 }
355
356 /// Construct a ModR/M byte using indirect r/m addressing
357 /// r/m effective address: [r/m]
358 ///
359 /// Note reg's effective address is always just reg for the ModR/M byte.
360 /// Remember to add a REX prefix byte if reg or rm are extended!
361 pub fn modRm_indirectDisp0(self: Self, reg_or_opx: u3, rm: u3) void {
362 assert(rm != 4 and rm != 5);
363 self.modRm(0b00, reg_or_opx, rm);
364 }
365
366 /// Construct a ModR/M byte using indirect SIB addressing
367 /// r/m effective address: [SIB]
368 ///
369 /// Note reg's effective address is always just reg for the ModR/M byte.
370 /// Remember to add a REX prefix byte if reg or rm are extended!
371 pub fn modRm_SIBDisp0(self: Self, reg_or_opx: u3) void {
372 self.modRm(0b00, reg_or_opx, 0b100);
373 }
374
375 /// Construct a ModR/M byte using RIP-relative addressing
376 /// r/m effective address: [RIP + disp32]
377 ///
378 /// Note reg's effective address is always just reg for the ModR/M byte.
379 /// Remember to add a REX prefix byte if reg or rm are extended!
380 pub fn modRm_RIPDisp32(self: Self, reg_or_opx: u3) void {
381 self.modRm(0b00, reg_or_opx, 0b101);
382 }
383
384 /// Construct a ModR/M byte using indirect r/m with a 8bit displacement
385 /// r/m effective address: [r/m + disp8]
386 ///
387 /// Note reg's effective address is always just reg for the ModR/M byte.
388 /// Remember to add a REX prefix byte if reg or rm are extended!
389 pub fn modRm_indirectDisp8(self: Self, reg_or_opx: u3, rm: u3) void {
390 assert(rm != 4);
391 self.modRm(0b01, reg_or_opx, rm);
392 }
393
394 /// Construct a ModR/M byte using indirect SIB with a 8bit displacement
395 /// r/m effective address: [SIB + disp8]
396 ///
397 /// Note reg's effective address is always just reg for the ModR/M byte.
398 /// Remember to add a REX prefix byte if reg or rm are extended!
399 pub fn modRm_SIBDisp8(self: Self, reg_or_opx: u3) void {
400 self.modRm(0b01, reg_or_opx, 0b100);
401 }
402
403 /// Construct a ModR/M byte using indirect r/m with a 32bit displacement
404 /// r/m effective address: [r/m + disp32]
405 ///
406 /// Note reg's effective address is always just reg for the ModR/M byte.
407 /// Remember to add a REX prefix byte if reg or rm are extended!
408 pub fn modRm_indirectDisp32(self: Self, reg_or_opx: u3, rm: u3) void {
409 assert(rm != 4);
410 self.modRm(0b10, reg_or_opx, rm);
411 }
412
413 /// Construct a ModR/M byte using indirect SIB with a 32bit displacement
414 /// r/m effective address: [SIB + disp32]
415 ///
416 /// Note reg's effective address is always just reg for the ModR/M byte.
417 /// Remember to add a REX prefix byte if reg or rm are extended!
418 pub fn modRm_SIBDisp32(self: Self, reg_or_opx: u3) void {
419 self.modRm(0b10, reg_or_opx, 0b100);
420 }
421
422 // ---
423 // SIB
424 // ---
425
426 /// Construct a SIB byte given all the fields
427 ///
428 /// Remember to add a REX prefix byte if index or base are extended!
429 pub fn sib(self: Self, scale: u2, index: u3, base: u3) void {
430 self.code.appendAssumeCapacity(
431 @as(u8, scale) << 6 | @as(u8, index) << 3 | base,
432 );
433 }
434
435 /// Construct a SIB byte with scale * index + base, no frills.
436 /// r/m effective address: [base + scale * index]
437 ///
438 /// Remember to add a REX prefix byte if index or base are extended!
439 pub fn sib_scaleIndexBase(self: Self, scale: u2, index: u3, base: u3) void {
440 assert(base != 5);
441
442 self.sib(scale, index, base);
443 }
444
445 /// Construct a SIB byte with scale * index + disp32
446 /// r/m effective address: [scale * index + disp32]
447 ///
448 /// Remember to add a REX prefix byte if index or base are extended!
449 pub fn sib_scaleIndexDisp32(self: Self, scale: u2, index: u3) void {
450 assert(index != 4);
451
452 // scale is actually ignored
453 // index = 4 means no index
454 // base = 5 means no base, if mod == 0.
455 self.sib(scale, index, 5);
456 }
457
458 /// Construct a SIB byte with just base
459 /// r/m effective address: [base]
460 ///
461 /// Remember to add a REX prefix byte if index or base are extended!
462 pub fn sib_base(self: Self, base: u3) void {
463 assert(base != 5);
464
465 // scale is actually ignored
466 // index = 4 means no index
467 self.sib(0, 4, base);
468 }
469
470 /// Construct a SIB byte with just disp32
471 /// r/m effective address: [disp32]
472 ///
473 /// Remember to add a REX prefix byte if index or base are extended!
474 pub fn sib_disp32(self: Self) void {
475 // scale is actually ignored
476 // index = 4 means no index
477 // base = 5 means no base, if mod == 0.
478 self.sib(0, 4, 5);
479 }
480
481 /// Construct a SIB byte with scale * index + base + disp8
482 /// r/m effective address: [base + scale * index + disp8]
483 ///
484 /// Remember to add a REX prefix byte if index or base are extended!
485 pub fn sib_scaleIndexBaseDisp8(self: Self, scale: u2, index: u3, base: u3) void {
486 self.sib(scale, index, base);
487 }
488
489 /// Construct a SIB byte with base + disp8, no index
490 /// r/m effective address: [base + disp8]
491 ///
492 /// Remember to add a REX prefix byte if index or base are extended!
493 pub fn sib_baseDisp8(self: Self, base: u3) void {
494 // scale is ignored
495 // index = 4 means no index
496 self.sib(0, 4, base);
497 }
498
499 /// Construct a SIB byte with scale * index + base + disp32
500 /// r/m effective address: [base + scale * index + disp32]
501 ///
502 /// Remember to add a REX prefix byte if index or base are extended!
503 pub fn sib_scaleIndexBaseDisp32(self: Self, scale: u2, index: u3, base: u3) void {
504 self.sib(scale, index, base);
505 }
506
507 /// Construct a SIB byte with base + disp32, no index
508 /// r/m effective address: [base + disp32]
509 ///
510 /// Remember to add a REX prefix byte if index or base are extended!
511 pub fn sib_baseDisp32(self: Self, base: u3) void {
512 // scale is ignored
513 // index = 4 means no index
514 self.sib(0, 4, base);
515 }
516
517 // -------------------------
518 // Trivial (no bit fiddling)
519 // -------------------------
520
521 /// Encode an 8 bit immediate
522 ///
523 /// It is sign-extended to 64 bits by the cpu.
524 pub fn imm8(self: Self, imm: i8) void {
525 self.code.appendAssumeCapacity(@bitCast(u8, imm));
526 }
527
528 /// Encode an 8 bit displacement
529 ///
530 /// It is sign-extended to 64 bits by the cpu.
531 pub fn disp8(self: Self, disp: i8) void {
532 self.code.appendAssumeCapacity(@bitCast(u8, disp));
533 }
534
535 /// Encode an 16 bit immediate
536 ///
537 /// It is sign-extended to 64 bits by the cpu.
538 pub fn imm16(self: Self, imm: i16) void {
539 self.writeIntLittle(i16, imm);
540 }
541
542 /// Encode an 32 bit immediate
543 ///
544 /// It is sign-extended to 64 bits by the cpu.
545 pub fn imm32(self: Self, imm: i32) void {
546 self.writeIntLittle(i32, imm);
547 }
548
549 /// Encode an 32 bit displacement
550 ///
551 /// It is sign-extended to 64 bits by the cpu.
552 pub fn disp32(self: Self, disp: i32) void {
553 self.writeIntLittle(i32, disp);
554 }
555
556 /// Encode an 64 bit immediate
557 ///
558 /// It is sign-extended to 64 bits by the cpu.
559 pub fn imm64(self: Self, imm: u64) void {
560 self.writeIntLittle(u64, imm);
561 }
562};
563
564test "x86_64 Encoder helpers" {
565 var code = ArrayList(u8).init(testing.allocator);
566 defer code.deinit();
567
568 // simple integer multiplication
569
570 // imul eax,edi
571 // 0faf c7
572 {
573 try code.resize(0);
574 const encoder = try Encoder.init(&code, 4);
575 encoder.rex(.{
576 .r = Register.eax.isExtended(),
577 .b = Register.edi.isExtended(),
578 });
579 encoder.opcode_2byte(0x0f, 0xaf);
580 encoder.modRm_direct(
581 Register.eax.low_id(),
582 Register.edi.low_id(),
583 );
584
585 try testing.expectEqualSlices(u8, &[_]u8{ 0x0f, 0xaf, 0xc7 }, code.items);
586 }
587
588 // simple mov
589
590 // mov eax,edi
591 // 89 f8
592 {
593 try code.resize(0);
594 const encoder = try Encoder.init(&code, 3);
595 encoder.rex(.{
596 .r = Register.edi.isExtended(),
597 .b = Register.eax.isExtended(),
598 });
599 encoder.opcode_1byte(0x89);
600 encoder.modRm_direct(
601 Register.edi.low_id(),
602 Register.eax.low_id(),
603 );
604
605 try testing.expectEqualSlices(u8, &[_]u8{ 0x89, 0xf8 }, code.items);
606 }
607
608 // signed integer addition of 32-bit sign extended immediate to 64 bit register
609
610 // add rcx, 2147483647
611 //
612 // Using the following opcode: REX.W + 81 /0 id, we expect the following encoding
613 //
614 // 48 : REX.W set for 64 bit operand (*r*cx)
615 // 81 : opcode for "<arithmetic> with immediate"
616 // c1 : id = rcx,
617 // : c1 = 11 <-- mod = 11 indicates r/m is register (rcx)
618 // : 000 <-- opcode_extension = 0 because opcode extension is /0. /0 specifies ADD
619 // : 001 <-- 001 is rcx
620 // ffffff7f : 2147483647
621 {
622 try code.resize(0);
623 const encoder = try Encoder.init(&code, 7);
624 encoder.rex(.{ .w = true }); // use 64 bit operation
625 encoder.opcode_1byte(0x81);
626 encoder.modRm_direct(
627 0,
628 Register.rcx.low_id(),
629 );
630 encoder.imm32(2147483647);
631
632 try testing.expectEqualSlices(u8, &[_]u8{ 0x48, 0x81, 0xc1, 0xff, 0xff, 0xff, 0x7f }, code.items);
633 }
634}
635
139636// TODO add these registers to the enum and populate dwarfLocOp
140637// // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register.
141638// RA = (16, "RA"),
src/glibc.zig+7-5
......@@ -40,10 +40,11 @@ pub const ABI = struct {
4040 }
4141};
4242
43// The order of the elements in this array defines the linking order.
4344pub const libs = [_]Lib{
44 .{ .name = "c", .sover = 6 },
4545 .{ .name = "m", .sover = 6 },
4646 .{ .name = "pthread", .sover = 0 },
47 .{ .name = "c", .sover = 6 },
4748 .{ .name = "dl", .sover = 2 },
4849 .{ .name = "rt", .sover = 1 },
4950 .{ .name = "ld", .sover = 2 },
......@@ -763,16 +764,17 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
763764 .lt => continue,
764765 .gt => {
765766 // TODO Expose via compile error mechanism instead of log.
766 std.log.warn("invalid target glibc version: {}", .{target_version});
767 std.log.err("invalid target glibc version: {}", .{target_version});
767768 return error.InvalidTargetGLibCVersion;
768769 },
769770 }
770 } else blk: {
771 } else {
771772 const latest_index = metadata.all_versions.len - 1;
772 std.log.warn("zig cannot build new glibc version {}; providing instead {}", .{
773 // TODO Expose via compile error mechanism instead of log.
774 std.log.err("zig does not yet provide glibc version {}, the max provided version is {}", .{
773775 target_version, metadata.all_versions[latest_index],
774776 });
775 break :blk latest_index;
777 return error.InvalidTargetGLibCVersion;
776778 };
777779 {
778780 var map_contents = std.ArrayList(u8).init(arena);
src/link/Elf.zig+12-13
......@@ -1648,19 +1648,18 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
16481648 // libc dep
16491649 if (self.base.options.link_libc) {
16501650 if (self.base.options.libc_installation != null) {
1651 if (self.base.options.link_mode == .Static) {
1652 try argv.append("--start-group");
1653 try argv.append("-lc");
1654 try argv.append("-lm");
1655 try argv.append("--end-group");
1656 } else {
1657 try argv.append("-lc");
1658 try argv.append("-lm");
1659 }
1660
1661 if (target.os.tag == .freebsd or target.os.tag == .netbsd or target.os.tag == .openbsd) {
1662 try argv.append("-lpthread");
1663 }
1651 const needs_grouping = self.base.options.link_mode == .Static;
1652 if (needs_grouping) try argv.append("--start-group");
1653 // This matches the order of glibc.libs
1654 try argv.appendSlice(&[_][]const u8{
1655 "-lm",
1656 "-lpthread",
1657 "-lc",
1658 "-ldl",
1659 "-lrt",
1660 "-lutil",
1661 });
1662 if (needs_grouping) try argv.append("--end-group");
16641663 } else if (target.isGnuLibC()) {
16651664 try argv.append(comp.libunwind_static_lib.?.full_object_path);
16661665 for (glibc.libs) |lib| {
src/link/MachO.zig+4-1
......@@ -442,6 +442,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
442442 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
443443 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
444444 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
445 main_cmd.stacksize = self.base.options.stack_size_override orelse 0;
445446 self.load_commands_dirty = true;
446447 }
447448 try self.writeRebaseInfoTable();
......@@ -695,7 +696,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
695696 Compilation.dump_argv(argv.items);
696697 }
697698
698 try zld.link(input_files.items, full_out_path);
699 try zld.link(input_files.items, full_out_path, .{
700 .stack_size = self.base.options.stack_size_override,
701 });
699702
700703 break :outer;
701704 }
src/link/MachO/Zld.zig+15-3
......@@ -29,6 +29,10 @@ page_size: ?u16 = null,
2929file: ?fs.File = null,
3030out_path: ?[]const u8 = null,
3131
32// TODO these args will become obselete once Zld is coalesced with incremental
33// linker.
34stack_size: u64 = 0,
35
3236objects: std.ArrayListUnmanaged(*Object) = .{},
3337archives: std.ArrayListUnmanaged(*Archive) = .{},
3438
......@@ -172,7 +176,11 @@ pub fn closeFiles(self: Zld) void {
172176 if (self.file) |f| f.close();
173177}
174178
175pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
179const LinkArgs = struct {
180 stack_size: ?u64 = null,
181};
182
183pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void {
176184 if (files.len == 0) return error.NoInputFiles;
177185 if (out_path.len == 0) return error.EmptyOutputPath;
178186
......@@ -206,6 +214,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
206214 .read = true,
207215 .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777,
208216 });
217 self.stack_size = args.stack_size orelse 0;
209218
210219 try self.populateMetadata();
211220 try self.parseInputFiles(files);
......@@ -1533,7 +1542,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
15331542 }
15341543 if (rel.target == .section) {
15351544 const source_sect = object.sections.items[rel.target.section];
1536 args.source_sect_addr = source_sect.inner.addr;
1545 args.source_source_sect_addr = sect.inner.addr;
1546 args.source_target_sect_addr = source_sect.inner.addr;
15371547 }
15381548
15391549 rebases: {
......@@ -1588,7 +1598,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
15881598 else => |tt| {
15891599 if (tt == .signed and rel.target == .section) {
15901600 const source_sect = object.sections.items[rel.target.section];
1591 args.source_sect_addr = source_sect.inner.addr;
1601 args.source_source_sect_addr = sect.inner.addr;
1602 args.source_target_sect_addr = source_sect.inner.addr;
15921603 }
15931604 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
15941605 },
......@@ -2202,6 +2213,7 @@ fn setEntryPoint(self: *Zld) !void {
22022213 const entry_sym = sym.cast(Symbol.Regular) orelse unreachable;
22032214 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;
22042215 ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr);
2216 ec.stacksize = self.stack_size;
22052217}
22062218
22072219fn writeRebaseInfoTable(self: *Zld) !void {
src/link/MachO/reloc.zig+7-4
......@@ -29,7 +29,8 @@ pub const Relocation = struct {
2929 source_addr: u64,
3030 target_addr: u64,
3131 subtractor: ?u64 = null,
32 source_sect_addr: ?u64 = null,
32 source_source_sect_addr: ?u64 = null,
33 source_target_sect_addr: ?u64 = null,
3334 };
3435
3536 pub fn resolve(base: *Relocation, args: ResolveArgs) !void {
......@@ -39,8 +40,10 @@ pub const Relocation = struct {
3940 log.debug(" | target address 0x{x}", .{args.target_addr});
4041 if (args.subtractor) |sub|
4142 log.debug(" | subtractor address 0x{x}", .{sub});
42 if (args.source_sect_addr) |addr|
43 log.debug(" | source section address 0x{x}", .{addr});
43 if (args.source_source_sect_addr) |addr|
44 log.debug(" | source source section address 0x{x}", .{addr});
45 if (args.source_target_sect_addr) |addr|
46 log.debug(" | source target section address 0x{x}", .{addr});
4447
4548 return switch (base.@"type") {
4649 .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args),
......@@ -104,7 +107,7 @@ pub const Unsigned = struct {
104107
105108 pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void {
106109 const addend = if (unsigned.base.target == .section)
107 unsigned.addend - @intCast(i64, args.source_sect_addr.?)
110 unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)
108111 else
109112 unsigned.addend;
110113
src/link/MachO/reloc/x86_64.zig+15-18
......@@ -33,16 +33,19 @@ pub const Signed = struct {
3333 pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {
3434 const target_addr = target_addr: {
3535 if (signed.base.target == .section) {
36 const source_target = @intCast(i64, signed.base.offset) + signed.addend + 4 + signed.correction;
37 const source_disp = source_target - @intCast(i64, args.source_sect_addr.?);
36 const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4;
37 const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?);
3838 break :target_addr @intCast(i64, args.target_addr) + source_disp;
3939 }
4040 break :target_addr @intCast(i64, args.target_addr) + signed.addend;
4141 };
42 const displacement = try math.cast(i32, target_addr - @intCast(i64, args.source_addr) - signed.correction - 4);
42 const displacement = try math.cast(
43 i32,
44 target_addr - @intCast(i64, args.source_addr) - signed.correction - 4,
45 );
4346
44 log.debug(" | calculated addend 0x{x}", .{signed.addend});
45 log.debug(" | calculated correction 0x{x}", .{signed.correction});
47 log.debug(" | addend 0x{x}", .{signed.addend});
48 log.debug(" | correction 0x{x}", .{signed.correction});
4649 log.debug(" | displacement 0x{x}", .{displacement});
4750
4851 mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement));
......@@ -172,20 +175,14 @@ pub const Parser = struct {
172175
173176 const offset = @intCast(u32, rel.r_address);
174177 const inst = parser.code[offset..][0..4];
175 const addend = mem.readIntLittle(i32, inst);
176
177 const correction: i4 = correction: {
178 if (is_extern) break :correction 0;
179
180 const corr: i4 = switch (rel_type) {
181 .X86_64_RELOC_SIGNED => 0,
182 .X86_64_RELOC_SIGNED_1 => 1,
183 .X86_64_RELOC_SIGNED_2 => 2,
184 .X86_64_RELOC_SIGNED_4 => 4,
185 else => unreachable,
186 };
187 break :correction corr;
178 const correction: i4 = switch (rel_type) {
179 .X86_64_RELOC_SIGNED => 0,
180 .X86_64_RELOC_SIGNED_1 => 1,
181 .X86_64_RELOC_SIGNED_2 => 2,
182 .X86_64_RELOC_SIGNED_4 => 4,
183 else => unreachable,
188184 };
185 const addend = mem.readIntLittle(i32, inst) + correction;
189186
190187 var signed = try parser.allocator.create(Signed);
191188 errdefer parser.allocator.destroy(signed);
src/main.zig+9-85
......@@ -2302,7 +2302,7 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi
23022302 defer if (enable_cache) man.deinit();
23032303
23042304 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
2305 _ = man.addFile(c_source_file.src_path, null) catch |err| {
2305 man.hashCSource(c_source_file) catch |err| {
23062306 fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
23072307 };
23082308
......@@ -2332,12 +2332,16 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi
23322332 }
23332333
23342334 // Convert to null terminated args.
2335 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);
2336 new_argv_with_sentinel[argv.items.len] = null;
2337 const new_argv = new_argv_with_sentinel[0..argv.items.len :null];
2335 const clang_args_len = argv.items.len + c_source_file.extra_flags.len;
2336 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, clang_args_len + 1);
2337 new_argv_with_sentinel[clang_args_len] = null;
2338 const new_argv = new_argv_with_sentinel[0..clang_args_len :null];
23382339 for (argv.items) |arg, i| {
23392340 new_argv[i] = try arena.dupeZ(u8, arg);
23402341 }
2342 for (c_source_file.extra_flags) |arg, i| {
2343 new_argv[argv.items.len + i] = try arena.dupeZ(u8, arg);
2344 }
23412345
23422346 const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});
23432347 const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);
......@@ -3526,88 +3530,8 @@ test "fds" {
35263530 gimmeMoreOfThoseSweetSweetFileDescriptors();
35273531}
35283532
3529fn detectNativeCpuWithLLVM(
3530 arch: std.Target.Cpu.Arch,
3531 llvm_cpu_name_z: ?[*:0]const u8,
3532 llvm_cpu_features_opt: ?[*:0]const u8,
3533) !std.Target.Cpu {
3534 var result = std.Target.Cpu.baseline(arch);
3535
3536 if (llvm_cpu_name_z) |cpu_name_z| {
3537 const llvm_cpu_name = mem.spanZ(cpu_name_z);
3538
3539 for (arch.allCpuModels()) |model| {
3540 const this_llvm_name = model.llvm_name orelse continue;
3541 if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
3542 // Here we use the non-dependencies-populated set,
3543 // so that subtracting features later in this function
3544 // affect the prepopulated set.
3545 result = std.Target.Cpu{
3546 .arch = arch,
3547 .model = model,
3548 .features = model.features,
3549 };
3550 break;
3551 }
3552 }
3553 }
3554
3555 const all_features = arch.allFeaturesList();
3556
3557 if (llvm_cpu_features_opt) |llvm_cpu_features| {
3558 var it = mem.tokenize(mem.spanZ(llvm_cpu_features), ",");
3559 while (it.next()) |decorated_llvm_feat| {
3560 var op: enum {
3561 add,
3562 sub,
3563 } = undefined;
3564 var llvm_feat: []const u8 = undefined;
3565 if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
3566 op = .add;
3567 llvm_feat = decorated_llvm_feat[1..];
3568 } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
3569 op = .sub;
3570 llvm_feat = decorated_llvm_feat[1..];
3571 } else {
3572 return error.InvalidLlvmCpuFeaturesFormat;
3573 }
3574 for (all_features) |feature, index_usize| {
3575 const this_llvm_name = feature.llvm_name orelse continue;
3576 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
3577 const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize);
3578 switch (op) {
3579 .add => result.features.addFeature(index),
3580 .sub => result.features.removeFeature(index),
3581 }
3582 break;
3583 }
3584 }
3585 }
3586 }
3587
3588 result.features.populateDependencies(all_features);
3589 return result;
3590}
3591
35923533fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !std.zig.system.NativeTargetInfo {
3593 var info = try std.zig.system.NativeTargetInfo.detect(gpa, cross_target);
3594 if (info.cpu_detection_unimplemented) {
3595 const arch = std.Target.current.cpu.arch;
3596
3597 // We want to just use detected_info.target but implementing
3598 // CPU model & feature detection is todo so here we rely on LLVM.
3599 // https://github.com/ziglang/zig/issues/4591
3600 if (!build_options.have_llvm)
3601 fatal("CPU features detection is not yet available for {s} without LLVM extensions", .{@tagName(arch)});
3602
3603 const llvm = @import("codegen/llvm/bindings.zig");
3604 const llvm_cpu_name = llvm.GetHostCPUName();
3605 const llvm_cpu_features = llvm.GetNativeFeatures();
3606 info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
3607 cross_target.updateCpuFeatures(&info.target.cpu.features);
3608 info.target.cpu.arch = cross_target.getCpuArch();
3609 }
3610 return info;
3534 return std.zig.system.NativeTargetInfo.detect(gpa, cross_target);
36113535}
36123536
36133537/// Indicate that we are now terminating with a successful exit code.
src/register_manager.zig+56-27
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const math = std.math;
3const mem = std.mem;
34const assert = std.debug.assert;
45const Allocator = std.mem.Allocator;
56const ir = @import("ir.zig");
......@@ -66,8 +67,13 @@ pub fn RegisterManager(
6667 }
6768
6869 /// Returns `null` if all registers are allocated.
69 pub fn tryAllocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ?[count]Register {
70 if (self.tryAllocRegsWithoutTracking(count)) |regs| {
70 pub fn tryAllocRegs(
71 self: *Self,
72 comptime count: comptime_int,
73 insts: [count]*ir.Inst,
74 exceptions: []Register,
75 ) ?[count]Register {
76 if (self.tryAllocRegsWithoutTracking(count, exceptions)) |regs| {
7177 for (regs) |reg, i| {
7278 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
7379 self.registers[index] = insts[i];
......@@ -81,21 +87,30 @@ pub fn RegisterManager(
8187 }
8288
8389 /// Returns `null` if all registers are allocated.
84 pub fn tryAllocReg(self: *Self, inst: *ir.Inst) ?Register {
85 return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null;
90 pub fn tryAllocReg(self: *Self, inst: *ir.Inst, exceptions: []Register) ?Register {
91 return if (tryAllocRegs(self, 1, .{inst}, exceptions)) |regs| regs[0] else null;
8692 }
8793
88 pub fn allocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ![count]Register {
94 pub fn allocRegs(
95 self: *Self,
96 comptime count: comptime_int,
97 insts: [count]*ir.Inst,
98 exceptions: []Register,
99 ) ![count]Register {
89100 comptime assert(count > 0 and count <= callee_preserved_regs.len);
101 assert(count + exceptions.len <= callee_preserved_regs.len);
90102
91 return self.tryAllocRegs(count, insts) orelse blk: {
103 return self.tryAllocRegs(count, insts, exceptions) orelse blk: {
92104 // We'll take over the first count registers. Spill
93105 // the instructions that were previously there to a
94106 // stack allocations.
95107 var regs: [count]Register = undefined;
96 std.mem.copy(Register, &regs, callee_preserved_regs[0..count]);
108 var i: usize = 0;
109 for (callee_preserved_regs) |reg| {
110 if (i >= count) break;
111 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
112 regs[i] = reg;
97113
98 for (regs) |reg, i| {
99114 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
100115 if (self.isRegFree(reg)) {
101116 self.markRegUsed(reg);
......@@ -104,21 +119,28 @@ pub fn RegisterManager(
104119 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
105120 }
106121 self.registers[index] = insts[i];
122
123 i += 1;
107124 }
108125
109126 break :blk regs;
110127 };
111128 }
112129
113 pub fn allocReg(self: *Self, inst: *ir.Inst) !Register {
114 return (try self.allocRegs(1, .{inst}))[0];
130 pub fn allocReg(self: *Self, inst: *ir.Inst, exceptions: []Register) !Register {
131 return (try self.allocRegs(1, .{inst}, exceptions))[0];
115132 }
116133
117134 /// Does not track the registers.
118135 /// Returns `null` if not enough registers are free.
119 pub fn tryAllocRegsWithoutTracking(self: *Self, comptime count: comptime_int) ?[count]Register {
136 pub fn tryAllocRegsWithoutTracking(
137 self: *Self,
138 comptime count: comptime_int,
139 exceptions: []Register,
140 ) ?[count]Register {
120141 comptime if (callee_preserved_regs.len == 0) return null;
121142 comptime assert(count > 0 and count <= callee_preserved_regs.len);
143 assert(count + exceptions.len <= callee_preserved_regs.len);
122144
123145 const free_registers = @popCount(FreeRegInt, self.free_registers);
124146 if (free_registers < count) return null;
......@@ -127,30 +149,35 @@ pub fn RegisterManager(
127149 var i: usize = 0;
128150 for (callee_preserved_regs) |reg| {
129151 if (i >= count) break;
152 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
130153 if (self.isRegFree(reg)) {
131154 regs[i] = reg;
132155 i += 1;
133156 }
134157 }
135 return regs;
158
159 return if (i < count) null else regs;
136160 }
137161
138162 /// Does not track the register.
139163 /// Returns `null` if all registers are allocated.
140 pub fn tryAllocRegWithoutTracking(self: *Self) ?Register {
141 return if (self.tryAllocRegsWithoutTracking(1)) |regs| regs[0] else null;
164 pub fn tryAllocRegWithoutTracking(self: *Self, exceptions: []Register) ?Register {
165 return if (self.tryAllocRegsWithoutTracking(1, exceptions)) |regs| regs[0] else null;
142166 }
143167
144168 /// Does not track the registers
145 pub fn allocRegsWithoutTracking(self: *Self, comptime count: comptime_int) ![count]Register {
146 return self.tryAllocRegsWithoutTracking(count) orelse blk: {
169 pub fn allocRegsWithoutTracking(self: *Self, comptime count: comptime_int, exceptions: []Register) ![count]Register {
170 return self.tryAllocRegsWithoutTracking(count, exceptions) orelse blk: {
147171 // We'll take over the first count registers. Spill
148172 // the instructions that were previously there to a
149173 // stack allocations.
150174 var regs: [count]Register = undefined;
151 std.mem.copy(Register, &regs, callee_preserved_regs[0..count]);
175 var i: usize = 0;
176 for (callee_preserved_regs) |reg| {
177 if (i >= count) break;
178 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
179 regs[i] = reg;
152180
153 for (regs) |reg, i| {
154181 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
155182 if (!self.isRegFree(reg)) {
156183 const spilled_inst = self.registers[index].?;
......@@ -158,6 +185,8 @@ pub fn RegisterManager(
158185 self.registers[index] = null;
159186 self.markRegFree(reg);
160187 }
188
189 i += 1;
161190 }
162191
163192 break :blk regs;
......@@ -165,8 +194,8 @@ pub fn RegisterManager(
165194 }
166195
167196 /// Does not track the register.
168 pub fn allocRegWithoutTracking(self: *Self) !Register {
169 return (try self.allocRegsWithoutTracking(1))[0];
197 pub fn allocRegWithoutTracking(self: *Self, exceptions: []Register) !Register {
198 return (try self.allocRegsWithoutTracking(1, exceptions))[0];
170199 }
171200
172201 /// Allocates the specified register with the specified
......@@ -270,9 +299,9 @@ test "tryAllocReg: no spilling" {
270299 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
271300 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));
272301
273 try std.testing.expectEqual(@as(?MockRegister, .r2), function.register_manager.tryAllocReg(&mock_instruction));
274 try std.testing.expectEqual(@as(?MockRegister, .r3), function.register_manager.tryAllocReg(&mock_instruction));
275 try std.testing.expectEqual(@as(?MockRegister, null), function.register_manager.tryAllocReg(&mock_instruction));
302 try std.testing.expectEqual(@as(?MockRegister, .r2), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
303 try std.testing.expectEqual(@as(?MockRegister, .r3), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
304 try std.testing.expectEqual(@as(?MockRegister, null), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
276305
277306 try std.testing.expect(function.register_manager.isRegAllocated(.r2));
278307 try std.testing.expect(function.register_manager.isRegAllocated(.r3));
......@@ -301,16 +330,16 @@ test "allocReg: spilling" {
301330 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
302331 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));
303332
304 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction));
305 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction));
333 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
334 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
306335
307336 // Spill a register
308 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction));
337 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
309338 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
310339
311340 // No spilling necessary
312341 function.register_manager.freeReg(.r3);
313 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction));
342 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
314343 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
315344}
316345
src/stage1/all_types.hpp-1
......@@ -718,7 +718,6 @@ struct AstNodeFnProto {
718718 Buf *name;
719719 ZigList<AstNode *> params;
720720 AstNode *return_type;
721 Token *return_anytype_token;
722721 AstNode *fn_def_node;
723722 // populated if this is an extern declaration
724723 Buf *lib_name;
src/stage1/analyze.cpp-13
......@@ -2125,18 +2125,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
21252125 return g->builtin_types.entry_invalid;
21262126 }
21272127
2128 if (fn_proto->return_anytype_token != nullptr) {
2129 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
2130 add_node_error(g, fn_proto->return_type,
2131 buf_sprintf("return type 'anytype' not allowed in function with calling convention '%s'",
2132 calling_convention_name(fn_type_id.cc)));
2133 return g->builtin_types.entry_invalid;
2134 }
2135 add_node_error(g, proto_node,
2136 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
2137 return g->builtin_types.entry_invalid;
2138 }
2139
21402128 ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
21412129 if (type_is_invalid(specified_return_type)) {
21422130 fn_type_id.return_type = g->builtin_types.entry_invalid;
......@@ -10220,4 +10208,3 @@ const char *float_op_to_name(BuiltinFnId op) {
1022010208 zig_unreachable();
1022110209 }
1022210210}
10223
src/stage1/ast_render.cpp+6-10
......@@ -490,17 +490,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
490490 fprintf(ar->f, ")");
491491 }
492492
493 if (node->data.fn_proto.return_anytype_token != nullptr) {
494 fprintf(ar->f, "anytype");
495 } else {
496 AstNode *return_type_node = node->data.fn_proto.return_type;
497 assert(return_type_node != nullptr);
498 fprintf(ar->f, " ");
499 if (node->data.fn_proto.auto_err_set) {
500 fprintf(ar->f, "!");
501 }
502 render_node_grouped(ar, return_type_node);
493 AstNode *return_type_node = node->data.fn_proto.return_type;
494 assert(return_type_node != nullptr);
495 fprintf(ar->f, " ");
496 if (node->data.fn_proto.auto_err_set) {
497 fprintf(ar->f, "!");
503498 }
499 render_node_grouped(ar, return_type_node);
504500 break;
505501 }
506502 case NodeTypeFnDef:
src/stage1/ir.cpp+37-46
......@@ -10104,19 +10104,12 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod
1010410104 }
1010510105
1010610106 IrInstSrc *return_type;
10107 if (node->data.fn_proto.return_anytype_token == nullptr) {
10108 if (node->data.fn_proto.return_type == nullptr) {
10109 return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
10110 } else {
10111 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
10112 if (return_type == irb->codegen->invalid_inst_src)
10113 return irb->codegen->invalid_inst_src;
10114 }
10107 if (node->data.fn_proto.return_type == nullptr) {
10108 return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
1011510109 } else {
10116 add_node_error(irb->codegen, node,
10117 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
10118 return irb->codegen->invalid_inst_src;
10119 //return_type = nullptr;
10110 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
10111 if (return_type == irb->codegen->invalid_inst_src)
10112 return irb->codegen->invalid_inst_src;
1012010113 }
1012110114
1012210115 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, callconv_value, return_type, is_var_args);
......@@ -14978,7 +14971,7 @@ static IrInstGen *ir_analyze_struct_literal_to_array(IrAnalyze *ira, IrInst* sou
1497814971
1497914972 if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown)))
1498014973 return ira->codegen->invalid_inst_gen;
14981
14974
1498214975 size_t array_len = wanted_type->data.array.len;
1498314976 size_t instr_field_count = actual_type->data.structure.src_field_count;
1498414977 assert(array_len == instr_field_count);
......@@ -20953,44 +20946,42 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
2095320946 inst_fn_type_id.alignment = align_bytes;
2095420947 }
2095520948
20956 if (fn_proto_node->data.fn_proto.return_anytype_token == nullptr) {
20957 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
20958 ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node);
20959 if (type_is_invalid(specified_return_type))
20960 return ira->codegen->invalid_inst_gen;
20961
20962 if(!is_valid_return_type(specified_return_type)){
20963 ErrorMsg *msg = ir_add_error(ira, source_instr,
20964 buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name)));
20965 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here"));
20949 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
20950 ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node);
20951 if (type_is_invalid(specified_return_type))
20952 return ira->codegen->invalid_inst_gen;
2096620953
20967 Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name);
20968 if (tld != nullptr) {
20969 add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here"));
20970 }
20971 return ira->codegen->invalid_inst_gen;
20972 }
20954 if(!is_valid_return_type(specified_return_type)){
20955 ErrorMsg *msg = ir_add_error(ira, source_instr,
20956 buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name)));
20957 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here"));
2097320958
20974 if (fn_proto_node->data.fn_proto.auto_err_set) {
20975 ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn);
20976 if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown)))
20977 return ira->codegen->invalid_inst_gen;
20978 inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
20979 } else {
20980 inst_fn_type_id.return_type = specified_return_type;
20959 Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name);
20960 if (tld != nullptr) {
20961 add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here"));
2098120962 }
20963 return ira->codegen->invalid_inst_gen;
20964 }
2098220965
20983 switch (type_requires_comptime(ira->codegen, specified_return_type)) {
20984 case ReqCompTimeYes:
20985 // Throw out our work and call the function as if it were comptime.
20986 return ir_analyze_fn_call(ira, source_instr, fn_entry, fn_type, fn_ref, first_arg_ptr,
20987 first_arg_ptr_src, CallModifierCompileTime, new_stack, new_stack_src, is_async_call_builtin,
20988 args_ptr, args_len, ret_ptr, call_result_loc);
20989 case ReqCompTimeInvalid:
20966 if (fn_proto_node->data.fn_proto.auto_err_set) {
20967 ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn);
20968 if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown)))
2099020969 return ira->codegen->invalid_inst_gen;
20991 case ReqCompTimeNo:
20992 break;
20993 }
20970 inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
20971 } else {
20972 inst_fn_type_id.return_type = specified_return_type;
20973 }
20974
20975 switch (type_requires_comptime(ira->codegen, specified_return_type)) {
20976 case ReqCompTimeYes:
20977 // Throw out our work and call the function as if it were comptime.
20978 return ir_analyze_fn_call(ira, source_instr, fn_entry, fn_type, fn_ref, first_arg_ptr,
20979 first_arg_ptr_src, CallModifierCompileTime, new_stack, new_stack_src, is_async_call_builtin,
20980 args_ptr, args_len, ret_ptr, call_result_loc);
20981 case ReqCompTimeInvalid:
20982 return ira->codegen->invalid_inst_gen;
20983 case ReqCompTimeNo:
20984 break;
2099420985 }
2099520986
2099620987 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);
src/stage1/parser.cpp+11-14
......@@ -820,21 +820,19 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
820820 AstNode *align_expr = ast_parse_byte_align(pc);
821821 AstNode *section_expr = ast_parse_link_section(pc);
822822 AstNode *callconv_expr = ast_parse_callconv(pc);
823 Token *anytype = eat_token_if(pc, TokenIdKeywordAnyType);
824823 Token *exmark = nullptr;
825824 AstNode *return_type = nullptr;
826 if (anytype == nullptr) {
827 exmark = eat_token_if(pc, TokenIdBang);
828 return_type = ast_parse_type_expr(pc);
829 if (return_type == nullptr) {
830 Token *next = peek_token(pc);
831 ast_error(
832 pc,
833 next,
834 "expected return type (use 'void' to return nothing), found: '%s'",
835 token_name(next->id)
836 );
837 }
825
826 exmark = eat_token_if(pc, TokenIdBang);
827 return_type = ast_parse_type_expr(pc);
828 if (return_type == nullptr) {
829 Token *next = peek_token(pc);
830 ast_error(
831 pc,
832 next,
833 "expected return type (use 'void' to return nothing), found: '%s'",
834 token_name(next->id)
835 );
838836 }
839837
840838 AstNode *res = ast_create_node(pc, NodeTypeFnProto, first);
......@@ -844,7 +842,6 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
844842 res->data.fn_proto.align_expr = align_expr;
845843 res->data.fn_proto.section_expr = section_expr;
846844 res->data.fn_proto.callconv_expr = callconv_expr;
847 res->data.fn_proto.return_anytype_token = anytype;
848845 res->data.fn_proto.auto_err_set = exmark != nullptr;
849846 res->data.fn_proto.return_type = return_type;
850847
src/target.zig+5-1
......@@ -24,6 +24,10 @@ pub const available_libcs = [_]ArchOsAbi{
2424 .{ .arch = .arm, .os = .linux, .abi = .gnueabihf },
2525 .{ .arch = .arm, .os = .linux, .abi = .musleabi },
2626 .{ .arch = .arm, .os = .linux, .abi = .musleabihf },
27 .{ .arch = .thumb, .os = .linux, .abi = .gnueabi },
28 .{ .arch = .thumb, .os = .linux, .abi = .gnueabihf },
29 .{ .arch = .thumb, .os = .linux, .abi = .musleabi },
30 .{ .arch = .thumb, .os = .linux, .abi = .musleabihf },
2731 .{ .arch = .arm, .os = .windows, .abi = .gnu },
2832 .{ .arch = .csky, .os = .linux, .abi = .gnueabi },
2933 .{ .arch = .csky, .os = .linux, .abi = .gnueabihf },
......@@ -97,7 +101,7 @@ pub fn libCGenericName(target: std.Target) [:0]const u8 {
97101pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {
98102 switch (arch) {
99103 .aarch64, .aarch64_be => return "aarch64",
100 .arm, .armeb => return "arm",
104 .arm, .armeb, .thumb, .thumbeb => return "arm",
101105 .mips, .mipsel => return "mips",
102106 .mips64el, .mips64 => return "mips64",
103107 .powerpc => return "powerpc",
src/translate_c.zig+7-1
......@@ -447,7 +447,13 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
447447 // TODO https://github.com/ziglang/zig/issues/3756
448448 // TODO https://github.com/ziglang/zig/issues/1802
449449 const name = if (isZigPrimitiveType(decl_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ decl_name, c.getMangle() }) else decl_name;
450 try c.unnamed_typedefs.putNoClobber(c.gpa, addr, name);
450 const result = try c.unnamed_typedefs.getOrPut(c.gpa, addr);
451 if (result.found_existing) {
452 // One typedef can declare multiple names.
453 // Don't put this one in `decl_table` so it's processed later.
454 return;
455 }
456 result.entry.value = name;
451457 // Put this typedef in the decl_table to avoid redefinitions.
452458 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
453459 }
test/run_translated_c.zig+14
......@@ -1476,4 +1476,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
14761476 \\ return 0;
14771477 \\}
14781478 , "");
1479
1480 cases.add("typedef with multiple names",
1481 \\#include <stdlib.h>
1482 \\typedef struct {
1483 \\ char field;
1484 \\} a_t, b_t;
1485 \\
1486 \\int main(void) {
1487 \\ a_t a = { .field = 42 };
1488 \\ b_t b = a;
1489 \\ if (b.field != 42) abort();
1490 \\ return 0;
1491 \\}
1492 , "");
14791493}
test/stage2/arm.zig+53
......@@ -458,4 +458,57 @@ pub fn addCases(ctx: *TestContext) !void {
458458 "",
459459 );
460460 }
461
462 {
463 var case = ctx.exe("spilling registers", linux_arm);
464 case.addCompareOutput(
465 \\export fn _start() noreturn {
466 \\ assert(add(3, 4) == 791);
467 \\ exit();
468 \\}
469 \\
470 \\fn add(a: u32, b: u32) u32 {
471 \\ const x: u32 = blk: {
472 \\ const c = a + b; // 7
473 \\ const d = a + c; // 10
474 \\ const e = d + b; // 14
475 \\ const f = d + e; // 24
476 \\ const g = e + f; // 38
477 \\ const h = f + g; // 62
478 \\ const i = g + h; // 100
479 \\ const j = i + d; // 110
480 \\ const k = i + j; // 210
481 \\ const l = k + c; // 217
482 \\ const m = l + d; // 227
483 \\ const n = m + e; // 241
484 \\ const o = n + f; // 265
485 \\ const p = o + g; // 303
486 \\ const q = p + h; // 365
487 \\ const r = q + i; // 465
488 \\ const s = r + j; // 575
489 \\ const t = s + k; // 785
490 \\ break :blk t;
491 \\ };
492 \\ const y = x + a; // 788
493 \\ const z = y + a; // 791
494 \\ return z;
495 \\}
496 \\
497 \\fn assert(ok: bool) void {
498 \\ if (!ok) unreachable;
499 \\}
500 \\
501 \\fn exit() noreturn {
502 \\ asm volatile ("svc #0"
503 \\ :
504 \\ : [number] "{r7}" (1),
505 \\ [arg1] "{r0}" (0)
506 \\ : "memory"
507 \\ );
508 \\ unreachable;
509 \\}
510 ,
511 "",
512 );
513 }
461514}
test/stage2/test.zig+117-13
......@@ -318,6 +318,81 @@ pub fn addCases(ctx: *TestContext) !void {
318318 , &[_][]const u8{":2:15: error: incompatible types: 'bool' and 'comptime_int'"});
319319 }
320320
321 {
322 var case = ctx.exe("multiplying numbers at runtime and comptime", linux_x64);
323 case.addCompareOutput(
324 \\export fn _start() noreturn {
325 \\ mul(3, 4);
326 \\
327 \\ exit();
328 \\}
329 \\
330 \\fn mul(a: u32, b: u32) void {
331 \\ if (a * b != 12) unreachable;
332 \\}
333 \\
334 \\fn exit() noreturn {
335 \\ asm volatile ("syscall"
336 \\ :
337 \\ : [number] "{rax}" (231),
338 \\ [arg1] "{rdi}" (0)
339 \\ : "rcx", "r11", "memory"
340 \\ );
341 \\ unreachable;
342 \\}
343 ,
344 "",
345 );
346 // comptime function call
347 case.addCompareOutput(
348 \\export fn _start() noreturn {
349 \\ exit();
350 \\}
351 \\
352 \\fn mul(a: u32, b: u32) u32 {
353 \\ return a * b;
354 \\}
355 \\
356 \\const x = mul(3, 4);
357 \\
358 \\fn exit() noreturn {
359 \\ asm volatile ("syscall"
360 \\ :
361 \\ : [number] "{rax}" (231),
362 \\ [arg1] "{rdi}" (x - 12)
363 \\ : "rcx", "r11", "memory"
364 \\ );
365 \\ unreachable;
366 \\}
367 ,
368 "",
369 );
370 // Inline function call
371 case.addCompareOutput(
372 \\export fn _start() noreturn {
373 \\ var x: usize = 5;
374 \\ const y = mul(2, 3, x);
375 \\ exit(y - 30);
376 \\}
377 \\
378 \\fn mul(a: usize, b: usize, c: usize) callconv(.Inline) usize {
379 \\ return a * b * c;
380 \\}
381 \\
382 \\fn exit(code: usize) noreturn {
383 \\ asm volatile ("syscall"
384 \\ :
385 \\ : [number] "{rax}" (231),
386 \\ [arg1] "{rdi}" (code)
387 \\ : "rcx", "r11", "memory"
388 \\ );
389 \\ unreachable;
390 \\}
391 ,
392 "",
393 );
394 }
395
321396 {
322397 var case = ctx.exe("assert function", linux_x64);
323398 case.addCompareOutput(
......@@ -700,7 +775,8 @@ pub fn addCases(ctx: *TestContext) !void {
700775 // Spilling registers to the stack.
701776 case.addCompareOutput(
702777 \\pub export fn _start() noreturn {
703 \\ assert(add(3, 4) == 791);
778 \\ assert(add(3, 4) == 1221);
779 \\ assert(mul(3, 4) == 21609);
704780 \\
705781 \\ exit();
706782 \\}
......@@ -716,19 +792,47 @@ pub fn addCases(ctx: *TestContext) !void {
716792 \\ const i = g + h; // 100
717793 \\ const j = i + d; // 110
718794 \\ const k = i + j; // 210
719 \\ const l = k + c; // 217
720 \\ const m = l + d; // 227
721 \\ const n = m + e; // 241
722 \\ const o = n + f; // 265
723 \\ const p = o + g; // 303
724 \\ const q = p + h; // 365
725 \\ const r = q + i; // 465
726 \\ const s = r + j; // 575
727 \\ const t = s + k; // 785
728 \\ break :blk t;
795 \\ const l = j + k; // 320
796 \\ const m = l + c; // 327
797 \\ const n = m + d; // 337
798 \\ const o = n + e; // 351
799 \\ const p = o + f; // 375
800 \\ const q = p + g; // 413
801 \\ const r = q + h; // 475
802 \\ const s = r + i; // 575
803 \\ const t = s + j; // 685
804 \\ const u = t + k; // 895
805 \\ const v = u + l; // 1215
806 \\ break :blk v;
807 \\ };
808 \\ const y = x + a; // 1218
809 \\ const z = y + a; // 1221
810 \\ return z;
811 \\}
812 \\
813 \\fn mul(a: u32, b: u32) u32 {
814 \\ const x: u32 = blk: {
815 \\ const c = a * a * a * a; // 81
816 \\ const d = a * a * a * b; // 108
817 \\ const e = a * a * b * a; // 108
818 \\ const f = a * a * b * b; // 144
819 \\ const g = a * b * a * a; // 108
820 \\ const h = a * b * a * b; // 144
821 \\ const i = a * b * b * a; // 144
822 \\ const j = a * b * b * b; // 192
823 \\ const k = b * a * a * a; // 108
824 \\ const l = b * a * a * b; // 144
825 \\ const m = b * a * b * a; // 144
826 \\ const n = b * a * b * b; // 192
827 \\ const o = b * b * a * a; // 144
828 \\ const p = b * b * a * b; // 192
829 \\ const q = b * b * b * a; // 192
830 \\ const r = b * b * b * b; // 256
831 \\ const s = c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r; // 2401
832 \\ break :blk s;
729833 \\ };
730 \\ const y = x + a; // 788
731 \\ const z = y + a; // 791
834 \\ const y = x * a; // 7203
835 \\ const z = y * a; // 21609
732836 \\ return z;
733837 \\}
734838 \\
test/stage2/wasm.zig+4-1
......@@ -58,7 +58,10 @@ pub fn addCases(ctx: *TestContext) !void {
5858 ,
5959 // This is what you get when you take the bits of the IEE-754
6060 // representation of 42.0 and reinterpret them as an unsigned
61 // integer. Guess that's a bug in wasmtime.
61 // integer.
62 // Bug is fixed in wasmtime v0.26 but updating to v0.26 is blocked
63 // on this issue:
64 // https://github.com/ziglang/zig/issues/8742
6265 "1109917696\n",
6366 );
6467
test/tests.zig+8-9
......@@ -98,15 +98,14 @@ const test_targets = blk: {
9898 },
9999 .link_libc = true,
100100 },
101 // https://github.com/ziglang/zig/issues/4926
102 //TestTarget{
103 // .target = .{
104 // .cpu_arch = .i386,
105 // .os_tag = .linux,
106 // .abi = .gnu,
107 // },
108 // .link_libc = true,
109 //},
101 TestTarget{
102 .target = .{
103 .cpu_arch = .i386,
104 .os_tag = .linux,
105 .abi = .gnu,
106 },
107 .link_libc = true,
108 },
110109
111110 TestTarget{
112111 .target = .{