blob: f556e1d27cea64bcf090f7bcd075820584e09789 [file] [log] [blame]
//===--- SILFunction.h - Defines the SILFunction class ----------*- C++ -*-===//
// This source file is part of the open source project
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
// See for license information
// See for the list of Swift project authors
// This file defines the SILFunction class.
#include "swift/AST/ASTNode.h"
#include "swift/AST/Availability.h"
#include "swift/AST/ResilienceExpansion.h"
#include "swift/Basic/ProfileCounter.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILLinkage.h"
#include "swift/SIL/SILPrintContext.h"
/// The symbol name used for the program entry point function.
namespace swift {
class ASTContext;
class SILInstruction;
class SILModule;
class SILFunctionBuilder;
class SILProfiler;
namespace Lowering {
class TypeLowering;
class AbstractionPattern;
enum IsBare_t { IsNotBare, IsBare };
enum IsTransparent_t { IsNotTransparent, IsTransparent };
enum Inline_t { InlineDefault, NoInline, AlwaysInline };
enum IsThunk_t {
enum IsDynamicallyReplaceable_t {
enum IsExactSelfClass_t {
class SILSpecializeAttr final {
friend SILFunction;
enum class SpecializationKind {
static SILSpecializeAttr *create(SILModule &M,
GenericSignature specializedSignature,
bool exported, SpecializationKind kind,
SILFunction *target, Identifier spiGroup,
const ModuleDecl *spiModule);
bool isExported() const {
return exported;
bool isFullSpecialization() const {
return kind == SpecializationKind::Full;
bool isPartialSpecialization() const {
return kind == SpecializationKind::Partial;
SpecializationKind getSpecializationKind() const {
return kind;
GenericSignature getSpecializedSignature() const {
return specializedSignature;
SILFunction *getFunction() const {
return F;
SILFunction *getTargetFunction() const {
return targetFunction;
Identifier getSPIGroup() const {
return spiGroup;
const ModuleDecl *getSPIModule() const {
return spiModule;
void print(llvm::raw_ostream &OS) const;
SpecializationKind kind;
bool exported;
GenericSignature specializedSignature;
Identifier spiGroup;
const ModuleDecl *spiModule = nullptr;
SILFunction *F = nullptr;
SILFunction *targetFunction = nullptr;
SILSpecializeAttr(bool exported, SpecializationKind kind,
GenericSignature specializedSignature, SILFunction *target,
Identifier spiGroup, const ModuleDecl *spiModule);
/// SILFunction - A function body that has been lowered to SIL. This consists of
/// zero or more SIL SILBasicBlock objects that contain the SILInstruction
/// objects making up the function.
class SILFunction
: public llvm::ilist_node<SILFunction>, public SILAllocated<SILFunction> {
using BlockListType = llvm::iplist<SILBasicBlock>;
// For more information see docs/SIL.rst
enum class Purpose : uint8_t {
friend class SILBasicBlock;
friend class SILModule;
friend class SILFunctionBuilder;
/// Module - The SIL module that the function belongs to.
SILModule &Module;
/// The mangled name of the SIL function, which will be propagated
/// to the binary. A pointer into the module's lookup table.
StringRef Name;
/// The lowered type of the function.
CanSILFunctionType LoweredType;
/// The context archetypes of the function.
GenericEnvironment *GenericEnv = nullptr;
/// The information about specialization.
/// Only set if this function is a specialization of another function.
const GenericSpecializationInformation *SpecializationInfo = nullptr;
/// The forwarding substitution map, lazily computed.
SubstitutionMap ForwardingSubMap;
/// The collection of all BasicBlocks in the SILFunction. Empty for external
/// function references.
BlockListType BlockList;
/// The owning declaration of this function's clang node, if applicable.
ValueDecl *ClangNodeOwner = nullptr;
/// The source location and scope of the function.
const SILDebugScope *DebugScope = nullptr;
/// The AST decl context of the function.
DeclContext *DeclCtxt = nullptr;
/// The profiler for instrumentation based profiling, or null if profiling is
/// disabled.
SILProfiler *Profiler = nullptr;
/// The function this function is meant to replace. Null if this is not a
/// @_dynamicReplacement(for:) function.
SILFunction *ReplacedFunction = nullptr;
Identifier ObjCReplacementFor;
/// The function's set of semantics attributes.
/// TODO: Why is this using a std::string? Why don't we use uniqued
/// StringRefs?
std::vector<std::string> SemanticsAttrSet;
/// The function's remaining set of specialize attributes.
std::vector<SILSpecializeAttr*> SpecializeAttrSet;
/// Has value if there's a profile for this function
/// Contains Function Entry Count
ProfileCounter EntryCount;
/// The availability used to determine if declarations of this function
/// should use weak linking.
AvailabilityContext Availability;
Purpose specialPurpose = Purpose::None;
/// This is the number of uses of this SILFunction inside the SIL.
/// It does not include references from debug scopes.
unsigned RefCount = 0;
/// The function's bare attribute. Bare means that the function is SIL-only
/// and does not require debug info.
unsigned Bare : 1;
/// The function's transparent attribute.
unsigned Transparent : 1;
/// The function's serialized attribute.
unsigned Serialized : 2;
/// Specifies if this function is a thunk or a reabstraction thunk.
/// The inliner uses this information to avoid inlining (non-trivial)
/// functions into the thunk.
unsigned Thunk : 2;
/// The scope in which the parent class can be subclassed, if this is a method
/// which is contained in the vtable of that class.
unsigned ClassSubclassScope : 2;
/// The function's global_init attribute.
unsigned GlobalInitFlag : 1;
/// The function's noinline attribute.
unsigned InlineStrategy : 2;
/// The linkage of the function.
unsigned Linkage : NumSILLinkageBits;
/// Set if the function may be referenced from C code and should thus be
/// preserved and exported more widely than its Swift linkage and usage
/// would indicate.
unsigned HasCReferences : 1;
/// Whether cross-module references to this function should always use
/// weak linking.
unsigned IsWeakImported : 1;
/// Whether the implementation can be dynamically replaced.
unsigned IsDynamicReplaceable : 1;
/// If true, this indicates that a class method implementation will always be
/// invoked with a `self` argument of the exact base class type.
unsigned ExactSelfClass : 1;
/// True if this function is inlined at least once. This means that the
/// debug info keeps a pointer to this function.
unsigned Inlined : 1;
/// True if this function is a zombie function. This means that the function
/// is dead and not referenced from anywhere inside the SIL. But it is kept
/// for other purposes:
/// *) It is inlined and the debug info keeps a reference to the function.
/// *) It is a dead method of a class which has higher visibility than the
/// method itself. In this case we need to create a vtable stub for it.
/// *) It is a function referenced by the specialization information.
unsigned Zombie : 1;
/// True if this function is in Ownership SSA form and thus must pass
/// ownership verification.
/// This enables the verifier to easily prove that before the Ownership Model
/// Eliminator runs on a function, we only see a non-semantic-arc world and
/// after the pass runs, we only see a semantic-arc world.
unsigned HasOwnership : 1;
/// Set if the function body was deserialized from canonical SIL. This implies
/// that the function's home module performed SIL diagnostics prior to
/// serialization.
unsigned WasDeserializedCanonical : 1;
/// True if this is a reabstraction thunk of escaping function type whose
/// single argument is a potentially non-escaping closure. This is an escape
/// hatch to allow non-escaping functions to be stored or passed as an
/// argument with escaping function type. The thunk argument's function type
/// is not necessarily @noescape. The only relevant aspect of the argument is
/// that it may have unboxed capture (i.e. @inout_aliasable parameters).
unsigned IsWithoutActuallyEscapingThunk : 1;
/// If != OptimizationMode::NotSet, the optimization mode specified with an
/// function attribute.
unsigned OptMode : NumOptimizationModeBits;
/// The function's effects attribute.
unsigned EffectsKindAttr : NumEffectsKindBits;
static void
validateSubclassScope(SubclassScope scope, IsThunk_t isThunk,
const GenericSpecializationInformation *genericInfo) {
#ifndef NDEBUG
// The _original_ function for a method can turn into a thunk through
// signature optimization, meaning it needs to retain its subclassScope, but
// other thunks and specializations are implementation details and so
// shouldn't be connected to their parent class.
bool thunkCanHaveSubclassScope;
switch (isThunk) {
case IsNotThunk:
case IsSignatureOptimizedThunk:
thunkCanHaveSubclassScope = true;
case IsThunk:
case IsReabstractionThunk:
thunkCanHaveSubclassScope = false;
auto allowsInterestingScopes = thunkCanHaveSubclassScope && !genericInfo;
allowsInterestingScopes ||
scope == SubclassScope::NotApplicable &&
"SubclassScope on specialization or non-signature-optimized thunk");
SILFunction(SILModule &module, SILLinkage linkage, StringRef mangledName,
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
Optional<SILLocation> loc, IsBare_t isBareSILFunction,
IsTransparent_t isTrans, IsSerialized_t isSerialized,
ProfileCounter entryCount, IsThunk_t isThunk,
SubclassScope classSubclassScope, Inline_t inlineStrategy,
EffectsKind E, const SILDebugScope *debugScope,
IsDynamicallyReplaceable_t isDynamic,
IsExactSelfClass_t isExactSelfClass);
static SILFunction *
create(SILModule &M, SILLinkage linkage, StringRef name,
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
Optional<SILLocation> loc, IsBare_t isBareSILFunction,
IsTransparent_t isTrans, IsSerialized_t isSerialized,
ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic,
IsExactSelfClass_t isExactSelfClass,
IsThunk_t isThunk = IsNotThunk,
SubclassScope classSubclassScope = SubclassScope::NotApplicable,
Inline_t inlineStrategy = InlineDefault,
EffectsKind EffectsKindAttr = EffectsKind::Unspecified,
SILFunction *InsertBefore = nullptr,
const SILDebugScope *DebugScope = nullptr);
void init(SILLinkage Linkage, StringRef Name,
CanSILFunctionType LoweredType,
GenericEnvironment *genericEnv,
Optional<SILLocation> Loc, IsBare_t isBareSILFunction,
IsTransparent_t isTrans, IsSerialized_t isSerialized,
ProfileCounter entryCount, IsThunk_t isThunk,
SubclassScope classSubclassScope,
Inline_t inlineStrategy, EffectsKind E,
const SILDebugScope *DebugScope,
IsDynamicallyReplaceable_t isDynamic,
IsExactSelfClass_t isExactSelfClass);
/// Set has ownership to the given value. True means that the function has
/// ownership, false means it does not.
/// Only for use by FunctionBuilders!
void setHasOwnership(bool newValue) { HasOwnership = newValue; }
SILModule &getModule() const { return Module; }
SILType getLoweredType() const {
return SILType::getPrimitiveObjectType(LoweredType);
CanSILFunctionType getLoweredFunctionType() const {
return LoweredType;
getLoweredFunctionTypeInContext(TypeExpansionContext context) const;
SILType getLoweredTypeInContext(TypeExpansionContext context) const {
return SILType::getPrimitiveObjectType(
SILFunctionConventions getConventions() const {
return SILFunctionConventions(LoweredType, getModule());
SILFunctionConventions getConventionsInContext() const {
auto fnType = getLoweredFunctionTypeInContext(getTypeExpansionContext());
return SILFunctionConventions(fnType, getModule());
SILProfiler *getProfiler() const { return Profiler; }
SILFunction *getDynamicallyReplacedFunction() const {
return ReplacedFunction;
void setDynamicallyReplacedFunction(SILFunction *f) {
assert(ReplacedFunction == nullptr && "already set");
if (f == nullptr)
ReplacedFunction = f;
/// This function should only be called when SILFunctions are bulk deleted.
void dropDynamicallyReplacedFunction() {
if (!ReplacedFunction)
ReplacedFunction = nullptr;
bool hasObjCReplacement() const {
return !ObjCReplacementFor.empty();
Identifier getObjCReplacement() const {
return ObjCReplacementFor;
void setObjCReplacement(AbstractFunctionDecl *replacedDecl);
void setObjCReplacement(Identifier replacedDecl);
void setProfiler(SILProfiler *InheritedProfiler) {
assert(!Profiler && "Function already has a profiler");
Profiler = InheritedProfiler;
void createProfiler(ASTNode Root, SILDeclRef forDecl,
ForDefinition_t forDefinition);
void discardProfiler() { Profiler = nullptr; }
ProfileCounter getEntryCount() const { return EntryCount; }
void setEntryCount(ProfileCounter Count) { EntryCount = Count; }
bool isNoReturnFunction(TypeExpansionContext context) const;
/// Unsafely rewrite the lowered type of this function.
/// This routine does not touch the entry block arguments
/// or return instructions; you need to do that yourself
/// if you care.
/// This routine does not update all the references in the module
/// You have to do that yourself
void rewriteLoweredTypeUnsafe(CanSILFunctionType newType) {
LoweredType = newType;
/// Return the number of entities referring to this function (other
/// than the SILModule).
unsigned getRefCount() const { return RefCount; }
/// Increment the reference count.
void incrementRefCount() {
assert(RefCount != 0 && "Overflow of reference count!");
/// Decrement the reference count.
void decrementRefCount() {
assert(RefCount != 0 && "Expected non-zero reference count on decrement!");
/// Drops all uses belonging to instructions in this function. The only valid
/// operation performable on this object after this is called is called the
/// destructor or deallocation.
void dropAllReferences() {
for (SILBasicBlock &BB : *this)
/// Notify that this function was inlined. This implies that it is still
/// needed for debug info generation, even if it is removed afterwards.
void setInlined() {
assert(!isZombie() && "Can't inline a zombie function");
Inlined = true;
/// Returns true if this function was inlined.
bool isInlined() const { return Inlined; }
/// Mark this function as removed from the module's function list, but kept
/// as "zombie" for debug info or vtable stub generation.
void setZombie() {
assert(!isZombie() && "Function is a zombie function already");
Zombie = true;
/// Returns true if this function is dead, but kept in the module's zombie list.
bool isZombie() const { return Zombie; }
/// Returns true if this function has qualified ownership instructions in it.
bool hasOwnership() const { return HasOwnership; }
/// Sets the HasOwnership flag to false. This signals to SIL that no
/// ownership instructions should be in this function any more.
void setOwnershipEliminated() { setHasOwnership(false); }
/// Returns true if this function was deserialized from canonical
/// SIL. (.swiftmodule files contain canonical SIL; .sib files may be 'raw'
/// SIL). If so, diagnostics should not be reapplied.
bool wasDeserializedCanonical() const { return WasDeserializedCanonical; }
void setWasDeserializedCanonical(bool val = true) {
WasDeserializedCanonical = val;
/// Returns true if this is a reabstraction thunk of escaping function type
/// whose single argument is a potentially non-escaping closure. i.e. the
/// thunks' function argument may itself have @inout_aliasable parameters.
bool isWithoutActuallyEscapingThunk() const {
return IsWithoutActuallyEscapingThunk;
void setWithoutActuallyEscapingThunk(bool val = true) {
assert(!val || isThunk() == IsReabstractionThunk);
IsWithoutActuallyEscapingThunk = val;
bool isAsync() const { return LoweredType->isAsync(); }
/// Returns the calling convention used by this entry point.
SILFunctionTypeRepresentation getRepresentation() const {
return getLoweredFunctionType()->getRepresentation();
ResilienceExpansion getResilienceExpansion() const {
return (isSerialized()
? ResilienceExpansion::Minimal
: ResilienceExpansion::Maximal);
// Returns the type expansion context to be used inside this function.
TypeExpansionContext getTypeExpansionContext() const {
return TypeExpansionContext(*this);
const Lowering::TypeLowering &
getTypeLowering(Lowering::AbstractionPattern orig, Type subst);
const Lowering::TypeLowering &getTypeLowering(Type t) const;
SILType getLoweredType(Lowering::AbstractionPattern orig, Type subst) const;
SILType getLoweredType(Type t) const;
SILType getLoweredLoadableType(Type t) const;
SILType getLoweredType(SILType t) const;
const Lowering::TypeLowering &getTypeLowering(SILType type) const;
bool isTypeABIAccessible(SILType type) const;
/// Returns true if this function has a calling convention that has a self
/// argument.
bool hasSelfParam() const {
return getLoweredFunctionType()->hasSelfParam();
/// Returns true if the function has parameters that are consumed by the
// callee.
bool hasOwnedParameters() const {
for (auto &ParamInfo : getLoweredFunctionType()->getParameters()) {
if (ParamInfo.isConsumed())
return true;
return false;
// Returns true if the function has indirect out parameters.
bool hasIndirectFormalResults() const {
return getLoweredFunctionType()->hasIndirectFormalResults();
/// Returns true if this function ie either a class method, or a
/// closure that captures the 'self' value or its metatype.
/// If this returns true, DynamicSelfType can be used in the body
/// of the function.
/// Note that this is not the same as hasSelfParam().
/// For closures that capture DynamicSelfType, hasDynamicSelfMetadata()
/// is true and hasSelfParam() is false. For methods on value types,
/// hasSelfParam() is true and hasDynamicSelfMetadata() is false.
bool hasDynamicSelfMetadata() const;
/// Return the mangled name of this SILFunction.
StringRef getName() const { return Name; }
/// A convenience function which checks if the function has a specific
/// \p name. It is equivalent to getName() == Name, but as it is not
/// inlined it can be called from the debugger.
bool hasName(const char *Name) const;
/// True if this is a declaration of a function defined in another module.
bool isExternalDeclaration() const { return BlockList.empty(); }
/// Returns true if this is a definition of a function defined in this module.
bool isDefinition() const { return !isExternalDeclaration(); }
/// Returns true if there exist pre-specializations.
bool hasPrespecialization() const;
/// Get this function's linkage attribute.
SILLinkage getLinkage() const { return SILLinkage(Linkage); }
/// Set the function's linkage attribute.
void setLinkage(SILLinkage linkage) { Linkage = unsigned(linkage); }
/// Returns true if this function can be inlined into a fragile function
/// body.
bool hasValidLinkageForFragileInline() const {
return (isSerialized() == IsSerialized ||
isSerialized() == IsSerializable);
/// Returns true if this function can be referenced from a fragile function
/// body.
bool hasValidLinkageForFragileRef() const;
/// Get's the effective linkage which is used to derive the llvm linkage.
/// Usually this is the same as getLinkage(), except in one case: if this
/// function is a method in a class which has higher visibility than the
/// method itself, the function can be referenced from vtables of derived
/// classes in other compilation units.
SILLinkage getEffectiveSymbolLinkage() const {
return effectiveLinkageForClassMember(getLinkage(),
/// Helper method which returns true if this function has "external" linkage.
bool isAvailableExternally() const {
return swift::isAvailableExternally(getLinkage());
/// Helper method which returns true if the linkage of the SILFunction
/// indicates that the object's definition might be required outside the
/// current SILModule.
bool isPossiblyUsedExternally() const;
/// In addition to isPossiblyUsedExternally() it returns also true if this
/// is a (private or internal) vtable method which can be referenced by
/// vtables of derived classes outside the compilation unit.
bool isExternallyUsedSymbol() const;
/// Return whether this function may be referenced by C code.
bool hasCReferences() const { return HasCReferences; }
void setHasCReferences(bool value) { HasCReferences = value; }
/// Returns the availability context used to determine if the function's
/// symbol should be weakly referenced across module boundaries.
AvailabilityContext getAvailabilityForLinkage() const {
return Availability;
void setAvailabilityForLinkage(AvailabilityContext availability) {
Availability = availability;
/// Returns whether this function's symbol must always be weakly referenced
/// across module boundaries.
bool isAlwaysWeakImported() const { return IsWeakImported; }
void setAlwaysWeakImported(bool value) {
IsWeakImported = value;
bool isWeakImported() const;
/// Returns whether this function implementation can be dynamically replaced.
IsDynamicallyReplaceable_t isDynamicallyReplaceable() const {
return IsDynamicallyReplaceable_t(IsDynamicReplaceable);
void setIsDynamic(IsDynamicallyReplaceable_t value = IsDynamic) {
IsDynamicReplaceable = value;
assert(!Transparent || !IsDynamicReplaceable);
IsExactSelfClass_t isExactSelfClass() const {
return IsExactSelfClass_t(ExactSelfClass);
void setIsExactSelfClass(IsExactSelfClass_t t) {
ExactSelfClass = t;
/// Get the DeclContext of this function.
DeclContext *getDeclContext() const { return DeclCtxt; }
/// \returns True if the function is marked with the @_semantics attribute
/// and has special semantics that the optimizer can use to optimize the
/// function.
bool hasSemanticsAttrs() const { return !SemanticsAttrSet.empty(); }
/// \returns True if the function has a semantic attribute that starts with a
/// specific string.
/// TODO: This needs a better name.
bool hasSemanticsAttrThatStartsWith(StringRef S) {
return count_if(getSemanticsAttrs(), [&S](const std::string &Attr) -> bool {
return StringRef(Attr).startswith(S);
/// \returns the semantics tag that describes this function.
ArrayRef<std::string> getSemanticsAttrs() const { return SemanticsAttrSet; }
/// \returns True if the function has the semantics flag \p Value;
bool hasSemanticsAttr(StringRef Value) const {
return count(SemanticsAttrSet, Value);
/// Add the given semantics attribute to the attr list set.
void addSemanticsAttr(StringRef Ref) {
if (hasSemanticsAttr(Ref))
std::sort(SemanticsAttrSet.begin(), SemanticsAttrSet.end());
/// Remove the semantics
void removeSemanticsAttr(StringRef Ref) {
auto Iter =
std::remove(SemanticsAttrSet.begin(), SemanticsAttrSet.end(), Ref);
/// \returns the range of specialize attributes.
ArrayRef<SILSpecializeAttr*> getSpecializeAttrs() const {
return SpecializeAttrSet;
/// Removes all specialize attributes from this function.
void clearSpecializeAttrs() {
[](SILFunction *targetFun) { targetFun->decrementRefCount(); });
void addSpecializeAttr(SILSpecializeAttr *Attr);
void removeSpecializeAttr(SILSpecializeAttr *attr);
void forEachSpecializeAttrTargetFunction(
llvm::function_ref<void(SILFunction *)> action);
/// Get this function's optimization mode or OptimizationMode::NotSet if it is
/// not set for this specific function.
OptimizationMode getOptimizationMode() const {
return OptimizationMode(OptMode);
/// Returns the optimization mode for the function. If no mode is set for the
/// function, returns the global mode, i.e. the mode of the module's options.
OptimizationMode getEffectiveOptimizationMode() const;
void setOptimizationMode(OptimizationMode mode) {
OptMode = unsigned(mode);
/// \returns True if the function is optimizable (i.e. not marked as no-opt),
/// or is raw SIL (so that the mandatory passes still run).
bool shouldOptimize() const;
/// Returns true if this function should be optimized for size.
bool optimizeForSize() const {
return getEffectiveOptimizationMode() == OptimizationMode::ForSize;
/// Returns true if this is a function that should have its ownership
/// verified.
bool shouldVerifyOwnership() const;
/// Check if the function has a location.
/// FIXME: All functions should have locations, so this method should not be
/// necessary.
bool hasLocation() const {
return DebugScope && !DebugScope->Loc.isNull();
/// Get the source location of the function.
SILLocation getLocation() const {
assert(DebugScope && "no scope/location");
return getDebugScope()->Loc;
/// Initialize the debug scope of the function and also set the DeclCtxt.
void setDebugScope(const SILDebugScope *DS) {
DebugScope = DS;
DeclCtxt = (DS ? DebugScope->Loc.getAsDeclContext() : nullptr);
/// Initialize the debug scope for debug info on SIL level (-gsil).
void setSILDebugScope(const SILDebugScope *DS) {
DebugScope = DS;
/// Get the source location of the function.
const SILDebugScope *getDebugScope() const { return DebugScope; }
/// Get this function's bare attribute.
IsBare_t isBare() const { return IsBare_t(Bare); }
void setBare(IsBare_t isB) { Bare = isB; }
/// Get this function's transparent attribute.
IsTransparent_t isTransparent() const { return IsTransparent_t(Transparent); }
void setTransparent(IsTransparent_t isT) {
Transparent = isT;
assert(!Transparent || !IsDynamicReplaceable);
/// Get this function's serialized attribute.
IsSerialized_t isSerialized() const { return IsSerialized_t(Serialized); }
void setSerialized(IsSerialized_t isSerialized) { Serialized = isSerialized; }
/// Get this function's thunk attribute.
IsThunk_t isThunk() const { return IsThunk_t(Thunk); }
void setThunk(IsThunk_t isThunk) {
validateSubclassScope(getClassSubclassScope(), isThunk, SpecializationInfo);
Thunk = isThunk;
/// Get the class visibility (relevant for class methods).
SubclassScope getClassSubclassScope() const {
return SubclassScope(ClassSubclassScope);
void setClassSubclassScope(SubclassScope scope) {
validateSubclassScope(scope, isThunk(), SpecializationInfo);
ClassSubclassScope = static_cast<unsigned>(scope);
/// Get this function's noinline attribute.
Inline_t getInlineStrategy() const { return Inline_t(InlineStrategy); }
void setInlineStrategy(Inline_t inStr) { InlineStrategy = inStr; }
/// \return the function side effects information.
EffectsKind getEffectsKind() const { return EffectsKind(EffectsKindAttr); }
/// \return True if the function is annotated with the @_effects attribute.
bool hasEffectsKind() const {
return EffectsKind(EffectsKindAttr) != EffectsKind::Unspecified;
/// Set the function side effect information.
void setEffectsKind(EffectsKind E) {
EffectsKindAttr = unsigned(E);
Purpose getSpecialPurpose() const { return specialPurpose; }
/// Get this function's global_init attribute.
/// The implied semantics are:
/// - side-effects can occur any time before the first invocation.
/// - all calls to the same global_init function have the same side-effects.
/// - any operation that may observe the initializer's side-effects must be
/// preceded by a call to the initializer.
/// This is currently true if the function is an addressor that was lazily
/// generated from a global variable access. Note that the initialization
/// function itself does not need this attribute. It is private and only
/// called within the addressor.
bool isGlobalInit() const { return specialPurpose == Purpose::GlobalInit; }
bool isGlobalInitOnceFunction() const {
return specialPurpose == Purpose::GlobalInitOnceFunction;
bool isLazyPropertyGetter() const {
return specialPurpose == Purpose::LazyPropertyGetter;
void setSpecialPurpose(Purpose purpose) { specialPurpose = purpose; }
/// Return whether this function has a foreign implementation which can
/// be emitted on demand.
bool hasForeignBody() const;
/// Return whether this function corresponds to a Clang node.
bool hasClangNode() const {
return ClangNodeOwner != nullptr;
/// Set the owning declaration of the Clang node associated with this
/// function. We have to store an owner (a Swift declaration) instead of
/// directly referencing the original declaration due to current
/// limitations in the serializer.
void setClangNodeOwner(ValueDecl *owner) {
ClangNodeOwner = owner;
/// Return the owning declaration of the Clang node associated with this
/// function. This should only be used for serialization.
ValueDecl *getClangNodeOwner() const {
return ClangNodeOwner;
/// Return the Clang node associated with this function if it has one.
ClangNode getClangNode() const {
return (ClangNodeOwner ? ClangNodeOwner->getClangNode() : ClangNode());
const clang::Decl *getClangDecl() const {
return (ClangNodeOwner ? ClangNodeOwner->getClangDecl() : nullptr);
/// Returns whether this function is a specialization.
bool isSpecialization() const { return SpecializationInfo != nullptr; }
/// Return the specialization information.
const GenericSpecializationInformation *getSpecializationInfo() const {
return SpecializationInfo;
void setSpecializationInfo(const GenericSpecializationInformation *Info) {
validateSubclassScope(getClassSubclassScope(), isThunk(), Info);
SpecializationInfo = Info;
/// If this function is a specialization, return the original function from
/// which this function was specialized.
const SILFunction *getOriginOfSpecialization() const;
/// Retrieve the generic environment containing the mapping from interface
/// types to context archetypes for this function. Only present if the
/// function has a body.
GenericEnvironment *getGenericEnvironment() const {
return GenericEnv;
void setGenericEnvironment(GenericEnvironment *env) {
GenericEnv = env;
/// Map the given type, which is based on an interface SILFunctionType and may
/// therefore be dependent, to a type based on the context archetypes of this
/// SILFunction.
Type mapTypeIntoContext(Type type) const;
/// Map the given type, which is based on an interface SILFunctionType and may
/// therefore be dependent, to a type based on the context archetypes of this
/// SILFunction.
SILType mapTypeIntoContext(SILType type) const;
/// Converts the given function definition to a declaration.
void convertToDeclaration();
/// Return the identity substitutions necessary to forward this call if it is
/// generic.
SubstitutionMap getForwardingSubstitutionMap();
// Block List Access
BlockListType &getBlocks() { return BlockList; }
const BlockListType &getBlocks() const { return BlockList; }
using iterator = BlockListType::iterator;
using reverse_iterator = BlockListType::reverse_iterator;
using const_iterator = BlockListType::const_iterator;
bool empty() const { return BlockList.empty(); }
iterator begin() { return BlockList.begin(); }
iterator end() { return BlockList.end(); }
reverse_iterator rbegin() { return BlockList.rbegin(); }
reverse_iterator rend() { return BlockList.rend(); }
const_iterator begin() const { return BlockList.begin(); }
const_iterator end() const { return BlockList.end(); }
unsigned size() const { return BlockList.size(); }
SILBasicBlock &front() { return *begin(); }
const SILBasicBlock &front() const { return *begin(); }
SILBasicBlock *getEntryBlock() { return &front(); }
const SILBasicBlock *getEntryBlock() const { return &front(); }
SILBasicBlock *createBasicBlock();
SILBasicBlock *createBasicBlockAfter(SILBasicBlock *afterBB);
SILBasicBlock *createBasicBlockBefore(SILBasicBlock *beforeBB);
/// Splice the body of \p F into this function at end.
void spliceBody(SILFunction *F) {
getBlocks().splice(begin(), F->getBlocks());
/// Return the unique basic block containing a return inst if it
/// exists. Otherwise, returns end.
iterator findReturnBB() {
return std::find_if(begin(), end(),
[](const SILBasicBlock &BB) -> bool {
const TermInst *TI = BB.getTerminator();
return isa<ReturnInst>(TI);
/// Return the unique basic block containing a return inst if it
/// exists. Otherwise, returns end.
const_iterator findReturnBB() const {
return std::find_if(begin(), end(),
[](const SILBasicBlock &BB) -> bool {
const TermInst *TI = BB.getTerminator();
return isa<ReturnInst>(TI);
/// Return the unique basic block containing a throw inst if it
/// exists. Otherwise, returns end.
iterator findThrowBB() {
return std::find_if(begin(), end(),
[](const SILBasicBlock &BB) -> bool {
const TermInst *TI = BB.getTerminator();
return isa<ThrowInst>(TI);
/// Return the unique basic block containing a throw inst if it
/// exists. Otherwise, returns end.
const_iterator findThrowBB() const {
return std::find_if(begin(), end(),
[](const SILBasicBlock &BB) -> bool {
const TermInst *TI = BB.getTerminator();
return isa<ThrowInst>(TI);
/// Loop over all blocks in this function and add all function exiting blocks
/// to output.
void findExitingBlocks(llvm::SmallVectorImpl<SILBasicBlock *> &output) const {
for (auto &Block : const_cast<SILFunction &>(*this)) {
if (Block.getTerminator()->isFunctionExiting()) {
// Argument Helper Methods
SILArgument *getArgument(unsigned i) {
assert(!empty() && "Cannot get argument of a function without a body");
return begin()->getArgument(i);
const SILArgument *getArgument(unsigned i) const {
assert(!empty() && "Cannot get argument of a function without a body");
return begin()->getArgument(i);
ArrayRef<SILArgument *> getArguments() const {
assert(!empty() && "Cannot get arguments of a function without a body");
return begin()->getArguments();
ArrayRef<SILArgument *> getIndirectResults() const {
assert(!empty() && "Cannot get arguments of a function without a body");
return begin()->getArguments().slice(
0, getConventions().getNumIndirectSILResults());
ArrayRef<SILArgument *> getArgumentsWithoutIndirectResults() const {
assert(!empty() && "Cannot get arguments of a function without a body");
return begin()->getArguments().slice(
const SILArgument *getSelfArgument() const {
assert(hasSelfParam() && "This method can only be called if the "
"SILFunction has a self parameter");
return getArguments().back();
const SILArgument *getDynamicSelfMetadata() const {
assert(hasDynamicSelfMetadata() && "This method can only be called if the "
"SILFunction has a self-metadata parameter");
return getArguments().back();
// Miscellaneous
/// verify - Run the IR verifier to make sure that the SILFunction follows
/// invariants.
void verify(bool SingleFunction = true) const;
/// Run the SIL ownership verifier to check for ownership invariant failures.
/// NOTE: The ownership verifier is always run when performing normal IR
/// verification, so this verification can be viewed as a subset of
/// SILFunction::verify.
void verifyOwnership(DeadEndBlocks *deadEndBlocks) const;
/// Verify that all non-cond-br critical edges have been split.
/// This is a fast subset of the checks performed in the SILVerifier.
void verifyCriticalEdges() const;
/// Pretty-print the SILFunction.
void dump(bool Verbose) const;
void dump() const;
/// Pretty-print the SILFunction.
/// Useful for dumping the function when running in a debugger.
/// Warning: no error handling is done. Fails with an assert if the file
/// cannot be opened.
void dump(const char *FileName) const;
/// Pretty-print the SILFunction to the tream \p OS.
/// \param Verbose Dump SIL location information in verbose mode.
void print(raw_ostream &OS, bool Verbose = false) const {
SILPrintContext PrintCtx(OS, Verbose);
/// Pretty-print the SILFunction with the context \p PrintCtx.
void print(SILPrintContext &PrintCtx) const;
/// Pretty-print the SILFunction's name using SIL syntax,
/// '@function_mangled_name'.
void printName(raw_ostream &OS) const;
/// Assigns consecutive numbers to all the SILNodes in the function.
/// For instructions, both the instruction node and the value nodes of
/// any results will be assigned numbers; the instruction node will
/// be numbered the same as the first result, if there are any results.
void numberValues(llvm::DenseMap<const SILNode*, unsigned> &nodeToNumberMap)
ASTContext &getASTContext() const;
/// This function is meant for use from the debugger. You can just say 'call
/// F->viewCFG()' and a ghostview window should pop up from the program,
/// displaying the CFG of the current function with the code for each basic
/// block inside. This depends on there being a 'dot' and 'gv' program in
/// your path.
void viewCFG() const;
/// Like ViewCFG, but the graph does not show the contents of basic blocks.
void viewCFGOnly() const;
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const SILFunction &F) {
return OS;
} // end swift namespace
// ilist_traits for SILFunction
namespace llvm {
template <>
struct ilist_traits<::swift::SILFunction> :
public ilist_node_traits<::swift::SILFunction> {
using SILFunction = ::swift::SILFunction;
static void deleteNode(SILFunction *V) { V->~SILFunction(); }
void createNode(const SILFunction &);
} // end llvm namespace