//===--- SILInstruction.h - Instructions for SIL code -----------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the high-level SILInstruction class used for SIL code. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_INSTRUCTION_H #define SWIFT_SIL_INSTRUCTION_H #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "swift/AST/Builtins.h" #include "swift/SIL/SILAllocated.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILSuccessor.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILValue.h" namespace swift { class CharacterLiteralExpr; class DeclRefExpr; class FloatLiteralExpr; class FuncDecl; class IntegerLiteralExpr; class SILBasicBlock; class SILDebugScope; class SILFunction; class SILGlobalVariable; class SILType; class Stmt; class StringLiteralExpr; class Substitution; class ValueDecl; class VarDecl; enum IsTake_t { IsNotTake, IsTake }; enum IsInitialization_t { IsNotInitialization, IsInitialization }; /// This is the root class for all instructions that can be used as the contents /// of a Swift SILBasicBlock. class SILInstruction : public ValueBase,public llvm::ilist_node{ friend struct llvm::ilist_traits; /// A backreference to the containing basic block. This is maintained by /// ilist_traits. SILBasicBlock *ParentBB; /// This instruction's containing lexical scope used for debug info. SILDebugScope* DebugScope; friend struct llvm::ilist_sentinel_traits; SILInstruction() = delete; void operator=(const SILInstruction &) = delete; void operator delete(void *Ptr, size_t) = delete; protected: /// This instruction's location (i.e., AST). SILLocation Loc; SILInstruction(ValueKind Kind, SILLocation Loc, SILType Ty, SILDebugScope *DS = nullptr) : ValueBase(Kind, Ty), ParentBB(0), DebugScope(DS), Loc(Loc) {} SILInstruction(ValueKind Kind, SILLocation Loc, SILTypeList *TypeList=nullptr, SILDebugScope *DS = nullptr) : ValueBase(Kind, TypeList), ParentBB(0), DebugScope(DS), Loc(Loc) {} public: enum class MemoryBehavior { None, /// The instruction may read memory. MayRead, /// \brief The instruction may write to memory. MayWrite, /// The instruction may read or write memory. MayReadWrite, /// \brief The instruction may have side effects not captured solely by its /// users. Specifically, it can return, release memory, or store. Note, /// alloc is not considered to have side effects because its /// result/users represent its effect. MayHaveSideEffects, }; const SILBasicBlock *getParent() const { return ParentBB; } SILBasicBlock *getParent() { return ParentBB; } SILFunction *getFunction(); const SILFunction *getFunction() const; SILModule &getModule() const; SILLocation getLoc() const { return Loc; } SILDebugScope *getDebugScope() const { return DebugScope; } SILInstruction *setDebugScope(SILDebugScope *DS) { DebugScope = DS; return this; } /// removeFromParent - This method unlinks 'self' from the containing basic /// block, but does not delete it. /// void removeFromParent(); /// eraseFromParent - This method unlinks 'self' from the containing basic /// block and deletes it. /// void eraseFromParent(); /// Unlink this instruction from its current basic block and insert it into /// the basic block that MovePos lives in, right before MovePos. void moveBefore(SILInstruction *MovePos); /// \brief Drops all uses that belong to this instruction. void dropAllReferences(); /// Return the array of operands for this instruction. ArrayRef getAllOperands() const; /// Return the array of mutable operands for this instruction. MutableArrayRef getAllOperands(); unsigned getNumOperands() const { return getAllOperands().size(); } SILValue getOperand(unsigned Num) const { return getAllOperands()[Num].get();} void setOperand(unsigned Num, SILValue V) { getAllOperands()[Num].set(V); } void swapOperands(unsigned Num1, unsigned Num2) { getAllOperands()[Num1].swap(getAllOperands()[Num2]); } MemoryBehavior getMemoryBehavior() const; /// Returns true if the given instruction is completely identical to RHS. bool isIdenticalTo(const SILInstruction *RHS) const; /// \brief Returns true if the instruction may have side effects. /// /// Instructions that store into memory or change retain counts as well as /// calls and deallocation instructions are considered to have side effects /// that are not visible by merely examining their uses. bool mayHaveSideEffects() const; /// Returns true if the instruction may write to memory. bool mayWriteToMemory() const { MemoryBehavior B = getMemoryBehavior(); return B == MemoryBehavior::MayWrite || B == MemoryBehavior::MayReadWrite || B == MemoryBehavior::MayHaveSideEffects; } /// Returns true if the instruction may read from memory. bool mayReadFromMemory() const { MemoryBehavior B = getMemoryBehavior(); return B == MemoryBehavior::MayRead || B == MemoryBehavior::MayReadWrite || B == MemoryBehavior::MayHaveSideEffects; } /// Returns true if the instruction may read from or write to memory. bool mayReadOrWriteMemory() const { return getMemoryBehavior() != MemoryBehavior::None; } static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_SILInstruction && V->getKind() <= ValueKind::Last_SILInstruction; } /// Create a new copy of this instruction, which retains all of the operands /// and other information of this one. If an insertion point is specified, /// then the new instruction is inserted before the specified point, otherwise /// the new instruction is returned without a parent. SILInstruction *clone(SILInstruction *InsertPt = nullptr); /// Invoke an Instruction's destructor. This dispatches to the appropriate /// leaf class destructor for the type of the instruction. This does not /// deallocate the instruction. static void destroy(SILInstruction *I); }; /// A template base class for instructions that take a single SILValue operand /// and has no result or a single value result. template class UnaryInstructionBase : public BASE { FixedOperandList<1> Operands; /// Check HAS_RESULT in enable_if predicates by injecting a dependency on /// a template argument. template struct has_result { enum { value = HAS_RESULT }; }; public: UnaryInstructionBase(SILLocation Loc, SILValue Operand) : BASE(KIND, Loc), Operands(this, Operand) {} template UnaryInstructionBase(SILLocation Loc, SILValue Operand, typename std::enable_if::value, SILType>::type Ty) : BASE(KIND, Loc, Ty), Operands(this, Operand) {} template UnaryInstructionBase(SILLocation Loc, SILValue Operand, typename std::enable_if::value, SILType>::type Ty, A &&...args) : BASE(KIND, Loc, Ty, std::forward(args)...), Operands(this, Operand) {} SILValue getOperand() const { return Operands[0].get(); } void setOperand(SILValue V) { Operands[0].set(V); } /// getType() is ok if this is known to only have one type. template typename std::enable_if::value, SILType>::type getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == KIND; } }; //===----------------------------------------------------------------------===// // Allocation Instructions //===----------------------------------------------------------------------===// /// Abstract base class for literal instructions. class AllocationInst : public SILInstruction { protected: AllocationInst(ValueKind Kind, SILLocation Loc, SILType Ty) : SILInstruction(Kind, Loc, Ty) {} AllocationInst(ValueKind Kind, SILLocation Loc, SILTypeList *TypeList=nullptr, SILDebugScope *DS = nullptr) : SILInstruction(Kind, Loc, TypeList, DS) {} public: static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_AllocationInst && V->getKind() <= ValueKind::Last_AllocationInst; } }; /// AllocStackInst - This represents the allocation of an unboxed (i.e., no /// reference count) stack memory. The memory is provided uninitialized. class AllocStackInst : public AllocationInst { public: AllocStackInst(SILLocation loc, SILType elementType, SILFunction &F); /// getDecl - Return the underlying variable declaration associated with this /// allocation, or null if this is a temporary allocation. VarDecl *getDecl() const; /// getElementType - Get the type of the allocated memory (as opposed to the /// (second) type of the instruction itself, which will be an address type). SILType getElementType() const { return getType(1).getObjectType(); } SILValue getContainerResult() const { return SILValue(this, 0); } SILValue getAddressResult() const { return SILValue(this, 1); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::AllocStackInst; } }; /// AllocRefInst - This represents the primitive allocation of an instance /// of a reference type. Aside from the reference count, the instance is /// returned uninitialized. class AllocRefInst : public AllocationInst { bool ObjC; public: AllocRefInst(SILLocation loc, SILType type, SILFunction &F, bool objc); SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } /// Whether to use Objective-C's allocation mechanism (+allocWithZone:). bool isObjC() const { return ObjC; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::AllocRefInst; } }; /// AllocRefDynamicInst - This represents the primitive allocation of /// an instance of a reference type whose runtime type is provided by /// the given metatype value. Aside from the reference count, the /// instance is returned uninitialized. class AllocRefDynamicInst : public UnaryInstructionBase { bool ObjC; public: AllocRefDynamicInst(SILLocation loc, SILValue operand, SILType ty, bool objc) : UnaryInstructionBase(loc, operand, ty), ObjC(objc) { } /// Whether to use Objective-C's allocation mechanism (+allocWithZone:). bool isObjC() const { return ObjC; } }; /// This represents the allocation of a heap box for a Swift value of some type. /// The instruction returns two values. The first return value is the object /// pointer with Builtin.NativeObject type. The second return value /// is an address pointing to the contained element. The contained /// element is uninitialized. class AllocBoxInst : public AllocationInst { public: AllocBoxInst(SILLocation Loc, SILType ElementType, SILFunction &F); SILType getElementType() const { return getType(1).getObjectType(); } SILValue getContainerResult() const { return SILValue(this, 0); } SILValue getAddressResult() const { return SILValue(this, 1); } /// getDecl - Return the underlying variable declaration associated with this /// allocation, or null if this is a temporary allocation. VarDecl *getDecl() const; ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::AllocBoxInst; } }; /// AllocArrayInst - This represents the allocation of an array of elements, /// whose element memory is left uninitialized. This returns two values. The /// first return element is the object pointer (pointer to the object /// header) with Builtin.NativeObject type. The second element returned is an /// lvalue to the first array element. /// class AllocArrayInst : public AllocationInst { enum { NumElements }; FixedOperandList<1> Operands; public: AllocArrayInst(SILLocation Loc, SILType ElementType, SILValue NumElements, SILFunction &F); SILType getElementType() const { return getType(1).getObjectType(); } SILValue getNumElements() const { return Operands[NumElements].get(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::AllocArrayInst; } }; /// ApplyInst - Represents the full application of a function value. class ApplyInst : public SILInstruction { enum { Callee }; /// The number of tail-allocated substitutions, allocated after the operand /// list's tail allocation. unsigned NumSubstitutions : 31; /// Whether the callee had the attribute [transparent]. unsigned Transparent : 1; /// The type of the callee with our substitutions applied. SILType SubstCalleeType; /// The fixed operand is the callee; the rest are arguments. TailAllocatedOperandList<1> Operands; Substitution *getSubstitutionsStorage() { return reinterpret_cast(Operands.asArray().end()); } const Substitution *getSubstitutionsStorage() const { return reinterpret_cast(Operands.asArray().end()); } ApplyInst(SILLocation Loc, SILValue Callee, SILType SubstCalleeType, SILType ReturnType, ArrayRef Substitutions, ArrayRef Args, bool Transparent); public: static ApplyInst *create(SILLocation Loc, SILValue Callee, SILType SubstCalleeType, SILType ReturnType, ArrayRef Substitutions, ArrayRef Args, bool Transparent, SILFunction &F); SILValue getCallee() const { return Operands[Callee].get(); } // Get the type of the callee without the applied substitutions. CanSILFunctionType getOrigCalleeType() const { return getCallee().getType().castTo(); } // Get the type of the callee with the applied substitutions. CanSILFunctionType getSubstCalleeType() const { return SubstCalleeType.castTo(); } SILType getSubstCalleeSILType() const { return SubstCalleeType; } bool isCalleeThin() const { auto Rep = getSubstCalleeType()->getRepresentation(); return Rep == FunctionType::Representation::Thin; } /// True if this application has generic substitutions. bool hasSubstitutions() const { return NumSubstitutions != 0; } /// The substitutions used to bind the generic arguments of this function. MutableArrayRef getSubstitutions() { return {getSubstitutionsStorage(), NumSubstitutions}; } ArrayRef getSubstitutions() const { return {getSubstitutionsStorage(), NumSubstitutions}; } /// The arguments passed to this instruction. MutableArrayRef getArgumentOperands() { return Operands.getDynamicAsArray(); } /// The arguments passed to this instruction. OperandValueArrayRef getArguments() const { return Operands.getDynamicValuesAsArray(); } /// The number of arguments passed to the ApplyInst. unsigned getNumArguments() const { return getArguments().size(); } /// Return the ith argument passed to this instruction. SILValue getArgument(unsigned i) const { return getArguments()[i]; } bool isTransparent() const { return Transparent; } bool hasIndirectResult() const { return getSubstCalleeType()->hasIndirectResult(); } SILValue getIndirectResult() const { assert(hasIndirectResult() && "apply inst does not have indirect result!"); return getArguments().front(); } OperandValueArrayRef getArgumentsWithoutIndirectResult() const { if (hasIndirectResult()) return getArguments().slice(1); return getArguments(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::ApplyInst; } }; /// PartialApplyInst - Represents the creation of a closure object by partial /// application of a function value. class PartialApplyInst : public SILInstruction { enum { Callee }; SILType SubstCalleeType; /// The number of tail-allocated substitutions, allocated after the operand /// list's tail allocation. unsigned NumSubstitutions; /// The fixed operand is the callee; the rest are arguments. TailAllocatedOperandList<1> Operands; Substitution *getSubstitutionsStorage() { return reinterpret_cast(Operands.asArray().end()); } const Substitution *getSubstitutionsStorage() const { return reinterpret_cast(Operands.asArray().end()); } PartialApplyInst(SILLocation Loc, SILValue Callee, SILType SubstCalleeType, ArrayRef Substitutions, ArrayRef Args, SILType ClosureType); public: static PartialApplyInst *create(SILLocation Loc, SILValue Callee, SILType SubstCalleeType, ArrayRef Substitutions, ArrayRef Args, SILType ClosureType, SILFunction &F); SILValue getCallee() const { return Operands[Callee].get(); } // Get the type of the callee without the applied substitutions. CanSILFunctionType getOrigCalleeType() const { return getCallee().getType().castTo(); } // Get the type of the callee with the applied substitutions. CanSILFunctionType getSubstCalleeType() const { return SubstCalleeType.castTo(); } SILType getSubstCalleeSILType() const { return SubstCalleeType; } /// True if this application has generic substitutions. bool hasSubstitutions() const { return NumSubstitutions != 0; } /// The substitutions used to bind the generic arguments of this function. MutableArrayRef getSubstitutions() { return {getSubstitutionsStorage(), NumSubstitutions}; } ArrayRef getSubstitutions() const { return {getSubstitutionsStorage(), NumSubstitutions}; } /// The arguments passed to this instruction. MutableArrayRef getArgumentOperands() { return Operands.getDynamicAsArray(); } /// The arguments passed to this instruction. OperandValueArrayRef getArguments() const { return Operands.getDynamicValuesAsArray(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::PartialApplyInst; } }; //===----------------------------------------------------------------------===// // Literal instructions. //===----------------------------------------------------------------------===// /// Abstract base class for literal instructions. class LiteralInst : public SILInstruction { protected: LiteralInst(ValueKind Kind, SILLocation Loc, SILType Ty) : SILInstruction(Kind, Loc, Ty) {} public: static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_LiteralInst && V->getKind() <= ValueKind::Last_LiteralInst; } }; /// FunctionRefInst - Represents a reference to a SIL function. class FunctionRefInst : public LiteralInst { SILFunction *Function; public: /// Construct a FunctionRefInst. /// /// \param Loc The location of the reference. /// \param F The function being referenced. FunctionRefInst(SILLocation Loc, SILFunction *F); ~FunctionRefInst(); /// Return the referenced function. SILFunction *getReferencedFunction() const { return Function; } void dropReferencedFunction(); /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::FunctionRefInst; } }; /// BuiltinFunctionRefInst - Represents a reference to a primitive function from /// the Builtin module. class BuiltinFunctionRefInst : public LiteralInst { Identifier Name; public: BuiltinFunctionRefInst(SILLocation Loc, Identifier Name, SILType Ty) : LiteralInst(ValueKind::BuiltinFunctionRefInst, Loc, Ty), Name(Name) {} /// Return the referenced function. Identifier getName() const { return Name; } SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } /// \brief Looks up the llvm intrinsic ID and type for the builtin function. /// /// \returns Returns llvm::Intrinsic::not_intrinsic if the function is not an /// intrinsic. The particular intrinsic functions which correspond to the /// retruned value are defined in llvm/Intrinsics.h. const IntrinsicInfo &getIntrinsicInfo() const; /// \brief Looks up the lazily cached identification for the builtin function. const BuiltinInfo &getBuiltinInfo() const; ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::BuiltinFunctionRefInst; } }; /// \brief Gives the address of a global variable. /// /// TODO: Fold into SILGlobalAddrInst. class GlobalAddrInst : public LiteralInst { VarDecl *Global; public: GlobalAddrInst(SILLocation Loc, VarDecl *Global, SILType AddrTy) : LiteralInst(ValueKind::GlobalAddrInst, Loc, AddrTy), Global(Global) {} /// Return the referenced global variable decl. VarDecl *getGlobal() const { return Global; } /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::GlobalAddrInst; } }; /// Gives the address of a SIL global variable. class SILGlobalAddrInst : public LiteralInst { SILGlobalVariable *Global; public: SILGlobalAddrInst(SILLocation Loc, SILGlobalVariable *Global); /// Return the referenced global variable. SILGlobalVariable *getReferencedGlobal() const { return Global; } /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::SILGlobalAddrInst; } }; /// IntegerLiteralInst - Encapsulates an integer constant, as defined originally /// by an an IntegerLiteralExpr or CharacterLiteralExpr. class IntegerLiteralInst : public LiteralInst { unsigned numBits; IntegerLiteralInst(SILLocation Loc, SILType Ty, const APInt &Value); public: static IntegerLiteralInst *create(IntegerLiteralExpr *E, SILFunction &B); static IntegerLiteralInst *create(CharacterLiteralExpr *E, SILFunction &B); static IntegerLiteralInst *create(SILLocation Loc, SILType Ty, intmax_t Value, SILFunction &B); static IntegerLiteralInst *create(SILLocation Loc, SILType Ty, const APInt &Value, SILFunction &B); /// getValue - Return the APInt for the underlying integer literal. APInt getValue() const; /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::IntegerLiteralInst; } }; /// FloatLiteralInst - Encapsulates a floating point constant, as defined /// originally by a FloatLiteralExpr. class FloatLiteralInst : public LiteralInst { unsigned numBits; FloatLiteralInst(SILLocation Loc, SILType Ty, const APInt &Bits); public: static FloatLiteralInst *create(FloatLiteralExpr *E, SILFunction &B); static FloatLiteralInst *create(SILLocation Loc, SILType Ty, const APFloat &Value, SILFunction &B); /// \brief Return the APFloat for the underlying FP literal. APFloat getValue() const; /// \brief Return the bitcast representation of the FP literal as an APInt. APInt getBits() const; /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::FloatLiteralInst; } }; /// StringLiteralInst - Encapsulates a string constant, as defined originally by /// a StringLiteralExpr. This produces the address of the string data as a /// Builtin.RawPointer. class StringLiteralInst : public LiteralInst { public: enum class Encoding { UTF8, UTF16 }; private: unsigned Length; Encoding TheEncoding; StringLiteralInst(SILLocation loc, StringRef text, Encoding encoding, SILType ty); public: static StringLiteralInst *create(SILLocation Loc, StringRef Text, Encoding encoding, SILFunction &F); /// getValue - Return the string data for the literal, in UTF-8. StringRef getValue() const { return {reinterpret_cast(this + 1), Length}; } /// getEncoding - Return the desired encoding of the text. Encoding getEncoding() const { return TheEncoding; } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::StringLiteralInst; } }; /// LoadInst - Represents a load from a memory location. class LoadInst : public UnaryInstructionBase { public: /// Constructs a LoadInst. /// /// \param Loc The location of the expression that caused the load. /// /// \param LValue The SILValue representing the lvalue (address) to /// use for the load. LoadInst(SILLocation Loc, SILValue LValue) : UnaryInstructionBase(Loc, LValue, LValue.getType().getObjectType()) {} }; /// StoreInst - Represents a store from a memory location. class StoreInst : public SILInstruction { enum { /// the value being stored Src, /// the lvalue being stored to Dest }; FixedOperandList<2> Operands; public: StoreInst(SILLocation Loc, SILValue Src, SILValue Dest); SILValue getSrc() const { return Operands[Src].get(); } SILValue getDest() const { return Operands[Dest].get(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::StoreInst; } }; /// AssignInst - Represents an abstract assignment to a memory location, which /// may either be an initialization or a store sequence. This is only valid in /// Raw SIL. class AssignInst : public SILInstruction { enum { /// the value being stored Src, /// the lvalue being stored to Dest }; FixedOperandList<2> Operands; public: AssignInst(SILLocation Loc, SILValue Src, SILValue Dest); SILValue getSrc() const { return Operands[Src].get(); } SILValue getDest() const { return Operands[Dest].get(); } bool isUnownedAssign() const { return getDest().getType().getObjectType().is(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::AssignInst; } }; /// MarkUninitializedInst - 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 { public: // This enum captures what the mark_uninitialized instruction is designating. enum Kind { /// Var designates the start of a normal variable live range. Var, /// RootSelf designates "self" in a struct, enum, or root class. RootSelf, /// DerivedSelf designates "self" in a derived (non-root) class. DerivedSelf, /// DerivedSelfOnly designates "self" in a derived (non-root) /// class whose stored properties have already been initialized. DerivedSelfOnly, /// DelegatingSelf designates "self" on a struct, enum, or class /// in a delegating constructor (one that calls self.init). DelegatingSelf, }; private: Kind ThisKind; public: MarkUninitializedInst(SILLocation Loc, SILValue Address, Kind K) : UnaryInstructionBase(Loc, Address, Address.getType()), ThisKind(K) { } Kind getKind() const { return ThisKind; } bool isVar() const { return ThisKind == Var; } bool isRootSelf() const { return ThisKind == RootSelf; } bool isDerivedClassSelf() const { return ThisKind == DerivedSelf; } bool isDerivedClassSelfOnly() const { return ThisKind == DerivedSelfOnly; } bool isDelegatingSelf() const { return ThisKind == DelegatingSelf; } }; /// MarkFunctionEscape - Represents the escape point of set of variables due to /// a function definition which uses the variables. This is only valid in Raw /// SIL. class MarkFunctionEscapeInst : public SILInstruction { TailAllocatedOperandList<0> Operands; /// Private constructor. Because this is variadic, object creation goes /// through 'create()'. MarkFunctionEscapeInst(SILLocation Loc, ArrayRef Elements); public: /// The elements referenced by this instruction. MutableArrayRef getElementOperands() { return Operands.getDynamicAsArray(); } /// The elements referenced by this instruction. OperandValueArrayRef getElements() const { return Operands.getDynamicValuesAsArray(); } /// Construct a MarkFunctionEscapeInst. static MarkFunctionEscapeInst *create(SILLocation Loc, ArrayRef Elements, SILFunction &F); ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::MarkFunctionEscapeInst; } }; /// Define the start or update to a symbolic variable value (for loadable /// types). class DebugValueInst : public UnaryInstructionBase { public: DebugValueInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} /// getDecl - Return the underlying variable declaration that this denotes, /// or null if we don't have one. VarDecl *getDecl() const; }; /// Define the start or update to a symbolic variable value (for address-only /// types) . class DebugValueAddrInst : public UnaryInstructionBase { public: DebugValueAddrInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} /// getDecl - Return the underlying variable declaration that this denotes, /// or null if we don't have one. VarDecl *getDecl() const; }; /// Represents a load from a @weak memory location. class LoadWeakInst : public UnaryInstructionBase { static SILType getResultType(SILType operandTy) { assert(operandTy.isAddress() && "loading from non-address operand?"); auto refType = cast(operandTy.getSwiftRValueType()); return SILType::getPrimitiveObjectType(refType.getReferentType()); } unsigned IsTake : 1; // FIXME: pack this somewhere public: /// \param loc The location of the expression that caused the load. /// \param lvalue The SILValue representing the address to /// use for the load. LoadWeakInst(SILLocation loc, SILValue lvalue, IsTake_t isTake) : UnaryInstructionBase(loc, lvalue, getResultType(lvalue.getType())), IsTake(unsigned(isTake)) {} IsTake_t isTake() const { return IsTake_t(IsTake); } }; /// Represents a store to a @weak memory location. class StoreWeakInst : public SILInstruction { enum { Src, Dest }; FixedOperandList<2> Operands; unsigned IsInitializationOfDest : 1; // FIXME: pack this somewhere public: StoreWeakInst(SILLocation loc, SILValue src, SILValue dest, IsInitialization_t isInit); SILValue getSrc() const { return Operands[Src].get(); } SILValue getDest() const { return Operands[Dest].get(); } IsInitialization_t isInitializationOfDest() const { return IsInitialization_t(IsInitializationOfDest); } void setIsInitializationOfDest(IsInitialization_t I) { IsInitializationOfDest = (bool)I; } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::StoreWeakInst; } }; /// CopyAddrInst - Represents a copy from one memory location to another. This /// is similar to: /// %1 = load %src /// store %1 to %dest /// but a copy instruction must be used for address-only types. class CopyAddrInst : public SILInstruction { // FIXME: compress storage /// IsTakeOfSrc - True if ownership will be taken from the value at the source /// memory location. unsigned IsTakeOfSrc : 1; /// IsInitializationOfDest - True if this is the initialization of the /// uninitialized destination memory location. unsigned IsInitializationOfDest : 1; enum { /// The lvalue being loaded from. Src, /// The lvalue being stored to. Dest }; FixedOperandList<2> Operands; public: CopyAddrInst(SILLocation Loc, SILValue Src, SILValue Dest, IsTake_t isTakeOfSrc, IsInitialization_t isInitializationOfDest); SILValue getSrc() const { return Operands[Src].get(); } SILValue getDest() const { return Operands[Dest].get(); } void setSrc(SILValue V) { Operands[Src].set(V); } void setDest(SILValue V) { Operands[Dest].set(V); } IsTake_t isTakeOfSrc() const { return IsTake_t(IsTakeOfSrc); } IsInitialization_t isInitializationOfDest() const { return IsInitialization_t(IsInitializationOfDest); } void setIsTakeOfSrc(IsTake_t T) { IsTakeOfSrc = (bool)T; } void setIsInitializationOfDest(IsInitialization_t I) { IsInitializationOfDest = (bool)I; } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::CopyAddrInst; } }; /// ConversionInst - Abstract class representing instructions that convert /// values. class ConversionInst : public SILInstruction { public: ConversionInst(ValueKind Kind, SILLocation Loc, SILType Ty) : SILInstruction(Kind, Loc, Ty) {} /// All conversion instructions return a single result. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_ConversionInst && V->getKind() <= ValueKind::Last_ConversionInst; } }; /// ConvertFunctionInst - Change the type of some value without affecting how it /// will codegen. class ConvertFunctionInst : public UnaryInstructionBase { public: ConvertFunctionInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// UpcastInst - Perform a conversion of a class instance to a supertype. class UpcastInst : public UnaryInstructionBase { public: UpcastInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// AddressToPointerInst - Convert a SIL address to a Builtin.RawPointer value. class AddressToPointerInst : public UnaryInstructionBase { public: AddressToPointerInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// PointerToAddressInst - Convert a Builtin.RawPointer value to a SIL address. class PointerToAddressInst : public UnaryInstructionBase { public: PointerToAddressInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// Convert a heap object reference to a different type without any runtime /// checks. class UncheckedRefCastInst : public UnaryInstructionBase { public: UncheckedRefCastInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; class UncheckedAddrCastInst : public UnaryInstructionBase { public: UncheckedAddrCastInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// RefToRawPointer - Convert a reference type to a Builtin.RawPointer. class RefToRawPointerInst : public UnaryInstructionBase { public: RefToRawPointerInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// RawPointerToRefInst - Convert a Builtin.RawPointer to a reference type. class RawPointerToRefInst : public UnaryInstructionBase { public: RawPointerToRefInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// RefToUnownedInst - Given a value of a reference type, /// convert it to an unowned reference. /// /// This does nothing at runtime; it just changes the formal type. class RefToUnownedInst : public UnaryInstructionBase { public: RefToUnownedInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// UnownedToRefInst - Given a value of an @unowned type, /// convert it to the underlying reference type. /// /// This does nothing at runtime; it just changes the formal type. class UnownedToRefInst : public UnaryInstructionBase { public: UnownedToRefInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// RefToUnmanagedInst - Given a value of a reference type, /// convert it to an unmanaged reference. /// /// This does nothing at runtime; it just changes the formal type. class RefToUnmanagedInst : public UnaryInstructionBase { public: RefToUnmanagedInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// UnmanagedToRefInst - Given a value of an unmanaged reference type, /// convert it to the underlying reference type. /// /// This does nothing at runtime; it just changes the formal type. class UnmanagedToRefInst : public UnaryInstructionBase { public: UnmanagedToRefInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// ThinToThickFunctionInst - Given a thin function reference, adds a null /// context to convert the value to a thick function type. class ThinToThickFunctionInst : public UnaryInstructionBase { public: ThinToThickFunctionInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// Given a thick metatype value, produces an Objective-C metatype /// value. class ThickToObjCMetatypeInst : public UnaryInstructionBase { public: ThickToObjCMetatypeInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// Given an Objective-C metatype value, produces a thick metatype /// value. class ObjCToThickMetatypeInst : public UnaryInstructionBase { public: ObjCToThickMetatypeInst(SILLocation Loc, SILValue Operand, SILType Ty) : UnaryInstructionBase(Loc, Operand, Ty) {} }; /// Test that an address or reference type is not null. class IsNonnullInst : public UnaryInstructionBase { public: IsNonnullInst(SILLocation Loc, SILValue Operand, SILType BoolTy) : UnaryInstructionBase(Loc, Operand, BoolTy) {} }; /// Perform an unconditional checked cast that aborts if the cast fails. class UnconditionalCheckedCastInst : public UnaryInstructionBase { CheckedCastKind CastKind; public: UnconditionalCheckedCastInst(SILLocation Loc, CheckedCastKind Kind, SILValue Operand, SILType DestTy) : UnaryInstructionBase(Loc, Operand, DestTy), CastKind(Kind) { assert(CastKind >= CheckedCastKind::First_Resolved && "cannot create a SIL cast with unresolved cast kind"); } CheckedCastKind getCastKind() const { return CastKind; } }; /// StructInst - Represents a constructed loadable struct. class StructInst : public SILInstruction { TailAllocatedOperandList<0> Operands; /// Private constructor. Because of the storage requirements of /// StructInst, object creation goes through 'create()'. StructInst(SILLocation Loc, SILType Ty, ArrayRef Elements); public: /// The elements referenced by this StructInst. MutableArrayRef getElementOperands() { return Operands.getDynamicAsArray(); } /// The elements referenced by this StructInst. OperandValueArrayRef getElements() const { return Operands.getDynamicValuesAsArray(); } /// Construct a StructInst. static StructInst *create(SILLocation Loc, SILType Ty, ArrayRef Elements, SILFunction &F); /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } SILValue getFieldValue(const VarDecl *V) const { return getOperandForField(V)->get(); } /// Return the Operand associated with the given VarDecl. const Operand *getOperandForField(const VarDecl *V) const { return const_cast(this)->getOperandForField(V); } Operand *getOperandForField(const VarDecl *V) { // If V is null or is computed, there is no operand associated with it. assert(V && V->hasStorage() && "getOperandForField only works with stored fields"); StructDecl *S = getStructDecl(); NominalTypeDecl::StoredPropertyRange Range = S->getStoredProperties(); unsigned Index = 0; for (auto I = Range.begin(), E = Range.end(); I != E; ++I, ++Index) if (V == *I) return &getAllOperands()[Index]; // Did not find a matching VarDecl, return nullptr. return nullptr; } StructDecl *getStructDecl() const { auto s = getType().getStructOrBoundGenericStruct(); assert(s && "A struct should always have a StructDecl associated with it"); return s; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::StructInst; } }; /// RetainValueInst - Copies a loadable value. class RetainValueInst : public UnaryInstructionBase { public: RetainValueInst(SILLocation loc, SILValue operand) : UnaryInstructionBase(loc, operand) {} }; /// ReleaseValueInst - Destroys a loadable value. class ReleaseValueInst : public UnaryInstructionBase { public: ReleaseValueInst(SILLocation loc, SILValue operand) : UnaryInstructionBase(loc, operand) {} }; /// Transfers ownership of a loadable value to the current autorelease pool. class AutoreleaseValueInst : public UnaryInstructionBase { public: AutoreleaseValueInst(SILLocation loc, SILValue operand) : UnaryInstructionBase(loc, operand) {} }; /// TupleInst - Represents a constructed loadable tuple. class TupleInst : public SILInstruction { TailAllocatedOperandList<0> Operands; /// Private constructor. Because of the storage requirements of /// TupleInst, object creation goes through 'create()'. TupleInst(SILLocation Loc, SILType Ty, ArrayRef Elements); public: /// The elements referenced by this TupleInst. MutableArrayRef getElementOperands() { return Operands.getDynamicAsArray(); } /// The elements referenced by this TupleInst. OperandValueArrayRef getElements() const { return Operands.getDynamicValuesAsArray(); } // Return the ith value referenced by this TupleInst. SILValue getElementValue(unsigned i) const { return getElements()[i]; } /// Construct a TupleInst. static TupleInst *create(SILLocation Loc, SILType Ty, ArrayRef Elements, SILFunction &F); /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::TupleInst; } TupleType *getTupleType() const { return getType().getSwiftRValueType()->castTo(); } }; /// Represents a loadable enum constructed from one of its /// elements. class EnumInst : public SILInstruction { Optional> OptionalOperand; EnumElementDecl *Element; public: EnumInst(SILLocation Loc, SILValue Operand, EnumElementDecl *Element, SILType ResultTy) : SILInstruction(ValueKind::EnumInst, Loc, ResultTy), Element(Element) { if (Operand) { OptionalOperand.emplace(this, Operand); } } EnumElementDecl *getElement() const { return Element; } bool hasOperand() const { return OptionalOperand.hasValue(); } SILValue getOperand() const { return OptionalOperand->asValueArray()[0]; } ArrayRef getAllOperands() const { return OptionalOperand ? OptionalOperand->asArray() : ArrayRef{}; } MutableArrayRef getAllOperands() { return OptionalOperand ? OptionalOperand->asArray() : MutableArrayRef{}; } SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::EnumInst; } }; /// Unsafely project the data for an enum case out of an enum without checking /// the tag. class UncheckedEnumDataInst : public UnaryInstructionBase { EnumElementDecl *Element; public: UncheckedEnumDataInst(SILLocation Loc, SILValue Operand, EnumElementDecl *Element, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), Element(Element) {} EnumElementDecl *getElement() const { return Element; } }; /// Projects the address of the data for a case inside an uninitialized enum in /// order to initialize the payload for that case. class InitEnumDataAddrInst : public UnaryInstructionBase { EnumElementDecl *Element; public: InitEnumDataAddrInst(SILLocation Loc, SILValue Operand, EnumElementDecl *Element, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), Element(Element) {} EnumElementDecl *getElement() const { return Element; } }; /// InjectEnumAddrInst - Tags an enum as containing a case. The data for /// that case, if any, must have been written into the enum first. class InjectEnumAddrInst : public UnaryInstructionBase { EnumElementDecl *Element; public: InjectEnumAddrInst(SILLocation Loc, SILValue Operand, EnumElementDecl *Element) : UnaryInstructionBase(Loc, Operand), Element(Element) {} EnumElementDecl *getElement() const { return Element; } }; /// Invalidate an enum value and take ownership of its payload data /// without moving it in memory. class UncheckedTakeEnumDataAddrInst : public UnaryInstructionBase { EnumElementDecl *Element; public: UncheckedTakeEnumDataAddrInst(SILLocation Loc, SILValue Operand, EnumElementDecl *Element, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), Element(Element) {} EnumElementDecl *getElement() const { return Element; } }; /// MetatypeInst - Represents the production of an instance of a given metatype /// named statically. class MetatypeInst : public SILInstruction { public: /// Constructs a MetatypeInst MetatypeInst(SILLocation Loc, SILType Metatype); /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::MetatypeInst; } }; /// Represents loading a dynamic metatype from a value. class ValueMetatypeInst : public UnaryInstructionBase { public: ValueMetatypeInst(SILLocation Loc, SILType Metatype, SILValue Base) : UnaryInstructionBase(Loc, Base, Metatype) {} }; /// ExistentialMetatype - Represents loading a dynamic metatype from an /// existential container. class ExistentialMetatypeInst : public UnaryInstructionBase { public: ExistentialMetatypeInst(SILLocation Loc, SILType Metatype, SILValue Base) : UnaryInstructionBase(Loc, Base, Metatype) {} }; /// Extract a numbered element out of a value of tuple type. class TupleExtractInst : public UnaryInstructionBase { unsigned FieldNo; public: TupleExtractInst(SILLocation Loc, SILValue Operand, unsigned FieldNo, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), FieldNo(FieldNo) {} unsigned getFieldNo() const { return FieldNo; } TupleType *getTupleType() const { return getOperand().getType().getSwiftRValueType()->castTo(); } }; /// Derive the address of a numbered element from the address of a tuple. class TupleElementAddrInst : public UnaryInstructionBase { unsigned FieldNo; public: TupleElementAddrInst(SILLocation Loc, SILValue Operand, unsigned FieldNo, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), FieldNo(FieldNo) {} unsigned getFieldNo() const { return FieldNo; } TupleType *getTupleType() const { return getOperand().getType().getSwiftRValueType()->castTo(); } }; /// Extract a physical, fragile field out of a value of struct type. class StructExtractInst : public UnaryInstructionBase { VarDecl *Field; public: StructExtractInst(SILLocation Loc, SILValue Operand, VarDecl *Field, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), Field(Field) {} VarDecl *getField() const { return Field; } unsigned getFieldNo() const { unsigned i = 0; for (auto *D : getStructDecl()->getStoredProperties()) { if (Field == D) return i; ++i; } llvm_unreachable("A struct_extract's structdecl has at least 1 field, the " "field of the struct_extract."); } StructDecl *getStructDecl() const { auto s = getOperand().getType().getStructOrBoundGenericStruct(); assert(s); return s; } }; /// Derive the address of a physical field from the address of a struct. class StructElementAddrInst : public UnaryInstructionBase { VarDecl *Field; public: StructElementAddrInst(SILLocation Loc, SILValue Operand, VarDecl *Field, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), Field(Field) {} VarDecl *getField() const { return Field; } unsigned getFieldNo() const { unsigned i = 0; for (auto *D : getStructDecl()->getStoredProperties()) { if (Field == D) return i; ++i; } llvm_unreachable("A struct_element_addr's structdecl has at least 1 field, " "the field of the struct_element_addr."); } StructDecl *getStructDecl() const { auto s = getOperand().getType().getStructOrBoundGenericStruct(); assert(s); return s; } }; /// RefElementAddrInst - Derive the address of a named element in a reference /// type instance. class RefElementAddrInst : public UnaryInstructionBase { VarDecl *Field; public: RefElementAddrInst(SILLocation Loc, SILValue Operand, VarDecl *Field, SILType ResultTy) : UnaryInstructionBase(Loc, Operand, ResultTy), Field(Field) {} VarDecl *getField() const { return Field; } unsigned getFieldNo() const { unsigned i = 0; for (auto *D : getClassDecl()->getStoredProperties()) { if (Field == D) return i; ++i; } llvm_unreachable("A ref_element_addr's classdecl has at least 1 field, the " "field of the ref_element_addr."); } ClassDecl *getClassDecl() const { auto s = getOperand().getType().getClassOrBoundGenericClass(); assert(s); return s; } }; /// MethodInst - Abstract base for instructions that implement dynamic /// method lookup. class MethodInst : public SILInstruction { SILDeclRef Member; bool Volatile; public: MethodInst(ValueKind Kind, SILLocation Loc, SILType Ty, SILDeclRef Member, bool Volatile = false) : SILInstruction(Kind, Loc, Ty), Member(Member), Volatile(Volatile) {} /// getType() is ok since this is known to only have one type. SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } SILDeclRef getMember() const { return Member; } /// True if this dynamic dispatch is semantically required. bool isVolatile() const { return Volatile; } static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_MethodInst && V->getKind() <= ValueKind::Last_MethodInst; } }; /// ClassMethodInst - Given the address of a value of class type and a method /// constant, extracts the implementation of that method for the dynamic /// instance type of the class. class ClassMethodInst : public UnaryInstructionBase { public: ClassMethodInst(SILLocation Loc, SILValue Operand, SILDeclRef Member, SILType Ty, bool Volatile = false) : UnaryInstructionBase(Loc, Operand, Ty, Member, Volatile) {} }; /// SuperMethodInst - Given the address of a value of class type and a method /// constant, extracts the implementation of that method for the superclass of /// the static type of the class. class SuperMethodInst : public UnaryInstructionBase { public: SuperMethodInst(SILLocation Loc, SILValue Operand, SILDeclRef Member, SILType Ty, bool Volatile = false) : UnaryInstructionBase(Loc, Operand, Ty, Member, Volatile) {} }; /// WitnessMethodInst - Given a type, a protocol conformance, /// and a protocol method constant, extracts the implementation of that method /// for the type. class WitnessMethodInst : public MethodInst { SILType LookupType; ProtocolConformance *Conformance; WitnessMethodInst(SILLocation Loc, SILType LookupType, ProtocolConformance *Conformance, SILDeclRef Member, SILType Ty, bool Volatile = false) : MethodInst(ValueKind::WitnessMethodInst, Loc, Ty, Member, Volatile), LookupType(LookupType), Conformance(Conformance) {} public: static WitnessMethodInst *create(SILLocation Loc, SILType LookupType, ProtocolConformance *Conformance, SILDeclRef Member, SILType Ty, SILFunction *Parent, bool Volatile=false); SILType getLookupType() const { return LookupType; } ProtocolDecl *getLookupProtocol() const { return cast(getMember().getDecl()->getDeclContext()); } ProtocolConformance *getConformance() const { return Conformance; } /// Get a representation of the lookup type as a substitution of the /// protocol's Self archetype. Substitution getSelfSubstitution() const { return Substitution{getLookupProtocol()->getSelf()->getArchetype(), getLookupType().getSwiftRValueType(), Conformance}; } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::WitnessMethodInst; } }; /// ProtocolMethodInst - Given the address of an existential and a method /// constant, extracts the implementation of that method for the existential. /// The result will be of the type Self -> F for a method of function type /// F. The "self" argument can be derived from the same existential /// using a ProjectExistentialInst. class ProtocolMethodInst : public UnaryInstructionBase { public: ProtocolMethodInst(SILLocation Loc, SILValue Operand, SILDeclRef Member, SILType Ty, bool Volatile = false) : UnaryInstructionBase(Loc, Operand, Ty, Member, Volatile) {} }; /// Given the address of a value of AnyObject protocol type and a method /// constant referring to some Objective-C method, performs dynamic method /// lookup to extract the implementation of that method. This method lookup /// can fail at run-time class DynamicMethodInst : public UnaryInstructionBase { public: DynamicMethodInst(SILLocation Loc, SILValue Operand, SILDeclRef Member, SILType Ty, bool Volatile = false) : UnaryInstructionBase(Loc, Operand, Ty, Member, Volatile) {} }; /// ProjectExistentialInst - Given the address of an existential, returns a /// RawPointer pointing to the value inside the existential. class ProjectExistentialInst : public UnaryInstructionBase { public: ProjectExistentialInst(SILLocation Loc, SILValue Operand, SILType SelfTy); }; /// ProjectExistentialRefInst - Given a class existential, returns an /// UnknownObject referencing the contained class instance. class ProjectExistentialRefInst : public UnaryInstructionBase { public: ProjectExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty); }; /// OpenExistentialInst - Given the address of an existential, "opens" the /// existential by returning a pointer to a fresh archetype T, which also /// captures the (dynamic) conformances. class OpenExistentialInst : public UnaryInstructionBase { public: OpenExistentialInst(SILLocation Loc, SILValue Operand, SILType SelfTy); }; /// OpenExistentialRefInst - Given a class existential, "opens" the /// existential by returning a pointer to a fresh archetype T, which also /// captures the (dynamic) conformances. class OpenExistentialRefInst : public UnaryInstructionBase { public: OpenExistentialRefInst(SILLocation Loc, SILValue Operand, SILType Ty); }; /// InitExistentialInst - Given an address to an uninitialized buffer of /// a protocol type, initializes its existential container to contain a concrete /// value of the given type, and returns the address of the uninitialized /// concrete value inside the existential container. class InitExistentialInst : public UnaryInstructionBase { ArrayRef Conformances; InitExistentialInst(SILLocation Loc, SILValue Existential, SILType ConcreteType, ArrayRef Conformances) : UnaryInstructionBase(Loc, Existential, ConcreteType.getAddressType()), Conformances(Conformances) {} public: static InitExistentialInst * create(SILLocation Loc, SILValue Existential, SILType ConcreteType, ArrayRef Conformances, SILFunction *Parent); ArrayRef getConformances() const { return Conformances; } SILType getConcreteType() const { return getType(); } }; /// InitExistentialRefInst - Given a class instance reference and a set of /// conformances, creates a class existential value referencing the /// class instance. class InitExistentialRefInst : public UnaryInstructionBase { ArrayRef Conformances; InitExistentialRefInst(SILLocation Loc, SILType ExistentialType, SILValue Instance, ArrayRef Conformances) : UnaryInstructionBase(Loc, Instance, ExistentialType), Conformances(Conformances) {} public: static InitExistentialRefInst * create(SILLocation Loc, SILType ExistentialType, SILValue Instance, ArrayRef Conformances, SILFunction *Parent); ArrayRef getConformances() const { return Conformances; } }; /// DeinitExistentialInst - Given an address of an existential that has been /// partially initialized with an InitExistentialInst but whose value buffer /// has not been initialized, deinitializes the existential and deallocates /// the value buffer. This should only be used for partially-initialized /// existentials; a fully-initialized existential can be destroyed with /// DestroyAddrInst and deallocated with DeallocStackInst. class DeinitExistentialInst : public UnaryInstructionBase { public: DeinitExistentialInst(SILLocation Loc, SILValue Existential) : UnaryInstructionBase(Loc, Existential) {} }; /// UpcastExistentialInst - Copies the concrete value from an existential /// container of a protocol type to another uninitialized existential container /// for a supertype of the original protocol type. The destination can be /// of a base protocol type or of a protocol composition that is a superset /// of the original type (or a protocol composition of base protocols). class UpcastExistentialInst : public SILInstruction { unsigned IsTakeOfSrc : 1; enum { SrcExistential, DestExistential }; FixedOperandList<2> Operands; public: UpcastExistentialInst(SILLocation Loc, SILValue SrcExistential, SILValue DestExistential, IsTake_t isTakeOfSrc); SILValue getSrcExistential() const { return Operands[SrcExistential].get(); } SILValue getDestExistential() const { return Operands[DestExistential].get();} /// True if the destination can take ownership of the concrete value from the /// source. IsTake_t isTakeOfSrc() const { return IsTake_t(IsTakeOfSrc); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::UpcastExistentialInst; } }; /// UpcastExistentialRefInst - Converts a value of class existential /// container to another, more general class existential container type. class UpcastExistentialRefInst : public UnaryInstructionBase { public: UpcastExistentialRefInst(SILLocation Loc, SILValue Operand, SILType DestTy) : UnaryInstructionBase(Loc, Operand, DestTy) {} }; /// Projects the capture storage address from a @block_storage address. class ProjectBlockStorageInst : public UnaryInstructionBase { public: ProjectBlockStorageInst(SILLocation Loc, SILValue Operand, SILType DestTy) : UnaryInstructionBase(Loc, Operand, DestTy) {} }; /// /// Initializes a block header, creating a block that /// invokes a given thin cdecl function. class InitBlockStorageHeaderInst : public SILInstruction { enum { BlockStorage, InvokeFunction }; FixedOperandList<2> Operands; public: InitBlockStorageHeaderInst(SILLocation Loc, SILValue BlockStorage, SILValue InvokeFunction, SILType BlockType) : SILInstruction(ValueKind::InitBlockStorageHeaderInst, Loc, BlockType), Operands(this, BlockStorage, InvokeFunction) {} /// Get the block storage address to be initialized. SILValue getBlockStorage() const { return Operands[BlockStorage].get(); } /// Get the invoke function to form the block around. SILValue getInvokeFunction() const { return Operands[InvokeFunction].get(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } /// getType() is OK since there's only one result. SILType getType() const { return SILInstruction::getType(0); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::InitBlockStorageHeaderInst; } }; /// RefCountingInst - An abstract class of instructions which /// manipulate the reference count of their object operand. class RefCountingInst : public SILInstruction { protected: RefCountingInst(ValueKind Kind, SILLocation Loc, SILTypeList *TypeList = 0, SILDebugScope *DS=0) : SILInstruction(Kind, Loc, TypeList, DS) {} public: static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_RefCountingInst && V->getKind() <= ValueKind::Last_RefCountingInst; } }; /// StrongRetainInst - Increase the strong reference count of an object. class StrongRetainInst : public UnaryInstructionBase { public: StrongRetainInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; /// StrongRetainAutoreleasedInst - Take ownership of the autoreleased return /// value of an ObjC method. class StrongRetainAutoreleasedInst : public UnaryInstructionBase { public: StrongRetainAutoreleasedInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; /// StrongReleaseInst - Decrease the strong reference count of an object. /// /// An object can be destroyed when its strong reference count is /// zero. It can be deallocated when both its strong reference and /// weak reference counts reach zero. class StrongReleaseInst : public UnaryInstructionBase { public: StrongReleaseInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; /// StrongRetainUnownedInst - Increase the strong reference count of an object /// and assert that it has not been deallocated. /// /// The operand must be an @unowned type. class StrongRetainUnownedInst : public UnaryInstructionBase { public: StrongRetainUnownedInst(SILLocation loc, SILValue operand) : UnaryInstructionBase(loc, operand) {} }; /// UnownedRetainInst - Increase the unowned reference count of an object. class UnownedRetainInst : public UnaryInstructionBase { public: UnownedRetainInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; /// UnownedReleaseInst - Decrease the unowned reference count of an object. class UnownedReleaseInst : public UnaryInstructionBase { public: UnownedReleaseInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; /// FixLifetimeInst - An artificial use of a value for the purposes of ARC or /// RVO optimizations. class FixLifetimeInst : public UnaryInstructionBase { public: FixLifetimeInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; /// Promote an Objective-C block that is on the stack to the heap, or simply /// retain a block that is already on the heap. class CopyBlockInst : public UnaryInstructionBase { public: CopyBlockInst(SILLocation loc, SILValue operand) : UnaryInstructionBase(loc, operand, operand.getType()) {} }; //===----------------------------------------------------------------------===// // DeallocationInsts //===----------------------------------------------------------------------===// /// DeallocationInst - An abstract parent class for Dealloc{Stack, Box, Ref}. class DeallocationInst : public SILInstruction { protected: DeallocationInst(ValueKind Kind, SILLocation Loc, SILTypeList *TypeList=nullptr, SILDebugScope *DS=nullptr) : SILInstruction(Kind, Loc, TypeList, DS) { } public: static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_DeallocationInst && V->getKind() <= ValueKind::Last_DeallocationInst; } }; /// DeallocStackInst - Deallocate stack memory allocated by alloc_stack. class DeallocStackInst : public UnaryInstructionBase { public: DeallocStackInst(SILLocation loc, SILValue operand) : UnaryInstructionBase(loc, operand) {} }; /// DeallocRefInst - Deallocate memory allocated for a reference type /// instance, as might have been created by an AllocRefInst. It is /// undefined behavior if the type of the operand does not match the /// most derived type of the allocated instance. /// /// This does not destroy the referenced instance; it must either be /// uninitialized or have been manually destroyed. class DeallocRefInst : public UnaryInstructionBase { public: DeallocRefInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; /// DeallocBoxInst - Deallocate memory allocated for a boxed value, /// as might have been created by an AllocBoxInst. It is undefined /// behavior if the type of the boxed type does not match the /// type of the boxed type of the allocated box. /// /// This does not destroy the boxed value instance; it must either be /// uninitialized or have been manually destroyed. class DeallocBoxInst : public UnaryInstructionBase { SILType ElementType; public: DeallocBoxInst(SILLocation loc, SILType elementType, SILValue operand) : UnaryInstructionBase(loc, operand), ElementType(elementType) {} SILType getElementType() const { return ElementType; } }; /// DestroyAddrInst - Destroy the value at a memory location according to /// its SIL type. This is similar to: /// %1 = load %operand /// release %1 /// but a destroy instruction can be used for types that cannot be loaded, /// such as resilient value types. class DestroyAddrInst : public UnaryInstructionBase { public: DestroyAddrInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; //===----------------------------------------------------------------------===// // Runtime failure //===----------------------------------------------------------------------===// /// Trigger a runtime failure if the given Int1 value is true. class CondFailInst : public UnaryInstructionBase { public: CondFailInst(SILLocation Loc, SILValue Operand) : UnaryInstructionBase(Loc, Operand) {} }; //===----------------------------------------------------------------------===// // Pointer/address indexing instructions //===----------------------------------------------------------------------===// /// Abstract base class for indexing instructions. class IndexingInst : public SILInstruction { enum { Base, Index }; FixedOperandList<2> Operands; public: IndexingInst(ValueKind Kind, SILLocation Loc, SILValue Operand, SILValue Index) : SILInstruction(Kind, Loc, Operand.getType()), Operands{this, Operand, Index} {} SILValue getBase() const { return Operands[Base].get(); } SILValue getIndex() const { return Operands[Index].get(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } SILType getType(unsigned i = 0) const { return ValueBase::getType(i); } static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_IndexingInst && V->getKind() <= ValueKind::Last_IndexingInst; } }; /// IndexAddrInst - "%2 : $*T = index_addr %0 : $*T, %1 : $Builtin.Int64" /// This takes an address and indexes it, striding by the pointed- /// to type. This is used to index into arrays of uniform elements. class IndexAddrInst : public IndexingInst { enum { Base, Index }; public: IndexAddrInst(SILLocation Loc, SILValue Operand, SILValue Index) : IndexingInst(ValueKind::IndexAddrInst, Loc, Operand, Index) {} static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::IndexAddrInst; } }; /// IndexRawPointerInst /// %2 : $Builtin.RawPointer \ /// = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Int64 /// This takes an address and indexes it, striding by the pointed- /// to type. This is used to index into arrays of uniform elements. class IndexRawPointerInst : public IndexingInst { enum { Base, Index }; public: IndexRawPointerInst(SILLocation Loc, SILValue Operand, SILValue Index) : IndexingInst(ValueKind::IndexRawPointerInst, Loc, Operand, Index) {} static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::IndexRawPointerInst; } }; //===----------------------------------------------------------------------===// // Instructions representing terminators //===----------------------------------------------------------------------===// /// This class defines a "terminating instruction" for a SILBasicBlock. class TermInst : public SILInstruction { protected: TermInst(ValueKind K, SILLocation Loc) : SILInstruction(K, Loc) {} public: typedef ArrayRef SuccessorListTy; /// The successor basic blocks of this terminator. SuccessorListTy getSuccessors(); /// The successor basic blocks of this terminator. const SuccessorListTy getSuccessors() const { return const_cast(this)->getSuccessors(); } static bool classof(const ValueBase *V) { return V->getKind() >= ValueKind::First_TermInst && V->getKind() <= ValueKind::Last_TermInst; } }; /// UnreachableInst - Position in the code which would be undefined to reach. /// These are always implicitly generated, e.g. when falling off the end of a /// function or after a no-return function call. class UnreachableInst : public TermInst { public: UnreachableInst(SILLocation Loc) : TermInst(ValueKind::UnreachableInst, Loc) {} SuccessorListTy getSuccessors() { // No Successors. return SuccessorListTy(); } ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::UnreachableInst; } }; /// ReturnInst - Representation of a ReturnStmt. class ReturnInst : public UnaryInstructionBase { public: /// Constructs a ReturnInst representing a return. /// /// \param Loc The backing AST location. /// /// \param ReturnValue The value to be returned. /// ReturnInst(SILLocation Loc, SILValue ReturnValue) : UnaryInstructionBase(Loc, ReturnValue) {} SuccessorListTy getSuccessors() { // No Successors. return SuccessorListTy(); } }; /// AutoreleaseReturnInst - Transfer ownership of a value to an ObjC /// autorelease pool, and then return the value. class AutoreleaseReturnInst : public UnaryInstructionBase { public: /// Constructs an AutoreleaseReturnInst representing an autorelease-return /// sequence. /// /// \param Loc The backing AST location. /// /// \param ReturnValue The value to be returned. /// AutoreleaseReturnInst(SILLocation Loc, SILValue ReturnValue) : UnaryInstructionBase(Loc, ReturnValue) {} SuccessorListTy getSuccessors() { // No Successors. return SuccessorListTy(); } }; /// BranchInst - An unconditional branch. class BranchInst : public TermInst { SILSuccessor DestBB; // FIXME: probably needs dynamic adjustment TailAllocatedOperandList<0> Operands; BranchInst(SILLocation Loc, SILBasicBlock *DestBB, ArrayRef Args); public: typedef ArrayRef ArgsTy; /// Construct a BranchInst that will branch to the specified block. /// The destination block must take no parameters. static BranchInst *create(SILLocation Loc, SILBasicBlock *DestBB, SILFunction &F); /// Construct a BranchInst that will branch to the specified block with /// the given parameters. static BranchInst *create(SILLocation Loc, SILBasicBlock *DestBB, ArrayRef Args, SILFunction &F); /// \brief returns jump target for the branch. SILBasicBlock *getDestBB() const { return DestBB; } /// The arguments for the destination BB. OperandValueArrayRef getArgs() const { return Operands.asValueArray(); } SuccessorListTy getSuccessors() { return DestBB; } unsigned getNumArgs() const { return Operands.size(); } SILValue getArg(unsigned i) const { return Operands[i].get(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::BranchInst; } }; /// A conditional branch. class CondBranchInst : public TermInst { enum { /// The condition value used for the branch. Condition }; SILSuccessor DestBBs[2]; // The number of arguments for the True branch. unsigned NumTrueArgs; // The number of arguments for the False branch. unsigned NumFalseArgs; // The first argument is the condition; the rest are BB arguments. TailAllocatedOperandList<1> Operands; CondBranchInst(SILLocation Loc, SILValue Condition, SILBasicBlock *TrueBB, SILBasicBlock *FalseBB, ArrayRef Args, unsigned NumTrue, unsigned NumFalse); public: /// Construct a CondBranchInst that will branch to TrueBB or FalseBB based on /// the Condition value. Both blocks must not take any arguments. static CondBranchInst *create(SILLocation Loc, SILValue Condition, SILBasicBlock *TrueBB, SILBasicBlock *FalseBB, SILFunction &F); /// Construct a CondBranchInst that will either branch to TrueBB and pass /// TrueArgs or branch to FalseBB and pass FalseArgs based on the Condition /// value. static CondBranchInst *create(SILLocation Loc, SILValue Condition, SILBasicBlock *TrueBB, ArrayRef TrueArgs, SILBasicBlock *FalseBB, ArrayRef FalseArgs, SILFunction &F); SILValue getCondition() const { return Operands[Condition].get(); } SuccessorListTy getSuccessors() { return DestBBs; } SILBasicBlock *getTrueBB() { return DestBBs[0]; } const SILBasicBlock *getTrueBB() const { return DestBBs[0]; } SILBasicBlock *getFalseBB() { return DestBBs[1]; } const SILBasicBlock *getFalseBB() const { return DestBBs[1]; } /// Get the arguments to the true BB. OperandValueArrayRef getTrueArgs() const; /// Get the arguments to the false BB. OperandValueArrayRef getFalseArgs() const; ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::CondBranchInst; } }; /// A switch on a builtin integer value. class SwitchIntInst : public TermInst { FixedOperandList<1> Operands; unsigned NumCases : 31; unsigned HasDefault : 1; /// \brief The number of APInt bits required to represent a case value. unsigned BitWidthForCase; SwitchIntInst(SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs); // Tail-allocated after the SwitchIntInst record are: // - `NumCases * getNumWordsForCase()` llvm::integerPart values, containing // the bitwise representations of the APInt value for each case // - `NumCases + HasDefault` SILSuccessor records, referencing the // destinations for each case, ending with the default destination if // present. /// Returns the number of APInt bits required to represent a case value, all /// of which are of the operand's type. unsigned getBitWidthForCase() const { return BitWidthForCase; } /// Returns the number of APInt words required to represent a case value, all /// of which are of the operand's type. unsigned getNumWordsForCase() const { return (getBitWidthForCase() + llvm::integerPartWidth - 1) / llvm::integerPartWidth; } llvm::integerPart *getCaseBuf() { return reinterpret_cast(this + 1); } const llvm::integerPart *getCaseBuf() const { return reinterpret_cast(this + 1); } SILSuccessor *getSuccessorBuf() { return reinterpret_cast( getCaseBuf() + (NumCases * getNumWordsForCase())); } const SILSuccessor *getSuccessorBuf() const { return reinterpret_cast( getCaseBuf() + (NumCases * getNumWordsForCase())); } public: /// Clean up tail-allocated successor records for the switch cases. ~SwitchIntInst(); static SwitchIntInst *create(SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F); SILValue getOperand() const { return Operands[0].get(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } SuccessorListTy getSuccessors() { return ArrayRef{getSuccessorBuf(), static_cast(NumCases + HasDefault)}; } unsigned getNumCases() const { return NumCases; } std::pair getCase(unsigned i) const { assert(i < NumCases && "case out of bounds"); unsigned words = getNumWordsForCase(); ArrayRef parts{getCaseBuf() + i * words, words}; return {APInt(getBitWidthForCase(), parts), getSuccessorBuf()[i]}; } bool hasDefault() const { return HasDefault; } SILBasicBlock *getDefaultBB() const { assert(HasDefault && "doesn't have a default"); return getSuccessorBuf()[NumCases]; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::SwitchIntInst; } }; /// Common implementation for the switch_enum and /// switch_enum_addr instructions. class SwitchEnumInstBase : public TermInst { FixedOperandList<1> Operands; unsigned NumCases : 31; unsigned HasDefault : 1; // Tail-allocated after the SwitchEnumInst record are: // - an array of `NumCases` EnumElementDecl* pointers, referencing the case // discriminators // - `NumCases + HasDefault` SILSuccessor records, referencing the // destinations for each case, ending with the default destination if // present. EnumElementDecl **getCaseBuf() { return reinterpret_cast(this + 1); } EnumElementDecl * const* getCaseBuf() const { return reinterpret_cast(this + 1); } SILSuccessor *getSuccessorBuf() { return reinterpret_cast(getCaseBuf() + NumCases); } const SILSuccessor *getSuccessorBuf() const { return reinterpret_cast(getCaseBuf() + NumCases); } protected: SwitchEnumInstBase(ValueKind Kind, SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs); template static SWITCH_ENUM_INST * createSwitchEnum(SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F); public: /// Clean up tail-allocated successor records for the switch cases. ~SwitchEnumInstBase(); SILValue getOperand() const { return Operands[0].get(); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } SuccessorListTy getSuccessors() { return ArrayRef{getSuccessorBuf(), static_cast(NumCases + HasDefault)}; } unsigned getNumCases() const { return NumCases; } std::pair getCase(unsigned i) const { assert(i < NumCases && "case out of bounds"); return {getCaseBuf()[i], getSuccessorBuf()[i].getBB()}; } /// \brief Return the block that will be branched to on the specified enum. SILBasicBlock *getCaseDestination(EnumElementDecl *D) { for (unsigned i = 0, e = getNumCases(); i != e; ++i) { auto Entry = getCase(i); if (Entry.first == D) return Entry.second; } // switch_enum is required to be fully covered, return the default if we // didn't find anything. return getDefaultBB(); } bool hasDefault() const { return HasDefault; } SILBasicBlock *getDefaultBB() const { assert(HasDefault && "doesn't have a default"); return getSuccessorBuf()[NumCases]; } }; /// A switch on a loadable enum's discriminator. The data for each case is /// passed into the corresponding destination block as an argument. class SwitchEnumInst : public SwitchEnumInstBase { private: friend class SwitchEnumInstBase; SwitchEnumInst(SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs) : SwitchEnumInstBase(ValueKind::SwitchEnumInst, Loc, Operand, DefaultBB, CaseBBs) {} public: static SwitchEnumInst *create(SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F); static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::SwitchEnumInst; } }; /// A switch on an enum's discriminator in memory. class SwitchEnumAddrInst : public SwitchEnumInstBase { private: friend class SwitchEnumInstBase; SwitchEnumAddrInst(SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs) : SwitchEnumInstBase(ValueKind::SwitchEnumAddrInst, Loc, Operand, DefaultBB, CaseBBs) {} public: static SwitchEnumAddrInst *create( SILLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F); static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::SwitchEnumAddrInst; } }; /// Branch on the existence of an Objective-C method in the dynamic type of /// an object. /// /// If the method exists, branches to the first BB, providing it with the /// method reference; otherwise, branches to the second BB. class DynamicMethodBranchInst : public TermInst { SILDeclRef Member; SILSuccessor DestBBs[2]; // The operand. FixedOperandList<1> Operands; DynamicMethodBranchInst(SILLocation Loc, SILValue Operand, SILDeclRef Member, SILBasicBlock *HasMethodBB, SILBasicBlock *NoMethodBB); public: /// Construct a DynamicMethodBranchInst that will branch to \c HasMethodBB or /// \c NoMethodBB based on the ability of the object operand to respond to /// a message with the same selector as the member. static DynamicMethodBranchInst *create(SILLocation Loc, SILValue Operand, SILDeclRef Member, SILBasicBlock *HasMethodBB, SILBasicBlock *NoMethodBB, SILFunction &F); SILValue getOperand() const { return Operands[0].get(); } SILDeclRef getMember() const { return Member; } SuccessorListTy getSuccessors() { return DestBBs; } SILBasicBlock *getHasMethodBB() { return DestBBs[0]; } const SILBasicBlock *getHasMethodBB() const { return DestBBs[0]; } SILBasicBlock *getNoMethodBB() { return DestBBs[1]; } const SILBasicBlock *getNoMethodBB() const { return DestBBs[1]; } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::DynamicMethodBranchInst; } }; /// Perform a checked cast operation and branch on whether the cast succeeds. /// The success branch destination block receives the cast result as a BB /// argument. class CheckedCastBranchInst : public TermInst { SILType DestTy; CheckedCastKind CastKind; FixedOperandList<1> Operands; SILSuccessor DestBBs[2]; public: CheckedCastBranchInst(SILLocation Loc, CheckedCastKind CastKind, SILValue Operand, SILType DestTy, SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB) : TermInst(ValueKind::CheckedCastBranchInst, Loc), DestTy(DestTy), CastKind(CastKind), Operands{this, Operand}, DestBBs{{this, SuccessBB}, {this, FailureBB}} { assert(CastKind >= CheckedCastKind::First_Resolved && "cannot create a cast instruction with an unresolved cast kind"); } ArrayRef getAllOperands() const { return Operands.asArray(); } MutableArrayRef getAllOperands() { return Operands.asArray(); } SILValue getOperand() const { return Operands[0].get(); } SuccessorListTy getSuccessors() { return DestBBs; } CheckedCastKind getCastKind() const { return CastKind; } SILType getCastType() const { return DestTy; } SILBasicBlock *getSuccessBB() { return DestBBs[0]; } const SILBasicBlock *getSuccessBB() const { return DestBBs[0]; } SILBasicBlock *getFailureBB() { return DestBBs[1]; } const SILBasicBlock *getFailureBB() const { return DestBBs[1]; } static bool classof(const ValueBase *V) { return V->getKind() == ValueKind::CheckedCastBranchInst; } }; } // end swift namespace //===----------------------------------------------------------------------===// // ilist_traits for SILInstruction //===----------------------------------------------------------------------===// namespace llvm { template <> struct ilist_traits<::swift::SILInstruction> : public ilist_default_traits<::swift::SILInstruction> { typedef ::swift::SILInstruction SILInstruction; private: mutable ilist_half_node Sentinel; swift::SILBasicBlock *getContainingBlock(); public: SILInstruction *createSentinel() const { return static_cast(&Sentinel); } void destroySentinel(SILInstruction *) const {} SILInstruction *provideInitialHead() const { return createSentinel(); } SILInstruction *ensureHead(SILInstruction*) const { return createSentinel(); } static void noteHead(SILInstruction*, SILInstruction*) {} static void deleteNode(SILInstruction *V) { SILInstruction::destroy(V); } void addNodeToList(SILInstruction *I); void removeNodeFromList(SILInstruction *I); void transferNodesFromList(ilist_traits &L2, ilist_iterator first, ilist_iterator last); private: void createNode(const SILInstruction &); }; } // end llvm namespace #endif