Use SIMD libc.

This commit is contained in:
Nuno Cruces
2025-04-07 12:49:01 +01:00
parent a3ce8f9de5
commit 73ac7e06f6
28 changed files with 787 additions and 421 deletions

View File

@@ -19,15 +19,17 @@ trap 'rm -f libc.tmp' EXIT
-mnontrapping-fptoint -msign-ext \
-fno-stack-protector -fno-stack-clash-protection \
-Wl,--initial-memory=16777216 \
-Wl,--export=memset \
-Wl,--export=memcpy \
-Wl,--export=memchr \
-Wl,--export=memcmp \
-Wl,--export=strlen \
-Wl,--export=memcpy \
-Wl,--export=memset \
-Wl,--export=strchr \
-Wl,--export=strchrnul \
-Wl,--export=strcmp \
-Wl,--export=strcspn \
-Wl,--export=strlen \
-Wl,--export=strncmp \
-Wl,--export=strchrnul
-Wl,--export=strspn
"$BINARYEN/wasm-ctor-eval" -g -c _initialize libc.wasm -o libc.tmp
"$BINARYEN/wasm-opt" -g --strip --strip-producers -c -O3 \

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
#include "strings.c"
// Amalgamation
#include "sqlite3.c"
// Extensions
@@ -10,12 +11,11 @@
#include "ext/spellfix.c"
#include "ext/uint.c"
// Bindings
#include "bind.c"
#include "column.c"
#include "func.c"
#include "hooks.c"
#include "pointer.c"
#include "result.c"
#include "stmt.c"
#include "text.c"
#include "time.c"
#include "vfs.c"
#include "vtab.c"

View File

@@ -1,14 +0,0 @@
#include <math.h>
#include <stdlib.h>
#include "sqlite3.h"
void sqlite3_result_text_go(sqlite3_context *ctx, const char *zData,
sqlite3_uint64 nData) {
sqlite3_result_text64(ctx, zData, nData, &sqlite3_free, SQLITE_UTF8);
}
void sqlite3_result_blob_go(sqlite3_context *ctx, const void *zData,
sqlite3_uint64 nData) {
sqlite3_result_blob64(ctx, zData, nData, &sqlite3_free);
}

View File

@@ -16,14 +16,12 @@
// #define SQLITE_OMIT_DECLTYPE
// #define SQLITE_OMIT_PROGRESS_CALLBACK
// TODO add this:
// #define SQLITE_ENABLE_API_ARMOR
// Other Options
#define SQLITE_ALLOW_URI_AUTHORITY
#define SQLITE_TRUSTED_SCHEMA 0
#define SQLITE_DEFAULT_FOREIGN_KEYS 1
#define SQLITE_ENABLE_API_ARMOR
#define SQLITE_ENABLE_ATOMIC_WRITE
#define SQLITE_ENABLE_BATCH_ATOMIC_WRITE
#define SQLITE_ENABLE_COLUMN_METADATA

View File

@@ -2,6 +2,11 @@
#include "sqlite3.h"
int sqlite3_exec_go(sqlite3_stmt *stmt) {
while (sqlite3_step(stmt) == SQLITE_ROW);
return sqlite3_reset(stmt);
}
union sqlite3_data {
sqlite3_int64 i;
double d;
@@ -16,7 +21,7 @@ int sqlite3_columns_go(sqlite3_stmt *stmt, int nCol, char *aType,
if (nCol != sqlite3_column_count(stmt)) {
return SQLITE_MISUSE;
}
int rc = SQLITE_OK;
bool check = false;
for (int i = 0; i < nCol; ++i) {
const void *ptr = NULL;
switch (aType[i] = sqlite3_column_type(stmt, i)) {
@@ -36,16 +41,14 @@ int sqlite3_columns_go(sqlite3_stmt *stmt, int nCol, char *aType,
ptr = sqlite3_column_blob(stmt, i);
break;
}
if (ptr == NULL && rc == SQLITE_OK) {
rc = sqlite3_errcode(sqlite3_db_handle(stmt));
if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
rc = SQLITE_OK;
}
}
aData[i].ptr = ptr;
aData[i].len = sqlite3_column_bytes(stmt, i);
if (ptr == NULL) check = true;
}
return rc;
if (check && SQLITE_NOMEM == sqlite3_errcode(sqlite3_db_handle(stmt))) {
return SQLITE_NOMEM;
}
return SQLITE_OK;
}
static_assert(offsetof(union sqlite3_data, i) == 0, "Unexpected offset");

View File

@@ -1,5 +1,3 @@
#include <__macro_PAGESIZE.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <wasm_simd128.h>
@@ -27,7 +25,7 @@ int memcmp(const void *v1, const void *v2, size_t n) {
const v128_t *w2 = v2;
for (; n >= sizeof(v128_t); n -= sizeof(v128_t)) {
if (wasm_v128_any_true(wasm_v128_load(w1) ^ wasm_v128_load(w2))) {
break; // *w1 != *w2
break;
}
w1++;
w2++;
@@ -50,7 +48,7 @@ void *memchr(const void *v, int c, size_t n) {
const v128_t *w = (void *)v;
for (; n >= sizeof(v128_t); n -= sizeof(v128_t)) {
if (wasm_v128_any_true(wasm_i8x16_eq(wasm_v128_load(w), wc))) {
break; // *w has a c
break;
}
w++;
}
@@ -64,51 +62,41 @@ void *memchr(const void *v, int c, size_t n) {
}
size_t strlen(const char *s) {
const v128_t *const limit =
(v128_t *)(__builtin_wasm_memory_size(0) * PAGESIZE) - 1;
uintptr_t align = (uintptr_t)s % sizeof(v128_t);
const v128_t *w = (void *)(s - align);
const v128_t *w = (void *)s;
while (w <= limit) {
if (!wasm_i8x16_all_true(wasm_v128_load(w))) {
break; // *w has a NUL
while (true) {
int mask =
wasm_i8x16_bitmask(wasm_i8x16_eq(*w, (v128_t){})) >> align << align;
if (mask) {
return (char *)w - s + __builtin_ctz(mask);
}
align = 0;
w++;
}
const char *ss = (void *)w;
while (true) {
if (*ss == 0) break;
ss++;
}
return ss - s;
}
int strcmp(const char *s1, const char *s2) {
const v128_t *const limit =
(v128_t *)(__builtin_wasm_memory_size(0) * PAGESIZE) - 1;
const v128_t *w1 = (void *)s1;
const v128_t *w2 = (void *)s2;
while (w1 <= limit && w2 <= limit) {
if (wasm_v128_any_true(wasm_v128_load(w1) ^ wasm_v128_load(w2))) {
break; // *w1 != *w2
if (((uintptr_t)s1 | (uintptr_t)s2) % sizeof(v128_t) == 0) {
while (!wasm_v128_any_true(*w1 ^ *w2)) {
if (!wasm_i8x16_all_true(*w1)) {
return 0;
}
w1++;
w2++;
}
if (!wasm_i8x16_all_true(wasm_v128_load(w1))) {
return 0; // *w1 == *w2 and have a NUL
}
w1++;
w2++;
}
const uint8_t *u1 = (void *)w1;
const uint8_t *u2 = (void *)w2;
while (true) {
if (*u1 != *u2) return *u1 - *u2;
if (*u1 == 0) break;
if (*u1 == 0) return 0;
u1++;
u2++;
}
return 0;
}
int strncmp(const char *s1, const char *s2, size_t n) {
@@ -116,10 +104,10 @@ int strncmp(const char *s1, const char *s2, size_t n) {
const v128_t *w2 = (void *)s2;
for (; n >= sizeof(v128_t); n -= sizeof(v128_t)) {
if (wasm_v128_any_true(wasm_v128_load(w1) ^ wasm_v128_load(w2))) {
break; // *w1 != *w2
break;
}
if (!wasm_i8x16_all_true(wasm_v128_load(w1))) {
return 0; // *w1 == *w2 and have a NUL
return 0;
}
w1++;
w2++;
@@ -139,27 +127,24 @@ int strncmp(const char *s1, const char *s2, size_t n) {
char *strchrnul(const char *s, int c) {
c = (char)c;
const v128_t *const limit =
(v128_t *)(__builtin_wasm_memory_size(0) * PAGESIZE) - 1;
if (__builtin_constant_p(c) && c == 0) {
return (char *)s + strlen(s);
}
uintptr_t align = (uintptr_t)s % sizeof(v128_t);
const v128_t *w = (void *)(s - align);
const v128_t wc = wasm_i8x16_splat(c);
const v128_t *w = (void *)s;
while (w <= limit) {
if (!wasm_i8x16_all_true(wasm_v128_load(w))) {
break; // *w has a NUL
}
if (wasm_v128_any_true(wasm_i8x16_eq(wasm_v128_load(w), wc))) {
break; // *w has a c
while (true) {
int mask = wasm_i8x16_bitmask(wasm_i8x16_eq(*w, (v128_t){}) |
wasm_i8x16_eq(*w, wc)) >>
align << align;
if (mask) {
return (char *)w + __builtin_ctz(mask);
}
align = 0;
w++;
}
s = (void *)w;
while (true) {
if (*s == 0 || *s == c) break;
s++;
}
return (void *)s;
}
char *strchr(const char *s, int c) {
@@ -168,3 +153,29 @@ char *strchr(const char *s, int c) {
}
#endif
#define BITOP(a, b, op) \
((a)[(b) / (8 * sizeof(size_t))] op((size_t)1) \
<< ((b) % (8 * sizeof(size_t))))
size_t strspn(const char *s, const char *c) {
const char *const a = s;
size_t byteset[32 / sizeof(size_t)] = {0};
for (; *c && BITOP(byteset, *(uint8_t *)c, |=); c++);
for (; *s && BITOP(byteset, *(uint8_t *)s, &); s++);
return s - a;
}
size_t strcspn(const char *s, const char *c) {
if (!c[0] || !c[1]) return strchrnul(s, *c) - s;
const char *const a = s;
size_t byteset[32 / sizeof(size_t)] = {0};
for (; *c && BITOP(byteset, *(uint8_t *)c, |=); c++);
for (; *s && !BITOP(byteset, *(uint8_t *)s, &); s++);
return s - a;
}
#undef BITOP

View File

@@ -10,4 +10,14 @@ int sqlite3_bind_text_go(sqlite3_stmt *stmt, int i, const char *zData,
int sqlite3_bind_blob_go(sqlite3_stmt *stmt, int i, const char *zData,
sqlite3_uint64 nData) {
return sqlite3_bind_blob64(stmt, i, zData, nData, &sqlite3_free);
}
void sqlite3_result_text_go(sqlite3_context *ctx, const char *zData,
sqlite3_uint64 nData) {
sqlite3_result_text64(ctx, zData, nData, &sqlite3_free, SQLITE_UTF8);
}
void sqlite3_result_blob_go(sqlite3_context *ctx, const void *zData,
sqlite3_uint64 nData) {
sqlite3_result_blob64(ctx, zData, nData, &sqlite3_free);
}