forked from OSchip/llvm-project
[ThinLTO] Enable importing of aliases as copy of aliasee
Summary: This implements a missing feature to allow importing of aliases, which was previously disabled because alias cannot be available_externally. We instead import an alias as a copy of its aliasee. Some additional work was required in the IndexBitcodeWriter for the distributed build case, to ensure that the aliasee has a value id in the distributed index file (i.e. even when it is not being imported directly). This is a performance win in codes that have many aliases, e.g. C++ applications that have many constructor and destructor aliases. Reviewers: pcc Subscribers: mehdi_amini, inglorion, eraman, llvm-commits Differential Revision: https://reviews.llvm.org/D40747 llvm-svn: 320895
This commit is contained in:
parent
c4fdbca604
commit
81bbf74265
|
@ -246,6 +246,7 @@ public:
|
|||
/// If this is an alias summary, returns the summary of the aliased object (a
|
||||
/// global variable or function), otherwise returns itself.
|
||||
GlobalValueSummary *getBaseObject();
|
||||
const GlobalValueSummary *getBaseObject() const;
|
||||
|
||||
friend class ModuleSummaryIndex;
|
||||
friend void computeDeadSymbols(class ModuleSummaryIndex &,
|
||||
|
@ -255,10 +256,14 @@ public:
|
|||
/// \brief Alias summary information.
|
||||
class AliasSummary : public GlobalValueSummary {
|
||||
GlobalValueSummary *AliaseeSummary;
|
||||
// AliaseeGUID is only set and accessed when we are building a combined index
|
||||
// via the BitcodeReader.
|
||||
GlobalValue::GUID AliaseeGUID;
|
||||
|
||||
public:
|
||||
AliasSummary(GVFlags Flags)
|
||||
: GlobalValueSummary(AliasKind, Flags, ArrayRef<ValueInfo>{}) {}
|
||||
: GlobalValueSummary(AliasKind, Flags, ArrayRef<ValueInfo>{}),
|
||||
AliaseeSummary(nullptr), AliaseeGUID(0) {}
|
||||
|
||||
/// Check if this is an alias summary.
|
||||
static bool classof(const GlobalValueSummary *GVS) {
|
||||
|
@ -266,6 +271,7 @@ public:
|
|||
}
|
||||
|
||||
void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; }
|
||||
void setAliaseeGUID(GlobalValue::GUID GUID) { AliaseeGUID = GUID; }
|
||||
|
||||
const GlobalValueSummary &getAliasee() const {
|
||||
assert(AliaseeSummary && "Unexpected missing aliasee summary");
|
||||
|
@ -276,8 +282,18 @@ public:
|
|||
return const_cast<GlobalValueSummary &>(
|
||||
static_cast<const AliasSummary *>(this)->getAliasee());
|
||||
}
|
||||
const GlobalValue::GUID &getAliaseeGUID() const {
|
||||
assert(AliaseeGUID && "Unexpected missing aliasee GUID");
|
||||
return AliaseeGUID;
|
||||
}
|
||||
};
|
||||
|
||||
const inline GlobalValueSummary *GlobalValueSummary::getBaseObject() const {
|
||||
if (auto *AS = dyn_cast<AliasSummary>(this))
|
||||
return &AS->getAliasee();
|
||||
return this;
|
||||
}
|
||||
|
||||
inline GlobalValueSummary *GlobalValueSummary::getBaseObject() {
|
||||
if (auto *AS = dyn_cast<AliasSummary>(this))
|
||||
return &AS->getAliasee();
|
||||
|
|
|
@ -330,6 +330,10 @@ public:
|
|||
return UseList == nullptr;
|
||||
}
|
||||
|
||||
bool materialized_use_empty() const {
|
||||
return UseList == nullptr;
|
||||
}
|
||||
|
||||
using use_iterator = use_iterator_impl<Use>;
|
||||
using const_use_iterator = use_iterator_impl<const Use>;
|
||||
|
||||
|
|
|
@ -98,6 +98,15 @@ void ComputeCrossModuleImportForModule(
|
|||
StringRef ModulePath, const ModuleSummaryIndex &Index,
|
||||
FunctionImporter::ImportMapTy &ImportList);
|
||||
|
||||
/// Mark all external summaries in \p Index for import into the given module.
|
||||
/// Used for distributed builds using a distributed index.
|
||||
///
|
||||
/// \p ImportList will be populated with a map that can be passed to
|
||||
/// FunctionImporter::importFunctions() above (see description there).
|
||||
void ComputeCrossModuleImportForModuleFromIndex(
|
||||
StringRef ModulePath, const ModuleSummaryIndex &Index,
|
||||
FunctionImporter::ImportMapTy &ImportList);
|
||||
|
||||
/// Compute all the symbols that are "dead": i.e these that can't be reached
|
||||
/// in the graph from any of the given symbols listed in
|
||||
/// \p GUIDPreservedSymbols.
|
||||
|
|
|
@ -5202,6 +5202,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
|
|||
if (!AliaseeInModule)
|
||||
return error("Alias expects aliasee summary to be parsed");
|
||||
AS->setAliasee(AliaseeInModule);
|
||||
AS->setAliaseeGUID(AliaseeGUID);
|
||||
|
||||
auto GUID = getValueInfoFromValueId(ValueID);
|
||||
AS->setOriginalName(GUID.second);
|
||||
|
@ -5288,9 +5289,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
|
|||
getValueInfoFromValueId(AliaseeValueId).first.getGUID();
|
||||
auto AliaseeInModule =
|
||||
TheIndex.findSummaryInModule(AliaseeGUID, AS->modulePath());
|
||||
if (!AliaseeInModule)
|
||||
return error("Alias expects aliasee summary to be parsed");
|
||||
AS->setAliasee(AliaseeInModule);
|
||||
AS->setAliaseeGUID(AliaseeGUID);
|
||||
|
||||
ValueInfo VI = getValueInfoFromValueId(ValueID).first;
|
||||
LastSeenGUID = VI.getGUID();
|
||||
|
|
|
@ -413,7 +413,7 @@ public:
|
|||
// in writing out the call graph edges. Save the mapping from GUID
|
||||
// to the new global value id to use when writing those edges, which
|
||||
// are currently saved in the index in terms of GUID.
|
||||
forEachSummary([&](GVInfo I) {
|
||||
forEachSummary([&](GVInfo I, bool) {
|
||||
GUIDToValueIdMap[I.first] = ++GlobalValueId;
|
||||
});
|
||||
}
|
||||
|
@ -428,12 +428,18 @@ public:
|
|||
void forEachSummary(Functor Callback) {
|
||||
if (ModuleToSummariesForIndex) {
|
||||
for (auto &M : *ModuleToSummariesForIndex)
|
||||
for (auto &Summary : M.second)
|
||||
Callback(Summary);
|
||||
for (auto &Summary : M.second) {
|
||||
Callback(Summary, false);
|
||||
// Ensure aliasee is handled, e.g. for assigning a valueId,
|
||||
// even if we are not importing the aliasee directly (the
|
||||
// imported alias will contain a copy of aliasee).
|
||||
if (auto *AS = dyn_cast<AliasSummary>(Summary.getSecond()))
|
||||
Callback({AS->getAliaseeGUID(), &AS->getAliasee()}, true);
|
||||
}
|
||||
} else {
|
||||
for (auto &Summaries : Index)
|
||||
for (auto &Summary : Summaries.second.SummaryList)
|
||||
Callback({Summaries.first, Summary.get()});
|
||||
Callback({Summaries.first, Summary.get()}, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3604,7 +3610,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
NameVals.clear();
|
||||
};
|
||||
|
||||
forEachSummary([&](GVInfo I) {
|
||||
forEachSummary([&](GVInfo I, bool IsAliasee) {
|
||||
GlobalValueSummary *S = I.second;
|
||||
assert(S);
|
||||
|
||||
|
@ -3612,6 +3618,12 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
|
|||
assert(ValueId);
|
||||
SummaryToValueIdMap[S] = *ValueId;
|
||||
|
||||
// If this is invoked for an aliasee, we want to record the above
|
||||
// mapping, but then not emit a summary entry (if the aliasee is
|
||||
// to be imported, we will invoke this separately with IsAliasee=false).
|
||||
if (IsAliasee)
|
||||
return;
|
||||
|
||||
if (auto *AS = dyn_cast<AliasSummary>(S)) {
|
||||
// Will process aliases as a post-pass because the reader wants all
|
||||
// global to be loaded first.
|
||||
|
|
|
@ -409,7 +409,7 @@ void Value::doRAUW(Value *New, bool NoMetadata) {
|
|||
if (!NoMetadata && isUsedByMetadata())
|
||||
ValueAsMetadata::handleRAUW(this, New);
|
||||
|
||||
while (!use_empty()) {
|
||||
while (!materialized_use_empty()) {
|
||||
Use &U = *UseList;
|
||||
// Must handle Constants specially, we cannot call replaceUsesOfWith on a
|
||||
// constant because they are uniqued.
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Bitcode/BitcodeReader.h"
|
||||
#include "llvm/IR/AutoUpgrade.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/GlobalAlias.h"
|
||||
#include "llvm/IR/GlobalObject.h"
|
||||
|
@ -44,7 +45,9 @@
|
|||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO/Internalize.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
|
||||
#include "llvm/Transforms/Utils/ValueMapper.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
@ -118,6 +121,12 @@ static cl::opt<std::string>
|
|||
SummaryFile("summary-file",
|
||||
cl::desc("The summary file to use for function importing."));
|
||||
|
||||
/// Used when testing importing from distributed indexes via opt
|
||||
// -function-import.
|
||||
static cl::opt<bool>
|
||||
ImportAllIndex("import-all-index",
|
||||
cl::desc("Import all external functions in index."));
|
||||
|
||||
// Load lazily a module from \p FileName in \p Context.
|
||||
static std::unique_ptr<Module> loadFile(const std::string &FileName,
|
||||
LLVMContext &Context) {
|
||||
|
@ -172,13 +181,8 @@ selectCallee(const ModuleSummaryIndex &Index,
|
|||
if (GlobalValue::isInterposableLinkage(GVSummary->linkage()))
|
||||
// There is no point in importing these, we can't inline them
|
||||
return false;
|
||||
if (isa<AliasSummary>(GVSummary))
|
||||
// Aliases can't point to "available_externally".
|
||||
// FIXME: we should import alias as available_externally *function*,
|
||||
// the destination module does not need to know it is an alias.
|
||||
return false;
|
||||
|
||||
auto *Summary = cast<FunctionSummary>(GVSummary);
|
||||
auto *Summary = cast<FunctionSummary>(GVSummary->getBaseObject());
|
||||
|
||||
// If this is a local function, make sure we import the copy
|
||||
// in the caller's module. The only time a local function can
|
||||
|
@ -275,9 +279,7 @@ static void computeImportForFunction(
|
|||
}
|
||||
|
||||
// "Resolve" the summary
|
||||
assert(!isa<AliasSummary>(CalleeSummary) &&
|
||||
"Unexpected alias in import list");
|
||||
const auto *ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary);
|
||||
const auto *ResolvedCalleeSummary = cast<FunctionSummary>(CalleeSummary->getBaseObject());
|
||||
|
||||
assert(ResolvedCalleeSummary->instCount() <= NewThreshold &&
|
||||
"selectCallee() didn't honor the threshold");
|
||||
|
@ -432,6 +434,19 @@ void llvm::ComputeCrossModuleImport(
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void dumpImportListForModule(StringRef ModulePath,
|
||||
FunctionImporter::ImportMapTy &ImportList) {
|
||||
DEBUG(dbgs() << "* Module " << ModulePath << " imports from "
|
||||
<< ImportList.size() << " modules.\n");
|
||||
for (auto &Src : ImportList) {
|
||||
auto SrcModName = Src.first();
|
||||
DEBUG(dbgs() << " - " << Src.second.size() << " functions imported from "
|
||||
<< SrcModName << "\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Compute all the imports for the given module in the Index.
|
||||
void llvm::ComputeCrossModuleImportForModule(
|
||||
StringRef ModulePath, const ModuleSummaryIndex &Index,
|
||||
|
@ -446,13 +461,34 @@ void llvm::ComputeCrossModuleImportForModule(
|
|||
ComputeImportForModule(FunctionSummaryMap, Index, ImportList);
|
||||
|
||||
#ifndef NDEBUG
|
||||
DEBUG(dbgs() << "* Module " << ModulePath << " imports from "
|
||||
<< ImportList.size() << " modules.\n");
|
||||
for (auto &Src : ImportList) {
|
||||
auto SrcModName = Src.first();
|
||||
DEBUG(dbgs() << " - " << Src.second.size() << " functions imported from "
|
||||
<< SrcModName << "\n");
|
||||
dumpImportListForModule(ModulePath, ImportList);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Mark all external summaries in Index for import into the given module.
|
||||
// Used for distributed builds using a distributed index.
|
||||
void llvm::ComputeCrossModuleImportForModuleFromIndex(
|
||||
StringRef ModulePath, const ModuleSummaryIndex &Index,
|
||||
FunctionImporter::ImportMapTy &ImportList) {
|
||||
for (auto &GlobalList : Index) {
|
||||
// Ignore entries for undefined references.
|
||||
if (GlobalList.second.SummaryList.empty())
|
||||
continue;
|
||||
|
||||
auto GUID = GlobalList.first;
|
||||
assert(GlobalList.second.SummaryList.size() == 1 &&
|
||||
"Expected individual combined index to have one summary per GUID");
|
||||
auto &Summary = GlobalList.second.SummaryList[0];
|
||||
// Skip the summaries for the importing module. These are included to
|
||||
// e.g. record required linkage changes.
|
||||
if (Summary->modulePath() == ModulePath)
|
||||
continue;
|
||||
// Doesn't matter what value we plug in to the map, just needs an entry
|
||||
// to provoke importing by thinBackend.
|
||||
ImportList[Summary->modulePath()][GUID] = 1;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
dumpImportListForModule(ModulePath, ImportList);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -692,6 +728,20 @@ void llvm::thinLTOInternalizeModule(Module &TheModule,
|
|||
internalizeModule(TheModule, MustPreserveGV);
|
||||
}
|
||||
|
||||
/// Make alias a clone of its aliasee.
|
||||
static Function *replaceAliasWithAliasee(Module *SrcModule, GlobalAlias *GA) {
|
||||
Function *Fn = cast<Function>(GA->getBaseObject());
|
||||
|
||||
ValueToValueMapTy VMap;
|
||||
Function *NewFn = CloneFunction(Fn, VMap);
|
||||
// Clone should use the original alias's linkage and name, and we ensure
|
||||
// all uses of alias instead use the new clone (casted if necessary).
|
||||
NewFn->setLinkage(GA->getLinkage());
|
||||
GA->replaceAllUsesWith(ConstantExpr::getBitCast(NewFn, GA->getType()));
|
||||
NewFn->takeName(GA);
|
||||
return NewFn;
|
||||
}
|
||||
|
||||
// Automatically import functions in Module \p DestModule based on the summaries
|
||||
// index.
|
||||
Expected<bool> FunctionImporter::importFunctions(
|
||||
|
@ -761,17 +811,36 @@ Expected<bool> FunctionImporter::importFunctions(
|
|||
GlobalsToImport.insert(&GV);
|
||||
}
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
for (GlobalAlias &GA : SrcModule->aliases()) {
|
||||
if (!GA.hasName())
|
||||
continue;
|
||||
auto GUID = GA.getGUID();
|
||||
assert(!ImportGUIDs.count(GUID) && "Unexpected alias in import list");
|
||||
DEBUG(dbgs() << "Not importing alias " << GUID
|
||||
auto Import = ImportGUIDs.count(GUID);
|
||||
DEBUG(dbgs() << (Import ? "Is" : "Not") << " importing alias " << GUID
|
||||
<< " " << GA.getName() << " from "
|
||||
<< SrcModule->getSourceFileName() << "\n");
|
||||
if (Import) {
|
||||
if (Error Err = GA.materialize())
|
||||
return std::move(Err);
|
||||
// Import alias as a copy of its aliasee.
|
||||
GlobalObject *Base = GA.getBaseObject();
|
||||
if (Error Err = Base->materialize())
|
||||
return std::move(Err);
|
||||
auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA);
|
||||
DEBUG(dbgs() << "Is importing aliasee fn " << Base->getGUID()
|
||||
<< " " << Base->getName() << " from "
|
||||
<< SrcModule->getSourceFileName() << "\n");
|
||||
if (EnableImportMetadata) {
|
||||
// Add 'thinlto_src_module' metadata for statistics and debugging.
|
||||
Fn->setMetadata(
|
||||
"thinlto_src_module",
|
||||
MDNode::get(DestModule.getContext(),
|
||||
{MDString::get(DestModule.getContext(),
|
||||
SrcModule->getSourceFileName())}));
|
||||
}
|
||||
GlobalsToImport.insert(Fn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Upgrade debug info after we're done materializing all the globals and we
|
||||
// have loaded all the required metadata!
|
||||
|
@ -817,6 +886,13 @@ static bool doImportingForModule(Module &M) {
|
|||
|
||||
// First step is collecting the import list.
|
||||
FunctionImporter::ImportMapTy ImportList;
|
||||
// If requested, simply import all functions in the index. This is used
|
||||
// when testing distributed backend handling via the opt tool, when
|
||||
// we have distributed indexes containing exactly the summaries to import.
|
||||
if (ImportAllIndex)
|
||||
ComputeCrossModuleImportForModuleFromIndex(M.getModuleIdentifier(), *Index,
|
||||
ImportList);
|
||||
else
|
||||
ComputeCrossModuleImportForModule(M.getModuleIdentifier(), *Index,
|
||||
ImportList);
|
||||
|
||||
|
|
|
@ -6,3 +6,9 @@ entry:
|
|||
%0 = load i32, i32* @G
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
@analias = alias void (...), bitcast (void ()* @aliasee to void (...)*)
|
||||
define void @aliasee() {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
|
|
@ -2,3 +2,9 @@ define void @g() {
|
|||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
@analias = alias void (...), bitcast (void ()* @aliasee to void (...)*)
|
||||
define void @aliasee() {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
; RUN: llvm-lto -thinlto-action=promote -thinlto-index %t.index.bc %t2.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=PROMOTE
|
||||
; RUN: llvm-lto -thinlto-action=import -thinlto-index %t.index.bc %t1.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT
|
||||
|
||||
; Alias can't point to "available_externally", so they cannot be imported for
|
||||
; now. This could be implemented by importing the alias as an
|
||||
; available_externally definition copied from the aliasee's body.
|
||||
; Alias can't point to "available_externally", so they are implemented by
|
||||
; importing the alias as an available_externally definition copied from the
|
||||
; aliasee's body.
|
||||
; PROMOTE-DAG: @globalfuncAlias = alias void (...), bitcast (void ()* @globalfunc to void (...)*)
|
||||
; PROMOTE-DAG: @globalfuncWeakAlias = weak alias void (...), bitcast (void ()* @globalfunc to void (...)*)
|
||||
; PROMOTE-DAG: @globalfuncLinkonceAlias = weak alias void (...), bitcast (void ()* @globalfunc to void (...)*)
|
||||
|
@ -45,45 +45,43 @@
|
|||
; PROMOTE-DAG: define weak void @linkoncefunc()
|
||||
; PROMOTE-DAG: define weak void @weakfunc()
|
||||
|
||||
; On the import side now, verify that aliases are not imported
|
||||
; On the import side now, verify that aliases are imported unless they
|
||||
; are preemptible (non-ODR weak/linkonce).
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncWeakAlias
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncLinkonceAlias
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncAlias
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncWeakODRAlias
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncLinkonceODRAlias
|
||||
|
||||
|
||||
; On the import side, these aliases are not imported (they don't point to a linkonce_odr)
|
||||
; IMPORT-DAG: declare void @globalfuncAlias()
|
||||
; IMPORT-DAG: define available_externally void @linkonceODRfuncAlias
|
||||
; IMPORT-DAG: define available_externally void @linkonceODRfuncWeakODRAlias
|
||||
; IMPORT-DAG: define available_externally void @linkonceODRfuncLinkonceODRAlias
|
||||
; IMPORT-DAG: define available_externally void @globalfuncAlias()
|
||||
; IMPORT-DAG: declare void @globalfuncWeakAlias()
|
||||
; IMPORT-DAG: declare void @globalfuncLinkonceAlias()
|
||||
; IMPORT-DAG: declare void @globalfuncWeakODRAlias()
|
||||
; IMPORT-DAG: declare void @globalfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: declare void @internalfuncAlias()
|
||||
; IMPORT-DAG: define available_externally void @globalfuncWeakODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @globalfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @internalfuncAlias()
|
||||
; IMPORT-DAG: declare void @internalfuncWeakAlias()
|
||||
; IMPORT-DAG: declare void @internalfuncLinkonceAlias()
|
||||
; IMPORT-DAG: declare void @internalfuncWeakODRAlias()
|
||||
; IMPORT-DAG: declare void @internalfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: declare void @weakODRfuncAlias()
|
||||
; IMPORT-DAG: define available_externally void @internalfuncWeakODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @internalfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @weakODRfuncAlias()
|
||||
; IMPORT-DAG: declare void @weakODRfuncWeakAlias()
|
||||
; IMPORT-DAG: declare void @weakODRfuncLinkonceAlias()
|
||||
; IMPORT-DAG: declare void @weakODRfuncWeakODRAlias()
|
||||
; IMPORT-DAG: declare void @weakODRfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: declare void @linkoncefuncAlias()
|
||||
; IMPORT-DAG: define available_externally void @weakODRfuncWeakODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @weakODRfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @linkoncefuncAlias()
|
||||
; IMPORT-DAG: declare void @linkoncefuncWeakAlias()
|
||||
; IMPORT-DAG: declare void @linkoncefuncLinkonceAlias()
|
||||
; IMPORT-DAG: declare void @linkoncefuncWeakODRAlias()
|
||||
; IMPORT-DAG: declare void @linkoncefuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: declare void @weakfuncAlias()
|
||||
; IMPORT-DAG: define available_externally void @linkoncefuncWeakODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @linkoncefuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @weakfuncAlias()
|
||||
; IMPORT-DAG: declare void @weakfuncWeakAlias()
|
||||
; IMPORT-DAG: declare void @weakfuncLinkonceAlias()
|
||||
; IMPORT-DAG: declare void @weakfuncWeakODRAlias()
|
||||
; IMPORT-DAG: declare void @weakfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncAlias()
|
||||
; IMPORT-DAG: define available_externally void @weakfuncWeakODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @weakfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @linkonceODRfuncAlias()
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncWeakAlias()
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncWeakODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @linkonceODRfuncWeakODRAlias()
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncLinkonceAlias()
|
||||
; IMPORT-DAG: declare void @linkonceODRfuncLinkonceODRAlias()
|
||||
; IMPORT-DAG: define available_externally void @linkonceODRfuncLinkonceODRAlias()
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
|
|
|
@ -10,11 +10,15 @@
|
|||
; RUN: llvm-lto2 run %t1.bc %t2.bc -o %t.o -save-temps \
|
||||
; RUN: -thinlto-distributed-indexes \
|
||||
; RUN: -r=%t1.bc,g, \
|
||||
; RUN: -r=%t1.bc,analias, \
|
||||
; RUN: -r=%t1.bc,f,px \
|
||||
; RUN: -r=%t2.bc,g,px
|
||||
; RUN: opt -function-import -summary-file %t1.bc.thinlto.bc %t1.bc -o %t1.out
|
||||
; RUN: opt -function-import -summary-file %t2.bc.thinlto.bc %t2.bc -o %t2.out
|
||||
; RUN: llvm-dis -o - %t2.out | FileCheck %s
|
||||
; RUN: -r=%t2.bc,g,px \
|
||||
; RUN: -r=%t2.bc,analias,px \
|
||||
; RUN: -r=%t2.bc,aliasee,px
|
||||
; RUN: opt -function-import -import-all-index -summary-file %t1.bc.thinlto.bc %t1.bc -o %t1.out
|
||||
; RUN: opt -function-import -import-all-index -summary-file %t2.bc.thinlto.bc %t2.bc -o %t2.out
|
||||
; RUN: llvm-dis -o - %t1.out | FileCheck %s --check-prefix=IMPORT
|
||||
; RUN: llvm-dis -o - %t2.out | FileCheck %s --check-prefix=EXPORT
|
||||
|
||||
; Save the generated index files.
|
||||
; RUN: cp %t1.bc.thinlto.bc %t1.bc.thinlto.bc.orig
|
||||
|
@ -34,26 +38,35 @@
|
|||
; RUN: llvm-lto2 run %t1.bc %t2.bc -o %t.o -save-temps \
|
||||
; RUN: -thinlto-distributed-indexes \
|
||||
; RUN: -r=%t1.bc,g, \
|
||||
; RUN: -r=%t1.bc,analias, \
|
||||
; RUN: -r=%t1.bc,f,px \
|
||||
; RUN: -r=%t2.bc,g,px
|
||||
; RUN: -r=%t2.bc,g,px \
|
||||
; RUN: -r=%t2.bc,analias,px \
|
||||
; RUN: -r=%t2.bc,aliasee,px
|
||||
; RUN: diff %t1.bc.thinlto.bc.orig %t1.bc.thinlto.bc
|
||||
; RUN: diff %t2.bc.thinlto.bc.orig %t2.bc.thinlto.bc
|
||||
|
||||
; Make sure importing occurs as expected
|
||||
; RUN: cp %t1.bc.sv %t1.bc
|
||||
; RUN: cp %t2.bc.sv %t2.bc
|
||||
; RUN: opt -function-import -summary-file %t2.bc.thinlto.bc %t2.bc -o %t2.out
|
||||
; RUN: llvm-dis -o - %t2.out | FileCheck %s
|
||||
; RUN: opt -function-import -import-all-index -summary-file %t1.bc.thinlto.bc %t1.bc -o %t1.out
|
||||
; RUN: opt -function-import -import-all-index -summary-file %t2.bc.thinlto.bc %t2.bc -o %t2.out
|
||||
; RUN: llvm-dis -o - %t1.out | FileCheck %s --check-prefix=IMPORT
|
||||
; RUN: llvm-dis -o - %t2.out | FileCheck %s --check-prefix=EXPORT
|
||||
|
||||
; CHECK: @G.llvm.
|
||||
; IMPORT: define available_externally i32 @g() !thinlto_src_module
|
||||
; IMPORT: define available_externally void @analias() !thinlto_src_module
|
||||
; EXPORT: @G.llvm.
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
||||
declare i32 @g(...)
|
||||
declare void @analias(...)
|
||||
|
||||
define void @f() {
|
||||
entry:
|
||||
call i32 (...) @g()
|
||||
call void (...) @analias()
|
||||
ret void
|
||||
}
|
||||
|
||||
|
|
|
@ -7,16 +7,22 @@
|
|||
|
||||
; The backend index for this module contains summaries from itself and
|
||||
; Inputs/distributed_indexes.ll, as it imports from the latter.
|
||||
; We should import @g and alias @analias. While we don't import the aliasee
|
||||
; directly (and therefore don't have a third COMBINED record from module
|
||||
; id 1), we will have a VALUE_GUID for it (hence the 4 VALUE_GUID entries).
|
||||
; BACKEND1: <MODULE_STRTAB_BLOCK
|
||||
; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}distributed_indexes.ll.tmp{{.*}}.bc'
|
||||
; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}distributed_indexes.ll.tmp{{.*}}.bc'
|
||||
; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; BACKEND1-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; BACKEND1-NEXT: <VERSION
|
||||
; BACKEND1-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
|
||||
; BACKEND1-NEXT: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}}
|
||||
; BACKEND1-NEXT: <COMBINED
|
||||
; BACKEND1-NEXT: <COMBINED
|
||||
; BACKEND1-DAG: <VALUE_GUID op0=2 op1=-5751648690987223394
|
||||
; BACKEND1-DAG: <VALUE_GUID op0=4 op1=-5300342847281564238
|
||||
; BACKEND1-DAG: <VALUE_GUID op0=1 op1=-3706093650706652785
|
||||
; BACKEND1-DAG: <VALUE_GUID op0=3 op1=-1039159065113703048
|
||||
; BACKEND1-DAG: <COMBINED {{.*}} op1=0
|
||||
; BACKEND1-DAG: <COMBINED {{.*}} op1=1
|
||||
; BACKEND1-DAG: <COMBINED_ALIAS {{.*}} op1=1
|
||||
; BACKEND1-NEXT: </GLOBALVAL_SUMMARY_BLOCK
|
||||
|
||||
; The backend index for Input/distributed_indexes.ll contains summaries from
|
||||
|
@ -26,14 +32,20 @@
|
|||
; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK
|
||||
; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK
|
||||
; BACKEND2-NEXT: <VERSION
|
||||
; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238
|
||||
; BACKEND2-DAG: <VALUE_GUID op0=1 op1=-5751648690987223394/>
|
||||
; BACKEND2-DAG: <VALUE_GUID op0=4 op1=-5300342847281564238/>
|
||||
; BACKEND2-DAG: <VALUE_GUID op0=3 op1=-1039159065113703048/>
|
||||
; BACKEND2-NEXT: <COMBINED
|
||||
; BACKEND2-NEXT: <COMBINED
|
||||
; BACKEND2-NEXT: <COMBINED_ALIAS
|
||||
; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK
|
||||
|
||||
declare void @g(...)
|
||||
declare void @analias(...)
|
||||
|
||||
define void @f() {
|
||||
entry:
|
||||
call void (...) @g()
|
||||
call void (...) @analias()
|
||||
ret void
|
||||
}
|
||||
|
|
|
@ -16,17 +16,19 @@
|
|||
; EXPORTSTATIC-DAG: define hidden i32 @staticfunc.llvm.0
|
||||
; EXPORTSTATIC-DAG: define hidden void @staticfunc2.llvm.0
|
||||
|
||||
; Ensure that both weak alias to an imported function and strong alias to a
|
||||
; non-imported function are correctly turned into declarations.
|
||||
; Ensure that weak alias to an imported function is correctly turned into
|
||||
; a declaration.
|
||||
; Also ensures that alias to a linkonce function is turned into a declaration
|
||||
; and that the associated linkonce function is not in the output, as it is
|
||||
; lazily linked and never referenced/materialized.
|
||||
; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORTGLOB1
|
||||
; IMPORTGLOB1-DAG: define available_externally void @globalfunc1
|
||||
; IMPORTGLOB1-DAG: declare void @weakalias
|
||||
; IMPORTGLOB1-DAG: declare void @analias
|
||||
; IMPORTGLOB1-NOT: @linkoncealias
|
||||
; IMPORTGLOB1-NOT: @linkoncefunc
|
||||
|
||||
; A strong alias is imported as an available_externally copy of its aliasee.
|
||||
; IMPORTGLOB1-DAG: define available_externally void @analias
|
||||
; IMPORTGLOB1-NOT: declare void @globalfunc2
|
||||
|
||||
; Verify that the optimizer run
|
||||
|
|
|
@ -36,13 +36,14 @@ entry:
|
|||
; CHECK-DAG: declare void @weakalias
|
||||
declare void @weakalias(...) #1
|
||||
|
||||
; Cannot create an alias to available_externally
|
||||
; CHECK-DAG: declare void @analias
|
||||
; External alias imported as available_externally copy of aliasee
|
||||
; CHECK-DAG: define available_externally void @analias
|
||||
declare void @analias(...) #1
|
||||
|
||||
; Aliases are not imported
|
||||
; External alias imported as available_externally copy of aliasee
|
||||
; (linkoncealias is an external alias to a linkonce_odr)
|
||||
declare void @linkoncealias(...) #1
|
||||
; CHECK-DAG: declare void @linkoncealias(...)
|
||||
; CHECK-DAG: define available_externally void @linkoncealias()
|
||||
|
||||
; INSTLIMDEF-DAG: Import referencestatics
|
||||
; INSTLIMDEF-DAG: define available_externally i32 @referencestatics(i32 %i) !thinlto_src_module !0 {
|
||||
|
@ -105,7 +106,7 @@ declare void @linkoncefunc2(...) #1
|
|||
declare void @variadic(...)
|
||||
|
||||
; INSTLIMDEF-DAG: Import globalfunc2
|
||||
; INSTLIMDEF-DAG: 11 function-import - Number of functions imported
|
||||
; INSTLIMDEF-DAG: 13 function-import - Number of functions imported
|
||||
; CHECK-DAG: !0 = !{!"{{.*}}/Inputs/funcimport.ll"}
|
||||
|
||||
; The actual GUID values will depend on path to test.
|
||||
|
|
Loading…
Reference in New Issue