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.
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
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`).
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.
* Introduce the `JumpTargetsFromConstantsPass` pass, which goes through
all the unvisited basic blocks looking for constants and trying to feed
them to `JumpTargetManager`, which will decide if they are code
pointers or not.
* To make life of `JumpTargetsFromConstantsPass` easier run
`EarlyCSEPass` before it, which is particularly useful to make explicit
constants that some architectures materialize in two steps (high and
low part).
* Remove the fake fallthrough workaround in `TranslateDirectBranchesPass`
which was used to register for exploration basic blocks after a direct
jump, which was necessary due to the fact that return instructions are
indirect jumps and were losing the basic blocks after function calls.
This is no longer necessary thanks to `JumpTargetsFromConstantsPass`.
In `TranslateDirectBranchesPass::getNextPC` we were using a normal
iterator backward with a faulty exit condition that lead us to skip the
first instruction in a basic block.
This patch implements a proper solution: use `reverse_iterator`.
In certain cases we have a call to `exitTB` right after an helper, in
particular in x86, after a syscall. We cannot know what the target
address will be, so we have to handle this as an indirect jump.
* `JumpTargetManager::getPrevPCWrite`: clean up.
* `JumpTargetManager::getPrevPCWrite`: while searching for stores to the
PC, also check for call instructions. If one is met, return nullptr.
* `TranslateDirectBranchesPass::runOnFunction` and
`JumpTargetManager::translateIndirectJumps`: insert new code before
`exitTB`, not the write to the PC.
* Move initialization and management of the structure describing the CPU
state (CPUStateType) into variablemanager.cpp.
* Support parts of CPU state outside "env" (e.g. the MIPSCPU
structure). Now "env" has an offset into the possibly larger CPU state
which we have to take into account where appropriate (see
VariableManager::envOffset).
* Link the helpers module into the generated module, including only what
is needed.
* Create some "no-op" or "abort" function corresponding to QEMU functions
not included in the helper module (e.g. logging and abort functions).
* Implement the CorrectCPUStateUsagePass pass, which starts from the
"env" global variable and looks for all its usages recursively, keeping
track of where pointers are pointing into the CPU state data structure,
and replaces all the load/stores with the global variable corresponding
to that specific field of the CPU state.
* After the linking phase, run SROA, the pass to adjust the CPU usage and
DCE.
* Let global variables have common linkage.
* Emit a call to an helper function (ExitTB) corresponding to each
exit_tb PTC instruction.
* Update TranslateDirectBranchesPass and
JumpTargetManager::translateIndirectJumps to look for the last write
to the PC before calls to ExitTB.
* Exposing the PC with JumpTargetManager::PC is not needed anymore. Users
from outside should only be interested in finding the the previous
write to the PC (using JumpTargetManager::getPrevPCWrite).