Skip to content

Commit 780d8e7

Browse files
some huge performance improvements in our micro libc
1 parent b99bc52 commit 780d8e7

File tree

10 files changed

+228
-251
lines changed

10 files changed

+228
-251
lines changed

include/basic/tokenizer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@
5050

5151
#define EMIT_FROM_FLAG(name, flag, dispatcher) EMIT_##flag(name, dispatcher)
5252

53+
/* Per-token compile-time string length */
54+
#define GENERATE_STRING_LENGTH(NAME, ...) (sizeof(#NAME) - 1u),
55+
56+
/* Builds: const unsigned char token_name_lengths[] = { ... }; */
57+
#define GENERATE_ENUM_STRING_LENGTHS(MACRO, ARRAY_NAME) \
58+
const unsigned char ARRAY_NAME[] = { MACRO(GENERATE_STRING_LENGTH) };
59+
5360
/* Handler function type */
5461
typedef void (*keyword_handler_t)(struct basic_ctx*);
5562

include/string.h

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ int stricmp(const char* s1, const char* s2);
5454
* @param n Number of characters to compare
5555
* @return int Comparison result as with strcmp()
5656
*/
57-
int strncmp(const char* s1, const char* s2, uint32_t n);
57+
__attribute__((hot)) int strncmp(const char* s1, const char* s2, uint32_t n);
5858

5959
/**
6060
* @brief Compare first n characters of two strings (case-insensitive).
@@ -72,47 +72,75 @@ int strnicmp(const char* s1, const char* s2, uint32_t n);
7272
* @param low Character to convert
7373
* @return char Uppercase equivalent if alphabetic, otherwise unchanged
7474
*/
75-
char toupper(char low);
75+
static inline char __attribute__((always_inline)) toupper(char low) {
76+
return low >= 'a' && low <= 'z' ? low - 32 : low;
77+
}
7678

7779
/**
7880
* @brief Check if a character is uppercase.
7981
*
8082
* @param x Character to check
8183
* @return int Non-zero if uppercase, 0 otherwise
8284
*/
83-
int isupper(const char x);
85+
static inline int __attribute__((always_inline)) isupper(const char x)
86+
{
87+
return (unsigned)(x - 'A') <= ('Z' - 'A');
88+
}
8489

8590
/**
8691
* @brief Convert a character to lowercase.
8792
*
8893
* @param low Character to convert
8994
* @return char Lowercase equivalent if alphabetic, otherwise unchanged
9095
*/
91-
char tolower(char low);
96+
static inline char __attribute__((always_inline)) tolower(char low) {
97+
return low >= 'A' && low <= 'Z' ? low + 32 : low;
98+
}
99+
92100

93101
/**
94-
* @brief Check if a character is alphanumeric.
102+
* @brief Check if a character is alphabetic.
95103
*
96104
* @param x Character to check
97-
* @return int Non-zero if alphanumeric, 0 otherwise
105+
* @return bool true if alphabetic, false otherwise
98106
*/
99-
int isalnum(const char x);
107+
static inline bool __attribute__((always_inline)) isalpha(const char x)
108+
{
109+
unsigned char c = (unsigned char)(x | 0x20);
110+
return (unsigned)(c - 'a') <= ('z' - 'a');
111+
}
112+
113+
static inline unsigned char __attribute__((always_inline)) isdigit(const char x)
114+
{
115+
return (unsigned)(x - '0') <= 9;
116+
}
117+
118+
static inline unsigned char __attribute__((always_inline)) isxdigit(const char x)
119+
{
120+
return (x >= '0' && x <= '9') || (x >= 'A' && x <= 'F');
121+
}
100122

101123
/**
102-
* @brief Check if a character is whitespace.
124+
* @brief Check if a character is alphanumeric.
103125
*
104126
* @param x Character to check
105-
* @return bool true if whitespace, false otherwise
127+
* @return int Non-zero if alphanumeric, 0 otherwise
106128
*/
107-
bool isspace(const char x);
129+
static inline int __attribute__((always_inline)) isalnum(const char x)
130+
{
131+
return isdigit(x) || isalpha(x);
132+
}
108133

109134
/**
110-
* @brief Check if a character is alphabetic.
135+
* @brief Check if a character is whitespace.
111136
*
112137
* @param x Character to check
113-
* @return bool true if alphabetic, false otherwise
138+
* @return bool true if whitespace, false otherwise
114139
*/
115-
bool isalpha(const char x);
140+
static inline bool __attribute__((always_inline)) isspace(const char x)
141+
{
142+
return x == ' ' || x == '\t';
143+
}
116144

117145
/**
118146
* @brief Locate first occurrence of a character in a string.
@@ -228,7 +256,7 @@ int atoi(const char *s);
228256
* @param radix Base (e.g. 10 for decimal, 16 for hex)
229257
* @return int64_t Converted value
230258
*/
231-
int64_t atoll(const char *s, int radix);
259+
__attribute__((hot)) int64_t atoll(const char *s, int radix);
232260

233261
/**
234262
* @brief Convert string to 64-bit unsigned integer.

os/programs/edit.rrbasic

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ ENDPROC
8787
REM display text to editor window
8888
DEF PROCtext
8989
PROChideCursor
90+
CLS
9091
PROCdraw
9192
CURSOR 1, 2
9293
FOR l = top TO top + TERMHEIGHT - 3

os/programs/rocketsh.rrbasic

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
REM *** Retro Rocket BASIC Shell ***
22
LIBRARY LIB$ + "/ansi"
33

4-
REM ON ERROR PROCerrorHandler
4+
ON ERROR PROCerrorHandler
55

66
PROCEdInit(TRUE)
77

src/basic/main.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ bool basic_hash_lines(struct basic_ctx *ctx, char **error) {
200200
int64_t last_line = LONG_MAX;
201201
const char *program = ctx->ptr;
202202
while (*program) {
203-
int64_t line = atoi(program);
203+
int64_t line = atoll(program, 10);
204204
if (last_line != LONG_MAX && (line <= last_line)) {
205205
*error = "Misordered lines in BASIC program";
206206
basic_destroy(ctx);
@@ -724,10 +724,10 @@ void basic_run(struct basic_ctx *ctx) {
724724
}
725725
/* TODO Make sure this only runs for foreground processes! */
726726
if (basic_esc() && !ctx->errored) {
727-
(void) kgetc();
727+
kgetc();
728728
tokenizer_error_print(ctx, "Escape");
729+
return;
729730
}
730-
basic_debug("BASIC RUN\n");
731731
line_statement(ctx);
732732
if (ctx->errored) {
733733
ctx->errored = false;

src/basic/statement.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22

33
extern bool debug;
44

5+
GENERATE_HANDLER_TABLE(dispatch_by_token)
6+
57
void statement(struct basic_ctx* ctx)
68
{
79
enum token_t token = tokenizer_token(ctx);
8-
9-
basic_debug("line %ld statement(%d)\n", ctx->current_linenum, token);
10-
11-
GENERATE_HANDLER_TABLE(dispatch_by_token)
1210
if (token < DISPATCH_TABLE_COUNT(dispatch_by_token)) {
1311
if (dispatch_by_token[token] != NULL) {
1412
dispatch_by_token[token](ctx);
@@ -18,7 +16,6 @@ void statement(struct basic_ctx* ctx)
1816

1917
dprintf("Unknown keyword: %d\n", token);
2018
tokenizer_error_print(ctx, "Unknown keyword");
21-
2219
}
2320

2421
void line_statement(struct basic_ctx* ctx)

src/basic/string.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ char* basic_lower(struct basic_ctx* ctx)
9595

9696
char* basic_highlight(struct basic_ctx* ctx) {
9797
GENERATE_ENUM_STRING_NAMES(TOKEN, token_names)
98+
GENERATE_ENUM_STRING_LENGTHS(TOKEN, token_name_lengths)
9899
const size_t token_count = sizeof(token_names) / sizeof(*token_names);
99100
PARAMS_START;
100101
PARAMS_GET_ITEM(BIP_STRING);
@@ -148,8 +149,8 @@ char* basic_highlight(struct basic_ctx* ctx) {
148149
}
149150
}
150151
for (size_t v = 0; v < token_count; ++v) {
151-
size_t kw_len = strlen(token_names[v]);
152-
if (pos + kw_len <= end && !memcmp(pos, token_names[v], kw_len)) {
152+
size_t kw_len = token_name_lengths[v];
153+
if (pos + kw_len <= end && !strncmp(pos, token_names[v], kw_len)) {
153154
const char *after = pos + kw_len;
154155
bool next_is_varlike = ((*after >= '0' && *after <= '9') || (toupper(*after) >= 'A' && toupper(*after) <= 'Z') || *after == '_');
155156
if (!next_is_varlike || v == PROC || v == FN || v == EQUALS) {
@@ -163,6 +164,7 @@ char* basic_highlight(struct basic_ctx* ctx) {
163164
found = true;
164165
}
165166
pos += kw_len - 1;
167+
break;
166168
}
167169
}
168170
}

src/basic/tokenizer.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ int get_next_token(struct basic_ctx* ctx)
137137
return STRING;
138138
} else {
139139
GENERATE_ENUM_STRING_NAMES(TOKEN, token_names)
140+
GENERATE_ENUM_STRING_LENGTHS(TOKEN, token_name_lengths)
140141
for(int kt = 0; keywords[kt] != -1; ++kt) {
141-
size_t len = strlen(token_names[keywords[kt]]);
142+
size_t len = token_name_lengths[keywords[kt]];
142143
int comparison = strncmp(ctx->ptr, token_names[keywords[kt]], len);
143144
if (comparison == 0) {
144145
const char* backup = ctx->nextptr;
@@ -287,6 +288,7 @@ void tokenizer_error_print(struct basic_ctx* ctx, const char* error)
287288
if (ctx->ended == 0) {
288289
debug = false;
289290
if (ctx->error_handler) {
291+
dprintf("Handled error\n");
290292
struct ub_proc_fn_def* def = basic_find_fn(ctx->error_handler, ctx);
291293
if (def && ctx->call_stack_ptr < MAX_CALL_STACK_DEPTH) {
292294
buddy_free(ctx->allocator, ctx->error_handler);
@@ -319,6 +321,7 @@ void tokenizer_error_print(struct basic_ctx* ctx, const char* error)
319321
ctx->ended = true;
320322
}
321323
}
324+
dprintf("Unhandled error\n");
322325
if (ctx->claimed_flip) {
323326
set_video_auto_flip(true);
324327
}
@@ -336,14 +339,15 @@ void tokenizer_error_print(struct basic_ctx* ctx, const char* error)
336339
offset = 1;
337340
}
338341
kprintf("%s\n", l);
339-
for (size_t x = 0; x < offset - 1; ++x) {
342+
for (size_t x = 0; x < offset ? offset - 1 : 0; ++x) {
340343
put(' ');
341344
}
342345
kprintf("^\n");
343346
}
344347
setforeground(COLOUR_WHITE);
345348
}
346349
} else {
350+
dprintf("Error in eval\n");
347351
if (!ctx->errored) {
348352
ctx->errored = true;
349353
setforeground(COLOUR_LIGHTRED);

0 commit comments

Comments
 (0)