Skip to content

Commit b3e756c

Browse files
visitorckwjserv
authored andcommitted
Optimize base-10 conversion for RV32I libc
To improve performance on RV32I, introduce __str_base10(), a base-10 conversion routine that avoids both division and multiplication by using bit shifts and additions. This is especially beneficial for targets lacking hardware support for RV32M. itoa() and vsprintf() now use this implementation for decimal output. A helper __str_base10_signed() is also added for signed integers.
1 parent eb3f4dc commit b3e756c

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

lib/libc.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,56 @@ int32_t strtol(const char *s, char **end, int32_t base)
462462
return value;
463463
}
464464

465+
/* Base-10 string conversion without division or multiplication */
466+
static char* __str_base10(uint32_t value, char* buffer, int* length)
467+
{
468+
if (value == 0) {
469+
buffer[0] = '0';
470+
*length = 1;
471+
return buffer;
472+
}
473+
474+
char temp[12]; /* Max digits for 32-bit: 4,294,967,295 (10 digits) + sign + null */
475+
int pos = 0;
476+
477+
while (value > 0) {
478+
uint32_t q, r, t;
479+
480+
q = (value >> 1) + (value >> 2);
481+
q += (q >> 4);
482+
q += (q >> 8);
483+
q += (q >> 16);
484+
q >>= 3;
485+
r = value - (((q << 2) + q) << 1);
486+
t = ((r + 6) >> 4);
487+
q += t;
488+
r -= (((t << 2) + t) << 1);
489+
490+
temp[pos++] = '0' + r;
491+
value = q;
492+
}
493+
494+
/* Reverse digits into output buffer */
495+
*length = pos;
496+
for (int i = 0; i < pos; i++) {
497+
buffer[i] = temp[pos - 1 - i];
498+
}
499+
500+
return buffer;
501+
}
502+
503+
/* Handle signed integers */
504+
static char* __str_base10_signed(int32_t value, char* buffer, int* length) {
505+
if (value < 0) {
506+
buffer[0] = '-';
507+
__str_base10((uint32_t)(-value), buffer + 1, length);
508+
(*length)++;
509+
return buffer;
510+
} else {
511+
return __str_base10((uint32_t)value, buffer, length);
512+
}
513+
}
514+
465515
/* Converts string @s to an integer. */
466516
int32_t atoi(const char *s)
467517
{
@@ -501,6 +551,7 @@ void itoa(int32_t i, char *s, int32_t base)
501551
char *p = s;
502552
char *q = s;
503553
uint32_t h;
554+
int32_t len;
504555

505556
if (base == 16) { /* Hexadecimal conversion */
506557
h = (uint32_t) i;
@@ -519,7 +570,9 @@ void itoa(int32_t i, char *s, int32_t base)
519570
(*q > '9') ? (*p = *q + 39) : (*p = *q);
520571
*q = c;
521572
}
522-
} else { /* Decimal or other bases */
573+
} else if (base == 10) { /* Decimal conversion */
574+
__str_base10_signed(i, s, &len);
575+
} else { /* Other bases */
523576
if (i >= 0) {
524577
do {
525578
*q++ = '0' + (i % base);
@@ -822,6 +875,8 @@ static int vsprintf(char **buf, const char *fmt, va_list args)
822875
i = 0;
823876
if (num == 0)
824877
tmp[i++] = '0';
878+
else if (base == 10)
879+
__str_base10(num, tmp, &i);
825880
else {
826881
while (num != 0)
827882
tmp[i++] = digits[divide(&num, base)];

0 commit comments

Comments
 (0)