Files
swift-mirror/include/swift/SIL/SILInstruction.h
Michael Gottesman fd0a78b301 [sil-combine] Canonicalize index_raw_addr byte indexing operations => index_addr object size indexing operations.
This should eliminate pointless operations that get added to our inline
cost itinerary.

rdar://15567647
rdar://16762768
rdar://16832529

Swift SVN r17644
2014-05-07 22:01:30 +00:00

2815 lines
96 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); }
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<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.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<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.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<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;
}
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<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();
}
/// 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<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; }
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<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) {}
};
/// Convert a heap object reference to a different type without any runtime
/// checks.
class UncheckedRefCastInst
: public UnaryInstructionBase<ValueKind::UncheckedRefCastInst,
ConversionInst>
{
public:
UncheckedRefCastInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
class UncheckedAddrCastInst
: public UnaryInstructionBase<ValueKind::UncheckedAddrCastInst,
ConversionInst>
{
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<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) {}
};
/// 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<ValueKind::RefToUnmanagedInst, ConversionInst>
{
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<ValueKind::UnmanagedToRefInst, ConversionInst>
{
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<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) {}
};
/// 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) {}
};
/// Transfers ownership of a loadable value to the current autorelease pool.
class AutoreleaseValueInst
: public UnaryInstructionBase<ValueKind::AutoreleaseValueInst,
SILInstruction,
/*HasValue*/ false> {
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<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();
}
// 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<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>();
}
};
/// 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;
}
};
/// Unsafely project the data for an enum case out of an enum without checking
/// the tag.
class UncheckedEnumDataInst
: public UnaryInstructionBase<ValueKind::UncheckedEnumDataInst>
{
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<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 UncheckedTakeEnumDataAddrInst
: public UnaryInstructionBase<ValueKind::UncheckedTakeEnumDataAddrInst>
{
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<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;
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<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
/// UnknownObject 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;
InitExistentialInst(SILLocation Loc,
SILValue Existential,
SILType ConcreteType,
ArrayRef<ProtocolConformance*> Conformances)
: UnaryInstructionBase(Loc, Existential, ConcreteType.getAddressType()),
Conformances(Conformances)
{}
public:
static InitExistentialInst *
create(SILLocation Loc, SILValue Existential, SILType ConcreteType,
ArrayRef<ProtocolConformance *> Conformances, SILFunction *Parent);
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;
InitExistentialRefInst(SILLocation Loc,
SILType ExistentialType,
SILValue Instance,
ArrayRef<ProtocolConformance*> Conformances)
: UnaryInstructionBase(Loc, Instance, ExistentialType),
Conformances(Conformances)
{}
public:
static InitExistentialRefInst *
create(SILLocation Loc, SILType ExistentialType, SILValue Instance,
ArrayRef<ProtocolConformance *> Conformances, SILFunction *Parent);
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)
{}
};
/// Projects the capture storage address from a @block_storage address.
class ProjectBlockStorageInst
: public UnaryInstructionBase<ValueKind::ProjectBlockStorageInst,
SILInstruction>
{
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<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> 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<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