otisonoza
otisonoza

Reputation: 1344

Why the compiler cannot (always?) optimize code that has GOTO?

I've written some PL/SQL programs where I found GOTO helpful, like jumping out of nested loops, etc.

I've been wondering, if it's really a bad idea to use gotos in other languages. (For example C++.)

I found these questions:

GOTO still considered harmful?

effect of goto on C++ compiler optimization

There's an answer saying: "a compiler typically cannot optimize code that contains gotos."

And in the other one: "It is possible, however, to produce a flow graph with gotos that couldn't be produced by any normal flow control statements (loops, switch, etc.)"

I've been told that's goto evil, but no one told me why, except for codes with gotos are horrible to read. Well, if no one learns, understands how to use them because they're "evil", no one can read them.

What are the cases when the compiler CAN and CANNOT optimize a code that contains GOTO? Why?

Upvotes: 3

Views: 644

Answers (1)

user395760
user395760

Reputation:

Big fat disclaimer:

I've been wondering, if it's really a bad idea to use gotos in other languages. (For example C++.)

Except for one exception (C, mentioned below) which is coupled with a great deal of discipline, it almost never is a good idea. It's language-dependent, so ask your local guru, but the odds that you'll find a good use case are rather slim. Err on the side of caution. Chances are the language has a more idiomatic and clearer way to do whatever you're inclined to use goto for.


It's not so much a case of "cannot ever" or halting-problem-impossible as "just impractical". Sometimes, especially if you just hide your loops by manually writing equivalent gotos (what a stupid thing to do!), it may work by chance. At other times, especially if the control flow graph resembles spaghetti or is otherwise weird/unusual, the compiler may not manage optimizing anything.

There's only so much time and thought to put into creating optimization passes, and only so much time the compiler can spend running optimization passes. It's much more rewarding to focus on the widely used, well-understood control flow patterns built into most languages (while loop, loops with known-at-start trip count, early return, switch, chains of else if, etc.). Even when the optimizations happen on an IR which only supports goto-esque control flow, these patterns lead to predictable, easily recognized disguises and the optimizations are tuned to look for those. This is what the second sentence you quote talks about. If the code jumps back and forth in a manner completely unlike a loop, a loop unrolling pass won't give it the time of the day even if it's actually a clever (the bad kind of clever) way of writing "do this four times".

Until now, I've assumed a goto like the one from standard C — that is, the target label is known statically and restricted to honor other language constructs (e.g. only jump within one function). There are extensions which allow jumping to arbitrary, dynamically-chosen targets (e.g. "computed goto"). These are much harder to analyse (and thus optimize), likely in the same ballpark as function pointers.

I've been told that's goto evil, but no one told me why, except for codes with gotos are horrible to read. Well, if no one learns, understands how to use them because they're "evil", no one can read them.

Then those who told you have done a bad job. This isn't the question for it, so I'll keep it brief: 99% of control flow fits into very few categories that warrant specialized control flow constructs. Using a single construct, GOTO, for all those cases obscures the intent, it's more code and it takes longer to understand roughly what the code is doing. You can experience this first hand: Write some reasonably complicated >100 line batch files (that awful ancient Windows scripting language).

Ah, one more thing:

I found GOTO helpful, like jumping out of nested loops

That is a potentially fine use, but most languages provide clearer ways of doing that. Alternatively, flatten the loop (e.g. with Python's itertools.combinations) and break, or put the nested loop into a separate function (good idea anyway in many cases) and return.

Moreover, these are good uses for goto. For example, error handling in C. These use cases often also conform to a simple pattern, but one which is not built into the language, so one has to make do without.

Upvotes: 2

Related Questions