//===--- ValueOwnershipKindClassifier.cpp ---------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #include "ValueOwnershipKindClassifier.h" #include "swift/SIL/SILBuiltinVisitor.h" #include "swift/SIL/SILModule.h" using namespace swift; using namespace sil; #define CONSTANT_OWNERSHIP_INST(OWNERSHIP, INST) \ ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \ INST##Inst *Arg) { \ assert(Arg->hasValue() && "Expected to have a result"); \ if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) { \ assert((Arg->getType().isAddress() || \ Arg->getType().isTrivial(Arg->getModule())) && \ "Trivial ownership requires a trivial type or an address"); \ } \ return ValueOwnershipKind::OWNERSHIP; \ } CONSTANT_OWNERSHIP_INST(Guaranteed, BeginBorrow) CONSTANT_OWNERSHIP_INST(Guaranteed, LoadBorrow) CONSTANT_OWNERSHIP_INST(Owned, AllocBox) CONSTANT_OWNERSHIP_INST(Owned, AllocExistentialBox) CONSTANT_OWNERSHIP_INST(Owned, AllocRef) CONSTANT_OWNERSHIP_INST(Owned, AllocRefDynamic) CONSTANT_OWNERSHIP_INST(Trivial, AllocValueBuffer) CONSTANT_OWNERSHIP_INST(Owned, CopyBlock) CONSTANT_OWNERSHIP_INST(Owned, CopyValue) CONSTANT_OWNERSHIP_INST(Owned, CopyUnownedValue) CONSTANT_OWNERSHIP_INST(Owned, LoadUnowned) CONSTANT_OWNERSHIP_INST(Owned, LoadWeak) CONSTANT_OWNERSHIP_INST(Owned, KeyPath) CONSTANT_OWNERSHIP_INST(Owned, PartialApply) CONSTANT_OWNERSHIP_INST(Owned, StrongPin) CONSTANT_OWNERSHIP_INST(Owned, ThinToThickFunction) CONSTANT_OWNERSHIP_INST(Owned, InitExistentialOpaque) CONSTANT_OWNERSHIP_INST(Owned, UnconditionalCheckedCastValue) // 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(Trivial, AddressToPointer) CONSTANT_OWNERSHIP_INST(Trivial, AllocStack) CONSTANT_OWNERSHIP_INST(Trivial, BindMemory) CONSTANT_OWNERSHIP_INST(Trivial, BeginAccess) CONSTANT_OWNERSHIP_INST(Trivial, BridgeObjectToWord) CONSTANT_OWNERSHIP_INST(Trivial, ClassMethod) CONSTANT_OWNERSHIP_INST(Trivial, DynamicMethod) CONSTANT_OWNERSHIP_INST(Trivial, ExistentialMetatype) CONSTANT_OWNERSHIP_INST(Trivial, FloatLiteral) CONSTANT_OWNERSHIP_INST(Trivial, FunctionRef) CONSTANT_OWNERSHIP_INST(Trivial, GlobalAddr) CONSTANT_OWNERSHIP_INST(Trivial, IndexAddr) CONSTANT_OWNERSHIP_INST(Trivial, IndexRawPointer) CONSTANT_OWNERSHIP_INST(Trivial, InitBlockStorageHeader) CONSTANT_OWNERSHIP_INST(Trivial, InitEnumDataAddr) CONSTANT_OWNERSHIP_INST(Trivial, InitExistentialAddr) CONSTANT_OWNERSHIP_INST(Trivial, InitExistentialMetatype) CONSTANT_OWNERSHIP_INST(Trivial, IntegerLiteral) CONSTANT_OWNERSHIP_INST(Trivial, IsNonnull) CONSTANT_OWNERSHIP_INST(Trivial, IsUnique) CONSTANT_OWNERSHIP_INST(Trivial, IsUniqueOrPinned) CONSTANT_OWNERSHIP_INST(Trivial, MarkFunctionEscape) CONSTANT_OWNERSHIP_INST(Trivial, MarkUninitializedBehavior) CONSTANT_OWNERSHIP_INST(Trivial, Metatype) CONSTANT_OWNERSHIP_INST(Trivial, ObjCProtocol) // Is this right? CONSTANT_OWNERSHIP_INST(Trivial, ObjCToThickMetatype) CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialAddr) CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialBox) CONSTANT_OWNERSHIP_INST(Trivial, OpenExistentialMetatype) CONSTANT_OWNERSHIP_INST(Trivial, PointerToAddress) CONSTANT_OWNERSHIP_INST(Trivial, PointerToThinFunction) CONSTANT_OWNERSHIP_INST(Trivial, ProjectBlockStorage) CONSTANT_OWNERSHIP_INST(Trivial, ProjectBox) CONSTANT_OWNERSHIP_INST(Trivial, ProjectExistentialBox) CONSTANT_OWNERSHIP_INST(Trivial, ProjectValueBuffer) CONSTANT_OWNERSHIP_INST(Trivial, RefElementAddr) CONSTANT_OWNERSHIP_INST(Trivial, RefTailAddr) CONSTANT_OWNERSHIP_INST(Trivial, RefToRawPointer) CONSTANT_OWNERSHIP_INST(Trivial, RefToUnmanaged) CONSTANT_OWNERSHIP_INST(Trivial, SelectEnumAddr) CONSTANT_OWNERSHIP_INST(Trivial, StringLiteral) CONSTANT_OWNERSHIP_INST(Trivial, ConstStringLiteral) CONSTANT_OWNERSHIP_INST(Trivial, StructElementAddr) CONSTANT_OWNERSHIP_INST(Trivial, SuperMethod) CONSTANT_OWNERSHIP_INST(Trivial, TailAddr) CONSTANT_OWNERSHIP_INST(Trivial, ThickToObjCMetatype) CONSTANT_OWNERSHIP_INST(Trivial, ThinFunctionToPointer) CONSTANT_OWNERSHIP_INST(Trivial, TupleElementAddr) CONSTANT_OWNERSHIP_INST(Trivial, UncheckedAddrCast) CONSTANT_OWNERSHIP_INST(Trivial, UncheckedRefCastAddr) CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTakeEnumDataAddr) CONSTANT_OWNERSHIP_INST(Trivial, UncheckedTrivialBitCast) CONSTANT_OWNERSHIP_INST(Trivial, UnconditionalCheckedCastAddr) CONSTANT_OWNERSHIP_INST(Trivial, ValueMetatype) CONSTANT_OWNERSHIP_INST(Trivial, WitnessMethod) CONSTANT_OWNERSHIP_INST(Trivial, StoreBorrow) // TODO: It would be great to get rid of these. CONSTANT_OWNERSHIP_INST(Unowned, RawPointerToRef) CONSTANT_OWNERSHIP_INST(Unowned, RefToUnowned) CONSTANT_OWNERSHIP_INST(Unowned, UnmanagedToRef) CONSTANT_OWNERSHIP_INST(Unowned, UnownedToRef) #undef CONSTANT_OWNERSHIP_INST #define CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(OWNERSHIP, INST) \ ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \ INST##Inst *I) { \ if (I->getType().isTrivial(I->getModule())) { \ return ValueOwnershipKind::Trivial; \ } \ return ValueOwnershipKind::OWNERSHIP; \ } CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, StructExtract) CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, TupleExtract) #undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST // These are instructions that do not have any result, so we should never reach // this point in the code since we need a SILValue to compute // ValueOwnershipKind. We define methods so that all instructions have a method // on the visitor (causing the compiler to warn if a new instruction is added // within a method being added). #define NO_RESULT_OWNERSHIP_INST(INST) \ ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \ INST##Inst *I) { \ assert(!I->hasValue() && "Expected an instruction without a result"); \ llvm_unreachable("Instruction without a result can not have ownership"); \ } NO_RESULT_OWNERSHIP_INST(BeginUnpairedAccess) NO_RESULT_OWNERSHIP_INST(DeallocStack) NO_RESULT_OWNERSHIP_INST(DeallocRef) NO_RESULT_OWNERSHIP_INST(DeallocPartialRef) NO_RESULT_OWNERSHIP_INST(DeallocValueBuffer) NO_RESULT_OWNERSHIP_INST(DeallocBox) NO_RESULT_OWNERSHIP_INST(DeallocExistentialBox) NO_RESULT_OWNERSHIP_INST(EndAccess) NO_RESULT_OWNERSHIP_INST(EndBorrow) NO_RESULT_OWNERSHIP_INST(EndBorrowArgument) NO_RESULT_OWNERSHIP_INST(EndUnpairedAccess) NO_RESULT_OWNERSHIP_INST(Store) NO_RESULT_OWNERSHIP_INST(StoreWeak) NO_RESULT_OWNERSHIP_INST(StoreUnowned) NO_RESULT_OWNERSHIP_INST(Assign) NO_RESULT_OWNERSHIP_INST(DebugValue) NO_RESULT_OWNERSHIP_INST(DebugValueAddr) NO_RESULT_OWNERSHIP_INST(CopyAddr) NO_RESULT_OWNERSHIP_INST(DestroyAddr) NO_RESULT_OWNERSHIP_INST(StrongRetain) NO_RESULT_OWNERSHIP_INST(StrongRelease) NO_RESULT_OWNERSHIP_INST(StrongRetainUnowned) NO_RESULT_OWNERSHIP_INST(StrongUnpin) NO_RESULT_OWNERSHIP_INST(UnmanagedRetainValue) NO_RESULT_OWNERSHIP_INST(UnmanagedReleaseValue) NO_RESULT_OWNERSHIP_INST(UnmanagedAutoreleaseValue) NO_RESULT_OWNERSHIP_INST(UnownedRetain) NO_RESULT_OWNERSHIP_INST(UnownedRelease) NO_RESULT_OWNERSHIP_INST(RetainValue) NO_RESULT_OWNERSHIP_INST(ReleaseValue) NO_RESULT_OWNERSHIP_INST(SetDeallocating) NO_RESULT_OWNERSHIP_INST(AutoreleaseValue) NO_RESULT_OWNERSHIP_INST(FixLifetime) NO_RESULT_OWNERSHIP_INST(DestroyValue) NO_RESULT_OWNERSHIP_INST(AllocGlobal) NO_RESULT_OWNERSHIP_INST(InjectEnumAddr) NO_RESULT_OWNERSHIP_INST(DeinitExistentialAddr) NO_RESULT_OWNERSHIP_INST(DeinitExistentialOpaque) NO_RESULT_OWNERSHIP_INST(CondFail) NO_RESULT_OWNERSHIP_INST(EndLifetime) // Terminators. These do not produce SILValue, so they do not have a // ValueOwnershipKind. They do have ownership implications in terms of the // SILArguments that they feed into. But that code is in SILArgument. NO_RESULT_OWNERSHIP_INST(Unreachable) NO_RESULT_OWNERSHIP_INST(Return) NO_RESULT_OWNERSHIP_INST(Throw) NO_RESULT_OWNERSHIP_INST(TryApply) NO_RESULT_OWNERSHIP_INST(Branch) NO_RESULT_OWNERSHIP_INST(CondBranch) NO_RESULT_OWNERSHIP_INST(SwitchValue) NO_RESULT_OWNERSHIP_INST(SwitchEnum) NO_RESULT_OWNERSHIP_INST(SwitchEnumAddr) NO_RESULT_OWNERSHIP_INST(DynamicMethodBranch) NO_RESULT_OWNERSHIP_INST(CheckedCastBranch) NO_RESULT_OWNERSHIP_INST(CheckedCastValueBranch) NO_RESULT_OWNERSHIP_INST(CheckedCastAddrBranch) #undef NO_RESULT_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 Ops) { // A forwarding inst without operands must be trivial. if (Ops.empty()) return ValueOwnershipKind::Trivial; // Find the first index where we have a trivial value. auto Iter = find_if(Ops, [&I](const Operand &Op) -> bool { if (I->isTypeDependentOperand(Op)) return false; return Op.get().getOwnershipKind() != ValueOwnershipKind::Trivial; }); // All trivial. if (Iter == Ops.end()) { return ValueOwnershipKind::Trivial; } // See if we have any Any. If we do, just return that for now. if (any_of(Ops, [&I](const Operand &Op) -> bool { if (I->isTypeDependentOperand(Op)) return false; return Op.get().getOwnershipKind() == ValueOwnershipKind::Any; })) return ValueOwnershipKind::Any; unsigned Index = std::distance(Ops.begin(), Iter); ValueOwnershipKind Base = Ops[Index].get().getOwnershipKind(); for (const Operand &Op : Ops.slice(Index + 1)) { if (I->isTypeDependentOperand(Op)) continue; auto OpKind = Op.get().getOwnershipKind(); if (OpKind.merge(ValueOwnershipKind::Trivial)) continue; auto MergedValue = Base.merge(OpKind.Value); if (!MergedValue.hasValue()) { // If we have mismatched SILOwnership and sil ownership is not enabled, // just return Any for staging purposes. If SILOwnership is enabled, then // we must assert! if (!I->getModule().getOptions().EnableSILOwnership) { return ValueOwnershipKind::Any; } llvm_unreachable("Forwarding inst with mismatching ownership kinds?!"); } } return Base; } #define FORWARDING_OWNERSHIP_INST(INST) \ ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \ INST##Inst *I) { \ assert(I->hasValue() && "Expected to have a value"); \ return visitForwardingInst(I); \ } FORWARDING_OWNERSHIP_INST(BridgeObjectToRef) FORWARDING_OWNERSHIP_INST(ConvertFunction) FORWARDING_OWNERSHIP_INST(InitExistentialRef) FORWARDING_OWNERSHIP_INST(OpenExistentialRef) FORWARDING_OWNERSHIP_INST(OpenExistentialOpaque) FORWARDING_OWNERSHIP_INST(RefToBridgeObject) FORWARDING_OWNERSHIP_INST(SelectValue) FORWARDING_OWNERSHIP_INST(Struct) FORWARDING_OWNERSHIP_INST(Tuple) FORWARDING_OWNERSHIP_INST(UncheckedRefCast) FORWARDING_OWNERSHIP_INST(UnconditionalCheckedCast) FORWARDING_OWNERSHIP_INST(Upcast) FORWARDING_OWNERSHIP_INST(MarkUninitialized) FORWARDING_OWNERSHIP_INST(UncheckedEnumData) #undef FORWARDING_OWNERSHIP_INST ValueOwnershipKind ValueOwnershipKindClassifier::visitSelectEnumInst(SelectEnumInst *SEI) { // We handle this specially, since a select enum forwards only its case // values. We drop the first element since that is the condition element. return visitForwardingInst(SEI, SEI->getAllOperands().drop_front()); } ValueOwnershipKind ValueOwnershipKindClassifier::visitUncheckedBitwiseCastInst( UncheckedBitwiseCastInst *UBCI) { ValueOwnershipKind OpOwnership = UBCI->getOperand().getOwnershipKind(); bool ResultTypeIsTrivial = UBCI->getType().isTrivial(UBCI->getModule()); // First check if our operand has a trivial value ownership kind... if (OpOwnership == ValueOwnershipKind::Trivial) { // If we do have a trivial value ownership kind, see if our result type is // trivial or non-trivial. If it is trivial, then we have trivial // ownership. Otherwise, we have unowned ownership since from an ownership // perspective, the value has instantaneously come into existence and // nothing has taken ownership of it. if (ResultTypeIsTrivial) { return ValueOwnershipKind::Trivial; } return ValueOwnershipKind::Unowned; } // If our operand has non-trivial ownership, but our result does, then of // course the result has trivial ownership. if (ResultTypeIsTrivial) { return ValueOwnershipKind::Trivial; } // Otherwise, we forward our ownership. return visitForwardingInst(UBCI); } ValueOwnershipKind ValueOwnershipKindClassifier::visitUncheckedOwnershipConversionInst( UncheckedOwnershipConversionInst *I) { return I->getConversionOwnershipKind(); } // An enum without payload is trivial. One with non-trivial payload is // forwarding. ValueOwnershipKind ValueOwnershipKindClassifier::visitEnumInst(EnumInst *EI) { if (!EI->hasOperand()) return ValueOwnershipKind::Trivial; return visitForwardingInst(EI); } ValueOwnershipKind ValueOwnershipKindClassifier::visitSILUndef(SILUndef *Arg) { return ValueOwnershipKind::Any; } ValueOwnershipKind ValueOwnershipKindClassifier::visitSILPHIArgument(SILPHIArgument *Arg) { return Arg->getOwnershipKind(); } ValueOwnershipKind ValueOwnershipKindClassifier::visitSILFunctionArgument( SILFunctionArgument *Arg) { return Arg->getOwnershipKind(); } // This is a forwarding instruction through only one of its arguments. ValueOwnershipKind ValueOwnershipKindClassifier::visitMarkDependenceInst(MarkDependenceInst *MDI) { return MDI->getValue().getOwnershipKind(); } ValueOwnershipKind ValueOwnershipKindClassifier::visitApplyInst(ApplyInst *AI) { SILModule &M = AI->getModule(); bool IsTrivial = AI->getType().isTrivial(M); SILFunctionConventions fnConv(AI->getSubstCalleeType(), M); auto Results = fnConv.getDirectSILResults(); // No results => empty tuple result => Trivial. if (Results.empty() || IsTrivial) return ValueOwnershipKind::Trivial; CanGenericSignature Sig = AI->getSubstCalleeType()->getGenericSignature(); // Find the first index where we have a trivial value. auto Iter = find_if(Results, [&M, &Sig](const SILResultInfo &Info) -> bool { return Info.getOwnershipKind(M, Sig) != ValueOwnershipKind::Trivial; }); // If we have all trivial, then we must be trivial. if (Iter == Results.end()) return ValueOwnershipKind::Trivial; ValueOwnershipKind Base = Iter->getOwnershipKind(M, Sig); for (const SILResultInfo &ResultInfo : SILFunctionConventions::DirectSILResultRange(next(Iter), Results.end())) { auto RKind = ResultInfo.getOwnershipKind(M, Sig); if (RKind.merge(ValueOwnershipKind::Trivial)) continue; auto MergedValue = Base.merge(RKind.Value); if (!MergedValue.hasValue()) { llvm_unreachable("Forwarding inst with mismatching ownership kinds?!"); } } return Base; } ValueOwnershipKind ValueOwnershipKindClassifier::visitLoadInst(LoadInst *LI) { switch (LI->getOwnershipQualifier()) { case LoadOwnershipQualifier::Take: case LoadOwnershipQualifier::Copy: return ValueOwnershipKind::Owned; case LoadOwnershipQualifier::Unqualified: return ValueOwnershipKind::Any; case LoadOwnershipQualifier::Trivial: return ValueOwnershipKind::Trivial; } llvm_unreachable("Unhandled LoadOwnershipQualifier in switch."); } //===----------------------------------------------------------------------===// // Builtin OwnershipValueKind Computation //===----------------------------------------------------------------------===// namespace { struct ValueOwnershipKindBuiltinVisitor : SILBuiltinVisitor { ValueOwnershipKind visitLLVMIntrinsic(BuiltinInst *BI, llvm::Intrinsic::ID ID) { // LLVM intrinsics do not traffic in ownership, so if we have a result, it // must be trivial. assert(BI->hasValue() && "Can only get here if we have a SILValue"); assert(BI->getType().isTrivial(BI->getModule()) && "LLVM intrinsics should always be trivial"); return ValueOwnershipKind::Trivial; } #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) { \ assert(BI->hasValue() && "Expected to have type"); \ if (ValueOwnershipKind::OWNERSHIP == ValueOwnershipKind::Trivial) { \ assert(BI->getType().isTrivial(BI->getModule()) && \ "Only trivial types can have trivial ownership"); \ } else { \ assert(!BI->getType().isTrivial(BI->getModule()) && \ "Only non trivial types can have non trivial ownership"); \ } \ return ValueOwnershipKind::OWNERSHIP; \ } CONSTANT_OWNERSHIP_BUILTIN(Owned, Take) CONSTANT_OWNERSHIP_BUILTIN(Owned, TryPin) // This returns a value at +1 that is destroyed strictly /after/ the // UnsafeGuaranteedEnd. This provides the guarantee that we want. CONSTANT_OWNERSHIP_BUILTIN(Owned, UnsafeGuaranteed) CONSTANT_OWNERSHIP_BUILTIN(Trivial, AShr) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Add) CONSTANT_OWNERSHIP_BUILTIN(Trivial, And) CONSTANT_OWNERSHIP_BUILTIN(Trivial, AssumeNonNegative) CONSTANT_OWNERSHIP_BUILTIN(Trivial, BitCast) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ExactSDiv) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ExactUDiv) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FAdd) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OEQ) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OGE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OGT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OLE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_OLT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ONE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UEQ) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UGE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UGT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ULE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ULT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UNE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FDiv) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FMul) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FNeg) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPExt) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPToSI) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPToUI) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FPTrunc) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FRem) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FSub) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_EQ) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_NE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SGE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SGT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SLE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_SLT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_UGE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_UGT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULE) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ICMP_ULT) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToPtr) CONSTANT_OWNERSHIP_BUILTIN(Trivial, LShr) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Load) CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadRaw) CONSTANT_OWNERSHIP_BUILTIN(Trivial, LoadInvariant) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Mul) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Or) CONSTANT_OWNERSHIP_BUILTIN(Trivial, PtrToInt) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SAddOver) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SDiv) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SExt) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SExtOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SIToFP) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SMulOver) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SRem) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SSubOver) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Shl) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Sub) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Trunc) CONSTANT_OWNERSHIP_BUILTIN(Trivial, TruncOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UAddOver) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UDiv) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UIToFP) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UMulOver) CONSTANT_OWNERSHIP_BUILTIN(Trivial, URem) CONSTANT_OWNERSHIP_BUILTIN(Trivial, USubOver) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Xor) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExt) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ZExtOrBitCast) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_ORD) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FCMP_UNO) CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToUnknownObject) CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastFromUnknownObject) CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToNativeObject) CONSTANT_OWNERSHIP_BUILTIN(Unowned, UnsafeCastToNativeObject) CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastFromNativeObject) CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastToBridgeObject) CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReferenceFromBridgeObject) CONSTANT_OWNERSHIP_BUILTIN(Trivial, CastBitPatternFromBridgeObject) CONSTANT_OWNERSHIP_BUILTIN(Trivial, BridgeToRawPointer) CONSTANT_OWNERSHIP_BUILTIN(Unowned, BridgeFromRawPointer) CONSTANT_OWNERSHIP_BUILTIN(Unowned, CastReference) CONSTANT_OWNERSHIP_BUILTIN(Trivial, AddressOf) CONSTANT_OWNERSHIP_BUILTIN(Trivial, GepRaw) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Gep) CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetTailAddr) CONSTANT_OWNERSHIP_BUILTIN(Trivial, OnFastPath) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique_native) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned_native) CONSTANT_OWNERSHIP_BUILTIN(Trivial, BindMemory) CONSTANT_OWNERSHIP_BUILTIN(Owned, AllocWithTailElems) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ProjectTailElems) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsOptionalType) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Sizeof) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Strideof) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsPOD) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Alignof) CONSTANT_OWNERSHIP_BUILTIN(Trivial, AllocRaw) CONSTANT_OWNERSHIP_BUILTIN(Trivial, AssertConf) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToSCheckedTrunc) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToSCheckedTrunc) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SToUCheckedTrunc) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UToUCheckedTrunc) CONSTANT_OWNERSHIP_BUILTIN(Trivial, SUCheckedConversion) CONSTANT_OWNERSHIP_BUILTIN(Trivial, USCheckedConversion) CONSTANT_OWNERSHIP_BUILTIN(Trivial, IntToFPWithOverflow) // This is surprising, Builtin.unreachable returns a "Never" value which is // trivially typed. CONSTANT_OWNERSHIP_BUILTIN(Trivial, Unreachable) /// AtomicRMW has type (Builtin.RawPointer, T) -> T. But it provides overloads /// for integer or rawpointer, so it should be trivial. CONSTANT_OWNERSHIP_BUILTIN(Trivial, AtomicRMW) CONSTANT_OWNERSHIP_BUILTIN(Trivial, CondUnreachable) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UnsafeGuaranteedEnd) CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetObjCTypeEncoding) CONSTANT_OWNERSHIP_BUILTIN(Trivial, CanBeObjCClass) CONSTANT_OWNERSHIP_BUILTIN(Trivial, WillThrow) CONSTANT_OWNERSHIP_BUILTIN(Trivial, StaticReport) CONSTANT_OWNERSHIP_BUILTIN(Trivial, DestroyArray) CONSTANT_OWNERSHIP_BUILTIN(Trivial, CopyArray) CONSTANT_OWNERSHIP_BUILTIN(Trivial, TakeArrayFrontToBack) CONSTANT_OWNERSHIP_BUILTIN(Trivial, TakeArrayBackToFront) CONSTANT_OWNERSHIP_BUILTIN(Trivial, UnexpectedError) CONSTANT_OWNERSHIP_BUILTIN(Trivial, ErrorInMain) CONSTANT_OWNERSHIP_BUILTIN(Trivial, DeallocRaw) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Fence) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Retain) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Release) CONSTANT_OWNERSHIP_BUILTIN(Trivial, CondFail) CONSTANT_OWNERSHIP_BUILTIN(Trivial, FixLifetime) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Autorelease) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Unpin) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Destroy) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Assign) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Init) CONSTANT_OWNERSHIP_BUILTIN(Trivial, AtomicStore) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Once) CONSTANT_OWNERSHIP_BUILTIN(Trivial, OnceWithContext) CONSTANT_OWNERSHIP_BUILTIN(Trivial, TSanInoutAccess) CONSTANT_OWNERSHIP_BUILTIN(Trivial, Swift3ImplicitObjCEntrypoint) #undef CONSTANT_OWNERSHIP_BUILTIN // Check all of these... #define UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ID) \ ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID( \ BuiltinInst *BI, StringRef Attr) { \ if (BI->getType().isTrivial(BI->getModule())) { \ return ValueOwnershipKind::Trivial; \ } \ return ValueOwnershipKind::Unowned; \ } UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ReinterpretCast) UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(CmpXChg) UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(AtomicLoad) UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ExtractElement) UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(InsertElement) UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT(ZeroInitializer) #undef UNOWNED_OR_TRIVIAL_DEPENDING_ON_RESULT 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); }