Re: Structure vs purism ?

Richard B. Johnson (root@chaos.analogic.com)
Thu, 21 Jan 1999 10:48:45 -0500 (EST)


On Thu, 21 Jan 1999, Philipp Rumpf wrote:

> On Wed, Jan 20, 1999 at 09:58:53PM -0500, Richard B. Johnson wrote:
> > Then 'tidy' up something so it looks good to 'humans' and do the same
> > thing again. You will then learn why there are strange constructs and,
> > as you say, a 1000 gotos.
>
> I think a lot of the goto's could be removed as soon as there is a decent
> possibility to tell the compiler to optimize for a certain case. This was
> discussed on the egcs lists some time ago IIRC.
>

Maybe, one function at a time --one carefully checked function at a time.
For instance, the way we were 'taught` to write code (by instuctors and
professors who never built actual products, BTW) goes something like
this...

funct()
{
if(funct1()) {
if(funct2()) {
if(funct3()) {
if(funct4())
do_something();
else
compain_about_funct4();
}
else
complain_about_funct3();
}
else
complain_about_funct2();
}
else
complain_about_funct1();
}
}

...... produces absolutely rotten code on every compiler I've ever
used. This is because it jumps on the normal-flow condition.

That's why it is often written as:

funct()
{
if(!funct1())
goto quit;
if(!funct2())
goto quit;
if(!funct3())
goto quit;
if(!funct4())
goto quit;
do_something();
return GOOD;
quit:;
complain();
return BAD;
}

This jumps only on the error conditions.

Sometimes gotos can be removed as:

if(!funct1())
return BAD;

Even the usual loop-counters often produce bad, bad, bad code.

for(i=0; i< MAX; i++)
do_something();

You would think that, since this construct is so often used, the 'C'
compilers would at least optimize this. Nope, guess again. Even telling
the compiler to use 'register int i`, even if it does, the loop test
and the increment end up being in the wrong order, forcing extra code
to determine the terminating condition.

You see, if `i` is used only as a count, not as an index, and if the
value of `i` is not used after the loop terminates, the compiler could
decrement a starting value to zero instead of starting at zero and
incrementing to some limit. In this case there would be no need to
compare against a final value because on most/many/(all?) processors
the flags change automatically when decrementing to zero or decrementing
to a negative number.

To get around the bad code generation, programmers who understand
these things often code....

while(i--)
;

However, gcc will usually mess with this and end up decrementing a
value on the stack or in the register-variable case, add extra code.

Like:

void foo()
{
puts("Do not optimize this away!");
}
main()
{
register int i;
i = 10;
while(i--)
foo();
}

.file "xxx.c"
.version "01.01"
gcc2_compiled.:
.section .rodata
.LC0:
.string "Do not optimize this away!"
.text
.align 4
.globl foo
.type foo,@function
foo:
pushl %ebp
movl %esp,%ebp
pushl $.LC0
call puts
addl $4,%esp
.L1:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:
.size foo,.Lfe1-foo
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp,%ebp
pushl %ebx
movl $10,%ebx
.L3:
decl %ebx # This changes the sign flag.
cmpl $-1,%ebx # This is NOT necessary
jne .L5 # Should be js .L4 (terminating condition)
jmp .L4 # Should fall through to `call foo`
.align 4 # Should not exist
.L5:
call foo
jmp .L3
.align 4
.L4:
.L2:
movl -4(%ebp),%ebx
movl %ebp,%esp
popl %ebp
ret
.Lfe2:
.size main,.Lfe2-main
.ident "GCC: (GNU) 2.8.1"

So, to have a fast Operating System, one must often compromise asthetics
and get down and dirty, mucking with the registers.

Cheers,
Dick Johnson
***** FILE SYSTEM WAS MODIFIED *****
Penguin : Linux version 2.1.131 on an i686 machine (400.59 BogoMips).
Warning : It's hard to remain at the trailing edge of technology.
Wisdom : It's not a Y2K problem. It's a Y2Day problem.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/