//===--- SILValue.h - Value base class for SIL ------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the SILValue class. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_SILVALUE_H #define SWIFT_SIL_SILVALUE_H #include "swift/Basic/Range.h" #include "swift/SIL/SILType.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/raw_ostream.h" namespace swift { class SILTypeList; class Operand; class SILValue; class ValueBaseUseIterator; class ValueUseIterator; class SILInstruction; enum class ValueKind { #define VALUE(Id, Parent) Id, #define VALUE_RANGE(Id, FirstId, LastId) \ First_##Id = FirstId, Last_##Id = LastId, #include "swift/SIL/SILNodes.def" }; /// ValueBase - This is the base class of the SIL value hierarchy, which /// represents a runtime computed value. Things like SILInstruction derive /// from this. class alignas(8) ValueBase : public SILAllocated { PointerUnion TypeOrTypeList; Operand *FirstUse = nullptr; friend class Operand; friend class SILValue; const ValueKind Kind; ValueBase(const ValueBase &) = delete; ValueBase &operator=(const ValueBase &) = delete; protected: ValueBase(ValueKind Kind, SILTypeList *TypeList = 0) : TypeOrTypeList(TypeList), Kind(Kind) {} ValueBase(ValueKind Kind, SILType Ty) : TypeOrTypeList(Ty), Kind(Kind) {} public: ~ValueBase() { assert(use_empty() && "Cannot destroy a value that still has uses!"); } ValueKind getKind() const { return Kind; } ArrayRef getTypes() const; /// True if the "value" is actually a value that can be used by other /// instructions. bool hasValue() const { return !TypeOrTypeList.isNull(); } SILType getType(unsigned i) const { if (TypeOrTypeList.is()) { assert(i == 0); return TypeOrTypeList.get(); } return getTypes()[i]; } unsigned getNumTypes() const { if (TypeOrTypeList.isNull()) return 0; if (TypeOrTypeList.is()) return 1; return getTypes().size(); } /// 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); bool use_empty() const { return FirstUse == nullptr; } inline ValueBaseUseIterator use_begin(); inline ValueBaseUseIterator use_end(); inline Range getUses(); inline bool hasOneUse(); /// 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 ValueBase *V) { return true; } }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ValueBase &V) { V.print(OS); return OS; } } // end namespace swift namespace llvm { // ValueBase* is always at least eight-byte aligned; make the three tag bits // available through PointerLikeTypeTraits. template<> class 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 { enum { /// The number of bits required to store a ResultNumber. /// This is primarily here as a way to allow everything that /// depends on it to be easily grepped. ValueResultNumberBits = 2 }; /// SILValue - A SILValue is a use of a specific result of an ValueBase. As /// such, it is a pair of the ValueBase and the result number being referenced. class SILValue { llvm::PointerIntPair ValueAndResultNumber; explicit SILValue(void *p) { ValueAndResultNumber = decltype(ValueAndResultNumber)::getFromOpaqueValue(p); } public: SILValue(const ValueBase *V = 0, unsigned ResultNumber = 0) : ValueAndResultNumber((ValueBase*)V, ResultNumber) { assert(ResultNumber == getResultNumber() && "Overflow"); } ValueBase *getDef() const { return ValueAndResultNumber.getPointer(); } ValueBase *operator->() const { return getDef(); } ValueBase &operator*() const { return *getDef(); } unsigned getResultNumber() const { return ValueAndResultNumber.getInt(); } SILType getType() const { return getDef()->getType(getResultNumber()); } // Comparison. bool operator==(SILValue RHS) const { return ValueAndResultNumber == RHS.ValueAndResultNumber; } bool operator!=(SILValue RHS) const { return !(*this == RHS); } // Ordering (for std::map). bool operator<(SILValue RHS) const { return ValueAndResultNumber.getOpaqueValue() < RHS.ValueAndResultNumber.getOpaqueValue(); } inline bool use_empty() const; inline ValueUseIterator use_begin(); inline ValueUseIterator use_end(); inline Range getUses(); inline bool hasOneUse(); // Return the underlying SILValue after stripping off all casts from the // current SILValue. SILValue stripCasts(); // Return the underlying SILValue after stripping off all casts and // address projection instructions. // // An address projection instruction is one of one of ref_element_addr, // struct_element_addr, tuple_element_addr. SILValue stripAddressProjections(); // Return the underlying SILValue after stripping off all aggregate projection // instructions. // // An aggregate projection instruction is either a struct_extract or a // tuple_extract instruction. SILValue stripAggregateProjections(); // Return the underlying SILValue after stripping off all indexing // instructions. // // An indexing inst is either index_addr or index_raw_pointer. SILValue stripIndexingInsts(); void replaceAllUsesWith(SILValue V); void dump() const; void print(raw_ostream &os) const; // Check validity. bool isValid() const { return getDef() != nullptr; } explicit operator bool() const { return getDef() != nullptr; } // Use as a pointer-like type. void *getOpaqueValue() const { return ValueAndResultNumber.getOpaqueValue(); } static SILValue getFromOpaqueValue(void *p) { return SILValue(p); } enum { NumLowBitsAvailable = llvm::PointerLikeTypeTraits:: NumLowBitsAvailable }; }; /// 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; Operand(SILInstruction *owner) : Owner(owner) {} Operand(SILInstruction *owner, SILValue theValue) : TheValue(theValue), Owner(owner) { insertIntoCurrent(); } template friend class FixedOperandList; template friend class TailAllocatedOperandList; public: // 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(); assert(cast(Owner) != newValue.getDef() && "Cannot add a value as an operand of the instruction that defines it!"); 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; }; /// 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 { const Operand *Ptr; public: 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)); } }; /// 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 ValueBaseUseIterator ValueBase::use_begin() { return ValueBaseUseIterator(FirstUse); } inline ValueBaseUseIterator ValueBase::use_end() { return ValueBaseUseIterator(nullptr); } inline Range ValueBase::getUses() { return { use_begin(), use_end() }; } inline bool ValueBase::hasOneUse() { auto I = use_begin(), E = use_end(); if (I == E) return false; return ++I == E; } /// An iterator over all uses of a specific result of a ValueBase. class ValueUseIterator : public std::iterator { llvm::PointerIntPair CurAndResultNumber; public: ValueUseIterator() = default; explicit ValueUseIterator(Operand *cur, unsigned resultNumber) { // Skip past uses with different result numbers. while (cur && cur->get().getResultNumber() != resultNumber) cur = cur->NextUse; CurAndResultNumber.setPointerAndInt(cur, resultNumber); } Operand *operator*() const { return CurAndResultNumber.getPointer(); } Operand *operator->() const { return operator*(); } SILInstruction *getUser() const { return CurAndResultNumber.getPointer()->getUser(); } ValueUseIterator &operator++() { Operand *next = CurAndResultNumber.getPointer(); assert(next && "incrementing past end()!"); // Skip past uses with different result numbers. while ((next = next->NextUse)) { if (next->get().getResultNumber() == CurAndResultNumber.getInt()) break; } CurAndResultNumber.setPointer(next); return *this; } ValueUseIterator operator++(int unused) { ValueUseIterator copy = *this; ++*this; return copy; } friend bool operator==(ValueUseIterator lhs, ValueUseIterator rhs) { return lhs.CurAndResultNumber.getPointer() == rhs.CurAndResultNumber.getPointer(); } friend bool operator!=(ValueUseIterator lhs, ValueUseIterator rhs) { return !(lhs == rhs); } }; inline ValueUseIterator SILValue::use_begin() { return ValueUseIterator((*this)->FirstUse, getResultNumber()); } inline ValueUseIterator SILValue::use_end() { return ValueUseIterator(nullptr, 0); } inline Range SILValue::getUses() { return { use_begin(), use_end() }; } inline bool SILValue::use_empty() const { SILValue *mthis = const_cast(this); return mthis->use_begin() == mthis->use_end(); } inline bool SILValue::hasOneUse() { auto I = use_begin(), E = use_end(); if (I == E) return false; return ++I == E; } /// 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); } } ~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]; } }; /// SILValue hashes just like a pointer. static inline llvm::hash_code hash_value(SILValue V) { return llvm::hash_value(V.getDef()); } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SILValue V) { OS << "(" << V.getResultNumber() << "): "; 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.getDef(); } }; 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) { auto ResultNumHash = DenseMapInfo::getHashValue(V.getResultNumber()); auto ValueBaseHash = DenseMapInfo::getHashValue(V.getDef()); return hash_combine(ResultNumHash, ValueBaseHash); } static bool isEqual(swift::SILValue LHS, swift::SILValue RHS) { return LHS == RHS; } }; // SILValue is a PointerLikeType. template<> class 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