`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.
Sometimes code performs an indirect jump without changing the value of
the PC. In most cases this is due to non-code or some other faulty
situation, but it is in principle possible that an instruction performs
an indirect branch to its own address.
This commit ensures that this situation does not end up in an hard
failure.
Before this commit, we used to decomple UndefValue to the literal 0.
This was causing problems in some cases, such as switch(0 /*undef*/)
where clang was issuing a warning that was impossible do disable without
turning off -Wall alltogether, which is undesirable.
This commit introduces a set of helper functions in
revng-primitive-types.h, that are now used to avoid emitting undef as
constant.
This is more semantically meaningful when looking at the decompiled
code, and it has the nice side effect that it silences the clang
warnings mentioned above.
Now extractvalue instruction are replaced by dedicated
OpaqueExtractValue custom opcode, that prevents LLVM from doing strange
things with extractvalues during optimizations (such as e.g. sinking).
This is important since extractvalue instructions and struct-typed
values in general in our LLVM IR are not real first-class citizens, but
only a byproduct of the binary lifting process, and they actually
represent bundles of registers that are returned from isolated
functions.
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.
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.
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.
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.