• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

function calling with an if statement?

Page 2 - Seeking answers? Join the AnandTech community: where nearly half-a-million members share solutions and discuss the latest tech.
Perhaps I am mistaken, but aren't 'goto' statements bad for other reasons:

A. The compiler cannot optimize a goto statement like a function call. For instance, a function may be inlined instead of creating a stack frame in certain cases (While a goto doesn't need a new stack frame, there are other optimizations that I am sure can be used).

B. It is bad for pipelining and branch prediction (There is a good chance this point is wrong because I would imagine that the branch prediction is sophisticated enough to follow a jump or long jump).

C. Additionally, having goto statements everywhere make code readability an absolute nightmare. (Plus, chances are if a person is using extensive goto statements, they are not a good programmer already. Thus, the code probably has no comments and bad formatting).

D. Can potentially get into infinite loops.

E. When used in a multi-threaded environment, unlocking and locking critical sections with a goto anywhere in your code would be a nightmare of epic proportions.

-Kevin
 
Perhaps I am mistaken, but aren't 'goto' statements bad for other reasons:

A. The compiler cannot optimize a goto statement like a function call. For instance, a function may be inlined instead of creating a stack frame in certain cases (While a goto doesn't need a new stack frame, there are other optimizations that I am sure can be used).

B. It is bad for pipelining and branch prediction (There is a good chance this point is wrong because I would imagine that the branch prediction is sophisticated enough to follow a jump or long jump).

C. Additionally, having goto statements everywhere make code readability an absolute nightmare. (Plus, chances are if a person is using extensive goto statements, they are not a good programmer already. Thus, the code probably has no comments and bad formatting).

D. Can potentially get into infinite loops.

E. When used in a multi-threaded environment, unlocking and locking critical sections with a goto anywhere in your code would be a nightmare of epic proportions.

-Kevin
A. The goto statement literally breaks down to a jmp instruction. So there really isn't a whole lot of optimizations the compiler could do even if it where a function call (I'm not using it as such either)

B. Yeah, this is a wrong point. Again, a jmp statement. There is no branching going on at all. Really it is more like "mov EIP, address" then a branching statement.

C. Is a potential problem, however, this is one case that a goto makes things cleaner then a non-goto. I'm in the "Avoid if possible" boat.

D. So can "While (true)" and recursion... Heck, any looping mechanism can lead to an infinite loop.

E. Ehh, not really. If you keep the goto label in the function that the goto is used (Why would you jump out?), then the locking rules are pretty much the same. So long as you keep the goto and label on the same locking level, there really isn't a problem IE

Code:
lock()
label:
goto label;
unlock();

or

label:
lock();
unlock();
goto label;
 
the change I was thinking of would look something like this

Code:
try
loopstart:
   if (count > 100)
      step = 100;
   while (i < count)
   {
      dostuff(i, step);
      i += step;
      if (i + step > count)
         step = 1;
   }
catch
   if (step > 100)
   {
      step = 1;
      goto loopstart;
   }
   else
   {
      saveErrorMessage();
      if (count - i > 100)
         step = 100;
      ++i;
      goto loopstart;
   }
Gimme a break;

Seriously! 🙂

Code:
while(true) {
try
   if (count > 100)
      step = 100;
   while (i < count)
   {
      dostuff(i, step);
      i += step;
      if (i + step > count)
         step = 1;
   }
   break;
catch
   if (step > 100)
   {
      step = 1;
   }
   else
   {
      saveErrorMessage();
      if (count - i > 100)
         step = 100;
      ++i;
   }
}

break; is nice, since it goes to the end of a loop, just like a goto, but it's better-known by the compiler. Also, Java supports break; but not goto.
 
Oh and as for the OP:

As others have said a simple selection or multiple selection statement is fine. Keep in mind; however, that a switch statement cannot evaluate strings.

Additionally, if you have a tight range for the values of the switch statement, the compiler can optimize the selections from an if-else chain into a jump table (Much faster)

-Kevin
 
A. The goto statement literally breaks down to a jmp instruction. So there really isn't a whole lot of optimizations the compiler could do even if it where a function call (I'm not using it as such either)

B. Yeah, this is a wrong point. Again, a jmp statement. There is no branching going on at all. Really it is more like "mov EIP, address" then a branching statement.

C. Is a potential problem, however, this is one case that a goto makes things cleaner then a non-goto. I'm in the "Avoid if possible" boat.

D. So can "While (true)" and recursion... Heck, any looping mechanism can lead to an infinite loop.

E. Ehh, not really. If you keep the goto label in the function that the goto is used (Why would you jump out?), then the locking rules are pretty much the same. So long as you keep the goto and label on the same locking level, there really isn't a problem IE

Code:
lock()
label:
goto label;
unlock();

or

label:
lock();
unlock();
goto label;

Yea I was thinking about everything after I posted it, and, at least in your instance, there aren't many compiler level optimizations that can be done. I suppose I was thinking of the absolute worst case scenarios.

As for the multi-threading comment, I was referring to when a goto is used to leave a critical portion of code entirely. Again, a rare and stupid idea, but something that could happen nonetheless.

A while(true) or a for(;😉 can't be done on accident though 😉 Whereas a goto is a lot easier to mess up.

I suppose the hatred for goto is somewhat unwarranted, but I do agree it is, as you said, one of those things that you want to "avoid in most cases".

-Kevin
 
Gimme a break;

Seriously! 🙂

Code:
while(true) {
try
   if (count > 100)
      step = 100;
   while (i < count)
   {
      dostuff(i, step);
      i += step;
      if (i + step > count)
         step = 1;
   }
   break;
catch
   if (step > 100)
   {
      step = 1;
   }
   else
   {
      saveErrorMessage();
      if (count - i > 100)
         step = 100;
      ++i;
   }
}
break; is nice, since it goes to the end of a loop, just like a goto, but it's better-known by the compiler. Also, Java supports break; but not goto.

lol, yeah, I came up with the exact same solution after I tried to implement my goto code. The compiler doesn't allow jumping out of exceptions. So no goto for me 🙂 (actually, my solution is a bit different, I do it without the second loop. I really could just move the try statements down a level to encompass pretty much only the function that was throwing the exceptions.)
 
Gamingphreek (G) and Cogman (C)
SOME PARTS ABRIDGED. Hopefully I have not changed the intent.

G: A. The compiler cannot optimize a goto statement like a function call...
C: The goto statement literally breaks down to a jmp instruction.
My take:
Branches do not get faster than PC-relative non-conditional flavored branches (x86's jmp is, in this case, a pc-relative branch). I would argue that goto is the quickest way to move to an arbitary piece of code (in high-level languages).

Aside: A compiler might have to insert cruft to fix the stack pointer when goto-ing up and down a local stack. Nominally, thats an extra add operation. It may or may not be needed after peephole optimization.

G: B. It is bad for pipelining and branch prediction...
C: Again, a jmp statement...
My take:
As above, unconditional pc-relative branches are the easiest class to predict. They would therefore have the least impact on the pipeline of all control transfer instructions.

G: C. Additionally, having goto statements everywhere make code readability an absolute nightmare...
C: (this) Is a potential problem
My take:
I agree, this can be a problem. But, what kind of statements can be used everywhere and still have readable code? Just as many gotos can kill readability, so can multiple if's, while's, for's, or switch's. All control constructs can be used badly -- this alone is not specific to goto, but many programmers never learn to use goto in a readable fashion.

G: D. Can potentially get into infinite loops.
C: any looping mechanism can lead to an infinite loop
My take:
Any looping mechanism can lead to an infinite loop

G: E. When used in a multi-threaded environment, unlocking and locking critical sections with a goto anywhere in your code would be a nightmare of epic proportions.
C: Ehh, not really...
My take:
goto is one of the best ways to implement check-and-lock functionality in graph-based data structures. Often, its difficult to tell if a lock is needed at a given node or not... sometimes you have to check the local data first. But then, you have to go back (hence the goto), acquire the lock, re-check the data (to prevent races, except ABA... subtle, that), and then do whatever manipulations need to be done.

Like all multithreaded code, there's plenty of room to hang yourself.

G: Additionally, if you have a tight range for the values of the switch statement, the compiler can optimize the selections from an if-else chain into a jump table (Much faster)
My take:
Jump tables are not always faster. Jump tables end up as a register-indirect branch, which can miss in the BTB. Furthermore, because register-indirect branches are typically predicted based on PC of the branch itself, jump tables tend to miss in the BTB. Therefore, they are only beneficial if there are many potential branch targets (e.g., a large switch statement), or if there is very little bias toward any one branch outcome. If there is a strong bias on one particular result, it is better to use an if/else tree, as that path will collapse into a series of correct pc-relative conditional branch predictions.
 
Last edited:
My take:
goto is one of the best ways to implement check-and-lock functionality in graph-based data structures. Often, its difficult to tell if a lock is needed at a given node or not... sometimes you have to check the local data first. But then, you have to go back (hence the goto), acquire the lock, re-check the data (to prevent races, except ABA... subtle, that), and then do whatever manipulations need to be done.

Like all multithreaded code, there's plenty of room to hang yourself.

You don't need to use a goto to implement an atomic update. (SLists) The push and pop can be implemented with a while or do while.
 
Back
Top