When DLA is activated, a larger variety of combinations between integers
and pointers operands need to be handled when emitting C code from LLVM
Instructions.
This commit removes some assertions that do not hold anymore about some
operands not being pointers, handles a set of new cases with strange
mixtures of pointer and integer operands, and introduces a fail path for
cases that are not handled when emitting code based on DLA results.
Before this commit, we assumed that given a Value V, if only a single
entry was found for in ValueLayouts, it meant that is was a scalar type.
This assumption was wrong, because it could be a struct type for which
we didn't have information about memory access for all fields but one.
This caused some struct type to be wrongly identified as scalar types.
This commit fixes the issue.
Before this commit, the creation of layouts in the DLA was very
aggressive, treating almost every instruction as if it could be an
address (hence creating a layout for it).
This commit adds assertions and narrows down the number of cases where
an instruction is actually considered an address.
Specifically, the following kinds of instructions are not considered
addresses anymore:
- Mul
- SDiv
- UDiv
- SRem
- URem
- AShr
- LShr
- Shl
- And
- Xor
- Or
Before this commit, we assumed integer-to-pointer casts were only
widening, never narrowing.
Turns out this is not true. For instance, narrowing casts happen when
decompiling s390x code.
With this commit, the decompiler can handle that case gracefully.
A logical bug prevented to properly identify some leaf Values in SCEVs
as base addresses, restricting such Value leaves to only be CallInst to
isolated Functions.
This commit fixes this bug and enables to identify base addresses that
are not CallInst.
This commit is just a skeleton. In order to actually build those member
accesses, we still need to compute the proper nested dla::Layouts for
which we want to emit those member accesses.
This commit fixes a bug due to interacting behaviors between
MarkForSerialization, AddSCEVBarrierPass, and the emission in C of calls
to revng_init_local_sp.
These interacting behaviors caused the following quirks:
- At the beginning of Functions that contained a call to
`revng_init_local_sp()`, that call was actually emitted twice.
The first time was due to the actual call to `revng_init_local_sp()`,
while the second was due to the first call being wrapped from a call
to `revng_scev_barrier_*`.
Now we properly emit only one call.
- The original call to `revng_init_local_sp()` was supposed to generate
a local variable, to be used in various places across the function.
However, due to the fact that the call was not properly labeled by
MarkForSerialization, there was no local variable, causing calls to
`revng_init_local_sp()` to be scattered around the body of the
functions, follwed by various arithmetic operations.
This behavior has been fixed as well, and we now emit the local
variable correctly.
Before this commit, the DLA code made very strong assumptions about
Functions that returned struct types.
In particular, calls to such Functions were expected to have at most a
number of uses equal to the number of fields of the returned struct.
Moreover, such uses were only expected to be ExtractValueInst.
Now, we still assume that such uses are ExtractValueInst, but we don't
make any strong assumption on their number anymore.
This makes the DLA code less reliant on specific form of LLVM IR, so we
can also drop -gvn-hoist from the decompilation test pipeline.
This commit introduces a new LatticeElement for the
MarkAnalysis::Analysis MonotoneFramework.
Before this it used a IntersectionMonotoneSet.
This commit extends the set transforming it into a map, that holds the
set of Instructions with side-effects that taint each pending
instruction.
This is not used yet. The behavior is identical to the old one.
It will be used in future commits to prevent serialization when
possible, to increase the quality of emitted C code, thanks to the fact
that serializing less instructions means less local variables in C.
This `FunctionPass` uses the results of `MarkForSerializationPass`, if
present, to wrap some instructions into calls to `revng_scev_barrier_*`
functions.
`revng_scev_barrier_*` functions have names that are deterministically
constructed from the type they wrap.
They have the semantics of an identity function, but we don't provide
the body, so that LLVM's ScalarEvolution Analysis cannot see through
them.
At the moment, the inserted function calls are not manipulated anywhere
else in the codebase, but we plan to use this mechanism in the
decompilation pass to prune the expressions that are converted to
pointer arithmetic.
This commits enable the emission of rich types associated with function
signatures. This types are forward-declared in the decompiled C code
before the definition of each decompiled function that uses them.
The types we emit for now are the types that the DLA is able to compute
(if any) for the return values and the arguments of the function.
Such types are not yet used in the body of the function, nor in the
function declaration. These are the next steps to come.
Before this commit, logical operators (&&, ||, !) were never emitted in
C. Bitwise operators were used instead (&, |, ~), relying on the
implicit equivalence of meaning.
This commit enables the emission of logical operators when the operands
are boolean types, making the emitted C more readable.
Before this commit, the MakeLayout step of the DLA used to deduplicate
structurally equal Layouts. This has turned out to be wrong when going
forward with the emission of types in C.
Being able to tell apart two different types that are structurally equal
is important for the emission of C types. Throwing this information away
with deduplication is bad. This commit disables such deduplication.
This is a utility class useful to make std::set<std::unique_ptr<T>>
searchable with raw pointers, by using
std::set<std::unique_ptr<T>, HeterogeneousPtrCompare<T>> instead.
Handling of command line options that specify paths for output files
have been improved in the following ways:
- If the CDecompilerPass is not default-constructed, it already has a
reference to the stream where outputs must be written. In this case,
it is wrong to use a command line option to specify the output
directory. If this happens the program is now able to detect it and to
terminate with an error.
- If some of the specified paths is not found or has the wrong
permission, the program fails early.
- On program failure because of one of the above safety checks, the
program terminates with an informative error message.
This means that they can be specified only once on the command line.
If they are specified more than once, the program fails with an
informative error.
Before this commit, the logic to generate all the emitted C forward
declarations (types, global variables, and functions) that has to be
printed before each decompiled function was scattered across three
classes: FuncDeclCreationAction, TypeDeclCreationAction, and
GlobalDeclCreationAction.
These are all gone now, because the scattered logic was very confusing
to follow. Now we only have a single class that takes care of
declarations with global scope: DeclCreator.
Thanks to this, I was able to drop a bunch of useless layers of software
engineering used to shape the creation of the declaration as if it was
some kind of clang ASTConsumer, which is pointless.
This class handles the creation of type declarations in clang's AST, and
holds the relationships between llvm Types and Values with those clang's
type declarations.
This commit prevents the creation of instance links for offsets that we
don't support yet, during the CreateIntraProceduralTypes DLAStep.
This makes possible to avoid explicitly handling those cases in many
DLASteps, such as ComputeUpperMemberAccess,
ComputeNonInterferingComponents, and DLAMakeLayouts.
The offsets that are not supported yet are:
- all negative offsets
- all strided offsets with non-strictly-positive stride values
- all strided offsets with non-strictly-positive stride values
- all strided offsets with known negative trip-count
Some beneficial side-effects of avoiding the creation of such links are:
- the total number of edges on the graph is reduced, reducing the worst
case depth of most visits
- it's impossible to create types with null or negative size (that we
wouldn't know how to emit in C)
This is a flag used to mark a given `LayoutTypeSystemNode`.
It represents the fact that the children nodes are either all
interfering with each other, non-interfering with each other, or
unknown.
This information will be filled-in by the
`ComputeNonInterferingComponents` step, and will be used from the
`MakeLayouts` step to decide if the children of the node will be emitted
as fields of a union (interfering) or fields of a struct
(non-interfering).