//===- UseDefLists.h --------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines generic use/def list machinery and manipulation utilities. // //===----------------------------------------------------------------------===// #ifndef MLIR_IR_USEDEFLISTS_H #define MLIR_IR_USEDEFLISTS_H #include "mlir/IR/Location.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/iterator_range.h" namespace mlir { class Operation; template class ValueUseIterator; template class ValueUserIterator; //===----------------------------------------------------------------------===// // IROperand //===----------------------------------------------------------------------===// namespace detail { /// This class is the base for IROperand, and provides all of the non-templated /// facilities for operand use management. class IROperandBase { public: /// Return the owner of this operand. Operation *getOwner() const { return owner; } /// Return the next operand on the use-list of the value we are referring to. /// This should generally only be used by the internal implementation details /// of the SSA machinery. IROperandBase *getNextOperandUsingThisValue() { return nextUse; } /// Initialize the use-def chain by setting the back address to self and /// nextUse to nullptr. void initChainWithUse(IROperandBase **self) { assert(this == *self); back = self; nextUse = nullptr; } /// Link the current node to next. void linkTo(IROperandBase *next) { nextUse = next; if (nextUse) nextUse->back = &nextUse; } protected: IROperandBase(Operation *owner) : owner(owner) {} IROperandBase(IROperandBase &&other) : owner(other.owner) { *this = std::move(other); } IROperandBase &operator=(IROperandBase &&other) { removeFromCurrent(); other.removeFromCurrent(); other.back = nullptr; nextUse = nullptr; back = nullptr; return *this; } /// Operands are not copyable or assignable. IROperandBase(const IROperandBase &use) = delete; IROperandBase &operator=(const IROperandBase &use) = delete; ~IROperandBase() { removeFromCurrent(); } /// Remove this use of the operand. void drop() { removeFromCurrent(); nextUse = nullptr; back = nullptr; } /// Remove this operand from the current use list. void removeFromCurrent() { if (!back) return; *back = nextUse; if (nextUse) nextUse->back = back; } /// Insert this operand into the given use list. template void insertInto(UseListT *useList) { back = &useList->firstUse; nextUse = useList->firstUse; if (nextUse) nextUse->back = &nextUse; useList->firstUse = this; } /// The next operand in the use-chain. IROperandBase *nextUse = nullptr; /// This points to the previous link in the use-chain. IROperandBase **back = nullptr; private: /// The operation owner of this operand. Operation *const owner; }; } // namespace detail //===----------------------------------------------------------------------===// // IROperand //===----------------------------------------------------------------------===// /// A reference to a value, suitable for use as an operand of an operation. /// IRValueT is the root type to use for values this tracks. Derived operand /// types are expected to provide the following: /// * static IRObjectWithUseList *getUseList(IRValueT value); /// - Provide the use list that is attached to the given value. template class IROperand : public detail::IROperandBase { public: IROperand(Operation *owner) : detail::IROperandBase(owner) {} IROperand(Operation *owner, IRValueT value) : detail::IROperandBase(owner), value(value) { insertIntoCurrent(); } /// We support a move constructor so IROperand's can be in vectors, but this /// shouldn't be used by general clients. IROperand(IROperand &&other) : detail::IROperandBase(std::move(other)) { *this = std::move(other); } IROperand &operator=(IROperand &&other) { detail::IROperandBase::operator=(std::move(other)); value = other.value; other.value = nullptr; if (value) insertIntoCurrent(); return *this; } /// Two operands are equal if they have the same owner and the same operand /// number. They are stored inside of ops, so it is valid to compare their /// pointers to determine equality. bool operator==(const IROperand &other) const { return this == &other; } bool operator!=(const IROperand &other) const { return !(*this == other); } /// Return the current value being used by this operand. IRValueT get() const { return value; } /// Set the current value being used by this operand. void set(IRValueT newValue) { // It isn't worth optimizing for the case of switching operands on a single // value. removeFromCurrent(); value = newValue; insertIntoCurrent(); } /// Returns true if this operand contains the given value. bool is(IRValueT other) const { return value == other; } /// \brief Remove this use of the operand. void drop() { detail::IROperandBase::drop(); value = nullptr; } private: /// The value used as this operand. This can be null when in a 'dropAllUses' /// state. IRValueT value = {}; /// Insert this operand into the given use list. void insertIntoCurrent() { insertInto(DerivedT::getUseList(value)); } }; //===----------------------------------------------------------------------===// // IRObjectWithUseList //===----------------------------------------------------------------------===// /// This class represents a single IR object that contains a use list. template class IRObjectWithUseList { public: ~IRObjectWithUseList() { assert(use_empty() && "Cannot destroy a value that still has uses!"); } /// Drop all uses of this object from their respective owners. void dropAllUses() { while (!use_empty()) use_begin()->drop(); } /// Replace all uses of 'this' value with the new value, updating anything in /// the IR that uses 'this' to use the other value instead. When this returns /// there are zero uses of 'this'. template void replaceAllUsesWith(ValueT &&newValue) { assert((!newValue || this != OperandType::getUseList(newValue)) && "cannot RAUW a value with itself"); while (!use_empty()) use_begin()->set(newValue); } /// Shuffle the use-list chain according to the provided indices vector, which /// need to represent a valid shuffle. That is, a vector of unique integers in /// range [0, numUses - 1]. Users of this function need to guarantee the /// validity of the indices vector. void shuffleUseList(ArrayRef indices) { assert((size_t)std::distance(getUses().begin(), getUses().end()) == indices.size() && "indices vector expected to have a number of elements equal to the " "number of uses"); SmallVector shuffled(indices.size()); detail::IROperandBase *ptr = firstUse; for (size_t idx = 0; idx < indices.size(); idx++, ptr = ptr->getNextOperandUsingThisValue()) shuffled[indices[idx]] = ptr; initFirstUse(shuffled.front()); auto *current = firstUse; for (auto &next : llvm::drop_begin(shuffled)) { current->linkTo(next); current = next; } current->linkTo(nullptr); } //===--------------------------------------------------------------------===// // Uses //===--------------------------------------------------------------------===// using use_iterator = ValueUseIterator; using use_range = iterator_range; use_iterator use_begin() const { return use_iterator(firstUse); } use_iterator use_end() const { return use_iterator(nullptr); } /// Returns a range of all uses, which is useful for iterating over all uses. use_range getUses() const { return {use_begin(), use_end()}; } /// Returns true if this value has exactly one use. bool hasOneUse() const { return firstUse && firstUse->getNextOperandUsingThisValue() == nullptr; } /// Returns true if this value has no uses. bool use_empty() const { return firstUse == nullptr; } //===--------------------------------------------------------------------===// // Users //===--------------------------------------------------------------------===// using user_iterator = ValueUserIterator; using user_range = iterator_range; user_iterator user_begin() const { return user_iterator(use_begin()); } user_iterator user_end() const { return user_iterator(use_end()); } /// Returns a range of all users. user_range getUsers() const { return {user_begin(), user_end()}; } protected: IRObjectWithUseList() = default; /// Return the first operand that is using this value, for use by custom /// use/def iterators. OperandType *getFirstUse() const { return (OperandType *)firstUse; } private: /// Set use as the first use of the chain. void initFirstUse(detail::IROperandBase *use) { firstUse = use; firstUse->initChainWithUse(&firstUse); } detail::IROperandBase *firstUse = nullptr; /// Allow access to `firstUse`. friend detail::IROperandBase; }; //===----------------------------------------------------------------------===// // ValueUseIterator //===----------------------------------------------------------------------===// /// An iterator class that allows for iterating over the uses of an IR operand /// type. template class ValueUseIterator : public llvm::iterator_facade_base, std::forward_iterator_tag, OperandType> { public: ValueUseIterator(detail::IROperandBase *use = nullptr) : current(use) {} /// Returns the operation that owns this use. Operation *getUser() const { return current->getOwner(); } /// Returns the current operands. OperandType *getOperand() const { return (OperandType *)current; } OperandType &operator*() const { return *getOperand(); } using llvm::iterator_facade_base, std::forward_iterator_tag, OperandType>::operator++; ValueUseIterator &operator++() { assert(current && "incrementing past end()!"); current = (OperandType *)current->getNextOperandUsingThisValue(); return *this; } bool operator==(const ValueUseIterator &rhs) const { return current == rhs.current; } protected: detail::IROperandBase *current; }; //===----------------------------------------------------------------------===// // ValueUserIterator //===----------------------------------------------------------------------===// /// An iterator over the users of an IRObject. This is a wrapper iterator around /// a specific use iterator. template class ValueUserIterator final : public llvm::mapped_iterator_base< ValueUserIterator, UseIteratorT, Operation *> { public: using llvm::mapped_iterator_base, UseIteratorT, Operation *>::mapped_iterator_base; /// Map the element to the iterator result type. Operation *mapElement(OperandType &value) const { return value.getOwner(); } /// Provide access to the underlying operation. Operation *operator->() { return **this; } }; } // namespace mlir #endif