Introduce a pass which statically demotes some helpers from candidates
for inlining:
1) Helpers which are part of SCC on the callgraph.
2) Helpers which contains an `insertvalue`.
3) Helpers which _fail_ the `CriticalArguments` criterion.
A critical argument is defined starting from the critical operand
definition.
A critical operand is either the condition of a `switch` instruction or
the indices of a `getelementptr` instruction.
If the dataflow computing the the operand trace back to a formal
parameter of the function, that parameter will be considered critical
when attempting the inlining of the helper.
In case each condition is satisfied, the `revng.inline.policy` metadata
is attached to the function, so that it can be used at _inline_ time to
take the decision based on the critical arguments constantness.
The metadata is encoded as an `iN` integer with N = `arg_size() + 1`:
the extra most-significant bit is always zero so LLVM's signed-decimal
`iN` printer renders the value positively (avoiding e.g. `!{i2 -2}`).
The (de)serialisation primitives live in `revng/Support/IRHelpers.h`
as `serializeInliningPolicy` / `deserializeInliningPolicy` so the
runtime `revngFunctionIsolation` doesn't need to link the build-time
`revngHelperInliningAnalyses` to read the metadata back.
Mirror the existing pointer overload of dumpToString but thread a
ModuleSlotTracker through to the underlying call, so that callers
can amortise slot-numbering work across many dumps. The new
overload returns "nullptr" when the input pointer is null,
matching the non-MST pointer overload.
Introduce templated readers and writers for the "revng.pointers"
metadata in revng/Support/IRHelpers.h. The metadata is a pair of
boolean tuples describing, for an llvm::Function or llvm::CallInst,
which of its return values and which of its argument operands are
pointer-typed in the model. This is the model-agnostic
representation later passes (e.g. ArithmeticToGEP) consume to find
pointers without having to look at the model directly.
In the new pipeline the root module is split off in its individual
isolated modules at the end of `isolate`. Before splitting, there are a
lot of global variables in the root module and only a small part is
going to be needed after splitting for each module. To avoid excessive
memory usage employ `ConservativeModuleCloner` in `Isolate` so that
only the needed global variables are actually cloned when splitting off.
Re-organize the variants of `libtcg-helpers-*.bc` as such:
* `libtcg-helpers-full-$ARCH.bc`: unchanged, contains all helper
function with their bodies and all CSVs.
* `libtcg-helpers-declarations-only-$ARCH.bc`: all helper
functions have been turned to declarations. All CSVs (except a couple
of special ones) have been dropped.
* `libtcg-helpers-to-inline-$ARCH.bc`: only functions with the
`revng_inline` section retain their body. Only CSVs that are used by
these functions are present.
Lift now loads only the `declarations-only` variant of helpers, as
their body is not required until `inline-helpers`. In `inline-helpers`
the `to-inline` variant is loaded and linked, which then allows the
helpers to be inlined.
Add infrastructure to pypeline that allows containers to be notified
when they are being used last, this allows two things:
* `Pipe`s eagerly clearing those containers once they are done reading
their contents
* `ScheduledTask`s clearing those out at the end of their execution in
case the pipe did not do it
This overall should improve memory usage as container no longer take up
memory if they are no longer used as part of a `Schedule`.
Add another container for LLVM modules. This one stores one
`llvm::Module` per function (all modules share the same
`llvm::LLVMContext` for performance reasons).
This commit drops libptc in favor of its new form libtcg.
It brings several improvements, among which:
* The QEMU version we work on has been upgraded.
* CPUStateAccessAnalysis has been reimplemented in a way that makes it
easier to debug and solves some limitations (e.g., tracking leaking
pointers).
* Identification of pieces of the CPU state that are read by each helper
and fixing access to the CPU state is now performed at build-time.
* We no longer mmap the code we need to translate, dropping all the
issues related to code that needed to be mapped where something is
already present.
* We now have two distinct flavors of helper modules: the full one and
the "slim" one. The latter contains the definition only of functions
we intend to inline. It is used in most of the pipeline, a good thing
since we spend less time optimizing code we don't really care about.
The full module is only used on the re-compilation branch of the
pipeline.
* We no longer split the `cpu_loop` function.
* We change MetaAddress to rely on architectures from `model::` as
opposed to the LLVM ones.
* We no longer attach debug info to LLVM IR containing the original
assembly.
* We now verify that the lifted code only contains code we expect.
Introduce the `ScopeCloser` and `GotoTarget` annotations in the IR, and
the relative necessary machinery, needed to handle scope closer and goto
edges for the new backend.
A specialization of the `llvm::GraphTraits`, called `ScopeGraph`, that
is able to handle both the above mentioned annotations is provided.
For the `llvm::GraphTraits` implementation, we introduce the
`GeneratorIterator` class, which uses a coroutine to store the status of
the iteration.
A debug logger pass is added, so that we are able to test the
functionality with `FileCheck`.
Before this commit, we used to attach to call site a metadata to trace
back the call site to the CFG (i.e., `FunctionMetadata`).
This led several passes in revng-c to depend on `FunctionMetadata` just
for this.
This commit, attaches to call sites a reference to the prototype itself
(on the `revng.prototype` metadata), breaking many of such dependencies.
Various parts of revng replace `llvm::GlobalVariable`s representing CSVs
with Allocal/Load/Store. In particular, these are PromoteCSV,
RootAnalyzer and PromoteGlobalToLocalVars.
Before this commit, those places were sloppy when replacing CSVs with
Alloca/Load/Store, and did that iterating on a container sorted by
pointers. This caused Alloca/Load/Store to be emitted in different order
accross runs, which in turn caused more non-determinism down the
pipeline.
This commit fixes the non-deterministic behavior, sorting CSVs based on
their names, which should always be present and deterministic.
getJumpTargetBlock takes llvm::BasicBlock * as argument, but doesn't
need to modify it, so const it adds const to it and other functions that
are used by getJumpTargetBlock: findJumpTarget, isTranslated, getType,
isJumpTarget.
`ValueMaterializer` is a rewrite of what was called `AdvancedValueInfo`
which follows the same principles.
The main benefits over the old version is:
* We materialize the data-flow graph and the CFG of the relevant part of
root. This makes debugging significantly easier.
* We drop the old MonotoneFramework infrastructure in favor of
getMaximalFixedPoint.
* We significantly reduce the amount of queries we make to
AdvancedValueInfo.