aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-07-16 02:41:54 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:52 -0400
commitb39a734097d5095d63eb9c709a6aaf965633bb01 (patch)
tree78afaae4c1229163279b902bacf99445dc16e767
parent4b4e5a1411c8b970983fb6022db1da31c4f5c301 (diff)
vsprintf.c: optimizing, part 1 (easy and obvious stuff)
* There is no point in having full "0...9a...z" constant vector, if we use only "0...9a...f" (and "x" for "0x"). * Post-decrement usually needs a few more instructions, so use pre decrement instead where makes sense: -       while (i < precision--) { +       while (i <= --precision) { * if base != 10 (=> base 8 or 16), we can avoid using division in a loop and use mask/shift, obtaining much faster conversion. (More complex optimization for base 10 case is in the second patch). Overall, size vsprintf.o shows ~80 bytes smaller text section with this patch applied. Signed-off-by: Douglas W Jones <jones@cs.uiowa.edu> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--lib/vsprintf.c73
1 files changed, 45 insertions, 28 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 017290241261..e94b4bd25bc5 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -143,12 +143,14 @@ static int skip_atoi(const char **s)
143#define SPECIAL 32 /* 0x */ 143#define SPECIAL 32 /* 0x */
144#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 144#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
145 145
146static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type) 146static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
147{ 147{
148 char c,sign,tmp[66]; 148 char sign,tmp[66];
149 const char *digits; 149 const char *digits;
150 static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 150 /* we are called with base 8, 10 or 16, only, thus don't need "g..." */
151 static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 151 static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */
152 static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
153 int need_pfx = ((type & SPECIAL) && base != 10);
152 int i; 154 int i;
153 155
154 digits = (type & LARGE) ? large_digits : small_digits; 156 digits = (type & LARGE) ? large_digits : small_digits;
@@ -156,7 +158,6 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
156 type &= ~ZEROPAD; 158 type &= ~ZEROPAD;
157 if (base < 2 || base > 36) 159 if (base < 2 || base > 36)
158 return NULL; 160 return NULL;
159 c = (type & ZEROPAD) ? '0' : ' ';
160 sign = 0; 161 sign = 0;
161 if (type & SIGN) { 162 if (type & SIGN) {
162 if ((signed long long) num < 0) { 163 if ((signed long long) num < 0) {
@@ -171,64 +172,80 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
171 size--; 172 size--;
172 } 173 }
173 } 174 }
174 if (type & SPECIAL) { 175 if (need_pfx) {
176 size--;
175 if (base == 16) 177 if (base == 16)
176 size -= 2;
177 else if (base == 8)
178 size--; 178 size--;
179 } 179 }
180
181 /* generate full string in tmp[], in reverse order */
180 i = 0; 182 i = 0;
181 if (num == 0) 183 if (num == 0)
182 tmp[i++]='0'; 184 tmp[i++] = '0';
183 else while (num != 0) 185 else if (base != 10) { /* 8 or 16 */
184 tmp[i++] = digits[do_div(num,base)]; 186 int mask = base - 1;
187 int shift = 3;
188 if (base == 16) shift = 4;
189 do {
190 tmp[i++] = digits[((unsigned char)num) & mask];
191 num >>= shift;
192 } while (num);
193 } else do { /* generic code, works for any base */
194 tmp[i++] = digits[do_div(num,10 /*base*/)];
195 } while (num);
196
197 /* printing 100 using %2d gives "100", not "00" */
185 if (i > precision) 198 if (i > precision)
186 precision = i; 199 precision = i;
200 /* leading space padding */
187 size -= precision; 201 size -= precision;
188 if (!(type&(ZEROPAD+LEFT))) { 202 if (!(type & (ZEROPAD+LEFT))) {
189 while(size-->0) { 203 while(--size >= 0) {
190 if (buf < end) 204 if (buf < end)
191 *buf = ' '; 205 *buf = ' ';
192 ++buf; 206 ++buf;
193 } 207 }
194 } 208 }
209 /* sign */
195 if (sign) { 210 if (sign) {
196 if (buf < end) 211 if (buf < end)
197 *buf = sign; 212 *buf = sign;
198 ++buf; 213 ++buf;
199 } 214 }
200 if (type & SPECIAL) { 215 /* "0x" / "0" prefix */
201 if (base==8) { 216 if (need_pfx) {
202 if (buf < end) 217 if (buf < end)
203 *buf = '0'; 218 *buf = '0';
204 ++buf; 219 ++buf;
205 } else if (base==16) { 220 if (base == 16) {
206 if (buf < end)
207 *buf = '0';
208 ++buf;
209 if (buf < end) 221 if (buf < end)
210 *buf = digits[33]; 222 *buf = digits[16]; /* for arbitrary base: digits[33]; */
211 ++buf; 223 ++buf;
212 } 224 }
213 } 225 }
226 /* zero or space padding */
214 if (!(type & LEFT)) { 227 if (!(type & LEFT)) {
215 while (size-- > 0) { 228 char c = (type & ZEROPAD) ? '0' : ' ';
229 while (--size >= 0) {
216 if (buf < end) 230 if (buf < end)
217 *buf = c; 231 *buf = c;
218 ++buf; 232 ++buf;
219 } 233 }
220 } 234 }
221 while (i < precision--) { 235 /* hmm even more zero padding? */
236 while (i <= --precision) {
222 if (buf < end) 237 if (buf < end)
223 *buf = '0'; 238 *buf = '0';
224 ++buf; 239 ++buf;
225 } 240 }
226 while (i-- > 0) { 241 /* actual digits of result */
242 while (--i >= 0) {
227 if (buf < end) 243 if (buf < end)
228 *buf = tmp[i]; 244 *buf = tmp[i];
229 ++buf; 245 ++buf;
230 } 246 }
231 while (size-- > 0) { 247 /* trailing space padding */
248 while (--size >= 0) {
232 if (buf < end) 249 if (buf < end)
233 *buf = ' '; 250 *buf = ' ';
234 ++buf; 251 ++buf;
@@ -276,7 +293,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
276 used for unknown buffer sizes. */ 293 used for unknown buffer sizes. */
277 if (unlikely((int) size < 0)) { 294 if (unlikely((int) size < 0)) {
278 /* There can be only one.. */ 295 /* There can be only one.. */
279 static int warn = 1; 296 static char warn = 1;
280 WARN_ON(warn); 297 WARN_ON(warn);
281 warn = 0; 298 warn = 0;
282 return 0; 299 return 0;