* QuickMetadata has been expanded to get a `MDString` or a `MDTuple`
from a `StringRef`.
* Introducing `skipCasts`, which, given a `Value`, returns the innermost
part of the expression, skipping over casts.
* Introducing `isCallTo`, which, given an `Instruction`, returns whether
it's a call to a specific function or not. `getCallTo` is a sister
function to be used in `if` statements.
* Moving `skip` and `erase_if` in `ir-helpers.h` so that all the
translation unit can benefit from their usage.
This commit fixes some warnings given by GCC 6.3.0.
* Some `assert(false)` are not recognized as `noreturn`ing. They have
been replaced with `llvm_unreachable`.
* Added `-Wno-ignored-attributes`: attributes are not part the function
name mangling, and therefore they might create some problems when they
are involved in template arguments. We don't care.
* Specializations of `readPointer` functions in `binaryfile.h` are now
`inline`, so they don't appear as "unused" functions.
We used to assert that a `BoundedValue` must not have any entries in the
`Bounds` field before translating a `boost::icl` interval to a
`BoundedValue`. However, if the `Value` associated to the `BoundedValue`
is a `Constant`, we might have an entry in `BoundedValue::Bounds`
immediately after constructing the object. This commit fixes this
problem by simply updating the assertion and clearing the field before
re-populating it.
While materializing values in SET through the `OperationStack` we used
to use as a type the type of the value associate to the currently used
`BoundedValue`. This was wrong, this patch uses the type on the free
operand on the top of the `OperationsStack` to perform the required
computations.
`OSRA:handleComparison` was too big and complex, it has been mostly
rewritten.
* Create `OSRA::identifyComparisonOperands` which expands the argument
of the comparison in a list of possible values (constants or
OSRs). The new way in which we handle possible operands also fixes a
bug showing up in case a constant OSR was being compared with an LLVM
constant, which was checked for being a tautology/contradiction,
preventing the reaching definitions of the operand to be considered
too.
* Squeeze more information from uge/ugt. Unsigned comparisons lead to
two pieces information: the result of the comparison itself, and the
fact the left-hand side is greather than or equal 0. This secondo
information is precious, but we were not able to exploit it in the
case the original comparison is already "greater than" or "greater
than or equal". In fact, `x - 4 > 10` gives us `x >= 4` and `x > 14`,
which boils down to `x > 14`. This commit introduces a change that
handles this case as `NOT x - 4 <= 10` leading to the negation of `x
>= 4` and `x < 14` which is way more informative.
* Improve `OSRA::mergePredicate` and `OSRA::applyConstraints`
interfaces.
* In case a comparison instructions leads to multiple constraints on the
same `Value`, these constraints are now first or-merged together and
then propagated. This change improves the quality of the analysis in
certain situations.
This commit introduces radically changes the implementation of
`BoundedValue`: it no longer represents a single, contiguous range, but
an arbitrary number of ranges.
The bounds are now represented through a
`llvm::SmallVector<std::pair<uint64_t, uint64_t>, 3>`.
* Introduce the `BoundedValue::bounds()` method, which allows to iterate
over all the ranges that a `BoundedValue` represents. The `bounds`
method returns a `Bounds` object, which can be used as a range
composed by `BoundsIterator`.
* All the methods dealing with the `BoundedValue`'s bounds have been
rewritten.
* New debugging information: "bv-merge". Print all the computations
performed by `BoundedValue::mergeImpl`.
* Drop dead code: `BoundedValue::setBound` and `isPositive`
* Introduce `BoundedValue::isRightOpen` and drop
`BoundedValue::isSingleRange`
Some subtle bugs have been fixed in `OSRA::pathSensitiveMerge`:
* Do not alter the current `BoundedValue` if merging a component would
lead to bottom.
* Do not deactivate a reacher in case an incoherent condition is met.
Constraints associated to a memory instruction are propagated to
reached loads. However, if a constraint on the same `Value` is already
present, the new constraint should be and-merged, not or-merged.
* Introduce some additional helpers
* Spread some `const`ness
* Improve documentation
* New debugging information: "osr-bv". Prints every update operation
performed in `BVMap::update`.
* Remove dead code
* Whitespace fixes
* Some new TODOs
* Fix some typos in comments
This commit drops the original handcrafted implementation of
`BoundedValue` merging, in favor of an implementation based on Boost
intervals. The old implementation was the source of intermittend bugs,
using Boost should be a more reliable solution. Moreover, this commit
enables moves us towards supporting multiple ranges in `BoundedValues`.
The main goal of this patch is to reduce the size of
`OSRAPass::runOnFunction()`. To do this we created the `OSRA` class
which handles everything `runOnFunction` was taking care of but without
the ugly lambdas nor being an endless function. Each class of
instruction is now handled by a dedicated function.
This also has the side effect of heavily reducing the amount of clutter
exposed by `OSRAPass` to its users.
When performing a comparison, we try to attach its signedness to the
base OSR it's working on. However, this is not always
effective. Typically, even after this, the OSR remains with an unknown
signedness due to the fact that we don't have information about its
bounded value from all the predecessors, and therefore it goes to top.
This commit reduces the amount of constraint we propagate. We do this in
two ways. First, by computing the set of all the instruction that will
ever be affected by the current instruction (recursively). Second, by
preventing propagation on constraints across function calls.
In quick test on `ls` compiled for MIPS we reduce the execution time by
55% of the peak memory usage by 68%. This makes me quite happy.
Fix a bug which lead to enforce that the left-hand side operand of an
unsigned greater than or greater than or equal comparison was <= 0. This
was the result of some intimate desire for symmetry in my mind which
does not actually exist.
Every time we don't know where an indirect jump can go, we used to emit
a jump to the dispatcher, however this complicates our analyses, in
particular the computed dominator tree provides less useful information
than it could.
This commit transforms all the jumps to the dispatcher into jumps to a
"anypc" basic block which during analysis just contains an unreachable
instruction, but during finalization this instruction is replaced with a
jump to the dispatcher. A similar (temporary) situation is for the
"unexpectepc" case.
This commit also makes the `visit(Sucessors|Predecessors)` functions
more idiomatic by employing a trait for black lists.
This commit introduces the `noreturn` analysis, whose aim is to detect
all the basic blocks the are doomed to lead to a `noreturn` syscall such
as `execve` or `exit`.
* Implement `NoreturnAnalysis`.
* Include and initialize in the `Architecture` data structure all the
necessary information to detect `noreturn` syscalls. Specifically, the
name of the QEMU helper for syscalls, the name of the register holding
the syscall number and the syscall numbers representing `noreturn`
syscalls.
* `ReachingDefinitionsPass`: make reaching definitions available both in
reaching definitions mode and reached loads mode. This part needs
further cleanup. We also might be willing to implement this with a
`Boost.Bimap`.
* Use `SET` to collect information useful for the
`NoreturnAnalysis`. Also restructure how the `OperationsStack` works
to be more streamlined and keep track of multiple information about
the instruction currently being tracked.
An unsigned comparison such as `x - 3 < 5` carries two information: the
first is the obvious one (`x < 8`), but the other one is even more
interesting. In fact any unsigned comparison implies that the LHS is not
negative, therefore we also can state that `x >= 3`. This commit
implements the usage of this information.
* When creating a new `BoundedValue`, check if the value associated to
it is a `ConstantInt` and if so, initialize the boundaries and the the
signedness as appropriate.
* Add various checks for the presence of the signedness information
before using functions that might require it.
* Clear all the data that's not part of the analysis results at the end
of the `runOnFunction` method
* Clear all the data that's part of the analysis results when the
`PassManager` tells us so (`Pass::releaseMemory`)
* Do not use the `clear()` method, since it doesn't release memory
* Add some debugging information
Record amount of reaching definitions for each load, even in
`ReachedLoads` mode, so that we can run the `pathSensitiveMerge` only
when we're sure we've collected all of them.
An instruction can now subscribe for the change of the list of reachers
of a certain load. This is particularly useful in the case of `ICmp`
instructions, which might hold constraints about the reachers of a
certain load without actually being a its user.
Before this commit, loads with multiple definitions were handled by
simply checking if all the definitions agreed. Now we also implement
some logic to put constraints on the new OSR, in case they don't agree.
To do this we implement a path-sensitive algorithm to collect
constraints about the reaching definitions.
This commit also introduce a set of methods to, if possible, apply an
OSR to a BoundedValue, e.g. [1 + 1 * x] will produce a new BoundedValue
whose bounds are shifted of 1 unit.
In OSRA, when producing constraints associated to a `ICmpInst`
associated to a load instruction, consider also all of its reaching
definitions.
Moreover, when propagating constraints due to a `Br` instruction, look
for loads which might be affected by the constraints being propagated,
and, if necessary, update them.
Constant OSR are now represented through an OSR such as
[0 + 1 * x with x = (*, c, c)]. Since equality doesn't hold any
signedness information we introduce a new signedness type (available
only in `BoundedValue`), `AnySignedness`, which is similar to
`UnknownSignedness` but does not trigger `isUninitialized() == true`.
In `BVMap` we also introduce the concept of "forced" constraint, i.e. a
constraint that is fixed, cannot be changed or update. Constant stores
will produce this type of constraints.
This commit introduces the `getName` function, which, given a
BasicBlock, an Instruction or a Value, outputs a sensible name. In
particular instructions are now identified as [basic block]:[instruction
index].
`getName` is now used in the various `describe` methods in OSRA.
Sometimes QEMU writes to register that are never used afterwards,
typically the `cmp` instruction sets several CPU flags which might be
ignored.
This becomes a problem when comparison are performed since they affect
the signedness of a BoundedValue. With this patch, we ignore their
effect if we can prove it's a dead store.
With this patch we basically handle a load as a sort of phi-node, since
we keep track of all the store/loads reaching a certain load, along with
their OSR, so that we can come up with smarter merging policies and
obtain more precise information.
This commit also introduce a change that leads to consider loads as
stores during propagation. This heavily simplifies the store
propagation logic by considering load instruction as aliasing, and by,
consequently, propagating load (along with stores). This removes
completely the need for the concept of "conflicts".
Introduce the `MemoryAccess` class which represents the source of a
`LoadInst` or the destination of a `StoreInst` for which we want to
propagate an OSR.
This patch handles more elegantly the propagation and introduces support
for propagating OSRs through register + offset memory accesses, in
particular stack pointer- (or base pointer-)relative memory accesses,
which are common in unoptimized code and that led to miss some cases
that we otherwise handle correctly.
The current modeling of constant OSRs prevent their merging on basic
blocks. This was due to the fact they had no `BoundedValue`
associated. This patch fixes this by representing them as:
[120 + 0 * x, with x = (null, ?)]
instead of:
[120 + 0 * x, with x = null]