//==-LTOInternalize.cpp - LLVM Link Time Optimizer Internalization Utility -==// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines a helper to run the internalization part of LTO. // //===----------------------------------------------------------------------===// #include "llvm/LTO/legacy/UpdateCompilerUsed.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; namespace { // Helper class that collects AsmUsed and user supplied libcalls. class PreserveLibCallsAndAsmUsed { public: PreserveLibCallsAndAsmUsed(const StringSet<> &AsmUndefinedRefs, const TargetMachine &TM, std::vector<GlobalValue *> &LLVMUsed) : AsmUndefinedRefs(AsmUndefinedRefs), TM(TM), LLVMUsed(LLVMUsed) {} void findInModule(Module &TheModule) { initializeLibCalls(TheModule); for (Function &F : TheModule) findLibCallsAndAsm(F); for (GlobalVariable &GV : TheModule.globals()) findLibCallsAndAsm(GV); for (GlobalAlias &GA : TheModule.aliases()) findLibCallsAndAsm(GA); } private: // Inputs const StringSet<> &AsmUndefinedRefs; const TargetMachine &TM; // Temps llvm::Mangler Mangler; StringSet<> Libcalls; // Output std::vector<GlobalValue *> &LLVMUsed; // Collect names of runtime library functions. User-defined functions with the // same names are added to llvm.compiler.used to prevent them from being // deleted by optimizations. void initializeLibCalls(const Module &TheModule) { TargetLibraryInfoImpl TLII(Triple(TM.getTargetTriple())); TargetLibraryInfo TLI(TLII); // TargetLibraryInfo has info on C runtime library calls on the current // target. for (unsigned I = 0, E = static_cast<unsigned>(LibFunc::NumLibFuncs); I != E; ++I) { LibFunc F = static_cast<LibFunc>(I); if (TLI.has(F)) Libcalls.insert(TLI.getName(F)); } SmallPtrSet<const TargetLowering *, 1> TLSet; for (const Function &F : TheModule) { const TargetLowering *Lowering = TM.getSubtargetImpl(F)->getTargetLowering(); if (Lowering && TLSet.insert(Lowering).second) // TargetLowering has info on library calls that CodeGen expects to be // available, both from the C runtime and compiler-rt. for (unsigned I = 0, E = static_cast<unsigned>(RTLIB::UNKNOWN_LIBCALL); I != E; ++I) if (const char *Name = Lowering->getLibcallName(static_cast<RTLIB::Libcall>(I))) Libcalls.insert(Name); } } void findLibCallsAndAsm(GlobalValue &GV) { // There are no restrictions to apply to declarations. if (GV.isDeclaration()) return; // There is nothing more restrictive than private linkage. if (GV.hasPrivateLinkage()) return; // Conservatively append user-supplied runtime library functions to // llvm.compiler.used. These could be internalized and deleted by // optimizations like -globalopt, causing problems when later optimizations // add new library calls (e.g., llvm.memset => memset and printf => puts). // Leave it to the linker to remove any dead code (e.g. with -dead_strip). if (isa<Function>(GV) && Libcalls.count(GV.getName())) { LLVMUsed.push_back(&GV); return; } SmallString<64> Buffer; TM.getNameWithPrefix(Buffer, &GV, Mangler); if (AsmUndefinedRefs.count(Buffer)) LLVMUsed.push_back(&GV); } }; } // namespace anonymous void llvm::updateCompilerUsed(Module &TheModule, const TargetMachine &TM, const StringSet<> &AsmUndefinedRefs) { std::vector<GlobalValue *> UsedValues; PreserveLibCallsAndAsmUsed(AsmUndefinedRefs, TM, UsedValues) .findInModule(TheModule); if (UsedValues.empty()) return; appendToCompilerUsed(TheModule, UsedValues); }