Discussion:
[avr-libc-dev] Gcc is weird sometimes...
George Spelvin
2016-12-18 04:33:23 UTC
Permalink
The following patch (analogous to one I made to the PRINTF_MIN code
which saved quite a bit of code space) has strangely contradictory code
size effects.

If anyone else feels like tying it with a different compiler version
(I'm using gcc-7 SVN trunk from a few days ago), I'd be interested in
the results. ("size `find . -name vfprintf_std.o | sort`" is the heart
of these tables.)

Before After Delta filename
1030 1036 + 6 ./avr/lib/avr2/tiny-stack/vfprintf_std.o
1030 1052 +22 ./avr/lib/avr2/vfprintf_std.o
916 932 +16 ./avr/lib/avr25/tiny-stack/vfprintf_std.o
916 948 +32 ./avr/lib/avr25/vfprintf_std.o
1064 1080 +16 ./avr/lib/avr3/vfprintf_std.o
1064 1080 +16 ./avr/lib/avr31/vfprintf_std.o
950 978 +28 ./avr/lib/avr35/vfprintf_std.o
916 948 +32 ./avr/lib/avr4/vfprintf_std.o
946 974 +28 ./avr/lib/avr5/vfprintf_std.o
1028 974 -54 ./avr/lib/avr51/vfprintf_std.o
1026 974 -54 ./avr/lib/avr6/vfprintf_std.o
946 962 +16 ./avr/lib/avrxmega2/vfprintf_std.o
1016 962 -54 ./avr/lib/avrxmega4/vfprintf_std.o
1016 962 -54 ./avr/lib/avrxmega5/vfprintf_std.o
1016 962 -54 ./avr/lib/avrxmega6/vfprintf_std.o
1016 962 -54 ./avr/lib/avrxmega7/vfprintf_std.o

What I'm doing is merging the signed decimal printing code with the
rest, so the "(flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int)"
code and the call to __ultoa_invert() is shared.

That requires a flag bit for "signed" which is hard to find; they're
nearly all in use. Already, the FL_SPACE and FL_PLUS flags
do double duty; if FL_ALT is set (which never happens with decimal),
then they're used for the FL_ALTHEX and FL_ALTUPP flags.

(I can't use the FL_NEGATIVE flag because that's the same bit
as FL_LONG, and so not available until after the va_arg() call.)

So I use the FL_ALT flag again, but directly test if base == 10.
If so, it's a "signed" flag.

There's a little bit more flag manipulation, but I had hoped the net
effect would be beneficial. Unfortunately, it's confusing.


diff --git a/avr-libc/libc/stdio/vfprintf.c b/avr-libc/libc/stdio/vfprintf.c
index 0d8c892a..0e1df5ba 100644
--- a/avr-libc/libc/stdio/vfprintf.c
+++ b/avr-libc/libc/stdio/vfprintf.c
@@ -615,19 +615,14 @@ int vfprintf (FILE * stream, const char *fmt, va_list ap)
}
}

- if (c == 'd' || c == 'i') {
- long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int);
- flags &= ~(FL_NEGATIVE | FL_ALT);
- if (x < 0) {
- x = -x;
- flags |= FL_NEGATIVE;
- }
- c = __ultoa_invert (x, (char *)buf, 10) - (char *)buf;
-
- } else {
+ {
int base;

- if (c == 'u') {
+ if (c == 'd' || c == 'i') {
+ flags |= FL_ALT;
+ base = 10;
+ goto ultoa;
+ } else if (c == 'u') {
flags &= ~FL_ALT;
base = 10;
goto ultoa;
@@ -638,7 +633,7 @@ int vfprintf (FILE * stream, const char *fmt, va_list ap)
switch (c) {
case 'o':
base = 8;
- goto ultoa;
+ break;
case 'p':
flags |= FL_ALT;
/* FALLTHROUGH */
@@ -646,22 +641,28 @@ int vfprintf (FILE * stream, const char *fmt, va_list ap)
if (flags & FL_ALT)
flags |= FL_ALTHEX;
base = 16;
- goto ultoa;
+ break;
case 'X':
if (flags & FL_ALT)
flags |= (FL_ALTHEX | FL_ALTUPP);
base = 16 | XTOA_UPPER;
- ultoa:
- c = __ultoa_invert ((flags & FL_LONG)
- ? va_arg(ap, unsigned long)
- : va_arg(ap, unsigned int),
- (char *)buf, base) - (char *)buf;
- flags &= ~FL_NEGATIVE;
break;
-
default:
goto ret;
}
+ ultoa:
+ {
+ long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int);
+ flags &= ~FL_LONG;
+ if (flags & FL_ALT && base == 10) {
+ flags &= ~FL_ALT;
+ if (x < 0) {
+ x = -x;
+ flags |= FL_NEGATIVE;
+ }
+ }
+ c = __ultoa_invert (x, (char *)buf, base) - (char *)buf;
+ }
}

{

Loading...