Skip to content

Commit 9b9b919

Browse files
committed
Better implementation of builtin functions when compiling wasm with clang
1 parent 03a3f54 commit 9b9b919

4 files changed

Lines changed: 49 additions & 30 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ examples/%: examples/%.c extlib.h
1919
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
2020

2121
examples/03_arena.wasm: examples/03_arena.c extlib.h
22-
clang $(CFLAGS) -DEXTLIB_WASM=1 \
22+
clang $(CFLAGS) \
2323
-std=c99 -fno-builtin --target=wasm32 --no-standard-libraries \
2424
-Wl,--no-entry \
2525
-Wl,--allow-undefined \

examples/03_arena.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
#include <stddef.h>
1111
#include <stdint.h>
1212

13+
#define EXTLIB_IMPL
14+
#include "../extlib.h"
15+
1316
#ifndef EXTLIB_WASM
1417
#include <stdio.h>
1518
#else
1619
int printf(const char *fmt, ...);
1720
#endif
1821

19-
#define EXTLIB_IMPL
20-
#include "../extlib.h"
21-
2222
static Arena arena = make_arena();
2323

2424
static const char *prec[] = {"+-", "*/"};

examples/03_arena.html

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@
2626
}
2727

2828
window.w = await WebAssembly.instantiateStreaming(fetch("./03_arena.wasm"), {
29-
"env": make_environment({
30-
assert: function(c) {
31-
if(!c) throw new Error("Assertion failed");
32-
}
33-
})
29+
"env": make_environment()
3430
});
3531
})();
3632
</script>

extlib.h

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
* Changelog:
4545
*
4646
* v2.0.1:
47+
* Better implementations of builtin functions when compiling wasm with clang
4748
* Correctly mark `ext_allocator_memdup` and `ext_allocator_strdup` inline.
4849
*
4950
* v2.0.0:
@@ -125,6 +126,10 @@
125126
#include <stddef.h>
126127
#include <stdint.h>
127128

129+
#if defined(__wasm__) && !defined(EXTLIB_WASM)
130+
#define EXTLIB_WASM
131+
#endif
132+
128133
#ifdef EXTLIB_WASM
129134
#ifndef EXTLIB_NO_STD
130135
#define EXTLIB_NO_STD
@@ -169,7 +174,21 @@
169174
#include <stdio.h>
170175
#include <stdlib.h>
171176
#include <string.h>
172-
#else // EXTLIB_NO_STD
177+
#elif defined(EXTLIB_WASM) && defined(__clang__)
178+
#define memcmp __builtin_memcmp
179+
#define memcpy __builtin_memcpy
180+
#define memset __builtin_memset
181+
#define memchr __builtin_memchr
182+
static inline int strcmp(const char *l, const char *r) {
183+
for(; *l == *r && *l; l++, r++);
184+
return *(unsigned char *)l - *(unsigned char *)r;
185+
}
186+
static inline size_t strlen(const char *s) {
187+
size_t len = 0;
188+
while(s[len] != '\0') len++;
189+
return len;
190+
}
191+
#else
173192
static inline int memcmp(const void *s1, const void *s2, size_t n) {
174193
const unsigned char *p1 = (const unsigned char *)s1;
175194
const unsigned char *p2 = (const unsigned char *)s2;
@@ -193,6 +212,14 @@ static inline void *memset(void *s, int c, size_t n) {
193212
while(n--) *p++ = (unsigned char)c;
194213
return s;
195214
}
215+
static inline void *memchr(const void *src_void, int c, size_t length) {
216+
const uint8_t *src = (const uint8_t *)src_void;
217+
while(length-- > 0) {
218+
if(*src == c) return (void *)src;
219+
src++;
220+
}
221+
return NULL;
222+
}
196223
static inline size_t strlen(const char *s) {
197224
size_t len = 0;
198225
while(s[len] != '\0') len++;
@@ -202,7 +229,6 @@ static inline int strcmp(const char *l, const char *r) {
202229
for(; *l == *r && *l; l++, r++);
203230
return *(unsigned char *)l - *(unsigned char *)r;
204231
}
205-
void assert(int c); // TODO: are we sure we want to require wasm embedder to provide `assert`?
206232
#endif // EXTLIB_NO_STD
207233

208234
#ifdef EXTLIB_THREADSAFE
@@ -232,6 +258,7 @@ void assert(int c); // TODO: are we sure we want to require wasm embedder to pr
232258
// Assert is disabled when compiling with NDEBUG, unreachable is instead replaced with compiler
233259
// intrinsics on gcc, clang and msvc.
234260
#ifndef NDEBUG
261+
235262
#ifndef EXTLIB_NO_STD
236263
#define EXT_ASSERT(cond, msg) \
237264
((cond) ? ((void)0) \
@@ -240,21 +267,33 @@ void assert(int c); // TODO: are we sure we want to require wasm embedder to pr
240267

241268
#define EXT_UNREACHABLE() \
242269
(fprintf(stderr, "%s:%d: error: reached unreachable code\n", __FILE__, __LINE__), abort())
270+
271+
#elif defined(EXTLIB_WASM) && defined(__clang__)
272+
273+
#define EXT_ASSERT(cond, msg) \
274+
do { \
275+
if(!(cond)) __builtin_trap(); \
276+
} while(0)
277+
278+
#define EXT_UNREACHABLE() __builtin_trap()
279+
243280
#else
244281
#define EXT_ASSERT(cond, msg) assert((cond) && msg)
245282
#define EXT_UNREACHABLE() assert(false && "reached unreachable code")
246283
#endif // EXTLIB_NO_STD
247284

248-
#else
249-
#define EXT_ASSERT(cond, msg) ((void)(cond))
285+
#else // NDEBUG
286+
#define EXT_ASSERT(cond, msg) \
287+
do { \
288+
} while(0)
250289

251290
#if defined(__GNUC__) || defined(__clang__)
252291
#define EXT_UNREACHABLE() __builtin_unreachable()
253292
#elif defined(_MSC_VER)
254293
#include <stdlib.h>
255294
#define EXT_UNREACHABLE() __assume(0)
256295
#else
257-
#define EXT_UNREACHABLE()
296+
#define EXT_UNREACHABLE() ((void)0)
258297
#endif // defined(__GNUC__) || defined(__clang__)
259298

260299
#endif // NDEBUG
@@ -2494,18 +2533,9 @@ void ext_sb_replace(Ext_StringBuffer *sb, size_t start, const char *to_replace,
24942533
EXT_ASSERT(start < sb->size, "start out of bounds");
24952534
size_t to_replace_len = strlen(to_replace);
24962535
for(size_t i = start; i < sb->size; i++) {
2497-
#ifdef EXTLIB_NO_STD
2498-
for(size_t j = 0; j < to_replace_len; j++) {
2499-
if(sb->items[i] == to_replace[j]) {
2500-
sb->items[i] = replacment;
2501-
break;
2502-
}
2503-
}
2504-
#else
25052536
if(memchr(to_replace, sb->items[i], to_replace_len) != NULL) {
25062537
sb->items[i] = replacment;
25072538
}
2508-
#endif
25092539
}
25102540
}
25112541

@@ -2689,14 +2719,7 @@ ptrdiff_t ext_ss_rfind_cstr(Ext_StringSlice ss, const char *needle, size_t offse
26892719
}
26902720

26912721
static bool any_match(char c, const char *set, size_t set_len) {
2692-
#ifdef EXTLIB_NO_STD
2693-
for(size_t i = 0; i < set_len; i++) {
2694-
if(c == set[i]) return true;
2695-
}
2696-
return false;
2697-
#else
26982722
return memchr(set, c, set_len) != NULL;
2699-
#endif // EXTLIB_NO_STD
27002723
}
27012724

27022725
Ext_StringSlice ext_ss_split_once_any(Ext_StringSlice *ss, const char *set) {

0 commit comments

Comments
 (0)