From 98a37c2b9c9c7f2791e0a8abda33b9a2eb36ad8e Mon Sep 17 00:00:00 2001
From: Cameron Buschardt <buschard@uiuc.edu>
Date: Wed, 27 Mar 2002 23:17:37 +0000
Subject: [PATCH] Implemented promote mem->reg pass.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@2005 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../Utils/PromoteMemoryToRegister.cpp         | 344 ++++++++++++++----
 1 file changed, 283 insertions(+), 61 deletions(-)

diff --git a/lib/Transforms/Utils/PromoteMemoryToRegister.cpp b/lib/Transforms/Utils/PromoteMemoryToRegister.cpp
index 47fe38f2a67..74ac04c8edf 100644
--- a/lib/Transforms/Utils/PromoteMemoryToRegister.cpp
+++ b/lib/Transforms/Utils/PromoteMemoryToRegister.cpp
@@ -13,7 +13,7 @@
 // Currently this just loops over all alloca instructions, looking for
 // instructions that are only used in simple load and stores.
 //
-// After this, the code is transformed by...
+// After this, the code is transformed by...something magical :)
 //
 //===----------------------------------------------------------------------===//
 
@@ -24,90 +24,312 @@
 #include "llvm/Method.h"
 #include "llvm/BasicBlock.h"
 #include "llvm/Assembly/Writer.h"  // For debugging
+#include "llvm/iPHINode.h"
+#include "llvm/iTerminators.h"
+
+using namespace std;
+
+
 using cfg::DominanceFrontier;
 
-// PromotePass - This class is implements the PromoteMemoryToRegister pass
-//
+
+//instance of the promoter -- to keep all the local method data.
+// gets re-created for each method processed
+class PromoteInstance
+{
+	protected:
+	vector<AllocaInst*>            		Allocas;   // the alloca instruction..
+	map<Instruction *, int>	   		AllocaLookup; //reverse mapping of above
+
+	vector<vector<BasicBlock *> >  		WriteSets; // index corresponds to Allocas
+	vector<vector<BasicBlock *> > 	 	PhiNodes;  // index corresponds to Allocas
+	vector<vector<Value *> > 		CurrentValue; //the current value stack
+
+	//list of instructions to remove at end of pass :)
+	vector<Instruction *> killlist;
+
+	set<BasicBlock *> 			visited;	//the basic blocks we've already visited
+	map<BasicBlock *, vector<PHINode *> > 	new_phinodes;	//the phinodes we're adding
+
+
+	void traverse(BasicBlock *f, BasicBlock * predecessor);
+	bool PromoteMethod(Method *M, DominanceFrontier & DF);
+	bool queuePhiNode(BasicBlock *bb, int alloca_index);
+	void findSafeAllocas(Method *M);
+	bool didchange;
+	public:
+	// I do this so that I can force the deconstruction of the local variables
+	PromoteInstance(Method *M, DominanceFrontier & DF)
+	{
+		didchange=PromoteMethod(M, DF);
+	}
+	//This returns whether the pass changes anything
+	operator bool () { return didchange; }
+};
+
 class PromotePass : public MethodPass {
-public:
-  // runOnMethod - To run this pass, first we calculate the alloca instructions
-  // that are safe for promotion, then we promote each one.
-  //
-  virtual bool runOnMethod(Method *M) {
-    std::vector<AllocaInst*> Allocas;
-    findSafeAllocas(M, Allocas);      // Calculate safe allocas
+	public:
 
-    // Get dominance frontier information...
-    DominanceFrontier &DF = getAnalysis<DominanceFrontier>();
-
-    // Transform each alloca in turn...
-    for (std::vector<AllocaInst*>::iterator I = Allocas.begin(),
-           E = Allocas.end(); I != E; ++I)
-      promoteAlloca(*I, DF);
-
-    return !Allocas.empty();
-  }
+	// runOnMethod - To run this pass, first we calculate the alloca instructions
+	// that are safe for promotion, then we promote each one.
+	//
+	virtual bool runOnMethod(Method *M)
+	{
+		PromoteInstance inst(M, getAnalysis<DominanceFrontier>());
+		return (bool)inst;
+	}
 
 
-  // getAnalysisUsageInfo - We need dominance frontiers
-  //
-  virtual void getAnalysisUsageInfo(Pass::AnalysisSet &Requires,
-                                    Pass::AnalysisSet &Destroyed,
-                                    Pass::AnalysisSet &Provided) {
-    Requires.push_back(DominanceFrontier::ID);
-  }
-
-private:
-  // findSafeAllocas - Find allocas that are safe to promote
-  //
-  void findSafeAllocas(Method *M, std::vector<AllocaInst*> &Allocas) const;
-
-  // promoteAlloca - Convert the use chain of an alloca instruction into
-  // register references.
-  //
-  void promoteAlloca(AllocaInst *AI, DominanceFrontier &DF);
+	// getAnalysisUsageInfo - We need dominance frontiers
+	//
+	virtual void getAnalysisUsageInfo(Pass::AnalysisSet &Requires,
+	Pass::AnalysisSet &Destroyed,
+	Pass::AnalysisSet &Provided) {
+		Requires.push_back(DominanceFrontier::ID);
+	}
 };
 
 
 // findSafeAllocas - Find allocas that are safe to promote
 //
-void PromotePass::findSafeAllocas(Method *M,
-                                  std::vector<AllocaInst*> &Allocas) const {
+void PromoteInstance::findSafeAllocas(Method *M)  
+{
   BasicBlock *BB = M->front();  // Get the entry node for the method
 
   // Look at all instructions in the entry node
   for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
     if (AllocaInst *AI = dyn_cast<AllocaInst>(*I))       // Is it an alloca?
       if (!AI->isArrayAllocation()) {
-        bool isSafe = true;
-        for (Value::use_iterator UI = AI->use_begin(), UE = AI->use_end();
-             UI != UE; ++UI) {   // Loop over all of the uses of the alloca
-          // Only allow nonindexed memory access instructions...
-          if (MemAccessInst *MAI = dyn_cast<MemAccessInst>(*UI)) {
-            if (MAI->hasIndices()) { isSafe = false; break; } // indexed?
-          } else {
-            isSafe = false; break;   // Not a load or store?
-          }
-        }
+	bool isSafe = true;
+	for (Value::use_iterator UI = AI->use_begin(), UE = AI->use_end();
+	     UI != UE; ++UI) {   // Loop over all of the uses of the alloca
 
-        if (isSafe)              // If all checks pass, add alloca to safe list
-          Allocas.push_back(AI);
+	  // Only allow nonindexed memory access instructions...
+	  if (MemAccessInst *MAI = dyn_cast<MemAccessInst>(*UI)) {
+	    if (MAI->hasIndices()) {  // indexed?
+	      // Allow the access if there is only one index and the index is zero.
+	      if (*MAI->idx_begin() != ConstantUInt::get(Type::UIntTy, 0) ||
+		  MAI->idx_begin()+1 != MAI->idx_end()) {
+		isSafe = false; break;
+	      }
+	    }
+	  } else {
+	    isSafe = false; break;   // Not a load or store?
+	  }
+	}
+	if (isSafe)              // If all checks pass, add alloca to safe list
+	  {
+	    AllocaLookup[AI]=Allocas.size();
+	    Allocas.push_back(AI);
+	  }
       }
-
 }
 
 
 
-// promoteAlloca - Convert the use chain of an alloca instruction into
-// register references.
-//
-void PromotePass::promoteAlloca(AllocaInst *AI, DominanceFrontier &DFInfo) {
-  std::cerr << "TODO: Should process: " << AI;
-}
-
-
 // newPromoteMemoryToRegister - Provide an entry point to create this pass.
 //
 Pass *newPromoteMemoryToRegister() {
-  return new PromotePass();
+	return new PromotePass();
+}
+
+
+bool PromoteInstance::PromoteMethod(Method *M, DominanceFrontier & DF) {
+	// Calculate the set of safe allocas
+	findSafeAllocas(M);
+
+	// Add each alloca to the killlist
+	// note: killlist is destroyed MOST recently added to least recently.
+	killlist.assign(Allocas.begin(), Allocas.end());
+
+	// Calculate the set of write-locations for each alloca.
+	// this is analogous to counting the number of 'redefinitions' of each variable.
+	for (unsigned i = 0; i<Allocas.size(); ++i)
+	{
+		AllocaInst * AI = Allocas[i];
+		WriteSets.push_back(std::vector<BasicBlock *>()); //add a new set
+		for (Value::use_iterator U = AI->use_begin();U!=AI->use_end();++U)
+		{
+			if (MemAccessInst *MAI = dyn_cast<StoreInst>(*U)) {
+				WriteSets[i].push_back(MAI->getParent()); // jot down the basic-block it came from
+			}
+		}
+	}
+
+	// Compute the locations where PhiNodes need to be inserted
+	// look at the dominance frontier of EACH basic-block we have a write in
+	PhiNodes.resize(Allocas.size());
+	for (unsigned i = 0; i<Allocas.size(); ++i)
+	{
+		for (unsigned j = 0; j<WriteSets[i].size(); j++)
+		{
+			//look up the DF for this write, add it to PhiNodes
+			DominanceFrontier::const_iterator it = DF.find(WriteSets[i][j]);
+			DominanceFrontier::DomSetType     s = (*it).second;
+			for (DominanceFrontier::DomSetType::iterator p = s.begin();p!=s.end(); ++p)
+			{
+				if (queuePhiNode((BasicBlock *)*p, i))
+				PhiNodes[i].push_back((BasicBlock *)*p);
+			}
+		}
+		// perform iterative step
+		for (unsigned k = 0; k<PhiNodes[i].size(); k++)
+		{
+			DominanceFrontier::const_iterator it = DF.find(PhiNodes[i][k]);
+			DominanceFrontier::DomSetType     s = it->second;
+			for (DominanceFrontier::DomSetType::iterator p = s.begin(); p!=s.end(); ++p)
+			{
+				if (queuePhiNode((BasicBlock *)*p,i))
+				PhiNodes[i].push_back((BasicBlock*)*p);
+			}
+		}
+	}
+
+	// Walks all basic blocks in the method
+	// performing the SSA rename algorithm
+	// and inserting the phi nodes we marked as necessary
+	BasicBlock * f = M->front(); //get root basic-block
+
+	CurrentValue.push_back(vector<Value *>(Allocas.size()));
+
+	traverse(f, NULL);  // there is no predecessor of the root node
+
+
+	// ** REMOVE EVERYTHING IN THE KILL-LIST **
+	// we need to kill 'uses' before root values
+	// so we should probably run through in reverse
+	for (vector<Instruction *>::reverse_iterator i = killlist.rbegin(); i!=killlist.rend(); ++i)
+	{
+		Instruction * r = *i;
+		BasicBlock * o = r->getParent();
+		//now go find..
+
+		BasicBlock::InstListType & l = o->getInstList();
+		o->getInstList().remove(r);
+		delete r;
+	}
+
+	return !Allocas.empty();
+}
+
+
+
+void PromoteInstance::traverse(BasicBlock *f, BasicBlock * predecessor)
+{
+	vector<Value *> * tos = &CurrentValue.back(); //look at top-
+
+	//if this is a BB needing a phi node, lookup/create the phinode for
+	// each variable we need phinodes for.
+	map<BasicBlock *, vector<PHINode *> >::iterator nd = new_phinodes.find(f);
+	if (nd!=new_phinodes.end())
+	{
+		for (unsigned k = 0; k!=nd->second.size(); ++k)
+		if (nd->second[k])
+		{
+			//at this point we can assume that the array has phi nodes.. let's
+			// add the incoming data
+			if ((*tos)[k])
+			nd->second[k]->addIncoming((*tos)[k],predecessor);
+			//also note that the active variable IS designated by the phi node
+			(*tos)[k] = nd->second[k];
+		}
+	}
+
+	//don't revisit nodes
+	if (visited.find(f)!=visited.end())
+	return;
+	//mark as visited
+	visited.insert(f);
+
+	BasicBlock::iterator i = f->begin();
+	//keep track of the value of each variable we're watching.. how?
+	while(i!=f->end())
+	{
+		Instruction * inst = *i; //get the instruction
+		//is this a write/read?
+		if (LoadInst * LI = dyn_cast<LoadInst>(inst))
+		{
+			// This is a bit weird...
+			Value * ptr = LI->getPointerOperand(); //of type value
+			if (AllocaInst * srcinstr = dyn_cast<AllocaInst>(ptr))
+			{
+				map<Instruction *, int>::iterator ai = AllocaLookup.find(srcinstr);
+				if (ai!=AllocaLookup.end())
+				{
+					if (Value *r = (*tos)[ai->second])
+					{
+						//walk the use list of this load and replace
+						// all uses with r
+						LI->replaceAllUsesWith(r);
+						//now delete the instruction.. somehow..
+						killlist.push_back((Instruction *)LI);
+					}
+				}
+			}
+		}
+		else if (StoreInst * SI = dyn_cast<StoreInst>(inst))
+		{
+			// delete this instruction and mark the name as the
+			// current holder of the value
+			Value * ptr =  SI->getPointerOperand(); //of type value
+			if (Instruction * srcinstr = dyn_cast<Instruction>(ptr))
+			{
+				map<Instruction *, int>::iterator ai = AllocaLookup.find(srcinstr);
+				if (ai!=AllocaLookup.end())
+				{
+					//what value were we writing?
+					Value * writeval = SI->getOperand(0);
+					//write down...
+					(*tos)[ai->second] = writeval;
+					//now delete it.. somehow?
+					killlist.push_back((Instruction *)SI);
+				}
+			}
+
+		}
+		else if (TerminatorInst * TI = dyn_cast<TerminatorInst>(inst))
+		{
+			// Recurse across our sucessors
+			for (unsigned i = 0; i!=TI->getNumSuccessors(); i++)
+			{
+				CurrentValue.push_back(CurrentValue.back());
+				traverse(TI->getSuccessor(i),f); //this node IS the predecessor
+				CurrentValue.pop_back();
+			}
+		}
+		i++;
+	}
+}
+
+// queues a phi-node to be added to a basic-block for a specific Alloca
+// returns true  if there wasn't already a phi-node for that variable
+
+
+bool PromoteInstance::queuePhiNode(BasicBlock *bb, int i /*the alloca*/)
+{
+	map<BasicBlock *, vector<PHINode *> >::iterator nd;
+	//look up the basic-block in question
+	nd = new_phinodes.find(bb);
+	//if the basic-block has no phi-nodes added, or at least none
+	//for the i'th alloca. then add.
+	if (nd==new_phinodes.end() || nd->second[i]==NULL)
+	{
+		//we're not added any phi nodes to this basicblock yet
+		// create the phi-node array.
+		if (nd==new_phinodes.end())
+		{
+			new_phinodes[bb] = vector<PHINode *>(Allocas.size());
+			nd = new_phinodes.find(bb);
+		}
+
+		//find the type the alloca returns
+		const PointerType * pt = Allocas[i]->getType();
+		//create a phi-node using the DEREFERENCED type
+		PHINode * ph = new PHINode(pt->getElementType(), Allocas[i]->getName()+".mem2reg");
+		nd->second[i] = ph;
+		//add the phi-node to the basic-block
+		bb->getInstList().push_front(ph);
+		return true;
+	}
+	return false;
 }