[llvm] [BOLT] Add support for safe-icf (PR #116275)
Alexander Yermolovich via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 19 15:38:36 PST 2024
================
@@ -341,6 +344,75 @@ typedef std::unordered_map<BinaryFunction *, std::vector<BinaryFunction *>,
namespace llvm {
namespace bolt {
+void IdenticalCodeFolding::processDataRelocations(
+ BinaryContext &BC, const SectionRef &SecRefRelData) {
+ for (const RelocationRef &Rel : SecRefRelData.relocations()) {
+ symbol_iterator SymbolIter = Rel.getSymbol();
+ const ObjectFile *OwningObj = Rel.getObject();
+ assert(SymbolIter != OwningObj->symbol_end() &&
+ "relocation Symbol expected");
+ const SymbolRef &Symbol = *SymbolIter;
+ const uint64_t SymbolAddress = cantFail(Symbol.getAddress());
+ const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(OwningObj);
+ if (!ELFObj)
+ llvm_unreachable("Only ELFObjectFileBase is supported");
+ const int64_t Addend = BinaryContext::getRelocationAddend(ELFObj, Rel);
+ BinaryFunction *BF = BC.getBinaryFunctionAtAddress(SymbolAddress + Addend);
+ if (!BF)
+ continue;
+ BF->setUnsafeICF();
+ }
+}
+
+Error IdenticalCodeFolding::markFunctionsUnsafeToFold(BinaryContext &BC) {
+ Error ErrorStatus = Error::success();
+ ErrorOr<BinarySection &> SecRelData = BC.getUniqueSectionByName(".rela.data");
+ if (!BC.HasRelocations)
+ ErrorStatus = joinErrors(
+ std::move(ErrorStatus),
+ createFatalBOLTError(Twine("BOLT-ERROR: Binary built without "
+ "relocations. Safe ICF is not supported")));
+ if (ErrorStatus)
+ return ErrorStatus;
+ if (SecRelData) {
+ SectionRef SecRefRelData = SecRelData->getSectionRef();
+ processDataRelocations(BC, SecRefRelData);
+ }
+
+ ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
+ if (BF.getState() == BinaryFunction::State::CFG) {
+ for (const BinaryBasicBlock *BB : BF.getLayout().blocks())
+ for (const MCInst &Inst : *BB)
+ BC.processInstructionForFuncReferences(Inst);
+ }
+ };
+ ParallelUtilities::PredicateTy SkipFunc =
+ [&](const BinaryFunction &BF) -> bool { return (bool)ErrorStatus; };
+ ParallelUtilities::runOnEachFunction(
+ BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, SkipFunc,
+ "markUnsafe", /*ForceSequential*/ false, 2);
+
+ LLVM_DEBUG({
+ std::vector<StringRef> Vect;
+ std::mutex PrintMutex;
+ ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
+ if (BF.isSafeToICF())
+ return;
+ std::lock_guard<std::mutex> Lock(PrintMutex);
+ Vect.push_back(BF.getOneName());
+ };
+ ParallelUtilities::PredicateTy SkipFunc =
+ [&](const BinaryFunction &BF) -> bool { return false; };
+ ParallelUtilities::runOnEachFunction(
+ BC, ParallelUtilities::SchedulingPolicy::SP_TRIVIAL, WorkFun, SkipFunc,
+ "markUnsafe", /*ForceSequential*/ false, 2);
+ llvm::sort(Vect);
----------------
ayermolo wrote:
So that output is in deterministic order, since all functions are processed in parallel and ones that are skipped are added to the vector.
This is used for tests to check which functions were skipped.
Alternative:
LLVM_DEBUG({
for (auto &BFIter : BC.getBinaryFunctions()) {
if (BFIter.second.isSafeToICF())
continue;
dbgs() << "BOLT-DEBUG: skipping function " << BFIter.second.getOneName()
<< '\n';
}
});
Order will be de deterministic since in BC it's a std::map.
let me just change to that. Not worth optimizing the debug print path.
https://github.com/llvm/llvm-project/pull/116275
More information about the llvm-commits
mailing list