diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index ce3810bc27f7d..bb131966f75a7 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -121,8 +121,19 @@ class SILBuilder { /// Reference to the provided SILBuilderContext. SILBuilderContext &C; + /// The SILFunction that we are currently inserting into if we have one. + /// + /// If we are building into a block associated with a SILGlobalVariable this + /// will be a nullptr. + /// + /// TODO: This can be made cleaner by using a PointerUnion or the like so we + /// can store the SILGlobalVariable here as well. SILFunction *F; + /// If the current block that we are inserting into must assume that + /// the current context we are in has ownership. + bool hasOwnership; + /// If this is non-null, the instruction is inserted in the specified /// basic block, at the specified InsertPt. If null, created instructions /// are not auto-inserted. @@ -133,18 +144,20 @@ class SILBuilder { public: explicit SILBuilder(SILFunction &F, bool isParsing = false) - : TempContext(F.getModule()), C(TempContext), F(&F), BB(0) { + : TempContext(F.getModule()), C(TempContext), F(&F), + hasOwnership(F.hasQualifiedOwnership()), BB(0) { C.isParsing = isParsing; } SILBuilder(SILFunction &F, SmallVectorImpl *InsertedInstrs) : TempContext(F.getModule(), InsertedInstrs), C(TempContext), F(&F), - BB(0) {} + hasOwnership(F.hasQualifiedOwnership()), BB(0) {} explicit SILBuilder(SILInstruction *I, SmallVectorImpl *InsertedInstrs = 0) : TempContext(I->getFunction()->getModule(), InsertedInstrs), - C(TempContext), F(I->getFunction()) { + C(TempContext), F(I->getFunction()), + hasOwnership(F->hasQualifiedOwnership()) { setInsertionPoint(I); } @@ -155,7 +168,8 @@ class SILBuilder { explicit SILBuilder(SILBasicBlock *BB, SmallVectorImpl *InsertedInstrs = 0) : TempContext(BB->getParent()->getModule(), InsertedInstrs), - C(TempContext), F(BB->getParent()) { + C(TempContext), F(BB->getParent()), + hasOwnership(F->hasQualifiedOwnership()) { setInsertionPoint(BB); } @@ -165,7 +179,8 @@ class SILBuilder { SILBuilder(SILBasicBlock *BB, SILBasicBlock::iterator InsertPt, SmallVectorImpl *InsertedInstrs = 0) : TempContext(BB->getParent()->getModule(), InsertedInstrs), - C(TempContext), F(BB->getParent()) { + C(TempContext), F(BB->getParent()), + hasOwnership(F->hasQualifiedOwnership()) { setInsertionPoint(BB, InsertPt); } @@ -174,7 +189,8 @@ class SILBuilder { /// /// SILBuilderContext must outlive this SILBuilder instance. SILBuilder(SILInstruction *I, const SILDebugScope *DS, SILBuilderContext &C) - : TempContext(C.getModule()), C(C), F(I->getFunction()) { + : TempContext(C.getModule()), C(C), F(I->getFunction()), + hasOwnership(F->hasQualifiedOwnership()) { assert(DS && "instruction has no debug scope"); setCurrentDebugScope(DS); setInsertionPoint(I); @@ -185,7 +201,8 @@ class SILBuilder { /// /// SILBuilderContext must outlive this SILBuilder instance. SILBuilder(SILBasicBlock *BB, const SILDebugScope *DS, SILBuilderContext &C) - : TempContext(C.getModule()), C(C), F(BB->getParent()) { + : TempContext(C.getModule()), C(C), F(BB->getParent()), + hasOwnership(F->hasQualifiedOwnership()) { assert(DS && "block has no debug scope"); setCurrentDebugScope(DS); setInsertionPoint(BB); @@ -243,6 +260,16 @@ class SILBuilder { return SILDebugLocation(overriddenLoc, Scope); } + /// Allow for users to override has ownership if necessary. + /// + /// This is only used in the SILParser since it sets whether or not ownership + /// is qualified after the SILBuilder is constructed due to the usage of + /// AssumeUnqualifiedOwnershipWhenParsing. + /// + /// TODO: Once we start printing [ossa] on SILFunctions to indicate ownership + /// and get rid of this global option, this can go away. + void setHasOwnership(bool newHasOwnership) { hasOwnership = newHasOwnership; } + //===--------------------------------------------------------------------===// // Insertion Point Management //===--------------------------------------------------------------------===// @@ -1187,25 +1214,23 @@ class SILBuilder { ObjectInst *createObject(SILLocation Loc, SILType Ty, ArrayRef Elements, unsigned NumBaseElements) { - return insert( - ObjectInst::create(getSILDebugLocation(Loc), Ty, Elements, - NumBaseElements, getModule())); + return insert(ObjectInst::create(getSILDebugLocation(Loc), Ty, Elements, + NumBaseElements, getModule(), + hasOwnership)); } StructInst *createStruct(SILLocation Loc, SILType Ty, ArrayRef Elements) { assert(Ty.isLoadableOrOpaque(getModule())); - return insert( - StructInst::create(getSILDebugLocation(Loc), Ty, Elements, - getModule())); + return insert(StructInst::create(getSILDebugLocation(Loc), Ty, Elements, + getModule(), hasOwnership)); } TupleInst *createTuple(SILLocation Loc, SILType Ty, ArrayRef Elements) { assert(Ty.isLoadableOrOpaque(getModule())); - return insert( - TupleInst::create(getSILDebugLocation(Loc), Ty, Elements, - getModule())); + return insert(TupleInst::create(getSILDebugLocation(Loc), Ty, Elements, + getModule(), hasOwnership)); } TupleInst *createTuple(SILLocation loc, ArrayRef elts); @@ -1286,7 +1311,7 @@ class SILBuilder { assert(Ty.isLoadableOrOpaque(getModule())); return insert(SelectEnumInst::create( getSILDebugLocation(Loc), Operand, Ty, DefaultValue, CaseValues, - getFunction(), CaseCounts, DefaultCount)); + getModule(), CaseCounts, DefaultCount, hasOwnership)); } SelectEnumAddrInst *createSelectEnumAddr( @@ -1296,7 +1321,7 @@ class SILBuilder { ProfileCounter DefaultCount = ProfileCounter()) { return insert(SelectEnumAddrInst::create( getSILDebugLocation(Loc), Operand, Ty, DefaultValue, CaseValues, - getFunction(), CaseCounts, DefaultCount)); + getModule(), CaseCounts, DefaultCount)); } SelectValueInst *createSelectValue( @@ -1304,7 +1329,7 @@ class SILBuilder { ArrayRef> CaseValuesAndResults) { return insert(SelectValueInst::create(getSILDebugLocation(Loc), Operand, Ty, DefaultResult, CaseValuesAndResults, - getFunction())); + getModule(), hasOwnership)); } TupleExtractInst *createTupleExtract(SILLocation Loc, SILValue Operand, @@ -1491,7 +1516,7 @@ class SILBuilder { OpenExistentialRefInst * createOpenExistentialRef(SILLocation Loc, SILValue Operand, SILType Ty) { auto *I = insert(new (getModule()) OpenExistentialRefInst( - getSILDebugLocation(Loc), Operand, Ty)); + getSILDebugLocation(Loc), Operand, Ty, hasOwnership)); if (C.OpenedArchetypesTracker) C.OpenedArchetypesTracker->registerOpenedArchetypes(I); return I; diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index a47225b0caf32..b7b1a9802b203 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -35,6 +35,7 @@ #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILSuccessor.h" #include "swift/SIL/SILValue.h" +#include "swift/SIL/ValueUtils.h" #include "swift/Strings.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" @@ -781,6 +782,25 @@ inline SingleValueInstruction *SILNode::castToSingleValueInstruction() { inst->getKind() <= SILInstructionKind::Last_##ID; \ } +/// A single value inst that also forwards either owned or guaranteed ownership. +/// +/// The specific forwarded ownership is static since it is set upon +/// construction. After that point the instruction can not have a different form +/// of ownership. +class OwnershipForwardingSingleValueInst : public SingleValueInstruction { + ValueOwnershipKind ownershipKind; + +protected: + OwnershipForwardingSingleValueInst(SILInstructionKind kind, + SILDebugLocation debugLoc, SILType ty, + ValueOwnershipKind ownershipKind) + : SingleValueInstruction(kind, debugLoc, ty), + ownershipKind(ownershipKind) {} + +public: + ValueOwnershipKind getOwnershipKind() const { return ownershipKind; } +}; + /// A value base result of a multiple value instruction. /// /// *NOTE* We want this to be a pure abstract class that does not add /any/ size @@ -3599,14 +3619,12 @@ class AssignInst MutableArrayRef getAllOperands() { return Operands.asArray(); } }; -/// Abstract base class for instructions that mark storage as uninitialized. - -/// Indicates that a memory location is uninitialized at -/// this point and needs to be initialized by the end of the function and before -/// any escape point for this instruction. This is only valid in Raw SIL. +/// Indicates that a memory location is uninitialized at this point and needs to +/// be initialized by the end of the function and before any escape point for +/// this instruction. This is only valid in Raw SIL. class MarkUninitializedInst : public UnaryInstructionBase { + OwnershipForwardingSingleValueInst> { friend SILBuilder; public: @@ -3640,8 +3658,9 @@ class MarkUninitializedInst private: Kind ThisKind; - MarkUninitializedInst(SILDebugLocation DebugLoc, SILValue Address, Kind K) - : UnaryInstructionBase(DebugLoc, Address, Address->getType()), + MarkUninitializedInst(SILDebugLocation DebugLoc, SILValue Value, Kind K) + : UnaryInstructionBase(DebugLoc, Value, Value->getType(), + Value.getOwnershipKind()), ThisKind(K) {} public: @@ -4023,19 +4042,35 @@ class ConversionInst : public SingleValueInstruction { DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(ConversionInst) }; +/// A conversion inst that produces a static OwnershipKind set upon the +/// instruction's construction. +class OwnershipForwardingConversionInst : public ConversionInst { + ValueOwnershipKind ownershipKind; + +protected: + OwnershipForwardingConversionInst(SILInstructionKind kind, + SILDebugLocation debugLoc, SILType ty, + ValueOwnershipKind ownershipKind) + : ConversionInst(kind, debugLoc, ty), ownershipKind(ownershipKind) {} + +public: + ValueOwnershipKind getOwnershipKind() const { return ownershipKind; } +}; + /// ConvertFunctionInst - Change the type of a function value without /// affecting how it will codegen. class ConvertFunctionInst final : public UnaryInstructionWithTypeDependentOperandsBase< - SILInstructionKind::ConvertFunctionInst, - ConvertFunctionInst, ConversionInst> { + SILInstructionKind::ConvertFunctionInst, ConvertFunctionInst, + OwnershipForwardingConversionInst> { friend SILBuilder; ConvertFunctionInst(SILDebugLocation DebugLoc, SILValue Operand, ArrayRef TypeDependentOperands, SILType Ty, bool WithoutActuallyEscaping) : UnaryInstructionWithTypeDependentOperandsBase( - DebugLoc, Operand, TypeDependentOperands, Ty) { + DebugLoc, Operand, TypeDependentOperands, Ty, + Operand.getOwnershipKind()) { SILInstruction::Bits.ConvertFunctionInst.WithoutActuallyEscaping = WithoutActuallyEscaping; assert((Operand->getType().castTo()->isNoEscape() == @@ -4140,18 +4175,16 @@ class PointerToThinFunctionInst final }; /// UpcastInst - Perform a conversion of a class instance to a supertype. -class UpcastInst final - : public UnaryInstructionWithTypeDependentOperandsBase< - SILInstructionKind::UpcastInst, - UpcastInst, ConversionInst> - -{ +class UpcastInst final : public UnaryInstructionWithTypeDependentOperandsBase< + SILInstructionKind::UpcastInst, UpcastInst, + OwnershipForwardingConversionInst> { friend SILBuilder; UpcastInst(SILDebugLocation DebugLoc, SILValue Operand, ArrayRef TypeDependentOperands, SILType Ty) : UnaryInstructionWithTypeDependentOperandsBase( - DebugLoc, Operand, TypeDependentOperands, Ty) {} + DebugLoc, Operand, TypeDependentOperands, Ty, + Operand.getOwnershipKind()) {} static UpcastInst * create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty, @@ -4201,17 +4234,16 @@ class PointerToAddressInst /// Convert a heap object reference to a different type without any runtime /// checks. class UncheckedRefCastInst final - : public UnaryInstructionWithTypeDependentOperandsBase< - SILInstructionKind::UncheckedRefCastInst, - UncheckedRefCastInst, - ConversionInst> -{ + : public UnaryInstructionWithTypeDependentOperandsBase< + SILInstructionKind::UncheckedRefCastInst, UncheckedRefCastInst, + OwnershipForwardingConversionInst> { friend SILBuilder; UncheckedRefCastInst(SILDebugLocation DebugLoc, SILValue Operand, ArrayRef TypeDependentOperands, SILType Ty) - : UnaryInstructionWithTypeDependentOperandsBase(DebugLoc, Operand, - TypeDependentOperands, Ty) {} + : UnaryInstructionWithTypeDependentOperandsBase( + DebugLoc, Operand, TypeDependentOperands, Ty, + Operand.getOwnershipKind()) {} static UncheckedRefCastInst * create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty, SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes); @@ -4313,13 +4345,14 @@ class UncheckedBitwiseCastInst final /// in bits from a word. class RefToBridgeObjectInst : public InstructionBase { + OwnershipForwardingConversionInst> { friend SILBuilder; FixedOperandList<2> Operands; RefToBridgeObjectInst(SILDebugLocation DebugLoc, SILValue ConvertedValue, SILValue MaskValue, SILType BridgeObjectTy) - : InstructionBase(DebugLoc, BridgeObjectTy), + : InstructionBase(DebugLoc, BridgeObjectTy, + ConvertedValue.getOwnershipKind()), Operands(this, ConvertedValue, MaskValue) {} public: @@ -4343,14 +4376,13 @@ class ClassifyBridgeObjectInst /// Extract the heap object reference from a BridgeObject. class BridgeObjectToRefInst - : public UnaryInstructionBase -{ + : public UnaryInstructionBase { friend SILBuilder; - BridgeObjectToRefInst(SILDebugLocation DebugLoc, SILValue Operand, - SILType Ty) - : UnaryInstructionBase(DebugLoc, Operand, Ty) {} + BridgeObjectToRefInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty) + : UnaryInstructionBase(DebugLoc, Operand, Ty, + Operand.getOwnershipKind()) {} }; /// Sets the BridgeObject to a tagged pointer representation holding its @@ -4516,19 +4548,17 @@ class ObjCProtocolInst /// Perform an unconditional checked cast that aborts if the cast fails. class UnconditionalCheckedCastInst final - : public UnaryInstructionWithTypeDependentOperandsBase< - SILInstructionKind::UnconditionalCheckedCastInst, - UnconditionalCheckedCastInst, - ConversionInst> -{ + : public UnaryInstructionWithTypeDependentOperandsBase< + SILInstructionKind::UnconditionalCheckedCastInst, + UnconditionalCheckedCastInst, OwnershipForwardingConversionInst> { friend SILBuilder; UnconditionalCheckedCastInst(SILDebugLocation DebugLoc, SILValue Operand, ArrayRef TypeDependentOperands, SILType DestTy) - : UnaryInstructionWithTypeDependentOperandsBase(DebugLoc, Operand, - TypeDependentOperands, - DestTy) {} + : UnaryInstructionWithTypeDependentOperandsBase( + DebugLoc, Operand, TypeDependentOperands, DestTy, + Operand.getOwnershipKind()) {} static UnconditionalCheckedCastInst * create(SILDebugLocation DebugLoc, SILValue Operand, SILType DestTy, @@ -4603,19 +4633,20 @@ class UnconditionalCheckedCastValueInst final }; /// StructInst - Represents a constructed loadable struct. -class StructInst final - : public InstructionBaseWithTrailingOperands { +class StructInst final : public InstructionBaseWithTrailingOperands< + SILInstructionKind::StructInst, StructInst, + OwnershipForwardingSingleValueInst> { friend SILBuilder; /// Because of the storage requirements of StructInst, object /// creation goes through 'create()'. - StructInst(SILDebugLocation DebugLoc, SILType Ty, - ArrayRef Elements); + StructInst(SILDebugLocation DebugLoc, SILType Ty, ArrayRef Elements, + bool HasOwnership); /// Construct a StructInst. static StructInst *create(SILDebugLocation DebugLoc, SILType Ty, - ArrayRef Elements, SILModule &M); + ArrayRef Elements, SILModule &M, + bool HasOwnership); public: /// The elements referenced by this StructInst. @@ -4856,24 +4887,27 @@ class SetDeallocatingInst /// /// This instruction can only appear at the end of a gobal variable's /// static initializer list. -class ObjectInst final - : public InstructionBaseWithTrailingOperands { +class ObjectInst final : public InstructionBaseWithTrailingOperands< + SILInstructionKind::ObjectInst, ObjectInst, + OwnershipForwardingSingleValueInst> { friend SILBuilder; /// Because of the storage requirements of ObjectInst, object /// creation goes through 'create()'. - ObjectInst(SILDebugLocation DebugLoc, SILType Ty, - ArrayRef Elements, unsigned NumBaseElements) - : InstructionBaseWithTrailingOperands(Elements, DebugLoc, Ty) { - SILInstruction::Bits.ObjectInst.NumBaseElements = NumBaseElements; + ObjectInst(SILDebugLocation DebugLoc, SILType Ty, ArrayRef Elements, + unsigned NumBaseElements, bool HasOwnership) + : InstructionBaseWithTrailingOperands( + Elements, DebugLoc, Ty, + HasOwnership ? *mergeSILValueOwnership(Elements) + : ValueOwnershipKind(ValueOwnershipKind::Any)) { + SILInstruction::Bits.ObjectInst.NumBaseElements = NumBaseElements; } /// Construct an ObjectInst. static ObjectInst *create(SILDebugLocation DebugLoc, SILType Ty, ArrayRef Elements, - unsigned NumBaseElements, SILModule &M); + unsigned NumBaseElements, SILModule &M, + bool HasOwnership); public: /// All elements referenced by this ObjectInst. @@ -4900,20 +4934,24 @@ class ObjectInst final }; /// TupleInst - Represents a constructed loadable tuple. -class TupleInst final - : public InstructionBaseWithTrailingOperands { +class TupleInst final : public InstructionBaseWithTrailingOperands< + SILInstructionKind::TupleInst, TupleInst, + OwnershipForwardingSingleValueInst> { friend SILBuilder; /// Because of the storage requirements of TupleInst, object /// creation goes through 'create()'. - TupleInst(SILDebugLocation DebugLoc, SILType Ty, ArrayRef Elems) - : InstructionBaseWithTrailingOperands(Elems, DebugLoc, Ty) {} + TupleInst(SILDebugLocation DebugLoc, SILType Ty, ArrayRef Elems, + bool HasOwnership) + : InstructionBaseWithTrailingOperands( + Elems, DebugLoc, Ty, + HasOwnership ? *mergeSILValueOwnership(Elems) + : ValueOwnershipKind(ValueOwnershipKind::Any)) {} /// Construct a TupleInst. static TupleInst *create(SILDebugLocation DebugLoc, SILType Ty, - ArrayRef Elements, SILModule &M); + ArrayRef Elements, SILModule &M, + bool HasOwnership); public: /// The elements referenced by this TupleInst. @@ -4973,9 +5011,8 @@ class TupleInst final /// Represents a loadable enum constructed from one of its /// elements. -class EnumInst - : public InstructionBase { +class EnumInst : public InstructionBase { friend SILBuilder; Optional> OptionalOperand; @@ -4983,7 +5020,10 @@ class EnumInst EnumInst(SILDebugLocation DebugLoc, SILValue Operand, EnumElementDecl *Element, SILType ResultTy) - : InstructionBase(DebugLoc, ResultTy), + : InstructionBase(DebugLoc, ResultTy, + Operand + ? Operand.getOwnershipKind() + : ValueOwnershipKind(ValueOwnershipKind::Trivial)), Element(Element) { if (Operand) { OptionalOperand.emplace(this, Operand); @@ -5011,16 +5051,17 @@ class EnumInst /// Unsafely project the data for an enum case out of an enum without checking /// the tag. class UncheckedEnumDataInst - : public UnaryInstructionBase -{ + : public UnaryInstructionBase { friend SILBuilder; EnumElementDecl *Element; UncheckedEnumDataInst(SILDebugLocation DebugLoc, SILValue Operand, EnumElementDecl *Element, SILType ResultTy) - : UnaryInstructionBase(DebugLoc, Operand, ResultTy), Element(Element) {} + : UnaryInstructionBase(DebugLoc, Operand, ResultTy, + Operand.getOwnershipKind()), + Element(Element) {} public: EnumElementDecl *getElement() const { return Element; } @@ -5123,11 +5164,13 @@ class UncheckedTakeEnumDataAddrInst // Subclasses must provide tail allocated storage. // The first operand is the operand of select_xxx instruction. The rest of // the operands are the case values and results of a select instruction. -template -class SelectInstBase : public SingleValueInstruction { +template +class SelectInstBase : public Base { public: - SelectInstBase(SILInstructionKind kind, SILDebugLocation Loc, SILType type) - : SingleValueInstruction(kind, Loc, type) {} + template + SelectInstBase(SILInstructionKind kind, SILDebugLocation Loc, SILType type, + Args &&... otherArgs) + : Base(kind, Loc, type, std::forward(otherArgs)...) {} SILValue getOperand() const { return getAllOperands()[0].get(); } @@ -5181,9 +5224,8 @@ class SelectEnumInstBase createSelectEnum(SILDebugLocation DebugLoc, SILValue Enum, SILType Type, SILValue DefaultValue, ArrayRef> CaseValues, - SILFunction &F, - Optional> CaseCounts, - ProfileCounter DefaultCount); + SILModule &M, Optional> CaseCounts, + ProfileCounter DefaultCount, bool HasOwnership); public: ArrayRef getAllOperands() const; @@ -5234,27 +5276,45 @@ class SelectEnumInstBase /// not to need this. NullablePtr getSingleTrueElement() const; }; - + +/// A select enum inst that produces a static OwnershipKind set upon the +/// instruction's construction. +class OwnershipForwardingSelectEnumInstBase : public SelectEnumInstBase { + ValueOwnershipKind ownershipKind; + +protected: + OwnershipForwardingSelectEnumInstBase( + SILInstructionKind kind, SILDebugLocation debugLoc, SILType type, + bool defaultValue, Optional> caseCounts, + ProfileCounter defaultCount, ValueOwnershipKind ownershipKind) + : SelectEnumInstBase(kind, debugLoc, type, defaultValue, caseCounts, + defaultCount), + ownershipKind(ownershipKind) {} + +public: + ValueOwnershipKind getOwnershipKind() const { return ownershipKind; } +}; + /// Select one of a set of values based on the case of an enum. class SelectEnumInst final : public InstructionBaseWithTrailingOperands< - SILInstructionKind::SelectEnumInst, - SelectEnumInst, - SelectEnumInstBase, EnumElementDecl *> { + SILInstructionKind::SelectEnumInst, SelectEnumInst, + OwnershipForwardingSelectEnumInstBase, EnumElementDecl *> { friend SILBuilder; private: friend SelectEnumInstBase; SelectEnumInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Type, - bool DefaultValue, - ArrayRef CaseValues, + bool DefaultValue, ArrayRef CaseValues, ArrayRef CaseDecls, Optional> CaseCounts, - ProfileCounter DefaultCount) - : InstructionBaseWithTrailingOperands(Operand, CaseValues, DebugLoc, Type, - bool(DefaultValue), CaseCounts, - DefaultCount) { + ProfileCounter DefaultCount, bool HasOwnership) + : InstructionBaseWithTrailingOperands( + Operand, CaseValues, DebugLoc, Type, bool(DefaultValue), CaseCounts, + DefaultCount, + HasOwnership ? *mergeSILValueOwnership(CaseValues) + : ValueOwnershipKind(ValueOwnershipKind::Any)) { assert(CaseValues.size() - DefaultValue == CaseDecls.size()); std::uninitialized_copy(CaseDecls.begin(), CaseDecls.end(), getTrailingObjects()); @@ -5263,8 +5323,8 @@ class SelectEnumInst final create(SILDebugLocation DebugLoc, SILValue Operand, SILType Type, SILValue DefaultValue, ArrayRef> CaseValues, - SILFunction &F, Optional> CaseCounts, - ProfileCounter DefaultCount); + SILModule &M, Optional> CaseCounts, + ProfileCounter DefaultCount, bool HasOwnership); }; /// Select one of a set of values based on the case of an enum. @@ -5276,16 +5336,15 @@ class SelectEnumAddrInst final friend SILBuilder; friend SelectEnumInstBase; - SelectEnumAddrInst( - SILDebugLocation DebugLoc, SILValue Operand, SILType Type, - bool DefaultValue, - ArrayRef CaseValues, - ArrayRef CaseDecls, - Optional> CaseCounts, - ProfileCounter DefaultCount) + SelectEnumAddrInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Type, + bool DefaultValue, ArrayRef CaseValues, + ArrayRef CaseDecls, + Optional> CaseCounts, + ProfileCounter DefaultCount, bool HasOwnership) : InstructionBaseWithTrailingOperands(Operand, CaseValues, DebugLoc, Type, bool(DefaultValue), CaseCounts, DefaultCount) { + (void)HasOwnership; assert(CaseValues.size() - DefaultValue == CaseDecls.size()); std::uninitialized_copy(CaseDecls.begin(), CaseDecls.end(), getTrailingObjects()); @@ -5294,7 +5353,7 @@ class SelectEnumAddrInst final create(SILDebugLocation DebugLoc, SILValue Operand, SILType Type, SILValue DefaultValue, ArrayRef> CaseValues, - SILFunction &F, Optional> CaseCounts, + SILModule &M, Optional> CaseCounts, ProfileCounter DefaultCount); }; @@ -5304,21 +5363,20 @@ class SelectEnumAddrInst final /// followed by an optional default operand. class SelectValueInst final : public InstructionBaseWithTrailingOperands< - SILInstructionKind::SelectValueInst, - SelectValueInst, - SelectInstBase> { + SILInstructionKind::SelectValueInst, SelectValueInst, + SelectInstBase> { friend SILBuilder; SelectValueInst(SILDebugLocation DebugLoc, SILValue Operand, SILType Type, SILValue DefaultResult, - ArrayRef CaseValuesAndResults) - : InstructionBaseWithTrailingOperands(Operand, CaseValuesAndResults, - DebugLoc, Type) {} + ArrayRef CaseValuesAndResults, bool HasOwnership); static SelectValueInst * create(SILDebugLocation DebugLoc, SILValue Operand, SILType Type, SILValue DefaultValue, - ArrayRef> CaseValues, SILFunction &F); + ArrayRef> CaseValues, SILModule &M, + bool HasOwnership); public: std::pair @@ -5757,13 +5815,12 @@ class OpenExistentialValueInst /// existential by returning a pointer to a fresh archetype T, which also /// captures the (dynamic) conformances. class OpenExistentialRefInst - : public UnaryInstructionBase -{ + : public UnaryInstructionBase { friend SILBuilder; OpenExistentialRefInst(SILDebugLocation DebugLoc, SILValue Operand, - SILType Ty); + SILType Ty, bool HasOwnership); }; /// Given an existential metatype, @@ -5888,11 +5945,9 @@ class InitExistentialValueInst final /// conformances, creates a class existential value referencing the /// class instance. class InitExistentialRefInst final - : public UnaryInstructionWithTypeDependentOperandsBase< - SILInstructionKind::InitExistentialRefInst, - InitExistentialRefInst, - SingleValueInstruction> -{ + : public UnaryInstructionWithTypeDependentOperandsBase< + SILInstructionKind::InitExistentialRefInst, InitExistentialRefInst, + OwnershipForwardingSingleValueInst> { friend SILBuilder; CanType ConcreteType; @@ -5902,9 +5957,9 @@ class InitExistentialRefInst final CanType FormalConcreteType, SILValue Instance, ArrayRef TypeDependentOperands, ArrayRef Conformances) - : UnaryInstructionWithTypeDependentOperandsBase(DebugLoc, Instance, - TypeDependentOperands, - ExistentialType), + : UnaryInstructionWithTypeDependentOperandsBase( + DebugLoc, Instance, TypeDependentOperands, ExistentialType, + Instance.getOwnershipKind()), ConcreteType(FormalConcreteType), Conformances(Conformances) {} static InitExistentialRefInst * diff --git a/include/swift/SIL/ValueUtils.h b/include/swift/SIL/ValueUtils.h new file mode 100644 index 0000000000000..646f77bbb9a5d --- /dev/null +++ b/include/swift/SIL/ValueUtils.h @@ -0,0 +1,29 @@ +//===--- ValueUtils.h -----------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 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_VALUEUTILS_H +#define SWIFT_SIL_VALUEUTILS_H + +#include "swift/SIL/SILValue.h" + +namespace swift { + +/// Attempt to merge the ValueOwnershipKind of the passed in range's +/// SILValues. Returns Optional if we found an incompatibility. +/// +/// NOTE: This assumes that the passed in SILValues are not values used as type +/// dependent operands. +Optional mergeSILValueOwnership(ArrayRef values); + +} // namespace swift + +#endif diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index fde8a2392070f..1c006bebfbf66 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2961,14 +2961,13 @@ IRGenSILFunction::visitSwitchEnumAddrInst(SwitchEnumAddrInst *inst) { // FIXME: We could lower select_enum directly to LLVM select in a lot of cases. // For now, just emit a switch and phi nodes, like a chump. -template +template static llvm::BasicBlock * -emitBBMapForSelect(IRGenSILFunction &IGF, - Explosion &resultPHI, - SmallVectorImpl> &BBs, +emitBBMapForSelect(IRGenSILFunction &IGF, Explosion &resultPHI, + SmallVectorImpl> &BBs, llvm::BasicBlock *&defaultBB, - SelectInstBase *inst) { - + SelectInstBase *inst) { + auto origBB = IGF.Builder.GetInsertBlock(); // Set up a continuation BB and phi nodes to receive the result value. @@ -3099,10 +3098,10 @@ mapTriviallyToInt(IRGenSILFunction &IGF, const EnumImplStrategy &EIS, SelectEnum return result; } -template -static LoweredValue -getLoweredValueForSelect(IRGenSILFunction &IGF, - Explosion &result, SelectInstBase *inst) { +template +static LoweredValue getLoweredValueForSelect(IRGenSILFunction &IGF, + Explosion &result, + SelectInstBase *inst) { if (inst->getType().isAddress()) // FIXME: Loses potentially better alignment info we might have. return LoweredValue(Address(result.claimNext(), diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 2f040a9541e29..388e11e771709 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -5224,6 +5224,7 @@ bool SILParser::parseSILBasicBlock(SILBuilder &B) { F->setUnqualifiedOwnership(); } B.setInsertionPoint(BB); + B.setHasOwnership(F->hasQualifiedOwnership()); do { if (parseSILInstruction(B)) return true; diff --git a/lib/SIL/CMakeLists.txt b/lib/SIL/CMakeLists.txt index c85aab0351dd3..76b095b9d2d86 100644 --- a/lib/SIL/CMakeLists.txt +++ b/lib/SIL/CMakeLists.txt @@ -44,6 +44,7 @@ add_swift_host_library(swiftSIL STATIC SILWitnessTable.cpp TypeLowering.cpp ValueOwnership.cpp + ValueUtils.cpp LINK_LIBRARIES swiftSerialization swiftSema diff --git a/lib/SIL/SILBuilder.cpp b/lib/SIL/SILBuilder.cpp index 7fec2ff03c480..3c93f292f762f 100644 --- a/lib/SIL/SILBuilder.cpp +++ b/lib/SIL/SILBuilder.cpp @@ -24,7 +24,7 @@ using namespace swift; SILBuilder::SILBuilder(SILGlobalVariable *GlobVar, SmallVectorImpl *InsertedInstrs) : TempContext(GlobVar->getModule(), InsertedInstrs), C(TempContext), - F(nullptr) { + F(nullptr), hasOwnership(false) { setInsertionPoint(&GlobVar->StaticInitializerBlock); } diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index 0ed07ad76cc91..296a69b8bd9d2 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -873,31 +873,38 @@ UnconditionalCheckedCastAddrInst::UnconditionalCheckedCastAddrInst( Operands(this, src, dest), SourceType(srcType), TargetType(targetType) {} StructInst *StructInst::create(SILDebugLocation Loc, SILType Ty, - ArrayRef Elements, SILModule &M) { + ArrayRef Elements, SILModule &M, + bool HasOwnership) { auto Size = totalSizeToAlloc(Elements.size()); auto Buffer = M.allocateInst(Size, alignof(StructInst)); - return ::new(Buffer) StructInst(Loc, Ty, Elements); + return ::new (Buffer) StructInst(Loc, Ty, Elements, HasOwnership); } StructInst::StructInst(SILDebugLocation Loc, SILType Ty, - ArrayRef Elems) - : InstructionBaseWithTrailingOperands(Elems, Loc, Ty) { + ArrayRef Elems, bool HasOwnership) + : InstructionBaseWithTrailingOperands( + Elems, Loc, Ty, + HasOwnership ? *mergeSILValueOwnership(Elems) + : ValueOwnershipKind(ValueOwnershipKind::Any)) { assert(!Ty.getStructOrBoundGenericStruct()->hasUnreferenceableStorage()); } ObjectInst *ObjectInst::create(SILDebugLocation Loc, SILType Ty, ArrayRef Elements, - unsigned NumBaseElements, SILModule &M) { + unsigned NumBaseElements, SILModule &M, + bool HasOwnership) { auto Size = totalSizeToAlloc(Elements.size()); auto Buffer = M.allocateInst(Size, alignof(ObjectInst)); - return ::new(Buffer) ObjectInst(Loc, Ty, Elements, NumBaseElements); + return ::new (Buffer) + ObjectInst(Loc, Ty, Elements, NumBaseElements, HasOwnership); } TupleInst *TupleInst::create(SILDebugLocation Loc, SILType Ty, - ArrayRef Elements, SILModule &M) { + ArrayRef Elements, SILModule &M, + bool HasOwnership) { auto Size = totalSizeToAlloc(Elements.size()); auto Buffer = M.allocateInst(Size, alignof(TupleInst)); - return ::new(Buffer) TupleInst(Loc, Ty, Elements); + return ::new (Buffer) TupleInst(Loc, Ty, Elements, HasOwnership); } bool TupleExtractInst::isTrivialEltOfOneRCIDTuple() const { @@ -1322,11 +1329,20 @@ SwitchValueInst *SwitchValueInst::create( return ::new (buf) SwitchValueInst(Loc, Operand, DefaultBB, Cases, BBs); } +SelectValueInst::SelectValueInst(SILDebugLocation DebugLoc, SILValue Operand, + SILType Type, SILValue DefaultResult, + ArrayRef CaseValuesAndResults, + bool HasOwnership) + : InstructionBaseWithTrailingOperands( + Operand, CaseValuesAndResults, DebugLoc, Type, + HasOwnership ? *mergeSILValueOwnership(CaseValuesAndResults) + : ValueOwnershipKind(ValueOwnershipKind::Any)) {} + SelectValueInst * SelectValueInst::create(SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultResult, ArrayRef> CaseValues, - SILFunction &F) { + SILModule &M, bool HasOwnership) { // Allocate enough room for the instruction with tail-allocated data for all // the case values and the SILSuccessor arrays. There are `CaseBBs.size()` // SILValues and `CaseBBs.size() + (DefaultBB ? 1 : 0)` successors. @@ -1340,17 +1356,17 @@ SelectValueInst::create(SILDebugLocation Loc, SILValue Operand, SILType Type, CaseValuesAndResults.push_back(DefaultResult); auto Size = totalSizeToAlloc(CaseValuesAndResults.size() + 1); - auto Buf = F.getModule().allocateInst(Size, alignof(SelectValueInst)); + auto Buf = M.allocateInst(Size, alignof(SelectValueInst)); return ::new (Buf) SelectValueInst(Loc, Operand, Type, DefaultResult, - CaseValuesAndResults); + CaseValuesAndResults, HasOwnership); } template SELECT_ENUM_INST *SelectEnumInstBase::createSelectEnum( SILDebugLocation Loc, SILValue Operand, SILType Ty, SILValue DefaultValue, ArrayRef> DeclsAndValues, - SILFunction &F, Optional> CaseCounts, - ProfileCounter DefaultCount) { + SILModule &Mod, Optional> CaseCounts, + ProfileCounter DefaultCount, bool HasOwnership) { // Allocate enough room for the instruction with tail-allocated // EnumElementDecl and operand arrays. There are `CaseBBs.size()` decls // and `CaseBBs.size() + (DefaultBB ? 1 : 0)` values. @@ -1367,31 +1383,34 @@ SELECT_ENUM_INST *SelectEnumInstBase::createSelectEnum( auto Size = SELECT_ENUM_INST::template totalSizeToAlloc(CaseValues.size() + 1, CaseDecls.size()); - auto Buf = F.getModule().allocateInst(Size + sizeof(ProfileCounter), - alignof(SELECT_ENUM_INST)); - return ::new (Buf) SELECT_ENUM_INST(Loc, Operand, Ty, bool(DefaultValue), - CaseValues, CaseDecls, CaseCounts, - DefaultCount); + auto Buf = Mod.allocateInst(Size + sizeof(ProfileCounter), + alignof(SELECT_ENUM_INST)); + return ::new (Buf) + SELECT_ENUM_INST(Loc, Operand, Ty, bool(DefaultValue), CaseValues, + CaseDecls, CaseCounts, DefaultCount, HasOwnership); } SelectEnumInst *SelectEnumInst::create( SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultValue, - ArrayRef> CaseValues, SILFunction &F, - Optional> CaseCounts, - ProfileCounter DefaultCount) { + ArrayRef> CaseValues, SILModule &M, + Optional> CaseCounts, ProfileCounter DefaultCount, + bool HasOwnership) { return createSelectEnum(Loc, Operand, Type, DefaultValue, - CaseValues, F, CaseCounts, - DefaultCount); + CaseValues, M, CaseCounts, + DefaultCount, HasOwnership); } SelectEnumAddrInst *SelectEnumAddrInst::create( SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultValue, - ArrayRef> CaseValues, SILFunction &F, + ArrayRef> CaseValues, SILModule &M, Optional> CaseCounts, ProfileCounter DefaultCount) { - return createSelectEnum(Loc, Operand, Type, DefaultValue, - CaseValues, F, CaseCounts, - DefaultCount); + // We always pass in false since SelectEnumAddrInst doesn't use ownership. We + // have to pass something in since SelectEnumInst /does/ need to consider + // ownership and both use the same creation function. + return createSelectEnum( + Loc, Operand, Type, DefaultValue, CaseValues, M, CaseCounts, DefaultCount, + false /*HasOwnership*/); } SwitchEnumInstBase::SwitchEnumInstBase( @@ -1792,9 +1811,13 @@ OpenExistentialAddrInst::OpenExistentialAddrInst( OpenedExistentialAccess AccessKind) : UnaryInstructionBase(DebugLoc, Operand, SelfTy), ForAccess(AccessKind) {} -OpenExistentialRefInst::OpenExistentialRefInst( - SILDebugLocation DebugLoc, SILValue Operand, SILType Ty) - : UnaryInstructionBase(DebugLoc, Operand, Ty) { +OpenExistentialRefInst::OpenExistentialRefInst(SILDebugLocation DebugLoc, + SILValue Operand, SILType Ty, + bool HasOwnership) + : UnaryInstructionBase(DebugLoc, Operand, Ty, + HasOwnership + ? Operand.getOwnershipKind() + : ValueOwnershipKind(ValueOwnershipKind::Any)) { assert(Operand->getType().isObject() && "Operand must be an object."); assert(Ty.isObject() && "Result type must be an object type."); } diff --git a/lib/SIL/ValueOwnership.cpp b/lib/SIL/ValueOwnership.cpp index 8db612938ab4c..dbfbf4675ace5 100644 --- a/lib/SIL/ValueOwnership.cpp +++ b/lib/SIL/ValueOwnership.cpp @@ -46,11 +46,6 @@ class ValueOwnershipKindClassifier #define CONSTANT_OWNERSHIP_INST(OWNERSHIP, INST) \ ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \ INST##Inst *Arg) { \ - 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; \ } @@ -259,7 +254,7 @@ ValueOwnershipKindClassifier::visitForwardingInst(SILInstruction *I, #define FORWARDING_OWNERSHIP_INST(INST) \ ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \ INST##Inst *I) { \ - return visitForwardingInst(I); \ + return I->getOwnershipKind(); \ } FORWARDING_OWNERSHIP_INST(BridgeObjectToRef) FORWARDING_OWNERSHIP_INST(ConvertFunction) @@ -275,29 +270,16 @@ FORWARDING_OWNERSHIP_INST(UnconditionalCheckedCast) FORWARDING_OWNERSHIP_INST(Upcast) FORWARDING_OWNERSHIP_INST(MarkUninitialized) FORWARDING_OWNERSHIP_INST(UncheckedEnumData) +FORWARDING_OWNERSHIP_INST(SelectEnum) +FORWARDING_OWNERSHIP_INST(Enum) #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::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; } @@ -396,8 +378,6 @@ struct ValueOwnershipKindBuiltinVisitor llvm::Intrinsic::ID ID) { // LLVM intrinsics do not traffic in ownership, so if we have a result, it // must be trivial. - assert(BI->getType().isTrivial(BI->getModule()) && - "LLVM intrinsics should always be trivial"); return ValueOwnershipKind::Trivial; } @@ -411,13 +391,6 @@ struct ValueOwnershipKindBuiltinVisitor #define CONSTANT_OWNERSHIP_BUILTIN(OWNERSHIP, ID) \ ValueOwnershipKind ValueOwnershipKindBuiltinVisitor::visit##ID( \ BuiltinInst *BI, StringRef Attr) { \ - 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; \ } // This returns a value at +1 that is destroyed strictly /after/ the diff --git a/lib/SIL/ValueUtils.cpp b/lib/SIL/ValueUtils.cpp new file mode 100644 index 0000000000000..84861816d13b0 --- /dev/null +++ b/lib/SIL/ValueUtils.cpp @@ -0,0 +1,55 @@ +//===--- ValueUtils.cpp ---------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 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/SIL/ValueUtils.h" +#include "swift/Basic/STLExtras.h" +#include "swift/SIL/SILFunction.h" + +using namespace swift; + +Optional +swift::mergeSILValueOwnership(ArrayRef values) { + // A forwarding inst without operands must be trivial. + if (values.empty()) + return Optional(ValueOwnershipKind::Trivial); + + // Find the first index where we have a trivial value. + auto iter = find_if(values, [](SILValue v) -> bool { + return v.getOwnershipKind() != ValueOwnershipKind::Trivial; + }); + // All trivial. + if (iter == values.end()) { + return Optional(ValueOwnershipKind::Trivial); + } + + // See if we have any Any. If we do, just return that for now. + if (any_of(values, [](SILValue v) -> bool { + return v.getOwnershipKind() == ValueOwnershipKind::Any; + })) + return Optional(ValueOwnershipKind::Any); + + unsigned index = std::distance(values.begin(), iter); + ValueOwnershipKind base = values[index].getOwnershipKind(); + + for (SILValue v : values.slice(index + 1)) { + auto opKind = v.getOwnershipKind(); + if (opKind.merge(ValueOwnershipKind::Trivial)) + continue; + + auto mergedValue = base.merge(opKind.Value); + if (!mergedValue.hasValue()) { + return None; + } + } + + return base; +} diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil index a6460da2fd8f1..c099627d87388 100644 --- a/test/SILOptimizer/sil_combine.sil +++ b/test/SILOptimizer/sil_combine.sil @@ -2352,10 +2352,8 @@ bb0: // CHECK-LABEL: sil @remove_dead_code_after_unreachable // CHECK-NEXT: bb0 -// CHECK-NOT: integer_literal $Builtin.Int32, -2 // CHECK-NEXT: unreachable -// CHECK-NOT: integer_literal $Builtin.Int32, -2 -// CHECK-NEXT: } +// CHECK-NEXT: } // end sil function 'remove_dead_code_after_unreachable' sil @remove_dead_code_after_unreachable : $@convention(thin) () -> (Int32) { bb0: unreachable