ADT: Split ilist_node_traits into alloc and callback, NFC

Many lists want to override only allocation semantics, or callbacks for
iplist.  Split these up to prevent code duplication.
- Specialize ilist_alloc_traits to change the implementations of
  deleteNode() and createNode().
- One common desire is to do nothing deleteNode() and disable
  createNode().  Specialize ilist_alloc_traits to inherit from
  ilist_noalloc_traits for that behaviour.
- Specialize ilist_callback_traits to use the addNodeToList(),
  removeNodeFromList(), and transferNodesFromList() callbacks.

As a drive-by, add some coverage to the callback-related unit tests.

llvm-svn: 280128
This commit is contained in:
Duncan P. N. Exon Smith 2016-08-30 18:40:47 +00:00
parent 982a3bcc48
commit f947c3afe1
16 changed files with 107 additions and 86 deletions

View File

@ -33,27 +33,57 @@
namespace llvm { namespace llvm {
/// A fragment for template traits for intrusive list that provides default /// Use new/delete by default for iplist and ilist.
/// node related operations.
/// ///
/// TODO: Split up (alloc vs. callback) and delete. /// Specialize this to get different behaviour for allocation-related API. (If
template <typename NodeTy> struct ilist_node_traits { /// you really want new/delete, consider just using std::list.)
///
/// \see ilist_noalloc_traits
template <typename NodeTy> struct ilist_alloc_traits {
static NodeTy *createNode(const NodeTy &V) { return new NodeTy(V); } static NodeTy *createNode(const NodeTy &V) { return new NodeTy(V); }
static void deleteNode(NodeTy *V) { delete V; } static void deleteNode(NodeTy *V) { delete V; }
};
/// Custom traits to disable node creation and do nothing on deletion.
///
/// Specialize ilist_alloc_traits to inherit from this to disable the
/// non-intrusive parts of iplist and/or ilist. It has no createNode function,
/// and deleteNode does nothing.
///
/// \code
/// template <>
/// struct ilist_alloc_traits<MyType> : ilist_noalloc_traits<MyType> {};
/// \endcode
template <typename NodeTy> struct ilist_noalloc_traits {
static void deleteNode(NodeTy *V) {}
};
/// Callbacks do nothing by default in iplist and ilist.
///
/// Specialize this for to use callbacks for when nodes change their list
/// membership.
template <typename NodeTy> struct ilist_callback_traits {
void addNodeToList(NodeTy *) {} void addNodeToList(NodeTy *) {}
void removeNodeFromList(NodeTy *) {} void removeNodeFromList(NodeTy *) {}
/// Callback before transferring nodes to this list. /// Callback before transferring nodes to this list.
/// ///
/// \pre \c this!=&OldList /// \pre \c this!=&OldList
void transferNodesFromList(ilist_node_traits &OldList, template <class Iterator>
ilist_iterator<NodeTy> /*first*/, void transferNodesFromList(ilist_callback_traits &OldList, Iterator /*first*/,
ilist_iterator<NodeTy> /*last*/) { Iterator /*last*/) {
(void)OldList; (void)OldList;
} }
}; };
/// A fragment for template traits for intrusive list that provides default
/// node related operations.
///
/// TODO: Remove this layer of indirection. It's not necessary.
template <typename NodeTy>
struct ilist_node_traits : ilist_alloc_traits<NodeTy>,
ilist_callback_traits<NodeTy> {};
/// Default template traits for intrusive list. /// Default template traits for intrusive list.
/// ///
/// By inheriting from this, you can easily use default implementations for all /// By inheriting from this, you can easily use default implementations for all

View File

@ -38,22 +38,20 @@ class MachineBranchProbabilityInfo;
// Forward declaration to avoid circular include problem with TargetRegisterInfo // Forward declaration to avoid circular include problem with TargetRegisterInfo
typedef unsigned LaneBitmask; typedef unsigned LaneBitmask;
template <> template <> struct ilist_traits<MachineInstr> {
struct ilist_traits<MachineInstr> : public ilist_default_traits<MachineInstr> {
private: private:
// this is only set by the MachineBasicBlock owning the LiveList friend class MachineBasicBlock; // Set by the owning MachineBasicBlock.
friend class MachineBasicBlock;
MachineBasicBlock *Parent; MachineBasicBlock *Parent;
public: public:
void addNodeToList(MachineInstr *N); void addNodeToList(MachineInstr *N);
void removeNodeFromList(MachineInstr *N); void removeNodeFromList(MachineInstr *N);
void transferNodesFromList(ilist_traits &SrcTraits, template <class Iterator>
ilist_iterator<MachineInstr> First, void transferNodesFromList(ilist_traits &OldList, Iterator First,
ilist_iterator<MachineInstr> Last); Iterator Last);
void deleteNode(MachineInstr *N);
private: void deleteNode(MachineInstr *MI);
void createNode(const MachineInstr &); // Leave out createNode...
}; };
class MachineBasicBlock class MachineBasicBlock
@ -697,7 +695,7 @@ private:
BranchProbability getSuccProbability(const_succ_iterator Succ) const; BranchProbability getSuccProbability(const_succ_iterator Succ) const;
// Methods used to maintain doubly linked list of blocks... // Methods used to maintain doubly linked list of blocks...
friend struct ilist_traits<MachineBasicBlock>; friend struct ilist_callback_traits<MachineBasicBlock>;
// Machine-CFG mutators // Machine-CFG mutators

View File

@ -48,14 +48,19 @@ class TargetRegisterClass;
struct MachinePointerInfo; struct MachinePointerInfo;
struct WinEHFuncInfo; struct WinEHFuncInfo;
template <> template <> struct ilist_alloc_traits<MachineBasicBlock> {
struct ilist_traits<MachineBasicBlock> void deleteNode(MachineBasicBlock *MBB);
: public ilist_default_traits<MachineBasicBlock> { // Disallow createNode...
};
template <> struct ilist_callback_traits<MachineBasicBlock> {
void addNodeToList(MachineBasicBlock* MBB); void addNodeToList(MachineBasicBlock* MBB);
void removeNodeFromList(MachineBasicBlock* MBB); void removeNodeFromList(MachineBasicBlock* MBB);
void deleteNode(MachineBasicBlock *MBB);
private: template <class Iterator>
void createNode(const MachineBasicBlock &); void transferNodesFromList(ilist_callback_traits &OldList, Iterator, Iterator) {
llvm_unreachable("Never transfer between lists");
}
}; };
/// MachineFunctionInfo - This class can be derived from and used by targets to /// MachineFunctionInfo - This class can be derived from and used by targets to

View File

@ -118,7 +118,7 @@ private:
// Intrusive list support // Intrusive list support
friend struct ilist_traits<MachineInstr>; friend struct ilist_traits<MachineInstr>;
friend struct ilist_traits<MachineBasicBlock>; friend struct ilist_callback_traits<MachineBasicBlock>;
void setParent(MachineBasicBlock *P) { Parent = P; } void setParent(MachineBasicBlock *P) { Parent = P; }
/// This constructor creates a copy of the given /// This constructor creates a copy of the given

View File

@ -81,12 +81,11 @@ template<> struct FoldingSetTrait<SDVTListNode> : DefaultFoldingSetTrait<SDVTLis
} }
}; };
template <> struct ilist_traits<SDNode> : public ilist_default_traits<SDNode> { template <> struct ilist_alloc_traits<SDNode> {
static void deleteNode(SDNode *) { static void deleteNode(SDNode *) {
llvm_unreachable("ilist_traits<SDNode> shouldn't see a deleteNode call!"); llvm_unreachable("ilist_traits<SDNode> shouldn't see a deleteNode call!");
} }
private: // Don't implement createNode...
static void createNode(const SDNode &);
}; };
/// Keeps track of dbg_value information through SDISel. We do /// Keeps track of dbg_value information through SDISel. We do

View File

@ -49,7 +49,6 @@ class Value;
class MCSymbol; class MCSymbol;
template <typename T> struct DenseMapInfo; template <typename T> struct DenseMapInfo;
template <typename T> struct simplify_type; template <typename T> struct simplify_type;
template <typename T> struct ilist_traits;
void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr, void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr,
bool force = false); bool force = false);
@ -503,7 +502,6 @@ private:
static const EVT *getValueTypeList(EVT VT); static const EVT *getValueTypeList(EVT VT);
friend class SelectionDAG; friend class SelectionDAG;
friend struct ilist_traits<SDNode>;
// TODO: unfriend HandleSDNode once we fix its operand handling. // TODO: unfriend HandleSDNode once we fix its operand handling.
friend class HandleSDNode; friend class HandleSDNode;

View File

@ -69,13 +69,8 @@ namespace llvm {
}; };
template <> template <>
struct ilist_traits<IndexListEntry> struct ilist_alloc_traits<IndexListEntry>
: public ilist_default_traits<IndexListEntry> { : public ilist_noalloc_traits<IndexListEntry> {};
void deleteNode(IndexListEntry *N) {}
private:
void createNode(const IndexListEntry &);
};
/// SlotIndex - An opaque wrapper around machine indexes. /// SlotIndex - An opaque wrapper around machine indexes.
class SlotIndex { class SlotIndex {

View File

@ -1247,7 +1247,6 @@ public:
/// ///
/// TODO: Inherit from Metadata. /// TODO: Inherit from Metadata.
class NamedMDNode : public ilist_node<NamedMDNode> { class NamedMDNode : public ilist_node<NamedMDNode> {
friend struct ilist_traits<NamedMDNode>;
friend class LLVMContextImpl; friend class LLVMContextImpl;
friend class Module; friend class Module;
NamedMDNode(const NamedMDNode &) = delete; NamedMDNode(const NamedMDNode &) = delete;

View File

@ -37,12 +37,6 @@ class RandomNumberGenerator;
class StructType; class StructType;
template <class PtrType> class SmallPtrSetImpl; template <class PtrType> class SmallPtrSetImpl;
template<> struct ilist_traits<NamedMDNode>
: public ilist_default_traits<NamedMDNode> {
void addNodeToList(NamedMDNode *) {}
void removeNodeFromList(NamedMDNode *) {}
};
/// A Module instance is used to store all the information related to an /// A Module instance is used to store all the information related to an
/// LLVM module. Modules are the top level container of all other LLVM /// LLVM module. Modules are the top level container of all other LLVM
/// Intermediate Representation (IR) objects. Each module directly contains a /// Intermediate Representation (IR) objects. Each module directly contains a

View File

@ -60,7 +60,7 @@ template <typename NodeTy> class SymbolTableList;
// ItemParentClass - The type of object that owns the list, e.g. BasicBlock. // ItemParentClass - The type of object that owns the list, e.g. BasicBlock.
// //
template <typename ValueSubClass> template <typename ValueSubClass>
class SymbolTableListTraits : public ilist_node_traits<ValueSubClass> { class SymbolTableListTraits : public ilist_alloc_traits<ValueSubClass> {
typedef SymbolTableList<ValueSubClass> ListTy; typedef SymbolTableList<ValueSubClass> ListTy;
typedef ilist_iterator<ValueSubClass, false> iterator; typedef ilist_iterator<ValueSubClass, false> iterator;
typedef typedef

View File

@ -31,16 +31,9 @@ class MCSection;
class MCSymbol; class MCSymbol;
class raw_ostream; class raw_ostream;
template<> template <> struct ilist_alloc_traits<MCFragment> {
struct ilist_node_traits<MCFragment> {
MCFragment *createNode(const MCFragment &V);
static void deleteNode(MCFragment *V); static void deleteNode(MCFragment *V);
// Leave out createNode...
void addNodeToList(MCFragment *) {}
void removeNodeFromList(MCFragment *) {}
void transferNodesFromList(ilist_node_traits & /*SrcTraits*/,
ilist_iterator<MCFragment> /*first*/,
ilist_iterator<MCFragment> /*last*/) {}
}; };
/// Instances of this class represent a uniqued identifier for a section in the /// Instances of this class represent a uniqued identifier for a section in the

View File

@ -74,7 +74,8 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const MachineBasicBlock &MBB) {
/// MBBs start out as #-1. When a MBB is added to a MachineFunction, it /// MBBs start out as #-1. When a MBB is added to a MachineFunction, it
/// gets the next available unique MBB number. If it is removed from a /// gets the next available unique MBB number. If it is removed from a
/// MachineFunction, it goes back to being #-1. /// MachineFunction, it goes back to being #-1.
void ilist_traits<MachineBasicBlock>::addNodeToList(MachineBasicBlock *N) { void ilist_callback_traits<MachineBasicBlock>::addNodeToList(
MachineBasicBlock *N) {
MachineFunction &MF = *N->getParent(); MachineFunction &MF = *N->getParent();
N->Number = MF.addToMBBNumbering(N); N->Number = MF.addToMBBNumbering(N);
@ -85,7 +86,8 @@ void ilist_traits<MachineBasicBlock>::addNodeToList(MachineBasicBlock *N) {
I->AddRegOperandsToUseLists(RegInfo); I->AddRegOperandsToUseLists(RegInfo);
} }
void ilist_traits<MachineBasicBlock>::removeNodeFromList(MachineBasicBlock *N) { void ilist_callback_traits<MachineBasicBlock>::removeNodeFromList(
MachineBasicBlock *N) {
N->getParent()->removeFromMBBNumbering(N->Number); N->getParent()->removeFromMBBNumbering(N->Number);
N->Number = -1; N->Number = -1;
} }
@ -116,10 +118,11 @@ void ilist_traits<MachineInstr>::removeNodeFromList(MachineInstr *N) {
/// When moving a range of instructions from one MBB list to another, we need to /// When moving a range of instructions from one MBB list to another, we need to
/// update the parent pointers and the use/def lists. /// update the parent pointers and the use/def lists.
void ilist_traits<MachineInstr>:: template <>
transferNodesFromList(ilist_traits<MachineInstr> &FromList, void ilist_traits<MachineInstr>::transferNodesFromList<
ilist_iterator<MachineInstr> First, ilist<MachineInstr>::iterator>(ilist_traits<MachineInstr> &FromList,
ilist_iterator<MachineInstr> Last) { ilist<MachineInstr>::iterator First,
ilist<MachineInstr>::iterator Last) {
assert(Parent->getParent() == FromList.Parent->getParent() && assert(Parent->getParent() == FromList.Parent->getParent() &&
"MachineInstr parent mismatch!"); "MachineInstr parent mismatch!");
assert(this != &FromList && "Called without a real transfer..."); assert(this != &FromList && "Called without a real transfer...");

View File

@ -86,7 +86,7 @@ void MachineFunctionProperties::print(raw_ostream &OS) const {
// Out-of-line virtual method. // Out-of-line virtual method.
MachineFunctionInfo::~MachineFunctionInfo() {} MachineFunctionInfo::~MachineFunctionInfo() {}
void ilist_traits<MachineBasicBlock>::deleteNode(MachineBasicBlock *MBB) { void ilist_alloc_traits<MachineBasicBlock>::deleteNode(MachineBasicBlock *MBB) {
MBB->getParent()->DeleteMachineBasicBlock(MBB); MBB->getParent()->DeleteMachineBasicBlock(MBB);
} }

View File

@ -232,9 +232,7 @@ uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler,
/* *** */ /* *** */
void ilist_node_traits<MCFragment>::deleteNode(MCFragment *V) { void ilist_alloc_traits<MCFragment>::deleteNode(MCFragment *V) { V->destroy(); }
V->destroy();
}
MCFragment::~MCFragment() { } MCFragment::~MCFragment() { }

View File

@ -149,22 +149,15 @@ struct Token : ilist_node<Token> {
} }
namespace llvm { namespace llvm {
template<> template <> struct ilist_alloc_traits<Token> {
struct ilist_node_traits<Token> {
Token *createNode(const Token &V) { Token *createNode(const Token &V) {
return new (Alloc.Allocate<Token>()) Token(V); return new (Alloc.Allocate<Token>()) Token(V);
} }
static void deleteNode(Token *V) { V->~Token(); } static void deleteNode(Token *V) { V->~Token(); }
void addNodeToList(Token *) {}
void removeNodeFromList(Token *) {}
void transferNodesFromList(ilist_node_traits & /*SrcTraits*/,
ilist_iterator<Token> /*first*/,
ilist_iterator<Token> /*last*/) {}
BumpPtrAllocator Alloc; BumpPtrAllocator Alloc;
}; };
} } // end namespace llvm
typedef ilist<Token> TokenQueueT; typedef ilist<Token> TokenQueueT;

View File

@ -167,6 +167,7 @@ TEST(IListTest, HasCreateSentinelTrait) {
struct NodeWithCallback : ilist_node<NodeWithCallback> { struct NodeWithCallback : ilist_node<NodeWithCallback> {
int Value = 0; int Value = 0;
bool IsInList = false; bool IsInList = false;
bool WasTransferred = false;
NodeWithCallback() = default; NodeWithCallback() = default;
NodeWithCallback(int Value) : Value(Value) {} NodeWithCallback(int Value) : Value(Value) {}
@ -176,29 +177,44 @@ struct NodeWithCallback : ilist_node<NodeWithCallback> {
} // end namespace } // end namespace
namespace llvm { namespace llvm {
template <> template <> struct ilist_callback_traits<NodeWithCallback> {
struct ilist_traits<NodeWithCallback>
: public ilist_node_traits<NodeWithCallback> {
void addNodeToList(NodeWithCallback *N) { N->IsInList = true; } void addNodeToList(NodeWithCallback *N) { N->IsInList = true; }
void removeNodeFromList(NodeWithCallback *N) { N->IsInList = false; } void removeNodeFromList(NodeWithCallback *N) { N->IsInList = false; }
template <class Iterator>
void transferNodesFromList(ilist_callback_traits &Other, Iterator First,
Iterator Last) {
for (; First != Last; ++First) {
First->WasTransferred = true;
Other.removeNodeFromList(&*First);
addNodeToList(&*First);
}
}
}; };
} // end namespace llvm } // end namespace llvm
namespace { namespace {
TEST(IListTest, addNodeToList) { TEST(IListTest, addNodeToList) {
ilist<NodeWithCallback> L; ilist<NodeWithCallback> L1, L2;
NodeWithCallback N(7); NodeWithCallback N(7);
ASSERT_FALSE(N.IsInList); ASSERT_FALSE(N.IsInList);
ASSERT_FALSE(N.WasTransferred);
L.insert(L.begin(), &N); L1.insert(L1.begin(), &N);
ASSERT_EQ(1u, L.size()); ASSERT_EQ(1u, L1.size());
ASSERT_EQ(&N, &*L.begin()); ASSERT_EQ(&N, &L1.front());
ASSERT_TRUE(N.IsInList); ASSERT_TRUE(N.IsInList);
ASSERT_FALSE(N.WasTransferred);
L.remove(&N); L2.splice(L2.end(), L1);
ASSERT_EQ(0u, L.size()); ASSERT_EQ(&N, &L2.front());
ASSERT_TRUE(N.IsInList);
ASSERT_TRUE(N.WasTransferred);
L1.remove(&N);
ASSERT_EQ(0u, L1.size());
ASSERT_FALSE(N.IsInList); ASSERT_FALSE(N.IsInList);
ASSERT_TRUE(N.WasTransferred);
} }
struct PrivateNode : private ilist_node<PrivateNode> { struct PrivateNode : private ilist_node<PrivateNode> {