Three closely-coupled changes that have to land together to keep
every caller compiling:
- Introduce a per-instance ExtraState recording surface (with a
NoExtraState default) and thread it through applyTransferFunction.
- Replace getMaximalFixedPoint's positional arg list with a single
MFPConfiguration struct, so callers spell out only the fields they
need.
- Replace the EntryLabels pointer with an Entry/All/vector* variant
so callers can ask for the graph entry, every node, or a custom
list without juggling extra arguments.
Update every existing caller for the new signatures and switch
Liveness::GraphType to a plain Function* (with the inverse
GraphTraits selected at call sites).
Split createReturn into a reusable createCall that emits the
struct-initializer call without wrapping it in a return. An EmitBody
flag lets callers create the declaration but skip the body, useful
when the body would later be stripped.
The YAML traits for Layout (and friends) move into Layout.h so callers
can serialize a Layout directly without pulling in Layout.cpp's
internals. As a result StackSpan gains default-initialized fields and
its operator+ is hoisted to a free function (with the symmetric
uint64+StackSpan overload) so it works with the YAML mapping.
Drop the SPTAR-specific special case in layoutToLLVMFunctionType: all
ModelAggregate-returning functions now use the same array-of-i8 return
type. Clifter is updated accordingly to treat any aggregate return the
same way, removing the SPTAR-specific branches that were just dead
code after the type unification.
After we drop legacy mode, the only user of LocalVariableBuilder will be
SegregateStackAccesses. This is possible thanks to the fact that
dropping the legacy mode will demistify local variables and turn them
into plain allocas accessed via loads/stores. This will end the need for
a centralized place to deal with local variable creation, that is caused
by the various ad-hoc manipulations we've been doing for a long time in
legacy mode.
The --import-debug-info CLI flag and the ImporterOptions::
AdditionalDebugInfoPaths field it populated were a side-channel that
loaded extra DWARF files outside the normal ELF dependency-resolution
path. It bypassed the symbol-aware machinery and is no longer needed.
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.
Translates a mlir::BlockArgument to an mlir::Value more directly
representing the entity or expression to which the block argument
refers, or null if not applicable for the statement in question.
Split the `invalidate` method in two phases: in `invalidateCheck` it
just checks if the model diff warrants the execution of the actual
`invalidate` method, which requires fetching the custom invalidation
data from storage. The actual `invalidation` method remains the same.
This should make invalidation faster for storage providers that store
the invalidation remotely.
Unfortunately, in DWARF, there's no widespread indicator on whether a
function is regular ARM or Thumb. Therefore, in this commit, instead of
blindly creating a new function, we first check if, in the model, we
already have a function at that address.
This means that, if we have a Thumb function in DWARF, but it doesn't
already exist in the model, we will import as regular ARM, which is
wrong.
Specifically, this can happen with `revng model import debug-info`.
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.
The Clifter public header only needs llvm::Function, not the full
llvm::Module definition, so drop the Module.h include. This
shaves a non-trivial amount of compile time off the translation
units that depend on Clifter.h without pulling in Module.h
themselves.
Drop the !revng.variable_type metadata and the matching helpers,
along with the only place in the Clifter that still consumed them.
After the previous LVB cleanup nothing emits this metadata, and the
model variable type can be reconstructed from the alloca's array
type alone.
Emit forward declarations and definitions of the opaque-array
artificial structs from the C model header (and from the helpers
header). Definitions are gated on a new DefineOpaqueTypes flag
threaded through PTMLHeaderBuilder::printModelHeader so that the
helpers header keeps emitting only the declarations.
Teach NameBuilder and ModelCBuilder how to produce names and
references for opaque-array types: NameBuilder gains
opaqueTypeName(ByteSize), ModelCBuilder gains the matching
reference and definition tags. Both rely on the new
Configuration::OpaqueTypePrefix.
Add an OpaqueTypePrefix string to the model configuration with
default `opaque_type_`. This is used to build the C name of the
artificial structs that wrap model array types and keeps the prefix
configurable alongside the other artificial-name prefixes.
Define a new "opaque-type" rank in revng/Pipes/Ranks.h, keyed by
the byte size of the wrapped type. This rank is used by upcoming
commits to identify the artificial structs that wrap model array
types in Clift.
Replace the home-grown hasSideEffects, mayHaveSideEffects,
mayWriteToMemory and mayReadMemory helpers (in
DecompilationHelpers.h) with the equivalent predicates from
llvm::Instruction. The legacy code paths still need a few extra
checks, so the templated wrappers in SwitchToStatements.cpp
specialise on IsLegacy and fall back to the LLVM predicates in
non-legacy mode.
This removes the now-unused helpers from DecompilationHelpers.h.
Reorganise LocalVariableBuilder so that the legacy and non-legacy
code paths are separated into two specialisations, and so that the
non-legacy specialisation does not need a model::Binary to operate.
This is a prerequisite for using LocalVariableBuilder from passes
that do not know about the model, e.g. unit tests for the new-PM
SwitchToStatements and the upcoming non-legacy decompilation
pipeline.
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.