Perform the ALAP Variable Declaration process.
The process is structured in the following stages:
- We start by collecting all the `Variable`s that need to be assigned in
a `ASTNode`.
- We build a `GenericGraph` where each `ASTNode` is connected with its
child nodes, and also its immediate successor.
- We perform a walk in post order over this graph, and for each
`ASTNode` we decide if the current node could be the ALAP location
where we can declare the `Variable`, i.e., where we dominate all its
uses.
Explicitly casting to uint8_t has the semantics of truncating, in case
the value being casted is larger than 8 bits.
Avoiding the cast default to regular C behavior, where every non-zero
integer is considered true.
Fix the needed attributes to allow navigation from the use of an
artificial return struct for raw functions to their definition in
`types-and-globals.h`.
We introduce the `InlineDispatcherSwitch` beautify pass. Its goal is to
try and inline the body of some of the `case`s of a exit dispatcher, in
place of the `SetNode` corresponding to that `case`, if this doesn't
introduce duplication in the code (i.e., a single `SetNode` for that
specific case value is present).
Additionally, if the inlining procedure is able to completely remove the
necessity of an exit dispatcher altogether, the pass removes it.
The pass is able to handle chains of weaved dispatcher `switch`es
referring to the same original dispatcher `switch`, by handling the
inline operation and the possible simplification level-wise.
The inlining procedure, cannot take place if a `SetNode` is contained in
the body of the case we are trying to inline, since this can possibly
break the semantics of the state variable of a loop, by placing a
`SetNode` in a more internal loop.
This commit drops `needsTopScopeDeclaration`.
Now all the LocalVariables are declared at the top of the function.
In DecompileFunction.cpp, the emission of LocalVariables if handled at
the scope of GHAST `ASTNode`s instead of being LLVM BasicBlock-based.
This enables in the future to design and implement an analysis that for
each LocalVariable decides the C scope (represented by an `ASTNode`)
where it's declaration should be emitted to always be visible in all its
uses.
This fixes a crash due to the fact that pointers on the model may have
different size than pointer on LLVM IR, due to revng always using
64-bits DataLayout, even when decompiling 32-bits architecture.
The assertion did not take this into account.
In principle the assertion could be removed, but it might become a
source of broken semantics, so it's better to keep an advanced verions
of the assertion in place, to make sure we only allow situations that we
fully understand, and that we can guarantee don't break semantics.
This Tag is used to tag all the funcitons that we use to decorate
integer literals to decide how to print them.
Using a single Tag shared among all the decorators enables more concise
code to handle it.
Improve the `fallThroughScope` computation, in order to handle calls to
`NoReturn` functions in the analysis, representing the fact that they
induce a `noFallthrough` scope (i.e., execution will not ever resume
after the call, and therefore we can later improve the nesting of the
code with the `promoteNoFallthrough` pass).
We introduce a simplification step, which looks for `switch`es that can
be reduced to simpler `if` statements.
Specifically, the logic is the following:
1) When we identify a `switch` statement composed by a single `case` and
a possible default, we transform it into an `if` with the `case` now
corresponding to the `then`, and the `default` corresponding to the
`else`, if present.
2) When we identify a `switch` statement composed by two `case`s, and no
`default` is present, we can promote it to an `if` with `then` `else`
branches.
Other key details:
- The promotion happens only if we can identify at least one of the
`case`s that have a single element in the `case` label. If this is not
the case, we do not promote one to RHS of the `if` condition.
- A new `CompareNode` class, inheriting from `ExprNode`, is created, in
order to represent the equality or inequality condition of an `IfNode`
instance that is the result of the promotion. This `CompareNode` can
represent for the LHS both an `llvm::Value` or the `loop_state_var`,
while it embeds the RHS constant which completes the comparison.
- We remove `SwitchBreak` AST nodes that may now appear as children of
an `if` node promoted from a `switch`.
- We introduce in the `CompareNode` the `weaved` concept. Indeed, if a
promotion of a weaved `switch` happens, we should avoid the
serialization of the instructions leading to the computation of the
condition of the original `switch`, because they have been already
emitted by the main related dominating `switch`.
We also introduce an additional simplification step, which takes care
of:
- Promoting `!(==)` to `(!=)` and `!(!=)` to `(==)`, if the inner
equal/not equal is represented via a `CompareNode`.
- Promoting `x == 0` to `!x` and `x != 0` to `x`.
To be able to correctly emit (or not) the instructions computing a
condition of an `IfNode`, we need to add the `EmittBB` flag, an
additional parameter to the `buildGHASTCondition` function, which
controls the emission of the statements of a basic block computing a
condition.
Consequently, the `IfNode` acquires a `IsWeaved` field, which is used to
mirror the property having the same name on `SwitchNode`. Being now
possible a promotion from a dual `SwitchNode` to an `IfNode`, we need to
represent this property on the `IfNode` too.
The `default` `case` is now a standard `case`, and it is identified only
by having the `label` set empty.
Therefore, a list of beautify and transformation actions now do not need
special casing in order to handle the `default` `case`, which is reached
during the standard iteration over the `case`s.
A special accessor is still necessary, in order to correctly emit the
`default` `case` in the backend.
Introduce implicit statements simplification phase, specifically:
- A implicit `return` simplification: `return` statements in `void`
type functions, which are not followed by any other scope, can be
omitted.
- A implicit `continue` simplification: `continue` statements whose
fallthrough leads directly to the end of the cycle scope (i.e., to
execute another iteration of the enclosing loop), can be omitted.
In order to avoid the printing of the implicit `return`, we need an
additional `emitReturn` parameter in the `emitBasicBlock` method of the
`CCodeGenerator` class.
This commit reorders the argument passed to various `printDeclaration`
and `printDefinition` helper functions, to make them more uniform across
each other, and to accept the same arguments in the same order.
This commit:
* Introduces `_` as a prefix for all non-user entities we emit in
decompiled code.
Also, some names have been changed to be more concise.
Specifically, the following entities have changed:
`_ENUM_UNDERLYING`, `_ABI`, `_REG`, `_padding_at_`,
`_artificial_struct_`, `_artificial_wrapper_`, `_stack`,
`_break_from_loop_`, `_var_`, `_stack_arguments`,
`_artificial_struct_returned_`, `_enum_max_value_`.
* Introduce _PACKED for `__attribute__((packed))`.
* `EnumEntry` name: drop the `EnumType` name prefix.
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.
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.
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.