SIL/IRGen: analysis of runtime effects for an instruction

Define the possible runtime effects of an instruction in an enum `RuntimeEffect`.
Add a new utility `swift:getRuntimeEffect` to estimate the runtime effects of an instruction.

Also, add a mechanism to validate the correctness of the analysis in IRGen: annotate all runtime functions in RuntimeFunctions.def with the actual effect what the runtime function has or can have. Then check if the effects of emitted runtime functions for an instruction match what `getRuntimeEffect` predicts.
This check is only enabled on demand by defining the CHECK_RUNTIME_EFFECT_ANALYSIS macro in RuntimeEffect.h
This commit is contained in:
Erik Eckstein
2021-10-25 13:16:47 +02:00
parent 4e6c5434f3
commit ff2db93922
8 changed files with 1093 additions and 236 deletions

View File

@@ -16,6 +16,7 @@
#ifndef SWIFT_RUNTIME_RUNTIMEFNWRAPPERSGEN_H #ifndef SWIFT_RUNTIME_RUNTIMEFNWRAPPERSGEN_H
#define SWIFT_RUNTIME_RUNTIMEFNWRAPPERSGEN_H #define SWIFT_RUNTIME_RUNTIMEFNWRAPPERSGEN_H
#include "swift/SIL/RuntimeEffect.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,7 @@
#ifndef SWIFT_SIL_INSTRUCTIONUTILS_H #ifndef SWIFT_SIL_INSTRUCTIONUTILS_H
#define SWIFT_SIL_INSTRUCTIONUTILS_H #define SWIFT_SIL_INSTRUCTIONUTILS_H
#include "swift/SIL/RuntimeEffect.h"
#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILInstruction.h"
namespace swift { namespace swift {
@@ -140,6 +141,15 @@ SILValue isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI);
/// init or set function. /// init or set function.
bool onlyUsedByAssignByWrapper(PartialApplyInst *PAI); bool onlyUsedByAssignByWrapper(PartialApplyInst *PAI);
/// Returns the runtime effects of \p inst.
///
/// Predicts which runtime calls are called in the generated code for `inst`.
/// This is sometimes a conservative approximation, i.e. more runtime effects
/// are reported than actually happen.
/// If the runtime effects can be associated with a type, this type is returned
/// in `impactType`. That's useful for diagnostics.
RuntimeEffect getRuntimeEffect(SILInstruction *inst, SILType &impactType);
/// If V is a function closure, return the reaching set of partial_apply's. /// If V is a function closure, return the reaching set of partial_apply's.
void findClosuresForFunctionValue(SILValue V, void findClosuresForFunctionValue(SILValue V,
TinyPtrVector<PartialApplyInst *> &results); TinyPtrVector<PartialApplyInst *> &results);

View File

@@ -0,0 +1,83 @@
//===--- RuntimeEffect.h - Defines the RuntimeEffect enum -------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_RUNTIMEIMPACT_H
#define SWIFT_SIL_RUNTIMEIMPACT_H
namespace swift {
/// Defines the effect of runtime functions.
enum class RuntimeEffect : unsigned {
/// The runtime function has no observable effect.
NoEffect = 0,
/// The runtime function can lock.
Locking = 0x01,
/// The runtime function can allocate memory (implies Locking).
Allocating = 0x02,
/// The runtime function can deallocate memory (implies Locking).
Deallocating = 0x04,
/// The runtime function performs ARC operations (implies Locking).
RefCounting = 0x08,
/// The runtime function performs metadata operations (which implies Locking
/// and Allocating).
/// TODO: distinguish between metadata runtime functions which only lock and
/// which also can allocate.
MetaData = 0x10,
/// The runtime function performs dynamic casting (which implies Locking
/// and Allocating).
/// TODO: distinguish between casting runtime functions which only lock and
/// which also can allocate.
Casting = 0x20,
/// The runtime function performs exclusivity checking.
/// This does not have any observable runtime effect like locking or
/// allocation, but it's modelled separatly.
ExclusivityChecking = 0x100,
/// The runtime function calls ObjectiveC methods.
ObjectiveC = 0x40,
/// Not modelled currently.
Concurrency = 0x0,
/// Not modelled currently.
AutoDiff = 0x0,
Releasing = RefCounting | Deallocating,
};
inline RuntimeEffect operator|(RuntimeEffect lhs, RuntimeEffect rhs) {
return (RuntimeEffect)((unsigned)lhs | (unsigned)rhs);
}
inline RuntimeEffect &operator|=(RuntimeEffect &lhs, RuntimeEffect rhs) {
lhs = lhs | rhs;
return lhs;
}
inline bool operator&(RuntimeEffect lhs, RuntimeEffect rhs) {
return ((unsigned)lhs & (unsigned)rhs) != 0;
}
} // end swift namespace
// Enable the following macro to perform validation check on the runtime effects
// of instructions in IRGen.
// #define CHECK_RUNTIME_EFFECT_ANALYSIS
#endif

View File

@@ -699,6 +699,20 @@ namespace RuntimeConstants {
const auto ZExt = llvm::Attribute::ZExt; const auto ZExt = llvm::Attribute::ZExt;
const auto FirstParamReturned = llvm::Attribute::Returned; const auto FirstParamReturned = llvm::Attribute::Returned;
#ifdef CHECK_RUNTIME_EFFECT_ANALYSIS
const auto NoEffect = RuntimeEffect::NoEffect;
const auto Locking = RuntimeEffect::Locking;
const auto Allocating = RuntimeEffect::Allocating;
const auto Deallocating = RuntimeEffect::Deallocating;
const auto RefCounting = RuntimeEffect::RefCounting;
const auto ObjectiveC = RuntimeEffect::ObjectiveC;
const auto Concurrency = RuntimeEffect::Concurrency;
const auto AutoDiff = RuntimeEffect::AutoDiff;
const auto MetaData = RuntimeEffect::MetaData;
const auto Casting = RuntimeEffect::Casting;
const auto ExclusivityChecking = RuntimeEffect::ExclusivityChecking;
#endif
RuntimeAvailability AlwaysAvailable(ASTContext &Context) { RuntimeAvailability AlwaysAvailable(ASTContext &Context) {
return RuntimeAvailability::AlwaysAvailable; return RuntimeAvailability::AlwaysAvailable;
} }
@@ -941,21 +955,37 @@ llvm::Constant *IRGenModule::getDeletedAsyncMethodErrorAsyncFunctionPointer() {
LinkEntity::forKnownAsyncFunctionPointer("swift_deletedAsyncMethodError")).getValue(); LinkEntity::forKnownAsyncFunctionPointer("swift_deletedAsyncMethodError")).getValue();
} }
#ifdef CHECK_RUNTIME_EFFECT_ANALYSIS
void IRGenModule::registerRuntimeEffect(ArrayRef<RuntimeEffect> effect,
const char *funcName) {
for (RuntimeEffect rt : effect) {
effectOfRuntimeFuncs = RuntimeEffect((unsigned)effectOfRuntimeFuncs |
(unsigned)rt);
emittedRuntimeFuncs.push_back(funcName);
}
}
#else
#define registerRuntimeEffect(...)
#endif
#define QUOTE(...) __VA_ARGS__ #define QUOTE(...) __VA_ARGS__
#define STR(X) #X #define STR(X) #X
#define FUNCTION(ID, NAME, CC, AVAILABILITY, RETURNS, ARGS, ATTRS) \ #define FUNCTION(ID, NAME, CC, AVAILABILITY, RETURNS, ARGS, ATTRS, EFFECT) \
FUNCTION_IMPL(ID, NAME, CC, AVAILABILITY, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS)) FUNCTION_IMPL(ID, NAME, CC, AVAILABILITY, QUOTE(RETURNS), QUOTE(ARGS), \
QUOTE(ATTRS), QUOTE(EFFECT))
#define RETURNS(...) { __VA_ARGS__ } #define RETURNS(...) { __VA_ARGS__ }
#define ARGS(...) { __VA_ARGS__ } #define ARGS(...) { __VA_ARGS__ }
#define NO_ARGS {} #define NO_ARGS {}
#define ATTRS(...) { __VA_ARGS__ } #define ATTRS(...) { __VA_ARGS__ }
#define NO_ATTRS {} #define NO_ATTRS {}
#define EFFECT(...) { __VA_ARGS__ }
#define FUNCTION_IMPL(ID, NAME, CC, AVAILABILITY, RETURNS, ARGS, ATTRS) \ #define FUNCTION_IMPL(ID, NAME, CC, AVAILABILITY, RETURNS, ARGS, ATTRS, EFFECT)\
llvm::Constant *IRGenModule::get##ID##Fn() { \ llvm::Constant *IRGenModule::get##ID##Fn() { \
using namespace RuntimeConstants; \ using namespace RuntimeConstants; \
registerRuntimeEffect(EFFECT, #NAME); \
return getRuntimeFn(Module, ID##Fn, #NAME, CC, \ return getRuntimeFn(Module, ID##Fn, #NAME, CC, \
AVAILABILITY(this->Context), \ AVAILABILITY(this->Context), \
RETURNS, ARGS, ATTRS); \ RETURNS, ARGS, ATTRS); \

View File

@@ -33,6 +33,7 @@
#include "swift/Basic/SuccessorMap.h" #include "swift/Basic/SuccessorMap.h"
#include "swift/IRGen/ValueWitness.h" #include "swift/IRGen/ValueWitness.h"
#include "swift/SIL/SILFunction.h" #include "swift/SIL/SILFunction.h"
#include "swift/SIL/RuntimeEffect.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Hashing.h" #include "llvm/ADT/Hashing.h"
@@ -760,6 +761,14 @@ public:
unsigned DereferenceableID; /// !dereferenceable unsigned DereferenceableID; /// !dereferenceable
llvm::MDNode *InvariantNode; llvm::MDNode *InvariantNode;
#ifdef CHECK_RUNTIME_EFFECT_ANALYSIS
RuntimeEffect effectOfRuntimeFuncs = RuntimeEffect::NoEffect;
llvm::SmallVector<const char *> emittedRuntimeFuncs;
void registerRuntimeEffect(ArrayRef<RuntimeEffect> realtime,
const char *funcName);
#endif
llvm::CallingConv::ID C_CC; /// standard C calling convention llvm::CallingConv::ID C_CC; /// standard C calling convention
llvm::CallingConv::ID DefaultCC; /// default calling convention llvm::CallingConv::ID DefaultCC; /// default calling convention
llvm::CallingConv::ID SwiftCC; /// swift calling convention llvm::CallingConv::ID SwiftCC; /// swift calling convention

View File

@@ -2387,7 +2387,30 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
if (isa<TermInst>(&I)) if (isa<TermInst>(&I))
emitDebugVariableRangeExtension(BB); emitDebugVariableRangeExtension(BB);
} }
#ifdef CHECK_RUNTIME_EFFECT_ANALYSIS
IGM.effectOfRuntimeFuncs = RuntimeEffect::NoEffect;
IGM.emittedRuntimeFuncs.clear();
#endif
visit(&I); visit(&I);
#ifdef CHECK_RUNTIME_EFFECT_ANALYSIS
if (!isa<DebugValueInst>(&I)) {
SILType impactType;
RuntimeEffect silImpact = getRuntimeEffect(&I, impactType);
if ((unsigned)IGM.effectOfRuntimeFuncs & ~(unsigned)silImpact) {
llvm::errs() << "Missing runtime impact " << (unsigned)silImpact
<< ", expected: " << (unsigned)IGM.effectOfRuntimeFuncs
<< "\n in " << I
<< "emitted runtime functions:\n";
for (const char *funcName : IGM.emittedRuntimeFuncs) {
llvm::errs() << " " << funcName << "()\n";
}
llvm_unreachable("wrong runtime impact definition");
}
}
#endif
} }
assert(Builder.hasPostTerminatorIP() && "SIL bb did not terminate block?!"); assert(Builder.hasPostTerminatorIP() && "SIL bb did not terminate block?!");

View File

@@ -385,6 +385,482 @@ bool swift::onlyUsedByAssignByWrapper(PartialApplyInst *PAI) {
return usedByAssignByWrapper; return usedByAssignByWrapper;
} }
static RuntimeEffect metadataEffect(SILType ty) {
ClassDecl *cl = ty.getClassOrBoundGenericClass();
if (cl && !cl->hasKnownSwiftImplementation())
return RuntimeEffect::MetaData | RuntimeEffect::ObjectiveC;
return RuntimeEffect::MetaData;
}
RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) {
switch (inst->getKind()) {
case SILInstructionKind::TailAddrInst:
case SILInstructionKind::IndexRawPointerInst:
case SILInstructionKind::FunctionRefInst:
case SILInstructionKind::DynamicFunctionRefInst:
case SILInstructionKind::PreviousDynamicFunctionRefInst:
case SILInstructionKind::GlobalAddrInst:
case SILInstructionKind::BaseAddrForOffsetInst:
case SILInstructionKind::IntegerLiteralInst:
case SILInstructionKind::FloatLiteralInst:
case SILInstructionKind::StringLiteralInst:
case SILInstructionKind::ClassMethodInst:
case SILInstructionKind::ObjCMethodInst:
case SILInstructionKind::ObjCSuperMethodInst:
case SILInstructionKind::UpcastInst:
case SILInstructionKind::AddressToPointerInst:
case SILInstructionKind::PointerToAddressInst:
case SILInstructionKind::UncheckedRefCastInst:
case SILInstructionKind::UncheckedAddrCastInst:
case SILInstructionKind::UncheckedTrivialBitCastInst:
case SILInstructionKind::UncheckedBitwiseCastInst:
case SILInstructionKind::UncheckedValueCastInst:
case SILInstructionKind::RefToRawPointerInst:
case SILInstructionKind::RawPointerToRefInst:
#define LOADABLE_REF_STORAGE(Name, ...) \
case SILInstructionKind::RefTo##Name##Inst: \
case SILInstructionKind::Name##ToRefInst:
#include "swift/AST/ReferenceStorage.def"
#undef LOADABLE_REF_STORAGE_HELPER
case SILInstructionKind::ConvertFunctionInst:
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
case SILInstructionKind::ThinFunctionToPointerInst:
case SILInstructionKind::PointerToThinFunctionInst:
case SILInstructionKind::RefToBridgeObjectInst:
case SILInstructionKind::BridgeObjectToRefInst:
case SILInstructionKind::BridgeObjectToWordInst:
case SILInstructionKind::ThinToThickFunctionInst:
case SILInstructionKind::ThickToObjCMetatypeInst:
case SILInstructionKind::ObjCMetatypeToObjectInst:
case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
case SILInstructionKind::ClassifyBridgeObjectInst:
case SILInstructionKind::ValueToBridgeObjectInst:
case SILInstructionKind::MarkDependenceInst:
case SILInstructionKind::MoveValueInst:
case SILInstructionKind::UncheckedOwnershipConversionInst:
case SILInstructionKind::LoadInst:
case SILInstructionKind::LoadBorrowInst:
case SILInstructionKind::BeginBorrowInst:
case SILInstructionKind::StoreBorrowInst:
case SILInstructionKind::MarkUninitializedInst:
case SILInstructionKind::ProjectExistentialBoxInst:
case SILInstructionKind::ObjCProtocolInst:
case SILInstructionKind::ObjectInst:
case SILInstructionKind::TupleInst:
case SILInstructionKind::TupleExtractInst:
case SILInstructionKind::StructInst:
case SILInstructionKind::StructExtractInst:
case SILInstructionKind::RefElementAddrInst:
case SILInstructionKind::EnumInst:
case SILInstructionKind::UncheckedEnumDataInst:
case SILInstructionKind::InitEnumDataAddrInst:
case SILInstructionKind::UncheckedTakeEnumDataAddrInst:
case SILInstructionKind::SelectEnumInst:
case SILInstructionKind::SelectEnumAddrInst:
case SILInstructionKind::SelectValueInst:
case SILInstructionKind::OpenExistentialMetatypeInst:
case SILInstructionKind::OpenExistentialBoxInst:
case SILInstructionKind::OpenExistentialValueInst:
case SILInstructionKind::OpenExistentialBoxValueInst:
case SILInstructionKind::ProjectBlockStorageInst:
case SILInstructionKind::UnreachableInst:
case SILInstructionKind::ReturnInst:
case SILInstructionKind::ThrowInst:
case SILInstructionKind::YieldInst:
case SILInstructionKind::UnwindInst:
case SILInstructionKind::BranchInst:
case SILInstructionKind::CondBranchInst:
case SILInstructionKind::SwitchValueInst:
case SILInstructionKind::SwitchEnumInst:
case SILInstructionKind::DeallocStackInst:
case SILInstructionKind::AutoreleaseValueInst:
case SILInstructionKind::BindMemoryInst:
case SILInstructionKind::FixLifetimeInst:
case SILInstructionKind::EndBorrowInst:
case SILInstructionKind::AssignInst:
case SILInstructionKind::AssignByWrapperInst:
case SILInstructionKind::MarkFunctionEscapeInst:
case SILInstructionKind::EndLifetimeInst:
case SILInstructionKind::EndApplyInst:
case SILInstructionKind::AbortApplyInst:
case SILInstructionKind::CondFailInst:
case SILInstructionKind::DestructureStructInst:
case SILInstructionKind::DestructureTupleInst:
case SILInstructionKind::DifferentiableFunctionInst:
case SILInstructionKind::DifferentiableFunctionExtractInst:
case SILInstructionKind::LinearFunctionInst:
case SILInstructionKind::LinearFunctionExtractInst:
case SILInstructionKind::DifferentiabilityWitnessFunctionInst:
case SILInstructionKind::EndCOWMutationInst:
return RuntimeEffect::NoEffect;
case SILInstructionKind::DebugValueInst:
// Ignore runtime calls of debug_vlaue
return RuntimeEffect::NoEffect;
case SILInstructionKind::GetAsyncContinuationInst:
case SILInstructionKind::GetAsyncContinuationAddrInst:
case SILInstructionKind::AwaitAsyncContinuationInst:
case SILInstructionKind::HopToExecutorInst:
case SILInstructionKind::ExtractExecutorInst:
return RuntimeEffect::Concurrency;
case SILInstructionKind::KeyPathInst:
return RuntimeEffect::Allocating | RuntimeEffect::Releasing |
RuntimeEffect::MetaData;
case SILInstructionKind::SwitchEnumAddrInst:
case SILInstructionKind::InjectEnumAddrInst:
case SILInstructionKind::TupleElementAddrInst:
case SILInstructionKind::StructElementAddrInst:
case SILInstructionKind::IndexAddrInst:
// TODO: hasArchetype() ?
if (!inst->getOperand(0)->getType().isLoadable(*inst->getFunction())) {
impactType = inst->getOperand(0)->getType();
return RuntimeEffect::MetaData;
}
return RuntimeEffect::NoEffect;
case SILInstructionKind::RefTailAddrInst:
if (!cast<RefTailAddrInst>(inst)->getTailType().isLoadable(*inst->getFunction())) {
impactType = cast<RefTailAddrInst>(inst)->getTailType();
return RuntimeEffect::MetaData;
}
return RuntimeEffect::NoEffect;
case SILInstructionKind::BeginAccessInst:
if (cast<BeginAccessInst>(inst)->getEnforcement() ==
SILAccessEnforcement::Dynamic)
return RuntimeEffect::ExclusivityChecking;
return RuntimeEffect::NoEffect;
case SILInstructionKind::EndAccessInst:
if (cast<EndAccessInst>(inst)->getBeginAccess()->getEnforcement() ==
SILAccessEnforcement::Dynamic)
return RuntimeEffect::ExclusivityChecking;
return RuntimeEffect::NoEffect;
case SILInstructionKind::BeginUnpairedAccessInst:
if (cast<BeginUnpairedAccessInst>(inst)->getEnforcement() ==
SILAccessEnforcement::Dynamic)
return RuntimeEffect::ExclusivityChecking;
return RuntimeEffect::NoEffect;
case SILInstructionKind::EndUnpairedAccessInst:
if (cast<EndUnpairedAccessInst>(inst)->getEnforcement() ==
SILAccessEnforcement::Dynamic)
return RuntimeEffect::ExclusivityChecking;
return RuntimeEffect::NoEffect;
case SILInstructionKind::InitExistentialAddrInst:
case SILInstructionKind::InitExistentialValueInst:
impactType = inst->getOperand(0)->getType();
return RuntimeEffect::Allocating | RuntimeEffect::Releasing |
RuntimeEffect::MetaData;
case SILInstructionKind::InitExistentialRefInst:
case SILInstructionKind::InitExistentialMetatypeInst:
case SILInstructionKind::ObjCToThickMetatypeInst:
impactType = inst->getOperand(0)->getType();
return RuntimeEffect::MetaData;
case SILInstructionKind::OpenExistentialAddrInst:
if (cast<OpenExistentialAddrInst>(inst)->getAccessKind() ==
OpenedExistentialAccess::Mutable)
return RuntimeEffect::Allocating;
return RuntimeEffect::NoEffect;
case SILInstructionKind::OpenExistentialRefInst: {
SILType opType = cast<OpenExistentialRefInst>(inst)->getOperand()->getType();
impactType = opType;
if (opType.getASTType()->isObjCExistentialType()) {
return RuntimeEffect::MetaData;
}
return RuntimeEffect::MetaData;
// TODO: should be NoEffect
//return RuntimeEffect::NoEffect;
}
case SILInstructionKind::UnconditionalCheckedCastValueInst:
case SILInstructionKind::UnconditionalCheckedCastInst:
impactType = inst->getOperand(0)->getType();
return RuntimeEffect::Casting | metadataEffect(impactType) |
metadataEffect(cast<SingleValueInstruction>(inst)->getType());
case SILInstructionKind::UnconditionalCheckedCastAddrInst:
case SILInstructionKind::CheckedCastAddrBranchInst:
case SILInstructionKind::UncheckedRefCastAddrInst:
impactType = inst->getOperand(0)->getType();
return RuntimeEffect::Casting | metadataEffect(impactType) |
metadataEffect(inst->getOperand(1)->getType());
case SILInstructionKind::CheckedCastBranchInst:
impactType = inst->getOperand(0)->getType();
return RuntimeEffect::Casting | metadataEffect(impactType) |
metadataEffect(cast<CheckedCastBranchInst>(inst)->getTargetLoweredType());
case SILInstructionKind::CheckedCastValueBranchInst:
impactType = inst->getOperand(0)->getType();
return RuntimeEffect::Casting | metadataEffect(impactType) |
metadataEffect(cast<CheckedCastValueBranchInst>(inst)->getTargetLoweredType());
case SILInstructionKind::AllocStackInst:
case SILInstructionKind::ProjectBoxInst:
if (!cast<SingleValueInstruction>(inst)->getType().
isLoadable(*inst->getFunction())) {
impactType = cast<SingleValueInstruction>(inst)->getType();
return RuntimeEffect::MetaData;
}
return RuntimeEffect::NoEffect;
case SILInstructionKind::AllocGlobalInst: {
SILType glTy = cast<AllocGlobalInst>(inst)->getReferencedGlobal()->
getLoweredType();
if (glTy.hasOpaqueArchetype()) {
impactType = glTy;
return RuntimeEffect::Allocating | RuntimeEffect::MetaData;
}
return RuntimeEffect::Allocating;
}
case SILInstructionKind::AllocBoxInst:
case SILInstructionKind::AllocExistentialBoxInst:
case SILInstructionKind::AllocRefInst:
case SILInstructionKind::AllocRefDynamicInst:
impactType = cast<SingleValueInstruction>(inst)->getType();
return RuntimeEffect::Allocating | RuntimeEffect::MetaData |
// TODO: why Releasing?
RuntimeEffect::Releasing;
case SILInstructionKind::DeallocRefInst:
case SILInstructionKind::DeallocPartialRefInst:
case SILInstructionKind::DeallocBoxInst:
case SILInstructionKind::DeallocExistentialBoxInst:
case SILInstructionKind::DeinitExistentialAddrInst:
case SILInstructionKind::DeinitExistentialValueInst:
return RuntimeEffect::Deallocating;
case SILInstructionKind::CopyAddrInst: {
auto *ca = cast<CopyAddrInst>(inst);
impactType = ca->getSrc()->getType();
if (!ca->isInitializationOfDest())
return RuntimeEffect::MetaData | RuntimeEffect::Releasing;
if (!ca->isTakeOfSrc())
return RuntimeEffect::MetaData | RuntimeEffect::RefCounting;
return RuntimeEffect::MetaData;
}
case SILInstructionKind::StoreInst:
switch (cast<StoreInst>(inst)->getOwnershipQualifier()) {
case StoreOwnershipQualifier::Unqualified:
case StoreOwnershipQualifier::Trivial:
return RuntimeEffect::NoEffect;
case StoreOwnershipQualifier::Init:
return RuntimeEffect::RefCounting;
case StoreOwnershipQualifier::Assign:
return RuntimeEffect::Releasing;
}
case SILInstructionKind::DestroyAddrInst:
impactType = inst->getOperand(0)->getType();
if (impactType.isTrivial(*inst->getFunction()))
return RuntimeEffect::NoEffect;
if (!impactType.isLoadable(*inst->getFunction()))
return RuntimeEffect::Releasing | RuntimeEffect::MetaData;
return RuntimeEffect::Releasing;
case SILInstructionKind::ValueMetatypeInst:
case SILInstructionKind::MetatypeInst: {
auto metaTy = cast<SingleValueInstruction>(inst)->getType().castTo<MetatypeType>();
if (metaTy->getRepresentation() != MetatypeRepresentation::Thin) {
Type instTy = metaTy->getInstanceType();
if (instTy->isLegalSILType())
impactType = SILType::getPrimitiveObjectType(CanType(instTy));
if (auto selfType = instTy->getAs<DynamicSelfType>())
instTy = selfType->getSelfType();
auto *cl = instTy->getClassOrBoundGenericClass();
if ((cl && (cl->usesObjCObjectModel() || cl->isForeign())) ||
instTy->isAnyObject())
return RuntimeEffect::MetaData | RuntimeEffect::ObjectiveC;
return RuntimeEffect::MetaData;
}
return RuntimeEffect::NoEffect;
}
case SILInstructionKind::ExistentialMetatypeInst: {
SILType opType = cast<ExistentialMetatypeInst>(inst)->getOperand()->getType();
impactType = opType;
switch (opType.getPreferredExistentialRepresentation()) {
case ExistentialRepresentation::Metatype:
case ExistentialRepresentation::Boxed:
case ExistentialRepresentation::Opaque:
return RuntimeEffect::MetaData;
case ExistentialRepresentation::Class: {
auto *cl = opType.getClassOrBoundGenericClass();
if ((cl && cl->usesObjCObjectModel()) || opType.isAnyObject())
return RuntimeEffect::MetaData | RuntimeEffect::ObjectiveC;
return RuntimeEffect::MetaData | RuntimeEffect::ObjectiveC;
}
case ExistentialRepresentation::None:
return RuntimeEffect::NoEffect;
}
llvm_unreachable("Bad existential representation");
}
case SILInstructionKind::StrongRetainInst:
case SILInstructionKind::UnmanagedRetainValueInst:
case SILInstructionKind::RetainValueAddrInst:
case SILInstructionKind::RetainValueInst:
case SILInstructionKind::BeginCOWMutationInst:
case SILInstructionKind::CopyValueInst:
case SILInstructionKind::SetDeallocatingInst:
case SILInstructionKind::IsUniqueInst:
case SILInstructionKind::IsEscapingClosureInst:
case SILInstructionKind::CopyBlockInst:
case SILInstructionKind::CopyBlockWithoutEscapingInst:
return RuntimeEffect::RefCounting;
case SILInstructionKind::InitBlockStorageHeaderInst:
return RuntimeEffect::Releasing;
case SILInstructionKind::StrongReleaseInst:
case SILInstructionKind::UnmanagedReleaseValueInst:
case SILInstructionKind::UnmanagedAutoreleaseValueInst:
case SILInstructionKind::ReleaseValueInst:
case SILInstructionKind::ReleaseValueAddrInst:
case SILInstructionKind::DestroyValueInst:
impactType = inst->getOperand(0)->getType();
if (impactType.isBlockPointerCompatible())
return RuntimeEffect::ObjectiveC | RuntimeEffect::Releasing;
return RuntimeEffect::Releasing;
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::StrongRetain##Name##Inst: \
case SILInstructionKind::Name##RetainInst: \
return RuntimeEffect::RefCounting; \
case SILInstructionKind::Name##ReleaseInst: \
return RuntimeEffect::Releasing;
#include "swift/AST/ReferenceStorage.def"
#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE
#define UNCHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::StrongCopy##Name##ValueInst: \
return RuntimeEffect::RefCounting;
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::StrongCopy##Name##ValueInst: \
return RuntimeEffect::RefCounting;
#include "swift/AST/ReferenceStorage.def"
#undef UNCHECKED_REF_STORAGE
#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::Store##Name##Inst: \
return RuntimeEffect::Releasing;
#include "swift/AST/ReferenceStorage.def"
#undef NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \
case SILInstructionKind::Load##Name##Inst: \
return RuntimeEffect::RefCounting;
#include "swift/AST/ReferenceStorage.def"
#undef NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE
case SILInstructionKind::GlobalValueInst:
return RuntimeEffect::Locking | RuntimeEffect::MetaData;
case SILInstructionKind::DynamicMethodBranchInst:
return RuntimeEffect::ObjectiveC;
case SILInstructionKind::PartialApplyInst:
case SILInstructionKind::ApplyInst:
case SILInstructionKind::TryApplyInst:
case SILInstructionKind::BeginApplyInst: {
RuntimeEffect rt = RuntimeEffect::NoEffect;
auto as = ApplySite(inst);
switch (as.getSubstCalleeType()->getRepresentation()) {
case SILFunctionTypeRepresentation::ObjCMethod:
case SILFunctionTypeRepresentation::Block:
rt |= RuntimeEffect::ObjectiveC | RuntimeEffect::MetaData;
break;
case SILFunctionTypeRepresentation::WitnessMethod:
rt |= RuntimeEffect::MetaData;
break;
case SILFunctionTypeRepresentation::CFunctionPointer:
case SILFunctionTypeRepresentation::Thin:
case SILFunctionTypeRepresentation::Method:
case SILFunctionTypeRepresentation::Closure:
case SILFunctionTypeRepresentation::Thick:
break;
}
if (isa<BeginApplyInst>(inst))
rt |= RuntimeEffect::Allocating;
if (auto *pa = dyn_cast<PartialApplyInst>(inst)) {
if (pa->isOnStack()) {
for (SILValue arg : pa->getArguments()) {
if (!arg->getType().isTrivial(*pa->getFunction()))
rt |= RuntimeEffect::RefCounting;
}
} else {
rt |= RuntimeEffect::Allocating | RuntimeEffect::Releasing;
}
}
if (!as.getSubstitutionMap().empty())
rt |= RuntimeEffect::MetaData;
if (auto *pa = dyn_cast<PartialApplyInst>(inst)) {
if (!pa->isOnStack())
rt |= RuntimeEffect::MetaData;
}
return rt;
}
case SILInstructionKind::WitnessMethodInst: {
return RuntimeEffect::MetaData;
}
case SILInstructionKind::SuperMethodInst: {
auto method = cast<SuperMethodInst>(inst)->getMember().getOverriddenVTableEntry();
auto *classDecl = cast<ClassDecl>(method.getDecl()->getDeclContext());
if (classDecl->hasResilientMetadata())
return RuntimeEffect::MetaData;
return RuntimeEffect::NoEffect;
}
case SILInstructionKind::BuiltinInst:
switch (cast<BuiltinInst>(inst)->getBuiltinInfo().ID) {
case BuiltinValueKind::Once:
case BuiltinValueKind::OnceWithContext:
return RuntimeEffect::Locking;
case BuiltinValueKind::IsUnique:
return RuntimeEffect::RefCounting;
case BuiltinValueKind::IsOptionalType:
return RuntimeEffect::Casting;
case BuiltinValueKind::AllocRaw:
return RuntimeEffect::Allocating;
case BuiltinValueKind::DeallocRaw:
return RuntimeEffect::Deallocating;
case BuiltinValueKind::Fence:
case BuiltinValueKind::CmpXChg:
case BuiltinValueKind::AtomicLoad:
case BuiltinValueKind::AtomicStore:
case BuiltinValueKind::AtomicRMW:
return RuntimeEffect::Locking;
case BuiltinValueKind::DestroyArray:
return RuntimeEffect::Releasing;
case BuiltinValueKind::CopyArray:
return RuntimeEffect::RefCounting;
case BuiltinValueKind::AssignCopyArrayNoAlias:
case BuiltinValueKind::AssignCopyArrayFrontToBack:
case BuiltinValueKind::AssignCopyArrayBackToFront:
case BuiltinValueKind::AssignTakeArray:
return RuntimeEffect::RefCounting | RuntimeEffect::Deallocating;
case BuiltinValueKind::Swift3ImplicitObjCEntrypoint:
return RuntimeEffect::ObjectiveC | RuntimeEffect::Allocating;
case BuiltinValueKind::BuildOrdinarySerialExecutorRef:
case BuiltinValueKind::BuildDefaultActorExecutorRef:
case BuiltinValueKind::BuildMainActorExecutorRef:
case BuiltinValueKind::StartAsyncLet:
case BuiltinValueKind::StartAsyncLetWithLocalBuffer:
return RuntimeEffect::MetaData;
default:
break;
}
return RuntimeEffect::NoEffect;
}
}
/// Given a block used as a noescape function argument, attempt to find all /// Given a block used as a noescape function argument, attempt to find all
/// Swift closures that invoking the block will call. The StoredClosures may not /// Swift closures that invoking the block will call. The StoredClosures may not
/// actually be partial_apply instructions. They may be copied, block arguments, /// actually be partial_apply instructions. They may be copied, block arguments,