[llvm-commits] CVS: llvm/lib/Transforms/IPO/PoolAllocate.cpp

Sumant Kowshik kowshik at cs.uiuc.edu
Thu May 29 17:43:01 PDT 2003


Changes in directory llvm/lib/Transforms/IPO:

PoolAllocate.cpp updated: 1.5 -> 1.6

---
Log message:




---
Diffs of the changes:

Index: llvm/lib/Transforms/IPO/PoolAllocate.cpp
diff -u llvm/lib/Transforms/IPO/PoolAllocate.cpp:1.5 llvm/lib/Transforms/IPO/PoolAllocate.cpp:1.6
--- llvm/lib/Transforms/IPO/PoolAllocate.cpp:1.5	Wed Apr 16 15:28:39 2003
+++ llvm/lib/Transforms/IPO/PoolAllocate.cpp	Thu May 29 17:42:44 2003
@@ -33,9 +33,73 @@
 
 void PoolAllocate::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<BUDataStructures>();
+  AU.addRequired<TDDataStructures>();
   AU.addRequired<TargetData>();
 }
 
+// Prints out the functions mapped to the leader of the equivalence class they
+// belong to.
+void PoolAllocate::printFuncECs() {
+  map<Function*, Function*> leaderMap = FuncECs.getLeaderMap();
+  std::cerr << "Indirect Function Map \n";
+  for (map<Function*, Function*>::iterator LI = leaderMap.begin(),
+	 LE = leaderMap.end(); LI != LE; ++LI) {
+    std::cerr << LI->first->getName() << ": leader is "
+	      << LI->second->getName() << "\n";
+  }
+}
+
+void PoolAllocate::buildIndirectFunctionSets(Module &M) {
+  // Iterate over the module looking for indirect calls to functions
+
+  // Get top down DSGraph for the functions
+  TDDS = &getAnalysis<TDDataStructures>();
+  
+  for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
+
+    DEBUG(std::cerr << "Processing indirect calls function:" <<  MI->getName() << "\n");
+
+    if (MI->isExternal())
+      continue;
+
+    DSGraph &TDG = TDDS->getDSGraph(*MI);
+
+    std::vector<DSCallSite> callSites = TDG.getFunctionCalls();
+
+    // For each call site in the function
+    // All the functions that can be called at the call site are put in the
+    // same equivalence class.
+    for (vector<DSCallSite>::iterator CSI = callSites.begin(), 
+	   CSE = callSites.end(); CSI != CSE ; ++CSI) {
+      if (CSI->isIndirectCall()) {
+	DSNode *DSN = CSI->getCalleeNode();
+	// assert(DSN->NodeType == DSNode::GlobalNode);
+	std::vector<GlobalValue*> Callees = DSN->getGlobals();
+	if (Callees.size() > 0) {
+	  Function *firstCalledF = dyn_cast<Function>(*Callees.begin());
+	  FuncECs.addElement(firstCalledF);
+	  CallInstTargets[&CSI->getCallInst()].push_back(firstCalledF);
+	  if (Callees.size() > 1) {
+	    for (std::vector<GlobalValue*>::iterator CalleesI = 
+		   ++Callees.begin(), CalleesE = Callees.end(); 
+		 CalleesI != CalleesE; ++CalleesI) {
+	      Function *calledF = dyn_cast<Function>(*CalleesI);
+	      FuncECs.unionElements(firstCalledF, calledF);
+	      CallInstTargets[&CSI->getCallInst()].push_back(calledF);
+	    }
+	  }
+	} else {
+	  std::cerr << "Callee has no targets\n";
+	}
+      }
+    }
+  }
+  
+  // Print the equivalence classes
+  DEBUG(printFuncECs());
+  
+}
+
 bool PoolAllocate::run(Module &M) {
   if (M.begin() == M.end()) return false;
   CurModule = &M;
@@ -43,18 +107,32 @@
   AddPoolPrototypes();
   BU = &getAnalysis<BUDataStructures>();
 
+  buildIndirectFunctionSets(M);
+
   std::map<Function*, Function*> FuncMap;
 
+   // Loop over the functions in the original program finding the pool desc.
+  // arguments necessary for each function that is indirectly callable.
+  // For each equivalence class, make a list of pool arguments and update
+  // the PoolArgFirst and PoolArgLast values for each function.
+  Module::iterator LastOrigFunction = --M.end();
+  for (Module::iterator I = M.begin(); ; ++I) {
+    if (!I->isExternal())
+      FindFunctionPoolArgs(*I);
+    if (I == LastOrigFunction) break;
+  }
+
+  // Now clone a function using the pool arg list obtained in the previous
+  // pass over the modules.
   // Loop over only the function initially in the program, don't traverse newly
   // added ones.  If the function uses memory, make its clone.
-  Module::iterator LastOrigFunction = --M.end();
   for (Module::iterator I = M.begin(); ; ++I) {
     if (!I->isExternal())
       if (Function *R = MakeFunctionClone(*I))
         FuncMap[I] = R;
     if (I == LastOrigFunction) break;
   }
-
+  
   ++LastOrigFunction;
 
   // Now that all call targets are available, rewrite the function bodies of the
@@ -65,7 +143,6 @@
       ProcessFunctionBody(*I, FI != FuncMap.end() ? *FI->second : *I);
     }
 
-  FunctionInfo.clear();
   return true;
 }
 
@@ -75,7 +152,7 @@
 //
 void PoolAllocate::AddPoolPrototypes() {
   CurModule->addTypeName("PoolDescriptor", PoolDescType);
-
+  
   // Get poolinit function...
   FunctionType *PoolInitTy =
     FunctionType::get(Type::VoidTy,
@@ -88,42 +165,54 @@
   FunctionType *PoolDestroyTy =
     FunctionType::get(Type::VoidTy, PDArgs, false);
   PoolDestroy = CurModule->getOrInsertFunction("pooldestroy", PoolDestroyTy);
-
+  
   // Get the poolalloc function...
   FunctionType *PoolAllocTy = FunctionType::get(VoidPtrTy, PDArgs, false);
   PoolAlloc = CurModule->getOrInsertFunction("poolalloc", PoolAllocTy);
-
+  
   // Get the poolfree function...
   PDArgs.push_back(VoidPtrTy);       // Pointer to free
   FunctionType *PoolFreeTy = FunctionType::get(Type::VoidTy, PDArgs, false);
   PoolFree = CurModule->getOrInsertFunction("poolfree", PoolFreeTy);
-
-#if 0
-  Args[0] = Type::UIntTy;            // Number of slots to allocate
-  FunctionType *PoolAllocArrayTy = FunctionType::get(VoidPtrTy, Args, true);
-  PoolAllocArray = CurModule->getOrInsertFunction("poolallocarray",
-                                                  PoolAllocArrayTy);
-#endif
+  
+  // The poolallocarray function
+  FunctionType *PoolAllocArrayTy =
+    FunctionType::get(VoidPtrTy,
+                      make_vector<const Type*>(PoolDescPtr, Type::UIntTy, 0),
+                      false);
+  PoolAllocArray = CurModule->getOrInsertFunction("poolallocarray", 
+						  PoolAllocArrayTy);
+  
 }
 
-
-// MakeFunctionClone - If the specified function needs to be modified for pool
-// allocation support, make a clone of it, adding additional arguments as
-// neccesary, and return it.  If not, just return null.
-//
-Function *PoolAllocate::MakeFunctionClone(Function &F) {
+void PoolAllocate::FindFunctionPoolArgs(Function &F) {
   DSGraph &G = BU->getDSGraph(F);
   std::vector<DSNode*> &Nodes = G.getNodes();
-  if (Nodes.empty()) return 0;  // No memory activity, nothing is required
+  if (Nodes.empty()) return ;  // No memory activity, nothing is required
 
   FuncInfo &FI = FunctionInfo[&F];   // Create a new entry for F
+  
   FI.Clone = 0;
-
+  
+  // Initialize the PoolArgFirst and PoolArgLast for the function depending
+  // on whether there have been other functions in the equivalence class
+  // that have pool arguments so far in the analysis.
+  if (!FuncECs.findClass(&F)) {
+    FI.PoolArgFirst = FI.PoolArgLast = 0;
+  } else {
+    if (EqClass2LastPoolArg.find(FuncECs.findClass(&F)) != 
+	EqClass2LastPoolArg.end())
+      FI.PoolArgFirst = FI.PoolArgLast = 
+	EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1;
+    else
+      FI.PoolArgFirst = FI.PoolArgLast = 0;
+  }
+  
   // Find DataStructure nodes which are allocated in pools non-local to the
   // current function.  This set will contain all of the DSNodes which require
   // pools to be passed in from outside of the function.
   hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
-
+  
   // Mark globals and incomplete nodes as live... (this handles arguments)
   if (F.getName() != "main")
     for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
@@ -137,22 +226,86 @@
       RetNode->markReachableNodes(MarkedNodes);
 
   if (MarkedNodes.empty())   // We don't need to clone the function if there
-    return 0;                // are no incoming arguments to be added.
+    return;                  // are no incoming arguments to be added.
+
+  for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
+	 E = MarkedNodes.end(); I != E; ++I)
+    FI.PoolArgLast++;
+
+  if (FuncECs.findClass(&F)) {
+    // Update the equivalence class last pool argument information
+    // only if there actually were pool arguments to the function.
+    // Also, there is no entry for the Eq. class in EqClass2LastPoolArg
+    // if there are no functions in the equivalence class with pool arguments.
+    if (FI.PoolArgLast != FI.PoolArgFirst)
+      EqClass2LastPoolArg[FuncECs.findClass(&F)] = FI.PoolArgLast - 1;
+  }
+  
+}
 
+// MakeFunctionClone - If the specified function needs to be modified for pool
+// allocation support, make a clone of it, adding additional arguments as
+// neccesary, and return it.  If not, just return null.
+//
+Function *PoolAllocate::MakeFunctionClone(Function &F) {
+  
+  DSGraph &G = BU->getDSGraph(F);
+  std::vector<DSNode*> &Nodes = G.getNodes();
+  if (Nodes.empty())
+    return 0;
+    
+  FuncInfo &FI = FunctionInfo[&F];
+  
+  hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
+  
+  if (!FuncECs.findClass(&F)) {
+    // Not in any equivalence class
+
+    if (MarkedNodes.empty())
+      return 0;
+  } else {
+    // No need to clone if there are no pool arguments in any function in the
+    // equivalence class
+    if (!EqClass2LastPoolArg.count(FuncECs.findClass(&F)))
+      return 0;
+  }
+      
   // Figure out what the arguments are to be for the new version of the function
   const FunctionType *OldFuncTy = F.getFunctionType();
   std::vector<const Type*> ArgTys;
-  ArgTys.reserve(OldFuncTy->getParamTypes().size() + MarkedNodes.size());
-
-  FI.ArgNodes.reserve(MarkedNodes.size());
-  for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
-         E = MarkedNodes.end(); I != E; ++I)
-    if ((*I)->NodeType & DSNode::Incomplete) {
+  if (!FuncECs.findClass(&F)) {
+    ArgTys.reserve(OldFuncTy->getParamTypes().size() + MarkedNodes.size());
+    FI.ArgNodes.reserve(MarkedNodes.size());
+    for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
+	   E = MarkedNodes.end(); I != E; ++I) {
       ArgTys.push_back(PoolDescPtr);      // Add the appropriate # of pool descs
       FI.ArgNodes.push_back(*I);
     }
-  if (FI.ArgNodes.empty()) return 0;      // No nodes to be pool allocated!
+    if (FI.ArgNodes.empty()) return 0;      // No nodes to be pool allocated!
+
+  }
+  else {
+    // This function is a member of an equivalence class and needs to be cloned 
+    ArgTys.reserve(OldFuncTy->getParamTypes().size() + 
+		   EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1);
+    FI.ArgNodes.reserve(EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1);
+    
+    for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i) {
+      ArgTys.push_back(PoolDescPtr);      // Add the appropriate # of pool 
+                                          // descs
+    }
+
+    for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
+	   E = MarkedNodes.end(); I != E; ++I) {
+      FI.ArgNodes.push_back(*I);
+    }
 
+    assert ((FI.ArgNodes.size() == (unsigned) (FI.PoolArgLast - 
+					       FI.PoolArgFirst)) && 
+	    "Number of ArgNodes equal to the number of pool arguments used by this function");
+  }
+      
+      
   ArgTys.insert(ArgTys.end(), OldFuncTy->getParamTypes().begin(),
                 OldFuncTy->getParamTypes().end());
 
@@ -168,18 +321,45 @@
   // pool descriptors map
   std::map<DSNode*, Value*> &PoolDescriptors = FI.PoolDescriptors;
   Function::aiterator NI = New->abegin();
-  for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI) {
-    NI->setName("PDa");  // Add pd entry
-    PoolDescriptors.insert(std::make_pair(FI.ArgNodes[i], NI));
+  
+  if (FuncECs.findClass(&F)) {
+    for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i, 
+	   ++NI)
+      NI->setName("PDa");
+    
+    NI = New->abegin();
+    if (FI.PoolArgFirst > 0)
+      for (int i = 0; i < FI.PoolArgFirst; ++NI, ++i)
+	;
+
+    if (FI.ArgNodes.size() > 0)
+      for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI)
+	PoolDescriptors.insert(std::make_pair(FI.ArgNodes[i], NI));
+
+    NI = New->abegin();
+    if (EqClass2LastPoolArg.count(FuncECs.findClass(&F)))
+      for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i, ++NI)
+	;
+  } else {
+    if (FI.ArgNodes.size())
+      for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI) {
+	NI->setName("PDa");  // Add pd entry
+	PoolDescriptors.insert(std::make_pair(FI.ArgNodes[i], NI));
+      }
+    NI = New->abegin();
+    if (FI.ArgNodes.size())
+      for (unsigned i = 0; i < FI.ArgNodes.size(); ++NI, ++i)
+	;
   }
 
   // Map the existing arguments of the old function to the corresponding
   // arguments of the new function.
   std::map<const Value*, Value*> ValueMap;
-  for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I, ++NI) {
-    ValueMap[I] = NI;
-    NI->setName(I->getName());
-  }
+  if (NI != New->aend()) 
+    for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I, ++NI) {
+      ValueMap[I] = NI;
+      NI->setName(I->getName());
+    }
 
   // Populate the value map with all of the globals in the program.
   // FIXME: This should be unneccesary!
@@ -208,28 +388,27 @@
   DSGraph &G = BU->getDSGraph(F);
   std::vector<DSNode*> &Nodes = G.getNodes();
   if (Nodes.empty()) return;     // Quick exit if nothing to do...
-
+  
   FuncInfo &FI = FunctionInfo[&F];   // Get FuncInfo for F
   hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
- 
+  
   DEBUG(std::cerr << "[" << F.getName() << "] Pool Allocate: ");
-
+  
   // Loop over all of the nodes which are non-escaping, adding pool-allocatable
   // ones to the NodesToPA vector.
   std::vector<DSNode*> NodesToPA;
   for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
     if (Nodes[i]->NodeType & DSNode::HeapNode &&   // Pick nodes with heap elems
-        !(Nodes[i]->NodeType & DSNode::Array) &&   // Doesn't handle arrays yet.
         !MarkedNodes.count(Nodes[i]))              // Can't be marked
       NodesToPA.push_back(Nodes[i]);
-
+  
   DEBUG(std::cerr << NodesToPA.size() << " nodes to pool allocate\n");
   if (!NodesToPA.empty()) {
     // Create pool construction/destruction code
     std::map<DSNode*, Value*> &PoolDescriptors = FI.PoolDescriptors;
     CreatePools(NewF, NodesToPA, PoolDescriptors);
   }
-
+  
   // Transform the body of the function now...
   TransformFunctionBody(NewF, G, FI);
 }
@@ -257,23 +436,28 @@
   Instruction *InsertPoint = F.front().begin();
   for (unsigned i = 0, e = NodesToPA.size(); i != e; ++i) {
     DSNode *Node = NodesToPA[i];
-
+    
     // Create a new alloca instruction for the pool...
     Value *AI = new AllocaInst(PoolDescType, 0, "PD", InsertPoint);
-
-    Value *ElSize =
-      ConstantUInt::get(Type::UIntTy, TD.getTypeSize(Node->getType()));
-
+    
+    Value *ElSize;
+    
+    // Void types in DS graph are never used
+    if (Node->getType() != Type::VoidTy)
+      ElSize = ConstantUInt::get(Type::UIntTy, TD.getTypeSize(Node->getType()));
+    else
+      ElSize = ConstantUInt::get(Type::UIntTy, 0);
+	
     // Insert the call to initialize the pool...
     new CallInst(PoolInit, make_vector(AI, ElSize, 0), "", InsertPoint);
-
+      
     // Update the PoolDescriptors map
     PoolDescriptors.insert(std::make_pair(Node, AI));
-
+    
     // Insert a call to pool destroy before each return inst in the function
     for (unsigned r = 0, e = ReturnNodes.size(); r != e; ++r)
       new CallInst(PoolDestroy, make_vector(AI, 0), "",
-                   ReturnNodes[r]->getTerminator());
+		   ReturnNodes[r]->getTerminator());
   }
 }
 
@@ -284,17 +468,41 @@
   struct FuncTransform : public InstVisitor<FuncTransform> {
     PoolAllocate &PAInfo;
     DSGraph &G;
+    DSGraph &TDG;
     FuncInfo &FI;
 
-    FuncTransform(PoolAllocate &P, DSGraph &g, FuncInfo &fi)
-      : PAInfo(P), G(g), FI(fi) {}
+    FuncTransform(PoolAllocate &P, DSGraph &g, DSGraph &tdg, FuncInfo &fi)
+      : PAInfo(P), G(g), TDG(tdg), FI(fi) {
+    }
 
     void visitMallocInst(MallocInst &MI);
     void visitFreeInst(FreeInst &FI);
     void visitCallInst(CallInst &CI);
+    
+    // The following instructions are never modified by pool allocation
+    void visitBranchInst(BranchInst &I) { }
+    void visitBinaryOperator(Instruction &I) { }
+    void visitShiftInst (ShiftInst &I) { }
+    void visitSwitchInst (SwitchInst &I) { }
+    void visitCastInst (CastInst &I) { }
+    void visitAllocaInst(AllocaInst &I) { }
+    void visitLoadInst(LoadInst &I) { }
+    void visitGetElementPtrInst (GetElementPtrInst &I) { }
+
+    void visitReturnInst(ReturnInst &I);
+    void visitStoreInst (StoreInst &I);
+    void visitPHINode(PHINode &I);
+
+    void visitInstruction(Instruction &I) {
+      std::cerr << "PoolAllocate does not recognize this instruction\n";
+      abort();
+    }
 
   private:
     DSNode *getDSNodeFor(Value *V) {
+      if (isa<Constant>(V))
+	return 0;
+
       if (!FI.NewToOldValueMap.empty()) {
         // If the NewToOldValueMap is in effect, use it.
         std::map<Value*,const Value*>::iterator I = FI.NewToOldValueMap.find(V);
@@ -310,13 +518,130 @@
       std::map<DSNode*, Value*>::iterator I = FI.PoolDescriptors.find(Node);
       return I != FI.PoolDescriptors.end() ? I->second : 0;
     }
+    
+    bool isFuncPtr(Value *V);
+
+    Function* getFuncClass(Value *V);
+
+    Value* retCloneIfNotFP(Value *V);
   };
 }
 
 void PoolAllocate::TransformFunctionBody(Function &F, DSGraph &G, FuncInfo &FI){
-  FuncTransform(*this, G, FI).visit(F);
+  DSGraph &TDG = TDDS->getDSGraph(G.getFunction());
+  FuncTransform(*this, G, TDG, FI).visit(F);
+}
+
+// Returns true if V is a function pointer
+bool FuncTransform::isFuncPtr(Value *V) {
+  if (V->getType()->getPrimitiveID() == Type::PointerTyID) {
+    const PointerType *PTy = dyn_cast<PointerType>(V->getType());
+    
+    if (PTy->getElementType()->getPrimitiveID() == Type::FunctionTyID)
+      return true;
+  }
+
+  return false;
+}
+
+// Given a function pointer, return the function eq. class if one exists
+Function* FuncTransform::getFuncClass(Value *V) {
+  // Look at DSGraph and see if the set of of functions it could point to
+  // are pool allocated.
+
+  if (!isFuncPtr(V))
+    return 0;
+
+  // Two cases: 
+  // if V is a constant
+  if (Function *theFunc = dyn_cast<Function>(V)) {
+    if (!PAInfo.FuncECs.findClass(theFunc))
+      // If this function does not belong to any equivalence class
+      return 0;
+    if (PAInfo.EqClass2LastPoolArg.count(PAInfo.FuncECs.findClass(theFunc)))
+      return PAInfo.FuncECs.findClass(theFunc);
+    else
+      return 0;
+  }
+
+  // if V is not a constant
+  DSNode *DSN = TDG.getNodeForValue(V).getNode();
+  if (!DSN) {
+    return 0;
+  }
+  std::vector<GlobalValue*> Callees = DSN->getGlobals();
+  if (Callees.size() > 0) {
+    Function *calledF = dyn_cast<Function>(*Callees.begin());
+    assert(PAInfo.FuncECs.findClass(calledF) && "should exist in some eq. class");
+    if (PAInfo.EqClass2LastPoolArg.count(PAInfo.FuncECs.findClass(calledF)))
+      return PAInfo.FuncECs.findClass(calledF);
+  }
+
+  return 0;
+}
+
+// Returns the clone if  V is not a function pointer 
+Value* FuncTransform::retCloneIfNotFP(Value *V) {
+  if (isFuncPtr(V))
+    if (isa<Function>(V))
+      if (getFuncClass(V)) {
+	Function *fixedFunc = dyn_cast<Function>(V);
+	return PAInfo.getFuncInfo(*fixedFunc)->Clone;
+      }
+  
+  return 0;
+}
+
+void FuncTransform::visitReturnInst (ReturnInst &I) {
+  if (I.getNumOperands())
+    if (Value *clonedFunc = retCloneIfNotFP(I.getOperand(0))) {
+      // Cast the clone of I.getOperand(0) to the non-pool-allocated type
+      CastInst *CastI = new CastInst(clonedFunc, I.getOperand(0)->getType(), 
+				     "", &I);
+      // Insert return instruction that returns the casted value
+      new ReturnInst(CastI, &I);
+
+      // Remove original return instruction
+      I.setName("");
+      I.getParent()->getInstList().erase(&I);
+    }
+}
+
+void FuncTransform::visitStoreInst (StoreInst &I) {
+  // Check if a constant function is being stored
+  if (Value *clonedFunc = retCloneIfNotFP(I.getOperand(0))) {
+    CastInst *CastI = new CastInst(clonedFunc, I.getOperand(0)->getType(), "", 
+				   &I);
+    new StoreInst(CastI, I.getOperand(1), &I);
+    I.setName("");
+    I.getParent()->getInstList().erase(&I);
+  }
 }
 
+void FuncTransform::visitPHINode(PHINode &I) {
+  // If any of the operands of the PHI node is a constant function pointer
+  // that is cloned, the cast instruction has to be inserted at the end of the
+  // previous basic block
+  
+  if (isFuncPtr(&I)) {
+    PHINode *V = new PHINode(I.getType(), I.getName(), &I);
+    for (unsigned i = 0 ; i < I.getNumIncomingValues(); ++i) {
+      if (Value *clonedFunc = retCloneIfNotFP(I.getIncomingValue(i))) {
+	// Insert CastInst at the end of  I.getIncomingBlock(i)
+	BasicBlock::iterator BBI = --I.getIncomingBlock(i)->end();
+	// BBI now points to the terminator instruction of the basic block.
+	CastInst *CastI = new CastInst(clonedFunc, I.getType(), "", BBI);
+	V->addIncoming(CastI, I.getIncomingBlock(i));
+      } else {
+	V->addIncoming(I.getIncomingValue(i), I.getIncomingBlock(i));
+      }
+      
+    }
+    I.replaceAllUsesWith(V);
+    I.setName("");
+    I.getParent()->getInstList().erase(&I);
+  }
+}
 
 void FuncTransform::visitMallocInst(MallocInst &MI) {
   // Get the pool handle for the node that this contributes to...
@@ -324,8 +649,15 @@
   if (PH == 0) return;
   
   // Insert a call to poolalloc
-  Value *V = new CallInst(PAInfo.PoolAlloc, make_vector(PH, 0),
-                          MI.getName(), &MI);
+  Value *V;
+  if (MI.isArrayAllocation()) 
+    V = new CallInst(PAInfo.PoolAllocArray, 
+		     make_vector(PH, MI.getOperand(0), 0),
+		     MI.getName(), &MI);
+  else
+    V = new CallInst(PAInfo.PoolAlloc, make_vector(PH, 0),
+		     MI.getName(), &MI);
+  
   MI.setName("");  // Nuke MIs name
   
   // Cast to the appropriate type...
@@ -372,7 +704,13 @@
 static void CalcNodeMapping(DSNode *Caller, DSNode *Callee,
                             std::map<DSNode*, DSNode*> &NodeMapping) {
   if (Callee == 0) return;
-  assert(Caller && "Callee has node but caller doesn't??");
+  // assert(Caller && "Callee has node but caller doesn't??");
+
+  // If callee has a node and caller doesn't, then a constant argument was
+  // passed by the caller
+  if (Caller == 0) {
+    NodeMapping.insert(NodeMapping.end(), std::make_pair(Callee, (DSNode*) 0));
+  }
 
   std::map<DSNode*, DSNode*>::iterator I = NodeMapping.find(Callee);
   if (I != NodeMapping.end()) {   // Node already in map...
@@ -381,66 +719,207 @@
     NodeMapping.insert(I, std::make_pair(Callee, Caller));
     
     // Recursively add pointed to nodes...
-    for (unsigned i = 0, e = Callee->getNumLinks(); i != e; ++i)
-      CalcNodeMapping(Caller->getLink(i << DS::PointerShift).getNode(),
-                      Callee->getLink(i << DS::PointerShift).getNode(),
-                      NodeMapping);
+    unsigned numCallerLinks = Caller->getNumLinks();
+    unsigned numCalleeLinks = Callee->getNumLinks();
+
+    assert (numCallerLinks <= numCalleeLinks || numCalleeLinks == 0);
+    
+    for (unsigned i = 0, e = numCalleeLinks; i != e; ++i)
+      CalcNodeMapping(Caller->getLink((i%numCallerLinks) << DS::PointerShift).getNode(), Callee->getLink(i << DS::PointerShift).getNode(), NodeMapping);
   }
 }
 
 void FuncTransform::visitCallInst(CallInst &CI) {
   Function *CF = CI.getCalledFunction();
-  assert(CF && "FIXME: Pool allocation doesn't handle indirect calls!");
-
-  FuncInfo *CFI = PAInfo.getFuncInfo(*CF);
-  if (CFI == 0 || CFI->Clone == 0) return;  // Nothing to transform...
+  
+  // optimization for function pointers that are basically gotten from a cast
+  // with only one use and constant expressions with casts in them
+  if (!CF) {
+    if (CastInst* CastI = dyn_cast<CastInst>(CI.getCalledValue())) {
+      if (isa<Function>(CastI->getOperand(0)) && 
+	  CastI->getOperand(0)->getType() == CastI->getType())
+	CF = dyn_cast<Function>(CastI->getOperand(0));
+    } else if (isa<ConstantExpr>(CI.getOperand(0))) {
+      ConstantExpr *CE = dyn_cast<ConstantExpr>(CI.getOperand(0));
+      if (CE->getOpcode() == Instruction::Cast) {
+	if (isa<ConstantPointerRef>(CE->getOperand(0)))
+	  return;
+	else
+	  assert(0 && "Function pointer cast not handled as called function\n");
+      }
+    }    
 
-  DEBUG(std::cerr << "  Handling call: " << CI);
+  }
 
-  DSGraph &CG = PAInfo.getBUDataStructures().getDSGraph(*CF);  // Callee graph
+  std::vector<Value*> Args;  
+  if (!CF) {
+    // Indirect call
+    
+    DEBUG(std::cerr << "  Handling call: " << CI);
+    
+    std::map<unsigned, Value*> PoolArgs;
+    Function *FuncClass;
+    
+    for (vector<Function *>::iterator TFI = PAInfo.CallInstTargets[&CI].begin(),
+	   TFE = PAInfo.CallInstTargets[&CI].end(); TFI != TFE; ++TFI) {
+      if (TFI == PAInfo.CallInstTargets[&CI].begin()) {
+	FuncClass = PAInfo.FuncECs.findClass(*TFI);
+	// Nothing to transform if there are no pool arguments in this
+	// equivalence class of functions.
+	if (!PAInfo.EqClass2LastPoolArg.count(FuncClass))
+	  return;
+      }
+      
+      FuncInfo *CFI = PAInfo.getFuncInfo(**TFI);
 
-  // We need to figure out which local pool descriptors correspond to the pool
-  // descriptor arguments passed into the function call.  Calculate a mapping
-  // from callee DSNodes to caller DSNodes.  We construct a partial isomophism
-  // between the graphs to figure out which pool descriptors need to be passed
-  // in.  The roots of this mapping is found from arguments and return values.
-  //
-  std::map<DSNode*, DSNode*> NodeMapping;
+      if (!CFI->ArgNodes.size()) continue;  // Nothing to transform...
+      
+      DSGraph &CG = PAInfo.getBUDataStructures().getDSGraph(**TFI);  
+      std::map<DSNode*, DSNode*> NodeMapping;
+      
+      Function::aiterator AI = (*TFI)->abegin(), AE = (*TFI)->aend();
+      unsigned OpNum = 1;
+      for ( ; AI != AE; ++AI, ++OpNum) {
+	if (!isa<Constant>(CI.getOperand(OpNum)))
+	  CalcNodeMapping(getDSNodeFor(CI.getOperand(OpNum)), 
+			  CG.getScalarMap()[AI].getNode(),
+			  NodeMapping);
+      }
+      assert(OpNum == CI.getNumOperands() && "Varargs calls not handled yet!");
+      
+      if (CI.getType() != Type::VoidTy)
+	CalcNodeMapping(getDSNodeFor(&CI), CG.getRetNode().getNode(), 
+			NodeMapping);
+      
+      unsigned idx = CFI->PoolArgFirst;
+
+      // The following loop determines the pool pointers corresponding to 
+      // CFI.
+      for (unsigned i = 0, e = CFI->ArgNodes.size(); i != e; ++i, ++idx) {
+	if (NodeMapping.count(CFI->ArgNodes[i])) {
+	  assert(NodeMapping.count(CFI->ArgNodes[i]) && "Node not in mapping!");
+	  DSNode *LocalNode = NodeMapping.find(CFI->ArgNodes[i])->second;
+	  if (LocalNode) {
+	    assert(FI.PoolDescriptors.count(LocalNode) && "Node not pool allocated?");
+	    PoolArgs[idx] = FI.PoolDescriptors.find(LocalNode)->second;
+	  }
+	  else
+	    // LocalNode is null when a constant is passed in as a parameter
+	    PoolArgs[idx] = Constant::getNullValue(PoolDescPtr);
+	} else {
+	  PoolArgs[idx] = Constant::getNullValue(PoolDescPtr);
+	}
+      }
+    }
+    
+    // Push the pool arguments into Args.
+    if (PAInfo.EqClass2LastPoolArg.count(FuncClass)) {
+      for (int i = 0; i <= PAInfo.EqClass2LastPoolArg[FuncClass]; ++i) {
+	if (PoolArgs.find(i) != PoolArgs.end())
+	  Args.push_back(PoolArgs[i]);
+	else
+	  Args.push_back(Constant::getNullValue(PoolDescPtr));
+      }
+    
+      assert (Args.size()== (unsigned) PAInfo.EqClass2LastPoolArg[FuncClass] + 1 
+	      && "Call has same number of pool args as the called function");
+    }
 
-  Function::aiterator AI = CF->abegin(), AE = CF->aend();
-  unsigned OpNum = 1;
-  for (; AI != AE; ++AI, ++OpNum)
-    CalcNodeMapping(getDSNodeFor(CI.getOperand(OpNum)),
-                    CG.getScalarMap()[AI].getNode(), NodeMapping);
-  assert(OpNum == CI.getNumOperands() && "Varargs calls not handled yet!");
-  
-  // Map the return value as well...
-  CalcNodeMapping(getDSNodeFor(&CI), CG.getRetNode().getNode(), NodeMapping);
-
-
-  // Okay, now that we have established our mapping, we can figure out which
-  // pool descriptors to pass in...
-  std::vector<Value*> Args;
-
-  // Add an argument for each pool which must be passed in...
-  for (unsigned i = 0, e = CFI->ArgNodes.size(); i != e; ++i) {
-    if (NodeMapping.count(CFI->ArgNodes[i])) {
-      assert(NodeMapping.count(CFI->ArgNodes[i]) && "Node not in mapping!");
-      DSNode *LocalNode = NodeMapping.find(CFI->ArgNodes[i])->second;
-      assert(FI.PoolDescriptors.count(LocalNode) && "Node not pool allocated?");
-      Args.push_back(FI.PoolDescriptors.find(LocalNode)->second);
+    // Add the rest of the arguments (the original arguments of the function)...
+    Args.insert(Args.end(), CI.op_begin()+1, CI.op_end());
+    
+    std::string Name = CI.getName();
+    
+    Value *NewCall;
+    if (Args.size() > CI.getNumOperands() - 1) {
+      CastInst *CastI = 
+	new CastInst(CI.getOperand(0), 
+		     PAInfo.getFuncInfo(*FuncClass)->Clone->getType(), "", &CI);
+      NewCall = new CallInst(CastI, Args, Name, &CI);
     } else {
-      Args.push_back(Constant::getNullValue(PoolDescPtr));
+      NewCall = new CallInst(CI.getOperand(0), Args, Name, &CI);
     }
+
+    CI.setName("");
+    CI.replaceAllUsesWith(NewCall);
+    DEBUG(std::cerr << "  Result Call: " << *NewCall);
   }
+  else {
+
+    FuncInfo *CFI = PAInfo.getFuncInfo(*CF);
+
+    if (CFI == 0 || CFI->Clone == 0) return;  // Nothing to transform...
+    
+    DEBUG(std::cerr << "  Handling call: " << CI);
+    
+    DSGraph &CG = PAInfo.getBUDataStructures().getDSGraph(*CF);  // Callee graph
+    
+    // We need to figure out which local pool descriptors correspond to the pool
+    // descriptor arguments passed into the function call.  Calculate a mapping
+    // from callee DSNodes to caller DSNodes.  We construct a partial isomophism
+    // between the graphs to figure out which pool descriptors need to be passed
+    // in.  The roots of this mapping is found from arguments and return values.
+    //
+    std::map<DSNode*, DSNode*> NodeMapping;
+    
+    Function::aiterator AI = CF->abegin(), AE = CF->aend();
+    unsigned OpNum = 1;
+    for (; AI != AE; ++AI, ++OpNum) {
+      // Check if the operand of the call is a return of another call
+      // for the operand will be transformed in which case.
+      // Look up the OldToNewRetValMap to see if the operand is a new value.
+      Value *callOp = CI.getOperand(OpNum);
+      if (!isa<Constant>(callOp))
+	CalcNodeMapping(getDSNodeFor(callOp),CG.getScalarMap()[AI].getNode(), 
+			NodeMapping);
+    }
+    assert(OpNum == CI.getNumOperands() && "Varargs calls not handled yet!");
+    
+    // Map the return value as well...
+    if (CI.getType() != Type::VoidTy)
+      CalcNodeMapping(getDSNodeFor(&CI), CG.getRetNode().getNode(), 
+		      NodeMapping);
+
+    // Okay, now that we have established our mapping, we can figure out which
+    // pool descriptors to pass in...
+
+    // Add an argument for each pool which must be passed in...
+    if (CFI->PoolArgFirst != 0) {
+      for (int i = 0; i < CFI->PoolArgFirst; ++i)
+	Args.push_back(Constant::getNullValue(PoolDescPtr));  
+    }
 
-  // Add the rest of the arguments...
-  Args.insert(Args.end(), CI.op_begin()+1, CI.op_end());
+    for (unsigned i = 0, e = CFI->ArgNodes.size(); i != e; ++i) {
+      if (NodeMapping.count(CFI->ArgNodes[i])) {
+	assert(NodeMapping.count(CFI->ArgNodes[i]) && "Node not in mapping!");
+	DSNode *LocalNode = NodeMapping.find(CFI->ArgNodes[i])->second;
+	if (LocalNode) {
+	  assert(FI.PoolDescriptors.count(LocalNode) && "Node not pool allocated?");
+	  Args.push_back(FI.PoolDescriptors.find(LocalNode)->second);
+	}
+	else
+	  Args.push_back(Constant::getNullValue(PoolDescPtr));
+      } else {
+	Args.push_back(Constant::getNullValue(PoolDescPtr));
+      }
+    }
 
-  std::string Name = CI.getName(); CI.setName("");
-  Value *NewCall = new CallInst(CFI->Clone, Args, Name, &CI);
-  CI.replaceAllUsesWith(NewCall);
+    Function *FuncClass = PAInfo.FuncECs.findClass(CF);
+    
+    if (PAInfo.EqClass2LastPoolArg.count(FuncClass))
+      for (unsigned i = CFI->PoolArgLast; 
+	   i <= PAInfo.EqClass2LastPoolArg.count(FuncClass); ++i)
+	Args.push_back(Constant::getNullValue(PoolDescPtr));
+
+    // Add the rest of the arguments...
+    Args.insert(Args.end(), CI.op_begin()+1, CI.op_end());
+    
+    std::string Name = CI.getName(); CI.setName("");
+    Value *NewCall = new CallInst(CFI->Clone, Args, Name, &CI);
+    CI.replaceAllUsesWith(NewCall);
+    DEBUG(std::cerr << "  Result Call: " << *NewCall);
 
-  DEBUG(std::cerr << "  Result Call: " << *NewCall);
+  }
+  
   CI.getParent()->getInstList().erase(&CI);
 }





More information about the llvm-commits mailing list