You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LLVM C back-end now generates a lot of gotos in the C code. These gotos can be removed by using certain transformations on the code. This can significantly improve the readability of the code.
It has 5 steps (keep reading if it has unknown words. Most of these are discussed later):
Collect a list of all goto and Target statements.
"Introduce one logical variable for each Target, initialize it to false, and insert another reinitialization to false at the point of the Target. These are required to make sure that the value of the logical variable is false on all paths except the path coming from the point at which the appropriate conditional test evaluated to true."
Convert unconditional gotos to conditional gotos: if (true) goto Target;
Eliminate Each goto one at a time: do movement transformations if needed to bring Target and goto to the same level (make them sibling). Then applying elimination transformation.
Remove unused labels
There are two main types of transformation that need to be applied:
Elimination Transformations:
when goto and Target are in the same level (siblings):
We should apply these transformations to bring the gotos to the same level of their Target. Then, we can use elimination transformations to remove them.
Each of these transformations moves goto up a level. So, it should be repeated until goto and its target are at the same level.
Outward-movement:
It doesn't matter if Target is before or after goto.
goto_condition_var=goto_condition;
if (!goto_condition) {
statement_1;
t_switch=i; // `i` is the original switch value
} else {
t_switch=1; // `1` is the case that contains `Target`
}
switch(t_switch): {
case1:
if (goto_condition_var) {
goto Target;
}
// ...
Target: target_statement;
// ...break;
case2:
// ...default:
// ...
}
Goto-lifting:
Inward movements require the goto to be before Target. In cases where Target is before goto, we can do goto-lifting transformation first and then apply inward movement.
There is a possibility that a do loop that we introduce has a break or continue that belongs to an outer loop or switch statement. To solve these cases, we use an extra check. For example:
More than one goto associated with a Target inside the same while, if, switch or loop statement:
It would be preferable to insert only one conditional check per label. We can first check to see if the appropriate conditional has already been inserted, and avoid duplicating the code.
ElimGotos/elimGotos : main function that removes any goto statements from stmts by rewriting them as conditionals and loops. It has a switch case and applies these functions:
movement functions:
IfStmt -> moveGotosOutOfIf: before: if body contains only gotos that refer to an outer label. after: if body contains no gotos
ForStmt -> moveGotosOutOfFor
RangeStmt -> moveGotosOutOfRange
SwitchStmt -> moveGotosOutOfSwitch
removal functions
BlockStmt -> elimSiblings: Eliminate conditional gotos from this block -> removeLabels: Remove the (now unused) labels
BranchStmt: Unconditional goto. Wrap in "if true { goto L }"
Here is the summary of the algorithm from the original paper:
The history of this repo contains a past attempt at this, but I reset the state of the repository in f02d746 to exclude it since it was broken.
There is possibly also an implementation of this algorithm on LLVM code as "relooper", inside the WebAssembly target (https://reviews.llvm.org/D11691).
Thanks for the links. I skimmed their code quickly. It seems that they are not directly working on gotos but certainly related.
Do you think we can implement this?
For the start, we can just implement elimination transformations for the cases where goto and Target are at the same level and probably have some simple optimizations for removal of obvious redundant gotos.
LLVM C back-end now generates a lot of
gotos
in the C code. Thesegotos
can be removed by using certain transformations on the code. This can significantly improve the readability of the code.In the following, I discuss a practical summary of the algorithm that was introduced in Taming Control Flow: A Structured Approach to Eliminating Goto Statements, and in the end, an implementation by @mbergin is given.
goto
Removal AlgorithmIt has 5 steps (keep reading if it has unknown words. Most of these are discussed later):
goto
andTarget
statements.Target
, initialize it to false, and insert another reinitialization to false at the point of theTarget
. These are required to make sure that the value of the logical variable is false on all paths except the path coming from the point at which the appropriate conditional test evaluated to true."gotos
to conditionalgotos
:if (true) goto Target;
goto
one at a time: do movement transformations if needed to bringTarget
andgoto
to the same level (make them sibling). Then applying elimination transformation.There are two main types of transformation that need to be applied:
Elimination Transformations:
when
goto
andTarget
are in the same level (siblings):goto
before target:can be replaced with:
goto
after target:can be replaced with:
Movement Transformations:
when
goto
andTarget
are in different levels:We should apply these transformations to bring the
gotos
to the same level of theirTarget
. Then, we can use elimination transformations to remove them.Each of these transformations moves
goto
up a level. So, it should be repeated untilgoto
and its target are at the same level.Outward-movement:
It doesn't matter if
Target
is before or aftergoto
.Move
goto
out ofloop
:All types of loops are similar:
can be replaced with:
Move
goto
out ofif
:can be replaced with:
Move
goto
out ofswitch
:can be replaced with:
Inward-movement:
We here assume that
goto
is beforeTarget
. If not, you should dogo-lifting
transformation before this step to bringgoto
before.Move
goto
into awhile-loop
:can be replaced with:
Move
goto
into afor-loop
:We convert
for
to an equivalentwhile
and then transform it similar to the previous transformation:can be replaced with:
Move
goto
into ado-while-loop
:can be replaced with:
Move
goto
into aif
:Target
is in thethen
part:can be replaced with:
Target
is in theelse
part:can be replaced with:
Move
goto
into aswitch
:can be replaced with:
Goto-lifting:
Inward movements require the
goto
to be beforeTarget
. In cases whereTarget
is beforegoto
, we can do goto-lifting transformation first and then apply inward movement.The transformation is as follows:
can be replaced with (we move the statement that contains
Target
):Conflict of do-loop with outer break/continue:
There is a possibility that a
do loop
that we introduce has abreak
orcontinue
that belongs to an outerloop
orswitch
statement. To solve these cases, we use an extra check. For example:should be replaced with the following for introducing
do-while-loop
instead of what we discussed before:Optimizations
The cases that we can simplify our transformations:
goto
next toTarget
:is reduced to:
goto
at the end of anif
:is replaced with:
goto
right before aloop
:is replaced with:
goto
right beforeswitch
is replaced with:
goto
associated with aTarget
inside the samewhile
,if
,switch
orloop
statement:It would be preferable to insert only one conditional check per label. We can first check to see if the appropriate conditional has already been inserted, and avoid duplicating the code.
For example:
can be replaced with:
Implementation:
This algorithm is implemented by @mbergin in https://github.com/mbergin/controlflow. The important functions of this program are:
ElimGotos
/elimGotos
: main function that removes any goto statements from stmts by rewriting them as conditionals and loops. It has aswitch case
and applies these functions:movement functions:
IfStmt
->moveGotosOutOfIf
: before: if body contains only gotos that refer to an outer label. after: if body contains no gotosForStmt
->moveGotosOutOfFor
RangeStmt
->moveGotosOutOfRange
SwitchStmt
->moveGotosOutOfSwitch
removal functions
BlockStmt
->elimSiblings
: Eliminate conditional gotos from this block ->removeLabels
: Remove the (now unused) labelsBranchStmt
: Unconditional goto. Wrap in "if true { goto L }"Here is the summary of the algorithm from the original paper:
References:
Related: #6
The text was updated successfully, but these errors were encountered: