Re: Structure vs purism ?

Arvind Sankar (arvinds@mit.edu)
Thu, 21 Jan 1999 23:42:10 -0500


On Thu, Jan 21, 1999 at 10:48:45AM -0500, Richard B. Johnson wrote:
> 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.

Ah, but this is now equivalent instead to
if (func1()&&func2()&&func3()&&func4())
do_something();
else
complain();

But of course, you're right, in the structured way it is too difficult
to code different cleanup depending on where I failed, while in the goto
case all the dirty stuff goes out of the normal flow.

>
> 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.

valid point.

>
> 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.
>

mm.. not with me. using egcs-1.1.1

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

> 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

Here's what I got:

main:
pushl %ebp
movl %esp,%ebp
pushl %ebx
movl $9,%ebx
.p2align 4,,7
.L5:
pushl $.LC0 # this was the string
call puts # even inlines foo() for you :-)
addl $4,%esp
subl $1,%ebx # mm.. ah! decl doesn't affect the flags
jnc .L5
movl -4(%ebp),%ebx
movl %ebp,%esp
popl %ebp
ret

I think writing code cleanly has the advantage that you don't carry around
stuff that was optimized for the 386 because gcc 2.6 or whatever had a poor
optimizer even when current compilers can do a good job.

Besides, if the code was written by someone with x86 experience, it is possible
that a different version would actually be faster on a RISC architecture like
the sparc. Leaving decisions up to the compiler might be better, and should get
less costly as compilers get better.

-- arvind

-
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/