From 24e54799fddf7c88e0feebeeef6ac2cc2f6543a0 Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 16:24:12 +0300 Subject: [PATCH 001/110] Fix CMake finding LLVM/clang/lld on FreeBSD --- cmake/Findclang.cmake | 2 ++ cmake/Findlld.cmake | 7 ++++++- cmake/Findllvm.cmake | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cmake/Findclang.cmake b/cmake/Findclang.cmake index ea1bc91d7..9268f1973 100644 --- a/cmake/Findclang.cmake +++ b/cmake/Findclang.cmake @@ -30,6 +30,7 @@ else() /usr/lib/llvm/7/include /usr/lib/llvm-7/include /usr/lib/llvm-7.0/include + /usr/local/llvm70/include /mingw64/include) macro(FIND_AND_ADD_CLANG_LIB _libname_) @@ -40,6 +41,7 @@ else() /usr/lib/llvm/7/lib /usr/lib/llvm-7/lib /usr/lib/llvm-7.0/lib + /usr/local/llvm70/lib /mingw64/lib /c/msys64/mingw64/lib c:\\msys64\\mingw64\\lib) diff --git a/cmake/Findlld.cmake b/cmake/Findlld.cmake index 1c4e9163a..4e5b0c9a1 100644 --- a/cmake/Findlld.cmake +++ b/cmake/Findlld.cmake @@ -9,9 +9,13 @@ find_path(LLD_INCLUDE_DIRS NAMES lld/Common/Driver.h PATHS /usr/lib/llvm-6.0/include + /usr/local/llvm60/include /mingw64/include) -find_library(LLD_LIBRARY NAMES lld-6.0 lld PATHS /usr/lib/llvm-6.0/lib) +find_library(LLD_LIBRARY NAMES lld-6.0 lld60 lld + PATHS + /usr/lib/llvm-6.0/lib + /usr/local/llvm70/lib) if(EXISTS ${LLD_LIBRARY}) set(LLD_LIBRARIES ${LLD_LIBRARY}) else() @@ -20,6 +24,7 @@ else() find_library(LLD_${_prettylibname_}_LIB NAMES ${_libname_} PATHS /usr/lib/llvm-6.0/lib + /usr/local/llvm70/lib /mingw64/lib /c/msys64/mingw64/lib c:/msys64/mingw64/lib) diff --git a/cmake/Findllvm.cmake b/cmake/Findllvm.cmake index 150f2a252..b84781368 100644 --- a/cmake/Findllvm.cmake +++ b/cmake/Findllvm.cmake @@ -8,7 +8,7 @@ # LLVM_LIBDIRS find_program(LLVM_CONFIG_EXE - NAMES llvm-config-7 llvm-config-7.0 llvm-config + NAMES llvm-config-7 llvm-config-7.0 llvm-config70 llvm-config PATHS "/mingw64/bin" "/c/msys64/mingw64/bin" From 9a541c12140e8768fabbbd8834cd0e1570df344b Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 16:48:17 +0300 Subject: [PATCH 002/110] Add FreeBSD support to os.cpp --- src/os.cpp | 26 ++++++++++++++++++++------ src/os.hpp | 2 ++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/os.cpp b/src/os.cpp index 6df463d8a..86bef6d5e 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -50,10 +50,13 @@ typedef SSIZE_T ssize_t; #endif -#if defined(ZIG_OS_LINUX) +#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) #include #endif +#if defined(ZIG_OS_FREEBSD) +#include +#endif #if defined(__MACH__) #include @@ -75,7 +78,9 @@ static clock_serv_t cclock; #if defined(__APPLE__) && !defined(environ) #include #define environ (*_NSGetEnviron()) -#endif +#elif defined(ZIG_OS_FREEBSD) +extern char **environ; +#endif #if defined(ZIG_OS_POSIX) static void populate_termination(Termination *term, int status) { @@ -1442,6 +1447,15 @@ Error os_self_exe_path(Buf *out_path) { } buf_resize(out_path, amt); return ErrorNone; +#elif defined(ZIG_OS_FREEBSD) + buf_resize(out_path, PATH_MAX); + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t cb = PATH_MAX; + if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) { + return ErrorUnexpected; + } + buf_resize(out_path, cb); + return ErrorNone; #endif return ErrorFileNotFound; } @@ -1747,7 +1761,7 @@ Error os_get_app_data_dir(Buf *out_path, const char *appname) { buf_resize(out_path, 0); buf_appendf(out_path, "%s/Library/Application Support/%s", home_dir, appname); return ErrorNone; -#elif defined(ZIG_OS_LINUX) +#elif defined(ZIG_OS_POSIX) const char *home_dir = getenv("HOME"); if (home_dir == nullptr) { // TODO use /etc/passwd @@ -1760,7 +1774,7 @@ Error os_get_app_data_dir(Buf *out_path, const char *appname) { } -#if defined(ZIG_OS_LINUX) +#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) { ZigList *libs = reinterpret_cast< ZigList *>(data); if (info->dlpi_name[0] == '/') { @@ -1771,7 +1785,7 @@ static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, #endif Error os_self_exe_shared_libs(ZigList &paths) { -#if defined(ZIG_OS_LINUX) +#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) paths.resize(0); dl_iterate_phdr(self_exe_shared_libs_callback, &paths); return ErrorNone; @@ -1940,7 +1954,7 @@ Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime; mtime->nsec = 0; return ErrorNone; -#elif defined(ZIG_OS_LINUX) +#elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) struct stat statbuf; if (fstat(file, &statbuf) == -1) return ErrorFileSystem; diff --git a/src/os.hpp b/src/os.hpp index 30083971e..a552c4461 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -24,6 +24,8 @@ #define ZIG_OS_WINDOWS #elif defined(__linux__) #define ZIG_OS_LINUX +#elif defined(__FreeBSD__) +#define ZIG_OS_FREEBSD #else #define ZIG_OS_UNKNOWN #endif From e2b9c153bdfa2c5e4005d5957062e0eaf3b339a2 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Fri, 20 Oct 2017 06:16:56 +0000 Subject: [PATCH 003/110] Add initial freebsd stdlib functionality Trivial program now compiles with now warnings. --- src/target.cpp | 2 +- std/os/freebsd.zig | 733 ++++++++++++++++++++++++++++++++++++++ std/os/freebsd_errno.zig | 121 +++++++ std/os/freebsd_i386.zig | 614 +++++++++++++++++++++++++++++++ std/os/freebsd_x86_64.zig | 637 +++++++++++++++++++++++++++++++++ std/os/get_user_id.zig | 2 +- std/os/index.zig | 6 +- std/os/path.zig | 4 +- 8 files changed, 2113 insertions(+), 6 deletions(-) create mode 100644 std/os/freebsd.zig create mode 100644 std/os/freebsd_errno.zig create mode 100644 std/os/freebsd_i386.zig create mode 100644 std/os/freebsd_x86_64.zig diff --git a/src/target.cpp b/src/target.cpp index 25dfa9d3c..e93465ba4 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -738,6 +738,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { case OsLinux: case OsMacOSX: case OsZen: + case OsFreeBSD: case OsOpenBSD: switch (id) { case CIntTypeShort: @@ -774,7 +775,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { case OsAnanas: case OsCloudABI: case OsDragonFly: - case OsFreeBSD: case OsIOS: case OsKFreeBSD: case OsLv2: diff --git a/std/os/freebsd.zig b/std/os/freebsd.zig new file mode 100644 index 000000000..7fd233aef --- /dev/null +++ b/std/os/freebsd.zig @@ -0,0 +1,733 @@ +const assert = @import("../debug.zig").assert; +const builtin = @import("builtin"); +const arch = switch (builtin.arch) { + builtin.Arch.x86_64 => @import("freebsd_x86_64.zig"), + builtin.Arch.i386 => @import("freebsd_i386.zig"), + else => @compileError("unsupported arch"), +}; +pub use @import("freebsd_errno.zig"); + +pub const PATH_MAX = 1024; + +pub const STDIN_FILENO = 0; +pub const STDOUT_FILENO = 1; +pub const STDERR_FILENO = 2; + +pub const PROT_NONE = 0; +pub const PROT_READ = 1; +pub const PROT_WRITE = 2; +pub const PROT_EXEC = 4; + +pub const MAP_FAILED = @maxValue(usize); +pub const MAP_SHARED = 0x0001; +pub const MAP_PRIVATE = 0x0002; +pub const MAP_FIXED = 0x0010; +pub const MAP_STACK = 0x0400; +pub const MAP_NOSYNC = 0x0800; +pub const MAP_ANON = 0x1000; +pub const MAP_ANONYMOUS = MAP_ANON; +pub const MAP_FILE = 0; + +pub const MAP_GUARD = 0x00002000; +pub const MAP_EXCL = 0x00004000; +pub const MAP_NOCORE = 0x00020000; +pub const MAP_PREFAULT_READ = 0x00040000; +pub const MAP_32BIT = 0x00080000; + +pub const WNOHANG = 1; +pub const WUNTRACED = 2; +pub const WSTOPPED = WUNTRACED; +pub const WCONTINUED = 4; +pub const WNOWAIT = 8; +pub const WEXITED = 16; +pub const WTRAPPED = 32; + +pub const SA_ONSTACK = 0x0001; +pub const SA_RESTART = 0x0002; +pub const SA_RESETHAND = 0x0004; +pub const SA_NOCLDSTOP = 0x0008; +pub const SA_NODEFER = 0x0010; +pub const SA_NOCLDWAIT = 0x0020; +pub const SA_SIGINFO = 0x0040; + +pub const SIGHUP = 1; +pub const SIGINT = 2; +pub const SIGQUIT = 3; +pub const SIGILL = 4; +pub const SIGTRAP = 5; +pub const SIGABRT = 6; +pub const SIGIOT = SIGABRT; +pub const SIGEMT = 7; +pub const SIGFPE = 8; +pub const SIGKILL = 9; +pub const SIGBUS = 10; +pub const SIGSEGV = 11; +pub const SIGSYS = 12; +pub const SIGPIPE = 13; +pub const SIGALRM = 14; +pub const SIGTERM = 15; +pub const SIGURG = 16; +pub const SIGSTOP = 17; +pub const SIGTSTP = 18; +pub const SIGCONT = 19; +pub const SIGCHLD = 20; +pub const SIGTTIN = 21; +pub const SIGTTOU = 22; +pub const SIGIO = 23; +pub const SIGXCPU = 24; +pub const SIGXFSZ = 25; +pub const SIGVTALRM = 26; +pub const SIGPROF = 27; +pub const SIGWINCH = 28; +pub const SIGINFO = 29; +pub const SIGUSR1 = 30; +pub const SIGUSR2 = 31; +pub const SIGTHR = 32; +pub const SIGLWP = SIGTHR; +pub const SIGLIBRT = 33; + +pub const SIGRTMIN = 65; +pub const SIGRTMAX = 126; + +pub const O_RDONLY = 0o0; +pub const O_WRONLY = 0o1; +pub const O_RDWR = 0o2; +pub const O_ACCMODE = 0o3; + +pub const O_CREAT = arch.O_CREAT; +pub const O_EXCL = arch.O_EXCL; +pub const O_NOCTTY = arch.O_NOCTTY; +pub const O_TRUNC = arch.O_TRUNC; +pub const O_APPEND = arch.O_APPEND; +pub const O_NONBLOCK = arch.O_NONBLOCK; +pub const O_DSYNC = arch.O_DSYNC; +pub const O_SYNC = arch.O_SYNC; +pub const O_RSYNC = arch.O_RSYNC; +pub const O_DIRECTORY = arch.O_DIRECTORY; +pub const O_NOFOLLOW = arch.O_NOFOLLOW; +pub const O_CLOEXEC = arch.O_CLOEXEC; + +pub const O_ASYNC = arch.O_ASYNC; +pub const O_DIRECT = arch.O_DIRECT; +pub const O_LARGEFILE = arch.O_LARGEFILE; +pub const O_NOATIME = arch.O_NOATIME; +pub const O_PATH = arch.O_PATH; +pub const O_TMPFILE = arch.O_TMPFILE; +pub const O_NDELAY = arch.O_NDELAY; + +pub const SEEK_SET = 0; +pub const SEEK_CUR = 1; +pub const SEEK_END = 2; + +pub const SIG_BLOCK = 1; +pub const SIG_UNBLOCK = 2; +pub const SIG_SETMASK = 3; + +pub const SOCK_STREAM = 1; +pub const SOCK_DGRAM = 2; +pub const SOCK_RAW = 3; +pub const SOCK_RDM = 4; +pub const SOCK_SEQPACKET = 5; + +pub const SOCK_CLOEXEC = 0x10000000; +pub const SOCK_NONBLOCK = 0x20000000; + +// TODO: From here +pub const PROTO_ip = 0o000; +pub const PROTO_icmp = 0o001; +pub const PROTO_igmp = 0o002; +pub const PROTO_ggp = 0o003; +pub const PROTO_ipencap = 0o004; +pub const PROTO_st = 0o005; +pub const PROTO_tcp = 0o006; +pub const PROTO_egp = 0o010; +pub const PROTO_pup = 0o014; +pub const PROTO_udp = 0o021; +pub const PROTO_hmp = 0o024; +pub const PROTO_xns_idp = 0o026; +pub const PROTO_rdp = 0o033; +pub const PROTO_iso_tp4 = 0o035; +pub const PROTO_xtp = 0o044; +pub const PROTO_ddp = 0o045; +pub const PROTO_idpr_cmtp = 0o046; +pub const PROTO_ipv6 = 0o051; +pub const PROTO_ipv6_route = 0o053; +pub const PROTO_ipv6_frag = 0o054; +pub const PROTO_idrp = 0o055; +pub const PROTO_rsvp = 0o056; +pub const PROTO_gre = 0o057; +pub const PROTO_esp = 0o062; +pub const PROTO_ah = 0o063; +pub const PROTO_skip = 0o071; +pub const PROTO_ipv6_icmp = 0o072; +pub const PROTO_ipv6_nonxt = 0o073; +pub const PROTO_ipv6_opts = 0o074; +pub const PROTO_rspf = 0o111; +pub const PROTO_vmtp = 0o121; +pub const PROTO_ospf = 0o131; +pub const PROTO_ipip = 0o136; +pub const PROTO_encap = 0o142; +pub const PROTO_pim = 0o147; +pub const PROTO_raw = 0o377; + +pub const PF_UNSPEC = 0; +pub const PF_LOCAL = 1; +pub const PF_UNIX = PF_LOCAL; +pub const PF_FILE = PF_LOCAL; +pub const PF_INET = 2; +pub const PF_AX25 = 3; +pub const PF_IPX = 4; +pub const PF_APPLETALK = 5; +pub const PF_NETROM = 6; +pub const PF_BRIDGE = 7; +pub const PF_ATMPVC = 8; +pub const PF_X25 = 9; +pub const PF_INET6 = 10; +pub const PF_ROSE = 11; +pub const PF_DECnet = 12; +pub const PF_NETBEUI = 13; +pub const PF_SECURITY = 14; +pub const PF_KEY = 15; +pub const PF_NETLINK = 16; +pub const PF_ROUTE = PF_NETLINK; +pub const PF_PACKET = 17; +pub const PF_ASH = 18; +pub const PF_ECONET = 19; +pub const PF_ATMSVC = 20; +pub const PF_RDS = 21; +pub const PF_SNA = 22; +pub const PF_IRDA = 23; +pub const PF_PPPOX = 24; +pub const PF_WANPIPE = 25; +pub const PF_LLC = 26; +pub const PF_IB = 27; +pub const PF_MPLS = 28; +pub const PF_CAN = 29; +pub const PF_TIPC = 30; +pub const PF_BLUETOOTH = 31; +pub const PF_IUCV = 32; +pub const PF_RXRPC = 33; +pub const PF_ISDN = 34; +pub const PF_PHONET = 35; +pub const PF_IEEE802154 = 36; +pub const PF_CAIF = 37; +pub const PF_ALG = 38; +pub const PF_NFC = 39; +pub const PF_VSOCK = 40; +pub const PF_MAX = 41; + +pub const AF_UNSPEC = PF_UNSPEC; +pub const AF_LOCAL = PF_LOCAL; +pub const AF_UNIX = AF_LOCAL; +pub const AF_FILE = AF_LOCAL; +pub const AF_INET = PF_INET; +pub const AF_AX25 = PF_AX25; +pub const AF_IPX = PF_IPX; +pub const AF_APPLETALK = PF_APPLETALK; +pub const AF_NETROM = PF_NETROM; +pub const AF_BRIDGE = PF_BRIDGE; +pub const AF_ATMPVC = PF_ATMPVC; +pub const AF_X25 = PF_X25; +pub const AF_INET6 = PF_INET6; +pub const AF_ROSE = PF_ROSE; +pub const AF_DECnet = PF_DECnet; +pub const AF_NETBEUI = PF_NETBEUI; +pub const AF_SECURITY = PF_SECURITY; +pub const AF_KEY = PF_KEY; +pub const AF_NETLINK = PF_NETLINK; +pub const AF_ROUTE = PF_ROUTE; +pub const AF_PACKET = PF_PACKET; +pub const AF_ASH = PF_ASH; +pub const AF_ECONET = PF_ECONET; +pub const AF_ATMSVC = PF_ATMSVC; +pub const AF_RDS = PF_RDS; +pub const AF_SNA = PF_SNA; +pub const AF_IRDA = PF_IRDA; +pub const AF_PPPOX = PF_PPPOX; +pub const AF_WANPIPE = PF_WANPIPE; +pub const AF_LLC = PF_LLC; +pub const AF_IB = PF_IB; +pub const AF_MPLS = PF_MPLS; +pub const AF_CAN = PF_CAN; +pub const AF_TIPC = PF_TIPC; +pub const AF_BLUETOOTH = PF_BLUETOOTH; +pub const AF_IUCV = PF_IUCV; +pub const AF_RXRPC = PF_RXRPC; +pub const AF_ISDN = PF_ISDN; +pub const AF_PHONET = PF_PHONET; +pub const AF_IEEE802154 = PF_IEEE802154; +pub const AF_CAIF = PF_CAIF; +pub const AF_ALG = PF_ALG; +pub const AF_NFC = PF_NFC; +pub const AF_VSOCK = PF_VSOCK; +pub const AF_MAX = PF_MAX; + +pub const DT_UNKNOWN = 0; +pub const DT_FIFO = 1; +pub const DT_CHR = 2; +pub const DT_DIR = 4; +pub const DT_BLK = 6; +pub const DT_REG = 8; +pub const DT_LNK = 10; +pub const DT_SOCK = 12; +pub const DT_WHT = 14; + + +pub const TCGETS = 0x5401; +pub const TCSETS = 0x5402; +pub const TCSETSW = 0x5403; +pub const TCSETSF = 0x5404; +pub const TCGETA = 0x5405; +pub const TCSETA = 0x5406; +pub const TCSETAW = 0x5407; +pub const TCSETAF = 0x5408; +pub const TCSBRK = 0x5409; +pub const TCXONC = 0x540A; +pub const TCFLSH = 0x540B; +pub const TIOCEXCL = 0x540C; +pub const TIOCNXCL = 0x540D; +pub const TIOCSCTTY = 0x540E; +pub const TIOCGPGRP = 0x540F; +pub const TIOCSPGRP = 0x5410; +pub const TIOCOUTQ = 0x5411; +pub const TIOCSTI = 0x5412; +pub const TIOCGWINSZ = 0x5413; +pub const TIOCSWINSZ = 0x5414; +pub const TIOCMGET = 0x5415; +pub const TIOCMBIS = 0x5416; +pub const TIOCMBIC = 0x5417; +pub const TIOCMSET = 0x5418; +pub const TIOCGSOFTCAR = 0x5419; +pub const TIOCSSOFTCAR = 0x541A; +pub const FIONREAD = 0x541B; +pub const TIOCINQ = FIONREAD; +pub const TIOCLINUX = 0x541C; +pub const TIOCCONS = 0x541D; +pub const TIOCGSERIAL = 0x541E; +pub const TIOCSSERIAL = 0x541F; +pub const TIOCPKT = 0x5420; +pub const FIONBIO = 0x5421; +pub const TIOCNOTTY = 0x5422; +pub const TIOCSETD = 0x5423; +pub const TIOCGETD = 0x5424; +pub const TCSBRKP = 0x5425; +pub const TIOCSBRK = 0x5427; +pub const TIOCCBRK = 0x5428; +pub const TIOCGSID = 0x5429; +pub const TIOCGRS485 = 0x542E; +pub const TIOCSRS485 = 0x542F; +pub const TIOCGPTN = 0x80045430; +pub const TIOCSPTLCK = 0x40045431; +pub const TIOCGDEV = 0x80045432; +pub const TCGETX = 0x5432; +pub const TCSETX = 0x5433; +pub const TCSETXF = 0x5434; +pub const TCSETXW = 0x5435; +pub const TIOCSIG = 0x40045436; +pub const TIOCVHANGUP = 0x5437; +pub const TIOCGPKT = 0x80045438; +pub const TIOCGPTLCK = 0x80045439; +pub const TIOCGEXCL = 0x80045440; + +fn unsigned(s: i32) -> u32 { @bitCast(u32, s) } +fn signed(s: u32) -> i32 { @bitCast(i32, s) } +pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) } +pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) } +pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) } +pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 } +pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 } +pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff } + + +pub const winsize = extern struct { + ws_row: u16, + ws_col: u16, + ws_xpixel: u16, + ws_ypixel: u16, +}; + +/// Get the errno from a syscall return value, or 0 for no error. +pub fn getErrno(r: usize) -> usize { + const signed_r = @bitCast(isize, r); + if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0 +} + +pub fn dup2(old: i32, new: i32) -> usize { + arch.syscall2(arch.SYS_dup2, usize(old), usize(new)) +} + +pub fn chdir(path: &const u8) -> usize { + arch.syscall1(arch.SYS_chdir, @ptrToInt(path)) +} + +pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize { + arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)) +} + +pub fn fork() -> usize { + arch.syscall0(arch.SYS_fork) +} + +pub fn getcwd(buf: &u8, size: usize) -> usize { + arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size) +} + +pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize { + arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count) +} + +pub fn isatty(fd: i32) -> bool { + var wsz: winsize = undefined; + return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; +} + +pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize { + arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len) +} + +pub fn mkdir(path: &const u8, mode: u32) -> usize { + arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode) +} + +pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) + -> usize +{ + arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), + @bitCast(usize, offset)) +} + +pub fn munmap(address: &u8, length: usize) -> usize { + arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length) +} + +pub fn read(fd: i32, buf: &u8, count: usize) -> usize { + arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count) +} + +pub fn rmdir(path: &const u8) -> usize { + arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)) +} + +pub fn symlink(existing: &const u8, new: &const u8) -> usize { + arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)) +} + +pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize { + arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset) +} + +pub fn pipe(fd: &[2]i32) -> usize { + pipe2(fd, 0) +} + +pub fn pipe2(fd: &[2]i32, flags: usize) -> usize { + arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags) +} + +pub fn write(fd: i32, buf: &const u8, count: usize) -> usize { + arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count) +} + +pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize { + arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset) +} + +pub fn rename(old: &const u8, new: &const u8) -> usize { + arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)) +} + +pub fn open(path: &const u8, flags: u32, perm: usize) -> usize { + arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm) +} + +pub fn create(path: &const u8, perm: usize) -> usize { + arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm) +} + +pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize { + arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode) +} + +pub fn close(fd: i32) -> usize { + arch.syscall1(arch.SYS_close, usize(fd)) +} + +pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize { + arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos) +} + +pub fn exit(status: i32) -> noreturn { + _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status))); + unreachable +} + +pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize { + arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags)) +} + +pub fn kill(pid: i32, sig: i32) -> usize { + arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig)) +} + +pub fn unlink(path: &const u8) -> usize { + arch.syscall1(arch.SYS_unlink, @ptrToInt(path)) +} + +pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize { + arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0) +} + +pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize { + arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)) +} + +pub fn setuid(uid: u32) -> usize { + arch.syscall1(arch.SYS_setuid, uid) +} + +pub fn setgid(gid: u32) -> usize { + arch.syscall1(arch.SYS_setgid, gid) +} + +pub fn setreuid(ruid: u32, euid: u32) -> usize { + arch.syscall2(arch.SYS_setreuid, ruid, euid) +} + +pub fn setregid(rgid: u32, egid: u32) -> usize { + arch.syscall2(arch.SYS_setregid, rgid, egid) +} + +pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { + arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) +} + +pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize { + assert(sig >= 1); + assert(sig != SIGKILL); + assert(sig != SIGSTOP); + var ksa = k_sigaction { + .handler = act.handler, + .flags = act.flags | SA_RESTORER, + .mask = undefined, + .restorer = @ptrCast(extern fn(), arch.restore_rt), + }; + var ksa_old: k_sigaction = undefined; + @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8); + const result = arch.syscall4(arch.SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask))); + const err = getErrno(result); + if (err != 0) { + return result; + } + if (oact) |old| { + old.handler = ksa_old.handler; + old.flags = @truncate(u32, ksa_old.flags); + @memcpy(@ptrCast(&u8, &old.mask), @ptrCast(&const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask))); + } + return 0; +} + +const NSIG = 65; +const sigset_t = [128 / @sizeOf(usize)]usize; +const all_mask = []usize{@maxValue(usize)}; +const app_mask = []usize{0xfffffffc7fffffff}; + +const k_sigaction = extern struct { + handler: extern fn(i32), + flags: usize, + restorer: extern fn(), + mask: [2]u32, +}; + +/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. +pub const Sigaction = struct { + handler: extern fn(i32), + mask: sigset_t, + flags: u32, +}; + +pub const SIG_ERR = @intToPtr(extern fn(i32), @maxValue(usize)); +pub const SIG_DFL = @intToPtr(extern fn(i32), 0); +pub const SIG_IGN = @intToPtr(extern fn(i32), 1); +pub const empty_sigset = []usize{0} ** sigset_t.len; + +pub fn raise(sig: i32) -> usize { + // TODO implement, see linux equivalent for what we want to try and do + return 0; +} + +fn blockAllSignals(set: &sigset_t) { + // TODO implement +} + +fn blockAppSignals(set: &sigset_t) { + // TODO implement +} + +fn restoreSignals(set: &sigset_t) { + // TODO implement +} + +pub fn sigaddset(set: &sigset_t, sig: u6) { + const s = sig - 1; + (*set)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1)); +} + +pub fn sigismember(set: &const sigset_t, sig: u6) -> bool { + const s = sig - 1; + return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0; +} + + +pub const sa_family_t = u16; +pub const socklen_t = u32; +pub const in_addr = u32; +pub const in6_addr = [16]u8; + +pub const sockaddr = extern struct { + family: sa_family_t, + port: u16, + data: [12]u8, +}; + +pub const sockaddr_in = extern struct { + family: sa_family_t, + port: u16, + addr: in_addr, + zero: [8]u8, +}; + +pub const sockaddr_in6 = extern struct { + family: sa_family_t, + port: u16, + flowinfo: u32, + addr: in6_addr, + scope_id: u32, +}; + +pub const iovec = extern struct { + iov_base: &u8, + iov_len: usize, +}; + +// +//const IF_NAMESIZE = 16; +// +//export struct ifreq { +// ifrn_name: [IF_NAMESIZE]u8, +// union { +// ifru_addr: sockaddr, +// ifru_dstaddr: sockaddr, +// ifru_broadaddr: sockaddr, +// ifru_netmask: sockaddr, +// ifru_hwaddr: sockaddr, +// ifru_flags: i16, +// ifru_ivalue: i32, +// ifru_mtu: i32, +// ifru_map: ifmap, +// ifru_slave: [IF_NAMESIZE]u8, +// ifru_newname: [IF_NAMESIZE]u8, +// ifru_data: &u8, +// } ifr_ifru; +//} +// + +pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { + arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)) +} + +pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { + arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len)) +} + +pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize { + arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol)) +} + +pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize { + arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen)) +} + +pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize { + arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen)) +} + +pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize { + arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags) +} + +pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { + arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len)) +} + +pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize { + arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags) +} + +pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, + noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize +{ + arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)) +} + +pub fn shutdown(fd: i32, how: i32) -> usize { + arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how)) +} + +pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { + arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len)) +} + +pub fn listen(fd: i32, backlog: i32) -> usize { + arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog)) +} + +pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize { + arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen)) +} + +pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize { + arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0])) +} + +pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { + accept4(fd, addr, len, 0) +} + +pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize { + arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags) +} + +// error NameTooLong; +// error SystemResources; +// error Io; +// +// pub fn if_nametoindex(name: []u8) -> %u32 { +// var ifr: ifreq = undefined; +// +// if (name.len >= ifr.ifr_name.len) { +// return error.NameTooLong; +// } +// +// const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); +// const socket_err = getErrno(socket_ret); +// if (socket_err > 0) { +// return error.SystemResources; +// } +// const socket_fd = i32(socket_ret); +// @memcpy(&ifr.ifr_name[0], &name[0], name.len); +// ifr.ifr_name[name.len] = 0; +// const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr); +// close(socket_fd); +// const ioctl_err = getErrno(ioctl_ret); +// if (ioctl_err > 0) { +// return error.Io; +// } +// return ifr.ifr_ifindex; +// } + +pub const Stat = arch.Stat; +pub const timespec = arch.timespec; + +pub fn fstat(fd: i32, stat_buf: &Stat) -> usize { + arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf)) +} diff --git a/std/os/freebsd_errno.zig b/std/os/freebsd_errno.zig new file mode 100644 index 000000000..132683de1 --- /dev/null +++ b/std/os/freebsd_errno.zig @@ -0,0 +1,121 @@ +pub const EPERM = 1; // Operation not permitted +pub const ENOENT = 2; // No such file or directory +pub const ESRCH = 3; // No such process +pub const EINTR = 4; // Interrupted system call +pub const EIO = 5; // Input/output error +pub const ENXIO = 6; // Device not configured +pub const E2BIG = 7; // Argument list too long +pub const ENOEXEC = 8; // Exec format error +pub const EBADF = 9; // Bad file descriptor +pub const ECHILD = 10; // No child processes +pub const EDEADLK = 11; // Resource deadlock avoided + // 11 was EAGAIN +pub const ENOMEM = 12; // Cannot allocate memory +pub const EACCES = 13; // Permission denied +pub const EFAULT = 14; // Bad address +pub const ENOTBLK = 15; // Block device required +pub const EBUSY = 16; // Device busy +pub const EEXIST = 17; // File exists +pub const EXDEV = 18; // Cross-device link +pub const ENODEV = 19; // Operation not supported by device +pub const ENOTDIR = 20; // Not a directory +pub const EISDIR = 21; // Is a directory +pub const EINVAL = 22; // Invalid argument +pub const ENFILE = 23; // Too many open files in system +pub const EMFILE = 24; // Too many open files +pub const ENOTTY = 25; // Inappropriate ioctl for device +pub const ETXTBSY = 26; // Text file busy +pub const EFBIG = 27; // File too large +pub const ENOSPC = 28; // No space left on device +pub const ESPIPE = 29; // Illegal seek +pub const EROFS = 30; // Read-only filesystem +pub const EMLINK = 31; // Too many links +pub const EPIPE = 32; // Broken pipe + +// math software +pub const EDOM = 33; // Numerical argument out of domain +pub const ERANGE = 34; // Result too large + +// non-blocking and interrupt i/o +pub const EAGAIN = 35; // Resource temporarily unavailable +pub const EWOULDBLOCK = EAGAIN; // Operation would block +pub const EINPROGRESS = 36; // Operation now in progress +pub const EALREADY = 37; // Operation already in progress + +// ipc/network software -- argument errors +pub const ENOTSOCK = 38; // Socket operation on non-socket +pub const EDESTADDRREQ = 39; // Destination address required +pub const EMSGSIZE = 40; // Message too long +pub const EPROTOTYPE = 41; // Protocol wrong type for socket +pub const ENOPROTOOPT = 42; // Protocol not available +pub const EPROTONOSUPPORT = 43; // Protocol not supported +pub const ESOCKTNOSUPPORT = 44; // Socket type not supported +pub const EOPNOTSUPP = 45; // Operation not supported +pub const ENOTSUP = EOPNOTSUPP; // Operation not supported +pub const EPFNOSUPPORT = 46; // Protocol family not supported +pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family +pub const EADDRINUSE = 48; // Address already in use +pub const EADDRNOTAVAIL = 49; // Can't assign requested address + +// ipc/network software -- operational errors +pub const ENETDOWN = 50; // Network is down +pub const ENETUNREACH = 51; // Network is unreachable +pub const ENETRESET = 52; // Network dropped connection on reset +pub const ECONNABORTED = 53; // Software caused connection abort +pub const ECONNRESET = 54; // Connection reset by peer +pub const ENOBUFS = 55; // No buffer space available +pub const EISCONN = 56; // Socket is already connected +pub const ENOTCONN = 57; // Socket is not connected +pub const ESHUTDOWN = 58; // Can't send after socket shutdown +pub const ETOOMANYREFS = 59; // Too many references: can't splice +pub const ETIMEDOUT = 60; // Operation timed out +pub const ECONNREFUSED = 61; // Connection refused + +pub const ELOOP = 62; // Too many levels of symbolic links +pub const ENAMETOOLONG = 63; // File name too long + +// should be rearranged +pub const EHOSTDOWN = 64; // Host is down +pub const EHOSTUNREACH = 65; // No route to host +pub const ENOTEMPTY = 66; // Directory not empty + +// quotas & mush +pub const EPROCLIM = 67; // Too many processes +pub const EUSERS = 68; // Too many users +pub const EDQUOT = 69; // Disc quota exceeded + +// Network File System +pub const ESTALE = 70; // Stale NFS file handle +pub const EREMOTE = 71; // Too many levels of remote in path +pub const EBADRPC = 72; // RPC struct is bad +pub const ERPCMISMATCH = 73; // RPC version wrong +pub const EPROGUNAVAIL = 74; // RPC prog. not avail +pub const EPROGMISMATCH = 75; // Program version wrong +pub const EPROCUNAVAIL = 76; // Bad procedure for program + +pub const ENOLCK = 77; // No locks available +pub const ENOSYS = 78; // Function not implemented + +pub const EFTYPE = 79; // Inappropriate file type or format +pub const EAUTH = 80; // Authentication error +pub const ENEEDAUTH = 81; // Need authenticator +pub const EIDRM = 82; // Identifier removed +pub const ENOMSG = 83; // No message of desired type +pub const EOVERFLOW = 84; // Value too large to be stored in data type +pub const ECANCELED = 85; // Operation canceled +pub const EILSEQ = 86; // Illegal byte sequence +pub const ENOATTR = 87; // Attribute not found + +pub const EDOOFUS = 88; // Programming error + +pub const EBADMSG = 89; // Bad message +pub const EMULTIHOP = 90; // Multihop attempted +pub const ENOLINK = 91; // Link has been severed +pub const EPROTO = 92; // Protocol error + +pub const ENOTCAPABLE = 93; // Capabilities insufficient +pub const ECAPMODE = 94; // Not permitted in capability mode +pub const ENOTRECOVERABLE = 95; // State not recoverable +pub const EOWNERDEAD = 96; // Previous owner died + +pub const ELAST = 96; // Must be equal largest errno diff --git a/std/os/freebsd_i386.zig b/std/os/freebsd_i386.zig new file mode 100644 index 000000000..fd1f58639 --- /dev/null +++ b/std/os/freebsd_i386.zig @@ -0,0 +1,614 @@ +const freebsd = @import("freebsd.zig"); +const socklen_t = freebsd.socklen_t; +const iovec = freebsd.iovec; + +pub const SYS_syscall = 0; +pub const SYS_exit = 1; +pub const SYS_fork = 2; +pub const SYS_read = 3; +pub const SYS_write = 4; +pub const SYS_open = 5; +pub const SYS_close = 6; +pub const SYS_wait4 = 7; +// 8 is old creat +pub const SYS_link = 9; +pub const SYS_unlink = 10; +// 11 is obsolete execv +pub const SYS_chdir = 12; +pub const SYS_fchdir = 13; +pub const SYS_freebsd11_mknod = 14; +pub const SYS_chmod = 15; +pub const SYS_chown = 16; +pub const SYS_break = 17; +// 18 is freebsd4 getfsstat +// 19 is old lseek +pub const SYS_getpid = 20; +pub const SYS_mount = 21; +pub const SYS_unmount = 22; +pub const SYS_setuid = 23; +pub const SYS_getuid = 24; +pub const SYS_geteuid = 25; +pub const SYS_ptrace = 26; +pub const SYS_recvmsg = 27; +pub const SYS_sendmsg = 28; +pub const SYS_recvfrom = 29; +pub const SYS_accept = 30; +pub const SYS_getpeername = 31; +pub const SYS_getsockname = 32; +pub const SYS_access = 33; +pub const SYS_chflags = 34; +pub const SYS_fchflags = 35; +pub const SYS_sync = 36; +pub const SYS_kill = 37; +// 38 is old stat +pub const SYS_getppid = 39; +// 40 is old lstat +pub const SYS_dup = 41; +pub const SYS_freebsd10_pipe = 42; +pub const SYS_getegid = 43; +pub const SYS_profil = 44; +pub const SYS_ktrace = 45; +// 46 is old sigaction +pub const SYS_getgid = 47; +// 48 is old sigprocmask +pub const SYS_getlogin = 49; +pub const SYS_setlogin = 50; +pub const SYS_acct = 51; +// 52 is old sigpending +pub const SYS_sigaltstack = 53; +pub const SYS_ioctl = 54; +pub const SYS_reboot = 55; +pub const SYS_revoke = 56; +pub const SYS_symlink = 57; +pub const SYS_readlink = 58; +pub const SYS_execve = 59; +pub const SYS_umask = 60; +pub const SYS_chroot = 61; +// 62 is old fstat +// 63 is old getkerninfo +// 64 is old getpagesize +pub const SYS_msync = 65; +pub const SYS_vfork = 66; +// 67 is obsolete vread +// 68 is obsolete vwrite +pub const SYS_sbrk = 69; +pub const SYS_sstk = 70; +// 71 is old mmap +pub const SYS_vadvise = 72; +pub const SYS_munmap = 73; +pub const SYS_mprotect = 74; +pub const SYS_madvise = 75; +// 76 is obsolete vhangup +// 77 is obsolete vlimit +pub const SYS_mincore = 78; +pub const SYS_getgroups = 79; +pub const SYS_setgroups = 80; +pub const SYS_getpgrp = 81; +pub const SYS_setpgid = 82; +pub const SYS_setitimer = 83; +// 84 is old wait +pub const SYS_swapon = 85; +pub const SYS_getitimer = 86; +// 87 is old gethostname +// 88 is old sethostname +pub const SYS_getdtablesize = 89; +pub const SYS_dup2 = 90; +pub const SYS_fcntl = 92; +pub const SYS_select = 93; +pub const SYS_fsync = 95; +pub const SYS_setpriority = 96; +pub const SYS_socket = 97; +pub const SYS_connect = 98; +// 99 is old accept +pub const SYS_getpriority = 100; +// 101 is old send +// 102 is old recv +// 103 is old sigreturn +pub const SYS_bind = 104; +pub const SYS_setsockopt = 105; +pub const SYS_listen = 106; +// 107 is obsolete vtimes +// 108 is old sigvec +// 109 is old sigblock +// 110 is old sigsetmask +// 111 is old sigsuspend +// 112 is old sigstack +// 113 is old recvmsg +// 114 is old sendmsg +// 115 is obsolete vtrace +pub const SYS_gettimeofday = 116; +pub const SYS_getrusage = 117; +pub const SYS_getsockopt = 118; +pub const SYS_readv = 120; +pub const SYS_writev = 121; +pub const SYS_settimeofday = 122; +pub const SYS_fchown = 123; +pub const SYS_fchmod = 124; +// 125 is old recvfrom +pub const SYS_setreuid = 126; +pub const SYS_setregid = 127; +pub const SYS_rename = 128; +// 129 is old truncate +// 130 is old ftruncate +pub const SYS_flock = 131; +pub const SYS_mkfifo = 132; +pub const SYS_sendto = 133; +pub const SYS_shutdown = 134; +pub const SYS_socketpair = 135; +pub const SYS_mkdir = 136; +pub const SYS_rmdir = 137; +pub const SYS_utimes = 138; +// 139 is obsolete 4.2 sigreturn +pub const SYS_adjtime = 140; +// 141 is old getpeername +// 142 is old gethostid +// 143 is old sethostid +// 144 is old getrlimit +// 145 is old setrlimit +// 146 is old killpg +pub const SYS_setsid = 147; +pub const SYS_quotactl = 148; +// 149 is old quota +// 150 is old getsockname +pub const SYS_nlm_syscall = 154; +pub const SYS_nfssvc = 155; +// 156 is old getdirentries +// 157 is freebsd4 statfs +// 158 is freebsd4 fstatfs +pub const SYS_lgetfh = 160; +pub const SYS_getfh = 161; +// 162 is freebsd4 getdomainname +// 163 is freebsd4 setdomainname +// 164 is freebsd4 uname +pub const SYS_sysarch = 165; +pub const SYS_rtprio = 166; +pub const SYS_semsys = 169; +pub const SYS_msgsys = 170; +pub const SYS_shmsys = 171; +// 173 is freebsd6 pread +// 174 is freebsd6 pwrite +pub const SYS_setfib = 175; +pub const SYS_ntp_adjtime = 176; +pub const SYS_setgid = 181; +pub const SYS_setegid = 182; +pub const SYS_seteuid = 183; +pub const SYS_freebsd11_stat = 188; +pub const SYS_freebsd11_fstat = 189; +pub const SYS_freebsd11_lstat = 190; +pub const SYS_pathconf = 191; +pub const SYS_fpathconf = 192; +pub const SYS_getrlimit = 194; +pub const SYS_setrlimit = 195; +pub const SYS_freebsd11_getdirentries = 196; +// 197 is freebsd6 mmap +pub const SYS___syscall = 198; +// 199 is freebsd6 lseek +// 200 is freebsd6 truncate +// 201 is freebsd6 ftruncate +pub const SYS___sysctl = 202; +pub const SYS_mlock = 203; +pub const SYS_munlock = 204; +pub const SYS_undelete = 205; +pub const SYS_futimes = 206; +pub const SYS_getpgid = 207; +pub const SYS_poll = 209; +pub const SYS_freebsd7___semctl = 220; +pub const SYS_semget = 221; +pub const SYS_semop = 222; +pub const SYS_freebsd7_msgctl = 224; +pub const SYS_msgget = 225; +pub const SYS_msgsnd = 226; +pub const SYS_msgrcv = 227; +pub const SYS_shmat = 228; +pub const SYS_freebsd7_shmctl = 229; +pub const SYS_shmdt = 230; +pub const SYS_shmget = 231; +pub const SYS_clock_gettime = 232; +pub const SYS_clock_settime = 233; +pub const SYS_clock_getres = 234; +pub const SYS_ktimer_create = 235; +pub const SYS_ktimer_delete = 236; +pub const SYS_ktimer_settime = 237; +pub const SYS_ktimer_gettime = 238; +pub const SYS_ktimer_getoverrun = 239; +pub const SYS_nanosleep = 240; +pub const SYS_ffclock_getcounter = 241; +pub const SYS_ffclock_setestimate = 242; +pub const SYS_ffclock_getestimate = 243; +pub const SYS_clock_nanosleep = 244; +pub const SYS_clock_getcpuclockid2 = 247; +pub const SYS_ntp_gettime = 248; +pub const SYS_minherit = 250; +pub const SYS_rfork = 251; +// 252 is obsolete openbsd_poll +pub const SYS_issetugid = 253; +pub const SYS_lchown = 254; +pub const SYS_aio_read = 255; +pub const SYS_aio_write = 256; +pub const SYS_lio_listio = 257; +pub const SYS_freebsd11_getdents = 272; +pub const SYS_lchmod = 274; +pub const SYS_netbsd_lchown = 275; +pub const SYS_lutimes = 276; +pub const SYS_netbsd_msync = 277; +pub const SYS_freebsd11_nstat = 278; +pub const SYS_freebsd11_nfstat = 279; +pub const SYS_freebsd11_nlstat = 280; +pub const SYS_preadv = 289; +pub const SYS_pwritev = 290; +// 297 is freebsd4 fhstatfs +pub const SYS_fhopen = 298; +pub const SYS_freebsd11_fhstat = 299; +pub const SYS_modnext = 300; +pub const SYS_modstat = 301; +pub const SYS_modfnext = 302; +pub const SYS_modfind = 303; +pub const SYS_kldload = 304; +pub const SYS_kldunload = 305; +pub const SYS_kldfind = 306; +pub const SYS_kldnext = 307; +pub const SYS_kldstat = 308; +pub const SYS_kldfirstmod = 309; +pub const SYS_getsid = 310; +pub const SYS_setresuid = 311; +pub const SYS_setresgid = 312; +// 313 is obsolete signanosleep +pub const SYS_aio_return = 314; +pub const SYS_aio_suspend = 315; +pub const SYS_aio_cancel = 316; +pub const SYS_aio_error = 317; +// 318 is freebsd6 aio_read +// 319 is freebsd6 aio_write +// 320 is freebsd6 lio_listio +pub const SYS_yield = 321; +// 322 is obsolete thr_sleep +// 323 is obsolete thr_wakeup +pub const SYS_mlockall = 324; +pub const SYS_munlockall = 325; +pub const SYS___getcwd = 326; +pub const SYS_sched_setparam = 327; +pub const SYS_sched_getparam = 328; +pub const SYS_sched_setscheduler = 329; +pub const SYS_sched_getscheduler = 330; +pub const SYS_sched_yield = 331; +pub const SYS_sched_get_priority_max = 332; +pub const SYS_sched_get_priority_min = 333; +pub const SYS_sched_rr_get_interval = 334; +pub const SYS_utrace = 335; +// 336 is freebsd4 sendfile +pub const SYS_kldsym = 337; +pub const SYS_jail = 338; +pub const SYS_nnpfs_syscall = 339; +pub const SYS_sigprocmask = 340; +pub const SYS_sigsuspend = 341; +// 342 is freebsd4 sigaction +pub const SYS_sigpending = 343; +// 344 is freebsd4 sigreturn +pub const SYS_sigtimedwait = 345; +pub const SYS_sigwaitinfo = 346; +pub const SYS___acl_get_file = 347; +pub const SYS___acl_set_file = 348; +pub const SYS___acl_get_fd = 349; +pub const SYS___acl_set_fd = 350; +pub const SYS___acl_delete_file = 351; +pub const SYS___acl_delete_fd = 352; +pub const SYS___acl_aclcheck_file = 353; +pub const SYS___acl_aclcheck_fd = 354; +pub const SYS_extattrctl = 355; +pub const SYS_extattr_set_file = 356; +pub const SYS_extattr_get_file = 357; +pub const SYS_extattr_delete_file = 358; +pub const SYS_aio_waitcomplete = 359; +pub const SYS_getresuid = 360; +pub const SYS_getresgid = 361; +pub const SYS_kqueue = 362; +pub const SYS_freebsd11_kevent = 363; +pub const SYS_extattr_set_fd = 371; +pub const SYS_extattr_get_fd = 372; +pub const SYS_extattr_delete_fd = 373; +pub const SYS___setugid = 374; +pub const SYS_eaccess = 376; +pub const SYS_afs3_syscall = 377; +pub const SYS_nmount = 378; +pub const SYS___mac_get_proc = 384; +pub const SYS___mac_set_proc = 385; +pub const SYS___mac_get_fd = 386; +pub const SYS___mac_get_file = 387; +pub const SYS___mac_set_fd = 388; +pub const SYS___mac_set_file = 389; +pub const SYS_kenv = 390; +pub const SYS_lchflags = 391; +pub const SYS_uuidgen = 392; +pub const SYS_sendfile = 393; +pub const SYS_mac_syscall = 394; +pub const SYS_freebsd11_getfsstat = 395; +pub const SYS_freebsd11_statfs = 396; +pub const SYS_freebsd11_fstatfs = 397; +pub const SYS_freebsd11_fhstatfs = 398; +pub const SYS_ksem_close = 400; +pub const SYS_ksem_post = 401; +pub const SYS_ksem_wait = 402; +pub const SYS_ksem_trywait = 403; +pub const SYS_ksem_init = 404; +pub const SYS_ksem_open = 405; +pub const SYS_ksem_unlink = 406; +pub const SYS_ksem_getvalue = 407; +pub const SYS_ksem_destroy = 408; +pub const SYS___mac_get_pid = 409; +pub const SYS___mac_get_link = 410; +pub const SYS___mac_set_link = 411; +pub const SYS_extattr_set_link = 412; +pub const SYS_extattr_get_link = 413; +pub const SYS_extattr_delete_link = 414; +pub const SYS___mac_execve = 415; +pub const SYS_sigaction = 416; +pub const SYS_sigreturn = 417; +pub const SYS_getcontext = 421; +pub const SYS_setcontext = 422; +pub const SYS_swapcontext = 423; +pub const SYS_swapoff = 424; +pub const SYS___acl_get_link = 425; +pub const SYS___acl_set_link = 426; +pub const SYS___acl_delete_link = 427; +pub const SYS___acl_aclcheck_link = 428; +pub const SYS_sigwait = 429; +pub const SYS_thr_create = 430; +pub const SYS_thr_exit = 431; +pub const SYS_thr_self = 432; +pub const SYS_thr_kill = 433; +pub const SYS_jail_attach = 436; +pub const SYS_extattr_list_fd = 437; +pub const SYS_extattr_list_file = 438; +pub const SYS_extattr_list_link = 439; +pub const SYS_ksem_timedwait = 441; +pub const SYS_thr_suspend = 442; +pub const SYS_thr_wake = 443; +pub const SYS_kldunloadf = 444; +pub const SYS_audit = 445; +pub const SYS_auditon = 446; +pub const SYS_getauid = 447; +pub const SYS_setauid = 448; +pub const SYS_getaudit = 449; +pub const SYS_setaudit = 450; +pub const SYS_getaudit_addr = 451; +pub const SYS_setaudit_addr = 452; +pub const SYS_auditctl = 453; +pub const SYS__umtx_op = 454; +pub const SYS_thr_new = 455; +pub const SYS_sigqueue = 456; +pub const SYS_kmq_open = 457; +pub const SYS_kmq_setattr = 458; +pub const SYS_kmq_timedreceive = 459; +pub const SYS_kmq_timedsend = 460; +pub const SYS_kmq_notify = 461; +pub const SYS_kmq_unlink = 462; +pub const SYS_abort2 = 463; +pub const SYS_thr_set_name = 464; +pub const SYS_aio_fsync = 465; +pub const SYS_rtprio_thread = 466; +pub const SYS_sctp_peeloff = 471; +pub const SYS_sctp_generic_sendmsg = 472; +pub const SYS_sctp_generic_sendmsg_iov = 473; +pub const SYS_sctp_generic_recvmsg = 474; +pub const SYS_pread = 475; +pub const SYS_pwrite = 476; +pub const SYS_mmap = 477; +pub const SYS_lseek = 478; +pub const SYS_truncate = 479; +pub const SYS_ftruncate = 480; +pub const SYS_thr_kill2 = 481; +pub const SYS_shm_open = 482; +pub const SYS_shm_unlink = 483; +pub const SYS_cpuset = 484; +pub const SYS_cpuset_setid = 485; +pub const SYS_cpuset_getid = 486; +pub const SYS_cpuset_getaffinity = 487; +pub const SYS_cpuset_setaffinity = 488; +pub const SYS_faccessat = 489; +pub const SYS_fchmodat = 490; +pub const SYS_fchownat = 491; +pub const SYS_fexecve = 492; +pub const SYS_freebsd11_fstatat = 493; +pub const SYS_futimesat = 494; +pub const SYS_linkat = 495; +pub const SYS_mkdirat = 496; +pub const SYS_mkfifoat = 497; +pub const SYS_freebsd11_mknodat = 498; +pub const SYS_openat = 499; +pub const SYS_readlinkat = 500; +pub const SYS_renameat = 501; +pub const SYS_symlinkat = 502; +pub const SYS_unlinkat = 503; +pub const SYS_posix_openpt = 504; +pub const SYS_gssd_syscall = 505; +pub const SYS_jail_get = 506; +pub const SYS_jail_set = 507; +pub const SYS_jail_remove = 508; +pub const SYS_closefrom = 509; +pub const SYS___semctl = 510; +pub const SYS_msgctl = 511; +pub const SYS_shmctl = 512; +pub const SYS_lpathconf = 513; +// 514 is obsolete cap_new +pub const SYS___cap_rights_get = 515; +pub const SYS_cap_enter = 516; +pub const SYS_cap_getmode = 517; +pub const SYS_pdfork = 518; +pub const SYS_pdkill = 519; +pub const SYS_pdgetpid = 520; +pub const SYS_pselect = 522; +pub const SYS_getloginclass = 523; +pub const SYS_setloginclass = 524; +pub const SYS_rctl_get_racct = 525; +pub const SYS_rctl_get_rules = 526; +pub const SYS_rctl_get_limits = 527; +pub const SYS_rctl_add_rule = 528; +pub const SYS_rctl_remove_rule = 529; +pub const SYS_posix_fallocate = 530; +pub const SYS_posix_fadvise = 531; +pub const SYS_wait6 = 532; +pub const SYS_cap_rights_limit = 533; +pub const SYS_cap_ioctls_limit = 534; +pub const SYS_cap_ioctls_get = 535; +pub const SYS_cap_fcntls_limit = 536; +pub const SYS_cap_fcntls_get = 537; +pub const SYS_bindat = 538; +pub const SYS_connectat = 539; +pub const SYS_chflagsat = 540; +pub const SYS_accept4 = 541; +pub const SYS_pipe2 = 542; +pub const SYS_aio_mlock = 543; +pub const SYS_procctl = 544; +pub const SYS_ppoll = 545; +pub const SYS_futimens = 546; +pub const SYS_utimensat = 547; +pub const SYS_numa_getaffinity = 548; +pub const SYS_numa_setaffinity = 549; +pub const SYS_fdatasync = 550; +pub const SYS_fstat = 551; +pub const SYS_fstatat = 552; +pub const SYS_fhstat = 553; +pub const SYS_getdirentries = 554; +pub const SYS_statfs = 555; +pub const SYS_fstatfs = 556; +pub const SYS_getfsstat = 557; +pub const SYS_fhstatfs = 558; +pub const SYS_mknodat = 559; +pub const SYS_kevent = 560; +pub const SYS_MAXSYSCALL = 561; + +// From here +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o200000; +pub const O_NOFOLLOW = 0o400000; +pub const O_CLOEXEC = 0o2000000; + +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o40000; +pub const O_LARGEFILE = 0o100000; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 12; +pub const F_SETLK = 13; +pub const F_SETLKW = 14; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; + +pub inline fn syscall0(number: usize) -> usize { + asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number)) +} + +pub inline fn syscall1(number: usize, arg1: usize) -> usize { + asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ebx}" (arg1)) +} + +pub inline fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize { + asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ebx}" (arg1), + [arg2] "{ecx}" (arg2)) +} + +pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { + asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ebx}" (arg1), + [arg2] "{ecx}" (arg2), + [arg3] "{edx}" (arg3)) +} + +pub inline fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize { + asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ebx}" (arg1), + [arg2] "{ecx}" (arg2), + [arg3] "{edx}" (arg3), + [arg4] "{esi}" (arg4)) +} + +pub inline fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, + arg4: usize, arg5: usize) -> usize +{ + asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ebx}" (arg1), + [arg2] "{ecx}" (arg2), + [arg3] "{edx}" (arg3), + [arg4] "{esi}" (arg4), + [arg5] "{edi}" (arg5)) +} + +pub inline fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, + arg4: usize, arg5: usize, arg6: usize) -> usize +{ + asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ebx}" (arg1), + [arg2] "{ecx}" (arg2), + [arg3] "{edx}" (arg3), + [arg4] "{esi}" (arg4), + [arg5] "{edi}" (arg5), + [arg6] "{ebp}" (arg6)) +} + +pub nakedcc fn restore() { + asm volatile ( + \\popl %%eax + \\movl $119, %%eax + \\int $0x80 + : + : + : "rcx", "r11") +} + +pub nakedcc fn restore_rt() { + asm volatile ("int $0x80" + : + : [number] "{eax}" (usize(SYS_rt_sigreturn)) + : "rcx", "r11") +} + +export struct msghdr { + msg_name: &u8, + msg_namelen: socklen_t, + msg_iov: &iovec, + msg_iovlen: i32, + msg_control: &u8, + msg_controllen: socklen_t, + msg_flags: i32, +} diff --git a/std/os/freebsd_x86_64.zig b/std/os/freebsd_x86_64.zig new file mode 100644 index 000000000..ec3b93be1 --- /dev/null +++ b/std/os/freebsd_x86_64.zig @@ -0,0 +1,637 @@ +const freebsd = @import("freebsd.zig"); +const socklen_t = freebsd.socklen_t; +const iovec = freebsd.iovec; + +pub const SYS_syscall = 0; +pub const SYS_exit = 1; +pub const SYS_fork = 2; +pub const SYS_read = 3; +pub const SYS_write = 4; +pub const SYS_open = 5; +pub const SYS_close = 6; +pub const SYS_wait4 = 7; +// 8 is old creat +pub const SYS_link = 9; +pub const SYS_unlink = 10; +// 11 is obsolete execv +pub const SYS_chdir = 12; +pub const SYS_fchdir = 13; +pub const SYS_freebsd11_mknod = 14; +pub const SYS_chmod = 15; +pub const SYS_chown = 16; +pub const SYS_break = 17; +// 18 is freebsd4 getfsstat +// 19 is old lseek +pub const SYS_getpid = 20; +pub const SYS_mount = 21; +pub const SYS_unmount = 22; +pub const SYS_setuid = 23; +pub const SYS_getuid = 24; +pub const SYS_geteuid = 25; +pub const SYS_ptrace = 26; +pub const SYS_recvmsg = 27; +pub const SYS_sendmsg = 28; +pub const SYS_recvfrom = 29; +pub const SYS_accept = 30; +pub const SYS_getpeername = 31; +pub const SYS_getsockname = 32; +pub const SYS_access = 33; +pub const SYS_chflags = 34; +pub const SYS_fchflags = 35; +pub const SYS_sync = 36; +pub const SYS_kill = 37; +// 38 is old stat +pub const SYS_getppid = 39; +// 40 is old lstat +pub const SYS_dup = 41; +pub const SYS_freebsd10_pipe = 42; +pub const SYS_getegid = 43; +pub const SYS_profil = 44; +pub const SYS_ktrace = 45; +// 46 is old sigaction +pub const SYS_getgid = 47; +// 48 is old sigprocmask +pub const SYS_getlogin = 49; +pub const SYS_setlogin = 50; +pub const SYS_acct = 51; +// 52 is old sigpending +pub const SYS_sigaltstack = 53; +pub const SYS_ioctl = 54; +pub const SYS_reboot = 55; +pub const SYS_revoke = 56; +pub const SYS_symlink = 57; +pub const SYS_readlink = 58; +pub const SYS_execve = 59; +pub const SYS_umask = 60; +pub const SYS_chroot = 61; +// 62 is old fstat +// 63 is old getkerninfo +// 64 is old getpagesize +pub const SYS_msync = 65; +pub const SYS_vfork = 66; +// 67 is obsolete vread +// 68 is obsolete vwrite +pub const SYS_sbrk = 69; +pub const SYS_sstk = 70; +// 71 is old mmap +pub const SYS_vadvise = 72; +pub const SYS_munmap = 73; +pub const SYS_mprotect = 74; +pub const SYS_madvise = 75; +// 76 is obsolete vhangup +// 77 is obsolete vlimit +pub const SYS_mincore = 78; +pub const SYS_getgroups = 79; +pub const SYS_setgroups = 80; +pub const SYS_getpgrp = 81; +pub const SYS_setpgid = 82; +pub const SYS_setitimer = 83; +// 84 is old wait +pub const SYS_swapon = 85; +pub const SYS_getitimer = 86; +// 87 is old gethostname +// 88 is old sethostname +pub const SYS_getdtablesize = 89; +pub const SYS_dup2 = 90; +pub const SYS_fcntl = 92; +pub const SYS_select = 93; +pub const SYS_fsync = 95; +pub const SYS_setpriority = 96; +pub const SYS_socket = 97; +pub const SYS_connect = 98; +// 99 is old accept +pub const SYS_getpriority = 100; +// 101 is old send +// 102 is old recv +// 103 is old sigreturn +pub const SYS_bind = 104; +pub const SYS_setsockopt = 105; +pub const SYS_listen = 106; +// 107 is obsolete vtimes +// 108 is old sigvec +// 109 is old sigblock +// 110 is old sigsetmask +// 111 is old sigsuspend +// 112 is old sigstack +// 113 is old recvmsg +// 114 is old sendmsg +// 115 is obsolete vtrace +pub const SYS_gettimeofday = 116; +pub const SYS_getrusage = 117; +pub const SYS_getsockopt = 118; +pub const SYS_readv = 120; +pub const SYS_writev = 121; +pub const SYS_settimeofday = 122; +pub const SYS_fchown = 123; +pub const SYS_fchmod = 124; +// 125 is old recvfrom +pub const SYS_setreuid = 126; +pub const SYS_setregid = 127; +pub const SYS_rename = 128; +// 129 is old truncate +// 130 is old ftruncate +pub const SYS_flock = 131; +pub const SYS_mkfifo = 132; +pub const SYS_sendto = 133; +pub const SYS_shutdown = 134; +pub const SYS_socketpair = 135; +pub const SYS_mkdir = 136; +pub const SYS_rmdir = 137; +pub const SYS_utimes = 138; +// 139 is obsolete 4.2 sigreturn +pub const SYS_adjtime = 140; +// 141 is old getpeername +// 142 is old gethostid +// 143 is old sethostid +// 144 is old getrlimit +// 145 is old setrlimit +// 146 is old killpg +pub const SYS_setsid = 147; +pub const SYS_quotactl = 148; +// 149 is old quota +// 150 is old getsockname +pub const SYS_nlm_syscall = 154; +pub const SYS_nfssvc = 155; +// 156 is old getdirentries +// 157 is freebsd4 statfs +// 158 is freebsd4 fstatfs +pub const SYS_lgetfh = 160; +pub const SYS_getfh = 161; +// 162 is freebsd4 getdomainname +// 163 is freebsd4 setdomainname +// 164 is freebsd4 uname +pub const SYS_sysarch = 165; +pub const SYS_rtprio = 166; +pub const SYS_semsys = 169; +pub const SYS_msgsys = 170; +pub const SYS_shmsys = 171; +// 173 is freebsd6 pread +// 174 is freebsd6 pwrite +pub const SYS_setfib = 175; +pub const SYS_ntp_adjtime = 176; +pub const SYS_setgid = 181; +pub const SYS_setegid = 182; +pub const SYS_seteuid = 183; +pub const SYS_freebsd11_stat = 188; +pub const SYS_freebsd11_fstat = 189; +pub const SYS_freebsd11_lstat = 190; +pub const SYS_pathconf = 191; +pub const SYS_fpathconf = 192; +pub const SYS_getrlimit = 194; +pub const SYS_setrlimit = 195; +pub const SYS_freebsd11_getdirentries = 196; +// 197 is freebsd6 mmap +pub const SYS___syscall = 198; +// 199 is freebsd6 lseek +// 200 is freebsd6 truncate +// 201 is freebsd6 ftruncate +pub const SYS___sysctl = 202; +pub const SYS_mlock = 203; +pub const SYS_munlock = 204; +pub const SYS_undelete = 205; +pub const SYS_futimes = 206; +pub const SYS_getpgid = 207; +pub const SYS_poll = 209; +pub const SYS_freebsd7___semctl = 220; +pub const SYS_semget = 221; +pub const SYS_semop = 222; +pub const SYS_freebsd7_msgctl = 224; +pub const SYS_msgget = 225; +pub const SYS_msgsnd = 226; +pub const SYS_msgrcv = 227; +pub const SYS_shmat = 228; +pub const SYS_freebsd7_shmctl = 229; +pub const SYS_shmdt = 230; +pub const SYS_shmget = 231; +pub const SYS_clock_gettime = 232; +pub const SYS_clock_settime = 233; +pub const SYS_clock_getres = 234; +pub const SYS_ktimer_create = 235; +pub const SYS_ktimer_delete = 236; +pub const SYS_ktimer_settime = 237; +pub const SYS_ktimer_gettime = 238; +pub const SYS_ktimer_getoverrun = 239; +pub const SYS_nanosleep = 240; +pub const SYS_ffclock_getcounter = 241; +pub const SYS_ffclock_setestimate = 242; +pub const SYS_ffclock_getestimate = 243; +pub const SYS_clock_nanosleep = 244; +pub const SYS_clock_getcpuclockid2 = 247; +pub const SYS_ntp_gettime = 248; +pub const SYS_minherit = 250; +pub const SYS_rfork = 251; +// 252 is obsolete openbsd_poll +pub const SYS_issetugid = 253; +pub const SYS_lchown = 254; +pub const SYS_aio_read = 255; +pub const SYS_aio_write = 256; +pub const SYS_lio_listio = 257; +pub const SYS_freebsd11_getdents = 272; +pub const SYS_lchmod = 274; +pub const SYS_netbsd_lchown = 275; +pub const SYS_lutimes = 276; +pub const SYS_netbsd_msync = 277; +pub const SYS_freebsd11_nstat = 278; +pub const SYS_freebsd11_nfstat = 279; +pub const SYS_freebsd11_nlstat = 280; +pub const SYS_preadv = 289; +pub const SYS_pwritev = 290; +// 297 is freebsd4 fhstatfs +pub const SYS_fhopen = 298; +pub const SYS_freebsd11_fhstat = 299; +pub const SYS_modnext = 300; +pub const SYS_modstat = 301; +pub const SYS_modfnext = 302; +pub const SYS_modfind = 303; +pub const SYS_kldload = 304; +pub const SYS_kldunload = 305; +pub const SYS_kldfind = 306; +pub const SYS_kldnext = 307; +pub const SYS_kldstat = 308; +pub const SYS_kldfirstmod = 309; +pub const SYS_getsid = 310; +pub const SYS_setresuid = 311; +pub const SYS_setresgid = 312; +// 313 is obsolete signanosleep +pub const SYS_aio_return = 314; +pub const SYS_aio_suspend = 315; +pub const SYS_aio_cancel = 316; +pub const SYS_aio_error = 317; +// 318 is freebsd6 aio_read +// 319 is freebsd6 aio_write +// 320 is freebsd6 lio_listio +pub const SYS_yield = 321; +// 322 is obsolete thr_sleep +// 323 is obsolete thr_wakeup +pub const SYS_mlockall = 324; +pub const SYS_munlockall = 325; +pub const SYS___getcwd = 326; +pub const SYS_sched_setparam = 327; +pub const SYS_sched_getparam = 328; +pub const SYS_sched_setscheduler = 329; +pub const SYS_sched_getscheduler = 330; +pub const SYS_sched_yield = 331; +pub const SYS_sched_get_priority_max = 332; +pub const SYS_sched_get_priority_min = 333; +pub const SYS_sched_rr_get_interval = 334; +pub const SYS_utrace = 335; +// 336 is freebsd4 sendfile +pub const SYS_kldsym = 337; +pub const SYS_jail = 338; +pub const SYS_nnpfs_syscall = 339; +pub const SYS_sigprocmask = 340; +pub const SYS_sigsuspend = 341; +// 342 is freebsd4 sigaction +pub const SYS_sigpending = 343; +// 344 is freebsd4 sigreturn +pub const SYS_sigtimedwait = 345; +pub const SYS_sigwaitinfo = 346; +pub const SYS___acl_get_file = 347; +pub const SYS___acl_set_file = 348; +pub const SYS___acl_get_fd = 349; +pub const SYS___acl_set_fd = 350; +pub const SYS___acl_delete_file = 351; +pub const SYS___acl_delete_fd = 352; +pub const SYS___acl_aclcheck_file = 353; +pub const SYS___acl_aclcheck_fd = 354; +pub const SYS_extattrctl = 355; +pub const SYS_extattr_set_file = 356; +pub const SYS_extattr_get_file = 357; +pub const SYS_extattr_delete_file = 358; +pub const SYS_aio_waitcomplete = 359; +pub const SYS_getresuid = 360; +pub const SYS_getresgid = 361; +pub const SYS_kqueue = 362; +pub const SYS_freebsd11_kevent = 363; +pub const SYS_extattr_set_fd = 371; +pub const SYS_extattr_get_fd = 372; +pub const SYS_extattr_delete_fd = 373; +pub const SYS___setugid = 374; +pub const SYS_eaccess = 376; +pub const SYS_afs3_syscall = 377; +pub const SYS_nmount = 378; +pub const SYS___mac_get_proc = 384; +pub const SYS___mac_set_proc = 385; +pub const SYS___mac_get_fd = 386; +pub const SYS___mac_get_file = 387; +pub const SYS___mac_set_fd = 388; +pub const SYS___mac_set_file = 389; +pub const SYS_kenv = 390; +pub const SYS_lchflags = 391; +pub const SYS_uuidgen = 392; +pub const SYS_sendfile = 393; +pub const SYS_mac_syscall = 394; +pub const SYS_freebsd11_getfsstat = 395; +pub const SYS_freebsd11_statfs = 396; +pub const SYS_freebsd11_fstatfs = 397; +pub const SYS_freebsd11_fhstatfs = 398; +pub const SYS_ksem_close = 400; +pub const SYS_ksem_post = 401; +pub const SYS_ksem_wait = 402; +pub const SYS_ksem_trywait = 403; +pub const SYS_ksem_init = 404; +pub const SYS_ksem_open = 405; +pub const SYS_ksem_unlink = 406; +pub const SYS_ksem_getvalue = 407; +pub const SYS_ksem_destroy = 408; +pub const SYS___mac_get_pid = 409; +pub const SYS___mac_get_link = 410; +pub const SYS___mac_set_link = 411; +pub const SYS_extattr_set_link = 412; +pub const SYS_extattr_get_link = 413; +pub const SYS_extattr_delete_link = 414; +pub const SYS___mac_execve = 415; +pub const SYS_sigaction = 416; +pub const SYS_sigreturn = 417; +pub const SYS_getcontext = 421; +pub const SYS_setcontext = 422; +pub const SYS_swapcontext = 423; +pub const SYS_swapoff = 424; +pub const SYS___acl_get_link = 425; +pub const SYS___acl_set_link = 426; +pub const SYS___acl_delete_link = 427; +pub const SYS___acl_aclcheck_link = 428; +pub const SYS_sigwait = 429; +pub const SYS_thr_create = 430; +pub const SYS_thr_exit = 431; +pub const SYS_thr_self = 432; +pub const SYS_thr_kill = 433; +pub const SYS_jail_attach = 436; +pub const SYS_extattr_list_fd = 437; +pub const SYS_extattr_list_file = 438; +pub const SYS_extattr_list_link = 439; +pub const SYS_ksem_timedwait = 441; +pub const SYS_thr_suspend = 442; +pub const SYS_thr_wake = 443; +pub const SYS_kldunloadf = 444; +pub const SYS_audit = 445; +pub const SYS_auditon = 446; +pub const SYS_getauid = 447; +pub const SYS_setauid = 448; +pub const SYS_getaudit = 449; +pub const SYS_setaudit = 450; +pub const SYS_getaudit_addr = 451; +pub const SYS_setaudit_addr = 452; +pub const SYS_auditctl = 453; +pub const SYS__umtx_op = 454; +pub const SYS_thr_new = 455; +pub const SYS_sigqueue = 456; +pub const SYS_kmq_open = 457; +pub const SYS_kmq_setattr = 458; +pub const SYS_kmq_timedreceive = 459; +pub const SYS_kmq_timedsend = 460; +pub const SYS_kmq_notify = 461; +pub const SYS_kmq_unlink = 462; +pub const SYS_abort2 = 463; +pub const SYS_thr_set_name = 464; +pub const SYS_aio_fsync = 465; +pub const SYS_rtprio_thread = 466; +pub const SYS_sctp_peeloff = 471; +pub const SYS_sctp_generic_sendmsg = 472; +pub const SYS_sctp_generic_sendmsg_iov = 473; +pub const SYS_sctp_generic_recvmsg = 474; +pub const SYS_pread = 475; +pub const SYS_pwrite = 476; +pub const SYS_mmap = 477; +pub const SYS_lseek = 478; +pub const SYS_truncate = 479; +pub const SYS_ftruncate = 480; +pub const SYS_thr_kill2 = 481; +pub const SYS_shm_open = 482; +pub const SYS_shm_unlink = 483; +pub const SYS_cpuset = 484; +pub const SYS_cpuset_setid = 485; +pub const SYS_cpuset_getid = 486; +pub const SYS_cpuset_getaffinity = 487; +pub const SYS_cpuset_setaffinity = 488; +pub const SYS_faccessat = 489; +pub const SYS_fchmodat = 490; +pub const SYS_fchownat = 491; +pub const SYS_fexecve = 492; +pub const SYS_freebsd11_fstatat = 493; +pub const SYS_futimesat = 494; +pub const SYS_linkat = 495; +pub const SYS_mkdirat = 496; +pub const SYS_mkfifoat = 497; +pub const SYS_freebsd11_mknodat = 498; +pub const SYS_openat = 499; +pub const SYS_readlinkat = 500; +pub const SYS_renameat = 501; +pub const SYS_symlinkat = 502; +pub const SYS_unlinkat = 503; +pub const SYS_posix_openpt = 504; +pub const SYS_gssd_syscall = 505; +pub const SYS_jail_get = 506; +pub const SYS_jail_set = 507; +pub const SYS_jail_remove = 508; +pub const SYS_closefrom = 509; +pub const SYS___semctl = 510; +pub const SYS_msgctl = 511; +pub const SYS_shmctl = 512; +pub const SYS_lpathconf = 513; +// 514 is obsolete cap_new +pub const SYS___cap_rights_get = 515; +pub const SYS_cap_enter = 516; +pub const SYS_cap_getmode = 517; +pub const SYS_pdfork = 518; +pub const SYS_pdkill = 519; +pub const SYS_pdgetpid = 520; +pub const SYS_pselect = 522; +pub const SYS_getloginclass = 523; +pub const SYS_setloginclass = 524; +pub const SYS_rctl_get_racct = 525; +pub const SYS_rctl_get_rules = 526; +pub const SYS_rctl_get_limits = 527; +pub const SYS_rctl_add_rule = 528; +pub const SYS_rctl_remove_rule = 529; +pub const SYS_posix_fallocate = 530; +pub const SYS_posix_fadvise = 531; +pub const SYS_wait6 = 532; +pub const SYS_cap_rights_limit = 533; +pub const SYS_cap_ioctls_limit = 534; +pub const SYS_cap_ioctls_get = 535; +pub const SYS_cap_fcntls_limit = 536; +pub const SYS_cap_fcntls_get = 537; +pub const SYS_bindat = 538; +pub const SYS_connectat = 539; +pub const SYS_chflagsat = 540; +pub const SYS_accept4 = 541; +pub const SYS_pipe2 = 542; +pub const SYS_aio_mlock = 543; +pub const SYS_procctl = 544; +pub const SYS_ppoll = 545; +pub const SYS_futimens = 546; +pub const SYS_utimensat = 547; +pub const SYS_numa_getaffinity = 548; +pub const SYS_numa_setaffinity = 549; +pub const SYS_fdatasync = 550; +pub const SYS_fstat = 551; +pub const SYS_fstatat = 552; +pub const SYS_fhstat = 553; +pub const SYS_getdirentries = 554; +pub const SYS_statfs = 555; +pub const SYS_fstatfs = 556; +pub const SYS_getfsstat = 557; +pub const SYS_fhstatfs = 558; +pub const SYS_mknodat = 559; +pub const SYS_kevent = 560; +pub const SYS_MAXSYSCALL = 561; + +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o200000; +pub const O_NOFOLLOW = 0o400000; +pub const O_CLOEXEC = 0o2000000; + +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o40000; +pub const O_LARGEFILE = 0; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 5; +pub const F_SETLK = 6; +pub const F_SETLKW = 7; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; + +pub fn syscall0(number: usize) -> usize { + asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number) + : "rcx", "r11") +} + +pub fn syscall1(number: usize, arg1: usize) -> usize { + asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1) + : "rcx", "r11") +} + +pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize { + asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2) + : "rcx", "r11") +} + +pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { + asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3) + : "rcx", "r11") +} + +pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize { + asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4) + : "rcx", "r11") +} + +pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize { + asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5) + : "rcx", "r11") +} + +pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, + arg5: usize, arg6: usize) -> usize +{ + asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5), + [arg6] "{r9}" (arg6) + : "rcx", "r11") +} + +pub nakedcc fn restore_rt() { + asm volatile ("syscall" + : + : [number] "{rax}" (usize(SYS_rt_sigreturn)) + : "rcx", "r11") +} + + +pub const msghdr = extern struct { + msg_name: &u8, + msg_namelen: socklen_t, + msg_iov: &iovec, + msg_iovlen: i32, + __pad1: i32, + msg_control: &u8, + msg_controllen: socklen_t, + __pad2: socklen_t, + msg_flags: i32, +}; + +/// Renamed to Stat to not conflict with the stat function. +pub const Stat = extern struct { + dev: u64, + ino: u64, + nlink: usize, + + mode: u32, + uid: u32, + gid: u32, + __pad0: u32, + rdev: u64, + size: i64, + blksize: isize, + blocks: i64, + + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [3]isize, +}; + +pub const timespec = extern struct { + tv_sec: isize, + tv_nsec: isize, +}; diff --git a/std/os/get_user_id.zig b/std/os/get_user_id.zig index 1bcf69478..b56b0fd1f 100644 --- a/std/os/get_user_id.zig +++ b/std/os/get_user_id.zig @@ -11,7 +11,7 @@ pub const UserInfo = struct.{ /// POSIX function which gets a uid from username. pub fn getUserInfo(name: []const u8) !UserInfo { return switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name), + Os.linux, Os.macosx, Os.ios, Os.freebsd => posixGetUserInfo(name), else => @compileError("Unsupported OS"), }; } diff --git a/std/os/index.zig b/std/os/index.zig index d9e6c3c81..f332e8212 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -24,10 +24,12 @@ test "std.os" { pub const windows = @import("windows/index.zig"); pub const darwin = @import("darwin.zig"); pub const linux = @import("linux/index.zig"); +pub const freebsd = @import("freebsd.zig"); pub const zen = @import("zen.zig"); pub const posix = switch (builtin.os) { Os.linux => linux, Os.macosx, Os.ios => darwin, + Os.freebsd => freebsd, Os.zen => zen, else => @compileError("Unsupported OS"), }; @@ -174,7 +176,7 @@ pub fn abort() noreturn { c.abort(); } switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { _ = posix.raise(posix.SIGABRT); _ = posix.raise(posix.SIGKILL); while (true) {} @@ -196,7 +198,7 @@ pub fn exit(status: u8) noreturn { c.exit(status); } switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { posix.exit(status); }, Os.windows => { diff --git a/std/os/path.zig b/std/os/path.zig index 01409abb8..8096cdd0d 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1161,7 +1161,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro const pathname_w = try windows_util.cStrToPrefixedFileW(pathname); return realW(out_buffer, pathname_w); }, - Os.macosx, Os.ios => { + Os.macosx, Os.ios, Os.freebsd => { // TODO instead of calling the libc function here, port the implementation to Zig const err = posix.getErrno(posix.realpath(pathname, out_buffer)); switch (err) { @@ -1202,7 +1202,7 @@ pub fn real(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: []const u8) RealError! const pathname_w = try windows_util.sliceToPrefixedFileW(pathname); return realW(out_buffer, &pathname_w); }, - Os.macosx, Os.ios, Os.linux => { + Os.macosx, Os.ios, Os.linux, Os.freebsd => { const pathname_c = try os.toPosixPath(pathname); return realC(out_buffer, &pathname_c); }, From 264dd2eb579e78471c639baf698f7665ea016349 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Sat, 21 Oct 2017 22:24:15 +0000 Subject: [PATCH 004/110] Set FreeBSD ELF OS/ABI when targeting Closes #553. --- src/link.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/link.cpp b/src/link.cpp index 424b06169..613768cec 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -150,6 +150,10 @@ static const char *getLDMOption(const ZigTarget *t) { if (t->env_type == ZigLLVM_GNUX32) { return "elf32_x86_64"; } + // Any target elf will use the freebsd osabi if suffixed with "_fbsd". + if (t->os == OsFreeBSD) { + return "elf_x86_64_fbsd"; + } return "elf_x86_64"; default: zig_unreachable(); From 102cb61e401ba2266938882d8a7d751a31a49ab2 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Mon, 9 Jul 2018 20:54:36 +1200 Subject: [PATCH 005/110] Get freebsd std compiling again --- std/os/freebsd.zig | 527 +++++++++++++------------------------- std/os/freebsd_errno.zig | 200 +++++++-------- std/os/freebsd_x86_64.zig | 143 ++++++----- std/os/index.zig | 2 +- 4 files changed, 362 insertions(+), 510 deletions(-) diff --git a/std/os/freebsd.zig b/std/os/freebsd.zig index 7fd233aef..ee7e93d65 100644 --- a/std/os/freebsd.zig +++ b/std/os/freebsd.zig @@ -1,11 +1,11 @@ +const c = @import("../c/index.zig"); const assert = @import("../debug.zig").assert; const builtin = @import("builtin"); const arch = switch (builtin.arch) { - builtin.Arch.x86_64 => @import("freebsd_x86_64.zig"), - builtin.Arch.i386 => @import("freebsd_i386.zig"), + builtin.Arch.x86_64 => @import("x86_64.zig"), else => @compileError("unsupported arch"), }; -pub use @import("freebsd_errno.zig"); +pub use @import("errno.zig"); pub const PATH_MAX = 1024; @@ -13,85 +13,86 @@ pub const STDIN_FILENO = 0; pub const STDOUT_FILENO = 1; pub const STDERR_FILENO = 2; -pub const PROT_NONE = 0; -pub const PROT_READ = 1; -pub const PROT_WRITE = 2; -pub const PROT_EXEC = 4; +pub const PROT_NONE = 0; +pub const PROT_READ = 1; +pub const PROT_WRITE = 2; +pub const PROT_EXEC = 4; -pub const MAP_FAILED = @maxValue(usize); -pub const MAP_SHARED = 0x0001; -pub const MAP_PRIVATE = 0x0002; -pub const MAP_FIXED = 0x0010; -pub const MAP_STACK = 0x0400; -pub const MAP_NOSYNC = 0x0800; -pub const MAP_ANON = 0x1000; -pub const MAP_ANONYMOUS = MAP_ANON; -pub const MAP_FILE = 0; +pub const MAP_FAILED = @maxValue(usize); +pub const MAP_SHARED = 0x0001; +pub const MAP_PRIVATE = 0x0002; +pub const MAP_FIXED = 0x0010; +pub const MAP_STACK = 0x0400; +pub const MAP_NOSYNC = 0x0800; +pub const MAP_ANON = 0x1000; +pub const MAP_ANONYMOUS = MAP_ANON; +pub const MAP_FILE = 0; +pub const MAP_NORESERVE = 0; -pub const MAP_GUARD = 0x00002000; -pub const MAP_EXCL = 0x00004000; -pub const MAP_NOCORE = 0x00020000; +pub const MAP_GUARD = 0x00002000; +pub const MAP_EXCL = 0x00004000; +pub const MAP_NOCORE = 0x00020000; pub const MAP_PREFAULT_READ = 0x00040000; -pub const MAP_32BIT = 0x00080000; +pub const MAP_32BIT = 0x00080000; -pub const WNOHANG = 1; -pub const WUNTRACED = 2; -pub const WSTOPPED = WUNTRACED; +pub const WNOHANG = 1; +pub const WUNTRACED = 2; +pub const WSTOPPED = WUNTRACED; pub const WCONTINUED = 4; -pub const WNOWAIT = 8; -pub const WEXITED = 16; -pub const WTRAPPED = 32; +pub const WNOWAIT = 8; +pub const WEXITED = 16; +pub const WTRAPPED = 32; -pub const SA_ONSTACK = 0x0001; -pub const SA_RESTART = 0x0002; +pub const SA_ONSTACK = 0x0001; +pub const SA_RESTART = 0x0002; pub const SA_RESETHAND = 0x0004; pub const SA_NOCLDSTOP = 0x0008; -pub const SA_NODEFER = 0x0010; +pub const SA_NODEFER = 0x0010; pub const SA_NOCLDWAIT = 0x0020; -pub const SA_SIGINFO = 0x0040; +pub const SA_SIGINFO = 0x0040; -pub const SIGHUP = 1; -pub const SIGINT = 2; -pub const SIGQUIT = 3; -pub const SIGILL = 4; -pub const SIGTRAP = 5; -pub const SIGABRT = 6; -pub const SIGIOT = SIGABRT; -pub const SIGEMT = 7; -pub const SIGFPE = 8; -pub const SIGKILL = 9; -pub const SIGBUS = 10; -pub const SIGSEGV = 11; -pub const SIGSYS = 12; -pub const SIGPIPE = 13; -pub const SIGALRM = 14; -pub const SIGTERM = 15; -pub const SIGURG = 16; -pub const SIGSTOP = 17; -pub const SIGTSTP = 18; -pub const SIGCONT = 19; -pub const SIGCHLD = 20; -pub const SIGTTIN = 21; -pub const SIGTTOU = 22; -pub const SIGIO = 23; -pub const SIGXCPU = 24; -pub const SIGXFSZ = 25; +pub const SIGHUP = 1; +pub const SIGINT = 2; +pub const SIGQUIT = 3; +pub const SIGILL = 4; +pub const SIGTRAP = 5; +pub const SIGABRT = 6; +pub const SIGIOT = SIGABRT; +pub const SIGEMT = 7; +pub const SIGFPE = 8; +pub const SIGKILL = 9; +pub const SIGBUS = 10; +pub const SIGSEGV = 11; +pub const SIGSYS = 12; +pub const SIGPIPE = 13; +pub const SIGALRM = 14; +pub const SIGTERM = 15; +pub const SIGURG = 16; +pub const SIGSTOP = 17; +pub const SIGTSTP = 18; +pub const SIGCONT = 19; +pub const SIGCHLD = 20; +pub const SIGTTIN = 21; +pub const SIGTTOU = 22; +pub const SIGIO = 23; +pub const SIGXCPU = 24; +pub const SIGXFSZ = 25; pub const SIGVTALRM = 26; -pub const SIGPROF = 27; -pub const SIGWINCH = 28; -pub const SIGINFO = 29; -pub const SIGUSR1 = 30; -pub const SIGUSR2 = 31; -pub const SIGTHR = 32; -pub const SIGLWP = SIGTHR; -pub const SIGLIBRT = 33; +pub const SIGPROF = 27; +pub const SIGWINCH = 28; +pub const SIGINFO = 29; +pub const SIGUSR1 = 30; +pub const SIGUSR2 = 31; +pub const SIGTHR = 32; +pub const SIGLWP = SIGTHR; +pub const SIGLIBRT = 33; -pub const SIGRTMIN = 65; -pub const SIGRTMAX = 126; +pub const SIGRTMIN = 65; +pub const SIGRTMAX = 126; pub const O_RDONLY = 0o0; pub const O_WRONLY = 0o1; -pub const O_RDWR = 0o2; +pub const O_RDWR = 0o2; pub const O_ACCMODE = 0o3; pub const O_CREAT = arch.O_CREAT; @@ -119,7 +120,7 @@ pub const SEEK_SET = 0; pub const SEEK_CUR = 1; pub const SEEK_END = 2; -pub const SIG_BLOCK = 1; +pub const SIG_BLOCK = 1; pub const SIG_UNBLOCK = 2; pub const SIG_SETMASK = 3; @@ -272,7 +273,6 @@ pub const DT_LNK = 10; pub const DT_SOCK = 12; pub const DT_WHT = 14; - pub const TCGETS = 0x5401; pub const TCSETS = 0x5402; pub const TCSETSW = 0x5403; @@ -329,15 +329,30 @@ pub const TIOCGPKT = 0x80045438; pub const TIOCGPTLCK = 0x80045439; pub const TIOCGEXCL = 0x80045440; -fn unsigned(s: i32) -> u32 { @bitCast(u32, s) } -fn signed(s: u32) -> i32 { @bitCast(i32, s) } -pub fn WEXITSTATUS(s: i32) -> i32 { signed((unsigned(s) & 0xff00) >> 8) } -pub fn WTERMSIG(s: i32) -> i32 { signed(unsigned(s) & 0x7f) } -pub fn WSTOPSIG(s: i32) -> i32 { WEXITSTATUS(s) } -pub fn WIFEXITED(s: i32) -> bool { WTERMSIG(s) == 0 } -pub fn WIFSTOPPED(s: i32) -> bool { (u16)(((unsigned(s)&0xffff)*%0x10001)>>8) > 0x7f00 } -pub fn WIFSIGNALED(s: i32) -> bool { (unsigned(s)&0xffff)-%1 < 0xff } - +fn unsigned(s: i32) u32 { + return @bitCast(u32, s); +} +fn signed(s: u32) i32 { + return @bitCast(i32, s); +} +pub fn WEXITSTATUS(s: i32) i32 { + return signed((unsigned(s) & 0xff00) >> 8); +} +pub fn WTERMSIG(s: i32) i32 { + return signed(unsigned(s) & 0x7f); +} +pub fn WSTOPSIG(s: i32) i32 { + return WEXITSTATUS(s); +} +pub fn WIFEXITED(s: i32) bool { + return WTERMSIG(s) == 0; +} +pub fn WIFSTOPPED(s: i32) bool { + return (u16)(((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00; +} +pub fn WIFSIGNALED(s: i32) bool { + return (unsigned(s) & 0xffff) -% 1 < 0xff; +} pub const winsize = extern struct { ws_row: u16, @@ -347,182 +362,160 @@ pub const winsize = extern struct { }; /// Get the errno from a syscall return value, or 0 for no error. -pub fn getErrno(r: usize) -> usize { +pub fn getErrno(r: usize) usize { const signed_r = @bitCast(isize, r); - if (signed_r > -4096 and signed_r < 0) usize(-signed_r) else 0 + return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0; } -pub fn dup2(old: i32, new: i32) -> usize { - arch.syscall2(arch.SYS_dup2, usize(old), usize(new)) +pub fn dup2(old: i32, new: i32) usize { + return arch.syscall2(arch.SYS_dup2, usize(old), usize(new)); } -pub fn chdir(path: &const u8) -> usize { - arch.syscall1(arch.SYS_chdir, @ptrToInt(path)) +pub fn chdir(path: [*]const u8) usize { + return arch.syscall1(arch.SYS_chdir, @ptrToInt(path)); } -pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize { - arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)) +pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { + return arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); } -pub fn fork() -> usize { - arch.syscall0(arch.SYS_fork) +pub fn fork() usize { + return arch.syscall0(arch.SYS_fork); } -pub fn getcwd(buf: &u8, size: usize) -> usize { - arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size) +pub fn getcwd(buf: [*]u8, size: usize) usize { + return arch.syscall2(arch.SYS___getcwd, @ptrToInt(buf), size); } -pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize { - arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count) +pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { + return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count); } -pub fn isatty(fd: i32) -> bool { +pub fn isatty(fd: i32) bool { var wsz: winsize = undefined; - return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; + return arch.syscall3(arch.SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } -pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize { - arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len) +pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { + return arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); } -pub fn mkdir(path: &const u8, mode: u32) -> usize { - arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode) +pub fn mkdir(path: [*]const u8, mode: u32) usize { + return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode); } -pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) - -> usize -{ - arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), - @bitCast(usize, offset)) +pub fn mmap(address: ?*u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize { + return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset)); } -pub fn munmap(address: &u8, length: usize) -> usize { - arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length) +pub fn munmap(address: usize, length: usize) usize { + return arch.syscall2(arch.SYS_munmap, address, length); } -pub fn read(fd: i32, buf: &u8, count: usize) -> usize { - arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count) +pub fn read(fd: i32, buf: [*]u8, count: usize) usize { + return arch.syscall3(arch.SYS_read, @intCast(usize, fd), @ptrToInt(buf), count); } -pub fn rmdir(path: &const u8) -> usize { - arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)) +pub fn rmdir(path: [*]const u8) usize { + return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)); } -pub fn symlink(existing: &const u8, new: &const u8) -> usize { - arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)) +pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { + return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); } -pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize { - arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset) +pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { + return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset); } -pub fn pipe(fd: &[2]i32) -> usize { - pipe2(fd, 0) +pub fn pipe(fd: *[2]i32) usize { + return pipe2(fd, 0); } -pub fn pipe2(fd: &[2]i32, flags: usize) -> usize { - arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags) +pub fn pipe2(fd: *[2]i32, flags: usize) usize { + return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags); } -pub fn write(fd: i32, buf: &const u8, count: usize) -> usize { - arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count) +pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { + return arch.syscall3(arch.SYS_write, @intCast(usize, fd), @ptrToInt(buf), count); } -pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize { - arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset) +pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { + return arch.syscall4(arch.SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); } -pub fn rename(old: &const u8, new: &const u8) -> usize { - arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)) +pub fn rename(old: [*]const u8, new: [*]const u8) usize { + return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)); } -pub fn open(path: &const u8, flags: u32, perm: usize) -> usize { - arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm) +pub fn open(path: [*]const u8, flags: u32, perm: usize) usize { + return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm); } -pub fn create(path: &const u8, perm: usize) -> usize { - arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm) +pub fn create(path: [*]const u8, perm: usize) usize { + return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm); } -pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize { - arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode) +pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize { + return arch.syscall4(arch.SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode); } -pub fn close(fd: i32) -> usize { - arch.syscall1(arch.SYS_close, usize(fd)) +pub fn close(fd: i32) usize { + return arch.syscall1(arch.SYS_close, @intCast(usize, fd)); } -pub fn lseek(fd: i32, offset: isize, ref_pos: usize) -> usize { - arch.syscall3(arch.SYS_lseek, usize(fd), @bitCast(usize, offset), ref_pos) +pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { + return arch.syscall3(arch.SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos); } -pub fn exit(status: i32) -> noreturn { +pub fn exit(status: i32) noreturn { _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status))); - unreachable + unreachable; } -pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize { - arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags)) +pub fn getrandom(buf: &u8, count: usize, flags: u32) usize { + return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, @bitCast(usize, flags)); } -pub fn kill(pid: i32, sig: i32) -> usize { - arch.syscall2(arch.SYS_kill, @bitCast(usize, isize(pid)), usize(sig)) +pub fn kill(pid: i32, sig: i32) usize { + return arch.syscall2(arch.SYS_kill, @bitCast(usize, @intCast(isize, pid)), @intCast(usize, sig)); } -pub fn unlink(path: &const u8) -> usize { - arch.syscall1(arch.SYS_unlink, @ptrToInt(path)) +pub fn unlink(path: [*]const u8) usize { + return arch.syscall1(arch.SYS_unlink, @ptrToInt(path)); } -pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize { - arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0) +pub fn waitpid(pid: i32, status: *i32, options: i32) usize { + return arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); } -pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize { - arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)) +pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { + return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); } -pub fn setuid(uid: u32) -> usize { - arch.syscall1(arch.SYS_setuid, uid) +pub fn setuid(uid: u32) usize { + return arch.syscall1(arch.SYS_setuid, uid); } -pub fn setgid(gid: u32) -> usize { - arch.syscall1(arch.SYS_setgid, gid) +pub fn setgid(gid: u32) usize { + return arch.syscall1(arch.SYS_setgid, gid); } -pub fn setreuid(ruid: u32, euid: u32) -> usize { - arch.syscall2(arch.SYS_setreuid, ruid, euid) +pub fn setreuid(ruid: u32, euid: u32) usize { + return arch.syscall2(arch.SYS_setreuid, ruid, euid); } -pub fn setregid(rgid: u32, egid: u32) -> usize { - arch.syscall2(arch.SYS_setregid, rgid, egid) +pub fn setregid(rgid: u32, egid: u32) usize { + return arch.syscall2(arch.SYS_setregid, rgid, egid); } -pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize { - arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8) +pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize { + // TODO: Implement + return 0; } -pub fn sigaction(sig: u6, noalias act: &const Sigaction, noalias oact: ?&Sigaction) -> usize { - assert(sig >= 1); - assert(sig != SIGKILL); - assert(sig != SIGSTOP); - var ksa = k_sigaction { - .handler = act.handler, - .flags = act.flags | SA_RESTORER, - .mask = undefined, - .restorer = @ptrCast(extern fn(), arch.restore_rt), - }; - var ksa_old: k_sigaction = undefined; - @memcpy(@ptrCast(&u8, &ksa.mask), @ptrCast(&const u8, &act.mask), 8); - const result = arch.syscall4(arch.SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask))); - const err = getErrno(result); - if (err != 0) { - return result; - } - if (oact) |old| { - old.handler = ksa_old.handler; - old.flags = @truncate(u32, ksa_old.flags); - @memcpy(@ptrCast(&u8, &old.mask), @ptrCast(&const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask))); - } +pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize { + // TODO: Implement return 0; } @@ -531,203 +524,49 @@ const sigset_t = [128 / @sizeOf(usize)]usize; const all_mask = []usize{@maxValue(usize)}; const app_mask = []usize{0xfffffffc7fffffff}; -const k_sigaction = extern struct { - handler: extern fn(i32), - flags: usize, - restorer: extern fn(), - mask: [2]u32, -}; - /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = struct { - handler: extern fn(i32), + // TODO: Adjust to use freebsd struct layout + handler: extern fn (i32) void, mask: sigset_t, flags: u32, }; -pub const SIG_ERR = @intToPtr(extern fn(i32), @maxValue(usize)); -pub const SIG_DFL = @intToPtr(extern fn(i32), 0); -pub const SIG_IGN = @intToPtr(extern fn(i32), 1); +pub const SIG_ERR = @intToPtr(extern fn (i32) void, @maxValue(usize)); +pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); +pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); pub const empty_sigset = []usize{0} ** sigset_t.len; -pub fn raise(sig: i32) -> usize { +pub fn raise(sig: i32) usize { // TODO implement, see linux equivalent for what we want to try and do return 0; } -fn blockAllSignals(set: &sigset_t) { +fn blockAllSignals(set: *sigset_t) void { // TODO implement } -fn blockAppSignals(set: &sigset_t) { +fn blockAppSignals(set: *sigset_t) void { // TODO implement } -fn restoreSignals(set: &sigset_t) { +fn restoreSignals(set: *sigset_t) void { // TODO implement } -pub fn sigaddset(set: &sigset_t, sig: u6) { +pub fn sigaddset(set: *sigset_t, sig: u6) void { const s = sig - 1; (*set)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1)); } -pub fn sigismember(set: &const sigset_t, sig: u6) -> bool { +pub fn sigismember(set: *const sigset_t, sig: u6) bool { const s = sig - 1; return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0; } - -pub const sa_family_t = u16; -pub const socklen_t = u32; -pub const in_addr = u32; -pub const in6_addr = [16]u8; - -pub const sockaddr = extern struct { - family: sa_family_t, - port: u16, - data: [12]u8, -}; - -pub const sockaddr_in = extern struct { - family: sa_family_t, - port: u16, - addr: in_addr, - zero: [8]u8, -}; - -pub const sockaddr_in6 = extern struct { - family: sa_family_t, - port: u16, - flowinfo: u32, - addr: in6_addr, - scope_id: u32, -}; - -pub const iovec = extern struct { - iov_base: &u8, - iov_len: usize, -}; - -// -//const IF_NAMESIZE = 16; -// -//export struct ifreq { -// ifrn_name: [IF_NAMESIZE]u8, -// union { -// ifru_addr: sockaddr, -// ifru_dstaddr: sockaddr, -// ifru_broadaddr: sockaddr, -// ifru_netmask: sockaddr, -// ifru_hwaddr: sockaddr, -// ifru_flags: i16, -// ifru_ivalue: i32, -// ifru_mtu: i32, -// ifru_map: ifmap, -// ifru_slave: [IF_NAMESIZE]u8, -// ifru_newname: [IF_NAMESIZE]u8, -// ifru_data: &u8, -// } ifr_ifru; -//} -// - -pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { - arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)) -} - -pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { - arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len)) -} - -pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize { - arch.syscall3(arch.SYS_socket, usize(domain), usize(socket_type), usize(protocol)) -} - -pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize { - arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen)) -} - -pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize { - arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen)) -} - -pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize { - arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags) -} - -pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { - arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len)) -} - -pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize { - arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags) -} - -pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32, - noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize -{ - arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)) -} - -pub fn shutdown(fd: i32, how: i32) -> usize { - arch.syscall2(arch.SYS_shutdown, usize(fd), usize(how)) -} - -pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize { - arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len)) -} - -pub fn listen(fd: i32, backlog: i32) -> usize { - arch.syscall2(arch.SYS_listen, usize(fd), usize(backlog)) -} - -pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize { - arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen)) -} - -pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize { - arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0])) -} - -pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { - accept4(fd, addr, len, 0) -} - -pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize { - arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags) -} - -// error NameTooLong; -// error SystemResources; -// error Io; -// -// pub fn if_nametoindex(name: []u8) -> %u32 { -// var ifr: ifreq = undefined; -// -// if (name.len >= ifr.ifr_name.len) { -// return error.NameTooLong; -// } -// -// const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); -// const socket_err = getErrno(socket_ret); -// if (socket_err > 0) { -// return error.SystemResources; -// } -// const socket_fd = i32(socket_ret); -// @memcpy(&ifr.ifr_name[0], &name[0], name.len); -// ifr.ifr_name[name.len] = 0; -// const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr); -// close(socket_fd); -// const ioctl_err = getErrno(ioctl_ret); -// if (ioctl_err > 0) { -// return error.Io; -// } -// return ifr.ifr_ifindex; -// } - pub const Stat = arch.Stat; pub const timespec = arch.timespec; -pub fn fstat(fd: i32, stat_buf: &Stat) -> usize { - arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf)) +pub fn fstat(fd: i32, stat_buf: *Stat) usize { + return arch.syscall2(arch.SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); } diff --git a/std/os/freebsd_errno.zig b/std/os/freebsd_errno.zig index 132683de1..0a0d825f5 100644 --- a/std/os/freebsd_errno.zig +++ b/std/os/freebsd_errno.zig @@ -1,121 +1,121 @@ -pub const EPERM = 1; // Operation not permitted -pub const ENOENT = 2; // No such file or directory -pub const ESRCH = 3; // No such process -pub const EINTR = 4; // Interrupted system call -pub const EIO = 5; // Input/output error -pub const ENXIO = 6; // Device not configured -pub const E2BIG = 7; // Argument list too long -pub const ENOEXEC = 8; // Exec format error -pub const EBADF = 9; // Bad file descriptor -pub const ECHILD = 10; // No child processes -pub const EDEADLK = 11; // Resource deadlock avoided - // 11 was EAGAIN -pub const ENOMEM = 12; // Cannot allocate memory -pub const EACCES = 13; // Permission denied -pub const EFAULT = 14; // Bad address -pub const ENOTBLK = 15; // Block device required -pub const EBUSY = 16; // Device busy -pub const EEXIST = 17; // File exists -pub const EXDEV = 18; // Cross-device link -pub const ENODEV = 19; // Operation not supported by device -pub const ENOTDIR = 20; // Not a directory -pub const EISDIR = 21; // Is a directory -pub const EINVAL = 22; // Invalid argument -pub const ENFILE = 23; // Too many open files in system -pub const EMFILE = 24; // Too many open files -pub const ENOTTY = 25; // Inappropriate ioctl for device -pub const ETXTBSY = 26; // Text file busy -pub const EFBIG = 27; // File too large -pub const ENOSPC = 28; // No space left on device -pub const ESPIPE = 29; // Illegal seek -pub const EROFS = 30; // Read-only filesystem -pub const EMLINK = 31; // Too many links -pub const EPIPE = 32; // Broken pipe +pub const EPERM = 1; // Operation not permitted +pub const ENOENT = 2; // No such file or directory +pub const ESRCH = 3; // No such process +pub const EINTR = 4; // Interrupted system call +pub const EIO = 5; // Input/output error +pub const ENXIO = 6; // Device not configured +pub const E2BIG = 7; // Argument list too long +pub const ENOEXEC = 8; // Exec format error +pub const EBADF = 9; // Bad file descriptor +pub const ECHILD = 10; // No child processes +pub const EDEADLK = 11; // Resource deadlock avoided +// 11 was EAGAIN +pub const ENOMEM = 12; // Cannot allocate memory +pub const EACCES = 13; // Permission denied +pub const EFAULT = 14; // Bad address +pub const ENOTBLK = 15; // Block device required +pub const EBUSY = 16; // Device busy +pub const EEXIST = 17; // File exists +pub const EXDEV = 18; // Cross-device link +pub const ENODEV = 19; // Operation not supported by device +pub const ENOTDIR = 20; // Not a directory +pub const EISDIR = 21; // Is a directory +pub const EINVAL = 22; // Invalid argument +pub const ENFILE = 23; // Too many open files in system +pub const EMFILE = 24; // Too many open files +pub const ENOTTY = 25; // Inappropriate ioctl for device +pub const ETXTBSY = 26; // Text file busy +pub const EFBIG = 27; // File too large +pub const ENOSPC = 28; // No space left on device +pub const ESPIPE = 29; // Illegal seek +pub const EROFS = 30; // Read-only filesystem +pub const EMLINK = 31; // Too many links +pub const EPIPE = 32; // Broken pipe // math software -pub const EDOM = 33; // Numerical argument out of domain -pub const ERANGE = 34; // Result too large +pub const EDOM = 33; // Numerical argument out of domain +pub const ERANGE = 34; // Result too large // non-blocking and interrupt i/o -pub const EAGAIN = 35; // Resource temporarily unavailable -pub const EWOULDBLOCK = EAGAIN; // Operation would block -pub const EINPROGRESS = 36; // Operation now in progress -pub const EALREADY = 37; // Operation already in progress +pub const EAGAIN = 35; // Resource temporarily unavailable +pub const EWOULDBLOCK = EAGAIN; // Operation would block +pub const EINPROGRESS = 36; // Operation now in progress +pub const EALREADY = 37; // Operation already in progress // ipc/network software -- argument errors -pub const ENOTSOCK = 38; // Socket operation on non-socket -pub const EDESTADDRREQ = 39; // Destination address required -pub const EMSGSIZE = 40; // Message too long -pub const EPROTOTYPE = 41; // Protocol wrong type for socket -pub const ENOPROTOOPT = 42; // Protocol not available -pub const EPROTONOSUPPORT = 43; // Protocol not supported -pub const ESOCKTNOSUPPORT = 44; // Socket type not supported -pub const EOPNOTSUPP = 45; // Operation not supported -pub const ENOTSUP = EOPNOTSUPP; // Operation not supported -pub const EPFNOSUPPORT = 46; // Protocol family not supported -pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family -pub const EADDRINUSE = 48; // Address already in use -pub const EADDRNOTAVAIL = 49; // Can't assign requested address +pub const ENOTSOCK = 38; // Socket operation on non-socket +pub const EDESTADDRREQ = 39; // Destination address required +pub const EMSGSIZE = 40; // Message too long +pub const EPROTOTYPE = 41; // Protocol wrong type for socket +pub const ENOPROTOOPT = 42; // Protocol not available +pub const EPROTONOSUPPORT = 43; // Protocol not supported +pub const ESOCKTNOSUPPORT = 44; // Socket type not supported +pub const EOPNOTSUPP = 45; // Operation not supported +pub const ENOTSUP = EOPNOTSUPP; // Operation not supported +pub const EPFNOSUPPORT = 46; // Protocol family not supported +pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family +pub const EADDRINUSE = 48; // Address already in use +pub const EADDRNOTAVAIL = 49; // Can't assign requested address // ipc/network software -- operational errors -pub const ENETDOWN = 50; // Network is down -pub const ENETUNREACH = 51; // Network is unreachable -pub const ENETRESET = 52; // Network dropped connection on reset -pub const ECONNABORTED = 53; // Software caused connection abort -pub const ECONNRESET = 54; // Connection reset by peer -pub const ENOBUFS = 55; // No buffer space available -pub const EISCONN = 56; // Socket is already connected -pub const ENOTCONN = 57; // Socket is not connected -pub const ESHUTDOWN = 58; // Can't send after socket shutdown -pub const ETOOMANYREFS = 59; // Too many references: can't splice -pub const ETIMEDOUT = 60; // Operation timed out -pub const ECONNREFUSED = 61; // Connection refused +pub const ENETDOWN = 50; // Network is down +pub const ENETUNREACH = 51; // Network is unreachable +pub const ENETRESET = 52; // Network dropped connection on reset +pub const ECONNABORTED = 53; // Software caused connection abort +pub const ECONNRESET = 54; // Connection reset by peer +pub const ENOBUFS = 55; // No buffer space available +pub const EISCONN = 56; // Socket is already connected +pub const ENOTCONN = 57; // Socket is not connected +pub const ESHUTDOWN = 58; // Can't send after socket shutdown +pub const ETOOMANYREFS = 59; // Too many references: can't splice +pub const ETIMEDOUT = 60; // Operation timed out +pub const ECONNREFUSED = 61; // Connection refused -pub const ELOOP = 62; // Too many levels of symbolic links -pub const ENAMETOOLONG = 63; // File name too long +pub const ELOOP = 62; // Too many levels of symbolic links +pub const ENAMETOOLONG = 63; // File name too long // should be rearranged -pub const EHOSTDOWN = 64; // Host is down -pub const EHOSTUNREACH = 65; // No route to host -pub const ENOTEMPTY = 66; // Directory not empty +pub const EHOSTDOWN = 64; // Host is down +pub const EHOSTUNREACH = 65; // No route to host +pub const ENOTEMPTY = 66; // Directory not empty // quotas & mush -pub const EPROCLIM = 67; // Too many processes -pub const EUSERS = 68; // Too many users -pub const EDQUOT = 69; // Disc quota exceeded +pub const EPROCLIM = 67; // Too many processes +pub const EUSERS = 68; // Too many users +pub const EDQUOT = 69; // Disc quota exceeded // Network File System -pub const ESTALE = 70; // Stale NFS file handle -pub const EREMOTE = 71; // Too many levels of remote in path -pub const EBADRPC = 72; // RPC struct is bad -pub const ERPCMISMATCH = 73; // RPC version wrong -pub const EPROGUNAVAIL = 74; // RPC prog. not avail -pub const EPROGMISMATCH = 75; // Program version wrong -pub const EPROCUNAVAIL = 76; // Bad procedure for program +pub const ESTALE = 70; // Stale NFS file handle +pub const EREMOTE = 71; // Too many levels of remote in path +pub const EBADRPC = 72; // RPC struct is bad +pub const ERPCMISMATCH = 73; // RPC version wrong +pub const EPROGUNAVAIL = 74; // RPC prog. not avail +pub const EPROGMISMATCH = 75; // Program version wrong +pub const EPROCUNAVAIL = 76; // Bad procedure for program -pub const ENOLCK = 77; // No locks available -pub const ENOSYS = 78; // Function not implemented +pub const ENOLCK = 77; // No locks available +pub const ENOSYS = 78; // Function not implemented -pub const EFTYPE = 79; // Inappropriate file type or format -pub const EAUTH = 80; // Authentication error -pub const ENEEDAUTH = 81; // Need authenticator -pub const EIDRM = 82; // Identifier removed -pub const ENOMSG = 83; // No message of desired type -pub const EOVERFLOW = 84; // Value too large to be stored in data type -pub const ECANCELED = 85; // Operation canceled -pub const EILSEQ = 86; // Illegal byte sequence -pub const ENOATTR = 87; // Attribute not found +pub const EFTYPE = 79; // Inappropriate file type or format +pub const EAUTH = 80; // Authentication error +pub const ENEEDAUTH = 81; // Need authenticator +pub const EIDRM = 82; // Identifier removed +pub const ENOMSG = 83; // No message of desired type +pub const EOVERFLOW = 84; // Value too large to be stored in data type +pub const ECANCELED = 85; // Operation canceled +pub const EILSEQ = 86; // Illegal byte sequence +pub const ENOATTR = 87; // Attribute not found -pub const EDOOFUS = 88; // Programming error +pub const EDOOFUS = 88; // Programming error -pub const EBADMSG = 89; // Bad message -pub const EMULTIHOP = 90; // Multihop attempted -pub const ENOLINK = 91; // Link has been severed -pub const EPROTO = 92; // Protocol error +pub const EBADMSG = 89; // Bad message +pub const EMULTIHOP = 90; // Multihop attempted +pub const ENOLINK = 91; // Link has been severed +pub const EPROTO = 92; // Protocol error -pub const ENOTCAPABLE = 93; // Capabilities insufficient -pub const ECAPMODE = 94; // Not permitted in capability mode -pub const ENOTRECOVERABLE = 95; // State not recoverable -pub const EOWNERDEAD = 96; // Previous owner died +pub const ENOTCAPABLE = 93; // Capabilities insufficient +pub const ECAPMODE = 94; // Not permitted in capability mode +pub const ENOTRECOVERABLE = 95; // State not recoverable +pub const EOWNERDEAD = 96; // Previous owner died -pub const ELAST = 96; // Must be equal largest errno +pub const ELAST = 96; // Must be equal largest errno diff --git a/std/os/freebsd_x86_64.zig b/std/os/freebsd_x86_64.zig index ec3b93be1..09b468032 100644 --- a/std/os/freebsd_x86_64.zig +++ b/std/os/freebsd_x86_64.zig @@ -1,4 +1,4 @@ -const freebsd = @import("freebsd.zig"); +const freebsd = @import("index.zig"); const socklen_t = freebsd.socklen_t; const iovec = freebsd.iovec; @@ -477,26 +477,26 @@ pub const SYS_mknodat = 559; pub const SYS_kevent = 560; pub const SYS_MAXSYSCALL = 561; -pub const O_CREAT = 0o100; -pub const O_EXCL = 0o200; -pub const O_NOCTTY = 0o400; -pub const O_TRUNC = 0o1000; -pub const O_APPEND = 0o2000; -pub const O_NONBLOCK = 0o4000; -pub const O_DSYNC = 0o10000; -pub const O_SYNC = 0o4010000; -pub const O_RSYNC = 0o4010000; +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; pub const O_DIRECTORY = 0o200000; -pub const O_NOFOLLOW = 0o400000; -pub const O_CLOEXEC = 0o2000000; +pub const O_NOFOLLOW = 0o400000; +pub const O_CLOEXEC = 0o2000000; -pub const O_ASYNC = 0o20000; -pub const O_DIRECT = 0o40000; -pub const O_LARGEFILE = 0; -pub const O_NOATIME = 0o1000000; -pub const O_PATH = 0o10000000; +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o40000; +pub const O_LARGEFILE = 0; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; pub const O_TMPFILE = 0o20200000; -pub const O_NDELAY = O_NONBLOCK; +pub const O_NDELAY = O_NONBLOCK; pub const F_DUPFD = 0; pub const F_GETFD = 1; @@ -518,86 +518,99 @@ pub const F_GETOWN_EX = 16; pub const F_GETOWNER_UIDS = 17; -pub fn syscall0(number: usize) -> usize { - asm volatile ("syscall" +pub fn syscall0(number: usize) usize { + return asm volatile ("syscall" : [ret] "={rax}" (-> usize) : [number] "{rax}" (number) - : "rcx", "r11") + : "rcx", "r11" + ); } -pub fn syscall1(number: usize, arg1: usize) -> usize { - asm volatile ("syscall" +pub fn syscall1(number: usize, arg1: usize) usize { + return asm volatile ("syscall" : [ret] "={rax}" (-> usize) : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1) - : "rcx", "r11") + [arg1] "{rdi}" (arg1) + : "rcx", "r11" + ); } -pub fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize { - asm volatile ("syscall" +pub fn syscall2(number: usize, arg1: usize, arg2: usize) usize { + return asm volatile ("syscall" : [ret] "={rax}" (-> usize) : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2) - : "rcx", "r11") + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2) + : "rcx", "r11" + ); } -pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { - asm volatile ("syscall" +pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize { + return asm volatile ("syscall" : [ret] "={rax}" (-> usize) : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3) - : "rcx", "r11") + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3) + : "rcx", "r11" + ); } -pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize { - asm volatile ("syscall" +pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { + return asm volatile ("syscall" : [ret] "={rax}" (-> usize) : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3), - [arg4] "{r10}" (arg4) - : "rcx", "r11") + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4) + : "rcx", "r11" + ); } -pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> usize { - asm volatile ("syscall" +pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { + return asm volatile ("syscall" : [ret] "={rax}" (-> usize) : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3), - [arg4] "{r10}" (arg4), - [arg5] "{r8}" (arg5) - : "rcx", "r11") + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5) + : "rcx", "r11" + ); } -pub fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, - arg5: usize, arg6: usize) -> usize -{ - asm volatile ("syscall" +pub fn syscall6( + number: usize, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, + arg6: usize, +) usize { + return asm volatile ("syscall" : [ret] "={rax}" (-> usize) : [number] "{rax}" (number), - [arg1] "{rdi}" (arg1), - [arg2] "{rsi}" (arg2), - [arg3] "{rdx}" (arg3), - [arg4] "{r10}" (arg4), - [arg5] "{r8}" (arg5), - [arg6] "{r9}" (arg6) - : "rcx", "r11") + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5), + [arg6] "{r9}" (arg6) + : "rcx", "r11" + ); } -pub nakedcc fn restore_rt() { +pub nakedcc fn restore_rt() void { asm volatile ("syscall" : : [number] "{rax}" (usize(SYS_rt_sigreturn)) - : "rcx", "r11") + : "rcx", "r11" + ); } - pub const msghdr = extern struct { msg_name: &u8, msg_namelen: socklen_t, diff --git a/std/os/index.zig b/std/os/index.zig index f332e8212..ba3771c15 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -24,7 +24,7 @@ test "std.os" { pub const windows = @import("windows/index.zig"); pub const darwin = @import("darwin.zig"); pub const linux = @import("linux/index.zig"); -pub const freebsd = @import("freebsd.zig"); +pub const freebsd = @import("freebsd/index.zig"); pub const zen = @import("zen.zig"); pub const posix = switch (builtin.os) { Os.linux => linux, From 19659c3bd347471d3d55597bdc1c141e9e4a1ae1 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Wed, 11 Jul 2018 21:53:59 +1200 Subject: [PATCH 006/110] freebsd: Fix argc resolution in _start FreeBSD appears to use rdi instead of rsp as in other posix systems. According to some loose documentation, x86 passes values on the stack, so amd64 freebsd may be the only exception. --- std/os/freebsd.zig | 8 ++++---- std/special/bootstrap.zig | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/std/os/freebsd.zig b/std/os/freebsd.zig index ee7e93d65..8a582db92 100644 --- a/std/os/freebsd.zig +++ b/std/os/freebsd.zig @@ -348,7 +348,7 @@ pub fn WIFEXITED(s: i32) bool { return WTERMSIG(s) == 0; } pub fn WIFSTOPPED(s: i32) bool { - return (u16)(((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00; + return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00; } pub fn WIFSIGNALED(s: i32) bool { return (unsigned(s) & 0xffff) -% 1 < 0xff; @@ -368,7 +368,7 @@ pub fn getErrno(r: usize) usize { } pub fn dup2(old: i32, new: i32) usize { - return arch.syscall2(arch.SYS_dup2, usize(old), usize(new)); + return arch.syscall2(arch.SYS_dup2, @intCast(usize, old), @intCast(usize, new)); } pub fn chdir(path: [*]const u8) usize { @@ -388,7 +388,7 @@ pub fn getcwd(buf: [*]u8, size: usize) usize { } pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { - return arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), count); + return arch.syscall3(arch.SYS_getdents, @intCast(usize, fd), @ptrToInt(dirp), count); } pub fn isatty(fd: i32) bool { @@ -425,7 +425,7 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { } pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset); + return arch.syscall4(arch.SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset); } pub fn pipe(fd: *[2]i32) usize { diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 53c646abd..1fc80f243 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -20,10 +20,17 @@ comptime { nakedcc fn _start() noreturn { switch (builtin.arch) { - builtin.Arch.x86_64 => { - argc_ptr = asm ("lea (%%rsp), %[argc]" - : [argc] "=r" (-> [*]usize) - ); + builtin.Arch.x86_64 => switch (builtin.os) { + builtin.Os.freebsd => { + argc_ptr = asm ("lea (%%rdi), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, + else => { + argc_ptr = asm ("lea (%%rsp), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, }, builtin.Arch.i386 => { argc_ptr = asm ("lea (%%esp), %[argc]" From 1829c093032764ef397a02d0d7512254f5bb4ad0 Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 18:00:22 +0300 Subject: [PATCH 007/110] Fix os/freebsd files --- CMakeLists.txt | 3 + .../{freebsd_errno.zig => freebsd/errno.zig} | 0 std/os/{freebsd.zig => freebsd/index.zig} | 19 +- .../x86_64.zig} | 7 +- std/os/freebsd_i386.zig | 614 ------------------ 5 files changed, 16 insertions(+), 627 deletions(-) rename std/os/{freebsd_errno.zig => freebsd/errno.zig} (100%) rename std/os/{freebsd.zig => freebsd/index.zig} (96%) rename std/os/{freebsd_x86_64.zig => freebsd/x86_64.zig} (99%) delete mode 100644 std/os/freebsd_i386.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index f39a05109..8df55a7fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -580,6 +580,9 @@ set(ZIG_STD_FILES "os/linux/vdso.zig" "os/linux/x86_64.zig" "os/linux/arm64.zig" + "os/freebsd/errno.zig" + "os/freebsd/index.zig" + "os/freebsd/x86_64.zig" "os/path.zig" "os/time.zig" "os/windows/advapi32.zig" diff --git a/std/os/freebsd_errno.zig b/std/os/freebsd/errno.zig similarity index 100% rename from std/os/freebsd_errno.zig rename to std/os/freebsd/errno.zig diff --git a/std/os/freebsd.zig b/std/os/freebsd/index.zig similarity index 96% rename from std/os/freebsd.zig rename to std/os/freebsd/index.zig index 8a582db92..e856f6291 100644 --- a/std/os/freebsd.zig +++ b/std/os/freebsd/index.zig @@ -1,4 +1,3 @@ -const c = @import("../c/index.zig"); const assert = @import("../debug.zig").assert; const builtin = @import("builtin"); const arch = switch (builtin.arch) { @@ -348,13 +347,13 @@ pub fn WIFEXITED(s: i32) bool { return WTERMSIG(s) == 0; } pub fn WIFSTOPPED(s: i32) bool { - return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00; + return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00; } pub fn WIFSIGNALED(s: i32) bool { return (unsigned(s) & 0xffff) -% 1 < 0xff; } -pub const winsize = extern struct { +pub const winsize = extern struct.{ ws_row: u16, ws_col: u16, ws_xpixel: u16, @@ -425,7 +424,7 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { } pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return arch.syscall4(arch.SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset); } pub fn pipe(fd: *[2]i32) usize { @@ -473,8 +472,8 @@ pub fn exit(status: i32) noreturn { unreachable; } -pub fn getrandom(buf: &u8, count: usize, flags: u32) usize { - return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, @bitCast(usize, flags)); +pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { + return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, @intCast(usize, flags)); } pub fn kill(pid: i32, sig: i32) usize { @@ -521,11 +520,11 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti const NSIG = 65; const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize{@maxValue(usize)}; -const app_mask = []usize{0xfffffffc7fffffff}; +const all_mask = []usize.{@maxValue(usize)}; +const app_mask = []usize.{0xfffffffc7fffffff}; /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. -pub const Sigaction = struct { +pub const Sigaction = struct.{ // TODO: Adjust to use freebsd struct layout handler: extern fn (i32) void, mask: sigset_t, @@ -535,7 +534,7 @@ pub const Sigaction = struct { pub const SIG_ERR = @intToPtr(extern fn (i32) void, @maxValue(usize)); pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); -pub const empty_sigset = []usize{0} ** sigset_t.len; +pub const empty_sigset = []usize.{0} ** sigset_t.len; pub fn raise(sig: i32) usize { // TODO implement, see linux equivalent for what we want to try and do diff --git a/std/os/freebsd_x86_64.zig b/std/os/freebsd/x86_64.zig similarity index 99% rename from std/os/freebsd_x86_64.zig rename to std/os/freebsd/x86_64.zig index 09b468032..cd9104b88 100644 --- a/std/os/freebsd_x86_64.zig +++ b/std/os/freebsd/x86_64.zig @@ -476,6 +476,7 @@ pub const SYS_fhstatfs = 558; pub const SYS_mknodat = 559; pub const SYS_kevent = 560; pub const SYS_MAXSYSCALL = 561; +pub const SYS_getrandom = 563; pub const O_CREAT = 0o100; pub const O_EXCL = 0o200; @@ -611,7 +612,7 @@ pub nakedcc fn restore_rt() void { ); } -pub const msghdr = extern struct { +pub const msghdr = extern struct.{ msg_name: &u8, msg_namelen: socklen_t, msg_iov: &iovec, @@ -624,7 +625,7 @@ pub const msghdr = extern struct { }; /// Renamed to Stat to not conflict with the stat function. -pub const Stat = extern struct { +pub const Stat = extern struct.{ dev: u64, ino: u64, nlink: usize, @@ -644,7 +645,7 @@ pub const Stat = extern struct { __unused: [3]isize, }; -pub const timespec = extern struct { +pub const timespec = extern struct.{ tv_sec: isize, tv_nsec: isize, }; diff --git a/std/os/freebsd_i386.zig b/std/os/freebsd_i386.zig deleted file mode 100644 index fd1f58639..000000000 --- a/std/os/freebsd_i386.zig +++ /dev/null @@ -1,614 +0,0 @@ -const freebsd = @import("freebsd.zig"); -const socklen_t = freebsd.socklen_t; -const iovec = freebsd.iovec; - -pub const SYS_syscall = 0; -pub const SYS_exit = 1; -pub const SYS_fork = 2; -pub const SYS_read = 3; -pub const SYS_write = 4; -pub const SYS_open = 5; -pub const SYS_close = 6; -pub const SYS_wait4 = 7; -// 8 is old creat -pub const SYS_link = 9; -pub const SYS_unlink = 10; -// 11 is obsolete execv -pub const SYS_chdir = 12; -pub const SYS_fchdir = 13; -pub const SYS_freebsd11_mknod = 14; -pub const SYS_chmod = 15; -pub const SYS_chown = 16; -pub const SYS_break = 17; -// 18 is freebsd4 getfsstat -// 19 is old lseek -pub const SYS_getpid = 20; -pub const SYS_mount = 21; -pub const SYS_unmount = 22; -pub const SYS_setuid = 23; -pub const SYS_getuid = 24; -pub const SYS_geteuid = 25; -pub const SYS_ptrace = 26; -pub const SYS_recvmsg = 27; -pub const SYS_sendmsg = 28; -pub const SYS_recvfrom = 29; -pub const SYS_accept = 30; -pub const SYS_getpeername = 31; -pub const SYS_getsockname = 32; -pub const SYS_access = 33; -pub const SYS_chflags = 34; -pub const SYS_fchflags = 35; -pub const SYS_sync = 36; -pub const SYS_kill = 37; -// 38 is old stat -pub const SYS_getppid = 39; -// 40 is old lstat -pub const SYS_dup = 41; -pub const SYS_freebsd10_pipe = 42; -pub const SYS_getegid = 43; -pub const SYS_profil = 44; -pub const SYS_ktrace = 45; -// 46 is old sigaction -pub const SYS_getgid = 47; -// 48 is old sigprocmask -pub const SYS_getlogin = 49; -pub const SYS_setlogin = 50; -pub const SYS_acct = 51; -// 52 is old sigpending -pub const SYS_sigaltstack = 53; -pub const SYS_ioctl = 54; -pub const SYS_reboot = 55; -pub const SYS_revoke = 56; -pub const SYS_symlink = 57; -pub const SYS_readlink = 58; -pub const SYS_execve = 59; -pub const SYS_umask = 60; -pub const SYS_chroot = 61; -// 62 is old fstat -// 63 is old getkerninfo -// 64 is old getpagesize -pub const SYS_msync = 65; -pub const SYS_vfork = 66; -// 67 is obsolete vread -// 68 is obsolete vwrite -pub const SYS_sbrk = 69; -pub const SYS_sstk = 70; -// 71 is old mmap -pub const SYS_vadvise = 72; -pub const SYS_munmap = 73; -pub const SYS_mprotect = 74; -pub const SYS_madvise = 75; -// 76 is obsolete vhangup -// 77 is obsolete vlimit -pub const SYS_mincore = 78; -pub const SYS_getgroups = 79; -pub const SYS_setgroups = 80; -pub const SYS_getpgrp = 81; -pub const SYS_setpgid = 82; -pub const SYS_setitimer = 83; -// 84 is old wait -pub const SYS_swapon = 85; -pub const SYS_getitimer = 86; -// 87 is old gethostname -// 88 is old sethostname -pub const SYS_getdtablesize = 89; -pub const SYS_dup2 = 90; -pub const SYS_fcntl = 92; -pub const SYS_select = 93; -pub const SYS_fsync = 95; -pub const SYS_setpriority = 96; -pub const SYS_socket = 97; -pub const SYS_connect = 98; -// 99 is old accept -pub const SYS_getpriority = 100; -// 101 is old send -// 102 is old recv -// 103 is old sigreturn -pub const SYS_bind = 104; -pub const SYS_setsockopt = 105; -pub const SYS_listen = 106; -// 107 is obsolete vtimes -// 108 is old sigvec -// 109 is old sigblock -// 110 is old sigsetmask -// 111 is old sigsuspend -// 112 is old sigstack -// 113 is old recvmsg -// 114 is old sendmsg -// 115 is obsolete vtrace -pub const SYS_gettimeofday = 116; -pub const SYS_getrusage = 117; -pub const SYS_getsockopt = 118; -pub const SYS_readv = 120; -pub const SYS_writev = 121; -pub const SYS_settimeofday = 122; -pub const SYS_fchown = 123; -pub const SYS_fchmod = 124; -// 125 is old recvfrom -pub const SYS_setreuid = 126; -pub const SYS_setregid = 127; -pub const SYS_rename = 128; -// 129 is old truncate -// 130 is old ftruncate -pub const SYS_flock = 131; -pub const SYS_mkfifo = 132; -pub const SYS_sendto = 133; -pub const SYS_shutdown = 134; -pub const SYS_socketpair = 135; -pub const SYS_mkdir = 136; -pub const SYS_rmdir = 137; -pub const SYS_utimes = 138; -// 139 is obsolete 4.2 sigreturn -pub const SYS_adjtime = 140; -// 141 is old getpeername -// 142 is old gethostid -// 143 is old sethostid -// 144 is old getrlimit -// 145 is old setrlimit -// 146 is old killpg -pub const SYS_setsid = 147; -pub const SYS_quotactl = 148; -// 149 is old quota -// 150 is old getsockname -pub const SYS_nlm_syscall = 154; -pub const SYS_nfssvc = 155; -// 156 is old getdirentries -// 157 is freebsd4 statfs -// 158 is freebsd4 fstatfs -pub const SYS_lgetfh = 160; -pub const SYS_getfh = 161; -// 162 is freebsd4 getdomainname -// 163 is freebsd4 setdomainname -// 164 is freebsd4 uname -pub const SYS_sysarch = 165; -pub const SYS_rtprio = 166; -pub const SYS_semsys = 169; -pub const SYS_msgsys = 170; -pub const SYS_shmsys = 171; -// 173 is freebsd6 pread -// 174 is freebsd6 pwrite -pub const SYS_setfib = 175; -pub const SYS_ntp_adjtime = 176; -pub const SYS_setgid = 181; -pub const SYS_setegid = 182; -pub const SYS_seteuid = 183; -pub const SYS_freebsd11_stat = 188; -pub const SYS_freebsd11_fstat = 189; -pub const SYS_freebsd11_lstat = 190; -pub const SYS_pathconf = 191; -pub const SYS_fpathconf = 192; -pub const SYS_getrlimit = 194; -pub const SYS_setrlimit = 195; -pub const SYS_freebsd11_getdirentries = 196; -// 197 is freebsd6 mmap -pub const SYS___syscall = 198; -// 199 is freebsd6 lseek -// 200 is freebsd6 truncate -// 201 is freebsd6 ftruncate -pub const SYS___sysctl = 202; -pub const SYS_mlock = 203; -pub const SYS_munlock = 204; -pub const SYS_undelete = 205; -pub const SYS_futimes = 206; -pub const SYS_getpgid = 207; -pub const SYS_poll = 209; -pub const SYS_freebsd7___semctl = 220; -pub const SYS_semget = 221; -pub const SYS_semop = 222; -pub const SYS_freebsd7_msgctl = 224; -pub const SYS_msgget = 225; -pub const SYS_msgsnd = 226; -pub const SYS_msgrcv = 227; -pub const SYS_shmat = 228; -pub const SYS_freebsd7_shmctl = 229; -pub const SYS_shmdt = 230; -pub const SYS_shmget = 231; -pub const SYS_clock_gettime = 232; -pub const SYS_clock_settime = 233; -pub const SYS_clock_getres = 234; -pub const SYS_ktimer_create = 235; -pub const SYS_ktimer_delete = 236; -pub const SYS_ktimer_settime = 237; -pub const SYS_ktimer_gettime = 238; -pub const SYS_ktimer_getoverrun = 239; -pub const SYS_nanosleep = 240; -pub const SYS_ffclock_getcounter = 241; -pub const SYS_ffclock_setestimate = 242; -pub const SYS_ffclock_getestimate = 243; -pub const SYS_clock_nanosleep = 244; -pub const SYS_clock_getcpuclockid2 = 247; -pub const SYS_ntp_gettime = 248; -pub const SYS_minherit = 250; -pub const SYS_rfork = 251; -// 252 is obsolete openbsd_poll -pub const SYS_issetugid = 253; -pub const SYS_lchown = 254; -pub const SYS_aio_read = 255; -pub const SYS_aio_write = 256; -pub const SYS_lio_listio = 257; -pub const SYS_freebsd11_getdents = 272; -pub const SYS_lchmod = 274; -pub const SYS_netbsd_lchown = 275; -pub const SYS_lutimes = 276; -pub const SYS_netbsd_msync = 277; -pub const SYS_freebsd11_nstat = 278; -pub const SYS_freebsd11_nfstat = 279; -pub const SYS_freebsd11_nlstat = 280; -pub const SYS_preadv = 289; -pub const SYS_pwritev = 290; -// 297 is freebsd4 fhstatfs -pub const SYS_fhopen = 298; -pub const SYS_freebsd11_fhstat = 299; -pub const SYS_modnext = 300; -pub const SYS_modstat = 301; -pub const SYS_modfnext = 302; -pub const SYS_modfind = 303; -pub const SYS_kldload = 304; -pub const SYS_kldunload = 305; -pub const SYS_kldfind = 306; -pub const SYS_kldnext = 307; -pub const SYS_kldstat = 308; -pub const SYS_kldfirstmod = 309; -pub const SYS_getsid = 310; -pub const SYS_setresuid = 311; -pub const SYS_setresgid = 312; -// 313 is obsolete signanosleep -pub const SYS_aio_return = 314; -pub const SYS_aio_suspend = 315; -pub const SYS_aio_cancel = 316; -pub const SYS_aio_error = 317; -// 318 is freebsd6 aio_read -// 319 is freebsd6 aio_write -// 320 is freebsd6 lio_listio -pub const SYS_yield = 321; -// 322 is obsolete thr_sleep -// 323 is obsolete thr_wakeup -pub const SYS_mlockall = 324; -pub const SYS_munlockall = 325; -pub const SYS___getcwd = 326; -pub const SYS_sched_setparam = 327; -pub const SYS_sched_getparam = 328; -pub const SYS_sched_setscheduler = 329; -pub const SYS_sched_getscheduler = 330; -pub const SYS_sched_yield = 331; -pub const SYS_sched_get_priority_max = 332; -pub const SYS_sched_get_priority_min = 333; -pub const SYS_sched_rr_get_interval = 334; -pub const SYS_utrace = 335; -// 336 is freebsd4 sendfile -pub const SYS_kldsym = 337; -pub const SYS_jail = 338; -pub const SYS_nnpfs_syscall = 339; -pub const SYS_sigprocmask = 340; -pub const SYS_sigsuspend = 341; -// 342 is freebsd4 sigaction -pub const SYS_sigpending = 343; -// 344 is freebsd4 sigreturn -pub const SYS_sigtimedwait = 345; -pub const SYS_sigwaitinfo = 346; -pub const SYS___acl_get_file = 347; -pub const SYS___acl_set_file = 348; -pub const SYS___acl_get_fd = 349; -pub const SYS___acl_set_fd = 350; -pub const SYS___acl_delete_file = 351; -pub const SYS___acl_delete_fd = 352; -pub const SYS___acl_aclcheck_file = 353; -pub const SYS___acl_aclcheck_fd = 354; -pub const SYS_extattrctl = 355; -pub const SYS_extattr_set_file = 356; -pub const SYS_extattr_get_file = 357; -pub const SYS_extattr_delete_file = 358; -pub const SYS_aio_waitcomplete = 359; -pub const SYS_getresuid = 360; -pub const SYS_getresgid = 361; -pub const SYS_kqueue = 362; -pub const SYS_freebsd11_kevent = 363; -pub const SYS_extattr_set_fd = 371; -pub const SYS_extattr_get_fd = 372; -pub const SYS_extattr_delete_fd = 373; -pub const SYS___setugid = 374; -pub const SYS_eaccess = 376; -pub const SYS_afs3_syscall = 377; -pub const SYS_nmount = 378; -pub const SYS___mac_get_proc = 384; -pub const SYS___mac_set_proc = 385; -pub const SYS___mac_get_fd = 386; -pub const SYS___mac_get_file = 387; -pub const SYS___mac_set_fd = 388; -pub const SYS___mac_set_file = 389; -pub const SYS_kenv = 390; -pub const SYS_lchflags = 391; -pub const SYS_uuidgen = 392; -pub const SYS_sendfile = 393; -pub const SYS_mac_syscall = 394; -pub const SYS_freebsd11_getfsstat = 395; -pub const SYS_freebsd11_statfs = 396; -pub const SYS_freebsd11_fstatfs = 397; -pub const SYS_freebsd11_fhstatfs = 398; -pub const SYS_ksem_close = 400; -pub const SYS_ksem_post = 401; -pub const SYS_ksem_wait = 402; -pub const SYS_ksem_trywait = 403; -pub const SYS_ksem_init = 404; -pub const SYS_ksem_open = 405; -pub const SYS_ksem_unlink = 406; -pub const SYS_ksem_getvalue = 407; -pub const SYS_ksem_destroy = 408; -pub const SYS___mac_get_pid = 409; -pub const SYS___mac_get_link = 410; -pub const SYS___mac_set_link = 411; -pub const SYS_extattr_set_link = 412; -pub const SYS_extattr_get_link = 413; -pub const SYS_extattr_delete_link = 414; -pub const SYS___mac_execve = 415; -pub const SYS_sigaction = 416; -pub const SYS_sigreturn = 417; -pub const SYS_getcontext = 421; -pub const SYS_setcontext = 422; -pub const SYS_swapcontext = 423; -pub const SYS_swapoff = 424; -pub const SYS___acl_get_link = 425; -pub const SYS___acl_set_link = 426; -pub const SYS___acl_delete_link = 427; -pub const SYS___acl_aclcheck_link = 428; -pub const SYS_sigwait = 429; -pub const SYS_thr_create = 430; -pub const SYS_thr_exit = 431; -pub const SYS_thr_self = 432; -pub const SYS_thr_kill = 433; -pub const SYS_jail_attach = 436; -pub const SYS_extattr_list_fd = 437; -pub const SYS_extattr_list_file = 438; -pub const SYS_extattr_list_link = 439; -pub const SYS_ksem_timedwait = 441; -pub const SYS_thr_suspend = 442; -pub const SYS_thr_wake = 443; -pub const SYS_kldunloadf = 444; -pub const SYS_audit = 445; -pub const SYS_auditon = 446; -pub const SYS_getauid = 447; -pub const SYS_setauid = 448; -pub const SYS_getaudit = 449; -pub const SYS_setaudit = 450; -pub const SYS_getaudit_addr = 451; -pub const SYS_setaudit_addr = 452; -pub const SYS_auditctl = 453; -pub const SYS__umtx_op = 454; -pub const SYS_thr_new = 455; -pub const SYS_sigqueue = 456; -pub const SYS_kmq_open = 457; -pub const SYS_kmq_setattr = 458; -pub const SYS_kmq_timedreceive = 459; -pub const SYS_kmq_timedsend = 460; -pub const SYS_kmq_notify = 461; -pub const SYS_kmq_unlink = 462; -pub const SYS_abort2 = 463; -pub const SYS_thr_set_name = 464; -pub const SYS_aio_fsync = 465; -pub const SYS_rtprio_thread = 466; -pub const SYS_sctp_peeloff = 471; -pub const SYS_sctp_generic_sendmsg = 472; -pub const SYS_sctp_generic_sendmsg_iov = 473; -pub const SYS_sctp_generic_recvmsg = 474; -pub const SYS_pread = 475; -pub const SYS_pwrite = 476; -pub const SYS_mmap = 477; -pub const SYS_lseek = 478; -pub const SYS_truncate = 479; -pub const SYS_ftruncate = 480; -pub const SYS_thr_kill2 = 481; -pub const SYS_shm_open = 482; -pub const SYS_shm_unlink = 483; -pub const SYS_cpuset = 484; -pub const SYS_cpuset_setid = 485; -pub const SYS_cpuset_getid = 486; -pub const SYS_cpuset_getaffinity = 487; -pub const SYS_cpuset_setaffinity = 488; -pub const SYS_faccessat = 489; -pub const SYS_fchmodat = 490; -pub const SYS_fchownat = 491; -pub const SYS_fexecve = 492; -pub const SYS_freebsd11_fstatat = 493; -pub const SYS_futimesat = 494; -pub const SYS_linkat = 495; -pub const SYS_mkdirat = 496; -pub const SYS_mkfifoat = 497; -pub const SYS_freebsd11_mknodat = 498; -pub const SYS_openat = 499; -pub const SYS_readlinkat = 500; -pub const SYS_renameat = 501; -pub const SYS_symlinkat = 502; -pub const SYS_unlinkat = 503; -pub const SYS_posix_openpt = 504; -pub const SYS_gssd_syscall = 505; -pub const SYS_jail_get = 506; -pub const SYS_jail_set = 507; -pub const SYS_jail_remove = 508; -pub const SYS_closefrom = 509; -pub const SYS___semctl = 510; -pub const SYS_msgctl = 511; -pub const SYS_shmctl = 512; -pub const SYS_lpathconf = 513; -// 514 is obsolete cap_new -pub const SYS___cap_rights_get = 515; -pub const SYS_cap_enter = 516; -pub const SYS_cap_getmode = 517; -pub const SYS_pdfork = 518; -pub const SYS_pdkill = 519; -pub const SYS_pdgetpid = 520; -pub const SYS_pselect = 522; -pub const SYS_getloginclass = 523; -pub const SYS_setloginclass = 524; -pub const SYS_rctl_get_racct = 525; -pub const SYS_rctl_get_rules = 526; -pub const SYS_rctl_get_limits = 527; -pub const SYS_rctl_add_rule = 528; -pub const SYS_rctl_remove_rule = 529; -pub const SYS_posix_fallocate = 530; -pub const SYS_posix_fadvise = 531; -pub const SYS_wait6 = 532; -pub const SYS_cap_rights_limit = 533; -pub const SYS_cap_ioctls_limit = 534; -pub const SYS_cap_ioctls_get = 535; -pub const SYS_cap_fcntls_limit = 536; -pub const SYS_cap_fcntls_get = 537; -pub const SYS_bindat = 538; -pub const SYS_connectat = 539; -pub const SYS_chflagsat = 540; -pub const SYS_accept4 = 541; -pub const SYS_pipe2 = 542; -pub const SYS_aio_mlock = 543; -pub const SYS_procctl = 544; -pub const SYS_ppoll = 545; -pub const SYS_futimens = 546; -pub const SYS_utimensat = 547; -pub const SYS_numa_getaffinity = 548; -pub const SYS_numa_setaffinity = 549; -pub const SYS_fdatasync = 550; -pub const SYS_fstat = 551; -pub const SYS_fstatat = 552; -pub const SYS_fhstat = 553; -pub const SYS_getdirentries = 554; -pub const SYS_statfs = 555; -pub const SYS_fstatfs = 556; -pub const SYS_getfsstat = 557; -pub const SYS_fhstatfs = 558; -pub const SYS_mknodat = 559; -pub const SYS_kevent = 560; -pub const SYS_MAXSYSCALL = 561; - -// From here -pub const O_CREAT = 0o100; -pub const O_EXCL = 0o200; -pub const O_NOCTTY = 0o400; -pub const O_TRUNC = 0o1000; -pub const O_APPEND = 0o2000; -pub const O_NONBLOCK = 0o4000; -pub const O_DSYNC = 0o10000; -pub const O_SYNC = 0o4010000; -pub const O_RSYNC = 0o4010000; -pub const O_DIRECTORY = 0o200000; -pub const O_NOFOLLOW = 0o400000; -pub const O_CLOEXEC = 0o2000000; - -pub const O_ASYNC = 0o20000; -pub const O_DIRECT = 0o40000; -pub const O_LARGEFILE = 0o100000; -pub const O_NOATIME = 0o1000000; -pub const O_PATH = 0o10000000; -pub const O_TMPFILE = 0o20200000; -pub const O_NDELAY = O_NONBLOCK; - -pub const F_DUPFD = 0; -pub const F_GETFD = 1; -pub const F_SETFD = 2; -pub const F_GETFL = 3; -pub const F_SETFL = 4; - -pub const F_SETOWN = 8; -pub const F_GETOWN = 9; -pub const F_SETSIG = 10; -pub const F_GETSIG = 11; - -pub const F_GETLK = 12; -pub const F_SETLK = 13; -pub const F_SETLKW = 14; - -pub const F_SETOWN_EX = 15; -pub const F_GETOWN_EX = 16; - -pub const F_GETOWNER_UIDS = 17; - -pub inline fn syscall0(number: usize) -> usize { - asm volatile ("int $0x80" - : [ret] "={eax}" (-> usize) - : [number] "{eax}" (number)) -} - -pub inline fn syscall1(number: usize, arg1: usize) -> usize { - asm volatile ("int $0x80" - : [ret] "={eax}" (-> usize) - : [number] "{eax}" (number), - [arg1] "{ebx}" (arg1)) -} - -pub inline fn syscall2(number: usize, arg1: usize, arg2: usize) -> usize { - asm volatile ("int $0x80" - : [ret] "={eax}" (-> usize) - : [number] "{eax}" (number), - [arg1] "{ebx}" (arg1), - [arg2] "{ecx}" (arg2)) -} - -pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize { - asm volatile ("int $0x80" - : [ret] "={eax}" (-> usize) - : [number] "{eax}" (number), - [arg1] "{ebx}" (arg1), - [arg2] "{ecx}" (arg2), - [arg3] "{edx}" (arg3)) -} - -pub inline fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) -> usize { - asm volatile ("int $0x80" - : [ret] "={eax}" (-> usize) - : [number] "{eax}" (number), - [arg1] "{ebx}" (arg1), - [arg2] "{ecx}" (arg2), - [arg3] "{edx}" (arg3), - [arg4] "{esi}" (arg4)) -} - -pub inline fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, - arg4: usize, arg5: usize) -> usize -{ - asm volatile ("int $0x80" - : [ret] "={eax}" (-> usize) - : [number] "{eax}" (number), - [arg1] "{ebx}" (arg1), - [arg2] "{ecx}" (arg2), - [arg3] "{edx}" (arg3), - [arg4] "{esi}" (arg4), - [arg5] "{edi}" (arg5)) -} - -pub inline fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize, - arg4: usize, arg5: usize, arg6: usize) -> usize -{ - asm volatile ("int $0x80" - : [ret] "={eax}" (-> usize) - : [number] "{eax}" (number), - [arg1] "{ebx}" (arg1), - [arg2] "{ecx}" (arg2), - [arg3] "{edx}" (arg3), - [arg4] "{esi}" (arg4), - [arg5] "{edi}" (arg5), - [arg6] "{ebp}" (arg6)) -} - -pub nakedcc fn restore() { - asm volatile ( - \\popl %%eax - \\movl $119, %%eax - \\int $0x80 - : - : - : "rcx", "r11") -} - -pub nakedcc fn restore_rt() { - asm volatile ("int $0x80" - : - : [number] "{eax}" (usize(SYS_rt_sigreturn)) - : "rcx", "r11") -} - -export struct msghdr { - msg_name: &u8, - msg_namelen: socklen_t, - msg_iov: &iovec, - msg_iovlen: i32, - msg_control: &u8, - msg_controllen: socklen_t, - msg_flags: i32, -} From 7a3f0a55d9a481f260935f26426ee4508d44cb18 Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 18:01:00 +0300 Subject: [PATCH 008/110] Add freebsd to more things --- std/debug/index.zig | 2 ++ std/heap.zig | 6 +++--- std/os/file.zig | 6 +++--- std/os/index.zig | 6 +++--- std/os/path.zig | 11 ++++++++++- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index e6d8fe3fc..cabeba14f 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -1078,6 +1078,8 @@ pub const DebugInfo = switch (builtin.os) { self.elf.close(); } }, + builtin.Os.freebsd => struct.{ + }, else => @compileError("Unsupported OS"), }; diff --git a/std/heap.zig b/std/heap.zig index 8a68a7b45..34addef09 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -69,7 +69,7 @@ pub const DirectAllocator = struct.{ const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const p = os.posix; const alloc_size = if (alignment <= os.page_size) n else n + alignment; const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0); @@ -120,7 +120,7 @@ pub const DirectAllocator = struct.{ const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { if (new_size <= old_mem.len) { const base_addr = @ptrToInt(old_mem.ptr); const old_addr_end = base_addr + old_mem.len; @@ -165,7 +165,7 @@ pub const DirectAllocator = struct.{ const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { _ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len); }, Os.windows => { diff --git a/std/os/file.zig b/std/os/file.zig index 293d637d1..4c21cc9b5 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -229,7 +229,7 @@ pub const File = struct.{ pub fn seekForward(self: File, amount: isize) !void { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); const err = posix.getErrno(result); if (err > 0) { @@ -260,7 +260,7 @@ pub const File = struct.{ pub fn seekTo(self: File, pos: usize) !void { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const ipos = try math.cast(isize, pos); const result = posix.lseek(self.handle, ipos, posix.SEEK_SET); const err = posix.getErrno(result); @@ -294,7 +294,7 @@ pub const File = struct.{ pub fn getPos(self: File) !usize { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); const err = posix.getErrno(result); if (err > 0) { diff --git a/std/os/index.zig b/std/os/index.zig index ba3771c15..16bc571a8 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -3,7 +3,7 @@ const builtin = @import("builtin"); const Os = builtin.Os; const is_windows = builtin.os == Os.windows; const is_posix = switch (builtin.os) { - builtin.Os.linux, builtin.Os.macosx => true, + builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => true, else => false, }; const os = @This(); @@ -42,7 +42,7 @@ pub const time = @import("time.zig"); pub const page_size = 4 * 1024; pub const MAX_PATH_BYTES = switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => posix.PATH_MAX, + Os.linux, Os.macosx, Os.ios, Os.freebsd => posix.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. // If it would require 4 UTF-8 bytes, then there would be a surrogate // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. @@ -103,7 +103,7 @@ const math = std.math; /// library implementation. pub fn getRandomBytes(buf: []u8) !void { switch (builtin.os) { - Os.linux => while (true) { + Os.linux, Os.freebsd => while (true) { // TODO check libc version and potentially call c.getrandom. // See #397 const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0)); diff --git a/std/os/path.zig b/std/os/path.zig index 8096cdd0d..e0d8030bc 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1161,7 +1161,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro const pathname_w = try windows_util.cStrToPrefixedFileW(pathname); return realW(out_buffer, pathname_w); }, - Os.macosx, Os.ios, Os.freebsd => { + Os.macosx, Os.ios => { // TODO instead of calling the libc function here, port the implementation to Zig const err = posix.getErrno(posix.realpath(pathname, out_buffer)); switch (err) { @@ -1188,6 +1188,15 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro return os.readLinkC(out_buffer, proc_path.ptr); }, + Os.freebsd => { // XXX requires fdescfs + const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0); + defer os.close(fd); + + var buf: ["/dev/fd/-2147483648".len]u8 = undefined; + const proc_path = fmt.bufPrint(buf[0..], "/dev/fd/{}\x00", fd) catch unreachable; + + return os.readLinkC(out_buffer, proc_path.ptr); + }, else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)), } } From afe26bbcbdfd7d6fc5ed141688dd9baeb2f1c104 Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 18:09:44 +0300 Subject: [PATCH 009/110] System call numbers on FreeBSD are machine-independent But e.g. sbrk is only removed in new architectures (aarch64, riscv), so keep it in x86_64 --- CMakeLists.txt | 1 + std/os/freebsd/index.zig | 71 +++--- std/os/freebsd/syscall.zig | 493 +++++++++++++++++++++++++++++++++++++ std/os/freebsd/x86_64.zig | 474 ----------------------------------- 4 files changed, 530 insertions(+), 509 deletions(-) create mode 100644 std/os/freebsd/syscall.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 8df55a7fb..f10fc91b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -582,6 +582,7 @@ set(ZIG_STD_FILES "os/linux/arm64.zig" "os/freebsd/errno.zig" "os/freebsd/index.zig" + "os/freebsd/syscall.zig" "os/freebsd/x86_64.zig" "os/path.zig" "os/time.zig" diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index e856f6291..c442dd665 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -4,6 +4,7 @@ const arch = switch (builtin.arch) { builtin.Arch.x86_64 => @import("x86_64.zig"), else => @compileError("unsupported arch"), }; +pub use @import("syscall.zig"); pub use @import("errno.zig"); pub const PATH_MAX = 1024; @@ -367,64 +368,64 @@ pub fn getErrno(r: usize) usize { } pub fn dup2(old: i32, new: i32) usize { - return arch.syscall2(arch.SYS_dup2, @intCast(usize, old), @intCast(usize, new)); + return arch.syscall2(SYS_dup2, @intCast(usize, old), @intCast(usize, new)); } pub fn chdir(path: [*]const u8) usize { - return arch.syscall1(arch.SYS_chdir, @ptrToInt(path)); + return arch.syscall1(SYS_chdir, @ptrToInt(path)); } pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { - return arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); + return arch.syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); } pub fn fork() usize { - return arch.syscall0(arch.SYS_fork); + return arch.syscall0(SYS_fork); } pub fn getcwd(buf: [*]u8, size: usize) usize { - return arch.syscall2(arch.SYS___getcwd, @ptrToInt(buf), size); + return arch.syscall2(SYS___getcwd, @ptrToInt(buf), size); } pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { - return arch.syscall3(arch.SYS_getdents, @intCast(usize, fd), @ptrToInt(dirp), count); + return arch.syscall3(SYS_getdents, @intCast(usize, fd), @ptrToInt(dirp), count); } pub fn isatty(fd: i32) bool { var wsz: winsize = undefined; - return arch.syscall3(arch.SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; + return arch.syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { - return arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); + return arch.syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); } pub fn mkdir(path: [*]const u8, mode: u32) usize { - return arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode); + return arch.syscall2(SYS_mkdir, @ptrToInt(path), mode); } pub fn mmap(address: ?*u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize { - return arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset)); + return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset)); } pub fn munmap(address: usize, length: usize) usize { - return arch.syscall2(arch.SYS_munmap, address, length); + return arch.syscall2(SYS_munmap, address, length); } pub fn read(fd: i32, buf: [*]u8, count: usize) usize { - return arch.syscall3(arch.SYS_read, @intCast(usize, fd), @ptrToInt(buf), count); + return arch.syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count); } pub fn rmdir(path: [*]const u8) usize { - return arch.syscall1(arch.SYS_rmdir, @ptrToInt(path)); + return arch.syscall1(SYS_rmdir, @ptrToInt(path)); } pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { - return arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); + return arch.syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); } pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset); + return arch.syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset); } pub fn pipe(fd: *[2]i32) usize { @@ -432,80 +433,80 @@ pub fn pipe(fd: *[2]i32) usize { } pub fn pipe2(fd: *[2]i32, flags: usize) usize { - return arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags); + return arch.syscall2(SYS_pipe2, @ptrToInt(fd), flags); } pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { - return arch.syscall3(arch.SYS_write, @intCast(usize, fd), @ptrToInt(buf), count); + return arch.syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count); } pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { - return arch.syscall4(arch.SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return arch.syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); } pub fn rename(old: [*]const u8, new: [*]const u8) usize { - return arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new)); + return arch.syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); } pub fn open(path: [*]const u8, flags: u32, perm: usize) usize { - return arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm); + return arch.syscall3(SYS_open, @ptrToInt(path), flags, perm); } pub fn create(path: [*]const u8, perm: usize) usize { - return arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm); + return arch.syscall2(SYS_creat, @ptrToInt(path), perm); } pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize { - return arch.syscall4(arch.SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode); + return arch.syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode); } pub fn close(fd: i32) usize { - return arch.syscall1(arch.SYS_close, @intCast(usize, fd)); + return arch.syscall1(SYS_close, @intCast(usize, fd)); } pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { - return arch.syscall3(arch.SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos); + return arch.syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos); } pub fn exit(status: i32) noreturn { - _ = arch.syscall1(arch.SYS_exit, @bitCast(usize, isize(status))); + _ = arch.syscall1(SYS_exit, @bitCast(usize, isize(status))); unreachable; } pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { - return arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, @intCast(usize, flags)); + return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, @intCast(usize, flags)); } pub fn kill(pid: i32, sig: i32) usize { - return arch.syscall2(arch.SYS_kill, @bitCast(usize, @intCast(isize, pid)), @intCast(usize, sig)); + return arch.syscall2(SYS_kill, @bitCast(usize, @intCast(isize, pid)), @intCast(usize, sig)); } pub fn unlink(path: [*]const u8) usize { - return arch.syscall1(arch.SYS_unlink, @ptrToInt(path)); + return arch.syscall1(SYS_unlink, @ptrToInt(path)); } pub fn waitpid(pid: i32, status: *i32, options: i32) usize { - return arch.syscall4(arch.SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); + return arch.syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); } pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { - return arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); + return arch.syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); } pub fn setuid(uid: u32) usize { - return arch.syscall1(arch.SYS_setuid, uid); + return arch.syscall1(SYS_setuid, uid); } pub fn setgid(gid: u32) usize { - return arch.syscall1(arch.SYS_setgid, gid); + return arch.syscall1(SYS_setgid, gid); } pub fn setreuid(ruid: u32, euid: u32) usize { - return arch.syscall2(arch.SYS_setreuid, ruid, euid); + return arch.syscall2(SYS_setreuid, ruid, euid); } pub fn setregid(rgid: u32, egid: u32) usize { - return arch.syscall2(arch.SYS_setregid, rgid, egid); + return arch.syscall2(SYS_setregid, rgid, egid); } pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize { @@ -567,5 +568,5 @@ pub const Stat = arch.Stat; pub const timespec = arch.timespec; pub fn fstat(fd: i32, stat_buf: *Stat) usize { - return arch.syscall2(arch.SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); + return arch.syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); } diff --git a/std/os/freebsd/syscall.zig b/std/os/freebsd/syscall.zig new file mode 100644 index 000000000..6cdd71de3 --- /dev/null +++ b/std/os/freebsd/syscall.zig @@ -0,0 +1,493 @@ +pub const SYS_syscall = 0; +pub const SYS_exit = 1; +pub const SYS_fork = 2; +pub const SYS_read = 3; +pub const SYS_write = 4; +pub const SYS_open = 5; +pub const SYS_close = 6; +pub const SYS_wait4 = 7; +// 8 is old creat +pub const SYS_link = 9; +pub const SYS_unlink = 10; +// 11 is obsolete execv +pub const SYS_chdir = 12; +pub const SYS_fchdir = 13; +pub const SYS_freebsd11_mknod = 14; +pub const SYS_chmod = 15; +pub const SYS_chown = 16; +pub const SYS_break = 17; +// 18 is freebsd4 getfsstat +// 19 is old lseek +pub const SYS_getpid = 20; +pub const SYS_mount = 21; +pub const SYS_unmount = 22; +pub const SYS_setuid = 23; +pub const SYS_getuid = 24; +pub const SYS_geteuid = 25; +pub const SYS_ptrace = 26; +pub const SYS_recvmsg = 27; +pub const SYS_sendmsg = 28; +pub const SYS_recvfrom = 29; +pub const SYS_accept = 30; +pub const SYS_getpeername = 31; +pub const SYS_getsockname = 32; +pub const SYS_access = 33; +pub const SYS_chflags = 34; +pub const SYS_fchflags = 35; +pub const SYS_sync = 36; +pub const SYS_kill = 37; +// 38 is old stat +pub const SYS_getppid = 39; +// 40 is old lstat +pub const SYS_dup = 41; +pub const SYS_freebsd10_pipe = 42; +pub const SYS_getegid = 43; +pub const SYS_profil = 44; +pub const SYS_ktrace = 45; +// 46 is old sigaction +pub const SYS_getgid = 47; +// 48 is old sigprocmask +pub const SYS_getlogin = 49; +pub const SYS_setlogin = 50; +pub const SYS_acct = 51; +// 52 is old sigpending +pub const SYS_sigaltstack = 53; +pub const SYS_ioctl = 54; +pub const SYS_reboot = 55; +pub const SYS_revoke = 56; +pub const SYS_symlink = 57; +pub const SYS_readlink = 58; +pub const SYS_execve = 59; +pub const SYS_umask = 60; +pub const SYS_chroot = 61; +// 62 is old fstat +// 63 is old getkerninfo +// 64 is old getpagesize +pub const SYS_msync = 65; +pub const SYS_vfork = 66; +// 67 is obsolete vread +// 68 is obsolete vwrite +// 69 is obsolete sbrk (still present on some platforms) +pub const SYS_sstk = 70; +// 71 is old mmap +pub const SYS_vadvise = 72; +pub const SYS_munmap = 73; +pub const SYS_mprotect = 74; +pub const SYS_madvise = 75; +// 76 is obsolete vhangup +// 77 is obsolete vlimit +pub const SYS_mincore = 78; +pub const SYS_getgroups = 79; +pub const SYS_setgroups = 80; +pub const SYS_getpgrp = 81; +pub const SYS_setpgid = 82; +pub const SYS_setitimer = 83; +// 84 is old wait +pub const SYS_swapon = 85; +pub const SYS_getitimer = 86; +// 87 is old gethostname +// 88 is old sethostname +pub const SYS_getdtablesize = 89; +pub const SYS_dup2 = 90; +pub const SYS_fcntl = 92; +pub const SYS_select = 93; +pub const SYS_fsync = 95; +pub const SYS_setpriority = 96; +pub const SYS_socket = 97; +pub const SYS_connect = 98; +// 99 is old accept +pub const SYS_getpriority = 100; +// 101 is old send +// 102 is old recv +// 103 is old sigreturn +pub const SYS_bind = 104; +pub const SYS_setsockopt = 105; +pub const SYS_listen = 106; +// 107 is obsolete vtimes +// 108 is old sigvec +// 109 is old sigblock +// 110 is old sigsetmask +// 111 is old sigsuspend +// 112 is old sigstack +// 113 is old recvmsg +// 114 is old sendmsg +// 115 is obsolete vtrace +pub const SYS_gettimeofday = 116; +pub const SYS_getrusage = 117; +pub const SYS_getsockopt = 118; +pub const SYS_readv = 120; +pub const SYS_writev = 121; +pub const SYS_settimeofday = 122; +pub const SYS_fchown = 123; +pub const SYS_fchmod = 124; +// 125 is old recvfrom +pub const SYS_setreuid = 126; +pub const SYS_setregid = 127; +pub const SYS_rename = 128; +// 129 is old truncate +// 130 is old ftruncate +pub const SYS_flock = 131; +pub const SYS_mkfifo = 132; +pub const SYS_sendto = 133; +pub const SYS_shutdown = 134; +pub const SYS_socketpair = 135; +pub const SYS_mkdir = 136; +pub const SYS_rmdir = 137; +pub const SYS_utimes = 138; +// 139 is obsolete 4.2 sigreturn +pub const SYS_adjtime = 140; +// 141 is old getpeername +// 142 is old gethostid +// 143 is old sethostid +// 144 is old getrlimit +// 145 is old setrlimit +// 146 is old killpg +pub const SYS_setsid = 147; +pub const SYS_quotactl = 148; +// 149 is old quota +// 150 is old getsockname +pub const SYS_nlm_syscall = 154; +pub const SYS_nfssvc = 155; +// 156 is old getdirentries +// 157 is freebsd4 statfs +// 158 is freebsd4 fstatfs +pub const SYS_lgetfh = 160; +pub const SYS_getfh = 161; +// 162 is freebsd4 getdomainname +// 163 is freebsd4 setdomainname +// 164 is freebsd4 uname +pub const SYS_sysarch = 165; +pub const SYS_rtprio = 166; +pub const SYS_semsys = 169; +pub const SYS_msgsys = 170; +pub const SYS_shmsys = 171; +// 173 is freebsd6 pread +// 174 is freebsd6 pwrite +pub const SYS_setfib = 175; +pub const SYS_ntp_adjtime = 176; +pub const SYS_setgid = 181; +pub const SYS_setegid = 182; +pub const SYS_seteuid = 183; +// 184 is obsolete lfs_bmapv +// 185 is obsolete lfs_markv +// 186 is obsolete lfs_segclean +// 187 is obsolete lfs_segwait +pub const SYS_freebsd11_stat = 188; +pub const SYS_freebsd11_fstat = 189; +pub const SYS_freebsd11_lstat = 190; +pub const SYS_pathconf = 191; +pub const SYS_fpathconf = 192; +pub const SYS_getrlimit = 194; +pub const SYS_setrlimit = 195; +pub const SYS_freebsd11_getdirentries = 196; +// 197 is freebsd6 mmap +pub const SYS___syscall = 198; +// 199 is freebsd6 lseek +// 200 is freebsd6 truncate +// 201 is freebsd6 ftruncate +pub const SYS___sysctl = 202; +pub const SYS_mlock = 203; +pub const SYS_munlock = 204; +pub const SYS_undelete = 205; +pub const SYS_futimes = 206; +pub const SYS_getpgid = 207; +pub const SYS_poll = 209; +pub const SYS_freebsd7___semctl = 220; +pub const SYS_semget = 221; +pub const SYS_semop = 222; +pub const SYS_freebsd7_msgctl = 224; +pub const SYS_msgget = 225; +pub const SYS_msgsnd = 226; +pub const SYS_msgrcv = 227; +pub const SYS_shmat = 228; +pub const SYS_freebsd7_shmctl = 229; +pub const SYS_shmdt = 230; +pub const SYS_shmget = 231; +pub const SYS_clock_gettime = 232; +pub const SYS_clock_settime = 233; +pub const SYS_clock_getres = 234; +pub const SYS_ktimer_create = 235; +pub const SYS_ktimer_delete = 236; +pub const SYS_ktimer_settime = 237; +pub const SYS_ktimer_gettime = 238; +pub const SYS_ktimer_getoverrun = 239; +pub const SYS_nanosleep = 240; +pub const SYS_ffclock_getcounter = 241; +pub const SYS_ffclock_setestimate = 242; +pub const SYS_ffclock_getestimate = 243; +pub const SYS_clock_nanosleep = 244; +pub const SYS_clock_getcpuclockid2 = 247; +pub const SYS_ntp_gettime = 248; +pub const SYS_minherit = 250; +pub const SYS_rfork = 251; +// 252 is obsolete openbsd_poll +pub const SYS_issetugid = 253; +pub const SYS_lchown = 254; +pub const SYS_aio_read = 255; +pub const SYS_aio_write = 256; +pub const SYS_lio_listio = 257; +pub const SYS_freebsd11_getdents = 272; +pub const SYS_lchmod = 274; +// 275 is obsolete netbsd_lchown +pub const SYS_lutimes = 276; +// 277 is obsolete netbsd_msync +pub const SYS_freebsd11_nstat = 278; +pub const SYS_freebsd11_nfstat = 279; +pub const SYS_freebsd11_nlstat = 280; +pub const SYS_preadv = 289; +pub const SYS_pwritev = 290; +// 297 is freebsd4 fhstatfs +pub const SYS_fhopen = 298; +pub const SYS_freebsd11_fhstat = 299; +pub const SYS_modnext = 300; +pub const SYS_modstat = 301; +pub const SYS_modfnext = 302; +pub const SYS_modfind = 303; +pub const SYS_kldload = 304; +pub const SYS_kldunload = 305; +pub const SYS_kldfind = 306; +pub const SYS_kldnext = 307; +pub const SYS_kldstat = 308; +pub const SYS_kldfirstmod = 309; +pub const SYS_getsid = 310; +pub const SYS_setresuid = 311; +pub const SYS_setresgid = 312; +// 313 is obsolete signanosleep +pub const SYS_aio_return = 314; +pub const SYS_aio_suspend = 315; +pub const SYS_aio_cancel = 316; +pub const SYS_aio_error = 317; +// 318 is freebsd6 aio_read +// 319 is freebsd6 aio_write +// 320 is freebsd6 lio_listio +pub const SYS_yield = 321; +// 322 is obsolete thr_sleep +// 323 is obsolete thr_wakeup +pub const SYS_mlockall = 324; +pub const SYS_munlockall = 325; +pub const SYS___getcwd = 326; +pub const SYS_sched_setparam = 327; +pub const SYS_sched_getparam = 328; +pub const SYS_sched_setscheduler = 329; +pub const SYS_sched_getscheduler = 330; +pub const SYS_sched_yield = 331; +pub const SYS_sched_get_priority_max = 332; +pub const SYS_sched_get_priority_min = 333; +pub const SYS_sched_rr_get_interval = 334; +pub const SYS_utrace = 335; +// 336 is freebsd4 sendfile +pub const SYS_kldsym = 337; +pub const SYS_jail = 338; +pub const SYS_nnpfs_syscall = 339; +pub const SYS_sigprocmask = 340; +pub const SYS_sigsuspend = 341; +// 342 is freebsd4 sigaction +pub const SYS_sigpending = 343; +// 344 is freebsd4 sigreturn +pub const SYS_sigtimedwait = 345; +pub const SYS_sigwaitinfo = 346; +pub const SYS___acl_get_file = 347; +pub const SYS___acl_set_file = 348; +pub const SYS___acl_get_fd = 349; +pub const SYS___acl_set_fd = 350; +pub const SYS___acl_delete_file = 351; +pub const SYS___acl_delete_fd = 352; +pub const SYS___acl_aclcheck_file = 353; +pub const SYS___acl_aclcheck_fd = 354; +pub const SYS_extattrctl = 355; +pub const SYS_extattr_set_file = 356; +pub const SYS_extattr_get_file = 357; +pub const SYS_extattr_delete_file = 358; +pub const SYS_aio_waitcomplete = 359; +pub const SYS_getresuid = 360; +pub const SYS_getresgid = 361; +pub const SYS_kqueue = 362; +pub const SYS_freebsd11_kevent = 363; +// 364 is obsolete __cap_get_proc +// 365 is obsolete __cap_set_proc +// 366 is obsolete __cap_get_fd +// 367 is obsolete __cap_get_file +// 368 is obsolete __cap_set_fd +// 369 is obsolete __cap_set_file +pub const SYS_extattr_set_fd = 371; +pub const SYS_extattr_get_fd = 372; +pub const SYS_extattr_delete_fd = 373; +pub const SYS___setugid = 374; +pub const SYS_eaccess = 376; +pub const SYS_afs3_syscall = 377; +pub const SYS_nmount = 378; +// 379 is obsolete kse_exit +// 380 is obsolete kse_wakeup +// 381 is obsolete kse_create +// 382 is obsolete kse_thr_interrupt +// 383 is obsolete kse_release +pub const SYS___mac_get_proc = 384; +pub const SYS___mac_set_proc = 385; +pub const SYS___mac_get_fd = 386; +pub const SYS___mac_get_file = 387; +pub const SYS___mac_set_fd = 388; +pub const SYS___mac_set_file = 389; +pub const SYS_kenv = 390; +pub const SYS_lchflags = 391; +pub const SYS_uuidgen = 392; +pub const SYS_sendfile = 393; +pub const SYS_mac_syscall = 394; +pub const SYS_freebsd11_getfsstat = 395; +pub const SYS_freebsd11_statfs = 396; +pub const SYS_freebsd11_fstatfs = 397; +pub const SYS_freebsd11_fhstatfs = 398; +pub const SYS_ksem_close = 400; +pub const SYS_ksem_post = 401; +pub const SYS_ksem_wait = 402; +pub const SYS_ksem_trywait = 403; +pub const SYS_ksem_init = 404; +pub const SYS_ksem_open = 405; +pub const SYS_ksem_unlink = 406; +pub const SYS_ksem_getvalue = 407; +pub const SYS_ksem_destroy = 408; +pub const SYS___mac_get_pid = 409; +pub const SYS___mac_get_link = 410; +pub const SYS___mac_set_link = 411; +pub const SYS_extattr_set_link = 412; +pub const SYS_extattr_get_link = 413; +pub const SYS_extattr_delete_link = 414; +pub const SYS___mac_execve = 415; +pub const SYS_sigaction = 416; +pub const SYS_sigreturn = 417; +pub const SYS_getcontext = 421; +pub const SYS_setcontext = 422; +pub const SYS_swapcontext = 423; +pub const SYS_swapoff = 424; +pub const SYS___acl_get_link = 425; +pub const SYS___acl_set_link = 426; +pub const SYS___acl_delete_link = 427; +pub const SYS___acl_aclcheck_link = 428; +pub const SYS_sigwait = 429; +pub const SYS_thr_create = 430; +pub const SYS_thr_exit = 431; +pub const SYS_thr_self = 432; +pub const SYS_thr_kill = 433; +pub const SYS_jail_attach = 436; +pub const SYS_extattr_list_fd = 437; +pub const SYS_extattr_list_file = 438; +pub const SYS_extattr_list_link = 439; +// 440 is obsolete kse_switchin +pub const SYS_ksem_timedwait = 441; +pub const SYS_thr_suspend = 442; +pub const SYS_thr_wake = 443; +pub const SYS_kldunloadf = 444; +pub const SYS_audit = 445; +pub const SYS_auditon = 446; +pub const SYS_getauid = 447; +pub const SYS_setauid = 448; +pub const SYS_getaudit = 449; +pub const SYS_setaudit = 450; +pub const SYS_getaudit_addr = 451; +pub const SYS_setaudit_addr = 452; +pub const SYS_auditctl = 453; +pub const SYS__umtx_op = 454; +pub const SYS_thr_new = 455; +pub const SYS_sigqueue = 456; +pub const SYS_kmq_open = 457; +pub const SYS_kmq_setattr = 458; +pub const SYS_kmq_timedreceive = 459; +pub const SYS_kmq_timedsend = 460; +pub const SYS_kmq_notify = 461; +pub const SYS_kmq_unlink = 462; +pub const SYS_abort2 = 463; +pub const SYS_thr_set_name = 464; +pub const SYS_aio_fsync = 465; +pub const SYS_rtprio_thread = 466; +pub const SYS_sctp_peeloff = 471; +pub const SYS_sctp_generic_sendmsg = 472; +pub const SYS_sctp_generic_sendmsg_iov = 473; +pub const SYS_sctp_generic_recvmsg = 474; +pub const SYS_pread = 475; +pub const SYS_pwrite = 476; +pub const SYS_mmap = 477; +pub const SYS_lseek = 478; +pub const SYS_truncate = 479; +pub const SYS_ftruncate = 480; +pub const SYS_thr_kill2 = 481; +pub const SYS_shm_open = 482; +pub const SYS_shm_unlink = 483; +pub const SYS_cpuset = 484; +pub const SYS_cpuset_setid = 485; +pub const SYS_cpuset_getid = 486; +pub const SYS_cpuset_getaffinity = 487; +pub const SYS_cpuset_setaffinity = 488; +pub const SYS_faccessat = 489; +pub const SYS_fchmodat = 490; +pub const SYS_fchownat = 491; +pub const SYS_fexecve = 492; +pub const SYS_freebsd11_fstatat = 493; +pub const SYS_futimesat = 494; +pub const SYS_linkat = 495; +pub const SYS_mkdirat = 496; +pub const SYS_mkfifoat = 497; +pub const SYS_freebsd11_mknodat = 498; +pub const SYS_openat = 499; +pub const SYS_readlinkat = 500; +pub const SYS_renameat = 501; +pub const SYS_symlinkat = 502; +pub const SYS_unlinkat = 503; +pub const SYS_posix_openpt = 504; +pub const SYS_gssd_syscall = 505; +pub const SYS_jail_get = 506; +pub const SYS_jail_set = 507; +pub const SYS_jail_remove = 508; +pub const SYS_closefrom = 509; +pub const SYS___semctl = 510; +pub const SYS_msgctl = 511; +pub const SYS_shmctl = 512; +pub const SYS_lpathconf = 513; +// 514 is obsolete cap_new +pub const SYS___cap_rights_get = 515; +pub const SYS_cap_enter = 516; +pub const SYS_cap_getmode = 517; +pub const SYS_pdfork = 518; +pub const SYS_pdkill = 519; +pub const SYS_pdgetpid = 520; +pub const SYS_pselect = 522; +pub const SYS_getloginclass = 523; +pub const SYS_setloginclass = 524; +pub const SYS_rctl_get_racct = 525; +pub const SYS_rctl_get_rules = 526; +pub const SYS_rctl_get_limits = 527; +pub const SYS_rctl_add_rule = 528; +pub const SYS_rctl_remove_rule = 529; +pub const SYS_posix_fallocate = 530; +pub const SYS_posix_fadvise = 531; +pub const SYS_wait6 = 532; +pub const SYS_cap_rights_limit = 533; +pub const SYS_cap_ioctls_limit = 534; +pub const SYS_cap_ioctls_get = 535; +pub const SYS_cap_fcntls_limit = 536; +pub const SYS_cap_fcntls_get = 537; +pub const SYS_bindat = 538; +pub const SYS_connectat = 539; +pub const SYS_chflagsat = 540; +pub const SYS_accept4 = 541; +pub const SYS_pipe2 = 542; +pub const SYS_aio_mlock = 543; +pub const SYS_procctl = 544; +pub const SYS_ppoll = 545; +pub const SYS_futimens = 546; +pub const SYS_utimensat = 547; +// 548 is obsolete numa_getaffinity +// 549 is obsolete numa_setaffinity +pub const SYS_fdatasync = 550; +pub const SYS_fstat = 551; +pub const SYS_fstatat = 552; +pub const SYS_fhstat = 553; +pub const SYS_getdirentries = 554; +pub const SYS_statfs = 555; +pub const SYS_fstatfs = 556; +pub const SYS_getfsstat = 557; +pub const SYS_fhstatfs = 558; +pub const SYS_mknodat = 559; +pub const SYS_kevent = 560; +pub const SYS_cpuset_getdomain = 561; +pub const SYS_cpuset_setdomain = 562; +pub const SYS_getrandom = 563; +pub const SYS_MAXSYSCALL = 564; diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig index cd9104b88..63255a902 100644 --- a/std/os/freebsd/x86_64.zig +++ b/std/os/freebsd/x86_64.zig @@ -2,481 +2,7 @@ const freebsd = @import("index.zig"); const socklen_t = freebsd.socklen_t; const iovec = freebsd.iovec; -pub const SYS_syscall = 0; -pub const SYS_exit = 1; -pub const SYS_fork = 2; -pub const SYS_read = 3; -pub const SYS_write = 4; -pub const SYS_open = 5; -pub const SYS_close = 6; -pub const SYS_wait4 = 7; -// 8 is old creat -pub const SYS_link = 9; -pub const SYS_unlink = 10; -// 11 is obsolete execv -pub const SYS_chdir = 12; -pub const SYS_fchdir = 13; -pub const SYS_freebsd11_mknod = 14; -pub const SYS_chmod = 15; -pub const SYS_chown = 16; -pub const SYS_break = 17; -// 18 is freebsd4 getfsstat -// 19 is old lseek -pub const SYS_getpid = 20; -pub const SYS_mount = 21; -pub const SYS_unmount = 22; -pub const SYS_setuid = 23; -pub const SYS_getuid = 24; -pub const SYS_geteuid = 25; -pub const SYS_ptrace = 26; -pub const SYS_recvmsg = 27; -pub const SYS_sendmsg = 28; -pub const SYS_recvfrom = 29; -pub const SYS_accept = 30; -pub const SYS_getpeername = 31; -pub const SYS_getsockname = 32; -pub const SYS_access = 33; -pub const SYS_chflags = 34; -pub const SYS_fchflags = 35; -pub const SYS_sync = 36; -pub const SYS_kill = 37; -// 38 is old stat -pub const SYS_getppid = 39; -// 40 is old lstat -pub const SYS_dup = 41; -pub const SYS_freebsd10_pipe = 42; -pub const SYS_getegid = 43; -pub const SYS_profil = 44; -pub const SYS_ktrace = 45; -// 46 is old sigaction -pub const SYS_getgid = 47; -// 48 is old sigprocmask -pub const SYS_getlogin = 49; -pub const SYS_setlogin = 50; -pub const SYS_acct = 51; -// 52 is old sigpending -pub const SYS_sigaltstack = 53; -pub const SYS_ioctl = 54; -pub const SYS_reboot = 55; -pub const SYS_revoke = 56; -pub const SYS_symlink = 57; -pub const SYS_readlink = 58; -pub const SYS_execve = 59; -pub const SYS_umask = 60; -pub const SYS_chroot = 61; -// 62 is old fstat -// 63 is old getkerninfo -// 64 is old getpagesize -pub const SYS_msync = 65; -pub const SYS_vfork = 66; -// 67 is obsolete vread -// 68 is obsolete vwrite pub const SYS_sbrk = 69; -pub const SYS_sstk = 70; -// 71 is old mmap -pub const SYS_vadvise = 72; -pub const SYS_munmap = 73; -pub const SYS_mprotect = 74; -pub const SYS_madvise = 75; -// 76 is obsolete vhangup -// 77 is obsolete vlimit -pub const SYS_mincore = 78; -pub const SYS_getgroups = 79; -pub const SYS_setgroups = 80; -pub const SYS_getpgrp = 81; -pub const SYS_setpgid = 82; -pub const SYS_setitimer = 83; -// 84 is old wait -pub const SYS_swapon = 85; -pub const SYS_getitimer = 86; -// 87 is old gethostname -// 88 is old sethostname -pub const SYS_getdtablesize = 89; -pub const SYS_dup2 = 90; -pub const SYS_fcntl = 92; -pub const SYS_select = 93; -pub const SYS_fsync = 95; -pub const SYS_setpriority = 96; -pub const SYS_socket = 97; -pub const SYS_connect = 98; -// 99 is old accept -pub const SYS_getpriority = 100; -// 101 is old send -// 102 is old recv -// 103 is old sigreturn -pub const SYS_bind = 104; -pub const SYS_setsockopt = 105; -pub const SYS_listen = 106; -// 107 is obsolete vtimes -// 108 is old sigvec -// 109 is old sigblock -// 110 is old sigsetmask -// 111 is old sigsuspend -// 112 is old sigstack -// 113 is old recvmsg -// 114 is old sendmsg -// 115 is obsolete vtrace -pub const SYS_gettimeofday = 116; -pub const SYS_getrusage = 117; -pub const SYS_getsockopt = 118; -pub const SYS_readv = 120; -pub const SYS_writev = 121; -pub const SYS_settimeofday = 122; -pub const SYS_fchown = 123; -pub const SYS_fchmod = 124; -// 125 is old recvfrom -pub const SYS_setreuid = 126; -pub const SYS_setregid = 127; -pub const SYS_rename = 128; -// 129 is old truncate -// 130 is old ftruncate -pub const SYS_flock = 131; -pub const SYS_mkfifo = 132; -pub const SYS_sendto = 133; -pub const SYS_shutdown = 134; -pub const SYS_socketpair = 135; -pub const SYS_mkdir = 136; -pub const SYS_rmdir = 137; -pub const SYS_utimes = 138; -// 139 is obsolete 4.2 sigreturn -pub const SYS_adjtime = 140; -// 141 is old getpeername -// 142 is old gethostid -// 143 is old sethostid -// 144 is old getrlimit -// 145 is old setrlimit -// 146 is old killpg -pub const SYS_setsid = 147; -pub const SYS_quotactl = 148; -// 149 is old quota -// 150 is old getsockname -pub const SYS_nlm_syscall = 154; -pub const SYS_nfssvc = 155; -// 156 is old getdirentries -// 157 is freebsd4 statfs -// 158 is freebsd4 fstatfs -pub const SYS_lgetfh = 160; -pub const SYS_getfh = 161; -// 162 is freebsd4 getdomainname -// 163 is freebsd4 setdomainname -// 164 is freebsd4 uname -pub const SYS_sysarch = 165; -pub const SYS_rtprio = 166; -pub const SYS_semsys = 169; -pub const SYS_msgsys = 170; -pub const SYS_shmsys = 171; -// 173 is freebsd6 pread -// 174 is freebsd6 pwrite -pub const SYS_setfib = 175; -pub const SYS_ntp_adjtime = 176; -pub const SYS_setgid = 181; -pub const SYS_setegid = 182; -pub const SYS_seteuid = 183; -pub const SYS_freebsd11_stat = 188; -pub const SYS_freebsd11_fstat = 189; -pub const SYS_freebsd11_lstat = 190; -pub const SYS_pathconf = 191; -pub const SYS_fpathconf = 192; -pub const SYS_getrlimit = 194; -pub const SYS_setrlimit = 195; -pub const SYS_freebsd11_getdirentries = 196; -// 197 is freebsd6 mmap -pub const SYS___syscall = 198; -// 199 is freebsd6 lseek -// 200 is freebsd6 truncate -// 201 is freebsd6 ftruncate -pub const SYS___sysctl = 202; -pub const SYS_mlock = 203; -pub const SYS_munlock = 204; -pub const SYS_undelete = 205; -pub const SYS_futimes = 206; -pub const SYS_getpgid = 207; -pub const SYS_poll = 209; -pub const SYS_freebsd7___semctl = 220; -pub const SYS_semget = 221; -pub const SYS_semop = 222; -pub const SYS_freebsd7_msgctl = 224; -pub const SYS_msgget = 225; -pub const SYS_msgsnd = 226; -pub const SYS_msgrcv = 227; -pub const SYS_shmat = 228; -pub const SYS_freebsd7_shmctl = 229; -pub const SYS_shmdt = 230; -pub const SYS_shmget = 231; -pub const SYS_clock_gettime = 232; -pub const SYS_clock_settime = 233; -pub const SYS_clock_getres = 234; -pub const SYS_ktimer_create = 235; -pub const SYS_ktimer_delete = 236; -pub const SYS_ktimer_settime = 237; -pub const SYS_ktimer_gettime = 238; -pub const SYS_ktimer_getoverrun = 239; -pub const SYS_nanosleep = 240; -pub const SYS_ffclock_getcounter = 241; -pub const SYS_ffclock_setestimate = 242; -pub const SYS_ffclock_getestimate = 243; -pub const SYS_clock_nanosleep = 244; -pub const SYS_clock_getcpuclockid2 = 247; -pub const SYS_ntp_gettime = 248; -pub const SYS_minherit = 250; -pub const SYS_rfork = 251; -// 252 is obsolete openbsd_poll -pub const SYS_issetugid = 253; -pub const SYS_lchown = 254; -pub const SYS_aio_read = 255; -pub const SYS_aio_write = 256; -pub const SYS_lio_listio = 257; -pub const SYS_freebsd11_getdents = 272; -pub const SYS_lchmod = 274; -pub const SYS_netbsd_lchown = 275; -pub const SYS_lutimes = 276; -pub const SYS_netbsd_msync = 277; -pub const SYS_freebsd11_nstat = 278; -pub const SYS_freebsd11_nfstat = 279; -pub const SYS_freebsd11_nlstat = 280; -pub const SYS_preadv = 289; -pub const SYS_pwritev = 290; -// 297 is freebsd4 fhstatfs -pub const SYS_fhopen = 298; -pub const SYS_freebsd11_fhstat = 299; -pub const SYS_modnext = 300; -pub const SYS_modstat = 301; -pub const SYS_modfnext = 302; -pub const SYS_modfind = 303; -pub const SYS_kldload = 304; -pub const SYS_kldunload = 305; -pub const SYS_kldfind = 306; -pub const SYS_kldnext = 307; -pub const SYS_kldstat = 308; -pub const SYS_kldfirstmod = 309; -pub const SYS_getsid = 310; -pub const SYS_setresuid = 311; -pub const SYS_setresgid = 312; -// 313 is obsolete signanosleep -pub const SYS_aio_return = 314; -pub const SYS_aio_suspend = 315; -pub const SYS_aio_cancel = 316; -pub const SYS_aio_error = 317; -// 318 is freebsd6 aio_read -// 319 is freebsd6 aio_write -// 320 is freebsd6 lio_listio -pub const SYS_yield = 321; -// 322 is obsolete thr_sleep -// 323 is obsolete thr_wakeup -pub const SYS_mlockall = 324; -pub const SYS_munlockall = 325; -pub const SYS___getcwd = 326; -pub const SYS_sched_setparam = 327; -pub const SYS_sched_getparam = 328; -pub const SYS_sched_setscheduler = 329; -pub const SYS_sched_getscheduler = 330; -pub const SYS_sched_yield = 331; -pub const SYS_sched_get_priority_max = 332; -pub const SYS_sched_get_priority_min = 333; -pub const SYS_sched_rr_get_interval = 334; -pub const SYS_utrace = 335; -// 336 is freebsd4 sendfile -pub const SYS_kldsym = 337; -pub const SYS_jail = 338; -pub const SYS_nnpfs_syscall = 339; -pub const SYS_sigprocmask = 340; -pub const SYS_sigsuspend = 341; -// 342 is freebsd4 sigaction -pub const SYS_sigpending = 343; -// 344 is freebsd4 sigreturn -pub const SYS_sigtimedwait = 345; -pub const SYS_sigwaitinfo = 346; -pub const SYS___acl_get_file = 347; -pub const SYS___acl_set_file = 348; -pub const SYS___acl_get_fd = 349; -pub const SYS___acl_set_fd = 350; -pub const SYS___acl_delete_file = 351; -pub const SYS___acl_delete_fd = 352; -pub const SYS___acl_aclcheck_file = 353; -pub const SYS___acl_aclcheck_fd = 354; -pub const SYS_extattrctl = 355; -pub const SYS_extattr_set_file = 356; -pub const SYS_extattr_get_file = 357; -pub const SYS_extattr_delete_file = 358; -pub const SYS_aio_waitcomplete = 359; -pub const SYS_getresuid = 360; -pub const SYS_getresgid = 361; -pub const SYS_kqueue = 362; -pub const SYS_freebsd11_kevent = 363; -pub const SYS_extattr_set_fd = 371; -pub const SYS_extattr_get_fd = 372; -pub const SYS_extattr_delete_fd = 373; -pub const SYS___setugid = 374; -pub const SYS_eaccess = 376; -pub const SYS_afs3_syscall = 377; -pub const SYS_nmount = 378; -pub const SYS___mac_get_proc = 384; -pub const SYS___mac_set_proc = 385; -pub const SYS___mac_get_fd = 386; -pub const SYS___mac_get_file = 387; -pub const SYS___mac_set_fd = 388; -pub const SYS___mac_set_file = 389; -pub const SYS_kenv = 390; -pub const SYS_lchflags = 391; -pub const SYS_uuidgen = 392; -pub const SYS_sendfile = 393; -pub const SYS_mac_syscall = 394; -pub const SYS_freebsd11_getfsstat = 395; -pub const SYS_freebsd11_statfs = 396; -pub const SYS_freebsd11_fstatfs = 397; -pub const SYS_freebsd11_fhstatfs = 398; -pub const SYS_ksem_close = 400; -pub const SYS_ksem_post = 401; -pub const SYS_ksem_wait = 402; -pub const SYS_ksem_trywait = 403; -pub const SYS_ksem_init = 404; -pub const SYS_ksem_open = 405; -pub const SYS_ksem_unlink = 406; -pub const SYS_ksem_getvalue = 407; -pub const SYS_ksem_destroy = 408; -pub const SYS___mac_get_pid = 409; -pub const SYS___mac_get_link = 410; -pub const SYS___mac_set_link = 411; -pub const SYS_extattr_set_link = 412; -pub const SYS_extattr_get_link = 413; -pub const SYS_extattr_delete_link = 414; -pub const SYS___mac_execve = 415; -pub const SYS_sigaction = 416; -pub const SYS_sigreturn = 417; -pub const SYS_getcontext = 421; -pub const SYS_setcontext = 422; -pub const SYS_swapcontext = 423; -pub const SYS_swapoff = 424; -pub const SYS___acl_get_link = 425; -pub const SYS___acl_set_link = 426; -pub const SYS___acl_delete_link = 427; -pub const SYS___acl_aclcheck_link = 428; -pub const SYS_sigwait = 429; -pub const SYS_thr_create = 430; -pub const SYS_thr_exit = 431; -pub const SYS_thr_self = 432; -pub const SYS_thr_kill = 433; -pub const SYS_jail_attach = 436; -pub const SYS_extattr_list_fd = 437; -pub const SYS_extattr_list_file = 438; -pub const SYS_extattr_list_link = 439; -pub const SYS_ksem_timedwait = 441; -pub const SYS_thr_suspend = 442; -pub const SYS_thr_wake = 443; -pub const SYS_kldunloadf = 444; -pub const SYS_audit = 445; -pub const SYS_auditon = 446; -pub const SYS_getauid = 447; -pub const SYS_setauid = 448; -pub const SYS_getaudit = 449; -pub const SYS_setaudit = 450; -pub const SYS_getaudit_addr = 451; -pub const SYS_setaudit_addr = 452; -pub const SYS_auditctl = 453; -pub const SYS__umtx_op = 454; -pub const SYS_thr_new = 455; -pub const SYS_sigqueue = 456; -pub const SYS_kmq_open = 457; -pub const SYS_kmq_setattr = 458; -pub const SYS_kmq_timedreceive = 459; -pub const SYS_kmq_timedsend = 460; -pub const SYS_kmq_notify = 461; -pub const SYS_kmq_unlink = 462; -pub const SYS_abort2 = 463; -pub const SYS_thr_set_name = 464; -pub const SYS_aio_fsync = 465; -pub const SYS_rtprio_thread = 466; -pub const SYS_sctp_peeloff = 471; -pub const SYS_sctp_generic_sendmsg = 472; -pub const SYS_sctp_generic_sendmsg_iov = 473; -pub const SYS_sctp_generic_recvmsg = 474; -pub const SYS_pread = 475; -pub const SYS_pwrite = 476; -pub const SYS_mmap = 477; -pub const SYS_lseek = 478; -pub const SYS_truncate = 479; -pub const SYS_ftruncate = 480; -pub const SYS_thr_kill2 = 481; -pub const SYS_shm_open = 482; -pub const SYS_shm_unlink = 483; -pub const SYS_cpuset = 484; -pub const SYS_cpuset_setid = 485; -pub const SYS_cpuset_getid = 486; -pub const SYS_cpuset_getaffinity = 487; -pub const SYS_cpuset_setaffinity = 488; -pub const SYS_faccessat = 489; -pub const SYS_fchmodat = 490; -pub const SYS_fchownat = 491; -pub const SYS_fexecve = 492; -pub const SYS_freebsd11_fstatat = 493; -pub const SYS_futimesat = 494; -pub const SYS_linkat = 495; -pub const SYS_mkdirat = 496; -pub const SYS_mkfifoat = 497; -pub const SYS_freebsd11_mknodat = 498; -pub const SYS_openat = 499; -pub const SYS_readlinkat = 500; -pub const SYS_renameat = 501; -pub const SYS_symlinkat = 502; -pub const SYS_unlinkat = 503; -pub const SYS_posix_openpt = 504; -pub const SYS_gssd_syscall = 505; -pub const SYS_jail_get = 506; -pub const SYS_jail_set = 507; -pub const SYS_jail_remove = 508; -pub const SYS_closefrom = 509; -pub const SYS___semctl = 510; -pub const SYS_msgctl = 511; -pub const SYS_shmctl = 512; -pub const SYS_lpathconf = 513; -// 514 is obsolete cap_new -pub const SYS___cap_rights_get = 515; -pub const SYS_cap_enter = 516; -pub const SYS_cap_getmode = 517; -pub const SYS_pdfork = 518; -pub const SYS_pdkill = 519; -pub const SYS_pdgetpid = 520; -pub const SYS_pselect = 522; -pub const SYS_getloginclass = 523; -pub const SYS_setloginclass = 524; -pub const SYS_rctl_get_racct = 525; -pub const SYS_rctl_get_rules = 526; -pub const SYS_rctl_get_limits = 527; -pub const SYS_rctl_add_rule = 528; -pub const SYS_rctl_remove_rule = 529; -pub const SYS_posix_fallocate = 530; -pub const SYS_posix_fadvise = 531; -pub const SYS_wait6 = 532; -pub const SYS_cap_rights_limit = 533; -pub const SYS_cap_ioctls_limit = 534; -pub const SYS_cap_ioctls_get = 535; -pub const SYS_cap_fcntls_limit = 536; -pub const SYS_cap_fcntls_get = 537; -pub const SYS_bindat = 538; -pub const SYS_connectat = 539; -pub const SYS_chflagsat = 540; -pub const SYS_accept4 = 541; -pub const SYS_pipe2 = 542; -pub const SYS_aio_mlock = 543; -pub const SYS_procctl = 544; -pub const SYS_ppoll = 545; -pub const SYS_futimens = 546; -pub const SYS_utimensat = 547; -pub const SYS_numa_getaffinity = 548; -pub const SYS_numa_setaffinity = 549; -pub const SYS_fdatasync = 550; -pub const SYS_fstat = 551; -pub const SYS_fstatat = 552; -pub const SYS_fhstat = 553; -pub const SYS_getdirentries = 554; -pub const SYS_statfs = 555; -pub const SYS_fstatfs = 556; -pub const SYS_getfsstat = 557; -pub const SYS_fhstatfs = 558; -pub const SYS_mknodat = 559; -pub const SYS_kevent = 560; -pub const SYS_MAXSYSCALL = 561; -pub const SYS_getrandom = 563; pub const O_CREAT = 0o100; pub const O_EXCL = 0o200; From d6cab0d4b653b1f6d7340b9a24766abae4f208a8 Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 18:12:53 +0300 Subject: [PATCH 010/110] Various fcntl flags are also machine-independent on FreeBSD --- std/os/freebsd/index.zig | 58 ++++++++++++++++++++++++++------------- std/os/freebsd/x86_64.zig | 41 --------------------------- 2 files changed, 39 insertions(+), 60 deletions(-) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index c442dd665..1df773b04 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -95,26 +95,46 @@ pub const O_WRONLY = 0o1; pub const O_RDWR = 0o2; pub const O_ACCMODE = 0o3; -pub const O_CREAT = arch.O_CREAT; -pub const O_EXCL = arch.O_EXCL; -pub const O_NOCTTY = arch.O_NOCTTY; -pub const O_TRUNC = arch.O_TRUNC; -pub const O_APPEND = arch.O_APPEND; -pub const O_NONBLOCK = arch.O_NONBLOCK; -pub const O_DSYNC = arch.O_DSYNC; -pub const O_SYNC = arch.O_SYNC; -pub const O_RSYNC = arch.O_RSYNC; -pub const O_DIRECTORY = arch.O_DIRECTORY; -pub const O_NOFOLLOW = arch.O_NOFOLLOW; -pub const O_CLOEXEC = arch.O_CLOEXEC; +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o200000; +pub const O_NOFOLLOW = 0o400000; +pub const O_CLOEXEC = 0o2000000; -pub const O_ASYNC = arch.O_ASYNC; -pub const O_DIRECT = arch.O_DIRECT; -pub const O_LARGEFILE = arch.O_LARGEFILE; -pub const O_NOATIME = arch.O_NOATIME; -pub const O_PATH = arch.O_PATH; -pub const O_TMPFILE = arch.O_TMPFILE; -pub const O_NDELAY = arch.O_NDELAY; +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o40000; +pub const O_LARGEFILE = 0; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 5; +pub const F_SETLK = 6; +pub const F_SETLKW = 7; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; pub const SEEK_SET = 0; pub const SEEK_CUR = 1; diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig index 63255a902..28ae2d547 100644 --- a/std/os/freebsd/x86_64.zig +++ b/std/os/freebsd/x86_64.zig @@ -4,47 +4,6 @@ const iovec = freebsd.iovec; pub const SYS_sbrk = 69; -pub const O_CREAT = 0o100; -pub const O_EXCL = 0o200; -pub const O_NOCTTY = 0o400; -pub const O_TRUNC = 0o1000; -pub const O_APPEND = 0o2000; -pub const O_NONBLOCK = 0o4000; -pub const O_DSYNC = 0o10000; -pub const O_SYNC = 0o4010000; -pub const O_RSYNC = 0o4010000; -pub const O_DIRECTORY = 0o200000; -pub const O_NOFOLLOW = 0o400000; -pub const O_CLOEXEC = 0o2000000; - -pub const O_ASYNC = 0o20000; -pub const O_DIRECT = 0o40000; -pub const O_LARGEFILE = 0; -pub const O_NOATIME = 0o1000000; -pub const O_PATH = 0o10000000; -pub const O_TMPFILE = 0o20200000; -pub const O_NDELAY = O_NONBLOCK; - -pub const F_DUPFD = 0; -pub const F_GETFD = 1; -pub const F_SETFD = 2; -pub const F_GETFL = 3; -pub const F_SETFL = 4; - -pub const F_SETOWN = 8; -pub const F_GETOWN = 9; -pub const F_SETSIG = 10; -pub const F_GETSIG = 11; - -pub const F_GETLK = 5; -pub const F_SETLK = 6; -pub const F_SETLKW = 7; - -pub const F_SETOWN_EX = 15; -pub const F_GETOWN_EX = 16; - -pub const F_GETOWNER_UIDS = 17; - pub fn syscall0(number: usize) usize { return asm volatile ("syscall" : [ret] "={rax}" (-> usize) From a983a0a59b348a885f24656a8646707554170574 Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 22:18:50 +0300 Subject: [PATCH 011/110] Add /usr/local/lib path for libxml2 and link libc++ on FreeBSD --- build.zig | 6 +++++- std/build.zig | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/build.zig b/build.zig index c2a20015a..fc460df12 100644 --- a/build.zig +++ b/build.zig @@ -284,7 +284,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { exe.addObjectFile(libstdcxx_path); exe.linkSystemLibrary("pthread"); - } else if (exe.target.isDarwin()) { + } else if (exe.target.isDarwin() or exe.target.isFreeBSD()) { exe.linkSystemLibrary("c++"); } @@ -293,6 +293,10 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { } if (exe.target.getOs() != builtin.Os.windows) { + if (exe.target.isFreeBSD()) { + exe.addLibPath("/usr/local/lib"); + // TODO use pkg-config + } exe.linkSystemLibrary("xml2"); } exe.linkSystemLibrary("c"); diff --git a/std/build.zig b/std/build.zig index a80580a38..743535eb1 100644 --- a/std/build.zig +++ b/std/build.zig @@ -795,6 +795,13 @@ pub const Target = union(enum).{ }; } + pub fn isFreeBSD(self: *const Target) bool { + return switch (self.getOs()) { + builtin.Os.freebsd => true, + else => false, + }; + } + pub fn wantSharedLibSymLinks(self: *const Target) bool { return !self.isWindows(); } From 831bb668955fa9d332f7beb1ea11f1c8028e5235 Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 22:21:16 +0300 Subject: [PATCH 012/110] Set up libc/rtld paths for FreeBSD --- src-self-hosted/libc_installation.zig | 2 +- src-self-hosted/target.zig | 9 ++++++++- src/analyze.cpp | 6 +++++- src/link.cpp | 3 +++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index daab05822..86672a2b9 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -172,7 +172,7 @@ pub const LibCInstallation = struct.{ try group.call(findNativeStaticLibDir, self, loop); try group.call(findNativeDynamicLinker, self, loop); }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include"); }, else => @compileError("unimplemented: find libc for this OS"), diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 44c98e79b..0b6842490 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -299,6 +299,13 @@ pub const Target = union(enum).{ pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { const env = self.getEnviron(); const arch = self.getArch(); + const os = self.getOs(); + switch (os) { + builtin.Os.freebsd => { + return "/libexec/ld-elf.so.1"; + }, + else => {}, + } switch (env) { builtin.Environ.android => { if (self.is64bit()) { @@ -493,6 +500,7 @@ pub const Target = union(enum).{ builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, builtin.Os.openbsd, builtin.Os.zen, => switch (id) { @@ -527,7 +535,6 @@ pub const Target = union(enum).{ builtin.Os.ananas, builtin.Os.cloudabi, builtin.Os.dragonfly, - builtin.Os.freebsd, builtin.Os.fuchsia, builtin.Os.ios, builtin.Os.kfreebsd, diff --git a/src/analyze.cpp b/src/analyze.cpp index e71369eac..4d7fe1a65 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4606,7 +4606,7 @@ void find_libc_include_path(CodeGen *g) { } } else if (g->zig_target.os == OsLinux) { g->libc_include_dir = get_linux_libc_include_path(); - } else if (g->zig_target.os == OsMacOSX) { + } else if (g->zig_target.os == OsMacOSX || g->zig_target.os == OsFreeBSD) { g->libc_include_dir = buf_create_from_str("/usr/include"); } else { // TODO find libc at runtime for other operating systems @@ -4652,6 +4652,8 @@ void find_libc_lib_path(CodeGen *g) { } else if (g->zig_target.os == OsLinux) { g->libc_lib_dir = get_linux_libc_lib_path("crt1.o"); + } else if (g->zig_target.os == OsFreeBSD) { + g->libc_lib_dir = buf_create_from_str("/usr/lib"); } else { zig_panic("Unable to determine libc lib path."); } @@ -4664,6 +4666,8 @@ void find_libc_lib_path(CodeGen *g) { return; } else if (g->zig_target.os == OsLinux) { g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o"); + } else if (g->zig_target.os == OsFreeBSD) { + g->libc_static_lib_dir = buf_create_from_str("/usr/lib"); } else { zig_panic("Unable to determine libc static lib path."); } diff --git a/src/link.cpp b/src/link.cpp index 613768cec..0913b96a0 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -195,6 +195,9 @@ static Buf *try_dynamic_linker_path(const char *ld_name) { } static Buf *get_dynamic_linker_path(CodeGen *g) { + if (g->zig_target.os == OsFreeBSD) { + return buf_create_from_str("/libexec/ld-elf.so.1"); + } if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) { static const char *ld_names[] = { "ld-linux-x86-64.so.2", From e5627f8e635c05a91edeb97b6d0e392d095ce39f Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 22:21:48 +0300 Subject: [PATCH 013/110] Support more of std on FreeBSD --- CMakeLists.txt | 1 + std/c/freebsd.zig | 36 ++++++ std/c/index.zig | 1 + std/event/fs.zig | 32 ++++-- std/event/loop.zig | 27 ++--- std/os/freebsd/index.zig | 212 +++++++++++++++++++++++++++++++++++- std/os/get_app_data_dir.zig | 2 +- std/os/index.zig | 34 ++++-- 8 files changed, 308 insertions(+), 37 deletions(-) create mode 100644 std/c/freebsd.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index f10fc91b1..4ee9bcad1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -444,6 +444,7 @@ set(ZIG_STD_FILES "buffer.zig" "build.zig" "c/darwin.zig" + "c/freebsd.zig" "c/index.zig" "c/linux.zig" "c/windows.zig" diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig new file mode 100644 index 000000000..6eb34929b --- /dev/null +++ b/std/c/freebsd.zig @@ -0,0 +1,36 @@ + +const timespec = @import("../os/freebsd/index.zig").timespec; + +extern "c" fn __error() *c_int; +pub const _errno = __error; + +pub extern "c" fn kqueue() c_int; +pub extern "c" fn kevent( + kq: c_int, + changelist: [*]const Kevent, + nchanges: c_int, + eventlist: [*]Kevent, + nevents: c_int, + timeout: ?*const timespec, +) c_int; +pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; +pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; +pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; + +/// Renamed from `kevent` to `Kevent` to avoid conflict with function name. +pub const Kevent = extern struct.{ + ident: usize, + filter: i16, + flags: u16, + fflags: u32, + data: i64, + udata: usize, + // TODO ext +}; + + +pub const pthread_attr_t = extern struct.{ + __size: [56]u8, + __align: c_long, +}; + diff --git a/std/c/index.zig b/std/c/index.zig index 6b20d718e..4aab39d93 100644 --- a/std/c/index.zig +++ b/std/c/index.zig @@ -5,6 +5,7 @@ pub use switch (builtin.os) { Os.linux => @import("linux.zig"), Os.windows => @import("windows.zig"), Os.macosx, Os.ios => @import("darwin.zig"), + Os.freebsd => @import("freebsd.zig"), else => empty_import, }; const empty_import = @import("../empty.zig"); diff --git a/std/event/fs.zig b/std/event/fs.zig index 56eee387b..b20272dcb 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -83,6 +83,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o switch (builtin.os) { builtin.Os.macosx, builtin.Os.linux, + builtin.Os.freebsd, => { const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); defer loop.allocator.free(iovecs); @@ -219,6 +220,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: switch (builtin.os) { builtin.Os.macosx, builtin.Os.linux, + builtin.Os.freebsd, => { const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); defer loop.allocator.free(iovecs); @@ -399,7 +401,7 @@ pub async fn openPosix( pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle { switch (builtin.os) { - builtin.Os.macosx, builtin.Os.linux => { + builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => { const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC; return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable); }, @@ -427,6 +429,7 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os switch (builtin.os) { builtin.Os.macosx, builtin.Os.linux, + builtin.Os.freebsd, => { const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC; return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable); @@ -449,7 +452,7 @@ pub async fn openReadWrite( mode: os.File.Mode, ) os.File.OpenError!os.FileHandle { switch (builtin.os) { - builtin.Os.macosx, builtin.Os.linux => { + builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => { const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC; return await (async openPosix(loop, path, flags, mode) catch unreachable); }, @@ -477,7 +480,7 @@ pub const CloseOperation = struct.{ os_data: OsData, const OsData = switch (builtin.os) { - builtin.Os.linux, builtin.Os.macosx => OsDataPosix, + builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => OsDataPosix, builtin.Os.windows => struct.{ handle: ?os.FileHandle, @@ -496,7 +499,7 @@ pub const CloseOperation = struct.{ self.* = CloseOperation.{ .loop = loop, .os_data = switch (builtin.os) { - builtin.Os.linux, builtin.Os.macosx => initOsDataPosix(self), + builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => initOsDataPosix(self), builtin.Os.windows => OsData.{ .handle = null }, else => @compileError("Unsupported OS"), }, @@ -525,6 +528,7 @@ pub const CloseOperation = struct.{ switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { if (self.os_data.have_fd) { self.loop.posixFsRequest(&self.os_data.close_req_node); @@ -546,6 +550,7 @@ pub const CloseOperation = struct.{ switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { self.os_data.close_req_node.data.msg.Close.fd = handle; self.os_data.have_fd = true; @@ -562,6 +567,7 @@ pub const CloseOperation = struct.{ switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { self.os_data.have_fd = false; }, @@ -576,6 +582,7 @@ pub const CloseOperation = struct.{ switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { assert(self.os_data.have_fd); return self.os_data.close_req_node.data.msg.Close.fd; @@ -599,6 +606,7 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable), builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable), else => @compileError("Unsupported OS"), @@ -704,7 +712,7 @@ pub fn Watch(comptime V: type) type { os_data: OsData, const OsData = switch (builtin.os) { - builtin.Os.macosx => struct.{ + builtin.Os.macosx, builtin.Os.freebsd => struct.{ file_table: FileTable, table_lock: event.Lock, @@ -793,7 +801,7 @@ pub fn Watch(comptime V: type) type { return self; }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const self = try loop.allocator.createOne(Self); errdefer loop.allocator.destroy(self); @@ -813,7 +821,7 @@ pub fn Watch(comptime V: type) type { /// All addFile calls and removeFile calls must have completed. pub fn destroy(self: *Self) void { switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { // TODO we need to cancel the coroutines before destroying the lock self.os_data.table_lock.deinit(); var it = self.os_data.file_table.iterator(); @@ -855,14 +863,14 @@ pub fn Watch(comptime V: type) type { pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V { switch (builtin.os) { - builtin.Os.macosx => return await (async addFileMacosx(self, file_path, value) catch unreachable), + builtin.Os.macosx, builtin.Os.freebsd => return await (async addFileKEvent(self, file_path, value) catch unreachable), builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable), builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable), else => @compileError("Unsupported OS"), } } - async fn addFileMacosx(self: *Self, file_path: []const u8, value: V) !?V { + async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V { const resolved_path = try os.path.resolve(self.channel.loop.allocator, file_path); var resolved_path_consumed = false; defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path); @@ -871,7 +879,11 @@ pub fn Watch(comptime V: type) type { var close_op_consumed = false; defer if (!close_op_consumed) close_op.finish(); - const flags = posix.O_SYMLINK | posix.O_EVTONLY; + + const flags = switch (builtin.os) { + builtin.Os.macosx => posix.O_SYMLINK | posix.O_EVTONLY, + else => 0, + }; const mode = 0; const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable); close_op.setHandle(fd); diff --git a/std/event/loop.zig b/std/event/loop.zig index 73d1d8975..68c22f38b 100644 --- a/std/event/loop.zig +++ b/std/event/loop.zig @@ -48,7 +48,7 @@ pub const Loop = struct.{ }; pub const EventFd = switch (builtin.os) { - builtin.Os.macosx => MacOsEventFd, + builtin.Os.macosx, builtin.Os.freebsd => KEventFd, builtin.Os.linux => struct.{ base: ResumeNode, epoll_op: u32, @@ -61,13 +61,13 @@ pub const Loop = struct.{ else => @compileError("unsupported OS"), }; - const MacOsEventFd = struct.{ + const KEventFd = struct.{ base: ResumeNode, kevent: posix.Kevent, }; pub const Basic = switch (builtin.os) { - builtin.Os.macosx => MacOsBasic, + builtin.Os.macosx, builtin.Os.freebsd => KEventBasic, builtin.Os.linux => struct.{ base: ResumeNode, }, @@ -77,7 +77,7 @@ pub const Loop = struct.{ else => @compileError("unsupported OS"), }; - const MacOsBasic = struct.{ + const KEventBasic = struct.{ base: ResumeNode, kev: posix.Kevent, }; @@ -213,7 +213,7 @@ pub const Loop = struct.{ self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun); } }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { self.os_data.kqfd = try os.bsdKQueue(); errdefer os.close(self.os_data.kqfd); @@ -368,7 +368,7 @@ pub const Loop = struct.{ os.close(self.os_data.epollfd); self.allocator.free(self.eventfd_resume_nodes); }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { os.close(self.os_data.kqfd); os.close(self.os_data.fs_kqfd); }, @@ -483,7 +483,7 @@ pub const Loop = struct.{ const eventfd_node = &resume_stack_node.data; eventfd_node.base.handle = next_tick_node.data; switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent); const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch { @@ -545,6 +545,7 @@ pub const Loop = struct.{ switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => self.os_data.fs_thread.wait(), else => {}, } @@ -609,7 +610,7 @@ pub const Loop = struct.{ os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; return; }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { self.posixFsRequest(&self.os_data.fs_end_request); const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent); const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; @@ -667,7 +668,7 @@ pub const Loop = struct.{ } } }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { var eventlist: [1]posix.Kevent = undefined; const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable; @@ -730,7 +731,7 @@ pub const Loop = struct.{ self.beginOneEvent(); // finished in posixFsRun after processing the msg self.os_data.fs_queue.put(request_node); switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake); const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable; @@ -800,7 +801,7 @@ pub const Loop = struct.{ else => unreachable, } }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wait); var out_kevs: [1]posix.Kevent = undefined; _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable; @@ -812,7 +813,7 @@ pub const Loop = struct.{ const OsData = switch (builtin.os) { builtin.Os.linux => LinuxOsData, - builtin.Os.macosx => MacOsData, + builtin.Os.macosx, builtin.Os.freebsd => KEventData, builtin.Os.windows => struct.{ io_port: windows.HANDLE, extra_thread_count: usize, @@ -820,7 +821,7 @@ pub const Loop = struct.{ else => struct.{}, }; - const MacOsData = struct.{ + const KEventData = struct.{ kqfd: i32, final_kevent: posix.Kevent, fs_kevent_wake: posix.Kevent, diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 1df773b04..1793379fb 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -7,6 +7,10 @@ const arch = switch (builtin.arch) { pub use @import("syscall.zig"); pub use @import("errno.zig"); +const std = @import("../../index.zig"); +const c = std.c; +pub const Kevent = c.Kevent; + pub const PATH_MAX = 1024; pub const STDIN_FILENO = 0; @@ -293,6 +297,156 @@ pub const DT_LNK = 10; pub const DT_SOCK = 12; pub const DT_WHT = 14; +/// add event to kq (implies enable) +pub const EV_ADD = 0x0001; + +/// delete event from kq +pub const EV_DELETE = 0x0002; + +/// enable event +pub const EV_ENABLE = 0x0004; + +/// disable event (not reported) +pub const EV_DISABLE = 0x0008; + +/// only report one occurrence +pub const EV_ONESHOT = 0x0010; + +/// clear event state after reporting +pub const EV_CLEAR = 0x0020; + +/// force immediate event output +/// ... with or without EV_ERROR +/// ... use KEVENT_FLAG_ERROR_EVENTS +/// on syscalls supporting flags +pub const EV_RECEIPT = 0x0040; + +/// disable event after reporting +pub const EV_DISPATCH = 0x0080; + +pub const EVFILT_READ = -1; +pub const EVFILT_WRITE = -2; + +/// attached to aio requests +pub const EVFILT_AIO = -3; + +/// attached to vnodes +pub const EVFILT_VNODE = -4; + +/// attached to struct proc +pub const EVFILT_PROC = -5; + +/// attached to struct proc +pub const EVFILT_SIGNAL = -6; + +/// timers +pub const EVFILT_TIMER = -7; + +/// Process descriptors +pub const EVFILT_PROCDESC = -8; + +/// Filesystem events +pub const EVFILT_FS = -9; + +pub const EVFILT_LIO = -10; + +/// User events +pub const EVFILT_USER = -11; + +/// Sendfile events +pub const EVFILT_SENDFILE = -12; + +pub const EVFILT_EMPTY = -13; + +/// On input, NOTE_TRIGGER causes the event to be triggered for output. +pub const NOTE_TRIGGER = 0x01000000; + +/// ignore input fflags +pub const NOTE_FFNOP = 0x00000000; + +/// and fflags +pub const NOTE_FFAND = 0x40000000; + +/// or fflags +pub const NOTE_FFOR = 0x80000000; + +/// copy fflags +pub const NOTE_FFCOPY = 0xc0000000; + +/// mask for operations +pub const NOTE_FFCTRLMASK = 0xc0000000; +pub const NOTE_FFLAGSMASK = 0x00ffffff; + + +/// low water mark +pub const NOTE_LOWAT = 0x00000001; + +/// behave like poll() +pub const NOTE_FILE_POLL = 0x00000002; + +/// vnode was removed +pub const NOTE_DELETE = 0x00000001; + +/// data contents changed +pub const NOTE_WRITE = 0x00000002; + +/// size increased +pub const NOTE_EXTEND = 0x00000004; + +/// attributes changed +pub const NOTE_ATTRIB = 0x00000008; + +/// link count changed +pub const NOTE_LINK = 0x00000010; + +/// vnode was renamed +pub const NOTE_RENAME = 0x00000020; + +/// vnode access was revoked +pub const NOTE_REVOKE = 0x00000040; + +/// vnode was opened +pub const NOTE_OPEN = 0x00000080; + +/// file closed, fd did not allow write +pub const NOTE_CLOSE = 0x00000100; + +/// file closed, fd did allow write +pub const NOTE_CLOSE_WRITE = 0x00000200; + +/// file was read +pub const NOTE_READ = 0x00000400; + +/// process exited +pub const NOTE_EXIT = 0x80000000; + +/// process forked +pub const NOTE_FORK = 0x40000000; + +/// process exec'd +pub const NOTE_EXEC = 0x20000000; + +/// mask for signal & exit status +pub const NOTE_PDATAMASK = 0x000fffff; +pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK); + +/// data is seconds +pub const NOTE_SECONDS = 0x00000001; + +/// data is milliseconds +pub const NOTE_MSECONDS = 0x00000002; + +/// data is microseconds +pub const NOTE_USECONDS = 0x00000004; + +/// data is nanoseconds +pub const NOTE_NSECONDS = 0x00000008; + +/// timeout is absolute +pub const NOTE_ABSTIME = 0x00000010; + + + pub const TCGETS = 0x5401; pub const TCSETS = 0x5402; pub const TCSETSW = 0x5403; @@ -445,7 +599,11 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { } pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pread, usize(fd), @ptrToInt(buf), count, offset); + return arch.syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset); +} + +pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize { + return arch.syscall4(SYS_preadv, @intCast(usize, fd), @ptrToInt(iov), count, offset); } pub fn pipe(fd: *[2]i32) usize { @@ -464,6 +622,10 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { return arch.syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); } +pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize { + return arch.syscall4(SYS_pwritev, @intCast(usize, fd), @ptrToInt(iov), count, offset); +} + pub fn rename(old: [*]const u8, new: [*]const u8) usize { return arch.syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); } @@ -590,3 +752,51 @@ pub const timespec = arch.timespec; pub fn fstat(fd: i32, stat_buf: *Stat) usize { return arch.syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); } + +pub const iovec = extern struct.{ + iov_base: [*]u8, + iov_len: usize, +}; + +pub const iovec_const = extern struct.{ + iov_base: [*]const u8, + iov_len: usize, +}; + +pub fn kqueue() usize { + return errnoWrap(c.kqueue()); +} + +pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize { + return errnoWrap(c.kevent( + kq, + changelist.ptr, + @intCast(c_int, changelist.len), + eventlist.ptr, + @intCast(c_int, eventlist.len), + timeout, + )); +} + +pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize { + return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen)); +} + +pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize { + return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen)); +} + +pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize { + return errnoWrap(c.sysctlnametomib(name, wibp, sizep)); +} + + + +/// Takes the return value from a syscall and formats it back in the way +/// that the kernel represents it to libc. Errno was a mistake, let's make +/// it go away forever. +fn errnoWrap(value: isize) usize { + return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value); +} + + diff --git a/std/os/get_app_data_dir.zig b/std/os/get_app_data_dir.zig index 48826f5ae..513978fef 100644 --- a/std/os/get_app_data_dir.zig +++ b/std/os/get_app_data_dir.zig @@ -43,7 +43,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD }; return os.path.join(allocator, home_dir, "Library", "Application Support", appname); }, - builtin.Os.linux => { + builtin.Os.linux, builtin.Os.freebsd => { const home_dir = os.getEnvPosix("HOME") orelse { // TODO look in /etc/passwd return error.AppDataDirUnavailable; diff --git a/std/os/index.zig b/std/os/index.zig index 16bc571a8..36a7290d7 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -421,7 +421,7 @@ pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, off } } }, - builtin.Os.linux => while (true) { + builtin.Os.linux, builtin.Os.freebsd => while (true) { const rc = posix.pwritev(fd, iov, count, offset); const err = posix.getErrno(rc); switch (err) { @@ -689,7 +689,7 @@ pub fn getBaseAddress() usize { }; return phdr - @sizeOf(ElfHeader); }, - builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header), + builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header), builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), else => @compileError("Unsupported OS"), } @@ -1307,7 +1307,7 @@ pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void { const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path); return deleteDirW(&dir_path_w); }, - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const err = posix.getErrno(posix.rmdir(dir_path)); switch (err) { 0 => return, @@ -1350,7 +1350,7 @@ pub fn deleteDir(dir_path: []const u8) DeleteDirError!void { const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path); return deleteDirW(&dir_path_w); }, - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const dir_path_c = try toPosixPath(dir_path); return deleteDirC(&dir_path_c); }, @@ -1467,7 +1467,7 @@ pub const Dir = struct.{ allocator: *Allocator, pub const Handle = switch (builtin.os) { - Os.macosx, Os.ios => struct.{ + Os.macosx, Os.ios, Os.freebsd => struct.{ fd: i32, seek: i64, buf: []u8, @@ -1543,7 +1543,7 @@ pub const Dir = struct.{ .name_data = undefined, }; }, - Os.macosx, Os.ios => Handle.{ + Os.macosx, Os.ios, Os.freebsd => Handle.{ .fd = try posixOpen( dir_path, posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, @@ -1574,7 +1574,7 @@ pub const Dir = struct.{ Os.windows => { _ = windows.FindClose(self.handle.handle); }, - Os.macosx, Os.ios, Os.linux => { + Os.macosx, Os.ios, Os.linux, Os.freebsd => { self.allocator.free(self.handle.buf); os.close(self.handle.fd); }, @@ -1589,6 +1589,7 @@ pub const Dir = struct.{ Os.linux => return self.nextLinux(), Os.macosx, Os.ios => return self.nextDarwin(), Os.windows => return self.nextWindows(), + Os.freebsd => return self.nextFreebsd(), else => @compileError("unimplemented"), } } @@ -1728,6 +1729,11 @@ pub const Dir = struct.{ }; } } + + fn nextFreebsd(self: *Dir) !?Entry { + self.handle.buf = try self.allocator.alloc(u8, page_size); + return null; // TODO + } }; pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void { @@ -2166,7 +2172,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError { pub fn openSelfExe() !os.File { switch (builtin.os) { Os.linux => return os.File.openReadC(c"/proc/self/exe"), - Os.macosx, Os.ios => { + Os.macosx, Os.ios, Os.freebsd => { var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; @@ -2183,7 +2189,7 @@ pub fn openSelfExe() !os.File { test "openSelfExe" { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(), + Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(), else => return error.SkipZigTest, // Unsupported OS. } } @@ -2214,6 +2220,7 @@ pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 { pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 { switch (builtin.os) { Os.linux => return readLink(out_buffer, "/proc/self/exe"), + Os.freebsd => return readLink(out_buffer, "/proc/curproc/file"), Os.windows => { var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined; const utf16le_slice = try selfExePathW(&utf16le_buf); @@ -2252,7 +2259,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 { // will not return null. return path.dirname(full_exe_path).?; }, - Os.windows, Os.macosx, Os.ios => { + Os.windows, Os.macosx, Os.ios, Os.freebsd => { const self_exe_path = try selfExePath(out_buffer); // Assume that the OS APIs return absolute paths, and therefore dirname // will not return null. @@ -3085,10 +3092,13 @@ pub const CpuCountError = error.{ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize { switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { var count: c_int = undefined; var count_len: usize = @sizeOf(c_int); - const rc = posix.sysctlbyname(c"hw.logicalcpu", @ptrCast(*c_void, &count), &count_len, null, 0); + const rc = posix.sysctlbyname(switch (builtin.os) { + builtin.Os.macosx => c"hw.logicalcpu", + else => c"hw.ncpu", + }, @ptrCast(*c_void, &count), &count_len, null, 0); const err = posix.getErrno(rc); switch (err) { 0 => return @intCast(usize, count), From 6a8fb060067685a2ff27d05092f3fcf2ee17e83c Mon Sep 17 00:00:00 2001 From: Greg V Date: Wed, 17 Oct 2018 18:00:36 +0300 Subject: [PATCH 014/110] Split at zero byte in SplitIterator To avoid extra zeros in buffers --- src/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.cpp b/src/util.cpp index 192d74e76..f7bda86c4 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -47,7 +47,7 @@ bool ptr_eq(const void *a, const void *b) { // Ported from std/mem.zig. bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { for (size_t i = 0; i < self->split_bytes.len; i += 1) { - if (byte == self->split_bytes.ptr[i]) { + if (byte == self->split_bytes.ptr[i] || byte == 0) { return true; } } From f3bc1c38bfb35cd588048f248c69100eaf709a4f Mon Sep 17 00:00:00 2001 From: Greg V Date: Sat, 20 Oct 2018 15:15:15 +0300 Subject: [PATCH 015/110] Specify 16-byte stack alignment in _start on FreeBSD --- std/special/bootstrap.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 1fc80f243..070a26bf7 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -57,6 +57,9 @@ extern fn WinMainCRTStartup() noreturn { // TODO https://github.com/ziglang/zig/issues/265 fn posixCallMainAndExit() noreturn { + if (builtin.os == builtin.Os.freebsd) { + @setAlignStack(16); + } const argc = argc_ptr[0]; const argv = @ptrCast([*][*]u8, argc_ptr + 1); From f1fd8d2b1fdfc32980883a3e5d254fd1f1bd06a6 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sat, 17 Nov 2018 14:36:36 +0100 Subject: [PATCH 016/110] Updated docs to newest grammar --- doc/langref.html.in | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index a29b9be4c..c3d8af442 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7830,11 +7830,11 @@ TypeExpr <- PrefixTypeOp* ErrorUnionExpr ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? SuffixExpr - <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArgumnets - / PrimaryTypeExpr (SuffixOp / FnCallArgumnets)* + <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments + / PrimaryTypeExpr (SuffixOp / FnCallArguments)* PrimaryTypeExpr - <- BUILTININDENTIFIER FnCallArgumnets + <- BUILTINIDENTIFIER FnCallArguments / CHAR_LITERAL / ContainerDecl / ErrorSetDecl @@ -7884,11 +7884,11 @@ AsmOutput <- COLON AsmOutputList AsmInput? AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN -AsmInput <- COLON AsmInputList AsmCloppers? +AsmInput <- COLON AsmInputList AsmClobbers? AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN -AsmCloppers <- COLON StringList +AsmClobbers <- COLON StringList # *** Helper grammar *** BreakLabel <- COLON IDENTIFIER @@ -8013,7 +8013,7 @@ SuffixOp AsyncPrefix <- KEYWORD_async (LARROW PrefixExpr RARROW)? -FnCallArgumnets <- LPAREN ExprList RPAREN +FnCallArguments <- LPAREN ExprList RPAREN # Ptr specific ArrayTypeStart <- LBRACKET Expr? RBRACKET @@ -8090,7 +8090,7 @@ STRINGLITERAL IDENTIFIER <- !keyword ("c" !["\\] / [A-Zabd-z_]) [A-Za-z0-9_]* skip / "@\"" string_char* "\"" skip -BUILTININDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* skip +BUILTINIDENTIFIER <- "@"[A-Za-z_][A-Za-z0-9_]* skip AMPERSAND <- '&' ![=] skip @@ -8109,9 +8109,9 @@ DOT2 <- '..' ![.] skip DOT3 <- '...' skip DOTASTERISK <- '.*' skip DOTQUESTIONMARK <- '.?' skip -EQUAL <- '=' ![>=] skip +EQUAL <- '=' ![>=] skip EQUALEQUAL <- '==' skip -EQUALRARROW <- '=>' skip +EQUALRARROW <- '=>' skip EXCLAMATIONMARK <- '!' ![=] skip EXCLAMATIONMARKEQUAL <- '!=' skip LARROW <- '<' ![<=] skip @@ -8121,11 +8121,11 @@ LARROWEQUAL <- '<=' skip LBRACE <- '{' skip LBRACKET <- '[' skip LPAREN <- '(' skip -MINUS <- '-' ![%=>] skip +MINUS <- '-' ![%=>] skip MINUSEQUAL <- '-=' skip MINUSPERCENT <- '-%' ![=] skip MINUSPERCENTEQUAL <- '-%=' skip -MINUSRARROW <- '->' skip +MINUSRARROW <- '->' skip PERCENT <- '%' ![=] skip PERCENTEQUAL <- '%=' skip PIPE <- '|' ![|=] skip @@ -8137,10 +8137,10 @@ PLUSEQUAL <- '+=' skip PLUSPERCENT <- '+%' ![=] skip PLUSPERCENTEQUAL <- '+%=' skip QUESTIONMARK <- '?' skip -RARROW <- '>' ![>=] skip -RARROW2 <- '>>' ![=] skip -RARROW2EQUAL <- '>>=' skip -RARROWEQUAL <- '>=' skip +RARROW <- '>' ![>=] skip +RARROW2 <- '>>' ![=] skip +RARROW2EQUAL <- '>>=' skip +RARROWEQUAL <- '>=' skip RBRACE <- '}' skip RBRACKET <- ']' skip RPAREN <- ')' skip From 2a580278c4db3a60766bb904f42486f0f1872c72 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sat, 17 Nov 2018 14:42:47 +0100 Subject: [PATCH 017/110] Updated comments in parser.cpp --- src/parser.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index b5c67875d..077365995 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -91,7 +91,7 @@ static Token *ast_parse_break_label(ParseContext *pc); static Token *ast_parse_block_label(ParseContext *pc); static AstNode *ast_parse_field_init(ParseContext *pc); static AstNode *ast_parse_while_continue_expr(ParseContext *pc); -static AstNode *ast_parse_section(ParseContext *pc); +static AstNode *ast_parse_link_section(ParseContext *pc); static Optional ast_parse_fn_cc(ParseContext *pc); static AstNode *ast_parse_param_decl(ParseContext *pc); static AstNode *ast_parse_param_type(ParseContext *pc); @@ -775,7 +775,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) { return nullptr; } -// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? Section? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) +// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) static AstNode *ast_parse_fn_proto(ParseContext *pc) { Token *first = peek_token(pc); AstNodeFnProto fn_cc; @@ -806,7 +806,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { expect_token(pc, TokenIdRParen); AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *section_expr = ast_parse_section(pc); + AstNode *section_expr = ast_parse_link_section(pc); Token *var = eat_token_if(pc, TokenIdKeywordVar); Token *exmark = nullptr; AstNode *return_type = nullptr; @@ -842,7 +842,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { return res; } -// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? Section? (EQUAL Expr)? SEMICOLON +// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON static AstNode *ast_parse_var_decl(ParseContext *pc) { Token *first = eat_token_if(pc, TokenIdKeywordConst); if (first == nullptr) @@ -856,7 +856,7 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { type_expr = ast_expect(pc, ast_parse_type_expr); AstNode *align_expr = ast_parse_byte_align(pc); - AstNode *section_expr = ast_parse_section(pc); + AstNode *section_expr = ast_parse_link_section(pc); AstNode *expr = nullptr; if (eat_token_if(pc, TokenIdEq) != nullptr) expr = ast_expect(pc, ast_parse_expr); @@ -1490,8 +1490,8 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) { } // SuffixExpr -// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArgumnets -// / PrimaryTypeExpr (SuffixOp / FnCallArgumnets)* +// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments +// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* static AstNode *ast_parse_suffix_expr(ParseContext *pc) { AstNode *async_call = ast_parse_async_prefix(pc); if (async_call != nullptr) { @@ -1599,7 +1599,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { } // PrimaryTypeExpr -// <- BUILTININDENTIFIER FnCallArgumnets +// <- BUILTINIDENTIFIER FnCallArguments // / CHAR_LITERAL // / ContainerDecl // / ErrorSetDecl @@ -1978,7 +1978,7 @@ static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { return res; } -// AsmInput <- COLON AsmInputList AsmCloppers? +// AsmInput <- COLON AsmInputList AsmClobbers? static AstNode *ast_parse_asm_input(ParseContext *pc) { if (eat_token_if(pc, TokenIdColon) == nullptr) return nullptr; @@ -2011,7 +2011,7 @@ static AsmInput *ast_parse_asm_input_item(ParseContext *pc) { return res; } -// AsmCloppers <- COLON StringList +// AsmClobbers <- COLON StringList static AstNode *ast_parse_asm_cloppers(ParseContext *pc) { if (eat_token_if(pc, TokenIdColon) == nullptr) return nullptr; @@ -2080,8 +2080,8 @@ static AstNode *ast_parse_while_continue_expr(ParseContext *pc) { return expr; } -// Section <- KEYWORD_section LPAREN Expr RPAREN -static AstNode *ast_parse_section(ParseContext *pc) { +// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN +static AstNode *ast_parse_link_section(ParseContext *pc) { Token *first = eat_token_if(pc, TokenIdKeywordLinkSection); if (first == nullptr) return nullptr; @@ -2742,7 +2742,7 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) { return res; } -// FnCallArgumnets <- LPAREN ExprList RPAREN +// FnCallArguments <- LPAREN ExprList RPAREN static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) { Token *paren = eat_token_if(pc, TokenIdLParen); if (paren == nullptr) From 085d049a088af20c1eeeab2b8ebeb7dc6af7b07d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 17 Nov 2018 11:19:46 -0500 Subject: [PATCH 018/110] aarch64 improvements * support C ABI for all return types * don't include __aeabi_uldivmod & co on aarch64 since it's 64 bit --- src/analyze.cpp | 2 +- src/target.cpp | 61 +++++++++++++ src/target.hpp | 2 + std/special/compiler_rt/index.zig | 143 +++++++++++++++++------------- 4 files changed, 144 insertions(+), 64 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index bc9789fca..349169f9d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1059,7 +1059,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { } zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481", buf_ptr(&fn_type_id->return_type->name)); - } else if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb) { + } else if (target_is_arm(&g->zig_target)) { return type_size(g, fn_type_id->return_type) > 16; } zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481"); diff --git a/src/target.cpp b/src/target.cpp index 8372e9ce9..7075c8a5c 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -1011,3 +1011,64 @@ const char *arch_stack_pointer_register_name(const ArchType *arch) { } zig_unreachable(); } + +bool target_is_arm(const ZigTarget *target) { + switch (target->arch.arch) { + case ZigLLVM_UnknownArch: + zig_unreachable(); + case ZigLLVM_aarch64: + case ZigLLVM_arm: + case ZigLLVM_thumb: + case ZigLLVM_aarch64_be: + case ZigLLVM_armeb: + case ZigLLVM_thumbeb: + return true; + + case ZigLLVM_x86: + case ZigLLVM_x86_64: + case ZigLLVM_amdgcn: + case ZigLLVM_amdil: + case ZigLLVM_amdil64: + case ZigLLVM_arc: + case ZigLLVM_avr: + case ZigLLVM_bpfeb: + case ZigLLVM_bpfel: + case ZigLLVM_hexagon: + case ZigLLVM_lanai: + case ZigLLVM_hsail: + case ZigLLVM_hsail64: + case ZigLLVM_kalimba: + case ZigLLVM_le32: + case ZigLLVM_le64: + case ZigLLVM_mips: + case ZigLLVM_mips64: + case ZigLLVM_mips64el: + case ZigLLVM_mipsel: + case ZigLLVM_msp430: + case ZigLLVM_nios2: + case ZigLLVM_nvptx: + case ZigLLVM_nvptx64: + case ZigLLVM_ppc64le: + case ZigLLVM_r600: + case ZigLLVM_renderscript32: + case ZigLLVM_renderscript64: + case ZigLLVM_riscv32: + case ZigLLVM_riscv64: + case ZigLLVM_shave: + case ZigLLVM_sparc: + case ZigLLVM_sparcel: + case ZigLLVM_sparcv9: + case ZigLLVM_spir: + case ZigLLVM_spir64: + case ZigLLVM_systemz: + case ZigLLVM_tce: + case ZigLLVM_tcele: + case ZigLLVM_wasm32: + case ZigLLVM_wasm64: + case ZigLLVM_xcore: + case ZigLLVM_ppc: + case ZigLLVM_ppc64: + return false; + } + zig_unreachable(); +} diff --git a/src/target.hpp b/src/target.hpp index a4685fc09..04652179d 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -121,4 +121,6 @@ Buf *target_dynamic_linker(ZigTarget *target); bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target); ZigLLVM_OSType get_llvm_os_type(Os os_type); +bool target_is_arm(const ZigTarget *target); + #endif diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index c826af83b..b2add4e3f 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -59,7 +59,7 @@ comptime { @export("__umoddi3", __umoddi3, linkage); @export("__udivmodsi4", __udivmodsi4, linkage); - if (isArmArch()) { + if (is_arm_arch and !is_arm_64) { @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage); @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); @export("__aeabi_uidiv", __udivsi3, linkage); @@ -149,68 +149,85 @@ extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult return result; } -fn isArmArch() bool { - return switch (builtin.arch) { - builtin.Arch.armv8_3a, - builtin.Arch.armv8_2a, - builtin.Arch.armv8_1a, - builtin.Arch.armv8, - builtin.Arch.armv8r, - builtin.Arch.armv8m_baseline, - builtin.Arch.armv8m_mainline, - builtin.Arch.armv7, - builtin.Arch.armv7em, - builtin.Arch.armv7m, - builtin.Arch.armv7s, - builtin.Arch.armv7k, - builtin.Arch.armv7ve, - builtin.Arch.armv6, - builtin.Arch.armv6m, - builtin.Arch.armv6k, - builtin.Arch.armv6t2, - builtin.Arch.armv5, - builtin.Arch.armv5te, - builtin.Arch.armv4t, - builtin.Arch.armebv8_3a, - builtin.Arch.armebv8_2a, - builtin.Arch.armebv8_1a, - builtin.Arch.armebv8, - builtin.Arch.armebv8r, - builtin.Arch.armebv8m_baseline, - builtin.Arch.armebv8m_mainline, - builtin.Arch.armebv7, - builtin.Arch.armebv7em, - builtin.Arch.armebv7m, - builtin.Arch.armebv7s, - builtin.Arch.armebv7k, - builtin.Arch.armebv7ve, - builtin.Arch.armebv6, - builtin.Arch.armebv6m, - builtin.Arch.armebv6k, - builtin.Arch.armebv6t2, - builtin.Arch.armebv5, - builtin.Arch.armebv5te, - builtin.Arch.armebv4t, - builtin.Arch.aarch64v8_3a, - builtin.Arch.aarch64v8_2a, - builtin.Arch.aarch64v8_1a, - builtin.Arch.aarch64v8, - builtin.Arch.aarch64v8r, - builtin.Arch.aarch64v8m_baseline, - builtin.Arch.aarch64v8m_mainline, - builtin.Arch.aarch64_bev8_3a, - builtin.Arch.aarch64_bev8_2a, - builtin.Arch.aarch64_bev8_1a, - builtin.Arch.aarch64_bev8, - builtin.Arch.aarch64_bev8r, - builtin.Arch.aarch64_bev8m_baseline, - builtin.Arch.aarch64_bev8m_mainline, - builtin.Arch.thumb, - builtin.Arch.thumbeb, - => true, - else => false, - }; -} +const is_arm_64 = switch (builtin.arch) { + builtin.Arch.aarch64v8_3a, + builtin.Arch.aarch64v8_2a, + builtin.Arch.aarch64v8_1a, + builtin.Arch.aarch64v8, + builtin.Arch.aarch64v8r, + builtin.Arch.aarch64v8m_baseline, + builtin.Arch.aarch64v8m_mainline, + builtin.Arch.aarch64_bev8_3a, + builtin.Arch.aarch64_bev8_2a, + builtin.Arch.aarch64_bev8_1a, + builtin.Arch.aarch64_bev8, + builtin.Arch.aarch64_bev8r, + builtin.Arch.aarch64_bev8m_baseline, + builtin.Arch.aarch64_bev8m_mainline, + => true, + else => false, +}; + +const is_arm_arch = switch (builtin.arch) { + builtin.Arch.armv8_3a, + builtin.Arch.armv8_2a, + builtin.Arch.armv8_1a, + builtin.Arch.armv8, + builtin.Arch.armv8r, + builtin.Arch.armv8m_baseline, + builtin.Arch.armv8m_mainline, + builtin.Arch.armv7, + builtin.Arch.armv7em, + builtin.Arch.armv7m, + builtin.Arch.armv7s, + builtin.Arch.armv7k, + builtin.Arch.armv7ve, + builtin.Arch.armv6, + builtin.Arch.armv6m, + builtin.Arch.armv6k, + builtin.Arch.armv6t2, + builtin.Arch.armv5, + builtin.Arch.armv5te, + builtin.Arch.armv4t, + builtin.Arch.armebv8_3a, + builtin.Arch.armebv8_2a, + builtin.Arch.armebv8_1a, + builtin.Arch.armebv8, + builtin.Arch.armebv8r, + builtin.Arch.armebv8m_baseline, + builtin.Arch.armebv8m_mainline, + builtin.Arch.armebv7, + builtin.Arch.armebv7em, + builtin.Arch.armebv7m, + builtin.Arch.armebv7s, + builtin.Arch.armebv7k, + builtin.Arch.armebv7ve, + builtin.Arch.armebv6, + builtin.Arch.armebv6m, + builtin.Arch.armebv6k, + builtin.Arch.armebv6t2, + builtin.Arch.armebv5, + builtin.Arch.armebv5te, + builtin.Arch.armebv4t, + builtin.Arch.aarch64v8_3a, + builtin.Arch.aarch64v8_2a, + builtin.Arch.aarch64v8_1a, + builtin.Arch.aarch64v8, + builtin.Arch.aarch64v8r, + builtin.Arch.aarch64v8m_baseline, + builtin.Arch.aarch64v8m_mainline, + builtin.Arch.aarch64_bev8_3a, + builtin.Arch.aarch64_bev8_2a, + builtin.Arch.aarch64_bev8_1a, + builtin.Arch.aarch64_bev8, + builtin.Arch.aarch64_bev8r, + builtin.Arch.aarch64_bev8m_baseline, + builtin.Arch.aarch64_bev8m_mainline, + builtin.Arch.thumb, + builtin.Arch.thumbeb, + => true, + else => false, +}; nakedcc fn __aeabi_uidivmod() void { @setRuntimeSafety(false); From 947cdafd917f30cfd3d28b85e16a6ca980162dc9 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Sun, 18 Nov 2018 15:15:17 +0900 Subject: [PATCH 019/110] src/os.cpp: os_file_read: return ErrorIsDir on case EISDIR; --- src/os.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.cpp b/src/os.cpp index 5d43e73d8..9d16d763e 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1976,7 +1976,7 @@ Error os_file_read(OsFile file, void *ptr, size_t *len) { case EFAULT: zig_unreachable(); case EISDIR: - zig_unreachable(); + return ErrorIsDir; default: return ErrorFileSystem; } From e9b47d960b81dfc1fd70c5ae663b4b692ab0b19d Mon Sep 17 00:00:00 2001 From: Duncan Date: Sun, 18 Nov 2018 11:14:05 +1300 Subject: [PATCH 020/110] Fix setsockopt syscall on linux --- std/os/linux/index.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig index c401eb3dc..bfa046ba0 100644 --- a/std/os/linux/index.zig +++ b/std/os/linux/index.zig @@ -1201,7 +1201,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { } pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { - return syscall5(SYS_setsockopt, @intCast(usize, fd), level, optname, @intCast(usize, optval), @ptrToInt(optlen)); + return syscall5(SYS_setsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); } pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { From 8d54cbb834ab606ecfe23c6514cbac699319f60c Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sun, 18 Nov 2018 10:14:37 -0800 Subject: [PATCH 021/110] Fix pushToParent to work for arrays of Objects The reference `*array` is a copy of the value on the stack. Instead use a reference to top of stack. This is the same technique used above for `var object` in `Value.String`. Added two simple tests. --- std/json.zig | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/std/json.zig b/std/json.zig index 23573b6d7..9eb3a0ea7 100644 --- a/std/json.zig +++ b/std/json.zig @@ -1323,7 +1323,8 @@ pub const Parser = struct { p.state = State.ObjectKey; }, // Array Parent -> [ ..., , value ] - Value.Array => |*array| { + Value.Array => { + var array = &p.stack.items[p.stack.len - 1].Array; try array.append(value); p.state = State.ArrayValue; }, @@ -1364,7 +1365,8 @@ test "json parser dynamic" { \\ "Width": 100 \\ }, \\ "Animated" : false, - \\ "IDs": [116, 943, 234, 38793] + \\ "IDs": [116, 943, 234, 38793], + \\ "ArrayOfObject": [{"n": "m"}] \\ } \\} ; @@ -1387,4 +1389,10 @@ test "json parser dynamic" { const animated = image.Object.get("Animated").?.value; debug.assert(animated.Bool == false); + + const array_of_object = image.Object.get("ArrayOfObject").?.value; + debug.assert(array_of_object.Array.len == 1); + + const obj0 = array_of_object.Array.at(0).Object.get("n").?.value; + debug.assert(mem.eql(u8, obj0.String, "m")); } From f8a782fb2ec63b89fadb409f7378066a26945d3b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 18 Nov 2018 19:36:27 -0500 Subject: [PATCH 022/110] all numbers with comptime known values implicitly cast to all number types. If the value does not fit, a compile error is emitted. closes #422 closes #1712 --- doc/langref.html.in | 4 +- src/ir.cpp | 406 +++++++++++++++++++++++++++------------- test/cases/cast.zig | 10 + test/compile_errors.zig | 87 ++++++--- 4 files changed, 346 insertions(+), 161 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index c3d8af442..022b03ef4 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6659,7 +6659,7 @@ fn foo(x: []const u8) u8 { {#header_close#} {#header_open|Cast Negative Number to Unsigned Integer#}

At compile-time:

- {#code_begin|test_err|attempt to cast negative value to unsigned integer#} + {#code_begin|test_err|cannot cast negative value -1 to unsigned integer type 'u32'#} comptime { const value: i32 = -1; const unsigned = @intCast(u32, value); @@ -6681,7 +6681,7 @@ pub fn main() void { {#header_close#} {#header_open|Cast Truncates Data#}

At compile-time:

- {#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#} + {#code_begin|test_err|integer value 300 cannot be implicitly casted to type 'u8'#} comptime { const spartan_count: u16 = 300; const byte = @intCast(u8, spartan_count); diff --git a/src/ir.cpp b/src/ir.cpp index 2c499e885..3a22d0aa1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -138,6 +138,11 @@ struct ConstCastErrSetMismatch { ZigList missing_errors; }; +enum UndefAllowed { + UndefOk, + UndefBad, +}; + static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval); static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); @@ -157,6 +162,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, ZigType *dest_type, IrInstruction *dest_type_src); +static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -8063,15 +8069,153 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc return false; } - ConstExprValue *const_val = &instruction->value; - assert(const_val->special != ConstValSpecialRuntime); + ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad); + assert(const_val != nullptr); + + bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); + bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); - bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || - const_val->type->id == ZigTypeIdComptimeInt); - bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || - const_val->type->id == ZigTypeIdComptimeFloat); if (other_type->id == ZigTypeIdFloat) { - return true; + if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) { + return true; + } + if (const_val->type->id == ZigTypeIdInt) { + BigFloat tmp_bf; + bigfloat_init_bigint(&tmp_bf, &const_val->data.x_bigint); + BigFloat orig_bf; + switch (other_type->data.floating.bit_count) { + case 16: { + float16_t tmp = bigfloat_to_f16(&tmp_bf); + bigfloat_init_16(&orig_bf, tmp); + break; + } + case 32: { + float tmp = bigfloat_to_f32(&tmp_bf); + bigfloat_init_32(&orig_bf, tmp); + break; + } + case 64: { + double tmp = bigfloat_to_f64(&tmp_bf); + bigfloat_init_64(&orig_bf, tmp); + break; + } + case 80: + zig_panic("TODO"); + case 128: { + float128_t tmp = bigfloat_to_f128(&tmp_bf); + bigfloat_init_128(&orig_bf, tmp); + break; + } + default: + zig_unreachable(); + } + BigInt orig_bi; + bigint_init_bigfloat(&orig_bi, &orig_bf); + if (bigint_cmp(&orig_bi, &const_val->data.x_bigint) == CmpEQ) { + return true; + } + Buf *val_buf = buf_alloc(); + bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); + ir_add_error(ira, instruction, + buf_sprintf("integer value %s has no representation in type '%s'", + buf_ptr(val_buf), + buf_ptr(&other_type->name))); + return false; + } + if (other_type->data.floating.bit_count >= const_val->type->data.floating.bit_count) { + return true; + } + switch (other_type->data.floating.bit_count) { + case 16: + switch (const_val->type->data.floating.bit_count) { + case 32: { + float16_t tmp = zig_double_to_f16(const_val->data.x_f32); + float orig = zig_f16_to_double(tmp); + if (const_val->data.x_f32 == orig) { + return true; + } + break; + } + case 64: { + float16_t tmp = zig_double_to_f16(const_val->data.x_f64); + double orig = zig_f16_to_double(tmp); + if (const_val->data.x_f64 == orig) { + return true; + } + break; + } + case 80: + zig_panic("TODO"); + case 128: { + float16_t tmp = f128M_to_f16(&const_val->data.x_f128); + float128_t orig; + f16_to_f128M(tmp, &orig); + if (f128M_eq(&orig, &const_val->data.x_f128)) { + return true; + } + break; + } + default: + zig_unreachable(); + } + break; + case 32: + switch (const_val->type->data.floating.bit_count) { + case 64: { + float tmp = const_val->data.x_f64; + double orig = tmp; + if (const_val->data.x_f64 == orig) { + return true; + } + break; + } + case 80: + zig_panic("TODO"); + case 128: { + float32_t tmp = f128M_to_f32(&const_val->data.x_f128); + float128_t orig; + f32_to_f128M(tmp, &orig); + if (f128M_eq(&orig, &const_val->data.x_f128)) { + return true; + } + break; + } + default: + zig_unreachable(); + } + break; + case 64: + switch (const_val->type->data.floating.bit_count) { + case 80: + zig_panic("TODO"); + case 128: { + float64_t tmp = f128M_to_f64(&const_val->data.x_f128); + float128_t orig; + f64_to_f128M(tmp, &orig); + if (f128M_eq(&orig, &const_val->data.x_f128)) { + return true; + } + break; + } + default: + zig_unreachable(); + } + break; + case 80: + assert(const_val->type->data.floating.bit_count == 128); + zig_panic("TODO"); + case 128: + return true; + default: + zig_unreachable(); + } + Buf *val_buf = buf_alloc(); + float_append_buf(val_buf, const_val); + ir_add_error(ira, instruction, + buf_sprintf("cast of value %s to type '%s' loses information", + buf_ptr(val_buf), + buf_ptr(&other_type->name))); + return false; } else if (other_type->id == ZigTypeIdInt && const_val_is_int) { if (!other_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) { Buf *val_buf = buf_alloc(); @@ -9453,11 +9597,6 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio return const_instr; } -enum UndefAllowed { - UndefOk, - UndefBad, -}; - static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) { switch (value->value.special) { case ConstValSpecialStatic: @@ -10370,6 +10509,121 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); } + // cast from T to ?T + // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism + if (wanted_type->id == ZigTypeIdOptional) { + ZigType *wanted_child_type = wanted_type->data.maybe.child_type; + if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, + false).id == ConstCastResultIdOk) + { + return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); + } else if (actual_type->id == ZigTypeIdComptimeInt || + actual_type->id == ZigTypeIdComptimeFloat) + { + if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { + return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); + } else { + return ira->codegen->invalid_instruction; + } + } else if ( + wanted_child_type->id == ZigTypeIdPointer && + wanted_child_type->data.pointer.ptr_len == PtrLenUnknown && + actual_type->id == ZigTypeIdPointer && + actual_type->data.pointer.ptr_len == PtrLenSingle && + actual_type->data.pointer.child_type->id == ZigTypeIdArray) + { + if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) && + types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node, + !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, + wanted_child_type); + if (type_is_invalid(cast1->value.type)) + return ira->codegen->invalid_instruction; + return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type); + } + } + } + + // T to E!T + if (wanted_type->id == ZigTypeIdErrorUnion) { + if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, + source_node, false).id == ConstCastResultIdOk) + { + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); + } else if (actual_type->id == ZigTypeIdComptimeInt || + actual_type->id == ZigTypeIdComptimeFloat) + { + if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); + } else { + return ira->codegen->invalid_instruction; + } + } + } + + // cast from T to E!?T + if (wanted_type->id == ZigTypeIdErrorUnion && + wanted_type->data.error_union.payload_type->id == ZigTypeIdOptional && + actual_type->id != ZigTypeIdOptional) + { + ZigType *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; + if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk || + actual_type->id == ZigTypeIdNull || + actual_type->id == ZigTypeIdComptimeInt || + actual_type->id == ZigTypeIdComptimeFloat) + { + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); + if (type_is_invalid(cast1->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + if (type_is_invalid(cast2->value.type)) + return ira->codegen->invalid_instruction; + + return cast2; + } + } + + + // cast from comptime-known number to another number type + if (instr_is_comptime(value) && + (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt || + actual_type->id == ZigTypeIdFloat || actual_type->id == ZigTypeIdComptimeFloat) && + (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || + wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat)) + { + if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { + if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { + IrInstruction *result = ir_const(ira, source_instr, wanted_type); + if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { + bigint_init_bigint(&result->value.data.x_bigint, &value->value.data.x_bigint); + } else { + float_init_bigint(&result->value.data.x_bigint, &value->value); + } + return result; + } else if (wanted_type->id == ZigTypeIdComptimeFloat || wanted_type->id == ZigTypeIdFloat) { + IrInstruction *result = ir_const(ira, source_instr, wanted_type); + if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { + BigFloat bf; + bigfloat_init_bigint(&bf, &value->value.data.x_bigint); + float_init_bigfloat(&result->value, &bf); + } else { + float_init_float(&result->value, &value->value); + } + return result; + } + zig_unreachable(); + } else { + return ira->codegen->invalid_instruction; + } + } + // widening conversion if (wanted_type->id == ZigTypeIdInt && actual_type->id == ZigTypeIdInt && @@ -10472,47 +10726,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } - // cast from T to ?T - // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism - if (wanted_type->id == ZigTypeIdOptional) { - ZigType *wanted_child_type = wanted_type->data.maybe.child_type; - if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, - false).id == ConstCastResultIdOk) - { - return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); - } else if (actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { - return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); - } else { - return ira->codegen->invalid_instruction; - } - } else if ( - wanted_child_type->id == ZigTypeIdPointer && - wanted_child_type->data.pointer.ptr_len == PtrLenUnknown && - actual_type->id == ZigTypeIdPointer && - actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) - { - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) && - types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk) - { - IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, - wanted_child_type); - if (type_is_invalid(cast1->value.type)) - return ira->codegen->invalid_instruction; - return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type); - } - } - } - // cast from null literal to maybe type if (wanted_type->id == ZigTypeIdOptional && actual_type->id == ZigTypeIdNull) @@ -10520,23 +10733,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type); } - // cast from child type of error type to error type - if (wanted_type->id == ZigTypeIdErrorUnion) { - if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, - source_node, false).id == ConstCastResultIdOk) - { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); - } else if (actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); - } else { - return ira->codegen->invalid_instruction; - } - } - } - // cast from [N]T to E![]const T if (wanted_type->id == ZigTypeIdErrorUnion && is_slice(wanted_type->data.error_union.payload_type) && @@ -10568,54 +10764,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); } - // cast from T to E!?T - if (wanted_type->id == ZigTypeIdErrorUnion && - wanted_type->data.error_union.payload_type->id == ZigTypeIdOptional && - actual_type->id != ZigTypeIdOptional) - { - ZigType *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; - if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk || - actual_type->id == ZigTypeIdNull || - actual_type->id == ZigTypeIdComptimeInt || - actual_type->id == ZigTypeIdComptimeFloat) - { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); - if (type_is_invalid(cast1->value.type)) - return ira->codegen->invalid_instruction; - - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); - if (type_is_invalid(cast2->value.type)) - return ira->codegen->invalid_instruction; - - return cast2; - } - } - - // cast from number literal to another type - if (actual_type->id == ZigTypeIdComptimeFloat || - actual_type->id == ZigTypeIdComptimeInt) - { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { - CastOp op; - if ((actual_type->id == ZigTypeIdComptimeFloat && - wanted_type->id == ZigTypeIdFloat) || - (actual_type->id == ZigTypeIdComptimeInt && - wanted_type->id == ZigTypeIdInt)) - { - op = CastOpNumLitToConcrete; - } else if (wanted_type->id == ZigTypeIdInt) { - op = CastOpFloatToInt; - } else if (wanted_type->id == ZigTypeIdFloat) { - op = CastOpIntToFloat; - } else { - zig_unreachable(); - } - return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false); - } else { - return ira->codegen->invalid_instruction; - } - } - // cast from typed number to integer or float literal. // works when the number is known at compile time if (instr_is_comptime(value) && @@ -17878,7 +18026,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdInt) { + if (dest_type->id != ZigTypeIdInt && dest_type->id != ZigTypeIdComptimeInt) { ir_add_error(ira, instruction->dest_type, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -17887,20 +18035,22 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; - if (target->value.type->id == ZigTypeIdComptimeInt) { - if (ir_num_lit_fits_in_other_type(ira, target, dest_type, true)) { - return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpNumLitToConcrete, false); - } else { - return ira->codegen->invalid_instruction; - } - } - - if (target->value.type->id != ZigTypeIdInt) { + if (target->value.type->id != ZigTypeIdInt && target->value.type->id != ZigTypeIdComptimeInt) { ir_add_error(ira, instruction->target, buf_sprintf("expected integer type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } + if (instr_is_comptime(target)) { + return ir_implicit_cast(ira, target, dest_type); + } + + if (dest_type->id == ZigTypeIdComptimeInt) { + ir_add_error(ira, instruction->target, buf_sprintf("attempt to cast runtime value to '%s'", + buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + return ir_analyze_widen_or_shorten(ira, &instruction->base, target, dest_type); } diff --git a/test/cases/cast.zig b/test/cases/cast.zig index e893ec13c..06c029a40 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -452,3 +452,13 @@ test "implicit ptr to *c_void" { var c: *u32 = @ptrCast(*u32, ptr2.?); assert(c.* == 1); } + +test "@intCast to comptime_int" { + assert(@intCast(comptime_int, 0) == 0); +} + +test "implicit cast comptime numbers to any type when the value fits" { + const a: u64 = 255; + var b: u8 = a; + assert(b == 255); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7339be7fa..45bd6cb40 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,61 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "cast negative value to unsigned integer", + \\comptime { + \\ const value: i32 = -1; + \\ const unsigned = @intCast(u32, value); + \\} + \\export fn entry1() void { + \\ const value: i32 = -1; + \\ const unsigned: u32 = value; + \\} + , + ".tmp_source.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'", + ".tmp_source.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'", + ); + + cases.add( + "integer cast truncates bits", + \\export fn entry1() void { + \\ const spartan_count: u16 = 300; + \\ const byte = @intCast(u8, spartan_count); + \\} + \\export fn entry2() void { + \\ const spartan_count: u16 = 300; + \\ const byte: u8 = spartan_count; + \\} + \\export fn entry3() void { + \\ var spartan_count: u16 = 300; + \\ var byte: u8 = spartan_count; + \\} + , + ".tmp_source.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'", + ".tmp_source.zig:7:22: error: integer value 300 cannot be implicitly casted to type 'u8'", + ".tmp_source.zig:11:20: error: expected type 'u8', found 'u16'", + ); + + cases.add( + "comptime implicit cast f64 to f32", + \\export fn entry() void { + \\ const x: f64 = 16777217; + \\ const y: f32 = x; + \\} + , + ".tmp_source.zig:3:20: error: cast of value 16777217.000000 to type 'f32' loses information", + ); + + cases.add( + "implicit cast from f64 to f32", + \\var x: f64 = 1.0; + \\var y: f32 = x; + \\ + \\export fn entry() usize { return @sizeOf(@typeOf(y)); } + , + ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'", + ); + cases.add( "exceeded maximum bit width of integer", \\export fn entry1() void { @@ -1819,7 +1874,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ if (0) {} \\} , - ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'", + ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'", ); cases.add( @@ -2422,16 +2477,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'", ); - cases.add( - "implicit cast from f64 to f32", - \\const x : f64 = 1.0; - \\const y : f32 = x; - \\ - \\export fn entry() usize { return @sizeOf(@typeOf(y)); } - , - ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'", - ); - cases.add( "colliding invalid top level functions", \\fn func() bogus {} @@ -4049,16 +4094,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod", ); - cases.add( - "cast negative value to unsigned integer", - \\comptime { - \\ const value: i32 = -1; - \\ const unsigned = @intCast(u32, value); - \\} - , - ".tmp_source.zig:3:22: error: attempt to cast negative value to unsigned integer", - ); - cases.add( "compile-time division by zero", \\comptime { @@ -4081,16 +4116,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:4:17: error: division by zero", ); - cases.add( - "compile-time integer cast truncates bits", - \\comptime { - \\ const spartan_count: u16 = 300; - \\ const byte = @intCast(u8, spartan_count); - \\} - , - ".tmp_source.zig:3:18: error: cast from 'u16' to 'u8' truncates bits", - ); - cases.add( "@setRuntimeSafety twice for same scope", \\export fn foo() void { From 3c05ad401282b0eb8b9960a2b521fc1375c4087e Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sun, 18 Nov 2018 19:43:13 -0500 Subject: [PATCH 023/110] atomic.Int.set --- std/atomic/int.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/std/atomic/int.zig b/std/atomic/int.zig index 38b85873c..94985b914 100644 --- a/std/atomic/int.zig +++ b/std/atomic/int.zig @@ -26,6 +26,10 @@ pub fn Int(comptime T: type) type { return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst); } + pub fn set(self: *Self, new_value: T) void { + _ = self.xchg(new_value); + } + pub fn xchg(self: *Self, new_value: T) T { return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Xchg, new_value, AtomicOrder.SeqCst); } From 3829e200ecc251d6b55686c24bdbd579c5a2246a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 18 Nov 2018 20:03:35 -0500 Subject: [PATCH 024/110] fix assertion failure related to @intToEnum --- src/ir.cpp | 2 +- test/cases/cast.zig | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 3a22d0aa1..55f17b811 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10153,7 +10153,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour return ira->codegen->invalid_instruction; } - assert(actual_type->id == ZigTypeIdInt); + assert(actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt); if (instr_is_comptime(target)) { ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); diff --git a/test/cases/cast.zig b/test/cases/cast.zig index 06c029a40..bd45bbc00 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -462,3 +462,11 @@ test "implicit cast comptime numbers to any type when the value fits" { var b: u8 = a; assert(b == 255); } + +test "@intToEnum passed a comptime_int to an enum with one item" { + const E = enum { + A, + }; + const x = @intToEnum(E, 0); + assert(x == E.A); +} From 921d9c9bcba40ca07283fa3607814bb173d7af7b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 18 Nov 2018 20:18:24 -0500 Subject: [PATCH 025/110] add std.meta.intToEnum --- std/meta/index.zig | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/std/meta/index.zig b/std/meta/index.zig index 20e66fbe3..2019543b5 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -483,3 +483,32 @@ test "std.meta.eql" { debug.assert(eql(EU.tst(false), EU.tst(false))); debug.assert(!eql(EU.tst(false), EU.tst(true))); } + +test "intToEnum with error return" { + const E1 = enum { + A, + }; + const E2 = enum { + A, + B, + }; + + var zero: u8 = 0; + var one: u16 = 1; + debug.assert(intToEnum(E1, zero) catch unreachable == E1.A); + debug.assert(intToEnum(E2, one) catch unreachable == E2.B); + debug.assertError(intToEnum(E1, one), error.InvalidEnumTag); +} + +pub const IntToEnumError = error{InvalidEnumTag}; + +pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag { + comptime var i = 0; + inline while (i != @memberCount(Tag)) : (i += 1) { + const this_tag_value = @field(Tag, @memberName(Tag, i)); + if (tag_int == @enumToInt(this_tag_value)) { + return this_tag_value; + } + } + return error.InvalidEnumTag; +} From 4c0163b69bafce753ee31e1bfa3ae0b5ba37fbf2 Mon Sep 17 00:00:00 2001 From: Marc Tiehuis Date: Mon, 19 Nov 2018 21:56:45 +1300 Subject: [PATCH 026/110] std/rand: fix ziggurat next_f64 call --- std/rand/ziggurat.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/rand/ziggurat.zig b/std/rand/ziggurat.zig index f7a1359f1..0636a5bfc 100644 --- a/std/rand/ziggurat.zig +++ b/std/rand/ziggurat.zig @@ -12,7 +12,7 @@ const std = @import("../index.zig"); const math = std.math; const Random = std.rand.Random; -pub fn next_f64(random: *Random, comptime tables: *const ZigTable) f64 { +pub fn next_f64(random: *Random, comptime tables: ZigTable) f64 { while (true) { // We manually construct a float from parts as we can avoid an extra random lookup here by // using the unused exponent for the lookup table entry. From 81d9403dcea172ce2fdb44610c9350821109adae Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sun, 30 Sep 2018 00:02:01 -0700 Subject: [PATCH 027/110] Add SegmentedList.shrink I was exploring std.zig.Tokenizer and wanted to compare performance of arrays, SegmentedList and ArrayList and needed SegmentedList.shrink to make the comparison "fair". --- std/segmented_list.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/std/segmented_list.zig b/std/segmented_list.zig index c7c39651c..d786e0bec 100644 --- a/std/segmented_list.zig +++ b/std/segmented_list.zig @@ -201,6 +201,11 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type self.dynamic_segments = self.allocator.shrink([*]T, self.dynamic_segments, new_cap_shelf_count); } + pub fn shrink(self: *Self, new_len: usize) void { + assert(new_len <= self.len); + self.len = new_len; + } + pub fn uncheckedAt(self: var, index: usize) AtType(@typeOf(self)) { if (index < prealloc_item_count) { return &self.prealloc_segment[index]; From 2f5d1ec5006ccae81f6de80233fa7800237779e2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Nov 2018 11:22:57 -0500 Subject: [PATCH 028/110] improve error message when wrong type returned closes #1650 --- src/ir.cpp | 8 +++++++- test/compile_errors.zig | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 55f17b811..03389a232 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -34,6 +34,7 @@ struct IrAnalyze { size_t old_bb_index; size_t instruction_index; ZigType *explicit_return_type; + AstNode *explicit_return_type_source_node; ZigList src_implicit_return_type_list; IrBasicBlock *const_predecessor_bb; }; @@ -11162,8 +11163,12 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio return ir_unreach_error(ira); IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); - if (type_is_invalid(casted_value->value.type)) + if (type_is_invalid(casted_value->value.type) && ira->explicit_return_type_source_node != nullptr) { + ErrorMsg *msg = ira->codegen->errors.last(); + add_error_note(ira->codegen, msg, ira->explicit_return_type_source_node, + buf_sprintf("return type declared here")); return ir_unreach_error(ira); + } if (casted_value->value.special == ConstValSpecialRuntime && casted_value->value.type->id == ZigTypeIdPointer && @@ -21213,6 +21218,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ ZigFn *fn_entry = exec_fn_entry(old_exec); bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; ira->explicit_return_type = is_async ? get_promise_type(codegen, expected_type) : expected_type; + ira->explicit_return_type_source_node = expected_type_source_node; ira->old_irb.codegen = codegen; ira->old_irb.exec = old_exec; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 45bd6cb40..16690daf2 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3219,6 +3219,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn something() anyerror!void { } , ".tmp_source.zig:2:5: error: expected type 'void', found 'anyerror'", + ".tmp_source.zig:1:15: note: return type declared here", ); cases.add( From b1a676b279db81e83f694142590fca9b53a6a235 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Nov 2018 13:20:39 -0500 Subject: [PATCH 029/110] docs: fix some incorrect error documentation --- doc/langref.html.in | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 022b03ef4..6e2d2bd9a 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -3273,13 +3273,13 @@ const err = (error {FileNotFound}).FileNotFound; This becomes useful when using {#link|Inferred Error Sets#}.

{#header_open|The Global Error Set#} -

{#syntax#}error{#endsyntax#} refers to the global error set. +

{#syntax#}anyerror{#endsyntax#} refers to the global error set. This is the error set that contains all errors in the entire compilation unit. It is a superset of all other error sets and a subset of none of them.

You can implicitly cast any error set to the global one, and you can explicitly - cast an error of global error set to a non-global one. This inserts a language-level + cast an error of the global error set to a non-global one. This inserts a language-level assert to make sure the error value is in fact in the destination error set.

@@ -5601,18 +5601,14 @@ test "main" { {#header_close#} {#header_open|@errorName#} -

{#syntax#}@errorName(err: error) []u8{#endsyntax#}
+
{#syntax#}@errorName(err: anyerror) []const u8{#endsyntax#}

- This function returns the string representation of an error. If an error - declaration is: -

-
{#syntax#}error OutOfMem{#endsyntax#}
-

- Then the string representation is {#syntax#}"OutOfMem"{#endsyntax#}. + This function returns the string representation of an error. The string representation + of {#syntax#}error.OutOfMem{#endsyntax#} is {#syntax#}"OutOfMem"{#endsyntax#}.

If there are no calls to {#syntax#}@errorName{#endsyntax#} in an entire application, - or all calls have a compile-time known value for {#syntax#}err{#endsyntax#}, then no + or all calls have a compile-time known value for {#syntax#}err{#endsyntax#}, then no error name table will be generated.

{#header_close#} @@ -5627,13 +5623,14 @@ test "main" { {#header_close#} {#header_open|@errorToInt#} -
{#syntax#}@errorToInt(err: var) @IntType(false, @sizeOf(error) * 8){#endsyntax#}
+
{#syntax#}@errorToInt(err: var) @IntType(false, @sizeOf(anyerror) * 8){#endsyntax#}

Supports the following types:

    -
  • error unions
  • -
  • {#syntax#}E!void{#endsyntax#}
  • +
  • {#link|The Global Error Set#}
  • +
  • {#link|Error Set Type#}
  • +
  • {#link|Error Union Type#}

Converts an error to the integer representation of an error. @@ -5788,7 +5785,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } {#header_open|@intToError#}

{#syntax#}@intToError(value: @IntType(false, @sizeOf(anyerror) * 8)) anyerror{#endsyntax#}

- Converts from the integer representation of an error into the global error set type. + Converts from the integer representation of an error into {#link|The Global Error Set#} type.

It is generally recommended to avoid this From 89e82281be73701f5a634770366e9dca5a0e89a9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Nov 2018 13:26:35 -0500 Subject: [PATCH 030/110] fix incorrect --help text --- src/main.cpp | 9 +-------- std/special/build_runner.zig | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 84ff2fb4b..078dfb25f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -466,16 +466,9 @@ int main(int argc, char **argv) { "\n" "General Options:\n" " --help Print this help and exit\n" - " --build-file [file] Override path to build.zig\n" - " --cache-dir [path] Override path to cache directory\n" " --verbose Print commands before executing them\n" - " --verbose-tokenize Enable compiler debug output for tokenization\n" - " --verbose-ast Enable compiler debug output for parsing into an AST\n" - " --verbose-link Enable compiler debug output for linking\n" - " --verbose-ir Enable compiler debug output for Zig IR\n" - " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n" - " --verbose-cimport Enable compiler debug output for C imports\n" " --prefix [path] Override default install prefix\n" + " --search-prefix [path] Add a path to look for binaries, libraries, headers\n" "\n" "Project-specific options become available when the build file is found.\n" "\n" diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index 15e353438..ff3b53619 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -164,7 +164,6 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { \\ \\General Options: \\ --help Print this help and exit - \\ --init Generate a build.zig template \\ --verbose Print commands before executing them \\ --prefix [path] Override default install prefix \\ --search-prefix [path] Add a path to look for binaries, libraries, headers From 703c6684d103f14193411b589eaa0e0b1e1189f0 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Mon, 19 Nov 2018 22:22:21 +0100 Subject: [PATCH 031/110] Crash fixes and small improvements to inline asm. (#1756) * codegen: LLVMConstInlineAsm is deprecated. * codegen: replace commas in asm constraint strings by pipes as required by LLVM. * ir: enforce usage of '=' constraint modifier for inline assembly outputs. Others are not currently supported and this was just asserted alter in `ir_render_asm`. * asm: forbid comptime_int/floats as inputs in favor of explicitely sized constants. Fixes a crash due to comptime_int/floats having no type_ref. * asm: handle inputs with integers of <8 or non power of 2 bitsize. We widen them to the next highest power of two. --- src/buffer.hpp | 10 ++++++++++ src/codegen.cpp | 31 +++++++++++++++++++++++++++---- src/ir.cpp | 23 +++++++++++++++++++++-- src/util.hpp | 11 +++++++++++ test/cases/asm.zig | 24 ++++++++++++++++++++++++ test/compile_errors.zig | 28 ++++++++++++++++++++++++++++ 6 files changed, 121 insertions(+), 6 deletions(-) diff --git a/src/buffer.hpp b/src/buffer.hpp index 8155df87a..afe9fd8a9 100644 --- a/src/buffer.hpp +++ b/src/buffer.hpp @@ -181,5 +181,15 @@ static inline Slice buf_to_slice(Buf *buf) { return Slice{reinterpret_cast(buf_ptr(buf)), buf_len(buf)}; } +static inline void buf_replace(Buf* buf, char from, char to) { + const size_t count = buf_len(buf); + char* ptr = buf_ptr(buf); + for (size_t i = 0; i < count; ++i) { + char& l = ptr[i]; + if (l == from) + l = to; + } +} + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index bd9063d02..40f71e38f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3660,6 +3660,13 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru AsmOutput *asm_output = asm_expr->output_list.at(i); bool is_return = (asm_output->return_type != nullptr); assert(*buf_ptr(asm_output->constraint) == '='); + // LLVM uses commas internally to separate different constraints, + // alternative constraints are achieved with pipes. + // We still allow the user to use commas in a way that is similar + // to GCC's inline assembly. + // http://llvm.org/docs/LangRef.html#constraint-codes + buf_replace(asm_output->constraint, ',', '|'); + if (is_return) { buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1); } else { @@ -3679,14 +3686,30 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru } for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) { AsmInput *asm_input = asm_expr->input_list.at(i); + buf_replace(asm_input->constraint, ',', '|'); IrInstruction *ir_input = instruction->input_list[i]; buf_append_buf(&constraint_buf, asm_input->constraint); if (total_index + 1 < total_constraint_count) { buf_append_char(&constraint_buf, ','); } - param_types[param_index] = ir_input->value.type->type_ref; - param_values[param_index] = ir_llvm_value(g, ir_input); + ZigType *const type = ir_input->value.type; + LLVMTypeRef type_ref = type->type_ref; + LLVMValueRef value_ref = ir_llvm_value(g, ir_input); + // Handle integers of non pot bitsize by widening them. + if (type->id == ZigTypeIdInt) { + const size_t bitsize = type->data.integral.bit_count; + if (bitsize < 8 || !is_power_of_2(bitsize)) { + const bool is_signed = type->data.integral.is_signed; + const size_t wider_bitsize = bitsize < 8 ? 8 : round_to_next_power_of_2(bitsize); + ZigType *const wider_type = get_int_type(g, is_signed, wider_bitsize); + type_ref = wider_type->type_ref; + value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref); + } + } + + param_types[param_index] = type_ref; + param_values[param_index] = value_ref; } for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) { Buf *clobber_buf = asm_expr->clobber_list.at(i); @@ -3705,8 +3728,8 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, (unsigned)input_and_output_count, false); bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0); - LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), - buf_ptr(&constraint_buf), is_volatile, false); + LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(&llvm_template), buf_len(&llvm_template), + buf_ptr(&constraint_buf), buf_len(&constraint_buf), is_volatile, false, LLVMInlineAsmDialectATT); return LLVMBuildCall(g->builder, asm_fn, param_values, (unsigned)input_and_output_count, ""); } diff --git a/src/ir.cpp b/src/ir.cpp index 03389a232..a62da827b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5537,6 +5537,15 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod return irb->codegen->invalid_instruction; } } + + const char modifier = *buf_ptr(asm_output->constraint); + if (modifier != '=') { + add_node_error(irb->codegen, node, + buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported." + " Compiler TODO: see https://github.com/ziglang/zig/issues/215", + buf_ptr(asm_output->asm_symbolic_name), modifier)); + return irb->codegen->invalid_instruction; + } } for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) { AsmInput *asm_input = node->data.asm_expr.input_list.at(i); @@ -15386,9 +15395,19 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs } for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - input_list[i] = asm_instruction->input_list[i]->child; - if (type_is_invalid(input_list[i]->value.type)) + IrInstruction *const input_value = asm_instruction->input_list[i]->child; + if (type_is_invalid(input_value->value.type)) return ira->codegen->invalid_instruction; + + if (instr_is_comptime(input_value) && + (input_value->value.type->id == ZigTypeIdComptimeInt || + input_value->value.type->id == ZigTypeIdComptimeFloat)) { + ir_add_error_node(ira, input_value->source_node, + buf_sprintf("expected sized integer or sized float, found %s", buf_ptr(&input_value->value.type->name))); + return ira->codegen->invalid_instruction; + } + + input_list[i] = input_value; } IrInstruction *result = ir_build_asm(&ira->new_irb, diff --git a/src/util.hpp b/src/util.hpp index a78231324..cc8302232 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -158,6 +158,17 @@ static inline bool is_power_of_2(uint64_t x) { return x != 0 && ((x & (~x + 1)) == x); } +static inline uint64_t round_to_next_power_of_2(uint64_t x) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x |= x >> 32; + return x + 1; +} + uint32_t int_hash(int i); bool int_eq(int a, int b); uint32_t uint64_hash(uint64_t i); diff --git a/test/cases/asm.zig b/test/cases/asm.zig index 1c4208f40..63e37c857 100644 --- a/test/cases/asm.zig +++ b/test/cases/asm.zig @@ -17,6 +17,30 @@ test "module level assembly" { } } +test "output constraint modifiers" { + // This is only testing compilation. + var a: u32 = 3; + asm volatile ("" : [_]"=m,r"(a) : : ""); + asm volatile ("" : [_]"=r,m"(a) : : ""); +} + +test "alternative constraints" { + // Make sure we allow commas as a separator for alternative constraints. + var a: u32 = 3; + asm volatile ("" : [_]"=r,m"(a) : [_]"r,m"(a) : ""); +} + +test "sized integer/float in asm input" { + asm volatile ("" : : [_]"m"(usize(3)) : ""); + asm volatile ("" : : [_]"m"(i15(-3)) : ""); + asm volatile ("" : : [_]"m"(u3(3)) : ""); + asm volatile ("" : : [_]"m"(i3(3)) : ""); + asm volatile ("" : : [_]"m"(u121(3)) : ""); + asm volatile ("" : : [_]"m"(i121(3)) : ""); + asm volatile ("" : : [_]"m"(f32(3.17)) : ""); + asm volatile ("" : : [_]"m"(f64(3.17)) : ""); +} + extern fn aoeu() i32; export fn derp() i32 { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 16690daf2..c5575a0c0 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5232,4 +5232,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic", ); + + cases.add( + "unsupported modifier at start of asm output constraint", + \\export fn foo() void { + \\ var bar: u32 = 3; + \\ asm volatile ("" : [baz]"+r"(bar) : : ""); + \\} + , + ".tmp_source.zig:3:5: error: invalid modifier starting output constraint for 'baz': '+', only '=' is supported. Compiler TODO: see https://github.com/ziglang/zig/issues/215", + ); + + cases.add( + "comptime_int in asm input", + \\export fn foo() void { + \\ asm volatile ("" : : [bar]"r"(3) : ""); + \\} + , + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", + ); + + cases.add( + "comptime_float in asm input", + \\export fn foo() void { + \\ asm volatile ("" : : [bar]"r"(3.17) : ""); + \\} + , + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", + ); } From 4dafdc00d5c0d73511d64c5edf7481c8fe254a61 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Nov 2018 17:28:18 -0500 Subject: [PATCH 032/110] zig fmt --- std/c/freebsd.zig | 7 ++----- std/debug/index.zig | 3 +-- std/mem.zig | 8 ++++---- std/os/freebsd/index.zig | 21 +++++++-------------- std/os/freebsd/x86_64.zig | 6 +++--- std/special/bootstrap.zig | 2 +- 6 files changed, 18 insertions(+), 29 deletions(-) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 6eb34929b..421e96482 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -1,4 +1,3 @@ - const timespec = @import("../os/freebsd/index.zig").timespec; extern "c" fn __error() *c_int; @@ -18,7 +17,7 @@ pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usi pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. -pub const Kevent = extern struct.{ +pub const Kevent = extern struct { ident: usize, filter: i16, flags: u16, @@ -28,9 +27,7 @@ pub const Kevent = extern struct.{ // TODO ext }; - -pub const pthread_attr_t = extern struct.{ +pub const pthread_attr_t = extern struct { __size: [56]u8, __align: c_long, }; - diff --git a/std/debug/index.zig b/std/debug/index.zig index a3509b311..722f95ccb 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -1101,8 +1101,7 @@ pub const DebugInfo = switch (builtin.os) { self.elf.close(); } }, - builtin.Os.freebsd => struct.{ - }, + builtin.Os.freebsd => struct {}, else => @compileError("Unsupported OS"), }; diff --git a/std/mem.zig b/std/mem.zig index 6b37dfe40..6b115a56f 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -475,8 +475,8 @@ test "readIntBE/LE" { assert(readIntBE(u8, []u8{0x32}) == 0x32); assert(readIntLE(u8, []u8{0x12}) == 0x12); - assert(readIntBE(u16, []u8{0x12, 0x34}) == 0x1234); - assert(readIntLE(u16, []u8{0x12, 0x34}) == 0x3412); + assert(readIntBE(u16, []u8{ 0x12, 0x34 }) == 0x1234); + assert(readIntLE(u16, []u8{ 0x12, 0x34 }) == 0x3412); assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); @@ -484,8 +484,8 @@ test "readIntBE/LE" { assert(readIntBE(i8, []u8{0xff}) == -1); assert(readIntLE(i8, []u8{0xfe}) == -2); - assert(readIntBE(i16, []u8{0xff, 0xfd}) == -3); - assert(readIntLE(i16, []u8{0xfc, 0xff}) == -4); + assert(readIntBE(i16, []u8{ 0xff, 0xfd }) == -3); + assert(readIntLE(i16, []u8{ 0xfc, 0xff }) == -4); } /// Writes an integer to memory with size equal to bytes.len. Pads with zeroes diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 1793379fb..75389fc40 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -377,7 +377,6 @@ pub const NOTE_FFCOPY = 0xc0000000; pub const NOTE_FFCTRLMASK = 0xc0000000; pub const NOTE_FFLAGSMASK = 0x00ffffff; - /// low water mark pub const NOTE_LOWAT = 0x00000001; @@ -445,8 +444,6 @@ pub const NOTE_NSECONDS = 0x00000008; /// timeout is absolute pub const NOTE_ABSTIME = 0x00000010; - - pub const TCGETS = 0x5401; pub const TCSETS = 0x5402; pub const TCSETSW = 0x5403; @@ -528,7 +525,7 @@ pub fn WIFSIGNALED(s: i32) bool { return (unsigned(s) & 0xffff) -% 1 < 0xff; } -pub const winsize = extern struct.{ +pub const winsize = extern struct { ws_row: u16, ws_col: u16, ws_xpixel: u16, @@ -703,11 +700,11 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti const NSIG = 65; const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize.{@maxValue(usize)}; -const app_mask = []usize.{0xfffffffc7fffffff}; +const all_mask = []usize{@maxValue(usize)}; +const app_mask = []usize{0xfffffffc7fffffff}; /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. -pub const Sigaction = struct.{ +pub const Sigaction = struct { // TODO: Adjust to use freebsd struct layout handler: extern fn (i32) void, mask: sigset_t, @@ -717,7 +714,7 @@ pub const Sigaction = struct.{ pub const SIG_ERR = @intToPtr(extern fn (i32) void, @maxValue(usize)); pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); -pub const empty_sigset = []usize.{0} ** sigset_t.len; +pub const empty_sigset = []usize{0} ** sigset_t.len; pub fn raise(sig: i32) usize { // TODO implement, see linux equivalent for what we want to try and do @@ -753,12 +750,12 @@ pub fn fstat(fd: i32, stat_buf: *Stat) usize { return arch.syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); } -pub const iovec = extern struct.{ +pub const iovec = extern struct { iov_base: [*]u8, iov_len: usize, }; -pub const iovec_const = extern struct.{ +pub const iovec_const = extern struct { iov_base: [*]const u8, iov_len: usize, }; @@ -790,13 +787,9 @@ pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize { return errnoWrap(c.sysctlnametomib(name, wibp, sizep)); } - - /// Takes the return value from a syscall and formats it back in the way /// that the kernel represents it to libc. Errno was a mistake, let's make /// it go away forever. fn errnoWrap(value: isize) usize { return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value); } - - diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig index 28ae2d547..20a671059 100644 --- a/std/os/freebsd/x86_64.zig +++ b/std/os/freebsd/x86_64.zig @@ -97,7 +97,7 @@ pub nakedcc fn restore_rt() void { ); } -pub const msghdr = extern struct.{ +pub const msghdr = extern struct { msg_name: &u8, msg_namelen: socklen_t, msg_iov: &iovec, @@ -110,7 +110,7 @@ pub const msghdr = extern struct.{ }; /// Renamed to Stat to not conflict with the stat function. -pub const Stat = extern struct.{ +pub const Stat = extern struct { dev: u64, ino: u64, nlink: usize, @@ -130,7 +130,7 @@ pub const Stat = extern struct.{ __unused: [3]isize, }; -pub const timespec = extern struct.{ +pub const timespec = extern struct { tv_sec: isize, tv_nsec: isize, }; diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 070a26bf7..a15be317a 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -23,7 +23,7 @@ nakedcc fn _start() noreturn { builtin.Arch.x86_64 => switch (builtin.os) { builtin.Os.freebsd => { argc_ptr = asm ("lea (%%rdi), %[argc]" - : [argc] "=r" (-> [*]usize) + : [argc] "=r" (-> [*]usize) ); }, else => { From a05716bd20ea5b90baa2819a0aaa5bfc7583e100 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Mon, 19 Nov 2018 13:04:17 -0800 Subject: [PATCH 033/110] Allow json tests to be easily filtered --- std/json.zig | 6 +- std/json_test.zig | 638 +++++++++++++++++++++++----------------------- 2 files changed, 322 insertions(+), 322 deletions(-) diff --git a/std/json.zig b/std/json.zig index 23573b6d7..d9113f5f9 100644 --- a/std/json.zig +++ b/std/json.zig @@ -910,7 +910,7 @@ fn checkNext(p: *TokenStream, id: Token.Id) void { debug.assert(token.id == id); } -test "token" { +test "json.token" { const s = \\{ \\ "Image": { @@ -980,7 +980,7 @@ pub fn validate(s: []const u8) bool { return p.complete; } -test "json validate" { +test "json.validate" { debug.assert(validate("{}")); } @@ -1348,7 +1348,7 @@ pub const Parser = struct { } }; -test "json parser dynamic" { +test "json.parser.dynamic" { var p = Parser.init(debug.global_allocator, false); defer p.deinit(); diff --git a/std/json_test.zig b/std/json_test.zig index 8c8862441..9e19ec592 100644 --- a/std/json_test.zig +++ b/std/json_test.zig @@ -21,7 +21,7 @@ fn any(comptime s: []const u8) void { // // Additional tests not part of test JSONTestSuite. -test "y_trailing_comma_after_empty" { +test "json.test.y_trailing_comma_after_empty" { ok( \\{"1":[],"2":{},"3":"4"} ); @@ -29,252 +29,252 @@ test "y_trailing_comma_after_empty" { //////////////////////////////////////////////////////////////////////////////////////////////////// -test "y_array_arraysWithSpaces" { +test "json.test.y_array_arraysWithSpaces" { ok( \\[[] ] ); } -test "y_array_empty" { +test "json.test.y_array_empty" { ok( \\[] ); } -test "y_array_empty-string" { +test "json.test.y_array_empty-string" { ok( \\[""] ); } -test "y_array_ending_with_newline" { +test "json.test.y_array_ending_with_newline" { ok( \\["a"] ); } -test "y_array_false" { +test "json.test.y_array_false" { ok( \\[false] ); } -test "y_array_heterogeneous" { +test "json.test.y_array_heterogeneous" { ok( \\[null, 1, "1", {}] ); } -test "y_array_null" { +test "json.test.y_array_null" { ok( \\[null] ); } -test "y_array_with_1_and_newline" { +test "json.test.y_array_with_1_and_newline" { ok( \\[1 \\] ); } -test "y_array_with_leading_space" { +test "json.test.y_array_with_leading_space" { ok( \\ [1] ); } -test "y_array_with_several_null" { +test "json.test.y_array_with_several_null" { ok( \\[1,null,null,null,2] ); } -test "y_array_with_trailing_space" { +test "json.test.y_array_with_trailing_space" { ok("[2] "); } -test "y_number_0e+1" { +test "json.test.y_number_0e+1" { ok( \\[0e+1] ); } -test "y_number_0e1" { +test "json.test.y_number_0e1" { ok( \\[0e1] ); } -test "y_number_after_space" { +test "json.test.y_number_after_space" { ok( \\[ 4] ); } -test "y_number_double_close_to_zero" { +test "json.test.y_number_double_close_to_zero" { ok( \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] ); } -test "y_number_int_with_exp" { +test "json.test.y_number_int_with_exp" { ok( \\[20e1] ); } -test "y_number" { +test "json.test.y_number" { ok( \\[123e65] ); } -test "y_number_minus_zero" { +test "json.test.y_number_minus_zero" { ok( \\[-0] ); } -test "y_number_negative_int" { +test "json.test.y_number_negative_int" { ok( \\[-123] ); } -test "y_number_negative_one" { +test "json.test.y_number_negative_one" { ok( \\[-1] ); } -test "y_number_negative_zero" { +test "json.test.y_number_negative_zero" { ok( \\[-0] ); } -test "y_number_real_capital_e" { +test "json.test.y_number_real_capital_e" { ok( \\[1E22] ); } -test "y_number_real_capital_e_neg_exp" { +test "json.test.y_number_real_capital_e_neg_exp" { ok( \\[1E-2] ); } -test "y_number_real_capital_e_pos_exp" { +test "json.test.y_number_real_capital_e_pos_exp" { ok( \\[1E+2] ); } -test "y_number_real_exponent" { +test "json.test.y_number_real_exponent" { ok( \\[123e45] ); } -test "y_number_real_fraction_exponent" { +test "json.test.y_number_real_fraction_exponent" { ok( \\[123.456e78] ); } -test "y_number_real_neg_exp" { +test "json.test.y_number_real_neg_exp" { ok( \\[1e-2] ); } -test "y_number_real_pos_exponent" { +test "json.test.y_number_real_pos_exponent" { ok( \\[1e+2] ); } -test "y_number_simple_int" { +test "json.test.y_number_simple_int" { ok( \\[123] ); } -test "y_number_simple_real" { +test "json.test.y_number_simple_real" { ok( \\[123.456789] ); } -test "y_object_basic" { +test "json.test.y_object_basic" { ok( \\{"asd":"sdf"} ); } -test "y_object_duplicated_key_and_value" { +test "json.test.y_object_duplicated_key_and_value" { ok( \\{"a":"b","a":"b"} ); } -test "y_object_duplicated_key" { +test "json.test.y_object_duplicated_key" { ok( \\{"a":"b","a":"c"} ); } -test "y_object_empty" { +test "json.test.y_object_empty" { ok( \\{} ); } -test "y_object_empty_key" { +test "json.test.y_object_empty_key" { ok( \\{"":0} ); } -test "y_object_escaped_null_in_key" { +test "json.test.y_object_escaped_null_in_key" { ok( \\{"foo\u0000bar": 42} ); } -test "y_object_extreme_numbers" { +test "json.test.y_object_extreme_numbers" { ok( \\{ "min": -1.0e+28, "max": 1.0e+28 } ); } -test "y_object" { +test "json.test.y_object" { ok( \\{"asd":"sdf", "dfg":"fgh"} ); } -test "y_object_long_strings" { +test "json.test.y_object_long_strings" { ok( \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} ); } -test "y_object_simple" { +test "json.test.y_object_simple" { ok( \\{"a":[]} ); } -test "y_object_string_unicode" { +test "json.test.y_object_string_unicode" { ok( \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } ); } -test "y_object_with_newlines" { +test "json.test.y_object_with_newlines" { ok( \\{ \\"a": "b" @@ -282,419 +282,419 @@ test "y_object_with_newlines" { ); } -test "y_string_1_2_3_bytes_UTF-8_sequences" { +test "json.test.y_string_1_2_3_bytes_UTF-8_sequences" { ok( \\["\u0060\u012a\u12AB"] ); } -test "y_string_accepted_surrogate_pair" { +test "json.test.y_string_accepted_surrogate_pair" { ok( \\["\uD801\udc37"] ); } -test "y_string_accepted_surrogate_pairs" { +test "json.test.y_string_accepted_surrogate_pairs" { ok( \\["\ud83d\ude39\ud83d\udc8d"] ); } -test "y_string_allowed_escapes" { +test "json.test.y_string_allowed_escapes" { ok( \\["\"\\\/\b\f\n\r\t"] ); } -test "y_string_backslash_and_u_escaped_zero" { +test "json.test.y_string_backslash_and_u_escaped_zero" { ok( \\["\\u0000"] ); } -test "y_string_backslash_doublequotes" { +test "json.test.y_string_backslash_doublequotes" { ok( \\["\""] ); } -test "y_string_comments" { +test "json.test.y_string_comments" { ok( \\["a/*b*/c/*d//e"] ); } -test "y_string_double_escape_a" { +test "json.test.y_string_double_escape_a" { ok( \\["\\a"] ); } -test "y_string_double_escape_n" { +test "json.test.y_string_double_escape_n" { ok( \\["\\n"] ); } -test "y_string_escaped_control_character" { +test "json.test.y_string_escaped_control_character" { ok( \\["\u0012"] ); } -test "y_string_escaped_noncharacter" { +test "json.test.y_string_escaped_noncharacter" { ok( \\["\uFFFF"] ); } -test "y_string_in_array" { +test "json.test.y_string_in_array" { ok( \\["asd"] ); } -test "y_string_in_array_with_leading_space" { +test "json.test.y_string_in_array_with_leading_space" { ok( \\[ "asd"] ); } -test "y_string_last_surrogates_1_and_2" { +test "json.test.y_string_last_surrogates_1_and_2" { ok( \\["\uDBFF\uDFFF"] ); } -test "y_string_nbsp_uescaped" { +test "json.test.y_string_nbsp_uescaped" { ok( \\["new\u00A0line"] ); } -test "y_string_nonCharacterInUTF-8_U+10FFFF" { +test "json.test.y_string_nonCharacterInUTF-8_U+10FFFF" { ok( \\["􏿿"] ); } -test "y_string_nonCharacterInUTF-8_U+FFFF" { +test "json.test.y_string_nonCharacterInUTF-8_U+FFFF" { ok( \\["￿"] ); } -test "y_string_null_escape" { +test "json.test.y_string_null_escape" { ok( \\["\u0000"] ); } -test "y_string_one-byte-utf-8" { +test "json.test.y_string_one-byte-utf-8" { ok( \\["\u002c"] ); } -test "y_string_pi" { +test "json.test.y_string_pi" { ok( \\["π"] ); } -test "y_string_reservedCharacterInUTF-8_U+1BFFF" { +test "json.test.y_string_reservedCharacterInUTF-8_U+1BFFF" { ok( \\["𛿿"] ); } -test "y_string_simple_ascii" { +test "json.test.y_string_simple_ascii" { ok( \\["asd "] ); } -test "y_string_space" { +test "json.test.y_string_space" { ok( \\" " ); } -test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { +test "json.test.y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { ok( \\["\uD834\uDd1e"] ); } -test "y_string_three-byte-utf-8" { +test "json.test.y_string_three-byte-utf-8" { ok( \\["\u0821"] ); } -test "y_string_two-byte-utf-8" { +test "json.test.y_string_two-byte-utf-8" { ok( \\["\u0123"] ); } -test "y_string_u+2028_line_sep" { +test "json.test.y_string_u+2028_line_sep" { ok("[\"\xe2\x80\xa8\"]"); } -test "y_string_u+2029_par_sep" { +test "json.test.y_string_u+2029_par_sep" { ok("[\"\xe2\x80\xa9\"]"); } -test "y_string_uescaped_newline" { +test "json.test.y_string_uescaped_newline" { ok( \\["new\u000Aline"] ); } -test "y_string_uEscape" { +test "json.test.y_string_uEscape" { ok( \\["\u0061\u30af\u30EA\u30b9"] ); } -test "y_string_unescaped_char_delete" { +test "json.test.y_string_unescaped_char_delete" { ok("[\"\x7f\"]"); } -test "y_string_unicode_2" { +test "json.test.y_string_unicode_2" { ok( \\["⍂㈴⍂"] ); } -test "y_string_unicodeEscapedBackslash" { +test "json.test.y_string_unicodeEscapedBackslash" { ok( \\["\u005C"] ); } -test "y_string_unicode_escaped_double_quote" { +test "json.test.y_string_unicode_escaped_double_quote" { ok( \\["\u0022"] ); } -test "y_string_unicode" { +test "json.test.y_string_unicode" { ok( \\["\uA66D"] ); } -test "y_string_unicode_U+10FFFE_nonchar" { +test "json.test.y_string_unicode_U+10FFFE_nonchar" { ok( \\["\uDBFF\uDFFE"] ); } -test "y_string_unicode_U+1FFFE_nonchar" { +test "json.test.y_string_unicode_U+1FFFE_nonchar" { ok( \\["\uD83F\uDFFE"] ); } -test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { +test "json.test.y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { ok( \\["\u200B"] ); } -test "y_string_unicode_U+2064_invisible_plus" { +test "json.test.y_string_unicode_U+2064_invisible_plus" { ok( \\["\u2064"] ); } -test "y_string_unicode_U+FDD0_nonchar" { +test "json.test.y_string_unicode_U+FDD0_nonchar" { ok( \\["\uFDD0"] ); } -test "y_string_unicode_U+FFFE_nonchar" { +test "json.test.y_string_unicode_U+FFFE_nonchar" { ok( \\["\uFFFE"] ); } -test "y_string_utf8" { +test "json.test.y_string_utf8" { ok( \\["€𝄞"] ); } -test "y_string_with_del_character" { +test "json.test.y_string_with_del_character" { ok("[\"a\x7fa\"]"); } -test "y_structure_lonely_false" { +test "json.test.y_structure_lonely_false" { ok( \\false ); } -test "y_structure_lonely_int" { +test "json.test.y_structure_lonely_int" { ok( \\42 ); } -test "y_structure_lonely_negative_real" { +test "json.test.y_structure_lonely_negative_real" { ok( \\-0.1 ); } -test "y_structure_lonely_null" { +test "json.test.y_structure_lonely_null" { ok( \\null ); } -test "y_structure_lonely_string" { +test "json.test.y_structure_lonely_string" { ok( \\"asd" ); } -test "y_structure_lonely_true" { +test "json.test.y_structure_lonely_true" { ok( \\true ); } -test "y_structure_string_empty" { +test "json.test.y_structure_string_empty" { ok( \\"" ); } -test "y_structure_trailing_newline" { +test "json.test.y_structure_trailing_newline" { ok( \\["a"] ); } -test "y_structure_true_in_array" { +test "json.test.y_structure_true_in_array" { ok( \\[true] ); } -test "y_structure_whitespace_array" { +test "json.test.y_structure_whitespace_array" { ok(" [] "); } //////////////////////////////////////////////////////////////////////////////////////////////////// -test "n_array_1_true_without_comma" { +test "json.test.n_array_1_true_without_comma" { err( \\[1 true] ); } -test "n_array_a_invalid_utf8" { +test "json.test.n_array_a_invalid_utf8" { err( \\[aå] ); } -test "n_array_colon_instead_of_comma" { +test "json.test.n_array_colon_instead_of_comma" { err( \\["": 1] ); } -test "n_array_comma_after_close" { +test "json.test.n_array_comma_after_close" { //err( // \\[""], //); } -test "n_array_comma_and_number" { +test "json.test.n_array_comma_and_number" { err( \\[,1] ); } -test "n_array_double_comma" { +test "json.test.n_array_double_comma" { err( \\[1,,2] ); } -test "n_array_double_extra_comma" { +test "json.test.n_array_double_extra_comma" { err( \\["x",,] ); } -test "n_array_extra_close" { +test "json.test.n_array_extra_close" { err( \\["x"]] ); } -test "n_array_extra_comma" { +test "json.test.n_array_extra_comma" { //err( // \\["",] //); } -test "n_array_incomplete_invalid_value" { +test "json.test.n_array_incomplete_invalid_value" { err( \\[x ); } -test "n_array_incomplete" { +test "json.test.n_array_incomplete" { err( \\["x" ); } -test "n_array_inner_array_no_comma" { +test "json.test.n_array_inner_array_no_comma" { err( \\[3[4]] ); } -test "n_array_invalid_utf8" { +test "json.test.n_array_invalid_utf8" { err( \\[ÿ] ); } -test "n_array_items_separated_by_semicolon" { +test "json.test.n_array_items_separated_by_semicolon" { err( \\[1:2] ); } -test "n_array_just_comma" { +test "json.test.n_array_just_comma" { err( \\[,] ); } -test "n_array_just_minus" { +test "json.test.n_array_just_minus" { err( \\[-] ); } -test "n_array_missing_value" { +test "json.test.n_array_missing_value" { err( \\[ , ""] ); } -test "n_array_newlines_unclosed" { +test "json.test.n_array_newlines_unclosed" { err( \\["a", \\4 @@ -702,41 +702,41 @@ test "n_array_newlines_unclosed" { ); } -test "n_array_number_and_comma" { +test "json.test.n_array_number_and_comma" { err( \\[1,] ); } -test "n_array_number_and_several_commas" { +test "json.test.n_array_number_and_several_commas" { err( \\[1,,] ); } -test "n_array_spaces_vertical_tab_formfeed" { +test "json.test.n_array_spaces_vertical_tab_formfeed" { err("[\"\x0aa\"\\f]"); } -test "n_array_star_inside" { +test "json.test.n_array_star_inside" { err( \\[*] ); } -test "n_array_unclosed" { +test "json.test.n_array_unclosed" { err( \\["" ); } -test "n_array_unclosed_trailing_comma" { +test "json.test.n_array_unclosed_trailing_comma" { err( \\[1, ); } -test "n_array_unclosed_with_new_lines" { +test "json.test.n_array_unclosed_with_new_lines" { err( \\[1, \\1 @@ -744,956 +744,956 @@ test "n_array_unclosed_with_new_lines" { ); } -test "n_array_unclosed_with_object_inside" { +test "json.test.n_array_unclosed_with_object_inside" { err( \\[{} ); } -test "n_incomplete_false" { +test "json.test.n_incomplete_false" { err( \\[fals] ); } -test "n_incomplete_null" { +test "json.test.n_incomplete_null" { err( \\[nul] ); } -test "n_incomplete_true" { +test "json.test.n_incomplete_true" { err( \\[tru] ); } -test "n_multidigit_number_then_00" { +test "json.test.n_multidigit_number_then_00" { err("123\x00"); } -test "n_number_0.1.2" { +test "json.test.n_number_0.1.2" { err( \\[0.1.2] ); } -test "n_number_-01" { +test "json.test.n_number_-01" { err( \\[-01] ); } -test "n_number_0.3e" { +test "json.test.n_number_0.3e" { err( \\[0.3e] ); } -test "n_number_0.3e+" { +test "json.test.n_number_0.3e+" { err( \\[0.3e+] ); } -test "n_number_0_capital_E" { +test "json.test.n_number_0_capital_E" { err( \\[0E] ); } -test "n_number_0_capital_E+" { +test "json.test.n_number_0_capital_E+" { err( \\[0E+] ); } -test "n_number_0.e1" { +test "json.test.n_number_0.e1" { err( \\[0.e1] ); } -test "n_number_0e" { +test "json.test.n_number_0e" { err( \\[0e] ); } -test "n_number_0e+" { +test "json.test.n_number_0e+" { err( \\[0e+] ); } -test "n_number_1_000" { +test "json.test.n_number_1_000" { err( \\[1 000.0] ); } -test "n_number_1.0e-" { +test "json.test.n_number_1.0e-" { err( \\[1.0e-] ); } -test "n_number_1.0e" { +test "json.test.n_number_1.0e" { err( \\[1.0e] ); } -test "n_number_1.0e+" { +test "json.test.n_number_1.0e+" { err( \\[1.0e+] ); } -test "n_number_-1.0." { +test "json.test.n_number_-1.0." { err( \\[-1.0.] ); } -test "n_number_1eE2" { +test "json.test.n_number_1eE2" { err( \\[1eE2] ); } -test "n_number_.-1" { +test "json.test.n_number_.-1" { err( \\[.-1] ); } -test "n_number_+1" { +test "json.test.n_number_+1" { err( \\[+1] ); } -test "n_number_.2e-3" { +test "json.test.n_number_.2e-3" { err( \\[.2e-3] ); } -test "n_number_2.e-3" { +test "json.test.n_number_2.e-3" { err( \\[2.e-3] ); } -test "n_number_2.e+3" { +test "json.test.n_number_2.e+3" { err( \\[2.e+3] ); } -test "n_number_2.e3" { +test "json.test.n_number_2.e3" { err( \\[2.e3] ); } -test "n_number_-2." { +test "json.test.n_number_-2." { err( \\[-2.] ); } -test "n_number_9.e+" { +test "json.test.n_number_9.e+" { err( \\[9.e+] ); } -test "n_number_expression" { +test "json.test.n_number_expression" { err( \\[1+2] ); } -test "n_number_hex_1_digit" { +test "json.test.n_number_hex_1_digit" { err( \\[0x1] ); } -test "n_number_hex_2_digits" { +test "json.test.n_number_hex_2_digits" { err( \\[0x42] ); } -test "n_number_infinity" { +test "json.test.n_number_infinity" { err( \\[Infinity] ); } -test "n_number_+Inf" { +test "json.test.n_number_+Inf" { err( \\[+Inf] ); } -test "n_number_Inf" { +test "json.test.n_number_Inf" { err( \\[Inf] ); } -test "n_number_invalid+-" { +test "json.test.n_number_invalid+-" { err( \\[0e+-1] ); } -test "n_number_invalid-negative-real" { +test "json.test.n_number_invalid-negative-real" { err( \\[-123.123foo] ); } -test "n_number_invalid-utf-8-in-bigger-int" { +test "json.test.n_number_invalid-utf-8-in-bigger-int" { err( \\[123å] ); } -test "n_number_invalid-utf-8-in-exponent" { +test "json.test.n_number_invalid-utf-8-in-exponent" { err( \\[1e1å] ); } -test "n_number_invalid-utf-8-in-int" { +test "json.test.n_number_invalid-utf-8-in-int" { err( \\[0å] ); } -test "n_number_++" { +test "json.test.n_number_++" { err( \\[++1234] ); } -test "n_number_minus_infinity" { +test "json.test.n_number_minus_infinity" { err( \\[-Infinity] ); } -test "n_number_minus_sign_with_trailing_garbage" { +test "json.test.n_number_minus_sign_with_trailing_garbage" { err( \\[-foo] ); } -test "n_number_minus_space_1" { +test "json.test.n_number_minus_space_1" { err( \\[- 1] ); } -test "n_number_-NaN" { +test "json.test.n_number_-NaN" { err( \\[-NaN] ); } -test "n_number_NaN" { +test "json.test.n_number_NaN" { err( \\[NaN] ); } -test "n_number_neg_int_starting_with_zero" { +test "json.test.n_number_neg_int_starting_with_zero" { err( \\[-012] ); } -test "n_number_neg_real_without_int_part" { +test "json.test.n_number_neg_real_without_int_part" { err( \\[-.123] ); } -test "n_number_neg_with_garbage_at_end" { +test "json.test.n_number_neg_with_garbage_at_end" { err( \\[-1x] ); } -test "n_number_real_garbage_after_e" { +test "json.test.n_number_real_garbage_after_e" { err( \\[1ea] ); } -test "n_number_real_with_invalid_utf8_after_e" { +test "json.test.n_number_real_with_invalid_utf8_after_e" { err( \\[1eå] ); } -test "n_number_real_without_fractional_part" { +test "json.test.n_number_real_without_fractional_part" { err( \\[1.] ); } -test "n_number_starting_with_dot" { +test "json.test.n_number_starting_with_dot" { err( \\[.123] ); } -test "n_number_U+FF11_fullwidth_digit_one" { +test "json.test.n_number_U+FF11_fullwidth_digit_one" { err( \\[1] ); } -test "n_number_with_alpha_char" { +test "json.test.n_number_with_alpha_char" { err( \\[1.8011670033376514H-308] ); } -test "n_number_with_alpha" { +test "json.test.n_number_with_alpha" { err( \\[1.2a-3] ); } -test "n_number_with_leading_zero" { +test "json.test.n_number_with_leading_zero" { err( \\[012] ); } -test "n_object_bad_value" { +test "json.test.n_object_bad_value" { err( \\["x", truth] ); } -test "n_object_bracket_key" { +test "json.test.n_object_bracket_key" { err( \\{[: "x"} ); } -test "n_object_comma_instead_of_colon" { +test "json.test.n_object_comma_instead_of_colon" { err( \\{"x", null} ); } -test "n_object_double_colon" { +test "json.test.n_object_double_colon" { err( \\{"x"::"b"} ); } -test "n_object_emoji" { +test "json.test.n_object_emoji" { err( \\{🇨🇭} ); } -test "n_object_garbage_at_end" { +test "json.test.n_object_garbage_at_end" { err( \\{"a":"a" 123} ); } -test "n_object_key_with_single_quotes" { +test "json.test.n_object_key_with_single_quotes" { err( \\{key: 'value'} ); } -test "n_object_lone_continuation_byte_in_key_and_trailing_comma" { +test "json.test.n_object_lone_continuation_byte_in_key_and_trailing_comma" { err( \\{"¹":"0",} ); } -test "n_object_missing_colon" { +test "json.test.n_object_missing_colon" { err( \\{"a" b} ); } -test "n_object_missing_key" { +test "json.test.n_object_missing_key" { err( \\{:"b"} ); } -test "n_object_missing_semicolon" { +test "json.test.n_object_missing_semicolon" { err( \\{"a" "b"} ); } -test "n_object_missing_value" { +test "json.test.n_object_missing_value" { err( \\{"a": ); } -test "n_object_no-colon" { +test "json.test.n_object_no-colon" { err( \\{"a" ); } -test "n_object_non_string_key_but_huge_number_instead" { +test "json.test.n_object_non_string_key_but_huge_number_instead" { err( \\{9999E9999:1} ); } -test "n_object_non_string_key" { +test "json.test.n_object_non_string_key" { err( \\{1:1} ); } -test "n_object_repeated_null_null" { +test "json.test.n_object_repeated_null_null" { err( \\{null:null,null:null} ); } -test "n_object_several_trailing_commas" { +test "json.test.n_object_several_trailing_commas" { err( \\{"id":0,,,,,} ); } -test "n_object_single_quote" { +test "json.test.n_object_single_quote" { err( \\{'a':0} ); } -test "n_object_trailing_comma" { +test "json.test.n_object_trailing_comma" { err( \\{"id":0,} ); } -test "n_object_trailing_comment" { +test "json.test.n_object_trailing_comment" { err( \\{"a":"b"}/**/ ); } -test "n_object_trailing_comment_open" { +test "json.test.n_object_trailing_comment_open" { err( \\{"a":"b"}/**// ); } -test "n_object_trailing_comment_slash_open_incomplete" { +test "json.test.n_object_trailing_comment_slash_open_incomplete" { err( \\{"a":"b"}/ ); } -test "n_object_trailing_comment_slash_open" { +test "json.test.n_object_trailing_comment_slash_open" { err( \\{"a":"b"}// ); } -test "n_object_two_commas_in_a_row" { +test "json.test.n_object_two_commas_in_a_row" { err( \\{"a":"b",,"c":"d"} ); } -test "n_object_unquoted_key" { +test "json.test.n_object_unquoted_key" { err( \\{a: "b"} ); } -test "n_object_unterminated-value" { +test "json.test.n_object_unterminated-value" { err( \\{"a":"a ); } -test "n_object_with_single_string" { +test "json.test.n_object_with_single_string" { err( \\{ "foo" : "bar", "a" } ); } -test "n_object_with_trailing_garbage" { +test "json.test.n_object_with_trailing_garbage" { err( \\{"a":"b"}# ); } -test "n_single_space" { +test "json.test.n_single_space" { err(" "); } -test "n_string_1_surrogate_then_escape" { +test "json.test.n_string_1_surrogate_then_escape" { err( \\["\uD800\"] ); } -test "n_string_1_surrogate_then_escape_u1" { +test "json.test.n_string_1_surrogate_then_escape_u1" { err( \\["\uD800\u1"] ); } -test "n_string_1_surrogate_then_escape_u1x" { +test "json.test.n_string_1_surrogate_then_escape_u1x" { err( \\["\uD800\u1x"] ); } -test "n_string_1_surrogate_then_escape_u" { +test "json.test.n_string_1_surrogate_then_escape_u" { err( \\["\uD800\u"] ); } -test "n_string_accentuated_char_no_quotes" { +test "json.test.n_string_accentuated_char_no_quotes" { err( \\[é] ); } -test "n_string_backslash_00" { +test "json.test.n_string_backslash_00" { err("[\"\x00\"]"); } -test "n_string_escaped_backslash_bad" { +test "json.test.n_string_escaped_backslash_bad" { err( \\["\\\"] ); } -test "n_string_escaped_ctrl_char_tab" { +test "json.test.n_string_escaped_ctrl_char_tab" { err("\x5b\x22\x5c\x09\x22\x5d"); } -test "n_string_escaped_emoji" { +test "json.test.n_string_escaped_emoji" { err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]"); } -test "n_string_escape_x" { +test "json.test.n_string_escape_x" { err( \\["\x00"] ); } -test "n_string_incomplete_escaped_character" { +test "json.test.n_string_incomplete_escaped_character" { err( \\["\u00A"] ); } -test "n_string_incomplete_escape" { +test "json.test.n_string_incomplete_escape" { err( \\["\"] ); } -test "n_string_incomplete_surrogate_escape_invalid" { +test "json.test.n_string_incomplete_surrogate_escape_invalid" { err( \\["\uD800\uD800\x"] ); } -test "n_string_incomplete_surrogate" { +test "json.test.n_string_incomplete_surrogate" { err( \\["\uD834\uDd"] ); } -test "n_string_invalid_backslash_esc" { +test "json.test.n_string_invalid_backslash_esc" { err( \\["\a"] ); } -test "n_string_invalid_unicode_escape" { +test "json.test.n_string_invalid_unicode_escape" { err( \\["\uqqqq"] ); } -test "n_string_invalid_utf8_after_escape" { +test "json.test.n_string_invalid_utf8_after_escape" { err("[\"\\\x75\xc3\xa5\"]"); } -test "n_string_invalid-utf-8-in-escape" { +test "json.test.n_string_invalid-utf-8-in-escape" { err( \\["\uå"] ); } -test "n_string_leading_uescaped_thinspace" { +test "json.test.n_string_leading_uescaped_thinspace" { err( \\[\u0020"asd"] ); } -test "n_string_no_quotes_with_bad_escape" { +test "json.test.n_string_no_quotes_with_bad_escape" { err( \\[\n] ); } -test "n_string_single_doublequote" { +test "json.test.n_string_single_doublequote" { err( \\" ); } -test "n_string_single_quote" { +test "json.test.n_string_single_quote" { err( \\['single quote'] ); } -test "n_string_single_string_no_double_quotes" { +test "json.test.n_string_single_string_no_double_quotes" { err( \\abc ); } -test "n_string_start_escape_unclosed" { +test "json.test.n_string_start_escape_unclosed" { err( \\["\ ); } -test "n_string_unescaped_crtl_char" { +test "json.test.n_string_unescaped_crtl_char" { err("[\"a\x00a\"]"); } -test "n_string_unescaped_newline" { +test "json.test.n_string_unescaped_newline" { err( \\["new \\line"] ); } -test "n_string_unescaped_tab" { +test "json.test.n_string_unescaped_tab" { err("[\"\t\"]"); } -test "n_string_unicode_CapitalU" { +test "json.test.n_string_unicode_CapitalU" { err( \\"\UA66D" ); } -test "n_string_with_trailing_garbage" { +test "json.test.n_string_with_trailing_garbage" { err( \\""x ); } -test "n_structure_100000_opening_arrays" { +test "json.test.n_structure_100000_opening_arrays" { err("[" ** 100000); } -test "n_structure_angle_bracket_." { +test "json.test.n_structure_angle_bracket_." { err( \\<.> ); } -test "n_structure_angle_bracket_null" { +test "json.test.n_structure_angle_bracket_null" { err( \\[] ); } -test "n_structure_array_trailing_garbage" { +test "json.test.n_structure_array_trailing_garbage" { err( \\[1]x ); } -test "n_structure_array_with_extra_array_close" { +test "json.test.n_structure_array_with_extra_array_close" { err( \\[1]] ); } -test "n_structure_array_with_unclosed_string" { +test "json.test.n_structure_array_with_unclosed_string" { err( \\["asd] ); } -test "n_structure_ascii-unicode-identifier" { +test "json.test.n_structure_ascii-unicode-identifier" { err( \\aÃ¥ ); } -test "n_structure_capitalized_True" { +test "json.test.n_structure_capitalized_True" { err( \\[True] ); } -test "n_structure_close_unopened_array" { +test "json.test.n_structure_close_unopened_array" { err( \\1] ); } -test "n_structure_comma_instead_of_closing_brace" { +test "json.test.n_structure_comma_instead_of_closing_brace" { err( \\{"x": true, ); } -test "n_structure_double_array" { +test "json.test.n_structure_double_array" { err( \\[][] ); } -test "n_structure_end_array" { +test "json.test.n_structure_end_array" { err( \\] ); } -test "n_structure_incomplete_UTF8_BOM" { +test "json.test.n_structure_incomplete_UTF8_BOM" { err( \\ï»{} ); } -test "n_structure_lone-invalid-utf-8" { +test "json.test.n_structure_lone-invalid-utf-8" { err( \\å ); } -test "n_structure_lone-open-bracket" { +test "json.test.n_structure_lone-open-bracket" { err( \\[ ); } -test "n_structure_no_data" { +test "json.test.n_structure_no_data" { err( \\ ); } -test "n_structure_null-byte-outside-string" { +test "json.test.n_structure_null-byte-outside-string" { err("[\x00]"); } -test "n_structure_number_with_trailing_garbage" { +test "json.test.n_structure_number_with_trailing_garbage" { err( \\2@ ); } -test "n_structure_object_followed_by_closing_object" { +test "json.test.n_structure_object_followed_by_closing_object" { err( \\{}} ); } -test "n_structure_object_unclosed_no_value" { +test "json.test.n_structure_object_unclosed_no_value" { err( \\{"": ); } -test "n_structure_object_with_comment" { +test "json.test.n_structure_object_with_comment" { err( \\{"a":/*comment*/"b"} ); } -test "n_structure_object_with_trailing_garbage" { +test "json.test.n_structure_object_with_trailing_garbage" { err( \\{"a": true} "x" ); } -test "n_structure_open_array_apostrophe" { +test "json.test.n_structure_open_array_apostrophe" { err( \\[' ); } -test "n_structure_open_array_comma" { +test "json.test.n_structure_open_array_comma" { err( \\[, ); } -test "n_structure_open_array_object" { +test "json.test.n_structure_open_array_object" { err("[{\"\":" ** 50000); } -test "n_structure_open_array_open_object" { +test "json.test.n_structure_open_array_open_object" { err( \\[{ ); } -test "n_structure_open_array_open_string" { +test "json.test.n_structure_open_array_open_string" { err( \\["a ); } -test "n_structure_open_array_string" { +test "json.test.n_structure_open_array_string" { err( \\["a" ); } -test "n_structure_open_object_close_array" { +test "json.test.n_structure_open_object_close_array" { err( \\{] ); } -test "n_structure_open_object_comma" { +test "json.test.n_structure_open_object_comma" { err( \\{, ); } -test "n_structure_open_object" { +test "json.test.n_structure_open_object" { err( \\{ ); } -test "n_structure_open_object_open_array" { +test "json.test.n_structure_open_object_open_array" { err( \\{[ ); } -test "n_structure_open_object_open_string" { +test "json.test.n_structure_open_object_open_string" { err( \\{"a ); } -test "n_structure_open_object_string_with_apostrophes" { +test "json.test.n_structure_open_object_string_with_apostrophes" { err( \\{'a' ); } -test "n_structure_open_open" { +test "json.test.n_structure_open_open" { err( \\["\{["\{["\{["\{ ); } -test "n_structure_single_eacute" { +test "json.test.n_structure_single_eacute" { err( \\é ); } -test "n_structure_single_star" { +test "json.test.n_structure_single_star" { err( \\* ); } -test "n_structure_trailing_#" { +test "json.test.n_structure_trailing_#" { err( \\{"a":"b"}#{} ); } -test "n_structure_U+2060_word_joined" { +test "json.test.n_structure_U+2060_word_joined" { err( \\[⁠] ); } -test "n_structure_uescaped_LF_before_string" { +test "json.test.n_structure_uescaped_LF_before_string" { err( \\[\u000A""] ); } -test "n_structure_unclosed_array" { +test "json.test.n_structure_unclosed_array" { err( \\[1 ); } -test "n_structure_unclosed_array_partial_null" { +test "json.test.n_structure_unclosed_array_partial_null" { err( \\[ false, nul ); } -test "n_structure_unclosed_array_unfinished_false" { +test "json.test.n_structure_unclosed_array_unfinished_false" { err( \\[ true, fals ); } -test "n_structure_unclosed_array_unfinished_true" { +test "json.test.n_structure_unclosed_array_unfinished_true" { err( \\[ false, tru ); } -test "n_structure_unclosed_object" { +test "json.test.n_structure_unclosed_object" { err( \\{"asd":"asd" ); } -test "n_structure_unicode-identifier" { +test "json.test.n_structure_unicode-identifier" { err( \\Ã¥ ); } -test "n_structure_UTF8_BOM_no_data" { +test "json.test.n_structure_UTF8_BOM_no_data" { err( \\ ); } -test "n_structure_whitespace_formfeed" { +test "json.test.n_structure_whitespace_formfeed" { err("[\x0c]"); } -test "n_structure_whitespace_U+2060_word_joiner" { +test "json.test.n_structure_whitespace_U+2060_word_joiner" { err( \\[⁠] ); @@ -1701,203 +1701,203 @@ test "n_structure_whitespace_U+2060_word_joiner" { //////////////////////////////////////////////////////////////////////////////////////////////////// -test "i_number_double_huge_neg_exp" { +test "json.test.i_number_double_huge_neg_exp" { any( \\[123.456e-789] ); } -test "i_number_huge_exp" { +test "json.test.i_number_huge_exp" { any( \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] ); } -test "i_number_neg_int_huge_exp" { +test "json.test.i_number_neg_int_huge_exp" { any( \\[-1e+9999] ); } -test "i_number_pos_double_huge_exp" { +test "json.test.i_number_pos_double_huge_exp" { any( \\[1.5e+9999] ); } -test "i_number_real_neg_overflow" { +test "json.test.i_number_real_neg_overflow" { any( \\[-123123e100000] ); } -test "i_number_real_pos_overflow" { +test "json.test.i_number_real_pos_overflow" { any( \\[123123e100000] ); } -test "i_number_real_underflow" { +test "json.test.i_number_real_underflow" { any( \\[123e-10000000] ); } -test "i_number_too_big_neg_int" { +test "json.test.i_number_too_big_neg_int" { any( \\[-123123123123123123123123123123] ); } -test "i_number_too_big_pos_int" { +test "json.test.i_number_too_big_pos_int" { any( \\[100000000000000000000] ); } -test "i_number_very_big_negative_int" { +test "json.test.i_number_very_big_negative_int" { any( \\[-237462374673276894279832749832423479823246327846] ); } -test "i_object_key_lone_2nd_surrogate" { +test "json.test.i_object_key_lone_2nd_surrogate" { any( \\{"\uDFAA":0} ); } -test "i_string_1st_surrogate_but_2nd_missing" { +test "json.test.i_string_1st_surrogate_but_2nd_missing" { any( \\["\uDADA"] ); } -test "i_string_1st_valid_surrogate_2nd_invalid" { +test "json.test.i_string_1st_valid_surrogate_2nd_invalid" { any( \\["\uD888\u1234"] ); } -test "i_string_incomplete_surrogate_and_escape_valid" { +test "json.test.i_string_incomplete_surrogate_and_escape_valid" { any( \\["\uD800\n"] ); } -test "i_string_incomplete_surrogate_pair" { +test "json.test.i_string_incomplete_surrogate_pair" { any( \\["\uDd1ea"] ); } -test "i_string_incomplete_surrogates_escape_valid" { +test "json.test.i_string_incomplete_surrogates_escape_valid" { any( \\["\uD800\uD800\n"] ); } -test "i_string_invalid_lonely_surrogate" { +test "json.test.i_string_invalid_lonely_surrogate" { any( \\["\ud800"] ); } -test "i_string_invalid_surrogate" { +test "json.test.i_string_invalid_surrogate" { any( \\["\ud800abc"] ); } -test "i_string_invalid_utf-8" { +test "json.test.i_string_invalid_utf-8" { any( \\["ÿ"] ); } -test "i_string_inverted_surrogates_U+1D11E" { +test "json.test.i_string_inverted_surrogates_U+1D11E" { any( \\["\uDd1e\uD834"] ); } -test "i_string_iso_latin_1" { +test "json.test.i_string_iso_latin_1" { any( \\["é"] ); } -test "i_string_lone_second_surrogate" { +test "json.test.i_string_lone_second_surrogate" { any( \\["\uDFAA"] ); } -test "i_string_lone_utf8_continuation_byte" { +test "json.test.i_string_lone_utf8_continuation_byte" { any( \\[""] ); } -test "i_string_not_in_unicode_range" { +test "json.test.i_string_not_in_unicode_range" { any( \\["ô¿¿¿"] ); } -test "i_string_overlong_sequence_2_bytes" { +test "json.test.i_string_overlong_sequence_2_bytes" { any( \\["À¯"] ); } -test "i_string_overlong_sequence_6_bytes" { +test "json.test.i_string_overlong_sequence_6_bytes" { any( \\["üƒ¿¿¿¿"] ); } -test "i_string_overlong_sequence_6_bytes_null" { +test "json.test.i_string_overlong_sequence_6_bytes_null" { any( \\["ü€€€€€"] ); } -test "i_string_truncated-utf-8" { +test "json.test.i_string_truncated-utf-8" { any( \\["àÿ"] ); } -test "i_string_utf16BE_no_BOM" { +test "json.test.i_string_utf16BE_no_BOM" { any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d"); } -test "i_string_utf16LE_no_BOM" { +test "json.test.i_string_utf16LE_no_BOM" { any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); } -test "i_string_UTF-16LE_with_BOM" { +test "json.test.i_string_UTF-16LE_with_BOM" { any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); } -test "i_string_UTF-8_invalid_sequence" { +test "json.test.i_string_UTF-8_invalid_sequence" { any( \\["日шú"] ); } -test "i_string_UTF8_surrogate_U+D800" { +test "json.test.i_string_UTF8_surrogate_U+D800" { any( \\["í €"] ); } -test "i_structure_500_nested_arrays" { +test "json.test.i_structure_500_nested_arrays" { any(("[" ** 500) ++ ("]" ** 500)); } -test "i_structure_UTF-8_BOM_empty_object" { +test "json.test.i_structure_UTF-8_BOM_empty_object" { any( \\{} ); From a69695a28c418924a13e2b8bd370fa3b86fef596 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Wed, 21 Nov 2018 00:38:25 +0900 Subject: [PATCH 034/110] std/mem: writeIntLE: buf.* to buf; --- std/mem.zig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/std/mem.zig b/std/mem.zig index 6b37dfe40..005d88791 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -546,9 +546,7 @@ pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { buf[0] = bits; return; } - // FIXME: this should just be for (buf). - // See https://github.com/ziglang/zig/issues/1663 - for (buf.*) |*b| { + for (buf) |*b| { b.* = @truncate(u8, bits); bits >>= 8; } From bb3ac177a83caf52556818e9ea163ac166bb6c07 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 20 Nov 2018 12:37:42 -0500 Subject: [PATCH 035/110] fix incorrect buf len --- std/os/path.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/path.zig b/std/os/path.zig index 4ef7f3eff..e2ef150ba 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1192,7 +1192,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0); defer os.close(fd); - var buf: ["/dev/fd/-2147483648".len]u8 = undefined; + var buf: ["/dev/fd/-2147483648\x00".len]u8 = undefined; const proc_path = fmt.bufPrint(buf[0..], "/dev/fd/{}\x00", fd) catch unreachable; return os.readLinkC(out_buffer, proc_path.ptr); From b953e322a857e58df2209ca7ae9e965b9e768887 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 21 Nov 2018 13:41:10 -0500 Subject: [PATCH 036/110] std.os.path.realC: make overflow more clearly impossible --- std/os/path.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/path.zig b/std/os/path.zig index b3cfec1a3..0d636353a 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1183,7 +1183,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0); defer os.close(fd); - var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined; + var buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable; return os.readLinkC(out_buffer, proc_path.ptr); From 56a8f2b018a6ee1f1116a64d34803511a6fbad80 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 24 Nov 2018 14:36:16 -0500 Subject: [PATCH 037/110] fix @intCast not catching negative numbers to unsigned --- src/codegen.cpp | 2 +- std/os/linux/index.zig | 103 ++++++++++++++++++++++------------------ test/runtime_safety.zig | 10 ++++ 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 40f71e38f..096552037 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1645,7 +1645,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z zig_unreachable(); } - if (actual_bits >= wanted_bits && actual_type->id == ZigTypeIdInt && + if (actual_type->id == ZigTypeIdInt && !wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed && want_runtime_safety) { diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig index bfa046ba0..ec9075516 100644 --- a/std/os/linux/index.zig +++ b/std/os/linux/index.zig @@ -703,7 +703,7 @@ pub fn dup2(old: i32, new: i32) usize { } pub fn dup3(old: i32, new: i32, flags: u32) usize { - return syscall3(SYS_dup3, @intCast(usize, old), @intCast(usize, new), flags); + return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags); } // TODO https://github.com/ziglang/zig/issues/265 @@ -747,7 +747,7 @@ pub fn getcwd(buf: [*]u8, size: usize) usize { } pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize { - return syscall3(SYS_getdents64, @intCast(usize, fd), @ptrToInt(dirp), count); + return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); } pub fn inotify_init1(flags: u32) usize { @@ -755,16 +755,16 @@ pub fn inotify_init1(flags: u32) usize { } pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize { - return syscall3(SYS_inotify_add_watch, @intCast(usize, fd), @ptrToInt(pathname), mask); + return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask); } pub fn inotify_rm_watch(fd: i32, wd: i32) usize { - return syscall2(SYS_inotify_rm_watch, @intCast(usize, fd), @intCast(usize, wd)); + return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd))); } pub fn isatty(fd: i32) bool { var wsz: winsize = undefined; - return syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; + return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } // TODO https://github.com/ziglang/zig/issues/265 @@ -774,7 +774,7 @@ pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usiz // TODO https://github.com/ziglang/zig/issues/265 pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { - return syscall4(SYS_readlinkat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); + return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); } // TODO https://github.com/ziglang/zig/issues/265 @@ -784,7 +784,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize { - return syscall3(SYS_mkdirat, @intCast(usize, dirfd), @ptrToInt(path), mode); + return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); } // TODO https://github.com/ziglang/zig/issues/265 @@ -803,7 +803,7 @@ pub fn umount2(special: [*]const u8, flags: u32) usize { } pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { - return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset)); + return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); } pub fn munmap(address: usize, length: usize) usize { @@ -811,23 +811,23 @@ pub fn munmap(address: usize, length: usize) usize { } pub fn read(fd: i32, buf: [*]u8, count: usize) usize { - return syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count); + return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize { - return syscall4(SYS_preadv, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize { - return syscall3(SYS_readv, @intCast(usize, fd), @ptrToInt(iov), count); + return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); } pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize { - return syscall3(SYS_writev, @intCast(usize, fd), @ptrToInt(iov), count); + return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); } pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize { - return syscall4(SYS_pwritev, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } // TODO https://github.com/ziglang/zig/issues/265 @@ -842,12 +842,12 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize { - return syscall3(SYS_symlinkat, @ptrToInt(existing), @intCast(usize, newfd), @ptrToInt(newpath)); + return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath)); } // TODO https://github.com/ziglang/zig/issues/265 pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } // TODO https://github.com/ziglang/zig/issues/265 @@ -856,7 +856,7 @@ pub fn access(path: [*]const u8, mode: u32) usize { } pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize { - return syscall3(SYS_faccessat, @intCast(usize, dirfd), @ptrToInt(path), mode); + return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); } pub fn pipe(fd: *[2]i32) usize { @@ -868,11 +868,11 @@ pub fn pipe2(fd: *[2]i32, flags: u32) usize { } pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { - return syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count); + return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { - return syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } // TODO https://github.com/ziglang/zig/issues/265 @@ -882,7 +882,7 @@ pub fn rename(old: [*]const u8, new: [*]const u8) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize { - return syscall5(SYS_renameat2, @intCast(usize, oldfd), @ptrToInt(oldpath), @intCast(usize, newfd), @ptrToInt(newpath), flags); + return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags); } // TODO https://github.com/ziglang/zig/issues/265 @@ -897,7 +897,8 @@ pub fn create(path: [*]const u8, perm: usize) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize { - return syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode); + // dirfd could be negative, for example AT_FDCWD is -100 + return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); } /// See also `clone` (from the arch-specific include) @@ -911,11 +912,11 @@ pub fn clone2(flags: u32, child_stack_ptr: usize) usize { } pub fn close(fd: i32) usize { - return syscall1(SYS_close, @intCast(usize, fd)); + return syscall1(SYS_close, @bitCast(usize, isize(fd))); } pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { - return syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos); + return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); } pub fn exit(status: i32) noreturn { @@ -933,7 +934,7 @@ pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { } pub fn kill(pid: i32, sig: i32) usize { - return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @intCast(usize, sig)); + return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); } // TODO https://github.com/ziglang/zig/issues/265 @@ -943,7 +944,7 @@ pub fn unlink(path: [*]const u8) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize { - return syscall3(SYS_unlinkat, @intCast(usize, dirfd), @ptrToInt(path), flags); + return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags); } pub fn waitpid(pid: i32, status: *i32, options: i32) usize { @@ -1120,8 +1121,8 @@ pub const empty_sigset = []usize{0} ** sigset_t.len; pub fn raise(sig: i32) usize { var set: sigset_t = undefined; blockAppSignals(&set); - const tid = @intCast(i32, syscall0(SYS_gettid)); - const ret = syscall2(SYS_tkill, @intCast(usize, tid), @intCast(usize, sig)); + const tid = syscall0(SYS_gettid); + const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig))); restoreSignals(&set); return ret; } @@ -1189,11 +1190,11 @@ pub const iovec_const = extern struct { }; pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { - return syscall3(SYS_getsockname, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len)); + return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); } pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { - return syscall3(SYS_getpeername, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len)); + return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); } pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { @@ -1201,47 +1202,47 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { } pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { - return syscall5(SYS_setsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); + return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); } pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { - return syscall5(SYS_getsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); + return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); } pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize { - return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags); + return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); } pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { - return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), len); + return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len); } pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { - return syscall3(SYS_recvmsg, @intCast(usize, fd), @ptrToInt(msg), flags); + return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); } pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { - return syscall6(SYS_recvfrom, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); + return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); } pub fn shutdown(fd: i32, how: i32) usize { - return syscall2(SYS_shutdown, @intCast(usize, fd), @intCast(usize, how)); + return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how))); } pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { - return syscall3(SYS_bind, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len)); + return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len)); } pub fn listen(fd: i32, backlog: u32) usize { - return syscall2(SYS_listen, @intCast(usize, fd), backlog); + return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog); } pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { - return syscall6(SYS_sendto, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); + return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); } pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { - return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(*fd[0])); + return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); } pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { @@ -1249,11 +1250,11 @@ pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { } pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize { - return syscall4(SYS_accept4, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len), flags); + return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags); } pub fn fstat(fd: i32, stat_buf: *Stat) usize { - return syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); + return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); } // TODO https://github.com/ziglang/zig/issues/265 @@ -1268,7 +1269,7 @@ pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize { - return syscall4(SYS_fstatat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(stat_buf), flags); + return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); } // TODO https://github.com/ziglang/zig/issues/265 @@ -1355,7 +1356,7 @@ pub fn epoll_create1(flags: usize) usize { } pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize { - return syscall4(SYS_epoll_ctl, @intCast(usize, epoll_fd), @intCast(usize, op), @intCast(usize, fd), @ptrToInt(ev)); + return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev)); } pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize { @@ -1363,7 +1364,15 @@ pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout } pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize { - return syscall6(SYS_epoll_pwait, @intCast(usize, epoll_fd), @ptrToInt(events), @intCast(usize, maxevents), @intCast(usize, timeout), @ptrToInt(sigmask), @sizeOf(sigset_t)); + return syscall6( + SYS_epoll_pwait, + @bitCast(usize, isize(epoll_fd)), + @ptrToInt(events), + @intCast(usize, maxevents), + @bitCast(usize, isize(timeout)), + @ptrToInt(sigmask), + @sizeOf(sigset_t), + ); } pub fn eventfd(count: u32, flags: u32) usize { @@ -1371,7 +1380,7 @@ pub fn eventfd(count: u32, flags: u32) usize { } pub fn timerfd_create(clockid: i32, flags: u32) usize { - return syscall2(SYS_timerfd_create, @intCast(usize, clockid), flags); + return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags); } pub const itimerspec = extern struct { @@ -1380,11 +1389,11 @@ pub const itimerspec = extern struct { }; pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize { - return syscall2(SYS_timerfd_gettime, @intCast(usize, fd), @ptrToInt(curr_value)); + return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value)); } pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize { - return syscall4(SYS_timerfd_settime, @intCast(usize, fd), flags, @ptrToInt(new_value), @ptrToInt(old_value)); + return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value)); } pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330; diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 343b3ff59..7c13f5b6f 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -275,6 +275,16 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} ); + cases.addRuntimeSafety("signed integer not fitting in cast to unsigned integer - widening", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() void { + \\ var value: c_short = -1; + \\ var casted = @intCast(u32, value); + \\} + ); + cases.addRuntimeSafety("unwrap error", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) { From 3d2752cc3677535ddfbeeefba4036633bcab01dc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 24 Nov 2018 16:15:58 -0500 Subject: [PATCH 038/110] refactor type_requires_comptime to have possible error fixes a compiler crash when building https://github.com/AndreaOrru/zen --- src/analyze.cpp | 85 +++++++++++++++++++++---------------- src/analyze.hpp | 8 +++- src/codegen.cpp | 10 ++++- src/ir.cpp | 110 ++++++++++++++++++++++++++++-------------------- 4 files changed, 129 insertions(+), 84 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 349169f9d..e5679a21d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1619,13 +1619,16 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: - if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) - return g->builtin_types.entry_invalid; - if (type_requires_comptime(type_entry)) { - add_node_error(g, param_node->data.param_decl.type, - buf_sprintf("parameter of type '%s' must be declared comptime", - buf_ptr(&type_entry->name))); - return g->builtin_types.entry_invalid; + switch (type_requires_comptime(g, type_entry)) { + case ReqCompTimeNo: + break; + case ReqCompTimeYes: + add_node_error(g, param_node->data.param_decl.type, + buf_sprintf("parameter of type '%s' must be declared comptime", + buf_ptr(&type_entry->name))); + return g->builtin_types.entry_invalid; + case ReqCompTimeInvalid: + return g->builtin_types.entry_invalid; } break; } @@ -1711,10 +1714,13 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: - if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusZeroBitsKnown))) - return g->builtin_types.entry_invalid; - if (type_requires_comptime(fn_type_id.return_type)) { - return get_generic_fn_type(g, &fn_type_id); + switch (type_requires_comptime(g, fn_type_id.return_type)) { + case ReqCompTimeInvalid: + return g->builtin_types.entry_invalid; + case ReqCompTimeYes: + return get_generic_fn_type(g, &fn_type_id); + case ReqCompTimeNo: + break; } break; } @@ -2560,8 +2566,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { assert(struct_type->id == ZigTypeIdStruct); - Error err; - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown) @@ -2619,13 +2623,15 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { buf_sprintf("enums, not structs, support field assignment")); } - if ((err = type_resolve(g, field_type, ResolveStatusZeroBitsKnown))) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - continue; - } - - if (type_requires_comptime(field_type)) { - struct_type->data.structure.requires_comptime = true; + switch (type_requires_comptime(g, field_type)) { + case ReqCompTimeYes: + struct_type->data.structure.requires_comptime = true; + break; + case ReqCompTimeInvalid: + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + continue; + case ReqCompTimeNo: + break; } if (!type_has_bits(field_type)) @@ -2890,11 +2896,17 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } union_field->type_entry = field_type; - if (type_requires_comptime(field_type)) { - union_type->data.unionation.requires_comptime = true; + switch (type_requires_comptime(g, field_type)) { + case ReqCompTimeInvalid: + union_type->data.unionation.is_invalid = true; + continue; + case ReqCompTimeYes: + union_type->data.unionation.requires_comptime = true; + break; + case ReqCompTimeNo: + break; } - if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, buf_sprintf("non-enum union field assignment")); @@ -5089,7 +5101,10 @@ bool type_has_bits(ZigType *type_entry) { return !type_entry->zero_bits; } -bool type_requires_comptime(ZigType *type_entry) { +ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { + Error err; + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) + return ReqCompTimeInvalid; switch (type_entry->id) { case ZigTypeIdInvalid: case ZigTypeIdOpaque: @@ -5102,27 +5117,25 @@ bool type_requires_comptime(ZigType *type_entry) { case ZigTypeIdNamespace: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: - return true; + return ReqCompTimeYes; case ZigTypeIdArray: - return type_requires_comptime(type_entry->data.array.child_type); + return type_requires_comptime(g, type_entry->data.array.child_type); case ZigTypeIdStruct: - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - return type_entry->data.structure.requires_comptime; + return type_entry->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdUnion: - assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown)); - return type_entry->data.unionation.requires_comptime; + return type_entry->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdOptional: - return type_requires_comptime(type_entry->data.maybe.child_type); + return type_requires_comptime(g, type_entry->data.maybe.child_type); case ZigTypeIdErrorUnion: - return type_requires_comptime(type_entry->data.error_union.payload_type); + return type_requires_comptime(g, type_entry->data.error_union.payload_type); case ZigTypeIdPointer: if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { - return false; + return ReqCompTimeNo; } else { - return type_requires_comptime(type_entry->data.pointer.child_type); + return type_requires_comptime(g, type_entry->data.pointer.child_type); } case ZigTypeIdFn: - return type_entry->data.fn.is_generic; + return type_entry->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; case ZigTypeIdEnum: case ZigTypeIdErrorSet: case ZigTypeIdBool: @@ -5131,7 +5144,7 @@ bool type_requires_comptime(ZigType *type_entry) { case ZigTypeIdVoid: case ZigTypeIdUnreachable: case ZigTypeIdPromise: - return false; + return ReqCompTimeNo; } zig_unreachable(); } diff --git a/src/analyze.hpp b/src/analyze.hpp index e727b050e..b506b533c 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -87,7 +87,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node); ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc); AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index); -bool type_requires_comptime(ZigType *type_entry); Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, ZigType *type_entry); Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status); void complete_enum(CodeGen *g, ZigType *enum_type); @@ -216,4 +215,11 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id); uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field); +enum ReqCompTime { + ReqCompTimeInvalid, + ReqCompTimeNo, + ReqCompTimeYes, +}; +ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 096552037..37e042496 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6281,8 +6281,14 @@ static void do_code_gen(CodeGen *g) { } if (ir_get_var_is_comptime(var)) continue; - if (type_requires_comptime(var->value->type)) - continue; + switch (type_requires_comptime(g, var->value->type)) { + case ReqCompTimeInvalid: + zig_unreachable(); + case ReqCompTimeYes: + continue; + case ReqCompTimeNo: + break; + } if (var->src_arg_index == SIZE_MAX) { var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); diff --git a/src/ir.cpp b/src/ir.cpp index a62da827b..1edb12267 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11276,7 +11276,6 @@ static bool optional_value_is_null(ConstExprValue *val) { } static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { - Error err; IrInstruction *op1 = bin_op_instruction->op1->child; if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; @@ -11470,10 +11469,19 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * if (casted_op2 == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, resolved_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_instruction; + bool requires_comptime; + switch (type_requires_comptime(ira->codegen, resolved_type)) { + case ReqCompTimeYes: + requires_comptime = true; + break; + case ReqCompTimeNo: + requires_comptime = false; + break; + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + } - bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type); + bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type); if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); if (op1_val == nullptr) @@ -12406,42 +12414,41 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct ZigType *result_type = casted_init_value->value.type; if (type_is_invalid(result_type)) { result_type = ira->codegen->builtin_types.entry_invalid; - } else { - if ((err = type_resolve(ira->codegen, result_type, ResolveStatusZeroBitsKnown))) { - result_type = ira->codegen->builtin_types.entry_invalid; - } + } else if (result_type->id == ZigTypeIdUnreachable || result_type->id == ZigTypeIdOpaque) { + ir_add_error_node(ira, source_node, + buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name))); + result_type = ira->codegen->builtin_types.entry_invalid; } - if (!type_is_invalid(result_type)) { - if (result_type->id == ZigTypeIdUnreachable || - result_type->id == ZigTypeIdOpaque) - { + switch (type_requires_comptime(ira->codegen, result_type)) { + case ReqCompTimeInvalid: + result_type = ira->codegen->builtin_types.entry_invalid; + break; + case ReqCompTimeYes: { + var_class_requires_const = true; + if (!var->gen_is_const && !is_comptime_var) { ir_add_error_node(ira, source_node, - buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name))); + buf_sprintf("variable of type '%s' must be const or comptime", + buf_ptr(&result_type->name))); result_type = ira->codegen->builtin_types.entry_invalid; - } else if (type_requires_comptime(result_type)) { + } + break; + } + case ReqCompTimeNo: + if (casted_init_value->value.special == ConstValSpecialStatic && + casted_init_value->value.type->id == ZigTypeIdFn && + casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) + { var_class_requires_const = true; - if (!var->gen_is_const && !is_comptime_var) { - ir_add_error_node(ira, source_node, - buf_sprintf("variable of type '%s' must be const or comptime", - buf_ptr(&result_type->name))); + if (!var->src_is_const && !is_comptime_var) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("functions marked inline must be stored in const or comptime var")); + AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node; + add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here")); result_type = ira->codegen->builtin_types.entry_invalid; } - } else { - if (casted_init_value->value.special == ConstValSpecialStatic && - casted_init_value->value.type->id == ZigTypeIdFn && - casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) - { - var_class_requires_const = true; - if (!var->src_is_const && !is_comptime_var) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("functions marked inline must be stored in const or comptime var")); - AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node; - add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here")); - result_type = ira->codegen->builtin_types.entry_invalid; - } - } } + break; } if (var->value->type != nullptr && !is_comptime_var) { @@ -12912,10 +12919,15 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod } if (!comptime_arg) { - if (type_requires_comptime(casted_arg->value.type)) { + switch (type_requires_comptime(ira->codegen, casted_arg->value.type)) { + case ReqCompTimeYes: ir_add_error(ira, casted_arg, buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name))); return false; + case ReqCompTimeInvalid: + return false; + case ReqCompTimeNo: + break; } casted_args[fn_type_id->param_count] = casted_arg; @@ -13388,12 +13400,15 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call inst_fn_type_id.return_type = specified_return_type; } - if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_instruction; - - if (type_requires_comptime(specified_return_type)) { + switch (type_requires_comptime(ira->codegen, specified_return_type)) { + case ReqCompTimeYes: // Throw out our work and call the function as if it were comptime. - return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto); + return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, + true, FnInlineAuto); + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeNo: + break; } } IrInstruction *async_allocator_inst = nullptr; @@ -14334,11 +14349,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } else { // runtime known element index - if (type_requires_comptime(return_type)) { + switch (type_requires_comptime(ira->codegen, return_type)) { + case ReqCompTimeYes: ir_add_error(ira, elem_index, buf_sprintf("values of type '%s' must be comptime known, but index value is runtime known", buf_ptr(&return_type->data.pointer.child_type->name))); return ira->codegen->invalid_instruction; + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeNo: + break; } if (ptr_align < abi_align) { if (elem_size >= ptr_align && elem_size % ptr_align == 0) { @@ -19390,7 +19410,6 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, } static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { - Error err; AstNode *proto_node = instruction->base.source_node; assert(proto_node->type == NodeTypeFnProto); @@ -19429,11 +19448,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct if (type_is_invalid(param_type_value->value.type)) return ira->codegen->invalid_instruction; ZigType *param_type = ir_resolve_type(ira, param_type_value); - if (type_is_invalid(param_type)) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, param_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_instruction; - if (type_requires_comptime(param_type)) { + switch (type_requires_comptime(ira->codegen, param_type)) { + case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { ir_add_error(ira, param_type_value, buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", @@ -19443,6 +19459,10 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct param_info->type = param_type; fn_type_id.next_param_index += 1; return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeNo: + break; } if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) { ir_add_error(ira, param_type_value, From 4d747d452fba0987332244c777dfd3a29d5a20bd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 24 Nov 2018 16:51:52 -0500 Subject: [PATCH 039/110] update zen os std lib for latest zig changes --- std/os/zen.zig | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/std/os/zen.zig b/std/os/zen.zig index 6ac480b89..76c4df9d6 100644 --- a/std/os/zen.zig +++ b/std/os/zen.zig @@ -12,20 +12,20 @@ pub const Message = struct { args: [5]usize, payload: ?[]const u8, - pub fn from(mailbox_id: *const MailboxId) Message { + pub fn from(mailbox_id: MailboxId) Message { return Message{ .sender = MailboxId.Undefined, - .receiver = mailbox_id.*, + .receiver = mailbox_id, .code = undefined, .args = undefined, .payload = null, }; } - pub fn to(mailbox_id: *const MailboxId, msg_code: usize, args: ...) Message { + pub fn to(mailbox_id: MailboxId, msg_code: usize, args: ...) Message { var message = Message{ .sender = MailboxId.This, - .receiver = mailbox_id.*, + .receiver = mailbox_id, .code = msg_code, .args = undefined, .payload = null, @@ -40,14 +40,14 @@ pub const Message = struct { return message; } - pub fn as(self: *const Message, sender: *const MailboxId) Message { - var message = self.*; - message.sender = sender.*; + pub fn as(self: Message, sender: MailboxId) Message { + var message = self; + message.sender = sender; return message; } - pub fn withPayload(self: *const Message, payload: []const u8) Message { - var message = self.*; + pub fn withPayload(self: Message, payload: []const u8) Message { + var message = self; message.payload = payload; return message; } @@ -93,7 +93,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize { STDIN_FILENO => { var i: usize = 0; while (i < count) : (i += 1) { - send(Message.to(Server.Keyboard, 0)); + send(&Message.to(Server.Keyboard, 0)); // FIXME: we should be certain that we are receiving from Keyboard. var message = Message.from(MailboxId.This); @@ -111,7 +111,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize { pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { switch (fd) { STDOUT_FILENO, STDERR_FILENO => { - send(Message.to(Server.Terminal, 1).withPayload(buf[0..count])); + send(&Message.to(Server.Terminal, 1).withPayload(buf[0..count])); }, else => unreachable, } From 1924ffa67d90f21852680b7c9a09df07fc218ebe Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 21 Nov 2018 17:33:37 -0500 Subject: [PATCH 040/110] better debiased random range implementation --- std/rand/index.zig | 74 +++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/std/rand/index.zig b/std/rand/index.zig index bb607a067..0d9e58fd8 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -69,22 +69,36 @@ pub const Random = struct { pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T { assert(T.is_signed == false); assert(0 < less_than); + // Small is typically u32 + const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); + // Large is typically u64 + const Large = @IntType(false, Small.bit_count * 2); - const last_group_size_minus_one: T = maxInt(T) % less_than; - if (last_group_size_minus_one == less_than - 1) { - // less_than is a power of two. - assert(math.floorPowerOfTwo(T, less_than) == less_than); - // There is no retry zone. The optimal retry_zone_start would be maxInt(T) + 1. - return r.int(T) % less_than; - } - const retry_zone_start = maxInt(T) - last_group_size_minus_one; + // adapted from: + // http://www.pcg-random.org/posts/bounded-rands.html + // "Lemire's (with an extra tweak from me)" + var x: Small = r.int(Small); + var m: Large = Large(x) * Large(less_than); + var l: Small = @truncate(Small, m); + if (l < less_than) { + // TODO: workaround for https://github.com/ziglang/zig/issues/1770 + // should be: + // var t: Small = -%less_than; + var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than))); - while (true) { - const rand_val = r.int(T); - if (rand_val < retry_zone_start) { - return rand_val % less_than; + if (t >= less_than) { + t -= less_than; + if (t >= less_than) { + t %= less_than; + } + } + while (l < t) { + x = r.int(Small); + m = Large(x) * Large(less_than); + l = @truncate(Small, m); } } + return @intCast(T, m >> Small.bit_count); } /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`. @@ -294,10 +308,19 @@ fn testRandomIntLessThan() void { var r = SequentialPrng.init(); r.next_value = 0xff; assert(r.random.uintLessThan(u8, 4) == 3); - r.next_value = 0xff; - assert(r.random.uintLessThan(u8, 3) == 0); + assert(r.next_value == 0); + assert(r.random.uintLessThan(u8, 4) == 0); assert(r.next_value == 1); + r.next_value = 0; + assert(r.random.uintLessThan(u64, 32) == 0); + + // trigger the bias rejection code path + r.next_value = 0; + assert(r.random.uintLessThan(u8, 3) == 0); + // verify we incremented twice + assert(r.next_value == 2); + r.next_value = 0xff; assert(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f); r.next_value = 0xff; @@ -310,17 +333,10 @@ fn testRandomIntLessThan() void { r.next_value = 0xff; assert(r.random.intRangeLessThan(i8, -0x80, 0) == -1); - r.next_value = 0xff; - assert(r.random.intRangeLessThan(i64, -0x8000000000000000, 0) == -1); r.next_value = 0xff; assert(r.random.intRangeLessThan(i3, -4, 0) == -1); r.next_value = 0xff; assert(r.random.intRangeLessThan(i3, -2, 2) == 1); - - // test retrying and eventually getting a good value - // start just out of bounds - r.next_value = 0x81; - assert(r.random.uintLessThan(u8, 0x81) == 0); } test "Random intAtMost" { @@ -332,9 +348,14 @@ fn testRandomIntAtMost() void { var r = SequentialPrng.init(); r.next_value = 0xff; assert(r.random.uintAtMost(u8, 3) == 3); - r.next_value = 0xff; + assert(r.next_value == 0); + assert(r.random.uintAtMost(u8, 3) == 0); + + // trigger the bias rejection code path + r.next_value = 0; assert(r.random.uintAtMost(u8, 2) == 0); - assert(r.next_value == 1); + // verify we incremented twice + assert(r.next_value == 2); r.next_value = 0xff; assert(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f); @@ -348,17 +369,10 @@ fn testRandomIntAtMost() void { r.next_value = 0xff; assert(r.random.intRangeAtMost(i8, -0x80, -1) == -1); - r.next_value = 0xff; - assert(r.random.intRangeAtMost(i64, -0x8000000000000000, -1) == -1); r.next_value = 0xff; assert(r.random.intRangeAtMost(i3, -4, -1) == -1); r.next_value = 0xff; assert(r.random.intRangeAtMost(i3, -2, 1) == 1); - - // test retrying and eventually getting a good value - // start just out of bounds - r.next_value = 0x81; - assert(r.random.uintAtMost(u8, 0x80) == 0); } // Generator to extend 64-bit seed values into longer sequences. From 49b49618d2db657b22c24a4c78d6516df0fd7e45 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 21 Nov 2018 18:24:14 -0500 Subject: [PATCH 041/110] add biased random range api --- std/rand/index.zig | 76 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/std/rand/index.zig b/std/rand/index.zig index 0d9e58fd8..43fc43330 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -57,6 +57,23 @@ pub const Random = struct { return @bitCast(T, unsigned_result); } + /// Constant-time implementation off ::uintLessThan. + /// The results of this function may be biased. + pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T { + assert(T.is_signed == false); + assert(0 < less_than); + // Small is typically u32 + const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); + // Large is typically u64 + const Large = @IntType(false, Small.bit_count * 2); + + // adapted from: + // http://www.pcg-random.org/posts/bounded-rands.html + // "Integer Multiplication (Biased)" + var x: Small = r.int(Small); + var m: Large = Large(x) * Large(less_than); + return @intCast(T, m >> Small.bit_count); + } /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`. /// This function assumes that the underlying ::fillFn produces evenly distributed values. /// Within this assumption, the runtime of this function is exponentially distributed. @@ -64,8 +81,7 @@ pub const Random = struct { /// the runtime of this function would technically be unbounded. /// However, if ::fillFn is backed by any evenly distributed pseudo random number generator, /// this function is guaranteed to return. - /// If you need deterministic runtime bounds, consider instead using `r.int(T) % less_than`, - /// which will usually be biased toward smaller values. + /// If you need deterministic runtime bounds, use `::uintLessThanBiased`. pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T { assert(T.is_signed == false); assert(0 < less_than); @@ -101,6 +117,16 @@ pub const Random = struct { return @intCast(T, m >> Small.bit_count); } + /// Constant-time implementation off ::uintAtMost. + /// The results of this function may be biased. + pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T { + assert(T.is_signed == false); + if (at_most == maxInt(T)) { + // have the full range + return r.int(T); + } + return r.uintLessThanBiased(T, at_most + 1); + } /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -113,6 +139,22 @@ pub const Random = struct { return r.uintLessThan(T, at_most + 1); } + /// Constant-time implementation off ::intRangeLessThan. + /// The results of this function may be biased. + pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T { + assert(at_least < less_than); + if (T.is_signed) { + // Two's complement makes this math pretty easy. + const UnsignedT = @IntType(false, T.bit_count); + const lo = @bitCast(UnsignedT, at_least); + const hi = @bitCast(UnsignedT, less_than); + const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo); + return @bitCast(T, result); + } else { + // The signed implementation would work fine, but we can use stricter arithmetic operators here. + return at_least + r.uintLessThanBiased(T, less_than - at_least); + } + } /// Returns an evenly distributed random integer `at_least <= i < less_than`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -131,6 +173,22 @@ pub const Random = struct { } } + /// Constant-time implementation off ::intRangeAtMostBiased. + /// The results of this function may be biased. + pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T { + assert(at_least <= at_most); + if (T.is_signed) { + // Two's complement makes this math pretty easy. + const UnsignedT = @IntType(false, T.bit_count); + const lo = @bitCast(UnsignedT, at_least); + const hi = @bitCast(UnsignedT, at_most); + const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo); + return @bitCast(T, result); + } else { + // The signed implementation would work fine, but we can use stricter arithmetic operators here. + return at_least + r.uintAtMostBiased(T, at_most - at_least); + } + } /// Returns an evenly distributed random integer `at_least <= i <= at_most`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -149,15 +207,11 @@ pub const Random = struct { } } - /// Return a random integer/boolean type. /// TODO: deprecated. use ::boolean or ::int instead. pub fn scalar(r: *Random, comptime T: type) T { - if (T == bool) return r.boolean(); - return r.int(T); + return if (T == bool) r.boolean() else r.int(T); } - /// Return a random integer with even distribution between `start` - /// inclusive and `end` exclusive. `start` must be less than `end`. /// TODO: deprecated. renamed to ::intRangeLessThan pub fn range(r: *Random, comptime T: type, start: T, end: T) T { return r.intRangeLessThan(T, start, end); @@ -373,6 +427,8 @@ fn testRandomIntAtMost() void { assert(r.random.intRangeAtMost(i3, -4, -1) == -1); r.next_value = 0xff; assert(r.random.intRangeAtMost(i3, -2, 1) == 1); + + assert(r.random.uintAtMost(u0, 0) == 0); } // Generator to extend 64-bit seed values into longer sequences. @@ -884,12 +940,16 @@ test "Random range" { } fn testRange(r: *Random, start: i8, end: i8) void { + testRangeBias(r, start, end, true); + testRangeBias(r, start, end, false); +} +fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void { const count = @intCast(usize, i32(end) - i32(start)); var values_buffer = []bool{false} ** 0x100; const values = values_buffer[0..count]; var i: usize = 0; while (i < count) { - const value: i32 = r.intRangeLessThan(i8, start, end); + const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end); const index = @intCast(usize, value - start); if (!values[index]) { i += 1; From eed7b48fe3e02670b3d276e09a2dd376348baf68 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 21 Nov 2018 18:47:32 -0500 Subject: [PATCH 042/110] test lots of types --- std/rand/index.zig | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/std/rand/index.zig b/std/rand/index.zig index 43fc43330..055565ad6 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -60,7 +60,8 @@ pub const Random = struct { /// Constant-time implementation off ::uintLessThan. /// The results of this function may be biased. pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T { - assert(T.is_signed == false); + comptime assert(T.is_signed == false); + comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! assert(0 < less_than); // Small is typically u32 const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); @@ -83,7 +84,8 @@ pub const Random = struct { /// this function is guaranteed to return. /// If you need deterministic runtime bounds, use `::uintLessThanBiased`. pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T { - assert(T.is_signed == false); + comptime assert(T.is_signed == false); + comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! assert(0 < less_than); // Small is typically u32 const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); @@ -431,6 +433,37 @@ fn testRandomIntAtMost() void { assert(r.random.uintAtMost(u0, 0) == 0); } +test "Random Biased" { + var r = DefaultPrng.init(0); + // Not thoroughly checking the logic here. + // Just want to execute all the paths with different types. + + assert(r.random.uintLessThanBiased(u1, 1) == 0); + assert(r.random.uintLessThanBiased(u32, 10) < 10); + assert(r.random.uintLessThanBiased(u64, 20) < 20); + + assert(r.random.uintAtMostBiased(u0, 0) == 0); + assert(r.random.uintAtMostBiased(u1, 0) <= 0); + assert(r.random.uintAtMostBiased(u32, 10) <= 10); + assert(r.random.uintAtMostBiased(u64, 20) <= 20); + + assert(r.random.intRangeLessThanBiased(u1, 0, 1) == 0); + assert(r.random.intRangeLessThanBiased(i1, -1, 0) == -1); + assert(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10); + assert(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10); + assert(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20); + assert(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20); + + // uncomment for broken module error: + //assert(r.random.intRangeAtMostBiased(u0, 0, 0) == 0); + assert(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0); + assert(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1); + assert(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10); + assert(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10); + assert(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20); + assert(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20); +} + // Generator to extend 64-bit seed values into longer sequences. // // The number of cycles is thus limited to 64-bits regardless of the engine, but this From 9ae5200bd2851aab704b786f53a1495a9f58049e Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 21 Nov 2018 19:46:42 -0500 Subject: [PATCH 043/110] factor out and expose biased range limiting function --- std/rand/index.zig | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/std/rand/index.zig b/std/rand/index.zig index 055565ad6..97101bc3b 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -63,17 +63,11 @@ pub const Random = struct { comptime assert(T.is_signed == false); comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! assert(0 < less_than); - // Small is typically u32 - const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); - // Large is typically u64 - const Large = @IntType(false, Small.bit_count * 2); - - // adapted from: - // http://www.pcg-random.org/posts/bounded-rands.html - // "Integer Multiplication (Biased)" - var x: Small = r.int(Small); - var m: Large = Large(x) * Large(less_than); - return @intCast(T, m >> Small.bit_count); + if (T.bit_count <= 32) { + return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than)); + } else { + return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than)); + } } /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`. /// This function assumes that the underlying ::fillFn produces evenly distributed values. @@ -276,6 +270,20 @@ pub const Random = struct { } }; +/// Convert a random integer 0 <= random_int <= maxValue(T), +/// into an integer 0 <= result < less_than. +/// This function introduces a minor bias. +pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T { + comptime assert(T.is_signed == false); + const T2 = @IntType(false, T.bit_count * 2); + + // adapted from: + // http://www.pcg-random.org/posts/bounded-rands.html + // "Integer Multiplication (Biased)" + var m: T2 = T2(random_int) * T2(less_than); + return @intCast(T, m >> T.bit_count); +} + const SequentialPrng = struct { const Self = @This(); random: Random, From f6cd02be6551f3ca702b76b7ca2ab7567effe680 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Mon, 26 Nov 2018 02:08:12 +1100 Subject: [PATCH 044/110] add std.meta.stringToEnum --- std/meta/index.zig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/std/meta/index.zig b/std/meta/index.zig index 2019543b5..69a309728 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -76,6 +76,25 @@ test "std.meta.tagName" { debug.assert(mem.eql(u8, tagName(u2b), "D")); } +pub fn stringToEnum(comptime T: type, str: []const u8) ?T { + inline for (@typeInfo(T).Enum.fields) |enumField| { + if (std.mem.eql(u8, str, enumField.name)) { + return @field(T, enumField.name); + } + } + return null; +} + +test "std.meta.stringToEnum" { + const E1 = enum { + A, + B, + }; + debug.assert(E1.A == stringToEnum(E1, "A").?); + debug.assert(E1.B == stringToEnum(E1, "B").?); + debug.assert(null == stringToEnum(E1, "C")); +} + pub fn bitCount(comptime T: type) u32 { return switch (@typeInfo(T)) { TypeId.Int => |info| info.bits, From 67a39a4c99106714588676db0168fef52e0ecd9c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 26 Nov 2018 20:04:35 -0500 Subject: [PATCH 045/110] stage1: better file path handling * better message printed when cache hash fails * better handling of '/' as root source file * os_path_split parses '/' and '/a' correctly closes #1693 closes #1746 --- src/cache_hash.cpp | 6 ++++-- src/codegen.cpp | 11 ++++++++++- src/error.cpp | 1 + src/error.hpp | 1 + src/os.cpp | 10 ++++++++-- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp index 7a3c08bc2..5e6c3b9a9 100644 --- a/src/cache_hash.cpp +++ b/src/cache_hash.cpp @@ -352,8 +352,9 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { // if the mtime matches we can trust the digest OsFile this_file; if ((err = os_file_open_r(chf->path, &this_file))) { + fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err)); os_file_close(ch->manifest_file); - return err; + return ErrorCacheUnavailable; } OsTimeStamp actual_mtime; if ((err = os_file_mtime(this_file, &actual_mtime))) { @@ -392,8 +393,9 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) { for (; file_i < input_file_count; file_i += 1) { CacheHashFile *chf = &ch->files.at(file_i); if ((err = populate_file_hash(ch, chf, nullptr))) { + fprintf(stderr, "Unable to hash %s: %s\n", buf_ptr(chf->path), err_str(err)); os_file_close(ch->manifest_file); - return err; + return ErrorCacheUnavailable; } } return ErrorNone; diff --git a/src/codegen.cpp b/src/codegen.cpp index 37e042496..1033ed812 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -129,6 +129,11 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out Buf *src_dir = buf_alloc(); os_path_split(root_src_path, src_dir, src_basename); + if (buf_len(src_basename) == 0) { + fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path)); + exit(1); + } + g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename)); g->std_package = new_package(buf_ptr(g->zig_std_dir), "index.zig"); g->root_package->package_table.put(buf_create_from_str("std"), g->std_package); @@ -8178,7 +8183,11 @@ void codegen_build_and_link(CodeGen *g) { os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir); if ((err = check_cache(g, manifest_dir, &digest))) { - fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); + if (err == ErrorCacheUnavailable) { + // message already printed + } else { + fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); + } exit(1); } diff --git a/src/error.cpp b/src/error.cpp index d0575a849..10186fbde 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -33,6 +33,7 @@ const char *err_str(Error err) { case ErrorSharingViolation: return "sharing violation"; case ErrorPipeBusy: return "pipe busy"; case ErrorPrimitiveTypeNotFound: return "primitive type not found"; + case ErrorCacheUnavailable: return "cache unavailable"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp index 8b8fa5ce1..b60cb8517 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -35,6 +35,7 @@ enum Error { ErrorSharingViolation, ErrorPipeBusy, ErrorPrimitiveTypeNotFound, + ErrorCacheUnavailable, }; const char *err_str(Error err); diff --git a/src/os.cpp b/src/os.cpp index 9d16d763e..f739ee44e 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -188,14 +188,20 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { size_t len = buf_len(full_path); if (len != 0) { size_t last_index = len - 1; - if (os_is_sep(buf_ptr(full_path)[last_index])) { + char last_char = buf_ptr(full_path)[last_index]; + if (os_is_sep(last_char)) { + if (last_index == 0) { + if (out_dirname) buf_init_from_mem(out_dirname, &last_char, 1); + if (out_basename) buf_init_from_str(out_basename, ""); + return; + } last_index -= 1; } for (size_t i = last_index;;) { uint8_t c = buf_ptr(full_path)[i]; if (os_is_sep(c)) { if (out_dirname) { - buf_init_from_mem(out_dirname, buf_ptr(full_path), i); + buf_init_from_mem(out_dirname, buf_ptr(full_path), (i == 0) ? 1 : i); } if (out_basename) { buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1)); From a5b79017a32e8ee1c9486b3b3bf2c13fa7db899c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Nov 2018 00:52:32 -0500 Subject: [PATCH 046/110] fix regression from d5648d26 thanks Wink Saville for the test case. --- std/json.zig | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/std/json.zig b/std/json.zig index e18de7ad1..4d07d7b89 100644 --- a/std/json.zig +++ b/std/json.zig @@ -1188,7 +1188,7 @@ pub const Parser = struct { } var value = p.stack.pop(); - try p.pushToParent(value); + try p.pushToParent(&value); }, Token.Id.String => { try p.stack.append(try p.parseString(allocator, token, input, i)); @@ -1251,7 +1251,7 @@ pub const Parser = struct { } var value = p.stack.pop(); - try p.pushToParent(value); + try p.pushToParent(&value); }, Token.Id.ObjectBegin => { try p.stack.append(Value{ .Object = ObjectMap.init(allocator) }); @@ -1312,20 +1312,19 @@ pub const Parser = struct { } } - fn pushToParent(p: *Parser, value: Value) !void { - switch (p.stack.at(p.stack.len - 1)) { + fn pushToParent(p: *Parser, value: *const Value) !void { + switch (p.stack.toSlice()[p.stack.len - 1]) { // Object Parent -> [ ..., object, , value ] Value.String => |key| { _ = p.stack.pop(); var object = &p.stack.items[p.stack.len - 1].Object; - _ = try object.put(key, value); + _ = try object.put(key, value.*); p.state = State.ObjectKey; }, // Array Parent -> [ ..., , value ] - Value.Array => { - var array = &p.stack.items[p.stack.len - 1].Array; - try array.append(value); + Value.Array => |*array| { + try array.append(value.*); p.state = State.ArrayValue; }, else => { From 2baf0e2ffc154d7915e690ddb4d892d1bafd5db2 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Mon, 26 Nov 2018 21:12:16 +1100 Subject: [PATCH 047/110] add std.math.IntFittingRange --- std/math/index.zig | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/std/math/index.zig b/std/math/index.zig index de09a6e94..83bd2310d 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -365,6 +365,69 @@ pub fn Log2Int(comptime T: type) type { return @IntType(false, count); } +pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type { + assert(from <= to); + if (from == 0 and to == 0) { + return u0; + } + const is_signed = from < 0; + const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement + const base = log2(largest_positive_integer); + const upper = (1 << base) - 1; + var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1; + if (is_signed) { + magnitude_bits += 1; + } + return @IntType(is_signed, magnitude_bits); +} + +test "math.IntFittingRange" { + assert(IntFittingRange(0, 0) == u0); + assert(IntFittingRange(0, 1) == u1); + assert(IntFittingRange(0, 2) == u2); + assert(IntFittingRange(0, 3) == u2); + assert(IntFittingRange(0, 4) == u3); + assert(IntFittingRange(0, 7) == u3); + assert(IntFittingRange(0, 8) == u4); + assert(IntFittingRange(0, 9) == u4); + assert(IntFittingRange(0, 15) == u4); + assert(IntFittingRange(0, 16) == u5); + assert(IntFittingRange(0, 17) == u5); + assert(IntFittingRange(0, 4095) == u12); + assert(IntFittingRange(2000, 4095) == u12); + assert(IntFittingRange(0, 4096) == u13); + assert(IntFittingRange(2000, 4096) == u13); + assert(IntFittingRange(0, 4097) == u13); + assert(IntFittingRange(2000, 4097) == u13); + assert(IntFittingRange(0, 123456789123456798123456789) == u87); + assert(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177); + + assert(IntFittingRange(-1, -1) == i1); + assert(IntFittingRange(-1, 0) == i1); + assert(IntFittingRange(-1, 1) == i2); + assert(IntFittingRange(-2, -2) == i2); + assert(IntFittingRange(-2, -1) == i2); + assert(IntFittingRange(-2, 0) == i2); + assert(IntFittingRange(-2, 1) == i2); + assert(IntFittingRange(-2, 2) == i3); + assert(IntFittingRange(-1, 2) == i3); + assert(IntFittingRange(-1, 3) == i3); + assert(IntFittingRange(-1, 4) == i4); + assert(IntFittingRange(-1, 7) == i4); + assert(IntFittingRange(-1, 8) == i5); + assert(IntFittingRange(-1, 9) == i5); + assert(IntFittingRange(-1, 15) == i5); + assert(IntFittingRange(-1, 16) == i6); + assert(IntFittingRange(-1, 17) == i6); + assert(IntFittingRange(-1, 4095) == i13); + assert(IntFittingRange(-4096, 4095) == i13); + assert(IntFittingRange(-1, 4096) == i14); + assert(IntFittingRange(-4097, 4095) == i14); + assert(IntFittingRange(-1, 4097) == i14); + assert(IntFittingRange(-1, 123456789123456798123456789) == i88); + assert(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178); +} + test "math overflow functions" { testOverflow(); comptime testOverflow(); From 3c4965a6162e50064d22bc1900584e74e2ef15ea Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Nov 2018 11:27:45 -0500 Subject: [PATCH 048/110] readme: update support table --- README.md | 86 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 344695764..e50d31856 100644 --- a/README.md +++ b/README.md @@ -42,33 +42,71 @@ clarity. * In addition to creating executables, creating a C library is a primary use case. You can export an auto-generated .h file. -### Support Table +### Supported Targets -Freestanding means that you do not directly interact with the OS -or you are writing your own OS. +#### Tier 1 Support -Note that if you use libc or other libraries to interact with the OS, -that counts as "freestanding" for the purposes of this table. + * Not only can Zig generate machine code for these targets, but the standard + library cross-platform abstractions have implementations for these targets. + Thus it is practical to write a pure Zig application with no dependency on + libc. + * The CI server automatically tests these targets on every commit to master + branch, and updates ziglang.org/download with links to pre-built binaries. + * These targets have debug info capabilities and therefore produce stack + traces on failed assertions. -| | freestanding | linux | macosx | windows | other | -|-------------|--------------|---------|---------|---------|---------| -|i386 | OK | planned | OK | planned | planned | -|x86_64 | OK | OK | OK | OK | planned | -|arm | OK | planned | planned | planned | planned | -|bpf | OK | planned | N/A | N/A | planned | -|hexagon | OK | planned | N/A | N/A | planned | -|mips | OK | planned | N/A | N/A | planned | -|powerpc | OK | planned | N/A | N/A | planned | -|r600 | OK | planned | N/A | N/A | planned | -|amdgcn | OK | planned | N/A | N/A | planned | -|sparc | OK | planned | N/A | N/A | planned | -|s390x | OK | planned | N/A | N/A | planned | -|spir | OK | planned | N/A | N/A | planned | -|lanai | OK | planned | N/A | N/A | planned | -|wasm32 | planned | N/A | N/A | N/A | N/A | -|wasm64 | planned | N/A | N/A | N/A | N/A | -|riscv32 | planned | planned | N/A | N/A | planned | -|riscv64 | planned | planned | N/A | N/A | planned | +#### Tier 2 Support + + * There may be some standard library implementations, but many abstractions + will give an "Unsupported OS" compile error. One can link with libc or other + libraries to fill in the gaps in the standard library. + * These targets are known to work, but are not automatically tested, so there + are occasional regressions. + * Some tests may be disabled for these targets as we work toward Tier 1 + support. + +#### Tier 3 Support + + * The standard library has little to no knowledge of the existence of this + target. + * Because Zig is based on LLVM, it has the capability to build for these + targets, and LLVM has the target enabled by default. + * These targets are not frequently tested; one will likely need to contribute + to Zig in order to build for these targets. + * The Zig compiler might need to be updated with a few things such as + - what sizes are the C integer types + - C ABI calling convention for this target + - bootstrap code and default panic handler + +#### Tier 4 Support + + * Support for these targets is entirely experimental. + * LLVM may have the target as an experimental target, which means that you + need to use Zig-provided binaries for the target to be available, or + build LLVM from source with special configure flags. + +#### Support Table + +| | freestanding | linux | macosx | windows | freebsd | other | +|--------|--------------|--------|--------|---------|---------|--------| +|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 3 | Tier 3 | +|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | +|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | +|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | +|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | +|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | +|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | +|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | +|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | ## Community From 1fb15be05f1037aad53d2db32d13123363365d10 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Wed, 28 Nov 2018 00:24:06 +0100 Subject: [PATCH 049/110] stack traces: fix for windows --- std/debug/index.zig | 5 +++-- std/pdb.zig | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index b077bdb3b..134f0a479 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -282,8 +282,9 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres var coff_section: *coff.Section = undefined; const mod_index = for (di.sect_contribs) |sect_contrib| { - if (sect_contrib.Section >= di.coff.sections.len) continue; - coff_section = &di.coff.sections.toSlice()[sect_contrib.Section]; + if (sect_contrib.Section > di.coff.sections.len) continue; + // Remember that SectionContribEntry.Section is 1-based. + coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1]; const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset; const vaddr_end = vaddr_start + sect_contrib.Size; diff --git a/std/pdb.zig b/std/pdb.zig index 17275ab2a..2c5df3e59 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -34,6 +34,7 @@ pub const DbiStreamHeader = packed struct { }; pub const SectionContribEntry = packed struct { + /// COFF Section index, 1-based Section: u16, Padding1: [2]u8, Offset: u32, From dd2450b1b21809c3fe62920498c318fbe519f579 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 27 Nov 2018 20:56:43 -0500 Subject: [PATCH 050/110] tier 2 support for freebsd --- README.md | 2 +- cmake/Findlld.cmake | 10 +- src-self-hosted/target.zig | 294 +++++++++++++++++++------------------ src/util.cpp | 2 +- std/os/index.zig | 4 +- 5 files changed, 157 insertions(+), 155 deletions(-) diff --git a/README.md b/README.md index e50d31856..a19e9eb67 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ clarity. | | freestanding | linux | macosx | windows | freebsd | other | |--------|--------------|--------|--------|---------|---------|--------| -|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 3 | Tier 3 | +|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 3 | |i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | |arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | |arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | diff --git a/cmake/Findlld.cmake b/cmake/Findlld.cmake index 4e5b0c9a1..93ed1a9de 100644 --- a/cmake/Findlld.cmake +++ b/cmake/Findlld.cmake @@ -8,13 +8,13 @@ find_path(LLD_INCLUDE_DIRS NAMES lld/Common/Driver.h PATHS - /usr/lib/llvm-6.0/include - /usr/local/llvm60/include + /usr/lib/llvm-7.0/include + /usr/local/llvm70/include /mingw64/include) -find_library(LLD_LIBRARY NAMES lld-6.0 lld60 lld +find_library(LLD_LIBRARY NAMES lld-7.0 lld70 lld PATHS - /usr/lib/llvm-6.0/lib + /usr/lib/llvm-7.0/lib /usr/local/llvm70/lib) if(EXISTS ${LLD_LIBRARY}) set(LLD_LIBRARIES ${LLD_LIBRARY}) @@ -23,7 +23,7 @@ else() string(TOUPPER ${_libname_} _prettylibname_) find_library(LLD_${_prettylibname_}_LIB NAMES ${_libname_} PATHS - /usr/lib/llvm-6.0/lib + /usr/lib/llvm-7.0/lib /usr/local/llvm70/lib /mingw64/lib /c/msys64/mingw64/lib diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index eae0a1232..218353c9d 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -304,154 +304,156 @@ pub const Target = union(enum) { builtin.Os.freebsd => { return "/libexec/ld-elf.so.1"; }, - else => {}, - } - switch (env) { - builtin.Environ.android => { - if (self.is64bit()) { - return "/system/bin/linker64"; - } else { - return "/system/bin/linker"; + builtin.Os.linux => { + switch (env) { + builtin.Environ.android => { + if (self.is64bit()) { + return "/system/bin/linker64"; + } else { + return "/system/bin/linker"; + } + }, + builtin.Environ.gnux32 => { + if (arch == builtin.Arch.x86_64) { + return "/libx32/ld-linux-x32.so.2"; + } + }, + builtin.Environ.musl, + builtin.Environ.musleabi, + builtin.Environ.musleabihf, + => { + if (arch == builtin.Arch.x86_64) { + return "/lib/ld-musl-x86_64.so.1"; + } + }, + else => {}, + } + switch (arch) { + builtin.Arch.i386, + builtin.Arch.sparc, + builtin.Arch.sparcel, + => return "/lib/ld-linux.so.2", + + builtin.Arch.aarch64v8_3a, + builtin.Arch.aarch64v8_2a, + builtin.Arch.aarch64v8_1a, + builtin.Arch.aarch64v8, + builtin.Arch.aarch64v8r, + builtin.Arch.aarch64v8m_baseline, + builtin.Arch.aarch64v8m_mainline, + => return "/lib/ld-linux-aarch64.so.1", + + builtin.Arch.aarch64_bev8_3a, + builtin.Arch.aarch64_bev8_2a, + builtin.Arch.aarch64_bev8_1a, + builtin.Arch.aarch64_bev8, + builtin.Arch.aarch64_bev8r, + builtin.Arch.aarch64_bev8m_baseline, + builtin.Arch.aarch64_bev8m_mainline, + => return "/lib/ld-linux-aarch64_be.so.1", + + builtin.Arch.armv8_3a, + builtin.Arch.armv8_2a, + builtin.Arch.armv8_1a, + builtin.Arch.armv8, + builtin.Arch.armv8r, + builtin.Arch.armv8m_baseline, + builtin.Arch.armv8m_mainline, + builtin.Arch.armv7, + builtin.Arch.armv7em, + builtin.Arch.armv7m, + builtin.Arch.armv7s, + builtin.Arch.armv7k, + builtin.Arch.armv7ve, + builtin.Arch.armv6, + builtin.Arch.armv6m, + builtin.Arch.armv6k, + builtin.Arch.armv6t2, + builtin.Arch.armv5, + builtin.Arch.armv5te, + builtin.Arch.armv4t, + builtin.Arch.thumb, + => return switch (self.getFloatAbi()) { + FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3", + else => return "/lib/ld-linux.so.3", + }, + + builtin.Arch.armebv8_3a, + builtin.Arch.armebv8_2a, + builtin.Arch.armebv8_1a, + builtin.Arch.armebv8, + builtin.Arch.armebv8r, + builtin.Arch.armebv8m_baseline, + builtin.Arch.armebv8m_mainline, + builtin.Arch.armebv7, + builtin.Arch.armebv7em, + builtin.Arch.armebv7m, + builtin.Arch.armebv7s, + builtin.Arch.armebv7k, + builtin.Arch.armebv7ve, + builtin.Arch.armebv6, + builtin.Arch.armebv6m, + builtin.Arch.armebv6k, + builtin.Arch.armebv6t2, + builtin.Arch.armebv5, + builtin.Arch.armebv5te, + builtin.Arch.armebv4t, + builtin.Arch.thumbeb, + => return switch (self.getFloatAbi()) { + FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3", + else => return "/lib/ld-linux.so.3", + }, + + builtin.Arch.mips, + builtin.Arch.mipsel, + builtin.Arch.mips64, + builtin.Arch.mips64el, + => return null, + + builtin.Arch.powerpc => return "/lib/ld.so.1", + builtin.Arch.powerpc64 => return "/lib64/ld64.so.2", + builtin.Arch.powerpc64le => return "/lib64/ld64.so.2", + builtin.Arch.s390x => return "/lib64/ld64.so.1", + builtin.Arch.sparcv9 => return "/lib64/ld-linux.so.2", + builtin.Arch.x86_64 => return "/lib64/ld-linux-x86-64.so.2", + + builtin.Arch.arc, + builtin.Arch.avr, + builtin.Arch.bpfel, + builtin.Arch.bpfeb, + builtin.Arch.hexagon, + builtin.Arch.msp430, + builtin.Arch.nios2, + builtin.Arch.r600, + builtin.Arch.amdgcn, + builtin.Arch.riscv32, + builtin.Arch.riscv64, + builtin.Arch.tce, + builtin.Arch.tcele, + builtin.Arch.xcore, + builtin.Arch.nvptx, + builtin.Arch.nvptx64, + builtin.Arch.le32, + builtin.Arch.le64, + builtin.Arch.amdil, + builtin.Arch.amdil64, + builtin.Arch.hsail, + builtin.Arch.hsail64, + builtin.Arch.spir, + builtin.Arch.spir64, + builtin.Arch.kalimbav3, + builtin.Arch.kalimbav4, + builtin.Arch.kalimbav5, + builtin.Arch.shave, + builtin.Arch.lanai, + builtin.Arch.wasm32, + builtin.Arch.wasm64, + builtin.Arch.renderscript32, + builtin.Arch.renderscript64, + => return null, } }, - builtin.Environ.gnux32 => { - if (arch == builtin.Arch.x86_64) { - return "/libx32/ld-linux-x32.so.2"; - } - }, - builtin.Environ.musl, - builtin.Environ.musleabi, - builtin.Environ.musleabihf, - => { - if (arch == builtin.Arch.x86_64) { - return "/lib/ld-musl-x86_64.so.1"; - } - }, - else => {}, - } - switch (arch) { - builtin.Arch.i386, - builtin.Arch.sparc, - builtin.Arch.sparcel, - => return "/lib/ld-linux.so.2", - - builtin.Arch.aarch64v8_3a, - builtin.Arch.aarch64v8_2a, - builtin.Arch.aarch64v8_1a, - builtin.Arch.aarch64v8, - builtin.Arch.aarch64v8r, - builtin.Arch.aarch64v8m_baseline, - builtin.Arch.aarch64v8m_mainline, - => return "/lib/ld-linux-aarch64.so.1", - - builtin.Arch.aarch64_bev8_3a, - builtin.Arch.aarch64_bev8_2a, - builtin.Arch.aarch64_bev8_1a, - builtin.Arch.aarch64_bev8, - builtin.Arch.aarch64_bev8r, - builtin.Arch.aarch64_bev8m_baseline, - builtin.Arch.aarch64_bev8m_mainline, - => return "/lib/ld-linux-aarch64_be.so.1", - - builtin.Arch.armv8_3a, - builtin.Arch.armv8_2a, - builtin.Arch.armv8_1a, - builtin.Arch.armv8, - builtin.Arch.armv8r, - builtin.Arch.armv8m_baseline, - builtin.Arch.armv8m_mainline, - builtin.Arch.armv7, - builtin.Arch.armv7em, - builtin.Arch.armv7m, - builtin.Arch.armv7s, - builtin.Arch.armv7k, - builtin.Arch.armv7ve, - builtin.Arch.armv6, - builtin.Arch.armv6m, - builtin.Arch.armv6k, - builtin.Arch.armv6t2, - builtin.Arch.armv5, - builtin.Arch.armv5te, - builtin.Arch.armv4t, - builtin.Arch.thumb, - => return switch (self.getFloatAbi()) { - FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3", - else => return "/lib/ld-linux.so.3", - }, - - builtin.Arch.armebv8_3a, - builtin.Arch.armebv8_2a, - builtin.Arch.armebv8_1a, - builtin.Arch.armebv8, - builtin.Arch.armebv8r, - builtin.Arch.armebv8m_baseline, - builtin.Arch.armebv8m_mainline, - builtin.Arch.armebv7, - builtin.Arch.armebv7em, - builtin.Arch.armebv7m, - builtin.Arch.armebv7s, - builtin.Arch.armebv7k, - builtin.Arch.armebv7ve, - builtin.Arch.armebv6, - builtin.Arch.armebv6m, - builtin.Arch.armebv6k, - builtin.Arch.armebv6t2, - builtin.Arch.armebv5, - builtin.Arch.armebv5te, - builtin.Arch.armebv4t, - builtin.Arch.thumbeb, - => return switch (self.getFloatAbi()) { - FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3", - else => return "/lib/ld-linux.so.3", - }, - - builtin.Arch.mips, - builtin.Arch.mipsel, - builtin.Arch.mips64, - builtin.Arch.mips64el, - => return null, - - builtin.Arch.powerpc => return "/lib/ld.so.1", - builtin.Arch.powerpc64 => return "/lib64/ld64.so.2", - builtin.Arch.powerpc64le => return "/lib64/ld64.so.2", - builtin.Arch.s390x => return "/lib64/ld64.so.1", - builtin.Arch.sparcv9 => return "/lib64/ld-linux.so.2", - builtin.Arch.x86_64 => return "/lib64/ld-linux-x86-64.so.2", - - builtin.Arch.arc, - builtin.Arch.avr, - builtin.Arch.bpfel, - builtin.Arch.bpfeb, - builtin.Arch.hexagon, - builtin.Arch.msp430, - builtin.Arch.nios2, - builtin.Arch.r600, - builtin.Arch.amdgcn, - builtin.Arch.riscv32, - builtin.Arch.riscv64, - builtin.Arch.tce, - builtin.Arch.tcele, - builtin.Arch.xcore, - builtin.Arch.nvptx, - builtin.Arch.nvptx64, - builtin.Arch.le32, - builtin.Arch.le64, - builtin.Arch.amdil, - builtin.Arch.amdil64, - builtin.Arch.hsail, - builtin.Arch.hsail64, - builtin.Arch.spir, - builtin.Arch.spir64, - builtin.Arch.kalimbav3, - builtin.Arch.kalimbav4, - builtin.Arch.kalimbav5, - builtin.Arch.shave, - builtin.Arch.lanai, - builtin.Arch.wasm32, - builtin.Arch.wasm64, - builtin.Arch.renderscript32, - builtin.Arch.renderscript64, - => return null, + else => return null, } } diff --git a/src/util.cpp b/src/util.cpp index f7bda86c4..192d74e76 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -47,7 +47,7 @@ bool ptr_eq(const void *a, const void *b) { // Ported from std/mem.zig. bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { for (size_t i = 0; i < self->split_bytes.len; i += 1) { - if (byte == self->split_bytes.ptr[i] || byte == 0) { + if (byte == self->split_bytes.ptr[i]) { return true; } } diff --git a/std/os/index.zig b/std/os/index.zig index ba1fdb2be..15be08c68 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -1731,8 +1731,8 @@ pub const Dir = struct { } fn nextFreebsd(self: *Dir) !?Entry { - self.handle.buf = try self.allocator.alloc(u8, page_size); - return null; // TODO + //self.handle.buf = try self.allocator.alloc(u8, page_size); + @compileError("TODO implement dirs for FreeBSD"); } }; From 11e8afb37cea3d4b951165f382eeee36a653978f Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 28 Nov 2018 18:33:55 -0500 Subject: [PATCH 051/110] fix child_process piped streams not getting closed --- std/os/child_process.zig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 9361d7882..c8865bfac 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -390,6 +390,19 @@ pub const ChildProcess = struct { setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err); setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err); + if (self.stdin_behavior == StdIo.Pipe) { + os.close(stdin_pipe[0]); + os.close(stdin_pipe[1]); + } + if (self.stdout_behavior == StdIo.Pipe) { + os.close(stdout_pipe[0]); + os.close(stdout_pipe[1]); + } + if (self.stderr_behavior == StdIo.Pipe) { + os.close(stderr_pipe[0]); + os.close(stderr_pipe[1]); + } + if (self.cwd) |cwd| { os.changeCurDir(self.allocator, cwd) catch |err| forkChildErrReport(err_pipe[1], err); } From c54fe0d3ae867744bf1c0b27202f779fffc5ac7f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 28 Nov 2018 22:58:52 -0500 Subject: [PATCH 052/110] work around to support debian's fork of llvm 7.0.1 it has a patch that adds an OS type, breaking the public API this commit avoids depending on the last os type enum item, but retains the safety assertion checks. closes #1788 --- src/zig_llvm.cpp | 175 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 163 insertions(+), 12 deletions(-) diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 00023f623..bda8fa0ad 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -681,18 +681,6 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { } -static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, ""); -static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, ""); -static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, ""); -static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, ""); -static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, ""); - -static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, ""); -static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, ""); -static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, ""); -static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, ""); -static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, ""); - const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch) { return (const char*)Triple::getArchTypeName((Triple::ArchType)arch).bytes_begin(); } @@ -919,3 +907,166 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_ assert(false); // unreachable abort(); } + +static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, ""); +static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, ""); +static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, ""); +static_assert((Triple::ArchType)ZigLLVM_aarch64 == Triple::aarch64, ""); +static_assert((Triple::ArchType)ZigLLVM_aarch64_be == Triple::aarch64_be, ""); +static_assert((Triple::ArchType)ZigLLVM_arc == Triple::arc, ""); +static_assert((Triple::ArchType)ZigLLVM_avr == Triple::avr, ""); +static_assert((Triple::ArchType)ZigLLVM_bpfel == Triple::bpfel, ""); +static_assert((Triple::ArchType)ZigLLVM_bpfeb == Triple::bpfeb, ""); +static_assert((Triple::ArchType)ZigLLVM_hexagon == Triple::hexagon, ""); +static_assert((Triple::ArchType)ZigLLVM_mips == Triple::mips, ""); +static_assert((Triple::ArchType)ZigLLVM_mipsel == Triple::mipsel, ""); +static_assert((Triple::ArchType)ZigLLVM_mips64 == Triple::mips64, ""); +static_assert((Triple::ArchType)ZigLLVM_mips64el == Triple::mips64el, ""); +static_assert((Triple::ArchType)ZigLLVM_msp430 == Triple::msp430, ""); +static_assert((Triple::ArchType)ZigLLVM_nios2 == Triple::nios2, ""); +static_assert((Triple::ArchType)ZigLLVM_ppc == Triple::ppc, ""); +static_assert((Triple::ArchType)ZigLLVM_ppc64 == Triple::ppc64, ""); +static_assert((Triple::ArchType)ZigLLVM_ppc64le == Triple::ppc64le, ""); +static_assert((Triple::ArchType)ZigLLVM_r600 == Triple::r600, ""); +static_assert((Triple::ArchType)ZigLLVM_amdgcn == Triple::amdgcn, ""); +static_assert((Triple::ArchType)ZigLLVM_riscv32 == Triple::riscv32, ""); +static_assert((Triple::ArchType)ZigLLVM_riscv64 == Triple::riscv64, ""); +static_assert((Triple::ArchType)ZigLLVM_sparc == Triple::sparc, ""); +static_assert((Triple::ArchType)ZigLLVM_sparcv9 == Triple::sparcv9, ""); +static_assert((Triple::ArchType)ZigLLVM_sparcel == Triple::sparcel, ""); +static_assert((Triple::ArchType)ZigLLVM_systemz == Triple::systemz, ""); +static_assert((Triple::ArchType)ZigLLVM_tce == Triple::tce, ""); +static_assert((Triple::ArchType)ZigLLVM_tcele == Triple::tcele, ""); +static_assert((Triple::ArchType)ZigLLVM_thumb == Triple::thumb, ""); +static_assert((Triple::ArchType)ZigLLVM_thumbeb == Triple::thumbeb, ""); +static_assert((Triple::ArchType)ZigLLVM_x86 == Triple::x86, ""); +static_assert((Triple::ArchType)ZigLLVM_x86_64 == Triple::x86_64, ""); +static_assert((Triple::ArchType)ZigLLVM_xcore == Triple::xcore, ""); +static_assert((Triple::ArchType)ZigLLVM_nvptx == Triple::nvptx, ""); +static_assert((Triple::ArchType)ZigLLVM_nvptx64 == Triple::nvptx64, ""); +static_assert((Triple::ArchType)ZigLLVM_le32 == Triple::le32, ""); +static_assert((Triple::ArchType)ZigLLVM_le64 == Triple::le64, ""); +static_assert((Triple::ArchType)ZigLLVM_amdil == Triple::amdil, ""); +static_assert((Triple::ArchType)ZigLLVM_amdil64 == Triple::amdil64, ""); +static_assert((Triple::ArchType)ZigLLVM_hsail == Triple::hsail, ""); +static_assert((Triple::ArchType)ZigLLVM_hsail64 == Triple::hsail64, ""); +static_assert((Triple::ArchType)ZigLLVM_spir == Triple::spir, ""); +static_assert((Triple::ArchType)ZigLLVM_spir64 == Triple::spir64, ""); +static_assert((Triple::ArchType)ZigLLVM_kalimba == Triple::kalimba, ""); +static_assert((Triple::ArchType)ZigLLVM_shave == Triple::shave, ""); +static_assert((Triple::ArchType)ZigLLVM_lanai == Triple::lanai, ""); +static_assert((Triple::ArchType)ZigLLVM_wasm32 == Triple::wasm32, ""); +static_assert((Triple::ArchType)ZigLLVM_wasm64 == Triple::wasm64, ""); +static_assert((Triple::ArchType)ZigLLVM_renderscript32 == Triple::renderscript32, ""); +static_assert((Triple::ArchType)ZigLLVM_renderscript64 == Triple::renderscript64, ""); +// Uncomment this when testing LLVM 8.0.0 +//static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, ""); + +static_assert((Triple::SubArchType)ZigLLVM_NoSubArch == Triple::NoSubArch, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_4a == Triple::ARMSubArch_v8_4a, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_3a == Triple::ARMSubArch_v8_3a, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_2a == Triple::ARMSubArch_v8_2a, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_1a == Triple::ARMSubArch_v8_1a, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8 == Triple::ARMSubArch_v8, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8r == Triple::ARMSubArch_v8r, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_baseline == Triple::ARMSubArch_v8m_baseline, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_mainline == Triple::ARMSubArch_v8m_mainline, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7 == Triple::ARMSubArch_v7, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7em == Triple::ARMSubArch_v7em, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7m == Triple::ARMSubArch_v7m, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7s == Triple::ARMSubArch_v7s, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7k == Triple::ARMSubArch_v7k, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7ve == Triple::ARMSubArch_v7ve, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6 == Triple::ARMSubArch_v6, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6m == Triple::ARMSubArch_v6m, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6k == Triple::ARMSubArch_v6k, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6t2 == Triple::ARMSubArch_v6t2, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5 == Triple::ARMSubArch_v5, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5te == Triple::ARMSubArch_v5te, ""); +static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v4t == Triple::ARMSubArch_v4t, ""); +static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v3 == Triple::KalimbaSubArch_v3, ""); +static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v4 == Triple::KalimbaSubArch_v4, ""); +static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, ""); + +static_assert((Triple::VendorType)ZigLLVM_UnknownVendor == Triple::UnknownVendor, ""); +static_assert((Triple::VendorType)ZigLLVM_Apple == Triple::Apple, ""); +static_assert((Triple::VendorType)ZigLLVM_PC == Triple::PC, ""); +static_assert((Triple::VendorType)ZigLLVM_SCEI == Triple::SCEI, ""); +static_assert((Triple::VendorType)ZigLLVM_BGP == Triple::BGP, ""); +static_assert((Triple::VendorType)ZigLLVM_BGQ == Triple::BGQ, ""); +static_assert((Triple::VendorType)ZigLLVM_Freescale == Triple::Freescale, ""); +static_assert((Triple::VendorType)ZigLLVM_IBM == Triple::IBM, ""); +static_assert((Triple::VendorType)ZigLLVM_ImaginationTechnologies == Triple::ImaginationTechnologies, ""); +static_assert((Triple::VendorType)ZigLLVM_MipsTechnologies == Triple::MipsTechnologies, ""); +static_assert((Triple::VendorType)ZigLLVM_NVIDIA == Triple::NVIDIA, ""); +static_assert((Triple::VendorType)ZigLLVM_CSR == Triple::CSR, ""); +static_assert((Triple::VendorType)ZigLLVM_Myriad == Triple::Myriad, ""); +static_assert((Triple::VendorType)ZigLLVM_AMD == Triple::AMD, ""); +static_assert((Triple::VendorType)ZigLLVM_Mesa == Triple::Mesa, ""); +static_assert((Triple::VendorType)ZigLLVM_SUSE == Triple::SUSE, ""); +static_assert((Triple::VendorType)ZigLLVM_OpenEmbedded == Triple::OpenEmbedded, ""); +// Uncomment this when testing LLVM 8.0.0 +//static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, ""); + +static_assert((Triple::OSType)ZigLLVM_UnknownOS == Triple::UnknownOS, ""); +static_assert((Triple::OSType)ZigLLVM_Ananas == Triple::Ananas, ""); +static_assert((Triple::OSType)ZigLLVM_CloudABI == Triple::CloudABI, ""); +static_assert((Triple::OSType)ZigLLVM_Darwin == Triple::Darwin, ""); +static_assert((Triple::OSType)ZigLLVM_DragonFly == Triple::DragonFly, ""); +static_assert((Triple::OSType)ZigLLVM_FreeBSD == Triple::FreeBSD, ""); +static_assert((Triple::OSType)ZigLLVM_Fuchsia == Triple::Fuchsia, ""); +static_assert((Triple::OSType)ZigLLVM_IOS == Triple::IOS, ""); +static_assert((Triple::OSType)ZigLLVM_KFreeBSD == Triple::KFreeBSD, ""); +static_assert((Triple::OSType)ZigLLVM_Linux == Triple::Linux, ""); +static_assert((Triple::OSType)ZigLLVM_Lv2 == Triple::Lv2, ""); +static_assert((Triple::OSType)ZigLLVM_MacOSX == Triple::MacOSX, ""); +static_assert((Triple::OSType)ZigLLVM_NetBSD == Triple::NetBSD, ""); +static_assert((Triple::OSType)ZigLLVM_OpenBSD == Triple::OpenBSD, ""); +static_assert((Triple::OSType)ZigLLVM_Solaris == Triple::Solaris, ""); +static_assert((Triple::OSType)ZigLLVM_Win32 == Triple::Win32, ""); +static_assert((Triple::OSType)ZigLLVM_Haiku == Triple::Haiku, ""); +static_assert((Triple::OSType)ZigLLVM_Minix == Triple::Minix, ""); +static_assert((Triple::OSType)ZigLLVM_RTEMS == Triple::RTEMS, ""); +static_assert((Triple::OSType)ZigLLVM_NaCl == Triple::NaCl, ""); +static_assert((Triple::OSType)ZigLLVM_CNK == Triple::CNK, ""); +static_assert((Triple::OSType)ZigLLVM_AIX == Triple::AIX, ""); +static_assert((Triple::OSType)ZigLLVM_CUDA == Triple::CUDA, ""); +static_assert((Triple::OSType)ZigLLVM_NVCL == Triple::NVCL, ""); +static_assert((Triple::OSType)ZigLLVM_AMDHSA == Triple::AMDHSA, ""); +static_assert((Triple::OSType)ZigLLVM_PS4 == Triple::PS4, ""); +static_assert((Triple::OSType)ZigLLVM_ELFIAMCU == Triple::ELFIAMCU, ""); +static_assert((Triple::OSType)ZigLLVM_TvOS == Triple::TvOS, ""); +static_assert((Triple::OSType)ZigLLVM_WatchOS == Triple::WatchOS, ""); +static_assert((Triple::OSType)ZigLLVM_Mesa3D == Triple::Mesa3D, ""); +static_assert((Triple::OSType)ZigLLVM_Contiki == Triple::Contiki, ""); +static_assert((Triple::OSType)ZigLLVM_AMDPAL == Triple::AMDPAL, ""); +// Uncomment this when testing LLVM 8.0.0 +//static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, ""); + +static_assert((Triple::EnvironmentType)ZigLLVM_UnknownEnvironment == Triple::UnknownEnvironment, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_GNU == Triple::GNU, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_GNUABIN32 == Triple::GNUABIN32, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_GNUABI64 == Triple::GNUABI64, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABI == Triple::GNUEABI, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABIHF == Triple::GNUEABIHF, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_GNUX32 == Triple::GNUX32, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_CODE16 == Triple::CODE16, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_EABI == Triple::EABI, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_EABIHF == Triple::EABIHF, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_Android == Triple::Android, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_Musl == Triple::Musl, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABI == Triple::MuslEABI, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABIHF == Triple::MuslEABIHF, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_MSVC == Triple::MSVC, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_Itanium == Triple::Itanium, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_Cygnus == Triple::Cygnus, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_CoreCLR == Triple::CoreCLR, ""); +static_assert((Triple::EnvironmentType)ZigLLVM_Simulator == Triple::Simulator, ""); +// Uncomment this when testing LLVM 8.0.0 +//static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, ""); + +static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, ""); +static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, ""); From 078a0a6999a916def004211a4c35a9e1b32ae355 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sun, 25 Nov 2018 10:10:44 -0800 Subject: [PATCH 053/110] Add math min/max for Float and Value --- std/math/index.zig | 89 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/std/math/index.zig b/std/math/index.zig index 83bd2310d..490a8d3eb 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -777,3 +777,92 @@ test "max value type" { const x: u32 = maxInt(i32); assert(x == 2147483647); } + +pub fn maxFloat(comptime T: type) T { + return switch (T) { + f16 => f16_max, + f32 => f32_max, + f64 => f64_max, + else => @compileError("Expecting type to be a float"), + }; +} + +test "math.maxFloat" { + assert(maxFloat(f16) == f16_max); + assert(maxFloat(f32) == f32_max); + assert(maxFloat(f64) == f64_max); +} + +pub fn minFloat(comptime T: type) T { + return switch (T) { + f16 => f16_min, + f32 => f32_min, + f64 => f64_min, + else => @compileError("Expecting type to be a float"), + }; +} + +test "math.minFloat" { + assert(minFloat(f16) == f16_min); + assert(minFloat(f32) == f32_min); + assert(minFloat(f64) == f64_min); +} + +pub fn maxValue(comptime T: type) T { + return switch (@typeId(T)) { + TypeId.Int => maxInt(T), + TypeId.Float => maxFloat(T), + else => @compileError("Expecting type to be a float or int"), + }; +} + +test "math.maxValue" { + assert(maxValue(u0) == 0); + assert(maxValue(u1) == 1); + assert(maxValue(u8) == 255); + assert(maxValue(u16) == 65535); + assert(maxValue(u32) == 4294967295); + assert(maxValue(u64) == 18446744073709551615); + + assert(maxValue(i0) == 0); + assert(maxValue(i1) == 0); + assert(maxValue(i8) == 127); + assert(maxValue(i16) == 32767); + assert(maxValue(i32) == 2147483647); + assert(maxValue(i63) == 4611686018427387903); + assert(maxValue(i64) == 9223372036854775807); + + assert(maxValue(f16) == f16_max); + assert(maxValue(f32) == f32_max); + assert(maxValue(f64) == f64_max); +} + +pub fn minValue(comptime T: type) T { + return switch (@typeId(T)) { + TypeId.Int => minInt(T), + TypeId.Float => minFloat(T), + else => @compileError("Expecting type to be a float or int"), + }; +} + +test "math.minValue" { + assert(minValue(u0) == 0); + assert(minValue(u1) == 0); + assert(minValue(u8) == 0); + assert(minValue(u16) == 0); + assert(minValue(u32) == 0); + assert(minValue(u63) == 0); + assert(minValue(u64) == 0); + + assert(minValue(i0) == 0); + assert(minValue(i1) == -1); + assert(minValue(i8) == -128); + assert(minValue(i16) == -32768); + assert(minValue(i32) == -2147483648); + assert(minValue(i63) == -4611686018427387904); + assert(minValue(i64) == -9223372036854775808); + + assert(minValue(f16) == f16_min); + assert(minValue(f32) == f32_min); + assert(minValue(f64) == f64_min); +} From f74320d56df33729fb8ae7a9a745480517f037bc Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Thu, 29 Nov 2018 09:10:15 +0100 Subject: [PATCH 054/110] Implemented getOrPutValue which wraps getOrPut --- std/hash_map.zig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/std/hash_map.zig b/std/hash_map.zig index 1b299eff7..99237047e 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -126,6 +126,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 }; } + pub fn getOrPutValue(self: *Self, key: K, value: V) !*KV { + const res = try self.getOrPut(key); + if (!res.found_existing) + res.kv.value = value; + + return res.kv; + } + fn ensureCapacity(self: *Self) !void { if (self.entries.len == 0) { return self.initCapacity(16); @@ -354,6 +362,12 @@ test "basic hash map usage" { gop2.kv.value = 42; assert(map.get(99).?.value == 42); + const gop3 = try map.getOrPutValue(5, 5); + assert(gop3.value == 77); + + const gop4 = try map.getOrPutValue(100, 41); + assert(gop4.value == 41); + assert(map.contains(2)); assert(map.get(2).?.value == 22); _ = map.remove(2); From 7005ec5efea6d261b6fc6fef84389f528fc6b472 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 29 Nov 2018 09:33:47 -0500 Subject: [PATCH 055/110] Revert "Add math min/max for Float and Value" This reverts commit 078a0a6999a916def004211a4c35a9e1b32ae355. On closer inspection, I'm not sure these values for float min/max make sense. Why is it max instead of true_max? Why isn't it positive and negative infinity? Let's discuss further before committing to these changes. --- std/math/index.zig | 89 ---------------------------------------------- 1 file changed, 89 deletions(-) diff --git a/std/math/index.zig b/std/math/index.zig index 490a8d3eb..83bd2310d 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -777,92 +777,3 @@ test "max value type" { const x: u32 = maxInt(i32); assert(x == 2147483647); } - -pub fn maxFloat(comptime T: type) T { - return switch (T) { - f16 => f16_max, - f32 => f32_max, - f64 => f64_max, - else => @compileError("Expecting type to be a float"), - }; -} - -test "math.maxFloat" { - assert(maxFloat(f16) == f16_max); - assert(maxFloat(f32) == f32_max); - assert(maxFloat(f64) == f64_max); -} - -pub fn minFloat(comptime T: type) T { - return switch (T) { - f16 => f16_min, - f32 => f32_min, - f64 => f64_min, - else => @compileError("Expecting type to be a float"), - }; -} - -test "math.minFloat" { - assert(minFloat(f16) == f16_min); - assert(minFloat(f32) == f32_min); - assert(minFloat(f64) == f64_min); -} - -pub fn maxValue(comptime T: type) T { - return switch (@typeId(T)) { - TypeId.Int => maxInt(T), - TypeId.Float => maxFloat(T), - else => @compileError("Expecting type to be a float or int"), - }; -} - -test "math.maxValue" { - assert(maxValue(u0) == 0); - assert(maxValue(u1) == 1); - assert(maxValue(u8) == 255); - assert(maxValue(u16) == 65535); - assert(maxValue(u32) == 4294967295); - assert(maxValue(u64) == 18446744073709551615); - - assert(maxValue(i0) == 0); - assert(maxValue(i1) == 0); - assert(maxValue(i8) == 127); - assert(maxValue(i16) == 32767); - assert(maxValue(i32) == 2147483647); - assert(maxValue(i63) == 4611686018427387903); - assert(maxValue(i64) == 9223372036854775807); - - assert(maxValue(f16) == f16_max); - assert(maxValue(f32) == f32_max); - assert(maxValue(f64) == f64_max); -} - -pub fn minValue(comptime T: type) T { - return switch (@typeId(T)) { - TypeId.Int => minInt(T), - TypeId.Float => minFloat(T), - else => @compileError("Expecting type to be a float or int"), - }; -} - -test "math.minValue" { - assert(minValue(u0) == 0); - assert(minValue(u1) == 0); - assert(minValue(u8) == 0); - assert(minValue(u16) == 0); - assert(minValue(u32) == 0); - assert(minValue(u63) == 0); - assert(minValue(u64) == 0); - - assert(minValue(i0) == 0); - assert(minValue(i1) == -1); - assert(minValue(i8) == -128); - assert(minValue(i16) == -32768); - assert(minValue(i32) == -2147483648); - assert(minValue(i63) == -4611686018427387904); - assert(minValue(i64) == -9223372036854775808); - - assert(minValue(f16) == f16_min); - assert(minValue(f32) == f32_min); - assert(minValue(f64) == f64_min); -} From 4ecb3ceafb7e82f1d2b44059b9bbb266aa1dce00 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Sat, 17 Nov 2018 21:17:47 +1100 Subject: [PATCH 056/110] Add std.LinkedList.concat --- std/linked_list.zig | 96 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/std/linked_list.zig b/std/linked_list.zig index 46cbeb03c..c3db55b5a 100644 --- a/std/linked_list.zig +++ b/std/linked_list.zig @@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type { list.len += 1; } + /// Concatenate list2 onto the end of list1, removing all entries from the former. + /// + /// Arguments: + /// list1: the list to concatenate onto + /// list2: the list to be concatenated + pub fn concatByMoving(list1: *Self, list2: *Self) void { + const l2_first = list2.first orelse return; + if (list1.last) |l1_last| { + l1_last.next = list2.first; + l2_first.prev = list1.last; + list1.len += list2.len; + } else { + // list1 was empty + list1.first = list2.first; + list1.len = list2.len; + } + list1.last = list2.last; + list2.first = null; + list2.last = null; + list2.len = 0; + } + /// Insert a new node at the end of the list. /// /// Arguments: @@ -247,3 +269,77 @@ test "basic linked list test" { assert(list.last.?.data == 4); assert(list.len == 2); } + +test "linked list concatenation" { + const allocator = debug.global_allocator; + var list1 = LinkedList(u32).init(); + var list2 = LinkedList(u32).init(); + + var one = try list1.createNode(1, allocator); + defer list1.destroyNode(one, allocator); + var two = try list1.createNode(2, allocator); + defer list1.destroyNode(two, allocator); + var three = try list1.createNode(3, allocator); + defer list1.destroyNode(three, allocator); + var four = try list1.createNode(4, allocator); + defer list1.destroyNode(four, allocator); + var five = try list1.createNode(5, allocator); + defer list1.destroyNode(five, allocator); + + list1.append(one); + list1.append(two); + list2.append(three); + list2.append(four); + list2.append(five); + + list1.concatByMoving(&list2); + + assert(list1.last == five); + assert(list1.len == 5); + assert(list2.first == null); + assert(list2.last == null); + assert(list2.len == 0); + + // Traverse forwards. + { + var it = list1.first; + var index: u32 = 1; + while (it) |node| : (it = node.next) { + assert(node.data == index); + index += 1; + } + } + + // Traverse backwards. + { + var it = list1.last; + var index: u32 = 1; + while (it) |node| : (it = node.prev) { + assert(node.data == (6 - index)); + index += 1; + } + } + + // Swap them back, this verifies that concating to an empty list works. + list2.concatByMoving(&list1); + + // Traverse forwards. + { + var it = list2.first; + var index: u32 = 1; + while (it) |node| : (it = node.next) { + assert(node.data == index); + index += 1; + } + } + + // Traverse backwards. + { + var it = list2.last; + var index: u32 = 1; + while (it) |node| : (it = node.prev) { + assert(node.data == (6 - index)); + index += 1; + } + } +} From 53766e7a3a5c7141a64e21c30540f9ed571cdfdd Mon Sep 17 00:00:00 2001 From: dbandstra Date: Tue, 27 Nov 2018 21:17:45 -0800 Subject: [PATCH 057/110] make parseUnsigned handle types <8 bits wide --- std/fmt/index.zig | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/std/fmt/index.zig b/std/fmt/index.zig index b4b2fdb01..eda0bfae0 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -2,6 +2,7 @@ const std = @import("../index.zig"); const math = std.math; const debug = std.debug; const assert = debug.assert; +const assertError = debug.assertError; const mem = std.mem; const builtin = @import("builtin"); const errol = @import("errol/index.zig"); @@ -811,13 +812,41 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned for (buf) |c| { const digit = try charToDigit(c, radix); - x = try math.mul(T, x, radix); - x = try math.add(T, x, digit); + + if (x != 0) x = try math.mul(T, x, try math.cast(T, radix)); + x = try math.add(T, x, try math.cast(T, digit)); } return x; } +test "parseUnsigned" { + assert((try parseUnsigned(u16, "050124", 10)) == 50124); + assert((try parseUnsigned(u16, "65535", 10)) == 65535); + assertError(parseUnsigned(u16, "65536", 10), error.Overflow); + + assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); + assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow); + + assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); + + assert((try parseUnsigned(u7, "1", 10)) == 1); + assert((try parseUnsigned(u7, "1000", 2)) == 8); + + assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter); + assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter); + + assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); + + // these numbers should fit even though the radix itself doesn't fit in the destination type + assert((try parseUnsigned(u1, "0", 10)) == 0); + assert((try parseUnsigned(u1, "1", 10)) == 1); + assertError(parseUnsigned(u1, "2", 10), error.Overflow); + assert((try parseUnsigned(u1, "001", 16)) == 1); + assert((try parseUnsigned(u2, "3", 16)) == 3); + assertError(parseUnsigned(u2, "4", 16), error.Overflow); +} + pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { const value = switch (c) { '0'...'9' => c - '0', From bbdc12891bdc3a7b43a44d40b8f3d0ac8f6bb2c0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 29 Nov 2018 11:05:30 -0500 Subject: [PATCH 058/110] ci: workaround azure quirk with set -x --- ci/azure/linux_script | 3 +++ ci/azure/macos_script | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ci/azure/linux_script b/ci/azure/linux_script index 6538c2145..0298644bf 100755 --- a/ci/azure/linux_script +++ b/ci/azure/linux_script @@ -34,6 +34,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then SHASUM=$(sha256sum $ARTIFACTSDIR/$TARBALL | cut '-d ' -f1) BYTESIZE=$(wc -c < $ARTIFACTSDIR/$TARBALL) + # `set -x` causes these variables to be mangled. + # See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html + set +x echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" diff --git a/ci/azure/macos_script b/ci/azure/macos_script index 239c35426..da2d9351d 100755 --- a/ci/azure/macos_script +++ b/ci/azure/macos_script @@ -98,6 +98,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1) BYTESIZE=$(wc -c < $TARBALL) + # `set -x` causes these variables to be mangled. + # See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html + set +x echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" From b29769532be198bbaeca20efae1016b23ba97e4a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 29 Nov 2018 14:54:23 -0500 Subject: [PATCH 059/110] ci: workaround azure quirk for windows too --- ci/azure/windows_upload | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/azure/windows_upload b/ci/azure/windows_upload index 8d30980fe..7d23ac7aa 100755 --- a/ci/azure/windows_upload +++ b/ci/azure/windows_upload @@ -25,6 +25,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1) BYTESIZE=$(wc -c < $TARBALL) + # `set -x` causes these variables to be mangled. + # See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html + set +x echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" From 823969a5a47e054842056e3380b3987058ccd2dd Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Thu, 29 Nov 2018 22:38:39 +0100 Subject: [PATCH 060/110] Implemented new more flexible readLineFrom (#1801) --- example/guess_number/main.zig | 8 ++-- std/io.zig | 76 ++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index ef0b9c08f..66264666b 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -24,15 +24,15 @@ pub fn main() !void { try stdout.print("\nGuess a number between 1 and 100: "); var line_buf: [20]u8 = undefined; - const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) { - error.InputTooLong => { + const line = io.readLineSlice(line_buf[0..]) catch |err| switch (err) { + error.OutOfMemory => { try stdout.print("Input too long.\n"); continue; }, - error.EndOfFile, error.StdInUnavailable => return err, + else => return err, }; - const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch { + const guess = fmt.parseUnsigned(u8, line, 10) catch { try stdout.print("Invalid number.\n"); continue; }; diff --git a/std/io.zig b/std/io.zig index 6473d993c..f4122a2f8 100644 --- a/std/io.zig +++ b/std/io.zig @@ -683,25 +683,73 @@ test "import io tests" { } } -pub fn readLine(buf: []u8) !usize { - var stdin = getStdIn() catch return error.StdInUnavailable; - var adapter = stdin.inStream(); - var stream = &adapter.stream; - var index: usize = 0; +pub fn readLine(buf: *std.Buffer) ![]u8 { + var stdin = try getStdIn(); + var stdin_stream = stdin.inStream(); + return readLineFrom(&stdin_stream.stream, buf); +} + +/// Reads all characters until the next newline into buf, and returns +/// a slice of the characters read (excluding the newline character(s)). +pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 { + const start = buf.len(); while (true) { - const byte = stream.readByte() catch return error.EndOfFile; + const byte = try stream.readByte(); switch (byte) { '\r' => { // trash the following \n - _ = stream.readByte() catch return error.EndOfFile; - return index; - }, - '\n' => return index, - else => { - if (index == buf.len) return error.InputTooLong; - buf[index] = byte; - index += 1; + _ = try stream.readByte(); + return buf.toSlice()[start..]; }, + '\n' => return buf.toSlice()[start..], + else => try buf.appendByte(byte), } } } + +test "io.readLineFrom" { + var bytes: [128]u8 = undefined; + const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; + + var buf = try std.Buffer.initSize(allocator, 0); + var mem_stream = SliceInStream.init( + \\Line 1 + \\Line 22 + \\Line 333 + ); + const stream = &mem_stream.stream; + + debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); + debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); + debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); + debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); +} + +pub fn readLineSlice(slice: []u8) ![]u8 { + var stdin = try getStdIn(); + var stdin_stream = stdin.inStream(); + return readLineSliceFrom(&stdin_stream.stream, slice); +} + +/// Reads all characters until the next newline into slice, and returns +/// a slice of the characters read (excluding the newline character(s)). +pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 { + // We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte + // after taking ownership, which would always require an allocation. + var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) }; + try buf.resize(0); + return try readLineFrom(stream, &buf); +} + +test "io.readLineSliceFrom" { + var buf: [7]u8 = undefined; + var mem_stream = SliceInStream.init( + \\Line 1 + \\Line 22 + \\Line 333 + ); + const stream = &mem_stream.stream; + + debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); + debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); +} From 5dfca87a65884f8564a8c8e2444bb906073425f3 Mon Sep 17 00:00:00 2001 From: Suirad Date: Thu, 22 Nov 2018 04:15:22 -0600 Subject: [PATCH 061/110] Update windows imports --- std/os/index.zig | 81 ++++++++++++++++++++++++++++++++----- std/os/windows/kernel32.zig | 6 +-- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 15be08c68..85e7eab01 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -702,8 +702,8 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { errdefer result.deinit(); if (is_windows) { - const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory; - defer assert(windows.FreeEnvironmentStringsA(ptr) != 0); + const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory; + defer assert(windows.FreeEnvironmentStringsW(ptr) != 0); var i: usize = 0; while (true) { @@ -712,17 +712,50 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { const key_start = i; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} - const key = ptr[key_start..i]; + + const stack_var_len = 50; + const key_slice = ptr[key_start..i]; + var key: []u8 = undefined; + var heap_key = false; + + // parse the key on the stack if smaller than 'stack_var_len' + if (key_slice.len < stack_var_len-@sizeOf(usize)) { + var buf = []u8{0} ** stack_var_len; + var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; + key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice); + } else { + key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); + heap_key = true; // key needs to outlive this scope, so we cannot defer + } if (ptr[i] == '=') i += 1; const value_start = i; while (ptr[i] != 0) : (i += 1) {} - const value = ptr[value_start..i]; + + const value_slice = ptr[value_start..i]; + var value: []u8 = undefined; + var heap_value = false; + + if (value_slice.len < stack_var_len-@sizeOf(usize)) { + var buf = []u8{0} ** stack_var_len; + var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; + value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice); + } else { + value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); + heap_value = true; // value needs to outlive this scope, so we cannot defer + } i += 1; // skip over null byte try result.set(key, value); + + if (heap_key) { + allocator.free(key); + } + if (heap_value) { + allocator.free(value); + } } } else { for (posix_environ_raw) |ptr| { @@ -740,6 +773,19 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { } } +test "os.getEnvMap" { + var env = try getEnvMap(std.debug.global_allocator); + var seen_path = false; + var it = env.iterator(); + while (it.next()) |pair| { + if (mem.eql(u8, pair.key, "PATH")) { + seen_path = true; + } + } + + assert(seen_path == true); +} + /// TODO make this go through libc when we have it pub fn getEnvPosix(key: []const u8) ?[]const u8 { for (posix_environ_raw) |ptr| { @@ -760,21 +806,27 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { pub const GetEnvVarOwnedError = error{ OutOfMemory, EnvironmentVariableNotFound, + DanglingSurrogateHalf, + ExpectedSecondSurrogateHalf, + UnexpectedSecondSurrogateHalf, + + /// See https://github.com/ziglang/zig/issues/1774 + InvalidUtf8, }; /// Caller must free returned memory. /// TODO make this go through libc when we have it pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { if (is_windows) { - const key_with_null = try cstr.addNullByte(allocator, key); + const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); defer allocator.free(key_with_null); - var buf = try allocator.alloc(u8, 256); - errdefer allocator.free(buf); + var buf = try allocator.alloc(u16, 256); + defer allocator.free(buf); while (true) { const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory; - const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len); + const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len); if (result == 0) { const err = windows.GetLastError(); @@ -788,11 +840,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } if (result > buf.len) { - buf = try allocator.realloc(u8, buf, result); + buf = try allocator.realloc(u16, buf, result); continue; } - return allocator.shrink(u8, buf, result); + return try std.unicode.utf16leToUtf8Alloc(allocator, buf); } } else { const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; @@ -800,6 +852,15 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } } +test "os.getEnvVarOwned" { + switch (builtin.os) { + builtin.Os.windows, builtin.Os.linux, builtin.Os.macosx, + builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "PATH"), + else => @compileError("unimplemented"), + } +} + + /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { var buf: [MAX_PATH_BYTES]u8 = undefined; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 7eec5faba..202b8bffe 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -50,7 +50,7 @@ pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFi pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL; pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL; -pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL; +pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsW(penv: [*]u16) BOOL; pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR; @@ -63,9 +63,9 @@ pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lp pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE; pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD; -pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8; +pub extern "kernel32" stdcallcc fn GetEnvironmentStringsW() ?[*]u16; -pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD; +pub extern "kernel32" stdcallcc fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) DWORD; pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL; From 0abd5520bdc8118369895f67f581d10c847ac139 Mon Sep 17 00:00:00 2001 From: Suirad Date: Sat, 24 Nov 2018 17:29:06 -0600 Subject: [PATCH 062/110] Platform specific tests --- std/os/index.zig | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 85e7eab01..62059a335 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -775,15 +775,26 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { test "os.getEnvMap" { var env = try getEnvMap(std.debug.global_allocator); - var seen_path = false; + var seen_home = false; var it = env.iterator(); while (it.next()) |pair| { - if (mem.eql(u8, pair.key, "PATH")) { - seen_path = true; - } + switch (builtin.os){ + builtin.Os.windows => { + if (mem.eql(u8, pair.key, "HOMEPATH")) { + seen_home = true; + } + }, + builtin.Os.linux, builtin.Os.macosx, + builtin.Os.ios => { + if (mem.eql(u8, pair.key, "HOME")) { + seen_home = true; + } + }, + else => @compileError("unimplemented"), + } } - assert(seen_path == true); + assert(seen_home == true); } /// TODO make this go through libc when we have it @@ -854,8 +865,10 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned test "os.getEnvVarOwned" { switch (builtin.os) { - builtin.Os.windows, builtin.Os.linux, builtin.Os.macosx, - builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "PATH"), + builtin.Os.windows => _ = try getEnvVarOwned(debug.global_allocator, "HOMEPATH"), + + builtin.Os.linux, builtin.Os.macosx, + builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "HOME"), else => @compileError("unimplemented"), } } From 24592d0216ce4830e9f0dd51a7d2542f1f8afa05 Mon Sep 17 00:00:00 2001 From: Suirad Date: Sat, 24 Nov 2018 19:21:12 -0600 Subject: [PATCH 063/110] Add more padding to parse buffer --- std/os/index.zig | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 62059a335..4272374b3 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -15,7 +15,7 @@ test "std.os" { _ = @import("get_user_id.zig"); _ = @import("linux/index.zig"); _ = @import("path.zig"); - _ = @import("test.zig"); + _ = @import("test.zig"); _ = @import("time.zig"); _ = @import("windows/index.zig"); _ = @import("get_app_data_dir.zig"); @@ -718,8 +718,9 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var key: []u8 = undefined; var heap_key = false; - // parse the key on the stack if smaller than 'stack_var_len' - if (key_slice.len < stack_var_len-@sizeOf(usize)) { + /// revisit needing the "-@sizeof(usize)*2" + /// after https://github.com/ziglang/zig/issues/1774 + if (key_slice.len < stack_var_len-@sizeOf(usize)*2) { var buf = []u8{0} ** stack_var_len; var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice); @@ -737,7 +738,9 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var value: []u8 = undefined; var heap_value = false; - if (value_slice.len < stack_var_len-@sizeOf(usize)) { + /// revisit needing the "-@sizeof(usize)*2" + /// after https://github.com/ziglang/zig/issues/1774 + if (value_slice.len < stack_var_len-@sizeOf(usize)*2) { var buf = []u8{0} ** stack_var_len; var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice); From 1fa2217c1008fefa7084ea34fedcf79ad214a02e Mon Sep 17 00:00:00 2001 From: Suirad Date: Thu, 29 Nov 2018 03:24:36 -0600 Subject: [PATCH 064/110] Simplify implementation --- std/os/index.zig | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index 4272374b3..cc7479b87 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -15,7 +15,7 @@ test "std.os" { _ = @import("get_user_id.zig"); _ = @import("linux/index.zig"); _ = @import("path.zig"); - _ = @import("test.zig"); + _ = @import("test.zig"); _ = @import("time.zig"); _ = @import("windows/index.zig"); _ = @import("get_app_data_dir.zig"); @@ -705,28 +705,26 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory; defer assert(windows.FreeEnvironmentStringsW(ptr) != 0); + var buf: [100]u8 = undefined; + var i: usize = 0; while (true) { if (ptr[i] == 0) return result; const key_start = i; + var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} - const stack_var_len = 50; const key_slice = ptr[key_start..i]; var key: []u8 = undefined; var heap_key = false; - /// revisit needing the "-@sizeof(usize)*2" - /// after https://github.com/ziglang/zig/issues/1774 - if (key_slice.len < stack_var_len-@sizeOf(usize)*2) { - var buf = []u8{0} ** stack_var_len; - var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; - key = try std.unicode.utf16leToUtf8Alloc(fallocator, key_slice); - } else { + key = std.unicode.utf16leToUtf8Alloc(fallocator, key_slice) catch undefined; + + if (key.len == 0) { key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); - heap_key = true; // key needs to outlive this scope, so we cannot defer + heap_key = true; } if (ptr[i] == '=') i += 1; @@ -738,15 +736,11 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { var value: []u8 = undefined; var heap_value = false; - /// revisit needing the "-@sizeof(usize)*2" - /// after https://github.com/ziglang/zig/issues/1774 - if (value_slice.len < stack_var_len-@sizeOf(usize)*2) { - var buf = []u8{0} ** stack_var_len; - var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; - value = try std.unicode.utf16leToUtf8Alloc(fallocator, value_slice); - } else { + value = std.unicode.utf16leToUtf8Alloc(fallocator, value_slice) catch undefined; + + if (value.len == 0) { value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); - heap_value = true; // value needs to outlive this scope, so we cannot defer + heap_value = true; } i += 1; // skip over null byte From e8e6ae57d41fdcdb4027ae95c04ad7aeea4a7aac Mon Sep 17 00:00:00 2001 From: Suirad Date: Thu, 29 Nov 2018 16:03:12 -0600 Subject: [PATCH 065/110] Find CI env variables --- std/os/index.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/std/os/index.zig b/std/os/index.zig index cc7479b87..d298ff432 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -775,6 +775,7 @@ test "os.getEnvMap" { var seen_home = false; var it = env.iterator(); while (it.next()) |pair| { + debug.warn("{}: {}\n", pair.key, pair.value); switch (builtin.os){ builtin.Os.windows => { if (mem.eql(u8, pair.key, "HOMEPATH")) { From cf266ff80a69d19140465b949350421dc541d4c8 Mon Sep 17 00:00:00 2001 From: Suirad Date: Fri, 30 Nov 2018 02:15:33 -0600 Subject: [PATCH 066/110] Update tests --- std/os/index.zig | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/std/os/index.zig b/std/os/index.zig index d298ff432..779fa8f8c 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -772,27 +772,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { test "os.getEnvMap" { var env = try getEnvMap(std.debug.global_allocator); - var seen_home = false; - var it = env.iterator(); - while (it.next()) |pair| { - debug.warn("{}: {}\n", pair.key, pair.value); - switch (builtin.os){ - builtin.Os.windows => { - if (mem.eql(u8, pair.key, "HOMEPATH")) { - seen_home = true; - } - }, - builtin.Os.linux, builtin.Os.macosx, - builtin.Os.ios => { - if (mem.eql(u8, pair.key, "HOME")) { - seen_home = true; - } - }, - else => @compileError("unimplemented"), - } - } - - assert(seen_home == true); + defer env.deinit(); } /// TODO make this go through libc when we have it @@ -862,13 +842,8 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } test "os.getEnvVarOwned" { - switch (builtin.os) { - builtin.Os.windows => _ = try getEnvVarOwned(debug.global_allocator, "HOMEPATH"), - - builtin.Os.linux, builtin.Os.macosx, - builtin.Os.ios => _ = try getEnvVarOwned(debug.global_allocator, "HOME"), - else => @compileError("unimplemented"), - } + var ga = debug.global_allocator; + debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); } From a9eab69b588176508d027f96eed298134433cd6e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 1 Dec 2018 01:21:59 -0500 Subject: [PATCH 067/110] zig build: addStaticExecutable --- std/build.zig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/std/build.zig b/std/build.zig index 5d894eeeb..034e3ce32 100644 --- a/std/build.zig +++ b/std/build.zig @@ -150,7 +150,11 @@ pub const Builder = struct { } pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return LibExeObjStep.createExecutable(self, name, root_src); + return LibExeObjStep.createExecutable(self, name, root_src, false); + } + + pub fn addStaticExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + return LibExeObjStep.createExecutable(self, name, root_src, true); } pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { @@ -891,8 +895,8 @@ pub const LibExeObjStep = struct { return self; } - pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable; + pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep { + const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable; return self; } @@ -1270,6 +1274,9 @@ pub const LibExeObjStep = struct { zig_args.append("--ver-patch") catch unreachable; zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable; } + if (self.kind == Kind.Exe and self.static) { + zig_args.append("--static") catch unreachable; + } switch (self.target) { Target.Native => {}, From 6f5e7ee09c9269cfcc454cde88960987054ee031 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 1 Dec 2018 02:14:17 -0500 Subject: [PATCH 068/110] make std.unicode.Utf8Iterator public --- std/unicode.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/unicode.zig b/std/unicode.zig index 559a2e739..fcb748401 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -208,7 +208,7 @@ pub const Utf8View = struct { } }; -const Utf8Iterator = struct { +pub const Utf8Iterator = struct { bytes: []const u8, i: usize, From a40d160a5ca7fe50680578541c40038e280272ce Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 2 Dec 2018 18:35:41 -0500 Subject: [PATCH 069/110] introduce std.io.SeekableStream Relevant #764 dwarf debug info is modified to use this instead of std.os.File directly to make it easier for bare metal projects to take advantage of debug info parsing --- CMakeLists.txt | 1 + std/debug/index.zig | 218 +++++++++++++++++++------------------ std/elf.zig | 45 ++++---- std/io.zig | 2 + std/io/seekable_stream.zig | 32 ++++++ std/os/file.zig | 64 ++++++++++- 6 files changed, 228 insertions(+), 134 deletions(-) create mode 100644 std/io/seekable_stream.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 9492d5dfa..0817c09f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -491,6 +491,7 @@ set(ZIG_STD_FILES "heap.zig" "index.zig" "io.zig" + "io/seekable_stream.zig" "json.zig" "lazy_init.zig" "linked_list.zig" diff --git a/std/debug/index.zig b/std/debug/index.zig index c31743265..3522da088 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -284,7 +284,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres const mod_index = for (di.sect_contribs) |sect_contrib| { if (sect_contrib.Section > di.coff.sections.len) continue; // Remember that SectionContribEntry.Section is 1-based. - coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1]; + coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1]; const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset; const vaddr_end = vaddr_start + sect_contrib.Size; @@ -872,9 +872,14 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { return list.toOwnedSlice(); } -fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { +pub fn openDwarfDebugInfo( + allocator: *mem.Allocator, + dwarf_seekable_stream: *DwarfSeekableStream, + dwarf_in_stream: *DwarfInStream, +) !DebugInfo { var di = DebugInfo{ - .self_exe_file = undefined, + .dwarf_seekable_stream = dwarf_seekable_stream, + .dwarf_in_stream = dwarf_in_stream, .elf = undefined, .debug_info = undefined, .debug_abbrev = undefined, @@ -884,10 +889,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), .compile_unit_list = ArrayList(CompileUnit).init(allocator), }; - di.self_exe_file = try os.openSelfExe(); - errdefer di.self_exe_file.close(); - - try di.elf.openFile(allocator, di.self_exe_file); + try di.elf.openStream(allocator, dwarf_seekable_stream, dwarf_in_stream); errdefer di.elf.close(); di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo; @@ -899,6 +901,27 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { return di; } +fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { + const S = struct { + var self_exe_file: os.File = undefined; + var self_exe_seekable_stream: os.File.SeekableStream = undefined; + var self_exe_in_stream: os.File.InStream = undefined; + }; + S.self_exe_file = try os.openSelfExe(); + errdefer S.self_exe_file.close(); + + S.self_exe_seekable_stream = S.self_exe_file.seekableStream(); + S.self_exe_in_stream = S.self_exe_file.inStream(); + + return openDwarfDebugInfo( + allocator, + // TODO https://github.com/ziglang/zig/issues/764 + @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream), + // TODO https://github.com/ziglang/zig/issues/764 + @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream), + ); +} + pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr { var file_stream = elf.in_file.inStream(); const in = &file_stream.stream; @@ -1053,6 +1076,9 @@ const MachOFile = struct { sect_debug_line: ?*const macho.section_64, }; +pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); +pub const DwarfInStream = io.InStream(anyerror); + pub const DebugInfo = switch (builtin.os) { builtin.Os.macosx => struct { symbols: []const MachoSymbol, @@ -1077,7 +1103,8 @@ pub const DebugInfo = switch (builtin.os) { modules: []Module, }, builtin.Os.linux => struct { - self_exe_file: os.File, + dwarf_seekable_stream: *DwarfSeekableStream, + dwarf_in_stream: *DwarfInStream, elf: elf.Elf, debug_info: *elf.SectionHeader, debug_abbrev: *elf.SectionHeader, @@ -1092,13 +1119,10 @@ pub const DebugInfo = switch (builtin.os) { } pub fn readString(self: *DebugInfo) ![]u8 { - var in_file_stream = self.self_exe_file.inStream(); - const in_stream = &in_file_stream.stream; - return readStringRaw(self.allocator(), in_stream); + return readStringRaw(self.allocator(), self.dwarf_in_stream); } pub fn close(self: *DebugInfo) void { - self.self_exe_file.close(); self.elf.close(); } }, @@ -1206,11 +1230,11 @@ const Die = struct { }; } - fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 { + fn getAttrString(self: *const Die, di: *DebugInfo, id: u64) ![]u8 { const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; return switch (form_value.*) { FormValue.String => |value| value, - FormValue.StrPtr => |offset| getString(st, offset), + FormValue.StrPtr => |offset| getString(di, offset), else => error.InvalidDebugInfo, }; } @@ -1321,10 +1345,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { return buf.toSlice(); } -fn getString(st: *DebugInfo, offset: u64) ![]u8 { - const pos = st.debug_str.offset + offset; - try st.self_exe_file.seekTo(pos); - return st.readString(); +fn getString(di: *DebugInfo, offset: u64) ![]u8 { + const pos = di.debug_str.offset + offset; + try di.dwarf_seekable_stream.seekTo(pos); + return di.readString(); } fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 { @@ -1371,14 +1395,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type return parseFormValueRefLen(allocator, in_stream, block_len); } -const ParseFormValueError = error{ - EndOfStream, - InvalidDebugInfo, - EndOfFile, - OutOfMemory, -} || std.os.File.ReadError; - -fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue { +fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue { return switch (form_id) { DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) }, DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), @@ -1428,25 +1445,22 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }; } -fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { - const in_file = st.self_exe_file; - var in_file_stream = in_file.inStream(); - const in_stream = &in_file_stream.stream; - var result = AbbrevTable.init(st.allocator()); +fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable { + var result = AbbrevTable.init(di.allocator()); while (true) { - const abbrev_code = try readULeb128(in_stream); + const abbrev_code = try readULeb128(di.dwarf_in_stream); if (abbrev_code == 0) return result; try result.append(AbbrevTableEntry{ .abbrev_code = abbrev_code, - .tag_id = try readULeb128(in_stream), - .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes, - .attrs = ArrayList(AbbrevAttr).init(st.allocator()), + .tag_id = try readULeb128(di.dwarf_in_stream), + .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes, + .attrs = ArrayList(AbbrevAttr).init(di.allocator()), }); const attrs = &result.items[result.len - 1].attrs; while (true) { - const attr_id = try readULeb128(in_stream); - const form_id = try readULeb128(in_stream); + const attr_id = try readULeb128(di.dwarf_in_stream); + const form_id = try readULeb128(di.dwarf_in_stream); if (attr_id == 0 and form_id == 0) break; try attrs.append(AbbrevAttr{ .attr_id = attr_id, @@ -1458,18 +1472,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, /// seeks in the stream and parses it. -fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable { - for (st.abbrev_table_list.toSlice()) |*header| { +fn getAbbrevTable(di: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable { + for (di.abbrev_table_list.toSlice()) |*header| { if (header.offset == abbrev_offset) { return &header.table; } } - try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset); - try st.abbrev_table_list.append(AbbrevTableHeader{ + try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset); + try di.abbrev_table_list.append(AbbrevTableHeader{ .offset = abbrev_offset, - .table = try parseAbbrevTable(st), + .table = try parseAbbrevTable(di), }); - return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table; + return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table; } fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry { @@ -1479,23 +1493,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con return null; } -fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { - const in_file = st.self_exe_file; - var in_file_stream = in_file.inStream(); - const in_stream = &in_file_stream.stream; - const abbrev_code = try readULeb128(in_stream); +fn parseDie(di: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { + const abbrev_code = try readULeb128(di.dwarf_in_stream); const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; var result = Die{ .tag_id = table_entry.tag_id, .has_children = table_entry.has_children, - .attrs = ArrayList(Die.Attr).init(st.allocator()), + .attrs = ArrayList(Die.Attr).init(di.allocator()), }; try result.attrs.resize(table_entry.attrs.len); for (table_entry.attrs.toSliceConst()) |attr, i| { result.attrs.items[i] = Die.Attr{ .id = attr.attr_id, - .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64), + .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64), }; } return result; @@ -1702,19 +1713,15 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); - const in_file = di.self_exe_file; const debug_line_end = di.debug_line.offset + di.debug_line.size; var this_offset = di.debug_line.offset; var this_index: usize = 0; - var in_file_stream = in_file.inStream(); - const in_stream = &in_file_stream.stream; - while (this_offset < debug_line_end) : (this_index += 1) { - try in_file.seekTo(this_offset); + try di.dwarf_seekable_stream.seekTo(this_offset); var is_64: bool = undefined; - const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); + const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); if (unit_length == 0) return error.MissingDebugInfo; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); @@ -1723,35 +1730,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ continue; } - const version = try in_stream.readInt(di.elf.endian, u16); + const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16); // TODO support 3 and 5 if (version != 2 and version != 4) return error.InvalidDebugInfo; - const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32); - const prog_start_offset = (try in_file.getPos()) + prologue_length; + const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32); + const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; - const minimum_instruction_length = try in_stream.readByte(); + const minimum_instruction_length = try di.dwarf_in_stream.readByte(); if (minimum_instruction_length == 0) return error.InvalidDebugInfo; if (version >= 4) { // maximum_operations_per_instruction - _ = try in_stream.readByte(); + _ = try di.dwarf_in_stream.readByte(); } - const default_is_stmt = (try in_stream.readByte()) != 0; - const line_base = try in_stream.readByteSigned(); + const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0; + const line_base = try di.dwarf_in_stream.readByteSigned(); - const line_range = try in_stream.readByte(); + const line_range = try di.dwarf_in_stream.readByte(); if (line_range == 0) return error.InvalidDebugInfo; - const opcode_base = try in_stream.readByte(); + const opcode_base = try di.dwarf_in_stream.readByte(); const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); { var i: usize = 0; while (i < opcode_base - 1) : (i += 1) { - standard_opcode_lengths[i] = try in_stream.readByte(); + standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte(); } } @@ -1769,9 +1776,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ while (true) { const file_name = try di.readString(); if (file_name.len == 0) break; - const dir_index = try readULeb128(in_stream); - const mtime = try readULeb128(in_stream); - const len_bytes = try readULeb128(in_stream); + const dir_index = try readULeb128(di.dwarf_in_stream); + const mtime = try readULeb128(di.dwarf_in_stream); + const len_bytes = try readULeb128(di.dwarf_in_stream); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1780,15 +1787,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ }); } - try in_file.seekTo(prog_start_offset); + try di.dwarf_seekable_stream.seekTo(prog_start_offset); while (true) { - const opcode = try in_stream.readByte(); + const opcode = try di.dwarf_in_stream.readByte(); if (opcode == DW.LNS_extended_op) { - const op_size = try readULeb128(in_stream); + const op_size = try readULeb128(di.dwarf_in_stream); if (op_size < 1) return error.InvalidDebugInfo; - var sub_op = try in_stream.readByte(); + var sub_op = try di.dwarf_in_stream.readByte(); switch (sub_op) { DW.LNE_end_sequence => { prog.end_sequence = true; @@ -1796,14 +1803,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ return error.MissingDebugInfo; }, DW.LNE_set_address => { - const addr = try in_stream.readInt(di.elf.endian, usize); + const addr = try di.dwarf_in_stream.readInt(di.elf.endian, usize); prog.address = addr; }, DW.LNE_define_file => { const file_name = try di.readString(); - const dir_index = try readULeb128(in_stream); - const mtime = try readULeb128(in_stream); - const len_bytes = try readULeb128(in_stream); + const dir_index = try readULeb128(di.dwarf_in_stream); + const mtime = try readULeb128(di.dwarf_in_stream); + const len_bytes = try readULeb128(di.dwarf_in_stream); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1813,7 +1820,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ }, else => { const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo; - try in_file.seekForward(fwd_amt); + try di.dwarf_seekable_stream.seekForward(fwd_amt); }, } } else if (opcode >= opcode_base) { @@ -1832,19 +1839,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ prog.basic_block = false; }, DW.LNS_advance_pc => { - const arg = try readULeb128(in_stream); + const arg = try readULeb128(di.dwarf_in_stream); prog.address += arg * minimum_instruction_length; }, DW.LNS_advance_line => { - const arg = try readILeb128(in_stream); + const arg = try readILeb128(di.dwarf_in_stream); prog.line += arg; }, DW.LNS_set_file => { - const arg = try readULeb128(in_stream); + const arg = try readULeb128(di.dwarf_in_stream); prog.file = arg; }, DW.LNS_set_column => { - const arg = try readULeb128(in_stream); + const arg = try readULeb128(di.dwarf_in_stream); prog.column = arg; }, DW.LNS_negate_stmt => { @@ -1858,14 +1865,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = try in_stream.readInt(di.elf.endian, u16); + const arg = try di.dwarf_in_stream.readInt(di.elf.endian, u16); prog.address += arg; }, DW.LNS_set_prologue_end => {}, else => { if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; const len_bytes = standard_opcode_lengths[opcode - 1]; - try in_file.seekForward(len_bytes); + try di.dwarf_seekable_stream.seekForward(len_bytes); }, } } @@ -1877,36 +1884,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ return error.MissingDebugInfo; } -fn scanAllCompileUnits(st: *DebugInfo) !void { - const debug_info_end = st.debug_info.offset + st.debug_info.size; - var this_unit_offset = st.debug_info.offset; +fn scanAllCompileUnits(di: *DebugInfo) !void { + const debug_info_end = di.debug_info.offset + di.debug_info.size; + var this_unit_offset = di.debug_info.offset; var cu_index: usize = 0; - var in_file_stream = st.self_exe_file.inStream(); - const in_stream = &in_file_stream.stream; - while (this_unit_offset < debug_info_end) { - try st.self_exe_file.seekTo(this_unit_offset); + try di.dwarf_seekable_stream.seekTo(this_unit_offset); var is_64: bool = undefined; - const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); + const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); - const version = try in_stream.readInt(st.elf.endian, u16); + const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16); if (version < 2 or version > 5) return error.InvalidDebugInfo; - const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32); + const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32); - const address_size = try in_stream.readByte(); + const address_size = try di.dwarf_in_stream.readByte(); if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; - const compile_unit_pos = try st.self_exe_file.getPos(); - const abbrev_table = try getAbbrevTable(st, debug_abbrev_offset); + const compile_unit_pos = try di.dwarf_seekable_stream.getPos(); + const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset); - try st.self_exe_file.seekTo(compile_unit_pos); + try di.dwarf_seekable_stream.seekTo(compile_unit_pos); - const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64)); + const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64)); if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; @@ -1934,7 +1938,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { } }; - try st.compile_unit_list.append(CompileUnit{ + try di.compile_unit_list.append(CompileUnit{ .version = version, .is_64 = is_64, .pc_range = pc_range, @@ -1947,20 +1951,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { } } -fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit { - var in_file_stream = st.self_exe_file.inStream(); - const in_stream = &in_file_stream.stream; - for (st.compile_unit_list.toSlice()) |*compile_unit| { +fn findCompileUnit(di: *DebugInfo, target_address: u64) !*const CompileUnit { + for (di.compile_unit_list.toSlice()) |*compile_unit| { if (compile_unit.pc_range) |range| { if (target_address >= range.start and target_address < range.end) return compile_unit; } if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| { var base_address: usize = 0; - if (st.debug_ranges) |debug_ranges| { - try st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset); + if (di.debug_ranges) |debug_ranges| { + try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset); while (true) { - const begin_addr = try in_stream.readIntLe(usize); - const end_addr = try in_stream.readIntLe(usize); + const begin_addr = try di.dwarf_in_stream.readIntLe(usize); + const end_addr = try di.dwarf_in_stream.readIntLe(usize); if (begin_addr == 0 and end_addr == 0) { break; } diff --git a/std/elf.zig b/std/elf.zig index e95222744..cf7c29b1e 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -353,7 +353,8 @@ pub const SectionHeader = struct { }; pub const Elf = struct { - in_file: os.File, + seekable_stream: *io.SeekableStream(anyerror, anyerror), + in_stream: *io.InStream(anyerror), auto_close_stream: bool, is_64: bool, endian: builtin.Endian, @@ -370,19 +371,24 @@ pub const Elf = struct { /// Call close when done. pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void { - try elf.prealloc_file.open(path); - try elf.openFile(allocator, *elf.prealloc_file); - elf.auto_close_stream = true; + @compileError("TODO implement"); } /// Call close when done. pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void { - elf.allocator = allocator; - elf.in_file = file; - elf.auto_close_stream = false; + @compileError("TODO implement"); + } - var file_stream = elf.in_file.inStream(); - const in = &file_stream.stream; + pub fn openStream( + elf: *Elf, + allocator: *mem.Allocator, + seekable_stream: *io.SeekableStream(anyerror, anyerror), + in: *io.InStream(anyerror), + ) !void { + elf.auto_close_stream = false; + elf.allocator = allocator; + elf.seekable_stream = seekable_stream; + elf.in_stream = in; var magic: [4]u8 = undefined; try in.readNoEof(magic[0..]); @@ -404,7 +410,7 @@ pub const Elf = struct { if (version_byte != 1) return error.InvalidFormat; // skip over padding - try elf.in_file.seekForward(9); + try seekable_stream.seekForward(9); elf.file_type = switch (try in.readInt(elf.endian, u16)) { 1 => FileType.Relocatable, @@ -441,7 +447,7 @@ pub const Elf = struct { } // skip over flags - try elf.in_file.seekForward(4); + try seekable_stream.seekForward(4); const header_size = try in.readInt(elf.endian, u16); if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { @@ -461,12 +467,12 @@ pub const Elf = struct { const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count); const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count); - const stream_end = try elf.in_file.getEndPos(); + const stream_end = try seekable_stream.getEndPos(); if (stream_end < end_sh or stream_end < end_ph) { return error.InvalidFormat; } - try elf.in_file.seekTo(elf.section_header_offset); + try seekable_stream.seekTo(elf.section_header_offset); elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count); errdefer elf.allocator.free(elf.section_headers); @@ -521,26 +527,23 @@ pub const Elf = struct { pub fn close(elf: *Elf) void { elf.allocator.free(elf.section_headers); - if (elf.auto_close_stream) elf.in_file.close(); + if (elf.auto_close_stream) elf.prealloc_file.close(); } pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader { - var file_stream = elf.in_file.inStream(); - const in = &file_stream.stream; - section_loop: for (elf.section_headers) |*elf_section| { if (elf_section.sh_type == SHT_NULL) continue; const name_offset = elf.string_section.offset + elf_section.name; - try elf.in_file.seekTo(name_offset); + try elf.seekable_stream.seekTo(name_offset); for (name) |expected_c| { - const target_c = try in.readByte(); + const target_c = try elf.in_stream.readByte(); if (target_c == 0 or expected_c != target_c) continue :section_loop; } { - const null_byte = try in.readByte(); + const null_byte = try elf.in_stream.readByte(); if (null_byte == 0) return elf_section; } } @@ -549,7 +552,7 @@ pub const Elf = struct { } pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void { - try elf.in_file.seekTo(elf_section.offset); + try elf.seekable_stream.seekTo(elf_section.offset); } }; diff --git a/std/io.zig b/std/io.zig index f4122a2f8..bdca2b03e 100644 --- a/std/io.zig +++ b/std/io.zig @@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File { return File.openHandle(handle); } +pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; + pub fn InStream(comptime ReadError: type) type { return struct { const Self = @This(); diff --git a/std/io/seekable_stream.zig b/std/io/seekable_stream.zig new file mode 100644 index 000000000..a766f4fb8 --- /dev/null +++ b/std/io/seekable_stream.zig @@ -0,0 +1,32 @@ +const std = @import("../index.zig"); +const InStream = std.io.InStream; + +pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type { + return struct { + const Self = @This(); + pub const SeekError = SeekErrorType; + pub const GetSeekPosError = GetSeekPosErrorType; + + seekToFn: fn (self: *Self, pos: usize) SeekError!void, + seekForwardFn: fn (self: *Self, pos: isize) SeekError!void, + + getPosFn: fn (self: *Self) GetSeekPosError!usize, + getEndPosFn: fn (self: *Self) GetSeekPosError!usize, + + pub fn seekTo(self: *Self, pos: usize) SeekError!void { + return self.seekToFn(self, pos); + } + + pub fn seekForward(self: *Self, amt: isize) SeekError!void { + return self.seekForwardFn(self, amt); + } + + pub fn getEndPos(self: *Self) GetSeekPosError!usize { + return self.getEndPosFn(self); + } + + pub fn getPos(self: *Self) GetSeekPosError!usize { + return self.getPosFn(self); + } + }; +} diff --git a/std/os/file.zig b/std/os/file.zig index 82bd24fec..2ae547c69 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -228,7 +228,14 @@ pub const File = struct { return os.isTty(self.handle); } - pub fn seekForward(self: File, amount: isize) !void { + pub const SeekError = error{ + /// TODO make this error impossible to get + Overflow, + Unseekable, + Unexpected, + }; + + pub fn seekForward(self: File, amount: isize) SeekError!void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd => { const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); @@ -259,7 +266,7 @@ pub const File = struct { } } - pub fn seekTo(self: File, pos: usize) !void { + pub fn seekTo(self: File, pos: usize) SeekError!void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd => { const ipos = try math.cast(isize, pos); @@ -293,7 +300,14 @@ pub const File = struct { } } - pub fn getPos(self: File) !usize { + pub const GetSeekPosError = error{ + Overflow, + SystemResources, + Unseekable, + Unexpected, + }; + + pub fn getPos(self: File) GetSeekPosError!usize { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd => { const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); @@ -323,13 +337,13 @@ pub const File = struct { } assert(pos >= 0); - return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange; + return math.cast(usize, pos); }, else => @compileError("unsupported OS"), } } - pub fn getEndPos(self: File) !usize { + pub fn getEndPos(self: File) GetSeekPosError!usize { if (is_posix) { const stat = try os.posixFStat(self.handle); return @intCast(usize, stat.size); @@ -431,6 +445,18 @@ pub const File = struct { }; } + pub fn seekableStream(file: File) SeekableStream { + return SeekableStream{ + .file = file, + .stream = SeekableStream.Stream{ + .seekToFn = SeekableStream.seekToFn, + .seekForwardFn = SeekableStream.seekForwardFn, + .getPosFn = SeekableStream.getPosFn, + .getEndPosFn = SeekableStream.getEndPosFn, + }, + }; + } + /// Implementation of io.InStream trait for File pub const InStream = struct { file: File, @@ -458,4 +484,32 @@ pub const File = struct { return self.file.write(bytes); } }; + + /// Implementation of io.SeekableStream trait for File + pub const SeekableStream = struct { + file: File, + stream: Stream, + + pub const Stream = io.SeekableStream(SeekError, GetSeekPosError); + + pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.seekTo(pos); + } + + pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.seekForward(amt); + } + + pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.getEndPos(); + } + + pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.getPos(); + } + }; }; From 4292ed9571ede4d616e92e9cba3986a07d135955 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 2 Dec 2018 18:54:04 -0500 Subject: [PATCH 070/110] std.debug.StackIterator --- std/debug/index.zig | 69 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 3522da088..268087664 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -198,49 +198,46 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, } } -pub inline fn getReturnAddress(frame_count: usize) usize { - var fp = @ptrToInt(@frameAddress()); - var i: usize = 0; - while (fp != 0 and i < frame_count) { - fp = @intToPtr(*const usize, fp).*; - i += 1; +pub const StackIterator = struct { + first_addr: ?usize, + debug_info: *DebugInfo, + fp: usize, + + pub fn init(debug_info: *DebugInfo, first_addr: ?usize) StackIterator { + return StackIterator{ + .debug_info = debug_info, + .first_addr = first_addr, + .fp = @ptrToInt(@frameAddress()), + }; } - return @intToPtr(*const usize, fp + @sizeOf(usize)).*; -} + + fn next(self: *StackIterator) ?usize { + if (self.fp == 0) return null; + self.fp = @intToPtr(*const usize, self.fp).*; + if (self.fp == 0) return null; + + if (self.first_addr) |addr| { + while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) { + const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*; + if (addr == return_address) { + self.first_addr = null; + return return_address; + } + } + } + + const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*; + return return_address; + } +}; pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { switch (builtin.os) { builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr), else => {}, } - const AddressState = union(enum) { - NotLookingForStartAddress, - LookingForStartAddress: usize, - }; - // TODO: I want to express like this: - //var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr } - // else AddressState.NotLookingForStartAddress; - var addr_state: AddressState = undefined; - if (start_addr) |addr| { - addr_state = AddressState{ .LookingForStartAddress = addr }; - } else { - addr_state = AddressState.NotLookingForStartAddress; - } - - var fp = @ptrToInt(@frameAddress()); - while (fp != 0) : (fp = @intToPtr(*const usize, fp).*) { - const return_address = @intToPtr(*const usize, fp + @sizeOf(usize)).*; - - switch (addr_state) { - AddressState.NotLookingForStartAddress => {}, - AddressState.LookingForStartAddress => |addr| { - if (return_address == addr) { - addr_state = AddressState.NotLookingForStartAddress; - } else { - continue; - } - }, - } + var it = StackIterator.init(debug_info, start_addr); + while (it.next()) |return_address| { try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); } } From a436d2ab8c61f46d97a5c31ac083ef8fa54ed706 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 2 Dec 2018 19:34:11 -0500 Subject: [PATCH 071/110] std.debug.printSourceAtAddressDwarf which works in freestanding mode --- std/debug/index.zig | 54 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 268087664..b74c412df 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -411,7 +411,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres if (opt_line_info) |line_info| { try out_stream.print("\n"); - if (printLineFromFile(out_stream, line_info)) { + if (printLineFromFileAnyOs(out_stream, line_info)) { if (line_info.column == 0) { try out_stream.write("\n"); } else { @@ -595,7 +595,16 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt } else "???"; if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { defer line_info.deinit(); - try printLineInfo(di, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); + try printLineInfo( + di, + out_stream, + line_info, + address, + symbol_name, + compile_unit_name, + tty_color, + printLineFromFileAnyOs, + ); } else |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => { if (tty_color) { @@ -608,7 +617,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt } } -pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { +/// This function works in freestanding mode. +/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void +pub fn printSourceAtAddressDwarf( + debug_info: *DebugInfo, + out_stream: var, + address: usize, + tty_color: bool, + comptime printLineFromFile: var, +) !void { const compile_unit = findCompileUnit(debug_info, address) catch { if (tty_color) { try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address); @@ -618,10 +635,19 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres return; }; const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); - if (getLineNumberInfoLinux(debug_info, compile_unit, address - 1)) |line_info| { + if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| { defer line_info.deinit(); const symbol_name = "???"; - try printLineInfo(debug_info, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); + try printLineInfo( + debug_info, + out_stream, + line_info, + address, + symbol_name, + compile_unit_name, + tty_color, + printLineFromFile, + ); } else |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => { if (tty_color) { @@ -634,6 +660,10 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres } } +pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { + return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs); +} + fn printLineInfo( debug_info: *DebugInfo, out_stream: var, @@ -642,6 +672,7 @@ fn printLineInfo( symbol_name: []const u8, compile_unit_name: []const u8, tty_color: bool, + comptime printLineFromFile: var, ) !void { if (tty_color) { try out_stream.print( @@ -1020,7 +1051,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { }; } -fn printLineFromFile(out_stream: var, line_info: LineInfo) !void { +fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { var f = try os.File.openRead(line_info.file_name); defer f.close(); // TODO fstat and make sure that the file has the correct size @@ -1247,11 +1278,12 @@ const FileEntry = struct { const LineInfo = struct { line: usize, column: usize, - file_name: []u8, - allocator: *mem.Allocator, + file_name: []const u8, + allocator: ?*mem.Allocator, - fn deinit(self: *const LineInfo) void { - self.allocator.free(self.file_name); + fn deinit(self: LineInfo) void { + const allocator = self.allocator orelse return; + allocator.free(self.file_name); } }; @@ -1707,7 +1739,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u return error.MissingDebugInfo; } -fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { +fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); const debug_line_end = di.debug_line.offset + di.debug_line.size; From 5c3b8cb3659172b539423972d996a66221c0e4a0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 2 Dec 2018 20:08:06 -0500 Subject: [PATCH 072/110] expose std.debug.DwarfInfo and delete unused function --- std/debug/index.zig | 74 ++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 48 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index b74c412df..ebf0f21a7 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -950,30 +950,6 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { ); } -pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr { - var file_stream = elf.in_file.inStream(); - const in = &file_stream.stream; - - section_loop: for (elf.section_headers) |*elf_section| { - if (elf_section.sh_type == SHT_NULL) continue; - - const name_offset = elf.string_section.offset + elf_section.name; - try elf.in_file.seekTo(name_offset); - - for (name) |expected_c| { - const target_c = try in.readByte(); - if (target_c == 0 or expected_c != target_c) continue :section_loop; - } - - { - const null_byte = try in.readByte(); - if (null_byte == 0) return elf_section; - } - } - - return null; -} - fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { const hdr = &std.c._mh_execute_header; assert(hdr.magic == std.macho.MH_MAGIC_64); @@ -1107,6 +1083,31 @@ const MachOFile = struct { pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); pub const DwarfInStream = io.InStream(anyerror); +pub const DwarfInfo = struct { + dwarf_seekable_stream: *DwarfSeekableStream, + dwarf_in_stream: *DwarfInStream, + elf: elf.Elf, + debug_info: *elf.SectionHeader, + debug_abbrev: *elf.SectionHeader, + debug_str: *elf.SectionHeader, + debug_line: *elf.SectionHeader, + debug_ranges: ?*elf.SectionHeader, + abbrev_table_list: ArrayList(AbbrevTableHeader), + compile_unit_list: ArrayList(CompileUnit), + + pub fn allocator(self: DebugInfo) *mem.Allocator { + return self.abbrev_table_list.allocator; + } + + pub fn readString(self: *DebugInfo) ![]u8 { + return readStringRaw(self.allocator(), self.dwarf_in_stream); + } + + pub fn close(self: *DebugInfo) void { + self.elf.close(); + } +}; + pub const DebugInfo = switch (builtin.os) { builtin.Os.macosx => struct { symbols: []const MachoSymbol, @@ -1130,30 +1131,7 @@ pub const DebugInfo = switch (builtin.os) { sect_contribs: []pdb.SectionContribEntry, modules: []Module, }, - builtin.Os.linux => struct { - dwarf_seekable_stream: *DwarfSeekableStream, - dwarf_in_stream: *DwarfInStream, - elf: elf.Elf, - debug_info: *elf.SectionHeader, - debug_abbrev: *elf.SectionHeader, - debug_str: *elf.SectionHeader, - debug_line: *elf.SectionHeader, - debug_ranges: ?*elf.SectionHeader, - abbrev_table_list: ArrayList(AbbrevTableHeader), - compile_unit_list: ArrayList(CompileUnit), - - pub fn allocator(self: DebugInfo) *mem.Allocator { - return self.abbrev_table_list.allocator; - } - - pub fn readString(self: *DebugInfo) ![]u8 { - return readStringRaw(self.allocator(), self.dwarf_in_stream); - } - - pub fn close(self: *DebugInfo) void { - self.elf.close(); - } - }, + builtin.Os.linux => DwarfInfo, builtin.Os.freebsd => struct {}, else => @compileError("Unsupported OS"), }; From 3a1612a0f5a41f5cfc9598dc4512b43ee17d030a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 2 Dec 2018 23:46:45 -0500 Subject: [PATCH 073/110] std.debug: fix some issues with freestanding debug info --- std/debug/index.zig | 132 ++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index ebf0f21a7..4a96e9d25 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -200,12 +200,10 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, pub const StackIterator = struct { first_addr: ?usize, - debug_info: *DebugInfo, fp: usize, - pub fn init(debug_info: *DebugInfo, first_addr: ?usize) StackIterator { + pub fn init(first_addr: ?usize) StackIterator { return StackIterator{ - .debug_info = debug_info, .first_addr = first_addr, .fp = @ptrToInt(@frameAddress()), }; @@ -236,7 +234,7 @@ pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr), else => {}, } - var it = StackIterator.init(debug_info, start_addr); + var it = StackIterator.init(start_addr); while (it.next()) |return_address| { try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); } @@ -596,7 +594,6 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { defer line_info.deinit(); try printLineInfo( - di, out_stream, line_info, address, @@ -620,7 +617,7 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt /// This function works in freestanding mode. /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void pub fn printSourceAtAddressDwarf( - debug_info: *DebugInfo, + debug_info: *DwarfInfo, out_stream: var, address: usize, tty_color: bool, @@ -639,7 +636,6 @@ pub fn printSourceAtAddressDwarf( defer line_info.deinit(); const symbol_name = "???"; try printLineInfo( - debug_info, out_stream, line_info, address, @@ -665,7 +661,6 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres } fn printLineInfo( - debug_info: *DebugInfo, out_stream: var, line_info: LineInfo, address: usize, @@ -900,36 +895,50 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { return list.toOwnedSlice(); } -pub fn openDwarfDebugInfo( - allocator: *mem.Allocator, - dwarf_seekable_stream: *DwarfSeekableStream, - dwarf_in_stream: *DwarfInStream, -) !DebugInfo { - var di = DebugInfo{ - .dwarf_seekable_stream = dwarf_seekable_stream, - .dwarf_in_stream = dwarf_in_stream, - .elf = undefined, - .debug_info = undefined, - .debug_abbrev = undefined, - .debug_str = undefined, - .debug_line = undefined, - .debug_ranges = null, - .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), - .compile_unit_list = ArrayList(CompileUnit).init(allocator), +fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section { + const elf_header = (try elf_file.findSection(name)) orelse return null; + return DwarfInfo.Section{ + .offset = elf_header.offset, + .size = elf_header.size, }; - try di.elf.openStream(allocator, dwarf_seekable_stream, dwarf_in_stream); - errdefer di.elf.close(); +} - di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo; - di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo; - di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo; - di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo; - di.debug_ranges = (try di.elf.findSection(".debug_ranges")); - try scanAllCompileUnits(&di); +/// Initialize DWARF info. The caller has the responsibility to initialize most +/// the DwarfInfo fields before calling. These fields can be left undefined: +/// * abbrev_table_list +/// * compile_unit_list +pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void { + di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator); + di.compile_unit_list = ArrayList(CompileUnit).init(allocator); + try scanAllCompileUnits(di); +} + +pub fn openElfDebugInfo( + allocator: *mem.Allocator, + elf_seekable_stream: *DwarfSeekableStream, + elf_in_stream: *DwarfInStream, +) !DwarfInfo { + var efile: elf.Elf = undefined; + try efile.openStream(allocator, elf_seekable_stream, elf_in_stream); + errdefer efile.close(); + + var di = DwarfInfo{ + .dwarf_seekable_stream = elf_seekable_stream, + .dwarf_in_stream = elf_in_stream, + .endian = efile.endian, + .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo, + .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo, + .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo, + .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo, + .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")), + .abbrev_table_list = undefined, + .compile_unit_list = undefined, + }; + try openDwarfDebugInfo(&di, allocator); return di; } -fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { +fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo { const S = struct { var self_exe_file: os.File = undefined; var self_exe_seekable_stream: os.File.SeekableStream = undefined; @@ -941,7 +950,7 @@ fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { S.self_exe_seekable_stream = S.self_exe_file.seekableStream(); S.self_exe_in_stream = S.self_exe_file.inStream(); - return openDwarfDebugInfo( + return openElfDebugInfo( allocator, // TODO https://github.com/ziglang/zig/issues/764 @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream), @@ -1086,26 +1095,27 @@ pub const DwarfInStream = io.InStream(anyerror); pub const DwarfInfo = struct { dwarf_seekable_stream: *DwarfSeekableStream, dwarf_in_stream: *DwarfInStream, - elf: elf.Elf, - debug_info: *elf.SectionHeader, - debug_abbrev: *elf.SectionHeader, - debug_str: *elf.SectionHeader, - debug_line: *elf.SectionHeader, - debug_ranges: ?*elf.SectionHeader, + endian: builtin.Endian, + debug_info: Section, + debug_abbrev: Section, + debug_str: Section, + debug_line: Section, + debug_ranges: ?Section, abbrev_table_list: ArrayList(AbbrevTableHeader), compile_unit_list: ArrayList(CompileUnit), - pub fn allocator(self: DebugInfo) *mem.Allocator { + pub const Section = struct { + offset: usize, + size: usize, + }; + + pub fn allocator(self: DwarfInfo) *mem.Allocator { return self.abbrev_table_list.allocator; } - pub fn readString(self: *DebugInfo) ![]u8 { + pub fn readString(self: *DwarfInfo) ![]u8 { return readStringRaw(self.allocator(), self.dwarf_in_stream); } - - pub fn close(self: *DebugInfo) void { - self.elf.close(); - } }; pub const DebugInfo = switch (builtin.os) { @@ -1236,7 +1246,7 @@ const Die = struct { }; } - fn getAttrString(self: *const Die, di: *DebugInfo, id: u64) ![]u8 { + fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 { const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; return switch (form_value.*) { FormValue.String => |value| value, @@ -1253,7 +1263,7 @@ const FileEntry = struct { len_bytes: usize, }; -const LineInfo = struct { +pub const LineInfo = struct { line: usize, column: usize, file_name: []const u8, @@ -1352,7 +1362,7 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { return buf.toSlice(); } -fn getString(di: *DebugInfo, offset: u64) ![]u8 { +fn getString(di: *DwarfInfo, offset: u64) ![]u8 { const pos = di.debug_str.offset + offset; try di.dwarf_seekable_stream.seekTo(pos); return di.readString(); @@ -1452,7 +1462,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }; } -fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable { +fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable { var result = AbbrevTable.init(di.allocator()); while (true) { const abbrev_code = try readULeb128(di.dwarf_in_stream); @@ -1479,7 +1489,7 @@ fn parseAbbrevTable(di: *DebugInfo) !AbbrevTable { /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, /// seeks in the stream and parses it. -fn getAbbrevTable(di: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable { +fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable { for (di.abbrev_table_list.toSlice()) |*header| { if (header.offset == abbrev_offset) { return &header.table; @@ -1500,7 +1510,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con return null; } -fn parseDie(di: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { +fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { const abbrev_code = try readULeb128(di.dwarf_in_stream); const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; @@ -1717,7 +1727,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u return error.MissingDebugInfo; } -fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { +fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); const debug_line_end = di.debug_line.offset + di.debug_line.size; @@ -1737,11 +1747,11 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr continue; } - const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16); + const version = try di.dwarf_in_stream.readInt(di.endian, u16); // TODO support 3 and 5 if (version != 2 and version != 4) return error.InvalidDebugInfo; - const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32); + const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; const minimum_instruction_length = try di.dwarf_in_stream.readByte(); @@ -1810,7 +1820,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr return error.MissingDebugInfo; }, DW.LNE_set_address => { - const addr = try di.dwarf_in_stream.readInt(di.elf.endian, usize); + const addr = try di.dwarf_in_stream.readInt(di.endian, usize); prog.address = addr; }, DW.LNE_define_file => { @@ -1872,7 +1882,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = try di.dwarf_in_stream.readInt(di.elf.endian, u16); + const arg = try di.dwarf_in_stream.readInt(di.endian, u16); prog.address += arg; }, DW.LNS_set_prologue_end => {}, @@ -1891,7 +1901,7 @@ fn getLineNumberInfoDwarf(di: *DebugInfo, compile_unit: CompileUnit, target_addr return error.MissingDebugInfo; } -fn scanAllCompileUnits(di: *DebugInfo) !void { +fn scanAllCompileUnits(di: *DwarfInfo) !void { const debug_info_end = di.debug_info.offset + di.debug_info.size; var this_unit_offset = di.debug_info.offset; var cu_index: usize = 0; @@ -1904,10 +1914,10 @@ fn scanAllCompileUnits(di: *DebugInfo) !void { if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); - const version = try di.dwarf_in_stream.readInt(di.elf.endian, u16); + const version = try di.dwarf_in_stream.readInt(di.endian, u16); if (version < 2 or version > 5) return error.InvalidDebugInfo; - const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.elf.endian, u64) else try di.dwarf_in_stream.readInt(di.elf.endian, u32); + const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); const address_size = try di.dwarf_in_stream.readByte(); if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; @@ -1958,7 +1968,7 @@ fn scanAllCompileUnits(di: *DebugInfo) !void { } } -fn findCompileUnit(di: *DebugInfo, target_address: u64) !*const CompileUnit { +fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { for (di.compile_unit_list.toSlice()) |*compile_unit| { if (compile_unit.pc_range) |range| { if (target_address >= range.start and target_address < range.end) return compile_unit; From 9ac838c8e3f5c3e77533e30f72bac30487b9ae23 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 4 Dec 2018 11:42:22 -0500 Subject: [PATCH 074/110] LLD patch: allow non-allocated sections to go into allocated sections Patch submitted upstream: https://reviews.llvm.org/D55276 --- deps/lld/ELF/OutputSections.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/lld/ELF/OutputSections.cpp b/deps/lld/ELF/OutputSections.cpp index 8253b18b4..9dd8bba26 100644 --- a/deps/lld/ELF/OutputSections.cpp +++ b/deps/lld/ELF/OutputSections.cpp @@ -95,7 +95,7 @@ void OutputSection::addSection(InputSection *IS) { Flags = IS->Flags; } else { // Otherwise, check if new type or flags are compatible with existing ones. - unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER; + unsigned Mask = SHF_TLS | SHF_LINK_ORDER; if ((Flags & Mask) != (IS->Flags & Mask)) error("incompatible section flags for " + Name + "\n>>> " + toString(IS) + ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name + From 518ff33e64f3970e6fc053d2cffe0751e21b0700 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 5 Dec 2018 14:10:09 +0100 Subject: [PATCH 075/110] Allow packages in TestStep --- std/build.zig | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/std/build.zig b/std/build.zig index 034e3ce32..90f5bec65 100644 --- a/std/build.zig +++ b/std/build.zig @@ -811,6 +811,11 @@ pub const Target = union(enum) { } }; +const Pkg = struct { + name: []const u8, + path: []const u8, +}; + pub const LibExeObjStep = struct { step: Step, builder: *Builder, @@ -853,11 +858,6 @@ pub const LibExeObjStep = struct { source_files: ArrayList([]const u8), object_src: []const u8, - const Pkg = struct { - name: []const u8, - path: []const u8, - }; - const Kind = enum { Exe, Lib, @@ -1667,6 +1667,7 @@ pub const TestStep = struct { exec_cmd_args: ?[]const ?[]const u8, include_dirs: ArrayList([]const u8), lib_paths: ArrayList([]const u8), + packages: ArrayList(Pkg), object_files: ArrayList([]const u8), no_rosegment: bool, output_path: ?[]const u8, @@ -1687,6 +1688,7 @@ pub const TestStep = struct { .exec_cmd_args = null, .include_dirs = ArrayList([]const u8).init(builder.allocator), .lib_paths = ArrayList([]const u8).init(builder.allocator), + .packages = ArrayList(Pkg).init(builder.allocator), .object_files = ArrayList([]const u8).init(builder.allocator), .no_rosegment = false, .output_path = null, @@ -1702,6 +1704,13 @@ pub const TestStep = struct { self.lib_paths.append(path) catch unreachable; } + pub fn addPackagePath(self: *TestStep, name: []const u8, pkg_index_path: []const u8) void { + self.packages.append(Pkg{ + .name = name, + .path = pkg_index_path, + }) catch unreachable; + } + pub fn setVerbose(self: *TestStep, value: bool) void { self.verbose = value; } @@ -1878,6 +1887,13 @@ pub const TestStep = struct { try zig_args.append(lib_path); } + for (self.packages.toSliceConst()) |pkg| { + zig_args.append("--pkg-begin") catch unreachable; + zig_args.append(pkg.name) catch unreachable; + zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable; + zig_args.append("--pkg-end") catch unreachable; + } + if (self.no_rosegment) { try zig_args.append("--no-rosegment"); } From 1b0f4d59763e273901717199e47764745aed2631 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 5 Dec 2018 15:32:25 -0500 Subject: [PATCH 076/110] implement compile error note for function parameter type mismatch --- src/ir.cpp | 14 +++++++++++++- test/compile_errors.zig | 20 ++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 1edb12267..68a0b7f6f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -67,6 +67,8 @@ enum ConstCastResultId { struct ConstCastOnly; struct ConstCastArg { size_t arg_index; + ZigType *actual_param_type; + ZigType *expected_param_type; ConstCastOnly *child; }; @@ -8638,6 +8640,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (arg_child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdFnArg; result.data.fn_arg.arg_index = i; + result.data.fn_arg.actual_param_type = actual_param_info->type; + result.data.fn_arg.expected_param_type = expected_param_info->type; result.data.fn_arg.child = allocate_nonzero(1); *result.data.fn_arg.child = arg_child; return result; @@ -10483,6 +10487,15 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa } break; } + case ConstCastResultIdFnArg: { + ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("parameter %" ZIG_PRI_usize ": '%s' cannot cast into '%s'", + cast_result->data.fn_arg.arg_index, + buf_ptr(&cast_result->data.fn_arg.actual_param_type->name), + buf_ptr(&cast_result->data.fn_arg.expected_param_type->name))); + report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg); + break; + } case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnCC: // TODO case ConstCastResultIdFnVarArgs: // TODO @@ -10490,7 +10503,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa case ConstCastResultIdFnReturnType: // TODO case ConstCastResultIdFnArgCount: // TODO case ConstCastResultIdFnGenericArgCount: // TODO - case ConstCastResultIdFnArg: // TODO case ConstCastResultIdFnArgNoAlias: // TODO case ConstCastResultIdUnresolvedInferredErrSet: // TODO case ConstCastResultIdAsyncAllocatorType: // TODO diff --git a/test/compile_errors.zig b/test/compile_errors.zig index c5575a0c0..be839f055 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,18 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "error note for function parameter incompatibility", + \\fn do_the_thing(func: fn (arg: i32) void) void {} + \\fn bar(arg: bool) void {} + \\export fn entry() void { + \\ do_the_thing(bar); + \\} + , + ".tmp_source.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void", + ".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'", + ); + cases.add( "cast negative value to unsigned integer", \\comptime { @@ -5248,8 +5260,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn foo() void { \\ asm volatile ("" : : [bar]"r"(3) : ""); \\} - , - ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", + , + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", ); cases.add( @@ -5257,7 +5269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn foo() void { \\ asm volatile ("" : : [bar]"r"(3.17) : ""); \\} - , - ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", + , + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", ); } From 68b0fce62f684a4b491ebb36dea06bd4d9ff5219 Mon Sep 17 00:00:00 2001 From: Henry Nelson Date: Mon, 10 Dec 2018 00:50:12 -0500 Subject: [PATCH 077/110] Document explicitly ignoring expression values --- doc/langref.html.in | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 6e2d2bd9a..57da8a5f0 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4264,13 +4264,21 @@ fn foo() i32 { return 1234; } {#code_end#} -

However, if the expression has type {#syntax#}void{#endsyntax#}:

+

However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Function return values can also be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}.

{#code_begin|test#} -test "ignoring expression value" { - foo(); +test "void is ignored" { + returnsVoid(); } -fn foo() void {} +test "explicitly ignoring expression value" { + _ = foo(); +} + +fn returnsVoid() void {} + +fn foo() i32 { + return 1234; +} {#code_end#} {#header_close#} From 57113bab2f3802cc823494b9aa1df280cb005e2a Mon Sep 17 00:00:00 2001 From: Jay Weisskopf Date: Sat, 8 Dec 2018 15:04:56 -0500 Subject: [PATCH 078/110] docs: Prefer system-ui font-family system-ui is a new generic font-family for matching the font used in the operating system's native user interface. E.g. Roboto on Android, San Francisco on macOS, Segoe UI on Windows, etc. https://caniuse.com/#search=system-ui --- doc/langref.html.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 57da8a5f0..7f3485289 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8,7 +8,7 @@ body{ background-color:#111; color: #bbb; - font-family: sans-serif; + font-family: system-ui, sans-serif; } a { color: #88f; From 5f5364ad73dc6c31e1e189596f407970f852701a Mon Sep 17 00:00:00 2001 From: Jay Weisskopf Date: Sun, 9 Dec 2018 12:51:28 -0500 Subject: [PATCH 079/110] font-family fallbacks for unsupported system-ui --- doc/langref.html.in | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 7f3485289..a1903331a 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -8,7 +8,13 @@ body{ background-color:#111; color: #bbb; - font-family: system-ui, sans-serif; + font-family: system-ui, + /* Fallbacks for browsers that don't support system-ui */ + /* https://caniuse.com/#search=system-ui */ + -apple-system, /* iOS and macOS */ + Roboto, /* Android */ + "Segoe UI", /* Windows */ + sans-serif; } a { color: #88f; From 634d11ab28839ebc3caae2bf18cbc028a7a1c3e9 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 5 Dec 2018 16:50:33 -0800 Subject: [PATCH 080/110] Add add compiler_rt routines for float to signed integer conversion And add std.math.f128_* constants. The routines are: __fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixtfdi, __fixtfsi, __fixtfti. These all call fixint which is a generic zig function that does the conversion: pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t There are also a set tests: __fixdfdi_test, __fixdfsi_test, __fixdfti_test, __fixsfdi_test, __fixsfsi_test, __fixsfti_test, __fixtfdi_test, __fixtfsi_test, __fixtfti_test. --- CMakeLists.txt | 10 ++ std/math/index.zig | 7 ++ std/special/compiler_rt/fixdfdi.zig | 11 ++ std/special/compiler_rt/fixdfdi_test.zig | 66 ++++++++++ std/special/compiler_rt/fixdfsi.zig | 11 ++ std/special/compiler_rt/fixdfsi_test.zig | 74 +++++++++++ std/special/compiler_rt/fixdfti.zig | 11 ++ std/special/compiler_rt/fixdfti_test.zig | 66 ++++++++++ std/special/compiler_rt/fixint.zig | 74 +++++++++++ std/special/compiler_rt/fixint_test.zig | 152 +++++++++++++++++++++++ std/special/compiler_rt/fixsfdi.zig | 11 ++ std/special/compiler_rt/fixsfdi_test.zig | 68 ++++++++++ std/special/compiler_rt/fixsfsi.zig | 11 ++ std/special/compiler_rt/fixsfsi_test.zig | 76 ++++++++++++ std/special/compiler_rt/fixsfti.zig | 11 ++ std/special/compiler_rt/fixsfti_test.zig | 84 +++++++++++++ std/special/compiler_rt/fixtfdi.zig | 11 ++ std/special/compiler_rt/fixtfdi_test.zig | 76 ++++++++++++ std/special/compiler_rt/fixtfsi.zig | 11 ++ std/special/compiler_rt/fixtfsi_test.zig | 76 ++++++++++++ std/special/compiler_rt/fixtfti.zig | 11 ++ std/special/compiler_rt/fixtfti_test.zig | 66 ++++++++++ std/special/compiler_rt/index.zig | 10 ++ 23 files changed, 1004 insertions(+) create mode 100644 std/special/compiler_rt/fixdfdi.zig create mode 100644 std/special/compiler_rt/fixdfdi_test.zig create mode 100644 std/special/compiler_rt/fixdfsi.zig create mode 100644 std/special/compiler_rt/fixdfsi_test.zig create mode 100644 std/special/compiler_rt/fixdfti.zig create mode 100644 std/special/compiler_rt/fixdfti_test.zig create mode 100644 std/special/compiler_rt/fixint.zig create mode 100644 std/special/compiler_rt/fixint_test.zig create mode 100644 std/special/compiler_rt/fixsfdi.zig create mode 100644 std/special/compiler_rt/fixsfdi_test.zig create mode 100644 std/special/compiler_rt/fixsfsi.zig create mode 100644 std/special/compiler_rt/fixsfsi_test.zig create mode 100644 std/special/compiler_rt/fixsfti.zig create mode 100644 std/special/compiler_rt/fixsfti_test.zig create mode 100644 std/special/compiler_rt/fixtfdi.zig create mode 100644 std/special/compiler_rt/fixtfdi_test.zig create mode 100644 std/special/compiler_rt/fixtfsi.zig create mode 100644 std/special/compiler_rt/fixtfsi_test.zig create mode 100644 std/special/compiler_rt/fixtfti.zig create mode 100644 std/special/compiler_rt/fixtfti_test.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 0817c09f2..1b64bcca8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -623,6 +623,16 @@ set(ZIG_STD_FILES "special/compiler_rt/fixunstfdi.zig" "special/compiler_rt/fixunstfsi.zig" "special/compiler_rt/fixunstfti.zig" + "special/compiler_rt/fixint.zig" + "special/compiler_rt/fixdfdi.zig" + "special/compiler_rt/fixdfsi.zig" + "special/compiler_rt/fixdfti.zig" + "special/compiler_rt/fixsfdi.zig" + "special/compiler_rt/fixsfsi.zig" + "special/compiler_rt/fixsfti.zig" + "special/compiler_rt/fixtfdi.zig" + "special/compiler_rt/fixtfsi.zig" + "special/compiler_rt/fixtfti.zig" "special/compiler_rt/floattidf.zig" "special/compiler_rt/floattisf.zig" "special/compiler_rt/floattitf.zig" diff --git a/std/math/index.zig b/std/math/index.zig index 83bd2310d..f37de2505 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -6,6 +6,13 @@ const assert = std.debug.assert; pub const e = 2.71828182845904523536028747135266249775724709369995; pub const pi = 3.14159265358979323846264338327950288419716939937510; +// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128) +pub const f128_true_min = @bitCast(f128, u128(0x00000000000000000000000000000001)); +pub const f128_min = @bitCast(f128, u128(0x00010000000000000000000000000000)); +pub const f128_max = @bitCast(f128, u128(0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); +pub const f128_epsilon = @bitCast(f128, u128(0x3F8F0000000000000000000000000000)); +pub const f128_toint = 1.0 / f128_epsilon; + // float.h details pub const f64_true_min = 4.94065645841246544177e-324; pub const f64_min = 2.2250738585072014e-308; diff --git a/std/special/compiler_rt/fixdfdi.zig b/std/special/compiler_rt/fixdfdi.zig new file mode 100644 index 000000000..c108fd15a --- /dev/null +++ b/std/special/compiler_rt/fixdfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfdi(a: f64) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i64, a); +} + +test "import fixdfdi" { + _ = @import("fixdfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfdi_test.zig b/std/special/compiler_rt/fixdfdi_test.zig new file mode 100644 index 000000000..72bcf452d --- /dev/null +++ b/std/special/compiler_rt/fixdfdi_test.zig @@ -0,0 +1,66 @@ +const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfdi(a: f64, expected: i64) void { + const x = __fixdfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixdfdi" { + //warn("\n"); + + test__fixdfdi(-math.f64_max, math.minInt(i64)); + + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixdfdi(-2.01, -2); + test__fixdfdi(-2.0, -2); + test__fixdfdi(-1.99, -1); + test__fixdfdi(-1.0, -1); + test__fixdfdi(-0.99, 0); + test__fixdfdi(-0.5, 0); + test__fixdfdi(-math.f64_min, 0); + test__fixdfdi(0.0, 0); + test__fixdfdi(math.f64_min, 0); + test__fixdfdi(0.5, 0); + test__fixdfdi(0.99, 0); + test__fixdfdi(1.0, 1); + test__fixdfdi(1.5, 1); + test__fixdfdi(1.99, 1); + test__fixdfdi(2.0, 2); + test__fixdfdi(2.01, 2); + + test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixdfdi(math.f64_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixdfsi.zig b/std/special/compiler_rt/fixdfsi.zig new file mode 100644 index 000000000..83a17b2b0 --- /dev/null +++ b/std/special/compiler_rt/fixdfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfsi(a: f64) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i32, a); +} + +test "import fixdfsi" { + _ = @import("fixdfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfsi_test.zig b/std/special/compiler_rt/fixdfsi_test.zig new file mode 100644 index 000000000..147f46534 --- /dev/null +++ b/std/special/compiler_rt/fixdfsi_test.zig @@ -0,0 +1,74 @@ +const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfsi(a: f64, expected: i32) void { + const x = __fixdfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixdfsi" { + //warn("\n"); + + test__fixdfsi(-math.f64_max, math.minInt(i32)); + + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixdfsi(-0x1.000000p+31, -0x80000000); + test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + + test__fixdfsi(-2.01, -2); + test__fixdfsi(-2.0, -2); + test__fixdfsi(-1.99, -1); + test__fixdfsi(-1.0, -1); + test__fixdfsi(-0.99, 0); + test__fixdfsi(-0.5, 0); + test__fixdfsi(-math.f64_min, 0); + test__fixdfsi(0.0, 0); + test__fixdfsi(math.f64_min, 0); + test__fixdfsi(0.5, 0); + test__fixdfsi(0.99, 0); + test__fixdfsi(1.0, 1); + test__fixdfsi(1.5, 1); + test__fixdfsi(1.99, 1); + test__fixdfsi(2.0, 2); + test__fixdfsi(2.01, 2); + + test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixdfsi(math.f64_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixdfti.zig b/std/special/compiler_rt/fixdfti.zig new file mode 100644 index 000000000..e30f885cf --- /dev/null +++ b/std/special/compiler_rt/fixdfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfti(a: f64) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i128, a); +} + +test "import fixdfti" { + _ = @import("fixdfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfti_test.zig b/std/special/compiler_rt/fixdfti_test.zig new file mode 100644 index 000000000..5bb3a31a3 --- /dev/null +++ b/std/special/compiler_rt/fixdfti_test.zig @@ -0,0 +1,66 @@ +const __fixdfti = @import("fixdfti.zig").__fixdfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfti(a: f64, expected: i128) void { + const x = __fixdfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixdfti" { + //warn("\n"); + + test__fixdfti(-math.f64_max, math.minInt(i128)); + + test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); + test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixdfti(-2.01, -2); + test__fixdfti(-2.0, -2); + test__fixdfti(-1.99, -1); + test__fixdfti(-1.0, -1); + test__fixdfti(-0.99, 0); + test__fixdfti(-0.5, 0); + test__fixdfti(-math.f64_min, 0); + test__fixdfti(0.0, 0); + test__fixdfti(math.f64_min, 0); + test__fixdfti(0.5, 0); + test__fixdfti(0.99, 0); + test__fixdfti(1.0, 1); + test__fixdfti(1.5, 1); + test__fixdfti(1.99, 1); + test__fixdfti(2.0, 2); + test__fixdfti(2.01, 2); + + test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); + + test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixdfti(math.f64_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixint.zig b/std/special/compiler_rt/fixint.zig new file mode 100644 index 000000000..fd31798cc --- /dev/null +++ b/std/special/compiler_rt/fixint.zig @@ -0,0 +1,74 @@ +const is_test = @import("builtin").is_test; +const std = @import("std"); +const math = std.math; +const Log2Int = std.math.Log2Int; +const maxInt = std.math.maxInt; +const minInt = std.math.minInt; + +const DBG = false; + +pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { + @setRuntimeSafety(is_test); + + const rep_t = switch (fp_t) { + f32 => u32, + f64 => u64, + f128 => u128, + else => unreachable, + }; + const significandBits = switch (fp_t) { + f32 => 23, + f64 => 52, + f128 => 112, + else => unreachable, + }; + + const typeWidth = rep_t.bit_count; + const exponentBits = (typeWidth - significandBits - 1); + const signBit = (rep_t(1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + const exponentBias = (maxExponent >> 1); + + const implicitBit = (rep_t(1) << significandBits); + const significandMask = (implicitBit - 1); + + // Break a into sign, exponent, significand + const aRep: rep_t = @bitCast(rep_t, a); + const absMask = signBit - 1; + const aAbs: rep_t = aRep & absMask; + + const negative = (aRep & signBit) != 0; + const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias; + const significand: rep_t = (aAbs & significandMask) | implicitBit; + + // If exponent is negative, the uint_result is zero. + if (exponent < 0) return 0; + + // The unsigned result needs to be large enough to handle an fixint_t or rep_t + const fixuint_t = @IntType(false, fixint_t.bit_count); + const UintResultType = if (fixint_t.bit_count > rep_t.bit_count) fixuint_t else rep_t; + var uint_result: UintResultType = undefined; + + // If the value is too large for the integer type, saturate. + if (@intCast(usize, exponent) >= fixint_t.bit_count) { + return if (negative) fixint_t(minInt(fixint_t)) else fixint_t(maxInt(fixint_t)); + } + + // If 0 <= exponent < significandBits, right shift else left shift + if (exponent < significandBits) { + uint_result = @intCast(UintResultType, significand) >> @intCast(Log2Int(UintResultType), significandBits - exponent); + } else { + uint_result = @intCast(UintResultType, significand) << @intCast(Log2Int(UintResultType), exponent - significandBits); + } + + // Cast to final signed result + if (negative) { + return if (uint_result >= -math.minInt(fixint_t)) math.minInt(fixint_t) else -@intCast(fixint_t, uint_result); + } else { + return if (uint_result >= math.maxInt(fixint_t)) math.maxInt(fixint_t) else @intCast(fixint_t, uint_result); + } +} + +test "import fixint" { + _ = @import("fixint_test.zig"); +} diff --git a/std/special/compiler_rt/fixint_test.zig b/std/special/compiler_rt/fixint_test.zig new file mode 100644 index 000000000..6676bddbe --- /dev/null +++ b/std/special/compiler_rt/fixint_test.zig @@ -0,0 +1,152 @@ +const is_test = @import("builtin").is_test; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +const fixint = @import("fixint.zig").fixint; + +fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) void { + const x = fixint(fp_t, fixint_t, a); + //warn("a={} x={}:{x} expected={}:{x})\n", a, x, x, expected, expected); + assert(x == expected); +} + +test "fixint.i1" { + test__fixint(f32, i1, -math.inf_f32, -1); + test__fixint(f32, i1, -math.f32_max, -1); + test__fixint(f32, i1, -2.0, -1); + test__fixint(f32, i1, -1.1, -1); + test__fixint(f32, i1, -1.0, -1); + test__fixint(f32, i1, -0.9, 0); + test__fixint(f32, i1, -0.1, 0); + test__fixint(f32, i1, -math.f32_min, 0); + test__fixint(f32, i1, -0.0, 0); + test__fixint(f32, i1, 0.0, 0); + test__fixint(f32, i1, math.f32_min, 0); + test__fixint(f32, i1, 0.1, 0); + test__fixint(f32, i1, 0.9, 0); + test__fixint(f32, i1, 1.0, 0); + test__fixint(f32, i1, 2.0, 0); + test__fixint(f32, i1, math.f32_max, 0); + test__fixint(f32, i1, math.inf_f32, 0); +} + +test "fixint.i2" { + test__fixint(f32, i2, -math.inf_f32, -2); + test__fixint(f32, i2, -math.f32_max, -2); + test__fixint(f32, i2, -2.0, -2); + test__fixint(f32, i2, -1.9, -1); + test__fixint(f32, i2, -1.1, -1); + test__fixint(f32, i2, -1.0, -1); + test__fixint(f32, i2, -0.9, 0); + test__fixint(f32, i2, -0.1, 0); + test__fixint(f32, i2, -math.f32_min, 0); + test__fixint(f32, i2, -0.0, 0); + test__fixint(f32, i2, 0.0, 0); + test__fixint(f32, i2, math.f32_min, 0); + test__fixint(f32, i2, 0.1, 0); + test__fixint(f32, i2, 0.9, 0); + test__fixint(f32, i2, 1.0, 1); + test__fixint(f32, i2, 2.0, 1); + test__fixint(f32, i2, math.f32_max, 1); + test__fixint(f32, i2, math.inf_f32, 1); +} + +test "fixint.i3" { + test__fixint(f32, i3, -math.inf_f32, -4); + test__fixint(f32, i3, -math.f32_max, -4); + test__fixint(f32, i3, -4.0, -4); + test__fixint(f32, i3, -3.0, -3); + test__fixint(f32, i3, -2.0, -2); + test__fixint(f32, i3, -1.9, -1); + test__fixint(f32, i3, -1.1, -1); + test__fixint(f32, i3, -1.0, -1); + test__fixint(f32, i3, -0.9, 0); + test__fixint(f32, i3, -0.1, 0); + test__fixint(f32, i3, -math.f32_min, 0); + test__fixint(f32, i3, -0.0, 0); + test__fixint(f32, i3, 0.0, 0); + test__fixint(f32, i3, math.f32_min, 0); + test__fixint(f32, i3, 0.1, 0); + test__fixint(f32, i3, 0.9, 0); + test__fixint(f32, i3, 1.0, 1); + test__fixint(f32, i3, 2.0, 2); + test__fixint(f32, i3, 3.0, 3); + test__fixint(f32, i3, 4.0, 3); + test__fixint(f32, i3, math.f32_max, 3); + test__fixint(f32, i3, math.inf_f32, 3); +} + +test "fixint.i32" { + test__fixint(f64, i32, -math.inf_f64, math.minInt(i32)); + test__fixint(f64, i32, -math.f64_max, math.minInt(i32)); + test__fixint(f64, i32, f64(math.minInt(i32)), math.minInt(i32)); + test__fixint(f64, i32, f64(math.minInt(i32))+1, math.minInt(i32)+1); + test__fixint(f64, i32, -2.0, -2); + test__fixint(f64, i32, -1.9, -1); + test__fixint(f64, i32, -1.1, -1); + test__fixint(f64, i32, -1.0, -1); + test__fixint(f64, i32, -0.9, 0); + test__fixint(f64, i32, -0.1, 0); + test__fixint(f64, i32, -math.f32_min, 0); + test__fixint(f64, i32, -0.0, 0); + test__fixint(f64, i32, 0.0, 0); + test__fixint(f64, i32, math.f32_min, 0); + test__fixint(f64, i32, 0.1, 0); + test__fixint(f64, i32, 0.9, 0); + test__fixint(f64, i32, 1.0, 1); + test__fixint(f64, i32, f64(math.maxInt(i32))-1, math.maxInt(i32)-1); + test__fixint(f64, i32, f64(math.maxInt(i32)), math.maxInt(i32)); + test__fixint(f64, i32, math.f64_max, math.maxInt(i32)); + test__fixint(f64, i32, math.inf_f64, math.maxInt(i32)); +} + +test "fixint.i64" { + test__fixint(f64, i64, -math.inf_f64, math.minInt(i64)); + test__fixint(f64, i64, -math.f64_max, math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64)), math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64))+1, math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64)/2), math.minInt(i64)/2); + test__fixint(f64, i64, -2.0, -2); + test__fixint(f64, i64, -1.9, -1); + test__fixint(f64, i64, -1.1, -1); + test__fixint(f64, i64, -1.0, -1); + test__fixint(f64, i64, -0.9, 0); + test__fixint(f64, i64, -0.1, 0); + test__fixint(f64, i64, -math.f32_min, 0); + test__fixint(f64, i64, -0.0, 0); + test__fixint(f64, i64, 0.0, 0); + test__fixint(f64, i64, math.f32_min, 0); + test__fixint(f64, i64, 0.1, 0); + test__fixint(f64, i64, 0.9, 0); + test__fixint(f64, i64, 1.0, 1); + test__fixint(f64, i64, f64(math.maxInt(i64))-1, math.maxInt(i64)); + test__fixint(f64, i64, f64(math.maxInt(i64)), math.maxInt(i64)); + test__fixint(f64, i64, math.f64_max, math.maxInt(i64)); + test__fixint(f64, i64, math.inf_f64, math.maxInt(i64)); +} + +test "fixint.i128" { + test__fixint(f64, i128, -math.inf_f64, math.minInt(i128)); + test__fixint(f64, i128, -math.f64_max, math.minInt(i128)); + test__fixint(f64, i128, f64(math.minInt(i128)), math.minInt(i128)); + test__fixint(f64, i128, f64(math.minInt(i128))+1, math.minInt(i128)); + test__fixint(f64, i128, -2.0, -2); + test__fixint(f64, i128, -1.9, -1); + test__fixint(f64, i128, -1.1, -1); + test__fixint(f64, i128, -1.0, -1); + test__fixint(f64, i128, -0.9, 0); + test__fixint(f64, i128, -0.1, 0); + test__fixint(f64, i128, -math.f32_min, 0); + test__fixint(f64, i128, -0.0, 0); + test__fixint(f64, i128, 0.0, 0); + test__fixint(f64, i128, math.f32_min, 0); + test__fixint(f64, i128, 0.1, 0); + test__fixint(f64, i128, 0.9, 0); + test__fixint(f64, i128, 1.0, 1); + test__fixint(f64, i128, f64(math.maxInt(i128))-1, math.maxInt(i128)); + test__fixint(f64, i128, f64(math.maxInt(i128)), math.maxInt(i128)); + test__fixint(f64, i128, math.f64_max, math.maxInt(i128)); + test__fixint(f64, i128, math.inf_f64, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixsfdi.zig b/std/special/compiler_rt/fixsfdi.zig new file mode 100644 index 000000000..ffa81d13a --- /dev/null +++ b/std/special/compiler_rt/fixsfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfdi(a: f32) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i64, a); +} + +test "import fixsfdi" { + _ = @import("fixsfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfdi_test.zig b/std/special/compiler_rt/fixsfdi_test.zig new file mode 100644 index 000000000..ef8e50e38 --- /dev/null +++ b/std/special/compiler_rt/fixsfdi_test.zig @@ -0,0 +1,68 @@ +const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfdi(a: f32, expected: i64) void { + const x = __fixsfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixsfdi" { + //warn("\n"); + + test__fixsfdi(-math.f32_max, math.minInt(i64)); + + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixsfdi(-2.01, -2); + test__fixsfdi(-2.0, -2); + test__fixsfdi(-1.99, -1); + test__fixsfdi(-1.0, -1); + test__fixsfdi(-0.99, 0); + test__fixsfdi(-0.5, 0); + test__fixsfdi(-math.f32_min, 0); + test__fixsfdi(0.0, 0); + test__fixsfdi(math.f32_min, 0); + test__fixsfdi(0.5, 0); + test__fixsfdi(0.99, 0); + test__fixsfdi(1.0, 1); + test__fixsfdi(1.5, 1); + test__fixsfdi(1.99, 1); + test__fixsfdi(2.0, 2); + test__fixsfdi(2.01, 2); + + test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixsfdi(math.f64_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixsfsi.zig b/std/special/compiler_rt/fixsfsi.zig new file mode 100644 index 000000000..9a94b4395 --- /dev/null +++ b/std/special/compiler_rt/fixsfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfsi(a: f32) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i32, a); +} + +test "import fixsfsi" { + _ = @import("fixsfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfsi_test.zig b/std/special/compiler_rt/fixsfsi_test.zig new file mode 100644 index 000000000..d5c0ba5c2 --- /dev/null +++ b/std/special/compiler_rt/fixsfsi_test.zig @@ -0,0 +1,76 @@ +const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfsi(a: f32, expected: i32) void { + const x = __fixsfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixsfsi" { + //warn("\n"); + + test__fixsfsi(-math.f32_max, math.minInt(i32)); + + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixsfsi(-0x1.000000p+31, -0x80000000); + test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); + test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixsfsi(-2.01, -2); + test__fixsfsi(-2.0, -2); + test__fixsfsi(-1.99, -1); + test__fixsfsi(-1.0, -1); + test__fixsfsi(-0.99, 0); + test__fixsfsi(-0.5, 0); + test__fixsfsi(-math.f32_min, 0); + test__fixsfsi(0.0, 0); + test__fixsfsi(math.f32_min, 0); + test__fixsfsi(0.5, 0); + test__fixsfsi(0.99, 0); + test__fixsfsi(1.0, 1); + test__fixsfsi(1.5, 1); + test__fixsfsi(1.99, 1); + test__fixsfsi(2.0, 2); + test__fixsfsi(2.01, 2); + + test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); + test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixsfsi(math.f32_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixsfti.zig b/std/special/compiler_rt/fixsfti.zig new file mode 100644 index 000000000..806a1678a --- /dev/null +++ b/std/special/compiler_rt/fixsfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfti(a: f32) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i128, a); +} + +test "import fixsfti" { + _ = @import("fixsfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfti_test.zig b/std/special/compiler_rt/fixsfti_test.zig new file mode 100644 index 000000000..d693143b1 --- /dev/null +++ b/std/special/compiler_rt/fixsfti_test.zig @@ -0,0 +1,84 @@ +const __fixsfti = @import("fixsfti.zig").__fixsfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfti(a: f32, expected: i128) void { + const x = __fixsfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixsfti" { + //warn("\n"); + + test__fixsfti(-math.f32_max, math.minInt(i128)); + + test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); + test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); + + test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixsfti(-0x1.000000p+31, -0x80000000); + test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); + test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixsfti(-2.01, -2); + test__fixsfti(-2.0, -2); + test__fixsfti(-1.99, -1); + test__fixsfti(-1.0, -1); + test__fixsfti(-0.99, 0); + test__fixsfti(-0.5, 0); + test__fixsfti(-math.f32_min, 0); + test__fixsfti(0.0, 0); + test__fixsfti(math.f32_min, 0); + test__fixsfti(0.5, 0); + test__fixsfti(0.99, 0); + test__fixsfti(1.0, 1); + test__fixsfti(1.5, 1); + test__fixsfti(1.99, 1); + test__fixsfti(2.0, 2); + test__fixsfti(2.01, 2); + + test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixsfti(0x1.FFFFFFp+30, 0x80000000); + test__fixsfti(0x1.000000p+31, 0x80000000); + + test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); + + test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); + test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); + test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); + + test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); + test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); + test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixsfti(math.f32_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixtfdi.zig b/std/special/compiler_rt/fixtfdi.zig new file mode 100644 index 000000000..8d99231b7 --- /dev/null +++ b/std/special/compiler_rt/fixtfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfdi(a: f128) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i64, a); +} + +test "import fixtfdi" { + _ = @import("fixtfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfdi_test.zig b/std/special/compiler_rt/fixtfdi_test.zig new file mode 100644 index 000000000..58ccbc583 --- /dev/null +++ b/std/special/compiler_rt/fixtfdi_test.zig @@ -0,0 +1,76 @@ +const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfdi(a: f128, expected: i64) void { + const x = __fixtfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixtfdi" { + //warn("\n"); + + test__fixtfdi(-math.f128_max, math.minInt(i64)); + + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); + test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); + + test__fixtfdi(-0x1.000000p+31, -0x80000000); + test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixtfdi(-2.01, -2); + test__fixtfdi(-2.0, -2); + test__fixtfdi(-1.99, -1); + test__fixtfdi(-1.0, -1); + test__fixtfdi(-0.99, 0); + test__fixtfdi(-0.5, 0); + test__fixtfdi(-math.f64_min, 0); + test__fixtfdi(0.0, 0); + test__fixtfdi(math.f64_min, 0); + test__fixtfdi(0.5, 0); + test__fixtfdi(0.99, 0); + test__fixtfdi(1.0, 1); + test__fixtfdi(1.5, 1); + test__fixtfdi(1.99, 1); + test__fixtfdi(2.0, 2); + test__fixtfdi(2.01, 2); + + test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixtfdi(0x1.000000p+31, 0x80000000); + + test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixtfdi(math.f128_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixtfsi.zig b/std/special/compiler_rt/fixtfsi.zig new file mode 100644 index 000000000..f3f83634b --- /dev/null +++ b/std/special/compiler_rt/fixtfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfsi(a: f128) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i32, a); +} + +test "import fixtfsi" { + _ = @import("fixtfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfsi_test.zig b/std/special/compiler_rt/fixtfsi_test.zig new file mode 100644 index 000000000..7a3cc7f46 --- /dev/null +++ b/std/special/compiler_rt/fixtfsi_test.zig @@ -0,0 +1,76 @@ +const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfsi(a: f128, expected: i32) void { + const x = __fixtfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixtfsi" { + //warn("\n"); + + test__fixtfsi(-math.f128_max, math.minInt(i32)); + + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixtfsi(-0x1.000000p+31, -0x80000000); + test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixtfsi(-2.01, -2); + test__fixtfsi(-2.0, -2); + test__fixtfsi(-1.99, -1); + test__fixtfsi(-1.0, -1); + test__fixtfsi(-0.99, 0); + test__fixtfsi(-0.5, 0); + test__fixtfsi(-math.f32_min, 0); + test__fixtfsi(0.0, 0); + test__fixtfsi(math.f32_min, 0); + test__fixtfsi(0.5, 0); + test__fixtfsi(0.99, 0); + test__fixtfsi(1.0, 1); + test__fixtfsi(1.5, 1); + test__fixtfsi(1.99, 1); + test__fixtfsi(2.0, 2); + test__fixtfsi(2.01, 2); + + test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixtfsi(math.f128_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixtfti.zig b/std/special/compiler_rt/fixtfti.zig new file mode 100644 index 000000000..07d38f2c3 --- /dev/null +++ b/std/special/compiler_rt/fixtfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfti(a: f128) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i128, a); +} + +test "import fixtfti" { + _ = @import("fixtfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfti_test.zig b/std/special/compiler_rt/fixtfti_test.zig new file mode 100644 index 000000000..520009486 --- /dev/null +++ b/std/special/compiler_rt/fixtfti_test.zig @@ -0,0 +1,66 @@ +const __fixtfti = @import("fixtfti.zig").__fixtfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfti(a: f128, expected: i128) void { + const x = __fixtfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixtfti" { + //warn("\n"); + + test__fixtfti(-math.f128_max, math.minInt(i128)); + + test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); + test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixtfti(-2.01, -2); + test__fixtfti(-2.0, -2); + test__fixtfti(-1.99, -1); + test__fixtfti(-1.0, -1); + test__fixtfti(-0.99, 0); + test__fixtfti(-0.5, 0); + test__fixtfti(-math.f128_min, 0); + test__fixtfti(0.0, 0); + test__fixtfti(math.f128_min, 0); + test__fixtfti(0.5, 0); + test__fixtfti(0.99, 0); + test__fixtfti(1.0, 1); + test__fixtfti(1.5, 1); + test__fixtfti(1.99, 1); + test__fixtfti(2.0, 2); + test__fixtfti(2.01, 2); + + test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); + + test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixtfti(math.f128_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index b2add4e3f..4bbfc2b29 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -52,6 +52,16 @@ comptime { @export("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); + @export("__fixdfdi", @import("fixdfdi.zig").__fixdfdi, linkage); + @export("__fixdfsi", @import("fixdfsi.zig").__fixdfsi, linkage); + @export("__fixdfti", @import("fixdfti.zig").__fixdfti, linkage); + @export("__fixsfdi", @import("fixsfdi.zig").__fixsfdi, linkage); + @export("__fixsfsi", @import("fixsfsi.zig").__fixsfsi, linkage); + @export("__fixsfti", @import("fixsfti.zig").__fixsfti, linkage); + @export("__fixtfdi", @import("fixtfdi.zig").__fixtfdi, linkage); + @export("__fixtfsi", @import("fixtfsi.zig").__fixtfsi, linkage); + @export("__fixtfti", @import("fixtfti.zig").__fixtfti, linkage); + @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); @export("__udivsi3", __udivsi3, linkage); From b883bc873df7f1a8fa3a13800402e1ec8da74328 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 12 Dec 2018 20:19:46 -0500 Subject: [PATCH 081/110] breaking API changes to all readInt/writeInt functions & more * add `@bswap` builtin function. See #767 * comptime evaluation facilities are improved to be able to handle a `@ptrCast` with a backing array. * `@truncate` allows "truncating" a u0 value to any integer type, and the result is always comptime known to be `0`. * when specifying pointer alignment in a type expression, the alignment value of pointers which do not have addresses at runtime is ignored, and always has the default/ABI alignment * threw in a fix to freebsd/x86_64.zig to update syntax from language changes * some improvements are pending #863 closes #638 closes #1733 std lib API changes * io.InStream().readIntNe renamed to readIntNative * io.InStream().readIntLe renamed to readIntLittle * io.InStream().readIntBe renamed to readIntBig * introduced io.InStream().readIntForeign * io.InStream().readInt has parameter order changed * io.InStream().readVarInt has parameter order changed * io.InStream().writeIntNe renamed to writeIntNative * introduced io.InStream().writeIntForeign * io.InStream().writeIntLe renamed to writeIntLittle * io.InStream().writeIntBe renamed to writeIntBig * io.InStream().writeInt has parameter order changed * mem.readInt has different parameters and semantics * introduced mem.readIntNative * introduced mem.readIntForeign * mem.readIntBE renamed to mem.readIntBig and different API * mem.readIntLE renamed to mem.readIntLittle and different API * introduced mem.readIntSliceNative * introduced mem.readIntSliceForeign * introduced mem.readIntSliceLittle * introduced mem.readIntSliceBig * introduced mem.readIntSlice * mem.writeInt has different parameters and semantics * introduced mem.writeIntNative * introduced mem.writeIntForeign * mem.writeIntBE renamed to mem.readIntBig and different semantics * mem.writeIntLE renamed to mem.readIntLittle and different semantics * introduced mem.writeIntSliceForeign * introduced mem.writeIntSliceNative * introduced mem.writeIntSliceBig * introduced mem.writeIntSliceLittle * introduced mem.writeIntSlice * removed mem.endianSwapIfLe * removed mem.endianSwapIfBe * removed mem.endianSwapIf * added mem.littleToNative * added mem.bigToNative * added mem.toNative * added mem.nativeTo * added mem.nativeToLittle * added mem.nativeToBig --- doc/langref.html.in | 9 + example/guess_number/main.zig | 2 +- src-self-hosted/compilation.zig | 2 +- src/all_types.hpp | 13 + src/analyze.cpp | 7 +- src/codegen.cpp | 31 +++ src/ir.cpp | 156 ++++++++++- src/ir_print.cpp | 15 ++ std/coff.zig | 44 +-- std/crypto/blake2.zig | 11 +- std/crypto/chacha20.zig | 53 ++-- std/crypto/md5.zig | 3 +- std/crypto/poly1305.zig | 27 +- std/crypto/sha1.zig | 3 +- std/crypto/sha2.zig | 6 +- std/crypto/sha3.zig | 5 +- std/crypto/x25519.zig | 41 +-- std/debug/index.zig | 60 +++-- std/elf.zig | 70 ++--- std/event/io.zig | 18 +- std/hash/siphash.zig | 14 +- std/heap.zig | 2 +- std/io.zig | 68 +++-- std/mem.zig | 457 +++++++++++++++++++------------- std/net.zig | 12 +- std/os/child_process.zig | 4 +- std/os/freebsd/x86_64.zig | 6 +- std/pdb.zig | 6 +- std/rand/index.zig | 8 +- std/unicode.zig | 30 +-- test/behavior.zig | 2 + test/cases/bswap.zig | 32 +++ test/cases/truncate.zig | 8 + test/compile_errors.zig | 12 + 34 files changed, 818 insertions(+), 419 deletions(-) create mode 100644 test/cases/bswap.zig create mode 100644 test/cases/truncate.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index a1903331a..f820a05b6 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5312,6 +5312,15 @@ comptime {

{#header_close#} + {#header_open|@bswap#} +
{#syntax#}@swap(comptime T: type, value: T) T{#endsyntax#}
+

{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.

+

+ Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, + and converts a little endian integer to a big endian integer. +

+ {#header_close#} + {#header_open|@bytesToSlice#}
{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}

diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index 66264666b..b4eb1c292 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -15,7 +15,7 @@ pub fn main() !void { std.debug.warn("unable to seed random number generator: {}", err); return err; }; - const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); + const seed = std.mem.readIntNative(u64, &seed_bytes); var prng = std.rand.DefaultPrng.init(seed); const answer = prng.random.range(u8, 0, 100) + 1; diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index a8c3e13e3..0594cbd74 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -55,7 +55,7 @@ pub const ZigCompiler = struct { var seed_bytes: [@sizeOf(u64)]u8 = undefined; try std.os.getRandomBytes(seed_bytes[0..]); - const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); + const seed = mem.readIntNative(u64, &seed_bytes); return ZigCompiler{ .loop = loop, diff --git a/src/all_types.hpp b/src/all_types.hpp index f7ada09a5..83b7e8495 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1415,6 +1415,7 @@ enum BuiltinFnId { BuiltinFnIdErrorReturnTrace, BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, + BuiltinFnIdBswap, }; struct BuiltinFnEntry { @@ -1487,6 +1488,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdFloor, ZigLLVMFnIdCeil, ZigLLVMFnIdSqrt, + ZigLLVMFnIdBswap, }; enum AddSubMul { @@ -1516,6 +1518,9 @@ struct ZigLLVMFnKey { uint32_t bit_count; bool is_signed; } overflow_arithmetic; + struct { + uint32_t bit_count; + } bswap; } data; }; @@ -2158,6 +2163,7 @@ enum IrInstructionId { IrInstructionIdMergeErrRetTraces, IrInstructionIdMarkErrRetTracePtr, IrInstructionIdSqrt, + IrInstructionIdBswap, IrInstructionIdErrSetCast, IrInstructionIdToBytes, IrInstructionIdFromBytes, @@ -3251,6 +3257,13 @@ struct IrInstructionCheckRuntimeScope { IrInstruction *is_comptime; }; +struct IrInstructionBswap { + IrInstruction base; + + IrInstruction *type; + IrInstruction *op; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 2f4b173c5..46686ce77 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -401,7 +401,8 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) { } ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) + bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, + uint32_t bit_offset_in_host, uint32_t host_int_bytes) { assert(!type_is_invalid(child_type)); assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); @@ -6110,6 +6111,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089; case ZigLLVMFnIdSqrt: return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; + case ZigLLVMFnIdBswap: + return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + @@ -6128,6 +6131,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.clz.bit_count == b.data.clz.bit_count; case ZigLLVMFnIdPopCount: return a.data.pop_count.bit_count == b.data.pop_count.bit_count; + case ZigLLVMFnIdBswap: + return a.data.bswap.bit_count == b.data.bswap.bit_count; case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: diff --git a/src/codegen.cpp b/src/codegen.cpp index 1033ed812..08dd11800 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3814,6 +3814,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI n_args = 1; key.id = ZigLLVMFnIdPopCount; key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count; + } else if (fn_id == BuiltinFnIdBswap) { + fn_name = "bswap"; + n_args = 1; + key.id = ZigLLVMFnIdBswap; + key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; } else { zig_unreachable(); } @@ -5098,6 +5103,29 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } +static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { + LLVMValueRef op = ir_llvm_value(g, instruction->op); + ZigType *int_type = instruction->base.value.type; + assert(int_type->id == ZigTypeIdInt); + if (int_type->data.integral.bit_count % 16 == 0) { + LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap); + return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); + } + // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate + ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, + int_type->data.integral.bit_count + 8); + // aabbcc + LLVMValueRef extended = LLVMBuildZExt(g->builder, op, extended_type->type_ref, ""); + // 00aabbcc + LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); + LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); + // ccbbaa00 + LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, + LLVMConstInt(extended_type->type_ref, 8, false), ""); + // 00ccbbaa + return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5335,6 +5363,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); + case IrInstructionIdBswap: + return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); } zig_unreachable(); } @@ -6757,6 +6787,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1); create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); + create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 68a0b7f6f..dc87f040b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -856,6 +856,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) { return IrInstructionIdSqrt; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { + return IrInstructionIdBswap; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { return IrInstructionIdCheckRuntimeScope; } @@ -2705,6 +2709,17 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc return &instruction->base; } +static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { + IrInstructionBswap *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -4689,6 +4704,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdBswap: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } } zig_unreachable(); } @@ -13674,18 +13704,55 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, return ErrorNone; } - if (dst_size > src_size) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", - dst_size, buf_ptr(&pointee->type->name), src_size)); - return ErrorSemanticAnalyzeFail; + if (dst_size <= src_size) { + Buf buf = BUF_INIT; + buf_resize(&buf, src_size); + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; } - Buf buf = BUF_INIT; - buf_resize(&buf, src_size); - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); - return ErrorNone; + switch (ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", + dst_size, buf_ptr(&pointee->type->name), src_size)); + return ErrorSemanticAnalyzeFail; + } + case ConstPtrSpecialBaseArray: { + ConstExprValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; + assert(array_val->type->id == ZigTypeIdArray); + if (array_val->data.x_array.special != ConstArraySpecialNone) + zig_panic("TODO"); + size_t elem_size = src_size; + src_size = elem_size * + (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index); + if (dst_size > src_size) { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", + dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index, + src_size)); + return ErrorSemanticAnalyzeFail; + } + size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); + Buf buf = BUF_INIT; + buf_resize(&buf, elem_count * elem_size); + for (size_t i = 0; i < elem_count; i += 1) { + ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + } + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; + } + case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialDiscard: + case ConstPtrSpecialHardCodedAddr: + case ConstPtrSpecialFunction: + zig_panic("TODO"); + } + zig_unreachable(); } static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { @@ -18054,6 +18121,12 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } + if (src_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) { const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned"; ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name))); @@ -20299,6 +20372,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; + if (!type_has_bits(child_type)) { + align_bytes = 0; + } } else { if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -20898,6 +20974,63 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS return result; } +static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + if (type_is_invalid(int_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op = instruction->op->child; + if (type_is_invalid(op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->id != ZigTypeIdInt) { + ir_add_error(ira, instruction->type, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); + return ira->codegen->invalid_instruction; + } + + if (int_type->data.integral.bit_count % 8 != 0) { + ir_add_error(ira, instruction->type, + buf_sprintf("@bswap integer type '%s' has %" PRIu32 " bits which is not evenly divisible by 8", + buf_ptr(&int_type->name), int_type->data.integral.bit_count)); + return ira->codegen->invalid_instruction; + } + + IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); + if (type_is_invalid(casted_op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + + if (int_type->data.integral.bit_count == 8) { + return casted_op; + } + + if (instr_is_comptime(casted_op)) { + ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + size_t buf_size = int_type->data.integral.bit_count / 8; + uint8_t *buf = allocate_nonzero(buf_size); + bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); + bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, + int_type->data.integral.is_signed); + return result; + } + + IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op); + result->value.type = int_type; + return result; +} + + static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; IrInstruction *target = instruction->target->child; @@ -21233,6 +21366,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); + case IrInstructionIdBswap: + return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -21454,6 +21589,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroPromise: case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: + case IrInstructionIdBswap: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 13c06e4e2..e09b0073e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1323,6 +1323,18 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { fprintf(irp->f, ")"); } +static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { + fprintf(irp->f, "@bswap("); + if (instruction->type != nullptr) { + ir_print_other_instruction(irp, instruction->type); + } else { + fprintf(irp->f, "null"); + } + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1736,6 +1748,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSqrt: ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); break; + case IrInstructionIdBswap: + ir_print_bswap(irp, (IrInstructionBswap *)instruction); + break; case IrInstructionIdAtomicLoad: ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); break; diff --git a/std/coff.zig b/std/coff.zig index 6a1aa34b4..53bd2a4b7 100644 --- a/std/coff.zig +++ b/std/coff.zig @@ -51,7 +51,7 @@ pub const Coff = struct { // Seek to PE File Header (coff header) try self.in_file.seekTo(pe_pointer_offset); - const pe_magic_offset = try in.readIntLe(u32); + const pe_magic_offset = try in.readIntLittle(u32); try self.in_file.seekTo(pe_magic_offset); var pe_header_magic: [4]u8 = undefined; @@ -60,13 +60,13 @@ pub const Coff = struct { return error.InvalidPEHeader; self.coff_header = CoffHeader{ - .machine = try in.readIntLe(u16), - .number_of_sections = try in.readIntLe(u16), - .timedate_stamp = try in.readIntLe(u32), - .pointer_to_symbol_table = try in.readIntLe(u32), - .number_of_symbols = try in.readIntLe(u32), - .size_of_optional_header = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u16), + .machine = try in.readIntLittle(u16), + .number_of_sections = try in.readIntLittle(u16), + .timedate_stamp = try in.readIntLittle(u32), + .pointer_to_symbol_table = try in.readIntLittle(u32), + .number_of_symbols = try in.readIntLittle(u32), + .size_of_optional_header = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u16), }; switch (self.coff_header.machine) { @@ -79,7 +79,7 @@ pub const Coff = struct { fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void { const in = &file_stream.stream; - self.pe_header.magic = try in.readIntLe(u16); + self.pe_header.magic = try in.readIntLittle(u16); // For now we're only interested in finding the reference to the .pdb, // so we'll skip most of this header, which size is different in 32 // 64 bits by the way. @@ -93,14 +93,14 @@ pub const Coff = struct { try self.in_file.seekForward(skip_size); - const number_of_rva_and_sizes = try in.readIntLe(u32); + const number_of_rva_and_sizes = try in.readIntLittle(u32); if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return error.InvalidPEHeader; for (self.pe_header.data_directory) |*data_dir| { data_dir.* = OptionalHeader.DataDirectory{ - .virtual_address = try in.readIntLe(u32), - .size = try in.readIntLe(u32), + .virtual_address = try in.readIntLittle(u32), + .size = try in.readIntLittle(u32), }; } } @@ -124,7 +124,7 @@ pub const Coff = struct { if (!mem.eql(u8, cv_signature, "RSDS")) return error.InvalidPEMagic; try in.readNoEof(self.guid[0..]); - self.age = try in.readIntLe(u32); + self.age = try in.readIntLittle(u32); // Finally read the null-terminated string. var byte = try in.readByte(); @@ -157,15 +157,15 @@ pub const Coff = struct { try self.sections.append(Section{ .header = SectionHeader{ .name = name, - .misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) }, - .virtual_address = try in.readIntLe(u32), - .size_of_raw_data = try in.readIntLe(u32), - .pointer_to_raw_data = try in.readIntLe(u32), - .pointer_to_relocations = try in.readIntLe(u32), - .pointer_to_line_numbers = try in.readIntLe(u32), - .number_of_relocations = try in.readIntLe(u16), - .number_of_line_numbers = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u32), + .misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) }, + .virtual_address = try in.readIntLittle(u32), + .size_of_raw_data = try in.readIntLittle(u32), + .pointer_to_raw_data = try in.readIntLittle(u32), + .pointer_to_relocations = try in.readIntLittle(u32), + .pointer_to_line_numbers = try in.readIntLittle(u32), + .number_of_relocations = try in.readIntLittle(u16), + .number_of_line_numbers = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u32), }, }); } diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig index dc68d806d..e3de65916 100644 --- a/std/crypto/blake2.zig +++ b/std/crypto/blake2.zig @@ -123,7 +123,8 @@ fn Blake2s(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } @@ -134,7 +135,8 @@ fn Blake2s(comptime out_len: usize) type { var v: [16]u32 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]); + // TODO https://github.com/ziglang/zig/issues/863 + r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); } var k: usize = 0; @@ -356,7 +358,8 @@ fn Blake2b(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); } } @@ -367,7 +370,7 @@ fn Blake2b(comptime out_len: usize) type { var v: [16]u64 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]); } var k: usize = 0; diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 059bc8208..5ec1e7975 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -59,7 +59,8 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { } for (x) |_, i| { - mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); } } @@ -70,10 +71,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo const c = "expand 32-byte k"; const constant_le = []u32{ - mem.readIntLE(u32, c[0..4]), - mem.readIntLE(u32, c[4..8]), - mem.readIntLE(u32, c[8..12]), - mem.readIntLE(u32, c[12..16]), + mem.readIntSliceLittle(u32, c[0..4]), + mem.readIntSliceLittle(u32, c[4..8]), + mem.readIntSliceLittle(u32, c[8..12]), + mem.readIntSliceLittle(u32, c[12..16]), }; mem.copy(u32, ctx[0..], constant_le[0..4]); @@ -117,19 +118,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = counter; - c[1] = mem.readIntLE(u32, nonce[0..4]); - c[2] = mem.readIntLE(u32, nonce[4..8]); - c[3] = mem.readIntLE(u32, nonce[8..12]); + c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); + c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); chaCha20_internal(out, in, k, c); } @@ -144,19 +145,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = @truncate(u32, counter); c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntLE(u32, nonce[0..4]); - c[3] = mem.readIntLE(u32, nonce[4..8]); + c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); const block_size = (1 << 6); const big_block = (block_size << 32); diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig index 8663fa751..994a7fa25 100644 --- a/std/crypto/md5.zig +++ b/std/crypto/md5.zig @@ -112,7 +112,8 @@ pub const Md5 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig index a5d9fcdf5..0d7a4d672 100644 --- a/std/crypto/poly1305.zig +++ b/std/crypto/poly1305.zig @@ -6,8 +6,8 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; pub const Poly1305 = struct { const Self = @This(); @@ -59,19 +59,19 @@ pub const Poly1305 = struct { { var i: usize = 0; while (i < 1) : (i += 1) { - ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff; + ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff; } } { var i: usize = 1; while (i < 4) : (i += 1) { - ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc; + ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc; } } { var i: usize = 0; while (i < 4) : (i += 1) { - ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little); + ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]); } } @@ -168,10 +168,10 @@ pub const Poly1305 = struct { const nb_blocks = nmsg.len >> 4; var i: usize = 0; while (i < nb_blocks) : (i += 1) { - ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little); - ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little); - ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little); - ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little); + ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); + ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); + ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); + ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); polyBlock(ctx); nmsg = nmsg[16..]; } @@ -210,10 +210,11 @@ pub const Poly1305 = struct { const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 - writeInt(out[0..], @truncate(u32, uu0), Endian.Little); - writeInt(out[4..], @truncate(u32, uu1), Endian.Little); - writeInt(out[8..], @truncate(u32, uu2), Endian.Little); - writeInt(out[12..], @truncate(u32, uu3), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); + writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); + writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); + writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); ctx.secureZero(); } diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig index 1cb0b1743..d5aab8f33 100644 --- a/std/crypto/sha1.zig +++ b/std/crypto/sha1.zig @@ -109,7 +109,8 @@ pub const Sha1 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig index 7e9749364..0476a3a25 100644 --- a/std/crypto/sha2.zig +++ b/std/crypto/sha2.zig @@ -167,7 +167,8 @@ fn Sha2_32(comptime params: Sha2Params32) type { const rr = d.s[0 .. params.out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } @@ -508,7 +509,8 @@ fn Sha2_64(comptime params: Sha2Params64) type { const rr = d.s[0 .. params.out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); } } diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig index 881370e68..e686e1337 100644 --- a/std/crypto/sha3.zig +++ b/std/crypto/sha3.zig @@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { var c = []const u64{0} ** 5; for (s) |*r, i| { - r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]); } comptime var x: usize = 0; @@ -167,7 +167,8 @@ fn keccak_f(comptime F: usize, d: []u8) void { } for (s) |r, i| { - mem.writeInt(d[8 * i .. 8 * i + 8], r, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); } } diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig index 281813b45..daccb5680 100644 --- a/std/crypto/x25519.zig +++ b/std/crypto/x25519.zig @@ -7,8 +7,8 @@ const builtin = @import("builtin"); const fmt = std.fmt; const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; // Based on Supercop's ref10 implementation. pub const X25519 = struct { @@ -255,16 +255,16 @@ const Fe = struct { var t: [10]i64 = undefined; - t[0] = readInt(s[0..4], u32, Endian.Little); - t[1] = readInt(s[4..7], u32, Endian.Little) << 6; - t[2] = readInt(s[7..10], u32, Endian.Little) << 5; - t[3] = readInt(s[10..13], u32, Endian.Little) << 3; - t[4] = readInt(s[13..16], u32, Endian.Little) << 2; - t[5] = readInt(s[16..20], u32, Endian.Little); - t[6] = readInt(s[20..23], u32, Endian.Little) << 7; - t[7] = readInt(s[23..26], u32, Endian.Little) << 5; - t[8] = readInt(s[26..29], u32, Endian.Little) << 4; - t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2; + t[0] = readIntSliceLittle(u32, s[0..4]); + t[1] = u32(readIntSliceLittle(u24, s[4..7])) << 6; + t[2] = u32(readIntSliceLittle(u24, s[7..10])) << 5; + t[3] = u32(readIntSliceLittle(u24, s[10..13])) << 3; + t[4] = u32(readIntSliceLittle(u24, s[13..16])) << 2; + t[5] = readIntSliceLittle(u32, s[16..20]); + t[6] = u32(readIntSliceLittle(u24, s[20..23])) << 7; + t[7] = u32(readIntSliceLittle(u24, s[23..26])) << 5; + t[8] = u32(readIntSliceLittle(u24, s[26..29])) << 4; + t[9] = (u32(readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; carry1(h, t[0..]); } @@ -544,14 +544,15 @@ const Fe = struct { ut[i] = @bitCast(u32, @intCast(i32, t[i])); } - writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little); - writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little); - writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little); - writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little); - writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little); - writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little); - writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little); - writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); + writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); + writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); + writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); + writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); + writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); + writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); + writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); std.mem.secureZero(i64, t[0..]); } diff --git a/std/debug/index.zig b/std/debug/index.zig index 4a96e9d25..3967e5a8b 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -523,7 +523,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void { const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo; - const signature = try modi.stream.readIntLe(u32); + const signature = try modi.stream.readIntLittle(u32); if (signature != 4) return error.InvalidDebugInfo; @@ -757,9 +757,9 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { try di.pdb.openFile(di.coff, path); var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo; - const version = try pdb_stream.stream.readIntLe(u32); - const signature = try pdb_stream.stream.readIntLe(u32); - const age = try pdb_stream.stream.readIntLe(u32); + const version = try pdb_stream.stream.readIntLittle(u32); + const signature = try pdb_stream.stream.readIntLittle(u32); + const age = try pdb_stream.stream.readIntLittle(u32); var guid: [16]u8 = undefined; try pdb_stream.stream.readNoEof(guid[0..]); if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age) @@ -767,7 +767,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { // We validated the executable and pdb match. const string_table_index = str_tab_index: { - const name_bytes_len = try pdb_stream.stream.readIntLe(u32); + const name_bytes_len = try pdb_stream.stream.readIntLittle(u32); const name_bytes = try allocator.alloc(u8, name_bytes_len); try pdb_stream.stream.readNoEof(name_bytes); @@ -797,8 +797,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { }; const bucket_list = try allocator.alloc(Bucket, present.len); for (present) |_| { - const name_offset = try pdb_stream.stream.readIntLe(u32); - const name_index = try pdb_stream.stream.readIntLe(u32); + const name_offset = try pdb_stream.stream.readIntLittle(u32); + const name_index = try pdb_stream.stream.readIntLittle(u32); const name = mem.toSlice(u8, name_bytes.ptr + name_offset); if (mem.eql(u8, name, "/names")) { break :str_tab_index name_index; @@ -859,7 +859,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator); var sect_cont_offset: usize = 0; if (section_contrib_size != 0) { - const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32)); + const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32)); if (ver != pdb.SectionContrSubstreamVersion.Ver60) return error.InvalidDebugInfo; sect_cont_offset += @sizeOf(u32); @@ -879,11 +879,11 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { } fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { - const num_words = try stream.readIntLe(u32); + const num_words = try stream.readIntLittle(u32); var word_i: usize = 0; var list = ArrayList(usize).init(allocator); while (word_i != num_words) : (word_i += 1) { - const word = try stream.readIntLe(u32); + const word = try stream.readIntLittle(u32); var bit_i: u5 = 0; while (true) : (bit_i += 1) { if (word & (u32(1) << bit_i) != 0) { @@ -1200,7 +1200,7 @@ const Constant = struct { fn asUnsignedLe(self: *const Constant) !u64 { if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readInt(self.payload, u64, builtin.Endian.Little); + return mem.readIntSliceLittle(u64, self.payload); } }; @@ -1381,7 +1381,7 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize } fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { - const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); + const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size); return parseFormValueBlockLen(allocator, in_stream, block_len); } @@ -1395,11 +1395,11 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo } fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { - return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32)); + return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32)); } fn parseFormValueTargetAddrSize(in_stream: var) !u64 { - return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable; + return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable; } fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { @@ -1408,7 +1408,7 @@ fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) } fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue { - const block_len = try in_stream.readIntLe(T); + const block_len = try in_stream.readIntLittle(T); return parseFormValueRefLen(allocator, in_stream, block_len); } @@ -1450,7 +1450,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }, DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) }, + DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) }, DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) }, DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, @@ -1747,11 +1747,11 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr continue; } - const version = try di.dwarf_in_stream.readInt(di.endian, u16); + const version = try di.dwarf_in_stream.readInt(u16, di.endian); // TODO support 3 and 5 if (version != 2 and version != 4) return error.InvalidDebugInfo; - const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); + const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; const minimum_instruction_length = try di.dwarf_in_stream.readByte(); @@ -1820,7 +1820,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr return error.MissingDebugInfo; }, DW.LNE_set_address => { - const addr = try di.dwarf_in_stream.readInt(di.endian, usize); + const addr = try di.dwarf_in_stream.readInt(usize, di.endian); prog.address = addr; }, DW.LNE_define_file => { @@ -1882,7 +1882,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = try di.dwarf_in_stream.readInt(di.endian, u16); + const arg = try di.dwarf_in_stream.readInt(u16, di.endian); prog.address += arg; }, DW.LNS_set_prologue_end => {}, @@ -1914,10 +1914,10 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); - const version = try di.dwarf_in_stream.readInt(di.endian, u16); + const version = try di.dwarf_in_stream.readInt(u16, di.endian); if (version < 2 or version > 5) return error.InvalidDebugInfo; - const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); + const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); const address_size = try di.dwarf_in_stream.readByte(); if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; @@ -1978,8 +1978,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { if (di.debug_ranges) |debug_ranges| { try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset); while (true) { - const begin_addr = try di.dwarf_in_stream.readIntLe(usize); - const end_addr = try di.dwarf_in_stream.readIntLe(usize); + const begin_addr = try di.dwarf_in_stream.readIntLittle(usize); + const end_addr = try di.dwarf_in_stream.readIntLittle(usize); if (begin_addr == 0 and end_addr == 0) { break; } @@ -2001,7 +2001,8 @@ fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { } fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T { - const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian); + // TODO https://github.com/ziglang/zig/issues/863 + const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian); ptr.* += @sizeOf(T); return result; } @@ -2017,11 +2018,12 @@ fn readByteSignedMem(ptr: *[*]const u8) i8 { } fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { - const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]); + // TODO this code can be improved with https://github.com/ziglang/zig/issues/863 + const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { ptr.* += 4; - const result = mem.readIntLE(u64, ptr.*[0..8]); + const result = mem.readIntSliceLittle(u64, ptr.*[0..8]); ptr.* += 8; return result; } else { @@ -2084,10 +2086,10 @@ fn readILeb128Mem(ptr: *[*]const u8) !i64 { } fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { - const first_32_bits = try in_stream.readIntLe(u32); + const first_32_bits = try in_stream.readIntLittle(u32); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { - return in_stream.readIntLe(u64); + return in_stream.readIntLittle(u64); } else { if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; return u64(first_32_bits); diff --git a/std/elf.zig b/std/elf.zig index cf7c29b1e..6a564c328 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -412,7 +412,7 @@ pub const Elf = struct { // skip over padding try seekable_stream.seekForward(9); - elf.file_type = switch (try in.readInt(elf.endian, u16)) { + elf.file_type = switch (try in.readInt(u16, elf.endian)) { 1 => FileType.Relocatable, 2 => FileType.Executable, 3 => FileType.Shared, @@ -420,7 +420,7 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - elf.arch = switch (try in.readInt(elf.endian, u16)) { + elf.arch = switch (try in.readInt(u16, elf.endian)) { 0x02 => Arch.Sparc, 0x03 => Arch.x86, 0x08 => Arch.Mips, @@ -433,32 +433,32 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - const elf_version = try in.readInt(elf.endian, u32); + const elf_version = try in.readInt(u32, elf.endian); if (elf_version != 1) return error.InvalidFormat; if (elf.is_64) { - elf.entry_addr = try in.readInt(elf.endian, u64); - elf.program_header_offset = try in.readInt(elf.endian, u64); - elf.section_header_offset = try in.readInt(elf.endian, u64); + elf.entry_addr = try in.readInt(u64, elf.endian); + elf.program_header_offset = try in.readInt(u64, elf.endian); + elf.section_header_offset = try in.readInt(u64, elf.endian); } else { - elf.entry_addr = u64(try in.readInt(elf.endian, u32)); - elf.program_header_offset = u64(try in.readInt(elf.endian, u32)); - elf.section_header_offset = u64(try in.readInt(elf.endian, u32)); + elf.entry_addr = u64(try in.readInt(u32, elf.endian)); + elf.program_header_offset = u64(try in.readInt(u32, elf.endian)); + elf.section_header_offset = u64(try in.readInt(u32, elf.endian)); } // skip over flags try seekable_stream.seekForward(4); - const header_size = try in.readInt(elf.endian, u16); + const header_size = try in.readInt(u16, elf.endian); if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { return error.InvalidFormat; } - const ph_entry_size = try in.readInt(elf.endian, u16); - const ph_entry_count = try in.readInt(elf.endian, u16); - const sh_entry_size = try in.readInt(elf.endian, u16); - const sh_entry_count = try in.readInt(elf.endian, u16); - elf.string_section_index = u64(try in.readInt(elf.endian, u16)); + const ph_entry_size = try in.readInt(u16, elf.endian); + const ph_entry_count = try in.readInt(u16, elf.endian); + const sh_entry_size = try in.readInt(u16, elf.endian); + const sh_entry_count = try in.readInt(u16, elf.endian); + elf.string_section_index = u64(try in.readInt(u16, elf.endian)); if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; @@ -481,32 +481,32 @@ pub const Elf = struct { if (sh_entry_size != 64) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = try in.readInt(elf.endian, u64); - elf_section.addr = try in.readInt(elf.endian, u64); - elf_section.offset = try in.readInt(elf.endian, u64); - elf_section.size = try in.readInt(elf.endian, u64); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = try in.readInt(elf.endian, u64); - elf_section.ent_size = try in.readInt(elf.endian, u64); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = try in.readInt(u64, elf.endian); + elf_section.addr = try in.readInt(u64, elf.endian); + elf_section.offset = try in.readInt(u64, elf.endian); + elf_section.size = try in.readInt(u64, elf.endian); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = try in.readInt(u64, elf.endian); + elf_section.ent_size = try in.readInt(u64, elf.endian); } } else { if (sh_entry_size != 40) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ? - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = u64(try in.readInt(elf.endian, u32)); - elf_section.addr = u64(try in.readInt(elf.endian, u32)); - elf_section.offset = u64(try in.readInt(elf.endian, u32)); - elf_section.size = u64(try in.readInt(elf.endian, u32)); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = u64(try in.readInt(elf.endian, u32)); - elf_section.ent_size = u64(try in.readInt(elf.endian, u32)); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = u64(try in.readInt(u32, elf.endian)); + elf_section.addr = u64(try in.readInt(u32, elf.endian)); + elf_section.offset = u64(try in.readInt(u32, elf.endian)); + elf_section.size = u64(try in.readInt(u32, elf.endian)); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = u64(try in.readInt(u32, elf.endian)); + elf_section.ent_size = u64(try in.readInt(u32, elf.endian)); } } diff --git a/std/event/io.zig b/std/event/io.zig index bb377a3b6..b11550f7a 100644 --- a/std/event/io.zig +++ b/std/event/io.zig @@ -39,18 +39,22 @@ pub fn InStream(comptime ReadError: type) type { if (amt_read < buf.len) return error.EndOfStream; } - pub async fn readIntLe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Little, T) catch unreachable); + pub async fn readIntLittle(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readIntLittle(T, &bytes); } pub async fn readIntBe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Big, T) catch unreachable); - } - - pub async fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try await (async self.readNoEof(bytes[0..]) catch unreachable); - return mem.readInt(bytes, T, endian); + return mem.readIntBig(T, &bytes); + } + + pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readInt(T, &bytes, endian); } pub async fn readStruct(self: *Self, comptime T: type) !T { diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig index 0fe958c38..ee2695027 100644 --- a/std/hash/siphash.zig +++ b/std/hash/siphash.zig @@ -42,8 +42,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) pub fn init(key: []const u8) Self { debug.assert(key.len >= 16); - const k0 = mem.readInt(key[0..8], u64, Endian.Little); - const k1 = mem.readInt(key[8..16], u64, Endian.Little); + const k0 = mem.readIntSliceLittle(u64, key[0..8]); + const k1 = mem.readIntSliceLittle(u64, key[8..16]); var d = Self{ .v0 = k0 ^ 0x736f6d6570736575, @@ -121,7 +121,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) fn round(d: *Self, b: []const u8) void { debug.assert(b.len == 8); - const m = mem.readInt(b[0..], u64, Endian.Little); + const m = mem.readIntSliceLittle(u64, b[0..]); d.v3 ^= m; comptime var i: usize = 0; @@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; test "siphash64-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][8]u8{ "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // "" "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00" "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc @@ -235,13 +235,13 @@ test "siphash64-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u64, Endian.Little); + const expected = mem.readIntLittle(u64, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } test "siphash128-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][16]u8{ "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93", "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45", "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4", @@ -314,7 +314,7 @@ test "siphash128-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u128, Endian.Little); + const expected = mem.readIntLittle(u128, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } diff --git a/std/heap.zig b/std/heap.zig index 5c31d412c..46b247fa7 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -66,7 +66,7 @@ pub const DirectAllocator = struct { } } - fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { + fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { diff --git a/std/io.zig b/std/io.zig index bdca2b03e..444219171 100644 --- a/std/io.zig +++ b/std/io.zig @@ -152,35 +152,42 @@ pub fn InStream(comptime ReadError: type) type { } /// Reads a native-endian integer - pub fn readIntNe(self: *Self, comptime T: type) !T { - return self.readInt(builtin.endian, T); - } - - pub fn readIntLe(self: *Self, comptime T: type) !T { + pub fn readIntNative(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntLE(T, bytes); + return mem.readIntSliceNative(T, bytes); } - pub fn readIntBe(self: *Self, comptime T: type) !T { + /// Reads a foreign-endian integer + pub fn readIntForeign(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntBE(T, bytes); + return mem.readIntSliceForeign(T, bytes); } - pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { + pub fn readIntLittle(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readInt(bytes, T, endian); + return mem.readIntSliceLittle(T, bytes); } - pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T { + pub fn readIntBig(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSliceBig(T, bytes); + } + + pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSlice(T, bytes, endian); + } + + pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T { assert(size <= @sizeOf(T)); - assert(size <= 8); - var input_buf: [8]u8 = undefined; - const input_slice = input_buf[0..size]; - try self.readNoEof(input_slice); - return mem.readInt(input_slice, T, endian); + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntSlice(T, bytes, endian); } pub fn skipBytes(self: *Self, num_bytes: usize) !void { @@ -229,25 +236,34 @@ pub fn OutStream(comptime WriteError: type) type { } /// Write a native-endian integer. - pub fn writeIntNe(self: *Self, comptime T: type, value: T) Error!void { - return self.writeInt(builtin.endian, T, value); - } - - pub fn writeIntLe(self: *Self, comptime T: type, value: T) Error!void { + pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntLE(T, &bytes, value); + mem.writeIntNative(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeIntBe(self: *Self, comptime T: type, value: T) Error!void { + /// Write a foreign-endian integer. + pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntBE(T, &bytes, value); + mem.writeIntForeign(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) Error!void { + pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeInt(bytes[0..], value, endian); + mem.writeIntLittle(T, &bytes, value); + return self.writeFn(self, bytes); + } + + pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeIntBig(T, &bytes, value); + return self.writeFn(self, bytes); + } + + pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeInt(T, &bytes, value, endian); return self.writeFn(self, bytes); } }; diff --git a/std/mem.zig b/std/mem.zig index 9914a08e6..97dc46a80 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -407,186 +407,250 @@ test "mem.indexOf" { assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); } -/// Reads an integer from memory with size equal to bytes.len. -/// T specifies the return type, which must be large enough to store -/// the result. -/// See also ::readIntBE or ::readIntLE. -pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T { - if (T.bit_count == 8) { - return bytes[0]; - } - var result: T = 0; - switch (endian) { - builtin.Endian.Big => { - for (bytes) |b| { - result = (result << 8) | b; - } - }, - builtin.Endian.Little => { - const ShiftType = math.Log2Int(T); - for (bytes) |b, index| { - result = result | (T(b) << @intCast(ShiftType, index * 8)); - } - }, - } - return result; +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + comptime assert(T.bit_count % 8 == 0); + return @ptrCast(*align(1) const T, bytes).*; } -/// Reads a big-endian int of type T from bytes. -/// bytes.len must be exactly @sizeOf(T). -pub fn readIntBE(comptime T: type, bytes: []const u8) T { - if (T.is_signed) { - return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes)); - } - assert(bytes.len == @sizeOf(T)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result = (result << 8) | T(bytes[i]); - } - } - return result; +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + comptime assert(T.bit_count % 8 == 0); + return @bswap(T, @ptrCast(*align(1) const T, bytes).*); } -/// Reads a little-endian int of type T from bytes. -/// bytes.len must be exactly @sizeOf(T). -pub fn readIntLE(comptime T: type, bytes: []const u8) T { - if (T.is_signed) { - return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes)); - } - assert(bytes.len == @sizeOf(T)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result |= T(bytes[i]) << i * 8; - } - } - return result; +pub const readIntLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntNative, + builtin.Endian.Big => readIntForeign, +}; + +pub const readIntBig = switch (builtin.endian) { + builtin.Endian.Little => readIntForeign, + builtin.Endian.Big => readIntNative, +}; + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); } -test "readIntBE/LE" { - assert(readIntBE(u0, []u8{}) == 0x0); - assert(readIntLE(u0, []u8{}) == 0x0); - - assert(readIntBE(u8, []u8{0x32}) == 0x32); - assert(readIntLE(u8, []u8{0x12}) == 0x12); - - assert(readIntBE(u16, []u8{ 0x12, 0x34 }) == 0x1234); - assert(readIntLE(u16, []u8{ 0x12, 0x34 }) == 0x3412); - - assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); - assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); - - assert(readIntBE(i8, []u8{0xff}) == -1); - assert(readIntLE(i8, []u8{0xfe}) == -2); - - assert(readIntBE(i16, []u8{ 0xff, 0xfd }) == -3); - assert(readIntLE(i16, []u8{ 0xfc, 0xff }) == -4); +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readIntForeign(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); } -/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes -/// to fill the entire buffer provided. -/// value must be an integer. -pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void { - const uint = @IntType(false, @typeOf(value).bit_count); +pub const readIntSliceLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceNative, + builtin.Endian.Big => readIntSliceForeign, +}; + +pub const readIntSliceBig = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceForeign, + builtin.Endian.Big => readIntSliceNative, +}; + +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { + if (endian == builtin.endian) { + return readIntNative(T, bytes); + } else { + return readIntForeign(T, bytes); + } +} + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); +} + +test "readIntBig and readIntLittle" { + assert(readIntSliceBig(u0, []u8{}) == 0x0); + assert(readIntSliceLittle(u0, []u8{}) == 0x0); + + assert(readIntSliceBig(u8, []u8{0x32}) == 0x32); + assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12); + + assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); + assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); + + assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); + assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); + + assert(readIntSliceBig(i8, []u8{0xff}) == -1); + assert(readIntSliceLittle(i8, []u8{0xfe}) == -2); + + assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); + assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); +} + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, and +/// accepts any integer bit width. +/// This function stores in native endian, which means it is implemented as a simple +/// memory store. +pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + @ptrCast(*align(1) T, buf).* = value; +} + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +/// This function stores in foreign endian, which means it does a @bswap first. +pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + @ptrCast(*align(1) T, buf).* = @bswap(T, value); +} + +pub const writeIntLittle = switch (builtin.endian) { + builtin.Endian.Little => writeIntNative, + builtin.Endian.Big => writeIntForeign, +}; + +pub const writeIntBig = switch (builtin.endian) { + builtin.Endian.Little => writeIntForeign, + builtin.Endian.Big => writeIntNative, +}; + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + if (endian == builtin.endian) { + return writeIntNative(T, buffer, value); + } else { + return writeIntForeign(T, buffer, value); + } +} + +/// Writes a twos-complement little-endian integer to memory. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer after writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntLittle +/// instead. +pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough + const uint = @IntType(false, T.bit_count); var bits = @truncate(uint, value); - switch (endian) { - builtin.Endian.Big => { - var index: usize = buf.len; - while (index != 0) { - index -= 1; - - buf[index] = @truncate(u8, bits); - bits >>= 8; - } - }, - builtin.Endian.Little => { - for (buf) |*b| { - b.* = @truncate(u8, bits); - bits >>= 8; - } - }, - } - assert(bits == 0); -} - -pub fn writeIntBE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); - const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; - } - var index: usize = buf.len; - while (index != 0) { - index -= 1; - - buf[index] = @truncate(u8, bits); - bits >>= 8; - } - assert(bits == 0); -} - -pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); - const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; - } - for (buf) |*b| { + for (buffer) |*b| { b.* = @truncate(u8, bits); bits >>= 8; } - assert(bits == 0); } -test "writeIntBE/LE" { +/// Writes a twos-complement big-endian integer to memory. +/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer before writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntBig instead. +pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough + const uint = @IntType(false, T.bit_count); + var bits = @truncate(uint, value); + var index: usize = buffer.len; + while (index != 0) { + index -= 1; + buffer[index] = @truncate(u8, bits); + bits >>= 8; + } +} + +pub const writeIntSliceNative = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceLittle, + builtin.Endian.Big => writeIntSliceBig, +}; + +pub const writeIntSliceForeign = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceBig, + builtin.Endian.Big => writeIntSliceLittle, +}; + +/// Writes a twos-complement integer to memory, with the specified endianness. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Any extra bytes in buffer not part of the integer are set to zero, with +/// respect to endianness. To avoid the branch to check for extra buffer bytes, +/// use writeInt instead. +pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + switch (endian) { + builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value), + builtin.Endian.Big => return writeIntSliceBig(T, buffer, value), + } +} + +test "writeIntBig and writeIntLittle" { var buf0: [0]u8 = undefined; var buf1: [1]u8 = undefined; var buf2: [2]u8 = undefined; var buf9: [9]u8 = undefined; - writeIntBE(u0, &buf0, 0x0); + writeIntBig(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntLE(u0, &buf0, 0x0); + writeIntLittle(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntBE(u8, &buf1, 0x12); + writeIntBig(u8, &buf1, 0x12); assert(eql_slice_u8(buf1[0..], []u8{0x12})); - writeIntLE(u8, &buf1, 0x34); + writeIntLittle(u8, &buf1, 0x34); assert(eql_slice_u8(buf1[0..], []u8{0x34})); - writeIntBE(u16, &buf2, 0x1234); + writeIntBig(u16, &buf2, 0x1234); assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); - writeIntLE(u16, &buf2, 0x5678); + writeIntLittle(u16, &buf2, 0x5678); assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); - writeIntBE(u72, &buf9, 0x123456789abcdef024); + writeIntBig(u72, &buf9, 0x123456789abcdef024); assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); - writeIntLE(u72, &buf9, 0xfedcba9876543210ec); + writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); - writeIntBE(i8, &buf1, -1); + writeIntBig(i8, &buf1, -1); assert(eql_slice_u8(buf1[0..], []u8{0xff})); - writeIntLE(i8, &buf1, -2); + writeIntLittle(i8, &buf1, -2); assert(eql_slice_u8(buf1[0..], []u8{0xfe})); - writeIntBE(i16, &buf2, -3); + writeIntBig(i16, &buf2, -3); assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); - writeIntLE(i16, &buf2, -4); + writeIntLittle(i16, &buf2, -4); assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); } @@ -735,12 +799,12 @@ fn testReadIntImpl() void { 0x56, 0x78, }; - assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678); - assert(readIntBE(u32, bytes) == 0x12345678); - assert(readIntBE(i32, bytes) == 0x12345678); - assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412); - assert(readIntLE(u32, bytes) == 0x78563412); - assert(readIntLE(i32, bytes) == 0x78563412); + assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); + assert(readIntBig(u32, &bytes) == 0x12345678); + assert(readIntBig(i32, &bytes) == 0x12345678); + assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); + assert(readIntLittle(u32, &bytes) == 0x78563412); + assert(readIntLittle(i32, &bytes) == 0x78563412); } { const buf = []u8{ @@ -749,7 +813,7 @@ fn testReadIntImpl() void { 0x12, 0x34, }; - const answer = readInt(buf, u64, builtin.Endian.Big); + const answer = readInt(u32, &buf, builtin.Endian.Big); assert(answer == 0x00001234); } { @@ -759,7 +823,7 @@ fn testReadIntImpl() void { 0x00, 0x00, }; - const answer = readInt(buf, u64, builtin.Endian.Little); + const answer = readInt(u32, &buf, builtin.Endian.Little); assert(answer == 0x00003412); } { @@ -767,21 +831,33 @@ fn testReadIntImpl() void { 0xff, 0xfe, }; - assert(readIntBE(u16, bytes) == 0xfffe); - assert(readIntBE(i16, bytes) == -0x0002); - assert(readIntLE(u16, bytes) == 0xfeff); - assert(readIntLE(i16, bytes) == -0x0101); + assert(readIntBig(u16, &bytes) == 0xfffe); + assert(readIntBig(i16, &bytes) == -0x0002); + assert(readIntLittle(u16, &bytes) == 0xfeff); + assert(readIntLittle(i16, &bytes) == -0x0101); } } -test "testWriteInt" { +test "std.mem.writeIntSlice" { testWriteIntImpl(); comptime testWriteIntImpl(); } fn testWriteIntImpl() void { var bytes: [8]u8 = undefined; - writeInt(bytes[0..], u64(0x12345678CAFEBABE), builtin.Endian.Big); + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -793,7 +869,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u64(0xBEBAFECA78563412), builtin.Endian.Little); + writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -805,7 +881,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big); + writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -817,7 +893,7 @@ fn testWriteIntImpl() void { 0x78, })); - writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little); + writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -829,7 +905,7 @@ fn testWriteIntImpl() void { 0x00, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -841,7 +917,7 @@ fn testWriteIntImpl() void { 0x34, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x34, 0x12, @@ -939,29 +1015,52 @@ test "std.mem.rotate" { })); } -// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by -// endian-casting the pointer and then dereferencing - -pub fn endianSwapIfLe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Little, T, x); +/// Converts a little-endian integer to host endianness. +pub fn littleToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; } -pub fn endianSwapIfBe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Big, T, x); +/// Converts a big-endian integer to host endianness. +pub fn bigToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } -pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T { - return if (builtin.endian == endian) endianSwap(T, x) else x; +/// Converts an integer from specified endianness to host endianness. +pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { + return switch (endianness_of_x) { + builtin.Endian.Little => littleToNative(T, x), + builtin.Endian.Big => bigToNative(T, x), + }; } -pub fn endianSwap(comptime T: type, x: T) T { - var buf: [@sizeOf(T)]u8 = undefined; - mem.writeInt(buf[0..], x, builtin.Endian.Little); - return mem.readInt(buf, T, builtin.Endian.Big); +/// Converts an integer which has host endianness to the desired endianness. +pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { + return switch (desired_endianness) { + builtin.Endian.Little => nativeToLittle(T, x), + builtin.Endian.Big => nativeToBig(T, x), + }; } -test "std.mem.endianSwap" { - assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE); +/// Converts an integer which has host endianness to little endian. +pub fn nativeToLittle(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; +} + +/// Converts an integer which has host endianness to big endian. +pub fn nativeToBig(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } fn AsBytesReturnType(comptime P: type) type { diff --git a/std/net.zig b/std/net.zig index 006a9d4ac..968c1f019 100644 --- a/std/net.zig +++ b/std/net.zig @@ -23,7 +23,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in = posix.sockaddr_in{ .family = posix.AF_INET, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .addr = ip4, .zero = []u8{0} ** 8, }, @@ -37,7 +37,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in6 = posix.sockaddr_in6{ .family = posix.AF_INET6, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .flowinfo = 0, .addr = ip6.addr, .scope_id = ip6.scope_id, @@ -47,7 +47,7 @@ pub const Address = struct { } pub fn port(self: Address) u16 { - return std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + return mem.bigToNative(u16, self.os_addr.in.port); } pub fn initPosix(addr: posix.sockaddr) Address { @@ -57,12 +57,12 @@ pub const Address = struct { pub fn format(self: *const Address, out_stream: var) !void { switch (self.os_addr.in.family) { posix.AF_INET => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port); const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]); try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port); }, posix.AF_INET6 => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port); try out_stream.print("[TODO render ip6 address]:{}", native_endian_port); }, else => try out_stream.write("(unrecognized address family)"), @@ -193,7 +193,7 @@ pub fn parseIp6(buf: []const u8) !Ip6Addr { } test "std.net.parseIp4" { - assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001)); + assert((try parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001)); testParseIp4Fail("256.0.0.1", error.Overflow); testParseIp4Fail("x.0.0.1", error.InvalidCharacter); diff --git a/std/os/child_process.zig b/std/os/child_process.zig index c8865bfac..0aa896ff1 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -807,10 +807,10 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8); fn writeIntFd(fd: i32, value: ErrInt) !void { const stream = &os.File.openHandle(fd).outStream().stream; - stream.writeIntNe(ErrInt, value) catch return error.SystemResources; + stream.writeIntNative(ErrInt, value) catch return error.SystemResources; } fn readIntFd(fd: i32) !ErrInt { const stream = &os.File.openHandle(fd).inStream().stream; - return stream.readIntNe(ErrInt) catch return error.SystemResources; + return stream.readIntNative(ErrInt) catch return error.SystemResources; } diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig index 20a671059..509075386 100644 --- a/std/os/freebsd/x86_64.zig +++ b/std/os/freebsd/x86_64.zig @@ -98,12 +98,12 @@ pub nakedcc fn restore_rt() void { } pub const msghdr = extern struct { - msg_name: &u8, + msg_name: *u8, msg_namelen: socklen_t, - msg_iov: &iovec, + msg_iov: *iovec, msg_iovlen: i32, __pad1: i32, - msg_control: &u8, + msg_control: *u8, msg_controllen: socklen_t, __pad2: socklen_t, msg_flags: i32, diff --git a/std/pdb.zig b/std/pdb.zig index 2c5df3e59..0cfc6a6cd 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -508,11 +508,11 @@ const Msf = struct { allocator, ); - const stream_count = try self.directory.stream.readIntLe(u32); + const stream_count = try self.directory.stream.readIntLittle(u32); const stream_sizes = try allocator.alloc(u32, stream_count); for (stream_sizes) |*s| { - const size = try self.directory.stream.readIntLe(u32); + const size = try self.directory.stream.readIntLittle(u32); s.* = blockCountFromSize(size, superblock.BlockSize); } @@ -603,7 +603,7 @@ const MsfStream = struct { var i: u32 = 0; while (i < block_count) : (i += 1) { - stream.blocks[i] = try in.readIntLe(u32); + stream.blocks[i] = try in.readIntLittle(u32); } return stream; diff --git a/std/rand/index.zig b/std/rand/index.zig index 97101bc3b..c335063e6 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -5,7 +5,7 @@ // ``` // var buf: [8]u8 = undefined; // try std.os.getRandomBytes(buf[0..]); -// const seed = mem.readIntLE(u64, buf[0..8]); +// const seed = mem.readIntSliceLittle(u64, buf[0..8]); // // var r = DefaultPrng.init(seed); // @@ -52,7 +52,7 @@ pub const Random = struct { // use LE instead of native endian for better portability maybe? // TODO: endian portability is pointless if the underlying prng isn't endian portable. // TODO: document the endian portability of this library. - const byte_aligned_result = mem.readIntLE(ByteAlignedT, rand_bytes); + const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes); const unsigned_result = @truncate(UnsignedT, byte_aligned_result); return @bitCast(T, unsigned_result); } @@ -69,6 +69,7 @@ pub const Random = struct { return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than)); } } + /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`. /// This function assumes that the underlying ::fillFn produces evenly distributed values. /// Within this assumption, the runtime of this function is exponentially distributed. @@ -123,6 +124,7 @@ pub const Random = struct { } return r.uintLessThanBiased(T, at_most + 1); } + /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -151,6 +153,7 @@ pub const Random = struct { return at_least + r.uintLessThanBiased(T, less_than - at_least); } } + /// Returns an evenly distributed random integer `at_least <= i < less_than`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -185,6 +188,7 @@ pub const Random = struct { return at_least + r.uintAtMostBiased(T, at_most - at_least); } } + /// Returns an evenly distributed random integer `at_least <= i <= at_most`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. diff --git a/std/unicode.zig b/std/unicode.zig index fcb748401..2e542bcb1 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -249,12 +249,12 @@ pub const Utf16LeIterator = struct { pub fn nextCodepoint(it: *Utf16LeIterator) !?u32 { assert(it.i <= it.bytes.len); if (it.i == it.bytes.len) return null; - const c0: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c0: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c0 & ~u32(0x03ff) == 0xd800) { // surrogate pair it.i += 2; if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; - const c1: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c1: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; it.i += 2; return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); @@ -510,46 +510,46 @@ test "utf16leToUtf8" { const utf16le_as_bytes = @sliceToBytes(utf16le[0..]); { - mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "Aa")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } { // the values just outside the surrogate half range - mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } { // smallest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } { // largest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } @@ -583,7 +583,7 @@ pub fn utf8ToUtf16Le(utf16le: []u16, utf8: []const u8) !usize { while (it.nextCodepoint()) |codepoint| { if (end_index == utf16le_as_bytes.len) return (end_index / 2) + 1; // TODO surrogate pairs - mem.writeInt(utf16le_as_bytes[end_index..], @intCast(u16, codepoint), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[end_index..], @intCast(u16, codepoint)); end_index += 2; } return end_index / 2; diff --git a/test/behavior.zig b/test/behavior.zig index 1d031343d..499c20ee2 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -8,6 +8,7 @@ comptime { _ = @import("cases/atomics.zig"); _ = @import("cases/bitcast.zig"); _ = @import("cases/bool.zig"); + _ = @import("cases/bswap.zig"); _ = @import("cases/bugs/1076.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); @@ -64,6 +65,7 @@ comptime { _ = @import("cases/switch_prong_implicit_cast.zig"); _ = @import("cases/syntax.zig"); _ = @import("cases/this.zig"); + _ = @import("cases/truncate.zig"); _ = @import("cases/try.zig"); _ = @import("cases/type_info.zig"); _ = @import("cases/undefined.zig"); diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig new file mode 100644 index 000000000..57993077e --- /dev/null +++ b/test/cases/bswap.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const assert = std.debug.assert; + +test "@bswap" { + comptime testByteSwap(); + testByteSwap(); +} + +fn testByteSwap() void { + assert(@bswap(u0, 0) == 0); + assert(@bswap(u8, 0x12) == 0x12); + assert(@bswap(u16, 0x1234) == 0x3412); + assert(@bswap(u24, 0x123456) == 0x563412); + assert(@bswap(u32, 0x12345678) == 0x78563412); + assert(@bswap(u40, 0x123456789a) == 0x9a78563412); + assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); + assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); + assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); + assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); + + assert(@bswap(i0, 0) == 0); + assert(@bswap(i8, -50) == -50); + assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); + assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); + assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); + assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); + assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); + assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); + assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); + assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == + @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); +} diff --git a/test/cases/truncate.zig b/test/cases/truncate.zig new file mode 100644 index 000000000..02b5085cc --- /dev/null +++ b/test/cases/truncate.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const assert = std.debug.assert; + +test "truncate u0 to larger integer allowed and has comptime known result" { + var x: u0 = 0; + const y = @truncate(u8, x); + comptime assert(y == 0); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index be839f055..ee3741ee6 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,18 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "reading past end of pointer casted array", + \\comptime { + \\ const array = "aoeu"; + \\ const slice = array[2..]; + \\ const int_ptr = @ptrCast(*const u24, slice.ptr); + \\ const deref = int_ptr.*; + \\} + , + ".tmp_source.zig:5:26: error: attempt to read 3 bytes from [4]u8 at index 2 which is 2 bytes", + ); + cases.add( "error note for function parameter incompatibility", \\fn do_the_thing(func: fn (arg: i32) void) void {} From d770333827549e5dcbb727c7f434eaac9dd433d2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 12 Dec 2018 22:28:15 -0500 Subject: [PATCH 082/110] freebsd: fix os_self_exe_path function and update std lib --- src/os.cpp | 2 +- std/os/freebsd/index.zig | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/os.cpp b/src/os.cpp index eba95b9f2..2f0379c09 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1456,7 +1456,7 @@ Error os_self_exe_path(Buf *out_path) { if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) { return ErrorUnexpected; } - buf_resize(out_path, cb); + buf_resize(out_path, cb - 1); return ErrorNone; #endif return ErrorFileNotFound; diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 75389fc40..9fbeaf1dc 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -9,6 +9,7 @@ pub use @import("errno.zig"); const std = @import("../../index.zig"); const c = std.c; +const maxInt = std.math.maxInt; pub const Kevent = c.Kevent; pub const PATH_MAX = 1024; @@ -22,7 +23,7 @@ pub const PROT_READ = 1; pub const PROT_WRITE = 2; pub const PROT_EXEC = 4; -pub const MAP_FAILED = @maxValue(usize); +pub const MAP_FAILED = maxInt(usize); pub const MAP_SHARED = 0x0001; pub const MAP_PRIVATE = 0x0002; pub const MAP_FIXED = 0x0010; @@ -700,7 +701,7 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti const NSIG = 65; const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize{@maxValue(usize)}; +const all_mask = []usize{maxInt(usize)}; const app_mask = []usize{0xfffffffc7fffffff}; /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. @@ -711,7 +712,7 @@ pub const Sigaction = struct { flags: u32, }; -pub const SIG_ERR = @intToPtr(extern fn (i32) void, @maxValue(usize)); +pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); pub const empty_sigset = []usize{0} ** sigset_t.len; From 7417f2e4b3a9c21249bac38688ef453c6b86acfa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 00:33:13 -0500 Subject: [PATCH 083/110] freebsd: fix issues with syscalls --- std/os/freebsd/index.zig | 133 ++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig index 9fbeaf1dc..34a3414a4 100644 --- a/std/os/freebsd/index.zig +++ b/std/os/freebsd/index.zig @@ -158,7 +158,6 @@ pub const SOCK_SEQPACKET = 5; pub const SOCK_CLOEXEC = 0x10000000; pub const SOCK_NONBLOCK = 0x20000000; -// TODO: From here pub const PROTO_ip = 0o000; pub const PROTO_icmp = 0o001; pub const PROTO_igmp = 0o002; @@ -540,7 +539,7 @@ pub fn getErrno(r: usize) usize { } pub fn dup2(old: i32, new: i32) usize { - return arch.syscall2(SYS_dup2, @intCast(usize, old), @intCast(usize, new)); + return arch.syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new))); } pub fn chdir(path: [*]const u8) usize { @@ -560,12 +559,12 @@ pub fn getcwd(buf: [*]u8, size: usize) usize { } pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { - return arch.syscall3(SYS_getdents, @intCast(usize, fd), @ptrToInt(dirp), count); + return arch.syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); } pub fn isatty(fd: i32) bool { var wsz: winsize = undefined; - return arch.syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; + return arch.syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { @@ -577,7 +576,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize { } pub fn mmap(address: ?*u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize { - return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset)); + return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); } pub fn munmap(address: usize, length: usize) usize { @@ -585,7 +584,7 @@ pub fn munmap(address: usize, length: usize) usize { } pub fn read(fd: i32, buf: [*]u8, count: usize) usize { - return arch.syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count); + return arch.syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn rmdir(path: [*]const u8) usize { @@ -597,11 +596,11 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { } pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return arch.syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize { - return arch.syscall4(SYS_preadv, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return arch.syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } pub fn pipe(fd: *[2]i32) usize { @@ -613,15 +612,15 @@ pub fn pipe2(fd: *[2]i32, flags: usize) usize { } pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { - return arch.syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count); + return arch.syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return arch.syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize { - return arch.syscall4(SYS_pwritev, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return arch.syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } pub fn rename(old: [*]const u8, new: [*]const u8) usize { @@ -637,15 +636,15 @@ pub fn create(path: [*]const u8, perm: usize) usize { } pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize { - return arch.syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode); + return arch.syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); } pub fn close(fd: i32) usize { - return arch.syscall1(SYS_close, @intCast(usize, fd)); + return arch.syscall1(SYS_close, @bitCast(usize, isize(fd))); } pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { - return arch.syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos); + return arch.syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); } pub fn exit(status: i32) noreturn { @@ -654,11 +653,11 @@ pub fn exit(status: i32) noreturn { } pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { - return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, @intCast(usize, flags)); + return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags)); } pub fn kill(pid: i32, sig: i32) usize { - return arch.syscall2(SYS_kill, @bitCast(usize, @intCast(isize, pid)), @intCast(usize, sig)); + return arch.syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); } pub fn unlink(path: [*]const u8) usize { @@ -689,66 +688,65 @@ pub fn setregid(rgid: u32, egid: u32) usize { return arch.syscall2(SYS_setregid, rgid, egid); } -pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize { - // TODO: Implement - return 0; -} - -pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize { - // TODO: Implement - return 0; -} - -const NSIG = 65; -const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize{maxInt(usize)}; -const app_mask = []usize{0xfffffffc7fffffff}; - -/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. -pub const Sigaction = struct { - // TODO: Adjust to use freebsd struct layout - handler: extern fn (i32) void, - mask: sigset_t, - flags: u32, -}; +const NSIG = 32; pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); -pub const empty_sigset = []usize{0} ** sigset_t.len; + +/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. +pub const Sigaction = extern struct { + /// signal handler + __sigaction_u: extern union { + __sa_handler: extern fn (i32) void, + __sa_sigaction: extern fn (i32, *__siginfo, usize) void, + }, + + /// see signal options + sa_flags: u32, + + /// signal mask to apply + sa_mask: sigset_t, +}; + +pub const _SIG_WORDS = 4; +pub const _SIG_MAXSIG = 128; + +pub inline fn _SIG_IDX(sig: usize) usize { + return sig - 1; +} +pub inline fn _SIG_WORD(sig: usize) usize { + return_SIG_IDX(sig) >> 5; +} +pub inline fn _SIG_BIT(sig: usize) usize { + return 1 << (_SIG_IDX(sig) & 31); +} +pub inline fn _SIG_VALID(sig: usize) usize { + return sig <= _SIG_MAXSIG and sig > 0; +} + +pub const sigset_t = extern struct { + __bits: [_SIG_WORDS]u32, +}; pub fn raise(sig: i32) usize { - // TODO implement, see linux equivalent for what we want to try and do - return 0; -} - -fn blockAllSignals(set: *sigset_t) void { - // TODO implement -} - -fn blockAppSignals(set: *sigset_t) void { - // TODO implement -} - -fn restoreSignals(set: *sigset_t) void { - // TODO implement -} - -pub fn sigaddset(set: *sigset_t, sig: u6) void { - const s = sig - 1; - (*set)[usize(s) / usize.bit_count] |= usize(1) << (s & (usize.bit_count - 1)); -} - -pub fn sigismember(set: *const sigset_t, sig: u6) bool { - const s = sig - 1; - return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0; + // TODO have a chat with the freebsd folks and make sure there's no bug in + // their libc. musl-libc blocks signals in between these calls because + // if a signal handler runs and forks between the gettid and sending the + // signal, the parent will get 2 signals, one from itself and one from the child + // if the protection does not belong here, then it belongs in abort(), + // like it does in freebsd's libc. + var id: usize = undefined; + const rc = arch.syscall1(SYS_thr_self, @ptrToInt(&id)); + if (getErrno(rc) != 0) return rc; + return arch.syscall2(SYS_thr_kill, id, @bitCast(usize, isize(sig))); } pub const Stat = arch.Stat; pub const timespec = arch.timespec; pub fn fstat(fd: i32, stat_buf: *Stat) usize { - return arch.syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); + return arch.syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); } pub const iovec = extern struct { @@ -761,10 +759,12 @@ pub const iovec_const = extern struct { iov_len: usize, }; +// TODO avoid libc dependency pub fn kqueue() usize { return errnoWrap(c.kqueue()); } +// TODO avoid libc dependency pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize { return errnoWrap(c.kevent( kq, @@ -776,18 +776,23 @@ pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: )); } +// TODO avoid libc dependency pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize { return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen)); } +// TODO avoid libc dependency pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize { return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen)); } +// TODO avoid libc dependency pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize { return errnoWrap(c.sysctlnametomib(name, wibp, sizep)); } +// TODO avoid libc dependency + /// Takes the return value from a syscall and formats it back in the way /// that the kernel represents it to libc. Errno was a mistake, let's make /// it go away forever. From 6395cf8d6b2cf585214a284039c16d6dc5ef5de3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 06:07:39 -0500 Subject: [PATCH 084/110] fix mistakes introduced in b883bc8 --- doc/langref.html.in | 2 +- std/io.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index f820a05b6..c1a6160e0 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5313,7 +5313,7 @@ comptime { {#header_close#} {#header_open|@bswap#} -

{#syntax#}@swap(comptime T: type, value: T) T{#endsyntax#}
+
{#syntax#}@bswap(comptime T: type, value: T) T{#endsyntax#}

{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.

Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, diff --git a/std/io.zig b/std/io.zig index 444219171..8d33dfc5e 100644 --- a/std/io.zig +++ b/std/io.zig @@ -186,7 +186,7 @@ pub fn InStream(comptime ReadError: type) type { pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T { assert(size <= @sizeOf(T)); var bytes: [@sizeOf(T)]u8 = undefined; - try self.readNoEof(bytes[0..]); + try self.readNoEof(bytes[0..size]); return mem.readIntSlice(T, bytes, endian); } From e98ba5fc4044cd84ab88b10cb8c88d765884462f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 06:38:14 -0500 Subject: [PATCH 085/110] add mem.readVarInt, fix InStream.readVarInt, fix stack traces fixes a regression from b883bc8 --- std/debug/index.zig | 2 +- std/io.zig | 11 ++++++----- std/mem.zig | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index 3967e5a8b..73c6ea7b5 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -1200,7 +1200,7 @@ const Constant = struct { fn asUnsignedLe(self: *const Constant) !u64 { if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readIntSliceLittle(u64, self.payload); + return mem.readVarInt(u64, self.payload, builtin.Endian.Little); } }; diff --git a/std/io.zig b/std/io.zig index 8d33dfc5e..c40ededc0 100644 --- a/std/io.zig +++ b/std/io.zig @@ -183,11 +183,12 @@ pub fn InStream(comptime ReadError: type) type { return mem.readIntSlice(T, bytes, endian); } - pub fn readVarInt(self: *Self, comptime T: type, endian: builtin.Endian, size: usize) !T { - assert(size <= @sizeOf(T)); - var bytes: [@sizeOf(T)]u8 = undefined; - try self.readNoEof(bytes[0..size]); - return mem.readIntSlice(T, bytes, endian); + pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType { + assert(size <= @sizeOf(ReturnType)); + var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined; + const bytes = bytes_buf[0..size]; + try self.readNoEof(bytes); + return mem.readVarInt(ReturnType, bytes, endian); } pub fn skipBytes(self: *Self, num_bytes: usize) !void { diff --git a/std/mem.zig b/std/mem.zig index 97dc46a80..393033f22 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -407,6 +407,27 @@ test "mem.indexOf" { assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); } +/// Reads an integer from memory with size equal to bytes.len. +/// T specifies the return type, which must be large enough to store +/// the result. +pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType { + var result: ReturnType = 0; + switch (endian) { + builtin.Endian.Big => { + for (bytes) |b| { + result = (result << 8) | b; + } + }, + builtin.Endian.Little => { + const ShiftType = math.Log2Int(ReturnType); + for (bytes) |b, index| { + result = result | (ReturnType(b) << @intCast(ShiftType, index * 8)); + } + }, + } + return result; +} + /// Reads an integer from memory with bit count specified by T. /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. From fff6e471259071d9ad8466bcdb0ce42c9d7a90d4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 13 Dec 2018 17:13:10 -0500 Subject: [PATCH 086/110] fixups --- std/buf_map.zig | 42 +++++++++++++++++++++++++++------------ std/os/index.zig | 51 ++++++++++++------------------------------------ 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/std/buf_map.zig b/std/buf_map.zig index a82d1b731..6de0d20cd 100644 --- a/std/buf_map.zig +++ b/std/buf_map.zig @@ -16,7 +16,7 @@ pub const BufMap = struct { return self; } - pub fn deinit(self: *const BufMap) void { + pub fn deinit(self: *BufMap) void { var it = self.hash_map.iterator(); while (true) { const entry = it.next() orelse break; @@ -27,16 +27,34 @@ pub const BufMap = struct { self.hash_map.deinit(); } - pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void { - self.delete(key); - const key_copy = try self.copy(key); - errdefer self.free(key_copy); - const value_copy = try self.copy(value); - errdefer self.free(value_copy); - _ = try self.hash_map.put(key_copy, value_copy); + /// Same as `set` but the key and value become owned by the BufMap rather + /// than being copied. + /// If `setMove` fails, the ownership of key and value does not transfer. + pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void { + const get_or_put = try self.hash_map.getOrPut(key); + if (get_or_put.found_existing) { + self.free(get_or_put.kv.key); + get_or_put.kv.key = key; + } + get_or_put.kv.value = value; } - pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 { + /// `key` and `value` are copied into the BufMap. + pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void { + const value_copy = try self.copy(value); + errdefer self.free(value_copy); + // Avoid copying key if it already exists + const get_or_put = try self.hash_map.getOrPut(key); + if (!get_or_put.found_existing) { + get_or_put.kv.key = self.copy(key) catch |err| { + _ = self.hash_map.remove(key); + return err; + }; + } + get_or_put.kv.value = value_copy; + } + + pub fn get(self: BufMap, key: []const u8) ?[]const u8 { const entry = self.hash_map.get(key) orelse return null; return entry.value; } @@ -47,7 +65,7 @@ pub const BufMap = struct { self.free(entry.value); } - pub fn count(self: *const BufMap) usize { + pub fn count(self: BufMap) usize { return self.hash_map.count(); } @@ -55,11 +73,11 @@ pub const BufMap = struct { return self.hash_map.iterator(); } - fn free(self: *const BufMap, value: []const u8) void { + fn free(self: BufMap, value: []const u8) void { self.hash_map.allocator.free(value); } - fn copy(self: *const BufMap, value: []const u8) ![]const u8 { + fn copy(self: BufMap, value: []const u8) ![]u8 { return mem.dupe(self.hash_map.allocator, u8, value); } }; diff --git a/std/os/index.zig b/std/os/index.zig index 779fa8f8c..be82ad471 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -705,54 +705,28 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory; defer assert(windows.FreeEnvironmentStringsW(ptr) != 0); - var buf: [100]u8 = undefined; - var i: usize = 0; while (true) { if (ptr[i] == 0) return result; const key_start = i; - var fallocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} - - const key_slice = ptr[key_start..i]; - var key: []u8 = undefined; - var heap_key = false; - - key = std.unicode.utf16leToUtf8Alloc(fallocator, key_slice) catch undefined; - - if (key.len == 0) { - key = try std.unicode.utf16leToUtf8Alloc(allocator, key_slice); - heap_key = true; - } + const key_w = ptr[key_start..i]; + const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w); + errdefer allocator.free(key); if (ptr[i] == '=') i += 1; const value_start = i; while (ptr[i] != 0) : (i += 1) {} - - const value_slice = ptr[value_start..i]; - var value: []u8 = undefined; - var heap_value = false; - - value = std.unicode.utf16leToUtf8Alloc(fallocator, value_slice) catch undefined; - - if (value.len == 0) { - value = try std.unicode.utf16leToUtf8Alloc(allocator, value_slice); - heap_value = true; - } + const value_w = ptr[value_start..i]; + const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w); + errdefer allocator.free(value); i += 1; // skip over null byte - try result.set(key, value); - - if (heap_key) { - allocator.free(key); - } - if (heap_value) { - allocator.free(value); - } + try result.setMove(key, value); } } else { for (posix_environ_raw) |ptr| { @@ -795,9 +769,6 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { pub const GetEnvVarOwnedError = error{ OutOfMemory, EnvironmentVariableNotFound, - DanglingSurrogateHalf, - ExpectedSecondSurrogateHalf, - UnexpectedSecondSurrogateHalf, /// See https://github.com/ziglang/zig/issues/1774 InvalidUtf8, @@ -833,7 +804,12 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned continue; } - return try std.unicode.utf16leToUtf8Alloc(allocator, buf); + return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) { + error.DanglingSurrogateHalf => return error.InvalidUtf8, + error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8, + error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8, + error.OutOfMemory => return error.OutOfMemory, + }; } } else { const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; @@ -846,7 +822,6 @@ test "os.getEnvVarOwned" { debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); } - /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { var buf: [MAX_PATH_BYTES]u8 = undefined; From 82bf1eb7a1ae54f0bb52fdb8fdcd89fdaab683f0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Dec 2018 20:21:23 -0500 Subject: [PATCH 087/110] docs: fix alphabetical sorting of builtin functions --- doc/langref.html.in | 187 +++++++++++++++++++++++++++----------------- 1 file changed, 116 insertions(+), 71 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index c1a6160e0..f41eb2dec 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5169,6 +5169,34 @@ fn seq(c: u8) void { If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

{#header_close#} + {#header_open|@alignCast#} +
{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}
+

+ {#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#}, + {#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#} + except with the alignment adjusted to the new value. +

+

A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added + to the generated code to make sure the pointer is aligned as promised.

+ + {#header_close#} + {#header_open|@alignOf#} +
{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}
+

+ This function returns the number of bytes that this type should be aligned to + for the current target to match the C ABI. When the child type of a pointer has + this alignment, the alignment can be omitted from the type. +

+
{#syntax#}const assert = @import("std").debug.assert;
+comptime {
+    assert(*u32 == *align(@alignOf(u32)) u32);
+}{#endsyntax#}
+

+ The result is a target-specific compile time constant. It is guaranteed to be + less than or equal to {#link|@sizeOf(T)|@sizeOf#}. +

+ {#see_also|Alignment#} + {#header_close#} {#header_open|@ArgType#}
{#syntax#}@ArgType(comptime T: type, comptime n: usize) type{#endsyntax#}

@@ -5241,6 +5269,7 @@ fn seq(c: u8) void { Works at compile-time if {#syntax#}value{#endsyntax#} is known at compile time. It's a compile error to bitcast a struct to a scalar type of the same size since structs have undefined layout. However if the struct is packed then it works.

{#header_close#} + {#header_open|@bitOffsetOf#}
{#syntax#}@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}

@@ -5253,52 +5282,6 @@ fn seq(c: u8) void {

{#see_also|@byteOffsetOf#} {#header_close#} - {#header_open|@breakpoint#} -
{#syntax#}@breakpoint(){#endsyntax#}
-

- This function inserts a platform-specific debug trap instruction which causes - debuggers to break there. -

-

- This function is only valid within function scope. -

- - {#header_close#} - {#header_open|@byteOffsetOf#} -
{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}
-

- Returns the byte offset of a field relative to its containing struct. -

- {#see_also|@bitOffsetOf#} - {#header_close#} - {#header_open|@alignCast#} -
{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}
-

- {#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#}, - {#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#} - except with the alignment adjusted to the new value. -

-

A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added - to the generated code to make sure the pointer is aligned as promised.

- - {#header_close#} - {#header_open|@alignOf#} -
{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}
-

- This function returns the number of bytes that this type should be aligned to - for the current target to match the C ABI. When the child type of a pointer has - this alignment, the alignment can be omitted from the type. -

-
{#syntax#}const assert = @import("std").debug.assert;
-comptime {
-    assert(*u32 == *align(@alignOf(u32)) u32);
-}{#endsyntax#}
-

- The result is a target-specific compile time constant. It is guaranteed to be - less than or equal to {#link|@sizeOf(T)|@sizeOf#}. -

- {#see_also|Alignment#} - {#header_close#} {#header_open|@boolToInt#}
{#syntax#}@boolToInt(value: bool) u1{#endsyntax#}
@@ -5312,6 +5295,18 @@ comptime {

{#header_close#} + {#header_open|@breakpoint#} +
{#syntax#}@breakpoint(){#endsyntax#}
+

+ This function inserts a platform-specific debug trap instruction which causes + debuggers to break there. +

+

+ This function is only valid within function scope. +

+ + {#header_close#} + {#header_open|@bswap#}
{#syntax#}@bswap(comptime T: type, value: T) T{#endsyntax#}

{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.

@@ -5321,6 +5316,14 @@ comptime {

{#header_close#} + {#header_open|@byteOffsetOf#} +
{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}
+

+ Returns the byte offset of a field relative to its containing struct. +

+ {#see_also|@bitOffsetOf#} + {#header_close#} + {#header_open|@bytesToSlice#}
{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}

@@ -5387,17 +5390,7 @@ comptime {

{#see_also|Import from C Header File|@cImport|@cDefine|@cUndef#} {#header_close#} - {#header_open|@cUndef#} -
{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}
-

- This function can only occur inside {#syntax#}@cImport{#endsyntax#}. -

-

- This appends #undef $name to the {#syntax#}@cImport{#endsyntax#} - temporary buffer. -

- {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} - {#header_close#} + {#header_open|@clz#}
{#syntax#}@clz(x: T) U{#endsyntax#}

@@ -5413,6 +5406,7 @@ comptime {

{#see_also|@ctz|@popCount#} {#header_close#} + {#header_open|@cmpxchgStrong#}
{#syntax#}@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}

@@ -5468,6 +5462,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val

{#syntax#}@typeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}

{#see_also|Compile Variables|cmpxchgStrong#} {#header_close#} + {#header_open|@compileError#}
{#syntax#}@compileError(comptime msg: []u8){#endsyntax#}

@@ -5480,6 +5475,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val and {#syntax#}comptime{#endsyntax#} functions.

{#header_close#} + {#header_open|@compileLog#}
{#syntax#}@compileLog(args: ...){#endsyntax#}

@@ -5534,6 +5530,7 @@ test "main" { } {#code_end#} {#header_close#} + {#header_open|@ctz#}

{#syntax#}@ctz(x: T) U{#endsyntax#}

@@ -5549,6 +5546,19 @@ test "main" {

{#see_also|@clz|@popCount#} {#header_close#} + + {#header_open|@cUndef#} +
{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}
+

+ This function can only occur inside {#syntax#}@cImport{#endsyntax#}. +

+

+ This appends #undef $name to the {#syntax#}@cImport{#endsyntax#} + temporary buffer. +

+ {#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} + {#header_close#} + {#header_open|@divExact#}
{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}

@@ -5615,14 +5625,6 @@ test "main" { {#see_also|@intToEnum#} {#header_close#} - {#header_open|@errSetCast#} -

{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}
-

- Converts an error value from one error set to another error set. Attempting to convert an error - which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}. -

- {#header_close#} - {#header_open|@errorName#}
{#syntax#}@errorName(err: anyerror) []const u8{#endsyntax#}

@@ -5665,6 +5667,14 @@ test "main" { {#see_also|@intToError#} {#header_close#} + {#header_open|@errSetCast#} +

{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}
+

+ Converts an error value from one error set to another error set. Attempting to convert an error + which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}. +

+ {#header_close#} + {#header_open|@export#}
{#syntax#}@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8{#endsyntax#}

@@ -5733,6 +5743,7 @@ test "main" { This function is only valid within function scope.

{#header_close#} + {#header_open|@handle#}
{#syntax#}@handle(){#endsyntax#}

@@ -5743,6 +5754,7 @@ test "main" { This function is only valid within an async function scope.

{#header_close#} + {#header_open|@import#}
{#syntax#}@import(comptime path: []u8) (namespace){#endsyntax#}

@@ -5763,6 +5775,7 @@ test "main" { {#see_also|Compile Variables|@embedFile#} {#header_close#} + {#header_open|@inlineCall#}

{#syntax#}@inlineCall(function: X, args: ...) Y{#endsyntax#}

@@ -5842,6 +5855,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } bit count for an integer type is {#syntax#}65535{#endsyntax#}.

{#header_close#} + {#header_open|@memberCount#}
{#syntax#}@memberCount(comptime T: type) comptime_int{#endsyntax#}

@@ -5868,6 +5882,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }

{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}

Returns the field type of a struct or union.

{#header_close#} + {#header_open|@memcpy#}
{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}

@@ -5886,6 +5901,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }

{#syntax#}const mem = @import("std").mem;
 mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
{#header_close#} + {#header_open|@memset#}
{#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize){#endsyntax#}

@@ -5903,6 +5919,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}

{#syntax#}const mem = @import("std").mem;
 mem.set(u8, dest, c);{#endsyntax#}
{#header_close#} + {#header_open|@mod#}
{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}

@@ -5916,6 +5933,7 @@ mem.set(u8, dest, c);{#endsyntax#}

For a function that returns an error code, see {#syntax#}@import("std").math.mod{#endsyntax#}.

{#see_also|@rem#} {#header_close#} + {#header_open|@mulWithOverflow#}
{#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}

@@ -5924,6 +5942,7 @@ mem.set(u8, dest, c);{#endsyntax#} If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

{#header_close#} + {#header_open|@newStackCall#}
{#syntax#}@newStackCall(new_stack: []u8, function: var, args: ...) var{#endsyntax#}

@@ -5960,6 +5979,7 @@ fn targetFunction(x: i32) usize { } {#code_end#} {#header_close#} + {#header_open|@noInlineCall#}

{#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}

@@ -5982,6 +6002,7 @@ fn add(a: i32, b: i32) i32 {

{#see_also|@inlineCall#} {#header_close#} + {#header_open|@OpaqueType#}
{#syntax#}@OpaqueType() type{#endsyntax#}

@@ -6005,6 +6026,7 @@ test "call foo" { } {#code_end#} {#header_close#} + {#header_open|@panic#}

{#syntax#}@panic(message: []const u8) noreturn{#endsyntax#}

@@ -6021,6 +6043,7 @@ test "call foo" { {#see_also|Root Source File#} {#header_close#} + {#header_open|@popCount#}

{#syntax#}@popCount(integer: var) var{#endsyntax#}

Counts the number of bits set in an integer.

@@ -6031,12 +6054,14 @@ test "call foo" {

{#see_also|@ctz|@clz#} {#header_close#} + {#header_open|@ptrCast#}
{#syntax#}@ptrCast(comptime DestType: type, value: var) DestType{#endsyntax#}

Converts a pointer of one type to a pointer of another type.

{#header_close#} + {#header_open|@ptrToInt#}
{#syntax#}@ptrToInt(value: var) usize{#endsyntax#}

@@ -6051,6 +6076,7 @@ test "call foo" {

To convert the other way, use {#link|@intToPtr#}

{#header_close#} + {#header_open|@rem#}
{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}

@@ -6064,6 +6090,7 @@ test "call foo" {

For a function that returns an error code, see {#syntax#}@import("std").math.rem{#endsyntax#}.

{#see_also|@mod#} {#header_close#} + {#header_open|@returnAddress#}
{#syntax#}@returnAddress(){#endsyntax#}

@@ -6084,19 +6111,14 @@ test "call foo" { Ensures that a function will have a stack alignment of at least {#syntax#}alignment{#endsyntax#} bytes.

{#header_close#} + {#header_open|@setCold#}
{#syntax#}@setCold(is_cold: bool){#endsyntax#}

Tells the optimizer that a function is rarely called.

{#header_close#} - {#header_open|@setRuntimeSafety#} -
{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}
-

- Sets whether runtime safety checks are on for the scope that contains the function call. -

- {#header_close#} {#header_open|@setEvalBranchQuota#}
{#syntax#}@setEvalBranchQuota(new_quota: usize){#endsyntax#}

@@ -6131,6 +6153,7 @@ test "foo" { {#see_also|comptime#} {#header_close#} + {#header_open|@setFloatMode#}

{#syntax#}@setFloatMode(mode: @import("builtin").FloatMode){#endsyntax#}

@@ -6165,6 +6188,7 @@ pub const FloatMode = enum {

{#see_also|Floating Point Operations#} {#header_close#} + {#header_open|@setGlobalLinkage#}
{#syntax#}@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage){#endsyntax#}

@@ -6172,6 +6196,15 @@ pub const FloatMode = enum {

{#see_also|Compile Variables#} {#header_close#} + + {#header_open|@setRuntimeSafety#} +
{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}
+

+ Sets whether runtime safety checks are on for the scope that contains the function call. +

+ + {#header_close#} + {#header_open|@shlExact#}
{#syntax#}@shlExact(value: T, shift_amt: Log2T) T{#endsyntax#}

@@ -6184,6 +6217,7 @@ pub const FloatMode = enum {

{#see_also|@shrExact|@shlWithOverflow#} {#header_close#} + {#header_open|@shlWithOverflow#}
{#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}

@@ -6197,6 +6231,7 @@ pub const FloatMode = enum {

{#see_also|@shlExact|@shrExact#} {#header_close#} + {#header_open|@shrExact#}
{#syntax#}@shrExact(value: T, shift_amt: Log2T) T{#endsyntax#}

@@ -6238,6 +6273,7 @@ pub const FloatMode = enum { This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead.

{#header_close#} + {#header_open|@subWithOverflow#}
{#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}

@@ -6246,12 +6282,14 @@ pub const FloatMode = enum { If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.

{#header_close#} + {#header_open|@tagName#}
{#syntax#}@tagName(value: var) []const u8{#endsyntax#}

Converts an enum value or union value to a slice of bytes representing the name.

{#header_close#} + {#header_open|@TagType#}
{#syntax#}@TagType(T: type) type{#endsyntax#}

@@ -6261,6 +6299,7 @@ pub const FloatMode = enum { For a union, returns the enum type that is used to store the tag value.

{#header_close#} + {#header_open|@This#}
{#syntax#}@This() type{#endsyntax#}

@@ -6296,6 +6335,7 @@ fn List(comptime T: type) type { #1047 for details.

{#header_close#} + {#header_open|@truncate#}
{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}

@@ -6320,6 +6360,7 @@ const b: u8 = @truncate(u8, a);

{#header_close#} + {#header_open|@typeId#}
{#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}

@@ -6354,6 +6395,7 @@ pub const TypeId = enum { }; {#code_end#} {#header_close#} + {#header_open|@typeInfo#}

{#syntax#}@typeInfo(comptime T: type) @import("builtin").TypeInfo{#endsyntax#}

@@ -6536,6 +6578,7 @@ pub const TypeInfo = union(TypeId) { }; {#code_end#} {#header_close#} + {#header_open|@typeName#}

{#syntax#}@typeName(T: type) []u8{#endsyntax#}

@@ -6543,6 +6586,7 @@ pub const TypeInfo = union(TypeId) {

{#header_close#} + {#header_open|@typeOf#}
{#syntax#}@typeOf(expression) type{#endsyntax#}

@@ -6552,6 +6596,7 @@ pub const TypeInfo = union(TypeId) { {#header_close#} {#header_close#} + {#header_open|Build Mode#}

Zig has four build modes: From 624c74af6f61da55e2ba5dcb6b8605b6aec2cea2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Dec 2018 11:22:33 -0500 Subject: [PATCH 088/110] ci: install openssl on windows --- ci/azure/windows_install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/azure/windows_install b/ci/azure/windows_install index 952e9f78c..760520e0b 100755 --- a/ci/azure/windows_install +++ b/ci/azure/windows_install @@ -3,7 +3,7 @@ set -x set -e -pacman -S --needed --noconfirm wget p7zip python3-pip +pacman -S --needed --noconfirm wget p7zip python3-pip openssl pip install s3cmd wget -nv "https://ziglang.org/deps/llvm%2bclang-7.0.0-win64-msvc-release.tar.xz" tar xf llvm+clang-7.0.0-win64-msvc-release.tar.xz From 7533d1b14cb105f604cac3bd1e9dd99cab7a0c2b Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sun, 16 Dec 2018 11:14:53 -0500 Subject: [PATCH 089/110] mem foreign functions call the native ones this reduces the amount of implementation to change for #1835 --- std/mem.zig | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/std/mem.zig b/std/mem.zig index 393033f22..b9772acd6 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -443,8 +443,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is foreign, so it must byte-swap. pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { - comptime assert(T.bit_count % 8 == 0); - return @bswap(T, @ptrCast(*align(1) const T, bytes).*); + return @bswap(T, readIntNative(T, bytes)); } pub const readIntLittle = switch (builtin.endian) { @@ -476,10 +475,7 @@ pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is foreign, so it must byte-swap. pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); - // TODO https://github.com/ziglang/zig/issues/863 - return readIntForeign(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); + return @bswap(T, readIntSliceNative(T, bytes)); } pub const readIntSliceLittle = switch (builtin.endian) { @@ -548,7 +544,7 @@ pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { /// the integer bit width must be divisible by 8. /// This function stores in foreign endian, which means it does a @bswap first. pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - @ptrCast(*align(1) T, buf).* = @bswap(T, value); + writeIntNative(T, buf, @bswap(T, value)); } pub const writeIntLittle = switch (builtin.endian) { From 757d0665ae951bdd5cb754adbe433488f0bea8c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Dec 2018 12:03:37 -0500 Subject: [PATCH 090/110] implement comptime pointer cast closes #955 closes #1835 --- src/ir.cpp | 25 ++++++++++++++++++++++--- std/mem.zig | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index dc87f040b..ef7ad221c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -166,6 +166,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, ZigType *dest_type, IrInstruction *dest_type_src); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); +static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -7364,15 +7365,31 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, return ir_add_error_node(ira, source_instruction->source_node, msg); } +// This function takes a comptime ptr and makes the child const value conform to the type +// described by the pointer. +static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, AstNode *source_node, ConstExprValue *ptr_val) { + Error err; + assert(ptr_val->type->id == ZigTypeIdPointer); + ConstExprValue tmp = {}; + tmp.special = ConstValSpecialStatic; + tmp.type = ptr_val->type->data.pointer.child_type; + if ((err = ir_read_const_ptr(ira, source_node, &tmp, ptr_val))) + return err; + ConstExprValue *child_val = const_ptr_pointee_unchecked(ira->codegen, ptr_val); + copy_const_val(child_val, &tmp, false); + return ErrorNone; +} + static ConstExprValue *ir_const_ptr_pointee(IrAnalyze *ira, ConstExprValue *const_val, AstNode *source_node) { + Error err; ConstExprValue *val = const_ptr_pointee_unchecked(ira->codegen, const_val); assert(val != nullptr); assert(const_val->type->id == ZigTypeIdPointer); ZigType *expected_type = const_val->type->data.pointer.child_type; if (!types_have_same_zig_comptime_repr(val->type, expected_type)) { - ir_add_error_node(ira, source_node, - buf_sprintf("TODO handle comptime reinterpreted pointer. See https://github.com/ziglang/zig/issues/955")); - return nullptr; + if ((err = eval_comptime_ptr_reinterpret(ira, source_node, const_val))) + return nullptr; + return const_ptr_pointee_unchecked(ira->codegen, const_val); } return val; } @@ -19990,6 +20007,8 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct } static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { + if (val->special == ConstValSpecialUndef) + val->special = ConstValSpecialStatic; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { case ZigTypeIdInvalid: diff --git a/std/mem.zig b/std/mem.zig index b9772acd6..0e51601eb 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -510,6 +510,15 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); } +test "comptime read/write int" { + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntLittle(u16, &bytes, 0x1234); + const result = std.mem.readIntBig(u16, &bytes); + std.debug.assert(result == 0x3412); + } +} + test "readIntBig and readIntLittle" { assert(readIntSliceBig(u0, []u8{}) == 0x0); assert(readIntSliceLittle(u0, []u8{}) == 0x0); From 5a68c600235fb7cc0e1bf6a8b314e37890e3823b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Dec 2018 12:32:20 -0500 Subject: [PATCH 091/110] ci: update msys packages before installing --- ci/azure/windows_install | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/azure/windows_install b/ci/azure/windows_install index 760520e0b..8a279210f 100755 --- a/ci/azure/windows_install +++ b/ci/azure/windows_install @@ -3,7 +3,8 @@ set -x set -e -pacman -S --needed --noconfirm wget p7zip python3-pip openssl +pacman -Su --needed --noconfirm +pacman -S --needed --noconfirm wget p7zip python3-pip pip install s3cmd wget -nv "https://ziglang.org/deps/llvm%2bclang-7.0.0-win64-msvc-release.tar.xz" tar xf llvm+clang-7.0.0-win64-msvc-release.tar.xz From f75262b79f0656ebfac7fb5bd2d6d8e8cce01258 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Dec 2018 11:05:50 -0500 Subject: [PATCH 092/110] fix comptime pointer reinterpretation array index offset closes #1835 --- src/ir.cpp | 9 ++++----- std/mem.zig | 6 ++++++ test/behavior.zig | 1 + test/cases/ptrcast.zig | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 test/cases/ptrcast.zig diff --git a/src/ir.cpp b/src/ir.cpp index ef7ad221c..09a9fceab 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13744,20 +13744,19 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, if (array_val->data.x_array.special != ConstArraySpecialNone) zig_panic("TODO"); size_t elem_size = src_size; - src_size = elem_size * - (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index); + size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; + src_size = elem_size * (array_val->type->data.array.len - elem_index); if (dst_size > src_size) { ir_add_error_node(ira, source_node, buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", - dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index, - src_size)); + dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); return ErrorSemanticAnalyzeFail; } size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); Buf buf = BUF_INIT; buf_resize(&buf, elem_count * elem_size); for (size_t i = 0; i < elem_count; i += 1) { - ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); diff --git a/std/mem.zig b/std/mem.zig index 0e51601eb..fb5f6fd5d 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -517,6 +517,12 @@ test "comptime read/write int" { const result = std.mem.readIntBig(u16, &bytes); std.debug.assert(result == 0x3412); } + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntBig(u16, &bytes, 0x1234); + const result = std.mem.readIntLittle(u16, &bytes); + std.debug.assert(result == 0x3412); + } } test "readIntBig and readIntLittle" { diff --git a/test/behavior.zig b/test/behavior.zig index 499c20ee2..e32063dec 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -52,6 +52,7 @@ comptime { _ = @import("cases/optional.zig"); _ = @import("cases/pointers.zig"); _ = @import("cases/popcount.zig"); + _ = @import("cases/ptrcast.zig"); _ = @import("cases/pub_enum/index.zig"); _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("cases/reflection.zig"); diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig new file mode 100644 index 000000000..071087c5c --- /dev/null +++ b/test/cases/ptrcast.zig @@ -0,0 +1,17 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "reinterpret bytes as integer with nonzero offset" { + testReinterpretBytesAsInteger(); + comptime testReinterpretBytesAsInteger(); +} + +fn testReinterpretBytesAsInteger() void { + const bytes = "\x12\x34\x56\x78\xab"; + const expected = switch (builtin.endian) { + builtin.Endian.Little => 0xab785634, + builtin.Endian.Big => 0x345678ab, + }; + assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); +} From e077a446566b0aa77a121f9554f3cb355899653a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Dec 2018 15:48:26 -0500 Subject: [PATCH 093/110] ir: delete dead code --- src/all_types.hpp | 1 - src/codegen.cpp | 26 -------------------------- src/ir.cpp | 3 +-- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 83b7e8495..11304e536 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -605,7 +605,6 @@ enum CastOp { CastOpFloatToInt, CastOpBoolToInt, CastOpResizeSlice, - CastOpBytesToSlice, CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, diff --git a/src/codegen.cpp b/src/codegen.cpp index 08dd11800..e37703d5f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2882,32 +2882,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, gen_store_untyped(g, new_len, dest_len_ptr, 0, false); - return cast_instruction->tmp_ptr; - } - case CastOpBytesToSlice: - { - assert(cast_instruction->tmp_ptr); - assert(wanted_type->id == ZigTypeIdStruct); - assert(wanted_type->data.structure.is_slice); - assert(actual_type->id == ZigTypeIdArray); - - ZigType *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; - ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type; - - - size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index; - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - (unsigned)wanted_ptr_index, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, ""); - gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false); - - size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index; - LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - (unsigned)wanted_len_index, ""); - LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, - actual_type->data.array.len / type_size(g, wanted_child_type), false); - gen_store_untyped(g, len_val, len_ptr, 0, false); - return cast_instruction->tmp_ptr; } case CastOpIntToFloat: diff --git a/src/ir.cpp b/src/ir.cpp index 09a9fceab..76dd6c639 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9339,7 +9339,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ const_val->type = new_type; break; case CastOpResizeSlice: - case CastOpBytesToSlice: // can't do it zig_unreachable(); case CastOpIntToFloat: @@ -9396,7 +9395,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst ZigType *wanted_type, CastOp cast_op, bool need_alloca) { if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && - cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice) + cast_op != CastOpResizeSlice) { IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type); From f6a02a427f6f81e531f05624ee353872e2de7d99 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Dec 2018 15:55:00 -0500 Subject: [PATCH 094/110] README: clarify self-hosted status --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a19e9eb67..c1eec599e 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,8 @@ See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows *Note: Stage 2 compiler is not complete. Beta users of Zig should use the Stage 1 compiler for now.* -Dependencies are the same as Stage 1, except now you have a working zig compiler. +Dependencies are the same as Stage 1, except now you can use stage 1 to compile +Zig code. ``` bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install @@ -183,11 +184,13 @@ binary. ### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler -This is the actual compiler binary that we will install to the system. - *Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is not yet supported.* +Once the self-hosted compiler can build itself, this will be the actual +compiler binary that we will install to the system. Until then, users should +use stage 1. + #### Debug / Development Build ``` From 260c3d9cc0c85c1c4dce98bda9e15ca49ca87d74 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 19 Dec 2018 11:50:29 +0100 Subject: [PATCH 095/110] formatType can now format comptime_int --- std/fmt/index.zig | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/std/fmt/index.zig b/std/fmt/index.zig index eda0bfae0..adf2882f3 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -117,7 +117,7 @@ pub fn formatType( return output(context, @errorName(value)); } switch (@typeInfo(T)) { - builtin.TypeId.Int, builtin.TypeId.Float => { + builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => { return formatValue(value, fmt, context, Errors, output); }, builtin.TypeId.Void => { @@ -268,11 +268,15 @@ fn formatValue( } } - comptime var T = @typeOf(value); + const T = @typeOf(value); switch (@typeId(T)) { builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output), builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output), - else => unreachable, + builtin.TypeId.ComptimeInt => { + const Int = math.IntFittingRange(value, value); + return formatIntValue(Int(value), fmt, context, Errors, output); + }, + else => comptime unreachable, } } @@ -289,9 +293,10 @@ pub fn formatIntValue( if (fmt.len > 0) { switch (fmt[0]) { 'c' => { - if (@typeOf(value) == u8) { - if (fmt.len > 1) @compileError("Unknown format character: " ++ []u8{fmt[1]}); - return formatAsciiChar(value, context, Errors, output); + if (@typeOf(value).bit_count <= 8) { + if (fmt.len > 1) + @compileError("Unknown format character: " ++ []u8{fmt[1]}); + return formatAsciiChar(u8(value), context, Errors, output); } }, 'b' => { @@ -964,6 +969,25 @@ test "fmt.format" { const value: u8 = 0b1100; try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value); } + { + var buf1: [32]u8 = undefined; + var context = BufPrintContext{ .remaining = buf1[0..] }; + try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite); + var res = buf1[0 .. buf1.len - context.remaining.len]; + assert(mem.eql(u8, res, "1234")); + + context = BufPrintContext{ .remaining = buf1[0..] }; + try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); + res = buf1[0 .. buf1.len - context.remaining.len]; + debug.warn("{}\n", res); + assert(mem.eql(u8, res, "a")); + + context = BufPrintContext{ .remaining = buf1[0..] }; + try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite); + res = buf1[0 .. buf1.len - context.remaining.len]; + debug.warn("{}\n", res); + assert(mem.eql(u8, res, "1100")); + } { const value: [3]u8 = "abc"; try testFmt("array: abc\n", "array: {}\n", value); @@ -985,6 +1009,10 @@ test "fmt.format" { try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value); try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value); } + { + const value = @intToPtr(fn () void, 0xdeadbeef); + try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value); + } try testFmt("buf: Test \n", "buf: {s5}\n", "Test"); try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test"); try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C"); From 45e72c0b3944b2fa6d06c7018e9648b4ae60006a Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 19 Dec 2018 15:39:18 +0100 Subject: [PATCH 096/110] Fixed intToPtr to fn type when the address is hardcoded (#1842) * Fixed intToPtr to fn type * Added test * Import inttoptr.zig in behavior.zig --- src/ir.cpp | 1 + test/behavior.zig | 1 + test/cases/inttoptr.zig | 13 +++++++++++++ 3 files changed, 15 insertions(+) create mode 100644 test/cases/inttoptr.zig diff --git a/src/ir.cpp b/src/ir.cpp index 76dd6c639..028582f87 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12495,6 +12495,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct case ReqCompTimeNo: if (casted_init_value->value.special == ConstValSpecialStatic && casted_init_value->value.type->id == ZigTypeIdFn && + casted_init_value->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) { var_class_requires_const = true; diff --git a/test/behavior.zig b/test/behavior.zig index e32063dec..809035977 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -42,6 +42,7 @@ comptime { _ = @import("cases/if.zig"); _ = @import("cases/import.zig"); _ = @import("cases/incomplete_struct_param_tld.zig"); + _ = @import("cases/inttoptr.zig"); _ = @import("cases/ir_block_deps.zig"); _ = @import("cases/math.zig"); _ = @import("cases/merge_error_sets.zig"); diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig new file mode 100644 index 000000000..669535238 --- /dev/null +++ b/test/cases/inttoptr.zig @@ -0,0 +1,13 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "casting random address to function pointer" { + randomAddressToFunction(); + comptime randomAddressToFunction(); +} + +fn randomAddressToFunction() void { + var addr: usize = 0xdeadbeef; + var ptr = @intToPtr(fn () void, addr); +} From a7670e80a49021fb96d1f9a1bbcbcfc6c1e835ab Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 19 Dec 2018 16:07:35 +0100 Subject: [PATCH 097/110] Added formatting of function pointers (#1843) --- std/fmt/index.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/std/fmt/index.zig b/std/fmt/index.zig index adf2882f3..b01007227 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -243,6 +243,9 @@ pub fn formatType( } return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value)); }, + builtin.TypeId.Fn => { + return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value)); + }, else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"), } } @@ -1013,6 +1016,10 @@ test "fmt.format" { const value = @intToPtr(fn () void, 0xdeadbeef); try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value); } + { + const value = @intToPtr(fn () void, 0xdeadbeef); + try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value); + } try testFmt("buf: Test \n", "buf: {s5}\n", "Test"); try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test"); try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C"); From 8768816d69ddf3253d2598923643f390cc18082c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Dec 2018 17:48:21 -0500 Subject: [PATCH 098/110] std.io: call the idiomatic std.mem.readInt functions I originally called the Slice variants to work around comptime code not supporting `@ptrCast`, but I fixed that in 757d0665 so now the workaround is no longer needed. --- std/io.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/std/io.zig b/std/io.zig index c40ededc0..428d95725 100644 --- a/std/io.zig +++ b/std/io.zig @@ -155,32 +155,32 @@ pub fn InStream(comptime ReadError: type) type { pub fn readIntNative(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceNative(T, bytes); + return mem.readIntNative(T, &bytes); } /// Reads a foreign-endian integer pub fn readIntForeign(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceForeign(T, bytes); + return mem.readIntForeign(T, &bytes); } pub fn readIntLittle(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceLittle(T, bytes); + return mem.readIntLittle(T, &bytes); } pub fn readIntBig(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSliceBig(T, bytes); + return mem.readIntBig(T, &bytes); } pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntSlice(T, bytes, endian); + return mem.readInt(T, &bytes, endian); } pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType { From 39567e8b50e9026288bb1323d84f481740bd0de7 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Thu, 20 Dec 2018 22:47:44 +0900 Subject: [PATCH 099/110] src/analyze.cpp: support alignOf(struct T) aligned member inside struct T; ref: ziglang/zig#1832 --- src/analyze.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 46686ce77..e20982213 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2686,13 +2686,22 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } size_t field_count = struct_type->data.structure.src_field_count; + bool self_resolving = false; for (size_t i = 0; i < field_count; i += 1) { TypeStructField *field = &struct_type->data.structure.fields[i]; - // If this assertion trips, look up the call stack. Probably something is - // calling type_resolve with ResolveStatusAlignmentKnown when it should only - // be resolving ResolveStatusZeroBitsKnown - assert(field->type_entry != nullptr); + // If we have no type_entry for the field, assume that we are in the + // midst of resolving this struct. We further assume that since the + // resolved alignment of the other fields of this struct is ultimately + // equal to the resolved alignment of this struct, we can safely ignore. + // + // If this struct is used down-stream in aligning a sub-struct, ignoring + // this struct in the context of a sub struct has the same effect since + // the other fields will be calculated and bubble-up. + if (nullptr == field->type_entry) { + self_resolving = true; + continue; + } if (type_is_invalid(field->type_entry)) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; @@ -2723,6 +2732,14 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } + if ( self_resolving + && field_count > 0 + ) { + // If we get here it's due to self-referencing this struct before it has been fully resolved. + // In this case, set alignment to target pointer default. + struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, + LLVMPointerType(LLVMInt8Type(), 0)); + } struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown; return ErrorNone; } From fb81b1978b87be5a72328a4d9efc21561ae53cfc Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Thu, 20 Dec 2018 22:49:09 +0900 Subject: [PATCH 100/110] tests: re: 79db394; ref: ziglang/zig#1832 --- std/array_list.zig | 11 +++++ .../cases/struct_contains_slice_of_itself.zig | 42 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/std/array_list.zig b/std/array_list.zig index 3ee425fe1..ddad9c989 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -398,3 +398,14 @@ test "std.ArrayList.insertSlice" { assert(list.len == 6); assert(list.items[0] == 1); } + +const Item = struct { + integer: i32, + sub_items: ArrayList(Item), +}; + +test "std.ArrayList: ArrayList(T) of struct T" { + var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) }; + try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } ); + assert(root.sub_items.items[0].integer == 42); +} diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases/struct_contains_slice_of_itself.zig index 07987ae32..aa3075312 100644 --- a/test/cases/struct_contains_slice_of_itself.zig +++ b/test/cases/struct_contains_slice_of_itself.zig @@ -5,6 +5,11 @@ const Node = struct { children: []Node, }; +const NodeAligned = struct { + payload: i32, + children: []align(@alignOf(NodeAligned)) NodeAligned, +}; + test "struct contains slice of itself" { var other_nodes = []Node{ Node{ @@ -41,3 +46,40 @@ test "struct contains slice of itself" { assert(root.children[2].children[0].payload == 31); assert(root.children[2].children[1].payload == 32); } + +test "struct contains aligned slice of itself" { + var other_nodes = []NodeAligned{ + NodeAligned{ + .payload = 31, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 32, + .children = []NodeAligned{}, + }, + }; + var nodes = []NodeAligned{ + NodeAligned{ + .payload = 1, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 2, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 3, + .children = other_nodes[0..], + }, + }; + const root = NodeAligned{ + .payload = 1234, + .children = nodes[0..], + }; + assert(root.payload == 1234); + assert(root.children[0].payload == 1); + assert(root.children[1].payload == 2); + assert(root.children[2].payload == 3); + assert(root.children[2].children[0].payload == 31); + assert(root.children[2].children[1].payload == 32); +} From 0f54194e6ab2b0cbdc798b84cc4213a07ed1d0c1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Dec 2018 12:36:15 -0500 Subject: [PATCH 101/110] fixups --- src/analyze.cpp | 70 ++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index e20982213..9c24f3cc8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2681,48 +2681,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { assert(decl_node->type == NodeTypeContainerDecl); assert(struct_type->di_type); + size_t field_count = struct_type->data.structure.src_field_count; if (struct_type->data.structure.layout == ContainerLayoutPacked) { struct_type->data.structure.abi_alignment = 1; - } - - size_t field_count = struct_type->data.structure.src_field_count; - bool self_resolving = false; - for (size_t i = 0; i < field_count; i += 1) { + for (size_t i = 0; i < field_count; i += 1) { + TypeStructField *field = &struct_type->data.structure.fields[i]; + if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + break; + } + } + } else for (size_t i = 0; i < field_count; i += 1) { TypeStructField *field = &struct_type->data.structure.fields[i]; + uint32_t this_field_align; - // If we have no type_entry for the field, assume that we are in the - // midst of resolving this struct. We further assume that since the - // resolved alignment of the other fields of this struct is ultimately - // equal to the resolved alignment of this struct, we can safely ignore. - // - // If this struct is used down-stream in aligning a sub-struct, ignoring - // this struct in the context of a sub struct has the same effect since - // the other fields will be calculated and bubble-up. - if (nullptr == field->type_entry) { - self_resolving = true; - continue; - } + // TODO If we have no type_entry for the field, we've already failed to + // compile the program correctly. This stage1 compiler needs a deeper + // reworking to make this correct, or we can ignore the problem + // and make sure it is fixed in stage2. This workaround is for when + // there is a false positive of a dependency loop, of alignment depending + // on itself. When this false positive happens we assume a pointer-aligned + // field, which is usually fine but could be incorrectly over-aligned or + // even under-aligned. See https://github.com/ziglang/zig/issues/1512 + if (field->type_entry == nullptr) { + this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0)); + } else { + if (type_is_invalid(field->type_entry)) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + break; + } - if (type_is_invalid(field->type_entry)) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - break; - } + if (!type_has_bits(field->type_entry)) + continue; - if (!type_has_bits(field->type_entry)) - continue; - - // alignment of structs is the alignment of the most-aligned field - if (struct_type->data.structure.layout != ContainerLayoutPacked) { if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; break; } - uint32_t this_field_align = get_abi_alignment(g, field->type_entry); + this_field_align = get_abi_alignment(g, field->type_entry); assert(this_field_align != 0); - if (this_field_align > struct_type->data.structure.abi_alignment) { - struct_type->data.structure.abi_alignment = this_field_align; - } + } + // alignment of structs is the alignment of the most-aligned field + if (this_field_align > struct_type->data.structure.abi_alignment) { + struct_type->data.structure.abi_alignment = this_field_align; } } @@ -2732,14 +2734,6 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } - if ( self_resolving - && field_count > 0 - ) { - // If we get here it's due to self-referencing this struct before it has been fully resolved. - // In this case, set alignment to target pointer default. - struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, - LLVMPointerType(LLVMInt8Type(), 0)); - } struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown; return ErrorNone; } From 48406009889c0e77052b57bc0220a332d3ea5cbd Mon Sep 17 00:00:00 2001 From: Marcio Giaxa Date: Wed, 19 Dec 2018 22:34:51 -0200 Subject: [PATCH 102/110] ci: add sr.ht build manifest for FreeBSD --- .builds/freebsd.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .builds/freebsd.yml diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml new file mode 100644 index 000000000..e293561c2 --- /dev/null +++ b/.builds/freebsd.yml @@ -0,0 +1,15 @@ +arch: x86_64 +image: freebsd +packages: + - cmake + - llvm70 +sources: + - https://github.com/ziglang/zig.git +tasks: + - build: | + cd zig && mkdir build && cd build + cmake .. + make && make install + - test: | + cd zig && cd build + ./bin/zig build --build-file ../build.zig test From 2a776ed8a8ff9220e316cb91fbfb49f23edee0d1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Dec 2018 13:05:34 -0500 Subject: [PATCH 103/110] ci: only run the debug behavior tests for FreeBSD --- .builds/freebsd.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index e293561c2..80b50841a 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -8,8 +8,14 @@ sources: tasks: - build: | cd zig && mkdir build && cd build - cmake .. - make && make install + cmake .. -DCMAKE_BUILD_TYPE=Release + make -j$(sysctl -n hw.ncpu) install - test: | - cd zig && cd build - ./bin/zig build --build-file ../build.zig test + cd zig/build + bin/zig test ../test/behavior.zig + # TODO enable all tests + #bin/zig build --build-file ../build.zig test + # TODO integrate with the download page updater and make a + # static build available to download for FreeBSD. + # This will require setting up a cache of LLVM/Clang built + # statically. From f35ba34a884eb8253c2ddd584605191e1b977595 Mon Sep 17 00:00:00 2001 From: tgschultz Date: Thu, 20 Dec 2018 11:51:37 -0600 Subject: [PATCH 104/110] Removed allocator from Linux version DynLib. Added dynamic_library.zig to std test list. --- std/dynamic_library.zig | 4 +--- std/index.zig | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 49f217bc8..4d1995131 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -19,7 +19,6 @@ pub const DynLib = switch (builtin.os) { }; pub const LinuxDynLib = struct { - allocator: *mem.Allocator, elf_lib: ElfLib, fd: i32, map_addr: usize, @@ -27,7 +26,7 @@ pub const LinuxDynLib = struct { /// Trusts the file pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib { - const fd = try std.os.posixOpen(allocator, path, 0, linux.O_RDONLY | linux.O_CLOEXEC); + const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC); errdefer std.os.close(fd); const size = @intCast(usize, (try std.os.posixFStat(fd)).size); @@ -45,7 +44,6 @@ pub const LinuxDynLib = struct { const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size]; return DynLib{ - .allocator = allocator, .elf_lib = try ElfLib.init(bytes), .fd = fd, .map_addr = addr, diff --git a/std/index.zig b/std/index.zig index 55ad016bb..33eec14b0 100644 --- a/std/index.zig +++ b/std/index.zig @@ -57,7 +57,8 @@ test "std" { _ = @import("mutex.zig"); _ = @import("segmented_list.zig"); _ = @import("spinlock.zig"); - + + _ = @import("dynamic_library.zig"); _ = @import("base64.zig"); _ = @import("build.zig"); _ = @import("c/index.zig"); From fa6c7c130308534af6da93ce3f46520e0bb07ba4 Mon Sep 17 00:00:00 2001 From: myfreeweb Date: Thu, 20 Dec 2018 23:01:49 +0300 Subject: [PATCH 105/110] Use Ninja in .builds/freebsd.yml It's faster and doesn't require manually getting the number of CPUs --- .builds/freebsd.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 80b50841a..db1ddb337 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -2,14 +2,15 @@ arch: x86_64 image: freebsd packages: - cmake + - ninja - llvm70 sources: - https://github.com/ziglang/zig.git tasks: - build: | cd zig && mkdir build && cd build - cmake .. -DCMAKE_BUILD_TYPE=Release - make -j$(sysctl -n hw.ncpu) install + cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release + ninja install - test: | cd zig/build bin/zig test ../test/behavior.zig From 56fedbb52423eba6d2088a1e2c8b94e0c4eb85ac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Dec 2018 19:56:24 -0500 Subject: [PATCH 106/110] translate-c: --verbose-cimport prints clang command --- src/translate_c.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 10f2124eb..f6bc9cd68 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4776,6 +4776,14 @@ Error parse_h_file(ImportTableEntry *import, ZigList *errors, const clang_argv.append(target_file); + if (codegen->verbose_cimport) { + fprintf(stderr, "clang"); + for (size_t i = 0; i < clang_argv.length; i += 1) { + fprintf(stderr, " %s", clang_argv.at(i)); + } + fprintf(stderr, "\n"); + } + // to make the [start...end] argument work clang_argv.append(nullptr); From 0eba5b6744c51892348a7b71726891189b0af7d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Dec 2018 19:50:21 -0500 Subject: [PATCH 107/110] I observed open() return EBUSY on linux when trying to open for writing a tty fd that is already opened with screen --- std/os/index.zig | 5 +++++ std/os/path.zig | 1 + 2 files changed, 6 insertions(+) diff --git a/std/os/index.zig b/std/os/index.zig index be82ad471..b19679c96 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -459,6 +459,7 @@ pub const PosixOpenError = error{ NoSpaceLeft, NotDir, PathAlreadyExists, + DeviceBusy, /// See https://github.com/ziglang/zig/issues/1396 Unexpected, @@ -497,6 +498,7 @@ pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 { posix.ENOTDIR => return PosixOpenError.NotDir, posix.EPERM => return PosixOpenError.AccessDenied, posix.EEXIST => return PosixOpenError.PathAlreadyExists, + posix.EBUSY => return PosixOpenError.DeviceBusy, else => return unexpectedErrorPosix(err), } } @@ -1402,6 +1404,7 @@ const DeleteTreeError = error{ FileSystem, FileBusy, DirNotEmpty, + DeviceBusy, /// On Windows, file paths must be valid Unicode. InvalidUtf8, @@ -1463,6 +1466,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError! error.Unexpected, error.InvalidUtf8, error.BadPathName, + error.DeviceBusy, => return err, }; defer dir.close(); @@ -1545,6 +1549,7 @@ pub const Dir = struct { OutOfMemory, InvalidUtf8, BadPathName, + DeviceBusy, /// See https://github.com/ziglang/zig/issues/1396 Unexpected, diff --git a/std/os/path.zig b/std/os/path.zig index af767b0dc..e61a0f84b 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1093,6 +1093,7 @@ pub const RealError = error{ NoSpaceLeft, FileSystem, BadPathName, + DeviceBusy, /// On Windows, file paths must be valid Unicode. InvalidUtf8, From f301474531fc640729aaa52d66209317c76367c8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Dec 2018 23:01:21 -0500 Subject: [PATCH 108/110] self-hosted: add DeviceBusy as a BuildError --- src-self-hosted/compilation.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 0594cbd74..c00c7c1d4 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -300,6 +300,7 @@ pub const Compilation = struct { UserResourceLimitReached, InvalidUtf8, BadPathName, + DeviceBusy, }; pub const Event = union(enum) { From 218a4d4b30f320797121ad9900d48743da77a1b3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 22 Dec 2018 23:06:30 -0500 Subject: [PATCH 109/110] comptime: ability to @ptrCast to an extern struct and read fields --- src/ir.cpp | 64 ++++++++++++++++++++++++++++++++---------- test/cases/ptrcast.zig | 19 +++++++++++++ 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 028582f87..83960f2ee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -159,7 +159,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); -static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); +static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val); static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); @@ -13725,7 +13725,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, Buf buf = BUF_INIT; buf_resize(&buf, src_size); buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; return ErrorNone; } @@ -13759,7 +13760,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; return ErrorNone; } case ConstPtrSpecialBaseStruct: @@ -20077,7 +20079,8 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } -static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { +static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { + Error err; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { case ZigTypeIdInvalid: @@ -20094,30 +20097,60 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdPromise: zig_unreachable(); case ZigTypeIdVoid: - return; + return ErrorNone; case ZigTypeIdBool: val->data.x_bool = (buf[0] != 0); - return; + return ErrorNone; case ZigTypeIdInt: bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - codegen->is_big_endian, val->type->data.integral.is_signed); - return; + ira->codegen->is_big_endian, val->type->data.integral.is_signed); + return ErrorNone; case ZigTypeIdFloat: - float_read_ieee597(val, buf, codegen->is_big_endian); - return; + float_read_ieee597(val, buf, ira->codegen->is_big_endian); + return ErrorNone; case ZigTypeIdPointer: { val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; BigInt bn; - bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, - codegen->is_big_endian, false); + bigint_read_twos_complement(&bn, buf, ira->codegen->builtin_types.entry_usize->data.integral.bit_count, + ira->codegen->is_big_endian, false); val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); - return; + return ErrorNone; } case ZigTypeIdArray: zig_panic("TODO buf_read_value_bytes array type"); case ZigTypeIdStruct: - zig_panic("TODO buf_read_value_bytes struct type"); + switch (val->type->data.structure.layout) { + case ContainerLayoutAuto: { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted", + buf_ptr(&val->type->name))); + add_error_note(ira->codegen, msg, val->type->data.structure.decl_node, + buf_sprintf("declared here")); + return ErrorSemanticAnalyzeFail; + } + case ContainerLayoutExtern: { + size_t src_field_count = val->type->data.structure.src_field_count; + val->data.x_struct.fields = create_const_vals(src_field_count); + for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { + ConstExprValue *field_val = &val->data.x_struct.fields[field_i]; + field_val->special = ConstValSpecialStatic; + TypeStructField *type_field = &val->type->data.structure.fields[field_i]; + field_val->type = type_field->type_entry; + if (type_field->gen_index == SIZE_MAX) + continue; + size_t offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, val->type->type_ref, + type_field->gen_index); + uint8_t *new_buf = buf + offset; + if ((err = buf_read_value_bytes(ira, source_node, new_buf, field_val))) + return err; + } + return ErrorNone; + } + case ContainerLayoutPacked: + zig_panic("TODO buf_read_value_bytes packed struct"); + } + zig_unreachable(); case ZigTypeIdOptional: zig_panic("TODO buf_read_value_bytes maybe type"); case ZigTypeIdErrorUnion: @@ -20220,7 +20253,8 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, dest_type); uint8_t *buf = allocate_nonzero(src_size_bytes); buf_write_value_bytes(ira->codegen, buf, val); - buf_read_value_bytes(ira->codegen, buf, &result->value); + if ((err = buf_read_value_bytes(ira, instruction->base.source_node, buf, &result->value))) + return ira->codegen->invalid_instruction; return result; } diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig index 071087c5c..6f0e6e594 100644 --- a/test/cases/ptrcast.zig +++ b/test/cases/ptrcast.zig @@ -15,3 +15,22 @@ fn testReinterpretBytesAsInteger() void { }; assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); } + +test "reinterpret bytes of an array into an extern struct" { + testReinterpretBytesAsExternStruct(); + comptime testReinterpretBytesAsExternStruct(); +} + +fn testReinterpretBytesAsExternStruct() void { + var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 }; + + const S = extern struct { + a: u8, + b: u16, + c: u8, + }; + + var ptr = @ptrCast(*const S, &bytes); + var val = ptr.c; + assertOrPanic(val == 5); +} From 45081c1e9cc28757cb563c77553631f7a92b29d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 23 Dec 2018 13:56:49 -0500 Subject: [PATCH 110/110] hello world example can use `const` instead of `var` --- doc/langref.html.in | 2 +- example/hello_world/hello.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index f41eb2dec..2a2b4003f 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -165,7 +165,7 @@ const std = @import("std"); pub fn main() !void { // If this program is run without stdout attached, exit with an error. - var stdout_file = try std.io.getStdOut(); + const stdout_file = try std.io.getStdOut(); // If this program encounters pipe failure when printing to stdout, exit // with an error. try stdout_file.write("Hello, world!\n"); diff --git a/example/hello_world/hello.zig b/example/hello_world/hello.zig index 8e65e06a9..cb7d5ef15 100644 --- a/example/hello_world/hello.zig +++ b/example/hello_world/hello.zig @@ -2,7 +2,7 @@ const std = @import("std"); pub fn main() !void { // If this program is run without stdout attached, exit with an error. - var stdout_file = try std.io.getStdOut(); + const stdout_file = try std.io.getStdOut(); // If this program encounters pipe failure when printing to stdout, exit // with an error. try stdout_file.write("Hello, world!\n");