mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
Initial import
This commit is contained in:
commit
c91b3c5006
14915 changed files with 590219 additions and 0 deletions
54
libc/README.md
Normal file
54
libc/README.md
Normal 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
119
libc/alg/alg.h
Normal 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
59
libc/alg/alg.mk
Normal 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
48
libc/alg/arraylist.h
Normal 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
32
libc/alg/arraylist2.h
Normal 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
29
libc/alg/bisect.h
Normal 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
31
libc/alg/bisectcarleft.h
Normal 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
27
libc/alg/bisectleft.h
Normal 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
26
libc/alg/bisectright.h
Normal 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
30
libc/alg/bsearch.c
Normal 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
30
libc/alg/bsearch_r.c
Normal 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);
|
||||
}
|
65
libc/alg/critbit0_allprefixed.c
Normal file
65
libc/alg/critbit0_allprefixed.c
Normal 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
47
libc/alg/critbit0_clear.c
Normal 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;
|
||||
}
|
43
libc/alg/critbit0_contains.c
Normal file
43
libc/alg/critbit0_contains.c
Normal 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);
|
||||
}
|
61
libc/alg/critbit0_delete.c
Normal file
61
libc/alg/critbit0_delete.c
Normal 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;
|
||||
}
|
88
libc/alg/critbit0_emplace.c
Normal file
88
libc/alg/critbit0_emplace.c
Normal 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
44
libc/alg/critbit0_get.c
Normal 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;
|
||||
}
|
35
libc/alg/critbit0_insert.c
Normal file
35
libc/alg/critbit0_insert.c
Normal 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
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
35
libc/alg/djbsort.c
Normal 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
34
libc/alg/insertionsort.h
Normal 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
14
libc/alg/internal.h
Normal 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
97
libc/alg/memmem.c
Normal 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
30
libc/alg/memmem16.c
Normal 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
243
libc/alg/qsort.c
Normal 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
64
libc/alg/replacestr.c
Normal 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
29
libc/alg/replacestr16.c
Normal 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
33
libc/alg/reverse.h
Normal 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
25
libc/alg/shuffle.h
Normal 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
183
libc/alg/tarjan.c
Normal 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
24
libc/assert.h
Normal 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
23
libc/bits/abs.c
Normal 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
52
libc/bits/atomic.h
Normal 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
133
libc/bits/avx2intrin.h
Normal 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
51
libc/bits/avxintrin.h
Normal 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
42
libc/bits/bcd2i.S
Normal 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
38
libc/bits/bcdadd.S
Normal 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
54
libc/bits/bcxcpy.S
Normal 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
28
libc/bits/bigword.h
Normal 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
31
libc/bits/bitreverse16.S
Normal 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
28
libc/bits/bitreverse32.c
Normal 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
28
libc/bits/bitreverse64.c
Normal 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
31
libc/bits/bitreverse8.S
Normal 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
531
libc/bits/bits.h
Normal 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
53
libc/bits/bits.mk
Normal 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
217
libc/bits/emmintrin.h
Normal 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
21
libc/bits/emptytonull.c
Normal 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
26
libc/bits/firstnonnull.c
Normal 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
30
libc/bits/gray.c
Normal 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
24
libc/bits/hamming.c
Normal 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
75
libc/bits/hilbert.c
Normal 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
11
libc/bits/hilbert.h
Normal 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
48
libc/bits/i2bcd.S
Normal 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
21
libc/bits/isempty.c
Normal 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
22
libc/bits/max.c
Normal 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
22
libc/bits/min.c
Normal 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
14
libc/bits/mmintrin.h
Normal 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
37
libc/bits/morton.c
Normal 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
25
libc/bits/morton.h
Normal 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
21
libc/bits/nulltoempty.c
Normal 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
14
libc/bits/pmmintrin.h
Normal 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
42
libc/bits/popcount.c
Normal 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
15
libc/bits/progn.h
Normal 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
53
libc/bits/pushpop.h
Normal 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
22
libc/bits/rounddown.c
Normal 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
31
libc/bits/rounddown2pow.c
Normal 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 (𝑥>0→2^⌊log₂𝑥⌋, x=0→0, 𝑇→⊥)
|
||||
* @see roundup2pow()
|
||||
*/
|
||||
unsigned long rounddown2pow(unsigned long x) {
|
||||
return x ? 1ul << bsrl(x) : 0;
|
||||
}
|
22
libc/bits/roundup.c
Normal file
22
libc/bits/roundup.c
Normal 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
29
libc/bits/roundup2log.c
Normal 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
31
libc/bits/roundup2pow.c
Normal 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 (𝑥>0→2^⌈log₂x⌉, x=0→0, 𝑇→⊥)
|
||||
* @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
86
libc/bits/safemacros.h
Normal 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
37
libc/bits/shaintrin.h
Normal 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
31
libc/bits/smmintrin.h
Normal 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
17
libc/bits/tmmintrin.h
Normal 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
14
libc/bits/typecheck.h
Normal 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
41
libc/bits/unmorton.c
Normal 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)};
|
||||
}
|
27
libc/bits/unsignedsubtract.c
Normal file
27
libc/bits/unsignedsubtract.c
Normal 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
29
libc/bits/wmmintrin.h
Normal 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
25
libc/bits/xchg.h
Normal 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
233
libc/bits/xmmintrin.h
Normal 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
56
libc/calls/atfork.c
Normal 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
292
libc/calls/calls.h
Normal 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
90
libc/calls/calls.mk
Normal 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
38
libc/calls/chdir-nt.c
Normal 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
34
libc/calls/chdir.c
Normal 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
49
libc/calls/chmod.c
Normal 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
38
libc/calls/chown.c
Normal 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
45
libc/calls/close-nt.c
Normal 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
49
libc/calls/close.c
Normal 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
73
libc/calls/copyfd.c
Normal 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
64
libc/calls/copyfile.c
Normal 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
36
libc/calls/creat.c
Normal 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
38
libc/calls/createfd.c
Normal 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
32
libc/calls/dprintf.c
Normal 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
54
libc/calls/dup-nt.c
Normal 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
37
libc/calls/dup.c
Normal 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
40
libc/calls/dup2.c
Normal 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
47
libc/calls/dup3-sysv.c
Normal 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
44
libc/calls/dup3.c
Normal 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
65
libc/calls/fadvise-nt.c
Normal 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
40
libc/calls/fadvise.c
Normal 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
Loading…
Add table
Add a link
Reference in a new issue