mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-21 03:53:04 +02:00
4e09f9bf86
Reverse iterators to doubly-linked lists can be simpler (and cheaper) than std::reverse_iterator. Make it so. In particular, change ilist<T>::reverse_iterator so that it is *never* invalidated unless the node it references is deleted. This matches the guarantees of ilist<T>::iterator. (Note: MachineBasicBlock::iterator is *not* an ilist iterator, but a MachineInstrBundleIterator<MachineInstr>. This commit does not change MachineBasicBlock::reverse_iterator, but it does update MachineBasicBlock::reverse_instr_iterator. See note at end of commit message for details on bundle iterators.) Given the list (with the Sentinel showing twice for simplicity): [Sentinel] <-> A <-> B <-> [Sentinel] the following is now true: 1. begin() represents A. 2. begin() holds the pointer for A. 3. end() represents [Sentinel]. 4. end() holds the poitner for [Sentinel]. 5. rbegin() represents B. 6. rbegin() holds the pointer for B. 7. rend() represents [Sentinel]. 8. rend() holds the pointer for [Sentinel]. The changes are #6 and #8. Here are some properties from the old scheme (which used std::reverse_iterator): - rbegin() held the pointer for [Sentinel] and rend() held the pointer for A; - operator*() cost two dereferences instead of one; - converting from a valid iterator to its valid reverse_iterator involved a confusing increment; and - "RI++->erase()" left RI invalid. The unintuitive replacement was "RI->erase(), RE = end()". With vector-like data structures these properties are hard to avoid (since past-the-beginning is not a valid pointer), and don't impose a real cost (since there's still only one dereference, and all iterators are invalidated on erase). But with lists, this was a poor design. Specifically, the following code (which obviously works with normal iterators) now works with ilist::reverse_iterator as well: for (auto RI = L.rbegin(), RE = L.rend(); RI != RE;) fooThatMightRemoveArgFromList(*RI++); Converting between iterator and reverse_iterator for the same node uses the getReverse() function. reverse_iterator iterator::getReverse(); iterator reverse_iterator::getReverse(); Why doesn't iterator <=> reverse_iterator conversion use constructors? In order to catch and update old code, reverse_iterator does not even have an explicit conversion from iterator. It wouldn't be safe because there would be no reasonable way to catch all the bugs from the changed semantic (see the changes at call sites that are part of this patch). Old code used this API: std::reverse_iterator::reverse_iterator(iterator); iterator std::reverse_iterator::base(); Here's how to update from old code to new (that incorporates the semantic change), assuming I is an ilist<>::iterator and RI is an ilist<>::reverse_iterator: [Old] ==> [New] reverse_iterator(I) (--I).getReverse() reverse_iterator(I) ++I.getReverse() --reverse_iterator(I) I.getReverse() reverse_iterator(++I) I.getReverse() RI.base() (--RI).getReverse() RI.base() ++RI.getReverse() --RI.base() RI.getReverse() (++RI).base() RI.getReverse() delete &*RI, RE = end() delete &*RI++ RI->erase(), RE = end() RI++->erase() ======================================= Note: bundle iterators are out of scope ======================================= MachineBasicBlock::iterator, also known as MachineInstrBundleIterator<MachineInstr>, is a wrapper to represent MachineInstr bundles. The idea is that each operator++ takes you to the beginning of the next bundle. Implementing a sane reverse iterator for this is harder than ilist. Here are the options: - Use std::reverse_iterator<MBB::i>. Store a handle to the beginning of the next bundle. A call to operator*() runs a loop (usually operator--() will be called 1 time, for unbundled instructions). Increment/decrement just works. This is the status quo. - Store a handle to the final node in the bundle. A call to operator*() still runs a loop, but it iterates one time fewer (usually operator--() will be called 0 times, for unbundled instructions). Increment/decrement just works. - Make the ilist_sentinel<MachineInstr> *always* store that it's the sentinel (instead of just in asserts mode). Then the bundle iterator can sniff the sentinel bit in operator++(). I initially tried implementing the end() option as part of this commit, but updating iterator/reverse_iterator conversion call sites was error-prone. I have a WIP series of patches that implements the final option. llvm-svn: 280032
164 lines
5.0 KiB
C++
164 lines
5.0 KiB
C++
//==-- llvm/ADT/ilist_node.h - Intrusive Linked List Helper ------*- C++ -*-==//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the ilist_node class template, which is a convenient
|
|
// base class for creating classes that can be used with ilists.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_ADT_ILIST_NODE_H
|
|
#define LLVM_ADT_ILIST_NODE_H
|
|
|
|
#include "llvm/ADT/PointerIntPair.h"
|
|
|
|
namespace llvm {
|
|
|
|
template<typename NodeTy>
|
|
struct ilist_traits;
|
|
|
|
/// Base class for ilist nodes.
|
|
class ilist_node_base {
|
|
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
|
|
PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
|
|
#else
|
|
ilist_node_base *Prev = nullptr;
|
|
#endif
|
|
ilist_node_base *Next = nullptr;
|
|
|
|
public:
|
|
#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
|
|
void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
|
|
ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
|
|
|
|
bool isKnownSentinel() const { return PrevAndSentinel.getInt(); }
|
|
void initializeSentinel() { PrevAndSentinel.setInt(true); }
|
|
#else
|
|
void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
|
|
ilist_node_base *getPrev() const { return Prev; }
|
|
|
|
bool isKnownSentinel() const { return false; }
|
|
void initializeSentinel() {}
|
|
#endif
|
|
|
|
void setNext(ilist_node_base *Next) { this->Next = Next; }
|
|
ilist_node_base *getNext() const { return Next; }
|
|
};
|
|
|
|
struct ilist_node_access;
|
|
template <typename NodeTy, bool IsReverse = false> class ilist_iterator;
|
|
template <typename NodeTy> class ilist_sentinel;
|
|
|
|
/// Templated wrapper class.
|
|
template <typename NodeTy> class ilist_node : ilist_node_base {
|
|
friend class ilist_base;
|
|
friend struct ilist_node_access;
|
|
friend struct ilist_traits<NodeTy>;
|
|
friend class ilist_iterator<NodeTy, false>;
|
|
friend class ilist_iterator<NodeTy, true>;
|
|
friend class ilist_sentinel<NodeTy>;
|
|
|
|
protected:
|
|
ilist_node() = default;
|
|
|
|
private:
|
|
ilist_node *getPrev() {
|
|
return static_cast<ilist_node *>(ilist_node_base::getPrev());
|
|
}
|
|
ilist_node *getNext() {
|
|
return static_cast<ilist_node *>(ilist_node_base::getNext());
|
|
}
|
|
|
|
const ilist_node *getPrev() const {
|
|
return static_cast<ilist_node *>(ilist_node_base::getPrev());
|
|
}
|
|
const ilist_node *getNext() const {
|
|
return static_cast<ilist_node *>(ilist_node_base::getNext());
|
|
}
|
|
|
|
void setPrev(ilist_node *N) { ilist_node_base::setPrev(N); }
|
|
void setNext(ilist_node *N) { ilist_node_base::setNext(N); }
|
|
|
|
public:
|
|
ilist_iterator<NodeTy> getIterator() { return ilist_iterator<NodeTy>(*this); }
|
|
ilist_iterator<const NodeTy> getIterator() const {
|
|
return ilist_iterator<const NodeTy>(*this);
|
|
}
|
|
|
|
using ilist_node_base::isKnownSentinel;
|
|
};
|
|
|
|
template <typename NodeTy> class ilist_sentinel : public ilist_node<NodeTy> {
|
|
public:
|
|
ilist_sentinel() {
|
|
ilist_node_base::initializeSentinel();
|
|
reset();
|
|
}
|
|
|
|
void reset() {
|
|
this->setPrev(this);
|
|
this->setNext(this);
|
|
}
|
|
|
|
bool empty() const { return this == this->getPrev(); }
|
|
};
|
|
|
|
/// An ilist node that can access its parent list.
|
|
///
|
|
/// Requires \c NodeTy to have \a getParent() to find the parent node, and the
|
|
/// \c ParentTy to have \a getSublistAccess() to get a reference to the list.
|
|
template <typename NodeTy, typename ParentTy>
|
|
class ilist_node_with_parent : public ilist_node<NodeTy> {
|
|
protected:
|
|
ilist_node_with_parent() = default;
|
|
|
|
private:
|
|
/// Forward to NodeTy::getParent().
|
|
///
|
|
/// Note: do not use the name "getParent()". We want a compile error
|
|
/// (instead of recursion) when the subclass fails to implement \a
|
|
/// getParent().
|
|
const ParentTy *getNodeParent() const {
|
|
return static_cast<const NodeTy *>(this)->getParent();
|
|
}
|
|
|
|
public:
|
|
/// @name Adjacent Node Accessors
|
|
/// @{
|
|
/// \brief Get the previous node, or \c nullptr for the list head.
|
|
NodeTy *getPrevNode() {
|
|
// Should be separated to a reused function, but then we couldn't use auto
|
|
// (and would need the type of the list).
|
|
const auto &List =
|
|
getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
|
|
return List.getPrevNode(*static_cast<NodeTy *>(this));
|
|
}
|
|
/// \brief Get the previous node, or \c nullptr for the list head.
|
|
const NodeTy *getPrevNode() const {
|
|
return const_cast<ilist_node_with_parent *>(this)->getPrevNode();
|
|
}
|
|
|
|
/// \brief Get the next node, or \c nullptr for the list tail.
|
|
NodeTy *getNextNode() {
|
|
// Should be separated to a reused function, but then we couldn't use auto
|
|
// (and would need the type of the list).
|
|
const auto &List =
|
|
getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr));
|
|
return List.getNextNode(*static_cast<NodeTy *>(this));
|
|
}
|
|
/// \brief Get the next node, or \c nullptr for the list tail.
|
|
const NodeTy *getNextNode() const {
|
|
return const_cast<ilist_node_with_parent *>(this)->getNextNode();
|
|
}
|
|
/// @}
|
|
};
|
|
|
|
} // End llvm namespace
|
|
|
|
#endif
|