Started to implement the iterative data flow pass to build the global DAG
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Fri, 16 Mar 2012 11:04:45 +0000 (04:04 -0700)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:15:41 +0000 (16:15 -0700)
backend/src/ir/function.hpp
backend/src/ir/instruction.hpp
backend/src/ir/liveness.cpp
backend/src/ir/liveness.hpp
backend/src/ir/value.cpp
backend/src/ir/value.hpp
backend/src/sys/alloc.hpp
backend/src/sys/map.hpp
backend/src/sys/set.hpp
backend/src/utest/utest_llvm.cpp

index 1739378..476362f 100644 (file)
@@ -70,6 +70,15 @@ namespace ir {
         curr = curr->getSuccessor();
       }
     }
+    /*! Apply the given functor on all instructions (reverse order) */
+    template <typename T>
+    INLINE void rforeach(const T &functor) const {
+      Instruction *curr = last;
+      while (curr) {
+        functor(*curr);
+        curr = curr->getPredecessor();
+      }
+    }
     /*! Get the parent function */
     Function &getParent(void) { return fn; }
     const Function &getParent(void) const { return fn; }
@@ -150,15 +159,8 @@ namespace ir {
       this->immediates.push_back(imm);
       return index;
     }
-    /*! Allocate a new instruction (with the growing pool) */
-    template <typename... Args>
-    INLINE Instruction *newInstruction(Args... args) {
-      return new (insnPool.allocate()) Instruction(args...);
-    }
-    /*! Deallocate an instruction (with the growing pool) */
-    INLINE void deleteInstruction(Instruction *insn) {
-      insnPool.deallocate(insn);
-    }
+    /*! Fast allocation / deallocation of instructions */
+    DECL_POOL(Instruction, insnPool);
     /*! Get input argument */
     INLINE const FunctionInput &getInput(uint32_t ID) const {
       GBE_ASSERT(ID < inputNum() && inputs[ID] != NULL);
@@ -217,8 +219,7 @@ namespace ir {
     vector<Immediate> immediates; //!< All immediate values in the function
     vector<BasicBlock*> blocks;   //!< All chained basic blocks
     RegisterFile file;            //!< RegisterDatas used by the instructions
-    GrowingPool<Instruction> insnPool; //!< For fast instruction allocation
-    Profile profile;                   //!< Current function profile
+    Profile profile;              //!< Current function profile
     GBE_CLASS(Function);
   };
 
index 7bde4c1..6cde6ff 100644 (file)
@@ -126,6 +126,7 @@ namespace ir {
     Instruction *predecessor;//!< Previous instruction in the basic block
     Instruction *successor;  //!< Next instruction in the basic block
     BasicBlock *parent;      //!< The basic block containing the instruction
+    GBE_CLASS(Instruction);  //!< Use internal allocators
   };
 
   /*! Output the instruction string in the given stream */
index eb049d0..0b9b560 100644 (file)
@@ -40,7 +40,7 @@ namespace ir {
   }
 
   void Liveness::initBlock(const BasicBlock &bb) {
-    GBE_ASSERT(liveness.find(&bb) == liveness.end());
+    GBE_ASSERT(liveness.contains(&bb) == false);
     BlockInfo *info = GBE_NEW(BlockInfo, bb);
     // Traverse all instructions to handle UEVar and VarKill
     bb.foreach([this, info](const Instruction &insn) {
@@ -57,7 +57,7 @@ namespace ir {
     for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
       const Register reg = insn.getSrcIndex(fn, srcID);
       // Not killed -> it is really an upward use
-      if (info.varKill.find(reg) == info.varKill.end())
+      if (info.varKill.contains(reg) == false)
         info.upwardUsed.insert(reg);
     }
     // A destination is a killed value
@@ -82,11 +82,10 @@ namespace ir {
       forEachSuccessor([&changed](BlockInfo &info, const BlockInfo &succ) {
         const UEVar &killSet = succ.varKill;
         const LiveOut &liveOut = succ.liveOut;
-        auto end = killSet.end();
         // Iterate over all the registers in the UEVar of our successor
         for (auto living = liveOut.begin(); living != liveOut.end(); ++living) {
-          if (killSet.find(*living) != end) continue;
-          if (info.liveOut.find(*living) != info.liveOut.end()) continue;
+          if (killSet.contains(*living)) continue;
+          if (info.liveOut.contains(*living)) continue;
           info.liveOut.insert(*living);
           changed = true;
         }
index 2625b81..ba34d89 100644 (file)
@@ -52,13 +52,13 @@ namespace ir {
       BlockInfo(const BasicBlock &bb) : bb(bb) {}
       const BasicBlock &bb;
       INLINE bool inUpwardUsed(Register reg) const {
-        return upwardUsed.find(reg) != upwardUsed.end();
+        return upwardUsed.contains(reg);
       }
       INLINE bool inLiveOut(Register reg) const {
-        return liveOut.find(reg) != liveOut.end();
+        return liveOut.contains(reg);
       }
       INLINE bool inVarKill(Register reg) const {
-        return varKill.find(reg) != varKill.end();
+        return varKill.contains(reg);
       }
       UEVar upwardUsed;
       LiveOut liveOut;
@@ -68,6 +68,12 @@ namespace ir {
     typedef map<const BasicBlock*, BlockInfo*> Info;
     /*! Return the complete liveness info */
     INLINE const Info &getLiveness(void) const { return liveness; }
+    /*! Return the complete block info */
+    INLINE const BlockInfo &getBlockInfo(const BasicBlock &bb) const {
+      auto it = liveness.find(&bb);
+      GBE_ASSERT(it != liveness.end() && it->second != NULL);
+      return *it->second;
+    }
     /*! Return the function the liveness was computed on */
     INLINE const Function &getFunction(void) const { return fn; }
   private:
index b438fb4..8d0cb1e 100644 (file)
 namespace gbe {
 namespace ir {
 
-  GraphUseDef::GraphUseDef(const Liveness &liveness) {
+  /*! To build the chains (i.e. basically the DAG of values), we are going to
+   *  iterate on liveout definitions: for each block and for each variable
+   *  (ir::Register) alive at the end of the block (in Block::LiveOut), we are
+   *  computing the set of all possible value definitions. Using these value
+   *  definitions, we will finally transfer these sets to the successors to get
+   *  the ud / du chains
+   *
+   *  LiveOutSet contains the set of definitions for each basic block
+   */
+  class LiveOutSet
+  {
+  public:
+    LiveOutSet(const Liveness &liveness, const FunctionDAG &dag);
+    ~LiveOutSet(void);
+    /*! One set per register */
+    typedef set<const ValueDef*> RegDefSet;
+    /*! We have one map of liveout register per block */
+    typedef map<Register, RegDefSet*> BlockDefMap;
+    /*! All the block definitions map in the functions */
+    typedef map<const BasicBlock*, BlockDefMap*> FunctionDefMap;
+    FunctionDefMap defMap;    //!< All per-block data
+    const Liveness &liveness; //!< Contains LiveOut information
+    const FunctionDAG &dag;   //!< Structure we are building
+    DECL_POOL(RegDefSet, regDefSetPool);
+    DECL_POOL(BlockDefMap, blockDefMapPool);
+  };
+
+  LiveOutSet::LiveOutSet(const Liveness &liveness, const FunctionDAG &dag) :
+    liveness(liveness), dag(dag)
+  {
     const Function &fn = liveness.getFunction();
 
+    // Iterate over each block
+    fn.foreachBlock([&](const BasicBlock &bb) {
+      GBE_ASSERT(defMap.find(&bb) == defMap.end());
+
+      // Allocate a map of register definition
+      auto blockDefMap = this->newBlockDefMap();
+      defMap.insert(std::make_pair(&bb, blockDefMap));
+
+      // We only consider liveout registers
+      auto info = this->liveness.getBlockInfo(bb);
+      auto liveOut = info.liveOut;
+      for (auto it = liveOut.begin(); it != liveOut.end(); ++it) {
+        GBE_ASSERT(blockDefMap->find(*it) == blockDefMap->end());
+        auto regDefSet = this->newRegDefSet();
+        blockDefMap->insert(std::make_pair(*it, regDefSet));
+      }
+
+      // Now traverse the blocks backwards and find the definition of each
+      // liveOut register
+      set<Register> defined; // Liveout registers for which we found a def
+      bb.rforeach([&](const Instruction &insn) {
+        const uint32_t dstNum = insn.getDstNum();
+        for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
+          const Register reg = insn.getDstIndex(fn, dstID);
+          // We only take the most recent definition
+          if (defined.contains(reg) == false) continue;
+          // Not in LiveOut, so does not matter
+          if (info.inLiveOut(reg) == false) continue;
+          // Insert the outgoing definition for this register
+          auto regDefSet = blockDefMap->find(reg);
+          const ValueDef *def = this->dag.getDefAddress(insn, dstID);
+          GBE_ASSERT(regDefSet != blockDefMap->end() && def != NULL);
+          regDefSet->second->insert(def);
+        }
+      });
+    });
+  }
+
+  LiveOutSet::~LiveOutSet(void) {
+    for (auto it = defMap.begin(); it != defMap.end(); ++it) {
+      BlockDefMap *block = it->second;
+      for (auto regSet = block->begin();regSet != block->end(); ++regSet)
+        this->deleteRegDefSet(regSet->second);
+      this->deleteBlockDefMap(block);
+    }
+  }
+
+  FunctionDAG::FunctionDAG(const Liveness &liveness) {
+    const Function &fn = liveness.getFunction();
+    LiveOutSet p(liveness, *this);
+    // We first start with empty chains
+    udEmpty = this->newUDChain(); udEmpty->second = NULL;
+    duEmpty = this->newDUChain(); duEmpty->second = NULL;
+
     // First create the chains and insert them in their respective maps
-    fn.foreachInstruction([this](const Instruction &insn) {
+    fn.foreachInstruction([this, udEmpty, duEmpty](const Instruction &insn) {
+
       // sources == value uses
       const uint32_t srcNum = insn.getSrcNum();
       for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
         ValueUse *valueUse = this->newValueUse(insn, srcID);
-        UDChain *udChain = this->newUDChain();
-        udChain->first = valueUse;
-        udGraph.insert(std::make_pair(*valueUse, udChain));
+        udGraph.insert(std::make_pair(*valueUse, udEmpty));
       }
       // destinations == value defs
       const uint32_t dstNum = insn.getDstNum();
       for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
         ValueDef *valueDef = this->newValueDef(insn, dstID);
-        DUChain *duChain = this->newDUChain();
-        duChain->first = valueDef;
-        duGraph.insert(std::make_pair(*valueDef, duChain));
+        duGraph.insert(std::make_pair(*valueDef, duEmpty));
       }
     });
 
@@ -56,12 +136,96 @@ namespace ir {
     for (uint32_t inputID = 0; inputID < inputNum; ++inputID) {
       const FunctionInput &input = fn.getInput(inputID);
       ValueDef *valueDef = this->newValueDef(input);
-      DUChain *duChain = this->newDUChain();
-      duChain->first = valueDef;
-      duGraph.insert(std::make_pair(*valueDef, duChain));
+      duGraph.insert(std::make_pair(*valueDef, duEmpty));
+    }
+  }
+
+/*! Helper to deallocate objects */
+#define PTR_RELEASE(TYPE, VAR)                      \
+  do {                                              \
+    if (VAR && destroyed.contains(VAR) == false) {  \
+      destroyed.insert(VAR);                        \
+      delete##TYPE(VAR);                            \
+    }                                               \
+  } while (0)
+
+  FunctionDAG::~FunctionDAG(void) {
+
+    // We track the already destroyed pointers
+    set<void*> destroyed;
+
+    // Release the empty ud-chains and du-chains
+    PTR_RELEASE(ValueUse, udEmpty->second);
+    PTR_RELEASE(ValueDef, duEmpty->second);
+    PTR_RELEASE(UDChain, udEmpty);
+    PTR_RELEASE(DUChain, duEmpty);
+
+    // We free all the ud-chains
+    for (auto it = udGraph.begin(); it != udGraph.end(); ++it) {
+      auto udChain = it->second;
+      auto defs = udChain->first;
+      for (auto def = defs.begin(); def != defs.end(); ++def)
+        PTR_RELEASE(ValueDef, *def);
+      PTR_RELEASE(ValueUse, udChain->second);
+      PTR_RELEASE(UDChain, udChain);
     }
+
+    // We free all the du-chains
+    for (auto it = duGraph.begin(); it != duGraph.end(); ++it) {
+      auto duChain = it->second;
+      auto uses = duChain->first;
+      for (auto use = uses.begin(); use != uses.end(); ++use)
+        PTR_RELEASE(ValueUse, *use);
+      PTR_RELEASE(ValueDef, duChain->second);
+      PTR_RELEASE(DUChain, duChain);
+    }
+  }
+#undef PTR_RELEASE
+
+  const DUChain &FunctionDAG::getDUChain(const Instruction &insn, uint32_t dstID) const {
+    const ValueDef def(insn, dstID);
+    auto it = duGraph.find(def);
+    GBE_ASSERT(it != duGraph.end());
+    return *it->second;
   }
 
+  const DUChain &FunctionDAG::getDUChain(const FunctionInput &input) const {
+    const ValueDef def(input);
+    auto it = duGraph.find(def);
+    GBE_ASSERT(it != duGraph.end());
+    return *it->second;
+  }
+
+  const UDChain &FunctionDAG::getUDChain(const Instruction &insn, uint32_t srcID) const {
+    const ValueUse use(insn, srcID);
+    auto it = udGraph.find(use);
+    GBE_ASSERT(it != udGraph.end());
+    return *it->second;
+  }
+  const ValueUseSet &FunctionDAG::getUse(const Instruction &insn, uint32_t dstID) const {
+    const DUChain &chain = this->getDUChain(insn, dstID);
+    return chain.first;
+  }
+  const ValueUseSet &FunctionDAG::getUse(const FunctionInput &input) const {
+    const DUChain &chain = this->getDUChain(input);
+    return chain.first;
+  }
+  const ValueDefSet &FunctionDAG::getDef(const Instruction &insn, uint32_t srcID) const {
+    const UDChain &chain = this->getUDChain(insn, srcID);
+    return chain.first;
+  }
+  const ValueDef *FunctionDAG::getDefAddress(const Instruction &insn, uint32_t dstID) const {
+    const DUChain &chain = this->getDUChain(insn, dstID);
+    return chain.second;
+  }
+  const ValueDef *FunctionDAG::getDefAddress(const FunctionInput &input) const {
+    const DUChain &chain = this->getDUChain(input);
+    return chain.second;
+  }
+  const ValueUse *FunctionDAG::getUseAddress(const Instruction &insn, uint32_t srcID) const {
+    const UDChain &chain = this->getUDChain(insn, srcID);
+    return chain.second;
+  }
 } /* namespace ir */
 } /* namespace gbe */
 
index fdd3c62..3704b26 100644 (file)
@@ -48,20 +48,22 @@ namespace ir {
       INSTRUCTION_DST = 1
     };
     /*! Build a value from an instruction destination */
-    ValueDef(Instruction &insn, uint32_t dstID = 0u) : type(INSTRUCTION_DST) {
+    ValueDef(const Instruction &insn, uint32_t dstID = 0u) :
+      type(INSTRUCTION_DST)
+    {
       this->data.insn = &insn;
       this->data.dstID = dstID;
     }
     /*! Build a value from a function argument */
-    ValueDef(FunctionInput &input) : type(FUNCTION_INPUT) {
+    ValueDef(const FunctionInput &input) : type(FUNCTION_INPUT) {
       this->data.input = &input;
     }
     /*! Get the type of the value */
     INLINE Type getType(void) const { return type; }
     /*! Get the instruction (only if this is a instruction value) */
-    INLINE Instruction *getInstruction(void) const {
+    INLINE const Instruction &getInstruction(void) const {
       GBE_ASSERT(type == INSTRUCTION_DST);
-      return data.insn;
+      return *data.insn;
     }
     /*! Get the destination ID (only if this is a instruction value) */
     INLINE uint32_t getDstID(void) const {
@@ -69,9 +71,9 @@ namespace ir {
       return data.dstID;
     }
     /*! Get the function input (only if this is a function argument) */
-    INLINE FunctionInput *getFunctionInput(void) const {
+    INLINE const FunctionInput &getFunctionInput(void) const {
       GBE_ASSERT(type == FUNCTION_INPUT);
-      return data.input;
+      return *data.input;
     }
 
   private:
@@ -79,31 +81,31 @@ namespace ir {
     union Data {
       /*! Instruction destination or ... */
       struct {
-        Instruction *insn;  //<! Instruction itself
-        uint32_t dstID;     //<! Which destination we take into account
+        const Instruction *insn; //<! Instruction itself
+        uint32_t dstID;          //<! Which destination we take into account
       };
       /*! ... function argument */
-      FunctionInput *input;
+      const FunctionInput *input;
     } data;
     /*!< Function argument or instruction dst? */
     Type type;
   };
 
   /*! Compare two value definitions (used in maps) */
-  INLINE bool operator < (const ValueDef &def0, const ValueDef &def1) {
+  INLINE bool operator< (const ValueDef &def0, const ValueDef &def1) {
     const ValueDef::Type type0 = def0.getType();
     const ValueDef::Type type1 = def1.getType();
     if (type0 != type1) return uint32_t(type0) < uint32_t(type1);
     if (type0 == ValueDef::FUNCTION_INPUT) {
-      const FunctionInput *in0 = def0.getFunctionInput();
-      const FunctionInput *in1 = def1.getFunctionInput();
+      const FunctionInput *in0 = &def0.getFunctionInput();
+      const FunctionInput *in1 = &def1.getFunctionInput();
       return uintptr_t(in0) < uintptr_t(in1);
     } else {
-      const Instruction *insn0 = def0.getInstruction();
-      const Instruction *insn1 = def1.getInstruction();
+      const Instruction *insn0 = &def0.getInstruction();
+      const Instruction *insn1 = &def1.getInstruction();
       if (insn0 != insn1) return uintptr_t(insn0) < uintptr_t(insn1);
       const uint32_t dst0 = def0.getDstID();
-      const uint32_t dst1 = def0.getDstID();
+      const uint32_t dst1 = def1.getDstID();
       return dst0 < dst1;
     }
   }
@@ -118,7 +120,7 @@ namespace ir {
     ValueUse(const Instruction &insn, uint32_t srcID = 0u) :
       insn(&insn), srcID(srcID) {}
     /*! Get the instruction of the use */
-    const Instruction *getInstruction(void) const { return insn; }
+    const Instruction &getInstruction(void) const { return *insn; }
     /*! Get the source index for this use */
     uint32_t getSrcID(void) const { return srcID; }
   private:
@@ -127,49 +129,62 @@ namespace ir {
   };
 
   /*! Compare two value uses (used in maps) */
-  INLINE bool operator < (const ValueUse &use0, const ValueUse &use1) {
-    const Instruction *insn0 = use0.getInstruction();
-    const Instruction *insn1 = use1.getInstruction();
+  INLINE bool operator< (const ValueUse &use0, const ValueUse &use1) {
+    const Instruction *insn0 = &use0.getInstruction();
+    const Instruction *insn1 = &use1.getInstruction();
     if (insn0 != insn1) return uintptr_t(insn0) < uintptr_t(insn1);
     const uint32_t src0 = use0.getSrcID();
-    const uint32_t src1 = use0.getSrcID();
+    const uint32_t src1 = use1.getSrcID();
     return src0 < src1;
   }
 
   /*! All uses of a definition */
-  typedef std::pair<ValueDef*, set<ValueUse*>> DUChain;
+  typedef set<ValueUse*> ValueUseSet;
+  typedef std::pair<ValueUseSet, ValueDef*> DUChain;
   /*! All possible definitions for a use */
-  typedef std::pair<ValueUse*, set<ValueDef*>> UDChain;
+  typedef set<ValueDef*> ValueDefSet;
+  typedef std::pair<ValueDefSet, ValueUse*> UDChain;
 
   /*! Get the chains (in both directions) for the complete program */
-  class GraphUseDef
+  class FunctionDAG
   {
   public:
     /*! Build the complete DU/UD graphs for the program included in liveness */
-    GraphUseDef(const Liveness &liveness);
+    FunctionDAG(const Liveness &liveness);
+    /*! Free all the resources */
+    ~FunctionDAG(void);
+    /*! Get the du-chain for the given instruction and destination */
+    const DUChain &getDUChain(const Instruction &insn, uint32_t dstID) const;
+    /*! Get the du-chain for the given function input */
+    const DUChain &getDUChain(const FunctionInput &input) const;
+    /*! Get the ud-chain for the instruction and source */
+    const UDChain &getUDChain(const Instruction &insn, uint32_t srcID) const;
+    /*! Get the use set for the given definition */
+    const ValueUseSet &getUse(const Instruction &insn, uint32_t dstID) const;
+    /*! Get the use set for the function argument */
+    const ValueUseSet &getUse(const FunctionInput &input) const;
+    /*! Get the definition set for the given source */
+    const ValueDefSet &getDef(const Instruction &insn, uint32_t srcID) const;
+    /*! Get the pointer to the definition *as stored in the DAG* */
+    const ValueDef *getDefAddress(const Instruction &insn, uint32_t dstID) const;
+    /*! Get the pointer to the definition *as stored in the DAG* */
+    const ValueDef *getDefAddress(const FunctionInput &input) const;
+    /*! Get the pointer to the use *as stored in the DAG* */
+    const ValueUse *getUseAddress(const Instruction &insn, uint32_t srcID) const;
     /*! The UDChain for each definition use */
     typedef map<ValueUse, UDChain*> UDGraph;
     /*! The DUChain for each definition */
     typedef map<ValueDef, DUChain*> DUGraph;
   private:
-    UDGraph udGraph; //!< All the UD chains
-    DUGraph duGraph; //!< All the DU chains
-    GrowingPool<ValueUse> valueUsePool; //!< Allocate the value uses
-    GrowingPool<ValueDef> valueDefPool; //!< Allocate the value defs
-    GrowingPool<UDChain> udChainPool;   //!< Allocate all the ud-chains
-    GrowingPool<DUChain> duChainPool;   //!< Allocate all the du-chains
-#define DECL_ALLOCATE_DEALLOCATE(TYPE, POOL)                        \
-    template <typename... Args>                                     \
-    INLINE TYPE *new##TYPE(Args... args) {                          \
-      return new (POOL.allocate()) TYPE(args...);                   \
-    }                                                               \
-    INLINE void delete##TYPE(TYPE *ptr) { POOL.deallocate(ptr); }
-    DECL_ALLOCATE_DEALLOCATE(ValueDef, valueDefPool)
-    DECL_ALLOCATE_DEALLOCATE(ValueUse, valueUsePool)
-    DECL_ALLOCATE_DEALLOCATE(UDChain, udChainPool)
-    DECL_ALLOCATE_DEALLOCATE(DUChain, duChainPool)
-#undef DECL_ALLOCATE_DEALLOCATE
-    GBE_CLASS(GraphUseDef);
+    UDGraph udGraph;                   //!< All the UD chains
+    DUGraph duGraph;                   //!< All the DU chains
+    UDChain *udEmpty;                  //!< For all empty ud chains
+    DUChain *duEmpty;                  //!< For all empty du chains
+    DECL_POOL(ValueDef, valueDefPool); //!< Fast ValueDef allocation
+    DECL_POOL(ValueUse, valueUsePool); //!< Fast ValueUse allocation
+    DECL_POOL(UDChain, udChainPool);   //!< Fast UDChain allocation
+    DECL_POOL(DUChain, duChainPool);   //!< Fast DUChain allocation
+    GBE_CLASS(FunctionDAG);            //!< Use internal allocators
   };
 
 } /* namespace ir */
index 624aad4..5e5d2ca 100644 (file)
@@ -87,6 +87,8 @@ namespace gbe
     else                                                     \
       return gbe::memFree(ptr);                              \
   }                                                          \
+  void* operator new(size_t size, void *p) { return p; }     \
+  void* operator new[](size_t size, void *p) { return p; }   \
 
 /*! Declare a class with custom allocators */
 #define GBE_CLASS(TYPE) \
@@ -94,19 +96,6 @@ public:                 \
   GBE_STRUCT(TYPE)      \
 private:
 
-/*! Declare an aligned structure */
-#define GBE_ALIGNED_STRUCT(ALIGN)                                               \
-  void* operator new(size_t size)   { return gbe::alignedMalloc(size, ALIGN); } \
-  void* operator new[](size_t size) { return gbe::alignedMalloc(size, ALIGN); } \
-  void  operator delete(void* ptr)   { gbe::alignedFree(ptr); }                 \
-  void  operator delete[](void* ptr) { gbe::alignedFree(ptr); }
-
-/*! Declare an aligned class */
-#define GBE_ALIGNED_CLASS(ALIGN)    \
-public:                             \
-  GBE_ALIGNED_STRUCT(ALIGN)         \
-private:
-
 /*! Macros to handle allocation position */
 #define GBE_NEW(T,...)               \
   gbe::_MemDebuggerInsertAlloc(new T(__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__)
@@ -232,6 +221,18 @@ namespace gbe
     void *freeList;           //!< Elements that have been deallocated
     GBE_CLASS(GrowingPool);
   };
+
+/*! Helper macros to build and destroy objects with a pool */
+#define DECL_POOL(TYPE, POOL)                     \
+  GrowingPool<TYPE> POOL;                         \
+  template <typename... Args>                     \
+  INLINE TYPE *new##TYPE(Args... args) {          \
+    return new (POOL.allocate()) TYPE(args...);   \
+  }                                               \
+  INLINE void delete##TYPE(TYPE *ptr) {           \
+    ptr->~TYPE();                                 \
+    POOL.deallocate(ptr);                         \
+  }
 } /* namespace gbe */
 
 #endif /* __GBE_ALLOC_HPP__ */
index 2298150..6e9d8dd 100644 (file)
@@ -60,6 +60,10 @@ namespace gbe
       parent_type(first, last, comp, a) {}
     /*! Copy constructor */
     INLINE map(const map& x) : parent_type(x) {}
+    /*! Better than using find if we do not care about the iterator itself */
+    INLINE bool contains(const Key &key) const {
+      return this->find(key) != this->end();
+    }
     GBE_CLASS(map);
   };
 } /* namespace gbe */
index cffca70..bf1da2d 100644 (file)
@@ -55,6 +55,10 @@ namespace gbe
       parent_type(first, last, comp, a) {}
     /*! Copy constructor */
     INLINE set(const set& x) : parent_type(x) {}
+    /*! Better than using find if we do not care about the iterator itself */
+    INLINE bool contains(const Key &key) const {
+      return this->find(key) != this->end();
+    }
     GBE_CLASS(set);
   };
 
index db8097b..d368c35 100644 (file)
@@ -28,6 +28,7 @@
 #include "llvm/llvm_to_gen.hpp"
 #include "ir/unit.hpp"
 #include "ir/liveness.hpp"
+#include "ir/value.hpp"
 #include <cstdlib>
 
 namespace gbe
@@ -52,6 +53,7 @@ namespace gbe
 
     unit.apply([](ir::Function &fn) {
       ir::Liveness liveness(fn);
+      ir::FunctionDAG dag(liveness);
       std::cout << liveness << std::endl;
     });
   }