During the RegionCFG creation from the LLVM IR handle the creation of
nodes with possibly more than two successors.
In this way we do not have to disassemble the switch nodes in nested if
trees.
This commit does three things.
- Removes explicit dependency from boost version 1.63. This is no longer
necessary since orchestra has moved to compiling boost test directly,
and ships version 1.71 (as of now).
- Switches UnitTests.cmake to using modern cmake package for
Boost::unit_test_framework
- Adds an header copied from revng, to define
boost::throw_exception(std::exception const &E)
This is necessary to compile with -fno-exception and boost
unit_test_framework.
Introduced various untangle algorithm improvements:
- Improve untangle edge reorganization: improve the criterion used for
reorganizing the edges between the old postdominator and the cloned
one, after an inline procedure is attempted during the untangle.
- Untangle counter: introduce two new counters which take into account
the number of times the untangle procedure is attempted and the actual
times it is performed.
- Disable not dominated restriction: disable the criterion which
restricts the untangle opportunities if we do not dominate entirely
at least one of the two branches. This has likely broken the
assumption that the postdominators of nodes do not changes after each
untangle step has been carried out.
- Change dominance criterion: the dominance of the nodes belonging to
the `then` and `else` nodes is now checked not with respect to the
conditional node, but to the `then` and `else` edges of the conditional
node.
- Untangle eager inlining: now, when the untangle procedure finds a
suitable candidate for the inlining, proceed the complete inlining
starting from the selected branch. By default new clones of all the
nodes till the exit are created and attached to the branch, while the
original nodes are detached. An additional pass which removes eventual
dandling nodes (nodes which are not reachable from the entry node of
the graph) is performed after the eager inlining. This means that if
no other incoming edges to this group of nodes is present the original
nodes will be purged.
The post dominator now is updated during the inlining analysis, and
the paths conducting to inlined exits are not taken into account for
the post dominator computation.
- Enable untangle for mixed branches: perform the untangle even if the
`then` and `else` branches share nodes. This was not feasible before
because without the eager inlining we couldn't decide which edge to
attach to the new postdominator clone. This problem is not present
anymore, so we can handle any kind of topology in the untangle.
- Improved also the analysis information serialized by the decompiler.
Add a flag to enable the decompilation of a single function.
In order to have a single flag shared between the `RestructureCFGPass`
and the `CDecompilerPass`, we added a new dedicated decompilation unit
called `TargetFunctionOption`.
This commits make the use of Loggers in revng-c more idiomatic, while
removing calls to the method, which clashes with the Qt emit keyword.
This is important, because this clash prevents integration of revng-c
into the GUI, which is written in Qt.
`ExprNode` and its child classes use LLVM-style RTTI.
Until now their destruction was not handled properly, causing the
constructor-destructor type mismatch warnings on ASAN.
Despite this all the code was working properly, but just for luck,
because of the fact that these classes are very shallow.
This commit fixes the issue, and allow `ExprNode` and its child classes
to be extended without worrying about wrong destructors being invoked.
Replicate the changes made by this commit
f2a0df309f78e1b5d7c5f81ada5110523644559e perfomed by Pietro on the
branch containing the development fixes for `revng-c`.
Add new headers files (terminating with `BB`, as `BasicBlockNodeBB.h`),
which will be used as the new header files by the users, and which
contain a declaration of the template instantiation, and a `using`
aliasing the instantiation.
This has been made to comply with the `-Wundefined-func-template` flag,
automatically enabled when using `-Weverything`
Added a new attribute for the `ContinueNode`, which tells if a
`ContinueNode` should be considered implicit. An implicit continue node
means that it can be dropped without it altering the semantics of the
code (e.g., when the `continue` is the last statement inside the body of
a cycle).
This attribute enables us to avoid directly dropping the continue node,
which would also cause the computation attached to this node to be
dropped, also in the output of the decompiler pass.
Enhanced the `findReachableNodes` algorithm, with a new `StackSet`
parallel data structure which is used to quickly check if we are
encountering a node already on the visit stack.
Modified the `findReachableNodes` to include in the returned set of
nodes also nodes which are encountered on self loop paths and that
should consequently be included in this set.
The new SCS merging criterion, checks that there are no abnormal
retreating nodes between SCS, meaning retreatings which exit from the
current SCS and do not point to the head of another SCS.
This kind of situation, if ignored could cause the introduction of some
cycles between outlined nodes and existing nodes, inserting new cycles
during the restructuring, which is a behavior which we aim to avoid.
When outlining nodes, we now include them in eventual parent metaregions
that included the nodes collapsed.
This should lead to minor duplication (as in the `cp` benchmark), since
we avoid duplicating two times nodes if also the external region causes
the first iteration outlining.
The method which computes the weight for a `BasicBlockNode` now relies
on a new `WeightTraits` which is specialized for `BasicBlock` and for
`DotNode`.
In this way, we can change the implementation of the `getWeight` method
without having to modify the implementation inside the `revng` project.
Implement a new `getWeight` method for the `BasicBlockNode` class.
This method is later used in the `untangle` pass to obtain an estimate
of the weight in terms of original instructions of the node under
analysis.
In case of a collapsed node the method recursively explore all the
collapsed region and return the sum of the weights of the nodes
composing the collapsed region.
Improve the computation of the weight for the nodes between the
immediate postdominator and all the exits from the region.
To do this we exploit the `findReachableNodes` helper function, since at
this point all the exits from the region are connected to the `Sink`
node.
Introduce the untangle pass.
This preprocessing phase is in charge of the untangling optimization.
This optimization searches for conditional node, where, if a branch is
completely inlined (i.e., the entire path until reaching the exit is
duplicated and directly attached to it) we can save duplication in the
combing phase.
The untanle is based on a euristics, which consists of estimating the
duplication that could be introduced by the combing (computing the
weight for the nodes not dominated from the conditional node, of both
branches), with respect to the weight of duplicating the path that will
be inlined (the weight of all the nodes of the branch inlined plus the
weight of the nodes from the immediate postdominator of the conditional
until the exits).
The current implementation of the untangle is very conservative (no
untangle is performed if the `then` and `else` branches share some
nodes, or if there isn't at least one of the two branches which
dominates all the nodes until the postdominator).
The euristics also does not take into consideration the weight for
collapsed nodes.
Implementation of the `comb` algorithm without dominator and
postdominator trees.
The comb now uses a list of nodes kept in reverse postorder (and updated
at each dummy insertion, node duplication and node removal), and various
sets of nodes that contains elements still to eplore under a certain
conditional node, nodes already visited, and so on.
Also the set of immediate post dominator (the point at which the comb
stops during its exploration) is computed only once at the beginning of
the algorithm, and simply kept updated at dummy insertion and removal.
The phase that checked if a conditional node dominates all the nodes
until the postdominator, has been replaced by a check which looks if all
the predecessors of a certain node have been visited during the current
exploration (which is perfomed in reverse postorder). If this condition
does not verify, it means that there is an incoming arc incoming in the
node under analysis which is not dominated by the current conditional
node.
There is still margin for improving the performance of this, this is
only a first implementation.
If the `-decompiled-prefix` is passed to the `revng opt` command the
decompilation pass takes care of serializing the decompiled code of each
function in a different file.
The filename is composed by the prefix string passed as parameter and by
the function name.