Verify that softfloat helper calls become visible after the helper
inlining phase in `DetectABI`.
Merge the previous tests for softfloat and these new ones in a single
file, since they use the same ground truth file.
Split the `InlineHelpers` pass into the three phases:
- `link-helpers-to-inline` links the missing `revng_inline` helper
bodies from the `libtcg-helpers-to-inline-arch` module.
- `inline-helpers` inlines, in every function except those tagged
`Root` or `Helper`, the calls to `revng_inline` helpers whose
critical arguments on the call site are constant.
- `delete-helper-bodies` drops from the module the body of every
`revng_inline` function, leaving only the declaration.
The three passes live in a dedicated `revngInlineHelpers` library
(`lib/InlineHelpers/` + `include/revng/InlineHelpers/`), so that
libraries which do not depend on `revngFunctionIsolation` can use them
without creating cyclic dependencies.
Several components in both pipeline YAMLs are slated for removal.
Prepend a legacy prefix to their names, and to the matching c++ code, so
they are clearly distinguished from the new Clift-based pipeline until
they are dropped.
Move all per-function state and logic into a new SegregateFunctionStack
worker, so the pass class itself only holds module-wide state and the
runOnFunction body is just upgrade() + segregate(). The discovery loop
now uses the MFP ExtraState surface to capture the analysis value
before each interesting program point, replacing the splitBasicBlock
trick that introduced fake nodes only to read the lattice value at
them.
Other changes that ride along:
- StackOffsetCache memoizes getStackOffset per function.
- findAllWriters does a single sorted sweep instead of a quadratic
scan over Ranges.
- The pipeline gains a stack-accesses-segregated artifact entry.
- Test fixtures (filecheck.ll, override.yml, segregate-stack-accesses
configuration) are updated to match the new IR shape.
Replace the hoist-struct-phis pass with a split-struct-phis pass that
breaks struct PHI nodes into per-field PHIs instead of moving them
out, and update both pipelines to use the new name.
Return a pointer to a buffer of the requested size and let the macro
dereference it as the target type, instead of casting a uintmax_t. This
makes the macro usable for types wider than uintmax_t.
These tests could pass even when the analysis crashed. The harness
joins the test command into a single shell line, and the diagnostic
block of the error-comparison branch was missing its statement
terminators: it collapsed into a single echo that swallowed `exit 1`,
so the comparison could never fail the test. Moreover, the exit code
of revng2 was only consumed as a boolean, mistaking crashes for
graceful failures, and tests without an expected-error.txt compared
the empty string against the empty RuntimeError payload extracted
from a crash trace, silently passing.
Now the diagnostics are properly terminated, the content of the error
file is printed on mismatch, and the expected-error path requires
exit code 1, an existing expected-error.txt and a non-empty
RuntimeError payload; any other failing outcome dumps stderr and
makes the test fail.
Walks through the full helper evolution pipeline (QEMU C ->
original IR -> full -> to-inline -> declarations-only), covering
env-to-CSV rewriting by fix-helpers, REVNG_INLINE/REVNG_EXCEPTIONAL
semantics, CSV access metadata, and per-artifact usage (lift,
enforce-abi, recompile).
All code snippets are tested via revng test-docs.
When running pypeline comparison tests, copy the `$PWD` to an exclusive
scratch directory, which should eliminate any problems related to the
cache being shared across multiple projects.
Since isort 5.11.0 if a import statement ends with a trailing comma it's
excluded for sorting, which makes the black-formatted import lines
unformatted by isort. Disable this behavior in the config so all import
lines are sorted as they should.
Smoke test that exercises the linux/x86-64 path: feeds malloc/calloc/
realloc plus a NonExistentFunction through the analysis and asserts that
the typed symbols pick up a prototype while the unknown one does not.
Remove the workaround that suppressed the redundant
self-assignment that the pass now occasionally introduces in
non-legacy mode.
The remaining self-assignments are not bugs but sub-optimal C
generation, so we just disable the -Wself-assign warning in the
tests.
The sub-optimal code generation comes from passes that emit local
variables (allocas) before conversion to Clift, e.g. STS and
ExitSSA (with more planned). Each of these passes generates local
variables independently and they don't know about each other; the
order between them might also be swapped in the future. The only
clean fix is to unify them into a single transformation pass that
takes the results of multiple analyses (in the LLVM sense) and
emits local variables once. We have plans to do that, and when
it's done the warning can be re-enabled.
Introduce a new canonicalisation pass that forces a small set of
exponential-dataflow-prone instructions (SelectInst plus the FShl
and FShr intrinsic patterns) to be stored into a dedicated local
variable. Without this, expanding their value into C expressions
during decompilation can blow up into exponential path enumeration
on real binaries.
This is a temporary workaround. A more principled split of
pathological dataflows is planned and will replace this pass.
The macro is no longer necessary: the code now ensures we never
need to assign anything to an array, which would be ill-advised
nevertheless given that array-typed rvalues in C immediately
decay to pointers.
The macro is no longer necessary: the code now ensures we never
need to bitcast anything to an array, which would be ill-advised
nevertheless given that array-typed rvalues in C immediately
decay to pointers.
Run -strip-dead-prototypes as part of the LLVM-pass list invoked
just before the Clifter, so that all unused helpers are stripped
away. In particular, this prevents some LLVM intrinsics that
return structs containing i1 (e.g. the overflow intrinsics) from
ending up in the C output and tripping later passes.
assign_array is necessary as a fallback for when the decompiled C
code may need assignments among array types. bit_cast_to_array is
necessary because when the target type of a bitcast is an array
the regular bit_cast macro is not enough.
Rework primitive-types.h so that the various bit_cast macros share
a single implementation based on `typeof`/`__typeof__`. As a
consequence both keywords are added to the model's reserved-name
set so that user identifiers cannot collide with them.