[llvm-commits] CVS: poolalloc/lib/PoolAllocate/PointerCompress.cpp

Chris Lattner lattner at cs.uiuc.edu
Thu Feb 10 12:39:22 PST 2005



Changes in directory poolalloc/lib/PoolAllocate:

PointerCompress.cpp updated: 1.2 -> 1.3

---
Log message:

Implement pointer compression for some instructions.  This can successfully
compress data structures that are only involved with the null pointer,
store, cast, and malloc instructions.

No frees, loads, etc allowed! :-)


---
Diffs of the changes:  (+253 -21)

Index: poolalloc/lib/PoolAllocate/PointerCompress.cpp
diff -u poolalloc/lib/PoolAllocate/PointerCompress.cpp:1.2 poolalloc/lib/PoolAllocate/PointerCompress.cpp:1.3
--- poolalloc/lib/PoolAllocate/PointerCompress.cpp:1.2	Wed Feb  9 16:55:53 2005
+++ poolalloc/lib/PoolAllocate/PointerCompress.cpp	Thu Feb 10 14:39:11 2005
@@ -14,6 +14,8 @@
 #define DEBUG_TYPE "pointercompress"
 #include "EquivClassGraphs.h"
 #include "PoolAllocate.h"
+#include "llvm/Constants.h"
+#include "llvm/Instructions.h"
 #include "llvm/Module.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Support/Debug.h"
@@ -34,12 +36,14 @@
     PoolAllocate *PoolAlloc;
     PA::EquivClassGraphs *ECG;
   public:
+    Function *PoolInitPC, *PoolDestroyPC, *PoolAllocPC, *PoolFreePC;
     typedef std::map<const DSNode*, CompressedPoolInfo> PoolInfoMap;
 
     bool runOnModule(Module &M);
     void getAnalysisUsage(AnalysisUsage &AU) const;
 
   private:
+    void InitializePoolLibraryFunctions(Module &M);
     bool CompressPoolsInFunction(Function &F);
     void FindPoolsToCompress(std::vector<const DSNode*> &Pools, Function &F,
                              DSGraph &DSG, PA::FuncInfo *FI);
@@ -58,17 +62,29 @@
   /// pool that is compressed.
   class CompressedPoolInfo {
     const DSNode *Pool;
+    Value *PoolDesc;
     const Type *NewTy;
+    unsigned NewSize;
   public:
-    CompressedPoolInfo(const DSNode *N) : Pool(N), NewTy(0) {}
+    CompressedPoolInfo(const DSNode *N, Value *PD)
+      : Pool(N), PoolDesc(PD), NewTy(0) {}
     
     /// Initialize - When we know all of the pools in a function that are going
     /// to be compressed, initialize our state based on that data.
-    void Initialize(std::map<const DSNode*, CompressedPoolInfo> &Nodes);
+    void Initialize(std::map<const DSNode*, CompressedPoolInfo> &Nodes,
+                    const TargetData &TD);
 
     const DSNode *getNode() const { return Pool; }
     const Type *getNewType() const { return NewTy; }
 
+    /// getNewSize - Return the size of each node after compression.
+    ///
+    unsigned getNewSize() const { return NewSize; }
+    
+    /// getPoolDesc - Return the Value* for the pool descriptor for this pool.
+    ///
+    Value *getPoolDesc() const { return PoolDesc; }
+
     // dump - Emit a debugging dump of this pool info.
     void dump() const;
 
@@ -81,11 +97,14 @@
 /// Initialize - When we know all of the pools in a function that are going
 /// to be compressed, initialize our state based on that data.
 void CompressedPoolInfo::Initialize(std::map<const DSNode*, 
-                                             CompressedPoolInfo> &Nodes) {
+                                             CompressedPoolInfo> &Nodes,
+                                    const TargetData &TD) {
   // First step, compute the type of the compressed node.  This basically
   // replaces all pointers to compressed pools with uints.
   NewTy = ComputeCompressedType(Pool->getType(), 0, Nodes);
 
+  // Get the compressed type size.
+  NewSize = TD.getTypeSize(NewTy);
 }
 
 
@@ -197,38 +216,224 @@
 
 
 namespace {
+  /// InstructionRewriter - This class implements the rewriting neccesary to
+  /// transform a function body from normal pool allocation to pointer
+  /// compression.  It is constructed, then the 'visit' method is called on a
+  /// function.  If is responsible for rewriting all instructions that refer to
+  /// pointers into compressed pools.
   class InstructionRewriter : public llvm::InstVisitor<InstructionRewriter> {
     /// OldToNewValueMap - This keeps track of what new instructions we create
     /// for instructions that used to produce pointers into our pool.
     std::map<Value*, Value*> OldToNewValueMap;
   
-    /// ForwardRefs - If a value is refered to before it is defined, create a
-    /// temporary Argument node as a placeholder.  When the value is really
-    /// defined, call replaceAllUsesWith on argument and remove it from this
-    /// map.
-    std::map<Value*, Argument*> ForwardRefs;
-
     const PointerCompress::PoolInfoMap &PoolInfo;
 
     const DSGraph &DSG;
+
+    PointerCompress &PtrComp;
   public:
     InstructionRewriter(const PointerCompress::PoolInfoMap &poolInfo,
-                        const DSGraph &dsg)
-      : PoolInfo(poolInfo), DSG(dsg) {
+                        const DSGraph &dsg, PointerCompress &ptrcomp)
+      : PoolInfo(poolInfo), DSG(dsg), PtrComp(ptrcomp) {
+    }
+
+    ~InstructionRewriter();
+
+    /// getTransformedValue - Return the transformed version of the specified
+    /// value, creating a new forward ref value as needed.
+    Value *getTransformedValue(Value *V) {
+      if (isa<ConstantPointerNull>(V))                // null -> uint 0
+        return Constant::getNullValue(Type::UIntTy);
+
+      assert(getNodeIfCompressed(V) && "Value is not compressed!");
+      Value *&RV = OldToNewValueMap[V];
+      if (RV) return RV;
+
+      RV = new Argument(Type::UIntTy);
+      return RV;
+    }
+
+    /// setTransformedValue - When we create a new value, this method sets it as
+    /// the current value.
+    void setTransformedValue(Instruction &Old, Value *New) {
+      Value *&EV = OldToNewValueMap[&Old];
+      if (EV) {
+        assert(isa<Argument>(EV) && "Not a forward reference!");
+        EV->replaceAllUsesWith(New);
+        delete EV;
+      }
+      EV = New;
     }
-    ~InstructionRewriter() {
-      assert(ForwardRefs.empty() && "Unresolved forward refs exist!");
+
+    /// getNodeIfCompressed - If the specified value is a pointer that will be
+    /// compressed, return the DSNode corresponding to the pool it belongs to.
+    const DSNode *getNodeIfCompressed(Value *V) {
+      if (!isa<PointerType>(V->getType())) return false;
+      DSNode *N = DSG.getNodeForValue(V).getNode();
+      return PoolInfo.count(N) ? N : 0;
     }
 
+    /// getPoolInfo - Return the pool info for the specified compressed pool.
+    ///
+    const CompressedPoolInfo &getPoolInfo(const DSNode *N) {
+      assert(N && "Pool not compressed!");
+      PointerCompress::PoolInfoMap::const_iterator I = PoolInfo.find(N);
+      assert(I != PoolInfo.end() && "Pool is not compressed!");
+      return I->second;
+    }
+
+    /// getPoolInfo - Return the pool info object for the specified value if the
+    /// pointer points into a compressed pool, otherwise return null.
+    const CompressedPoolInfo *getPoolInfo(Value *V) {
+      if (const DSNode *N = getNodeIfCompressed(V))
+        return &getPoolInfo(N);
+      return 0;
+    }
+
+    //===------------------------------------------------------------------===//
+    // Visitation methods.  These do all of the heavy lifting for the various
+    // cases we have to handle.
+
+    void visitCastInst(CastInst &CI);
+    void visitStoreInst(StoreInst &SI);
+
+    void visitCallInst(CallInst &CI);
+    void visitPoolInit(CallInst &CI);
+    void visitPoolDestroy(CallInst &CI);
+    void visitPoolAlloc(CallInst &CI);
+    void visitPoolFree(CallInst &CI);
+
     void visitInstruction(Instruction &I) {
-      std::cerr << "ERROR: UNHANDLED INSTRUCTION: " << I;
-      //assert(0);
-      //abort();
+#ifndef NDEBUG
+      bool Unhandled = !!getNodeIfCompressed(&I);
+      for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i)
+        Unhandled |= !!getNodeIfCompressed(I.getOperand(i));
+
+      if (Unhandled) {
+        std::cerr << "ERROR: UNHANDLED INSTRUCTION: " << I;
+        //assert(0);
+        //abort();
+      }
+#endif
     }
   };
 } // end anonymous namespace.
 
 
+InstructionRewriter::~InstructionRewriter() {
+  // Nuke all of the old values from the program.
+  for (std::map<Value*, Value*>::iterator I = OldToNewValueMap.begin(),
+         E = OldToNewValueMap.end(); I != E; ++I) {
+    assert((!isa<Argument>(I->second) || cast<Argument>(I->second)->getParent())
+           && "ERROR: Unresolved value still left in the program!");
+    // If there is anything still using this, provide a temporary value.
+    if (!I->first->use_empty())
+      I->first->replaceAllUsesWith(UndefValue::get(I->first->getType()));
+
+    // Finally, remove it from the program.
+    cast<Instruction>(I->first)->eraseFromParent();
+  }
+}
+
+
+void InstructionRewriter::visitCastInst(CastInst &CI) {
+  if (!isa<PointerType>(CI.getType())) return;
+
+  const CompressedPoolInfo *PI = getPoolInfo(&CI);
+  if (!PI) return;
+  assert(getPoolInfo(CI.getOperand(0)) == PI && "Not cast from ptr -> ptr?");
+
+  // A cast from one pointer to another turns into a cast from uint -> uint,
+  // which is a noop.
+  setTransformedValue(CI, getTransformedValue(CI.getOperand(0)));
+}
+
+void InstructionRewriter::visitStoreInst(StoreInst &SI) {
+  const CompressedPoolInfo *DestPI = getPoolInfo(SI.getOperand(1));
+  if (DestPI == 0) {
+    assert(getPoolInfo(SI.getOperand(0)) == 0 &&
+           "Cannot store a compressed pointer into non-compressed memory!");
+    return;
+  }
+
+  // We care about two cases, here:
+  //  1. Storing a normal value into a ptr compressed data structure.
+  //  2. Storing a compressed ptr into a ptr compressed data structure.  Note
+  //     that we cannot use the src value to decide if this is a compressed
+  //     pointer if it's a null pointer.  We have to try harder.
+  //
+  Value *SrcVal = SI.getOperand(0);
+  if (!isa<ConstantPointerNull>(SrcVal)) {
+    const CompressedPoolInfo *SrcPI = getPoolInfo(SrcVal);
+    if (SrcPI)     // If the stored value is compressed, get the xformed version
+      SrcVal = getTransformedValue(SrcVal);
+  } else {
+    // FIXME: This assumes that all pointers are compressed!
+    SrcVal = getTransformedValue(SrcVal);
+  }
+  
+  // Get the pool base pointer.
+  Constant *Zero = Constant::getNullValue(Type::UIntTy);
+  Value *BasePtrPtr = new GetElementPtrInst(DestPI->getPoolDesc(), Zero, Zero,
+                                            "poolbaseptrptr", &SI);
+  Value *BasePtr = new LoadInst(BasePtrPtr, "poolbaseptr", &SI);
+  std::vector<Value*> Ops;
+  Ops.push_back(getTransformedValue(SI.getOperand(1)));
+  Value *DestPtr = new GetElementPtrInst(BasePtr, Ops,
+                                         SI.getOperand(1)->getName()+".pp",
+                                         &SI);
+  DestPtr = new CastInst(DestPtr, PointerType::get(SrcVal->getType()),
+                         DestPtr->getName(), &SI);
+  new StoreInst(SrcVal, DestPtr, &SI);
+
+  // Finally, explicitly remove the store from the program, as it does not
+  // produce a pointer result.
+  SI.eraseFromParent();
+}
+
+
+void InstructionRewriter::visitPoolInit(CallInst &CI) {
+  // Transform to poolinit_pc if necessary.
+}
+
+void InstructionRewriter::visitPoolDestroy(CallInst &CI) {
+  // Transform to pooldestroy_pc if necessary.
+  /* TODO */
+}
+void InstructionRewriter::visitPoolAlloc(CallInst &CI) {
+  // Transform to poolalloc_pc if necessary.
+  const CompressedPoolInfo *PI = getPoolInfo(&CI);
+  if (PI == 0) return;  // Not a compressed pool!
+
+  std::vector<Value*> Ops;
+  Ops.push_back(CI.getOperand(1));
+  Ops.push_back(ConstantUInt::get(Type::UIntTy, PI->getNewSize()));
+  Value *New = new CallInst(PtrComp.PoolAllocPC, Ops, CI.getName(), &CI);
+  setTransformedValue(CI, New);
+}
+
+void InstructionRewriter::visitPoolFree(CallInst &CI) {
+  // Transform to poolfree_pc if necessary.
+}
+
+void InstructionRewriter::visitCallInst(CallInst &CI) {
+  if (Function *F = CI.getCalledFunction())
+    if (F->getName() == "poolinit") {
+      visitPoolInit(CI);
+      return;
+    } else if (F->getName() == "pooldestroy") {
+      visitPoolDestroy(CI);
+      return;
+    } else if (F->getName() == "poolalloc") {
+      visitPoolAlloc(CI);
+      return;
+    } else if (F->getName() == "poolfree") {
+      visitPoolFree(CI);
+      return;
+    }
+  
+  visitInstruction(CI);
+}
 
 
 /// CompressPoolsInFunction - Find all pools that are compressible in this
@@ -264,30 +469,57 @@
 
   // Compute the initial collection of compressed pointer infos.
   std::map<const DSNode*, CompressedPoolInfo> PoolsToCompress;
-  for (unsigned i = 0, e = PoolsToCompressList.size(); i != e; ++i)
-    PoolsToCompress.insert(std::make_pair(PoolsToCompressList[i], 
-                                          PoolsToCompressList[i]));
+  for (unsigned i = 0, e = PoolsToCompressList.size(); i != e; ++i) {
+    const DSNode *N = PoolsToCompressList[i];
+    Value *PD = FI->PoolDescriptors[N];
+    assert(PD && "No pool descriptor available for this pool???");
+    PoolsToCompress.insert(std::make_pair(N, CompressedPoolInfo(N, PD)));
+  }
 
   // Use these to compute the closure of compression information.  In
   // particular, if one pool points to another, we need to know if the outgoing
   // pointer is compressed.
+  const TargetData &TD = DSG.getTargetData();
   std::cerr << "In function '" << F.getName() << "':\n";
   for (std::map<const DSNode*, CompressedPoolInfo>::iterator
          I = PoolsToCompress.begin(), E = PoolsToCompress.end(); I != E; ++I) {
-    I->second.Initialize(PoolsToCompress);
+    I->second.Initialize(PoolsToCompress, TD);
     std::cerr << "  COMPRESSING POOL:\nPCS:";
     I->second.dump();
   }
   
   // Finally, rewrite the function body to use compressed pointers!
-  InstructionRewriter(PoolsToCompress, DSG).visit(F);
+  InstructionRewriter(PoolsToCompress, DSG, *this).visit(F);
   return true;
 }
 
+
+/// InitializePoolLibraryFunctions - Create the function prototypes for pointer
+/// compress runtime library functions.
+void PointerCompress::InitializePoolLibraryFunctions(Module &M) {
+  const Type *VoidPtrTy = PointerType::get(Type::SByteTy);
+  const Type *PoolDescPtrTy = PointerType::get(ArrayType::get(VoidPtrTy, 16));
+
+  PoolInitPC = M.getOrInsertFunction("poolinit_pc", Type::VoidTy,
+                                     PoolDescPtrTy, Type::UIntTy,
+                                     Type::UIntTy, 0);
+  PoolDestroyPC = M.getOrInsertFunction("pooldestroy_pc", Type::VoidTy,
+                                        PoolDescPtrTy, 0);
+  PoolAllocPC = M.getOrInsertFunction("poolalloc_pc",  Type::UIntTy,
+                                      PoolDescPtrTy, Type::UIntTy, 0);
+  PoolFreePC = M.getOrInsertFunction("poolfree_pc",  Type::VoidTy,
+                                      PoolDescPtrTy, Type::UIntTy, 0);
+  // FIXME: Need bumppointer versions as well as realloc??/memalign??
+}  
+
 bool PointerCompress::runOnModule(Module &M) {
   PoolAlloc = &getAnalysis<PoolAllocate>();
   ECG = &getAnalysis<PA::EquivClassGraphs>();
 
+  // Create the function prototypes for pointer compress runtime library
+  // functions.
+  InitializePoolLibraryFunctions(M);
+
   // Iterate over all functions in the module, looking for compressible data
   // structures.
   bool Changed = false;





More information about the llvm-commits mailing list