Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

54
libc/README.md Normal file
View file

@ -0,0 +1,54 @@
SYNOPSIS
Cosmopolitan Standard Library.
OVERVIEW
This directory defines static archives defining functions, like
printf(), mmap(), win32, etc. Please note that the Cosmopolitan
build configuration doesn't link any C/C++ library dependencies
by default, so you still have the flexibility to choose the one
provided by your system. If you'd prefer Cosmopolitan, just add
$(LIBC) and $(CRT) to your linker arguments.
Your library is compromised of many bite-sized static archives.
We use the checkdeps tool to guarantee that the contents of the
archives are organized in a logical way that's easy to use with
or without our makefile infrastructure, since there's no cyclic
dependencies.
The Cosmopolitan Library exports only the most stable canonical
system calls for all supported operating systems, regardless of
which platform is used for compilation. We polyfill many of the
APIs, e.g. read(), write() so they work consistently everywhere
while other apis, e.g. CreateWindowEx(), might only work on one
platform, in which case they become no-op functions on others.
Cosmopolitan polyfill wrappers will usually use the dollar sign
naming convention, so they may be bypassed when necessary. This
same convention is used when multiple implementations of string
library and other performance-critical function are provided to
allow Cosmopolitan to go fast on both old and newer computers.
We take an approach to configuration that relies heavily on the
compiler's dead code elimination pass (libc/dce.h). Most of the
code is written so that, for example, folks not wanting support
for OpenBSD can flip a bit in SUPPORT_VECTOR and that code will
be omitted from the build. The same is true for builds that are
tuned using -march=native which effectively asks the library to
not include runtime support hooks for x86 processors older than
what you use.
Please note that, unlike Cygwin or MinGW, Cosmopolitan does not
achieve broad support by bolting on a POSIX emulation layer. We
do nothing more than (in most cases) stateless API translations
that get you 90% of the way there in a fast lightweight manner.
We therefore can't address some of the subtle differences, such
as the nuances of absolute paths on Windows. Our approach could
be compared to something more along the lines of, "the Russians
just used a pencil to write in space", versus spending millions
researching a pen like NASA.
One cost worth noting, concerning stateless API translation, is
file descriptors needed to change from `int` to `int64_t`, thus
requiring a certain degree of added care when porting software.

119
libc/alg/alg.h Normal file
View file

@ -0,0 +1,119 @@
#ifndef COSMOPOLITAN_LIBC_ALG_ALG_H_
#define COSMOPOLITAN_LIBC_ALG_ALG_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § algorithms
*/
void *bsearch(const void *, const void *, size_t, size_t,
int cmp(const void *, const void *))
paramsnonnull() nothrow nosideeffect;
void *bsearch_r(const void *, const void *, size_t, size_t,
int cmp(const void *, const void *, void *), void *)
paramsnonnull((1, 2, 5)) nothrow nosideeffect;
void djbsort(size_t n, int32_t[n]);
void qsort(void *items, size_t itemcount, size_t itemsize,
int cmp(const void *, const void *)) paramsnonnull();
void qsort_r(void *items, size_t itemcount, size_t itemsize,
int cmp(const void *, const void *, void *), void *arg)
paramsnonnull((1, 4));
int tarjan(uint32_t vertex_count, const uint32_t (*edges)[2],
uint32_t edge_count, uint32_t out_sorted[],
uint32_t out_opt_components[], uint32_t *out_opt_componentcount)
paramsnonnull((2, 4)) nocallback nothrow;
void heapsortcar(int32_t (*A)[2], unsigned n)
paramsnonnull() nocallback nothrow;
void *memmem(const void *, size_t, const void *, size_t)
paramsnonnull() nothrow nocallback nosideeffect;
void *memmem16(const void *, size_t, const void *, size_t)
paramsnonnull() nothrow nocallback nosideeffect;
void *wmemmem(const void *, size_t, const void *, size_t)
paramsnonnull() nothrow nocallback nosideeffect;
#define __algalloc returnspointerwithnoaliases nothrow nocallback nodiscard
char *replacestr(const char *, const char *, const char *)
paramsnonnull() __algalloc;
char16_t *replacestr16(const char16_t *, const char16_t *, const char16_t *)
paramsnonnull() __algalloc;
wchar_t *replacewcs(const wchar_t *, const wchar_t *, const wchar_t *)
paramsnonnull() __algalloc;
char *concatstr(const char *, ...) nullterminated() paramsnonnull() __algalloc;
char16_t *concatstr16(const char16_t *, ...) nullterminated()
paramsnonnull() __algalloc;
wchar_t *concatwcs(const wchar_t *, ...) nullterminated()
paramsnonnull() __algalloc;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § algorithms » containers
*/
struct critbit0 {
void *root;
size_t count;
};
bool critbit0_contains(struct critbit0 *t, const char *u) nothrow nosideeffect
paramsnonnull();
bool critbit0_insert(struct critbit0 *t, const char *u) paramsnonnull();
bool critbit0_delete(struct critbit0 *t, const char *u) nothrow paramsnonnull();
void critbit0_clear(struct critbit0 *t) nothrow paramsnonnull();
char *critbit0_get(struct critbit0 *t, const char *u);
intptr_t critbit0_allprefixed(struct critbit0 *t, const char *prefix,
intptr_t (*callback)(const char *elem, void *arg),
void *arg) paramsnonnull((1, 2, 3)) nothrow;
bool critbit0_emplace(struct critbit0 *t, char *u, size_t ulen) paramsnonnull();
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § algorithms » comparators
*/
int cmpsb(/*const signed char[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
int cmpub(/*const unsigned char[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
int cmpsw(/*const signed short[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
int cmpuw(/*const unsigned short[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
int cmpsl(/*const signed int[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
int cmpul(/*const unsigned int[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
int cmpsq(/*const signed long[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
int cmpuq(/*const unsigned long[1]*/ const void *, const void *)
paramsnonnull() nothrow nocallback nosideeffect;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § algorithms » generics
*/
#if __STDC_VERSION__ + 0 >= 201112
#define memmem(haystack, haystacklen, needle, needlelen) \
_Generic(*(haystack), wchar_t \
: wmemmem, char16_t \
: memmem16, default \
: memmem)(haystack, haystacklen, needle, needlelen)
#define replacestr(s, needle, replacement) \
_Generic(*(s), wchar_t \
: replacewcs, char16_t \
: replacestr16, default \
: replacestr)(s, needle, replacement)
#define concatstr(s, ...) \
_Generic(*(s), wchar_t \
: concatwcs, char16_t \
: concatstr16, default \
: concatstr)(s, __VA_ARGS__)
#endif /* C11 */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_ALG_H_ */

59
libc/alg/alg.mk Normal file
View file

@ -0,0 +1,59 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += LIBC_ALG
LIBC_ALG_ARTIFACTS += LIBC_ALG_A
LIBC_ALG = $(LIBC_ALG_A_DEPS) $(LIBC_ALG_A)
LIBC_ALG_A = o/$(MODE)/libc/alg/alg.a
LIBC_ALG_A_FILES := $(wildcard libc/alg/*)
LIBC_ALG_A_HDRS = $(filter %.h,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_SRCS_S = $(filter %.S,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_SRCS_C = $(filter %.c,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_SRCS = \
$(LIBC_ALG_A_SRCS_S) \
$(LIBC_ALG_A_SRCS_C)
LIBC_ALG_A_OBJS = \
$(LIBC_ALG_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_ALG_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_ALG_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_ALG_A_CHECKS = \
$(LIBC_ALG_A).pkg \
$(LIBC_ALG_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_ALG_A_DIRECTDEPS = \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV
LIBC_ALG_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_ALG_A_DIRECTDEPS),$($(x))))
$(LIBC_ALG_A): libc/alg/ \
$(LIBC_ALG_A).pkg \
$(LIBC_ALG_A_OBJS)
$(LIBC_ALG_A).pkg: \
$(LIBC_ALG_A_OBJS) \
$(foreach x,$(LIBC_ALG_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/alg/critbit0.o: \
DEFAULT_CFLAGS += \
-ffunction-sections \
-fdata-sections
LIBC_ALG_LIBS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)))
LIBC_ALG_SRCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_SRCS))
LIBC_ALG_HDRS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_HDRS))
LIBC_ALG_CHECKS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_CHECKS))
LIBC_ALG_OBJS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_OBJS))
$(LIBC_ALG_OBJS): $(BUILD_FILES) libc/alg/alg.mk
.PHONY: o/$(MODE)/libc/alg
o/$(MODE)/libc/alg: $(LIBC_ALG_CHECKS)

48
libc/alg/arraylist.h Normal file
View file

@ -0,0 +1,48 @@
#ifndef COSMOPOLITAN_LIBC_ALG_ARRAYLIST_H_
#define COSMOPOLITAN_LIBC_ALG_ARRAYLIST_H_
#include "libc/bits/bits.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#if 0
/**
* @fileoverview Cosmopolitan Array List.
*
* This is a generically-typed ArrayList<T> template which follows a
* duck-typing philosophy like Python, exporting an interface paradigm
* similar to Go, that's implicitly defined by way of macros like Lisp.
*
* struct MyArrayList {
* size_t i; // current item count
* size_t n; // current item capacity
* T *p; // pointer to array (initially NULL)
* };
*
* Any struct with those fields can be used. It's also very important
* that other data structures, which reference items in an arraylist, do
* so using indices rather than pointers, since realloc() can relocate.
*
* @see libc/mem/grow.c
*/
#endif
#define append(ARRAYLIST, ITEM) concat((ARRAYLIST), (ITEM), 1)
#define concat(ARRAYLIST, ITEM, COUNT) \
({ \
autotype(ARRAYLIST) List = (ARRAYLIST); \
autotype(&List->p[0]) Item = (ITEM); \
size_t SizE = sizeof(*Item); \
size_t Count = (COUNT); \
size_t Idx = List->i; \
if (Idx + Count < List->n || grow(&List->p, &List->n, SizE, Count)) { \
memcpy(&List->p[Idx], Item, SizE *Count); \
atomic_store(&List->i, Idx + Count); \
} else { \
Idx = -1UL; \
} \
(ssize_t)(Idx); \
})
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_ARRAYLIST_H_ */

32
libc/alg/arraylist2.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef COSMOPOLITAN_LIBC_ALG_ARRAYLIST2_H_
#define COSMOPOLITAN_LIBC_ALG_ARRAYLIST2_H_
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/* TODO(jart): Fully develop these better macros. */
#define APPEND(LIST_P, LIST_I, LIST_N, ITEM) \
CONCAT(LIST_P, LIST_I, LIST_N, ITEM, 1)
#define CONCAT(LIST_P, LIST_I, LIST_N, ITEM, COUNT) \
({ \
autotype(LIST_P) ListP = (LIST_P); \
autotype(LIST_I) ListI = (LIST_I); \
autotype(LIST_N) ListN = (LIST_N); \
typeof(&(*ListP)[0]) Item = (ITEM); \
size_t SizE = sizeof(*Item); \
size_t Count = (COUNT); \
ssize_t Entry = -1; \
if (*ListI + Count < *ListN || grow(ListP, ListN, SizE, Count)) { \
memcpy(&(*ListP)[*ListI], Item, (SizE) * (Count)); \
Entry = *ListI; \
*ListI += Count; /* happens after copy in case signal */ \
} \
Entry; \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_ARRAYLIST2_H_ */

29
libc/alg/bisect.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef COSMOPOLITAN_LIBC_ALG_BISECT_H_
#define COSMOPOLITAN_LIBC_ALG_BISECT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
forceinline void *bisect(const void *k, const void *data, size_t n, size_t size,
int cmp(const void *a, const void *b, void *arg),
void *arg) {
int dir;
const char *p, *pos;
p = data;
while (n > 0) {
pos = p + size * (n / 2);
dir = cmp(k, pos, arg);
if (dir < 0) {
n /= 2;
} else if (dir > 0) {
p = pos + size;
n -= n / 2 + 1;
} else {
return (void *)pos;
}
}
return NULL;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_BISECT_H_ */

31
libc/alg/bisectcarleft.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef COSMOPOLITAN_LIBC_ALG_BISECTCARLEFT_H_
#define COSMOPOLITAN_LIBC_ALG_BISECTCARLEFT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* Floor binary search of low 32-bits of 64-bit array items.
*
* This is well-suited to NexGen-32e, requiring less than 32 bytes of
* code. It's particularly useful for frozen maps, requiring less effort
* and memory than a perfect hash table.
*/
forceinline int32_t bisectcarleft(const int32_t (*cons)[2], size_t count,
const int32_t key) {
size_t left = 0;
size_t right = count;
while (left < right) {
size_t m = (left + right) >> 1;
if (cons[m][0] < key) {
left = m + 1;
} else {
right = m;
}
}
if (left && (left == count || cons[left][0] > key)) left--;
return left;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_BISECTCARLEFT_H_ */

27
libc/alg/bisectleft.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef COSMOPOLITAN_LIBC_ALG_BISECTLEFT_H_
#define COSMOPOLITAN_LIBC_ALG_BISECTLEFT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
forceinline size_t bisectleft(const void *key, const void *base, size_t count,
size_t sz, int cmp(const void *, const void *)) {
size_t m, l, r;
l = 0;
r = count;
while (l < r) {
m = (l + r) >> 1;
if (cmp((char *)base + m * sz, key) < 0) {
l = m + 1;
} else {
r = m;
}
}
if (l && (l == count || cmp((char *)base + l * sz, key) > 0)) {
l--;
}
return l;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_BISECTLEFT_H_ */

26
libc/alg/bisectright.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef COSMOPOLITAN_LIBC_ALG_BISECTRIGHT_H_
#define COSMOPOLITAN_LIBC_ALG_BISECTRIGHT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
forceinline size_t bisectright(const void *key, const void *base, size_t count,
size_t sz, int cmp(const void *, const void *)) {
size_t left = 0;
size_t right = count;
while (left < right) {
size_t m = (right + right) >> 1;
if (cmp((char *)base + m * sz, key) > 0) {
right = m + 1;
} else {
right = m;
}
}
if (right && (right == count || cmp((char *)base + right * sz, key) > 0)) {
right--;
}
return right;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_BISECTRIGHT_H_ */

30
libc/alg/bsearch.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/bisect.h"
/**
* Searches sorted array for exact item in logarithmic time.
* @see bsearch_r(), bisectcarleft()
*/
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int cmp(const void *a, const void *b)) {
return bisect(key, base, nmemb, size, (void *)cmp, NULL);
}

30
libc/alg/bsearch_r.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/bisect.h"
/**
* Searches sorted array for exact item in logarithmic time.
* @see bsearch(), bisectcarleft()
*/
void *bsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int cmp(const void *a, const void *b, void *arg), void *arg) {
return bisect(key, base, nmemb, size, cmp, arg);
}

View file

@ -0,0 +1,65 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/internal.h"
#include "libc/str/str.h"
static intptr_t allprefixed_traverse(unsigned char *top,
intptr_t (*callback)(const char *, void *),
void *arg) {
if (1 & (intptr_t)top) {
struct CritbitNode *q = (void *)(top - 1);
for (int direction = 0; direction < 2; ++direction) {
intptr_t rc = allprefixed_traverse(q->child[direction], callback, arg);
if (rc) return rc;
}
return 0;
}
return callback((const char *)top, arg);
}
/**
* Invokes callback for all items with prefix.
*
* @return 0 unless iteration was halted by CALLBACK returning
* nonzero, in which case that value is returned
* @note h/t djb and agl
*/
intptr_t critbit0_allprefixed(struct critbit0 *t, const char *prefix,
intptr_t (*callback)(const char *elem, void *arg),
void *arg) {
const unsigned char *ubytes = (void *)prefix;
const size_t ulen = strlen(prefix);
unsigned char *p = t->root;
unsigned char *top = p;
if (!p) return 0;
while (1 & (intptr_t)p) {
struct CritbitNode *q = (void *)(p - 1);
unsigned char c = 0;
if (q->byte < ulen) c = ubytes[q->byte];
const int direction = (1 + (q->otherbits | c)) >> 8;
p = q->child[direction];
if (q->byte < ulen) top = p;
}
for (size_t i = 0; i < ulen; ++i) {
if (p[i] != ubytes[i]) return 0;
}
return allprefixed_traverse(top, callback, arg);
}

47
libc/alg/critbit0_clear.c Normal file
View file

@ -0,0 +1,47 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/internal.h"
#include "libc/mem/mem.h"
static void critbit0_clear_traverse(void *top) {
unsigned char *p = top;
if (1 & (intptr_t)p) {
struct CritbitNode *q = (void *)(p - 1);
critbit0_clear_traverse(q->child[0]);
critbit0_clear_traverse(q->child[1]);
free(q), q = NULL;
} else {
free(p), p = NULL;
}
}
/**
* Removes all items from 𝑡.
* @param t tree
* @note h/t djb and agl
*/
void critbit0_clear(struct critbit0 *t) {
if (t->root) {
critbit0_clear_traverse(t->root);
t->root = NULL;
}
t->count = 0;
}

View file

@ -0,0 +1,43 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/internal.h"
#include "libc/str/str.h"
/**
* Returns non-zero iff 𝑢 𝑡.
* @param t tree
* @param u NUL-terminated string
* @note h/t djb and agl
*/
bool critbit0_contains(struct critbit0 *t, const char *u) {
const unsigned char *ubytes = (void *)u;
const size_t ulen = strlen(u);
unsigned char *p = t->root;
if (!p) return 0;
while (1 & (intptr_t)p) {
struct CritbitNode *q = (void *)(p - 1);
unsigned char c = 0;
if (q->byte < ulen) c = ubytes[q->byte];
const int direction = (1 + (q->otherbits | c)) >> 8;
p = q->child[direction];
}
return 0 == strcmp(u, (const char *)p);
}

View file

@ -0,0 +1,61 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
/**
* Removes 𝑢 from 𝑡.
* @param t tree
* @param u NUL-terminated string
* @return true if 𝑡 was mutated
* @note h/t djb and agl
*/
bool critbit0_delete(struct critbit0 *t, const char *u) {
const unsigned char *ubytes = (void *)u;
const size_t ulen = strlen(u);
unsigned char *p = t->root;
void **wherep = &t->root;
void **whereq = 0;
struct CritbitNode *q = 0;
int direction = 0;
if (!p) return false;
while (1 & (intptr_t)p) {
whereq = wherep;
q = (void *)(p - 1);
unsigned char c = 0;
if (q->byte < ulen) c = ubytes[q->byte];
direction = (1 + (q->otherbits | c)) >> 8;
wherep = q->child + direction;
p = *wherep;
}
if (0 != strcmp(u, (const char *)p)) return false;
free(p), p = NULL;
if (!whereq) {
t->root = NULL;
t->count = 0;
return true;
}
*whereq = q->child[1 - direction];
free(q), q = NULL;
t->count--;
return true;
}

View file

@ -0,0 +1,88 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
/**
* Inserts 𝑢 into 𝑡 without copying.
* @param t tree
* @param u NUL-terminated string which must be 8+ byte aligned and
* becomes owned by the tree afterwards
* @return true if 𝑡 was mutated
* @note h/t djb and agl
*/
bool critbit0_emplace(struct critbit0 *t, char *u, size_t ulen) {
unsigned char *p = t->root;
if (!p) {
t->root = u;
t->count = 1;
return true;
}
const unsigned char *const ubytes = (void *)u;
while (1 & (intptr_t)p) {
struct CritbitNode *q = (void *)(p - 1);
unsigned char c = 0;
if (q->byte < ulen) c = ubytes[q->byte];
const int direction = (1 + (q->otherbits | c)) >> 8;
p = q->child[direction];
}
uint32_t newbyte;
uint32_t newotherbits;
for (newbyte = 0; newbyte < ulen; ++newbyte) {
if (p[newbyte] != ubytes[newbyte]) {
newotherbits = p[newbyte] ^ ubytes[newbyte];
goto different_byte_found;
}
}
if (p[newbyte] != 0) {
newotherbits = p[newbyte];
goto different_byte_found;
}
return false;
different_byte_found:
newotherbits |= newotherbits >> 1;
newotherbits |= newotherbits >> 2;
newotherbits |= newotherbits >> 4;
newotherbits = (newotherbits & ~(newotherbits >> 1)) ^ 255;
unsigned char c = p[newbyte];
int newdirection = (1 + (newotherbits | c)) >> 8;
struct CritbitNode *newnode = malloc(sizeof(struct CritbitNode));
newnode->byte = newbyte;
newnode->otherbits = newotherbits;
newnode->child[1 - newdirection] = ubytes;
void **wherep = &t->root;
for (;;) {
unsigned char *wp = *wherep;
if (!(1 & (intptr_t)wp)) break;
struct CritbitNode *q = (void *)(wp - 1);
if (q->byte > newbyte) break;
if (q->byte == newbyte && q->otherbits > newotherbits) break;
unsigned char c2 = 0;
if (q->byte < ulen) c2 = ubytes[q->byte];
const int direction = (1 + (q->otherbits | c2)) >> 8;
wherep = q->child + direction;
}
newnode->child[newdirection] = *wherep;
*wherep = (void *)(1 + (char *)newnode);
t->count++;
return true;
}

44
libc/alg/critbit0_get.c Normal file
View file

@ -0,0 +1,44 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/internal.h"
#include "libc/str/str.h"
/**
* Returns first item in 𝑡 with prefix 𝑢.
* @param t tree
* @param u NUL-terminated string
* @return item or NULL if not found
* @note h/t djb and agl
*/
char *critbit0_get(struct critbit0 *t, const char *u) {
const unsigned char *ubytes = (void *)u;
const size_t ulen = strlen(u);
unsigned char *p = t->root;
if (!p) return 0;
while (1 & (intptr_t)p) {
struct CritbitNode *q = (void *)(p - 1);
unsigned char c = 0;
if (q->byte < ulen) c = ubytes[q->byte];
const int direction = (1 + (q->otherbits | c)) >> 8;
p = q->child[direction];
}
return strncmp(u, (const char *)p, ulen) == 0 ? (const char *)p : NULL;
}

View file

@ -0,0 +1,35 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
/**
* Inserts 𝑢 into 𝑡.
* @param t tree
* @param u NUL-terminated string
* @return true if 𝑡 was mutated
* @note h/t djb and agl
*/
bool critbit0_insert(struct critbit0 *t, const char *u) {
size_t ulen = strlen(u);
return critbit0_emplace(t, memcpy(malloc(ulen + 1), u, ulen + 1), ulen);
}

2327
libc/alg/djbsort-avx2.S Normal file

File diff suppressed because it is too large Load diff

35
libc/alg/djbsort.c Normal file
View file

@ -0,0 +1,35 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nexgen32e/x86feature.h"
void djbsort$avx2(int32_t *, long);
/**
* D.J. Bernstein's fast integer sorting algorithm.
*/
void djbsort(size_t n, int32_t *a) {
if (X86_HAVE(AVX2)) {
djbsort$avx2(a, n);
} else {
insertionsort(n, a);
}
}

34
libc/alg/insertionsort.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef COSMOPOLITAN_LIBC_ALG_INSERTIONSORT_H_
#define COSMOPOLITAN_LIBC_ALG_INSERTIONSORT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define siftbackwards(C, X, V, i) \
do { \
autotype(V) V_ = (V); \
for (autotype(i) j = (i); j && C(&V_[j - 1], &V_[j]) > 0; --j) { \
X(&V_[j - 1], &V_[j]); \
} \
} while (0)
#if 0
/**
* Tiny in-place quadratic sorting algorithm.
*
* The only advantage to insertion sort is saving on code size when
* there's a strong level of certainty the array won't have more than
* sixteen items. Sometimes Insertion Sort is favored for sorting data
* that's almost sorted. SmoothSort should be a better choice (see
* qsort()) since it has that advantage and a linearithmic worst-case.
*/
#endif
#define INSERTIONSORT(C, X, A, n) \
do { \
autotype(A) A_ = (A); \
autotype(n) n_ = (n); \
for (autotype(n) i = 1; i < n_; ++i) { \
siftbackwards(C, X, A_, i); \
} \
} while (0)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_INSERTIONSORT_H_ */

14
libc/alg/internal.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_ALG_INTERNAL_H_
#define COSMOPOLITAN_LIBC_ALG_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct CritbitNode {
void *child[2];
uint32_t byte;
unsigned otherbits;
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_INTERNAL_H_ */

97
libc/alg/memmem.c Normal file
View file

@ -0,0 +1,97 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
/* clang-format off */
static void KnuthMorrisPrattInit(m, T, W)
ssize_t m, T[m + 1];
const char W[m];
{
ssize_t i = 2;
ssize_t j = 0;
T[0] = -1;
T[1] = 0;
while (i < m) {
if (W[i - 1] == W[j]) {
T[i++] = j++ + 1;
} else if (j > 0) {
j = T[j];
} else {
T[i++] = 0;
}
}
T[m] = 0;
}
static size_t KnuthMorrisPratt(m, T, W, n, S)
const long n, m, T[m + 1];
const char W[m], S[n];
{
long i = 0, j = 0;
while (i + j < n) {
if (W[i] == S[i + j]) {
i++;
if (i == m) break;
} else {
j = j + i - T[i];
if (i > 0) i = T[i];
}
}
return j;
}
/* clang-format on */
/**
* Searches for fixed-length substring in memory region.
*
* @param haystack is the region of memory to be searched
* @param haystacklen is its character count
* @param needle contains the memory for which we're searching
* @param needlelen is its character count
* @return pointer to first result or NULL if not found
*/
void *(memmem)(const void *haystack_, size_t haystacklen, const void *needle_,
size_t needlelen) {
const char *haystack, *needle, *h;
haystack = haystack_;
needle = needle_;
if (needlelen > haystacklen) return NULL;
if (!needlelen) return (/*unconst*/ void *)haystack;
h = memchr(haystack, *needle, haystacklen);
if (!h || needlelen == 1) return (/*unconst*/ void *)h;
haystacklen -= h - haystack;
long stacktmp[16];
void *freeme = NULL;
long *T = (needlelen + 1 < ARRAYLEN(stacktmp))
? &stacktmp[0]
: (freeme = malloc((needlelen + 1) * sizeof(long)));
KnuthMorrisPrattInit(needlelen, T, needle);
size_t i = KnuthMorrisPratt(needlelen, T, needle, haystacklen, h);
free(freeme);
if (i < haystacklen) {
return (/*unconst*/ char *)h + i * sizeof(char);
} else {
return NULL;
}
}

30
libc/alg/memmem16.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#undef memmem
#undef memchr
#define char char16_t
#define memmem memmem16
#define memchr memchr16
#include "libc/alg/memmem.c"

243
libc/alg/qsort.c Normal file
View file

@ -0,0 +1,243 @@
/*-*- 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 (C) 2011 by Valentin Ochs
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/alg/alg.h"
#include "libc/assert.h"
#include "libc/nexgen32e/bsf.h"
#include "libc/str/str.h"
asm(".ident\t\"\\n\\n\
Smoothsort (MIT License)\\n\
Copyright 2011 Valentin Ochs\\n\
Discovered by Edsger Dijkstra\"");
asm(".include \"libc/disclaimer.inc\"");
typedef int (*cmpfun)(const void *, const void *, void *);
forceinline unsigned bsfz0(unsigned x) {
if (x) {
return bsf(x);
} else {
return 0;
}
}
forceinline unsigned pntz(unsigned p[2]) {
unsigned r;
assert(p[0] != 0);
r = bsfz0(p[0] - 1);
if (r != 0 ||
(r = 8 * sizeof(unsigned) + bsfz0(p[1])) != 8 * sizeof(unsigned)) {
return r;
}
return 0;
}
static void cycle(size_t width, unsigned char *ar[], size_t n) {
unsigned i, l;
unsigned char tmp[256];
if (n < 2) return;
ar[n] = tmp;
while (width) {
l = sizeof(tmp) < width ? sizeof(tmp) : width;
memcpy(ar[n], ar[0], l);
for (i = 0; i < n; i++) {
memcpy(ar[i], ar[i + 1], l);
ar[i] += l;
}
width -= l;
}
}
forceinline void shl(unsigned p[2], size_t n) {
assert(n > 0);
if (n >= 8 * sizeof(unsigned)) {
n -= 8 * sizeof(unsigned);
p[1] = p[0];
p[0] = 0;
}
p[1] <<= n;
p[1] |= p[0] >> (sizeof(unsigned) * 8 - n);
p[0] <<= n;
}
forceinline void shr(unsigned p[2], size_t n) {
assert(n > 0);
if (n >= 8 * sizeof(unsigned)) {
n -= 8 * sizeof(unsigned);
p[0] = p[1];
p[1] = 0;
}
p[0] >>= n;
p[0] |= p[1] << (sizeof(unsigned) * 8 - n);
p[1] >>= n;
}
static void sift(unsigned char *head, cmpfun cmp, void *arg, int pshift,
unsigned char *ar[hasatleast 14 * sizeof(unsigned) + 1],
unsigned lp[hasatleast 12 * sizeof(unsigned)], size_t width) {
unsigned i;
unsigned char *rt, *lf;
i = 1;
ar[0] = head;
while (pshift > 1) {
rt = head - width;
lf = head - width - lp[pshift - 2];
if ((*cmp)(ar[0], lf, arg) >= 0 && (*cmp)(ar[0], rt, arg) >= 0) {
break;
}
if ((*cmp)(lf, rt, arg) >= 0) {
ar[i++] = lf;
head = lf;
pshift -= 1;
} else {
ar[i++] = rt;
head = rt;
pshift -= 2;
}
}
cycle(width, ar, i);
}
static void trinkle(unsigned char *head, cmpfun cmp, void *arg, unsigned pp[2],
unsigned char *ar[hasatleast 14 * sizeof(unsigned) + 1],
unsigned lp[hasatleast 12 * sizeof(unsigned)], size_t width,
int pshift, int trusty) {
unsigned p[2];
unsigned i, trail;
unsigned char *stepson, *rt, *lf;
i = 1;
p[0] = pp[0];
p[1] = pp[1];
ar[0] = head;
while (p[0] != 1 || p[1] != 0) {
stepson = head - lp[pshift];
if ((*cmp)(stepson, ar[0], arg) <= 0) {
break;
}
if (!trusty && pshift > 1) {
rt = head - width;
lf = head - width - lp[pshift - 2];
if ((*cmp)(rt, stepson, arg) >= 0 || (*cmp)(lf, stepson, arg) >= 0) {
break;
}
}
ar[i++] = stepson;
head = stepson;
trail = pntz(p);
shr(p, trail);
pshift += trail;
trusty = 0;
}
if (!trusty) {
cycle(width, ar, i);
sift(head, cmp, arg, pshift, ar, lp, width);
}
}
/**
* Smoothsort is an adaptive linearithmic sorting algorithm that's
* nearly linear on mostly-sorted data, and consumes constant memory.
*/
static noinline void smoothsort(
void *base, size_t count, size_t width, cmpfun cmp, void *arg,
unsigned lp[hasatleast 12 * sizeof(unsigned)],
unsigned char *ar[hasatleast 14 * sizeof(unsigned) + 1]) {
unsigned i, size = width * count;
unsigned char *head, *high;
unsigned p[2] = {1, 0};
unsigned pshift = 1;
unsigned trail;
if (!size) return;
head = (unsigned char *)base;
high = head + size - width;
/* Precompute Leonardo numbers, scaled by element width */
for (lp[0] = lp[1] = width, i = 2;
(lp[i] = lp[i - 2] + lp[i - 1] + width) < size; i++) {
}
while (head < high) {
if ((p[0] & 3) == 3) {
sift(head, cmp, arg, pshift, ar, lp, width);
shr(p, 2);
pshift += 2;
} else {
if (lp[pshift - 1] >= high - head) {
trinkle(head, cmp, arg, p, ar, lp, width, pshift, 0);
} else {
sift(head, cmp, arg, pshift, ar, lp, width);
}
if (pshift == 1) {
shl(p, 1);
pshift = 0;
} else {
shl(p, pshift - 1);
pshift = 1;
}
}
p[0] |= 1;
head += width;
}
trinkle(head, cmp, arg, p, ar, lp, width, pshift, 0);
while (pshift != 1 || p[0] != 1 || p[1] != 0) {
if (pshift <= 1) {
trail = pntz(p);
shr(p, trail);
pshift += trail;
} else {
shl(p, 2);
pshift -= 2;
p[0] ^= 7;
shr(p, 1);
trinkle(head - lp[pshift] - width, cmp, arg, p, ar, lp, width, pshift + 1,
1);
shl(p, 1);
p[0] |= 1;
trinkle(head - width, cmp, arg, p, ar, lp, width, pshift, 1);
}
head -= width;
}
}
/**
* Sorts array.
*
* @param base points to an array to sort in-place
* @param count is the item count
* @param width is the size of each item
* @param cmp is a callback returning <0, 0, or >0
* @param arg will optionally be passed as the third argument to cmp
*/
void qsort_r(void *base, size_t count, size_t width, cmpfun cmp, void *arg) {
unsigned lp[12 * sizeof(unsigned)];
unsigned char *ar[14 * sizeof(unsigned) + 1];
smoothsort(base, count, width, (cmpfun)cmp, arg, lp, ar);
}
/**
* Sorts array.
* @see qsort_r() for further details
*/
void qsort(void *base, size_t count, size_t width,
int cmp(const void *, const void *)) {
qsort_r(base, count, width, (cmpfun)cmp, NULL);
}

64
libc/alg/replacestr.c Normal file
View file

@ -0,0 +1,64 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist2.h"
#include "libc/bits/safemacros.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Replaces all instances of NEEDLE in S with REPLACEMENT.
*
* @param needle can't be empty
* @return newly allocated memory that must be free()'d or NULL w/ errno
* @error ENOMEM, EINVAL
*/
char *(replacestr)(const char *s, const char *needle, const char *replacement) {
char *p1, *p2, *res_p;
size_t left, nlen, rlen, res_i, res_n;
if (*needle) {
p1 = s;
left = strlen(s);
nlen = strlen(needle);
rlen = strlen(replacement);
res_i = 0;
res_n = max(left, 32);
if ((res_p = malloc(res_n * sizeof(char)))) {
do {
if (!(p2 = memmem(p1, left, needle, nlen))) break;
if (CONCAT(&res_p, &res_i, &res_n, p1, p2 - p1) == -1 ||
CONCAT(&res_p, &res_i, &res_n, replacement, rlen) == -1) {
goto oom;
}
p2 += nlen;
left -= p2 - p1;
p1 = p2;
} while (left);
if (CONCAT(&res_p, &res_i, &res_n, p1, left + 1) != -1) {
return res_p;
}
}
oom:
free(res_p);
} else {
einval();
}
return NULL;
}

29
libc/alg/replacestr16.c Normal file
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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist2.h"
#include "libc/bits/safemacros.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#undef replacestr
#define replacestr replacestr16
#define char char16_t
#include "libc/alg/replacestr.c"

33
libc/alg/reverse.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef COSMOPOLITAN_LIBC_ALG_REVERSE_H_
#define COSMOPOLITAN_LIBC_ALG_REVERSE_H_
#include "libc/bits/xchg.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#if 0
/**
* Reverses array.
*
* @param ARRAY is a typed array or a pointer to one
* @param COUNT is the number of items
* @return pointer to start of array
* @see ARRAYLEN()
*/
#endif
#define reverse(ARRAY, COUNT) \
({ \
autotype(&(ARRAY)[0]) Array = (ARRAY); \
size_t Count = (COUNT); \
if (Count) { \
size_t Start = 0; \
size_t End = Count - 1; \
while (Start < End) { \
xchg(&Array[Start], &Array[End]); \
++Start; \
--End; \
} \
} \
Array; \
})
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ALG_REVERSE_H_ */

25
libc/alg/shuffle.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_LIBC_RAND_SHUFFLE_H_
#define COSMOPOLITAN_LIBC_RAND_SHUFFLE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#include "libc/bits/xchg.h"
#if 0
/**
* Fisher-Yates shuffle.
*
* @param R is a function like rand() 0
* @param A is a typed array
* @param n is the number of items in A
* @see ARRAYLEN()
*/
#endif
#define shuffle(R, A, n) \
do { \
autotype(A) Array = (A); \
for (size_t i = (n)-1; i >= 1; --i) { \
xchg(&Array[i], &Array[R() % (i + 1)]); \
} \
} while (0)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RAND_SHUFFLE_H_ */

183
libc/alg/tarjan.c Normal file
View file

@ -0,0 +1,183 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/assert.h"
#include "libc/bits/safemacros.h"
#include "libc/limits.h"
#include "libc/mem/mem.h"
/**
* @fileoverview Tarjan's Strongly Connected Components Algorithm.
*
* The data structures that [Tarjan] devised for this problem fit
* together in an amazingly beautiful way, so that the quantities
* you need to look at while exploring a directed graph are always
* magically at your fingertips. And his algorithm also does
* topological sorting as a byproduct. D.E. Knuth
*/
struct Vertex {
uint32_t Vi;
uint32_t Ei;
uint32_t index;
uint32_t lowlink;
bool onstack;
bool selfreferential;
};
struct TarjanStack {
size_t i;
size_t n;
uint32_t *p;
};
struct Tarjan {
uint32_t Vn;
uint32_t En;
struct Vertex *V;
const uint32_t (*E)[2];
uint32_t *R;
uint32_t *C;
uint32_t Ci;
uint32_t Ri;
uint32_t index;
struct TarjanStack S;
};
static uint32_t TarjanPush(struct TarjanStack *st, uint32_t Vi) {
if (st->i < st->n || grow(&st->p, &st->n, sizeof(uint32_t), 0)) {
return (st->p[st->i++] = Vi);
} else {
return -1;
}
}
static uint32_t TarjanPop(struct TarjanStack *st) {
assert(st->i != 0);
return st->p[--st->i];
}
static int TarjanConnect(struct Tarjan **tj, uint32_t Vi) {
struct Vertex *v = &(*tj)->V[Vi];
v->index = (*tj)->index;
v->lowlink = (*tj)->index;
v->onstack = true;
(*tj)->index++;
if (TarjanPush(&(*tj)->S, Vi) == -1) return -1;
uint32_t fs = (*tj)->V[Vi].Ei;
if (fs != -1) {
for (uint32_t Ei = fs; Ei < (*tj)->En && Vi == (*tj)->E[Ei][0]; ++Ei) {
struct Vertex *w = &(*tj)->V[(*tj)->E[Ei][1]];
if (!w->index) {
if (TarjanConnect(tj, w->Vi) == -1) return -1;
v->lowlink = min(v->lowlink, w->lowlink);
} else if (w->onstack) {
v->lowlink = min(v->lowlink, w->index);
}
if (w == v) {
w->selfreferential = true;
}
}
}
if (v->lowlink == v->index) {
struct Vertex *w;
do {
w = &(*tj)->V[TarjanPop(&(*tj)->S)];
w->onstack = false;
(*tj)->R[(*tj)->Ri++] = w->Vi;
} while (w != v);
if ((*tj)->C) (*tj)->C[(*tj)->Ci++] = (*tj)->Ri;
}
return 0;
}
/**
* Determines order of things in network and finds tangled clusters too.
*
* @param vertices is an array of vertex values, which isn't passed to
* this function, since the algorithm only needs to consider indices
* @param vertex_count is the number of items in the vertices array
* @param edges are grouped directed links between indices of vertices,
* which can be thought of as "edge[i][0] depends on edge[i][1]" or
* "edge[i][1] must come before edge[i][0]" in topological order
* @param edge_count is the number of items in edges, which may be 0 if
* there aren't any connections between vertices in the graph
* @param out_sorted receives indices into the vertices array in
* topologically sorted order, and must be able to store
* vertex_count items, and that's always how many are stored
* @param out_opt_components receives indices into the out_sorted array,
* indicating where each strongly-connected component ends; must be
* able to store vertex_count items; and it may be NULL
* @param out_opt_componentcount receives the number of cycle indices
* written to out_opt_components, which will be vertex_count if
* there aren't any cycles in the graph; and may be NULL if
* out_opt_components is NULL
* @return 0 on success or -1 w/ errno
* @error ENOMEM
* @note Tarjan's Algorithm is O(|V|+|E|)
*/
int tarjan(uint32_t vertex_count, const uint32_t (*edges)[2],
uint32_t edge_count, uint32_t out_sorted[],
uint32_t out_opt_components[], uint32_t *out_opt_componentcount) {
assert(edge_count <= INT_MAX);
assert(vertex_count <= INT_MAX);
for (unsigned i = 0; i < edge_count; ++i) {
if (i) assert(edges[i - 1][0] <= edges[i][0]);
assert(edges[i][0] < vertex_count);
assert(edges[i][1] < vertex_count);
}
int rc;
struct Tarjan *tj;
if ((tj = calloc(1, (sizeof(struct Tarjan) +
sizeof(struct Vertex) * vertex_count)))) {
tj->V = (struct Vertex *)((char *)tj + sizeof(struct Tarjan));
tj->Vn = vertex_count;
tj->E = edges;
tj->En = edge_count;
tj->R = out_sorted;
tj->C = out_opt_components;
tj->index = 1;
uint32_t Vi, Ei;
for (Vi = 0; Vi < tj->Vn; ++Vi) {
tj->V[Vi].Vi = Vi;
tj->V[Vi].Ei = -1u;
}
for (Ei = 0, Vi = -1u; Ei < tj->En; ++Ei) {
if (tj->E[Ei][0] == Vi) continue;
Vi = tj->E[Ei][0];
tj->V[Vi].Ei = Ei;
}
rc = 0;
for (Vi = 0; Vi < tj->Vn; ++Vi) {
if (!tj->V[Vi].index) {
if ((rc = TarjanConnect(&tj, Vi)) == -1) {
break;
}
}
}
free(tj->S.p);
assert(tj->Ri == vertex_count);
if (out_opt_components) *out_opt_componentcount = tj->Ci;
} else {
rc = -1;
}
free(tj);
return rc;
}

24
libc/assert.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef COSMOPOLITAN_LIBC_ASSERT_H_
#define COSMOPOLITAN_LIBC_ASSERT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void __assert_fail(const char *, const char *, int) hidden noreturn relegated;
#ifdef NDEBUG
#define __ASSERT_FAIL(EXPR, FILE, LINE)
#else
#define __ASSERT_FAIL(EXPR, FILE, LINE) __assert_fail(EXPR, FILE, LINE)
#endif
#define assert(EXPR) \
do { \
if (!(EXPR)) { \
__ASSERT_FAIL(#EXPR, __FILE__, __LINE__); \
unreachable; \
} \
} while (0)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ASSERT_H_ */

23
libc/bits/abs.c Normal file
View file

@ -0,0 +1,23 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/conv/conv.h"
#include "libc/macros.h"
int(abs)(int x) { return ABS(x); }

52
libc/bits/atomic.h Normal file
View file

@ -0,0 +1,52 @@
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
#include "libc/bits/bits.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview C11 version of The Cosmopolitan Atomics Library.
*
* - Forty-two different ways to say MOV.
* - Fourteen different ways to say XCHG.
* - Twenty different ways to say LOCK CMPXCHG.
*
* Living proof high-level languages can be lower-level than assembly.
*/
#define memory_order int
#define memory_order_relaxed 0
#define memory_order_consume 1
#define memory_order_acquire 2
#define memory_order_release 3
#define memory_order_acq_rel 4
#define memory_order_seq_cst 5
#define atomic_flag struct AtomicFlag
#define atomic_flag_clear(PTR) atomic_store((PTR)->__cacheline, 0)
#define atomic_flag_test_and_set(PTR) \
({ \
uint32_t ax = 0; \
lockcmpxchg((PTR)->__cacheline, &ax, 1); \
})
#define atomic_init(PTR, VAL) atomic_store(PTR, VAL)
#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL))
#define atomic_compare_exchange_strong(X, Y, Z) lockcmpxchg(X, Y, Z)
#define atomic_compare_exchange_weak(X, Y, Z) lockcmpxchg(X, Y, Z)
#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR)
#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL)
#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0)
#define atomic_exchange_explicit(PTR, VAL, ORDER) lockxchg(PTR, &(VAL))
#define atomic_flag_test_and_set_explicit(PTR, ORDER) lockcmpxchg(PTR, 0, 1)
#define atomic_compare_exchange_strong_explicit(X, Y, Z, S, F) \
lockcmpxchg(X, Y, Z)
#define atomic_compare_exchange_weak_explicit(X, Y, Z, S, F) \
lockcmpxchg(X, Y, Z)
struct AtomicFlag {
uint32_t __cacheline[16]; /* Intel V.O §9.4.6 */
} aligned(64);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ */

133
libc/bits/avx2intrin.h Normal file
View file

@ -0,0 +1,133 @@
#ifndef COSMOPOLITAN_LIBC_BITS_AVX2INTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_AVX2INTRIN_H_
#include "libc/bits/avxintrin.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define _mm256_min_epi16(M256_0, M256_1) \
((__m256i)__builtin_ia32_minps((__v16hi)(M256_0), (__v16hi)(M256_1)))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § avx2 » simd ops
*/
#define _mm256_add_ps(M256_0, M256_1) \
((__m256)((__v8sf)(M256_0) + (__v8sf)(M256_1)))
#define _mm256_sub_ps(M256_0, M256_1) \
((__m256)((__v8sf)(M256_0) - (__v8sf)(M256_1)))
#define _mm256_mul_ps(M256_0, M256_1) \
((__m256)((__v8sf)(M256_0) * (__v8sf)(M256_1)))
#define _mm256_div_ps(M256_0, M256_1) \
((__m256)((__v8sf)(M256_0) / (__v8sf)(M256_1)))
#define _mm256_and_ps(M256_0, M256_1) \
((__m256)((__v8su)(M256_0) & (__v8su)(M256_1)))
#define _mm256_or_ps(M256_0, M256_1) \
((__m256)((__v8su)(M256_0) | (__v8su)(M256_1)))
#define _mm256_xor_ps(M256_0, M256_1) /* XORPD [u32 simd xor] */ \
((__m256)((__v8su)(M256_0) ^ (__v8su)(M256_1)))
#define _mm256_andnot_ps(M256_0, M256_1) /* ANDNPS [u32 simd nand] */ \
((__m256)(~(__v8su)(M256_0) & (__v8su)(M256_1)))
#define _mm256_rcp_ps(M256) __builtin_ia32_rcpps256((__v8sf)(M256))
#define _mm256_sqrt_ps(M256) __builtin_ia32_sqrtps256((__v8sf)(M256))
#define _mm256_rsqrt_ps(M256) __builtin_ia32_rsqrtps256((__v8sf)(M256))
#define _mm256_round_ps(M256, IMM) \
((__m256)__builtin_ia32_roundps256((__v8sf)(__m256)(M256), IMM))
#define _mm256_add_epi32(M256I_0, M256I_1) \
((__m256i)((__v8su)(M256I_0) + (__v8su)(M256I_1)))
#define _mm256_cmpgt_epi32(M256I_0, M256I_1) \
((__m256i)((__v8si)(M256I_0) > (__v8si)(M256I_1)))
#define _mm256_min_epi32(M256I_0, M256I_1) \
((__m256i)__builtin_ia32_pminsd256((__v8si)(M256I_0), (__v8si)(M256I_1)))
#define _mm256_min_epu32(M256I_0, M256I_1) \
((__m256i)__builtin_ia32_pminud256((__v8si)(M256I_0), (__v8si)(M256I_1)))
#define _mm256_max_epi32(M256I_0, M256I_1) \
((__m256i)__builtin_ia32_pmaxsd256((__v8si)(M256I_0), (__v8si)(M256I_1)))
#define _mm256_max_epu32(M256I_0, M256I_1) \
((__m256i)__builtin_ia32_pmaxud256((__v8si)(M256I_0), (__v8si)(M256I_1)))
#define _mm256_blendv_epi8(M256I_0, M256I_1, M256I_2) \
((__m256i)__builtin_ia32_pblendvb256((__v32qi)(M256I_0), (__v32qi)(M256I_1), \
(__v32qi)(M256I_2)))
#define _mm256_min_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_minps256((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_max_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_maxps256((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_cmpneq_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpneqps((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_cmplt_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpltps((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_cmpnlt_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpnltps((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_cmple_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpleps((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_cmpnle_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpnleps((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_cmpgt_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpltps((__v8sf)(__m256)(M256_1), \
(__v8sf)(__m256)(M256_0)))
#define _mm256_cmpngt_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpnltps((__v8sf)(__m256)(M256_1), \
(__v8sf)(__m256)(M256_0)))
#define _mm256_cmpge_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpleps((__v8sf)(__m256)(M256_1), \
(__v8sf)(__m256)(M256_0)))
#define _mm256_cmpnge_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpnleps((__v8sf)(__m256)(M256_1), \
(__v8sf)(__m256)(M256_0)))
#define _mm256_cmpord_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpordps((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
#define _mm256_cmpunord_ps(M256_0, M256_1) \
((__m256)__builtin_ia32_cmpunordps((__v8sf)(__m256)(M256_0), \
(__v8sf)(__m256)(M256_1)))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § avx2 » memory ops
*/
struct thatispacked PackedMayaliasIntyYmm {
__m256i Ymm;
} mayalias;
#define _mm256_set_ps(FLT_0, FLT_1, FLT_2, FLT_3, FLT_4, FLT_5, FLT_6, FLT_7) \
((__m256)(__v8sf){(float)(FLT_0), (float)(FLT_1), (float)(FLT_2), \
(float)(FLT_3), (float)(FLT_4), (float)(FLT_5), \
(float)(FLT_6), (float)(FLT_7)})
#define _mm256_set1_ps(FLT_0) \
_mm256_set_ps(FLT_0, FLT_0, FLT_0, FLT_0, FLT_0, FLT_0, FLT_0, FLT_0)
#define _mm256_setr_ps(FLT_0, FLT_1, FLT_2, FLT_3, FLT_4, FLT_5, FLT_6, FLT_7) \
_mm256_set_ps(FLT_7, FLT_6, FLT_5, FLT_4, FLT_3, FLT_2, FLT_1, FLT_0)
#define _mm256_set_epi32(INT_0, INT_1, INT_2, INT_3, INT_4, INT_5, INT_6, \
INT_7) \
((__m256i)(__v8si){(int)(INT_0), (int)(INT_1), (int)(INT_2), (int)(INT_3), \
(int)(INT_4), (int)(INT_5), (int)(INT_6), (int)(INT_7)})
#define _mm256_set1_epi32(INT_0) \
_mm256_set_epi32(INT_0, INT_0, INT_0, INT_0, INT_0, INT_0, INT_0, INT_0)
#define _mm256_setr_epi32(INT_0, INT_1, INT_2, INT_3, INT_4, INT_5, INT_6, \
INT_7) \
_mm256_set_epi32(INT_7, INT_6, INT_5, INT_4, INT_3, INT_2, INT_1, INT_0)
#define _mm256_loadu_si256(M256IP_0) \
({ \
const __m256i *Ymm = (M256IP_0); \
((struct PackedMayaliasIntyYmm *)Ymm)->Ymm; \
})
#define _mm256_storeu_si256(M256IP_0, M256I_1) \
({ \
__m256i *Ymm = (M256IP_0); \
((struct PackedMayaliasIntyYmm *)Ymm)->Ymm = M256I_1; \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_AVX2INTRIN_H_ */

51
libc/bits/avxintrin.h Normal file
View file

@ -0,0 +1,51 @@
#ifndef COSMOPOLITAN_LIBC_BITS_AVXINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_AVXINTRIN_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef float __m256 _Vector_size(32) mayalias;
typedef double __m256d _Vector_size(32) mayalias;
typedef long long __m256i _Vector_size(32) mayalias;
typedef float __m256_u _Vector_size(32) aligned(1) mayalias;
typedef double __m256d_u _Vector_size(32) aligned(1) mayalias;
typedef long long __m256i_u _Vector_size(32) aligned(1) mayalias;
typedef double __v4df _Vector_size(32);
typedef float __v8sf _Vector_size(32);
typedef long long __v4di _Vector_size(32);
typedef unsigned long long __v4du _Vector_size(32);
typedef int __v8si _Vector_size(32);
typedef unsigned __v8su _Vector_size(32);
typedef short __v16hi _Vector_size(32);
typedef unsigned short __v16hu _Vector_size(32);
typedef char __v32qi _Vector_size(32);
typedef unsigned char __v32qu _Vector_size(32);
#define _mm256_setzero_ps() ((__m256)(__v8sf){0})
#define _mm256_load_ps(FLOATPTR) (*(__m256 *)(FLOATPTR))
#define _mm256_loadu_ps(FLOATPTR) (*(__m256_u *)(FLOATPTR))
#define _mm256_store_ps(FLOATPTR, M256_0) \
(*(__m256 *)(FLOATPTR) = (__m256)(M256_0))
#define _mm256_storeu_ps(FLOATPTR, M256_0) \
(*(__m256_u *)(FLOATPTR) = (__m256)(M256_0))
#define _mm256_extractf128_ps(M256_0, INT_1) \
((__m128)__builtin_ia32_vextractf128_ps256((__v8sf)(__m256)(M256_0), \
(int)(INT_1)))
#define _mm256_insertf128_ps(M256_0, M128_1, IMM_2) \
((__m256)__builtin_ia32_vinsertf128_ps256( \
(__v8sf)(__m256)(M256_0), (__v4sf)(__m128)(M128_1), (int)(IMM_2)))
#ifdef __llvm__
#define _mm256_castps128_ps256(M128_0) \
((__m256)__builtin_shufflevector((__v4sf)(__m128)(M128_0), \
(__v4sf)(__m128)(M128_0), 0, 1, 2, 3, -1, \
-1, -1, -1))
#else
#define _mm256_castps128_ps256(M128_0) \
((__m256)__builtin_ia32_ps256_ps((__v4sf)(__m128)(M128_0)))
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_AVXINTRIN_H_ */

42
libc/bits/bcd2i.S Normal file
View file

@ -0,0 +1,42 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
/ Converts binary-coded-decimal to integer.
/
/ @param rdi is the string copied into a word
bcd2i: .leafprologue
.profilable
test %rdi,%rdi
je 2f
mov $1,%ecx
xor %eax,%eax
1: mov %edi,%edx
and $15,%edx
imul %rcx,%rdx
add %rdx,%rax
add %rcx,%rcx
lea (%rcx,%rcx,4),%rcx
shr $4,%rdi
jne 1b
ret
2: xor %eax,%eax
.leafepilogue
.endfn bcd2i,globl

38
libc/bits/bcdadd.S Normal file
View file

@ -0,0 +1,38 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
/ Performs addition on binary-coded decimals.
bcdadd: .leafprologue
.profilable
lea 0x6666666(%rdi),%ecx
xor %esi,%ecx
lea (%rdi,%rsi),%eax
add $0x6666666,%eax
xor %eax,%ecx
not %ecx
and $0x11111110,%ecx
mov %ecx,%edx
shr $2,%edx
shr $3,%ecx
orl %edx,%ecx
sub %ecx,%eax
.leafepilogue
.endfn bcdadd,globl

54
libc/bits/bcxcpy.S Normal file
View file

@ -0,0 +1,54 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
bcxcpy: push %rbp
mov %rsp,%rbp
.profilable
push %rbx
xor %ebx,%ebx
lea -64(%rbp),%rdx
sub $24,%rsp
3: lea (,%rbx,4),%ecx
mov %rsi,%rax
shr %cl,%rax
and $15,%eax
cmp $9,%eax
lea 7(%rax),%ecx
cmova %ecx,%eax
add $48,%eax
mov %al,(%rdx,%rbx)
add $1,%rbx
cmp $16,%rbx
jne 3b
mov %rdx,%rax
lea -48(%rbp),%rcx
lea 15(%rdi),%rdx
4: movzbl (%rax),%ebx
add $1,%rax
sub $1,%rdx
mov %bl,1(%rdx)
cmp %rcx,%rax
jne 4b
add $24,%rsp
pop %rbx
pop %rbp
ret
.endfn bcxcpy,globl

28
libc/bits/bigword.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef COSMOPOLITAN_LIBC_BITS_BIGWORD_H_
#define COSMOPOLITAN_LIBC_BITS_BIGWORD_H_
#if 0
/**
* Let BIGWORD be the the number of bytes in the largest cpu register
* available within the instruction set architecture requirements chosen
* at compile-time.
*
* In plainer terms, if you tune with flags like -mavx, you're not just
* giving the compiler permission to generate code that's incompatible
* with older computers; you're also asking Cosmopolitan to systemically
* change alignment, vectoring, buffering, ABIs, memory allocation, etc.
*/
#endif
#ifndef BIGWORD
#if __AVX512F__ + 0
#define BIGWORD 64
#elif __AVX2__ + 0
#define BIGWORD 32
#elif __SSE2__ + 0
#define BIGWORD 16
#else
#define BIGWORD __BIGGEST_ALIGNMENT__
#endif
#endif /*BIGWORD*/
#endif /* COSMOPOLITAN_LIBC_BITS_BIGWORD_H_ */

31
libc/bits/bitreverse16.S Normal file
View file

@ -0,0 +1,31 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
bitreverse16:
push %rbx
mov %edi,%eax
mov $kReverseBits,%ebx
xlat
xchg %al,%ah
xlat
pop %rbx
ret
.endfn bitreverse16,globl

28
libc/bits/bitreverse32.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
uint32_t(bitreverse32)(uint32_t x) {
x = bswap_32(x);
x = ((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1);
x = ((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2);
x = ((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4);
return x;
}

28
libc/bits/bitreverse64.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
uint64_t bitreverse64(uint64_t x) {
x = bswap_64(x);
x = ((x & 0xaaaaaaaaaaaaaaaa) >> 1) | ((x & 0x5555555555555555) << 1);
x = ((x & 0xcccccccccccccccc) >> 2) | ((x & 0x3333333333333333) << 2);
x = ((x & 0xf0f0f0f0f0f0f0f0) >> 4) | ((x & 0x0f0f0f0f0f0f0f0f) << 4);
return x;
}

31
libc/bits/bitreverse8.S Normal file
View file

@ -0,0 +1,31 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
bitreverse8:
.leafprologue
.profilable
push %rbx
mov %edi,%eax
mov $kReverseBits,%ebx
xlat
pop %rbx
.leafepilogue
.endfn bitreverse8,globl

531
libc/bits/bits.h Normal file
View file

@ -0,0 +1,531 @@
#ifndef COSMOPOLITAN_LIBC_BITS_H_
#define COSMOPOLITAN_LIBC_BITS_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define CheckUnsigned(x) ((x) / !((typeof(x))(-1) < 0))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § bits
*/
extern const bool kTrue;
extern const bool kFalse;
extern const uint8_t kReverseBits[256];
uint16_t bswap_16(uint16_t) pureconst;
uint32_t bswap_32(uint32_t) pureconst;
uint32_t bswap_64(uint32_t) pureconst;
unsigned long popcount(unsigned long) pureconst;
uint32_t gray(uint32_t) pureconst;
uint32_t ungray(uint32_t) pureconst;
unsigned bcdadd(unsigned, unsigned) pureconst;
unsigned long bcd2i(unsigned long) pureconst;
unsigned long i2bcd(unsigned long) pureconst;
void bcxcpy(unsigned char (*)[16], unsigned long);
int ffs(int) pureconst;
int ffsl(long int) pureconst;
int ffsll(long long int) pureconst;
int fls(int) pureconst;
int flsl(long int) pureconst;
int flsll(long long int) pureconst;
uint8_t bitreverse8(uint8_t) libcesque pureconst;
uint16_t bitreverse16(uint16_t) libcesque pureconst;
uint32_t bitreverse32(uint32_t) libcesque pureconst;
uint64_t bitreverse64(uint64_t) libcesque pureconst;
unsigned long roundup2pow(unsigned long) libcesque pureconst;
unsigned long roundup2log(unsigned long) libcesque pureconst;
unsigned long rounddown2pow(unsigned long) libcesque pureconst;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § bits » no assembly required
*/
/**
* Undocumented incantations for ROR, ROL, and SAR.
*/
#define ROR(w, k) (CheckUnsigned(w) >> (k) | (w) << (sizeof(w) * 8 - (k)))
#define ROL(w, k) ((w) << (k) | CheckUnsigned(w) >> (sizeof(w) * 8 - (k)))
#define SAR(w, k) (((w) & ~(~0u >> (k))) | ((w) >> ((k) & (sizeof(w) * 8 - 1))))
#define bitreverse8(X) (kReverseBits[(X)&0xff])
#define bitreverse16(X) \
((uint16_t)kReverseBits[(X)&0xff] << 010 | \
kReverseBits[((uint16_t)(X) >> 010) & 0xff])
#ifndef __GNUC__
#define READ16LE(P) ((unsigned)(P)[1] << 010 | (unsigned)(P)[0])
#define READ32LE(P) \
((unsigned long)(P)[3] << 030 | (unsigned long)(P)[2] << 020 | \
(unsigned long)(P)[1] << 010 | (unsigned long)(P)[0])
#define READ64LE(P) \
((unsigned long long)(P)[3] << 030 | (unsigned long)(P)[2] << 020 | \
(unsigned long long)(P)[1] << 010 | (unsigned long)(P)[0])
#else
#define READ16LE(P) read16le(P)
#define READ32LE(P) read32le(P)
#define READ64LE(P) read64le(P)
#define read16le(P) \
({ \
const unsigned char *Pu = (const unsigned char *)(P); \
(uint16_t) Pu[1] << 010 | (uint16_t)Pu[0]; \
})
#define read32le(P) \
({ \
const unsigned char *Pu = (const unsigned char *)(P); \
((uint32_t)Pu[3] << 030 | (uint32_t)Pu[2] << 020 | \
(uint32_t)Pu[1] << 010 | (uint32_t)Pu[0] << 000); \
})
#define read64le(P) \
({ \
const unsigned char *Pu = (const unsigned char *)(P); \
((uint64_t)Pu[7] << 070 | (uint64_t)Pu[6] << 060 | \
(uint64_t)Pu[5] << 050 | (uint64_t)Pu[4] << 040 | \
(uint64_t)Pu[3] << 030 | (uint64_t)Pu[2] << 020 | \
(uint64_t)Pu[1] << 010 | (uint64_t)Pu[0] << 000); \
})
#endif
#define WRITE16LE(P, V) \
do { \
uint8_t *Ple = (P); \
uint16_t Vle = (V); \
Ple[0] = (uint8_t)(Vle >> 000); \
Ple[1] = (uint8_t)(Vle >> 010); \
} while (0)
#define WRITE32LE(P, V) \
do { \
uint8_t *Ple = (P); \
uint32_t Vle = (V); \
Ple[0] = (uint8_t)(Vle >> 000); \
Ple[1] = (uint8_t)(Vle >> 010); \
Ple[2] = (uint8_t)(Vle >> 020); \
Ple[3] = (uint8_t)(Vle >> 030); \
} while (0)
#define WRITE64LE(P, V) \
do { \
uint8_t *Ple = (P); \
uint64_t Vle = (V); \
Ple[0] = (uint8_t)(Vle >> 000); \
Ple[1] = (uint8_t)(Vle >> 010); \
Ple[2] = (uint8_t)(Vle >> 020); \
Ple[3] = (uint8_t)(Vle >> 030); \
Ple[4] = (uint8_t)(Vle >> 040); \
Ple[5] = (uint8_t)(Vle >> 050); \
Ple[6] = (uint8_t)(Vle >> 060); \
Ple[7] = (uint8_t)(Vle >> 070); \
} while (0)
/* TODO(jart): these ones aren't coded correctly */
#define read128le(P) ((uint128_t)read64le((P) + 8) << 0100 | read64le(P))
#define read16be(P) ((uint16_t)(*(P) << 010) | (uint16_t)(*((P) + 1)))
#define read32be(P) ((uint32_t)read16be(P) << 020 | (uint32_t)read16be((P) + 2))
#define read64be(P) ((uint64_t)read32be(P) << 040 | read32be((P) + 4))
#define read128be(P) ((uint128_t)read64be(P) << 0100 | read64be((P) + 8))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § bits » some assembly required
*/
/**
* Constraints for virtual machine flags.
* @note we beseech clang devs for flag constraints
*/
#ifdef __GCC_ASM_FLAG_OUTPUTS__ /* GCC6+ CLANG10+ */
#define CF "=@ccc"
#define CFLAG(OP) OP
#define ZF "=@ccz"
#define ZFLAG(OP) OP
#define OF "=@cco"
#define OFLAG(OP) OP
#define SF "=@ccs"
#define SFLAG(SP) SP
#define ABOVEF "=@cca" /* i.e. !ZF && !CF */
#define ABOVEFLAG(OP) OP
#else
#define CF "=q"
#define CFLAG(OP) OP "\n\tsetc\t%b0"
#define ZF "=q"
#define ZFLAG(OP) OP "\n\tsetz\t%b0"
#define OF "=q"
#define OFLAG(OP) OP "\n\tseto\t%b0"
#define SF "=q"
#define SFLAG(SP) OP "\n\tsets\t%b0"
#define ABOVEF "=@cca"
#define ABOVEFLAG(OP) OP "\n\tseta\t%b0"
#endif
/**
* Reads scalar from memory, offset by segment.
*
* @return *(MEM) relative to segment
* @see arch_prctl()
* @see pushpop()
*/
#define fs(MEM) __peek("fs", MEM)
#define gs(MEM) __peek("gs", MEM)
/**
* Reads scalar from memory w/ one operation.
*
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @return *(MEM)
* @note defeats compiler load tearing optimizations
* @note alignas(𝑘) is implied if compiler knows type
* @note alignas(𝑘) only avoids multi-core / cross-page edge cases
* @see Intel's Six-Thousand Page Manual V.3A §8.2.3.1
* @see atomic_store()
*/
#define atomic_load(MEM) \
({ \
autotype(MEM) Mem = (MEM); \
typeof(*Mem) Reg; \
asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \
Reg; \
})
/**
* Saves scalar to memory w/ one operation.
*
* This is guaranteed to happen in either one or zero operations,
* depending on whether or not it's possible for *(MEM) to be read
* afterwards. This macro only forbids compiler from using >1 ops.
*
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @param VAL is uint𝑘_t w/ better encoding for immediates (constexpr)
* @return VAL
* @note alignas(𝑘) on nexgen32e only needed for end of page gotcha
* @note alignas(𝑘) is implied if compiler knows type
* @note needed to defeat store tearing optimizations
* @see Intel Six-Thousand Page Manual Manual V.3A §8.2.3.1
* @see atomic_load()
*/
#define atomic_store(MEM, VAL) \
({ \
autotype(VAL) Val = (VAL); \
typeof(&Val) Mem = (MEM); \
asm("mov%z1\t%1,%0" : "=m,m"(*Mem) : "i,r"(Val)); \
Val; \
})
/**
* Returns true if bit is set in memory.
*
* This is a generically-typed Bitset<T> RAM. This macro is intended
* to be container-like with optimal machine instruction encoding, cf.
* machine-agnostic container abstractions. Memory accesses are words.
* Register allocation can be avoided if BIT is known. Be careful when
* casting character arrays since that should cause a page fault.
*
* @param MEM is uint𝑘_t[] where 𝑘 {16,32,64} base address
* @param BIT [-(2**(𝑘-1)),2**(𝑘-1)) is zero-based index
* @return true if bit is set, otherwise false
* @see Intel's Six Thousand Page Manual V.2A 3-113
* @see bts(), btr(), btc()
*/
#define bt(MEM, BIT) \
({ \
bool OldBit; \
if (isconstant(BIT)) { \
asm(CFLAG("bt%z1\t%2,%1") \
: CF(OldBit) \
: "m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]), \
"J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 2) { \
asm(CFLAG("bt\t%w2,%1") : CF(OldBit) : "m"((MEM)[0]), "r"(BIT) : "cc"); \
} else if (sizeof((MEM)[0]) == 4) { \
asm(CFLAG("bt\t%k2,%1") : CF(OldBit) : "m"((MEM)[0]), "r"(BIT) : "cc"); \
} else if (sizeof((MEM)[0]) == 8) { \
asm(CFLAG("bt\t%q2,%1") : CF(OldBit) : "m"((MEM)[0]), "r"(BIT) : "cc"); \
} \
OldBit; \
})
#define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */
#define btr(MEM, BIT) __BitOp("btr", BIT, MEM) /** bit test and reset */
#define btc(MEM, BIT) __BitOp("btc", BIT, MEM) /** bit test and complement */
#define lockbts(MEM, BIT) __BitOp("lock bts", BIT, MEM)
#define lockbtr(MEM, BIT) __BitOp("lock btr", BIT, MEM)
#define lockbtc(MEM, BIT) __BitOp("lock btc", BIT, MEM)
#define lockinc(MEM) __ArithmeticOp1("lock inc", MEM)
#define lockdec(MEM) __ArithmeticOp1("lock dec", MEM)
#define locknot(MEM) __ArithmeticOp1("lock not", MEM)
#define lockneg(MEM) __ArithmeticOp1("lock neg", MEM)
#define lockaddeq(MEM, VAL) __ArithmeticOp2("lock add", VAL, MEM)
#define locksubeq(MEM, VAL) __ArithmeticOp2("lock sub", VAL, MEM)
#define lockxoreq(MEM, VAL) __ArithmeticOp2("lock xor", VAL, MEM)
#define lockandeq(MEM, VAL) __ArithmeticOp2("lock and", VAL, MEM)
#define lockoreq(MEM, VAL) __ArithmeticOp2("lock or", VAL, MEM)
/**
* Exchanges *MEMORY into *LOCALVAR w/ one operation.
*
* @param MEMORY is uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @param LOCALVAR is uint𝑘_t[hasatleast 1]
* @return LOCALVAR[0]
* @see xchg()
*/
#define lockxchg(MEMORY, LOCALVAR) \
({ \
static_assert(typescompatible(typeof(*(MEMORY)), typeof(*(LOCALVAR)))); \
asm("xchg\t%0,%1" : "+%m"(*(MEMORY)), "+r"(*(LOCALVAR))); \
*(LOCALVAR); \
})
/**
* Compares and exchanges.
*
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @return true if value was exchanged, otherwise false
* @see lockcmpxchg()
*/
#define cmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
({ \
bool DidIt; \
asm(ZFLAG("cmpxchg\t%3,%1") \
: ZF(DidIt), "+m"(*(IFTHING)), "+a"(*(ISEQUALTOME)) \
: "r"((typeof(*(IFTHING)))(REPLACEITWITHME)) \
: "cc"); \
DidIt; \
})
#define ezcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
({ \
bool DidIt; \
autotype(IFTHING) IfThing = (IFTHING); \
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
asm(ZFLAG("cmpxchg\t%3,%1") \
: ZF(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
: "r"(ReplaceItWithMe) \
: "cc"); \
DidIt; \
})
/**
* Compares and exchanges w/ one operation.
*
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 {8,16,32,64}
* @return true if value was exchanged, otherwise false
* @see lockcmpxchg()
*/
#define lockcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
({ \
bool DidIt; \
asm(ZFLAG("lock cmpxchg\t%3,%1") \
: ZF(DidIt), "+m"(*(IFTHING)), "+a"(*(ISEQUALTOME)) \
: "r"((typeof(*(IFTHING)))(REPLACEITWITHME)) \
: "cc"); \
DidIt; \
})
/**
* Gets value of extended control register.
*/
#define xgetbv(xcr_register_num) \
({ \
unsigned hi, lo; \
asm("xgetbv" : "=d"(hi), "=a"(lo) : "c"(cr_register_num)); \
(uint64_t) hi << 32 | lo; \
})
/**
* Reads model-specific register.
* @note programs running as guests won't have authorization
*/
#define rdmsr(msr) \
({ \
uint32_t lo, hi; \
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr)); \
(uint64_t) hi << 32 | lo; \
})
/**
* Writes model-specific register.
* @note programs running as guests won't have authorization
*/
#define wrmsr(msr, val) \
do { \
uint64_t val_ = (val); \
asm volatile("wrmsr" \
: /* no outputs */ \
: "c"(msr), "a"((uint32_t)val_), \
"d"((uint32_t)(val_ >> 32))); \
} while (0)
/**
* Tells CPU page tables changed for virtual address.
* @note programs running as guests won't have authorization
*/
#define invlpg(MEM) \
asm volatile("invlpg\t(%0)" : /* no outputs */ : "r"(MEM) : "memory")
/**
* Teleports code fragment inside _init().
*/
#define INITIALIZER(PRI, NAME, CODE) \
asm(".pushsection .init." #PRI "." #NAME ",\"ax\",@progbits\n\t" \
"call\t" #NAME "\n\t" \
".popsection"); \
textstartup optimizesize void NAME(char *rdi, const char *rsi) { \
CODE; \
asm volatile("" : /* no outputs */ : "D"(rdi), "S"(rsi)); \
}
#ifndef __STRICT_ANSI__
#if __PIC__ + __code_model_medium__ + __code_model_large__ + 0 > 1
#define __EZLEA(SYMBOL) "lea\t" SYMBOL "(%%rip),%"
#else
#define __EZLEA(SYMBOL) "mov\t$" SYMBOL ",%k"
#endif
#define weaken(symbol) ((const typeof(&(symbol)))weakaddr(#symbol))
#define strongaddr(symbolstr) \
({ \
intptr_t waddr; \
asm(__EZLEA(symbolstr) "0" : "=r"(waddr)); \
waddr; \
})
#define weakaddr(symbolstr) \
({ \
intptr_t waddr; \
asm(".weak\t" symbolstr "\n\t" __EZLEA(symbolstr) "0" : "=r"(waddr)); \
waddr; \
})
#else
#define weaken(symbol) symbol
#define weakaddr(symbolstr) &(symbolstr)
#endif
#define slowcall(fn, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
void *ax; \
asm volatile("push\t%7\n\t" \
"push\t%6\n\t" \
"push\t%5\n\t" \
"push\t%4\n\t" \
"push\t%3\n\t" \
"push\t%2\n\t" \
"push\t%1\n\t" \
"call\tslowcall" \
: "=a"(ax) \
: "g"(fn), "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), \
"g"(arg5), "g"(arg6) \
: "memory"); \
ax; \
})
#define IsAddressCanonicalForm(P) \
({ \
intptr_t p2 = (intptr_t)(P); \
(0xffff800000000000l <= p2 && p2 <= 0x00007fffffffffffl); \
})
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § bits » optimizations
*/
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define popcount(X) (isconstant(X) ? __builtin_popcount(X) : __popcount(X))
#define popcount$nehalem(X) \
({ \
typeof(X) BitCount; \
asm("popcnt\t%1,%0" : "=r,r"(BitCount) : "r,m"(X) : "cc"); \
BitCount; \
})
#ifdef __POPCNT__
#define __popcount(X) popcount$nehalem(X)
#else
#define __popcount(X) (popcount)(X)
#endif
#define bswap_16(U16) \
(isconstant(U16) ? ((((U16)&0xff00) >> 010) | (((U16)&0x00ff) << 010)) : ({ \
uint16_t Swapped16, Werd16 = (U16); \
asm("xchg\t%b0,%h0" : "=Q"(Swapped16) : "0"(Werd16)); \
Swapped16; \
}))
#define bswap_32(U32) \
(isconstant(U32) \
? ((((U32)&0xff000000) >> 030) | (((U32)&0x000000ff) << 030) | \
(((U32)&0x00ff0000) >> 010) | (((U32)&0x0000ff00) << 010)) \
: ({ \
uint32_t Swapped32, Werd32 = (U32); \
asm("bswap\t%0" : "=r"(Swapped32) : "0"(Werd32)); \
Swapped32; \
}))
#define bswap_64(U64) \
(isconstant(U64) ? ((((U64)&0xff00000000000000ul) >> 070) | \
(((U64)&0x00000000000000fful) << 070) | \
(((U64)&0x00ff000000000000ul) >> 050) | \
(((U64)&0x000000000000ff00ul) << 050) | \
(((U64)&0x0000ff0000000000ul) >> 030) | \
(((U64)&0x0000000000ff0000ul) << 030) | \
(((U64)&0x000000ff00000000ul) >> 010) | \
(((U64)&0x00000000ff000000ul) << 010)) \
: ({ \
uint64_t Swapped64, Werd64 = (U64); \
asm("bswap\t%0" : "=r"(Swapped64) : "0"(Werd64)); \
Swapped64; \
}))
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § bits » implementation details
*/
#define __peek(SEGMENT, ADDRESS) \
({ \
typeof(*(ADDRESS)) Pk; \
asm("mov\t%%" SEGMENT ":%1,%0" : "=r"(Pk) : "m"(*(ADDRESS))); \
Pk; \
})
#define __ArithmeticOp1(OP, MEM) \
({ \
asm(OP "%z0\t%0" : "+m"(*(MEM)) : /* no inputs */ : "cc"); \
MEM; \
})
#define __ArithmeticOp2(OP, VAL, MEM) \
({ \
asm(OP "%z0\t%1,%0" : "+m,m"(*(MEM)) : "i,r"(VAL) : "cc"); \
MEM; \
})
#define __BitOp(OP, BIT, MEM) \
({ \
bool OldBit; \
if (isconstant(BIT)) { \
asm(CFLAG(OP "%z1\t%2,%1") \
: CF(OldBit), "+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
: "J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 2) { \
asm(CFLAG(OP "\t%w2,%1") \
: CF(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 4) { \
asm(CFLAG(OP "\t%k2,%1") \
: CF(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} else if (sizeof((MEM)[0]) == 8) { \
asm(CFLAG(OP "\t%q2,%1") \
: CF(OldBit), "+m"((MEM)[0]) \
: "r"(BIT) \
: "cc"); \
} \
OldBit; \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_H_ */

53
libc/bits/bits.mk Normal file
View file

@ -0,0 +1,53 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += LIBC_BITS
LIBC_BITS_ARTIFACTS += LIBC_BITS_A
LIBC_BITS = $(LIBC_BITS_A_DEPS) $(LIBC_BITS_A)
LIBC_BITS_A = o/$(MODE)/libc/bits/bits.a
LIBC_BITS_A_FILES := $(wildcard libc/bits/*)
LIBC_BITS_A_HDRS = $(filter %.h,$(LIBC_BITS_A_FILES))
LIBC_BITS_A_SRCS_S = $(filter %.S,$(LIBC_BITS_A_FILES))
LIBC_BITS_A_SRCS_C = $(filter %.c,$(LIBC_BITS_A_FILES))
LIBC_BITS_A_SRCS = \
$(LIBC_BITS_A_SRCS_S) \
$(LIBC_BITS_A_SRCS_C)
LIBC_BITS_A_OBJS = \
$(LIBC_BITS_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_BITS_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_BITS_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_BITS_A_CHECKS = \
$(LIBC_BITS_A).pkg \
$(LIBC_BITS_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_BITS_A_DIRECTDEPS = \
LIBC_STUBS \
LIBC_NEXGEN32E
LIBC_BITS_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_BITS_A_DIRECTDEPS),$($(x))))
$(LIBC_BITS_A): libc/bits/ \
$(LIBC_BITS_A).pkg \
$(LIBC_BITS_A_OBJS)
$(LIBC_BITS_A).pkg: \
$(LIBC_BITS_A_OBJS) \
$(foreach x,$(LIBC_BITS_A_DIRECTDEPS),$($(x)_A).pkg)
#o/$(MODE)/libc/bits/bsf.o: CC = clang-10
#o/$(MODE)/libc/bits/bsf.o: CC = /opt/cross9cc/bin/x86_64-linux-musl-cc
LIBC_BITS_LIBS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x)))
LIBC_BITS_SRCS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x)_SRCS))
LIBC_BITS_HDRS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x)_HDRS))
LIBC_BITS_CHECKS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x)_CHECKS))
LIBC_BITS_OBJS = $(foreach x,$(LIBC_BITS_ARTIFACTS),$($(x)_OBJS))
$(LIBC_BITS_OBJS): $(BUILD_FILES) libc/bits/bits.mk
.PHONY: o/$(MODE)/libc/bits
o/$(MODE)/libc/bits: $(LIBC_BITS_CHECKS)

217
libc/bits/emmintrin.h Normal file
View file

@ -0,0 +1,217 @@
#ifndef COSMOPOLITAN_LIBC_BITS_EMMINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_EMMINTRIN_H_
#include "libc/bits/progn.h"
#include "libc/bits/xmmintrin.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse2
*/
typedef char __v16qi _Vector_size(16);
typedef unsigned char __v16qu _Vector_size(16);
typedef signed char __v16qs _Vector_size(16);
typedef short __v8hi _Vector_size(16);
typedef unsigned short __v8hu _Vector_size(16);
typedef double __v2df _Vector_size(16);
typedef double __m128d _Vector_size(16) aligned(16);
typedef double __m128d_u _Vector_size(16) aligned(1);
typedef long long __v2di _Vector_size(16);
typedef long long __m128i _Vector_size(16) aligned(16);
typedef long long __m128i_u _Vector_size(16) aligned(1);
typedef unsigned long long __v2du _Vector_size(16);
struct thatispacked mayalias __usi128ma {
__m128i_u __v;
};
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse2 » memory ops
*/
#define _mm_loadu_si128(M128IP) ((struct __usi128ma *)(M128IP))->__v
#define _mm_storeu_si128(M128IP, M128I) \
(((struct __usi128ma *)(M128IP))->__v = (M128I))
#define _mm_set_epi8(I8_15, I8_14, I8_13, I8_12, I8_11, I8_10, I8_9, I8_8, \
I8_7, I8_6, I8_5, I8_4, I8_3, I8_2, I8_1, I8_0) \
((__m128i)(__v16qi){I8_0, I8_1, I8_2, I8_3, I8_4, I8_5, I8_6, I8_7, I8_8, \
I8_9, I8_10, I8_11, I8_12, I8_13, I8_14, I8_15})
#define _mm_set_epi16(I16_7, I16_6, I16_5, I16_4, I16_3, I16_2, I16_1, I16_0) \
((__m128i)(__v8hi){I16_0, I16_1, I16_2, I16_3, I16_4, I16_5, I16_6, I16_7})
#define _mm_set_epi32(I32_3, I32_2, I32_1, I32_0) \
((__m128i)(__v4si){I32_0, I32_1, I32_2, I32_3})
#define _mm_set_epi64x(I64_1, I64_0) ((__m128i)(__v2di){I64_0, I64_1})
#define _mm_setr_epi8(I8_15, I8_14, I8_13, I8_12, I8_11, I8_10, I8_9, I8_8, \
I8_7, I8_6, I8_5, I8_4, I8_3, I8_2, I8_1, I8_0) \
_mm_set_epi8(I8_0, I8_1, I8_2, I8_3, I8_4, I8_5, I8_6, I8_7, I8_8, I8_9, \
I8_10, I8_11, I8_12, I8_13, I8_14, I8_15)
#define _mm_setr_epi16(I16_7, I16_6, I16_5, I16_4, I16_3, I16_2, I16_1, I16_0) \
_mm_set_epi16(I16_0, I16_1, I16_2, I16_3, I16_4, I16_5, I16_6, I16_7)
#define _mm_setr_epi32(I32_3, I32_2, I32_1, I32_0) \
_mm_set_epi32(I32_0, I32_1, I32_2, I32_3)
#define _mm_setr_epi64x(I64_1, I64_0) _mm_set_epi64x(I64_0, I64_1)
#define _mm_set1_epi8(I8) \
_mm_set_epi8(I8, I8, I8, I8, I8, I8, I8, I8, I8, I8, I8, I8, I8, I8, I8, I8)
#define _mm_set1_epi16(I16) \
_mm_set_epi16(I16, I16, I16, I16, I16, I16, I16, I16)
#define _mm_set1_epi32(I32) _mm_set_epi32(I32, I32, I32, I32)
#define _mm_set1_epi64x(I64) _mm_set_epi64x(I64, I64)
#define _mm_cvtsi128_si32(M128I) ((__v4si)(M128I))[0]
#define _mm_cvtsi32_si128(I32) ((__m128i)(__v4si){(I32), 0, 0, 0})
#define _mm_setzero_si128() ((__m128i)(__v2di){0LL, 0LL})
#define _mm_castsi128_ps(M128I) ((__m128)(M128I))
#define _mm_castps_si128(M128) ((__m128i)(M128))
#define _mm_load_si128(M128I) (*(M128I))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse2 » simd ops
*/
#define _mm_and_si128(M128I_0, M128I_1) \
((__m128i)((__v2du)(M128I_0) & (__v2du)(M128I_1)))
#define _mm_or_si128(M128I_0, M128I_1) \
((__m128i)((__v2du)(M128I_0) | (__v2du)(M128I_1)))
#define _mm_xor_si128(M128I_0, M128I_1) \
((__m128i)((__v2du)(M128I_0) ^ (__v2du)(M128I_1)))
#define _mm_andnot_si128(M128I_0, M128I_1) \
((__m128i)(~(__v2du)(M128I_0) & (__v2du)(M128I_1)))
#define _mm_add_pd(M128D_0, M128D_1) \
(__m128d)((__v2df)(M128D_0) + (__v2df)(M128D_1))
#define _mm_sub_pd(M128D_0, M128D_1) \
(__m128d)((__v2df)(M128D_0) - (__v2df)(M128D_1))
#define _mm_mul_pd(M128D_0, M128D_1) \
(__m128d)((__v2df)(M128D_0) * (__v2df)(M128D_1))
#define _mm_div_pd(M128D_0, M128D_1) \
(__m128d)((__v2df)(M128D_0) / (__v2df)(M128D_1))
#define _mm_and_pd(M128D_0, M128D_1) \
(__m128d)((__v2df)(M128D_0) & (__v2df)(M128D_1))
#define _mm_or_pd(M128D_0, M128D_1) \
(__m128d)((__v2df)(M128D_0) | (__v2df)(M128D_1))
#define _mm_xor_pd(M128D_0, M128D_1) \
(__m128d)((__v2df)(M128D_0) ^ (__v2df)(M128D_1))
#define _mm_andnot_pd(M128D_0, M128D_1) \
(__m128d)(~(__v2df)(M128D_0) & (__v2df)(M128D_1))
#define _mm_sqrt_pd(M128D) __builtin_ia32_sqrtpd((__v2df)(M128D))
#define _mm_min_pd(M128D_0, M128D_1) \
__builtin_ia32_minpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_max_pd(M128D_0, M128D_1) \
__builtin_ia32_maxpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpeq_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpeqpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpneq_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpneqpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmplt_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpltpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpnlt_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpnltpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmple_pd(M128D_0, M128D_1) \
__builtin_ia32_cmplepd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpnle_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpnlepd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpgt_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpltpd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpngt_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpnltpd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpge_pd(M128D_0, M128D_1) \
__builtin_ia32_cmplepd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpnge_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpnlepd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpord_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpordpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpunord_pd(M128D_0, M128D_1) \
__builtin_ia32_cmpunordpd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_sad_epu8(M128I_0, M128I_1) \
__builtin_ia32_psadbw128((__v16qi)(M128I_0), (__v16qi)(M128I_1))
#define _mm_subs_epi8(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_psubsb128((__v16qi)(M128I_0), (__v16qi)(M128I_1)))
#define _mm_subs_epu8(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_psubusw128((__v16qi)(M128I_0), (__v16qi)(M128I_1)))
#define _mm_subs_epi16(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_psubsw128((__v8hi)(M128I_0), (__v8hi)(M128I_1)))
#define _mm_subs_epu16(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_psubusw128((__v8hi)(M128I_0), (__v8hi)(M128I_1)))
#define _mm_add_epi32(M128I_0, M128I_1) \
((__m128i)((__v4su)(M128I_0) + (__v4su)(M128I_1)))
#define _mm_sub_epi32(M128I_0, M128I_1) \
((__m128i)((__v4su)(M128I_0) - (__v4su)(M128I_1)))
#define _mm_madd_epi16(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_pmaddwd128((__v8hi)(M128I_0), (__v8hi)(M128I_1)))
#define _mm_shuffle_epi32(V, IMM) \
((__m128i)__builtin_ia32_pshufd((__v4si)(__m128i)(V), (int)(IMM)))
#define _mm_slli_epi32(M128I, COUNT) \
((__m128i)__builtin_ia32_pslldi128((__v4si)(M128I), (COUNT)))
#define _mm_slli_si128(M128I, IMM) \
((__m128i)__builtin_ia32_pslldqi128((__v2di)(__m128i)(M128I), (int)(IMM)*8))
#define _mm_srli_si128(M128I, IMM) \
((__m128i)__builtin_ia32_psrldqi128((__v2di)(__m128i)(M128I), (int)(IMM)*8))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse2 » scalar ops
*/
#define _mm_sqrt_sd(M128D_0, M128D_1) \
({ \
__m128d M128d2 = __builtin_ia32_sqrtsd((__v2df)(M128D_1)); \
(__m128d){M128d2[0], (M128D_0)[1]}; \
})
#define _mm_add_sd(M128D_0, M128D_1) \
PROGN((M128D_0)[0] += (M128D_1)[0], (M128D_0))
#define _mm_sub_sd(M128D_0, M128D_1) \
PROGN((M128D_0)[0] -= (M128D_1)[0], (M128D_0))
#define _mm_mul_sd(M128D_0, M128D_1) \
PROGN((M128D_0)[0] *= (M128D_1)[0], (M128D_0))
#define _mm_div_sd(M128D_0, M128D_1) \
PROGN((M128D_0)[0] /= (M128D_1)[0], (M128D_0))
#define _mm_min_sd(M128D_0, M128D_1) \
__builtin_ia32_minsd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_max_sd(M128D_0, M128D_1) \
__builtin_ia32_maxsd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpeq_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpeqsd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpneq_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpneqsd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmplt_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpltsd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpnlt_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpnltsd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmple_sd(M128D_0, M128D_1) \
__builtin_ia32_cmplesd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpnle_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpnlesd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpgt_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpltsd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpngt_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpnltsd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpge_sd(M128D_0, M128D_1) \
__builtin_ia32_cmplesd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpnge_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpnlesd((__v2df)(M128D_1), (__v2df)(M128D_0))
#define _mm_cmpord_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpordsd((__v2df)(M128D_0), (__v2df)(M128D_1))
#define _mm_cmpunord_sd(M128D_0, M128D_1) \
__builtin_ia32_cmpunordsd((__v2df)(M128D_0), (__v2df)(M128D_1))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse2 » miscellaneous
*/
#define _mm_pause() asm("rep nop")
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_EMMINTRIN_H_ */

21
libc/bits/emptytonull.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
const char *emptytonull(const char *s) { return s && !*s ? 0 : s; }

26
libc/bits/firstnonnull.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/runtime/runtime.h"
const char *(firstnonnull)(const char *a, const char *b) {
if (a) return a;
if (b) return b;
abort();
}

30
libc/bits/gray.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
uint32_t gray(uint32_t x) { return x ^ (x >> 1); }
uint32_t ungray(uint32_t x) {
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x ^= x >> 2;
x ^= x >> 1;
return x;
}

24
libc/bits/hamming.c Normal file
View file

@ -0,0 +1,24 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
unsigned long(hamming)(unsigned long x, unsigned long y) {
return popcount(x ^ y);
}

75
libc/bits/hilbert.c Normal file
View file

@ -0,0 +1,75 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/hilbert.h"
static axdx_t RotateQuadrant(long n, long y, long x, long ry, long rx) {
long t;
if (ry == 0) {
if (rx == 1) {
y = n - 1 - y;
x = n - 1 - x;
}
t = x;
x = y;
y = t;
}
return (axdx_t){y, x};
}
/**
* Generates Hilbert space-filling curve.
*
* @see morton()
*/
long hilbert(long n, long y, long x) {
axdx_t m;
long d, s, ry, rx;
d = 0;
for (s = n / 2; s > 0; s /= 2) {
rx = (x & s) > 0;
ry = (y & s) > 0;
d += s * s * ((3 * rx) ^ ry);
m = RotateQuadrant(n, y, x, ry, rx);
x = m.dx;
y = m.ax;
}
return d;
}
/**
* Decodes Hilbert space-filling curve.
*
* @see unmorton()
*/
axdx_t unhilbert(long n, long i) {
axdx_t m;
long s, t, y, x, ry, rx;
t = i;
x = y = 0;
for (s = 1; s < n; s *= 2) {
rx = (t / 2) & 1;
ry = (t ^ rx) & 1;
m = RotateQuadrant(s, y, x, ry, rx);
x = m.dx + s * rx;
y = m.ax + s * ry;
t /= 4;
}
return (axdx_t){y, x};
}

11
libc/bits/hilbert.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef COSMOPOLITAN_LIBC_BITS_HILBERT_H_
#define COSMOPOLITAN_LIBC_BITS_HILBERT_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
long hilbert(long, long, long) pureconst;
axdx_t unhilbert(long, long) pureconst;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_HILBERT_H_ */

48
libc/bits/i2bcd.S Normal file
View file

@ -0,0 +1,48 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
/ Converts integer to binary-coded decimal.
i2bcd: .leafprologue
.profilable
test %rdi,%rdi
je 2f
mov %rdi,%rsi
xor %r9d,%r9d
mov $0xcccccccccccccccd,%r8
xor %ecx,%ecx
1: mov %rsi,%rax
mul %r8
shr $3,%rdx
lea (%rdx,%rdx),%rax
lea (%rax,%rax,4),%rax
mov %rsi,%rdi
sub %rax,%rdi
shl %cl,%rdi
add %rdi,%r9
add $4,%rcx
cmp $9,%rsi
mov %rdx,%rsi
ja 1b
jmp 3f
2: xor %r9d,%r9d
3: mov %r9,%rax
.leafepilogue
.endfn i2bcd,globl

21
libc/bits/isempty.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
bool isempty(const char *s) { return !s || !*s; }

22
libc/bits/max.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
long(max)(long x, long y) { return MAX(x, y); }

22
libc/bits/min.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
long(min)(long x, long y) { return MIN(x, y); }

14
libc/bits/mmintrin.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_BITS_MMINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_MMINTRIN_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef long long __m64 _Vector_size(8);
typedef float __v2sf _Vector_size(8);
typedef int __v2si _Vector_size(8);
typedef short __v4hi _Vector_size(8);
typedef char __v8qi _Vector_size(8);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_MMINTRIN_H_ */

37
libc/bits/morton.c Normal file
View file

@ -0,0 +1,37 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/morton.h"
/**
* Interleaves bits.
*/
unsigned long(morton)(unsigned long y, unsigned long x) {
x = (x | x << 020) & 0x0000FFFF0000FFFF;
x = (x | x << 010) & 0x00FF00FF00FF00FF;
x = (x | x << 004) & 0x0F0F0F0F0F0F0F0F;
x = (x | x << 002) & 0x3333333333333333;
x = (x | x << 001) & 0x5555555555555555;
y = (y | y << 020) & 0x0000FFFF0000FFFF;
y = (y | y << 010) & 0x00FF00FF00FF00FF;
y = (y | y << 004) & 0x0F0F0F0F0F0F0F0F;
y = (y | y << 002) & 0x3333333333333333;
y = (y | y << 001) & 0x5555555555555555;
return x | y << 1;
}

25
libc/bits/morton.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_LIBC_BITS_MORTON_H_
#define COSMOPOLITAN_LIBC_BITS_MORTON_H_
#include "libc/intrin/pdep.h"
#include "libc/intrin/pext.h"
#include "libc/nexgen32e/x86feature.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
unsigned long morton(unsigned long, unsigned long) libcesque pureconst;
axdx_t unmorton(unsigned long) libcesque pureconst;
#ifndef __STRICT_ANSI__
#define morton(Y, X) \
(X86_NEED(BMI2) \
? pdep(X, 0x5555555555555555ul) | pdep(Y, 0xAAAAAAAAAAAAAAAAul) \
: morton(Y, X))
#define unmorton(I) \
(X86_NEED(BMI2) ? (axdx_t){pext(I, 0xAAAAAAAAAAAAAAAAul), \
pext(I, 0x5555555555555555ul)} \
: unmorton(I))
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_MORTON_H_ */

21
libc/bits/nulltoempty.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
const char *nulltoempty(const char *s) { return s ? s : ""; }

14
libc/bits/pmmintrin.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_BITS_PMMINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_PMMINTRIN_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse3
*/
#define _mm_hadd_ps(M128_0, M128_1) \
((__m128)__builtin_ia32_haddps((__v4sf)(__m128)(M128_0), \
(__v4sf)(__m128)(M128_0)))
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_PMMINTRIN_H_ */

42
libc/bits/popcount.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/nexgen32e/x86feature.h"
static noinline uint32_t popcount$swar32(uint32_t x) {
x -= (x >> 1) & 0x55555555;
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
return (((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
unsigned long(popcount)(unsigned long x) {
size_t i;
unsigned long r;
if (X86_HAVE(POPCNT)) {
return popcount$nehalem(x);
} else {
r = 0;
for (i = 0; i < sizeof(x); i += 4) {
r |= popcount$swar32(x);
x >>= 32;
}
return r;
}
}

15
libc/bits/progn.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef COSMOPOLITAN_LIBC_BITS_PROGN_H_
#define COSMOPOLITAN_LIBC_BITS_PROGN_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* Evaluates args, returning value of last one.
*
* This API comes from LISP.
*/
#define PROGN(...) ({ __VA_ARGS__; })
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_PROGN_H_ */

53
libc/bits/pushpop.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef COSMOPOLITAN_LIBC_BITS_PUSHPOP_H_
#define COSMOPOLITAN_LIBC_BITS_PUSHPOP_H_
#include "libc/macros.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* PushPop
* An elegant weapon for a more civilized age.
*/
#if !defined(__GNUC__) || defined(__STRICT_ANSI__)
#define pushpop(x) (x)
#else
#define pushpop(x) \
({ \
typeof(x) Popped; \
if (isconstant(x) && (TYPE_SIGNED(typeof(x)) ? (intptr_t)(x) + 128 < 256 \
: (intptr_t)(x) < 128)) { \
if (x) { \
asm("push\t%1\n\t" \
"pop\t%q0" \
: "=r"(Popped) \
: "ir"(x)); \
} else { \
asm("xor\t%k0,%k0" : "=r"(Popped)); \
} \
} else { \
asm("" : "=r"(Popped) : "0"(x)); \
} \
Popped; \
})
#endif
#if !defined(__GNUC__) || defined(__STRICT_ANSI__)
#define pushmov(d, x) ((d) = (x))
#else
#define pushmov(d, x) \
({ \
typeof(*(d)) Popped = (x); \
if (isconstant(x) && (TYPE_SIGNED(typeof(x)) ? (intptr_t)(x) + 128 < 256 \
: (intptr_t)(x) < 128)) { \
asm("pushq\t%1\n\t" \
"popq\t%0" \
: "=m"(*(d)) \
: "ir"(Popped)); \
} else { \
*(d) = Popped; \
} \
Popped; \
})
#endif
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_PUSHPOP_H_ */

22
libc/bits/rounddown.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
long(rounddown)(long w, long k) { return ROUNDDOWN(w, k); }

31
libc/bits/rounddown2pow.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/nexgen32e/bsr.h"
/**
* Returns 𝑥 rounded down to previous two power.
*
* @define (𝑥>02^log𝑥, x=00, 𝑇)
* @see roundup2pow()
*/
unsigned long rounddown2pow(unsigned long x) {
return x ? 1ul << bsrl(x) : 0;
}

22
libc/bits/roundup.c Normal file
View file

@ -0,0 +1,22 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
long(roundup)(long w, long k) { return ROUNDUP(w, k); }

29
libc/bits/roundup2log.c Normal file
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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/nexgen32e/bsr.h"
/**
* Returns 𝑥 rounded up to next two power and log'd.
* @see roundup2pow
*/
unsigned long roundup2log(unsigned long x) {
return x > 1 ? (bsrl(x - 1) + 1) : x ? 1 : 0;
}

31
libc/bits/roundup2pow.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 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/nexgen32e/bsr.h"
/**
* Returns 𝑥 rounded up to next two power.
*
* @define (𝑥>02^logx, x=00, 𝑇)
* @see rounddown2pow)()
*/
unsigned long roundup2pow(unsigned long x) {
return x > 1 ? 1ul << (bsrl(x - 1) + 1) : x ? 1 : 0;
}

86
libc/bits/safemacros.h Normal file
View file

@ -0,0 +1,86 @@
#ifndef COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_
#define COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
long min(long x, long y);
long max(long x, long y);
long roundup(long w, long k);
long rounddown(long w, long k);
bool isempty(const char *s);
const char *nulltoempty(const char *s);
const char *emptytonull(const char *s);
const char *firstnonnull(const char *a, const char *b);
uint64_t(unsignedsubtract)(uint64_t x, uint64_t y) pureconst;
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
#define min(x, y) \
({ \
autotype(x) MinX = (x); \
autotype(y) MinY = (y); \
MinX < MinY ? MinX : MinY; \
})
#define max(x, y) \
({ \
autotype(x) MaxX = (x); \
autotype(y) MaxY = (y); \
MaxX > MaxY ? MaxX : MaxY; \
})
#define roundup(x, k) \
({ \
autotype(x) RoundupX = (x); \
autotype(k) RoundupK = (k); \
ROUNDUP(RoundupX, RoundupK); \
})
#define rounddown(x, k) \
({ \
autotype(x) RounddownX = (x); \
autotype(k) RounddownK = (k); \
ROUNDDOWN(RounddownX, RounddownK); \
})
#define isempty(s) \
({ \
autotype(s) IsEmptyS = (s); \
!IsEmptyS || !(*IsEmptyS); \
})
#define nulltoempty(s) \
({ \
autotype(s) NullToEmptyS = (s); \
NullToEmptyS ? NullToEmptyS : ""; \
})
#define firstnonnull(a, b) \
({ \
autotype(a) FirstNonNullA = (a); \
autotype(a) FirstNonNullB = (b); \
if (!FirstNonNullA && !FirstNonNullB) abort(); \
FirstNonNullA ? FirstNonNullA : FirstNonNullB; \
})
#define emptytonull(s) \
({ \
autotype(s) EmptyToNullS = (s); \
EmptyToNullS && !(*EmptyToNullS) ? NULL : EmptyToNullS; \
})
#define unsignedsubtract(a, b) \
({ \
uint64_t UnsubA = (a); \
uint64_t UnsubB = (b); \
UnsubA >= UnsubB ? UnsubA - UnsubB : ~UnsubB + UnsubA + 1; \
})
#endif /* GNU && !ANSI */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_ */

37
libc/bits/shaintrin.h Normal file
View file

@ -0,0 +1,37 @@
#ifndef COSMOPOLITAN_LIBC_BITS_SHAINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_SHAINTRIN_H_
#include "libc/bits/emmintrin.h"
#include "libc/bits/xmmintrin.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define _mm_sha1rnds4_epu32(M128I_0, M128I_1, MEM) \
__builtin_ia32_sha1rnds4((__v4si)(__m128i)(M128I_0), \
(__v4si)(__m128i)(M128I_1), (MEM))
#define _mm_sha1nexte_epu32(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_sha1nexte((__v4si)(__m128i)(M128I_0), \
(__v4si)(__m128i)(M128I_1)))
#define _mm_sha1msg1_epu32(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_sha1msg1((__v4si)(__m128i)(M128I_0), \
(__v4si)(__m128i)(M128I_1)))
#define _mm_sha1msg2_epu32(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_sha1msg2((__v4si)(__m128i)(M128I_0), \
(__v4si)(__m128i)(M128I_1)))
#define _mm_sha256rnds2_epu32(M128I_0, M128I_1, M128I_2) \
((__m128i)__builtin_ia32_sha256rnds2((__v4si)(__m128i)(M128I_0), \
(__v4si)(__m128i)(M128I_1), \
(__v4si)(__m128i)(M128I_2)))
#define _mm_sha256msg1_epu32(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_sha256msg1((__v4si)(__m128i)(M128I_0), \
(__v4si)(__m128i)(M128I_1)))
#define _mm_sha256msg2_epu32(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_sha256msg2((__v4si)(__m128i)(M128I_0), \
(__v4si)(__m128i)(M128I_1)))
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_SHAINTRIN_H_ */

31
libc/bits/smmintrin.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef COSMOPOLITAN_LIBC_BITS_SMMINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_SMMINTRIN_H_
/**
* @fileoverview SSE4 intrinsics.
*/
#define _MM_FROUND_CEIL (_MM_FROUND_TO_POS_INF | _MM_FROUND_RAISE_EXC)
#define _MM_FROUND_CUR_DIRECTION 4
#define _MM_FROUND_FLOOR (_MM_FROUND_TO_NEG_INF | _MM_FROUND_RAISE_EXC)
#define _MM_FROUND_NEARBYINT (_MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC)
#define _MM_FROUND_NINT (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_RAISE_EXC)
#define _MM_FROUND_NO_EXC 8
#define _MM_FROUND_RAISE_EXC 0
#define _MM_FROUND_RINT (_MM_FROUND_CUR_DIRECTION | _MM_FROUND_RAISE_EXC)
#define _MM_FROUND_TO_NEAREST_INT 0
#define _MM_FROUND_TO_NEG_INF 1
#define _MM_FROUND_TO_POS_INF 2
#define _MM_FROUND_TO_ZERO 3
#define _MM_FROUND_TRUNC (_MM_FROUND_TO_ZERO | _MM_FROUND_RAISE_EXC)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define _mm_extract_epi32(M128I, I32) \
((int)__builtin_ia32_vec_ext_v4si((__v4si)(__m128i)(M128I), (int)(I32)))
#define _mm_minpos_epu16(M128I) \
((int)__builtin_ia32_phminposuw128((__v4si)(__m128i)(M128I), (int)(I32)))
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_SMMINTRIN_H_ */

17
libc/bits/tmmintrin.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef COSMOPOLITAN_LIBC_BITS_TMMINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_TMMINTRIN_H_
#include "libc/bits/emmintrin.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § ssse3
*/
#define _mm_maddubs_epi16(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_pmaddubsw128((__v16qi)(M128I_0), (__v16qi)(M128I_1)))
#define _mm_shuffle_epi8(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_pshufb128((__v16qi)(M128I_0), (__v16qi)(M128I_1)))
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_TMMINTRIN_H_ */

14
libc/bits/typecheck.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_BITS_TYPECHECK_H_
#define COSMOPOLITAN_LIBC_BITS_TYPECHECK_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define TYPECHECK(T, X) \
({ \
T Lol1; \
typeof(X) Lol2; \
(void)(&Lol1 == &Lol2); \
X; \
})
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_TYPECHECK_H_ */

41
libc/bits/unmorton.c Normal file
View file

@ -0,0 +1,41 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/morton.h"
static unsigned long GetOddBits(unsigned long x) {
x = (x | x >> 000) & 0x5555555555555555;
x = (x | x >> 001) & 0x3333333333333333;
x = (x | x >> 002) & 0x0F0F0F0F0F0F0F0F;
x = (x | x >> 004) & 0x00FF00FF00FF00FF;
x = (x | x >> 010) & 0x0000FFFF0000FFFF;
x = (x | x >> 020) & 0x00000000FFFFFFFF;
return x;
}
/**
* Deinterleaves bits.
*
* @param 𝑖 is interleaved index
* @return deinterleaved coordinate {ax := 𝑦, dx := 𝑥}
* @see en.wikipedia.org/wiki/Z-order_curve
*/
axdx_t(unmorton)(unsigned long i) {
return (axdx_t){GetOddBits(i >> 1), GetOddBits(i)};
}

View file

@ -0,0 +1,27 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
/**
* Subtracts unsigned integers w/ wraparound.
*/
uint64_t(unsignedsubtract)(uint64_t x, uint64_t y) {
return unsignedsubtract(x, y);
}

29
libc/bits/wmmintrin.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef COSMOPOLITAN_LIBC_BITS_WMMINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_WMMINTRIN_H_
#include "libc/bits/emmintrin.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define _mm_clmulepi64_si128(X, Y, IMM) \
((__m128i)__builtin_ia32_pclmulqdq128((__v2di)(__m128i)(X), \
(__v2di)(__m128i)(Y), (char)(IMM)))
#define _mm_aesenc_si128(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_aesenc128((__v2di)(M128I_0), (__v2di)(M128I_1)))
#define _mm_aesenclast_si128(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_aesenclast128((__v2di)(M128I_0), (__v2di)(M128I_1)))
#define _mm_aesdec_si128(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_aesdec128((__v2di)(M128I_0), (__v2di)(M128I_1)))
#define _mm_aesdeclast_si128(M128I_0, M128I_1) \
((__m128i)__builtin_ia32_aesdeclast128((__v2di)(M128I_0), (__v2di)(M128I_1)))
#define _mm_aesimc_si128(M128I) \
((__m128i)__builtin_ia32_aesimc128((__v2di)(M128I)))
#define _mm_aesimclast_si128(M128I) \
((__m128i)__builtin_ia32_aesimclast128((__v2di)(M128I)))
#define _mm_aeskeygenassist_si128(X, Y) \
((__m128i)__builtin_ia32_aeskeygenassist128((__v2di)(__m128i)(X), (int)(Y)))
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_WMMINTRIN_H_ */

25
libc/bits/xchg.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_LIBC_BITS_XCHG_H_
#define COSMOPOLITAN_LIBC_BITS_XCHG_H_
#include "libc/str/str.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/**
* Exchanges *MEMORY into *LOCALVAR.
*
* @return *MEMORY
* @see lockcmpxchg()
* todo(jart): what's the point of this?
*/
#define xchg(MEMORY, LOCALVAR) \
({ \
autotype(MEMORY) Memory = (MEMORY); \
typeof(Memory) LocalVar = (LOCALVAR); \
typeof(*Memory) Temp; \
memcpy(&Temp, Memory, sizeof(Temp)); \
memcpy(Memory, LocalVar, sizeof(Temp)); \
memcpy(LocalVar, &Temp, sizeof(Temp)); \
Temp; \
})
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_XCHG_H_ */

233
libc/bits/xmmintrin.h Normal file
View file

@ -0,0 +1,233 @@
#ifndef COSMOPOLITAN_LIBC_BITS_XMMINTRIN_H_
#define COSMOPOLITAN_LIBC_BITS_XMMINTRIN_H_
#include "libc/bits/emmintrin.h"
#include "libc/bits/mmintrin.h"
#include "libc/bits/progn.h"
#include "libc/dce.h"
#define _MM_EXCEPT_MASK 0x003f
#define _MM_EXCEPT_INVALID 0x0001
#define _MM_EXCEPT_DENORM 0x0002
#define _MM_EXCEPT_DIV_ZERO 0x0004
#define _MM_EXCEPT_OVERFLOW 0x0008
#define _MM_EXCEPT_UNDERFLOW 0x0010
#define _MM_EXCEPT_INEXACT 0x0020
#define _MM_MASK_MASK 0x1f80
#define _MM_MASK_INVALID 0x0080
#define _MM_MASK_DENORM 0x0100
#define _MM_MASK_DIV_ZERO 0x0200
#define _MM_MASK_OVERFLOW 0x0400
#define _MM_MASK_UNDERFLOW 0x0800
#define _MM_MASK_INEXACT 0x1000
#define _MM_ROUND_MASK 0x6000
#define _MM_ROUND_NEAREST 0x0000
#define _MM_ROUND_DOWN 0x2000
#define _MM_ROUND_UP 0x4000
#define _MM_ROUND_TOWARD_ZERO 0x6000
#define _MM_FLUSH_ZERO_MASK 0x8000
#define _MM_FLUSH_ZERO_ON 0x8000
#define _MM_FLUSH_ZERO_OFF 0x0000
#define _MM_SHUFFLE(A, B, C, D) (((A) << 6) | ((B) << 4) | ((C) << 2) | (D))
#if !(__ASSEMBLER__ + __LINKER__ + 0)
typedef int __v4si _Vector_size(16);
typedef unsigned int __v4su _Vector_size(16);
typedef float __v4sf _Vector_size(16);
typedef float __m128 _Vector_size(16) aligned(16) mayalias;
typedef float __m128_u _Vector_size(16) aligned(1) mayalias;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse » simd ops
*/
#define _mm_add_ps(M128_0, M128_1) \
((__m128)((__v4sf)(M128_0) + (__v4sf)(M128_1)))
#define _mm_sub_ps(M128_0, M128_1) \
((__m128)((__v4sf)(M128_0) - (__v4sf)(M128_1)))
#define _mm_mul_ps(M128_0, M128_1) \
((__m128)((__v4sf)(M128_0) * (__v4sf)(M128_1)))
#define _mm_div_ps(M128_0, M128_1) \
((__m128)((__v4sf)(M128_0) / (__v4sf)(M128_1)))
#define _mm_and_ps(M128_0, M128_1) \
((__m128)((__v4su)(M128_0) & (__v4su)(M128_1)))
#define _mm_or_ps(M128_0, M128_1) \
((__m128)((__v4su)(M128_0) | (__v4su)(M128_1)))
#define _mm_xor_ps(M128_0, M128_1) /* XORPD [u32 simd xor] */ \
((__m128)((__v4su)(M128_0) ^ (__v4su)(M128_1)))
#define _mm_andnot_ps(M128_0, M128_1) /* ANDNPS [u32 simd nand] */ \
((__m128)(~(__v4su)(M128_0) & (__v4su)(M128_1)))
#define _mm_rcp_ps(M128) __builtin_ia32_rcpps((__v4sf)(M128))
#define _mm_sqrt_ps(M128) __builtin_ia32_sqrtps((__v4sf)(M128))
#define _mm_rsqrt_ps(M128) __builtin_ia32_rsqrtps((__v4sf)(M128))
#define _mm_min_ps(M128_0, M128_1) \
__builtin_ia32_minps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_max_ps(M128_0, M128_1) \
__builtin_ia32_maxps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_min_ss(M128_0, M128_1) \
__builtin_ia32_minss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_max_ss(M128_0, M128_1) \
__builtin_ia32_maxss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpeq_ps(M128_0, M128_1) \
__builtin_ia32_cmpeqps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpneq_ps(M128_0, M128_1) \
__builtin_ia32_cmpneqps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmplt_ps(M128_0, M128_1) \
__builtin_ia32_cmpltps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpnlt_ps(M128_0, M128_1) \
__builtin_ia32_cmpnltps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmple_ps(M128_0, M128_1) \
__builtin_ia32_cmpleps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpnle_ps(M128_0, M128_1) \
__builtin_ia32_cmpnleps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpgt_ps(M128_0, M128_1) \
__builtin_ia32_cmpltps((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpngt_ps(M128_0, M128_1) \
__builtin_ia32_cmpnltps((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpge_ps(M128_0, M128_1) \
__builtin_ia32_cmpleps((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpnge_ps(M128_0, M128_1) \
__builtin_ia32_cmpnleps((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpord_ps(M128_0, M128_1) \
__builtin_ia32_cmpordps((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpunord_ps(M128_0, M128_1) \
__builtin_ia32_cmpunordps((__v4sf)(M128_0), (__v4sf)(M128_1))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse » scalar ops
*/
forceinline __m128 _mm_add_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] += m128_1[0];
return m128_0;
}
forceinline __m128 _mm_sub_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] -= m128_1[0];
return m128_0;
}
forceinline __m128 _mm_mul_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] *= m128_1[0];
return m128_0;
}
forceinline __m128 _mm_div_ss(__m128 m128_0, __m128 m128_1) {
m128_0[0] /= m128_1[0];
return m128_0;
}
#define _mm_rcp_ss(M128) __builtin_ia32_rcpss((__v4sf)(M128)) /*~1/x*/
#define _mm_sqrt_ss(M128) __builtin_ia32_sqrtss((__v4sf)(M128)) /*sqrt𝑥*/
#define _mm_rsqrt_ss(M128) __builtin_ia32_rsqrtss((__v4sf)(M128)) /*~1/sqrt𝑥*/
#define _mm_min_ss(M128_0, M128_1) \
__builtin_ia32_minss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_max_ss(M128_0, M128_1) \
__builtin_ia32_maxss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpeq_ss(M128_0, M128_1) \
__builtin_ia32_cmpeqss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpneq_ss(M128_0, M128_1) \
__builtin_ia32_cmpneqss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmplt_ss(M128_0, M128_1) \
__builtin_ia32_cmpltss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpnlt_ss(M128_0, M128_1) \
__builtin_ia32_cmpnltss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmple_ss(M128_0, M128_1) \
__builtin_ia32_cmpless((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpnle_ss(M128_0, M128_1) \
__builtin_ia32_cmpnless((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpgt_ss(M128_0, M128_1) \
__builtin_ia32_cmpltss((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpngt_ss(M128_0, M128_1) \
__builtin_ia32_cmpnltss((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpge_ss(M128_0, M128_1) \
__builtin_ia32_cmpless((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpnge_ss(M128_0, M128_1) \
__builtin_ia32_cmpnless((__v4sf)(M128_1), (__v4sf)(M128_0))
#define _mm_cmpord_ss(M128_0, M128_1) \
__builtin_ia32_cmpordss((__v4sf)(M128_0), (__v4sf)(M128_1))
#define _mm_cmpunord_ss(M128_0, M128_1) \
__builtin_ia32_cmpunordss((__v4sf)(M128_0), (__v4sf)(M128_1))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse » memory ops
*/
#define _mm_set1_ps(M128_0) ((__m128)(__v4sf){M128_0, M128_0, M128_0, M128_0})
#define _mm_setzero_ps() ((__m128)(__v4sf){0})
#define _mm_cvtss_f32(M128_0) (((__v4sf)(M128_0))[0])
#define _mm_load_ps(FLOATPTR) (*(__m128 *)(FLOATPTR))
#define _mm_loadu_ps(FLOATPTR) (*(__m128_u *)(FLOATPTR))
#define _mm_set_ps(WHO, DESIGNED, THIS, SHEESH) \
((__m128)(__v4sf){SHEESH, THIS, DESIGNED, WHO})
#define _mm_set_ss(FLOAT) ((__m128)(__v4sf){FLOAT, 0, 0, 0})
#define _mm_load_ss(FLOATPTR) _mm_set_ss(*(FLOATPTR))
#define _mm_store_ss(FLOATPTR, M128_0) ((FLOATPTR)[0] = ((__v4sf)(M128_0))[0])
#define _mm_store_ps(FLOATPTR, M128_0) (*(__m128 *)(FLOATPTR) = (M128_0))
#define _mm_storeu_ps(FLOATPTR, M128_0) (*(__m128_u *)(FLOATPTR) = (M128_0))
#define _mm_shuffle_ps(M128_0, M128_1, MASK) \
((__m128)__builtin_ia32_shufps((__v4sf)(M128_0), (__v4sf)(M128_1), (MASK)))
#ifdef __llvm__
#define _mm_movehl_ps(M128_0, M128_1) \
((__m128)__builtin_shufflevector((__v4sf)(__m128)(M128_0), \
(__v4sf)(__m128)(M128_1), 6, 7, 2, 3))
/* instrinsics unstable & constantly breaking, consider ansi c or asm. */
/* each version of llvm has a different incompatible impl for this one */
#else
#define _mm_movehl_ps(M128_0, M128_1) \
((__m128)__builtin_ia32_movhlps((__v4sf)(__m128)(M128_0), \
(__v4sf)(__m128)(M128_1)))
#define _mm_storel_pi(M64PTR, M128_0) \
__builtin_ia32_storelps((__v2sf *)(M64PTR), (__v4sf)(M128_0))
#endif
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse » cast ops
*/
#define _mm_cvtps_epi32(M128_0) \
((__m128i)__builtin_ia32_cvtps2dq((__v4sf)(M128_0)))
#ifdef __llvm__
#define _mm_cvtepi32_ps(M128I_0) \
((__m128) __builtin_convertvector((__v4si)(__m128i)(M128I_0), __v4sf))
#else
#define _mm_cvtepi32_ps(M128I_0) \
((__m128)__builtin_ia32_cvtdq2ps((__v4si)(M128I_0)))
#endif
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § sse » misc
*/
#define _mm_getcsr() (__builtin_ia32_stmxcsr())
#define _mm_setcsr(U32CONF) (__builtin_ia32_ldmxcsr(U32CONF))
#define _MM_GET_ROUNDING_MODE() (_mm_getcsr() & _MM_ROUND_MASK)
#define _MM_SET_ROUNDING_MODE(MODE) \
(_mm_setcsr((_mm_getcsr() & ~_MM_ROUND_MASK) | (MODE)))
#define XMM_DESTROY(VAR) \
do { \
if (!IsTrustworthy()) { \
asm volatile("xorps\t%1,%0" : "=x"(VAR) : "0"(VAR)); \
} \
} while (0)
/*
** Ternary:
**
** Integer: _mm_or_si128(_mm_and_si128(a, cond), _mm_andnot_si128(cond, b))
** 32-bit float: _mm_or_ps(_mm_and_ps(a, cond), _mm_andnot_ps(cond, b))
** 64-bit float: _mm_or_pd(_mm_and_pd(a, cond), _mm_andnot_pd(cond, b))
** Integer (SSE4.1+): _mm_blendv_epi8(a, b, cond)
** 32-bit float (SSE4.1+): _mm_blendv_ps(a, b, cond)
** 64-bit float (SSE4.1+): _mm_blendv_pd(a, b, cond)
*/
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BITS_XMMINTRIN_H_ */

56
libc/calls/atfork.c Normal file
View file

@ -0,0 +1,56 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/calls/internal.h"
#include "libc/macros.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
static struct AtFork {
size_t i;
struct AtForkCallback {
void (*fn)(void *);
void *arg;
} p[ATEXIT_MAX];
} g_atfork;
/**
* Registers function to be called when PID changes.
*
* @return 0 on success, or -1 w/ errno
*/
int atfork(void *fn, void *arg) {
if (g_atfork.i == ARRAYLEN(g_atfork.p)) return enomem();
g_atfork.p[g_atfork.i++] = (struct AtForkCallback){.fn = fn, .arg = arg};
return 0;
}
/**
* Triggers atfork() callbacks.
*
* Only fork() should call this.
*/
void __onfork(void) {
size_t i;
for (i = 0; i < g_atfork.i; ++i) {
g_atfork.p[i].fn(g_atfork.p[i].arg);
}
}

292
libc/calls/calls.h Normal file
View file

@ -0,0 +1,292 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SYSCALLS_H_
#define COSMOPOLITAN_LIBC_CALLS_SYSCALLS_H_
#include "libc/calls/struct/timespec.h"
#include "libc/calls/typedef/sighandler_t.h"
#include "libc/dce.h"
#include "libc/fmt/pflink.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/sig.h"
#define EOF -1 /* end of file */
#define WEOF -1u /* end of file (multibyte) */
#define _IOFBF 0 /* fully buffered */
#define _IOLBF 1 /* line buffered */
#define _IONBF 2 /* no buffering */
#define SEEK_SET 0 /* relative to beginning */
#define SEEK_CUR 1 /* relative to current position */
#define SEEK_END 2 /* relative to end */
#define SIG_ERR ((void (*)(int))(-1))
#define SIG_DFL ((void *)0)
#define SIG_IGN ((void *)1)
#define MAP_FAILED ((void *)__SIZE_MAX__)
#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 S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
#define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK)
#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)
#define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO)
#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK)
#define WCOREDUMP(s) ((s)&0x80)
#define WEXITSTATUS(s) (((s)&0xff00) >> 8)
#define WIFCONTINUED(s) ((s) == 0xffff)
#define WIFEXITED(s) (!WTERMSIG(s))
#define WIFSIGNALED(s) (((s)&0xffff) - 1U < 0xffu)
#define WIFSTOPPED(s) ((short)((((s)&0xffff) * 0x10001) >> 8) > 0x7f00)
#define WSTOPSIG(s) WEXITSTATUS(s)
#define WTERMSIG(s) ((s)&0x7f)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls
*/
struct dirstream;
struct iovec;
struct rlimit;
struct rusage;
struct sigaction;
struct siginfo;
struct sigset;
struct stat;
struct sysinfo;
struct tms;
struct ucontext;
struct utsname;
typedef int sig_atomic_t;
typedef struct dirstream DIR;
extern const struct sigset kSigsetFull;
extern const struct sigset kSigsetEmpty;
DIR *fdopendir(int) nodiscard;
DIR *opendir(const char *) nodiscard;
bool fileexists(const char *);
bool isdirectory(const char *);
bool isexecutable(const char *);
bool isregularfile(const char *);
bool32 isatty(int) nosideeffect;
bool32 ischardev(int) nosideeffect;
char *get_current_dir_name(void) nodiscard;
char *getcwd(char *, size_t) paramsnonnull();
char *realpath(const char *, char *);
char *replaceuser(const char *) nodiscard;
char *slurp(const char *, size_t *) nodiscard;
char *ttyname(int);
const char *commandv(const char *);
int access(const char *, int) nothrow paramsnonnull();
int arch_prctl();
int chdir(const char *) paramsnonnull();
int chmod(const char *, uint32_t);
int chown(const char *, uint32_t, uint32_t) paramsnonnull();
int close(int);
int closedir(DIR *);
int copyfile(const char *, const char *, bool);
int creat(const char *, uint32_t) nodiscard;
int dirfd(DIR *);
int dup(int) nodiscard;
int dup2(int, int);
int dup3(int, int, int);
int execl(const char *, const char *, ...) nullterminated();
int execle(const char *, const char *, ...) nullterminated((1));
int execlp(const char *, const char *, ...) nullterminated();
int execv(const char *, char *const[]) paramsnonnull();
int execve(const char *, char *const[], char *const[]) paramsnonnull();
int execvp(const char *, char *const[]) paramsnonnull();
int execvpe(const char *, char *const[], char *const[]) paramsnonnull();
int faccessat(int, const char *, int, uint32_t);
int fadvise(int, uint64_t, uint64_t, int);
int fallocate(int, int32_t, int64_t, int64_t);
int fchmod(int, uint32_t) nothrow;
int fchmodat(int, const char *, uint32_t, uint32_t);
int fchown(int, uint32_t, uint32_t);
int fchownat(int, const char *, uint32_t, uint32_t, uint32_t);
int fcntl();
int fdatasync(int);
int filecmp(const char *, const char *);
int flock(int, int);
int fork(void);
int fstat(int, struct stat *) paramsnonnull();
int fstatat(int, const char *, struct stat *, uint32_t);
int fsync(int);
int ftruncate(int, int64_t);
int getppid(void);
int getpriority(int, unsigned);
int getrlimit(int, struct rlimit *);
int getrusage(int, struct rusage *);
int kill(int, int);
int killpg(int, int);
int link(const char *, const char *) nothrow;
int linkat(int, const char *, int, const char *, uint32_t);
int lstat(const char *, struct stat *) paramsnonnull();
int madvise(void *, uint64_t, int);
int mkdir(const char *, uint32_t);
int mkdirat(int, const char *, uint32_t);
int mkfifo(const char *, uint32_t);
int mknod(const char *, uint32_t, uint64_t);
int mknodat(int, const char *, int32_t, uint64_t);
int mlock(const void *, size_t);
int mlock2(const void *, size_t, int);
int mlockall(int);
int mprotect(void *, uint64_t, int) paramsnonnull() privileged;
int msync(void *, size_t, int);
int munlock(const void *, size_t);
int munlockall(void);
int munmap(void *, uint64_t);
int munmap_s(void *, uint64_t);
int nice(int);
int open(const char *, int, ...) nodiscard;
int openanon(char *, unsigned) nodiscard;
int openat();
int pause(void);
int personality(uint64_t);
int pipe(int[hasatleast 2]) paramsnonnull() nodiscard;
int pipe2(int[hasatleast 2], int) paramsnonnull() nodiscard;
int posix_fadvise(int, uint64_t, uint64_t, int);
int posix_fallocate(int, int64_t, int64_t);
int posix_madvise(void *, uint64_t, int);
int raise(int);
int readlink(const char *, char *, size_t);
int remove(const char *);
int rename(const char *, const char *);
int renameat(int, const char *, int, const char *);
int renameat2(long, const char *, long, const char *, int);
int rmdir(const char *);
int sched_getaffinity(int, uint64_t, void *);
int sched_setaffinity(int, uint64_t, const void *);
int sched_yield(void);
int setpgid(int, int);
int setpriority(int, unsigned, int);
int setrlimit(int, const struct rlimit *);
int setsid(void);
int setuid(uint32_t);
int setgid(uint32_t);
int seteuid(uint32_t);
int setegid(uint32_t);
int setreuid(uint32_t, uint32_t);
int setregid(uint32_t, uint32_t);
int setresuid(uint32_t, uint32_t, uint32_t);
int setresgid(uint32_t, uint32_t, uint32_t);
int sigaction(int, const struct sigaction *, struct sigaction *);
int sigignore(int);
int sigprocmask(int, const struct sigset *, struct sigset *);
int sigsuspend(const struct sigset *);
int stat(const char *, struct stat *) paramsnonnull();
int symlink(const char *, const char *);
int symlinkat(const char *, int, const char *);
int sync_file_range(int, int64_t, int64_t, unsigned);
int sysinfo(struct sysinfo *) paramsnonnull();
int touch(const char *, uint32_t);
int truncate(const char *, uint64_t);
int ttyname_r(int, char *, size_t);
int uname(struct utsname *);
int unlink(const char *);
int unlink_s(const char **);
int unlinkat(int, const char *, int);
int vfork(void);
int wait(int *);
int wait3(int *, int, struct rusage *);
int wait4(int, int *, int, struct rusage *);
int waitpid(int, int *, int);
int64_t lseek(int, int64_t, int);
int64_t pread(int, void *, size_t, int64_t);
int64_t preadv(int, struct iovec *, int, int64_t);
int64_t pwrite(int, const void *, size_t, int64_t);
int64_t pwritev(int, const struct iovec *, int, int64_t);
int64_t syscall();
long telldir(DIR *);
int getpid(void);
long times(struct tms *);
sighandler_t signal(int, sighandler_t);
size_t GetFileSize(const char *);
size_t getfiledescriptorsize(int);
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t read(int, void *, size_t);
ssize_t readlinkat(int, const char *, char *, size_t);
ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
ssize_t vmsplice(int, const struct iovec *, int64_t, uint32_t);
ssize_t write(int, const void *, size_t);
struct dirent *readdir(DIR *);
uint32_t getegid(void) nosideeffect;
uint32_t geteuid(void) nosideeffect;
uint32_t getgid(void) nosideeffect;
uint32_t getpgrp(void) nosideeffect;
uint32_t getsid(int) nosideeffect;
uint32_t gettid(void) nosideeffect;
uint32_t getuid(void) nosideeffect;
uint32_t umask(int32_t);
void *getprocaddressmodule(const char *, const char *);
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t) vallocesque;
void *mremap(void *, uint64_t, uint64_t, int32_t, void *);
#define getcwd(BUF, SIZE) \
(isconstant(BUF) && (&(BUF)[0] == NULL) ? get_current_dir_name() \
: getcwd(BUF, SIZE))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » formatting
*/
int dprintf(int, const char *, ...) printfesque(2) paramsnonnull((2));
int vdprintf(int, const char *, va_list) paramsnonnull();
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » link-time optimizations
*/
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
void _init_onntconsoleevent(void);
void _init_onwincrash(void);
#define __SIGACTION(FN, SIG, ...) \
({ \
if (SupportsWindows()) { \
if (isconstant(SIG)) { \
switch (SIG) { \
case SIGINT: \
case SIGQUIT: \
case SIGHUP: \
case SIGTERM: \
YOINK(_init_onntconsoleevent); \
break; \
case SIGTRAP: \
case SIGILL: \
case SIGSEGV: \
case SIGABRT: \
case SIGFPE: \
YOINK(_init_onwincrash); \
break; \
default: \
break; \
} \
} else { \
YOINK(_init_onntconsoleevent); \
YOINK(_init_onwincrash); \
} \
} \
(FN)(SIG, __VA_ARGS__); \
})
#define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__)
#define sigaction(SIG, ACT, OLD) __SIGACTION(sigaction, SIG, ACT, OLD)
#define signal(SIG, HAND) __SIGACTION(signal, SIG, HAND)
#define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA)
#endif /* GNU && !ANSI */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALLS_H_ */

90
libc/calls/calls.mk Normal file
View file

@ -0,0 +1,90 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
# System Call Compatibility Layer
#
# DESCRIPTION
#
# This package exports a familiar system call interface that works
# across platforms.
PKGS += LIBC_CALLS
LIBC_CALLS_ARTIFACTS += LIBC_CALLS_A
LIBC_CALLS = $(LIBC_CALLS_A_DEPS) $(LIBC_CALLS_A)
LIBC_CALLS_A = o/$(MODE)/libc/calls/syscalls.a
LIBC_CALLS_A_FILES := \
$(wildcard libc/calls/typedef/*) \
$(wildcard libc/calls/thunks/*) \
$(wildcard libc/calls/struct/*) \
$(wildcard libc/calls/*)
LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_SRCS = \
$(LIBC_CALLS_A_SRCS_S) \
$(LIBC_CALLS_A_SRCS_C)
LIBC_CALLS_A_OBJS = \
$(LIBC_CALLS_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_CALLS_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_CALLS_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_CALLS_A_CHECKS = \
$(LIBC_CALLS_A).pkg \
$(LIBC_CALLS_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_CALLS_A_DIRECTDEPS = \
LIBC_FMT \
LIBC_STR \
LIBC_RAND \
LIBC_CONV \
LIBC_STUBS \
LIBC_NEXGEN32E \
LIBC_NT_NTDLL \
LIBC_NT_ADVAPI32 \
LIBC_NT_KERNEL32 \
LIBC_NT_KERNELBASE \
LIBC_SYSV_CALLS \
LIBC_SYSV
LIBC_CALLS_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x))))
$(LIBC_CALLS_A): \
libc/calls/ \
$(LIBC_CALLS_A).pkg \
$(LIBC_CALLS_A_OBJS)
$(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/calls/raise.o: \
OVERRIDE_COPTS += \
$(NO_MAGIC)
o/$(MODE)/libc/calls/siggy.o: \
OVERRIDE_COPTS += \
-ffunction-sections
o/$(MODE)/libc/calls/xnutrampoline.o \
o/$(MODE)/libc/calls/ntcontext2linux.o: \
OVERRIDE_COPTS += \
-O3
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
LIBC_CALLS_BINS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_BINS))
LIBC_CALLS_CHECKS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_CHECKS))
LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS))
LIBC_CALLS_TESTS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_TESTS))
.PHONY: o/$(MODE)/libc/calls
o/$(MODE)/libc/calls: \
o/$(MODE)/libc/calls/hefty \
$(LIBC_CALLS_CHECKS)

38
libc/calls/chdir-nt.c Normal file
View file

@ -0,0 +1,38 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int chdir$nt(const char *path) {
int len;
char16_t path16[PATH_MAX];
if ((len = mkntpath(path, path16)) == -1) return -1;
if (path16[len - 1] != u'/' && path16[len - 1] != u'\\') {
path16[len + 0] = u'/';
path16[len + 1] = u'\0';
}
if (SetCurrentDirectory(path16)) {
return 0;
} else {
return winerr();
}
}

34
libc/calls/chdir.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
/**
* Sets current directory.
* @asyncsignalsafe
*/
int chdir(const char *path) {
if (!IsWindows()) {
return chdir$sysv(path);
} else {
return chdir$nt(path);
}
}

49
libc/calls/chmod.c Normal file
View file

@ -0,0 +1,49 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Changes permissions on file, e.g.:
*
* CHECK_NE(-1, chmod("foo/bar.txt", 0644));
* CHECK_NE(-1, chmod("o/default/program.com", 0755));
* CHECK_NE(-1, chmod("privatefolder/", 0700));
*
* The esoteric bits generally available on System Five are:
*
* CHECK_NE(-1, chmod("/opt/", 01000)); // sticky bit
* CHECK_NE(-1, chmod("/usr/bin/sudo", 04755)); // setuid bit
* CHECK_NE(-1, chmod("/usr/bin/wall", 02755)); // setgid bit
*
* This works on Windows NT if you ignore the error ;-)
*
* @param pathname must exist
* @param mode contains octal flags (base 8)
* @errors ENOENT, ENOTDIR, ENOSYS
* @asyncsignalsafe
* @see fchmod()
*/
int chmod(const char *pathname, uint32_t mode) {
return fchmodat$sysv(AT_FDCWD, pathname, mode, 0);
}

38
libc/calls/chown.c Normal file
View file

@ -0,0 +1,38 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/sysv/consts/at.h"
/**
* Changes owner and/or group of pathname.
*
* @param uid is user id, or -1u to not change
* @param gid is group id, or -1u to not change
* @return 0 on success, or -1 w/ errno
* @see fchown() if pathname is already open()'d
* @see lchown() which does not dereference symbolic links
* @see /etc/passwd for user ids
* @see /etc/group for group ids
* @asyncsignalsafe
*/
int chown(const char *pathname, uint32_t uid, uint32_t gid) {
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, 0);
}

45
libc/calls/close-nt.c Normal file
View file

@ -0,0 +1,45 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int close$nt(int fd) {
bool32 ok;
if (isfdindex(fd)) {
if (g_fds.p[fd].kind == kFdFile) {
/*
* Like Linux, closing a file on Windows doesn't guarantee it's
* immediately synced to disk. But unlike Linux, this could cause
* subsequent operations, e.g. unlink() to break w/ access error.
*/
FlushFileBuffers(g_fds.p[fd].handle);
}
ok = CloseHandle(g_fds.p[fd].handle);
if (g_fds.p[fd].kind == kFdConsole) {
ok &= CloseHandle(g_fds.p[fd].extra);
}
removefd(fd);
return ok ? 0 : winerr();
} else {
return ebadf();
}
}

49
libc/calls/close.c Normal file
View file

@ -0,0 +1,49 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.h"
/**
* Closes file descriptor.
*
* @return 0 on success, or -1 w/ errno
* @asyncsignalsafe
*/
int close(int fd) {
int rc;
if (fd == -1) return 0;
if (isfdkind(fd, kFdZip)) {
rc = weaken(__zipos_close)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle);
} else if (!IsWindows()) {
rc = close$sysv(fd);
} else if (isfdkind(fd, kFdSocket)) {
rc = weaken(closesocket$nt)(fd);
} else {
rc = close$nt(fd);
}
removefd(fd);
return rc;
}

73
libc/calls/copyfd.c Normal file
View file

@ -0,0 +1,73 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/sysv/errfuns.h"
/**
* Copies data between file descriptors the slow way.
*
* @return -1 on error/interrupt, 0 on eof, or [1..uptobytes] on success
* @see copy_file_range() for file file
* @see sendfile() for seekable socket
* @see splice() for fd pipe
*/
ssize_t copyfd(int infd, int64_t *inopt_out_inoffset, int to_fd,
int64_t *inopt_out_outoffset, size_t uptobytes, uint32_t flags) {
size_t i;
int64_t offset;
ssize_t got, wrote;
static unsigned char buf[1024 * 64];
/* unsigned char buf[1024 * 3]; */
uptobytes = min(sizeof(buf), uptobytes);
if (inopt_out_inoffset) {
got = pread(infd, buf, uptobytes, *inopt_out_inoffset);
} else {
got = read(infd, buf, uptobytes);
}
if (got == -1) return -1;
offset = inopt_out_outoffset ? *inopt_out_outoffset : -1;
for (i = 0; i < got; i += wrote) {
tryagain:
if (inopt_out_outoffset) {
wrote = pwrite(to_fd, buf, got - i, offset + i);
} else {
wrote = write(to_fd, buf, got - i);
}
if (wrote != -1) continue;
if (errno == EINTR) {
if (inopt_out_inoffset != NULL) {
return -1;
}
goto tryagain;
}
if (errno == EWOULDBLOCK) {
assert(inopt_out_inoffset != NULL); /* or caller is nuts */
}
return -1;
}
if (inopt_out_inoffset) *inopt_out_inoffset += got;
if (inopt_out_outoffset) *inopt_out_outoffset += got;
return got;
}

64
libc/calls/copyfile.c Normal file
View file

@ -0,0 +1,64 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/nt/files.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h"
int copyfile(const char *frompath, const char *topath, bool dontoverwrite) {
if (IsWindows()) {
char16_t frompath16[PATH_MAX], topath16[PATH_MAX];
if (mkntpath(frompath, frompath16) == -1) return -1;
if (mkntpath(topath, topath16) == -1) return -1;
if (CopyFile(frompath16, topath16, dontoverwrite)) {
return 0;
} else {
return winerr();
}
} else {
struct stat st;
ssize_t transferred;
int rc, fromfd, tofd;
int64_t inoffset, outoffset;
rc = -1;
if ((fromfd = openat$sysv(AT_FDCWD, frompath, O_RDONLY, 0)) != -1) {
if (fstat$sysv(fromfd, &st) != -1 &&
(tofd = openat$sysv(AT_FDCWD, topath,
O_WRONLY | O_CREAT | (dontoverwrite ? O_EXCL : 0),
st.st_mode & 0777)) != -1) {
inoffset = 0;
outoffset = 0;
while (st.st_size && (transferred = copy_file_range(
fromfd, &inoffset, tofd, &outoffset,
st.st_size, 0)) != -1) {
st.st_size -= transferred;
}
if (!st.st_size) rc = 0;
rc |= close$sysv(tofd);
}
rc |= close$sysv(fromfd);
}
return rc;
}
}

36
libc/calls/creat.c Normal file
View file

@ -0,0 +1,36 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/sysv/consts/o.h"
/**
* Creates new file, returning open()'d file descriptor.
*
* @param file is a UTF-8 string, which is truncated if it exists
* @param mode is an octal user/group/other permission, e.g. 0755
* @return a number registered with the system to track the open file,
* which must be stored using a 64-bit type in order to support both
* System V and Windows, and must be closed later on using close()
* @see touch()
* @asyncsignalsafe
*/
nodiscard int creat(const char *file, uint32_t mode) {
return open(file, O_CREAT | O_WRONLY | O_TRUNC, mode);
}

38
libc/calls/createfd.c Normal file
View file

@ -0,0 +1,38 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/calls/internal.h"
#include "libc/mem/mem.h"
#include "libc/sysv/errfuns.h"
/**
* Finds open file descriptor slot.
*/
ssize_t createfd(void) {
size_t fd;
for (;;) {
while (g_fds.f < g_fds.n) {
if (g_fds.p[(fd = g_fds.f++)].kind == kFdEmpty) {
return fd;
}
}
if (growfds() == -1) return -1;
}
}

32
libc/calls/dprintf.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
/**
* Formats string directly to system i/o device.
*/
int(dprintf)(int fd, const char *fmt, ...) {
int rc;
va_list va;
va_start(va, fmt);
rc = (vdprintf)(fd, fmt, va);
va_end(va);
return rc;
}

54
libc/calls/dup-nt.c Normal file
View file

@ -0,0 +1,54 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
/**
* Implements dup(), dup2(), and dup3() for Windows NT.
*/
textwindows int dup$nt(int oldfd, int newfd, int flags) {
if (!isfdkind(oldfd, kFdFile)) return ebadf();
if (newfd == -1) {
if ((newfd = createfd()) == -1) return -1;
} else if (isfdindex(newfd)) {
close(newfd);
} else if (isfdlegal(newfd)) {
do {
if (growfds() == -1) return -1;
} while (newfd >= g_fds.n);
} else {
return ebadf();
}
if (DuplicateHandle(GetCurrentProcess(), g_fds.p[oldfd].handle,
GetCurrentProcess(), &g_fds.p[newfd].handle, 0,
(flags & O_CLOEXEC), kNtDuplicateSameAccess)) {
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
g_fds.p[newfd].flags = flags;
return newfd;
} else {
return winerr();
}
}

37
libc/calls/dup.c Normal file
View file

@ -0,0 +1,37 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
/**
* Duplicates file descriptor/handle.
*
* @param fd remains open afterwards
* @return some arbitrary new number for fd
* @asyncsignalsafe
*/
nodiscard int dup(int fd) {
if (!IsWindows()) {
return dup$sysv(fd);
} else {
return dup$nt(fd, -1, 0);
}
}

40
libc/calls/dup2.c Normal file
View file

@ -0,0 +1,40 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
/**
* Duplicates file descriptor, granting it specific number.
*
* @param oldfd isn't closed afterwards
* @param newfd if already assigned, is silently closed beforehand;
* unless it's equal to oldfd, in which case dup2() is a no-op
* @return new file descriptor, or -1 w/ errno
* @asyncsignalsafe
*/
int dup2(int oldfd, int newfd) {
if (oldfd == newfd) return newfd;
if (!IsWindows()) {
return dup3$sysv(oldfd, newfd, 0);
} else {
return dup$nt(oldfd, newfd, 0);
}
}

47
libc/calls/dup3-sysv.c Normal file
View file

@ -0,0 +1,47 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/errno.h"
#define __NR_dup3_linux 0x0124 /*RHEL5:CVE-2010-3301*/
int32_t dup3$sysv(int32_t oldfd, int32_t newfd, int flags) {
static bool once, demodernize;
int olderr, fd;
if (!once) {
once = true;
olderr = errno;
fd = __dup3$sysv(oldfd, newfd, flags);
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) {
demodernize = true;
errno = olderr;
goto OldSkool;
}
} else if (demodernize) {
goto OldSkool;
} else {
fd = __dup3$sysv(oldfd, newfd, flags);
}
return fd;
OldSkool:
fd = dup2$sysv(oldfd, newfd);
if (flags) fd = fixupnewfd$sysv(fd, flags);
return fd;
}

44
libc/calls/dup3.c Normal file
View file

@ -0,0 +1,44 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/errfuns.h"
/**
* Duplicates file descriptor/handle.
*
* On Windows, we can't guarantee the desired file descriptor is used.
* We can however remap the standard handles (non-atomically) if their
* symbolic names are used.
*
* @param oldfd isn't closed afterwards
* @param newfd if already assigned, is silently closed beforehand;
* unless it's equal to oldfd, in which case dup2() is a no-op
* @flags can have O_CLOEXEC
*/
int dup3(int oldfd, int newfd, int flags) {
if (oldfd == newfd) return einval();
if (!IsWindows()) {
return dup3$sysv(oldfd, newfd, flags);
} else {
return dup$nt(oldfd, newfd, flags);
}
}

65
libc/calls/fadvise-nt.c Normal file
View file

@ -0,0 +1,65 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/files.h"
#include "libc/nt/nt/file.h"
#include "libc/nt/ntdll.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/fileaccessinformation.h"
#include "libc/nt/struct/filebasicinformation.h"
#include "libc/nt/struct/iostatusblock.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int fadvise$nt(int fd, uint64_t offset, uint64_t len, int advice) {
int64_t h2;
NtStatus status;
uint32_t sharemode;
struct NtIoStatusBlock iostatus;
struct NtFileBasicInformation basicinfo;
struct NtFileAccessInformation accessinfo;
if (!isfdkind(fd, kFdFile)) return ebadf();
sharemode = /* xxx: no clue how to query this */
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
/* TODO(jart): can we do it in one call w/ NtQueryObject? */
if (!NtError(status = NtQueryInformationFile(g_fds.p[fd].handle, &iostatus,
&basicinfo, sizeof(basicinfo),
kNtFileBasicInformation)) &&
!NtError(status = NtQueryInformationFile(g_fds.p[fd].handle, &iostatus,
&accessinfo, sizeof(accessinfo),
kNtFileAccessInformation))) {
if ((h2 = ReOpenFile(g_fds.p[fd].handle, accessinfo.AccessFlags, sharemode,
advice | basicinfo.FileAttributes)) != -1) {
if (h2 != g_fds.p[fd].handle) {
CloseHandle(g_fds.p[fd].handle);
g_fds.p[fd].handle = h2;
}
return 0;
}
return winerr();
} else if (status == kNtStatusDllNotFound) {
return enosys();
} else {
return ntreturn(status);
}
}

40
libc/calls/fadvise.c Normal file
View file

@ -0,0 +1,40 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
/**
* Drops hints to O/S about intended I/O behavior.
*
* It makes a huge difference. For example, when copying a large file,
* it can stop the system from persisting GBs of useless memory content.
*
* @param len 0 means til end of file
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
* @return -1 on error
*/
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
if (!IsWindows()) {
return fadvise$sysv(fd, offset, len, advice); /* linux & freebsd */
} else {
return fadvise$nt(fd, offset, len, advice);
}
}

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