blob: 4b99d342472ce24b203156ca5e76888caa35a06f [file] [log] [blame]
//===--- SILInstruction.h - Instructions for SIL code -----------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the high-level SILInstruction class used for SIL code.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_INSTRUCTION_H
#define SWIFT_SIL_INSTRUCTION_H
#include "swift/AST/AutoDiff.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/Decl.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/ProtocolConformanceRef.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/TypeAlignments.h"
#include "swift/Basic/Compiler.h"
#include "swift/Basic/NullablePtr.h"
#include "swift/Basic/ProfileCounter.h"
#include "swift/Basic/Range.h"
#include "swift/SIL/Consumption.h"
#include "swift/SIL/SILAllocated.h"
#include "swift/SIL/SILArgumentArrayRef.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILFunctionConventions.h"
#include "swift/SIL/SILLocation.h"
#include "swift/SIL/SILSuccessor.h"
#include "swift/SIL/SILValue.h"
#include "swift/SIL/ValueUtils.h"
#include "swift/Strings.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/Support/TrailingObjects.h"
#include <array>
namespace swift {
class AllocationInst;
class DeclRefExpr;
class FloatLiteralExpr;
class FuncDecl;
class IntegerLiteralExpr;
class SingleValueInstruction;
class MultipleValueInstruction;
class MultipleValueInstructionResult;
class DestructureTupleInst;
class DestructureStructInst;
class NonValueInstruction;
class SILBasicBlock;
class SILBuilder;
class SILDebugLocation;
class SILDebugScope;
class SILDifferentiabilityWitness;
class SILFunction;
class SILGlobalVariable;
class SILInstructionResultArray;
class SILOpenedArchetypesState;
class SILType;
class SILArgument;
class SILPhiArgument;
class SILUndef;
class Stmt;
class StringLiteralExpr;
class ValueDecl;
class VarDecl;
class FunctionRefBaseInst;
template <typename ImplClass> class SILClonerWithScopes;
// An enum class for SILInstructions that enables exhaustive switches over
// instructions.
enum class SILInstructionKind : std::underlying_type<SILNodeKind>::type {
#define INST(ID, PARENT) \
ID = unsigned(SILNodeKind::ID),
#define INST_RANGE(ID, FIRST, LAST) \
First_##ID = unsigned(SILNodeKind::First_##ID), \
Last_##ID = unsigned(SILNodeKind::Last_##ID),
#include "SILNodes.def"
};
/// Return a range which can be used to easily iterate over all
/// SILInstructionKinds.
inline IntRange<SILInstructionKind> allSILInstructionKinds() {
return IntRange<SILInstructionKind>(
SILInstructionKind(SILNodeKind::First_SILInstruction),
SILInstructionKind(unsigned(SILNodeKind::Last_SILInstruction) + 1));
}
/// Map SILInstruction's mnemonic name to its SILInstructionKind.
SILInstructionKind getSILInstructionKind(StringRef InstName);
/// Map SILInstructionKind to a corresponding SILInstruction name.
StringRef getSILInstructionName(SILInstructionKind Kind);
/// A formal SIL reference to a list of values, suitable for use as the result
/// of a SILInstruction.
///
/// *NOTE* Most multiple value instructions will not have many results, so if we
/// want we can cache up to 3 bytes in the lower bits of the value.
///
/// *NOTE* Most of this defined out of line further down in the file to work
/// around forward declaration issues.
///
/// *NOTE* The reason why this does not store the size of the stored element is
/// that just from the number of elements we can infer the size of each element
/// due to the restricted problem space. Specificially:
///
/// 1. Size == 0 implies nothing is stored and thus element size is irrelevent.
/// 2. Size == 1 implies we either had a single value instruction or a multiple
/// value instruction, but no matter what instruction we had, we are going to
/// store the results at the same starting location so element size is
/// irrelevent.
/// 3. Size > 1 implies we must be storing multiple value instruction results
/// implying that the size of each stored element must be
/// sizeof(MultipleValueInstructionResult).
///
/// If we ever allow for subclasses of MultipleValueInstructionResult of
/// different sizes, we will need to store a stride into
/// SILInstructionResultArray. We always assume all results are the same
/// subclass of MultipleValueInstructionResult.
class SILInstructionResultArray {
friend class MultipleValueInstruction;
/// Byte pointer to our data. nullptr for empty arrays.
const uint8_t *Pointer;
/// The number of stored elements.
unsigned Size;
public:
SILInstructionResultArray() : Pointer(nullptr), Size(0) {}
SILInstructionResultArray(const SingleValueInstruction *SVI);
SILInstructionResultArray(ArrayRef<MultipleValueInstructionResult> results);
template <class Result>
SILInstructionResultArray(ArrayRef<Result> results);
SILInstructionResultArray(const SILInstructionResultArray &Other) = default;
SILInstructionResultArray &
operator=(const SILInstructionResultArray &Other) = default;
SILInstructionResultArray(SILInstructionResultArray &&Other) = default;
SILInstructionResultArray &
operator=(SILInstructionResultArray &&Other) = default;
SILValue operator[](size_t Index) const;
bool empty() const { return Size == 0; }
size_t size() const { return Size; }
class iterator;
friend bool operator==(iterator, iterator);
friend bool operator!=(iterator, iterator);
iterator begin() const;
iterator end() const;
using reverse_iterator = std::reverse_iterator<iterator>;
reverse_iterator rbegin() const;
reverse_iterator rend() const;
using range = iterator_range<iterator>;
range getValues() const;
using reverse_range = iterator_range<reverse_iterator>;
reverse_range getReversedValues() const;
using type_range = iterator_range<
llvm::mapped_iterator<iterator, SILType(*)(SILValue), SILType>>;
type_range getTypes() const;
bool operator==(const SILInstructionResultArray &rhs);
bool operator!=(const SILInstructionResultArray &other) {
return !(*this == other);
}
/// Returns true if both this and \p rhs have the same result types.
///
/// *NOTE* This does not imply that the actual return SILValues are the
/// same. Just that the types are the same.
bool hasSameTypes(const SILInstructionResultArray &rhs);
private:
/// Return the first element of the array. Asserts if the array is empty.
///
/// Please do not use this outside of this class. It is only meant to speedup
/// MultipleValueInstruction::getIndexOfResult(SILValue).
const ValueBase *front() const;
/// Return the last element of the array. Asserts if the array is empty.
///
/// Please do not use this outside of this class. It is only meant to speedup
/// MultipleValueInstruction::getIndexOfResult(SILValue).
const ValueBase *back() const;
};
class SILInstructionResultArray::iterator {
/// Our "parent" array.
///
/// This is actually a value type reference into a SILInstruction of some
/// sort. So we can just have our own copy. This also allows us to not worry
/// about our underlying array having too short of a lifetime.
SILInstructionResultArray Parent;
/// The index into the parent array.
unsigned Index;
public:
using difference_type = int;
using value_type = SILValue;
using pointer = void;
using reference = SILValue;
using iterator_category = std::bidirectional_iterator_tag;
iterator() = default;
iterator(const SILInstructionResultArray &Parent, unsigned Index = 0)
: Parent(Parent), Index(Index) {}
SILValue operator*() const { return Parent[Index]; }
SILValue operator->() const { return operator*(); }
iterator &operator++() {
++Index;
return *this;
}
iterator operator++(int) {
iterator copy = *this;
++Index;
return copy;
}
iterator &operator--() {
--Index;
return *this;
}
iterator operator--(int) {
iterator copy = *this;
--Index;
return copy;
}
friend bool operator==(iterator lhs, iterator rhs) {
assert(lhs.Parent.Pointer == rhs.Parent.Pointer);
return lhs.Index == rhs.Index;
}
friend bool operator!=(iterator lhs, iterator rhs) { return !(lhs == rhs); }
};
inline SILInstructionResultArray::iterator
SILInstructionResultArray::begin() const {
return iterator(*this, 0);
}
inline SILInstructionResultArray::iterator
SILInstructionResultArray::end() const {
return iterator(*this, size());
}
inline SILInstructionResultArray::reverse_iterator
SILInstructionResultArray::rbegin() const {
return llvm::make_reverse_iterator(end());
}
inline SILInstructionResultArray::reverse_iterator
SILInstructionResultArray::rend() const {
return llvm::make_reverse_iterator(begin());
}
inline SILInstructionResultArray::range
SILInstructionResultArray::getValues() const {
return {begin(), end()};
}
inline SILInstructionResultArray::reverse_range
SILInstructionResultArray::getReversedValues() const {
return {rbegin(), rend()};
}
/// This is the root class for all instructions that can be used as the
/// contents of a Swift SILBasicBlock.
///
/// Most instructions are defined in terms of two basic kinds of
/// structure: a list of operand values upon which the instruction depends
/// and a list of result values upon which other instructions can depend.
///
/// The operands can be divided into two sets:
/// - the formal operands of the instruction, which reflect its
/// direct value dependencies, and
/// - the type-dependent operands, which reflect dependencies that are
/// not captured by the formal operands; currently, these dependencies
/// only arise due to certain instructions (e.g. open_existential_addr)
/// that bind new archetypes in the local context.
class SILInstruction
: public SILNode, public llvm::ilist_node<SILInstruction> {
friend llvm::ilist_traits<SILInstruction>;
friend llvm::ilist_traits<SILBasicBlock>;
friend SILBasicBlock;
/// A backreference to the containing basic block. This is maintained by
/// ilist_traits<SILInstruction>.
SILBasicBlock *ParentBB;
/// This instruction's containing lexical scope and source location
/// used for debug info and diagnostics.
SILDebugLocation Location;
SILInstruction() = delete;
void operator=(const SILInstruction &) = delete;
void operator delete(void *Ptr, size_t) = delete;
/// Check any special state of instructions that are not represented in the
/// instructions operands/type.
bool hasIdenticalState(const SILInstruction *RHS) const;
/// Update this instruction's SILDebugScope. This function should
/// never be called directly. Use SILBuilder, SILBuilderWithScope or
/// SILClonerWithScope instead.
void setDebugScope(const SILDebugScope *DS);
/// Total number of created and deleted SILInstructions.
/// It is used only for collecting the compiler statistics.
static int NumCreatedInstructions;
static int NumDeletedInstructions;
// Helper functions used by the ArrayRefViews below.
static SILValue projectValueBaseAsSILValue(const ValueBase &value) {
return &value;
}
static SILType projectValueBaseType(const ValueBase &value) {
return value.getType();
}
/// An internal method which retrieves the result values of the
/// instruction as an array of ValueBase objects.
SILInstructionResultArray getResultsImpl() const;
protected:
SILInstruction(SILInstructionKind kind, SILDebugLocation DebugLoc)
: SILNode(SILNodeKind(kind), SILNodeStorageLocation::Instruction,
IsRepresentative::Yes),
ParentBB(nullptr), Location(DebugLoc) {
NumCreatedInstructions++;
}
~SILInstruction() {
NumDeletedInstructions++;
}
public:
/// Instructions should be allocated using a dedicated instruction allocation
/// function from the ContextTy.
template <typename ContextTy>
void *operator new(size_t Bytes, const ContextTy &C,
size_t Alignment = alignof(ValueBase)) {
return C.allocateInst(Bytes, Alignment);
}
enum class MemoryBehavior {
None,
/// The instruction may read memory.
MayRead,
/// The instruction may write to memory.
/// This includes destroying or taking from memory (e.g. destroy_addr,
/// copy_addr [take], load [take]).
/// Although, physically, destroying or taking does not modify the memory,
/// it is important to model it is a write. Optimizations must not assume
/// that the value stored in memory is still available for loading after
/// the memory is destroyed or taken.
MayWrite,
/// The instruction may read or write memory.
MayReadWrite,
/// 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,
};
/// Enumeration representing whether the execution of an instruction can
/// result in memory being released.
enum class ReleasingBehavior {
DoesNotRelease,
MayRelease,
};
LLVM_ATTRIBUTE_ALWAYS_INLINE
SILInstructionKind getKind() const {
return SILInstructionKind(SILNode::getKind());
}
const SILBasicBlock *getParent() const { return ParentBB; }
SILBasicBlock *getParent() { return ParentBB; }
SILFunction *getFunction();
const SILFunction *getFunction() const;
/// Is this instruction part of a static initializer of a SILGlobalVariable?
bool isStaticInitializerInst() const { return getFunction() == nullptr; }
SILModule &getModule() const;
/// This instruction's source location (AST node).
SILLocation getLoc() const;
const SILDebugScope *getDebugScope() const;
SILDebugLocation getDebugLocation() const { return Location; }
/// Sets the debug location.
/// Note: Usually it should not be needed to use this function as the location
/// is already set in when creating an instruction.
void setDebugLocation(SILDebugLocation Loc) { Location = Loc; }
/// This method unlinks 'self' from the containing basic block and deletes it.
void eraseFromParent();
/// Unlink this instruction from its current basic block and insert the
/// instruction such that it is the first instruction of \p Block.
void moveFront(SILBasicBlock *Block);
/// Unlink this instruction from its current basic block and insert it into
/// the basic block that Later lives in, right before Later.
void moveBefore(SILInstruction *Later);
/// Unlink this instruction from its current basic block and insert it into
/// the basic block that Earlier lives in, right after Earlier.
void moveAfter(SILInstruction *Earlier);
/// Drops all uses that belong to this instruction.
void dropAllReferences();
/// Replace all uses of all results of this instruction with undef.
void replaceAllUsesOfAllResultsWithUndef();
/// Replace all uses of all results of this instruction
/// with the parwise-corresponding results of the given instruction.
void replaceAllUsesPairwiseWith(SILInstruction *other);
/// Replace all uses of all results of this instruction with the
/// parwise-corresponding results of the passed in array.
void
replaceAllUsesPairwiseWith(const llvm::SmallVectorImpl<SILValue> &NewValues);
/// Are there uses of any of the results of this instruction?
bool hasUsesOfAnyResult() const {
for (auto result : getResults()) {
if (!result->use_empty())
return true;
}
return false;
}
/// Return the array of operands for this instruction.
ArrayRef<Operand> getAllOperands() const;
/// Return the array of type dependent operands for this instruction.
///
/// Type dependent operands are hidden operands, i.e. not part of the SIL
/// syntax (although they are printed as "type-defs" in comments).
/// Their purpose is to establish a def-use relationship between
/// -) an instruction/argument which defines a type, e.g. open_existential
/// and
/// -) this instruction, which uses the type, but doesn't use the defining
/// instruction as value-operand, e.g. a type in the substitution list.
///
/// Currently there are two kinds of type dependent operands:
///
/// 1. for opened archetypes:
/// %o = open_existential_addr %0 : $*P to $*@opened("UUID") P
/// %w = witness_method $@opened("UUID") P, ... // type-defs: %o
///
/// 2. for the dynamic self argument:
/// sil @foo : $@convention(method) (@thick X.Type) {
/// bb0(%0 : $@thick X.Type):
/// %a = apply %f<@dynamic_self X>() ... // type-defs: %0
///
/// The type dependent operands are just there to let optimizations know that
/// there is a dependency between the instruction/argument which defines the
/// type and the instruction which uses the type.
ArrayRef<Operand> getTypeDependentOperands() const;
/// Return the array of mutable operands for this instruction.
MutableArrayRef<Operand> getAllOperands();
/// Return the array of mutable type dependent operands for this instruction.
MutableArrayRef<Operand> getTypeDependentOperands();
unsigned getNumOperands() const { return getAllOperands().size(); }
unsigned getNumTypeDependentOperands() const {
return getTypeDependentOperands().size();
}
bool isTypeDependentOperand(unsigned i) const {
return i >= getNumOperands() - getNumTypeDependentOperands();
}
bool isTypeDependentOperand(const Operand &Op) const {
assert(Op.getUser() == this &&
"Operand does not belong to a SILInstruction");
return isTypeDependentOperand(Op.getOperandNumber());
}
/// Returns true if evaluation of this instruction may cause suspension of an
/// async task.
bool maySuspend() const;
private:
/// Predicate used to filter OperandValueRange.
struct OperandToValue;
/// Predicate used to filter TransformedOperandValueRange.
struct OperandToTransformedValue;
public:
using OperandValueRange =
OptionalTransformRange<ArrayRef<Operand>, OperandToValue>;
using TransformedOperandValueRange =
OptionalTransformRange<ArrayRef<Operand>, OperandToTransformedValue>;
OperandValueRange
getOperandValues(bool skipTypeDependentOperands = false) const;
TransformedOperandValueRange
getOperandValues(std::function<SILValue(SILValue)> transformFn,
bool skipTypeDependentOperands) const;
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]);
}
private:
/// Predicate used to filter OperandTypeRange.
struct OperandToType;
public:
using OperandTypeRange =
OptionalTransformRange<ArrayRef<Operand>, OperandToType>;
// NOTE: We always skip type dependent operands.
OperandTypeRange getOperandTypes() const;
/// Return the list of results produced by this instruction.
bool hasResults() const { return !getResults().empty(); }
SILInstructionResultArray getResults() const { return getResultsImpl(); }
unsigned getNumResults() const { return getResults().size(); }
SILValue getResult(unsigned index) const { return getResults()[index]; }
/// Return the types of the results produced by this instruction.
SILInstructionResultArray::type_range getResultTypes() const {
return getResultsImpl().getTypes();
}
MemoryBehavior getMemoryBehavior() const;
ReleasingBehavior getReleasingBehavior() const;
/// Returns true if the instruction may release any object.
bool mayRelease() const;
/// Returns true if the instruction may release or may read the reference
/// count of any object.
bool mayReleaseOrReadRefCount() const;
/// Can this instruction abort the program in some manner?
bool mayTrap() const;
/// Returns true if the given instruction is completely identical to RHS.
bool isIdenticalTo(const SILInstruction *RHS) const {
return isIdenticalTo(RHS,
[](const SILValue &Op1, const SILValue &Op2) -> bool {
return Op1 == Op2; });
}
/// Returns true if the given instruction is completely identical to RHS,
/// using \p opEqual to compare operands.
///
template <typename OpCmp>
bool isIdenticalTo(const SILInstruction *RHS, OpCmp &&opEqual) const {
// Quick check if both instructions have the same kind, number of operands,
// and types. This should filter out most cases.
if (getKind() != RHS->getKind() ||
getNumOperands() != RHS->getNumOperands()) {
return false;
}
if (!getResults().hasSameTypes(RHS->getResults()))
return false;
// Check operands.
for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
if (!opEqual(getOperand(i), RHS->getOperand(i)))
return false;
// Check any special state of instructions that are not represented in the
// instructions operands/type.
return hasIdenticalState(RHS);
}
/// 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;
}
/// Return true if the instruction is "pure" in the sense that it may execute
/// multiple times without affecting behavior. This implies that it can be
/// trivially cloned at multiple use sites without preserving path
/// equivalence.
bool isPure() const {
return !mayReadOrWriteMemory() && !mayTrap() && !isa<AllocationInst>(this)
&& !isa<TermInst>(this);
}
/// Returns true if the result of this instruction is a pointer to stack
/// allocated memory. In this case there must be an adjacent deallocating
/// instruction.
bool isAllocatingStack() const;
/// Returns true if this is the deallocation of a stack allocating instruction.
/// The first operand must be the allocating instruction.
bool isDeallocatingStack() const;
/// 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);
/// Returns true if the instruction can be duplicated without any special
/// additional handling. It is important to know this information when
/// you perform such optimizations like e.g. jump-threading.
bool isTriviallyDuplicatable() const;
/// Returns true if the instruction is only relevant for debug
/// informations and has no other impact on program semantics.
bool isDebugInstruction() const {
return getKind() == SILInstructionKind::DebugValueInst ||
getKind() == SILInstructionKind::DebugValueAddrInst;
}
/// Returns true if the instruction is a meta instruction which is
/// relevant for debug information and does not get lowered to a real
/// instruction.
bool isMetaInstruction() const;
/// Verify that all operands of this instruction have compatible ownership
/// with this instruction.
void verifyOperandOwnership() const;
/// Get the number of created SILInstructions.
static int getNumCreatedInstructions() {
return NumCreatedInstructions;
}
/// Get the number of deleted SILInstructions.
static int getNumDeletedInstructions() {
return NumDeletedInstructions;
}
/// Pretty-print the value.
void dump() const;
void print(raw_ostream &OS) const;
/// Pretty-print the value in context, preceded by its operands (if the
/// value represents the result of an instruction) and followed by its
/// users.
void dumpInContext() const;
void printInContext(raw_ostream &OS) const;
static bool classof(const SILNode *N) {
return N->getKind() >= SILNodeKind::First_SILInstruction &&
N->getKind() <= SILNodeKind::Last_SILInstruction;
}
static bool classof(const SILInstruction *I) { return true; }
/// This is supportable but usually suggests a logic mistake.
static bool classof(const ValueBase *) = delete;
};
struct SILInstruction::OperandToValue {
const SILInstruction &i;
bool skipTypeDependentOps;
OperandToValue(const SILInstruction &i, bool skipTypeDependentOps)
: i(i), skipTypeDependentOps(skipTypeDependentOps) {}
Optional<SILValue> operator()(const Operand &use) const {
if (skipTypeDependentOps && i.isTypeDependentOperand(use))
return None;
return use.get();
}
};
struct SILInstruction::OperandToTransformedValue {
const SILInstruction &i;
std::function<SILValue(SILValue)> transformFn;
bool skipTypeDependentOps;
OperandToTransformedValue(const SILInstruction &i,
std::function<SILValue(SILValue)> transformFn,
bool skipTypeDependentOps)
: i(i), transformFn(transformFn),
skipTypeDependentOps(skipTypeDependentOps) {}
Optional<SILValue> operator()(const Operand &use) const {
if (skipTypeDependentOps && i.isTypeDependentOperand(use))
return None;
return transformFn(use.get());
}
};
inline auto
SILInstruction::getOperandValues(bool skipTypeDependentOperands) const
-> OperandValueRange {
return OperandValueRange(getAllOperands(),
OperandToValue(*this, skipTypeDependentOperands));
}
inline auto
SILInstruction::getOperandValues(std::function<SILValue(SILValue)> transformFn,
bool skipTypeDependentOperands) const
-> TransformedOperandValueRange {
return TransformedOperandValueRange(
getAllOperands(),
OperandToTransformedValue(*this, transformFn, skipTypeDependentOperands));
}
struct SILInstruction::OperandToType {
const SILInstruction &i;
OperandToType(const SILInstruction &i) : i(i) {}
Optional<SILType> operator()(const Operand &use) const {
if (i.isTypeDependentOperand(use))
return None;
return use.get()->getType();
}
};
inline auto SILInstruction::getOperandTypes() const -> OperandTypeRange {
return OperandTypeRange(getAllOperands(), OperandToType(*this));
}
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const SILInstruction &I) {
I.print(OS);
return OS;
}
/// Returns the combined behavior of \p B1 and \p B2.
inline SILInstruction::MemoryBehavior
combineMemoryBehavior(SILInstruction::MemoryBehavior B1,
SILInstruction::MemoryBehavior B2) {
// Basically the combined behavior is the maximum of both operands.
auto Result = std::max(B1, B2);
// With one exception: MayRead, MayWrite -> MayReadWrite.
if (Result == SILInstruction::MemoryBehavior::MayWrite &&
(B1 == SILInstruction::MemoryBehavior::MayRead ||
B2 == SILInstruction::MemoryBehavior::MayRead))
return SILInstruction::MemoryBehavior::MayReadWrite;
return Result;
}
/// Pretty-print the MemoryBehavior.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
SILInstruction::MemoryBehavior B);
/// Pretty-print the ReleasingBehavior.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
SILInstruction::ReleasingBehavior B);
/// An instruction which always produces a single value.
///
/// Because this instruction is both a SILInstruction and a ValueBase,
/// both of which inherit from SILNode, it introduces the need for
/// some care when working with SILNodes. See the comment on SILNode.
class SingleValueInstruction : public SILInstruction, public ValueBase {
static bool isSingleValueInstKind(SILNodeKind kind) {
return kind >= SILNodeKind::First_SingleValueInstruction &&
kind <= SILNodeKind::Last_SingleValueInstruction;
}
friend class SILInstruction;
SILInstructionResultArray getResultsImpl() const {
return SILInstructionResultArray(this);
}
public:
SingleValueInstruction(SILInstructionKind kind, SILDebugLocation loc,
SILType type)
: SILInstruction(kind, loc),
ValueBase(ValueKind(kind), type, IsRepresentative::No) {}
using SILInstruction::operator new;
using SILInstruction::dumpInContext;
using SILInstruction::print;
using SILInstruction::printInContext;
// Redeclare because lldb currently doesn't know about using-declarations
void dump() const;
SILFunction *getFunction() { return SILInstruction::getFunction(); }
const SILFunction *getFunction() const {
return SILInstruction::getFunction();
}
SILModule &getModule() const { return SILInstruction::getModule(); }
SILInstructionKind getKind() const { return SILInstruction::getKind(); }
void operator delete(void *Ptr, size_t) = delete;
ValueKind getValueKind() const {
return ValueBase::getKind();
}
SingleValueInstruction *clone(SILInstruction *insertPt = nullptr) {
return cast<SingleValueInstruction>(SILInstruction::clone(insertPt));
}
/// Override this to reflect the more efficient access pattern.
SILInstructionResultArray getResults() const { return getResultsImpl(); }
static bool classof(const SILNode *node) {
return isSingleValueInstKind(node->getKind());
}
};
// Resolve ambiguities.
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const SingleValueInstruction &I) {
I.print(OS);
return OS;
}
inline SingleValueInstruction *SILNode::castToSingleValueInstruction() {
assert(isa<SingleValueInstruction>(this));
// We do reference static_casts to convince the host compiler to do
// null-unchecked conversions.
// If we're in the value slot, cast through ValueBase.
if (getStorageLoc() == SILNodeStorageLocation::Value) {
return &static_cast<SingleValueInstruction&>(
static_cast<ValueBase&>(*this));
// Otherwise, cast through SILInstruction.
} else {
return &static_cast<SingleValueInstruction&>(
static_cast<SILInstruction&>(*this));
}
}
#define DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(ID) \
static bool classof(const SILNode *node) { \
return node->getKind() >= SILNodeKind::First_##ID && \
node->getKind() <= SILNodeKind::Last_##ID; \
} \
static bool classof(const SingleValueInstruction *inst) { \
return inst->getKind() >= SILInstructionKind::First_##ID && \
inst->getKind() <= SILInstructionKind::Last_##ID; \
}
/// Abstract base class used for isa checks on instructions to determine if they
/// forward ownership and to verify that the set of ownership instructions and
/// the ownership utilities stay in sync via assertions.
///
/// NOTE: We assume that the constructor for the instruction subclass that
/// initializes the kind field on our object is run before our constructor runs.
class OwnershipForwardingInst {
ValueOwnershipKind ownershipKind;
protected:
OwnershipForwardingInst(SILInstructionKind kind,
ValueOwnershipKind ownershipKind)
: ownershipKind(ownershipKind) {
assert(classof(kind) && "Invalid subclass?!");
}
public:
ValueOwnershipKind getOwnershipKind() const { return ownershipKind; }
void setOwnershipKind(ValueOwnershipKind newKind) { ownershipKind = newKind; }
static bool classof(const SILNode *node) {
if (auto *i = dyn_cast<SILInstruction>(node))
return classof(i);
return false;
}
// Defined inline below due to forward declaration issues.
static bool classof(const SILInstruction *inst);
/// Define inline below due to forward declaration issues.
static bool classof(SILInstructionKind kind);
};
/// A single value inst that forwards a static ownership from one (or all) of
/// its operands.
///
/// The ownership kind is set on construction and afterwards must be changed
/// explicitly using setOwnershipKind().
class FirstArgOwnershipForwardingSingleValueInst
: public SingleValueInstruction,
public OwnershipForwardingInst {
protected:
FirstArgOwnershipForwardingSingleValueInst(SILInstructionKind kind,
SILDebugLocation debugLoc,
SILType ty,
ValueOwnershipKind ownershipKind)
: SingleValueInstruction(kind, debugLoc, ty),
OwnershipForwardingInst(kind, ownershipKind) {
assert(classof(kind) && "classof missing new subclass?!");
}
public:
static bool classof(const SILNode *node) {
if (auto *i = dyn_cast<SILInstruction>(node))
return classof(i);
return false;
}
static bool classof(SILInstructionKind kind);
static bool classof(const SILInstruction *inst) {
return classof(inst->getKind());
}
};
/// An ownership forwarding single value that has a preferred operand of owned
/// but if its inputs are all none can have OwnershipKind::None as a result. We
/// assume that we always forward from operand 0.
class OwnedFirstArgForwardingSingleValueInst
: public FirstArgOwnershipForwardingSingleValueInst {
protected:
OwnedFirstArgForwardingSingleValueInst(SILInstructionKind kind,
SILDebugLocation debugLoc, SILType ty,
ValueOwnershipKind resultOwnershipKind)
: FirstArgOwnershipForwardingSingleValueInst(kind, debugLoc, ty,
resultOwnershipKind) {
assert(resultOwnershipKind.isCompatibleWith(OwnershipKind::Owned));
assert(classof(kind) && "classof missing new subclass?!");
}
public:
ValueOwnershipKind getPreferredOwnership() const {
return OwnershipKind::Owned;
}
static bool classof(const SILNode *node) {
if (auto *i = dyn_cast<SILInstruction>(node))
return classof(i);
return false;
}
static bool classof(SILInstructionKind kind) {
switch (kind) {
case SILInstructionKind::MarkUninitializedInst:
return true;
default:
return false;
}
}
static bool classof(const SILInstruction *inst) {
return classof(inst->getKind());
}
};
/// An instruction that forwards guaranteed or none ownership. Assumed to always
/// forward from Operand(0) -> Result(0).
class GuaranteedFirstArgForwardingSingleValueInst
: public FirstArgOwnershipForwardingSingleValueInst {
protected:
GuaranteedFirstArgForwardingSingleValueInst(
SILInstructionKind kind, SILDebugLocation debugLoc, SILType ty,
ValueOwnershipKind resultOwnershipKind)
: FirstArgOwnershipForwardingSingleValueInst(kind, debugLoc, ty,
resultOwnershipKind) {
assert(resultOwnershipKind.isCompatibleWith(OwnershipKind::Guaranteed));
assert(classof(kind) && "classof missing new subclass?!");
}
public:
ValueOwnershipKind getPreferredOwnership() const {
return OwnershipKind::Guaranteed;
}
static bool classof(const SILNode *node) {
if (auto *i = dyn_cast<SILInstruction>(node))
return classof(i);
return false;
}
static bool classof(SILInstructionKind kind) {
switch (kind) {
case SILInstructionKind::TupleExtractInst:
case SILInstructionKind::StructExtractInst:
case SILInstructionKind::DifferentiableFunctionExtractInst:
case SILInstructionKind::LinearFunctionExtractInst:
case SILInstructionKind::OpenExistentialValueInst:
case SILInstructionKind::OpenExistentialBoxValueInst:
return true;
default:
return false;
}
}
static bool classof(const SILInstruction *inst) {
return classof(inst->getKind());
}
};
inline bool
FirstArgOwnershipForwardingSingleValueInst::classof(SILInstructionKind kind) {
if (OwnedFirstArgForwardingSingleValueInst::classof(kind))
return true;
if (GuaranteedFirstArgForwardingSingleValueInst::classof(kind))
return true;
switch (kind) {
case SILInstructionKind::ObjectInst:
case SILInstructionKind::EnumInst:
case SILInstructionKind::UncheckedEnumDataInst:
case SILInstructionKind::SelectValueInst:
case SILInstructionKind::OpenExistentialRefInst:
case SILInstructionKind::InitExistentialRefInst:
case SILInstructionKind::MarkDependenceInst:
return true;
default:
return false;
}
}
class AllArgOwnershipForwardingSingleValueInst
: public SingleValueInstruction,
public OwnershipForwardingInst {
protected:
AllArgOwnershipForwardingSingleValueInst(SILInstructionKind kind,
SILDebugLocation debugLoc,
SILType ty,
ValueOwnershipKind ownershipKind)
: SingleValueInstruction(kind, debugLoc, ty),
OwnershipForwardingInst(kind, ownershipKind) {
assert(classof(kind) && "classof missing new subclass?!");
}
public:
static bool classof(const SILNode *node) {
if (auto *i = dyn_cast<SILInstruction>(node))
return classof(i);
return false;
}
static bool classof(SILInstructionKind kind) {
switch (kind) {
case SILInstructionKind::StructInst:
case SILInstructionKind::TupleInst:
case SILInstructionKind::LinearFunctionInst:
case SILInstructionKind::DifferentiableFunctionInst:
return true;
default:
return false;
}
}
static bool classof(const SILInstruction *inst) {
return classof(inst->getKind());
}
};
/// A value base result of a multiple value instruction.
///
/// *NOTE* We want this to be a pure abstract class that does not add /any/ size
/// to subclasses.
class MultipleValueInstructionResult : public ValueBase {
public:
/// Create a new multiple value instruction result.
///
/// \arg subclassDeltaOffset This is the delta offset in our parent object's
/// layout in between the end of the MultipleValueInstruction object and the
/// end of the specific subclass object.
///
/// *NOTE* subclassDeltaOffset must be use only 5 bits. This gives us to
/// support subclasses up to 32 bytes in size. We can scavange up to 6 more
/// bits from ValueBase if this is not large enough.
MultipleValueInstructionResult(ValueKind valueKind, unsigned index,
SILType type,
ValueOwnershipKind ownershipKind);
/// Return the parent instruction of this result.
MultipleValueInstruction *getParent();
const MultipleValueInstruction *getParent() const {
return const_cast<MultipleValueInstructionResult *>(this)->getParent();
}
unsigned getIndex() const {
return Bits.MultipleValueInstructionResult.Index;
}
/// Get the ownership kind assigned to this result by its parent.
///
/// This is stored in the bottom 3 bits of ValueBase's subclass data.
ValueOwnershipKind getOwnershipKind() const;
/// Set the ownership kind assigned to this result.
///
/// This is stored in SILNode in the subclass data.
void setOwnershipKind(ValueOwnershipKind Kind);
static bool classof(const SILInstruction *) = delete;
static bool classof(const SILUndef *) = delete;
static bool classof(const SILArgument *) = delete;
static bool classof(const MultipleValueInstructionResult *) { return true; }
static bool classof(const SILNode *node) {
// This is an abstract class without anything implementing it right now, so
// just return false. This will be fixed in a subsequent commit.
SILNodeKind kind = node->getKind();
return kind >= SILNodeKind::First_MultipleValueInstructionResult &&
kind <= SILNodeKind::Last_MultipleValueInstructionResult;
}
protected:
/// Set the index of this result.
void setIndex(unsigned NewIndex);
};
template <class Result>
SILInstructionResultArray::SILInstructionResultArray(ArrayRef<Result> results)
: SILInstructionResultArray(
ArrayRef<MultipleValueInstructionResult>(results.data(),
results.size())) {
static_assert(sizeof(Result) == sizeof(MultipleValueInstructionResult),
"MultipleValueInstructionResult subclass has wrong size");
}
/// An instruction that may produce an arbitrary number of values.
class MultipleValueInstruction : public SILInstruction {
friend class SILInstruction;
friend class SILInstructionResultArray;
protected:
MultipleValueInstruction(SILInstructionKind kind, SILDebugLocation loc)
: SILInstruction(kind, loc) {}
public:
void operator delete(void *Ptr, size_t) = delete;
MultipleValueInstruction *clone(SILInstruction *insertPt = nullptr) {
return cast<MultipleValueInstruction>(SILInstruction::clone(insertPt));
}
SILValue getResult(unsigned Index) const { return getResults()[Index]; }
/// Return the index of \p Target if it is a result in the given
/// MultipleValueInstructionResult. Otherwise, returns None.
Optional<unsigned> getIndexOfResult(SILValue Target) const;
unsigned getNumResults() const { return getResults().size(); }
static bool classof(const SILNode *node) {
SILNodeKind kind = node->getKind();
return kind >= SILNodeKind::First_MultipleValueInstruction &&
kind <= SILNodeKind::Last_MultipleValueInstruction;
}
};
template <typename...> class InitialTrailingObjects;
template <typename...> class FinalTrailingObjects;
/// A utility mixin class that must be used by /all/ subclasses of
/// MultipleValueInstruction to store their results.
///
/// The exact ordering of trailing types matters quite a lot because
/// it's vital that the fields used by preceding numTrailingObjects
/// implementations be initialized before this base class is (and
/// conversely that this base class be initialized before any of the
/// succeeding numTrailingObjects implementations are called).
template <typename Derived, typename DerivedResult,
typename Init = InitialTrailingObjects<>,
typename Final = FinalTrailingObjects<>>
class MultipleValueInstructionTrailingObjects;
template <typename Derived, typename DerivedResult,
typename... InitialOtherTrailingTypes,
typename... FinalOtherTrailingTypes>
class MultipleValueInstructionTrailingObjects<Derived, DerivedResult,
InitialTrailingObjects<InitialOtherTrailingTypes...>,
FinalTrailingObjects<FinalOtherTrailingTypes...>>
: protected llvm::TrailingObjects<Derived,
InitialOtherTrailingTypes...,
MultipleValueInstruction *,
DerivedResult,
FinalOtherTrailingTypes...> {
static_assert(std::is_final<DerivedResult>(),
"Expected DerivedResult to be final");
static_assert(
std::is_base_of<MultipleValueInstructionResult, DerivedResult>::value,
"Expected DerivedResult to be a subclass of "
"MultipleValueInstructionResult");
static_assert(sizeof(MultipleValueInstructionResult) == sizeof(DerivedResult),
"Expected DerivedResult to be the same size as a "
"MultipleValueInstructionResult");
protected:
using TrailingObjects =
llvm::TrailingObjects<Derived,
InitialOtherTrailingTypes...,
MultipleValueInstruction *, DerivedResult,
FinalOtherTrailingTypes...>;
friend TrailingObjects;
using TrailingObjects::totalSizeToAlloc;
using TrailingObjects::getTrailingObjects;
unsigned NumResults;
size_t numTrailingObjects(typename TrailingObjects::template OverloadToken<
MultipleValueInstruction *>) const {
return 1;
}
size_t numTrailingObjects(
typename TrailingObjects::template OverloadToken<DerivedResult>) const {
return NumResults;
}
template <typename... Args>
MultipleValueInstructionTrailingObjects(
Derived *Parent, ArrayRef<SILType> Types,
ArrayRef<ValueOwnershipKind> OwnershipKinds, Args &&... OtherArgs)
: NumResults(Types.size()) {
// If we do not have any results, then we do not need to initialize even the
// parent pointer since we do not have any results that will attempt to get
// our parent pointer.
if (!NumResults)
return;
auto **ParentPtr = this->TrailingObjects::template
getTrailingObjects<MultipleValueInstruction *>();
*ParentPtr = static_cast<MultipleValueInstruction *>(Parent);
auto *DataPtr = this->TrailingObjects::template
getTrailingObjects<DerivedResult>();
for (unsigned i : range(NumResults)) {
::new (&DataPtr[i]) DerivedResult(i, Types[i], OwnershipKinds[i],
std::forward<Args>(OtherArgs)...);
assert(DataPtr[i].getParent() == Parent &&
"Failed to setup parent reference correctly?!");
}
}
// Destruct the Derived Results.
~MultipleValueInstructionTrailingObjects() {
if (!NumResults)
return;
auto *DataPtr = this->TrailingObjects::template
getTrailingObjects<DerivedResult>();
// We call the DerivedResult destructors to ensure that:
//
// 1. If our derived results have any stored data that need to be cleaned
// up, we clean them up. *NOTE* Today, no results have this property.
// 2. In ~ValueBase, we validate via an assert that a ValueBase no longer
// has any uses when it is being destroyed. Rather than re-implement that in
// result, we get that for free.
for (unsigned i : range(NumResults))
DataPtr[i].~DerivedResult();
}
public:
ArrayRef<DerivedResult> getAllResultsBuffer() const {
auto *ptr = this->TrailingObjects::template
getTrailingObjects<DerivedResult>();
return { ptr, NumResults };
}
MutableArrayRef<DerivedResult> getAllResultsBuffer() {
auto *ptr = this->TrailingObjects::template
getTrailingObjects<DerivedResult>();
return { ptr, NumResults };
}
SILInstructionResultArray getAllResults() const {
// Our results start at element 1 since we stash the pointer to our parent
// MultipleValueInstruction in the 0 elt slot. This allows all
// MultipleValueInstructionResult to find their parent
// MultipleValueInstruction by using pointer arithmetic.
return SILInstructionResultArray(getAllResultsBuffer());
};
};
/// A subclass of SILInstruction which does not produce any values.
class NonValueInstruction : public SILInstruction {
public:
NonValueInstruction(SILInstructionKind kind, SILDebugLocation loc)
: SILInstruction(kind, loc) {}
/// Doesn't produce any results.
SILType getType() const = delete;
SILInstructionResultArray getResults() const = delete;
static bool classof(const ValueBase *value) = delete;
static bool classof(const SILNode *N) {
return N->getKind() >= SILNodeKind::First_NonValueInstruction &&
N->getKind() <= SILNodeKind::Last_NonValueInstruction;
}
static bool classof(const NonValueInstruction *) { return true; }
};
#define DEFINE_ABSTRACT_NON_VALUE_INST_BOILERPLATE(ID) \
static bool classof(const ValueBase *value) = delete; \
static bool classof(const SILNode *node) { \
return node->getKind() >= SILNodeKind::First_##ID && \
node->getKind() <= SILNodeKind::Last_##ID; \
}
/// A helper class for defining some basic boilerplate.
template <SILInstructionKind Kind, typename InstBase,
bool IsSingleResult =
std::is_base_of<SingleValueInstruction, InstBase>::value>
class InstructionBase;
template <SILInstructionKind Kind, typename InstBase>
class InstructionBase<Kind, InstBase, /*HasResult*/ true> : public InstBase {
protected:
template <typename... As>
InstructionBase(As &&... args) : InstBase(Kind, std::forward<As>(args)...) {}
public:
/// Override to statically return the kind.
static constexpr SILInstructionKind getKind() {
return Kind;
}
static bool classof(const SILNode *node) {
return node->getKind() == SILNodeKind(Kind);
}
static bool classof(const SingleValueInstruction *I) { // resolve ambiguities
return I->getKind() == Kind;
}
};
template <SILInstructionKind Kind, typename InstBase>
class InstructionBase<Kind, InstBase, /*HasResult*/ false> : public InstBase {
protected:
template <typename... As>
InstructionBase(As &&... args) : InstBase(Kind, std::forward<As>(args)...) {}
public:
static constexpr SILInstructionKind getKind() {
return Kind;
}
/// Can never dynamically succeed.
static bool classof(const ValueBase *value) = delete;
static bool classof(const SILNode *node) {
return node->getKind() == SILNodeKind(Kind);
}
};
/// A template base class for instructions that take a single SILValue operand.
template<SILInstructionKind Kind, typename Base>
class UnaryInstructionBase : public InstructionBase<Kind, Base> {
// Space for 1 operand.
FixedOperandList<1> Operands;
public:
template <typename... A>
UnaryInstructionBase(SILDebugLocation loc, SILValue op, A &&... args)
: InstructionBase<Kind, Base>(loc, std::forward<A>(args)...),
Operands(this, op) {}
SILValue getOperand() const { return Operands[0].get(); }
void setOperand(SILValue V) { Operands[0].set(V); }
Operand &getOperandRef() { return Operands[0]; }
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
ArrayRef<Operand> getTypeDependentOperands() const {
return {};
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return {};
}
};
/// A template base class for instructions that a variable number of SILValue
/// operands, and has zero or one value results. The operands are tail allocated
/// after the instruction. Further trailing data can be allocated as well if
/// OtherTrailingTypes are provided.
template<SILInstructionKind Kind,
typename Derived,
typename Base,
typename... OtherTrailingTypes>
class InstructionBaseWithTrailingOperands
: public InstructionBase<Kind, Base>,
protected llvm::TrailingObjects<Derived, Operand, OtherTrailingTypes...> {
protected:
friend llvm::TrailingObjects<Derived, Operand, OtherTrailingTypes...>;
using TrailingObjects =
llvm::TrailingObjects<Derived, Operand, OtherTrailingTypes...>;
using TrailingObjects::totalSizeToAlloc;
public:
template <typename... Args>
InstructionBaseWithTrailingOperands(ArrayRef<SILValue> Operands,
Args &&...args)
: InstructionBase<Kind, Base>(std::forward<Args>(args)...) {
SILInstruction::Bits.IBWTO.NumOperands = Operands.size();
TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
Operands);
}
template <typename... Args>
InstructionBaseWithTrailingOperands(SILValue Operand0,
ArrayRef<SILValue> Operands,
Args &&...args)
: InstructionBase<Kind, Base>(std::forward<Args>(args)...) {
SILInstruction::Bits.IBWTO.NumOperands = Operands.size() + 1;
TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
Operand0, Operands);
}
template <typename... Args>
InstructionBaseWithTrailingOperands(SILValue Operand0,
SILValue Operand1,
ArrayRef<SILValue> Operands,
Args &&...args)
: InstructionBase<Kind, Base>(std::forward<Args>(args)...) {
SILInstruction::Bits.IBWTO.NumOperands = Operands.size() + 2;
TrailingOperandsList::InitOperandsList(getAllOperands().begin(), this,
Operand0, Operand1, Operands);
}
// Destruct tail allocated objects.
~InstructionBaseWithTrailingOperands() {
Operand *Operands = TrailingObjects::template getTrailingObjects<Operand>();
auto end = SILInstruction::Bits.IBWTO.NumOperands;
for (unsigned i = 0; i < end; ++i) {
Operands[i].~Operand();
}
}
size_t numTrailingObjects(typename TrailingObjects::template
OverloadToken<Operand>) const {
return SILInstruction::Bits.IBWTO.NumOperands;
}
ArrayRef<Operand> getAllOperands() const {
return {TrailingObjects::template getTrailingObjects<Operand>(),
SILInstruction::Bits.IBWTO.NumOperands};
}
MutableArrayRef<Operand> getAllOperands() {
return {TrailingObjects::template getTrailingObjects<Operand>(),
SILInstruction::Bits.IBWTO.NumOperands};
}
};
/// A template base class for instructions that take a single regular SILValue
/// operand, a set of type dependent operands and has no result
/// or a single value result. The operands are tail allocated after the
/// instruction. Further trailing data can be allocated as well if
/// TRAILING_TYPES are provided.
template<SILInstructionKind Kind,
typename Derived,
typename Base,
typename... OtherTrailingTypes>
class UnaryInstructionWithTypeDependentOperandsBase
: public InstructionBaseWithTrailingOperands<Kind, Derived, Base,
OtherTrailingTypes...> {
protected:
friend InstructionBaseWithTrailingOperands<Kind, Derived, Operand,
OtherTrailingTypes...>;
using TrailingObjects =
InstructionBaseWithTrailingOperands<Kind, Derived, Operand,
OtherTrailingTypes...>;
public:
template <typename... Args>
UnaryInstructionWithTypeDependentOperandsBase(SILDebugLocation debugLoc,
SILValue operand,
ArrayRef<SILValue> typeDependentOperands,
Args &&...args)
: InstructionBaseWithTrailingOperands<Kind, Derived, Base,
OtherTrailingTypes...>(
operand, typeDependentOperands,
debugLoc,
std::forward<Args>(args)...) {}
unsigned getNumTypeDependentOperands() const {
return this->getAllOperands().size() - 1;
}
SILValue getOperand() const {
return this->getAllOperands()[0].get();
}
void setOperand(SILValue V) {
this->getAllOperands()[0].set(V);
}
Operand &getOperandRef() {
return this->getAllOperands()[0];
}
ArrayRef<Operand> getTypeDependentOperands() const {
return this->getAllOperands().slice(1);
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return this->getAllOperands().slice(1);
}
};
/// Holds common debug information about local variables and function
/// arguments that are needed by DebugValueInst, DebugValueAddrInst,
/// AllocStackInst, and AllocBoxInst.
struct SILDebugVariable {
StringRef Name;
unsigned ArgNo : 16;
unsigned Constant : 1;
SILDebugVariable() : ArgNo(0), Constant(false) {}
SILDebugVariable(bool Constant, uint16_t ArgNo)
: ArgNo(ArgNo), Constant(Constant) {}
SILDebugVariable(StringRef Name, bool Constant, unsigned ArgNo)
: Name(Name), ArgNo(ArgNo), Constant(Constant) {}
bool operator==(const SILDebugVariable &V) {
return ArgNo == V.ArgNo && Constant == V.Constant && Name == V.Name;
}
};
/// A DebugVariable where storage for the strings has been
/// tail-allocated following the parent SILInstruction.
class TailAllocatedDebugVariable {
using int_type = uint32_t;
union {
int_type RawValue;
struct {
/// Whether this is a debug variable at all.
int_type HasValue : 1;
/// True if this is a let-binding.
int_type Constant : 1;
/// When this is nonzero there is a tail-allocated string storing
/// variable name present. This typically only happens for
/// instructions that were created from parsing SIL assembler.
int_type NameLength : 14;
/// The source function argument position from left to right
/// starting with 1 or 0 if this is a local variable.
int_type ArgNo : 16;
} Data;
} Bits;
public:
TailAllocatedDebugVariable(Optional<SILDebugVariable>, char *buf);
TailAllocatedDebugVariable(int_type RawValue) { Bits.RawValue = RawValue; }
int_type getRawValue() const { return Bits.RawValue; }
unsigned getArgNo() const { return Bits.Data.ArgNo; }
void setArgNo(unsigned N) { Bits.Data.ArgNo = N; }
/// Returns the name of the source variable, if it is stored in the
/// instruction.
StringRef getName(const char *buf) const;
bool isLet() const { return Bits.Data.Constant; }
Optional<SILDebugVariable> get(VarDecl *VD, const char *buf) const {
if (!Bits.Data.HasValue)
return None;
if (VD)
return SILDebugVariable(VD->getName().empty() ? "" : VD->getName().str(),
VD->isLet(), getArgNo());
else
return SILDebugVariable(getName(buf), isLet(), getArgNo());
}
};
static_assert(sizeof(TailAllocatedDebugVariable) == 4,
"SILNode inline bitfield needs updating");
//===----------------------------------------------------------------------===//
// Allocation Instructions
//===----------------------------------------------------------------------===//
/// Abstract base class for allocation instructions, like alloc_stack, alloc_box
/// and alloc_ref, etc.
class AllocationInst : public SingleValueInstruction {
protected:
AllocationInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, SILType Ty)
: SingleValueInstruction(Kind, DebugLoc, Ty) {}
public:
DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(AllocationInst)
/// Return the underlying variable declaration associated with this
/// allocation, or null if this allocation inst is associated with a temporary
/// allocation.
VarDecl *getDecl() const;
};
class DeallocStackInst;
/// AllocStackInst - This represents the allocation of an unboxed (i.e., no
/// reference count) stack memory. The memory is provided uninitialized.
class AllocStackInst final
: public InstructionBase<SILInstructionKind::AllocStackInst,
AllocationInst>,
private llvm::TrailingObjects<AllocStackInst, Operand, char> {
friend TrailingObjects;
friend SILBuilder;
bool dynamicLifetime = false;
AllocStackInst(SILDebugLocation Loc, SILType elementType,
ArrayRef<SILValue> TypeDependentOperands,
SILFunction &F,
Optional<SILDebugVariable> Var, bool hasDynamicLifetime);
static AllocStackInst *create(SILDebugLocation Loc, SILType elementType,
SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes,
Optional<SILDebugVariable> Var,
bool hasDynamicLifetime);
size_t numTrailingObjects(OverloadToken<Operand>) const {
return SILInstruction::Bits.AllocStackInst.NumOperands;
}
public:
~AllocStackInst() {
Operand *Operands = getTrailingObjects<Operand>();
size_t end = SILInstruction::Bits.AllocStackInst.NumOperands;
for (unsigned i = 0; i < end; ++i) {
Operands[i].~Operand();
}
}
/// Set to true that this alloc_stack contains a value whose lifetime can not
/// be ascertained from uses.
///
/// As an example if an alloc_stack is known to be only conditionally
/// initialized.
void setDynamicLifetime() { dynamicLifetime = true; }
/// Returns true if the alloc_stack's initialization can not be ascertained
/// from uses directly (so should be treated conservatively).
///
/// An example of an alloc_stack with dynamic lifetime is an alloc_stack that
/// is conditionally initialized.
bool hasDynamicLifetime() const { return dynamicLifetime; }
/// Return the debug variable information attached to this instruction.
Optional<SILDebugVariable> getVarInfo() const {
auto RawValue = SILInstruction::Bits.AllocStackInst.VarInfo;
auto VI = TailAllocatedDebugVariable(RawValue);
return VI.get(getDecl(), getTrailingObjects<char>());
};
void setArgNo(unsigned N) {
auto RawValue = SILInstruction::Bits.AllocStackInst.VarInfo;
auto VI = TailAllocatedDebugVariable(RawValue);
VI.setArgNo(N);
SILInstruction::Bits.AllocStackInst.VarInfo = VI.getRawValue();
}
/// getElementType - Get the type of the allocated memory (as opposed to the
/// type of the instruction itself, which will be an address type).
SILType getElementType() const {
return getType().getObjectType();
}
ArrayRef<Operand> getAllOperands() const {
return { getTrailingObjects<Operand>(),
static_cast<size_t>(SILInstruction::Bits.AllocStackInst.NumOperands) };
}
MutableArrayRef<Operand> getAllOperands() {
return { getTrailingObjects<Operand>(),
static_cast<size_t>(SILInstruction::Bits.AllocStackInst.NumOperands) };
}
ArrayRef<Operand> getTypeDependentOperands() const {
return getAllOperands();
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return getAllOperands();
}
/// Return a single dealloc_stack user or null.
DeallocStackInst *getSingleDeallocStack() const;
};
/// The base class for AllocRefInst and AllocRefDynamicInst.
///
/// The first NumTailTypes operands are counts for the tail allocated
/// elements, the remaining operands are opened archetype operands.
class AllocRefInstBase : public AllocationInst {
protected:
AllocRefInstBase(SILInstructionKind Kind,
SILDebugLocation DebugLoc,
SILType ObjectType,
bool objc, bool canBeOnStack,
ArrayRef<SILType> ElementTypes);
SILType *getTypeStorage();
const SILType *getTypeStorage() const {
return const_cast<AllocRefInstBase*>(this)->getTypeStorage();
}
unsigned getNumTailTypes() const {
return SILInstruction::Bits.AllocRefInstBase.NumTailTypes;
}
public:
bool canAllocOnStack() const {
return SILInstruction::Bits.AllocRefInstBase.OnStack;
}
void setStackAllocatable(bool OnStack = true) {
SILInstruction::Bits.AllocRefInstBase.OnStack = OnStack;
}
ArrayRef<SILType> getTailAllocatedTypes() const {
return {getTypeStorage(), getNumTailTypes()};
}
MutableArrayRef<SILType> getTailAllocatedTypes() {
return {getTypeStorage(), getNumTailTypes()};
}
ArrayRef<Operand> getTailAllocatedCounts() const {
return getAllOperands().slice(0, getNumTailTypes());
}
MutableArrayRef<Operand> getTailAllocatedCounts() {
return getAllOperands().slice(0, getNumTailTypes());
}
ArrayRef<Operand> getAllOperands() const;
MutableArrayRef<Operand> getAllOperands();
/// Whether to use Objective-C's allocation mechanism (+allocWithZone:).
bool isObjC() const {
return SILInstruction::Bits.AllocRefInstBase.ObjC;
}
};
/// AllocRefInst - This represents the primitive allocation of an instance
/// of a reference type. Aside from the reference count, the instance is
/// returned uninitialized.
/// Optionally, the allocated instance contains space for one or more tail-
/// allocated arrays.
class AllocRefInst final
: public InstructionBaseWithTrailingOperands<
SILInstructionKind::AllocRefInst,
AllocRefInst,
AllocRefInstBase, SILType> {
friend AllocRefInstBase;
friend SILBuilder;
AllocRefInst(SILDebugLocation DebugLoc, SILFunction &F,
SILType ObjectType,
bool objc, bool canBeOnStack,
ArrayRef<SILType> ElementTypes,
ArrayRef<SILValue> AllOperands)
: InstructionBaseWithTrailingOperands(AllOperands, DebugLoc, ObjectType,
objc, canBeOnStack, ElementTypes) {
assert(AllOperands.size() >= ElementTypes.size());
std::uninitialized_copy(ElementTypes.begin(), ElementTypes.end(),
getTrailingObjects<SILType>());
}
static AllocRefInst *create(SILDebugLocation DebugLoc, SILFunction &F,
SILType ObjectType,
bool objc, bool canBeOnStack,
ArrayRef<SILType> ElementTypes,
ArrayRef<SILValue> ElementCountOperands,
SILOpenedArchetypesState &OpenedArchetypes);
public:
ArrayRef<Operand> getTypeDependentOperands() const {
return getAllOperands().slice(getNumTailTypes());
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return getAllOperands().slice(getNumTailTypes());
}
};
/// 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.
/// Optionally, the allocated instance contains space for one or more tail-
/// allocated arrays.
class AllocRefDynamicInst final
: public InstructionBaseWithTrailingOperands<
SILInstructionKind::AllocRefDynamicInst,
AllocRefDynamicInst,
AllocRefInstBase, SILType> {
friend AllocRefInstBase;
friend SILBuilder;
AllocRefDynamicInst(SILDebugLocation DebugLoc,
SILType ty,
bool objc,
ArrayRef<SILType> ElementTypes,
ArrayRef<SILValue> AllOperands)
: InstructionBaseWithTrailingOperands(AllOperands, DebugLoc, ty, objc,
false, ElementTypes) {
assert(AllOperands.size() >= ElementTypes.size() + 1);
std::uninitialized_copy(ElementTypes.begin(), ElementTypes.end(),
getTrailingObjects<SILType>());
}
static AllocRefDynamicInst *
create(SILDebugLocation DebugLoc, SILFunction &F,
SILValue metatypeOperand, SILType ty, bool objc,
ArrayRef<SILType> ElementTypes,
ArrayRef<SILValue> ElementCountOperands,
SILOpenedArchetypesState &OpenedArchetypes);
public:
SILValue getMetatypeOperand() const {
return getAllOperands()[getNumTailTypes()].get();
}
ArrayRef<Operand> getTypeDependentOperands() const {
return getAllOperands().slice(getNumTailTypes() + 1);
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return getAllOperands().slice(getNumTailTypes() + 1);
}
};
/// AllocValueBufferInst - Allocate memory in a value buffer.
class AllocValueBufferInst final
: public UnaryInstructionWithTypeDependentOperandsBase<
SILInstructionKind::AllocValueBufferInst,
AllocValueBufferInst,
AllocationInst> {
friend SILBuilder;
AllocValueBufferInst(SILDebugLocation DebugLoc, SILType valueType,
SILValue operand,
ArrayRef<SILValue> TypeDependentOperands);
static AllocValueBufferInst *
create(SILDebugLocation DebugLoc, SILType valueType, SILValue operand,
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);
public:
SILType getValueType() const { return getType().getObjectType(); }
};
/// 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 final
: public InstructionBaseWithTrailingOperands<
SILInstructionKind::AllocBoxInst,
AllocBoxInst, AllocationInst, char> {
friend SILBuilder;
TailAllocatedDebugVariable VarInfo;
bool dynamicLifetime = false;
AllocBoxInst(SILDebugLocation DebugLoc, CanSILBoxType BoxType,
ArrayRef<SILValue> TypeDependentOperands, SILFunction &F,
Optional<SILDebugVariable> Var, bool hasDynamicLifetime);
static AllocBoxInst *create(SILDebugLocation Loc, CanSILBoxType boxType,
SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes,
Optional<SILDebugVariable> Var,
bool hasDynamicLifetime);
public:
CanSILBoxType getBoxType() const {
return getType().castTo<SILBoxType>();
}
void setDynamicLifetime() { dynamicLifetime = true; }
bool hasDynamicLifetime() const { return dynamicLifetime; }
// Return the type of the memory stored in the alloc_box.
SILType getAddressType() const;
/// Return the debug variable information attached to this instruction.
Optional<SILDebugVariable> getVarInfo() const {
return VarInfo.get(getDecl(), getTrailingObjects<char>());
};
ArrayRef<Operand> getTypeDependentOperands() const {
return getAllOperands();
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return getAllOperands();
}
};
/// This represents the allocation of a heap box for an existential container.
/// The instruction returns two values. The first return value is the owner
/// pointer, which has the existential type. The second return value
/// is an address pointing to the contained element. The contained
/// value is uninitialized.
class AllocExistentialBoxInst final
: public InstructionBaseWithTrailingOperands<
SILInstructionKind::AllocExistentialBoxInst,
AllocExistentialBoxInst, AllocationInst> {
friend SILBuilder;
CanType ConcreteType;
ArrayRef<ProtocolConformanceRef> Conformances;
AllocExistentialBoxInst(SILDebugLocation DebugLoc, SILType ExistentialType,
CanType ConcreteType,
ArrayRef<ProtocolConformanceRef> Conformances,
ArrayRef<SILValue> TypeDependentOperands,
SILFunction *Parent)
: InstructionBaseWithTrailingOperands(TypeDependentOperands, DebugLoc,
ExistentialType.getObjectType()),
ConcreteType(ConcreteType), Conformances(Conformances) {}
static AllocExistentialBoxInst *
create(SILDebugLocation DebugLoc, SILType ExistentialType,
CanType ConcreteType, ArrayRef<ProtocolConformanceRef> Conformances,
SILFunction *Parent, SILOpenedArchetypesState &OpenedArchetypes);
public:
CanType getFormalConcreteType() const { return ConcreteType; }
SILType getExistentialType() const { return getType(); }
ArrayRef<ProtocolConformanceRef> getConformances() const {
return Conformances;
}
ArrayRef<Operand> getTypeDependentOperands() const {
return getAllOperands();
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return getAllOperands();
}
};
/// GenericSpecializationInformation - provides information about a generic
/// specialization. This meta-information is created for each generic
/// specialization, which allows for tracking of dependencies between
/// specialized generic functions and can be used to detect specialization loops
/// during generic specialization.
class GenericSpecializationInformation {
/// The caller function that triggered this specialization.
SILFunction *Caller;
/// The original function that was specialized.
SILFunction *Parent;
/// Substitutions used to produce this specialization.
SubstitutionMap Subs;
GenericSpecializationInformation(SILFunction *Caller, SILFunction *Parent,
SubstitutionMap Subs);
public:
static const GenericSpecializationInformation *create(SILFunction *Caller,
SILFunction *Parent,
SubstitutionMap Subs);
static const GenericSpecializationInformation *create(SILInstruction *Inst,
SILBuilder &B);
const SILFunction *getCaller() const { return Caller; }
const SILFunction *getParent() const { return Parent; }
SubstitutionMap getSubstitutions() const { return Subs; }
};
class PartialApplyInst;
// There's no good reason for the OverloadToken type to be internal
// or protected, and it makes it very difficult to write our CRTP classes
// if it is, so pull it out. TODO: just fix LLVM.
struct TerribleOverloadTokenHack :
llvm::trailing_objects_internal::TrailingObjectsBase {
template <class T>
using Hack = OverloadToken<T>;
};
template <class T>
using OverloadToken = TerribleOverloadTokenHack::Hack<T>;
/// ApplyInstBase - An abstract class for different kinds of function
/// application.
template <class Impl, class Base,
bool IsFullApply = !std::is_same<Impl, PartialApplyInst>::value>
class ApplyInstBase;
// The partial specialization for non-full applies. Note that the
// partial specialization for full applies inherits from this.
template <class Impl, class Base>
class ApplyInstBase<Impl, Base, false> : public Base {
enum { Callee, NumStaticOperands };
/// The type of the callee with our substitutions applied.
SILType SubstCalleeType;
/// Information about specialization and inlining of this apply.
/// This is only != nullptr if the apply was inlined. And in this case it
/// points to the specialization info of the inlined function.
const GenericSpecializationInformation *SpecializationInfo;
/// Used for apply_inst instructions: true if the called function has an
/// error result but is not actually throwing.
unsigned NonThrowing: 1;
/// The number of call arguments as required by the callee.
unsigned NumCallArguments : 31;
/// The total number of type-dependent operands.
unsigned NumTypeDependentOperands;
/// The substitutions being applied to the callee.
SubstitutionMap Substitutions;
Impl &asImpl() { return static_cast<Impl &>(*this); }
const Impl &asImpl() const { return static_cast<const Impl &>(*this); }
protected:
template <class... As>
ApplyInstBase(SILInstructionKind kind, SILDebugLocation DebugLoc, SILValue callee,
SILType substCalleeType, SubstitutionMap subs,
ArrayRef<SILValue> args,
ArrayRef<SILValue> typeDependentOperands,
const GenericSpecializationInformation *specializationInfo,
As... baseArgs)
: Base(kind, DebugLoc, baseArgs...), SubstCalleeType(substCalleeType),
SpecializationInfo(specializationInfo),
NonThrowing(false), NumCallArguments(args.size()),
NumTypeDependentOperands(typeDependentOperands.size()),
Substitutions(subs) {
// Initialize the operands.
auto allOperands = getAllOperands();
new (&allOperands[Callee]) Operand(this, callee);
for (size_t i : indices(args)) {
new (&allOperands[NumStaticOperands + i]) Operand(this, args[i]);
}
for (size_t i : indices(typeDependentOperands)) {
new (&allOperands[NumStaticOperands + args.size() + i])
Operand(this, typeDependentOperands[i]);
}
}
~ApplyInstBase() {
for (auto &operand : getAllOperands())
operand.~Operand();
}
template <class, class...>
friend class llvm::TrailingObjects;
unsigned numTrailingObjects(OverloadToken<Operand>) const {
return getNumAllOperands();
}
static size_t getNumAllOperands(ArrayRef<SILValue> args,
ArrayRef<SILValue> typeDependentOperands) {
return NumStaticOperands + args.size() + typeDependentOperands.size();
}
void setNonThrowing(bool isNonThrowing) { NonThrowing = isNonThrowing; }
bool isNonThrowingApply() const { return NonThrowing; }
public:
/// The operand number of the first argument.
static unsigned getArgumentOperandNumber() { return NumStaticOperands; }
Operand *getCalleeOperand() { return &getAllOperands()[Callee]; }
const Operand *getCalleeOperand() const { return &getAllOperands()[Callee]; }
SILValue getCallee() const { return getCalleeOperand()->get(); }
/// Gets the origin of the callee by looking through function type conversions
/// until we find a function_ref, partial_apply, or unrecognized value.
///
/// This is defined out of line to work around incomplete definition
/// issues. It is at the bottom of the file.
SILValue getCalleeOrigin() const;
/// Gets the referenced function by looking through partial apply,
/// convert_function, and thin to thick function until we find a function_ref.
///
/// This is defined out of line to work around incomplete definition
/// issues. It is at the bottom of the file.
SILFunction *getCalleeFunction() const;
bool isCalleeDynamicallyReplaceable() const;
/// Gets the referenced function if the callee is a function_ref instruction.
/// Returns null if the callee is dynamic or a (prev_)dynamic_function_ref
/// instruction.
SILFunction *getReferencedFunctionOrNull() const {
if (auto *FRI = dyn_cast<FunctionRefBaseInst>(getCallee()))
return FRI->getReferencedFunctionOrNull();
return nullptr;
}
/// Return the referenced function if the callee is a function_ref like
/// instruction.
///
/// WARNING: This not necessarily the function that will be called at runtime.
/// If the callee is a (prev_)dynamic_function_ref the actual function called
/// might be different because it could be dynamically replaced at runtime.
///
/// If the client of this API wants to look at the content of the returned SIL
/// function it should call getReferencedFunctionOrNull() instead.
SILFunction *getInitiallyReferencedFunction() const {
if (auto *FRI = dyn_cast<FunctionRefBaseInst>(getCallee()))
return FRI->getInitiallyReferencedFunction();
return nullptr;
}
/// Get the type of the callee without the applied substitutions.
CanSILFunctionType getOrigCalleeType() const {
return getCallee()->getType().template castTo<SILFunctionType>();
}
SILFunctionConventions getOrigCalleeConv() const {
return SILFunctionConventions(getOrigCalleeType(), this->getModule());
}
/// Get the type of the callee with the applied substitutions.
CanSILFunctionType getSubstCalleeType() const {
return SubstCalleeType.castTo<SILFunctionType>();
}
SILType getSubstCalleeSILType() const {
return SubstCalleeType;
}
void setSubstCalleeType(CanSILFunctionType t) {
SubstCalleeType = SILType::getPrimitiveObjectType(t);
}
SILFunctionConventions getSubstCalleeConv() const {
return SILFunctionConventions(getSubstCalleeType(), this->getModule());
}
bool isCalleeNoReturn() const {
return getSubstCalleeSILType().isNoReturnFunction(
this->getModule(), TypeExpansionContext(*this->getFunction()));
}
bool isCalleeThin() const {
auto Rep = getSubstCalleeType()->getRepresentation();
return Rep == FunctionType::Representation::Thin;
}
/// Returns true if the callee function is annotated with
/// @_semantics("programtermination_point")
bool isCalleeKnownProgramTerminationPoint() const {
auto calleeFn = getCalleeFunction();
if (!calleeFn) return false;
return calleeFn->hasSemanticsAttr(SEMANTICS_PROGRAMTERMINATION_POINT);
}
/// True if this application has generic substitutions.
bool hasSubstitutions() const {
return Substitutions.hasAnySubstitutableParams();
}
/// The substitutions used to bind the generic arguments of this function.
SubstitutionMap getSubstitutionMap() const { return Substitutions; }
/// Return the total number of operands of this instruction.
unsigned getNumAllOperands() const {
return NumStaticOperands + NumCallArguments + NumTypeDependentOperands;
}
/// Return all the operands of this instruction, which are (in order):
/// - the callee
/// - the formal arguments
/// - the type-dependency arguments
MutableArrayRef<Operand> getAllOperands() {
return { asImpl().template getTrailingObjects<Operand>(),
getNumAllOperands() };
}
ArrayRef<Operand> getAllOperands() const {
return { asImpl().template getTrailingObjects<Operand>(),
getNumAllOperands() };
}
/// Check whether the given operand index is a call-argument index
/// and, if so, return that index.
Optional<unsigned> getArgumentIndexForOperandIndex(unsigned index) {
assert(index < getNumAllOperands());
if (index < NumStaticOperands) return None;
index -= NumStaticOperands;
if (index >= NumCallArguments) return None;
return index;
}
/// The arguments passed to this instruction.
MutableArrayRef<Operand> getArgumentOperands() {
return getAllOperands().slice(NumStaticOperands, NumCallArguments);
}
ArrayRef<Operand> getArgumentOperands() const {
return getAllOperands().slice(NumStaticOperands, NumCallArguments);
}
/// The arguments passed to this instruction.
OperandValueArrayRef getArguments() const {
return OperandValueArrayRef(getArgumentOperands());
}
/// Returns the number of arguments being passed by this apply.
/// If this is a partial_apply, it can be less than the number of
/// parameters.
unsigned getNumArguments() const { return NumCallArguments; }
Operand &getArgumentRef(unsigned i) {
return getArgumentOperands()[i];
}
/// Return the ith argument passed to this instruction.
SILValue getArgument(unsigned i) const { return getArguments()[i]; }
/// Set the ith argument of this instruction.
void setArgument(unsigned i, SILValue V) {
return getArgumentOperands()[i].set(V);
}
ArrayRef<Operand> getTypeDependentOperands() const {
return getAllOperands().slice(NumStaticOperands + NumCallArguments);
}
MutableArrayRef<Operand> getTypeDependentOperands() {
return getAllOperands().slice(NumStaticOperands + NumCallArguments);
}
const GenericSpecializationInformation *getSpecializationInfo() const {
return SpecializationInfo;
}
};
/// Given the callee operand of an apply or try_apply instruction,
/// does it have the given semantics?
bool doesApplyCalleeHaveSemantics(SILValue callee, StringRef semantics);
/// Predicate used to filter InoutArgumentRange.
struct OperandToInoutArgument {
ArrayRef<SILParameterInfo> paramInfos;
OperandValueArrayRef arguments;
OperandToInoutArgument(ArrayRef<SILParameterInfo> paramInfos,
OperandValueArrayRef arguments)
: paramInfos(paramInfos), arguments(arguments) {
assert(paramInfos.size() == arguments.size());
}
Optional<SILValue> operator()(size_t i) const {
if (paramInfos[i].isIndirectMutating())
return arguments[i];
return None;
}
};
using InoutArgumentRange =
OptionalTransformRange<IntRange<size_t>, OperandToInoutArgument>;
/// The partial specialization of ApplyInstBase for full applications.
/// Adds some methods relating to 'self' and to result types that don't
/// make sense for partial applications.
template <class Impl, class Base>
class ApplyInstBase<Impl, Base, true>
: public ApplyInstBase<Impl, Base, false> {
using super = ApplyInstBase<Impl, Base, false>;
protected:
template <class... As>
ApplyInstBase(As &&...args)
: ApplyInstBase<Impl, Base, false>(std::forward<As>(args)...) {}
private:
const Impl &asImpl() const { return static_cast<const Impl &>(*this); }
public:
using super::getCallee;
using super::getSubstCalleeType;
using super::getSubstCalleeConv;
using super::hasSubstitutions;
using super::getNumArguments;
using super::getArgument;
using super::getArguments;
using super::getArgumentOperands;
/// The collection of following routines wrap the representation difference in
/// between the self substitution being first, but the self parameter of a
/// function being last.
///
/// The hope is that this will prevent any future bugs from coming up related
/// to this.
///
/// Self is always the last parameter, but self substitutions are always
/// first. The reason to add this method is to wrap that dichotomy to reduce
/// errors.
///
/// FIXME: Could this be standardized? It has and will lead to bugs. IMHO.
SILValue getSelfArgument() const {
assert(hasSelfArgument() && "Must have a self argument");
assert(getNumArguments() && "Should only be called when Callee has "
"arguments.");
return getArgument(getNumArguments()-1);
}
Operand &getSelfArgumentOperand() {
assert(hasSelfArgument() && "Must have a self argument");
assert(getNumArguments() && "Should only be called when Callee has "
"arguments.");
return getArgumentOperands()[getNumArguments()-1];
}
void setSelfArgument(SILValue V) {
assert(hasSelfArgument() && "Must have a self argument");
assert(getNumArguments() && "Should only be called when Callee has "
"arguments.");
getArgumentOperands()[getNumArguments() - 1].set(V);
}
OperandValueArrayRef getArgumentsWithoutSelf() const {
assert(hasSelfArgument() && "Must have a self argument");
assert(getNumArguments() && "Should only be called when Callee has "
"at least a self parameter.");
ArrayRef<Operand> ops = this->getArgumentOperands();
ArrayRef<Operand> opsWithoutSelf = ArrayRef<Operand>(&ops[0],
ops.size()-1);
return OperandValueArrayRef(opsWithoutSelf);
}
Optional<SILResultInfo> getSingleResult() const {
auto SubstCallee = getSubstCalleeType();
if (SubstCallee->getNumAllResults() != 1)
return None;
return SubstCallee->getSingleResult();
}
bool hasIndirectResults() const {
return getSubstCalleeConv().hasIndirectSILResults();
}
unsigned getNumIndirectResults() const {
return getSubstCalleeConv().getNumIndirectSILResults();
}
bool hasSelfArgument() const {
return getSubstCalleeType()->hasSelfParam();
}
bool hasGuaranteedSelfArgument() const {
auto C = getSubstCalleeType()->getSelfParameter().getConvention();
return C == ParameterConvention::Direct_Guaranteed;
}
OperandValueArrayRef getIndirectSILResults() const {
return getArguments().slice(0, getNumIndirectResults());
}
OperandValueArrayRef getArgumentsWithoutIndirectResults() const {
return getArguments().slice(getNumIndirectResults());
}
/// Returns all `@inout` and `@inout_aliasable` arguments passed to the
/// instruction.
InoutArgumentRange getInoutArguments() const {
auto &impl = asImpl();
return InoutArgumentRange(
indices(getArgumentsWithoutIndirectResults()),
OperandToInoutArgument(impl.getSubstCalleeConv().getParameters(),
impl.getArgumentsWithoutIndirectResults()));
}
bool hasSemantics(StringRef semanticsString) const {
return doesApplyCalleeHaveSemantics(getCallee(), semanticsString);
}
};
/// ApplyInst - Represents the full application of a function value.
class ApplyInst final
: public InstructionBase<SILInstructionKind::ApplyInst,
ApplyInstBase<ApplyInst, SingleValueInstruction>>,
public llvm::TrailingObjects<ApplyInst, Operand> {
friend SILBuilder;
ApplyInst(SILDebugLocation DebugLoc, SILValue Callee,
SILType SubstCalleeType, SILType ReturnType,
SubstitutionMap Substitutions,
ArrayRef<SILValue> Args,
ArrayRef<SILValue> TypeDependentOperands,
bool isNonThrowing,
const GenericSpecializationInformation *SpecializationInfo);
static ApplyInst *
create(SILDebugLocation DebugLoc, SILValue Callee,
SubstitutionMap Substitutions, ArrayRef<SILValue> Args,
bool isNonThrowing, Optional<SILModuleConventions> ModuleConventions,
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes,
const GenericSpecializationInformation *SpecializationInfo);
public:
/// Returns true if the called function has an error result but is not actually
/// throwing an error.
bool isNonThrowing() const {
return isNonThrowingApply();
}
};
/// PartialApplyInst - Represents the creation of a closure object by partial
/// application of a function value.
class PartialApplyInst final
: public InstructionBase<SILInstructionKind::PartialApplyInst,
ApplyInstBase<PartialApplyInst,
SingleValueInstruction>>,
public llvm::TrailingObjects<PartialApplyInst, Operand> {
friend SILBuilder;
public:
enum OnStackKind {
NotOnStack, OnStack
};
private:
PartialApplyInst(SILDebugLocation DebugLoc, SILValue Callee,
SILType SubstCalleeType,
SubstitutionMap Substitutions,
ArrayRef<SILValue> Args,
ArrayRef<SILValue> TypeDependentOperands,
SILType ClosureType,
const GenericSpecializationInformation *SpecializationInfo);
static PartialApplyInst *
create(SILDebugLocation DebugLoc, SILValue Callee, ArrayRef<SILValue> Args,
SubstitutionMap Substitutions, ParameterConvention CalleeConvention,
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes,
const GenericSpecializationInformation *SpecializationInfo,
OnStackKind onStack);
public:
/// Return the result function type of this partial apply.
CanSILFunctionType getFunctionType() const {
return getType().castTo<SILFunctionType>();
}
bool hasCalleeGuaranteedContext() const {
return getType().castTo<SILFunctionType>()->isCalleeGuaranteed();
}
OnStackKind isOnStack() const {
return getFunctionType()->isNoEscape() ? OnStack : NotOnStack;
}
};
class BeginApplyInst;
class BeginApplyResult final : public MultipleValueInstructionResult {
public:
BeginApplyResult(unsigned index, SILType type,
ValueOwnershipKind ownershipKind)
: MultipleValueInstructionResult(ValueKind::BeginApplyResult,
index, type, ownershipKind) {}
BeginApplyInst *getParent(); // inline below
const BeginApplyInst *getParent() const {
return const_cast<BeginApplyResult *>(this)->getParent();
}
/// Is this result the token result of the begin_apply, which abstracts
/// over the implicit coroutine state?
bool isTokenResult() const; // inline below
static bool classof(const SILNode *N) {
return N->getKind() == SILNodeKind::BeginApplyResult;
}
};
class EndApplyInst;
class AbortApplyInst;
/// BeginApplyInst - Represents the beginning of the full application of
/// a yield_once coroutine (up until the coroutine yields a value back).
class BeginApplyInst final
: public InstructionBase<SILInstructionKind::BeginApplyInst,
ApplyInstBase<BeginApplyInst,
MultipleValueInstruction>>,
public MultipleValueInstructionTrailingObjects<
BeginApplyInst, BeginApplyResult,
// These must be earlier trailing objects because their
// count fields are initialized by an earlier base class.
InitialTrailingObjects<Operand>> {
friend SILBuilder;
template <class, class...>
friend class llvm::TrailingObjects;
using InstructionBase::numTrailingObjects;
using MultipleValueInstructionTrailingObjects::numTrailingObjects;
friend class ApplyInstBase<BeginApplyInst, MultipleValueInstruction, false>;
using MultipleValueInstructionTrailingObjects::getTrailingObjects;
BeginApplyInst(SILDebugLocation debugLoc, SILValue callee,
SILType substCalleeType,
ArrayRef<SILType> allResultTypes,
ArrayRef<ValueOwnershipKind> allResultOwnerships,
SubstitutionMap substitutions,
ArrayRef<SILValue> args,
ArrayRef<SILValue> typeDependentOperands,
bool isNonThrowing,
const GenericSpecializationInformation *specializationInfo);
static BeginApplyInst *
create(SILDebugLocation debugLoc, SILValue Callee,
SubstitutionMap substitutions, ArrayRef<SILValue> args,
bool isNonThrowing, Optional<SILModuleConventions> moduleConventions,
SILFunction &F, SILOpenedArchetypesState &openedArchetypes,
const GenericSpecializationInformation *specializationInfo);
public:
using MultipleValueInstructionTrailingObjects::totalSizeToAlloc;
SILValue getTokenResult() const {
return &getAllResultsBuffer().back();
}
SILInstructionResultArray getYieldedValues() const {
return getAllResultsBuffer().drop_back();
}
/// Returns true if the called coroutine has an error result but is not
/// actually throwing an error.
bool isNonThrowing() const {
return isNonThrowingApply();
}
void getCoroutineEndPoints(
SmallVectorImpl<EndApplyInst *> &endApplyInsts,
SmallVectorImpl<AbortApplyInst *> &abortApplyInsts) const;
void getCoroutineEndPoints(SmallVectorImpl<Operand *> &endApplyInsts,
SmallVectorImpl<Operand *> &abortApplyInsts) const;
};
inline BeginApplyInst *BeginApplyResult::getParent() {
auto *Parent = MultipleValueInstructionResult::getParent();
return cast<BeginApplyInst>(Parent);
}
inline bool BeginApplyResult::isTokenResult() const {
return getIndex() == getParent()->getNumResults() - 1;
}
/// AbortApplyInst - Unwind the full application of a yield_once coroutine.
class AbortApplyInst
: public UnaryInstructionBase<SILInstructionKind::AbortApplyInst,
NonValueInstruction> {
friend SILBuilder;
AbortApplyInst(SILDebugLocation debugLoc, SILValue beginApplyToken)
: UnaryInstructionBase(debugLoc, beginApplyToken) {
assert(isa<BeginApplyResult>(beginApplyToken) &&
cast<BeginApplyResult>(beginApplyToken)->isTokenResult());
}
public:
BeginApplyInst *getBeginApply() const {
return cast<BeginApplyResult>(getOperand())->getParent();
}
};
/// EndApplyInst - Resume the full application of a yield_once coroutine
/// normally.
class EndApplyInst
: public UnaryInstructionBase<SILInstructionKind::EndApplyInst,
NonValueInstruction> {
friend SILBuilder;
EndApplyInst(SILDebugLocation debugLoc, SILValue beginApplyToken)
: UnaryInstructionBase(debugLoc, beginApplyToken) {
assert(isa<BeginApplyResult>(beginApplyToken) &&
cast<BeginApplyResult>(beginApplyToken)->isTokenResult());
}
public:
BeginApplyInst *getBeginApply() const {
return cast<BeginApplyResult>(getOperand())->getParent();
}
};
//===----------------------------------------------------------------------===//
// Literal instructions.
//===----------------------------------------------------------------------===//
/// Abstract base class for literal instructions.
class LiteralInst : public SingleValueInstruction {
protected:
LiteralInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, SILType Ty)
: SingleValueInstruction(Kind, DebugLoc, Ty) {}
public:
DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(LiteralInst)
};
class FunctionRefBaseInst : public LiteralInst {
SILFunction *f;
protected:
FunctionRefBaseInst(SILInstructionKind Kind, SILDebugLocation DebugLoc,
SILFunction *F, TypeExpansionContext context);
public:
~FunctionRefBaseInst();
/// Return the referenced function if this is a function_ref instruction and
/// therefore a client can rely on the dynamically called function being equal
/// to the returned value and null otherwise.
SILFunction *getReferencedFunctionOrNull() const {
auto kind = getKind();
if (kind == SILInstructionKind::FunctionRefInst)
return f;
assert(kind == SILInstructionKind::DynamicFunctionRefInst ||
kind == SILInstructionKind::PreviousDynamicFunctionRefInst);
return nullptr;
}
/// Return the initially referenced function.
///
/// WARNING: This not necessarily the function that will be called at runtime.
/// If the callee is a (prev_)dynamic_function_ref the actual function called
/// might be different because it could be dynamically replaced at runtime.
///
/// If the client of this API wants to look at the content of the returned SIL
/// function it should call getReferencedFunctionOrNull() instead.
SILFunction *getInitiallyReferencedFunction() const { return f; }
void dropReferencedFunction();
CanSILFunctionType getFunctionType() const {
return getType().castTo<SILFunctionType>();
}
SILFunctionConventions getConventions() const {
return SILFunctionConventions(getFunctionType(), getModule());
}
ArrayRef<Operand> getAllOperands() const { return {}; }
MutableArrayRef<Operand> getAllOperands() { return {}; }
static bool classof(const SILNode *node) {
return (node->getKind() == SILNodeKind::FunctionRefInst ||
node->getKind() == SILNodeKind::DynamicFunctionRefInst ||
node->getKind() == SILNodeKind::PreviousDynamicFunctionRefInst);
}
static bool classof(const SingleValueInstruction *node) {
return (node->getKind() == SILInstructionKind::FunctionRefInst ||
node->getKind() == SILInstructionKind::DynamicFunctionRefInst ||
node->getKind() == SILInstructionKind::PreviousDynamicFunctionRefInst);
}
};
/// FunctionRefInst - Represents a reference to a SIL function.
class FunctionRefInst : public FunctionRefBaseInst {
friend SILBuilder;
/// Construct a FunctionRefInst.
///
/// \param DebugLoc The location of the reference.
/// \param F The function being referenced.
/// \param context The type expansion context of the function reference.
FunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F,
TypeExpansionContext context);
public:
static bool classof(const SILNode *node) {
return node->getKind() == SILNodeKind::FunctionRefInst;
}
static bool classof(const SingleValueInstruction *node) {
return node->getKind() == SILInstructionKind::FunctionRefInst;
}
};
class DynamicFunctionRefInst : public FunctionRefBaseInst {
friend SILBuilder;
/// Construct a DynamicFunctionRefInst.
///
/// \param DebugLoc The location of the reference.
/// \param F The function being referenced.
/// \param context The type expansion context of the function reference.
DynamicFunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F,
TypeExpansionContext context);
public:
static bool classof(const SILNode *node) {
return node->getKind() == SILNodeKind::DynamicFunctionRefInst;
}
static bool classof(const SingleValueInstruction *node) {
return node->getKind() == SILInstructionKind::DynamicFunctionRefInst;
}
};
class PreviousDynamicFunctionRefInst : public FunctionRefBaseInst {
friend SILBuilder;
/// Construct a PreviousDynamicFunctionRefInst.
///
/// \param DebugLoc The location of the reference.
/// \param F The function being referenced.
/// \param context The type expansion context of the function reference.
PreviousDynamicFunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F,
TypeExpansionContext context);
public:
static bool classof(const SILNode *node) {
return node->getKind() == SILNodeKind::PreviousDynamicFunctionRefInst;
}
static bool classof(const SingleValueInstruction *node) {
return node->getKind() ==
SILInstructionKind::PreviousDynamicFunctionRefInst;
}
};
/// Component of a KeyPathInst.
class KeyPathPatternComponent {
public:
/// Computed property components require an identifier so they can be stably
/// identified at runtime. This has to correspond to the ABI of the property--
/// whether a reabstracted stored property, a property dispatched through a
/// vtable or witness table, or a computed property.
class ComputedPropertyId {
friend KeyPathPatternComponent;
public:
enum KindType {
Property, Function, DeclRef,
};
private:
union ValueType {
AbstractStorageDecl *Property;
SILFunction *Function;
SILDeclRef DeclRef;
ValueType() : Property(nullptr) {}
ValueType(AbstractStorageDecl *p) : Property(p) {}
ValueType(SILFunction *f) : Function(f) {}
ValueType(SILDeclRef d) : DeclRef(d) {}
} Value;
KindType Kind;
explicit ComputedPropertyId(ValueType Value, KindType Kind)
: Value(Value), Kind(Kind)
{}
public:
ComputedPropertyId() : Value(), Kind(Property) {}
/*implicit*/ ComputedPropertyId(VarDecl *property)
: Value{property}, Kind{Property}
{
}
/*implicit*/ ComputedPropertyId(SILFunction *function)
: Value{function}, Kind{Function}
{}
/*implicit*/ ComputedPropertyId(SILDeclRef declRef)
: Value{declRef}, Kind{DeclRef}
{}
KindType getKind() const { return Kind; }
VarDecl *getProperty() const {
assert(getKind() == Property);
return cast<VarDecl>(Value.Property);
}
SILFunction *getFunction() const {
assert(getKind() == Function);
return Value.Function;
}
SILDeclRef getDeclRef() const {
assert(getKind() == DeclRef);
return Value.DeclRef;
}
};
enum class Kind: unsigned {
StoredProperty,
GettableProperty,
SettableProperty,
TupleElement,
OptionalChain,
OptionalForce,
OptionalWrap,
};
// Description of a captured index value and its Hashable conformance for a
// subscript keypath.
struct Index {
unsigned Operand;
CanType FormalType;
SILType LoweredType;
ProtocolConformanceRef Hashable;
};
private:
enum PackedKind: unsigned {
PackedStored,
PackedComputed,
Unpacked,
};
static const unsigned KindPackingBits = 2;
static unsigned getPackedKind(Kind k) {
switch (k) {
case Kind::StoredProperty:
case Kind::TupleElement:
return PackedStored;
case Kind::GettableProperty:
case Kind::SettableProperty:
return PackedComputed;
case Kind::OptionalChain:
case Kind::OptionalForce:
case Kind::OptionalWrap:
return Unpacked;
}
}
// Value is the VarDecl* for StoredProperty, the SILFunction* of the
// Getter for computed properties, or the Kind for other kinds
llvm::PointerIntPair<void *, KindPackingBits, unsigned> ValueAndKind;
llvm::PointerIntPair<SILFunction *, 2,
ComputedPropertyId::KindType> SetterAndIdKind;
// If this component refers to a tuple element then TupleIndex is the
// 1-based index of the element in the tuple, in order to allow the
// discrimination of the TupleElement Kind from the StoredProperty Kind
union {
unsigned TupleIndex = 0;
ComputedPropertyId::ValueType IdValue;
};
ArrayRef<Index> Indices;
struct {
SILFunction *Equal;
SILFunction *Hash;
} IndexEquality;
CanType ComponentType;
AbstractStorageDecl *ExternalStorage;
SubstitutionMap ExternalSubstitutions;
/// Constructor for stored components
KeyPathPatternComponent(VarDecl *storedProp,
CanType ComponentType)
: ValueAndKind(storedProp, PackedStored),
ComponentType(ComponentType) {}
/// Constructor for computed components
KeyPathPatternComponent(ComputedPropertyId id,
SILFunction *getter,
SILFunction *setter,
ArrayRef<Index> indices,
SILFunction *indicesEqual,
SILFunction *indicesHash,
AbstractStorageDecl *externalStorage,
SubstitutionMap externalSubstitutions,
CanType ComponentType)
: ValueAndKind(getter, PackedComputed),
SetterAndIdKind{setter, id.Kind},
IdValue{id.Value},
Indices(indices),
IndexEquality{indicesEqual, indicesHash},
ComponentType(ComponentType),
ExternalStorage(externalStorage),
ExternalSubstitutions(externalSubstitutions)
{
}
/// Constructor for optional components.
KeyPathPatternComponent(Kind kind, CanType componentType)
: ValueAndKind((void*)((uintptr_t)kind << KindPackingBits), Unpacked),
ComponentType(componentType) {
assert((unsigned)kind >