[sil-linker] Improve the implementation of the hasSILFunction API

It it now possible to check if a function with a given name and a given linkage exists in one of the modules,
even if the current module contains a function with this name but a difference linkage.
This is useful e.g. for performing a lookup of pre-specializations.
This commit is contained in:
Roman Levenstein
2016-04-13 13:50:19 -07:00
parent e806fd2d1d
commit 9234eb3ca7
7 changed files with 126 additions and 6 deletions

View File

@@ -94,6 +94,7 @@ public:
SILFunction * SILFunction *
lookupSILFunction(StringRef Name, bool declarationOnly = false, lookupSILFunction(StringRef Name, bool declarationOnly = false,
SILLinkage linkage = SILLinkage::Private); SILLinkage linkage = SILLinkage::Private);
bool hasSILFunction(StringRef Name, SILLinkage linkage = SILLinkage::Private);
SILVTable *lookupVTable(Identifier Name); SILVTable *lookupVTable(Identifier Name);
SILVTable *lookupVTable(const ClassDecl *C) { SILVTable *lookupVTable(const ClassDecl *C) {
return lookupVTable(C->getName()); return lookupVTable(C->getName());

View File

@@ -139,6 +139,10 @@ SILFunction *SILLinkerVisitor::lookupFunction(StringRef Name,
return NewFn; return NewFn;
} }
/// Process Decl, recursively deserializing any thing Decl may reference.
bool SILLinkerVisitor::hasFunction(StringRef Name, SILLinkage Linkage) {
return Loader->hasSILFunction(Name, Linkage);
}
/// Deserialize the VTable mapped to C if it exists and all SIL the VTable /// Deserialize the VTable mapped to C if it exists and all SIL the VTable
/// transitively references. /// transitively references.

View File

@@ -58,6 +58,10 @@ public:
/// this Name. /// this Name.
SILFunction *lookupFunction(StringRef Name, SILLinkage Linkage); SILFunction *lookupFunction(StringRef Name, SILLinkage Linkage);
/// Process Name, try to check if there is a declaration of a function
/// with this Name.
bool hasFunction(StringRef Name, SILLinkage Linkage);
/// Process Decl, recursively deserializing any thing that /// Process Decl, recursively deserializing any thing that
/// the SILFunction corresponding to Decl may reference. /// the SILFunction corresponding to Decl may reference.
bool processDeclRef(SILDeclRef Decl); bool processDeclRef(SILDeclRef Decl);

View File

@@ -484,12 +484,48 @@ bool SILModule::linkFunction(StringRef Name, SILModule::LinkingMode Mode) {
} }
SILFunction *SILModule::hasFunction(StringRef Name, SILLinkage Linkage) { SILFunction *SILModule::hasFunction(StringRef Name, SILLinkage Linkage) {
assert(!lookUpFunction(Name) && "hasFunction should be only called for " SILFunction *F = lookUpFunction(Name);
"functions that are not contained in the "
"SILModule yet"); assert((Linkage == SILLinkage::Public ||
return SILLinkerVisitor(*this, getSILLoader(), Linkage == SILLinkage::PublicExternal) &&
SILModule::LinkingMode::LinkNormal) "Only a lookup of public functions is supported currently");
.lookupFunction(Name, Linkage);
// Nothing to do if the current module has a required function
// with a proper linkage.
if (F && F->getLinkage() == Linkage)
return F;
assert((!F || F->getLinkage() != Linkage) &&
"hasFunction should be only called for functions that are not "
"contained in the SILModule yet or do not have a required linkage");
(void)F;
SILLinkerVisitor Visitor(*this, getSILLoader(),
SILModule::LinkingMode::LinkNormal);
if (Visitor.hasFunction(Name, Linkage)) {
if (!F) {
// Load the function.
F = Visitor.lookupFunction(Name, Linkage);
assert(F && "Function should be present");
assert(F->getLinkage() == Linkage &&
"SILFunction has a wrong linkage");
}
// If a function exists already and it is a non-optimizing
// compilaiton, simply convert it into an external declaration,
// so that a compiled version from the shared library is used.
if (F->isDefinition() &&
F->getModule().getOptions().Optimization <
SILOptions::SILOptMode::Optimize) {
F->convertToDeclaration();
}
if (F->isExternalDeclaration())
F->setFragile(IsFragile_t::IsNotFragile);
F->setLinkage(Linkage);
} else {
F = nullptr;
}
return F;
} }
void SILModule::linkAllWitnessTables() { void SILModule::linkAllWitnessTables() {

View File

@@ -1798,6 +1798,68 @@ SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) {
return Func; return Func;
} }
/// Check for existence of a function with a given name and required linkage.
/// This function is modelled after readSILFunction. But it does not
/// create a SILFunction object.
bool SILDeserializer::hasSILFunction(StringRef Name,
SILLinkage Linkage) {
if (!FuncTable)
return false;
auto iter = FuncTable->find(Name);
if (iter == FuncTable->end())
return false;
// There is a function with the required name.
// Find out which linkage it has.
auto FID = *iter;
auto &cacheEntry = Funcs[FID-1];
if (cacheEntry.isFullyDeserialized() ||
(cacheEntry.isDeserialized()))
return cacheEntry.get()->getLinkage() == Linkage ||
Linkage == SILLinkage::Private;
BCOffsetRAII restoreOffset(SILCursor);
SILCursor.JumpToBit(cacheEntry.getOffset());
auto entry = SILCursor.advance(AF_DontPopBlockAtEnd);
if (entry.Kind == llvm::BitstreamEntry::Error) {
DEBUG(llvm::dbgs() << "Cursor advance error in hasSILFunction.\n");
MF->error();
return false;
}
SmallVector<uint64_t, 64> scratch;
StringRef blobData;
unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData);
assert(kind == SIL_FUNCTION && "expect a sil function");
(void)kind;
// Read function properties only, e.g. its linkage and other attributes.
// TODO: If this results in any noticable performance problems, Cache the
// linkage to avoid re-reading it from the bitcode each time?
TypeID funcTyID;
unsigned rawLinkage, isTransparent, isFragile, isThunk, isGlobal,
inlineStrategy, effect, numSpecAttrs;
ArrayRef<uint64_t> SemanticsIDs;
SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isFragile,
isThunk, isGlobal, inlineStrategy, effect,
numSpecAttrs, funcTyID, SemanticsIDs);
auto linkage = fromStableSILLinkage(rawLinkage);
if (!linkage) {
DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
<< " for SIL function " << Name << "\n");
return false;
}
// Bail if it is not a required linkage.
if (linkage.getValue() != Linkage && Linkage != SILLinkage::Private)
return false;
DEBUG(llvm::dbgs() << "Found SIL Function: " << Name << "\n");
return true;
}
SILFunction *SILDeserializer::lookupSILFunction(StringRef name, SILFunction *SILDeserializer::lookupSILFunction(StringRef name,
bool declarationOnly) { bool declarationOnly) {
if (!FuncTable) if (!FuncTable)

View File

@@ -117,6 +117,7 @@ public:
SILFunction *lookupSILFunction(SILFunction *InFunc); SILFunction *lookupSILFunction(SILFunction *InFunc);
SILFunction *lookupSILFunction(StringRef Name, SILFunction *lookupSILFunction(StringRef Name,
bool declarationOnly = false); bool declarationOnly = false);
bool hasSILFunction(StringRef Name, SILLinkage Linkage);
SILVTable *lookupVTable(Identifier Name); SILVTable *lookupVTable(Identifier Name);
SILWitnessTable *lookupWitnessTable(SILWitnessTable *wt); SILWitnessTable *lookupWitnessTable(SILWitnessTable *wt);
SILDefaultWitnessTable * SILDefaultWitnessTable *

View File

@@ -104,6 +104,18 @@ SILFunction *SerializedSILLoader::lookupSILFunction(StringRef Name,
return retVal; return retVal;
} }
bool SerializedSILLoader::hasSILFunction(StringRef Name, SILLinkage Linkage) {
// It is possible that one module has a declaration of a SILFunction, while
// another has the full definition.
SILFunction *retVal = nullptr;
for (auto &Des : LoadedSILSections) {
if (Des->hasSILFunction(Name, Linkage))
return true;
}
return retVal;
}
SILVTable *SerializedSILLoader::lookupVTable(Identifier Name) { SILVTable *SerializedSILLoader::lookupVTable(Identifier Name) {
for (auto &Des : LoadedSILSections) { for (auto &Des : LoadedSILSections) {
if (auto VT = Des->lookupVTable(Name)) if (auto VT = Des->lookupVTable(Name))