//===--- SILValue.h - Value base class for SIL ------------------*- 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 SILValue class. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_SILVALUE_H #define SWIFT_SIL_SILVALUE_H #include "swift/Basic/Range.h" #include "swift/SIL/SILNode.h" #include "swift/SIL/SILType.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/Support/raw_ostream.h" namespace swift { class DominanceInfo; class PostOrderFunctionInfo; class ReversePostOrderInfo; class Operand; class SILInstruction; class SILLocation; class DeadEndBlocks; class ValueBaseUseIterator; class ValueUseIterator; /// An enumeration which contains values for all the concrete ValueBase /// subclasses. enum class ValueKind : std::underlying_type::type { #define VALUE(ID, PARENT) \ ID = unsigned(SILNodeKind::ID), #define VALUE_RANGE(ID, FIRST, LAST) \ First_##ID = unsigned(SILNodeKind::First_##ID), \ Last_##ID = unsigned(SILNodeKind::Last_##ID), #include "swift/SIL/SILNodes.def" }; /// ValueKind hashes to its underlying integer representation. static inline llvm::hash_code hash_value(ValueKind K) { return llvm::hash_value(size_t(K)); } /// A value representing the specific ownership semantics that a SILValue may /// have. struct ValueOwnershipKind { enum innerty : uint8_t { /// A SILValue with Trivial ownership kind is an independent value that can /// not be owned. Ownership does not place any constraints on how a SILValue /// with Trivial ownership kind can be used. Other side effects (e.g. Memory /// dependencies) must still be respected. A SILValue with Trivial ownership /// kind must be of Trivial SILType (i.e. SILType::isTrivial(SILModule &) /// must /// return true). /// /// Some examples of SIL types with Trivial ownership are: Builtin.Int32, /// Builtin.RawPointer, aggregates containing all trivial types. Trivial, /// A SILValue with `Unowned` ownership kind is an independent value that /// has /// a lifetime that is only guaranteed to last until the next program /// visible /// side-effect. To maintain the lifetime of an unowned value, it must be /// converted to an owned representation via a copy_value. /// /// Unowned ownership kind occurs mainly along method/function boundaries in /// between Swift and Objective-C code. Unowned, /// A SILValue with `Owned` ownership kind is an independent value that has /// an /// ownership independent of any other ownership imbued within it. The /// SILValue must be paired with a consuming operation that ends the SSA /// value's lifetime exactly once along all paths through the program. Owned, /// A SILValue with `Guaranteed` ownership kind is an independent value that /// is guaranteed to be live over a specific region of the program. This /// region can come in several forms: /// /// 1. @guaranteed function argument. This guarantees that a value will /// outlive a function. /// /// 2. A shared borrow region. This is a region denoted by a /// begin_borrow/load_borrow instruction and an end_borrow instruction. The /// SSA value must not be destroyed or taken inside the borrowed region. /// /// Any value with guaranteed ownership must be paired with an end_borrow /// instruction exactly once along any path through the program. Guaranteed, /// A SILValue with undefined ownership. It can pair with /Any/ ownership /// kinds . This means that it could take on /any/ ownership semantics. This /// is meant only to model SILUndef and to express certain situations where /// we /// use unqualified ownership. Expected to tighten over time. Any, LastValueOwnershipKind = Any, } Value; using UnderlyingType = std::underlying_type::type; static constexpr unsigned NumBits = SILNode::NumVOKindBits; static constexpr UnderlyingType MaxValue = (UnderlyingType(1) << NumBits); static constexpr uint64_t Mask = MaxValue - 1; static_assert(unsigned(ValueOwnershipKind::LastValueOwnershipKind) < MaxValue, "LastValueOwnershipKind is larger than max representable " "ownership value?!"); ValueOwnershipKind(innerty NewValue) : Value(NewValue) {} ValueOwnershipKind(unsigned NewValue) : Value(innerty(NewValue)) {} ValueOwnershipKind(SILModule &M, SILType Type, SILArgumentConvention Convention); /// Parse Value into a ValueOwnershipKind. /// /// *NOTE* Emits an unreachable if an invalid value is passed in. explicit ValueOwnershipKind(StringRef Value); operator innerty() const { return Value; } Optional merge(ValueOwnershipKind RHS) const; bool isTrivialOr(ValueOwnershipKind Kind) const { return Value == Trivial || Value == Kind; } /// Given that there is an aggregate value (like a struct or enum) with this /// ownership kind, and a subobject of type Proj is being projected from the /// aggregate, return Trivial if Proj has trivial type and the aggregate's /// ownership kind otherwise. ValueOwnershipKind getProjectedOwnershipKind(SILModule &M, SILType Proj) const; }; llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ValueOwnershipKind Kind); /// This is the base class of the SIL value hierarchy, which represents a /// runtime computed value. Some examples of ValueBase are SILArgument and /// SingleValueInstruction. class ValueBase : public SILNode, public SILAllocated { friend class Operand; SILType Type; Operand *FirstUse = nullptr; ValueBase(const ValueBase &) = delete; ValueBase &operator=(const ValueBase &) = delete; protected: ValueBase(ValueKind kind, SILType type, IsRepresentative isRepresentative) : SILNode(SILNodeKind(kind), SILNodeStorageLocation::Value, isRepresentative), Type(type) {} public: ~ValueBase() { assert(use_empty() && "Cannot destroy a value that still has uses!"); } LLVM_ATTRIBUTE_ALWAYS_INLINE ValueKind getKind() const { return ValueKind(SILNode::getKind()); } SILType getType() const { return Type; } /// Replace every use of a result of this instruction with the corresponding /// result from RHS. /// /// The method assumes that both instructions have the same number of /// results. To replace just one result use SILValue::replaceAllUsesWith. void replaceAllUsesWith(ValueBase *RHS); /// \brief Replace all uses of this instruction with an undef value of the /// same type as the result of this instruction. void replaceAllUsesWithUndef(); /// Is this value a direct result of the given instruction? bool isResultOf(SILInstruction *I) const; /// Returns true if this value has no uses. /// To ignore debug-info instructions use swift::onlyHaveDebugUses instead /// (see comment in DebugUtils.h). bool use_empty() const { return FirstUse == nullptr; } using use_iterator = ValueBaseUseIterator; using use_range = iterator_range; inline use_iterator use_begin() const; inline use_iterator use_end() const; /// Returns a range of all uses, which is useful for iterating over all uses. /// To ignore debug-info instructions use swift::getNonDebugUses instead /// (see comment in DebugUtils.h). inline use_range getUses() const; /// Returns true if this value has exactly one use. /// To ignore debug-info instructions use swift::hasOneNonDebugUse instead /// (see comment in DebugUtils.h). inline bool hasOneUse() const; /// Returns .some(single user) if this value has a single user. Returns .none /// otherwise. inline Operand *getSingleUse() const; template inline T *getSingleUserOfType(); /// Return the instruction that defines this value, or null if it is /// not defined by an instruction. const SILInstruction *getDefiningInstruction() const { return const_cast(this)->getDefiningInstruction(); } SILInstruction *getDefiningInstruction(); struct DefiningInstructionResult { SILInstruction *Instruction; size_t ResultIndex; }; /// Return the instruction that defines this value and the appropriate /// result index, or None if it is not defined by an instruction. Optional getDefiningInstructionResult(); static bool classof(const SILNode *N) { return N->getKind() >= SILNodeKind::First_ValueBase && N->getKind() <= SILNodeKind::Last_ValueBase; } static bool classof(const ValueBase *V) { return true; } /// This is supportable but usually suggests a logic mistake. static bool classof(const SILInstruction *) = delete; }; } // end namespace swift namespace llvm { /// ValueBase * is always at least eight-byte aligned; make the three tag bits /// available through PointerLikeTypeTraits. template<> struct PointerLikeTypeTraits { public: static inline void *getAsVoidPointer(swift::ValueBase *I) { return (void*)I; } static inline swift::ValueBase *getFromVoidPointer(void *P) { return (swift::ValueBase *)P; } enum { NumLowBitsAvailable = 3 }; }; } // end namespace llvm namespace swift { /// SILValue - A SILValue is a wrapper around a ValueBase pointer. class SILValue { ValueBase *Value; public: SILValue(const ValueBase *V = nullptr) : Value(const_cast(V)) { } ValueBase *operator->() const { return Value; } ValueBase &operator*() const { return *Value; } operator ValueBase *() const { return Value; } // Comparison. bool operator==(SILValue RHS) const { return Value == RHS.Value; } bool operator==(ValueBase *RHS) const { return Value == RHS; } bool operator!=(SILValue RHS) const { return !(*this == RHS); } bool operator!=(ValueBase *RHS) const { return Value != RHS; } /// Return true if underlying ValueBase of this SILValue is non-null. Return /// false otherwise. explicit operator bool() const { return Value != nullptr; } /// Get a location for this value. SILLocation getLoc() const; /// Convert this SILValue into an opaque pointer like type. For use with /// PointerLikeTypeTraits. void *getOpaqueValue() const { return (void *)Value; } /// Convert the given opaque pointer into a SILValue. For use with /// PointerLikeTypeTraits. static SILValue getFromOpaqueValue(void *p) { return SILValue((ValueBase *)p); } enum { NumLowBitsAvailable = llvm::PointerLikeTypeTraits:: NumLowBitsAvailable }; /// Returns the ValueOwnershipKind that describes this SILValue's ownership /// semantics if the SILValue has ownership semantics. Returns is a value /// without any Ownership Semantics. /// /// An example of a SILValue without ownership semantics is a /// struct_element_addr. ValueOwnershipKind getOwnershipKind() const; /// Verify that this SILValue and its uses respects ownership invariants. void verifyOwnership(SILModule &Mod, DeadEndBlocks *DEBlocks = nullptr) const; }; /// A formal SIL reference to a value, suitable for use as a stored /// operand. class Operand { /// The value used as this operand. SILValue TheValue; /// The next operand in the use-chain. Note that the chain holds /// every use of the current ValueBase, not just those of the /// designated result. Operand *NextUse = nullptr; /// A back-pointer in the use-chain, required for fast patching /// of use-chains. Operand **Back = nullptr; /// The owner of this operand. /// FIXME: this could be space-compressed. SILInstruction *Owner; public: Operand(SILInstruction *owner) : Owner(owner) {} Operand(SILInstruction *owner, SILValue theValue) : TheValue(theValue), Owner(owner) { insertIntoCurrent(); } /// Operands are not copyable. Operand(const Operand &use) = delete; Operand &operator=(const Operand &use) = delete; /// Return the current value being used by this operand. SILValue get() const { return TheValue; } /// Set the current value being used by this operand. void set(SILValue newValue) { // It's probably not worth optimizing for the case of switching // operands on a single value. removeFromCurrent(); TheValue = newValue; insertIntoCurrent(); } /// Swap the given operand with the current one. void swap(Operand &Op) { SILValue OtherV = Op.get(); Op.set(get()); set(OtherV); } /// \brief Remove this use of the operand. void drop() { removeFromCurrent(); TheValue = SILValue(); NextUse = nullptr; Back = nullptr; Owner = nullptr; } ~Operand() { removeFromCurrent(); } /// Return the user that owns this use. SILInstruction *getUser() { return Owner; } const SILInstruction *getUser() const { return Owner; } /// getOperandNumber - Return which operand this is in the operand list of the /// using instruction. unsigned getOperandNumber() const; private: void removeFromCurrent() { if (!Back) return; *Back = NextUse; if (NextUse) NextUse->Back = Back; } void insertIntoCurrent() { Back = &TheValue->FirstUse; NextUse = TheValue->FirstUse; if (NextUse) NextUse->Back = &NextUse; TheValue->FirstUse = this; } friend class ValueBaseUseIterator; friend class ValueUseIterator; template friend class FixedOperandList; template friend class TailAllocatedOperandList; friend class TrailingOperandsList; }; /// A class which adapts an array of Operands into an array of Values. /// /// The intent is that this should basically act exactly like /// ArrayRef except projecting away the Operand-ness. class OperandValueArrayRef { ArrayRef Operands; public: explicit OperandValueArrayRef(ArrayRef operands) : Operands(operands) {} /// A simple iterator adapter. class iterator : public std::iterator { const Operand *Ptr; public: iterator() = default; iterator(const Operand *ptr) : Ptr(ptr) {} SILValue operator*() const { assert(Ptr); return Ptr->get(); } SILValue operator->() const { return operator*(); } iterator &operator++() { ++Ptr; return *this; } iterator operator++(int) { iterator copy = *this; ++Ptr; return copy; } friend bool operator==(iterator lhs, iterator rhs) { return lhs.Ptr == rhs.Ptr; } friend bool operator!=(iterator lhs, iterator rhs) { return lhs.Ptr != rhs.Ptr; } }; iterator begin() const { return iterator(Operands.begin()); } iterator end() const { return iterator(Operands.end()); } size_t size() const { return Operands.size(); } bool empty() const { return Operands.empty(); } SILValue front() const { return Operands.front().get(); } SILValue back() const { return Operands.back().get(); } SILValue operator[](unsigned i) const { return Operands[i].get(); } OperandValueArrayRef slice(unsigned begin, unsigned length) const { return OperandValueArrayRef(Operands.slice(begin, length)); } OperandValueArrayRef slice(unsigned begin) const { return OperandValueArrayRef(Operands.slice(begin)); } OperandValueArrayRef drop_back() const { return OperandValueArrayRef(Operands.drop_back()); } bool operator==(const OperandValueArrayRef RHS) const { if (size() != RHS.size()) return false; for (auto L = begin(), LE = end(), R = RHS.begin(); L != LE; ++L, ++R) if (*L != *R) return false; return true; } bool operator!=(const OperandValueArrayRef RHS) const { return !(*this == RHS); } }; /// An iterator over all uses of a ValueBase. class ValueBaseUseIterator : public std::iterator { Operand *Cur; public: ValueBaseUseIterator() = default; explicit ValueBaseUseIterator(Operand *cur) : Cur(cur) {} Operand *operator->() const { return Cur; } Operand *operator*() const { return Cur; } SILInstruction *getUser() const { return Cur->getUser(); } ValueBaseUseIterator &operator++() { assert(Cur && "incrementing past end()!"); Cur = Cur->NextUse; return *this; } ValueBaseUseIterator operator++(int unused) { ValueBaseUseIterator copy = *this; ++*this; return copy; } friend bool operator==(ValueBaseUseIterator lhs, ValueBaseUseIterator rhs) { return lhs.Cur == rhs.Cur; } friend bool operator!=(ValueBaseUseIterator lhs, ValueBaseUseIterator rhs) { return !(lhs == rhs); } }; inline ValueBase::use_iterator ValueBase::use_begin() const { return ValueBase::use_iterator(FirstUse); } inline ValueBase::use_iterator ValueBase::use_end() const { return ValueBase::use_iterator(nullptr); } inline iterator_range ValueBase::getUses() const { return { use_begin(), use_end() }; } inline bool ValueBase::hasOneUse() const { auto I = use_begin(), E = use_end(); if (I == E) return false; return ++I == E; } inline Operand *ValueBase::getSingleUse() const { auto I = use_begin(), E = use_end(); // If we have no elements, return nullptr. if (I == E) return nullptr; // Otherwise, grab the first element and then increment. Operand *Op = *I; ++I; // If the next element is not the end list, then return nullptr. We do not // have one user. if (I != E) return nullptr; // Otherwise, the element that we accessed. return Op; } template inline T *ValueBase::getSingleUserOfType() { T *Result = nullptr; for (auto *Op : getUses()) { if (auto *Tmp = dyn_cast(Op->getUser())) { if (Result) return nullptr; Result = Tmp; } } return Result; } /// A constant-size list of the operands of an instruction. template class FixedOperandList { Operand Buffer[N]; FixedOperandList(const FixedOperandList &) = delete; FixedOperandList &operator=(const FixedOperandList &) = delete; public: template FixedOperandList(SILInstruction *user, T&&...args) : Buffer{ { user, std::forward(args) }... } { static_assert(sizeof...(args) == N, "wrong number of initializers"); } /// Returns the full list of operands. MutableArrayRef asArray() { return MutableArrayRef(Buffer, N); } ArrayRef asArray() const { return ArrayRef(Buffer, N); } /// Returns the full list of operand values. OperandValueArrayRef asValueArray() const { return OperandValueArrayRef(asArray()); } /// Indexes into the full list of operands. Operand &operator[](unsigned i) { return asArray()[i]; } const Operand &operator[](unsigned i) const { return asArray()[i]; } }; /// An operator list with a fixed number of known operands /// (possibly zero) and a dynamically-determined set of extra /// operands (also possibly zero). The number of dynamic operands /// is permanently set at initialization time. /// /// 'N' is the number of static operands. /// /// This class assumes that a number of bytes of extra storage have /// been allocated immediately after it. This means that this class /// must always be the final data member in a class. template class TailAllocatedOperandList { unsigned NumExtra; Operand Buffer[N]; TailAllocatedOperandList(const TailAllocatedOperandList &) = delete; TailAllocatedOperandList &operator=(const TailAllocatedOperandList &) =delete; public: /// Given the number of dynamic operands required, returns the /// number of bytes of extra storage to allocate. static size_t getExtraSize(unsigned numExtra) { return sizeof(Operand) * numExtra; } /// Initialize this operand list. /// /// The dynamic operands are actually out of order: logically they /// will placed after the fixed operands, not before them. But /// the variadic arguments have to come last. template TailAllocatedOperandList(SILInstruction *user, ArrayRef dynamicArgs, T&&... fixedArgs) : NumExtra(dynamicArgs.size()), Buffer{ { user, std::forward(fixedArgs) }... } { static_assert(sizeof...(fixedArgs) == N, "wrong number of initializers"); Operand *dynamicSlot = Buffer + N; for (auto value : dynamicArgs) { new (dynamicSlot++) Operand(user, value); } } /// Initialize this operand list. /// /// The dynamic operands are actually out of order: logically they /// will placed after the fixed operands, not before them. But /// the variadic arguments have to come last. template TailAllocatedOperandList(SILInstruction *user, ArrayRef dynamicArgs, ArrayRef additionalDynamicArgs, T&&... fixedArgs) : NumExtra(dynamicArgs.size() + additionalDynamicArgs.size()), Buffer{ { user, std::forward(fixedArgs) }... } { static_assert(sizeof...(fixedArgs) == N, "wrong number of initializers"); Operand *dynamicSlot = Buffer + N; for (auto value : dynamicArgs) { new (dynamicSlot++) Operand(user, value); } for (auto value : additionalDynamicArgs) { new (dynamicSlot++) Operand(user, value); } } ~TailAllocatedOperandList() { for (auto &op : getDynamicAsArray()) { op.~Operand(); } } /// Returns the full list of operands. MutableArrayRef asArray() { return MutableArrayRef(Buffer, N+NumExtra); } ArrayRef asArray() const { return ArrayRef(Buffer, N+NumExtra); } /// Returns the full list of operand values. OperandValueArrayRef asValueArray() const { return OperandValueArrayRef(asArray()); } /// Returns the list of the dynamic operands. MutableArrayRef getDynamicAsArray() { return MutableArrayRef(Buffer+N, NumExtra); } ArrayRef getDynamicAsArray() const { return ArrayRef(Buffer+N, NumExtra); } /// Returns the list of the dynamic operand values. OperandValueArrayRef getDynamicValuesAsArray() const { return OperandValueArrayRef(getDynamicAsArray()); } unsigned size() const { return N+NumExtra; } /// Indexes into the full list of operands. Operand &operator[](unsigned i) { return asArray()[i]; } const Operand &operator[](unsigned i) const { return asArray()[i]; } }; /// A specialization of TailAllocatedOperandList for zero static operands. template<> class TailAllocatedOperandList<0> { unsigned NumExtra; union { // suppress value semantics Operand Buffer[1]; }; TailAllocatedOperandList(const TailAllocatedOperandList &) = delete; TailAllocatedOperandList &operator=(const TailAllocatedOperandList &) =delete; public: static size_t getExtraSize(unsigned numExtra) { return sizeof(Operand) * (numExtra > 0 ? numExtra - 1 : 0); } TailAllocatedOperandList(SILInstruction *user, ArrayRef dynamicArgs) : NumExtra(dynamicArgs.size()) { Operand *dynamicSlot = Buffer; for (auto value : dynamicArgs) { new (dynamicSlot++) Operand(user, value); } } ~TailAllocatedOperandList() { for (auto &op : getDynamicAsArray()) { op.~Operand(); } } /// Returns the full list of operands. MutableArrayRef asArray() { return MutableArrayRef(Buffer, NumExtra); } ArrayRef asArray() const { return ArrayRef(Buffer, NumExtra); } /// Returns the full list of operand values. OperandValueArrayRef asValueArray() const { return OperandValueArrayRef(asArray()); } /// Returns the list of the dynamic operands. MutableArrayRef getDynamicAsArray() { return MutableArrayRef(Buffer, NumExtra); } ArrayRef getDynamicAsArray() const { return ArrayRef(Buffer, NumExtra); } /// Returns the list of the dynamic operand values. OperandValueArrayRef getDynamicValuesAsArray() const { return OperandValueArrayRef(getDynamicAsArray()); } unsigned size() const { return NumExtra; } /// Indexes into the full list of operands. Operand &operator[](unsigned i) { return asArray()[i]; } const Operand &operator[](unsigned i) const { return asArray()[i]; } }; /// A helper class for initializing the list of trailing operands. class TrailingOperandsList { public: static void InitOperandsList(Operand *p, SILInstruction *user, SILValue operand, ArrayRef operands) { assert(p && "Trying to initialize operands using a nullptr"); new (p++) Operand(user, operand); for (auto op : operands) { new (p++) Operand(user, op); } } static void InitOperandsList(Operand *p, SILInstruction *user, SILValue operand0, SILValue operand1, ArrayRef operands) { assert(p && "Trying to initialize operands using a nullptr"); new (p++) Operand(user, operand0); new (p++) Operand(user, operand1); for (auto op : operands) { new (p++) Operand(user, op); } } static void InitOperandsList(Operand *p, SILInstruction *user, ArrayRef operands) { assert(p && "Trying to initialize operands using a nullptr"); for (auto op : operands) { new (p++) Operand(user, op); } } }; /// SILValue hashes just like a pointer. static inline llvm::hash_code hash_value(SILValue V) { return llvm::hash_value((ValueBase *)V); } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SILValue V) { V->print(OS); return OS; } } // end namespace swift namespace llvm { /// A SILValue casts like a ValueBase *. template<> struct simplify_type { typedef ::swift::ValueBase *SimpleType; static SimpleType getSimplifiedValue(::swift::SILValue Val) { return Val; } }; template<> struct simplify_type< ::swift::SILValue> : public simplify_type {}; // Values hash just like pointers. template<> struct DenseMapInfo { static swift::SILValue getEmptyKey() { return swift::SILValue::getFromOpaqueValue( llvm::DenseMapInfo::getEmptyKey()); } static swift::SILValue getTombstoneKey() { return swift::SILValue::getFromOpaqueValue( llvm::DenseMapInfo::getTombstoneKey()); } static unsigned getHashValue(swift::SILValue V) { return DenseMapInfo::getHashValue(V); } static bool isEqual(swift::SILValue LHS, swift::SILValue RHS) { return LHS == RHS; } }; /// SILValue is a PointerLikeType. template<> struct PointerLikeTypeTraits<::swift::SILValue> { using SILValue = ::swift::SILValue; public: static void *getAsVoidPointer(SILValue v) { return v.getOpaqueValue(); } static SILValue getFromVoidPointer(void *p) { return SILValue::getFromOpaqueValue(p); } enum { NumLowBitsAvailable = swift::SILValue::NumLowBitsAvailable }; }; } // end namespace llvm #endif