From: Duncan P. N. Exon Smith Date: Wed, 7 Oct 2015 20:05:10 +0000 (+0000) Subject: IR: Create SymbolTableList wrapper around iplist, NFC X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=2a8bcfaff1fda1ed06e277521d546c668bc7a0d9;p=oota-llvm.git 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249602 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/ADT/ilist.h b/include/llvm/ADT/ilist.h index ede3a9ced36..eb3f2cce929 100644 --- a/include/llvm/ADT/ilist.h +++ b/include/llvm/ADT/ilist.h @@ -104,6 +104,53 @@ struct ilist_sentinel_traits { } }; +template class ilist_half_node; +template class ilist_node; + +/// Traits with an embedded ilist_node as a sentinel. +/// +/// FIXME: The downcast in createSentinel() is UB. +template 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, + // 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), so no one will ever notice the superposition. + return static_cast(&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 Sentinel; +}; + +/// Trait with an embedded ilist_half_node as a sentinel. +/// +/// FIXME: The downcast in createSentinel() is UB. +template 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(&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 Sentinel; +}; + /// ilist_node_traits - A fragment for template traits for intrusive list /// that provides default node related operations. /// diff --git a/include/llvm/ADT/ilist_node.h b/include/llvm/ADT/ilist_node.h index 26d0b55e409..85d7a908096 100644 --- a/include/llvm/ADT/ilist_node.h +++ b/include/llvm/ADT/ilist_node.h @@ -19,12 +19,15 @@ namespace llvm { template struct ilist_traits; +template struct ilist_embedded_sentinel_traits; +template struct ilist_half_embedded_sentinel_traits; /// ilist_half_node - Base class that provides prev services for sentinels. /// template class ilist_half_node { friend struct ilist_traits; + friend struct ilist_half_embedded_sentinel_traits; NodeTy *Prev; protected: NodeTy *getPrev() { return Prev; } @@ -43,6 +46,8 @@ template class ilist_node : private ilist_half_node { friend struct ilist_nextprev_traits; friend struct ilist_traits; + friend struct ilist_half_embedded_sentinel_traits; + friend struct ilist_embedded_sentinel_traits; NodeTy *Next; NodeTy *getNext() { return Next; } const NodeTy *getNext() const { return Next; } diff --git a/include/llvm/IR/Argument.h b/include/llvm/IR/Argument.h index 97eedf9c4cd..0092f49e49a 100644 --- a/include/llvm/IR/Argument.h +++ b/include/llvm/IR/Argument.h @@ -21,8 +21,7 @@ namespace llvm { -template - class SymbolTableListTraits; +template class SymbolTableListTraits; /// \brief LLVM Argument representation /// @@ -36,7 +35,7 @@ class Argument : public Value, public ilist_node { virtual void anchor(); Function *Parent; - friend class SymbolTableListTraits; + friend class SymbolTableListTraits; void setParent(Function *parent); public: diff --git a/include/llvm/IR/BasicBlock.h b/include/llvm/IR/BasicBlock.h index d3a8ec3d3e6..9e76fa229e0 100644 --- a/include/llvm/IR/BasicBlock.h +++ b/include/llvm/IR/BasicBlock.h @@ -30,20 +30,9 @@ class LLVMContext; class BlockAddress; class Function; -// Traits for intrusive list of basic blocks... -template<> struct ilist_traits - : public SymbolTableListTraits { - - 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 Sentinel; -}; - +template <> +struct SymbolTableListSentinelTraits + : public ilist_half_embedded_sentinel_traits {}; /// \brief LLVM Basic Block Representation /// @@ -64,13 +53,14 @@ class BasicBlock : public Value, // Basic blocks are data objects also public ilist_node { friend class BlockAddress; public: - typedef iplist InstListType; + typedef SymbolTableList InstListType; + private: InstListType InstList; Function *Parent; void setParent(Function *parent); - friend class SymbolTableListTraits; + friend class SymbolTableListTraits; 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::iterator eraseFromParent(); + SymbolTableList::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) -inline BasicBlock *ilist_traits::createSentinel() const { - return static_cast(&Sentinel); -} - // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(BasicBlock, LLVMBasicBlockRef) diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index c6486d1b4e5..cb850e3d2af 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -34,26 +34,14 @@ class FunctionType; class LLVMContext; class DISubprogram; -template<> struct ilist_traits - : public SymbolTableListTraits { - - Argument *createSentinel() const { - return static_cast(&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 Sentinel; -}; +template <> +struct SymbolTableListSentinelTraits + : public ilist_half_embedded_sentinel_traits {}; class Function : public GlobalObject, public ilist_node { public: - typedef iplist ArgumentListType; - typedef iplist BasicBlockListType; + typedef SymbolTableList ArgumentListType; + typedef SymbolTableList BasicBlockListType; // BasicBlock iterators... typedef BasicBlockListType::iterator iterator; @@ -90,7 +78,7 @@ private: (Value ? Mask : 0u)); } - friend class SymbolTableListTraits; + friend class SymbolTableListTraits; void setParent(Module *parent); diff --git a/include/llvm/IR/GlobalAlias.h b/include/llvm/IR/GlobalAlias.h index d0672c8aac0..b0772143309 100644 --- a/include/llvm/IR/GlobalAlias.h +++ b/include/llvm/IR/GlobalAlias.h @@ -23,11 +23,10 @@ namespace llvm { class Module; -template - class SymbolTableListTraits; +template class SymbolTableListTraits; class GlobalAlias : public GlobalValue, public ilist_node { - friend class SymbolTableListTraits; + friend class SymbolTableListTraits; void operator=(const GlobalAlias &) = delete; GlobalAlias(const GlobalAlias &) = delete; diff --git a/include/llvm/IR/GlobalVariable.h b/include/llvm/IR/GlobalVariable.h index a0159830ba3..62d3e43f9d6 100644 --- a/include/llvm/IR/GlobalVariable.h +++ b/include/llvm/IR/GlobalVariable.h @@ -29,11 +29,10 @@ namespace llvm { class Module; class Constant; -template - class SymbolTableListTraits; +template class SymbolTableListTraits; class GlobalVariable : public GlobalObject, public ilist_node { - friend class SymbolTableListTraits; + friend class SymbolTableListTraits; void *operator new(size_t, unsigned) = delete; void operator=(const GlobalVariable &) = delete; GlobalVariable(const GlobalVariable &) = delete; diff --git a/include/llvm/IR/InstIterator.h b/include/llvm/IR/InstIterator.h index 40f66c8d98b..1baca21c73a 100644 --- a/include/llvm/IR/InstIterator.h +++ b/include/llvm/IR/InstIterator.h @@ -115,13 +115,10 @@ private: } }; - -typedef InstIterator, - Function::iterator, BasicBlock::iterator, - Instruction> inst_iterator; -typedef InstIterator, - Function::const_iterator, - BasicBlock::const_iterator, +typedef InstIterator, Function::iterator, + BasicBlock::iterator, Instruction> inst_iterator; +typedef InstIterator, + Function::const_iterator, BasicBlock::const_iterator, const Instruction> const_inst_iterator; typedef iterator_range inst_range; typedef iterator_range const_inst_range; diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index 000e8545836..581ac09cf0c 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -30,23 +30,8 @@ class BasicBlock; struct AAMDNodes; template <> -struct ilist_traits - : public SymbolTableListTraits { - - /// \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 Sentinel; -}; +struct SymbolTableListSentinelTraits + : public ilist_half_embedded_sentinel_traits {}; class Instruction : public User, public ilist_node { 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::iterator eraseFromParent(); + SymbolTableList::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; + friend class SymbolTableListTraits; 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::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, - // 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), so no one will ever notice the superposition. - return static_cast(&Sentinel); -} - // Instruction* is only 4-byte aligned. template<> class PointerLikeTypeTraits { diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 94b24f4e288..5c95a98473e 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -32,9 +32,6 @@ class LLVMContext; class Module; class ModuleSlotTracker; -template - 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 { - friend class SymbolTableListTraits; friend struct ilist_traits; friend class LLVMContextImpl; friend class Module; diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 8bb9c21bd35..4e99c425673 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -34,58 +34,6 @@ class LLVMContext; class RandomNumberGenerator; class StructType; -template<> struct ilist_traits - : public SymbolTableListTraits { - - // createSentinel is used to get hold of the node that marks the end of the - // list... (same trick used here as in ilist_traits) - Function *createSentinel() const { - return static_cast(&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 Sentinel; -}; - -template<> struct ilist_traits - : public SymbolTableListTraits { - // createSentinel is used to create a node that marks the end of the list. - GlobalVariable *createSentinel() const { - return static_cast(&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 Sentinel; -}; - -template<> struct ilist_traits - : public SymbolTableListTraits { - // createSentinel is used to create a node that marks the end of the list. - GlobalAlias *createSentinel() const { - return static_cast(&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 Sentinel; -}; - template<> struct ilist_traits : public ilist_default_traits { // 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 GlobalListType; + typedef SymbolTableList GlobalListType; /// The type for the list of functions. - typedef iplist FunctionListType; + typedef SymbolTableList FunctionListType; /// The type for the list of aliases. - typedef iplist AliasListType; + typedef SymbolTableList AliasListType; /// The type for the list of named metadata. typedef ilist NamedMDListType; /// The type of the comdat "symbol" table. diff --git a/include/llvm/IR/SymbolTableListTraits.h b/include/llvm/IR/SymbolTableListTraits.h index de1d1398196..5fc48d10d63 100644 --- a/include/llvm/IR/SymbolTableListTraits.h +++ b/include/llvm/IR/SymbolTableListTraits.h @@ -34,11 +34,46 @@ template class ilist_iterator; template class iplist; template struct ilist_traits; +template +struct SymbolTableListSentinelTraits + : public ilist_embedded_sentinel_traits {}; + +/// 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 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 { 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 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 -class SymbolTableListTraits : public ilist_default_traits { +template +class SymbolTableListTraits + : public ilist_nextprev_traits, + public SymbolTableListSentinelTraits, + public ilist_node_traits { + typedef SymbolTableList ListTy; + typedef + typename SymbolTableListParentType::type ItemParentClass; + public: SymbolTableListTraits() {} @@ -48,12 +83,12 @@ private: ItemParentClass *getListOwner() { size_t Offset(size_t(&((ItemParentClass*)nullptr->*ItemParentClass:: getSublistAccess(static_cast(nullptr))))); - iplist* Anchor(static_cast*>(this)); + ListTy *Anchor(static_cast(this)); return reinterpret_cast(reinterpret_cast(Anchor)- Offset); } - static iplist &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 &L2, + void transferNodesFromList(SymbolTableListTraits &L2, ilist_iterator first, ilist_iterator 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 +class SymbolTableList : public iplist> {}; + } // End llvm namespace #endif diff --git a/include/llvm/IR/ValueSymbolTable.h b/include/llvm/IR/ValueSymbolTable.h index 011d17153fe..edeb31030ed 100644 --- a/include/llvm/IR/ValueSymbolTable.h +++ b/include/llvm/IR/ValueSymbolTable.h @@ -19,8 +19,7 @@ #include "llvm/Support/DataTypes.h" namespace llvm { - template - class SymbolTableListTraits; + template class SymbolTableListTraits; class BasicBlock; class Function; class NamedMDNode; @@ -33,12 +32,12 @@ namespace llvm { /// class ValueSymbolTable { friend class Value; - friend class SymbolTableListTraits; - friend class SymbolTableListTraits; - friend class SymbolTableListTraits; - friend class SymbolTableListTraits; - friend class SymbolTableListTraits; - friend class SymbolTableListTraits; + friend class SymbolTableListTraits; + friend class SymbolTableListTraits; + friend class SymbolTableListTraits; + friend class SymbolTableListTraits; + friend class SymbolTableListTraits; + friend class SymbolTableListTraits; /// @name Types /// @{ public: diff --git a/lib/IR/BasicBlock.cpp b/lib/IR/BasicBlock.cpp index 97e4da41ea9..02e07eb5bb5 100644 --- a/lib/IR/BasicBlock.cpp +++ b/lib/IR/BasicBlock.cpp @@ -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; +template class llvm::SymbolTableListTraits; BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent, BasicBlock *InsertBefore) diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp index 5e4c8ecbd22..3935a33d170 100644 --- a/lib/IR/Function.cpp +++ b/lib/IR/Function.cpp @@ -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; -template class llvm::SymbolTableListTraits; +template class llvm::SymbolTableListTraits; +template class llvm::SymbolTableListTraits; //===----------------------------------------------------------------------===// // Argument Implementation diff --git a/lib/IR/Module.cpp b/lib/IR/Module.cpp index 49586f42e10..21dfb0912fc 100644 --- a/lib/IR/Module.cpp +++ b/lib/IR/Module.cpp @@ -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; -template class llvm::SymbolTableListTraits; -template class llvm::SymbolTableListTraits; +template class llvm::SymbolTableListTraits; +template class llvm::SymbolTableListTraits; +template class llvm::SymbolTableListTraits; //===----------------------------------------------------------------------===// // Primitive Module methods. diff --git a/lib/IR/SymbolTableListTraitsImpl.h b/lib/IR/SymbolTableListTraitsImpl.h index 4d17d75859c..e7fa8ba58f4 100644 --- a/lib/IR/SymbolTableListTraitsImpl.h +++ b/lib/IR/SymbolTableListTraitsImpl.h @@ -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 -template -void SymbolTableListTraits -::setSymTabObject(TPtr *Dest, TPtr Src) { +template +template +void SymbolTableListTraits::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 if (OldST == NewST) return; // Move all the elements from the old symtab to the new one. - iplist &ItemList = getList(getListOwner()); + ListTy &ItemList = getList(getListOwner()); if (ItemList.empty()) return; if (OldST) { @@ -60,9 +60,8 @@ void SymbolTableListTraits } -template -void SymbolTableListTraits -::addNodeToList(ValueSubClass *V) { +template +void SymbolTableListTraits::addNodeToList(ValueSubClass *V) { assert(!V->getParent() && "Value already in a container!!"); ItemParentClass *Owner = getListOwner(); V->setParent(Owner); @@ -71,20 +70,19 @@ void SymbolTableListTraits ST->reinsertValue(V); } -template -void SymbolTableListTraits -::removeNodeFromList(ValueSubClass *V) { +template +void SymbolTableListTraits::removeNodeFromList( + ValueSubClass *V) { V->setParent(nullptr); if (V->hasName()) if (ValueSymbolTable *ST = getSymTab(getListOwner())) ST->removeValueName(V->getValueName()); } -template -void SymbolTableListTraits -::transferNodesFromList(ilist_traits &L2, - ilist_iterator first, - ilist_iterator last) { +template +void SymbolTableListTraits::transferNodesFromList( + SymbolTableListTraits &L2, ilist_iterator first, + ilist_iterator 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...