1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 19:12:56 +02:00
llvm-mirror/lib/LTO/UpdateCompilerUsed.cpp
Warren Ristow c0dcf88967 [LTO] Account for overriding lib calls via the alias attribute
Given a library call that is represented as an llvm intrinsic call, but
later transformed to an actual call, if an overriding definition of that
library routine is provided indirectly via an alias, prevent LTO from
eliminating the definition.

This is a fix for PR38547.

Differential Revision: https://reviews.llvm.org/D52836

llvm-svn: 344198
2018-10-10 22:54:31 +00:00

134 lines
4.4 KiB
C++

//==-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 (supplied
// either directly, or via a function alias) 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).
GlobalValue *FuncAliasee = nullptr;
if (isa<GlobalAlias>(GV)) {
auto *A = cast<GlobalAlias>(&GV);
FuncAliasee = dyn_cast<Function>(A->getAliasee());
}
if ((isa<Function>(GV) || FuncAliasee) && 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);
}