Before this commit we were restoring opaque extractvalue instructions to
actual non-opaque extractvalue instructions in the pipeline.
We will not do this anymore, since LLVM ends up messing around too much
with them and it breaks the somewhat assumptions we're making around
values with aggregate types, that in our IR only represent tuples of
registers coming from the binary.
We were not properly handling functions with a `CABIFunctionType` whose
return value covered multiple registers (e.g., a `uint64_t` being
returned through two registers in i386).
Also, we were not correctly handling `CABIFunctionType` returning a
integer type that is smaller than the register containing it (e.g., a
`uint32_t` being returned through `rax` in x86-64).
This commit fixes both situations.
Introduce the hybrid beautifier aiming to simplify double `not`s (one on
the IR side (e.g., a `icmp ne`), and one on the `ExprNode` side on the
`GHAST` in the form of a `NotNode`.
To do this hybrid beautifier, we basically need to do the following:
- Implement a preliminary collection phase which computes which
`ExprNode`s are affected by which `BasicBlock`.
- Compute the so-called consesus, i.e., verify that for all the
`ExprNode`s affected by a certain `BasicBlock`, the transformation
would be beneficial in terms of output. Basically:
1) That the number of `!(!=)` transformed into `(==)` outscores the
number of correlated `(!=)` which are transformed into `!(==)`.
2) That the number of `!(==)` transformed into `(!=)` outscores the
number of correlated `(==)` which are transformed into `!(!=)`.
- Actually perform the transformation for those situations where the
consensus agrees.
If the base pointer that we're trying to use to build a ModelGEP points
to a zero-sized type, just ignore it, since we wouldn't be able to
traverse that type in any sensible way.
Before this commit, we assumed that the size of model types could be
either smaller, equal or larger than IR types.
Hence, the code was designed to take care of all those situations with
various workarounds and assertions.
Thanks to recent developments, the size of Model types can only be equal
to the size of IR types.
There are only 2 exceptions to this rule:
- the size of SPTARs, that can be larger on the Model than on IR, since
on the IR they are returned as pointers, while on the Model they are
aggregates;
these were already handled properly before this commit.
- the size of IR-pointers, since their size in LLVM is target-dependent;
before this commit they were handled poorly, using LLVM's DataLayout
but not taking into account that the DataLayout is not necessarily the
one of the proper target;
this commit fixes this, just taking the pointer sizes from the Model,
which effectively represents the proper pointer size for what we're
handling.
If a function was returning a scalar, we used to forward the return type
from before Segregate. However, this was not OK in case a return value
was in a 64-bit register, but was actually using only the lower 32-bits.
This commit improves handling of such situation.
This commit enables to emit accesses with the square bracket array
access operator on pointers.
This is accomplished by adding an additional mandatory argument to
ModelGEP (AND NOT to ModelGEPRef) to represent this case.
MakeModelGEPPass is updated to take this into account, together with all
the other passes that handle ModelGEPs.
Before this commit the pass was assuming that the types on the model and
the types on LLVM IR were always of the same size.
This is not always guaranteed, especially if the model is user-provided
or coming from debug info, because in such cases we can have e.g. a
function returning `int` in C, but returning `i64` on LLVM IR.
Another corner-case are CABIFunctionTypes returning big aggregates, that
are represented by pointer-sized integers in LLVM IR.
This commit handles the above mentioned cases.
Not equal is handled separatedly during the decompilation process in
order to add the appropriate cast.
Currently, the code only triggers when the not equal is the outermost
operation in the expression - case for which there are no tests in the
test suite.
This commit is a major refactor of the data structures underlying the
MakeModelGEPPass, and of all the functions that manipulate them.
The refactor is aimed at fixing a major but of the previous design,
that made impossible to support MakeModelGEPs with partial mismatch.
This meant that until now we were emitting code that was not
semantically preserving whenever we could only match a part of the IR of
with a ModelGEP.
In particular, whenever a partial match was detected, the ModelGEP of
the matched part was still emitted, but we completely failed to emit the
mismatching part as raw pointer arithmetic.
This was due to the old design of the data structure, that cause the old
algorithm to lose track of the mismatch part at some point, without any
safeguard to avoid that.
Now all the data structures have been designed to properly represent the
mismatching part, so that the algorithms can avoid to lose track of
them, and finally emit the proper ModelGEP with additional pointer
arithmetic in case of partial match.
By using this class we can create ptml::Tags without
XML tags. It is useful in the revng-c part when we
want to generate Plain C. All PTML Tags, from now on,
should be created via this class only.
In addition, port `Yield` library to be using this.
Before this commit, the TwosComplementArithmeticNormalizationPass wasn't
taking into consideration properly all the cases where the arithmetic
can wrap around in case of expression such as (x + const1 <=> const2) or
(x - const1 <=> const 2).
This caused 2 different classes of problems that affected semantics.
1) In some cases we were emitting comparisons that were too broad,
meaning that they were true in a larger set of cases than the
original one.
2) In other cases we were emitting tautological comparisons, i.e.
comparisons that were always demonstrably true or false at compile
time.
This commit fixes the problem, treating all the cases in a generalized
unique way that works correctly for every case.
Before this commit, ExitSSAPass was collapsing PHINodes too aggressively
onto the same variable.
In particular we were mishandling the case where two PHINodes were
candidates for being collapsed to the same variable, but they had
overlapping live ranges.
Having overlapping live ranges means that they don't store the same
value (otherwise LLVM would have CSE'd them), so if we collapse them
onto the same variable we end up losing the value.