[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