[llvm] [BOLT] Add support for safe-icf (PR #116275)
Maksim Panchenko via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 10 15:36:01 PST 2024
================
@@ -340,6 +354,113 @@ typedef std::unordered_map<BinaryFunction *, std::vector<BinaryFunction *>,
namespace llvm {
namespace bolt {
+/// Scans symbol table and creates a bit vector of memory addresses of vtables.
+static void processSymbolTable(const BinaryContext &BC,
+ llvm::BitVector &BitVector) {
+ for (auto &[Address, Data] : BC.getBinaryData()) {
+ // Filter out all symbols that are not vtables.
+ if (!Data->getName().starts_with("_ZTV"))
+ continue;
+ for (uint64_t I = Address / 8, End = I + (Data->getSize() / 8); I < End;
+ ++I)
+ BitVector.set(I);
+ }
+}
+Error IdenticalCodeFolding::processDataRelocations(
+ BinaryContext &BC, const SectionRef &SecRefRelData,
+ const llvm::BitVector &BitVector, const bool HasAddressTaken) {
+ for (const RelocationRef &Rel : SecRefRelData.relocations()) {
+ if (BitVector.test(Rel.getOffset() / 8))
+ continue;
+ 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)
+ return createFatalBOLTError(
+ Twine("BOLT-ERROR: Only ELFObjectFileBase is supported"));
+ const int64_t Addend = getRelocationAddend(ELFObj, Rel);
+ BinaryFunction *BF = BC.getBinaryFunctionAtAddress(SymbolAddress + Addend);
+ if (!BF)
+ continue;
+ BF->setHasAddressTaken(HasAddressTaken);
+ }
+ return Error::success();
+}
+
+Error IdenticalCodeFolding::markFunctionsUnsafeToFold(BinaryContext &BC) {
+ if (!BC.isX86())
+ BC.outs() << "BOLT-WARNING: Safe ICF is only supported for x86\n";
+ constexpr uint64_t NumBits = (((uint64_t)1) << 32) / 8;
+ llvm::BitVector BitVector(NumBits);
+ processSymbolTable(BC, BitVector);
+ for (const auto &Sec : BC.sections()) {
+ if (!Sec.hasSectionRef() || !Sec.isRela())
+ continue;
+ const SectionRef &SecRef = Sec.getSectionRef();
+ section_iterator RelocatedSecIter = cantFail(SecRef.getRelocatedSection());
+ assert(RelocatedSecIter != SecRef.getObject()->section_end() &&
+ "Relocation section exists without corresponding relocated section");
+ const SectionRef &RelocatedSecRef = *RelocatedSecIter;
+ const StringRef RelocatedSectionName = cantFail(RelocatedSecRef.getName());
+ const bool SkipRelocs =
+ StringSwitch<bool>(RelocatedSectionName)
+ .Cases(".plt", ".got.plt", ".eh_frame", ".gcc_except_table",
+ ".fini_array", ".init_array", true)
+ .Default(false);
+ if (!RelocatedSecRef.isData() || SkipRelocs)
+ continue;
+
+ Error ErrorStatus = processDataRelocations(BC, SecRef, BitVector,
----------------
maksfb wrote:
In RewriteInstance, we read ELF relocations and record them as `BinarySection` relocations. We should use the `BinarySection` interface to get relocation info from passes. If there is information that is missing, we can expand the interface.
https://github.com/llvm/llvm-project/pull/116275
More information about the llvm-commits
mailing list