Re: goto's ???

Richard B. Johnson (root@chaos.analogic.com)
Tue, 25 May 1999 08:53:12 -0400 (EDT)


On Sun, 23 May 1999, Mofeed Shahin wrote:

>
> G'day all,
>
> I was just have a bit of a look at the fs code, and noticed something a
> little odd. There are alot of 'goto' statements in the code. From what I
> can see they are not needed.
>
> eg :
> line 632 of /usr/src/linux/fs/open.c :
>
> struct file *filp_open(const char * filename, int flags, int mode)
> {
> struct inode * inode;
> struct dentry * dentry;
> struct file * f;
> int flag,error;
>
> error = -ENFILE;
> f = get_empty_filp();
> if (!f)
> goto out;
> ....
> <SNIP>
>
> out:
> return ERR_PTR(error);
> }
>
> this seems like an extra jmp statement to me (unless the compiler
> optimises it)
>
> ie why not just do this :
> struct file *filp_open(const char * filename, int flags, int mode)
> {
> struct inode * inode;
> struct dentry * dentry;
> struct file * f;
> int flag,error;
>
> error = -ENFILE;
> f = get_empty_filp();
> if (!f)
> return ERR_PTR(error);
> ....
> <SNIP>
> }
>
> Cheers Mof.
>

Compile questionable code with the -S option, with output to a file.
Check the assembly. Usually, the gotos are important to maintain
straight-through code for the normal case. If you put a return in
the middle of the code, it doesn't return. It jumps to somewhere
where the saved registers are restored, the stack leveled, and then
a return. In other words, there is only one exit path anyway. So
the designer designed in the exit path so the compiler is less likely
to muck with the straight through code.

Given:

int foo(int bar)
{
if (bar == 1)
goto end;
if (bar == 2)
goto end;
printf("%d\n", bar);
end:;
return 0;
}

You get:

foo:
pushl %ebp
movl %esp,%ebp
cmpl $1,8(%ebp) ; if (bar == 1)
jne .L2 ; Not a 1, try next
jmp .L3 ; This is the goto
.align 4
.L2:
cmpl $2,8(%ebp) ; if (bar == 2)
jne .L4 ; Not a 2
jmp .L3 ; This is the goto
.align 4
.L4:
movl 8(%ebp),%eax ; This is where we print it.
pushl %eax
pushl $.LC0
call printf
addl $8,%esp
.L3: ; Common exit
xorl %eax,%eax
jmp .L1
.align 4
.L1:
movl %ebp,%esp
popl %ebp
ret

Now, you may say; "Nobody writes code like that!". True, it's a demo,
one would probably write such trivial code as:

int foo(int bar)
{
if ((bar != 1) && (bar != 2))
printf("%d\n", bar);
return 0;
}

How, guess what this produces?!!

foo:
pushl %ebp
movl %esp,%ebp
cmpl $1,8(%ebp) ; (foo != 1)
je .L2 ; The goto
cmpl $2,8(%ebp) ; (foo != 2)
je .L2 ; Another goto
movl 8(%ebp),%eax ; Now we print it.
pushl %eax
pushl $.LC0
call printf
addl $8,%esp
.L2:
xorl %eax,%eax
jmp .L1
.align 4
.L1:
movl %ebp,%esp
popl %ebp
ret
.Lfe1:

By checking what the compiler produces, you can see if it might be
best to put a goto in your code even though it might bring up shreeks
of horror from some.

You will find that just ordering something a bit differently, while
maintaining the same logic, may produce a better straight-through path.
For instance everybody loves 'switches'. They make coding clear and
straight forward, however, unless the 'case' is sequential, better
code may be obtained by using 'if() else if()'.

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

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