Make improvements

- More timspec_*() and timeval_*() APIs have been introduced.
- The copyfd() function is now simplified thanks to POSIX rules.
- More Cosmo-specific APIs have been moved behind the COSMO define.
- The setitimer() polyfill for Windows NT is now much higher quality.
- Fixed build error for MODE=aarch64 due to -mstringop-strategy=loop.
- This change introduces `make MODE=nox87 toolchain` which makes it
  possible to build programs using your cosmocc toolchain that don't
  have legacy fpu instructions. This is useful, for example, if you
  want to have a ~22kb tinier blink virtual machine.
This commit is contained in:
Justine Tunney 2023-06-15 13:50:42 -07:00
parent 8dc11afcf6
commit c3440d040c
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
132 changed files with 539 additions and 587 deletions

View file

@ -364,6 +364,28 @@ TARGET_ARCH ?= \
-msse3
endif
# no x87 instructions mode
#
# export MODE=nox87
# make -j8 toolchain
# cosmocc -o /tmp/hello.com hello.c
#
# lets you shave ~23kb off blink
#
# git clone https://github.com/jart/blink
# cd blink
# ./configure --disable-x87
# make -j8
# o//blink/blink /tmp/hello.com
#
ifeq ($(MODE), nox87)
ENABLE_FTRACE = 1
CONFIG_COPTS += -mlong-double-64
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DNOX87
TARGET_ARCH ?= -msse3
endif
# LLVM Mode
ifeq ($(MODE), llvm)
TARGET_ARCH ?= -msse3

View file

@ -33,7 +33,6 @@
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/tls.h"
#ifdef __x86_64__
/**

View file

@ -42,14 +42,6 @@
#define MAP_FAILED ((void *)-1)
#define ARCH_SET_GS 0x1001
#define ARCH_SET_FS 0x1002
#define ARCH_GET_FS 0x1003
#define ARCH_GET_GS 0x1004
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
#define WCOREDUMP(s) (128 & (s))
#define WEXITSTATUS(s) ((0xff00 & (s)) >> 8)
#define WIFCONTINUED(s) ((s) == 0xffff)
@ -69,11 +61,9 @@ COSMOPOLITAN_C_START_
typedef int sig_atomic_t;
bool32 isatty(int) nosideeffect;
char *commandv(const char *, char *, size_t);
char *get_current_dir_name(void) dontdiscard;
char *getcwd(char *, size_t);
char *realpath(const char *, char *);
char *replaceuser(const char *) dontdiscard;
char *ttyname(int);
int access(const char *, int) dontthrow;
int chdir(const char *);
@ -122,7 +112,6 @@ int getpriority(int, unsigned);
int getresgid(unsigned *, unsigned *, unsigned *);
int getresuid(unsigned *, unsigned *, unsigned *);
int getsid(int) nosideeffect libcesque;
int gettid(void) libcesque;
int ioprio_get(int, int);
int ioprio_set(int, int, int);
int issetugid(void);
@ -133,8 +122,6 @@ int lchown(const char *, unsigned, unsigned);
int link(const char *, const char *) dontthrow;
int linkat(int, const char *, int, const char *, int);
int madvise(void *, uint64_t, int);
int makedirs(const char *, unsigned);
int memfd_create(const char *, unsigned int);
int mincore(void *, size_t, unsigned char *);
int mkdir(const char *, unsigned);
int mkdirat(int, const char *, unsigned);
@ -146,14 +133,10 @@ int nice(int);
int open(const char *, int, ...);
int openat(int, const char *, int, ...);
int pause(void);
int personality(uint64_t);
int pipe(int[hasatleast 2]);
int pipe2(int[hasatleast 2], int);
int pivot_root(const char *, const char *);
int pledge(const char *, const char *);
int posix_fadvise(int, int64_t, int64_t, int);
int posix_madvise(void *, uint64_t, int);
int prctl(int, ...);
int raise(int);
int reboot(int);
int remove(const char *);
@ -161,7 +144,6 @@ int rename(const char *, const char *);
int renameat(int, const char *, int, const char *);
int rmdir(const char *);
int sched_yield(void);
int seccomp(unsigned, unsigned, void *);
int setegid(unsigned);
int seteuid(unsigned);
int setfsgid(unsigned);
@ -182,37 +164,21 @@ int siginterrupt(int, int);
int symlink(const char *, const char *);
int symlinkat(const char *, int, const char *);
int sync_file_range(int, int64_t, int64_t, unsigned);
int sys_iopl(int);
int sys_mlock(const void *, size_t);
int sys_mlock2(const void *, size_t, int);
int sys_mlockall(int);
int sys_munlock(const void *, size_t);
int sys_munlockall(void);
int sys_ptrace(int, ...);
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
int tcgetpgrp(int);
int tcsetpgrp(int, int);
int tgkill(int, int, int);
int tkill(int, int);
int tmpfd(void);
int touch(const char *, unsigned);
int truncate(const char *, int64_t);
int ttyname_r(int, char *, size_t);
int unlink(const char *);
int unlink_s(const char **);
int unlinkat(int, const char *, int);
int unveil(const char *, const char *);
int usleep(unsigned);
int vfork(void) returnstwice;
int wait(int *);
int waitpid(int, int *, int);
long ptrace(int, ...);
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
ssize_t lseek(int, int64_t, int);
ssize_t pread(int, void *, size_t, int64_t);
ssize_t pwrite(int, const void *, size_t, int64_t);
ssize_t read(int, void *, size_t);
ssize_t readansi(int, char *, size_t);
ssize_t readlink(const char *, char *, size_t);
ssize_t readlinkat(int, const char *, char *, size_t);
ssize_t splice(int, int64_t *, int, int64_t *, size_t, unsigned);
@ -225,20 +191,38 @@ unsigned umask(unsigned);
void sync(void);
#ifdef COSMO
#define fileexists __fileexists
#define isdirectory __isdirectory
#define isexecutable __isexecutable
#define isregularfile __isregularfile
#define issymlink __issymlink
#define ischardev __ischardev
#define copyfd __copyfd
bool fileexists(const char *);
bool isdirectory(const char *);
bool isexecutable(const char *);
bool isregularfile(const char *);
bool issymlink(const char *);
bool32 ischardev(int) nosideeffect;
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
bool32 ischardev(int);
char *commandv(const char *, char *, size_t);
char *replaceuser(const char *) dontdiscard;
int gettid(void) libcesque;
int makedirs(const char *, unsigned);
int memfd_create(const char *, unsigned int);
int personality(uint64_t);
int pivot_root(const char *, const char *);
int pledge(const char *, const char *);
int prctl(int, ...);
int seccomp(unsigned, unsigned, void *);
int sys_iopl(int);
int sys_mlock(const void *, size_t);
int sys_mlock2(const void *, size_t, int);
int sys_mlockall(int);
int sys_munlock(const void *, size_t);
int sys_munlockall(void);
int sys_ptrace(int, ...);
int sys_sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
int tgkill(int, int, int);
int tkill(int, int);
int tmpfd(void);
int touch(const char *, unsigned);
int unveil(const char *, const char *);
long ptrace(int, ...);
ssize_t copyfd(int, int, size_t);
ssize_t readansi(int, char *, size_t);
#endif
COSMOPOLITAN_C_END_

View file

@ -103,6 +103,7 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: private \
COPTS += \
-fno-sanitize=all
ifneq ($(ARCH), aarch64)
# we always want -O3 because:
# it makes the code size smaller too
# we need -mstringop-strategy=loop because:
@ -116,6 +117,7 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: private \
COPTS += \
-O3 \
-mstringop-strategy=loop
endif
# we must disable static stack safety because:
# these functions use alloca(n)

View file

@ -42,7 +42,6 @@
* time. Among the more popular is CLOCK_MONOTONIC. This function has a
* zero syscall implementation of that on modern x86.
*
* nowl l: 45𝑐 15𝑛𝑠
* rdtsc l: 13𝑐 4𝑛𝑠
* gettimeofday l: 44𝑐 14𝑛𝑠
* clock_gettime l: 40𝑐 13𝑛𝑠

View file

@ -17,59 +17,34 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#define CHUNK 32768
#include "libc/macros.internal.h"
/**
* Copies data between fds the old fashioned way.
* Copies data between file descriptors the old fashioned way.
*
* @return bytes successfully exchanged
* This function is intended for simple programs without signals. If
* signals are in play, then `SA_RESTART` needs to be used.
*
* @param in is input file descriptor
* @param out is input file descriptor
* @param n is number of bytes to exchange, or -1 for until eof
* @return bytes successfully exchanged, or -1 w/ errno
*/
ssize_t _copyfd(int infd, int outfd, size_t n) {
int e;
char *buf;
ssize_t rc;
size_t i, j, got, sent;
rc = 0;
if (n) {
if ((buf = malloc(CHUNK))) {
for (e = errno, i = 0; i < n; i += j) {
rc = read(infd, buf, CHUNK);
if (rc == -1) {
// eintr may interrupt the read operation
if (i && errno == EINTR) {
// suppress error if partially completed
errno = e;
rc = i;
}
break;
}
got = rc;
if (!got) {
rc = i;
break;
}
// write operation must complete
for (j = 0; j < got; j += sent) {
rc = write(outfd, buf + j, got - j);
if (rc != -1) {
sent = rc;
} else if (errno == EINTR) {
// write operation must be uninterruptible
errno = e;
sent = 0;
} else {
break;
}
}
if (rc == -1) break;
}
free(buf);
} else {
rc = -1;
ssize_t copyfd(int in, int out, size_t n) {
size_t i;
char buf[512];
ssize_t dr, dw;
for (i = 0; i < n; i += dr) {
dr = read(in, buf, MIN(n - i, sizeof(buf)));
if (dr == -1) return -1;
if (!dr) break;
dw = write(out, buf, dr);
if (dw == -1) return -1;
if (dw != dr) {
// POSIX requires atomic IO up to PIPE_BUF
// The minimum permissible PIPE_BUF is 512
__builtin_trap();
}
}
return rc;
return i;
}

View file

@ -17,10 +17,10 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/asan.internal.h"
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"

View file

@ -21,6 +21,7 @@
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
@ -41,12 +42,7 @@ int getitimer(int which, struct itimerval *curvalue) {
} else {
rc = sys_setitimer_nt(which, 0, curvalue);
}
if (curvalue) {
STRACE("getitimer(%d, [{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m", which,
curvalue->it_interval.tv_sec, curvalue->it_interval.tv_usec,
curvalue->it_value.tv_sec, curvalue->it_value.tv_usec, rc);
} else {
STRACE("getitimer(%d, 0) → %d% m", which, rc);
}
STRACE("getitimer(%s, [%s]) → %d% m", DescribeItimer(which),
DescribeItimerval(rc, curvalue), rc);
return rc;
}

View file

@ -38,13 +38,13 @@ static gettimeofday_f *__gettimeofday = __gettimeofday_init;
* Returns system wall time in microseconds, e.g.
*
* int64_t t;
* char p[30];
* char p[20];
* struct tm tm;
* struct timeval tv;
* gettimeofday(&tv, 0);
* t = tv.tv_sec;
* gmtime_r(&t, &tm);
* FormatHttpDateTime(p, &tm);
* iso8601(p, &tm);
* printf("%s\n", p);
*
* @param tv points to timeval that receives result if non-NULL

View file

@ -16,120 +16,49 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/nt2sysv.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/str/str.h"
#include "libc/calls/struct/timeval.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#ifdef __x86_64__
/**
* @fileoverview Heartbreaking polyfill for SIGALRM on NT.
*
* Threads are used to trigger the SIGALRM handler, which should
* hopefully be an unfancy function like this:
*
* void OnAlarm(int sig, struct siginfo *si, struct ucontext *uc) {
* g_alarmed = true;
* }
*
* This is needed because WIN32 provides no obvious solutions for
* interrupting i/o operations on the standard input handle.
*/
static bool __hastimer;
static bool __singleshot;
static long double __lastalrm;
static long double __interval;
static struct itimerval g_setitimer;
textwindows void _check_sigalrm(void) {
// TODO(jart): use a different timing source
// TODO(jart): synchronize across intervals?
long double now, elapsed;
if (!__hastimer) return;
now = nowl();
elapsed = now - __lastalrm;
if (elapsed > __interval) {
__sig_add(0, SIGALRM, SI_TIMER);
if (__singleshot) {
__hastimer = false;
} else {
__lastalrm = now;
}
struct timeval now;
if (timeval_iszero(g_setitimer.it_value)) return;
now = timeval_real();
if (timeval_cmp(now, g_setitimer.it_value) < 0) return;
if (timeval_iszero(g_setitimer.it_interval)) {
g_setitimer.it_value = timeval_zero;
} else {
do {
g_setitimer.it_value =
timeval_add(g_setitimer.it_value, g_setitimer.it_interval);
} while (timeval_cmp(now, g_setitimer.it_value) > 0);
}
__sig_add(0, SIGALRM, SI_TIMER);
}
textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue,
struct itimerval *out_opt_oldvalue) {
long double elapsed, untilnext;
if (which != ITIMER_REAL ||
(newvalue && (!(0 <= newvalue->it_value.tv_usec &&
newvalue->it_value.tv_usec < 1000000) ||
!(0 <= newvalue->it_interval.tv_usec &&
newvalue->it_interval.tv_usec < 1000000)))) {
textwindows int sys_setitimer_nt(int which, const struct itimerval *neu,
struct itimerval *old) {
if (which != ITIMER_REAL || (neu && (!timeval_isvalid(neu->it_value) ||
!timeval_isvalid(neu->it_interval)))) {
return einval();
}
if (out_opt_oldvalue) {
if (__hastimer) {
elapsed = nowl() - __lastalrm;
if (elapsed > __interval) {
untilnext = 0;
} else {
untilnext = __interval - elapsed;
}
out_opt_oldvalue->it_interval.tv_sec = __interval;
out_opt_oldvalue->it_interval.tv_usec = 1 / 1e6 * fmodl(__interval, 1);
out_opt_oldvalue->it_value.tv_sec = untilnext;
out_opt_oldvalue->it_value.tv_usec = 1 / 1e6 * fmodl(untilnext, 1);
} else {
out_opt_oldvalue->it_interval.tv_sec = 0;
out_opt_oldvalue->it_interval.tv_usec = 0;
out_opt_oldvalue->it_value.tv_sec = 0;
out_opt_oldvalue->it_value.tv_usec = 0;
}
if (old) {
old->it_interval = g_setitimer.it_interval;
old->it_value = timeval_subz(g_setitimer.it_value, timeval_real());
}
if (newvalue) {
if (newvalue->it_interval.tv_sec || newvalue->it_interval.tv_usec ||
newvalue->it_value.tv_sec || newvalue->it_value.tv_usec) {
__hastimer = true;
if (newvalue->it_interval.tv_sec || newvalue->it_interval.tv_usec) {
__singleshot = false;
__interval = newvalue->it_interval.tv_sec +
1 / 1e6 * newvalue->it_interval.tv_usec;
} else {
__singleshot = true;
__interval =
newvalue->it_value.tv_sec + 1 / 1e6 * newvalue->it_value.tv_usec;
}
__lastalrm = nowl();
} else {
__hastimer = false;
}
if (neu) {
g_setitimer.it_interval = neu->it_interval;
g_setitimer.it_value = timeval_iszero(neu->it_value)
? timeval_zero
: timeval_add(timeval_real(), neu->it_value);
}
return 0;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
@ -66,7 +67,6 @@
int setitimer(int which, const struct itimerval *newvalue,
struct itimerval *oldvalue) {
int rc;
if (IsAsan() &&
((newvalue && !__asan_is_valid(newvalue, sizeof(*newvalue))) ||
(oldvalue && !__asan_is_valid(oldvalue, sizeof(*oldvalue))))) {
@ -80,28 +80,7 @@ int setitimer(int which, const struct itimerval *newvalue,
} else {
rc = sys_setitimer_nt(which, newvalue, oldvalue);
}
#ifdef SYSDEBUG
if (newvalue && oldvalue) {
STRACE("setitimer(%d, "
"{{%'ld, %'ld}, {%'ld, %'ld}}, "
"[{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m",
which, newvalue->it_interval.tv_sec, newvalue->it_interval.tv_usec,
newvalue->it_value.tv_sec, newvalue->it_value.tv_usec,
oldvalue->it_interval.tv_sec, oldvalue->it_interval.tv_usec,
oldvalue->it_value.tv_sec, oldvalue->it_value.tv_usec, rc);
} else if (newvalue) {
STRACE("setitimer(%d, {{%'ld, %'ld}, {%'ld, %'ld}}, NULL) → %d% m", which,
newvalue->it_interval.tv_sec, newvalue->it_interval.tv_usec,
newvalue->it_value.tv_sec, newvalue->it_value.tv_usec, rc);
} else if (oldvalue) {
STRACE("setitimer(%d, NULL, [{{%'ld, %'ld}, {%'ld, %'ld}}]) → %d% m", which,
oldvalue->it_interval.tv_sec, oldvalue->it_interval.tv_usec,
oldvalue->it_value.tv_sec, oldvalue->it_value.tv_usec, rc);
} else {
STRACE("setitimer(%d, NULL, NULL) → %d% m", which, rc);
}
#endif
STRACE("setitimer(%s, %s, [%s]) → %d% m", DescribeItimer(which),
DescribeItimerval(0, newvalue), DescribeItimerval(rc, oldvalue), rc);
return rc;
}

View file

@ -9,8 +9,8 @@ int sys_getitimer(int, struct itimerval *) _Hide;
int sys_setitimer(int, const struct itimerval *, struct itimerval *) _Hide;
int sys_setitimer_nt(int, const struct itimerval *, struct itimerval *) _Hide;
const char *DescribeTimeval(char[45], int, const struct timeval *);
#define DescribeTimeval(rc, ts) DescribeTimeval(alloca(45), rc, ts)
const char *DescribeItimerval(char[90], int, const struct itimerval *);
#define DescribeItimerval(rc, ts) DescribeItimerval(alloca(90), rc, ts)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -14,14 +14,14 @@ int clock_nanosleep(int, int, const struct timespec *, struct timespec *);
int futimens(int, const struct timespec[2]);
int nanosleep(const struct timespec *, struct timespec *);
int utimensat(int, const char *, const struct timespec[2], int);
int timespec_getres(struct timespec *, int);
int timespec_get(struct timespec *, int);
#ifdef COSMO
/* cosmopolitan libc's non-posix timespec library
removed by default due to emacs codebase clash */
#define timespec_zero ((struct timespec){0})
#define timespec_max ((struct timespec){0x7fffffffffffffff, 999999999})
int timespec_get(struct timespec *, int);
int timespec_getres(struct timespec *, int);
int timespec_cmp(struct timespec, struct timespec) pureconst;
int64_t timespec_tomicros(struct timespec) pureconst;
int64_t timespec_tomillis(struct timespec) pureconst;
@ -35,7 +35,14 @@ struct timespec timespec_mono(void);
struct timespec timespec_sleep(struct timespec);
int timespec_sleep_until(struct timespec);
struct timespec timespec_sub(struct timespec, struct timespec) pureconst;
struct timespec timespec_subz(struct timespec, struct timespec) pureconst;
int sys_futex(int *, int, int, const struct timespec *, int *);
static inline bool timespec_iszero(struct timespec __ts) {
return !(__ts.tv_sec | __ts.tv_nsec);
}
static inline bool timespec_isvalid(struct timespec __ts) {
return __ts.tv_sec >= 0 && __ts.tv_nsec < 1000000000ull;
}
#endif /* COSMO */
COSMOPOLITAN_C_END_

View file

@ -19,13 +19,23 @@ int utimes(const char *, const struct timeval[2]);
#ifdef COSMO
/* cosmopolitan libc's non-posix timevals library
removed by default due to emacs codebase clash */
#define timeval_zero ((struct timeval){0})
#define timeval_max ((struct timeval){0x7fffffffffffffff, 999999})
int timeval_cmp(struct timeval, struct timeval) pureconst;
struct timeval timeval_real(void);
struct timeval timeval_frommicros(int64_t) pureconst;
struct timeval timeval_frommillis(int64_t) pureconst;
struct timeval timeval_add(struct timeval, struct timeval) pureconst;
struct timeval timeval_sub(struct timeval, struct timeval) pureconst;
struct timeval timeval_subz(struct timeval, struct timeval) pureconst;
struct timeval timespec_totimeval(struct timespec) pureconst;
struct timespec timeval_totimespec(struct timeval) pureconst;
static inline bool timeval_iszero(struct timeval __tv) {
return !(__tv.tv_sec | __tv.tv_usec);
}
static inline bool timeval_isvalid(struct timeval __tv) {
return __tv.tv_sec >= 0 && __tv.tv_usec < 1000000ull;
}
#endif /* COSMO */
COSMOPOLITAN_C_END_

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_INTERNAL_H_
#include "libc/calls/struct/timeval.h"
#include "libc/mem/alloca.h"
#include "libc/time/struct/timezone.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -15,6 +16,9 @@ axdx_t sys_gettimeofday_nt(struct timeval *, struct timezone *, void *) _Hide;
int sys_utimes_nt(const char *, const struct timeval[2]) _Hide;
axdx_t sys_gettimeofday_metal(struct timeval *, struct timezone *, void *);
const char *DescribeTimeval(char[45], int, const struct timeval *);
#define DescribeTimeval(rc, ts) DescribeTimeval(alloca(45), rc, ts)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_TIMEVAL_INTERNAL_H_ */

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,30 +16,17 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/pc.internal.h"
#include "libc/macros.internal.h"
#include "libc/calls/struct/timespec.h"
// fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding.
//
// @param 𝑥 is an 80-bit long double passed on stack in 16-bytes
// @param 𝑦 is the power, also pushed on stack, in reverse order
// @return remainder ∈ (-|𝑦|,|𝑦|) in %st
// @define 𝑥-truncl(𝑥/𝑦)*𝑦
// @see emod()
.ftrace1
fmodl: .ftrace2
push %rbp
mov %rsp,%rbp
fldt 32(%rbp)
fldt 16(%rbp)
1: fprem
fnstsw
test $FPU_C2>>8,%ah
jnz 1b
fstp %st(1)
pop %rbp
ret
1: int3
pop %rbp
ret
.endfn fmodl,globl
/**
* Subtracts two nanosecond timestamps.
*
* Unlike `timespec_sub()` this function will return zero if `x < y`.
*/
struct timespec timespec_subz(struct timespec x, struct timespec y) {
if (timespec_cmp(x, y) > 0) {
return timespec_sub(x, y);
} else {
return timespec_zero;
}
}

31
libc/calls/timeval_real.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/struct/timeval.h"
/**
* Returns current time w/ microsecond precision.
*
* @see timespec_real()
*/
struct timeval timeval_real(void) {
struct timeval tv;
_npassert(!gettimeofday(&tv, 0));
return tv;
}

30
libc/calls/timeval_subz.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timeval.h"
/**
* Subtracts two nanosecond timestamps.
*/
struct timeval timeval_subz(struct timeval x, struct timeval y) {
if (timeval_cmp(x, y) > 0) {
return timeval_sub(x, y);
} else {
return timeval_zero;
}
}

View file

@ -16,10 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/at.h"

View file

@ -21,6 +21,7 @@
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/directmap.internal.h"
#include "libc/intrin/kmalloc.h"
@ -437,10 +438,7 @@ static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
if (UNLIKELY(!((intptr_t)s & (FRAMESIZE - 1))) && kisdangerous(s)) {
return (struct AsanFault){kAsanUnmapped, s};
}
if ((w = ((uint64_t)(255 & s[0]) << 000 | (uint64_t)(255 & s[1]) << 010 |
(uint64_t)(255 & s[2]) << 020 | (uint64_t)(255 & s[3]) << 030 |
(uint64_t)(255 & s[4]) << 040 | (uint64_t)(255 & s[5]) << 050 |
(uint64_t)(255 & s[6]) << 060 | (uint64_t)(255 & s[7]) << 070))) {
if ((w = READ64LE(s))) {
s += __asan_bsf(w) >> 3;
return __asan_fault(s, kAsanHeapOverrun);
}

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/arch.h"
const char *(DescribeArchPrctlCode)(char buf[12], int x) {
if (x == ARCH_SET_FS) return "ARCH_SET_FS";

View file

@ -24,6 +24,7 @@ const char *DescribeFrame(char[32], int);
const char *DescribeFutexOp(char[64], int);
const char *DescribeHow(char[12], int);
const char *DescribeInOutInt64(char[23], ssize_t, int64_t *);
const char *DescribeItimer(char[12], int);
const char *DescribeMapFlags(char[64], int);
const char *DescribeMapping(char[8], int, int);
const char *DescribeNtConsoleInFlags(char[256], uint32_t);
@ -77,6 +78,7 @@ const char *DescribeWhichPrio(char[12], int);
#define DescribeFutexOp(x) DescribeFutexOp(alloca(64), x)
#define DescribeHow(x) DescribeHow(alloca(12), x)
#define DescribeInOutInt64(rc, x) DescribeInOutInt64(alloca(23), rc, x)
#define DescribeItimer(x) DescribeItimer(alloca(12), x)
#define DescribeMapFlags(x) DescribeMapFlags(alloca(64), x)
#define DescribeMapping(x, y) DescribeMapping(alloca(8), x, y)
#define DescribeNtConsoleInFlags(x) DescribeNtConsoleInFlags(alloca(256), x)

View file

@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/itoa.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/itimer.h"
const char *(DescribeItimer)(char buf[12], int which) {
if (which == ITIMER_REAL) return "ITIMER_REAL";
if (which == ITIMER_VIRTUAL) return "ITIMER_VIRTUAL";
if (which == ITIMER_PROF) return "ITIMER_PROF";
FormatInt32(buf, which);
return buf;
}

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,67 +16,26 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/conv.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
#include "libc/x/xasprintf.h"
#include "libc/calls/struct/itimerval.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
float b32;
double b64;
long double b80;
uint32_t u32;
uint64_t u64;
int128_t x;
#define N 90
void int2float(const char *s) {
x = strtoi128(s, NULL, 0);
if ((0 <= x && x <= UINT32_MAX) && !_startswith(s, "-") &&
(!_endswith(s, "l") && !_endswith(s, "L"))) {
u32 = x;
memcpy(&b32, &u32, 4);
s = _gc(xdtoa(b32));
if (!strchr(s, '.')) s = _gc(xasprintf("%s.", s));
s = _gc(xasprintf("%sf", s));
puts(s);
} else if ((0 <= x && x <= UINT64_MAX) && !_startswith(s, "-")) {
u64 = x;
memcpy(&b64, &u64, 8);
s = _gc(xdtoa(b64));
if (!strchr(s, '.')) s = _gc(xasprintf("%s.", s));
puts(s);
} else if ((INT32_MIN <= x && x <= 0) &&
(!_endswith(s, "l") && !_endswith(s, "L"))) {
u32 = ABS(x);
memcpy(&b32, &u32, 4);
b32 = -b32;
s = _gc(xdtoa(b32));
if (!strchr(s, '.')) s = _gc(xasprintf("%s.", s));
s = _gc(xasprintf("%sf", s));
puts(s);
} else if (INT64_MIN <= x && x <= 0) {
u64 = ABS(x);
memcpy(&b64, &u64, 8);
b64 = -b64;
s = _gc(xdtoa(b64));
if (!strchr(s, '.')) s = _gc(xasprintf("%s.", s));
puts(s);
const char *(DescribeItimerval)(char buf[N], int rc,
const struct itimerval *it) {
if (!it) return "NULL";
if (rc == -1) return "n/a";
if ((!IsAsan() && kisdangerous(it)) ||
(IsAsan() && !__asan_is_valid(it, sizeof(*it)))) {
ksnprintf(buf, N, "%p", it);
} else {
memcpy(&b80, &x, 16);
s = _gc(xdtoa(b80));
if (!strchr(s, '.')) s = _gc(xasprintf("%s.", s));
s = _gc(xasprintf("%sL", s));
puts(s);
ksnprintf(buf, N, "{%s, %s}", DescribeTimeval(0, &it->it_interval),
DescribeTimeval(0, &it->it_value));
}
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; ++i) {
int2float(argv[i]);
}
return 0;
return buf;
}

View file

@ -31,7 +31,6 @@ const char *(DescribeMapFlags)(char buf[64], int x) {
{MAP_FIXED, "FIXED"}, //
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
{MAP_CONCEAL, "CONCEAL"}, //
{MAP_HUGETLB, "HUGETLB"}, //
{MAP_LOCKED, "LOCKED"}, //
{MAP_NORESERVE, "NORESERVE"}, //
{MAP_NONBLOCK, "NONBLOCK"}, //

View file

@ -21,6 +21,8 @@
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sol.h"
#define N (PAGESIZE / 2 / sizeof(struct DescribeFlags))
@ -29,17 +31,42 @@
* Describes clock_gettime() clock argument.
*/
const char *(DescribeOpenFlags)(char buf[128], int x) {
char *s;
char *p;
int i, n;
const char *pipe;
struct DescribeFlags d[N];
if (x == -1) return "-1";
// TODO(jart): unify DescribeFlags and MagnumStr data structures
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR; ++n) {
if (n == N) notpossible;
p = buf;
switch (x & O_ACCMODE) {
case O_RDONLY:
p = stpcpy(p, "O_RDONLY");
x &= ~O_ACCMODE;
pipe = "|";
break;
case O_WRONLY:
p = stpcpy(p, "O_WRONLY");
x &= ~O_ACCMODE;
pipe = "|";
break;
case O_RDWR:
p = stpcpy(p, "O_RDWR");
x &= ~O_ACCMODE;
pipe = "|";
break;
default:
pipe = "";
break;
}
for (i = 0; i < n; ++i) {
d[i].flag = MAGNUM_NUMBER(kOpenFlags, i);
d[i].name = MAGNUM_STRING(kOpenFlags, i);
if (x) {
p = stpcpy(p, pipe);
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR; ++n) {
if (n == N) notpossible;
}
for (i = 0; i < n; ++i) {
d[i].flag = MAGNUM_NUMBER(kOpenFlags, i);
d[i].name = MAGNUM_STRING(kOpenFlags, i);
}
DescribeFlags(p, 128 - (p - buf), d, n, "O_", x);
}
return DescribeFlags(buf, 128, d, n, "O_", x);
return buf;
}

View file

@ -23,8 +23,8 @@
#include "libc/intrin/kprintf.h"
const char *(DescribeTimeval)(char buf[45], int rc, const struct timeval *tv) {
if (rc == -1) return "n/a";
if (!tv) return "NULL";
if (rc == -1) return "n/a";
if ((!IsAsan() && kisdangerous(tv)) ||
(IsAsan() && !__asan_is_valid(tv, sizeof(*tv)))) {
ksnprintf(buf, 45, "%p", tv);

View file

@ -46,11 +46,14 @@ feclearexcept:
// maintain exceptions in the sse mxcsr, clear x87 exceptions
mov %edi,%ecx
and $0x3f,%ecx
#ifndef NOX87
fnstsw %ax
test %eax,%ecx
jz 1f
fnclex
1: stmxcsr -8(%rsp)
1:
#endif
stmxcsr -8(%rsp)
and $0x3f,%eax
or %eax,-8(%rsp)
test %ecx,-8(%rsp)
@ -96,12 +99,16 @@ fetestexcept:
.ftrace2
#ifdef __x86_64__
and $0x3f,%edi
push %rax
push $0
stmxcsr (%rsp)
#ifdef NOX87
pop %rax
#else
pop %rsi
fnstsw %ax
or %esi,%eax
and %edi,%eax
#endif
ret
#elif defined(__aarch64__)
and w0,w0,#0x1f
@ -138,10 +145,12 @@ __fesetround:
push %rax
xor %eax,%eax
mov %edi,%ecx
#ifndef NOX87
fnstcw (%rsp)
andb $0xf3,1(%rsp)
or %ch,1(%rsp)
fldcw (%rsp)
#endif
stmxcsr (%rsp)
shl $3,%ch
andb $0x9f,1(%rsp)
@ -181,7 +190,9 @@ fegetenv:
.ftrace2
#ifdef __x86_64__
xor %eax,%eax
#ifndef NOX87
fnstenv (%rdi)
#endif
stmxcsr 28(%rdi)
ret
#elif defined(__aarch64__)
@ -200,14 +211,18 @@ fesetenv:
xor %eax,%eax
inc %rdi
jz 1f
#ifndef NOX87
fldenv -1(%rdi)
#endif
ldmxcsr 27(%rdi)
ret
1: push %rax
push %rax
pushq $0xffff
pushq $0x37f
#ifndef NOX87
fldenv (%rsp)
#endif
pushq $0x1f80
ldmxcsr (%rsp)
add $40,%rsp

View file

@ -35,5 +35,5 @@ double fmax(double x, double y) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(fmax, fmaxl);
__weak_reference(fmax, fmaxl);
#endif

View file

@ -69,6 +69,6 @@ double scalbn(double x, int n)
__strong_reference(scalbn, ldexp);
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(scalbn, ldexpl);
__strong_reference(scalbn, scalbnl);
__weak_reference(scalbn, ldexpl);
__weak_reference(scalbn, scalbnl);
#endif

View file

@ -1,10 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_MEM_IO_H_
#define COSMOPOLITAN_LIBC_MEM_IO_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
ssize_t _copyfd(int, int, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_MEM_IO_H_ */

View file

@ -45,6 +45,7 @@ cosmo: push %rbp
mov %eax,%r12d
#endif /* SYSDEBUG */
#ifndef NOX87
// Windows always initializes FPU to douuble precision.
// WSL breaks Linux ABI by initializing FPU to double precision.
// This code makes long double long again.
@ -70,6 +71,7 @@ cosmo: push %rbp
// drr
1: .short 0b00000000000000000001101111111
.previous
#endif
#ifdef __FAST_MATH__
push %rax

View file

@ -20,24 +20,9 @@ typedef unsigned long jmp_buf[26];
typedef long sigjmp_buf[12];
extern char **environ; /* CRT */
extern int __argc; /* CRT */
extern char **__argv; /* CRT */
extern char **__envp; /* CRT */
extern unsigned long *__auxv; /* CRT */
extern intptr_t __oldstack; /* CRT */
extern uint64_t __nosync; /* SYS */
extern int __strace; /* SYS */
extern int __ftrace; /* SYS */
extern char *program_invocation_name; /* RII */
extern char *program_invocation_short_name; /* RII */
extern uint64_t __syscount; /* RII */
extern uint64_t kStartTsc; /* RII */
extern char kTmpPath[]; /* RII */
extern const char kNtSystemDirectory[]; /* RII */
extern const char kNtWindowsDirectory[]; /* RII */
extern size_t __virtualmax;
extern bool __isworker;
extern char **environ;
extern char *program_invocation_name;
extern char *program_invocation_short_name;
void mcount(void);
int daemon(int, int);
@ -83,6 +68,21 @@ int sethostname(const char *, size_t);
int acct(const char *);
#ifdef COSMO
extern int __argc;
extern char **__argv;
extern char **__envp;
extern unsigned long *__auxv;
extern intptr_t __oldstack;
extern uint64_t __nosync;
extern int __strace;
extern int __ftrace;
extern uint64_t __syscount;
extern uint64_t kStartTsc;
extern char kTmpPath[];
extern const char kNtSystemDirectory[];
extern const char kNtWindowsDirectory[];
extern size_t __virtualmax;
extern bool __isworker;
/* utilities */
void _intsort(int *, size_t);
void _longsort(long *, size_t);

View file

@ -23,6 +23,7 @@
#include "libc/errno.h"
#include "libc/nexgen32e/msr.internal.h"
#include "libc/nt/thread.h"
#include "libc/sysv/consts/arch.h"
#include "libc/thread/tls.h"
#include "libc/thread/tls2.h"
@ -60,8 +61,10 @@ textstartup void __set_tls(struct CosmoTib *tib) {
: "c"(MSR_IA32_FS_BASE), "a"((uint32_t)val),
"d"((uint32_t)(val >> 32)));
}
#else
#elif defined(__aarch64__)
register long x28 asm("x28") = (long)tib;
asm volatile("" : "+r"(x28));
#else
#error "unsupported architecture"
#endif
}

View file

@ -231,14 +231,11 @@ syscon mmap MAP_LOCKED 0x00002000 0x00002000 0 0 0 0 0 0
syscon mmap MAP_NORESERVE 0x00004000 0x00004000 0x00000040 0x00000040 0 0 0x00000040 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
syscon mmap MAP_POPULATE 0x00008000 0x00008000 0 0 0x00040000 0 0 0 # MAP_PREFAULT_READ on FreeBSD; can avoid madvise(MADV_WILLNEED) on private file mapping
syscon mmap MAP_NONBLOCK 0x00010000 0x00010000 0 0 0 0 0 0
syscon mmap MAP_HUGETLB 0x00040000 0x00040000 0 0 0 0 0 0x80000000 # kNtSecLargePages
syscon mmap MAP_SYNC 0x00080000 0x00080000 0 0 0 0 0 0 # perform synchronous page faults for mapping (Linux 4.15+)
syscon mmap MAP_INHERIT -1 -1 -1 -1 -1 -1 0x00000080 -1 # make it inherit across execve()
syscon mmap MAP_HASSEMAPHORE 0 0 0x00000200 0x00000200 0x00000200 0 0x00000200 0 # does it matter on x86?
syscon mmap MAP_NOSYNC 0 0 0 0 0x00000800 0 0 0 # flush to physical media only when necessary rather than gratuitously; be sure to use write() rather than ftruncate() with this!
syscon mmap MAP_CONCEAL 0 0 0 0 0x00020000 0x00008000 0x00008000 0 # omit from core dumps; MAP_NOCORE on FreeBSD
syscon mmap MAP_HUGE_MASK 63 63 0 0 0 0 0 0
syscon mmap MAP_HUGE_SHIFT 26 26 0 0 0 0 0 0
syscon compat MAP_NOCORE 0 0 0 0 0x00020000 0x00008000 0x00008000 0 # use MAP_CONCEAL
syscon compat MAP_ANON 0x00000020 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt
syscon compat MAP_EXECUTABLE 0x00001000 0x00001000 0 0 0 0 0 0 # ignored

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_HUGETLB,0x00040000,0x00040000,0,0,0,0,0,0x80000000

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_HUGE_MASK,63,63,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_HUGE_SHIFT,26,26,0,0,0,0,0,0

9
libc/sysv/consts/arch.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_ARCH_H_
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_ARCH_H_
#define ARCH_SET_GS 0x1001
#define ARCH_SET_FS 0x1002
#define ARCH_GET_FS 0x1003
#define ARCH_GET_GS 0x1004
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_ARCH_H_ */

View file

@ -13,9 +13,6 @@ extern const int MAP_FILE;
extern const int MAP_FIXED;
extern const int MAP_FIXED_NOREPLACE;
extern const int MAP_HASSEMAPHORE;
extern const int MAP_HUGETLB;
extern const int MAP_HUGE_MASK;
extern const int MAP_HUGE_SHIFT;
extern const int MAP_INHERIT;
extern const int MAP_LOCKED;
extern const int MAP_NONBLOCK;

View file

@ -17,7 +17,6 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/mem/copyfd.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"
@ -34,7 +33,7 @@ void testlib_extract(const char *zip, const char *to, int mode) {
int fdin, fdout;
ASSERT_NE(-1, (fdin = open(zip, O_RDONLY)));
ASSERT_NE(-1, (fdout = creat(to, mode)));
ASSERT_NE(-1, _copyfd(fdin, fdout, -1));
ASSERT_NE(-1, copyfd(fdin, fdout, -1));
ASSERT_NE(-1, close(fdout));
ASSERT_NE(-1, close(fdin));
}

View file

@ -143,5 +143,5 @@ double acos(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(acos, acosl);
__weak_reference(acos, acosl);
#endif

View file

@ -55,5 +55,5 @@ double acosh(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(acosh, acoshl);
__weak_reference(acosh, acoshl);
#endif

View file

@ -149,5 +149,5 @@ double asin(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(asin, asinl);
__weak_reference(asin, asinl);
#endif

View file

@ -66,5 +66,5 @@ double asinh(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(asinh, asinhl);
__weak_reference(asinh, asinhl);
#endif

View file

@ -156,5 +156,5 @@ double atan(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(atan, atanl);
__weak_reference(atan, atanl);
#endif

View file

@ -155,5 +155,5 @@ atan2(double y, double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(atan2, atan2l);
__weak_reference(atan2, atan2l);
#endif

View file

@ -66,5 +66,5 @@ double atanh(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(atanh, atanhl);
__weak_reference(atanh, atanhl);
#endif

View file

@ -27,5 +27,5 @@ double cabs(double complex z) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(cabs, cabsl);
__weak_reference(cabs, cabsl);
#endif

View file

@ -45,5 +45,5 @@ double complex cacosh(double complex z)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(cacosh, cacoshl);
__weak_reference(cacosh, cacoshl);
#endif

View file

@ -24,5 +24,5 @@ double carg(double complex z) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(carg, cargl);
__weak_reference(carg, cargl);
#endif

View file

@ -52,5 +52,5 @@ double complex casin(double complex z)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(casin, casinl);
__weak_reference(casin, casinl);
#endif

View file

@ -147,5 +147,5 @@ double complex catan(double complex z)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(catan, catanl);
__weak_reference(catan, catanl);
#endif

View file

@ -32,5 +32,5 @@ double copysign(double x, double y) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(copysign, copysignl);
__weak_reference(copysign, copysignl);
#endif

View file

@ -122,5 +122,5 @@ double cos(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(cos, cosl);
__weak_reference(cos, cosl);
#endif

View file

@ -76,3 +76,7 @@ double cosh(double x)
t = __expo2(x, 1.0);
return t;
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__weak_reference(cosh, coshl);
#endif

View file

@ -38,6 +38,7 @@
*/
#include "libc/math.h"
#include "libc/tinymath/freebsd.internal.h"
#if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
asm(".ident\t\"\\n\\n\
FreeBSD libm (BSD-2 License)\\n\
@ -155,3 +156,5 @@ coshl(long double x)
/* |x| > o_threshold, cosh(x) overflow */
RETURNI(huge*huge);
}
#endif /* long double is long */

View file

@ -170,5 +170,5 @@ double exp(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(exp, expl);
__weak_reference(exp, expl);
#endif

View file

@ -57,5 +57,6 @@ double exp10(double x)
__strong_reference(exp10, pow10);
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(exp10, exp10l);
__weak_reference(exp10, exp10l);
__weak_reference(exp10, pow10l);
#endif

View file

@ -57,6 +57,6 @@ long double exp10l(long double x)
return powl(10.0, x);
}
__strong_reference(exp10l, pow10l);
__weak_reference(exp10l, pow10l);
#endif /* long double is long */

View file

@ -157,5 +157,5 @@ double exp2(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(exp2, exp2l);
__weak_reference(exp2, exp2l);
#endif

View file

@ -238,5 +238,5 @@ double expm1(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(expm1, expm1l);
__weak_reference(expm1, expm1l);
#endif

View file

@ -31,5 +31,5 @@ double fabs(double x) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(fabs, fabsl);
__weak_reference(fabs, fabsl);
#endif

View file

@ -27,5 +27,5 @@ double fdim(double x, double y) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(fdim, fdiml);
__weak_reference(fdim, fdiml);
#endif

View file

@ -96,5 +96,5 @@ double floor(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(floor, floorl);
__weak_reference(floor, floorl);
#endif

View file

@ -35,5 +35,5 @@ double fmin(double x, double y) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(fmin, fminl);
__weak_reference(fmin, fminl);
#endif

View file

@ -103,3 +103,7 @@ double fmod(double x, double y)
ux.i = uxi;
return ux.f;
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__weak_reference(fmod, fmodl);
#endif

View file

@ -27,6 +27,7 @@
*/
#include "libc/math.h"
#include "libc/tinymath/ldshape.internal.h"
#if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\
@ -34,10 +35,13 @@ Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/**
* Does (𝑥 rem 𝑦) w/ round()-style rounding.
* @return remainder (-|𝑦|,|𝑦|) in %xmm0
* @define 𝑥-trunc(𝑥/𝑦)*𝑦
*/
long double fmodl(long double x, long double y) {
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
return fmod(x, y);
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
union ldshape ux = {x}, uy = {y};
int ex = ux.i.se & 0x7fff;
int ey = uy.i.se & 0x7fff;
@ -135,3 +139,5 @@ long double fmodl(long double x, long double y) {
#error "architecture unsupported"
#endif
}
#endif /* long double is long */

View file

@ -58,5 +58,5 @@ double frexp(double x, int *e)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(frexp, frexpl);
__weak_reference(frexp, frexpl);
#endif

View file

@ -101,5 +101,5 @@ double hypot(double x, double y)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(hypot, hypotl);
__weak_reference(hypot, hypotl);
#endif

View file

@ -63,5 +63,5 @@ int ilogb(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(ilogb, ilogbl);
__weak_reference(ilogb, ilogbl);
#endif

View file

@ -1,88 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi
Musl Libc
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/limits.h"
#include "libc/math.h"
#include "libc/tinymath/internal.h"
#include "libc/tinymath/ldshape.internal.h"
#if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\
Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/**
* Returns log𝑥 exponent part of double.
*/
int ilogbl(long double x)
{
#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
// #pragma STDC FENV_ACCESS ON
union ldshape u = {x};
uint64_t m = u.i.m;
int e = u.i.se & 0x7fff;
if (!e) {
if (m == 0) {
FORCE_EVAL(0/0.0f);
return FP_ILOGB0;
}
/* subnormal x */
for (e = -0x3fff+1; m>>63 == 0; e--, m<<=1);
return e;
}
if (e == 0x7fff) {
FORCE_EVAL(0/0.0f);
return m<<1 ? FP_ILOGBNAN : INT_MAX;
}
return e - 0x3fff;
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// #pragma STDC FENV_ACCESS ON
union ldshape u = {x};
int e = u.i.se & 0x7fff;
if (!e) {
if (x == 0) {
FORCE_EVAL(0/0.0f);
return FP_ILOGB0;
}
/* subnormal x */
x *= 0x1p120;
return ilogbl(x) - 120;
}
if (e == 0x7fff) {
FORCE_EVAL(0/0.0f);
u.i.se = 0;
return u.f ? FP_ILOGBNAN : INT_MAX;
}
return e - 0x3fff;
#endif
}
#endif /* long double is long */

View file

@ -27,6 +27,7 @@
*/
#include "libc/math.h"
#include "libc/tinymath/kernel.internal.h"
#if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
asm(".ident\t\"\\n\\n\
FreeBSD libm (BSD-2 License)\\n\
@ -183,3 +184,5 @@ long double __tanl(long double x, long double y, int odd) {
#else
#error "architecture unsupported"
#endif
#endif /* long double is long */

View file

@ -142,5 +142,5 @@ double log(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(log, logl);
__weak_reference(log, logl);
#endif

View file

@ -143,5 +143,5 @@ double log10(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(log10, log10l);
__weak_reference(log10, log10l);
#endif

View file

@ -161,5 +161,5 @@ double log1p(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(log1p, log1pl);
__weak_reference(log1p, log1pl);
#endif

View file

@ -159,5 +159,5 @@ double log2(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(log2, log2l);
__weak_reference(log2, log2l);
#endif

View file

@ -23,3 +23,7 @@ double logb(double x) {
if (!x) return -1 / (x * x);
return ilogb(x);
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__weak_reference(logb, logbl);
#endif

View file

@ -45,8 +45,8 @@ __weak_reference(lrint, llrint);
#endif
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(lrint, lrintl);
__weak_reference(lrint, lrintl);
#if __SIZEOF_LONG__ == __SIZEOF_LONG_LONG__
__strong_reference(lrint, llrintl);
__weak_reference(lrint, llrintl);
#endif
#endif

View file

@ -26,5 +26,5 @@ long lround(double x) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(lround, lroundl);
__weak_reference(lround, lroundl);
#endif

View file

@ -33,6 +33,9 @@ Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
/**
* Returns fractional part of 𝑥.
*/
double modf(double x, double *iptr)
{
union {double f; uint64_t i;} u = {x};
@ -65,3 +68,7 @@ double modf(double x, double *iptr)
*iptr = u.f;
return x - u.f;
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__weak_reference(modf, modfl);
#endif

View file

@ -26,6 +26,7 @@
*/
#include "libc/math.h"
#if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
asm(".ident\t\"\\n\\n\
Musl libc (MIT License)\\n\
@ -33,20 +34,11 @@ Copyright 2005-2014 Rich Felker, et. al.\"");
asm(".include \"libc/disclaimer.inc\"");
// clang-format off
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
long double modfl(long double x, long double *iptr)
{
double d;
long double r;
r = modf(x, &d);
*iptr = d;
return r;
}
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
static const long double toint = 1/LDBL_EPSILON;
/**
* Returns fractional part of 𝑥.
*/
long double modfl(long double x, long double *iptr)
{
union {
@ -90,6 +82,4 @@ long double modfl(long double x, long double *iptr)
return -y;
}
#else
#error "architecture unsupported"
#endif
#endif /* long double is long */

View file

@ -42,5 +42,5 @@ double nearbyint(double x) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(nearbyint, nearbyintl);
__weak_reference(nearbyint, nearbyintl);
#endif

View file

@ -65,5 +65,5 @@ double nextafter(double x, double y)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(nextafter, nextafterl);
__weak_reference(nextafter, nextafterl);
#endif

View file

@ -381,5 +381,5 @@ double pow(double x, double y)
__weak_reference(pow, __pow_finite);
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(pow, powl);
__weak_reference(pow, powl);
#endif

View file

@ -28,5 +28,5 @@ double remainder(double x, double y) {
__strong_reference(remainder, drem);
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(remainder, remainderl);
__weak_reference(remainder, remainderl);
#endif

View file

@ -225,3 +225,7 @@ medium:
y[1] = ty[1];
return n;
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__weak_reference(__rem_pio2, __rem_pio2l);
#endif

View file

@ -29,6 +29,7 @@
#include "libc/math.h"
#include "libc/tinymath/kernel.internal.h"
#include "libc/tinymath/ldshape.internal.h"
#if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
asm(".ident\t\"\\n\\n\
FreeBSD libm (BSD-2 License)\\n\
@ -200,3 +201,5 @@ int __rem_pio2l(long double x, long double *y)
#else
#error "architecture unsupported"
#endif
#endif /* long double is long */

View file

@ -117,5 +117,5 @@ end:
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(remquo, remquol);
__weak_reference(remquo, remquol);
#endif

View file

@ -66,5 +66,5 @@ double rint(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(rint, rintl);
__weak_reference(rint, rintl);
#endif

View file

@ -92,5 +92,5 @@ double round(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(round, roundl);
__weak_reference(round, roundl);
#endif

View file

@ -26,5 +26,5 @@ double scalbln(double x, long n) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(scalbln, scalblnl);
__weak_reference(scalbln, scalblnl);
#endif

View file

@ -26,5 +26,5 @@ double significand(double x) {
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(significand, significandl);
__weak_reference(significand, significandl);
#endif

View file

@ -123,5 +123,5 @@ double sin(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(sin, sinl);
__weak_reference(sin, sinl);
#endif

View file

@ -114,5 +114,5 @@ void sincos(double x, double *sin, double *cos)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(sincos, sincosl);
__weak_reference(sincos, sincosl);
#endif

View file

@ -75,3 +75,7 @@ double sinh(double x)
t = __expo2(absx, 2*h);
return t;
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__weak_reference(sinh, sinhl);
#endif

View file

@ -39,6 +39,7 @@
#include "libc/intrin/likely.h"
#include "libc/math.h"
#include "libc/tinymath/freebsd.internal.h"
#if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024)
asm(".ident\t\"\\n\\n\
FreeBSD libm (BSD-2 License)\\n\
@ -154,3 +155,5 @@ sinhl(long double x)
/* |x| > o_threshold, sinh(x) overflow */
return x*shuge;
}
#endif /* long double is long */

View file

@ -222,5 +222,5 @@ double sqrt(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(sqrt, sqrtl);
__weak_reference(sqrt, sqrtl);
#endif

View file

@ -115,5 +115,5 @@ double tan(double x)
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(tan, tanl);
__weak_reference(tan, tanl);
#endif

View file

@ -76,3 +76,7 @@ double tanh(double x)
}
return sign ? -t : t;
}
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__weak_reference(tanh, tanhl);
#endif

Some files were not shown because too many files have changed in this diff Show more