Files
swift-mirror/lib/SIL/IR/SILFunction.cpp
Allan Shortlidge d0f63a0753 AST: Split Availability.h into multiple headers.
Put AvailabilityRange into its own header with very few dependencies so that it
can be included freely in other headers that need to use it as a complete type.

NFC.
2025-01-03 18:36:04 -08:00

1296 lines
44 KiB
C++

//===--- SILFunction.cpp - Defines the SILFunction data structure ---------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-function"
#include "swift/SIL/SILFunction.h"
#include "swift/AST/AvailabilityRange.h"
#include "swift/AST/Expr.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/LocalArchetypeRequirementCollector.h"
#include "swift/AST/Module.h"
#include "swift/AST/Stmt.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/OptimizationMode.h"
#include "swift/Basic/Statistic.h"
#include "swift/SIL/CFG.h"
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILBridging.h"
#include "swift/SIL/SILCloner.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILProfiler.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/GraphWriter.h"
#include <optional>
using namespace swift;
using namespace Lowering;
GenericSignature SILSpecializeAttr::buildTypeErasedSignature(
GenericSignature sig, ArrayRef<Type> typeErasedParams) {
bool changedSignature = false;
llvm::SmallVector<Requirement, 2> requirementsErased;
auto &C = sig->getASTContext();
for (auto req : sig.getRequirements()) {
bool found = std::any_of(typeErasedParams.begin(),
typeErasedParams.end(),
[&](Type t) {
auto other = req.getFirstType();
return t->isEqual(other);
});
if (found && req.getKind() == RequirementKind::Layout) {
auto layout = req.getLayoutConstraint();
if (layout->isClass()) {
requirementsErased.push_back(Requirement(RequirementKind::SameType,
req.getFirstType(),
C.getAnyObjectType()));
} else if (layout->isBridgeObject()) {
requirementsErased.push_back(Requirement(RequirementKind::SameType,
req.getFirstType(),
C.TheBridgeObjectType));
} else if (layout->isFixedSizeTrivial()) {
unsigned bitWidth = layout->getTrivialSizeInBits();
requirementsErased.push_back(
Requirement(RequirementKind::SameType, req.getFirstType(),
CanType(BuiltinIntegerType::get(bitWidth, C))));
} else if (layout->isTrivialStride()) {
requirementsErased.push_back(
Requirement(RequirementKind::SameType, req.getFirstType(),
CanType(BuiltinVectorType::get(
C,
BuiltinIntegerType::get(8, C),
layout->getTrivialStride()))));
} else {
requirementsErased.push_back(req);
}
} else {
requirementsErased.push_back(req);
}
changedSignature |= found;
}
if (changedSignature) {
return buildGenericSignature(
C, GenericSignature(),
SmallVector<GenericTypeParamType *>(sig.getGenericParams()),
requirementsErased,
/*allowInverses=*/false);
}
return sig;
}
SILSpecializeAttr::SILSpecializeAttr(bool exported, SpecializationKind kind,
GenericSignature specializedSig,
GenericSignature unerasedSpecializedSig,
ArrayRef<Type> typeErasedParams,
SILFunction *target, Identifier spiGroup,
const ModuleDecl *spiModule,
AvailabilityRange availability)
: kind(kind), exported(exported), specializedSignature(specializedSig),
unerasedSpecializedSignature(unerasedSpecializedSig),
typeErasedParams(typeErasedParams.begin(), typeErasedParams.end()),
spiGroup(spiGroup), availability(availability), spiModule(spiModule),
targetFunction(target) {
if (targetFunction)
targetFunction->incrementRefCount();
}
SILSpecializeAttr *
SILSpecializeAttr::create(SILModule &M, GenericSignature specializedSig,
ArrayRef<Type> typeErasedParams,
bool exported, SpecializationKind kind,
SILFunction *target, Identifier spiGroup,
const ModuleDecl *spiModule,
AvailabilityRange availability) {
auto erasedSpecializedSig =
SILSpecializeAttr::buildTypeErasedSignature(specializedSig,
typeErasedParams);
void *buf = M.allocate(sizeof(SILSpecializeAttr), alignof(SILSpecializeAttr));
return ::new (buf) SILSpecializeAttr(exported, kind, erasedSpecializedSig,
specializedSig, typeErasedParams, target,
spiGroup, spiModule, availability);
}
void SILFunction::addSpecializeAttr(SILSpecializeAttr *Attr) {
if (getLoweredFunctionType()->getInvocationGenericSignature()) {
Attr->F = this;
SpecializeAttrSet.push_back(Attr);
}
}
void SILFunction::removeSpecializeAttr(SILSpecializeAttr *attr) {
// Drop the reference to the _specialize(target:) function.
if (auto *targetFun = attr->getTargetFunction()) {
targetFun->decrementRefCount();
}
SpecializeAttrSet.erase(std::remove_if(SpecializeAttrSet.begin(),
SpecializeAttrSet.end(),
[attr](SILSpecializeAttr *member) {
return member == attr;
}),
SpecializeAttrSet.end());
}
SILFunction *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,
SubclassScope classSubclassScope, Inline_t inlineStrategy, EffectsKind E,
SILFunction *insertBefore, const SILDebugScope *debugScope) {
// Get a StringMapEntry for the function. As a sop to error cases,
// allow the name to have an empty string.
llvm::StringMapEntry<SILFunction*> *entry = nullptr;
if (!name.empty()) {
entry = &*M.FunctionTable.insert(std::make_pair(name, nullptr)).first;
PrettyStackTraceSILFunction trace("creating", entry->getValue());
assert(!entry->getValue() && "function already exists");
name = entry->getKey();
}
SILFunction *fn = M.removeFromZombieList(name);
if (fn) {
// Resurrect a zombie function.
// This happens for example if a specialized function gets dead and gets
// deleted. And afterwards the same specialization is created again.
fn->init(linkage, name, loweredType, genericEnv, isBareSILFunction, isTrans,
serializedKind, entryCount, isThunk, classSubclassScope,
inlineStrategy, E, debugScope, isDynamic, isExactSelfClass,
isDistributed, isRuntimeAccessible);
assert(fn->empty());
} else {
fn = new (M) SILFunction(
M, linkage, name, loweredType, genericEnv, isBareSILFunction, isTrans,
serializedKind, entryCount, isThunk, classSubclassScope, inlineStrategy,
E, debugScope, isDynamic, isExactSelfClass, isDistributed,
isRuntimeAccessible);
}
if (entry) entry->setValue(fn);
if (insertBefore)
M.functions.insert(SILModule::iterator(insertBefore), fn);
else
M.functions.push_back(fn);
auto iter = M.pendingSpecializeAttrs.find(name);
if (iter != M.pendingSpecializeAttrs.end()) {
for (auto *attr : iter->second) {
fn->addSpecializeAttr(attr);
}
M.pendingSpecializeAttrs.erase(iter);
}
return fn;
}
static SwiftMetatype functionMetatype;
static BridgedFunction::RegisterFn initFunction = nullptr;
static BridgedFunction::RegisterFn destroyFunction = nullptr;
static BridgedFunction::WriteFn writeFunction = nullptr;
static BridgedFunction::ParseFn parseFunction = nullptr;
static BridgedFunction::CopyEffectsFn copyEffectsFunction = nullptr;
static BridgedFunction::GetEffectInfoFn getEffectInfoFunction = nullptr;
static BridgedFunction::GetMemBehaviorFn getMemBehvaiorFunction = nullptr;
static BridgedFunction::ArgumentMayReadFn argumentMayReadFunction = nullptr;
SILFunction::SILFunction(
SILModule &Module, 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)
: SwiftObjectHeader(functionMetatype), Module(Module),
index(Module.getNewFunctionIndex()),
Availability(AvailabilityRange::alwaysAvailable()) {
init(Linkage, Name, LoweredType, genericEnv, isBareSILFunction, isTrans,
serializedKind, entryCount, isThunk, classSubclassScope, inlineStrategy, E,
DebugScope, isDynamic, isExactSelfClass, isDistributed,
isRuntimeAccessible);
// Set our BB list to have this function as its parent. This enables us to
// splice efficiently basic blocks in between functions.
BlockList.Parent = this;
if (initFunction)
initFunction({this}, &libswiftSpecificData, sizeof(libswiftSpecificData));
}
void SILFunction::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) {
setName(Name);
assert(!LoweredType->hasTypeParameter() &&
"function type has open type parameters");
this->LoweredType = LoweredType;
this->SpecializationInfo = nullptr;
this->EntryCount = entryCount;
this->Availability = AvailabilityRange::alwaysAvailable();
this->Bare = isBareSILFunction;
this->Transparent = isTrans;
this->SerializedKind = serializedKind;
this->Thunk = isThunk;
this->ClassSubclassScope = unsigned(classSubclassScope);
this->GlobalInitFlag = false;
this->InlineStrategy = inlineStrategy;
this->Linkage = unsigned(Linkage);
this->HasCReferences = false;
this->MarkedAsUsed = false;
this->IsAlwaysWeakImported = false;
this->IsDynamicReplaceable = isDynamic;
this->ExactSelfClass = isExactSelfClass;
this->IsDistributed = isDistributed;
this->IsRuntimeAccessible = isRuntimeAccessible;
this->ForceEnableLexicalLifetimes = DoNotForceEnableLexicalLifetimes;
this->UseStackForPackMetadata = DoUseStackForPackMetadata;
this->HasUnsafeNonEscapableResult = false;
this->IsPerformanceConstraint = false;
this->stackProtection = false;
this->Inlined = false;
this->Zombie = false;
this->HasOwnership = true,
this->WasDeserializedCanonical = false;
this->IsWithoutActuallyEscapingThunk = false;
this->OptMode = unsigned(OptimizationMode::NotSet);
this->perfConstraints = PerformanceConstraints::None;
this->EffectsKindAttr = unsigned(E);
assert(!Transparent || !IsDynamicReplaceable);
validateSubclassScope(classSubclassScope, isThunk, nullptr);
setDebugScope(DebugScope);
setGenericEnvironment(genericEnv);
}
SILFunction::~SILFunction() {
// If the function is recursive, a function_ref inst inside of the function
// will give the function a non-zero ref count triggering the assertion. Thus
// we drop all instruction references before we erase.
// We also need to drop all references if instructions are allocated using
// an allocator that may recycle freed memory.
dropAllReferences();
if (snapshots)
snapshots->~SILFunction();
if (ReplacedFunction) {
ReplacedFunction->decrementRefCount();
ReplacedFunction = nullptr;
}
auto &M = getModule();
for (auto &BB : *this) {
BB.eraseAllInstructions(M);
}
assert(RefCount == 0 &&
"Function cannot be deleted while function_ref's still exist");
assert(!newestAliveBlockBitfield &&
"Not all BasicBlockBitfields deleted at function destruction");
assert(!newestAliveNodeBitfield &&
"Not all NodeBitfields deleted at function destruction");
assert(!newestAliveOperandBitfield &&
"Not all OperandBitfields deleted at function destruction");
if (destroyFunction)
destroyFunction({this}, &libswiftSpecificData, sizeof(libswiftSpecificData));
}
void SILFunction::createSnapshot(int id) {
assert(id != 0 && "invalid snapshot ID");
assert(!getSnapshot(id) && "duplicate snapshot");
SILFunction *newSnapshot = new (Module) SILFunction(
Module, getLinkage(), getName(), getLoweredFunctionType(),
getGenericEnvironment(), isBare(), isTransparent(), getSerializedKind(),
getEntryCount(), isThunk(), getClassSubclassScope(), getInlineStrategy(),
getEffectsKind(), getDebugScope(), isDynamicallyReplaceable(),
isExactSelfClass(), isDistributed(), isRuntimeAccessible());
// Copy all relevant properties.
// TODO: It's really unfortunate that this needs to be done manually. It would
// be nice if all the properties are encapsulated into a single state,
// which can be copied at once.
newSnapshot->SpecializationInfo = SpecializationInfo;
newSnapshot->ClangNodeOwner = ClangNodeOwner;
newSnapshot->DeclCtxt = DeclCtxt;
newSnapshot->Profiler = Profiler;
newSnapshot->ReplacedFunction = ReplacedFunction;
newSnapshot->RefAdHocRequirementFunction = RefAdHocRequirementFunction;
newSnapshot->ObjCReplacementFor = ObjCReplacementFor;
newSnapshot->SemanticsAttrSet = SemanticsAttrSet;
newSnapshot->SpecializeAttrSet = SpecializeAttrSet;
newSnapshot->Section = Section;
newSnapshot->Availability = Availability;
newSnapshot->specialPurpose = specialPurpose;
newSnapshot->perfConstraints = perfConstraints;
newSnapshot->GlobalInitFlag = GlobalInitFlag;
newSnapshot->HasCReferences = HasCReferences;
newSnapshot->MarkedAsUsed = MarkedAsUsed;
newSnapshot->IsAlwaysWeakImported = IsAlwaysWeakImported;
newSnapshot->HasOwnership = HasOwnership;
newSnapshot->IsWithoutActuallyEscapingThunk = IsWithoutActuallyEscapingThunk;
newSnapshot->OptMode = OptMode;
newSnapshot->copyEffects(this);
SILFunctionCloner cloner(newSnapshot);
cloner.cloneFunction(this);
newSnapshot->snapshotID = id;
newSnapshot->snapshots = this->snapshots;
this->snapshots = newSnapshot;
// The cloner sometimes removes temporary instructions.
getModule().flushDeletedInsts();
}
SILFunction *SILFunction::getSnapshot(int ID) {
SILFunction *sn = this;
do {
if (sn->snapshotID == ID)
return sn;
sn = sn->snapshots;
} while (sn);
return nullptr;
}
void SILFunction::restoreFromSnapshot(int ID) {
SILFunction *sn = getSnapshot(ID);
assert(sn && "no snapshot found");
clear();
SILFunctionCloner cloner(this);
cloner.cloneFunction(sn);
// Beside the function body, only restore those properties, which are/can be
// modified by passes.
// TODO: There should be a clear sepratation from initialize-once properties
// (`let`) and properties which can be modified by passes (`var`).
copyEffects(sn);
// The cloner sometimes removes temporary instructions.
getModule().flushDeletedInsts();
}
void SILFunction::deleteSnapshot(int ID) {
SILFunction *f = this;
do {
if (SILFunction *sn = f->snapshots) {
if (sn->snapshotID == ID) {
f->snapshots = sn->snapshots;
sn->snapshots = nullptr;
sn->~SILFunction();
getModule().flushDeletedInsts();
return;
}
}
} while ((f = f->snapshots) != nullptr);
}
void SILFunction::createProfiler(SILDeclRef Ref) {
assert(!Profiler && "Function already has a profiler");
assert(Ref && "Must have non-null SILDeclRef");
Profiler = SILProfiler::create(Module, Ref);
if (!Profiler)
return;
// If we loaded a profile, set the entry counts for functions and closures
// for PGO to use.
if (Ref.isFunc()) {
if (auto *Closure = Ref.getAbstractClosureExpr()) {
setEntryCount(Profiler->getExecutionCount(Closure));
} else {
auto *FD = Ref.getFuncDecl();
assert(FD);
setEntryCount(Profiler->getExecutionCount(FD->getBody()));
}
}
}
bool SILFunction::hasForeignBody() const {
if (!hasClangNode()) return false;
return SILDeclRef::isClangGenerated(getClangNode());
}
const SILFunction *SILFunction::getOriginOfSpecialization() const {
if (!isSpecialization())
return nullptr;
const SILFunction *p = getSpecializationInfo()->getParent();
while (p->isSpecialization()) {
p = p->getSpecializationInfo()->getParent();
}
return p;
}
GenericSignature SILFunction::getGenericSignature() const {
return GenericEnv ? GenericEnv->getGenericSignature() : GenericSignature();
}
void SILFunction::numberValues(llvm::DenseMap<const SILNode*, unsigned> &
ValueToNumberMap) const {
unsigned idx = 0;
for (auto &BB : *this) {
for (auto I = BB.args_begin(), E = BB.args_end(); I != E; ++I)
ValueToNumberMap[*I] = idx++;
for (auto &I : BB) {
auto results = I.getResults();
if (results.empty()) {
ValueToNumberMap[I.asSILNode()] = idx++;
} else {
// Assign the instruction node the first result ID.
ValueToNumberMap[I.asSILNode()] = idx;
for (auto result : results) {
ValueToNumberMap[result] = idx++;
}
}
}
}
}
ASTContext &SILFunction::getASTContext() const {
return getModule().getASTContext();
}
OptimizationMode SILFunction::getEffectiveOptimizationMode() const {
if (OptimizationMode(OptMode) != OptimizationMode::NotSet)
return OptimizationMode(OptMode);
return getModule().getOptions().OptMode;
}
bool SILFunction::preserveDebugInfo() const {
return getEffectiveOptimizationMode() <= OptimizationMode::NoOptimization;
}
bool SILFunction::shouldOptimize() const {
return getEffectiveOptimizationMode() != OptimizationMode::NoOptimization;
}
Type SILFunction::mapTypeIntoContext(Type type) const {
assert(!type->hasPrimaryArchetype());
if (GenericEnv) {
// The complication here is that we sometimes call this with an AST interface
// type, which might contain element archetypes, if it was the interface type
// of a closure or local variable.
if (type->hasElementArchetype())
return GenericEnv->mapTypeIntoContext(type);
// Otherwise, assume we have an interface type for the "combined" captured
// environment.
return type.subst(MapIntoLocalArchetypeContext(GenericEnv, CapturedEnvs),
LookUpConformanceInModule(),
SubstFlags::PreservePackExpansionLevel);
}
assert(!type->hasTypeParameter());
return type;
}
SILType SILFunction::mapTypeIntoContext(SILType type) const {
assert(!type.hasPrimaryArchetype());
if (GenericEnv) {
auto genericSig = GenericEnv->getGenericSignature().getCanonicalSignature();
return type.subst(Module,
MapIntoLocalArchetypeContext(GenericEnv, CapturedEnvs),
LookUpConformanceInModule(),
genericSig,
SubstFlags::PreservePackExpansionLevel);
}
assert(!type.hasTypeParameter());
return type;
}
SILType GenericEnvironment::mapTypeIntoContext(SILModule &M,
SILType type) const {
assert(!type.hasPrimaryArchetype());
auto genericSig = getGenericSignature().getCanonicalSignature();
return type.subst(M,
QueryInterfaceTypeSubstitutions(this),
LookUpConformanceInModule(),
genericSig,
SubstFlags::PreservePackExpansionLevel);
}
bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const {
return SILType::getPrimitiveObjectType(getLoweredFunctionType())
.isNoReturnFunction(getModule(), context);
}
ResilienceExpansion SILFunction::getResilienceExpansion() const {
// If a function definition is in another module, and
// it was serialized due to package serialization opt,
// a new attribute [serialized_for_package] is added
// to the definition site. During deserialization, this
// attribute is preserved if the current module is in
// the same package, thus should be in the same resilience
// domain.
return (isSerialized()
? ResilienceExpansion::Minimal
: ResilienceExpansion::Maximal);
}
const TypeLowering &
SILFunction::getTypeLowering(AbstractionPattern orig, Type subst) {
return getModule().Types.getTypeLowering(orig, subst,
TypeExpansionContext(*this));
}
const TypeLowering &SILFunction::getTypeLowering(Type t) const {
return getModule().Types.getTypeLowering(t, TypeExpansionContext(*this));
}
SILType
SILFunction::getLoweredType(AbstractionPattern orig, Type subst) const {
return getModule().Types.getLoweredType(orig, subst,
TypeExpansionContext(*this));
}
SILType SILFunction::getLoweredType(Type t) const {
return getModule().Types.getLoweredType(t, TypeExpansionContext(*this));
}
CanType
SILFunction::getLoweredRValueType(AbstractionPattern orig, Type subst) const {
return getModule().Types.getLoweredRValueType(TypeExpansionContext(*this),
orig, subst);
}
CanType SILFunction::getLoweredRValueType(Type t) const {
return getModule().Types.getLoweredRValueType(TypeExpansionContext(*this), t);
}
SILType SILFunction::getLoweredLoadableType(Type t) const {
auto &M = getModule();
return M.Types.getLoweredLoadableType(t, TypeExpansionContext(*this), M);
}
const TypeLowering &SILFunction::getTypeLowering(SILType type) const {
return getModule().Types.getTypeLowering(type, *this);
}
SILType SILFunction::getLoweredType(SILType t) const {
return getTypeLowering(t).getLoweredType().getCategoryType(t.getCategory());
}
bool SILFunction::isTypeABIAccessible(SILType type) const {
return getModule().isTypeABIAccessible(type, TypeExpansionContext(*this));
}
bool SILFunction::isWeakImported(ModuleDecl *module) const {
if (auto *parent = getParentModule())
if (module->isImportedAsWeakLinked(parent))
return true;
// For imported functions check the Clang declaration.
if (ClangNodeOwner)
return ClangNodeOwner->getClangDecl()->isWeakImported();
// For native functions check a flag on the SILFunction
// itself.
if (!isAvailableExternally())
return false;
if (isAlwaysWeakImported())
return true;
if (Availability.isAlwaysAvailable())
return false;
auto deploymentTarget =
AvailabilityRange::forDeploymentTarget(getASTContext());
if (getASTContext().LangOpts.WeakLinkAtTarget)
return !Availability.isSupersetOf(deploymentTarget);
return !deploymentTarget.isContainedIn(Availability);
}
SILBasicBlock *SILFunction::createBasicBlock() {
SILBasicBlock *newBlock = new (getModule()) SILBasicBlock(this);
BlockList.push_back(newBlock);
return newBlock;
}
SILBasicBlock *SILFunction::createBasicBlock(llvm::StringRef debugName) {
SILBasicBlock *newBlock = new (getModule()) SILBasicBlock(this);
newBlock->setDebugName(debugName);
BlockList.push_back(newBlock);
return newBlock;
}
SILBasicBlock *SILFunction::createBasicBlockAfter(SILBasicBlock *afterBB) {
SILBasicBlock *newBlock = new (getModule()) SILBasicBlock(this);
BlockList.insertAfter(afterBB->getIterator(), newBlock);
return newBlock;
}
SILBasicBlock *SILFunction::createBasicBlockBefore(SILBasicBlock *beforeBB) {
SILBasicBlock *newBlock = new (getModule()) SILBasicBlock(this);
BlockList.insert(beforeBB->getIterator(), newBlock);
return newBlock;
}
void SILFunction::moveAllBlocksFromOtherFunction(SILFunction *F) {
BlockList.splice(begin(), F->BlockList);
SILModule &mod = getModule();
for (SILBasicBlock &block : *this) {
for (SILInstruction &inst : block) {
mod.notifyMovedInstruction(&inst, F);
}
}
}
void SILFunction::moveBlockFromOtherFunction(SILBasicBlock *blockInOtherFunction,
iterator insertPointInThisFunction) {
SILFunction *otherFunc = blockInOtherFunction->getParent();
assert(otherFunc != this);
BlockList.splice(insertPointInThisFunction, otherFunc->BlockList,
blockInOtherFunction);
SILModule &mod = getModule();
for (SILInstruction &inst : *blockInOtherFunction) {
mod.notifyMovedInstruction(&inst, otherFunc);
}
}
void SILFunction::moveBlockBefore(SILBasicBlock *BB, SILFunction::iterator IP) {
assert(BB->getParent() == this);
if (SILFunction::iterator(BB) == IP)
return;
BlockList.remove(BB);
BlockList.insert(IP, BB);
}
//===----------------------------------------------------------------------===//
// View CFG Implementation
//===----------------------------------------------------------------------===//
#ifndef NDEBUG
static llvm::cl::opt<unsigned>
MaxColumns("view-cfg-max-columns", llvm::cl::init(80),
llvm::cl::desc("Maximum width of a printed node"));
namespace {
enum class LongLineBehavior { None, Truncate, Wrap };
} // end anonymous namespace
static llvm::cl::opt<LongLineBehavior>
LLBehavior("view-cfg-long-line-behavior",
llvm::cl::init(LongLineBehavior::Truncate),
llvm::cl::desc("Behavior when line width is greater than the "
"value provided my -view-cfg-max-columns "
"option"),
llvm::cl::values(
clEnumValN(LongLineBehavior::None, "none", "Print everything"),
clEnumValN(LongLineBehavior::Truncate, "truncate",
"Truncate long lines"),
clEnumValN(LongLineBehavior::Wrap, "wrap", "Wrap long lines")));
static llvm::cl::opt<bool>
RemoveUseListComments("view-cfg-remove-use-list-comments",
llvm::cl::init(false),
llvm::cl::desc("Should use list comments be removed"));
template <typename InstTy, typename CaseValueTy>
inline CaseValueTy getCaseValueForBB(const InstTy *Inst,
const SILBasicBlock *BB) {
for (unsigned i = 0, e = Inst->getNumCases(); i != e; ++i) {
auto P = Inst->getCase(i);
if (P.second != BB)
continue;
return P.first;
}
llvm_unreachable("Error! should never pass in BB that is not a successor");
}
namespace llvm {
template <>
struct DOTGraphTraits<SILFunction *> : public DefaultDOTGraphTraits {
DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
static std::string getGraphName(SILFunction *F) {
return "CFG for '" + F->getName().str() + "' function";
}
static std::string getSimpleNodeLabel(SILBasicBlock *Node, SILFunction *F) {
std::string OutStr;
raw_string_ostream OSS(OutStr);
const_cast<SILBasicBlock *>(Node)->printAsOperand(OSS, false);
return OSS.str();
}
static std::string getCompleteNodeLabel(SILBasicBlock *Node, SILFunction *F) {
std::string Str;
raw_string_ostream OS(Str);
OS << *Node;
std::string OutStr = OS.str();
if (OutStr[0] == '\n')
OutStr.erase(OutStr.begin());
// Process string output to make it nicer...
unsigned ColNum = 0;
unsigned LastSpace = 0;
for (unsigned i = 0; i != OutStr.length(); ++i) {
if (OutStr[i] == '\n') { // Left justify
OutStr[i] = '\\';
OutStr.insert(OutStr.begin() + i + 1, 'l');
ColNum = 0;
LastSpace = 0;
} else if (RemoveUseListComments && OutStr[i] == '/' &&
i != (OutStr.size() - 1) && OutStr[i + 1] == '/') {
unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
--i;
} else if (ColNum == MaxColumns) { // Handle long lines.
if (LLBehavior == LongLineBehavior::Wrap) {
if (!LastSpace)
LastSpace = i;
OutStr.insert(LastSpace, "\\l...");
ColNum = i - LastSpace;
LastSpace = 0;
i += 3; // The loop will advance 'i' again.
} else if (LLBehavior == LongLineBehavior::Truncate) {
unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
OutStr.erase(OutStr.begin() + i, OutStr.begin() + Idx);
--i;
}
// Else keep trying to find a space.
} else
++ColNum;
if (OutStr[i] == ' ')
LastSpace = i;
}
return OutStr;
}
std::string getNodeLabel(SILBasicBlock *Node, SILFunction *Graph) {
if (isSimple())
return getSimpleNodeLabel(Node, Graph);
else
return getCompleteNodeLabel(Node, Graph);
}
static std::string getEdgeSourceLabel(SILBasicBlock *Node,
SILBasicBlock::succblock_iterator I) {
const SILBasicBlock *Succ = *I;
const TermInst *Term = Node->getTerminator();
// Label source of conditional branches with "T" or "F"
if (auto *CBI = dyn_cast<CondBranchInst>(Term))
return (Succ == CBI->getTrueBB()) ? "T" : "F";
// Label source of switch edges with the associated value.
if (auto *SI = dyn_cast<SwitchValueInst>(Term)) {
if (SI->hasDefault() && SI->getDefaultBB() == Succ)
return "def";
std::string Str;
raw_string_ostream OS(Str);
SILValue I = getCaseValueForBB<SwitchValueInst, SILValue>(SI, Succ);
OS << I; // TODO: or should we output the literal value of I?
return OS.str();
}
if (auto *SEIB = dyn_cast<SwitchEnumInst>(Term)) {
std::string Str;
raw_string_ostream OS(Str);
EnumElementDecl *E =
getCaseValueForBB<SwitchEnumInst, EnumElementDecl *>(SEIB, Succ);
OS << E->getName();
return OS.str();
}
if (auto *SEIB = dyn_cast<SwitchEnumAddrInst>(Term)) {
std::string Str;
raw_string_ostream OS(Str);
EnumElementDecl *E =
getCaseValueForBB<SwitchEnumAddrInst, EnumElementDecl *>(SEIB, Succ);
OS << E->getName();
return OS.str();
}
if (auto *DMBI = dyn_cast<DynamicMethodBranchInst>(Term))
return (Succ == DMBI->getHasMethodBB()) ? "T" : "F";
if (auto *CCBI = dyn_cast<CheckedCastBranchInst>(Term))
return (Succ == CCBI->getSuccessBB()) ? "T" : "F";
if (auto *CCBI = dyn_cast<CheckedCastAddrBranchInst>(Term))
return (Succ == CCBI->getSuccessBB()) ? "T" : "F";
return "";
}
};
} // namespace llvm
#endif
#ifndef NDEBUG
static llvm::cl::opt<std::string>
TargetFunction("view-cfg-only-for-function", llvm::cl::init(""),
llvm::cl::desc("Only print out the cfg for this function"));
#endif
static void viewCFGHelper(const SILFunction* f, bool skipBBContents) {
/// When asserts are disabled, this should be a NoOp.
#ifndef NDEBUG
// If we have a target function, only print that function out.
if (!TargetFunction.empty() && !(f->getName().str() == TargetFunction))
return;
ViewGraph(const_cast<SILFunction *>(f), "cfg" + f->getName().str(),
/*shortNames=*/skipBBContents);
#endif
}
void SILFunction::viewCFG() const {
viewCFGHelper(this, /*skipBBContents=*/false);
}
void SILFunction::viewCFGOnly() const {
viewCFGHelper(this, /*skipBBContents=*/true);
}
bool SILFunction::hasDynamicSelfMetadata() const {
auto paramTypes =
getConventions().getParameterSILTypes(TypeExpansionContext::minimal());
if (paramTypes.empty())
return false;
auto silTy = *std::prev(paramTypes.end());
if (!silTy.isObject())
return false;
auto selfTy = silTy.getASTType();
if (auto metaTy = dyn_cast<MetatypeType>(selfTy)) {
selfTy = metaTy.getInstanceType();
if (auto dynamicSelfTy = dyn_cast<DynamicSelfType>(selfTy))
selfTy = dynamicSelfTy.getSelfType();
}
if (selfTy.isForeignReferenceType())
return false;
return !!selfTy.getClassOrBoundGenericClass();
}
bool SILFunction::hasName(const char *Name) const {
return getName() == Name;
}
/*
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
*/
bool SILFunction::canBeInlinedIntoCaller(SerializedKind_t callerSerializedKind) const {
switch (getSerializedKind()) {
// 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.
case IsNotSerialized:
return callerSerializedKind == IsNotSerialized;
// If Package-CMO is enabled, we serialize package, public,
// and @usableFromInline decls as [serialized_for_package].
// Their bodies must not, however, leak into @inlinable
// functons (that are [serialized]) since they are inlined
// outside of their defining module.
//
// If this callee is [serialized_for_package], the caller
// must be either non-serialized or [serialized_for_package]
// for this callee's body to be inlined into the caller.
// It can however be referenced by [serialized] caller.
case IsSerializedForPackage:
return callerSerializedKind != IsSerialized;
case IsSerialized:
return true;
}
llvm_unreachable("Invalid serialized kind");
}
/// Returns true if this function can be referenced from a fragile function
/// body.
bool SILFunction::hasValidLinkageForFragileRef(SerializedKind_t callerSerializedKind) const {
// Fragile functions can reference 'static inline' functions imported
// from C.
if (hasForeignBody())
return true;
// The call site of this function must have checked that
// caller.isAnySerialized() is true, as indicated by the
// function name itself (contains 'ForFragileRef').
assert(callerSerializedKind != IsNotSerialized);
// If we can inline it, we can reference it.
if (canBeInlinedIntoCaller(callerSerializedKind))
return true;
// If the containing module has been serialized already, we no longer
// enforce any invariants.
if (getModule().isSerialized())
return true;
// If the function has a subclass scope that limits its visibility outside
// the module despite its linkage, we cannot reference it.
if (getClassSubclassScope() == SubclassScope::Resilient &&
isAvailableExternally())
return false;
// Otherwise, only public or package functions can be referenced.
// If it has a package linkage at this point, package CMO must
// have been enabled, so opt in for visibility.
return hasPublicOrPackageVisibility(getLinkage(), /*includePackage*/ true);
}
bool
SILFunction::isPossiblyUsedExternally() const {
auto linkage = getLinkage();
// Hidden functions may be referenced by other C code in the linkage unit.
if (linkage == SILLinkage::Hidden && hasCReferences())
return true;
if (ReplacedFunction)
return true;
if (isDistributed() && isThunk())
return true;
if (isRuntimeAccessible())
return true;
if (markedAsUsed())
return true;
if (shouldBePreservedForDebugger())
return true;
// Declaration marked as `@_alwaysEmitIntoClient` that
// returns opaque result type with availability conditions
// has to be kept alive to emit opaque type metadata descriptor.
if (markedAsAlwaysEmitIntoClient() &&
hasOpaqueResultTypeWithAvailabilityConditions())
return true;
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
}
bool SILFunction::shouldBePreservedForDebugger() const {
// Only preserve for the debugger at Onone.
if (getEffectiveOptimizationMode() != OptimizationMode::NoOptimization)
return false;
if (!getModule().getOptions().ShouldFunctionsBePreservedToDebugger)
return false;
if (getModule().getASTContext().LangOpts.hasFeature(Feature::Embedded))
return false;
if (isAvailableExternally())
return false;
if (hasSemanticsAttr("no.preserve.debugger"))
return false;
// Only keep functions defined in this module.
if (!isDefinition())
return false;
if (getLinkage() == SILLinkage::Shared)
return false;
// Don't preserve anything markes as always emit into client.
if (markedAsAlwaysEmitIntoClient())
return false;
// Needed by lldb to print global variables which are propagated by the
// mandatory GlobalOpt.
if (isGlobalInit())
return true;
// Preserve any user-written functions.
if (auto declContext = getDeclContext())
if (auto decl = declContext->getAsDecl())
if (!decl->isImplicit())
return true;
// Keep any setters/getters, even compiler generated ones.
if (auto *accessorDecl =
llvm::dyn_cast_or_null<swift::AccessorDecl>(getDeclContext()))
if (accessorDecl->isGetterOrSetter())
return true;
return false;
}
bool SILFunction::isExternallyUsedSymbol() const {
return swift::isPossiblyUsedExternally(getEffectiveSymbolLinkage(),
getModule().isWholeModule());
}
void SILFunction::clear() {
dropAllReferences();
eraseAllBlocks();
}
void SILFunction::eraseAllBlocks() {
BlockList.clear();
}
void SILFunction::setGenericEnvironment(GenericEnvironment *env) {
setGenericEnvironment(env, ArrayRef<GenericEnvironment *>(),
env ? env->getForwardingSubstitutionMap()
: SubstitutionMap());
}
bool SILFunction::shouldVerifyOwnership() const {
return !hasSemanticsAttr("verify.ownership.sil.never");
}
static Identifier getIdentifierForObjCSelector(ObjCSelector selector, ASTContext &Ctxt) {
SmallVector<char, 64> buffer;
auto str = selector.getString(buffer);
return Ctxt.getIdentifier(str);
}
void SILFunction::setObjCReplacement(AbstractFunctionDecl *replacedFunc) {
assert(ReplacedFunction == nullptr && ObjCReplacementFor.empty());
assert(replacedFunc != nullptr);
ObjCReplacementFor = getIdentifierForObjCSelector(
replacedFunc->getObjCSelector(), getASTContext());
}
void SILFunction::setObjCReplacement(Identifier replacedFunc) {
assert(ReplacedFunction == nullptr && ObjCReplacementFor.empty());
ObjCReplacementFor = replacedFunc;
}
// See swift/Basic/Statistic.h for declaration: this enables tracing
// SILFunctions, is defined here to avoid too much layering violation / circular
// linkage dependency.
struct SILFunctionTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
void traceName(const void *Entity, raw_ostream &OS) const override {
if (!Entity)
return;
const SILFunction *F = static_cast<const SILFunction *>(Entity);
F->printName(OS);
}
void traceLoc(const void *Entity, SourceManager *SM,
clang::SourceManager *CSM, raw_ostream &OS) const override {
if (!Entity)
return;
const SILFunction *F = static_cast<const SILFunction *>(Entity);
if (!F->hasLocation())
return;
F->getLocation().getSourceRange().print(OS, *SM, false);
}
};
static SILFunctionTraceFormatter TF;
template<>
const UnifiedStatsReporter::TraceFormatter*
FrontendStatsTracer::getTraceFormatter<const SILFunction *>() {
return &TF;
}
bool SILFunction::hasPrespecialization() const {
for (auto *attr : getSpecializeAttrs()) {
if (attr->isExported())
return true;
}
return false;
}
void SILFunction::forEachSpecializeAttrTargetFunction(
llvm::function_ref<void(SILFunction *)> action) {
for (auto *attr : getSpecializeAttrs()) {
if (auto *f = attr->getTargetFunction()) {
action(f);
}
}
}
void BridgedFunction::registerBridging(SwiftMetatype metatype,
RegisterFn initFn, RegisterFn destroyFn,
WriteFn writeFn, ParseFn parseFn,
CopyEffectsFn copyEffectsFn,
GetEffectInfoFn effectInfoFn,
GetMemBehaviorFn memBehaviorFn,
ArgumentMayReadFn argumentMayReadFn) {
functionMetatype = metatype;
initFunction = initFn;
destroyFunction = destroyFn;
writeFunction = writeFn;
parseFunction = parseFn;
copyEffectsFunction = copyEffectsFn;
getEffectInfoFunction = effectInfoFn;
getMemBehvaiorFunction = memBehaviorFn;
argumentMayReadFunction = argumentMayReadFn;
}
std::pair<const char *, int> SILFunction::
parseArgumentEffectsFromSource(StringRef effectStr, ArrayRef<StringRef> paramNames) {
if (parseFunction) {
llvm::SmallVector<BridgedStringRef, 8> bridgedParamNames;
for (StringRef paramName : paramNames) {
bridgedParamNames.push_back(paramName);
}
ArrayRef<BridgedStringRef> bridgedParamNameArray = bridgedParamNames;
auto error = parseFunction(
{this}, effectStr, BridgedFunction::ParseEffectsMode::argumentEffectsFromSource, -1,
{(const unsigned char *)bridgedParamNameArray.data(), bridgedParamNameArray.size()});
return {(const char *)error.message, (int)error.position};
}
return {nullptr, 0};
}
std::pair<const char *, int> SILFunction::
parseArgumentEffectsFromSIL(StringRef effectStr, int argumentIndex) {
if (parseFunction) {
auto error = parseFunction(
{this}, effectStr, BridgedFunction::ParseEffectsMode::argumentEffectsFromSIL, argumentIndex, {nullptr, 0});
return {(const char *)error.message, (int)error.position};
}
return {nullptr, 0};
}
std::pair<const char *, int> SILFunction::parseGlobalEffectsFromSIL(StringRef effectStr) {
if (parseFunction) {
auto error = parseFunction(
{this}, effectStr, BridgedFunction::ParseEffectsMode::globalEffectsFromSIL, -1, {nullptr, 0});
return {(const char *)error.message, (int)error.position};
}
return {nullptr, 0};
}
std::pair<const char *, int> SILFunction::
parseMultipleEffectsFromSIL(StringRef effectStr) {
if (parseFunction) {
auto error = parseFunction(
{this}, effectStr, BridgedFunction::ParseEffectsMode::multipleEffectsFromSIL, -1, {nullptr, 0});
return {(const char *)error.message, (int)error.position};
}
return {nullptr, 0};
}
void SILFunction::writeEffect(llvm::raw_ostream &OS, int effectIdx) const {
if (writeFunction) {
writeFunction({const_cast<SILFunction *>(this)}, {&OS}, effectIdx);
}
}
void SILFunction::copyEffects(SILFunction *from) {
if (copyEffectsFunction) {
copyEffectsFunction({this}, {from});
}
}
bool SILFunction::hasArgumentEffects() const {
if (getEffectInfoFunction) {
BridgedFunction f = {const_cast<SILFunction *>(this)};
return getEffectInfoFunction(f, 0).isValid;
}
return false;
}
void SILFunction::
visitArgEffects(std::function<void(int, int, bool)> c) const {
if (!getEffectInfoFunction)
return;
int idx = 0;
BridgedFunction bridgedFn = {const_cast<SILFunction *>(this)};
while (true) {
BridgedFunction::EffectInfo ei = getEffectInfoFunction(bridgedFn, idx);
if (!ei.isValid)
return;
if (!ei.isEmpty) {
c(idx, ei.argumentIndex, ei.isDerived);
}
idx++;
}
}
MemoryBehavior SILFunction::getMemoryBehavior(bool observeRetains) {
if (!getMemBehvaiorFunction)
return MemoryBehavior::MayHaveSideEffects;
auto b = getMemBehvaiorFunction({this}, observeRetains);
return (MemoryBehavior)b;
}
// Used by the MemoryLifetimeVerifier
bool SILFunction::argumentMayRead(Operand *argOp, SILValue addr) {
if (!argumentMayReadFunction)
return true;
return argumentMayReadFunction({this}, {argOp}, {addr});
}
SourceFile *SILFunction::getSourceFile() const {
auto declRef = getDeclRef();
if (!declRef)
return nullptr;
return declRef.getInnermostDeclContext()->getParentSourceFile();
}