Index: branches/zenith432/i386/libsa/prf.c =================================================================== --- branches/zenith432/i386/libsa/prf.c (revision 2821) +++ branches/zenith432/i386/libsa/prf.c (revision 2822) @@ -53,7 +53,38 @@ * */ +#define DIVIDEND_LOW *(unsigned int*) dividend +#define DIVIDEND_HIGH ((unsigned int*) dividend)[1] + /* + * Divides 64-bit dividend by 32-bit divisor. + * Quotient stored in dividend, remainder returned. + * Assumes little-endian byte order. + * Assumes divisor is non-zero. + */ +unsigned int i386_unsigned_div( + unsigned long long* dividend, + unsigned int divisor + ) +{ + unsigned int high = DIVIDEND_HIGH; + + if (high >= divisor) + { + __asm__ volatile ("xorl %%edx, %%edx; divl %2" : "=a"(DIVIDEND_HIGH), "=d"(high) : "r"(divisor), "a"(high)); + } + else + { + DIVIDEND_HIGH = 0; + } + __asm__ volatile("divl %2" : "+a"(DIVIDEND_LOW), "+d"(high) : "r"(divisor)); + return high; +} + +#undef DIVIDEND_HIGH +#undef DIVIDEND_LOW + +/* * Printn prints a number n in base b. * We don't use recursion to avoid deep kernel stacks. */ @@ -69,6 +100,7 @@ char prbuf[22]; register char *cp; int width = 0, neg = 0; + static const char hexdig[] = "0123456789abcdef0123456789ABCDEF"; if ((flag & SIGNED) && (long long)n < 0) { @@ -76,13 +108,27 @@ n = (unsigned long long)(-(long long)n); } cp = prbuf; - do + if ((b & -b) == b) // b is a power of 2 { - *cp++ = "0123456789abcdef0123456789ABCDEF"[(flag & UCASE) + (int) (n%b)]; - n /= b; - width++; + unsigned int log2b = (unsigned int) (__builtin_ctz((unsigned int) b) & 31); + unsigned int mask = (unsigned int) (b - 1); + do + { + *cp++ = hexdig[(flag & UCASE) + (int) (n & mask)]; + n >>= log2b; + width++; + } + while (n); } - while (n); + else // b is not a power of 2 + { + do + { + *cp++ = hexdig[(flag & UCASE) + (int) i386_unsigned_div(&n, (unsigned int) b)]; + width++; + } + while (n); + } if (neg) { @@ -223,21 +269,24 @@ case 's': s = va_arg(ap, const char*); width = 0; - while (s && (c = *s++)) + if (!putfn_p) { - if (putfn_p) + while (s && (c = *s++)) { - (void)(*putfn_p)(c, putfn_arg); + width++; } + len += ((width < minwidth) ? minwidth : width); + break; + } + while (s && (c = *s++)) + { + (void)(*putfn_p)(c, putfn_arg); len++; width++; } while (width++ < minwidth) { - if (putfn_p) - { - (void)(*putfn_p)(' ', putfn_arg); - } + (void)(*putfn_p)(' ', putfn_arg); len++; } break; Index: branches/zenith432/i386/libsa/strtol.c =================================================================== --- branches/zenith432/i386/libsa/strtol.c (revision 2821) +++ branches/zenith432/i386/libsa/strtol.c (revision 2822) @@ -324,8 +324,9 @@ register const char *s = nptr; register unsigned long long acc; register int c; - register unsigned long long qbase, cutoff; + /* register */ unsigned long long qbase, cutoff; register int neg, any, cutlim; + extern unsigned int i386_unsigned_div(unsigned long long*, unsigned int); /* * See strtoq for comments as to the logic used. @@ -365,8 +366,8 @@ } qbase = (unsigned)base; - cutoff = (unsigned long long)UQUAD_MAX / qbase; - cutlim = (unsigned long long)UQUAD_MAX % qbase; + cutoff = (unsigned long long)UQUAD_MAX; + cutlim = (int) i386_unsigned_div(&cutoff, (unsigned int) base); for (acc = 0, any = 0;; c = *s++) {