IR: Create SymbolTableList wrapper around iplist, NFC

Create `SymbolTableList`, a wrapper around `iplist` for lists that
automatically manage a symbol table.  This commit reduces a ton of code
duplication between the six traits classes that were used previously.

As a drive by, reduce the number of template parameters from 2 to 1 by
using a SymbolTableListParentType metafunction (I originally had this as
a separate commit, but it touched most of the same lines so I squashed
them).

I'm in the process of trying to remove the UB in `createSentinel()` (see
the FIXMEs I added for `ilist_embedded_sentinel_traits` and
`ilist_half_embedded_sentinel_traits`).  My eventual goal is to separate
the list logic into a base class layer that knows nothing about (and
isn't templated on) the downcasted nodes -- removing the need to invoke
UB -- but for now I'm just trying to get a handle on all the current use
cases (and cleaning things up as I see them).

Besides these six SymbolTable lists, there are two others that use the
addNode/removeNode/transferNodes() hooks: the `MachineInstruction` and
`MachineBasicBlock` lists.  Ideally there'll be a way to factor these
hooks out of the low-level API entirely, but I'm not quite there yet.

llvm-svn: 249602
This commit is contained in:
Duncan P. N. Exon Smith 2015-10-07 20:05:10 +00:00
parent f6945cd657
commit d8033eebd6
17 changed files with 157 additions and 181 deletions

View File

@ -104,6 +104,53 @@ struct ilist_sentinel_traits {
}
};
template <typename NodeTy> class ilist_half_node;
template <typename NodeTy> class ilist_node;
/// Traits with an embedded ilist_node as a sentinel.
///
/// FIXME: The downcast in createSentinel() is UB.
template <typename NodeTy> struct ilist_embedded_sentinel_traits {
/// Get hold of the node that marks the end of the list.
NodeTy *createSentinel() const {
// Since i(p)lists always publicly derive from their corresponding traits,
// placing a data member in this class will augment the i(p)list. But since
// the NodeTy is expected to be publicly derive from ilist_node<NodeTy>,
// there is a legal viable downcast from it to NodeTy. We use this trick to
// superimpose an i(p)list with a "ghostly" NodeTy, which becomes the
// sentinel. Dereferencing the sentinel is forbidden (save the
// ilist_node<NodeTy>), so no one will ever notice the superposition.
return static_cast<NodeTy *>(&Sentinel);
}
static void destroySentinel(NodeTy *) {}
NodeTy *provideInitialHead() const { return createSentinel(); }
NodeTy *ensureHead(NodeTy *) const { return createSentinel(); }
static void noteHead(NodeTy *, NodeTy *) {}
private:
mutable ilist_node<NodeTy> Sentinel;
};
/// Trait with an embedded ilist_half_node as a sentinel.
///
/// FIXME: The downcast in createSentinel() is UB.
template <typename NodeTy> struct ilist_half_embedded_sentinel_traits {
/// Get hold of the node that marks the end of the list.
NodeTy *createSentinel() const {
// See comment in ilist_embedded_sentinel_traits::createSentinel().
return static_cast<NodeTy *>(&Sentinel);
}
static void destroySentinel(NodeTy *) {}
NodeTy *provideInitialHead() const { return createSentinel(); }
NodeTy *ensureHead(NodeTy *) const { return createSentinel(); }
static void noteHead(NodeTy *, NodeTy *) {}
private:
mutable ilist_half_node<NodeTy> Sentinel;
};
/// ilist_node_traits - A fragment for template traits for intrusive list
/// that provides default node related operations.
///

View File

@ -19,12 +19,15 @@ namespace llvm {
template<typename NodeTy>
struct ilist_traits;
template <typename NodeTy> struct ilist_embedded_sentinel_traits;
template <typename NodeTy> struct ilist_half_embedded_sentinel_traits;
/// ilist_half_node - Base class that provides prev services for sentinels.
///
template<typename NodeTy>
class ilist_half_node {
friend struct ilist_traits<NodeTy>;
friend struct ilist_half_embedded_sentinel_traits<NodeTy>;
NodeTy *Prev;
protected:
NodeTy *getPrev() { return Prev; }
@ -43,6 +46,8 @@ template<typename NodeTy>
class ilist_node : private ilist_half_node<NodeTy> {
friend struct ilist_nextprev_traits<NodeTy>;
friend struct ilist_traits<NodeTy>;
friend struct ilist_half_embedded_sentinel_traits<NodeTy>;
friend struct ilist_embedded_sentinel_traits<NodeTy>;
NodeTy *Next;
NodeTy *getNext() { return Next; }
const NodeTy *getNext() const { return Next; }

View File

@ -21,8 +21,7 @@
namespace llvm {
template<typename ValueSubClass, typename ItemParentClass>
class SymbolTableListTraits;
template <typename NodeTy> class SymbolTableListTraits;
/// \brief LLVM Argument representation
///
@ -36,7 +35,7 @@ class Argument : public Value, public ilist_node<Argument> {
virtual void anchor();
Function *Parent;
friend class SymbolTableListTraits<Argument, Function>;
friend class SymbolTableListTraits<Argument>;
void setParent(Function *parent);
public:

View File

@ -30,20 +30,9 @@ class LLVMContext;
class BlockAddress;
class Function;
// Traits for intrusive list of basic blocks...
template<> struct ilist_traits<BasicBlock>
: public SymbolTableListTraits<BasicBlock, Function> {
BasicBlock *createSentinel() const;
static void destroySentinel(BasicBlock*) {}
BasicBlock *provideInitialHead() const { return createSentinel(); }
BasicBlock *ensureHead(BasicBlock*) const { return createSentinel(); }
static void noteHead(BasicBlock*, BasicBlock*) {}
private:
mutable ilist_half_node<BasicBlock> Sentinel;
};
template <>
struct SymbolTableListSentinelTraits<BasicBlock>
: public ilist_half_embedded_sentinel_traits<BasicBlock> {};
/// \brief LLVM Basic Block Representation
///
@ -64,13 +53,14 @@ class BasicBlock : public Value, // Basic blocks are data objects also
public ilist_node<BasicBlock> {
friend class BlockAddress;
public:
typedef iplist<Instruction> InstListType;
typedef SymbolTableList<Instruction> InstListType;
private:
InstListType InstList;
Function *Parent;
void setParent(Function *parent);
friend class SymbolTableListTraits<BasicBlock, Function>;
friend class SymbolTableListTraits<BasicBlock>;
BasicBlock(const BasicBlock &) = delete;
void operator=(const BasicBlock &) = delete;
@ -169,7 +159,7 @@ public:
/// \brief Unlink 'this' from the containing function and delete it.
///
// \returns an iterator pointing to the element after the erased one.
iplist<BasicBlock>::iterator eraseFromParent();
SymbolTableList<BasicBlock>::iterator eraseFromParent();
/// \brief Unlink this basic block from its current function and insert it
/// into the function that \p MovePos lives in, right before \p MovePos.
@ -340,12 +330,6 @@ private:
}
};
// createSentinel is used to get hold of the node that marks the end of the
// list... (same trick used here as in ilist_traits<Instruction>)
inline BasicBlock *ilist_traits<BasicBlock>::createSentinel() const {
return static_cast<BasicBlock*>(&Sentinel);
}
// Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(BasicBlock, LLVMBasicBlockRef)

View File

@ -34,26 +34,14 @@ class FunctionType;
class LLVMContext;
class DISubprogram;
template<> struct ilist_traits<Argument>
: public SymbolTableListTraits<Argument, Function> {
Argument *createSentinel() const {
return static_cast<Argument*>(&Sentinel);
}
static void destroySentinel(Argument*) {}
Argument *provideInitialHead() const { return createSentinel(); }
Argument *ensureHead(Argument*) const { return createSentinel(); }
static void noteHead(Argument*, Argument*) {}
private:
mutable ilist_half_node<Argument> Sentinel;
};
template <>
struct SymbolTableListSentinelTraits<Argument>
: public ilist_half_embedded_sentinel_traits<Argument> {};
class Function : public GlobalObject, public ilist_node<Function> {
public:
typedef iplist<Argument> ArgumentListType;
typedef iplist<BasicBlock> BasicBlockListType;
typedef SymbolTableList<Argument> ArgumentListType;
typedef SymbolTableList<BasicBlock> BasicBlockListType;
// BasicBlock iterators...
typedef BasicBlockListType::iterator iterator;
@ -90,7 +78,7 @@ private:
(Value ? Mask : 0u));
}
friend class SymbolTableListTraits<Function, Module>;
friend class SymbolTableListTraits<Function>;
void setParent(Module *parent);

View File

@ -23,11 +23,10 @@
namespace llvm {
class Module;
template<typename ValueSubClass, typename ItemParentClass>
class SymbolTableListTraits;
template <typename ValueSubClass> class SymbolTableListTraits;
class GlobalAlias : public GlobalValue, public ilist_node<GlobalAlias> {
friend class SymbolTableListTraits<GlobalAlias, Module>;
friend class SymbolTableListTraits<GlobalAlias>;
void operator=(const GlobalAlias &) = delete;
GlobalAlias(const GlobalAlias &) = delete;

View File

@ -29,11 +29,10 @@ namespace llvm {
class Module;
class Constant;
template<typename ValueSubClass, typename ItemParentClass>
class SymbolTableListTraits;
template <typename ValueSubClass> class SymbolTableListTraits;
class GlobalVariable : public GlobalObject, public ilist_node<GlobalVariable> {
friend class SymbolTableListTraits<GlobalVariable, Module>;
friend class SymbolTableListTraits<GlobalVariable>;
void *operator new(size_t, unsigned) = delete;
void operator=(const GlobalVariable &) = delete;
GlobalVariable(const GlobalVariable &) = delete;

View File

@ -115,13 +115,10 @@ private:
}
};
typedef InstIterator<iplist<BasicBlock>,
Function::iterator, BasicBlock::iterator,
Instruction> inst_iterator;
typedef InstIterator<const iplist<BasicBlock>,
Function::const_iterator,
BasicBlock::const_iterator,
typedef InstIterator<SymbolTableList<BasicBlock>, Function::iterator,
BasicBlock::iterator, Instruction> inst_iterator;
typedef InstIterator<const SymbolTableList<BasicBlock>,
Function::const_iterator, BasicBlock::const_iterator,
const Instruction> const_inst_iterator;
typedef iterator_range<inst_iterator> inst_range;
typedef iterator_range<const_inst_iterator> const_inst_range;

View File

@ -30,23 +30,8 @@ class BasicBlock;
struct AAMDNodes;
template <>
struct ilist_traits<Instruction>
: public SymbolTableListTraits<Instruction, BasicBlock> {
/// \brief Return a node that marks the end of a list.
///
/// The sentinel is relative to this instance, so we use a non-static
/// method.
Instruction *createSentinel() const;
static void destroySentinel(Instruction *) {}
Instruction *provideInitialHead() const { return createSentinel(); }
Instruction *ensureHead(Instruction *) const { return createSentinel(); }
static void noteHead(Instruction *, Instruction *) {}
private:
mutable ilist_half_node<Instruction> Sentinel;
};
struct SymbolTableListSentinelTraits<Instruction>
: public ilist_half_embedded_sentinel_traits<Instruction> {};
class Instruction : public User, public ilist_node<Instruction> {
void operator=(const Instruction &) = delete;
@ -89,7 +74,7 @@ public:
/// block and deletes it.
///
/// \returns an iterator pointing to the element after the erased one
iplist<Instruction>::iterator eraseFromParent();
SymbolTableList<Instruction>::iterator eraseFromParent();
/// Insert an unlinked instruction into a basic block immediately before
/// the specified instruction.
@ -506,7 +491,7 @@ private:
(V ? HasMetadataBit : 0));
}
friend class SymbolTableListTraits<Instruction, BasicBlock>;
friend class SymbolTableListTraits<Instruction>;
void setParent(BasicBlock *P);
protected:
// Instruction subclasses can stick up to 15 bits of stuff into the
@ -532,17 +517,6 @@ private:
Instruction *cloneImpl() const;
};
inline Instruction *ilist_traits<Instruction>::createSentinel() const {
// Since i(p)lists always publicly derive from their corresponding traits,
// placing a data member in this class will augment the i(p)list. But since
// the NodeTy is expected to be publicly derive from ilist_node<NodeTy>,
// there is a legal viable downcast from it to NodeTy. We use this trick to
// superimpose an i(p)list with a "ghostly" NodeTy, which becomes the
// sentinel. Dereferencing the sentinel is forbidden (save the
// ilist_node<NodeTy>), so no one will ever notice the superposition.
return static_cast<Instruction *>(&Sentinel);
}
// Instruction* is only 4-byte aligned.
template<>
class PointerLikeTypeTraits<Instruction*> {

View File

@ -32,9 +32,6 @@ class LLVMContext;
class Module;
class ModuleSlotTracker;
template<typename ValueSubClass, typename ItemParentClass>
class SymbolTableListTraits;
enum LLVMConstants : uint32_t {
DEBUG_METADATA_VERSION = 3 // Current debug info version number.
};
@ -1129,7 +1126,6 @@ public:
///
/// TODO: Inherit from Metadata.
class NamedMDNode : public ilist_node<NamedMDNode> {
friend class SymbolTableListTraits<NamedMDNode, Module>;
friend struct ilist_traits<NamedMDNode>;
friend class LLVMContextImpl;
friend class Module;

View File

@ -34,58 +34,6 @@ class LLVMContext;
class RandomNumberGenerator;
class StructType;
template<> struct ilist_traits<Function>
: public SymbolTableListTraits<Function, Module> {
// createSentinel is used to get hold of the node that marks the end of the
// list... (same trick used here as in ilist_traits<Instruction>)
Function *createSentinel() const {
return static_cast<Function*>(&Sentinel);
}
static void destroySentinel(Function*) {}
Function *provideInitialHead() const { return createSentinel(); }
Function *ensureHead(Function*) const { return createSentinel(); }
static void noteHead(Function*, Function*) {}
private:
mutable ilist_node<Function> Sentinel;
};
template<> struct ilist_traits<GlobalVariable>
: public SymbolTableListTraits<GlobalVariable, Module> {
// createSentinel is used to create a node that marks the end of the list.
GlobalVariable *createSentinel() const {
return static_cast<GlobalVariable*>(&Sentinel);
}
static void destroySentinel(GlobalVariable*) {}
GlobalVariable *provideInitialHead() const { return createSentinel(); }
GlobalVariable *ensureHead(GlobalVariable *) const {
return createSentinel();
}
static void noteHead(GlobalVariable *, GlobalVariable *) {}
private:
mutable ilist_node<GlobalVariable> Sentinel;
};
template<> struct ilist_traits<GlobalAlias>
: public SymbolTableListTraits<GlobalAlias, Module> {
// createSentinel is used to create a node that marks the end of the list.
GlobalAlias *createSentinel() const {
return static_cast<GlobalAlias*>(&Sentinel);
}
static void destroySentinel(GlobalAlias*) {}
GlobalAlias *provideInitialHead() const { return createSentinel(); }
GlobalAlias *ensureHead(GlobalAlias *) const { return createSentinel(); }
static void noteHead(GlobalAlias *, GlobalAlias *) {}
private:
mutable ilist_node<GlobalAlias> Sentinel;
};
template<> struct ilist_traits<NamedMDNode>
: public ilist_default_traits<NamedMDNode> {
// createSentinel is used to get hold of a node that marks the end of
@ -121,11 +69,11 @@ class Module {
/// @{
public:
/// The type for the list of global variables.
typedef iplist<GlobalVariable> GlobalListType;
typedef SymbolTableList<GlobalVariable> GlobalListType;
/// The type for the list of functions.
typedef iplist<Function> FunctionListType;
typedef SymbolTableList<Function> FunctionListType;
/// The type for the list of aliases.
typedef iplist<GlobalAlias> AliasListType;
typedef SymbolTableList<GlobalAlias> AliasListType;
/// The type for the list of named metadata.
typedef ilist<NamedMDNode> NamedMDListType;
/// The type of the comdat "symbol" table.

View File

@ -34,11 +34,46 @@ template <typename NodeTy> class ilist_iterator;
template <typename NodeTy, typename Traits> class iplist;
template <typename Ty> struct ilist_traits;
template <typename NodeTy>
struct SymbolTableListSentinelTraits
: public ilist_embedded_sentinel_traits<NodeTy> {};
/// Template metafunction to get the parent type for a symbol table list.
///
/// Implementations create a typedef called \c type so that we only need a
/// single template parameter for the list and traits.
template <typename NodeTy> struct SymbolTableListParentType {};
class Argument;
class BasicBlock;
class Function;
class Instruction;
class GlobalVariable;
class GlobalAlias;
class Module;
#define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT) \
template <> struct SymbolTableListParentType<NODE> { typedef PARENT type; };
DEFINE_SYMBOL_TABLE_PARENT_TYPE(Instruction, BasicBlock)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(BasicBlock, Function)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(Argument, Function)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(Function, Module)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalVariable, Module)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalAlias, Module)
#undef DEFINE_SYMBOL_TABLE_PARENT_TYPE
template <typename NodeTy> class SymbolTableList;
// ValueSubClass - The type of objects that I hold, e.g. Instruction.
// ItemParentClass - The type of object that owns the list, e.g. BasicBlock.
//
template<typename ValueSubClass, typename ItemParentClass>
class SymbolTableListTraits : public ilist_default_traits<ValueSubClass> {
template <typename ValueSubClass>
class SymbolTableListTraits
: public ilist_nextprev_traits<ValueSubClass>,
public SymbolTableListSentinelTraits<ValueSubClass>,
public ilist_node_traits<ValueSubClass> {
typedef SymbolTableList<ValueSubClass> ListTy;
typedef
typename SymbolTableListParentType<ValueSubClass>::type ItemParentClass;
public:
SymbolTableListTraits() {}
@ -48,12 +83,12 @@ private:
ItemParentClass *getListOwner() {
size_t Offset(size_t(&((ItemParentClass*)nullptr->*ItemParentClass::
getSublistAccess(static_cast<ValueSubClass*>(nullptr)))));
iplist<ValueSubClass>* Anchor(static_cast<iplist<ValueSubClass>*>(this));
ListTy *Anchor(static_cast<ListTy *>(this));
return reinterpret_cast<ItemParentClass*>(reinterpret_cast<char*>(Anchor)-
Offset);
}
static iplist<ValueSubClass> &getList(ItemParentClass *Par) {
static ListTy &getList(ItemParentClass *Par) {
return Par->*(Par->getSublistAccess((ValueSubClass*)nullptr));
}
@ -64,7 +99,7 @@ private:
public:
void addNodeToList(ValueSubClass *V);
void removeNodeFromList(ValueSubClass *V);
void transferNodesFromList(ilist_traits<ValueSubClass> &L2,
void transferNodesFromList(SymbolTableListTraits &L2,
ilist_iterator<ValueSubClass> first,
ilist_iterator<ValueSubClass> last);
//private:
@ -74,6 +109,14 @@ public:
static ValueSymbolTable *toPtr(ValueSymbolTable &R) { return &R; }
};
/// List that automatically updates parent links and symbol tables.
///
/// When nodes are inserted into and removed from this list, the associated
/// symbol table will be automatically updated. Similarly, parent links get
/// updated automatically.
template <typename NodeTy>
class SymbolTableList : public iplist<NodeTy, SymbolTableListTraits<NodeTy>> {};
} // End llvm namespace
#endif

View File

@ -19,8 +19,7 @@
#include "llvm/Support/DataTypes.h"
namespace llvm {
template<typename ValueSubClass, typename ItemParentClass>
class SymbolTableListTraits;
template <typename ValueSubClass> class SymbolTableListTraits;
class BasicBlock;
class Function;
class NamedMDNode;
@ -33,12 +32,12 @@ namespace llvm {
///
class ValueSymbolTable {
friend class Value;
friend class SymbolTableListTraits<Argument, Function>;
friend class SymbolTableListTraits<BasicBlock, Function>;
friend class SymbolTableListTraits<Instruction, BasicBlock>;
friend class SymbolTableListTraits<Function, Module>;
friend class SymbolTableListTraits<GlobalVariable, Module>;
friend class SymbolTableListTraits<GlobalAlias, Module>;
friend class SymbolTableListTraits<Argument>;
friend class SymbolTableListTraits<BasicBlock>;
friend class SymbolTableListTraits<Instruction>;
friend class SymbolTableListTraits<Function>;
friend class SymbolTableListTraits<GlobalVariable>;
friend class SymbolTableListTraits<GlobalAlias>;
/// @name Types
/// @{
public:

View File

@ -36,7 +36,7 @@ LLVMContext &BasicBlock::getContext() const {
// Explicit instantiation of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class llvm::SymbolTableListTraits<Instruction, BasicBlock>;
template class llvm::SymbolTableListTraits<Instruction>;
BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent,
BasicBlock *InsertBefore)

View File

@ -35,8 +35,8 @@ using namespace llvm;
// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class llvm::SymbolTableListTraits<Argument, Function>;
template class llvm::SymbolTableListTraits<BasicBlock, Function>;
template class llvm::SymbolTableListTraits<Argument>;
template class llvm::SymbolTableListTraits<BasicBlock>;
//===----------------------------------------------------------------------===//
// Argument Implementation

View File

@ -38,9 +38,9 @@ using namespace llvm;
// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file.
template class llvm::SymbolTableListTraits<Function, Module>;
template class llvm::SymbolTableListTraits<GlobalVariable, Module>;
template class llvm::SymbolTableListTraits<GlobalAlias, Module>;
template class llvm::SymbolTableListTraits<Function>;
template class llvm::SymbolTableListTraits<GlobalVariable>;
template class llvm::SymbolTableListTraits<GlobalAlias>;
//===----------------------------------------------------------------------===//
// Primitive Module methods.

View File

@ -24,10 +24,10 @@ namespace llvm {
/// setSymTabObject - This is called when (f.e.) the parent of a basic block
/// changes. This requires us to remove all the instruction symtab entries from
/// the current function and reinsert them into the new function.
template<typename ValueSubClass, typename ItemParentClass>
template<typename TPtr>
void SymbolTableListTraits<ValueSubClass,ItemParentClass>
::setSymTabObject(TPtr *Dest, TPtr Src) {
template <typename ValueSubClass>
template <typename TPtr>
void SymbolTableListTraits<ValueSubClass>::setSymTabObject(TPtr *Dest,
TPtr Src) {
// Get the old symtab and value list before doing the assignment.
ValueSymbolTable *OldST = getSymTab(getListOwner());
@ -41,7 +41,7 @@ void SymbolTableListTraits<ValueSubClass,ItemParentClass>
if (OldST == NewST) return;
// Move all the elements from the old symtab to the new one.
iplist<ValueSubClass> &ItemList = getList(getListOwner());
ListTy &ItemList = getList(getListOwner());
if (ItemList.empty()) return;
if (OldST) {
@ -60,9 +60,8 @@ void SymbolTableListTraits<ValueSubClass,ItemParentClass>
}
template<typename ValueSubClass, typename ItemParentClass>
void SymbolTableListTraits<ValueSubClass,ItemParentClass>
::addNodeToList(ValueSubClass *V) {
template <typename ValueSubClass>
void SymbolTableListTraits<ValueSubClass>::addNodeToList(ValueSubClass *V) {
assert(!V->getParent() && "Value already in a container!!");
ItemParentClass *Owner = getListOwner();
V->setParent(Owner);
@ -71,20 +70,19 @@ void SymbolTableListTraits<ValueSubClass,ItemParentClass>
ST->reinsertValue(V);
}
template<typename ValueSubClass, typename ItemParentClass>
void SymbolTableListTraits<ValueSubClass,ItemParentClass>
::removeNodeFromList(ValueSubClass *V) {
template <typename ValueSubClass>
void SymbolTableListTraits<ValueSubClass>::removeNodeFromList(
ValueSubClass *V) {
V->setParent(nullptr);
if (V->hasName())
if (ValueSymbolTable *ST = getSymTab(getListOwner()))
ST->removeValueName(V->getValueName());
}
template<typename ValueSubClass, typename ItemParentClass>
void SymbolTableListTraits<ValueSubClass,ItemParentClass>
::transferNodesFromList(ilist_traits<ValueSubClass> &L2,
ilist_iterator<ValueSubClass> first,
ilist_iterator<ValueSubClass> last) {
template <typename ValueSubClass>
void SymbolTableListTraits<ValueSubClass>::transferNodesFromList(
SymbolTableListTraits &L2, ilist_iterator<ValueSubClass> first,
ilist_iterator<ValueSubClass> last) {
// We only have to do work here if transferring instructions between BBs
ItemParentClass *NewIP = getListOwner(), *OldIP = L2.getListOwner();
if (NewIP == OldIP) return; // No work to do at all...