svn commit: r275241 - head/sys/boot/pc98/boot2

Bruce Evans brde at optusnet.com.au
Sat Nov 29 13:49:40 UTC 2014


On Sat, 29 Nov 2014, Takahashi Yoshihiro wrote:

> Log:
>  MFi386: r275059, r275061, r275062 and r275191 (by rdivacky)
>
>    Shrink boot2 by a couple more bytes.

These changes don't look too good to me.  One is just a bug.

> Modified: head/sys/boot/pc98/boot2/boot2.c
> ==============================================================================
> --- head/sys/boot/pc98/boot2/boot2.c	Sat Nov 29 11:50:19 2014	(r275240)
> +++ head/sys/boot/pc98/boot2/boot2.c	Sat Nov 29 12:22:31 2014	(r275241)
> ...
> @@ -533,6 +534,7 @@ parse()
>     const char *cp;
>     unsigned int drv;
>     int c, i, j;
> +    size_t k;

This still has a style bug (unsorting).

>
>     while ((c = *arg++)) {
> 	if (c == ' ' || c == '\t' || c == '\n')
> @@ -555,7 +557,7 @@ parse()
> #if SERIAL
> 		} else if (c == 'S') {
> 		    j = 0;
> -		    while ((unsigned int)(i = *arg++ - '0') <= 9)
> +		    while ((i = *arg++ - '0') <= 9)
> 			j = j * 10 + i;
> 		    if (j > 0 && i == -'0') {
> 			comspeed = j;

This used to work.  The cast was an obfuscated way of checking for
characters less than '0'.  Removing the cast breaks the code.  Garbage
non-digits below '0' (including all characters below '\0') are now
treated as digits.

This still asks for the pessimization of promoting *arg++ to int before
checking it.  The compiler might be able to unpessimize this, but large
code shouldn't be asked for.  The following should be better:

     uint8_t uc;
     ...

 		    /* Check that the compiler generates 8-bit ops. */
 		    while ((uc = *arg++ - '0') <= 9)
 			j = j * 10 + uc;
 		    if (j > 0 && uc == (uint8_t)-'0') {
 			comspeed = j;


I don't see a correct way to avoid the second check of uc.

Subtracting '0' and using the unsigned obfuscation to check for digits
is used in several other places:

 		    drv = *arg - '0';
 		    if (drv > 9)
 			...;

This works since 'drv' is unsigned.  Drive numbers above 9 are not supported,
so uint8_t could be used here, saving 1 byte.  At least 1 more byte can be
saved in each of 'drv == -1' and 'if (drv == -1)'.  'drv' would probably
need to be promoted before use; it is only used once to initialize
dsk.drive.  It can be promoted there using no extra bytes by statically
initializing dsk.drive to 0 and storing only 8 bits from 'drv'.  The total
savings should be 4-5 bytes.


 		    dsk.unit = *arg - '0';
 		    if (arg[1] != ',' || dsk.unit > 9)
 			...;

dsk.unit is also unsigned.  Unit numbers above 9 are not supported, so
uint8_t should work here too, but since dsk.unit probably needs to be
a 32-bit type and there is no local variable like 'drv', the savings are
not as easy.

 		    dsk.slice = WHOLE_DISK_SLICE;
 		    ...
 			dsk.slice = *arg - '0' + 1;
 			if (dsk.slice > NDOSPART + 1)
 			    ...;

Now disk.slice is already uint8_t, so this code should be optimal.  However,
when dsk.slice is used it has to be promoted and about 3 bytes are wasted
there.  To avoid this wastage, make disk.slice plain int (no need for
unsigned hacks), initialize it all to 0, and store only the low 8 bits
in the above.

There are so many of these that it might be smaller to use a function
that handles the general case.  I suspect that this is not in fact smaller,
since it would need complications like passing back the endptr (like
strtol(), not atoi()).

Bruce


More information about the svn-src-all mailing list