diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-11-19 15:55:31 -0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2013-11-20 18:43:56 +0000 |
commit | 7f5019c9e34319265933b347d493ec28e2ff015d (patch) | |
tree | 51405a67abae8bfdbe66b557e9bb7b00e6ce0173 /common/printf.c | |
parent | abf4fb8392c6674903a3778670a2fec0fe23c6c6 (diff) | |
download | chrome-ec-7f5019c9e34319265933b347d493ec28e2ff015d.tar.gz |
Reduce stack space used by vfnprintf()
Converting some of the boolean variables in vfnprintf() to a single
flags word reduces stack usage by 8 bytes and function size by 12
bytes. So it's slightly more efficient in both respects.
Confirmed size and stack usage improvements via 'make BOARD=rambi all
dis' and looking at the disassembly for vfnprintf()
BUG=chrome-os-partner:24148
BRANCH=none
TEST=Run taskinfo command twice and compare stack used by CONSOLE task.
Run timerinfo and charger commands and verify output looks reasonable;
those exercise binary and 64-bit number printing.
Change-Id: Ie4396bb0bc01dc155956fa2d8ca84c6630006729
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/177400
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'common/printf.c')
-rw-r--r-- | common/printf.c | 87 |
1 files changed, 51 insertions, 36 deletions
diff --git a/common/printf.c b/common/printf.c index dad02ac4c7..f52100e2c6 100644 --- a/common/printf.c +++ b/common/printf.c @@ -14,67 +14,84 @@ static const char error_str[] = "ERROR"; #define MAX_FORMAT 1024 /* Maximum chars in a single format field */ /** - * Convert a single digit to hex + * Convert the lowest nibble of a number to hex * - * @param c Value of digit (0 - 0x0f) + * @param c Number to extract lowest nibble from * * @return The corresponding ASCII character ('0' - 'f'). */ static int hexdigit(int c) { + /* Strip off just the last nibble */ + c &= 0x0f; + return c > 9 ? (c + 'a' - 10) : (c + '0'); } +/* Flags for vfnprintf() flags */ +#define PF_LEFT (1 << 0) /* Left-justify */ +#define PF_PADZERO (1 << 1) /* Pad with 0's not spaces */ +#define PF_NEGATIVE (1 << 2) /* Number is negative */ +#define PF_64BIT (1 << 3) /* Number is 64-bit */ + int vfnprintf(int (*addchar)(void *context, int c), void *context, const char *format, va_list args) { /* * Longest uint64 in decimal = 20 - * longest uint32 in binary = 32 + * Longest uint32 in binary = 32 + * + sign bit + * + terminating null */ char intbuf[34]; - int dropped_chars = 0; - int is_left; - int pad_zero; + int flags; int pad_width; int precision; char *vstr; int vlen; - while (*format && !dropped_chars) { + while (*format) { int c = *format++; /* Copy normal characters */ if (c != '%') { - dropped_chars |= addchar(context, c); + if (addchar(context, c)) + return EC_ERROR_OVERFLOW; continue; } + /* Zero flags, now that we're in a format */ + flags = 0; + /* Get first format character */ c = *format++; /* Send "%" for "%%" input */ if (c == '%' || c == '\0') { - dropped_chars |= addchar(context, '%'); + if (addchar(context, '%')) + return EC_ERROR_OVERFLOW; continue; } /* Handle %c */ if (c == 'c') { c = va_arg(args, int); - dropped_chars |= addchar(context, c); + if (addchar(context, c)) + return EC_ERROR_OVERFLOW; continue; } /* Handle left-justification ("%-5s") */ - is_left = (c == '-'); - if (is_left) + if (c == '-') { + flags |= PF_LEFT; c = *format++; + } /* Handle padding with 0's */ - pad_zero = (c == '0'); - if (pad_zero) + if (c == '0') { + flags |= PF_PADZERO; c = *format++; + } /* Count padding length */ pad_width = 0; @@ -128,33 +145,28 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, } for ( ; precision; precision--, vstr++) { - dropped_chars |= - addchar(context, - hexdigit((*vstr >> 4) & 0x0f)); - dropped_chars |= - addchar(context, - hexdigit(*vstr & 0x0f)); + if (addchar(context, hexdigit(*vstr >> 4)) || + addchar(context, hexdigit(*vstr))) + return EC_ERROR_OVERFLOW; } continue; } else { uint64_t v; - int is_negative = 0; - int is_64bit = 0; int base = 10; /* Handle length */ if (c == 'l') { - is_64bit = 1; + flags |= PF_64BIT; c = *format++; } /* Special-case: %T = current time */ if (c == 'T') { v = get_time().val; - is_64bit = 1; + flags |= PF_64BIT; precision = 6; - } else if (is_64bit) { + } else if (flags & PF_64BIT) { v = va_arg(args, uint64_t); } else { v = va_arg(args, uint32_t); @@ -162,15 +174,15 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, switch (c) { case 'd': - if (is_64bit) { + if (flags & PF_64BIT) { if ((int64_t)v < 0) { - is_negative = 1; + flags |= PF_NEGATIVE; if (v != (1ULL << 63)) v = -v; } } else { if ((int)v < 0) { - is_negative = 1; + flags |= PF_NEGATIVE; if (v != (1ULL << 31)) v = -(int)v; } @@ -229,7 +241,7 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, *(--vstr) = 'a' + digit - 10; } - if (is_negative) + if (flags & PF_NEGATIVE) *(--vstr) = '-'; /* @@ -250,20 +262,23 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, if (!precision) precision = MAX(vlen, pad_width); - while (vlen < pad_width && !is_left) { - dropped_chars |= addchar(context, pad_zero ? '0' : ' '); + while (vlen < pad_width && !(flags & PF_LEFT)) { + if (addchar(context, flags & PF_PADZERO ? '0' : ' ')) + return EC_ERROR_OVERFLOW; vlen++; } while (*vstr && --precision >= 0) - dropped_chars |= addchar(context, *vstr++); - while (vlen < pad_width && is_left) { - dropped_chars |= addchar(context, ' '); + if (addchar(context, *vstr++)) + return EC_ERROR_OVERFLOW; + while (vlen < pad_width && flags & PF_LEFT) { + if (addchar(context, ' ')) + return EC_ERROR_OVERFLOW; vlen++; } } - /* Successful if we consumed all output */ - return dropped_chars ? EC_ERROR_OVERFLOW : EC_SUCCESS; + /* If we're still here, we consumed all output */ + return EC_SUCCESS; } /* Context for snprintf() */ |