blob: 845e403edcfbb38455d690aeb0b233bfa87e703d [file] [log] [blame]
//===- 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 <typename OperandType> class ValueUseIterator;
template <typename OperandType> class FilteredValueUseIterator;
template <typename UseIteratorT, typename OperandType> 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; }
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 <typename UseListT> 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 <typename DerivedT, typename IRValueT>
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;
}
/// 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 <typename OperandType> 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 <typename ValueT>
void replaceAllUsesWith(ValueT &&newValue) {
assert((!newValue || this != OperandType::getUseList(newValue)) &&
"cannot RAUW a value with itself");
while (!use_empty())
use_begin()->set(newValue);
}
//===--------------------------------------------------------------------===//
// Uses
//===--------------------------------------------------------------------===//
using use_iterator = ValueUseIterator<OperandType>;
using use_range = iterator_range<use_iterator>;
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<use_iterator, OperandType>;
using user_range = iterator_range<user_iterator>;
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:
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 <typename OperandType>
class ValueUseIterator
: public llvm::iterator_facade_base<ValueUseIterator<OperandType>,
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<ValueUseIterator<OperandType>,
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 <typename UseIteratorT, typename OperandType>
class ValueUserIterator final
: public llvm::mapped_iterator_base<
ValueUserIterator<UseIteratorT, OperandType>, UseIteratorT,
Operation *> {
public:
using llvm::mapped_iterator_base<ValueUserIterator<UseIteratorT, OperandType>,
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