x86: trivial printk optimizations

In arch/x86/boot/printf.c gets rid of unused tail of digits: const char
*digits = "0123456789abcdefghijklmnopqrstuvwxyz"; (we are using 0-9a-f
only)

Uses smaller/faster lowercasing (by ORing with 0x20)
if we know that we work on numbers/digits. Makes
strtoul smaller, and also we are getting rid of

static const char small_digits[] = "0123456789abcdefx";
static const char large_digits[] = "0123456789ABCDEFX";

since this works equally well:

static const char digits[16] = "0123456789ABCDEF";

Size savings:

$ size vmlinux.org vmlinux
text data bss dec hex filename
877320 112252 90112 1079684 107984 vmlinux.org
877048 112252 90112 1079412 107874 vmlinux

It may be also a tiny bit faster because code has less
branches now, but I doubt it is measurable.

[ hugh@veritas.com: uppercase pointers fix ]

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by Denys Vlasenko and committed by Thomas Gleixner 9b706aee b6fbb669

+41 -32
+14 -10
arch/x86/boot/printf.c
··· 33 33 #define PLUS 4 /* show plus */ 34 34 #define SPACE 8 /* space if plus */ 35 35 #define LEFT 16 /* left justified */ 36 - #define SPECIAL 32 /* 0x */ 37 - #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 36 + #define SMALL 32 /* Must be 32 == 0x20 */ 37 + #define SPECIAL 64 /* 0x */ 38 38 39 39 #define do_div(n,base) ({ \ 40 40 int __res; \ ··· 45 45 static char *number(char *str, long num, int base, int size, int precision, 46 46 int type) 47 47 { 48 - char c, sign, tmp[66]; 49 - const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 48 + /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 49 + static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 50 + 51 + char tmp[66]; 52 + char c, sign, locase; 50 53 int i; 51 54 52 - if (type & LARGE) 53 - digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 55 + /* locase = 0 or 0x20. ORing digits or letters with 'locase' 56 + * produces same digits or (maybe lowercased) letters */ 57 + locase = (type & SMALL); 54 58 if (type & LEFT) 55 59 type &= ~ZEROPAD; 56 60 if (base < 2 || base > 36) ··· 85 81 tmp[i++] = '0'; 86 82 else 87 83 while (num != 0) 88 - tmp[i++] = digits[do_div(num, base)]; 84 + tmp[i++] = (digits[do_div(num, base)] | locase); 89 85 if (i > precision) 90 86 precision = i; 91 87 size -= precision; ··· 99 95 *str++ = '0'; 100 96 else if (base == 16) { 101 97 *str++ = '0'; 102 - *str++ = digits[33]; 98 + *str++ = ('X' | locase); 103 99 } 104 100 } 105 101 if (!(type & LEFT)) ··· 248 244 base = 8; 249 245 break; 250 246 251 - case 'X': 252 - flags |= LARGE; 253 247 case 'x': 248 + flags |= SMALL; 249 + case 'X': 254 250 base = 16; 255 251 break; 256 252
+27 -22
lib/vsprintf.c
··· 26 26 #include <asm/page.h> /* for PAGE_SIZE */ 27 27 #include <asm/div64.h> 28 28 29 + /* Works only for digits and letters, but small and fast */ 30 + #define TOLOWER(x) ((x) | 0x20) 31 + 29 32 /** 30 33 * simple_strtoul - convert a string to an unsigned long 31 34 * @cp: The start of the string ··· 44 41 if (*cp == '0') { 45 42 base = 8; 46 43 cp++; 47 - if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { 44 + if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { 48 45 cp++; 49 46 base = 16; 50 47 } 51 48 } 52 49 } else if (base == 16) { 53 - if (cp[0] == '0' && toupper(cp[1]) == 'X') 50 + if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') 54 51 cp += 2; 55 52 } 56 53 while (isxdigit(*cp) && 57 - (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { 54 + (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) { 58 55 result = result*base + value; 59 56 cp++; 60 57 } ··· 95 92 if (*cp == '0') { 96 93 base = 8; 97 94 cp++; 98 - if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { 95 + if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { 99 96 cp++; 100 97 base = 16; 101 98 } 102 99 } 103 100 } else if (base == 16) { 104 - if (cp[0] == '0' && toupper(cp[1]) == 'X') 101 + if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') 105 102 cp += 2; 106 103 } 107 - while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) 108 - ? toupper(*cp) : *cp)-'A'+10) < base) { 104 + while (isxdigit(*cp) 105 + && (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) { 109 106 result = result*base + value; 110 107 cp++; 111 108 } ··· 363 360 #define PLUS 4 /* show plus */ 364 361 #define SPACE 8 /* space if plus */ 365 362 #define LEFT 16 /* left justified */ 366 - #define SPECIAL 32 /* 0x */ 367 - #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 363 + #define SMALL 32 /* Must be 32 == 0x20 */ 364 + #define SPECIAL 64 /* 0x */ 368 365 369 366 static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) 370 367 { 371 - char sign,tmp[66]; 372 - const char *digits; 373 - /* we are called with base 8, 10 or 16, only, thus don't need "g..." */ 374 - static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */ 375 - static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 368 + /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 369 + static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 370 + 371 + char tmp[66]; 372 + char sign; 373 + char locase; 376 374 int need_pfx = ((type & SPECIAL) && base != 10); 377 375 int i; 378 376 379 - digits = (type & LARGE) ? large_digits : small_digits; 377 + /* locase = 0 or 0x20. ORing digits or letters with 'locase' 378 + * produces same digits or (maybe lowercased) letters */ 379 + locase = (type & SMALL); 380 380 if (type & LEFT) 381 381 type &= ~ZEROPAD; 382 - if (base < 2 || base > 36) 383 - return NULL; 384 382 sign = 0; 385 383 if (type & SIGN) { 386 384 if ((signed long long) num < 0) { ··· 408 404 tmp[i++] = '0'; 409 405 /* Generic code, for any base: 410 406 else do { 411 - tmp[i++] = digits[do_div(num,base)]; 407 + tmp[i++] = (digits[do_div(num,base)] | locase); 412 408 } while (num != 0); 413 409 */ 414 410 else if (base != 10) { /* 8 or 16 */ ··· 416 412 int shift = 3; 417 413 if (base == 16) shift = 4; 418 414 do { 419 - tmp[i++] = digits[((unsigned char)num) & mask]; 415 + tmp[i++] = (digits[((unsigned char)num) & mask] | locase); 420 416 num >>= shift; 421 417 } while (num); 422 418 } else { /* base 10 */ ··· 448 444 ++buf; 449 445 if (base == 16) { 450 446 if (buf < end) 451 - *buf = digits[16]; /* for arbitrary base: digits[33]; */ 447 + *buf = ('X' | locase); 452 448 ++buf; 453 449 } 454 450 } ··· 648 644 continue; 649 645 650 646 case 'p': 647 + flags |= SMALL; 651 648 if (field_width == -1) { 652 649 field_width = 2*sizeof(void *); 653 650 flags |= ZEROPAD; ··· 685 680 base = 8; 686 681 break; 687 682 688 - case 'X': 689 - flags |= LARGE; 690 683 case 'x': 684 + flags |= SMALL; 685 + case 'X': 691 686 base = 16; 692 687 break; 693 688