diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -118,6 +118,9 @@ /// Read ORC unwind information and annotate instructions. Error readORCTables(); + /// Update ORC for functions once CFG is constructed. + Error processORCPostCFG(); + /// Update ORC data in the binary. Error rewriteORCTables(); @@ -139,6 +142,13 @@ return Error::success(); } + Error postCFGInitializer() override { + if (Error E = processORCPostCFG()) + return E; + + return Error::success(); + } + Error postEmitFinalizer() override { updateLKMarkers(); @@ -517,6 +527,41 @@ return Error::success(); } +Error LinuxKernelRewriter::processORCPostCFG() { + // Propagate ORC to the rest of the function. We can annotate every + // instruction in every function, but to minimize the overhead, we annotate + // the first instruction in every basic block to reflect the state at the + // entry. This way, the ORC state can be calculated based on annotations + // regardless of the basic block layout. Note that if we insert/delete + // instructions, we must take care to attach ORC info to the new/deleted ones. + for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { + if (!BF.hasORC()) + continue; + + std::optional CurrentState; + for (BinaryBasicBlock &BB : BF) { + for (MCInst &Inst : BB) { + ErrorOr State = + BC.MIB->tryGetAnnotationAs(Inst, "ORC"); + + if (State) { + CurrentState = *State; + continue; + } + + if (!CurrentState) + continue; + + // While printing ORC, attach info to every instruction for convenience. + if (opts::PrintORC || &Inst == &BB.front()) + BC.MIB->addAnnotation(Inst, "ORC", *CurrentState); + } + } + } + + return Error::success(); +} + Error LinuxKernelRewriter::rewriteORCTables() { // TODO: return Error::success();