Since when we added the -exit-ssa pass, allocas are never supposed to
reach the C backend anymore.
This commit drops the code that supports them, that was effectively dead
code since a quite long time.
For segmentRef type of the segment and type returned by segmentRef
function are the same.
For cstringLiteral every call returns pointer to 1-byte type. Pointer is
offsetted by value of strlen+1. strlen is fetched from metadata.
Additionally, all uses of cstringLiteral function has same type as the
type of cstringLiteral (pointer to 1-byte).
This commit changes MakeSegmentRefPass so that it's now a ModulePass and
it uses the binary to detect integer constants that represent the
address of strings.
When it detects address of constant strings, instead of injecting calls
to SegmentRef, we now inject calls to cstringLiteral, so that we can
later emit them as inline string literals in C.
In segmentRef we use integer type meaning address in memory, so we
generate segmentRef function with non-pointer type. For cstringLiteral
function we need real pointer type of operand.
Save MetaAddress, size, offset and original type for every
cstringLiteral call in metadata as we do for segmentRef calls.
For cstringLiteral "revng.cstring_literal" metadata name is used.
StringLiteralPool needs tuple of address, size, offset and type to
keep distinct string decorator functions for each string. This tuple is
represented by StringLiteralPoolKey struct.
Pipe for MakeSegmentRefPass needs to be defined explicitly, because
additional wrapper passes are required in MakeSegmentRef:
1. LoadModelWrapperPass
2. LoadBinaryWrapperPass
MakeSegmentRefPass requires access to RawBinaryView to detect cstring
literals in binary.
Fix printed command in MakeSegmentRefPipe
This printed command might not work. @ale commented it will be replaced
with `revng pipe run-pipe` once we will have it.
Update IRHelpers to new revng API
Switch String and Namespace arguments in getUniqueString
SegregateStackAccesses and PromoteStackPointer were not handling
functions declarated (but not defined) properly.
This commit fixes this, in part by adopting `TaggedFunctionPass`.
Do not promote registers to `undef` initializers of registers not marked
as being preserved by the current function.
This is useful to highlight usages of registers that are not an
argument, nor a callee saved register. Mainly this has been introduced
to preserved reads from x86-64 `fs` register.
We need to prevent DCE from killing `revng_init_local_sp`, since certain
passes downstream might want to introduce new uses of it, and they might
be the first.
`SegregateStackAccesses` will take care of removing it by hand.
The previous implementation was iterating on the instructions in order.
This caused problems when we had two instructions, A and B, both tagged
IsRef, and B was using A and B had 2 or more uses.
In this case the pass was looking at A before looking at B, so A was not
duplicated because it only had one use (B).
Then B was analyzed and it had 2 uses so it was duplicated, causing the
number of uses of A to increase accordingly.
This commit fixes the problem iterating on the BasicBlocks in post
order, and on the instruction list in reverse order.
It also fixes MarkAssignments.cpp not to erroneously mark instructions
that are marked IsRef.
Using a named metadata is simply wrong, because we need to have many of
these metadata alive at the same time with different values.
Using a named metadata has the unpleasant side effect of making all the
`SegmentRef` functions to refer to the same segment.
Before this commit we couldn't handle gracefully situations where the
model had an array with elements of given size X and the IR had strided
accesses with a stride Y that was larger than X.
This commit gracefully handles that case, but for now it always bail
out.
In the future we could think of handling this better if Y is a multiple
of X.
Ensure that no backedges are left after the restructuring of all the
metaregions.
This additional assertion should help ensuring that no entries in the
`Backedges` set are left after the restructuring process, in turn making
it easier to spot bugs if backedges references are not handled correctly
during the steps of the restructuring.
Before this commit, MakeModelGEPPass was materializing all possible
traversals of the type system to select the best match for translating
some pointer arithmetic on the IR into ModelGEPs.
This proved to be very slow and to do a lot of useless computation on
larger binaries with big type systems.
This commit partially rewrites MakeModelGEPPass to adopt a
branch-and-bound approach to only explore paths on the type system that
have some chance of improving the best match.
Before this commit, the dla::Step CompactCompatibleArrays was
occasionally generating artificial nodes that were larger than the inner
data, forcing their size to Stride - AvailableSlack.
This commit fixes the problem keeping track of the actual size that is
consumed in the array element, and forcing the size of the artificial
nodes to that.
Assign a value to cloned and collapsed nodes in terms of shortest path
from entry, which is a criterion we use to elect region entry.
The shortest path is computed at the beginning for the nodes present in
the CFG, but needs to keep updated for additional nodes that we insert
that may become loop entry candidates.
During the creation of the exit dispatcher, take care of removing from
the `Backedges` set the additional backedge that is collapsed in case
two exiting backedges do target the same destination.
When this is not done, a ghost backedge is left inside the set, making
it not coherent with the state of the graph.
In addition, we add an assertion which ensures that during this phase of
the restructuring dummy nodes are present only as source of retreating
edges, and have one and only one successor.
The dla::Step ArrangeAccessesHierarchically looks throught the DLA graph
and for each node with many outgoing instance edges tries to see if some
of them are hierachically contained within each other.
In order to do this, before this commit, we were building an auxiliary
graph representing this hierarchy, and in order to build it we had to
perform a number of comparisons between edges that was quadratic with
the number of edges.
Moreover, once all the comparisons were done, we had a deep graph
representing inclusion between edges, but we only cared about the
top-level of this graph, i.e. only the edges that contained other edges
hierarchically, but were not contained in other edges (we'll call them
the root edges).
So we were doing a quadratic number of comparisons but possibly many of
them were useless.
Finally, all the edges that were included in root edges, were pushed
down, but only for a single layer, because they needed to be re-compared
later with the children of the root edges they were being pushed
through. This latter part was responsible for a lot of wasted
computation that just needed to be done over and over at all the layers.
Overall this algorithm was doing a lot of wasted computation.
This commit replaces this logic with a new algorithm.
Now we keep track only of the root edges, and we compare only root edges
with other root edges.
Initially all edges are root edges.
Then we start comparing them.
If a root edge A is included in another one B, then A is not a root edge
anymore, and all the edges that were previously found to be included in
A are not included in B.
This algorithm still does a worst case of quadratic number of
comparisons, but drastically reduces the amount of useless computation
that is redone later. In particular:
- in cases where there are a lot of root edges (meaning that only a few,
or no edge can be included in others) we do a number of comparison
close to quadratic, but we're only pushing non-root edges down, so
we'll never have to redo comparisons in deeper layers
- in cases where there is only a small number of root edges, we're doing
a number of comparisons close to linear, and we never compare non-root
edges with each other, so we're saving a lot of computation that would
be wasted (because it would need to be redone in deeper layers).
Before this commit we were manually building a topological ordering,
that resulted in worse overall performance in some scenarios.
This commit changes the dla::Step to temporarily introduce a fake root
node, and computes a RPOT from there, which overall yields better
results.
We always emit a variable for calls to QEMU helpers. For this reason,
for what concerns operator precedence, calls to QEMU helpers should be
considered as references to variables. Hence, they should never be
parenthesized.
Before this commit, calls were marked to push ALAP in the wrong order,
resulting in preventing to actually push them ALAP.
This commit fixes the ordering, reactivating the code motion.
This commit does various things oriented at reducing the number of local
variables emitted in C:
- MarkAssignments now know that @Copy and @Assign involving
@LocalVariable only have side effects that affect the local variable
itself; this enables to reduce the number of times we're forced to
emit a local variable due to interfering side effects
- Drop the @AssignmentMarker FunctionTag; AddAssignmentMarkerPass now
doesn't emit @AssignmentMarker anymore; instead it emits groups of
@LocalVariable, @Copy, and @Assign, which benefit from the previous
point
- Drop 2 MarkAssignments::Reasons: HasManyUses and HasUsesOutsideOfBB;
both these have now been aggregated into the AlwaysAssign reason for
simplicity, representing all reasons non involving side effects
- Update BeautifyGHAST and how it reasons about side effects when
beautifying; before this commit it used @AssignmentMarker, now it
looks at @Assign
- Simplify ExitSSA; before this commit it was trying hard to be smart on
where it emitted the store instructions representing the incoming
values of the PHI that was being destroyed; this seemed smart when we
originally did it but it generated C code that was not really better
to read, so this useless complexity is finally gone