mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1307 lines
45 KiB
C++
1307 lines
45 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;
|
|
static BridgedFunction::IsDeinitBarrierFn isDeinitBarrierFunction = 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(
|
|
getASTContext().LangOpts.getMinPlatformVersion());
|
|
|
|
// 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,
|
|
IsDeinitBarrierFn isDeinitBarrierFn) {
|
|
functionMetatype = metatype;
|
|
initFunction = initFn;
|
|
destroyFunction = destroyFn;
|
|
writeFunction = writeFn;
|
|
parseFunction = parseFn;
|
|
copyEffectsFunction = copyEffectsFn;
|
|
getEffectInfoFunction = effectInfoFn;
|
|
getMemBehvaiorFunction = memBehaviorFn;
|
|
argumentMayReadFunction = argumentMayReadFn;
|
|
isDeinitBarrierFunction = isDeinitBarrierFn;
|
|
}
|
|
|
|
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});
|
|
}
|
|
|
|
bool SILFunction::isDeinitBarrier() {
|
|
if (!isDeinitBarrierFunction)
|
|
return true;
|
|
|
|
return isDeinitBarrierFunction({this});
|
|
}
|
|
|
|
SourceFile *SILFunction::getSourceFile() const {
|
|
auto declRef = getDeclRef();
|
|
if (!declRef)
|
|
return nullptr;
|
|
|
|
return declRef.getInnermostDeclContext()->getParentSourceFile();
|
|
}
|