We introduce the `CycleEquivalence` analysis.
This is an analysis which implements the _Cycle Equivalence_ computation
algorithm, and provides as result the _cycle equivalence classes_
Specifically, we introduce:
- The `CycleEquivalenceClass`, which is the unitary element computed by
the analysis.
- The `CycleEquivalenceAnalysis`, which contains the algorithm to
compute the cycle equivalence.
- The `CycleEquivalencePass`, a `FunctionPass` that can be used to
perform the analysis on a `llvm::Function`.
The algorithm is composed by various stages:
- We construct a new `GenericGraph` object, replicating the input CFG,
with the addition of the `exit`->`entry` edge.
- Taking advantage of `llvm::GraphTraits<Undirected<>>`, we can now
implement the algorithm working on an undirected version of the input.
- We perform the `CycleEquivalence` computation, returning a
`llvm::SmallVector` of `CycleEquivalenceClass` objects.
In addition to using the `llvm::GraphTraits<Undirected<>>` traits to
walk on the equivalent undirected graph, we also need to:
- Perform a preliminary DFS, in order to:
- Assign the DFS number to each node in the graph.
- Compute the spanning tree, and use this information to distinguish
tree edges and back edges when running the algorithm.
The internal graph used by the analysis also normalizes the graph in
order to have a sinle exit node (called sink), which is a requirement
for the `CycleEquivalence` algorithm.
We also implement the `llvm::DOTGraphTraits` for the
`CycleEquivalenceAnalysis<llvm::Function *>` specialization. In this
way, we can have a graphical representation of the undirected graph used
internally in the `CycleEquivalenceAnalysis` core implementation.
We add some `FileCheck` tests on some well-known graph topologies.
This is due to the fact that type inlining currently is broken in some
corner cases involving recursive types.
The bugs are caused by the fact that TypeInlineHelper uses its own
custom graph instead of using the DependencyGraph used by ModelToHeader,
causing different decisions about the order of emission of types.
As a result, the generated C types are not valid C, and they fail to
compile because a field of a struct has a type that is defined later
than its use.
After refactoring TypeInlineHelper to use DependencyGraph like
ModelToHeader, this can be reverted.
This change is a preparation for further decoupling of the
TypeInlineHelper from its custom dependency graph type, to try and reuse
the DependencyGraph used in ModelToHeader.
There seem to be some issues with defining these in headers due to the
storage type being incomplete. The storage type is only defined in the
.cpp file.
`TypeToNumOfRefs` was used only in one method, so it can be computed
directly there on the fly.
`calculateNumOfOccurrences` doesn't need to be a method (it can be a
free function), it doesn't need to run at construction time, and it
doesn't need to return a map. So it's been moved in the `.cpp` file,
renamed to `getCrossReferencedTypes` and changed to return a set. It is
now only called when needed.