If before a call to an heper the PC is saved, it means that the helper
can change the PC, therefore we need to go the dispatcher on return. In
this case, we also have to force the PC after the call to be a jump
target.
When we meet a new PC from the PTC input, find immediately the next PC.
This makes the information available early and removes the necessity for
`closeLastInstruction`.
Give a new, useful, meaning to the `--entry` parameter: it's new purpose
is to be able to easily try to translate the code at a certain address.
In this sense, prevent global data harvesting if `--entry` is specified.
The handling of GVN options has also been improved.
Implement producing a CSV file containing information about the which
PCs have been translated. For each PC it is specified whether its a jump
target or not.
Pass local temporaries' allocas as parameters to newpc, so they can't be
promoted to SSA values by SROA, which creates problem when a basic block
must be split between a use and a def of such a value.
Assigning support variables (such as those for original segments and the
ELF header helper) external linkage and giving them a name prevents the
optimizer from dropping them.
* Create 3 constant global variables (`phdr_address`, `e_phentsize` and
`e_phnum`) in the IR which will be used to populate the auxiliary
vectors at run-time.
* Update compile options for `support.c` to ignore useless warnings and
enable debug information
* Implement in `support.c` some functions required by QEMU run-time and
other cleanups to make it compatible with programs translated from
`_start`, not `root`
* Implement in `support.c` the `prepare_stack` function, which
initializes the base of the stack with environment variables,
arguments and auxiliary vectors
* Improve syscall support
If EarlyCSE didn't produce any new code pointer, we use
GlobalValueNumbering which usually leads to better results, in
particular if we remove `newpc` markers and if it can make use of alias
information, which we introduce to let the compiler know that
loads/stores to the CPU state will never alias loads/stores to normal
memory.
* Before generating any load/store instruction mark it with the
appropriate aliasing information.
* Update `JumpTargetManager::harvest` to run GVN
* Move the `Visited` set of `JumpTargetsFromConstantsPass` in
`JumpTargetManager`, even if currently we clear it at each invocation
of the pass
Some hand crafted assembly code perform a PC-relative jump of an
non-statically known amount. This patch introduces a simple hack to
handle such a situation by simply detecting it and marking as potential
jump targets all the instructions to come until the next jump.
This is implemented by the `JumpTargetManager::handleSumJump` and
`isSumJump` functions.
This commit also introduces a new implementation of `getNextPC` not
requiring the dominator tree.
* Ignore support functions (i.e. everything outside the `root` function)
* Update DWARF version to 4
* Update subrprogram creation interface to LLVM 3.8
The logic to implement harvesting of new code pointers when we're out of
them during translation, has been moved to `JumpTargetManager`. Its
interface has also been reduced and some logging has been introduced.
At the current stage, if there's nothing to `peek`, we first give a shot
of `SROA` and `TranslateDirectBranchesPass`, and then, if nothing came
out, we go for `EarlyCSE` and `JumpTargetsFromConstantsPass`.
Introduce an unreachable instruction after each emitted call to
`exit_tb` to terminate properly basic blocks. This patch also removes it
when appropropriate (i.e. in `TranslateDirectBranchesPass` and
`JumpTargetManager::translateIndirectJumps`).
Instead of taking note of the executable ranges exclusively, keep track
of all the segments in `CodeGenerator`. `JumpTargetManager` instead will
keep track of executable areas only.
* Introduce the `SegmentInfo` struct, which simply holds essential
information about the segment such as start and end address,
permissions and a reference to the global variable holding its content.
* Update `CodeGenerator` to keep a vector of `SegmentInfo`.
* `JumpTargetManager`: polish the constructor and make it take the vector
of `SegmentInfo`, from which the executable ranges are then extracted.
Detect simplest cases of writes to the program counter while they're
being translated. This way, we avoid running expensive passes to collect
straightforward jump targets.
Note: if the PC-write value is the current PC, ignore it. Splitting the
basic block being created is problematic.
* Let `InstructionTranslator::newInstruction` return also the PC.
* `InstructionTranslator::translate`: make it aware of the current PC,
and make it abort in case of error and return a boolean to indicate
whether the translation should proceed or not.
* Simplify the fetch of a new address to translate.
* Let `InstructionTranslator::translateOpcode` return an error condition
in case of failure, instead of asserting.
* Don't start exploration from `VirtualAddress` but just add it as a
block to explore. Then start the translation with
`JumpTargetManager::peek` as usual.
* Remove the unreachable instruction we were using as a delimiter to
create new local variables, since it make the module invalid. Use the
fake branch to the dispatcher instead.
`JumpTargetManager::getPrevPCWrite` used to assert in case a write to the
PC is not immediately found before an `exit_tb`. Relax this constraint.
In the future we might re-introduce it if we handle a couple of common
cases.
In variable-length encoding architectures, sometimes you might have one
instruction containing another one. This is not a problem until you get
the next one, which would be translated twice, in fact, it's not at the
beginning of a basic block and the current mechanism to detect already
translated code does not handle it.
This patch makes `JumpTargetManager::newPC` check the whole map of the
translated instructions. This might have to be improved in the future.