mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-29 16:52:28 +00:00
Make minor improvements
This commit is contained in:
parent
04caf6f9ad
commit
95b142e4e5
95 changed files with 3818 additions and 2760 deletions
|
@ -263,11 +263,12 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
* @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); \
|
||||
#define lockxchg(MEMORY, LOCALVAR) \
|
||||
({ \
|
||||
_Static_assert( \
|
||||
__builtin_types_compatible_p(typeof(*(MEMORY)), typeof(*(LOCALVAR)))); \
|
||||
asm("xchg\t%0,%1" : "+%m"(*(MEMORY)), "+r"(*(LOCALVAR))); \
|
||||
*(LOCALVAR); \
|
||||
})
|
||||
|
||||
/**
|
||||
|
@ -376,7 +377,7 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
#define __BitOp(OP, BIT, MEM) \
|
||||
({ \
|
||||
bool OldBit; \
|
||||
if (isconstant(BIT)) { \
|
||||
if (__builtin_constant_p(BIT)) { \
|
||||
asm(CFLAG_ASM(OP "%z1\t%2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), \
|
||||
"+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
|
||||
|
|
|
@ -8,39 +8,9 @@ uint32_t bswap_32(uint32_t) pureconst;
|
|||
uint32_t bswap_64(uint32_t) pureconst;
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
#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; \
|
||||
}))
|
||||
|
||||
#define bswap_16(x) __builtin_bswap16(x)
|
||||
#define bswap_32(x) __builtin_bswap32(x)
|
||||
#define bswap_64(x) __builtin_bswap64(x)
|
||||
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "libc/bits/popcnt.h"
|
||||
|
||||
uint64_t(popcnt)(uint64_t x) {
|
||||
uint32_t r;
|
||||
x = x - ((x >> 1) & 0x5555555555555555);
|
||||
x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333);
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
|
||||
|
|
|
@ -8,7 +8,7 @@ unsigned long popcnt(unsigned long) pureconst;
|
|||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define popcnt(X) \
|
||||
(isconstant(X) ? __builtin_popcountll(X) : ({ \
|
||||
(__builtin_constant_p(X) ? __builtin_popcountll(X) : ({ \
|
||||
unsigned long Res, Pop = (X); \
|
||||
if (X86_HAVE(POPCNT)) { \
|
||||
asm("popcnt\t%1,%0" : "=r"(Res) : "r"(Pop) : "cc"); \
|
||||
|
|
|
@ -10,42 +10,44 @@
|
|||
#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; \
|
||||
#define pushpop(x) \
|
||||
({ \
|
||||
typeof(x) Popped; \
|
||||
if (__builtin_constant_p(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; \
|
||||
#define pushmov(d, x) \
|
||||
({ \
|
||||
typeof(*(d)) Popped = (x); \
|
||||
if (__builtin_constant_p(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
|
||||
|
||||
|
|
|
@ -227,9 +227,9 @@ uint32_t gettid(void) nosideeffect;
|
|||
uint32_t getuid(void) nosideeffect;
|
||||
uint32_t umask(int32_t);
|
||||
|
||||
#define getcwd(BUF, SIZE) \
|
||||
(isconstant(BUF) && (&(BUF)[0] == NULL) ? get_current_dir_name() \
|
||||
: getcwd(BUF, SIZE))
|
||||
#define getcwd(BUF, SIZE) \
|
||||
(__builtin_constant_p(BUF) && (&(BUF)[0] == NULL) ? get_current_dir_name() \
|
||||
: getcwd(BUF, SIZE))
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § system calls » formatting ─╬─│┼
|
||||
|
@ -249,7 +249,7 @@ void _init_wincrash(void);
|
|||
#define __SIGACTION(FN, SIG, ...) \
|
||||
({ \
|
||||
if (SupportsWindows()) { \
|
||||
if (isconstant(SIG)) { \
|
||||
if (__builtin_constant_p(SIG)) { \
|
||||
switch (SIG) { \
|
||||
case SIGINT: \
|
||||
case SIGQUIT: \
|
||||
|
|
|
@ -63,7 +63,7 @@ int clock_gettime(int clockid, struct timespec *out_ts) {
|
|||
return clock_gettime$sysv(clockid, out_ts);
|
||||
} else {
|
||||
int rc;
|
||||
static_assert(sizeof(struct timeval) == sizeof(struct timespec));
|
||||
_Static_assert(sizeof(struct timeval) == sizeof(struct timespec));
|
||||
if (out_ts) {
|
||||
out_ts->tv_sec = 0;
|
||||
out_ts->tv_nsec = 0;
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#define kBufSize 1024
|
||||
#define kProcStatus "/proc/self/status"
|
||||
alignas(16) static const char kGdbPid[] = "TracerPid:\t";
|
||||
_Alignas(16) static const char kGdbPid[] = "TracerPid:\t";
|
||||
|
||||
/**
|
||||
* Determines if gdb, strace, windbg, etc. is controlling process.
|
||||
|
|
|
@ -121,11 +121,11 @@ static void sigaction$native2cosmo(union metasigaction *sa) {
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||
static_assert(sizeof(struct sigaction) > sizeof(struct sigaction$linux) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$xnu_in) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$xnu_out) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$freebsd) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$openbsd));
|
||||
_Static_assert(sizeof(struct sigaction) > sizeof(struct sigaction$linux) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$xnu_in) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$xnu_out) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$freebsd) &&
|
||||
sizeof(struct sigaction) > sizeof(struct sigaction$openbsd));
|
||||
int rc, rva, oldrva;
|
||||
struct sigaction *ap, copy;
|
||||
if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
|
||||
/**
|
||||
* Deletes file, the Cosmopolitan way.
|
||||
* Deletes file.
|
||||
*
|
||||
* The caller's variable is made NULL. Note that we define unlink(NULL)
|
||||
* as a no-op.
|
||||
|
|
|
@ -19,7 +19,6 @@ long labs(long) libcesque pureconst;
|
|||
long long llabs(long long) libcesque pureconst;
|
||||
char *ltpcpy(char *, long) paramsnonnull() libcesque nocallback;
|
||||
int llog10(unsigned long) libcesque pureconst;
|
||||
int unsleb128(const void *, size_t, int64_t *);
|
||||
int atoi(const char *) paramsnonnull() libcesque;
|
||||
long atol(const char *) paramsnonnull() libcesque;
|
||||
long long atoll(const char *) paramsnonnull() libcesque;
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
|
||||
#define ISDELIM(c) (c == '/' || c == '\\' || c == '.')
|
||||
|
||||
/**
|
||||
* Returns directory portion of path.
|
||||
* @param s is mutated
|
||||
*/
|
||||
char *dirname(char *s) {
|
||||
size_t i, n;
|
||||
if (!(n = strlen(s))) return s;
|
||||
|
|
11
libc/fmt/leb128.h
Normal file
11
libc/fmt/leb128.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_LEB128_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_LEB128_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int sleb128(const void *, size_t, int128_t);
|
||||
int unsleb128(const void *, size_t, int128_t *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_LEB128_H_ */
|
|
@ -46,7 +46,7 @@
|
|||
#define ___PFLINK(FMT, FN, C) 1
|
||||
#else
|
||||
#define ___PFLINK(FMT, FN, C) \
|
||||
!isconstant(FMT) || ((FMT) && __builtin_##FN(FMT, C) != NULL)
|
||||
!__builtin_constant_p(FMT) || ((FMT) && __builtin_##FN(FMT, C) != NULL)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 6
|
||||
|
|
39
libc/fmt/sleb128.c
Normal file
39
libc/fmt/sleb128.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*-*- 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/fmt/leb128.h"
|
||||
|
||||
/**
|
||||
* Encodes sleb-128 signed integer.
|
||||
*/
|
||||
int sleb128(const void *buf, size_t size, int128_t x) {
|
||||
int c;
|
||||
unsigned i;
|
||||
for (i = 0; i < size; ++i) {
|
||||
c = x & 0x7f;
|
||||
x >>= 7;
|
||||
if ((x == 0 && !(c & 0x40)) || (x == -1 && (c & 0x40))) {
|
||||
break;
|
||||
} else {
|
||||
c |= 0x80;
|
||||
}
|
||||
((char *)buf)[i] = c;
|
||||
}
|
||||
return i;
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
* @see strerror_r()
|
||||
*/
|
||||
char *strerror(int err) {
|
||||
alignas(1) static char buf[512];
|
||||
_Alignas(1) static char buf[512];
|
||||
strerror_r(err, buf, sizeof(buf));
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/leb128.h"
|
||||
|
||||
/**
|
||||
* Decodes a GNU-style varint from a buffer.
|
||||
|
@ -25,9 +25,9 @@
|
|||
* The GNU Assembler is able to encode numbers this way, since it's used
|
||||
* by the DWARF debug format.
|
||||
*/
|
||||
int unsleb128(const void *buf, size_t size, int64_t *out) {
|
||||
int unsleb128(const void *buf, size_t size, int128_t *out) {
|
||||
int b;
|
||||
int64_t r, w;
|
||||
int128_t r, w;
|
||||
unsigned char c;
|
||||
const unsigned char *p, *pe;
|
||||
pe = (p = buf) + size;
|
||||
|
|
|
@ -806,36 +806,6 @@ typedef uint64_t uintmax_t;
|
|||
do { \
|
||||
} while (0)
|
||||
|
||||
#ifndef likely
|
||||
#define likely(expr) __builtin_expect(!!(expr), 1)
|
||||
#endif
|
||||
|
||||
#ifndef unlikely
|
||||
#define unlikely(expr) __builtin_expect(!!(expr), 0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Evaluates ternary expression without type promotion.
|
||||
*/
|
||||
#ifndef chooseexpr
|
||||
#define chooseexpr(pred, a, b) __builtin_choose_expr(pred, a, b)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns true if expression can be evaluated at compile-time.
|
||||
*/
|
||||
#ifndef isconstant
|
||||
#define isconstant(expr) __builtin_constant_p(expr)
|
||||
#endif
|
||||
|
||||
#ifndef static_assert
|
||||
#define static_assert(expr) _Static_assert(expr, #expr)
|
||||
#endif
|
||||
|
||||
#ifndef typescompatible
|
||||
#define typescompatible(a, b) __builtin_types_compatible_p(a, b)
|
||||
#endif
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
#define testonly noinline _Section(".test")
|
||||
#define textstartup _Section(".text.startup") noinstrument
|
||||
|
@ -873,10 +843,6 @@ typedef uint64_t uintmax_t;
|
|||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
#endif
|
||||
|
||||
#ifndef alignas
|
||||
#define alignas(x) _Alignas(x)
|
||||
#endif
|
||||
|
||||
#ifndef _Section
|
||||
#ifndef __STRICT_ANSI__
|
||||
#define _Section(s) __attribute__((__section__(s)))
|
||||
|
@ -1029,15 +995,15 @@ typedef uint64_t uintmax_t;
|
|||
* Pulls another module, by symbol, into linkage.
|
||||
* @note nop is discarded by ape/ape.lds
|
||||
*/
|
||||
#define YOINK(SYMBOL) \
|
||||
do { \
|
||||
_Static_assert(!typescompatible(typeof(SYMBOL), char[]), \
|
||||
"Please YOINK(symbol), not YOINK(\"symbol\")"); \
|
||||
asm(".pushsection .yoink\n\t" \
|
||||
"nop\t%a0\n\t" \
|
||||
".popsection" \
|
||||
: /* no outputs */ \
|
||||
: "X"(SYMBOL)); \
|
||||
#define YOINK(SYMBOL) \
|
||||
do { \
|
||||
_Static_assert(!__builtin_types_compatible_p(typeof(SYMBOL), char[]), \
|
||||
"Please YOINK(symbol), not YOINK(\"symbol\")"); \
|
||||
asm(".pushsection .yoink\n\t" \
|
||||
"nop\t%a0\n\t" \
|
||||
".popsection" \
|
||||
: /* no outputs */ \
|
||||
: "X"(SYMBOL)); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,11 +10,12 @@ void mpsadbw(uint16_t[8], const uint8_t[16], const uint8_t[16], uint8_t);
|
|||
__intrin_xmm_t __mpsadbws(__intrin_xmm_t, __intrin_xmm_t);
|
||||
#define mpsadbw(C, B, A, I) \
|
||||
do { \
|
||||
if (likely(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE4_1))) { \
|
||||
if (__builtin_expect(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE4_1), \
|
||||
1)) { \
|
||||
__intrin_xmm_t *Xmm0 = (void *)(C); \
|
||||
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \
|
||||
const __intrin_xmm_t *Xmm2 = (const __intrin_xmm_t *)(A); \
|
||||
if (isconstant(I)) { \
|
||||
if (__builtin_constant_p(I)) { \
|
||||
if (!X86_NEED(AVX)) { \
|
||||
asm("mpsadbw\t%2,%1,%0" \
|
||||
: "=x"(*Xmm0) \
|
||||
|
|
|
@ -9,35 +9,36 @@ void palignr(void *, const void *, const void *, unsigned long);
|
|||
|
||||
#if !defined(__STRICT_ANSI__) && !defined(__chibicc__)
|
||||
__intrin_xmm_t __palignrs(__intrin_xmm_t, __intrin_xmm_t);
|
||||
#define palignr(C, B, A, I) \
|
||||
do { \
|
||||
if (likely(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSSE3))) { \
|
||||
__intrin_xmm_t *Xmm0 = (void *)(C); \
|
||||
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \
|
||||
const __intrin_xmm_t *Xmm2 = (const __intrin_xmm_t *)(A); \
|
||||
if (isconstant(I)) { \
|
||||
if (!X86_NEED(AVX)) { \
|
||||
asm("palignr\t%2,%1,%0" \
|
||||
: "=x"(*Xmm0) \
|
||||
: "x"(*Xmm2), "i"(I), "0"(*Xmm1)); \
|
||||
} else { \
|
||||
asm("vpalignr\t%3,%2,%1,%0" \
|
||||
: "=x"(*Xmm0) \
|
||||
: "x"(*Xmm1), "x"(*Xmm2), "i"(I)); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned long Vimm = (I); \
|
||||
typeof(__palignrs) *Fn; \
|
||||
if (likely(Vimm < 32)) { \
|
||||
Fn = (typeof(__palignrs) *)((uintptr_t)&__palignrs + Vimm * 8); \
|
||||
*Xmm0 = Fn(*Xmm1, *Xmm2); \
|
||||
} else { \
|
||||
memset(Xmm0, 0, 16); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
palignr(C, B, A, I); \
|
||||
} \
|
||||
#define palignr(C, B, A, I) \
|
||||
do { \
|
||||
if (__builtin_expect(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSSE3), \
|
||||
1)) { \
|
||||
__intrin_xmm_t *Xmm0 = (void *)(C); \
|
||||
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \
|
||||
const __intrin_xmm_t *Xmm2 = (const __intrin_xmm_t *)(A); \
|
||||
if (__builtin_constant_p(I)) { \
|
||||
if (!X86_NEED(AVX)) { \
|
||||
asm("palignr\t%2,%1,%0" \
|
||||
: "=x"(*Xmm0) \
|
||||
: "x"(*Xmm2), "i"(I), "0"(*Xmm1)); \
|
||||
} else { \
|
||||
asm("vpalignr\t%3,%2,%1,%0" \
|
||||
: "=x"(*Xmm0) \
|
||||
: "x"(*Xmm1), "x"(*Xmm2), "i"(I)); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned long Vimm = (I); \
|
||||
typeof(__palignrs) *Fn; \
|
||||
if (__builtin_expect(Vimm < 32, 1)) { \
|
||||
Fn = (typeof(__palignrs) *)((uintptr_t)&__palignrs + Vimm * 8); \
|
||||
*Xmm0 = Fn(*Xmm1, *Xmm2); \
|
||||
} else { \
|
||||
memset(Xmm0, 0, 16); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
palignr(C, B, A, I); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -8,27 +8,28 @@ void pslldq(uint8_t[16], const uint8_t[16], unsigned long);
|
|||
|
||||
#ifndef __STRICT_ANSI__
|
||||
__intrin_xmm_t __pslldqs(__intrin_xmm_t);
|
||||
#define pslldq(B, A, I) \
|
||||
do { \
|
||||
if (likely(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE2))) { \
|
||||
__intrin_xmm_t *Xmm0 = (void *)(B); \
|
||||
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(A); \
|
||||
if (isconstant(I)) { \
|
||||
if (!X86_NEED(AVX)) { \
|
||||
asm("pslldq\t%1,%0" : "=x"(*Xmm0) : "i"(I), "0"(*Xmm1)); \
|
||||
} else { \
|
||||
asm("vpslldq\t%2,%1,%0" : "=x"(*Xmm0) : "x"(*Xmm1), "i"(I)); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned long Vimm = (I); \
|
||||
typeof(__pslldqs) *Fn; \
|
||||
if (Vimm > 16) Vimm = 16; \
|
||||
Fn = (typeof(__pslldqs) *)((uintptr_t)&__pslldqs + Vimm * 8); \
|
||||
*Xmm0 = Fn(*Xmm1); \
|
||||
} \
|
||||
} else { \
|
||||
pslldq(B, A, I); \
|
||||
} \
|
||||
#define pslldq(B, A, I) \
|
||||
do { \
|
||||
if (__builtin_expect(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE2), \
|
||||
1)) { \
|
||||
__intrin_xmm_t *Xmm0 = (void *)(B); \
|
||||
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(A); \
|
||||
if (__builtin_constant_p(I)) { \
|
||||
if (!X86_NEED(AVX)) { \
|
||||
asm("pslldq\t%1,%0" : "=x"(*Xmm0) : "i"(I), "0"(*Xmm1)); \
|
||||
} else { \
|
||||
asm("vpslldq\t%2,%1,%0" : "=x"(*Xmm0) : "x"(*Xmm1), "i"(I)); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned long Vimm = (I); \
|
||||
typeof(__pslldqs) *Fn; \
|
||||
if (Vimm > 16) Vimm = 16; \
|
||||
Fn = (typeof(__pslldqs) *)((uintptr_t)&__pslldqs + Vimm * 8); \
|
||||
*Xmm0 = Fn(*Xmm1); \
|
||||
} \
|
||||
} else { \
|
||||
pslldq(B, A, I); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -8,27 +8,28 @@ void psrldq(uint8_t[16], const uint8_t[16], unsigned long);
|
|||
|
||||
#ifndef __STRICT_ANSI__
|
||||
__intrin_xmm_t __psrldqs(__intrin_xmm_t);
|
||||
#define psrldq(B, A, I) \
|
||||
do { \
|
||||
if (likely(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE2))) { \
|
||||
__intrin_xmm_t *Xmm0 = (void *)(B); \
|
||||
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(A); \
|
||||
if (isconstant(I)) { \
|
||||
if (!X86_NEED(AVX)) { \
|
||||
asm("psrldq\t%1,%0" : "=x"(*Xmm0) : "i"(I), "0"(*Xmm1)); \
|
||||
} else { \
|
||||
asm("vpsrldq\t%2,%1,%0" : "=x"(*Xmm0) : "x"(*Xmm1), "i"(I)); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned long Vimm = (I); \
|
||||
typeof(__psrldqs) *Fn; \
|
||||
if (Vimm > 16) Vimm = 16; \
|
||||
Fn = (typeof(__psrldqs) *)((uintptr_t)&__psrldqs + Vimm * 8); \
|
||||
*Xmm0 = Fn(*Xmm1); \
|
||||
} \
|
||||
} else { \
|
||||
psrldq(B, A, I); \
|
||||
} \
|
||||
#define psrldq(B, A, I) \
|
||||
do { \
|
||||
if (__builtin_expect(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE2), \
|
||||
1)) { \
|
||||
__intrin_xmm_t *Xmm0 = (void *)(B); \
|
||||
const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(A); \
|
||||
if (__builtin_constant_p(I)) { \
|
||||
if (!X86_NEED(AVX)) { \
|
||||
asm("psrldq\t%1,%0" : "=x"(*Xmm0) : "i"(I), "0"(*Xmm1)); \
|
||||
} else { \
|
||||
asm("vpsrldq\t%2,%1,%0" : "=x"(*Xmm0) : "x"(*Xmm1), "i"(I)); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned long Vimm = (I); \
|
||||
typeof(__psrldqs) *Fn; \
|
||||
if (Vimm > 16) Vimm = 16; \
|
||||
Fn = (typeof(__psrldqs) *)((uintptr_t)&__psrldqs + Vimm * 8); \
|
||||
*Xmm0 = Fn(*Xmm1); \
|
||||
} \
|
||||
} else { \
|
||||
psrldq(B, A, I); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -56,8 +56,9 @@ bool isrunningundermake(void);
|
|||
|
||||
extern unsigned g_loglevel; /* log level for runtime check */
|
||||
|
||||
#define LOGGABLE(LEVEL) \
|
||||
((!isconstant(LEVEL) || (LEVEL) <= LOGGABLELEVEL) && (LEVEL) <= g_loglevel)
|
||||
#define LOGGABLE(LEVEL) \
|
||||
((!__builtin_constant_p(LEVEL) || (LEVEL) <= LOGGABLELEVEL) && \
|
||||
(LEVEL) <= g_loglevel)
|
||||
|
||||
#define LOGF(FMT, ...) \
|
||||
do { \
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
/* clang-format off */
|
||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ 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 "ape/relocations.h"
|
||||
/* clang-format off */
|
||||
|
||||
#if __MNO_VZEROUPPER__ + 0
|
||||
#define vzeroupper
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define alignas(x) _Alignas(x)
|
||||
#define static_assert(x) _Static_assert(x, #x)
|
||||
|
||||
#define ROUNDUP(X, K) (((X) + (K)-1) & -(K))
|
||||
#define ROUNDDOWN(X, K) ((X) & -(K))
|
||||
#define ABS(X) ((X) >= 0 ? (X) : -(X))
|
||||
|
@ -20,7 +23,7 @@
|
|||
#define MAX(X, Y) ((Y) < (X) ? (X) : (Y))
|
||||
#define PASTE(A, B) __PASTE(A, B)
|
||||
#define STRINGIFY(A) __STRINGIFY(A)
|
||||
#define EQUIVALENT(X, Y) (isconstant((X) == (Y)) && ((X) == (Y)))
|
||||
#define EQUIVALENT(X, Y) (__builtin_constant_p((X) == (Y)) && ((X) == (Y)))
|
||||
#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT)
|
||||
#define TYPE_SIGNED(type) (((type)-1) < 0)
|
||||
#define TYPE_INTEGRAL(type) (((type)0.5) != 0.5)
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ 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 │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
|
||||
/ Shorthand notation for widely-acknowledged sections.
|
||||
.macro .rodata
|
||||
.section .rodata,"a",@progbits
|
||||
|
|
|
@ -5,7 +5,7 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
void crc32init(uint32_t[hasatleast 256], uint32_t);
|
||||
uint32_t crc32_z(uint32_t, const void *, size_t);
|
||||
extern uint32_t (*const crc32c)(uint32_t, const void *, size_t) paramsnonnull();
|
||||
extern uint32_t (*const crc32c)(uint32_t, const void *, size_t);
|
||||
uint32_t crc32c$pure(uint32_t, const void *, size_t) strlenesque hidden;
|
||||
uint32_t crc32c$sse42(uint32_t, const void *, size_t) strlenesque hidden;
|
||||
uint32_t crc32$pclmul(uint32_t, const void *, size_t) hidden;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* Hashes data with hardware acceleration at 10GBps.
|
||||
* @note needs Nehalem+ c. 2008 or Bulldozer+ c. 2011
|
||||
*/
|
||||
uint32_t crc32c$sse42(uint32_t init, const void *data, size_t n) {
|
||||
optimizespeed uint32_t crc32c$sse42(uint32_t init, const void *data, size_t n) {
|
||||
const unsigned char *p = (const unsigned char *)data;
|
||||
const unsigned char *pe = (const unsigned char *)data + n;
|
||||
uint32_t h = init ^ 0xffffffff;
|
||||
|
|
|
@ -1,467 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Intel Corporation nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
.ident "\n
|
||||
memmove (Licensed BSD-3)\n
|
||||
Copyright 2014 Intel Corporation"
|
||||
.include "libc/disclaimer.inc"
|
||||
|
||||
#ifndef L
|
||||
# define L(label) .L##label
|
||||
#endif
|
||||
|
||||
#ifndef SHARED_CACHE_SIZE_HALF
|
||||
#define SHARED_CACHE_SIZE_HALF (4 * 1024 * 1024)
|
||||
#endif
|
||||
|
||||
push %rbx
|
||||
push %rdx
|
||||
push %r8
|
||||
push %r9
|
||||
|
||||
/* Check whether we should copy backward or forward. */
|
||||
cmp %rsi, %rdi
|
||||
je L(mm_return)
|
||||
jg L(mm_len_0_or_more_backward)
|
||||
|
||||
/* Now do checks for lengths. We do [0..16], [0..32], [0..64], [0..128]
|
||||
separately. */
|
||||
cmp $16, %rdx
|
||||
jbe L(mm_len_0_16_bytes_forward)
|
||||
|
||||
cmp $32, %rdx
|
||||
ja L(mm_len_32_or_more_forward)
|
||||
|
||||
/* Copy [0..32] and return. */
|
||||
movdqu (%rsi), %xmm0
|
||||
movdqu -16(%rsi, %rdx), %xmm1
|
||||
movdqu %xmm0, (%rdi)
|
||||
movdqu %xmm1, -16(%rdi, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_32_or_more_forward):
|
||||
cmp $64, %rdx
|
||||
ja L(mm_len_64_or_more_forward)
|
||||
|
||||
/* Copy [0..64] and return. */
|
||||
movdqu (%rsi), %xmm0
|
||||
movdqu 16(%rsi), %xmm1
|
||||
movdqu -16(%rsi, %rdx), %xmm2
|
||||
movdqu -32(%rsi, %rdx), %xmm3
|
||||
movdqu %xmm0, (%rdi)
|
||||
movdqu %xmm1, 16(%rdi)
|
||||
movdqu %xmm2, -16(%rdi, %rdx)
|
||||
movdqu %xmm3, -32(%rdi, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_64_or_more_forward):
|
||||
cmp $128, %rdx
|
||||
ja L(mm_len_128_or_more_forward)
|
||||
|
||||
/* Copy [0..128] and return. */
|
||||
movdqu (%rsi), %xmm0
|
||||
movdqu 16(%rsi), %xmm1
|
||||
movdqu 32(%rsi), %xmm2
|
||||
movdqu 48(%rsi), %xmm3
|
||||
movdqu -64(%rsi, %rdx), %xmm4
|
||||
movdqu -48(%rsi, %rdx), %xmm5
|
||||
movdqu -32(%rsi, %rdx), %xmm6
|
||||
movdqu -16(%rsi, %rdx), %xmm7
|
||||
movdqu %xmm0, (%rdi)
|
||||
movdqu %xmm1, 16(%rdi)
|
||||
movdqu %xmm2, 32(%rdi)
|
||||
movdqu %xmm3, 48(%rdi)
|
||||
movdqu %xmm4, -64(%rdi, %rdx)
|
||||
movdqu %xmm5, -48(%rdi, %rdx)
|
||||
movdqu %xmm6, -32(%rdi, %rdx)
|
||||
movdqu %xmm7, -16(%rdi, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_128_or_more_forward):
|
||||
/* Aligning the address of destination. */
|
||||
/* save first unaligned 64 bytes */
|
||||
movdqu (%rsi), %xmm0
|
||||
movdqu 16(%rsi), %xmm1
|
||||
movdqu 32(%rsi), %xmm2
|
||||
movdqu 48(%rsi), %xmm3
|
||||
|
||||
lea 64(%rdi), %r8
|
||||
and $-64, %r8 /* r8 now aligned to next 64 byte boundary */
|
||||
sub %rdi, %rsi /* rsi = src - dst = diff */
|
||||
|
||||
movdqu (%r8, %rsi), %xmm4
|
||||
movdqu 16(%r8, %rsi), %xmm5
|
||||
movdqu 32(%r8, %rsi), %xmm6
|
||||
movdqu 48(%r8, %rsi), %xmm7
|
||||
|
||||
movdqu %xmm0, (%rdi)
|
||||
movdqu %xmm1, 16(%rdi)
|
||||
movdqu %xmm2, 32(%rdi)
|
||||
movdqu %xmm3, 48(%rdi)
|
||||
movdqa %xmm4, (%r8)
|
||||
movaps %xmm5, 16(%r8)
|
||||
movaps %xmm6, 32(%r8)
|
||||
movaps %xmm7, 48(%r8)
|
||||
add $64, %r8
|
||||
|
||||
lea (%rdi, %rdx), %rbx
|
||||
and $-64, %rbx
|
||||
cmp %r8, %rbx
|
||||
jbe L(mm_copy_remaining_forward)
|
||||
|
||||
cmp $SHARED_CACHE_SIZE_HALF, %rdx
|
||||
jae L(mm_large_page_loop_forward)
|
||||
|
||||
.p2align 4
|
||||
L(mm_main_loop_forward):
|
||||
|
||||
prefetcht0 128(%r8, %rsi)
|
||||
|
||||
movdqu (%r8, %rsi), %xmm0
|
||||
movdqu 16(%r8, %rsi), %xmm1
|
||||
movdqu 32(%r8, %rsi), %xmm2
|
||||
movdqu 48(%r8, %rsi), %xmm3
|
||||
movdqa %xmm0, (%r8)
|
||||
movaps %xmm1, 16(%r8)
|
||||
movaps %xmm2, 32(%r8)
|
||||
movaps %xmm3, 48(%r8)
|
||||
lea 64(%r8), %r8
|
||||
cmp %r8, %rbx
|
||||
ja L(mm_main_loop_forward)
|
||||
|
||||
L(mm_copy_remaining_forward):
|
||||
add %rdi, %rdx
|
||||
sub %r8, %rdx
|
||||
/* We copied all up till %rdi position in the dst.
|
||||
In %rdx now is how many bytes are left to copy.
|
||||
Now we need to advance %r8. */
|
||||
lea (%r8, %rsi), %r9
|
||||
|
||||
L(mm_remaining_0_64_bytes_forward):
|
||||
cmp $32, %rdx
|
||||
ja L(mm_remaining_33_64_bytes_forward)
|
||||
cmp $16, %rdx
|
||||
ja L(mm_remaining_17_32_bytes_forward)
|
||||
test %rdx, %rdx
|
||||
.p2align 4,,2
|
||||
je L(mm_return)
|
||||
|
||||
cmpb $8, %dl
|
||||
ja L(mm_remaining_9_16_bytes_forward)
|
||||
cmpb $4, %dl
|
||||
.p2align 4,,5
|
||||
ja L(mm_remaining_5_8_bytes_forward)
|
||||
cmpb $2, %dl
|
||||
.p2align 4,,1
|
||||
ja L(mm_remaining_3_4_bytes_forward)
|
||||
movzbl -1(%r9,%rdx), %esi
|
||||
movzbl (%r9), %ebx
|
||||
movb %sil, -1(%r8,%rdx)
|
||||
movb %bl, (%r8)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_remaining_33_64_bytes_forward):
|
||||
movdqu (%r9), %xmm0
|
||||
movdqu 16(%r9), %xmm1
|
||||
movdqu -32(%r9, %rdx), %xmm2
|
||||
movdqu -16(%r9, %rdx), %xmm3
|
||||
movdqu %xmm0, (%r8)
|
||||
movdqu %xmm1, 16(%r8)
|
||||
movdqu %xmm2, -32(%r8, %rdx)
|
||||
movdqu %xmm3, -16(%r8, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_remaining_17_32_bytes_forward):
|
||||
movdqu (%r9), %xmm0
|
||||
movdqu -16(%r9, %rdx), %xmm1
|
||||
movdqu %xmm0, (%r8)
|
||||
movdqu %xmm1, -16(%r8, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_remaining_5_8_bytes_forward):
|
||||
movl (%r9), %esi
|
||||
movl -4(%r9,%rdx), %ebx
|
||||
movl %esi, (%r8)
|
||||
movl %ebx, -4(%r8,%rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_remaining_9_16_bytes_forward):
|
||||
mov (%r9), %rsi
|
||||
mov -8(%r9, %rdx), %rbx
|
||||
mov %rsi, (%r8)
|
||||
mov %rbx, -8(%r8, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_remaining_3_4_bytes_forward):
|
||||
movzwl -2(%r9,%rdx), %esi
|
||||
movzwl (%r9), %ebx
|
||||
movw %si, -2(%r8,%rdx)
|
||||
movw %bx, (%r8)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_0_16_bytes_forward):
|
||||
testb $24, %dl
|
||||
jne L(mm_len_9_16_bytes_forward)
|
||||
testb $4, %dl
|
||||
.p2align 4,,5
|
||||
jne L(mm_len_5_8_bytes_forward)
|
||||
test %rdx, %rdx
|
||||
.p2align 4,,2
|
||||
je L(mm_return)
|
||||
testb $2, %dl
|
||||
.p2align 4,,1
|
||||
jne L(mm_len_2_4_bytes_forward)
|
||||
movzbl -1(%rsi,%rdx), %ebx
|
||||
movzbl (%rsi), %esi
|
||||
movb %bl, -1(%rdi,%rdx)
|
||||
movb %sil, (%rdi)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_2_4_bytes_forward):
|
||||
movzwl -2(%rsi,%rdx), %ebx
|
||||
movzwl (%rsi), %esi
|
||||
movw %bx, -2(%rdi,%rdx)
|
||||
movw %si, (%rdi)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_5_8_bytes_forward):
|
||||
movl (%rsi), %ebx
|
||||
movl -4(%rsi,%rdx), %esi
|
||||
movl %ebx, (%rdi)
|
||||
movl %esi, -4(%rdi,%rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_9_16_bytes_forward):
|
||||
mov (%rsi), %rbx
|
||||
mov -8(%rsi, %rdx), %rsi
|
||||
mov %rbx, (%rdi)
|
||||
mov %rsi, -8(%rdi, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_recalc_len):
|
||||
/* Compute in %rdx how many bytes are left to copy after
|
||||
the main loop stops. */
|
||||
mov %rbx, %rdx
|
||||
sub %rdi, %rdx
|
||||
/* The code for copying backwards. */
|
||||
L(mm_len_0_or_more_backward):
|
||||
|
||||
/* Now do checks for lengths. We do [0..16], [16..32], [32..64], [64..128]
|
||||
separately. */
|
||||
cmp $16, %rdx
|
||||
jbe L(mm_len_0_16_bytes_backward)
|
||||
|
||||
cmp $32, %rdx
|
||||
ja L(mm_len_32_or_more_backward)
|
||||
|
||||
/* Copy [0..32] and return. */
|
||||
movdqu (%rsi), %xmm0
|
||||
movdqu -16(%rsi, %rdx), %xmm1
|
||||
movdqu %xmm0, (%rdi)
|
||||
movdqu %xmm1, -16(%rdi, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_32_or_more_backward):
|
||||
cmp $64, %rdx
|
||||
ja L(mm_len_64_or_more_backward)
|
||||
|
||||
/* Copy [0..64] and return. */
|
||||
movdqu (%rsi), %xmm0
|
||||
movdqu 16(%rsi), %xmm1
|
||||
movdqu -16(%rsi, %rdx), %xmm2
|
||||
movdqu -32(%rsi, %rdx), %xmm3
|
||||
movdqu %xmm0, (%rdi)
|
||||
movdqu %xmm1, 16(%rdi)
|
||||
movdqu %xmm2, -16(%rdi, %rdx)
|
||||
movdqu %xmm3, -32(%rdi, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_64_or_more_backward):
|
||||
cmp $128, %rdx
|
||||
ja L(mm_len_128_or_more_backward)
|
||||
|
||||
/* Copy [0..128] and return. */
|
||||
movdqu (%rsi), %xmm0
|
||||
movdqu 16(%rsi), %xmm1
|
||||
movdqu 32(%rsi), %xmm2
|
||||
movdqu 48(%rsi), %xmm3
|
||||
movdqu -64(%rsi, %rdx), %xmm4
|
||||
movdqu -48(%rsi, %rdx), %xmm5
|
||||
movdqu -32(%rsi, %rdx), %xmm6
|
||||
movdqu -16(%rsi, %rdx), %xmm7
|
||||
movdqu %xmm0, (%rdi)
|
||||
movdqu %xmm1, 16(%rdi)
|
||||
movdqu %xmm2, 32(%rdi)
|
||||
movdqu %xmm3, 48(%rdi)
|
||||
movdqu %xmm4, -64(%rdi, %rdx)
|
||||
movdqu %xmm5, -48(%rdi, %rdx)
|
||||
movdqu %xmm6, -32(%rdi, %rdx)
|
||||
movdqu %xmm7, -16(%rdi, %rdx)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_128_or_more_backward):
|
||||
/* Aligning the address of destination. We need to save
|
||||
16 bits from the source in order not to overwrite them. */
|
||||
|
||||
movdqu -16(%rsi, %rdx), %xmm0
|
||||
movdqu -32(%rsi, %rdx), %xmm1
|
||||
movdqu -48(%rsi, %rdx), %xmm2
|
||||
movdqu -64(%rsi, %rdx), %xmm3
|
||||
|
||||
lea (%rdi, %rdx), %r9
|
||||
and $-64, %r9 /* r9 = aligned dst */
|
||||
|
||||
mov %rsi, %r8
|
||||
sub %rdi, %r8 /* r8 = src - dst, diff */
|
||||
|
||||
movdqu -16(%r9, %r8), %xmm4
|
||||
movdqu -32(%r9, %r8), %xmm5
|
||||
movdqu -48(%r9, %r8), %xmm6
|
||||
movdqu -64(%r9, %r8), %xmm7
|
||||
|
||||
movdqu %xmm0, -16(%rdi, %rdx)
|
||||
movdqu %xmm1, -32(%rdi, %rdx)
|
||||
movdqu %xmm2, -48(%rdi, %rdx)
|
||||
movdqu %xmm3, -64(%rdi, %rdx)
|
||||
movdqa %xmm4, -16(%r9)
|
||||
movaps %xmm5, -32(%r9)
|
||||
movaps %xmm6, -48(%r9)
|
||||
movaps %xmm7, -64(%r9)
|
||||
lea -64(%r9), %r9
|
||||
|
||||
lea 64(%rdi), %rbx
|
||||
and $-64, %rbx
|
||||
|
||||
cmp %r9, %rbx
|
||||
jae L(mm_recalc_len)
|
||||
|
||||
cmp $SHARED_CACHE_SIZE_HALF, %rdx
|
||||
jae L(mm_large_page_loop_backward)
|
||||
|
||||
.p2align 4
|
||||
L(mm_main_loop_backward):
|
||||
|
||||
prefetcht0 -128(%r9, %r8)
|
||||
|
||||
movdqu -64(%r9, %r8), %xmm0
|
||||
movdqu -48(%r9, %r8), %xmm1
|
||||
movdqu -32(%r9, %r8), %xmm2
|
||||
movdqu -16(%r9, %r8), %xmm3
|
||||
movdqa %xmm0, -64(%r9)
|
||||
movaps %xmm1, -48(%r9)
|
||||
movaps %xmm2, -32(%r9)
|
||||
movaps %xmm3, -16(%r9)
|
||||
lea -64(%r9), %r9
|
||||
cmp %r9, %rbx
|
||||
jb L(mm_main_loop_backward)
|
||||
jmp L(mm_recalc_len)
|
||||
|
||||
/* Copy [0..16] and return. */
|
||||
L(mm_len_0_16_bytes_backward):
|
||||
testb $24, %dl
|
||||
jnz L(mm_len_9_16_bytes_backward)
|
||||
testb $4, %dl
|
||||
.p2align 4,,5
|
||||
jnz L(mm_len_5_8_bytes_backward)
|
||||
test %rdx, %rdx
|
||||
.p2align 4,,2
|
||||
je L(mm_return)
|
||||
testb $2, %dl
|
||||
.p2align 4,,1
|
||||
jne L(mm_len_3_4_bytes_backward)
|
||||
movzbl -1(%rsi,%rdx), %ebx
|
||||
movzbl (%rsi), %ecx
|
||||
movb %bl, -1(%rdi,%rdx)
|
||||
movb %cl, (%rdi)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_3_4_bytes_backward):
|
||||
movzwl -2(%rsi,%rdx), %ebx
|
||||
movzwl (%rsi), %ecx
|
||||
movw %bx, -2(%rdi,%rdx)
|
||||
movw %cx, (%rdi)
|
||||
jmp L(mm_return)
|
||||
|
||||
L(mm_len_9_16_bytes_backward):
|
||||
movl -4(%rsi,%rdx), %ebx
|
||||
movl -8(%rsi,%rdx), %ecx
|
||||
movl %ebx, -4(%rdi,%rdx)
|
||||
movl %ecx, -8(%rdi,%rdx)
|
||||
sub $8, %rdx
|
||||
jmp L(mm_len_0_16_bytes_backward)
|
||||
|
||||
L(mm_len_5_8_bytes_backward):
|
||||
movl (%rsi), %ebx
|
||||
movl -4(%rsi,%rdx), %ecx
|
||||
movl %ebx, (%rdi)
|
||||
movl %ecx, -4(%rdi,%rdx)
|
||||
|
||||
L(mm_return):
|
||||
pop %r9
|
||||
pop %r8
|
||||
pop %rdx
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
/* Big length copy forward part. */
|
||||
|
||||
.p2align 4
|
||||
L(mm_large_page_loop_forward):
|
||||
movdqu (%r8, %rsi), %xmm0
|
||||
movdqu 16(%r8, %rsi), %xmm1
|
||||
movdqu 32(%r8, %rsi), %xmm2
|
||||
movdqu 48(%r8, %rsi), %xmm3
|
||||
movntdq %xmm0, (%r8)
|
||||
movntdq %xmm1, 16(%r8)
|
||||
movntdq %xmm2, 32(%r8)
|
||||
movntdq %xmm3, 48(%r8)
|
||||
lea 64(%r8), %r8
|
||||
cmp %r8, %rbx
|
||||
ja L(mm_large_page_loop_forward)
|
||||
sfence
|
||||
jmp L(mm_copy_remaining_forward)
|
||||
|
||||
/* Big length copy backward part. */
|
||||
.p2align 4
|
||||
L(mm_large_page_loop_backward):
|
||||
movdqu -64(%r9, %r8), %xmm0
|
||||
movdqu -48(%r9, %r8), %xmm1
|
||||
movdqu -32(%r9, %r8), %xmm2
|
||||
movdqu -16(%r9, %r8), %xmm3
|
||||
movntdq %xmm0, -64(%r9)
|
||||
movntdq %xmm1, -48(%r9)
|
||||
movntdq %xmm2, -32(%r9)
|
||||
movntdq %xmm3, -16(%r9)
|
||||
lea -64(%r9), %r9
|
||||
cmp %r9, %rbx
|
||||
jb L(mm_large_page_loop_backward)
|
||||
sfence
|
||||
jmp L(mm_recalc_len)
|
52
libc/nexgen32e/strlen.S
Normal file
52
libc/nexgen32e/strlen.S
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*-*- mode:unix-assembly; 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"
|
||||
|
||||
/ Returns length of NUL-terminated string.
|
||||
/
|
||||
/ @param rdi is non-null NUL-terminated string pointer
|
||||
/ @return rax is number of bytes (excluding NUL)
|
||||
/ @clob ax,dx,cx,xmm3,xmm4
|
||||
/ @note h/t agner fog
|
||||
/ @asyncsignalsafe
|
||||
strlen: .leafprologue
|
||||
.profilable
|
||||
mov %rdi,%rax
|
||||
mov %edi,%ecx
|
||||
and $15,%ecx
|
||||
and $-16,%rax
|
||||
pxor %xmm4,%xmm4
|
||||
movdqa (%rax),%xmm3
|
||||
pcmpeqb %xmm4,%xmm3
|
||||
pmovmskb %xmm3,%edx
|
||||
shr %cl,%edx
|
||||
shl %cl,%edx
|
||||
bsf %edx,%edx
|
||||
jnz 2f
|
||||
1: lea 16(%rax),%rax
|
||||
movdqa (%rax),%xmm3
|
||||
pcmpeqb %xmm4,%xmm3
|
||||
pmovmskb %xmm3,%edx
|
||||
bsf %edx,%edx
|
||||
jz 1b
|
||||
2: add %rdx,%rax
|
||||
sub %rdi,%rax
|
||||
.leafepilogue
|
||||
.endfn strlen,globl
|
|
@ -42,8 +42,8 @@ int bind(int fd, const void *addr, uint32_t addrsize) {
|
|||
return bind$sysv(fd, addr, addrsize);
|
||||
} else {
|
||||
struct sockaddr_in$bsd addr2;
|
||||
static_assert(sizeof(struct sockaddr_in) ==
|
||||
sizeof(struct sockaddr_in$bsd));
|
||||
_Static_assert(sizeof(struct sockaddr_in) ==
|
||||
sizeof(struct sockaddr_in$bsd));
|
||||
memcpy(&addr2, addr, sizeof(struct sockaddr_in));
|
||||
sockaddr2bsd(&addr2);
|
||||
return bind$sysv(fd, &addr2, addrsize);
|
||||
|
|
|
@ -28,7 +28,8 @@ int connect$sysv(int fd, const void *addr, uint32_t addrsize) {
|
|||
return __connect$sysv(fd, addr, addrsize);
|
||||
} else {
|
||||
struct sockaddr_in$bsd addr2;
|
||||
static_assert(sizeof(struct sockaddr_in) == sizeof(struct sockaddr_in$bsd));
|
||||
_Static_assert(sizeof(struct sockaddr_in) ==
|
||||
sizeof(struct sockaddr_in$bsd));
|
||||
memcpy(&addr2, addr, sizeof(struct sockaddr_in));
|
||||
sockaddr2bsd(&addr2);
|
||||
return connect$sysv(fd, &addr2, addrsize);
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
*/
|
||||
ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
|
||||
const void *opt_addr, uint32_t addrsize) {
|
||||
static_assert(sizeof(struct sockaddr_in) == sizeof(struct sockaddr_in$bsd));
|
||||
_Static_assert(sizeof(struct sockaddr_in) == sizeof(struct sockaddr_in$bsd));
|
||||
if (!IsWindows()) {
|
||||
if (!IsBsd() || !opt_addr) {
|
||||
return sendto$sysv(fd, buf, size, flags, opt_addr, addrsize);
|
||||
|
|
|
@ -21,14 +21,8 @@
|
|||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* Writes byte to stream.
|
||||
*
|
||||
* @return c (as unsigned char) if written or -1 w/ errno
|
||||
*/
|
||||
noinstrument int fputc(int c, FILE *f) {
|
||||
static noinline int __fputcg(int c, FILE *f) {
|
||||
if (f->beg < f->size) {
|
||||
c &= 0xff;
|
||||
f->buf[f->beg++] = c;
|
||||
if (f->beg == f->size || f->bufmode == _IONBF ||
|
||||
(f->bufmode == _IOLBF && c == '\n')) {
|
||||
|
@ -38,8 +32,22 @@ noinstrument int fputc(int c, FILE *f) {
|
|||
f->beg = 0;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
return c & 0xff;
|
||||
} else {
|
||||
return __fseteof(f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes byte to stream.
|
||||
* @return c (as unsigned char) if written or -1 w/ errno
|
||||
* @see putc() if called within loop
|
||||
*/
|
||||
noinstrument int fputc(int c, FILE *f) {
|
||||
if (f->beg + 1 < f->size && f->bufmode == _IOFBF) {
|
||||
f->buf[f->beg++] = c;
|
||||
return c & 0xff;
|
||||
} else {
|
||||
return __fputcg(c, f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,34 +17,37 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/pcmpeqb.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/stdio/internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
static noinline int slowpath(int c, FILE *f) {
|
||||
if (f->beg < f->size) {
|
||||
c &= 0xff;
|
||||
f->buf[f->beg++] = c;
|
||||
if (f->beg == f->size) {
|
||||
if (f->writer) {
|
||||
if (f->writer(f) == -1) return -1;
|
||||
} else if (f->beg == f->size) {
|
||||
f->beg = 0;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
} else {
|
||||
return __fseteof(f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns length of NUL-terminated string.
|
||||
* Writes byte to stream.
|
||||
*
|
||||
* @param s is non-null NUL-terminated string pointer
|
||||
* @return number of bytes (excluding NUL)
|
||||
* @asyncsignalsafe
|
||||
* @return c (as unsigned char) if written or -1 w/ errno
|
||||
*/
|
||||
size_t strlen(const char *s) {
|
||||
const char *p;
|
||||
unsigned k, m;
|
||||
uint8_t v1[16], vz[16];
|
||||
k = (uintptr_t)s & 15;
|
||||
p = (const char *)((uintptr_t)s & -16);
|
||||
memset(vz, 0, 16);
|
||||
memcpy(v1, p, 16);
|
||||
pcmpeqb(v1, v1, vz);
|
||||
m = pmovmskb(v1) >> k << k;
|
||||
while (!m) {
|
||||
p += 16;
|
||||
memcpy(v1, p, 16);
|
||||
pcmpeqb(v1, v1, vz);
|
||||
m = pmovmskb(v1);
|
||||
noinstrument int fputcfb(int c, FILE *f) {
|
||||
if (f->beg + 1 < f->size) {
|
||||
c &= 0xff;
|
||||
f->buf[f->beg++] = c;
|
||||
return c;
|
||||
} else {
|
||||
return slowpath(c, f);
|
||||
}
|
||||
return p + bsf(m) - s;
|
||||
}
|
|
@ -38,7 +38,7 @@ int fputs(const char *s, FILE *f) {
|
|||
int i, n, m;
|
||||
n = strlen(s);
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (fputc(s[i], f) == -1) {
|
||||
if (putc(s[i], f) == -1) {
|
||||
if (ferror(f) == EINTR) continue;
|
||||
if (feof(f)) errno = f->state = EPIPE;
|
||||
return -1;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "libc/str/internal.h"
|
||||
|
||||
/**
|
||||
* Reads data to stream.
|
||||
* Reads data from stream.
|
||||
*
|
||||
* @param stride specifies the size of individual items
|
||||
* @param count is the number of strides to fetch
|
||||
|
@ -36,7 +36,7 @@ size_t fread(void *buf, size_t stride, size_t count, FILE *f) {
|
|||
size_t i, n;
|
||||
unsigned char *p;
|
||||
for (n = stride * count, p = buf, i = 0; i < n; ++i) {
|
||||
if ((c = fgetc(f)) != -1) {
|
||||
if ((c = getc(f)) != -1) {
|
||||
p[i] = c & 0xff;
|
||||
} else if (!(i % stride)) {
|
||||
return i / stride;
|
||||
|
|
|
@ -19,5 +19,5 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/internal.h"
|
||||
|
||||
alignas(PAGESIZE) unsigned char g_stdoutbuf[BUFSIZ];
|
||||
alignas(PAGESIZE) unsigned char g_stderrbuf[BUFSIZ];
|
||||
_Alignas(PAGESIZE) unsigned char g_stdoutbuf[BUFSIZ];
|
||||
_Alignas(PAGESIZE) unsigned char g_stderrbuf[BUFSIZ];
|
||||
|
|
|
@ -100,8 +100,8 @@ int vfscanf(FILE *, const char *, va_list);
|
|||
│ cosmopolitan § standard i/o » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define putc(c, f) fputc(c, f)
|
||||
#define getc(f) (f->beg < f->end ? f->buf[f->beg++] : fgetc(f))
|
||||
#define putc(c, f) fputc(c, f)
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* @param line is NULL-propagating
|
||||
* @see getline
|
||||
*/
|
||||
char *(chomp)(char *line) {
|
||||
char *chomp(char *line) {
|
||||
size_t i;
|
||||
for (i = strlen(line); i--;) {
|
||||
if (line[i] == '\r' || line[i] == '\n') {
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/str/utf16.h"
|
||||
|
||||
/**
|
||||
* Helps runtime decode UTF-16 with slightly smaller code size.
|
||||
*/
|
||||
wint_t DecodeNtsUtf16(const char16_t **s) {
|
||||
wint_t x, y;
|
||||
for (;;) {
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Converts ASCII hexadecimal character to integer case-insensitively.
|
||||
* @return integer or 0 if c ∉ [0-9A-Fa-f]
|
||||
*/
|
||||
int hextoint(int c) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns nonzero if c is printable ascii that isn't space.
|
||||
*/
|
||||
int isgraph(int c) {
|
||||
return 0x21 <= c && c <= 0x7E;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns nonzero if c is printable ascii including space.
|
||||
*/
|
||||
int isprint(int c) {
|
||||
return 0x20 <= c && c <= 0x7E;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns nonzero if c ∈ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
|
||||
*/
|
||||
int ispunct(int c) {
|
||||
return (0x21 <= c && c <= 0x7E) && !('0' <= c && c <= '9') &&
|
||||
!('A' <= c && c <= 'Z') && !('a' <= c && c <= 'z');
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
compatfn int mbtowc(wchar_t *wc, const char *s, size_t n) {
|
||||
if (!s) return 0;
|
||||
alignas(8) char alt[ROUNDUP(MB_CUR_MAX, 8)];
|
||||
_Alignas(8) char alt[ROUNDUP(MB_CUR_MAX, 8)];
|
||||
if (n < MB_CUR_MAX) {
|
||||
memset(alt, 0, sizeof(alt));
|
||||
memcpy(alt, s, n);
|
||||
|
|
|
@ -233,37 +233,21 @@ int iswctype(wint_t, wctype_t) pureconst;
|
|||
|
||||
char *strsignal(int) returnsnonnull libcesque;
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § strings » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
#define explicit_bzero(STR, BYTES) \
|
||||
do { \
|
||||
void *Str; \
|
||||
size_t Bytes; \
|
||||
asm volatile("call\texplicit_bzero" \
|
||||
: "=D"(Str), "=S"(Bytes) \
|
||||
: "0"(STR), "1"(BYTES) \
|
||||
: "rax", "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", \
|
||||
"cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); \
|
||||
} while (0)
|
||||
#define __memcpy_isgoodsize(SIZE) \
|
||||
(__builtin_constant_p(SIZE) && ((SIZE) <= __BIGGEST_ALIGNMENT__ * 2 && \
|
||||
__builtin_popcountl((unsigned)(SIZE)) == 1))
|
||||
|
||||
#ifdef UNBLOAT_STDARG
|
||||
#define __STR_XMM_CLOBBER
|
||||
#else
|
||||
#define __STR_XMM_CLOBBER "xmm3", "xmm4",
|
||||
#endif
|
||||
|
||||
#define __memcpy_isgoodsize(SIZE) \
|
||||
(isconstant(SIZE) && ((SIZE) <= __BIGGEST_ALIGNMENT__ * 2 && \
|
||||
__builtin_popcountl((unsigned)(SIZE)) == 1))
|
||||
|
||||
#define __memset_isgoodsize(SIZE) \
|
||||
(isconstant(SIZE) && (((SIZE) <= __BIGGEST_ALIGNMENT__ && \
|
||||
__builtin_popcountl((unsigned)(SIZE)) == 1) || \
|
||||
((SIZE) % __BIGGEST_ALIGNMENT__ == 0 && \
|
||||
(SIZE) / __BIGGEST_ALIGNMENT__ <= 3)))
|
||||
#define __memset_isgoodsize(SIZE) \
|
||||
(__builtin_constant_p(SIZE) && \
|
||||
(((SIZE) <= __BIGGEST_ALIGNMENT__ && \
|
||||
__builtin_popcountl((unsigned)(SIZE)) == 1) || \
|
||||
((SIZE) % __BIGGEST_ALIGNMENT__ == 0 && \
|
||||
(SIZE) / __BIGGEST_ALIGNMENT__ <= 3)))
|
||||
|
||||
#define memcpy(DEST, SRC, SIZE) \
|
||||
(__memcpy_isgoodsize(SIZE) ? __builtin_memcpy(DEST, SRC, SIZE) \
|
||||
|
@ -273,7 +257,18 @@ char *strsignal(int) returnsnonnull libcesque;
|
|||
(__memset_isgoodsize(SIZE) ? __builtin_memset(DEST, BYTE, SIZE) \
|
||||
: __memset(DEST, BYTE, SIZE))
|
||||
|
||||
#if defined(__STDC_HOSTED__) && (defined(__SSE2__) || defined(UNBLOAT_STDARG))
|
||||
#if defined(__STDC_HOSTED__) && defined(__SSE2__)
|
||||
|
||||
#define strlen(STR) \
|
||||
(__builtin_constant_p(STR) ? __builtin_strlen(STR) : ({ \
|
||||
size_t LeN; \
|
||||
const char *StR = (STR); \
|
||||
asm("call\tstrlen" \
|
||||
: "=a"(LeN) \
|
||||
: "D"(StR), "m"(*(char(*)[0x7fffffff])StR) \
|
||||
: "rcx", "rdx", "xmm3", "xmm4", "cc"); \
|
||||
LeN; \
|
||||
}))
|
||||
|
||||
#define memmove(DEST, SRC, SIZE) __memcpy("MemMove", (DEST), (SRC), (SIZE))
|
||||
|
||||
|
@ -291,7 +286,7 @@ char *strsignal(int) returnsnonnull libcesque;
|
|||
asm("call\t" FN \
|
||||
: "=m"(*(char(*)[SiZe])(DeSt)) \
|
||||
: "D"(DeSt), "S"(SrC), "d"(SiZe), "m"(*(const char(*)[SiZe])(SrC)) \
|
||||
: __STR_XMM_CLOBBER "rcx", "cc"); \
|
||||
: "xmm3", "xmm4", "rcx", "cc"); \
|
||||
DeSt; \
|
||||
})
|
||||
|
||||
|
@ -302,11 +297,22 @@ char *strsignal(int) returnsnonnull libcesque;
|
|||
asm("call\tMemSet" \
|
||||
: "=m"(*(char(*)[SiZe])(DeSt)) \
|
||||
: "D"(DeSt), "S"(BYTE), "d"(SiZe) \
|
||||
: __STR_XMM_CLOBBER "rcx", "cc"); \
|
||||
: "xmm3", "xmm4", "rcx", "cc"); \
|
||||
DeSt; \
|
||||
})
|
||||
|
||||
#else /* hosted/sse2/unbloat */
|
||||
#define explicit_bzero(STR, BYTES) \
|
||||
do { \
|
||||
void *Str; \
|
||||
size_t Bytes; \
|
||||
asm volatile("call\texplicit_bzero" \
|
||||
: "=D"(Str), "=S"(Bytes) \
|
||||
: "0"(STR), "1"(BYTES) \
|
||||
: "rax", "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", \
|
||||
"cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); \
|
||||
} while (0)
|
||||
|
||||
#else /* hosted+sse2 */
|
||||
|
||||
#define mempcpy(DEST, SRC, SIZE) \
|
||||
({ \
|
||||
|
@ -347,7 +353,6 @@ char *strsignal(int) returnsnonnull libcesque;
|
|||
})
|
||||
|
||||
#endif /* hosted/sse2/unbloat */
|
||||
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
@ -34,7 +35,7 @@ size_t strlcpy(char *d, const char *s, size_t n) {
|
|||
size_t slen, actual;
|
||||
slen = strlen(s);
|
||||
if (n) {
|
||||
actual = min(n, slen);
|
||||
actual = MIN(n, slen);
|
||||
memcpy(d, s, actual);
|
||||
d[actual] = '\0';
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
static const char kSig[4] = "SIG";
|
||||
static const char kUnknown[8] = "UNKNOWN";
|
||||
|
||||
alignas(1) static const char kStrSignals[][8] = {
|
||||
_Alignas(char) static const char kStrSignals[][8] = {
|
||||
"EXIT", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "BUS",
|
||||
"FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM",
|
||||
"STKFLT", "CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "URG",
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "libc/nexgen32e/bsr.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/* TODO(jart): DELETE? */
|
||||
|
||||
/**
|
||||
* Generic Thompson-Pike Varint Decoder.
|
||||
* @return number of bytes successfully consumed or -1 w/ errno
|
||||
|
@ -12,11 +14,11 @@
|
|||
forceinline int tpdecodecb(wint_t *out, int first,
|
||||
int get(void *arg, uint32_t i), void *arg) {
|
||||
uint32_t wc, cb, need, msb, j, i = 1;
|
||||
if (unlikely((wc = first) == -1)) return -1;
|
||||
while (unlikely((wc & 0b11000000) == 0b10000000)) {
|
||||
if (__builtin_expect((wc = first) == -1, 0)) return -1;
|
||||
while (__builtin_expect((wc & 0b11000000) == 0b10000000, 0)) {
|
||||
if ((wc = get(arg, i++)) == -1) return -1;
|
||||
}
|
||||
if (unlikely(!(0 <= wc && wc <= 0x7F))) {
|
||||
if (__builtin_expect(!(0 <= wc && wc <= 0x7F), 0)) {
|
||||
msb = wc < 252 ? bsr(~wc & 0xff) : 1;
|
||||
need = 7 - msb;
|
||||
wc &= ((1u << msb) - 1) | 0b00000011;
|
||||
|
@ -30,7 +32,7 @@ forceinline int tpdecodecb(wint_t *out, int first,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (likely(out)) *out = (wint_t)wc;
|
||||
if (__builtin_expect(!!out, 1)) *out = (wint_t)wc;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/tpencode.internal.h"
|
||||
|
||||
/* TODO: DELETE */
|
||||
|
||||
/**
|
||||
* Thompson-Pike Varint Encoder.
|
||||
*
|
||||
|
|
|
@ -11,13 +11,14 @@ COSMOPOLITAN_C_START_
|
|||
#define IsUcs2(wc) (((wc)&UTF16_MASK) != UTF16_MOAR)
|
||||
#define IsUtf16Cont(wc) (((wc)&UTF16_MASK) == UTF16_CONT)
|
||||
#define MergeUtf16(lo, hi) ((((lo)-0xD800) << 10) + ((hi)-0xDC00) + 0x10000)
|
||||
#define EncodeUtf16(wc) \
|
||||
(likely((0x0000 <= (wc) && (wc) <= 0xFFFF) || \
|
||||
(0xE000 <= (wc) && (wc) <= 0xFFFF)) \
|
||||
? (wc) \
|
||||
: 0x10000 <= (wc) && (wc) <= 0x10FFFF \
|
||||
? (((((wc)-0x10000) >> 10) + 0xD800) | \
|
||||
((((wc)-0x10000) & 1023) + 0xDC00) << 16) \
|
||||
#define EncodeUtf16(wc) \
|
||||
(__builtin_expect(((0x0000 <= (wc) && (wc) <= 0xFFFF) || \
|
||||
(0xE000 <= (wc) && (wc) <= 0xFFFF)), \
|
||||
1) \
|
||||
? (wc) \
|
||||
: 0x10000 <= (wc) && (wc) <= 0x10FFFF \
|
||||
? (((((wc)-0x10000) >> 10) + 0xD800) | \
|
||||
((((wc)-0x10000) & 1023) + 0xDC00) << 16) \
|
||||
: 0xFFFD)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#define __BENCH_ARRAY(S) \
|
||||
_Section(".piro.relo.sort.bench.2." #S ",\"aw\",@init_array #")
|
||||
|
||||
#define __TEST_PROTOTYPE(S, N, A, K) \
|
||||
testonly void S##_##N(void); \
|
||||
alignas(8) const void *const S##_##N##_ptr[] A(S) = {S##_##N}; \
|
||||
#define __TEST_PROTOTYPE(S, N, A, K) \
|
||||
testonly void S##_##N(void); \
|
||||
_Alignas(long) const void *const S##_##N##_ptr[] A(S) = {S##_##N}; \
|
||||
testonly K void S##_##N(void)
|
||||
|
||||
#define __TEST_SECTION(NAME, CONTENT) \
|
||||
|
|
|
@ -45,6 +45,7 @@ char *xstrdup(const char *) _XPNN _XMAL;
|
|||
char *xstrndup(const char *, size_t) _XPNN _XMAL;
|
||||
char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL;
|
||||
char *xstrmul(const char *, size_t) paramsnonnull((1)) _XMAL;
|
||||
char *xdirname(const char *) paramsnonnull() _XMAL;
|
||||
char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL;
|
||||
char *xinet_ntop(int, const void *) _XPNN _XMAL;
|
||||
|
||||
|
|
28
libc/x/xdirname.c
Normal file
28
libc/x/xdirname.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/fmt/conv.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Returns directory portion of path.
|
||||
*/
|
||||
char *xdirname(const char *path) {
|
||||
return dirname(xstrdup(path));
|
||||
}
|
|
@ -22,14 +22,25 @@
|
|||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Joins paths.
|
||||
* Joins paths, e.g.
|
||||
*
|
||||
* "a" + "b" → "a/b"
|
||||
* "a/" + "b" → "a/b"
|
||||
* "a" + "b/" → "a/b/"
|
||||
* "a" + "/b" → "/b"
|
||||
* "." + "b" → "b"
|
||||
* "" + "b" → "b"
|
||||
*
|
||||
* @return newly allocated string of resulting path
|
||||
*/
|
||||
char *xjoinpaths(const char *path, const char *other) {
|
||||
if (!*other) {
|
||||
return xstrdup(path);
|
||||
} else if (startswith(other, "/") || strcmp(path, ".") == 0) {
|
||||
} else if (!*path) {
|
||||
return xstrdup(other);
|
||||
} else if (endswith(other, "/")) {
|
||||
} else if (startswith(other, "/") || !strcmp(path, ".")) {
|
||||
return xstrdup(other);
|
||||
} else if (endswith(path, "/")) {
|
||||
return xstrcat(path, other);
|
||||
} else {
|
||||
return xstrcat(path, '/', other);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue