mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Specifically: 1. swift_task_addCancellationHandler 2. swift_task_removeCancellationHandler 3. swift_task_addPriorityEscalationHandler 4. swift_task_removePriorityEscalationHandler 5. swift_task_localValuePush 6. swift_task_localValuePop rdar://109850951
770 lines
35 KiB
C++
770 lines
35 KiB
C++
//===--- ValueOwnership.cpp -----------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2022 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/SIL/ApplySite.h"
|
|
#include "swift/SIL/SILBuiltinVisitor.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "swift/SIL/SILVisitor.h"
|
|
#include "swift/SIL/Test.h"
|
|
|
|
using namespace swift;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Interface
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
class ValueOwnershipKindClassifier
|
|
: public SILValueVisitor<ValueOwnershipKindClassifier, ValueOwnershipKind> {
|
|
|
|
public:
|
|
ValueOwnershipKindClassifier() = default;
|
|
~ValueOwnershipKindClassifier() = default;
|
|
ValueOwnershipKindClassifier(const ValueOwnershipKindClassifier &) = delete;
|
|
ValueOwnershipKindClassifier(ValueOwnershipKindClassifier &&) = delete;
|
|
|
|
ValueOwnershipKind visitForwardingInst(SILInstruction *I,
|
|
ArrayRef<Operand> Ops);
|
|
ValueOwnershipKind visitForwardingInst(SILInstruction *I) {
|
|
return visitForwardingInst(I, I->getAllOperands());
|
|
}
|
|
|
|
#define VALUE(Id, Parent) ValueOwnershipKind visit##Id(Id *ID);
|
|
#include "swift/SIL/SILNodes.def"
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
#define CONSTANT_OWNERSHIP_INST(OWNERSHIP, INST) \
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \
|
|
INST##Inst *Arg) { \
|
|
return OwnershipKind::OWNERSHIP; \
|
|
}
|
|
|
|
CONSTANT_OWNERSHIP_INST(Owned, UnownedCopyValue)
|
|
CONSTANT_OWNERSHIP_INST(Owned, WeakCopyValue)
|
|
#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
|
|
CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value) \
|
|
CONSTANT_OWNERSHIP_INST(Owned, Load##Name)
|
|
#define ALWAYS_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
|
|
CONSTANT_OWNERSHIP_INST(Unowned, RefTo##Name) \
|
|
CONSTANT_OWNERSHIP_INST(Unowned, Name##ToRef) \
|
|
CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value)
|
|
#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
|
|
CONSTANT_OWNERSHIP_INST(Owned, Load##Name) \
|
|
CONSTANT_OWNERSHIP_INST(Unowned, RefTo##Name) \
|
|
CONSTANT_OWNERSHIP_INST(Unowned, Name##ToRef) \
|
|
CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value)
|
|
#define UNCHECKED_REF_STORAGE(Name, ...) \
|
|
CONSTANT_OWNERSHIP_INST(None, RefTo##Name) \
|
|
CONSTANT_OWNERSHIP_INST(Unowned, Name##ToRef) \
|
|
CONSTANT_OWNERSHIP_INST(Owned, StrongCopy##Name##Value)
|
|
#include "swift/AST/ReferenceStorage.def"
|
|
|
|
CONSTANT_OWNERSHIP_INST(Guaranteed, BeginBorrow)
|
|
CONSTANT_OWNERSHIP_INST(Guaranteed, BorrowedFrom)
|
|
CONSTANT_OWNERSHIP_INST(Guaranteed, LoadBorrow)
|
|
CONSTANT_OWNERSHIP_INST(Guaranteed, FunctionExtractIsolation)
|
|
CONSTANT_OWNERSHIP_INST(Guaranteed, ImplicitActorToOpaqueIsolationCast)
|
|
CONSTANT_OWNERSHIP_INST(None, GlobalValue)
|
|
CONSTANT_OWNERSHIP_INST(Owned, AllocBox)
|
|
CONSTANT_OWNERSHIP_INST(Owned, AllocExistentialBox)
|
|
CONSTANT_OWNERSHIP_INST(Owned, AllocRef)
|
|
CONSTANT_OWNERSHIP_INST(Owned, AllocRefDynamic)
|
|
CONSTANT_OWNERSHIP_INST(Owned, CopyBlock)
|
|
CONSTANT_OWNERSHIP_INST(Owned, CopyBlockWithoutEscaping)
|
|
CONSTANT_OWNERSHIP_INST(Owned, CopyValue)
|
|
CONSTANT_OWNERSHIP_INST(Owned, ExplicitCopyValue)
|
|
CONSTANT_OWNERSHIP_INST(Owned, EndCOWMutation)
|
|
CONSTANT_OWNERSHIP_INST(Owned, EndInitLetRef)
|
|
CONSTANT_OWNERSHIP_INST(Owned, BeginDeallocRef)
|
|
CONSTANT_OWNERSHIP_INST(Owned, KeyPath)
|
|
CONSTANT_OWNERSHIP_INST(Owned, InitExistentialValue)
|
|
CONSTANT_OWNERSHIP_INST(Owned, Thunk)
|
|
|
|
// One would think that these /should/ be unowned. In truth they are owned since
|
|
// objc metatypes do not go through the retain/release fast path. In their
|
|
// implementations of retain/release nothing happens, so this is safe.
|
|
//
|
|
// You could even have an optimization that just always removed retain/release
|
|
// operations on these objects.
|
|
CONSTANT_OWNERSHIP_INST(Owned, ObjCExistentialMetatypeToObject)
|
|
CONSTANT_OWNERSHIP_INST(Owned, ObjCMetatypeToObject)
|
|
|
|
// All addresses have trivial ownership. The values stored at the address may
|
|
// not though.
|
|
CONSTANT_OWNERSHIP_INST(None, AddressToPointer)
|
|
CONSTANT_OWNERSHIP_INST(None, AllocStack)
|
|
CONSTANT_OWNERSHIP_INST(None, AllocPack)
|
|
CONSTANT_OWNERSHIP_INST(None, AllocPackMetadata)
|
|
CONSTANT_OWNERSHIP_INST(None, PackLength)
|
|
CONSTANT_OWNERSHIP_INST(None, BeginAccess)
|
|
CONSTANT_OWNERSHIP_INST(None, MoveOnlyWrapperToCopyableAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, CopyableToMoveOnlyWrapperAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, BindMemory)
|
|
CONSTANT_OWNERSHIP_INST(None, RebindMemory)
|
|
CONSTANT_OWNERSHIP_INST(None, BridgeObjectToWord)
|
|
CONSTANT_OWNERSHIP_INST(None, ClassMethod)
|
|
CONSTANT_OWNERSHIP_INST(None, ClassifyBridgeObject)
|
|
CONSTANT_OWNERSHIP_INST(None, ObjCMethod)
|
|
CONSTANT_OWNERSHIP_INST(None, ExistentialMetatype)
|
|
CONSTANT_OWNERSHIP_INST(None, FloatLiteral)
|
|
CONSTANT_OWNERSHIP_INST(None, FunctionRef)
|
|
CONSTANT_OWNERSHIP_INST(None, DynamicFunctionRef)
|
|
CONSTANT_OWNERSHIP_INST(None, PreviousDynamicFunctionRef)
|
|
CONSTANT_OWNERSHIP_INST(None, GlobalAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, BaseAddrForOffset)
|
|
CONSTANT_OWNERSHIP_INST(None, HasSymbol)
|
|
CONSTANT_OWNERSHIP_INST(None, VectorBaseAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, IndexAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, IndexRawPointer)
|
|
CONSTANT_OWNERSHIP_INST(None, InitEnumDataAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, InitExistentialAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, InitExistentialMetatype)
|
|
CONSTANT_OWNERSHIP_INST(None, IntegerLiteral)
|
|
CONSTANT_OWNERSHIP_INST(None, IsUnique)
|
|
CONSTANT_OWNERSHIP_INST(None, DestroyNotEscapedClosure)
|
|
CONSTANT_OWNERSHIP_INST(None, Metatype)
|
|
CONSTANT_OWNERSHIP_INST(None, ObjCToThickMetatype)
|
|
CONSTANT_OWNERSHIP_INST(None, OpenExistentialAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, OpenExistentialBox)
|
|
CONSTANT_OWNERSHIP_INST(None, OpenExistentialMetatype)
|
|
CONSTANT_OWNERSHIP_INST(None, PointerToAddress)
|
|
CONSTANT_OWNERSHIP_INST(None, ProjectBlockStorage)
|
|
CONSTANT_OWNERSHIP_INST(None, ProjectBox)
|
|
CONSTANT_OWNERSHIP_INST(None, ProjectExistentialBox)
|
|
CONSTANT_OWNERSHIP_INST(None, RefElementAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, RefTailAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, RefToRawPointer)
|
|
CONSTANT_OWNERSHIP_INST(None, SelectEnum)
|
|
CONSTANT_OWNERSHIP_INST(None, SelectEnumAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, StringLiteral)
|
|
CONSTANT_OWNERSHIP_INST(None, StructElementAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, SuperMethod)
|
|
CONSTANT_OWNERSHIP_INST(None, ObjCSuperMethod)
|
|
CONSTANT_OWNERSHIP_INST(None, TailAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, ThickToObjCMetatype)
|
|
CONSTANT_OWNERSHIP_INST(None, TupleElementAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, UncheckedAddrCast)
|
|
CONSTANT_OWNERSHIP_INST(None, UncheckedTakeEnumDataAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, UncheckedTrivialBitCast)
|
|
CONSTANT_OWNERSHIP_INST(None, ValueMetatype)
|
|
CONSTANT_OWNERSHIP_INST(None, WitnessMethod)
|
|
CONSTANT_OWNERSHIP_INST(None, StoreBorrow)
|
|
CONSTANT_OWNERSHIP_INST(Owned, ConvertEscapeToNoEscape)
|
|
CONSTANT_OWNERSHIP_INST(Unowned, InitBlockStorageHeader)
|
|
CONSTANT_OWNERSHIP_INST(None, DifferentiabilityWitnessFunction)
|
|
// TODO: It would be great to get rid of these.
|
|
CONSTANT_OWNERSHIP_INST(Unowned, RawPointerToRef)
|
|
CONSTANT_OWNERSHIP_INST(Unowned, ObjCProtocol)
|
|
CONSTANT_OWNERSHIP_INST(Unowned, ValueToBridgeObject)
|
|
CONSTANT_OWNERSHIP_INST(None, GetAsyncContinuation)
|
|
CONSTANT_OWNERSHIP_INST(None, GetAsyncContinuationAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, ThinToThickFunction)
|
|
CONSTANT_OWNERSHIP_INST(None, ExtractExecutor)
|
|
CONSTANT_OWNERSHIP_INST(None, OpenPackElement)
|
|
CONSTANT_OWNERSHIP_INST(None, DynamicPackIndex)
|
|
CONSTANT_OWNERSHIP_INST(None, PackPackIndex)
|
|
CONSTANT_OWNERSHIP_INST(None, ScalarPackIndex)
|
|
CONSTANT_OWNERSHIP_INST(None, PackElementGet)
|
|
CONSTANT_OWNERSHIP_INST(None, TuplePackElementAddr)
|
|
CONSTANT_OWNERSHIP_INST(None, Object)
|
|
CONSTANT_OWNERSHIP_INST(None, Vector)
|
|
CONSTANT_OWNERSHIP_INST(None, TypeValue)
|
|
|
|
#undef CONSTANT_OWNERSHIP_INST
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitStructExtractInst(StructExtractInst *sei) {
|
|
if (sei->getType().isTrivial(*sei->getFunction()) ||
|
|
// A struct value can have "none" ownership even if its type is not trivial.
|
|
// This happens when the struct/tuple contains a non-trivial enum, but it's initialized with
|
|
// a trivial enum case (e.g. with `Optional.none`).
|
|
sei->getOperand()->getOwnershipKind() == OwnershipKind::None) {
|
|
return OwnershipKind::None;
|
|
}
|
|
return OwnershipKind::Guaranteed;
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitTupleExtractInst(TupleExtractInst *tei) {
|
|
if (tei->getType().isTrivial(*tei->getFunction()) ||
|
|
// A tuple value can have "none" ownership even if its type is not trivial.
|
|
// This happens when the struct/tuple contains a non-trivial enum, but it's initialized with
|
|
// a trivial enum case (e.g. with `Optional.none`).
|
|
tei->getOperand()->getOwnershipKind() == OwnershipKind::None)
|
|
return OwnershipKind::None;
|
|
return OwnershipKind::Guaranteed;
|
|
}
|
|
|
|
#define CONSTANT_OR_NONE_OWNERSHIP_INST(OWNERSHIP, INST) \
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \
|
|
INST##Inst *I) { \
|
|
if (I->getType().isTrivial(*I->getFunction()) || \
|
|
I->getType().isAddress()) { \
|
|
return OwnershipKind::None; \
|
|
} \
|
|
return OwnershipKind::OWNERSHIP; \
|
|
}
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, TuplePackExtract)
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, DifferentiableFunctionExtract)
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, LinearFunctionExtract)
|
|
// OpenExistentialValue opens the boxed value inside an existential
|
|
// CoW box. The semantics of an existential CoW box implies that we
|
|
// can only consume the projected value inside the box if the box is
|
|
// unique. Since we do not know in general if the box is unique
|
|
// without additional work, in SIL we require opened archetypes to
|
|
// be borrowed sub-objects of the parent CoW box.
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, OpenExistentialValue)
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Guaranteed, OpenExistentialBoxValue)
|
|
|
|
// Given an owned value, mark_uninitialized always forwards an owned value since
|
|
// we want to make sure that all destroys of that value must come through the
|
|
// mark_uninitialized (which will happen due to mark_uninitialized consuming the
|
|
// value).
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Owned, MarkUninitialized)
|
|
|
|
// In raw SIL, a MoveValue delimits the scope of trivial variables.
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Owned, MoveValue)
|
|
|
|
// result.
|
|
//
|
|
// If the operand is nontrivial and the result is trivial, then it is the
|
|
// programmer's responsibility to use Builtin.fixLifetime.
|
|
//
|
|
// If both the operand and the result are nontrivial, then either the types must
|
|
// be compatible so that TBAA doesn't allow the destroy to be hoisted above uses
|
|
// of the cast, or the programmer must use Builtin.fixLifetime.
|
|
//
|
|
// FIXME(https://github.com/apple/swift/issues/49723): Since we model this as unowned, then we must copy the value before use.
|
|
// This directly contradicts the semantics mentioned above since we will copy
|
|
// the value upon any use lest we use an unowned value in an owned or guaranteed
|
|
// way. So really all we will do here is perhaps add a copy slightly earlier
|
|
// unless the unowned value immediately is cast to something trivial. In such a
|
|
// case, we should be able to simplify the cast to just a trivial value and
|
|
// then eliminate the copy. That being said, we should investigate
|
|
// this since this is used in reinterpret_cast which is important from
|
|
// a performance perspective.
|
|
CONSTANT_OR_NONE_OWNERSHIP_INST(Unowned, UncheckedBitwiseCast)
|
|
|
|
#undef CONSTANT_OR_NONE_OWNERSHIP_INST
|
|
|
|
// For a forwarding instruction, we loop over all operands and make sure that
|
|
// all non-trivial values have the same ownership.
|
|
ValueOwnershipKind
|
|
ValueOwnershipKindClassifier::visitForwardingInst(SILInstruction *i,
|
|
ArrayRef<Operand> ops) {
|
|
// A forwarding inst without operands must be trivial.
|
|
if (ops.empty())
|
|
return OwnershipKind::None;
|
|
|
|
auto mergedValue = ValueOwnershipKind::merge(makeOptionalTransformRange(
|
|
ops, [&i](const Operand &op) -> std::optional<ValueOwnershipKind> {
|
|
if (i->isTypeDependentOperand(op))
|
|
return std::nullopt;
|
|
return op.get()->getOwnershipKind();
|
|
}));
|
|
|
|
if (!mergedValue) {
|
|
// If we have mismatched SILOwnership and sil ownership is not enabled,
|
|
// just return None for staging purposes. If SILOwnership is enabled, then
|
|
// we must assert!
|
|
if (!i->getModule().getOptions().VerifySILOwnership) {
|
|
return OwnershipKind::None;
|
|
}
|
|
llvm_unreachable("Forwarding inst with mismatching ownership kinds?!");
|
|
}
|
|
|
|
return mergedValue;
|
|
}
|
|
|
|
#define FORWARDING_OWNERSHIP_INST(INST) \
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \
|
|
INST##Inst *I) { \
|
|
return I->getType().isTrivial(*I->getFunction()) \
|
|
? ValueOwnershipKind(OwnershipKind::None) \
|
|
: I->getForwardingOwnershipKind(); \
|
|
}
|
|
FORWARDING_OWNERSHIP_INST(BridgeObjectToRef)
|
|
FORWARDING_OWNERSHIP_INST(ConvertFunction)
|
|
FORWARDING_OWNERSHIP_INST(OpenExistentialRef)
|
|
FORWARDING_OWNERSHIP_INST(RefToBridgeObject)
|
|
FORWARDING_OWNERSHIP_INST(Struct)
|
|
FORWARDING_OWNERSHIP_INST(Tuple)
|
|
FORWARDING_OWNERSHIP_INST(UncheckedRefCast)
|
|
FORWARDING_OWNERSHIP_INST(UnconditionalCheckedCast)
|
|
FORWARDING_OWNERSHIP_INST(Upcast)
|
|
FORWARDING_OWNERSHIP_INST(UncheckedValueCast)
|
|
FORWARDING_OWNERSHIP_INST(UncheckedEnumData)
|
|
FORWARDING_OWNERSHIP_INST(MarkDependence)
|
|
// NOTE: init_existential_ref from a reference counting perspective is not
|
|
// considered to be "owned" since it doesn't affect reference counts. That being
|
|
// said in the past, we wanted to conceptually treat it as an owned value that
|
|
// produces owned things, rather than a forwarding thing since initialization is
|
|
// generally a consuming operation. That being said, there are often cases in
|
|
// class based code where we are propagating around a plus zero version of a
|
|
// value and need to wrap the class in an existential wrapper in an intermediate
|
|
// frame from usage. In such cases, we have been creating unnecessary ref count
|
|
// traffic in code.
|
|
FORWARDING_OWNERSHIP_INST(InitExistentialRef)
|
|
FORWARDING_OWNERSHIP_INST(DifferentiableFunction)
|
|
FORWARDING_OWNERSHIP_INST(LinearFunction)
|
|
FORWARDING_OWNERSHIP_INST(MarkUnresolvedNonCopyableValue)
|
|
FORWARDING_OWNERSHIP_INST(MarkUnresolvedReferenceBinding)
|
|
FORWARDING_OWNERSHIP_INST(MoveOnlyWrapperToCopyableValue)
|
|
FORWARDING_OWNERSHIP_INST(CopyableToMoveOnlyWrapperValue)
|
|
FORWARDING_OWNERSHIP_INST(MoveOnlyWrapperToCopyableBox)
|
|
FORWARDING_OWNERSHIP_INST(UncheckedOwnership)
|
|
#undef FORWARDING_OWNERSHIP_INST
|
|
|
|
ValueOwnershipKind
|
|
ValueOwnershipKindClassifier::visitEnumInst(EnumInst *I) {
|
|
if (!I->getModule().useLoweredAddresses() && I->getType().isAddressOnly(*I->getFunction())) {
|
|
// During address lowering, an address-only enum instruction will eventually
|
|
// be lowered to inject_enum_addr/init_enum_data_addr, initializing a
|
|
// non-trivial storage location. So prior to AddressLowering (in opaque
|
|
// values mode) such an enum instruction produces a non-trivial value,
|
|
// without regard to whether it is in a trivial case. Otherwise, non-trivial
|
|
// storage would fail to be destroy_addr'd.
|
|
assert(!I->getType().isTrivial(*I->getFunction()));
|
|
// An enum instruction is representation changing, so its address-only
|
|
// operand must be owned.
|
|
return OwnershipKind::Owned;
|
|
}
|
|
return I->getType().isTrivial(*I->getFunction())
|
|
? ValueOwnershipKind(OwnershipKind::None)
|
|
: I->getForwardingOwnershipKind();
|
|
}
|
|
|
|
ValueOwnershipKind
|
|
ValueOwnershipKindClassifier::visitUncheckedOwnershipConversionInst(
|
|
UncheckedOwnershipConversionInst *I) {
|
|
return I->getConversionOwnershipKind();
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitSILUndef(SILUndef *arg) {
|
|
return arg->getOwnershipKind();
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::
|
|
visitPlaceholderValue(PlaceholderValue *v) {
|
|
return OwnershipKind::None;
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::
|
|
visitMultipleValueInstructionResult(MultipleValueInstructionResult *Result) {
|
|
return Result->getOwnershipKind();
|
|
}
|
|
|
|
ValueOwnershipKind
|
|
ValueOwnershipKindClassifier::visitSILPhiArgument(SILPhiArgument *Arg) {
|
|
return Arg->getOwnershipKind();
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitSILFunctionArgument(
|
|
SILFunctionArgument *Arg) {
|
|
return Arg->getOwnershipKind();
|
|
}
|
|
|
|
// We have to separate out ResultType here as `begin_apply` does not produce
|
|
// normal results, `end_apply` does and there might be multiple `end_apply`'s
|
|
// that correspond to a single `begin_apply`.
|
|
static ValueOwnershipKind visitFullApplySite(FullApplySite fai,
|
|
SILType ResultType) {
|
|
auto *f = fai->getFunction();
|
|
bool isTrivial = ResultType.isTrivial(*f);
|
|
// Quick is trivial check.
|
|
if (isTrivial)
|
|
return OwnershipKind::None;
|
|
|
|
SILFunctionConventions fnConv(fai.getSubstCalleeType(), f->getModule());
|
|
auto results = fnConv.getDirectSILResults();
|
|
// No results => None.
|
|
if (results.empty())
|
|
return OwnershipKind::None;
|
|
|
|
// Otherwise, map our results to their ownership kinds and then merge them!
|
|
auto resultOwnershipKinds =
|
|
makeTransformRange(results, [&](const SILResultInfo &info) {
|
|
return info.getOwnershipKind(*f, fai.getSubstCalleeType());
|
|
});
|
|
auto mergedOwnershipKind = ValueOwnershipKind::merge(resultOwnershipKinds);
|
|
if (!mergedOwnershipKind) {
|
|
llvm_unreachable("Forwarding inst with mismatching ownership kinds?!");
|
|
}
|
|
|
|
return mergedOwnershipKind;
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitApplyInst(ApplyInst *ai) {
|
|
return visitFullApplySite(ai, ai->getType());
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitEndApplyInst(EndApplyInst *eai) {
|
|
return visitFullApplySite(eai->getBeginApply(), eai->getType());
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitLoadInst(LoadInst *LI) {
|
|
switch (LI->getOwnershipQualifier()) {
|
|
case LoadOwnershipQualifier::Take:
|
|
case LoadOwnershipQualifier::Copy:
|
|
return OwnershipKind::Owned;
|
|
case LoadOwnershipQualifier::Unqualified:
|
|
case LoadOwnershipQualifier::Trivial:
|
|
return OwnershipKind::None;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled LoadOwnershipQualifier in switch.");
|
|
}
|
|
|
|
ValueOwnershipKind ValueOwnershipKindClassifier::visitDropDeinitInst(DropDeinitInst *ddi) {
|
|
return ddi->getType().isAddress() ? OwnershipKind::None : OwnershipKind::Owned;
|
|
}
|
|
|
|
ValueOwnershipKind
|
|
ValueOwnershipKindClassifier::visitPartialApplyInst(PartialApplyInst *PA) {
|
|
// partial_apply instructions are modeled as creating an owned value during
|
|
// OSSA, to track borrows of their captures, and so that they can themselves
|
|
// be borrowed during calls, but they become trivial once ownership is
|
|
// lowered away.
|
|
if (PA->isOnStack() && !PA->getFunction()->hasOwnership())
|
|
return OwnershipKind::None;
|
|
return OwnershipKind::Owned;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Builtin OwnershipValueKind Computation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
struct ValueOwnershipKindBuiltinVisitor
|
|
: SILBuiltinVisitor<ValueOwnershipKindBuiltinVisitor, ValueOwnershipKind> {
|
|
|
|
ValueOwnershipKind visitLLVMIntrinsic(BuiltinInst *BI,
|
|
llvm::Intrinsic::ID ID) {
|
|
// LLVM intrinsics do not traffic in ownership, so if we have a result, it
|
|
// must be any.
|
|
return OwnershipKind::None;
|
|
}
|
|
|
|
#define BUILTIN(ID, NAME, ATTRS) \
|
|
ValueOwnershipKind visit##ID(BuiltinInst *BI, StringRef Attr);
|
|
#include "swift/AST/Builtins.def"
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
#define CONSTANT_OWNERSHIP_BUILTIN(OWNERSHIP, ID) \
|
|
ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID( \
|
|
BuiltinInst *BI, StringRef Attr) { \
|
|
return OwnershipKind::OWNERSHIP; \
|
|
}
|
|
// This returns a value at +1 that is destroyed strictly /after/ the
|
|
// UnsafeGuaranteedEnd. This provides the guarantee that we want.
|
|
CONSTANT_OWNERSHIP_BUILTIN(Owned, COWBufferForReading)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AddressOfBorrowOpaque)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UnprotectedAddressOfBorrowOpaque)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AShr)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericAShr)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Add)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericAdd)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, And)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericAnd)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssumeAlignment)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssumeNonNegative)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssumeTrue)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, BitCast)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, CondFailMessage)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ExactSDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericExactSDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ExactUDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericExactUDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FAdd)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericFAdd)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_OEQ)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_OGE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_OGT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_OLE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_OLT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_ONE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_UEQ)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_UGE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_UGT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_ULE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_ULT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_UNE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericFDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FMul)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericFMul)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FNeg)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FPExt)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FPToSI)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FPToUI)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FPTrunc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FRem)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericFRem)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FSub)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericFSub)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Freeze)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_EQ)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_NE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_SGE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_SGT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_SLE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_SLT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_UGE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_UGT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_ULE)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ICMP_ULT)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IntToPtr)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, LShr)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericLShr)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Mul)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericMul)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Or)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericOr)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, PtrToInt)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SAddOver)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericSDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SExt)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SExtOrBitCast)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SIToFP)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SMulOver)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SRem)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericSRem)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SSubOver)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Expect)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Shl)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericShl)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Sub)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericSub)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Trunc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TruncOrBitCast)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UAddOver)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericUDiv)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UIToFP)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UMulOver)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, URem)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericURem)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, USubOver)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Xor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GenericXor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ZExt)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ZExtOrBitCast)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_ORD)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FCMP_UNO)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, OnFastPath)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IsOptionalType)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Sizeof)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Strideof)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, StringObjectOr)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IsPOD)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IsConcrete)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IsBitwiseTakable)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IsSameMetatype)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Alignof)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AllocRaw)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssertConf)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UToSCheckedTrunc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, StackAlloc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UnprotectedStackAlloc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, StackDealloc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AllocVector)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SToSCheckedTrunc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, SToUCheckedTrunc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UToUCheckedTrunc)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IntToFPWithOverflow)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, BitWidth)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, IsNegative)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, WordAtIndex)
|
|
|
|
// This is surprising, Builtin.unreachable returns a "Never" value which is
|
|
// trivially typed.
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Unreachable)
|
|
|
|
/// AtomicRMW has type (Builtin.RawPointer, T) -> T. But it provides overloads
|
|
/// for integer or rawpointer, so it should be trivial.
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AtomicRMW)
|
|
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, CondUnreachable)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GetObjCTypeEncoding)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, CanBeObjCClass)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, WillThrow)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, StaticReport)
|
|
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, DestroyArray)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, CopyArray)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TakeArrayNoAlias)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TakeArrayFrontToBack)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TakeArrayBackToFront)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssignCopyArrayNoAlias)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssignCopyArrayFrontToBack)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssignCopyArrayBackToFront)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AssignTakeArray)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, UnexpectedError)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ErrorInMain)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, DeallocRaw)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Fence)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Ifdef)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AtomicStore)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, Once)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, OnceWithContext)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TSanInoutAccess)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, PoundAssert)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TypePtrAuthDiscriminator)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TargetOSVersionAtLeast)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TargetVariantOSVersionAtLeast)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TargetOSVersionOrVariantOSVersionAtLeast)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GlobalStringTablePointer)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GetCurrentAsyncTask)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, CancelAsyncTask)
|
|
CONSTANT_OWNERSHIP_BUILTIN(Owned, CreateAsyncTask)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ConvertTaskToJob)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, InitializeDefaultActor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, DestroyDefaultActor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, InitializeDistributedRemoteActor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, InitializeNonDefaultDistributedActor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(Owned, AutoDiffCreateLinearMapContextWithType)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AutoDiffProjectTopLevelSubcontext)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AutoDiffAllocateSubcontextWithType)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GetCurrentExecutor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeNonThrowingContinuationReturning)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeThrowingContinuationReturning)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, ResumeThrowingContinuationThrowing)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, BuildOrdinaryTaskExecutorRef)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, BuildOrdinarySerialExecutorRef)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, BuildComplexEqualitySerialExecutorRef)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, BuildDefaultActorExecutorRef)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, BuildMainActorExecutorRef)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, StartAsyncLetWithLocalBuffer)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, FinishAsyncLet)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, EndAsyncLetLifetime)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroup)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroupWithFlags)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, DestroyTaskGroup)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TaskRunInline)
|
|
CONSTANT_OWNERSHIP_BUILTIN(Owned, FlowSensitiveSelfIsolation)
|
|
CONSTANT_OWNERSHIP_BUILTIN(Owned, FlowSensitiveDistributedSelfIsolation)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, GetEnumTag)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, InjectEnumTag)
|
|
CONSTANT_OWNERSHIP_BUILTIN(Owned, DistributedActorAsAnyActor)
|
|
CONSTANT_OWNERSHIP_BUILTIN(Guaranteed, ExtractFunctionIsolation) // unreachable
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, AddressOfRawLayout)
|
|
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TaskAddCancellationHandler)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TaskRemoveCancellationHandler)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TaskAddPriorityEscalationHandler)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TaskRemovePriorityEscalationHandler)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TaskLocalValuePush)
|
|
CONSTANT_OWNERSHIP_BUILTIN(None, TaskLocalValuePop)
|
|
|
|
#undef CONSTANT_OWNERSHIP_BUILTIN
|
|
|
|
// Check all of these...
|
|
#define UNOWNED_OR_NONE_DEPENDING_ON_RESULT(ID) \
|
|
ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID( \
|
|
BuiltinInst *BI, StringRef Attr) { \
|
|
if (BI->getType().isTrivial(*BI->getFunction())) { \
|
|
return OwnershipKind::None; \
|
|
} \
|
|
return OwnershipKind::Unowned; \
|
|
}
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(CmpXChg)
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(AtomicLoad)
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(ExtractElement)
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(InsertElement)
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(Select)
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(ShuffleVector)
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(Interleave)
|
|
UNOWNED_OR_NONE_DEPENDING_ON_RESULT(Deinterleave)
|
|
#undef UNOWNED_OR_NONE_DEPENDING_ON_RESULT
|
|
|
|
#define OWNED_OR_NONE_DEPENDING_ON_RESULT(ID) \
|
|
ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID( \
|
|
BuiltinInst *BI, StringRef Attr) { \
|
|
if (BI->getType().isTrivial(*BI->getFunction())) { \
|
|
return OwnershipKind::None; \
|
|
} \
|
|
return OwnershipKind::Owned; \
|
|
}
|
|
// A zeroInitializer may initialize an imported struct with __unsafe_unretained
|
|
// fields. The initialized value is immediately consumed by an assignment, so it
|
|
// must be owned.
|
|
OWNED_OR_NONE_DEPENDING_ON_RESULT(ZeroInitializer)
|
|
OWNED_OR_NONE_DEPENDING_ON_RESULT(PrepareInitialization)
|
|
#undef OWNED_OR_NONE_DEPENDING_ON_RESULT
|
|
|
|
#define BUILTIN(X,Y,Z)
|
|
#define BUILTIN_SIL_OPERATION(ID, NAME, CATEGORY) \
|
|
ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID( \
|
|
BuiltinInst *BI, StringRef Attr) { \
|
|
llvm_unreachable("builtin should have been lowered in SILGen"); \
|
|
}
|
|
#include "swift/AST/Builtins.def"
|
|
|
|
ValueOwnershipKind
|
|
ValueOwnershipKindClassifier::visitBuiltinInst(BuiltinInst *BI) {
|
|
// For now, just conservatively say builtins are None. We need to use a
|
|
// builtin in here to guarantee correctness.
|
|
return ValueOwnershipKindBuiltinVisitor().visit(BI);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Top Level Entrypoint
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ValueOwnershipKind ValueBase::getOwnershipKind() const {
|
|
// If we do not have an undef, we should always be able to get to our function
|
|
// here. If we do not have ownership enabled, just return none for everything
|
|
// to short circuit ownership optimizations. Since SILUndef in either case
|
|
// will be ValueOwnershipKind::None, we will not get any wonky behavior here.
|
|
//
|
|
// We assume that any time we are in SILBuilder and call this without having a
|
|
// value in a block yet, ossa is enabled.
|
|
if (auto *block = getParentBlock()) {
|
|
auto *f = block->getParent();
|
|
// If our block isn't in a function, then it must be in a global
|
|
// variable. We don't verify ownership there so just return
|
|
// OwnershipKind::None.
|
|
if (!f)
|
|
return OwnershipKind::None;
|
|
|
|
// Now that we know that we do have a block/function, check if we have
|
|
// ownership.
|
|
if (!f->hasOwnership())
|
|
return OwnershipKind::None;
|
|
}
|
|
|
|
ValueOwnershipKindClassifier Classifier;
|
|
auto result = Classifier.visit(const_cast<ValueBase *>(this));
|
|
assert(result && "Returned ownership kind invalid on values");
|
|
return result;
|
|
}
|
|
|
|
namespace swift::test {
|
|
// Arguments:
|
|
// - SILValue: value
|
|
// Dumps:
|
|
// - message
|
|
static FunctionTest GetOwnershipKind("get_ownership_kind", [](auto &function,
|
|
auto &arguments,
|
|
auto &test) {
|
|
SILValue value = arguments.takeValue();
|
|
llvm::outs() << value;
|
|
llvm::outs() << "OwnershipKind: " << value->getOwnershipKind() << "\n";
|
|
});
|
|
} // end namespace swift::test
|