Skip to content

Commit 9234eb3

Browse files
committed
[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.
1 parent e806fd2 commit 9234eb3

File tree

7 files changed

+126
-6
lines changed

7 files changed

+126
-6
lines changed

include/swift/Serialization/SerializedSILLoader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class SerializedSILLoader {
9494
SILFunction *
9595
lookupSILFunction(StringRef Name, bool declarationOnly = false,
9696
SILLinkage linkage = SILLinkage::Private);
97+
bool hasSILFunction(StringRef Name, SILLinkage linkage = SILLinkage::Private);
9798
SILVTable *lookupVTable(Identifier Name);
9899
SILVTable *lookupVTable(const ClassDecl *C) {
99100
return lookupVTable(C->getName());

lib/SIL/Linker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ SILFunction *SILLinkerVisitor::lookupFunction(StringRef Name,
139139
return NewFn;
140140
}
141141

142+
/// Process Decl, recursively deserializing any thing Decl may reference.
143+
bool SILLinkerVisitor::hasFunction(StringRef Name, SILLinkage Linkage) {
144+
return Loader->hasSILFunction(Name, Linkage);
145+
}
142146

143147
/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
144148
/// transitively references.

lib/SIL/Linker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ class SILLinkerVisitor : public SILInstructionVisitor<SILLinkerVisitor, bool> {
5858
/// this Name.
5959
SILFunction *lookupFunction(StringRef Name, SILLinkage Linkage);
6060

61+
/// Process Name, try to check if there is a declaration of a function
62+
/// with this Name.
63+
bool hasFunction(StringRef Name, SILLinkage Linkage);
64+
6165
/// Process Decl, recursively deserializing any thing that
6266
/// the SILFunction corresponding to Decl may reference.
6367
bool processDeclRef(SILDeclRef Decl);

lib/SIL/SILModule.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -484,12 +484,48 @@ bool SILModule::linkFunction(StringRef Name, SILModule::LinkingMode Mode) {
484484
}
485485

486486
SILFunction *SILModule::hasFunction(StringRef Name, SILLinkage Linkage) {
487-
assert(!lookUpFunction(Name) && "hasFunction should be only called for "
488-
"functions that are not contained in the "
489-
"SILModule yet");
490-
return SILLinkerVisitor(*this, getSILLoader(),
491-
SILModule::LinkingMode::LinkNormal)
492-
.lookupFunction(Name, Linkage);
487+
SILFunction *F = lookUpFunction(Name);
488+
489+
assert((Linkage == SILLinkage::Public ||
490+
Linkage == SILLinkage::PublicExternal) &&
491+
"Only a lookup of public functions is supported currently");
492+
493+
// Nothing to do if the current module has a required function
494+
// with a proper linkage.
495+
if (F && F->getLinkage() == Linkage)
496+
return F;
497+
498+
assert((!F || F->getLinkage() != Linkage) &&
499+
"hasFunction should be only called for functions that are not "
500+
"contained in the SILModule yet or do not have a required linkage");
501+
(void)F;
502+
503+
SILLinkerVisitor Visitor(*this, getSILLoader(),
504+
SILModule::LinkingMode::LinkNormal);
505+
506+
if (Visitor.hasFunction(Name, Linkage)) {
507+
if (!F) {
508+
// Load the function.
509+
F = Visitor.lookupFunction(Name, Linkage);
510+
assert(F && "Function should be present");
511+
assert(F->getLinkage() == Linkage &&
512+
"SILFunction has a wrong linkage");
513+
}
514+
// If a function exists already and it is a non-optimizing
515+
// compilaiton, simply convert it into an external declaration,
516+
// so that a compiled version from the shared library is used.
517+
if (F->isDefinition() &&
518+
F->getModule().getOptions().Optimization <
519+
SILOptions::SILOptMode::Optimize) {
520+
F->convertToDeclaration();
521+
}
522+
if (F->isExternalDeclaration())
523+
F->setFragile(IsFragile_t::IsNotFragile);
524+
F->setLinkage(Linkage);
525+
} else {
526+
F = nullptr;
527+
}
528+
return F;
493529
}
494530

495531
void SILModule::linkAllWitnessTables() {

lib/Serialization/DeserializeSIL.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,68 @@ SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) {
17981798
return Func;
17991799
}
18001800

1801+
/// Check for existence of a function with a given name and required linkage.
1802+
/// This function is modelled after readSILFunction. But it does not
1803+
/// create a SILFunction object.
1804+
bool SILDeserializer::hasSILFunction(StringRef Name,
1805+
SILLinkage Linkage) {
1806+
if (!FuncTable)
1807+
return false;
1808+
auto iter = FuncTable->find(Name);
1809+
if (iter == FuncTable->end())
1810+
return false;
1811+
1812+
// There is a function with the required name.
1813+
// Find out which linkage it has.
1814+
auto FID = *iter;
1815+
auto &cacheEntry = Funcs[FID-1];
1816+
if (cacheEntry.isFullyDeserialized() ||
1817+
(cacheEntry.isDeserialized()))
1818+
return cacheEntry.get()->getLinkage() == Linkage ||
1819+
Linkage == SILLinkage::Private;
1820+
1821+
BCOffsetRAII restoreOffset(SILCursor);
1822+
SILCursor.JumpToBit(cacheEntry.getOffset());
1823+
1824+
auto entry = SILCursor.advance(AF_DontPopBlockAtEnd);
1825+
if (entry.Kind == llvm::BitstreamEntry::Error) {
1826+
DEBUG(llvm::dbgs() << "Cursor advance error in hasSILFunction.\n");
1827+
MF->error();
1828+
return false;
1829+
}
1830+
1831+
SmallVector<uint64_t, 64> scratch;
1832+
StringRef blobData;
1833+
unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData);
1834+
assert(kind == SIL_FUNCTION && "expect a sil function");
1835+
(void)kind;
1836+
1837+
// Read function properties only, e.g. its linkage and other attributes.
1838+
// TODO: If this results in any noticable performance problems, Cache the
1839+
// linkage to avoid re-reading it from the bitcode each time?
1840+
TypeID funcTyID;
1841+
unsigned rawLinkage, isTransparent, isFragile, isThunk, isGlobal,
1842+
inlineStrategy, effect, numSpecAttrs;
1843+
ArrayRef<uint64_t> SemanticsIDs;
1844+
SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isFragile,
1845+
isThunk, isGlobal, inlineStrategy, effect,
1846+
numSpecAttrs, funcTyID, SemanticsIDs);
1847+
auto linkage = fromStableSILLinkage(rawLinkage);
1848+
if (!linkage) {
1849+
DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
1850+
<< " for SIL function " << Name << "\n");
1851+
return false;
1852+
}
1853+
1854+
// Bail if it is not a required linkage.
1855+
if (linkage.getValue() != Linkage && Linkage != SILLinkage::Private)
1856+
return false;
1857+
1858+
DEBUG(llvm::dbgs() << "Found SIL Function: " << Name << "\n");
1859+
return true;
1860+
}
1861+
1862+
18011863
SILFunction *SILDeserializer::lookupSILFunction(StringRef name,
18021864
bool declarationOnly) {
18031865
if (!FuncTable)

lib/Serialization/DeserializeSIL.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ namespace swift {
117117
SILFunction *lookupSILFunction(SILFunction *InFunc);
118118
SILFunction *lookupSILFunction(StringRef Name,
119119
bool declarationOnly = false);
120+
bool hasSILFunction(StringRef Name, SILLinkage Linkage);
120121
SILVTable *lookupVTable(Identifier Name);
121122
SILWitnessTable *lookupWitnessTable(SILWitnessTable *wt);
122123
SILDefaultWitnessTable *

lib/Serialization/SerializedSILLoader.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,18 @@ SILFunction *SerializedSILLoader::lookupSILFunction(StringRef Name,
104104
return retVal;
105105
}
106106

107+
bool SerializedSILLoader::hasSILFunction(StringRef Name, SILLinkage Linkage) {
108+
// It is possible that one module has a declaration of a SILFunction, while
109+
// another has the full definition.
110+
SILFunction *retVal = nullptr;
111+
for (auto &Des : LoadedSILSections) {
112+
if (Des->hasSILFunction(Name, Linkage))
113+
return true;
114+
}
115+
return retVal;
116+
}
117+
118+
107119
SILVTable *SerializedSILLoader::lookupVTable(Identifier Name) {
108120
for (auto &Des : LoadedSILSections) {
109121
if (auto VT = Des->lookupVTable(Name))

0 commit comments

Comments
 (0)