Skip to content

SIL: Introduce has_symbol instruction #62147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7882,3 +7882,16 @@ IRGen will replace the application by the constant representing Debug mode (0).
This happens we can build the standard library .dylib. The generate sil will
retain the function call but the generated .dylib will contain code with
assertions enabled.

Weak linking support
~~~~~~~~~~~~~~~~~~~~~~~

has_symbol
```````````````````````````
::

sil-instruction ::= 'has_symbol' sil-decl-ref

Returns true if each of the underlying symbol addresses associated with the
given declaration are non-null. This can be used to determine whether a
weakly-imported declaration is available at runtime.
5 changes: 0 additions & 5 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2790,11 +2790,6 @@ class ValueDecl : public Decl {
/// 'func foo(Int) -> () -> Self?'.
GenericParameterReferenceInfo findExistentialSelfReferences(
Type baseTy, bool treatNonResultCovariantSelfAsInvariant) const;

/// Returns a synthesized declaration for a query function that provides
/// the boolean value for a `if #_hasSymbol(...)` condition. The interface
/// type of the function is `() -> Builtin.Int1`.
FuncDecl *getHasSymbolQueryDecl() const;
};

/// This is a common base class for declarations which declare a type.
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -6029,9 +6029,6 @@ ERROR(availability_macro_in_inlinable, none,
"availability macro cannot be used in " FRAGILE_FUNC_KIND "0",
(unsigned))

ERROR(has_symbol_condition_in_inlinable, none,
"'#_hasSymbol' cannot be used in " FRAGILE_FUNC_KIND "0", (unsigned))

#undef FRAGILE_FUNC_KIND

NOTE(resilience_decl_declared_here_public,
Expand Down
18 changes: 0 additions & 18 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -3715,24 +3715,6 @@ class GetTypeWrapperInitializer
bool isCached() const { return true; }
};

/// Synthesizes and returns a `#_hasSymbol` query function for the given
/// `ValueDecl`. The function has an interface type of `() -> Builtin.Int1`.
class SynthesizeHasSymbolQueryRequest
: public SimpleRequest<SynthesizeHasSymbolQueryRequest,
FuncDecl *(const ValueDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

FuncDecl *evaluate(Evaluator &evaluator, const ValueDecl *decl) const;

public:
bool isCached() const { return true; }
};

/// Lookup all macros with the given name that are visible from the given
/// module.
class MacroLookupRequest
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -437,9 +437,6 @@ SWIFT_REQUEST(TypeChecker, SynthesizeLocalVariableForTypeWrapperStorage,
SWIFT_REQUEST(TypeChecker, GetTypeWrapperInitializer,
ConstructorDecl *(NominalTypeDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SynthesizeHasSymbolQueryRequest,
FuncDecl *(ValueDecl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, MacroLookupRequest,
ArrayRef<Macro *>(Identifier, ModuleDecl *),
Cached, NoLocationInfo)
8 changes: 8 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2725,6 +2725,14 @@ class SILBuilder {
FunctionType));
}

//===--------------------------------------------------------------------===//
// Weak linking support
//===--------------------------------------------------------------------===//
HasSymbolInst *createHasSymbol(SILLocation Loc, ValueDecl *Decl) {
return insert(new (getModule()) HasSymbolInst(
getModule(), getSILDebugLocation(Loc), Decl));
}

//===--------------------------------------------------------------------===//
// Private Helper Methods
//===--------------------------------------------------------------------===//
Expand Down
8 changes: 8 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -3103,6 +3103,14 @@ ::visitExtractExecutorInst(ExtractExecutorInst *Inst) {
getOpValue(Inst->getExpectedExecutor())));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitHasSymbolInst(HasSymbolInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(
Inst, getBuilder().createHasSymbol(getOpLocation(Inst->getLoc()),
Inst->getDecl()));
}

} // end namespace swift

#endif
26 changes: 26 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4086,6 +4086,32 @@ class StringLiteralInst final
MutableArrayRef<Operand> getAllOperands() { return {}; }
};

/// HasSymbolInst - Determines whether a weakly-imported declaration is
/// available at runtime. Produces true if each of the underlying symbol
/// addresses associated with a given declaration are non-null, false otherwise.
class HasSymbolInst final : public LiteralInst {
private:
friend SILBuilder;

ValueDecl *Decl;

public:
HasSymbolInst(SILModule &M, SILDebugLocation Loc, ValueDecl *Decl)
: LiteralInst(SILInstructionKind::HasSymbolInst, Loc,
SILType::getBuiltinIntegerType(1, Decl->getASTContext())),
Decl{Decl} {}

ValueDecl *getDecl() const { return Decl; }
void getReferencedFunctions(llvm::SmallVector<SILFunction *, 4> &fns) const;

ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; }

static bool classof(SILNodePointer node) {
return node->getKind() == SILNodeKind::HasSymbolInst;
}
};

//===----------------------------------------------------------------------===//
// Memory instructions.
//===----------------------------------------------------------------------===//
Expand Down
9 changes: 0 additions & 9 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,6 @@ class SILModule {
/// This is the set of undef values we've created, for uniquing purposes.
llvm::DenseMap<SILType, SILUndef *> UndefValues;

/// The list of decls that require query functions for #_hasSymbol conditions.
llvm::SetVector<ValueDecl *> hasSymbolDecls;

llvm::DenseMap<std::pair<Decl *, VarDecl *>, unsigned> fieldIndices;
llvm::DenseMap<EnumElementDecl *, unsigned> enumCaseIndices;

Expand Down Expand Up @@ -703,12 +700,6 @@ class SILModule {
return externallyVisible.count(decl) != 0;
}

void addHasSymbolDecl(ValueDecl *decl) { hasSymbolDecls.insert(decl); }

ArrayRef<ValueDecl *> getHasSymbolDecls() {
return hasSymbolDecls.getArrayRef();
}

using sil_global_iterator = GlobalListType::iterator;
using sil_global_const_iterator = GlobalListType::const_iterator;
GlobalListType &getSILGlobalList() { return silGlobals; }
Expand Down
4 changes: 3 additions & 1 deletion include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,9 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
LiteralInst, None, DoesNotRelease)
SINGLE_VALUE_INST(StringLiteralInst, string_literal,
LiteralInst, None, DoesNotRelease)
SINGLE_VALUE_INST_RANGE(LiteralInst, FunctionRefInst, StringLiteralInst)
SINGLE_VALUE_INST(HasSymbolInst, has_symbol,
LiteralInst, MayRead, DoesNotRelease)
SINGLE_VALUE_INST_RANGE(LiteralInst, FunctionRefInst, HasSymbolInst)

// Dynamic Dispatch
ABSTRACT_SINGLE_VALUE_INST(MethodInst, SingleValueInstruction)
Expand Down
28 changes: 28 additions & 0 deletions include/swift/SIL/SILSymbolVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/AST/ProtocolAssociations.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILModule.h"

namespace swift {

Expand Down Expand Up @@ -126,6 +127,33 @@ class SILSymbolVisitor {
virtual void addTypeMetadataAddress(CanType T) {}
};

template <typename F>
void enumerateFunctionsForHasSymbol(SILModule &M, ValueDecl *D, F Handler) {
class SymbolVisitor : public SILSymbolVisitor {
F Handler;

public:
SymbolVisitor(F Handler) : Handler{Handler} {};

void addFunction(SILDeclRef declRef) override { Handler(declRef); }

virtual void addFunction(StringRef name, SILDeclRef declRef) override {
// The kinds of functions which go through this callback (e.g.
// differentiability witnesses) have custom manglings and are incompatible
// with #_hasSymbol currently.
//
// Ideally, this callback will be removed entirely in favor of SILDeclRef
// being able to represent all function variants with no special cases
// required.
}
};

SILSymbolVisitorOptions opts;
opts.VisitMembers = false;
auto visitorCtx = SILSymbolVisitorContext(M.getSwiftModule(), opts);
SymbolVisitor(Handler).visitDecl(D, visitorCtx);
}

} // end namespace swift

#endif
83 changes: 39 additions & 44 deletions lib/IRGen/GenHasSymbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,48 +86,43 @@ class HasSymbolIRGenVisitor : public IRSymbolVisitor {
}
};

void IRGenModule::emitHasSymbolFunctions() {
SILSymbolVisitorOptions opts;
opts.VisitMembers = false;
auto silCtx = SILSymbolVisitorContext(getSwiftModule(), opts);
auto linkInfo = UniversalLinkageInfo(*this);
auto symbolVisitorCtx = IRSymbolVisitorContext(linkInfo, silCtx);

for (ValueDecl *decl : getSILModule().getHasSymbolDecls()) {
PrettyStackTraceDecl trace("emitting #_hasSymbol query for", decl);
Mangle::ASTMangler mangler;

auto func = cast<llvm::Function>(getOrCreateHelperFunction(
mangler.mangleHasSymbolQuery(decl), Int1Ty, {},
[decl, this, symbolVisitorCtx](IRGenFunction &IGF) {
auto &Builder = IGF.Builder;
llvm::SmallVector<llvm::Constant *, 4> addrs;
HasSymbolIRGenVisitor(*this, addrs).visit(decl, symbolVisitorCtx);

llvm::Value *ret = nullptr;
for (llvm::Constant *addr : addrs) {
assert(cast<llvm::GlobalValue>(addr)->hasExternalWeakLinkage());

auto isNonNull = IGF.Builder.CreateIsNotNull(addr);
ret = (ret) ? IGF.Builder.CreateAnd(ret, isNonNull) : isNonNull;
}

if (ret) {
Builder.CreateRet(ret);
} else {
// There were no addresses produced by the visitor, return true.
Builder.CreateRet(llvm::ConstantInt::get(Int1Ty, 1));
}
},
/*IsNoInline*/ false));

func->setDoesNotThrow();
func->setCallingConv(SwiftCC);
func->addFnAttr(llvm::Attribute::ReadOnly);
}
}

void IRGenerator::emitHasSymbolFunctions() {
for (auto &IGM : *this)
IGM.second->emitHasSymbolFunctions();
llvm::Function *IRGenModule::emitHasSymbolFunction(ValueDecl *decl) {

PrettyStackTraceDecl trace("emitting #_hasSymbol query for", decl);
Mangle::ASTMangler mangler;

auto func = cast<llvm::Function>(getOrCreateHelperFunction(
mangler.mangleHasSymbolQuery(decl), Int1Ty, {},
[decl, this](IRGenFunction &IGF) {
SILSymbolVisitorOptions opts;
opts.VisitMembers = false;
auto silCtx = SILSymbolVisitorContext(getSwiftModule(), opts);
auto linkInfo = UniversalLinkageInfo(*this);
auto symbolVisitorCtx = IRSymbolVisitorContext(linkInfo, silCtx);
auto &Builder = IGF.Builder;
llvm::SmallVector<llvm::Constant *, 4> addrs;
HasSymbolIRGenVisitor(*this, addrs).visit(decl, symbolVisitorCtx);

llvm::Value *ret = nullptr;
for (llvm::Constant *addr : addrs) {
assert(cast<llvm::GlobalValue>(addr)->hasExternalWeakLinkage());

auto isNonNull = IGF.Builder.CreateIsNotNull(addr);
ret = (ret) ? IGF.Builder.CreateAnd(ret, isNonNull) : isNonNull;
}

if (ret) {
Builder.CreateRet(ret);
} else {
// There were no addresses produced by the visitor, return true.
Builder.CreateRet(llvm::ConstantInt::get(Int1Ty, 1));
}
},
/*IsNoInline*/ false));

func->setDoesNotThrow();
func->setCallingConv(DefaultCC);
func->addFnAttr(llvm::Attribute::ReadOnly);

return func;
}
3 changes: 0 additions & 3 deletions lib/IRGen/IRGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,9 +1348,6 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator,
// Okay, emit any definitions that we suddenly need.
irgen.emitLazyDefinitions();

// Emit functions supporting `if #_hasSymbol(...)` conditions.
IGM.emitHasSymbolFunctions();

// Register our info with the runtime if needed.
if (Opts.UseJIT) {
IGM.emitBuiltinReflectionMetadata();
Expand Down
5 changes: 1 addition & 4 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,6 @@ class IRGenerator {
/// Emit coverage mapping info.
void emitCoverageMapping();

/// Emit helper functions for `if #_hasSymbol(...)` conditions.
void emitHasSymbolFunctions();

/// Checks if metadata for this type can be emitted lazily. This is true for
/// non-public types as well as imported types, except for classes and
/// protocols which are always emitted eagerly.
Expand Down Expand Up @@ -1832,7 +1829,7 @@ private: \
void emitRuntimeRegistration();
void emitVTableStubs();
void emitTypeVerifier();
void emitHasSymbolFunctions();
llvm::Function *emitHasSymbolFunction(ValueDecl *decl);

/// Create llvm metadata which encodes the branch weights given by
/// \p TrueCount and \p FalseCount.
Expand Down
11 changes: 11 additions & 0 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,8 @@ class IRGenSILFunction :
llvm_unreachable("test-only instruction in Lowered SIL?!");
}

void visitHasSymbolInst(HasSymbolInst *i);

#define LOADABLE_REF_STORAGE_HELPER(Name) \
void visitRefTo##Name##Inst(RefTo##Name##Inst *i); \
void visit##Name##ToRefInst(Name##ToRefInst *i); \
Expand Down Expand Up @@ -2611,6 +2613,15 @@ void IRGenSILFunction::visitDifferentiabilityWitnessFunctionInst(
i, FunctionPointer::createUnsigned(fnType, diffWitness, signature, true));
}

void IRGenSILFunction::visitHasSymbolInst(HasSymbolInst *i) {
auto fn = IGM.emitHasSymbolFunction(i->getDecl());
llvm::CallInst *call = Builder.CreateCall(fn->getFunctionType(), fn, {});

Explosion e;
e.add(call);
setLoweredValue(i, e);
}

FunctionPointer::Kind irgen::classifyFunctionPointerKind(SILFunction *fn) {
using SpecialKind = FunctionPointer::SpecialKind;

Expand Down
1 change: 1 addition & 0 deletions lib/SIL/IR/OperandOwnership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ SHOULD_NEVER_VISIT_INST(PreviousDynamicFunctionRef)
SHOULD_NEVER_VISIT_INST(GlobalAddr)
SHOULD_NEVER_VISIT_INST(GlobalValue)
SHOULD_NEVER_VISIT_INST(BaseAddrForOffset)
SHOULD_NEVER_VISIT_INST(HasSymbol)
SHOULD_NEVER_VISIT_INST(IntegerLiteral)
SHOULD_NEVER_VISIT_INST(Metatype)
SHOULD_NEVER_VISIT_INST(ObjCProtocol)
Expand Down
11 changes: 11 additions & 0 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "swift/SIL/SILCloner.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILSymbolVisitor.h"
#include "swift/SIL/SILVisitor.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
Expand Down Expand Up @@ -2993,3 +2994,13 @@ SILPhiArgument *SwitchEnumInst::createOptionalSomeResult() {
auto someBB = getCaseDestination(someDecl);
return createResult(someBB, getOperand()->getType().unwrapOptionalType());
}

void HasSymbolInst::getReferencedFunctions(
llvm::SmallVector<SILFunction *, 4> &fns) const {
auto &M = getModule();
enumerateFunctionsForHasSymbol(M, getDecl(), [&M, &fns](SILDeclRef declRef) {
SILFunction *fn = M.lookUpFunction(declRef);
assert(fn);
fns.push_back(fn);
});
}
5 changes: 5 additions & 0 deletions lib/SIL/IR/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2860,6 +2860,11 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
*this << dwfi->getType();
}
}

void visitHasSymbolInst(HasSymbolInst *hsi) {
*this << "#";
printValueDecl(hsi->getDecl(), PrintState.OS);
}
};

} // namespace swift
Expand Down
Loading