prevents delay slots from becoming a basic block start #1170
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Our control-flow graph representation is unable to handle cases when a
delay slot of some branching instruction becomes a target of a call or
a jump, because we do not allow the same instruction to belong to
several basic blocks (aka instruction sharing). When we encounter such a
case, our control-flow invariants are broken which leads to failures
downstream (e.g., we have duplicating term identifiers).
While it is possible that a delay slot might become a target of a
jump, in reality compilers are not generating such code (well, at
least we are not aware of such compilers) and the main source of calls
that target delays slots is Byteweight, which false positively
identifies them as function starts.
Since we don't have an option to represent such graphs right now, to
preserve our invariants, we cancel all disassembling chains that end
up in classifying some delay slots as function starts or targets of
a jump or call. To implement this, we remember each task that lead to
a creating of a new basic block. When we discover a new basic block we
check if its start is a known delay slot, and if it is , we cancel the
chain. If later we discover jump whose delay slot is a start of a
basic block we cancel all chains that were responsible for the
creation of that basic block and continue. To summarize, the invariant
is that a delay slot may never be a start of a basic block.
Another change, which is more of an optimization, that bundled with
this commit, is that we now track the function starts and use them
as the starting points to build the whole program CFG. Before we were
using all basic blocks, when we build the whole program CFG which
ended up in lots of unreachable code, which was ignored by
the subroutine partitoning algorithm, so there is no need to
disassemble them anyways.