Messages in this thread |  | | Date | Tue, 25 May 1999 08:53:12 -0400 (EDT) | | From | "Richard B. Johnson" <> | | Subject | Re: goto's ??? |
| |
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/
|  |