Files
swift-mirror/include/swift/SIL/SILInstruction.h
Joe Groff d149851607 SILGen: Copy blocks received as function arguments.
We want to generally treat blocks as heap objects until proven stack-able by escape analysis, like we do generally with other heap entities. The only place we should be exposed to stack blocks is when they're passed as arguments, so handle this by copy_block'ing any block arguments we get in the function prolog. Optimization can eliminate them when analysis shows the block doesn't escape or is already on the heap.

Swift SVN r16096
2014-04-09 04:35:17 +00:00

2696 lines
92 KiB
C++

//===--- 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<SILInstruction>{
friend struct llvm::ilist_traits<SILInstruction>;
/// A backreference to the containing basic block. This is maintained by
/// ilist_traits<SILInstruction>.
SILBasicBlock *ParentBB;
/// This instruction's containing lexical scope used for debug info.
SILDebugScope* DebugScope;
friend struct llvm::ilist_sentinel_traits<SILInstruction>;
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<Operand> getAllOperands() const;
/// Return the array of mutable operands for this instruction.
MutableArrayRef<Operand> 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); }
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<ValueKind KIND, typename BASE = SILInstruction, bool HAS_RESULT = true>
class UnaryInstructionBase : public BASE {
FixedOperandList<1> Operands;
/// Check HAS_RESULT in enable_if predicates by injecting a dependency on
/// a template argument.
template<typename X>
struct has_result {
enum { value = HAS_RESULT };
};
public:
UnaryInstructionBase(SILLocation Loc, SILValue Operand)
: BASE(KIND, Loc), Operands(this, Operand) {}
template<typename X = void>
UnaryInstructionBase(SILLocation Loc, SILValue Operand,
typename std::enable_if<has_result<X>::value,
SILType>::type Ty)
: BASE(KIND, Loc, Ty), Operands(this, Operand) {}
template<typename X = void, typename...A>
UnaryInstructionBase(SILLocation Loc, SILValue Operand,
typename std::enable_if<has_result<X>::value,
SILType>::type Ty,
A &&...args)
: BASE(KIND, Loc, Ty, std::forward<A>(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 X = void>
typename std::enable_if<has_result<X>::value, SILType>::type
getType(unsigned i = 0) const { return ValueBase::getType(i); }
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<ValueKind::AllocRefDynamicInst, AllocationInst>
{
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.ObjectPointer 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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.ObjectPointer 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<Substitution*>(Operands.asArray().end());
}
const Substitution *getSubstitutionsStorage() const {
return reinterpret_cast<const Substitution*>(Operands.asArray().end());
}
ApplyInst(SILLocation Loc, SILValue Callee,
SILType SubstCalleeType,
SILType ReturnType,
ArrayRef<Substitution> Substitutions,
ArrayRef<SILValue> Args, bool Transparent);
public:
static ApplyInst *create(SILLocation Loc, SILValue Callee,
SILType SubstCalleeType,
SILType ReturnType,
ArrayRef<Substitution> Substitutions,
ArrayRef<SILValue> 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<SILFunctionType>();
}
// Get the type of the callee with the applied substitutions.
CanSILFunctionType getSubstCalleeType() const {
return SubstCalleeType.castTo<SILFunctionType>();
}
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<Substitution> getSubstitutions() {
return {getSubstitutionsStorage(), NumSubstitutions};
}
ArrayRef<Substitution> getSubstitutions() const {
return {getSubstitutionsStorage(), NumSubstitutions};
}
/// The arguments passed to this instruction.
MutableArrayRef<Operand> getArgumentOperands() {
return Operands.getDynamicAsArray();
}
/// The arguments passed to this instruction.
OperandValueArrayRef getArguments() const {
return Operands.getDynamicValuesAsArray();
}
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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<Substitution*>(Operands.asArray().end());
}
const Substitution *getSubstitutionsStorage() const {
return reinterpret_cast<const Substitution*>(Operands.asArray().end());
}
PartialApplyInst(SILLocation Loc, SILValue Callee,
SILType SubstCalleeType,
ArrayRef<Substitution> Substitutions,
ArrayRef<SILValue> Args,
SILType ClosureType);
public:
static PartialApplyInst *create(SILLocation Loc, SILValue Callee,
SILType SubstCalleeType,
ArrayRef<Substitution> Substitutions,
ArrayRef<SILValue> 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<SILFunctionType>();
}
// Get the type of the callee with the applied substitutions.
CanSILFunctionType getSubstCalleeType() const {
return SubstCalleeType.castTo<SILFunctionType>();
}
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<Substitution> getSubstitutions() {
return {getSubstitutionsStorage(), NumSubstitutions};
}
ArrayRef<Substitution> getSubstitutions() const {
return {getSubstitutionsStorage(), NumSubstitutions};
}
/// The arguments passed to this instruction.
MutableArrayRef<Operand> getArgumentOperands() {
return Operands.getDynamicAsArray();
}
/// The arguments passed to this instruction.
OperandValueArrayRef getArguments() const {
return Operands.getDynamicValuesAsArray();
}
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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; }
/// getType() is ok since this is known to only have one type.
SILType getType(unsigned i = 0) const { return ValueBase::getType(i); }
ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<char const *>(this + 1), Length};
}
/// getEncoding - Return the desired encoding of the text.
Encoding getEncoding() const { return TheEncoding; }
ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<ValueKind::LoadInst>
{
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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<UnownedStorageType>();
}
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<ValueKind::MarkUninitializedInst> {
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<SILValue> Elements);
public:
/// The elements referenced by this instruction.
MutableArrayRef<Operand> 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<SILValue> Elements,
SILFunction &F);
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<ValueKind::DebugValueInst> {
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<ValueKind::DebugValueAddrInst> {
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<ValueKind::LoadWeakInst>
{
static SILType getResultType(SILType operandTy) {
assert(operandTy.isAddress() && "loading from non-address operand?");
auto refType = cast<ReferenceStorageType>(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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<ValueKind::ConvertFunctionInst, ConversionInst>
{
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<ValueKind::UpcastInst, ConversionInst>
{
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<ValueKind::AddressToPointerInst,
ConversionInst>
{
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<ValueKind::PointerToAddressInst, ConversionInst>
{
public:
PointerToAddressInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// RefToObjectPointerInst - Convert a class instance reference to a
/// Builtin.ObjectPointer or Builtin.ObjCPointer.
class RefToObjectPointerInst
: public UnaryInstructionBase<ValueKind::RefToObjectPointerInst,
ConversionInst>
{
public:
RefToObjectPointerInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// ObjectPointerToRefInst - Convert a Builtin.ObjectPointer or
/// Builtin.ObjCPointer to a class instance reference.
class ObjectPointerToRefInst
: public UnaryInstructionBase<ValueKind::ObjectPointerToRefInst,
ConversionInst>
{
public:
ObjectPointerToRefInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// RefToRawPointer - Convert a reference type to a Builtin.RawPointer.
class RefToRawPointerInst
: public UnaryInstructionBase<ValueKind::RefToRawPointerInst, ConversionInst>
{
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<ValueKind::RawPointerToRefInst, ConversionInst>
{
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<ValueKind::RefToUnownedInst, ConversionInst>
{
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<ValueKind::UnownedToRefInst, ConversionInst>
{
public:
UnownedToRefInst(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<ValueKind::ThinToThickFunctionInst,
ConversionInst>
{
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<ValueKind::ThickToObjCMetatypeInst,
ConversionInst>
{
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<ValueKind::ObjCToThickMetatypeInst,
ConversionInst>
{
public:
ObjCToThickMetatypeInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// BridgeToBlockInst - Converts a Swift function value to an ObjC-compatible
/// block.
class BridgeToBlockInst
: public UnaryInstructionBase<ValueKind::BridgeToBlockInst, ConversionInst>
{
public:
BridgeToBlockInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// Test that an address or reference type is not null.
class IsNonnullInst : public UnaryInstructionBase<ValueKind::IsNonnullInst> {
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<ValueKind::UnconditionalCheckedCastInst,
ConversionInst>
{
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<SILValue> Elements);
public:
/// The elements referenced by this StructInst.
MutableArrayRef<Operand> 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<SILValue> 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<StructInst*>(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<ValueKind::RetainValueInst,
SILInstruction,
/*HasValue*/ false> {
public:
RetainValueInst(SILLocation loc, SILValue operand)
: UnaryInstructionBase(loc, operand) {}
};
/// ReleaseValueInst - Destroys a loadable value.
class ReleaseValueInst : public UnaryInstructionBase<ValueKind::ReleaseValueInst,
SILInstruction,
/*HasValue*/ false> {
public:
ReleaseValueInst(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<SILValue> Elements);
public:
/// The elements referenced by this TupleInst.
MutableArrayRef<Operand> getElementOperands() {
return Operands.getDynamicAsArray();
}
/// The elements referenced by this TupleInst.
OperandValueArrayRef getElements() const {
return Operands.getDynamicValuesAsArray();
}
/// Construct a TupleInst.
static TupleInst *create(SILLocation Loc, SILType Ty,
ArrayRef<SILValue> 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
static bool classof(const ValueBase *V) {
return V->getKind() == ValueKind::TupleInst;
}
TupleType *getTupleType() const {
return getType().getSwiftRValueType()->castTo<TupleType>();
}
};
/// EnumInst - Represents a loadable enum constructed from one of its
/// elements.
class EnumInst : public SILInstruction {
Optional<FixedOperandList<1>> 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<Operand> getAllOperands() const {
return OptionalOperand ? OptionalOperand->asArray() : ArrayRef<Operand>{};
}
MutableArrayRef<Operand> getAllOperands() {
return OptionalOperand
? OptionalOperand->asArray() : MutableArrayRef<Operand>{};
}
SILType getType(unsigned i = 0) const { return ValueBase::getType(i); }
static bool classof(const ValueBase *V) {
return V->getKind() == ValueKind::EnumInst;
}
};
/// Projects the address of the data for a case inside the enum in order to
/// initialize the payload for that case.
class InitEnumDataAddrInst
: public UnaryInstructionBase<ValueKind::InitEnumDataAddrInst>
{
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<ValueKind::InjectEnumAddrInst,
SILInstruction,
/*HAS_RESULT*/ false>
{
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 TakeEnumDataAddrInst
: public UnaryInstructionBase<ValueKind::TakeEnumDataAddrInst>
{
EnumElementDecl *Element;
public:
TakeEnumDataAddrInst(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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<ValueKind::ValueMetatypeInst>
{
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<ValueKind::ExistentialMetatypeInst>
{
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<ValueKind::TupleExtractInst>
{
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<TupleType>();
}
};
/// Derive the address of a numbered element from the address of a tuple.
class TupleElementAddrInst
: public UnaryInstructionBase<ValueKind::TupleElementAddrInst>
{
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<TupleType>();
}
};
/// Extract a physical, fragile field out of a value of struct type.
class StructExtractInst
: public UnaryInstructionBase<ValueKind::StructExtractInst>
{
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<ValueKind::StructElementAddrInst>
{
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<ValueKind::RefElementAddrInst>
{
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<ValueKind::ClassMethodInst, MethodInst>
{
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<ValueKind::SuperMethodInst, MethodInst>
{
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;
public:
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)
{}
SILType getLookupType() const { return LookupType; }
ProtocolDecl *getLookupProtocol() const {
return cast<ProtocolDecl>(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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> 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<ValueKind::ProtocolMethodInst,
MethodInst>
{
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<ValueKind::DynamicMethodInst, MethodInst>
{
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<ValueKind::ProjectExistentialInst>
{
public:
ProjectExistentialInst(SILLocation Loc, SILValue Operand, SILType SelfTy);
};
/// ProjectExistentialRefInst - Given a class existential, returns an
/// ObjCPointer referencing the contained class instance.
class ProjectExistentialRefInst
: public UnaryInstructionBase<ValueKind::ProjectExistentialRefInst>
{
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<ValueKind::OpenExistentialInst>
{
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<ValueKind::OpenExistentialRefInst>
{
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<ValueKind::InitExistentialInst>
{
ArrayRef<ProtocolConformance*> Conformances;
public:
InitExistentialInst(SILLocation Loc,
SILValue Existential,
SILType ConcreteType,
ArrayRef<ProtocolConformance*> Conformances)
: UnaryInstructionBase(Loc, Existential, ConcreteType.getAddressType()),
Conformances(Conformances)
{}
ArrayRef<ProtocolConformance*> 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<ValueKind::InitExistentialRefInst>
{
ArrayRef<ProtocolConformance*> Conformances;
public:
InitExistentialRefInst(SILLocation Loc,
SILType ExistentialType,
SILValue Instance,
ArrayRef<ProtocolConformance*> Conformances)
: UnaryInstructionBase(Loc, Instance, ExistentialType),
Conformances(Conformances)
{}
ArrayRef<ProtocolConformance*> 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<ValueKind::DeinitExistentialInst,
SILInstruction,
/*HAS_RESULT*/ false>
{
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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<ValueKind::UpcastExistentialRefInst,
ConversionInst>
{
public:
UpcastExistentialRefInst(SILLocation Loc,
SILValue Operand,
SILType DestTy)
: UnaryInstructionBase(Loc, Operand, DestTy)
{}
};
/// 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<ValueKind::StrongRetainInst,
RefCountingInst,
/*HAS_RESULT*/ false>
{
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<ValueKind::StrongRetainAutoreleasedInst,
RefCountingInst, /*HAS_RESULT*/ false>
{
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<ValueKind::StrongReleaseInst,
RefCountingInst, /*HAS_RESULT*/ false>
{
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<ValueKind::StrongRetainUnownedInst,
RefCountingInst, /*HAS_RESULT*/ false>
{
public:
StrongRetainUnownedInst(SILLocation loc, SILValue operand)
: UnaryInstructionBase(loc, operand) {}
};
/// UnownedRetainInst - Increase the unowned reference count of an object.
class UnownedRetainInst :
public UnaryInstructionBase<ValueKind::UnownedRetainInst,
RefCountingInst, /*HAS_RESULT*/ false>
{
public:
UnownedRetainInst(SILLocation Loc, SILValue Operand)
: UnaryInstructionBase(Loc, Operand) {}
};
/// UnownedReleaseInst - Decrease the unowned reference count of an object.
class UnownedReleaseInst :
public UnaryInstructionBase<ValueKind::UnownedReleaseInst,
RefCountingInst, /*HAS_RESULT*/ false>
{
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<ValueKind::FixLifetimeInst,
SILInstruction, /*HAS_RESULT*/ false>
{
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<ValueKind::CopyBlockInst,
SILInstruction, /*HAS_RESULT*/ true>
{
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<ValueKind::DeallocStackInst, DeallocationInst,
/*HAS_RESULT*/ false> {
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<ValueKind::DeallocRefInst, DeallocationInst,
/*HAS_RESULT*/ false> {
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<ValueKind::DeallocBoxInst, DeallocationInst,
/*HAS_RESULT*/ false> {
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<ValueKind::DestroyAddrInst,
SILInstruction,
/*HAS_RESULT*/ false>
{
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<ValueKind::CondFailInst,
SILInstruction,
/*HAS_RESULT*/ false>
{
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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<SILSuccessor> SuccessorListTy;
/// The successor basic blocks of this terminator.
SuccessorListTy getSuccessors();
/// The successor basic blocks of this terminator.
const SuccessorListTy getSuccessors() const {
return const_cast<TermInst*>(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<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; }
static bool classof(const ValueBase *V) {
return V->getKind() == ValueKind::UnreachableInst;
}
};
/// ReturnInst - Representation of a ReturnStmt.
class ReturnInst
: public UnaryInstructionBase<ValueKind::ReturnInst, TermInst,
/*HAS_RESULT*/ false>
{
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<ValueKind::AutoreleaseReturnInst, TermInst,
/*HAS_RESULT*/ false>
{
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<SILValue> Args);
public:
typedef ArrayRef<SILValue> 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<SILValue> 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<SILValue> 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<SILValue> TrueArgs,
SILBasicBlock *FalseBB,
ArrayRef<SILValue> 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<std::pair<APInt, SILBasicBlock*>> 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<llvm::integerPart*>(this + 1);
}
const llvm::integerPart *getCaseBuf() const {
return reinterpret_cast<const llvm::integerPart *>(this + 1);
}
SILSuccessor *getSuccessorBuf() {
return reinterpret_cast<SILSuccessor*>(
getCaseBuf() + (NumCases * getNumWordsForCase()));
}
const SILSuccessor *getSuccessorBuf() const {
return reinterpret_cast<const SILSuccessor *>(
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<std::pair<APInt, SILBasicBlock*>> CaseBBs,
SILFunction &F);
SILValue getOperand() const { return Operands[0].get(); }
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
SuccessorListTy getSuccessors() {
return ArrayRef<SILSuccessor>{getSuccessorBuf(),
static_cast<size_t>(NumCases + HasDefault)};
}
unsigned getNumCases() const { return NumCases; }
std::pair<APInt, SILBasicBlock*>
getCase(unsigned i) const {
assert(i < NumCases && "case out of bounds");
unsigned words = getNumWordsForCase();
ArrayRef<llvm::integerPart> 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<EnumElementDecl**>(this + 1);
}
EnumElementDecl * const* getCaseBuf() const {
return reinterpret_cast<EnumElementDecl* const*>(this + 1);
}
SILSuccessor *getSuccessorBuf() {
return reinterpret_cast<SILSuccessor*>(getCaseBuf() + NumCases);
}
const SILSuccessor *getSuccessorBuf() const {
return reinterpret_cast<const SILSuccessor*>(getCaseBuf() + NumCases);
}
protected:
SwitchEnumInstBase(ValueKind Kind, SILLocation Loc, SILValue Operand,
SILBasicBlock *DefaultBB,
ArrayRef<std::pair<EnumElementDecl*, SILBasicBlock*>> CaseBBs);
template<typename SWITCH_ENUM_INST>
static SWITCH_ENUM_INST *
createSwitchEnum(SILLocation Loc, SILValue Operand,
SILBasicBlock *DefaultBB,
ArrayRef<std::pair<EnumElementDecl*, SILBasicBlock*>> CaseBBs,
SILFunction &F);
public:
/// Clean up tail-allocated successor records for the switch cases.
~SwitchEnumInstBase();
SILValue getOperand() const { return Operands[0].get(); }
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
SuccessorListTy getSuccessors() {
return ArrayRef<SILSuccessor>{getSuccessorBuf(),
static_cast<size_t>(NumCases + HasDefault)};
}
unsigned getNumCases() const { return NumCases; }
std::pair<EnumElementDecl*, SILBasicBlock*>
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<std::pair<EnumElementDecl*, SILBasicBlock*>> CaseBBs)
: SwitchEnumInstBase(ValueKind::SwitchEnumInst, Loc, Operand, DefaultBB,
CaseBBs)
{}
public:
static SwitchEnumInst *create(SILLocation Loc, SILValue Operand,
SILBasicBlock *DefaultBB,
ArrayRef<std::pair<EnumElementDecl*, SILBasicBlock*>> 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<std::pair<EnumElementDecl*, SILBasicBlock*>> CaseBBs)
: SwitchEnumInstBase(ValueKind::SwitchEnumAddrInst,
Loc, Operand, DefaultBB, CaseBBs)
{}
public:
static SwitchEnumAddrInst *create(
SILLocation Loc, SILValue Operand,
SILBasicBlock *DefaultBB,
ArrayRef<std::pair<EnumElementDecl*, SILBasicBlock*>> 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<SILInstruction> Sentinel;
swift::SILBasicBlock *getContainingBlock();
public:
SILInstruction *createSentinel() const {
return static_cast<SILInstruction*>(&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<SILInstruction> &L2,
ilist_iterator<SILInstruction> first,
ilist_iterator<SILInstruction> last);
private:
void createNode(const SILInstruction &);
};
} // end llvm namespace
#endif