This commit drops the `CallToLifted` tag in favor of a
`getCallToIsolatedFunction` function which checks if the call has the
`IsolatedFunction` tag. The function also assumes that indirect calls
are calls to lifted functions.
SimplifyCFG with instruction sinking enabled sometimes can merge two
call sites that are identical at LLVM IR level, but originally come from
two distinct addresses in the original binary.
The nomerge attribute prevents this type of problematic deduplication.
We used to only color instructions in the same BasicBlock as the call to
`newpc`. However, an instruction in the original binary can span
multiple BasicBlocks.
We used to jump to the dispatcher, however we only sink to an
unreachable `anypc`. We were threfore significantly complicating the CFG
in case of indirect function calls.
Custom opcodes that are tagged AllocatesLocalVariable never have
arguments that should be replaced with SegmentRef or cstringLiteral.
Constant arguments or those custom opcodes are actually used to encode
another kinds of informations so they should be preserved.
This commit prevents that replacements to happen.
This commit refactors the C Backend as follows.
- The emission of basic blocks is now statement based.
There are some instructions that are handled as statements.
Those instructions are the points where the codegen starts from when
emitting C.
Conversely, all the other instructions are initially ignored when
iterating on instructions in a basic block, and are only reached when
traversing the dataflow that originates from statements.
- The TokenMap, that originally included all the string representing all
the instructions, is now used only to store the names of funciton
arguments and instructions representing local variables.
- Starting from each statement-like instruction, the C codegen is driven
by a traversal of the dataflow of the operands. The dataflow is
traversed recursively with the `getToken` method, materializing
strings on the fly until the visit reaches "leaves" i.e. instruction
that represent local variables, constants, or function arguments.
Adopting this approach allowed to reduce the peak memory consumption of
the backend, as well as making it faster on our benchmarks.