mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* When constructing instructions which have substitution maps: initialize those with the canonical SubstitutionMap * Also initialize SILFunction::ForwardingSubMap with the canonical one Non-canonical substitution maps may prevent generic specializations. This fixes a problem in Embedded Swift where an error is given because a function cannot be specialized, although it should. https://github.com/swiftlang/swift/issues/83895 rdar://159065157
1823 lines
64 KiB
C++
1823 lines
64 KiB
C++
//===--- SILFunction.h - Defines the SILFunction class ----------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org 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 https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the SILFunction class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SIL_SILFUNCTION_H
|
|
#define SWIFT_SIL_SILFUNCTION_H
|
|
|
|
#include "swift/AST/ASTNode.h"
|
|
#include "swift/AST/AvailabilityRange.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/AST/ResilienceExpansion.h"
|
|
#include "swift/Basic/ProfileCounter.h"
|
|
#include "swift/Basic/SwiftObjectHeader.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"
|
|
#include "swift/SIL/SILUndef.h"
|
|
#include "llvm/ADT/MapVector.h"
|
|
|
|
namespace swift {
|
|
|
|
class ASTContext;
|
|
class SILInstruction;
|
|
class SILModule;
|
|
class SILFunctionBuilder;
|
|
class SILProfiler;
|
|
class BasicBlockBitfield;
|
|
class NodeBitfield;
|
|
class OperandBitfield;
|
|
class CalleeCache;
|
|
class SILTypeProperties;
|
|
class SILUndef;
|
|
|
|
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 {
|
|
IsNotThunk,
|
|
IsThunk,
|
|
IsReabstractionThunk,
|
|
IsSignatureOptimizedThunk,
|
|
IsBackDeployedThunk,
|
|
};
|
|
enum IsDynamicallyReplaceable_t {
|
|
IsNotDynamic,
|
|
IsDynamic
|
|
};
|
|
enum IsExactSelfClass_t {
|
|
IsNotExactSelfClass,
|
|
IsExactSelfClass,
|
|
};
|
|
enum IsDistributed_t {
|
|
IsNotDistributed,
|
|
IsDistributed,
|
|
};
|
|
enum IsRuntimeAccessible_t {
|
|
IsNotRuntimeAccessible,
|
|
IsRuntimeAccessible
|
|
};
|
|
|
|
enum ForceEnableLexicalLifetimes_t {
|
|
DoNotForceEnableLexicalLifetimes,
|
|
DoForceEnableLexicalLifetimes
|
|
};
|
|
|
|
enum UseStackForPackMetadata_t {
|
|
DoNotUseStackForPackMetadata,
|
|
DoUseStackForPackMetadata,
|
|
};
|
|
|
|
enum class PerformanceConstraints : uint8_t {
|
|
None = 0,
|
|
NoAllocation = 1,
|
|
NoLocks = 2,
|
|
NoRuntime = 3,
|
|
NoExistentials = 4,
|
|
NoObjCBridging = 5
|
|
};
|
|
|
|
class SILSpecializeAttr final {
|
|
friend SILFunction;
|
|
public:
|
|
enum class SpecializationKind {
|
|
Full,
|
|
Partial
|
|
};
|
|
|
|
static GenericSignature buildTypeErasedSignature(
|
|
GenericSignature sig, ArrayRef<Type> typeErasedParams);
|
|
|
|
static SILSpecializeAttr *
|
|
create(SILModule &M, GenericSignature specializedSignature,
|
|
ArrayRef<Type> typeErasedParams, bool exported,
|
|
SpecializationKind kind, SILFunction *target, Identifier spiGroup,
|
|
const ModuleDecl *spiModule, AvailabilityRange availability);
|
|
|
|
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;
|
|
}
|
|
|
|
GenericSignature getUnerasedSpecializedSignature() const {
|
|
return unerasedSpecializedSignature;
|
|
}
|
|
|
|
ArrayRef<Type> getTypeErasedParams() const {
|
|
return typeErasedParams;
|
|
}
|
|
|
|
SILFunction *getFunction() const {
|
|
return F;
|
|
}
|
|
|
|
SILFunction *getTargetFunction() const {
|
|
return targetFunction;
|
|
}
|
|
|
|
Identifier getSPIGroup() const {
|
|
return spiGroup;
|
|
}
|
|
|
|
const ModuleDecl *getSPIModule() const {
|
|
return spiModule;
|
|
}
|
|
|
|
AvailabilityRange getAvailability() const {
|
|
return availability;
|
|
}
|
|
|
|
void print(llvm::raw_ostream &OS) const;
|
|
|
|
private:
|
|
SpecializationKind kind;
|
|
bool exported;
|
|
GenericSignature specializedSignature;
|
|
GenericSignature unerasedSpecializedSignature;
|
|
llvm::SmallVector<Type, 2> typeErasedParams;
|
|
Identifier spiGroup;
|
|
AvailabilityRange availability;
|
|
const ModuleDecl *spiModule = nullptr;
|
|
SILFunction *F = nullptr;
|
|
SILFunction *targetFunction = nullptr;
|
|
|
|
SILSpecializeAttr(bool exported, SpecializationKind kind,
|
|
GenericSignature specializedSignature,
|
|
GenericSignature unerasedSpecializedSignature,
|
|
ArrayRef<Type> typeErasedParams,
|
|
SILFunction *target, Identifier spiGroup,
|
|
const ModuleDecl *spiModule,
|
|
AvailabilityRange availability);
|
|
};
|
|
|
|
/// 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>,
|
|
public SwiftObjectHeader {
|
|
|
|
private:
|
|
void *libswiftSpecificData[4];
|
|
|
|
public:
|
|
using BlockListType = llvm::iplist<SILBasicBlock>;
|
|
|
|
// For more information see docs/SIL.rst
|
|
enum class Purpose : uint8_t {
|
|
None,
|
|
GlobalInit,
|
|
GlobalInitOnceFunction,
|
|
LazyPropertyGetter
|
|
};
|
|
|
|
private:
|
|
friend class SILBasicBlock;
|
|
friend class SILModule;
|
|
friend class SILFunctionBuilder;
|
|
template <typename, unsigned> friend class BasicBlockData;
|
|
template <class, class> friend class SILBitfield;
|
|
friend class BasicBlockBitfield;
|
|
friend class NodeBitfield;
|
|
friend class OperandBitfield;
|
|
friend SILUndef;
|
|
|
|
/// 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;
|
|
|
|
/// A single-linked list of snapshots of the function.
|
|
///
|
|
/// Snapshots are copies of the current function at a given point in time.
|
|
SILFunction *snapshots = nullptr;
|
|
|
|
/// The snapshot ID of this function.
|
|
///
|
|
/// 0 means, it's not a snapshot, but the original function.
|
|
int snapshotID = 0;
|
|
|
|
/// The lowered type of the function.
|
|
CanSILFunctionType LoweredType;
|
|
|
|
CanSILFunctionType LoweredTypeInContext;
|
|
|
|
/// The context archetypes of the function.
|
|
GenericEnvironment *GenericEnv = nullptr;
|
|
|
|
/// Captured local generic environments.
|
|
ArrayRef<GenericEnvironment *> CapturedEnvs;
|
|
|
|
/// 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 module that defines this function. This member should only be set as
|
|
/// a fallback when a \c DeclCtxt is unavailable.
|
|
ModuleDecl *ParentModule = 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;
|
|
|
|
/// The SILDeclRef that this function was created for by SILGen if one exists.
|
|
SILDeclRef DeclRef = SILDeclRef();
|
|
|
|
/// This SILFunction REFerences an ad-hoc protocol requirement witness in
|
|
/// order to keep it alive, such that it main be obtained in IRGen. Without
|
|
/// this explicit reference, the witness would seem not-used, and not be
|
|
/// accessible for IRGen.
|
|
///
|
|
/// Specifically, one such case is the DistributedTargetInvocationDecoder's
|
|
/// 'decodeNextArgument' which must be retained, as it is only used from IRGen
|
|
/// and such, appears as-if unused in SIL and would get optimized away.
|
|
// TODO: Consider making this a general "references adhoc functions" and make it an array?
|
|
SILFunction *RefAdHocRequirementFunction = nullptr;
|
|
|
|
Identifier ObjCReplacementFor;
|
|
|
|
/// The head of a single-linked list of currently alive BasicBlockBitfield.
|
|
BasicBlockBitfield *newestAliveBlockBitfield = nullptr;
|
|
|
|
/// The head of a single-linked list of currently alive NodeBitfield.
|
|
NodeBitfield *newestAliveNodeBitfield = nullptr;
|
|
|
|
/// The head of a single-linked list of currently alive OperandBitfields.
|
|
OperandBitfield *newestAliveOperandBitfield = nullptr;
|
|
|
|
/// A monotonically increasing ID which is incremented whenever a
|
|
/// BasicBlockBitfield, NodeBitfield, or OperandBitfield is constructed. For
|
|
/// details see SILBitfield::bitfieldID;
|
|
uint64_t currentBitfieldID = 1;
|
|
|
|
/// Unique identifier for vector indexing and deterministic sorting.
|
|
/// May be reused when zombie functions are recovered.
|
|
unsigned index;
|
|
|
|
/// 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;
|
|
|
|
/// Name of a section if @_section attribute was used, otherwise empty.
|
|
StringRef Section;
|
|
|
|
/// Name of a Wasm export if @_expose(wasm) attribute was used, otherwise
|
|
/// empty.
|
|
StringRef WasmExportName;
|
|
|
|
/// Name of a Wasm import module and field if @_extern(wasm) attribute
|
|
std::optional<std::pair<StringRef, StringRef>> WasmImportModuleAndField;
|
|
|
|
/// 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.
|
|
AvailabilityRange Availability;
|
|
|
|
Purpose specialPurpose = Purpose::None;
|
|
|
|
PerformanceConstraints perfConstraints = PerformanceConstraints::None;
|
|
|
|
/// The undefs of each type in the function.
|
|
llvm::SmallMapVector<SILType, SILUndef *, 1> undefValues;
|
|
|
|
/// This is the number of uses of this SILFunction inside the SIL.
|
|
/// It does not include references from debug scopes.
|
|
unsigned RefCount = 0;
|
|
|
|
/// Used to verify if a BasicBlockData is not valid anymore.
|
|
/// This counter is incremented every time a BasicBlockData re-assigns new
|
|
/// block indices.
|
|
unsigned BlockListChangeIdx = 0;
|
|
|
|
/// The isolation of this function.
|
|
std::optional<ActorIsolation> actorIsolation;
|
|
|
|
/// 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 SerializedKind : 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 : 3;
|
|
|
|
/// 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 attribute @_used was present
|
|
unsigned MarkedAsUsed : 1;
|
|
|
|
/// Whether cross-module references to this function should always use weak
|
|
/// linking.
|
|
unsigned IsAlwaysWeakImported : 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;
|
|
|
|
/// Check whether this is a distributed method.
|
|
unsigned IsDistributed : 1;
|
|
|
|
/// Check whether this function could be looked up at runtime via special API.
|
|
unsigned IsRuntimeAccessible : 1;
|
|
|
|
unsigned stackProtection : 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;
|
|
|
|
/// If true, the function has lexical lifetimes even if the module does not.
|
|
unsigned ForceEnableLexicalLifetimes : 1;
|
|
|
|
/// If true, the function contains an instruction that prevents stack nesting
|
|
/// from running with pack metadata markers in place.
|
|
unsigned UseStackForPackMetadata : 1;
|
|
|
|
/// If true, the function returns a non-escapable value without any
|
|
/// lifetime-dependence on an argument.
|
|
unsigned HasUnsafeNonEscapableResult : 1;
|
|
|
|
/// True, if this function or a caller (transitively) has a performance
|
|
/// constraint.
|
|
/// If true, optimizations must not introduce new runtime calls or metadata
|
|
/// creation, which are not there after SILGen.
|
|
/// Note that this flag is not serialized, because it's computed locally
|
|
/// within a module by the MandatoryOptimizations pass.
|
|
unsigned IsPerformanceConstraint : 1;
|
|
|
|
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;
|
|
break;
|
|
case IsThunk:
|
|
case IsReabstractionThunk:
|
|
case IsBackDeployedThunk:
|
|
thunkCanHaveSubclassScope = false;
|
|
break;
|
|
}
|
|
auto allowsInterestingScopes = thunkCanHaveSubclassScope && !genericInfo;
|
|
assert(
|
|
allowsInterestingScopes ||
|
|
scope == SubclassScope::NotApplicable &&
|
|
"SubclassScope on specialization or non-signature-optimized thunk");
|
|
#endif
|
|
}
|
|
|
|
SILFunction(SILModule &module, SILLinkage linkage, StringRef mangledName,
|
|
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
|
|
IsBare_t isBareSILFunction, IsTransparent_t isTrans,
|
|
SerializedKind_t serializedKind, ProfileCounter entryCount,
|
|
IsThunk_t isThunk, SubclassScope classSubclassScope,
|
|
Inline_t inlineStrategy, EffectsKind E,
|
|
const SILDebugScope *debugScope,
|
|
IsDynamicallyReplaceable_t isDynamic,
|
|
IsExactSelfClass_t isExactSelfClass,
|
|
IsDistributed_t isDistributed,
|
|
IsRuntimeAccessible_t isRuntimeAccessible);
|
|
|
|
static SILFunction *
|
|
create(SILModule &M, SILLinkage linkage, StringRef name,
|
|
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
|
|
std::optional<SILLocation> loc, IsBare_t isBareSILFunction,
|
|
IsTransparent_t isTrans, SerializedKind_t serializedKind,
|
|
ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic,
|
|
IsDistributed_t isDistributed,
|
|
IsRuntimeAccessible_t isRuntimeAccessible,
|
|
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, IsBare_t isBareSILFunction,
|
|
IsTransparent_t isTrans, SerializedKind_t serializedKind,
|
|
ProfileCounter entryCount, IsThunk_t isThunk,
|
|
SubclassScope classSubclassScope, Inline_t inlineStrategy,
|
|
EffectsKind E, const SILDebugScope *DebugScope,
|
|
IsDynamicallyReplaceable_t isDynamic,
|
|
IsExactSelfClass_t isExactSelfClass, IsDistributed_t isDistributed,
|
|
IsRuntimeAccessible_t isRuntimeAccessible);
|
|
|
|
/// 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; }
|
|
|
|
void setName(StringRef name) {
|
|
// All the snapshots share the same name.
|
|
SILFunction *sn = this;
|
|
do {
|
|
sn->Name = name;
|
|
} while ((sn = sn->snapshots) != nullptr);
|
|
}
|
|
|
|
public:
|
|
~SILFunction();
|
|
|
|
SILModule &getModule() const { return Module; }
|
|
|
|
/// Creates a snapshot with a given `ID` from the current function.
|
|
void createSnapshot(int ID);
|
|
|
|
/// Returns the snapshot with the given `ID` or null if no such snapshot exists.
|
|
SILFunction *getSnapshot(int ID);
|
|
|
|
/// Restores the current function from a given snapshot.
|
|
void restoreFromSnapshot(int ID);
|
|
|
|
/// Deletes a snapshot with the `ID`.
|
|
void deleteSnapshot(int ID);
|
|
|
|
SILType getLoweredType() const {
|
|
return SILType::getPrimitiveObjectType(LoweredType);
|
|
}
|
|
CanSILFunctionType getLoweredFunctionType() const {
|
|
return LoweredType;
|
|
}
|
|
|
|
CanSILFunctionType getLoweredFunctionTypeInContext() const;
|
|
|
|
CanSILFunctionType
|
|
getLoweredFunctionTypeInContext(TypeExpansionContext context) const;
|
|
|
|
SILType getLoweredTypeInContext(TypeExpansionContext context) const {
|
|
return SILType::getPrimitiveObjectType(
|
|
getLoweredFunctionTypeInContext(context));
|
|
}
|
|
|
|
SILFunctionConventions getConventions() const {
|
|
return SILFunctionConventions(LoweredType, getModule());
|
|
}
|
|
|
|
SILFunctionConventions getConventionsInContext() const {
|
|
auto fnType = getLoweredFunctionTypeInContext(getTypeExpansionContext());
|
|
return SILFunctionConventions(fnType, getModule());
|
|
}
|
|
|
|
unsigned getIndex() const { return index; }
|
|
|
|
SILProfiler *getProfiler() const { return Profiler; }
|
|
|
|
SILFunction *getDynamicallyReplacedFunction() const {
|
|
return ReplacedFunction;
|
|
}
|
|
|
|
void setDynamicallyReplacedFunction(SILFunction *f) {
|
|
assert(ReplacedFunction == nullptr && "already set");
|
|
assert(!hasObjCReplacement());
|
|
|
|
if (f == nullptr)
|
|
return;
|
|
ReplacedFunction = f;
|
|
ReplacedFunction->incrementRefCount();
|
|
}
|
|
/// This function should only be called when SILFunctions are bulk deleted.
|
|
void dropDynamicallyReplacedFunction() {
|
|
if (!ReplacedFunction)
|
|
return;
|
|
ReplacedFunction->decrementRefCount();
|
|
ReplacedFunction = nullptr;
|
|
}
|
|
|
|
SILFunction *getReferencedAdHocRequirementWitnessFunction() const {
|
|
return RefAdHocRequirementFunction;
|
|
}
|
|
// Marks that this `SILFunction` uses the passed in ad-hoc protocol
|
|
// requirement witness `f` and therefore must retain it explicitly,
|
|
// otherwise we might not be able to get a reference to it.
|
|
void setReferencedAdHocRequirementWitnessFunction(SILFunction *f) {
|
|
assert(RefAdHocRequirementFunction == nullptr && "already set");
|
|
|
|
if (f == nullptr)
|
|
return;
|
|
RefAdHocRequirementFunction = f;
|
|
RefAdHocRequirementFunction->incrementRefCount();
|
|
}
|
|
void dropReferencedAdHocRequirementWitnessFunction() {
|
|
if (!RefAdHocRequirementFunction)
|
|
return;
|
|
RefAdHocRequirementFunction->decrementRefCount();
|
|
RefAdHocRequirementFunction = 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(SILDeclRef Ref);
|
|
|
|
ProfileCounter getEntryCount() const { return EntryCount; }
|
|
|
|
void setEntryCount(ProfileCounter Count) { EntryCount = Count; }
|
|
|
|
bool isNoReturnFunction(TypeExpansionContext context) const;
|
|
|
|
/// True if this function should have a non-unique definition based on the
|
|
/// embedded linkage model.
|
|
bool hasNonUniqueDefinition() 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() {
|
|
RefCount++;
|
|
assert(RefCount != 0 && "Overflow of reference count!");
|
|
}
|
|
|
|
/// Decrement the reference count.
|
|
void decrementRefCount() {
|
|
assert(RefCount != 0 && "Expected non-zero reference count on decrement!");
|
|
RefCount--;
|
|
}
|
|
|
|
/// 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)
|
|
BB.dropAllReferences();
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
ForceEnableLexicalLifetimes_t forceEnableLexicalLifetimes() const {
|
|
return ForceEnableLexicalLifetimes_t(ForceEnableLexicalLifetimes);
|
|
}
|
|
|
|
void setForceEnableLexicalLifetimes(ForceEnableLexicalLifetimes_t value) {
|
|
ForceEnableLexicalLifetimes = value;
|
|
}
|
|
|
|
UseStackForPackMetadata_t useStackForPackMetadata() const {
|
|
return UseStackForPackMetadata_t(UseStackForPackMetadata);
|
|
}
|
|
|
|
void setUseStackForPackMetadata(UseStackForPackMetadata_t value) {
|
|
UseStackForPackMetadata = value;
|
|
}
|
|
|
|
bool hasUnsafeNonEscapableResult() const {
|
|
return HasUnsafeNonEscapableResult;
|
|
}
|
|
|
|
void setHasUnsafeNonEscapableResult(bool value) {
|
|
HasUnsafeNonEscapableResult = value;
|
|
}
|
|
|
|
/// 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(); }
|
|
|
|
bool isCalleeAllocatedCoroutine() const {
|
|
return LoweredType->isCalleeAllocatedCoroutine();
|
|
}
|
|
|
|
/// Returns the calling convention used by this entry point.
|
|
SILFunctionTypeRepresentation getRepresentation() const {
|
|
return getLoweredFunctionType()->getRepresentation();
|
|
}
|
|
|
|
ResilienceExpansion getResilienceExpansion() const;
|
|
|
|
// Returns the type expansion context to be used inside this function.
|
|
TypeExpansionContext getTypeExpansionContext() const {
|
|
return TypeExpansionContext(*this);
|
|
}
|
|
|
|
SILTypeProperties getTypeProperties(Lowering::AbstractionPattern orig,
|
|
Type subst) const;
|
|
SILTypeProperties getTypeProperties(Type subst) const;
|
|
SILTypeProperties getTypeProperties(SILType type) const;
|
|
|
|
const Lowering::TypeLowering &
|
|
getTypeLowering(Lowering::AbstractionPattern orig, Type subst) const;
|
|
|
|
const Lowering::TypeLowering &getTypeLowering(Type t) const;
|
|
|
|
const Lowering::TypeLowering &getTypeLowering(SILType type) const;
|
|
|
|
SILType getLoweredType(Lowering::AbstractionPattern orig, Type subst) const;
|
|
|
|
SILType getLoweredType(Type t) const;
|
|
|
|
CanType getLoweredRValueType(Lowering::AbstractionPattern orig, Type subst) const;
|
|
|
|
CanType getLoweredRValueType(Type t) const;
|
|
|
|
SILType getLoweredLoadableType(Type t) const;
|
|
|
|
SILType getLoweredType(SILType t) 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.isConsumedInCallee())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Returns true if the function has indirect out parameters.
|
|
bool hasIndirectFormalResults() const {
|
|
return getLoweredFunctionType()->hasIndirectFormalResults();
|
|
}
|
|
|
|
// Returns true if the function has any generic arguments.
|
|
bool isGeneric() const {
|
|
auto s = getLoweredFunctionType()->getInvocationGenericSignature();
|
|
return s && !s->areAllParamsConcrete();
|
|
}
|
|
|
|
/// 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); }
|
|
|
|
/// Checks if this (callee) function body can be inlined into the caller
|
|
/// by comparing their `SerializedKind_t` values.
|
|
///
|
|
/// If both callee and caller are `not_serialized`, the callee can be inlined
|
|
/// into the caller during SIL inlining passes even if it (and the caller)
|
|
/// might contain private symbols. If this callee is `serialized_for_pkg`,
|
|
/// it can only be referenced by a serialized caller but not inlined into
|
|
/// it.
|
|
///
|
|
/// ```
|
|
/// canInlineInto: Caller
|
|
/// | not_serialized | serialized_for_pkg | serialized
|
|
/// not_serialized | ok | no | no
|
|
/// Callee serialized_for_pkg | ok | ok | no
|
|
/// serialized | ok | ok | ok
|
|
///
|
|
/// ```
|
|
///
|
|
/// \p callerSerializedKind The caller's SerializedKind.
|
|
bool canBeInlinedIntoCaller(SerializedKind_t callerSerializedKind) const;
|
|
|
|
/// Returns true if this function can be referenced from a fragile function
|
|
/// body.
|
|
/// \p callerSerializedKind The caller's SerializedKind. Used to be passed to
|
|
/// \c canBeInlinedIntoCaller.
|
|
bool hasValidLinkageForFragileRef(SerializedKind_t callerSerializedKind) 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(),
|
|
getClassSubclassScope());
|
|
}
|
|
|
|
/// Helper method which returns true if this function has "external" linkage.
|
|
bool isAvailableExternally() const {
|
|
return swift::isAvailableExternally(getLinkage());
|
|
}
|
|
|
|
/// Helper method that determines whether this SILFunction is a Swift runtime
|
|
/// function, such as swift_retain.
|
|
bool isSwiftRuntimeFunction() const;
|
|
|
|
/// 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;
|
|
|
|
/// Helper method which returns whether this function should be preserved so
|
|
/// it can potentially be used in the debugger.
|
|
bool shouldBePreservedForDebugger() 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.
|
|
AvailabilityRange getAvailabilityForLinkage() const {
|
|
return Availability;
|
|
}
|
|
|
|
void setAvailabilityForLinkage(AvailabilityRange availability) {
|
|
Availability = availability;
|
|
}
|
|
|
|
/// Returns whether this function's symbol must always be weakly referenced
|
|
/// across module boundaries.
|
|
bool isAlwaysWeakImported() const { return IsAlwaysWeakImported; }
|
|
|
|
void setIsAlwaysWeakImported(bool value) { IsAlwaysWeakImported = value; }
|
|
|
|
bool isWeakImported(ModuleDecl *module) 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;
|
|
}
|
|
|
|
IsDistributed_t isDistributed() const {
|
|
return IsDistributed_t(IsDistributed);
|
|
}
|
|
void
|
|
setIsDistributed(IsDistributed_t value = IsDistributed_t::IsDistributed) {
|
|
IsDistributed = value;
|
|
}
|
|
|
|
IsRuntimeAccessible_t isRuntimeAccessible() const {
|
|
return IsRuntimeAccessible_t(IsRuntimeAccessible);
|
|
}
|
|
void setIsRuntimeAccessible(IsRuntimeAccessible_t value =
|
|
IsRuntimeAccessible_t::IsRuntimeAccessible) {
|
|
IsRuntimeAccessible = value;
|
|
}
|
|
|
|
bool needsStackProtection() const { return stackProtection; }
|
|
void setNeedStackProtection(bool needSP) { stackProtection = needSP; }
|
|
|
|
/// 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).starts_with(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))
|
|
return;
|
|
SemanticsAttrSet.push_back(Ref.str());
|
|
std::sort(SemanticsAttrSet.begin(), SemanticsAttrSet.end());
|
|
}
|
|
|
|
/// Remove the semantics
|
|
void removeSemanticsAttr(StringRef Ref) {
|
|
auto Iter =
|
|
std::remove(SemanticsAttrSet.begin(), SemanticsAttrSet.end(), Ref);
|
|
SemanticsAttrSet.erase(Iter);
|
|
}
|
|
|
|
/// \returns the range of specialize attributes.
|
|
ArrayRef<SILSpecializeAttr*> getSpecializeAttrs() const {
|
|
return SpecializeAttrSet;
|
|
}
|
|
|
|
/// Removes all specialize attributes from this function.
|
|
void clearSpecializeAttrs() {
|
|
forEachSpecializeAttrTargetFunction(
|
|
[](SILFunction *targetFun) { targetFun->decrementRefCount(); });
|
|
SpecializeAttrSet.clear();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/// True if debug information must be preserved (-Onone).
|
|
///
|
|
/// If this is false (-O), then the presence of debug info must not affect the
|
|
/// outcome of any transformations.
|
|
///
|
|
/// Typically used to determine whether a debug_value is a normal SSA use or
|
|
/// incidental use.
|
|
bool preserveDebugInfo() const;
|
|
|
|
PerformanceConstraints getPerfConstraints() const { return perfConstraints; }
|
|
|
|
void setPerfConstraints(PerformanceConstraints perfConstr) {
|
|
perfConstraints = perfConstr;
|
|
}
|
|
|
|
// see `IsPerformanceConstraint`
|
|
bool isPerformanceConstraint() const { return IsPerformanceConstraint; }
|
|
|
|
void setIsPerformanceConstraint(bool flag = true) {
|
|
IsPerformanceConstraint = flag;
|
|
}
|
|
|
|
/// \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 {
|
|
if (!DebugScope) {
|
|
return SILLocation::invalid();
|
|
}
|
|
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);
|
|
}
|
|
|
|
/// Returns the module that defines this function.
|
|
ModuleDecl *getParentModule() const {
|
|
return DeclCtxt ? DeclCtxt->getParentModule() : ParentModule;
|
|
}
|
|
|
|
/// Sets \c ParentModule as fallback if \c DeclCtxt is not available to
|
|
/// provide the parent module.
|
|
void setParentModule(ModuleDecl *module) {
|
|
assert(!DeclCtxt && "already have a DeclCtxt");
|
|
ParentModule = module;
|
|
}
|
|
|
|
/// Initialize the debug scope for debug info on SIL level
|
|
/// (-sil-based-debuginfo).
|
|
void setSILDebugScope(const SILDebugScope *DS) {
|
|
DebugScope = DS;
|
|
}
|
|
|
|
/// Get the source location of the function.
|
|
const SILDebugScope *getDebugScope() const { return DebugScope; }
|
|
|
|
/// Return the SILDeclRef for this SILFunction if one was assigned by SILGen.
|
|
SILDeclRef getDeclRef() const { return DeclRef; }
|
|
|
|
/// Set the SILDeclRef for this SILFunction. Used mainly by SILGen.
|
|
void setDeclRef(SILDeclRef declRef) { DeclRef = declRef; }
|
|
|
|
/// 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);
|
|
}
|
|
|
|
bool isSerialized() const {
|
|
return SerializedKind_t(SerializedKind) == IsSerialized;
|
|
}
|
|
bool isAnySerialized() const {
|
|
return SerializedKind_t(SerializedKind) == IsSerialized ||
|
|
SerializedKind_t(SerializedKind) == IsSerializedForPackage;
|
|
}
|
|
|
|
/// Get this function's serialized attribute.
|
|
SerializedKind_t getSerializedKind() const {
|
|
return SerializedKind_t(SerializedKind);
|
|
}
|
|
void setSerializedKind(SerializedKind_t serializedKind) {
|
|
SerializedKind = serializedKind;
|
|
assert(this->getSerializedKind() == serializedKind &&
|
|
"too few bits for Serialized storage");
|
|
}
|
|
|
|
/// 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);
|
|
}
|
|
|
|
std::pair<const char *, int> parseArgumentEffectsFromSource(StringRef effectStr,
|
|
ArrayRef<StringRef> paramNames);
|
|
std::pair<const char *, int> parseArgumentEffectsFromSIL(StringRef effectStr,
|
|
int argumentIndex);
|
|
std::pair<const char *, int> parseGlobalEffectsFromSIL(StringRef effectStr);
|
|
std::pair<const char *, int> parseMultipleEffectsFromSIL(StringRef effectStr);
|
|
void writeEffect(llvm::raw_ostream &OS, int effectIdx) const;
|
|
void writeEffects(llvm::raw_ostream &OS) const {
|
|
writeEffect(OS, -1);
|
|
}
|
|
void copyEffects(SILFunction *from);
|
|
bool hasArgumentEffects() const;
|
|
void visitArgEffects(std::function<void(int, int, bool)> c) const;
|
|
MemoryBehavior getMemoryBehavior(bool observeRetains);
|
|
|
|
// Used by the MemoryLifetimeVerifier
|
|
bool argumentMayRead(Operand *argOp, SILValue addr);
|
|
|
|
bool isDeinitBarrier();
|
|
|
|
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) {
|
|
assert(owner->hasClangNode());
|
|
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 {
|
|
assert(isSpecialization());
|
|
return SpecializationInfo;
|
|
}
|
|
|
|
void setSpecializationInfo(const GenericSpecializationInformation *Info) {
|
|
assert(!isSpecialization());
|
|
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;
|
|
}
|
|
|
|
/// Return any captured local generic environments, currently used for pack
|
|
/// element environments only. After SILGen, these are rewritten into
|
|
/// primary archetypes.
|
|
ArrayRef<GenericEnvironment *> getCapturedEnvironments() const {
|
|
return CapturedEnvs;
|
|
}
|
|
|
|
void setGenericEnvironment(GenericEnvironment *env);
|
|
|
|
void setGenericEnvironment(GenericEnvironment *env,
|
|
ArrayRef<GenericEnvironment *> capturedEnvs,
|
|
SubstitutionMap forwardingSubs) {
|
|
GenericEnv = env;
|
|
CapturedEnvs = capturedEnvs;
|
|
ForwardingSubMap = forwardingSubs.getCanonical();
|
|
}
|
|
|
|
/// Retrieve the generic signature from the generic environment of this
|
|
/// function, if any. Else returns the null \c GenericSignature.
|
|
GenericSignature getGenericSignature() 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.
|
|
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() {
|
|
assert(isDefinition() && "Can only convert definitions to declarations");
|
|
clear();
|
|
}
|
|
|
|
void clear();
|
|
|
|
/// Like `clear`, but does not call `dropAllReferences`, which is the
|
|
/// responsibility of the caller.
|
|
void eraseAllBlocks();
|
|
|
|
/// A substitution map that sends the generic parameters of the invocation
|
|
/// generic signature to some combination of primar and local archetypes.
|
|
///
|
|
/// CAUTION: If this is a SILFunction that captures pack element environments,
|
|
/// then at SILGen time, this is not actually the forwarding substitution map
|
|
/// of the SILFunction's generic environment. This is because:
|
|
///
|
|
/// 1) The SILFunction's generic signature includes extra generic parameters,
|
|
/// to model captured pack elements;
|
|
/// 2) The SILFunction's generic environment is the AST generic environment,
|
|
/// so it's based on the original generic signature;
|
|
/// 3) SILGen uses this AST generic environment together with local archetypes
|
|
/// for lowering SIL instructions.
|
|
///
|
|
/// Therefore, the SILFunction's forwarding substitution map takes the extended
|
|
/// generic signature (1). It maps the original generic parameters to the
|
|
/// archetypes of (2), and the extended generic parameters to the local archetypes
|
|
/// of (3).
|
|
///
|
|
/// After SILGen, all archetypes are re-instantiated inside the SIL function,
|
|
/// and the forwarding substitution map and generic environment then align.
|
|
SubstitutionMap getForwardingSubstitutionMap() const {
|
|
return ForwardingSubMap;
|
|
}
|
|
|
|
/// Returns true if this SILFunction must be a defer statement.
|
|
///
|
|
/// NOTE: This may return false for defer statements that have been
|
|
/// deserialized without a DeclContext. This means that this is guaranteed to
|
|
/// be correct for SILFunctions in Raw SIL that were not deserialized as
|
|
/// canonical. Thus one can use it for diagnostics.
|
|
bool isDefer() const {
|
|
if (auto *dc = getDeclContext())
|
|
if (auto *decl = dyn_cast_or_null<FuncDecl>(dc->getAsDecl()))
|
|
return decl->isDeferBody();
|
|
return false;
|
|
}
|
|
|
|
/// Returns true if this function belongs to a declaration that
|
|
/// has `@_alwaysEmitIntoClient` attribute.
|
|
bool markedAsAlwaysEmitIntoClient() const {
|
|
if (!hasLocation())
|
|
return false;
|
|
|
|
auto *V = getLocation().getAsASTNode<ValueDecl>();
|
|
return V && V->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>();
|
|
}
|
|
|
|
/// Return whether this function has attribute @_used on it
|
|
bool markedAsUsed() const { return MarkedAsUsed; }
|
|
void setMarkedAsUsed(bool value) { MarkedAsUsed = value; }
|
|
|
|
/// Return custom section name if @_section was used, otherwise empty
|
|
StringRef section() const { return Section; }
|
|
void setSection(StringRef value) { Section = value; }
|
|
|
|
/// Return Wasm export name if @_expose(wasm) was used, otherwise empty
|
|
StringRef wasmExportName() const { return WasmExportName; }
|
|
void setWasmExportName(StringRef value) { WasmExportName = value; }
|
|
|
|
/// Return Wasm import module name if @_extern(wasm) was used otherwise empty
|
|
StringRef wasmImportModuleName() const {
|
|
if (WasmImportModuleAndField)
|
|
return WasmImportModuleAndField->first;
|
|
return StringRef();
|
|
}
|
|
|
|
/// Return Wasm import field name if @_extern(wasm) was used otherwise empty
|
|
StringRef wasmImportFieldName() const {
|
|
if (WasmImportModuleAndField)
|
|
return WasmImportModuleAndField->second;
|
|
return StringRef();
|
|
}
|
|
|
|
void setWasmImportModuleAndField(StringRef module, StringRef field) {
|
|
WasmImportModuleAndField = std::make_pair(module, field);
|
|
}
|
|
|
|
bool isExternForwardDeclaration() const {
|
|
if (isExternalDeclaration()) {
|
|
if (auto declContext = getDeclContext()) {
|
|
if (auto decl = declContext->getAsDecl()) {
|
|
if (decl->getAttrs().hasAttribute<ExternAttr>())
|
|
return true;
|
|
if (decl->getAttrs().hasAttribute<SILGenNameAttr>())
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Returns true if this function belongs to a declaration that returns
|
|
/// an opaque result type with one or more availability conditions that are
|
|
/// allowed to produce a different underlying type at runtime.
|
|
bool hasOpaqueResultTypeWithAvailabilityConditions() const {
|
|
if (!hasLocation())
|
|
return false;
|
|
|
|
if (auto *V = getLocation().getAsASTNode<ValueDecl>()) {
|
|
auto *opaqueResult = V->getOpaqueResultTypeDecl();
|
|
return opaqueResult &&
|
|
opaqueResult->hasConditionallyAvailableSubstitutions();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void setActorIsolation(ActorIsolation newActorIsolation) {
|
|
actorIsolation = newActorIsolation;
|
|
}
|
|
|
|
std::optional<ActorIsolation> getActorIsolation() const {
|
|
return actorIsolation;
|
|
}
|
|
|
|
bool isNonisolatedNonsending() const {
|
|
return actorIsolation && actorIsolation->isCallerIsolationInheriting();
|
|
}
|
|
|
|
/// Return the source file that this SILFunction belongs to if it exists.
|
|
SourceFile *getSourceFile() const;
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Block List Access
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
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 *createBasicBlock(llvm::StringRef debugName);
|
|
SILBasicBlock *createBasicBlockAfter(SILBasicBlock *afterBB);
|
|
SILBasicBlock *createBasicBlockBefore(SILBasicBlock *beforeBB);
|
|
|
|
/// Removes and destroys \p BB;
|
|
void eraseBlock(SILBasicBlock *BB) {
|
|
assert(BB->getParent() == this);
|
|
BlockList.erase(BB);
|
|
}
|
|
|
|
/// Transfer all blocks of \p F into this function, at the begin of the block
|
|
/// list.
|
|
void moveAllBlocksFromOtherFunction(SILFunction *F);
|
|
|
|
/// Transfer \p blockInOtherFunction of another function into this function,
|
|
/// before \p insertPointInThisFunction.
|
|
void moveBlockFromOtherFunction(SILBasicBlock *blockInOtherFunction,
|
|
iterator insertPointInThisFunction);
|
|
|
|
/// Move block \p BB to immediately before the iterator \p IP.
|
|
///
|
|
/// The block must be part of this function.
|
|
void moveBlockBefore(SILBasicBlock *BB, SILFunction::iterator IP);
|
|
|
|
/// Move block \p BB to immediately after block \p After.
|
|
///
|
|
/// The block must be part of this function.
|
|
void moveBlockAfter(SILBasicBlock *BB, SILBasicBlock *After) {
|
|
moveBlockBefore(BB, std::next(After->getIterator()));
|
|
}
|
|
|
|
/// 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) || isa<ThrowAddrInst>(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) || isa<ThrowAddrInst>(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()) {
|
|
output.emplace_back(&Block);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Populate \p output with every block terminated by an unreachable
|
|
/// instruction.
|
|
void visitUnreachableTerminatedBlocks(
|
|
llvm::function_ref<void(SILBasicBlock &)> visitor) const {
|
|
for (auto &block : const_cast<SILFunction &>(*this)) {
|
|
if (isa<UnreachableInst>(block.getTerminator())) {
|
|
visitor(block);
|
|
}
|
|
}
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// 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(
|
|
getConventions().getNumIndirectSILResults() +
|
|
getConventions().getNumIndirectSILErrorResults());
|
|
}
|
|
|
|
const SILArgument *getSelfArgument() const {
|
|
assert(hasSelfParam() && "This method can only be called if the "
|
|
"SILFunction has a self parameter");
|
|
return getArguments().back();
|
|
}
|
|
|
|
/// Like getSelfArgument() except it returns a nullptr if we do not have a
|
|
/// selfparam.
|
|
const SILArgument *maybeGetSelfArgument() const {
|
|
if (!hasSelfParam())
|
|
return nullptr;
|
|
return getArguments().back();
|
|
}
|
|
|
|
/// If we have an isolated argument, return that. Returns nullptr otherwise.
|
|
const SILArgument *maybeGetIsolatedArgument() const {
|
|
for (auto *arg : getArgumentsWithoutIndirectResults()) {
|
|
if (cast<SILFunctionArgument>(arg)->getKnownParameterInfo().hasOption(
|
|
SILParameterInfo::Isolated))
|
|
return arg;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const SILArgument *getDynamicSelfMetadata() const {
|
|
assert(hasDynamicSelfMetadata() && "This method can only be called if the "
|
|
"SILFunction has a self-metadata parameter");
|
|
return getArguments().back();
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Miscellaneous
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
/// A value's lifetime, determined by looking at annotations on its decl and
|
|
/// the default lifetime for the type.
|
|
Lifetime getLifetime(VarDecl *decl, SILType ty) {
|
|
return ty.getLifetime(*this).getLifetimeForAnnotatedValue(
|
|
decl->getLifetimeAnnotation());
|
|
}
|
|
|
|
ArrayRef<std::pair<SILType, SILUndef *>> getUndefValues() {
|
|
return {undefValues.begin(), undefValues.end()};
|
|
}
|
|
|
|
/// verify - Run the SIL verifier to make sure that the SILFunction follows
|
|
/// invariants.
|
|
void verify(CalleeCache *calleeCache = nullptr,
|
|
bool SingleFunction = true,
|
|
bool isCompleteOSSA = true,
|
|
bool checkLinearLifetime = true) const;
|
|
|
|
/// Run the SIL verifier without assuming OSSA lifetimes end at dead end
|
|
/// blocks.
|
|
void verifyIncompleteOSSA() const {
|
|
verify(/*calleeCache*/nullptr, /*SingleFunction=*/true, /*completeOSSALifetimes=*/false);
|
|
}
|
|
|
|
/// Verifies the lifetime of memory locations in the function.
|
|
void verifyMemoryLifetime(CalleeCache *calleeCache,
|
|
DeadEndBlocks *deadEndBlocks);
|
|
|
|
/// Verifies ownership of the function.
|
|
/// Since we don't have complete lifetimes everywhere, computes DeadEndBlocks
|
|
/// and calls verifyOwnership(DeadEndBlocks *deadEndBlocks)
|
|
void verifyOwnership() const;
|
|
|
|
/// Run the SIL ownership verifier to check that all values with ownership
|
|
/// have a linear lifetime. Regular OSSA invariants are checked separately in
|
|
/// normal SIL verification.
|
|
///
|
|
/// \p deadEndBlocks is nullptr when OSSA lifetimes are complete.
|
|
///
|
|
/// NOTE: The ownership verifier is run when performing normal IR
|
|
/// verification, so this verification can be viewed as a subset of
|
|
/// SILFunction::verify(checkLinearLifetimes=true).
|
|
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;
|
|
|
|
/// Validate that all SILUndefs stored in the function's type -> SILUndef map
|
|
/// have this function as their parent function.
|
|
///
|
|
/// Please only call this from the SILVerifier.
|
|
void verifySILUndefMap() const;
|
|
|
|
/// Pretty-print the SILFunction.
|
|
void dump(bool Verbose) const;
|
|
void dump() const;
|
|
|
|
/// Pretty-print the SILFunction with DebugInfo.
|
|
void dump(bool Verbose, bool DebugInfo) 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);
|
|
print(PrintCtx);
|
|
}
|
|
|
|
/// 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)
|
|
const;
|
|
|
|
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) {
|
|
F.print(OS);
|
|
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;
|
|
|
|
public:
|
|
static void deleteNode(SILFunction *V) { V->~SILFunction(); }
|
|
|
|
private:
|
|
void createNode(const SILFunction &);
|
|
};
|
|
|
|
} // end llvm namespace
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Inline SIL implementations
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace swift {
|
|
|
|
inline bool SILBasicBlock::isEntry() const {
|
|
return this == &*getParent()->begin();
|
|
}
|
|
|
|
inline SILModule &SILInstruction::getModule() const {
|
|
return getFunction()->getModule();
|
|
}
|
|
|
|
} // end swift namespace
|
|
|
|
#endif
|