Commit 9b706aee7d92d6ac3002547aea12e3eaa0a750ae

Authored by Denys Vlasenko
Committed by Thomas Gleixner
1 parent b6fbb669c8

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>

Showing 2 changed files with 41 additions and 32 deletions Side-by-side Diff

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