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.
To avoid skeing the results the serialization of `DOT` intermediate file
for both restructuring and AST semplification passes are now serialized
only when the corresponding loggers (`CombLogger` and `BeautifyLogger`)
are enabled.
When a retreating edge involves as source node a `SetNode` belonging to
an internal region (which should be the default `SetNode` that remains
outside the collpased node), move it just after the `CheckNode` that is
being introduced, so that the semantics of the code remains untouched.
Use a `llvm::SmallString` for the `Name` field of `BasicBlockNode`.
This enables us to modify the name of the node, which is very useful
during debugging and manual inspection of the graph serialized in
output.
`BasicBlockNode` and `RegionCFG` classes are now template classes. This
means that the `BasicBlockNode` class can be used as a generic wrapper
for any type of object in the original graph (it is usually used to wrap
a `llvm::BasicBlock *` for decompilation purposes, but in tests it can
be used to wrap a `DotNode` object) that implementes `GraphTraits`.
Improved the interaction with the `StringRef` name field of
`BasicBlockNode`.
In case of artificial nodes, the name is left empty and created
on-the-fly for serialization purposes.
Removed the computation of the information contained in the
`NDuplicates` prevously done in the `MarkForSerialization` pass, since
the information is now precomputed in the `RestructureCFG` pass and
exposed with a dedicated method.
Add a `DotGraph` and `DotNode` classes, which implements `GraphTraits`,
so that we can create a `RegionCFG` starting from a graph specified in
a `.dot` file.
The `DotClass` implements a minimal parser for graph specified in `.dot`
format.
The `.dot` should begin with the specification of the name of the graph
`digraph TestGraph {`, followed by an arbitrary number of lines which
specify the edges in the graph (no attributes allowed, e.g., `a -> b;`).
The file should end with a single line ending in `}`.
Add helpers to test if two `RegionCFG` objects can be considered
equivalent.
This will be used in the test environment to check if the comb
transformation is consistent with the expected behavior.
Update the `OriginalBB` map (which will be later used for retrieving the
original basic block linked to a certain BBNode) during nested
`RegionCFG` creation and during flattening, which are steps that modify
the allocation of the `BBNode` objects.
The `RegionCFG::initialize` method is now a template method, which
accepts as input any kind of object which exposes the `GraphTraits`.
In this way we can build a `RegionCFG` object not only starting from
LLVM IR, which can be very useful for testing purpose.
Since we also removed the information about the original
`llvm::BasicBlock` inside the `BasicBlockNode`, we need to keep this
link to later feed this information to the GHAST in an external data
structure (potentially a `std::map`).
The `BasicBlockNode` does not contain anymore any pointer to the
`llvm::BasicBlock` object that generated the `BasicBlockNode`.
This change is necessary for decoupling completely the `BasicBlockNode`
and `RegionCFG` classes from the LLVM IR, so that we can build up a
`RegionCFG` from any object which implements the `GraphTraits`.
The `RegionCFG` does not contain anymore a map between
`llvm::BasicBlock` and `BasicBlockNode`.
The `removeNotReachables` method now can take care of removing any
reference of the removed nodes from any `MetaRegion` which contains any
reference to it.