[llvm-commits] CVS: reopt/lib/LightWtProfiling/TraceToFunction.cpp

Brian Gaeke gaeke at cs.uiuc.edu
Thu Aug 28 12:40:03 PDT 2003


Changes in directory reopt/lib/LightWtProfiling:

TraceToFunction.cpp added (r1.1)

---
Log message:

Initial checkin of TraceToFunction converter.


---
Diffs of the changes:

Index: reopt/lib/LightWtProfiling/TraceToFunction.cpp
diff -c /dev/null reopt/lib/LightWtProfiling/TraceToFunction.cpp:1.1
*** /dev/null	Thu Aug 28 12:39:14 2003
--- reopt/lib/LightWtProfiling/TraceToFunction.cpp	Thu Aug 28 12:39:03 2003
***************
*** 0 ****
--- 1,484 ----
+ //===- TraceToFunction.cpp - Convert traces to functions ---------*- C++ -*--=//
+ //
+ // Repackage traces as functions.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "Trace.h"
+ #include "llvm/Transforms/Utils/Cloning.h"
+ #include "llvm/Pass.h"
+ #include "llvm/Module.h"
+ #include "llvm/DerivedTypes.h"
+ #include "llvm/iTerminators.h"
+ #include "llvm/iPHINode.h"
+ #include "llvm/iMemory.h"
+ #include "llvm/iOther.h"
+ #include "llvm/Constants.h"
+ #include "Support/StringExtras.h"  // for utostr()
+ #include "Support/Debug.h"         // for DEBUG()
+ #include <set>
+ 
+ typedef std::vector<const Type *> TypeVector;
+ typedef std::set<Value *> LiveVariableSet;
+ typedef std::map<Value *, unsigned int> ValueToIntMap;
+ typedef std::map<const Value *, Value *> ValueMap;
+ typedef std::map<BranchInst *, unsigned int> BranchNumberMap;
+ 
+ class TraceToFunction {
+   ValueToIntMap LiveInToParameterMap;
+   BranchNumberMap BranchNumber;
+   virtual TypeVector createFunctionArgTypeVector (PointerType *ST,
+ 						  LiveVariableSet S);
+   virtual void fillInFunctionBody (Trace &T, Function *F, LiveVariableSet &So);
+   virtual void fixupFunctionBodyBB (Trace &T, Function *F, BasicBlock *srcB,
+ 				    BasicBlock *dstB, ValueMap &O2CMap,
+ 				    LiveVariableSet &So);
+ public:
+   TraceToFunction () { }
+   virtual ~TraceToFunction () { }
+   virtual Function *traceToFunction (Trace &T);
+ };
+ 
+ /// getTraceLiveInSet - Return the set of variables which are used in
+ /// the trace but which are not defined in the trace.
+ ///
+ static LiveVariableSet getTraceLiveInSet (Trace &T) {
+   LiveVariableSet S;
+   for (Trace::iterator TI = T.begin (), TE = T.end (); TI != TE; ++TI) {
+     BasicBlock *B = *TI;
+     // B is a basic block in the trace.
+     for (BasicBlock::iterator BI = B->begin (), BE = B->end (); BI != BE; ++BI){
+       Instruction &I = *BI;
+       // I is an instruction in B, which is in the trace.
+       for (unsigned i = 0; i < I.getNumOperands (); ++i) {
+ 	Value *V = I.getOperand (i);
+ 	// V is used in the trace by instruction I.
+ 	if (Instruction *VI = dyn_cast<Instruction> (V))
+ 	  // V is defined by an instruction; not a constant or global.
+ 	  if (!T.contains (VI->getParent ()))
+ 	    // V is defined by an instruction outside the trace.
+ 	    S.insert (V);
+       }
+     }
+   }
+   return S;
+ }
+ 
+ /// getTraceLiveOutSet - Return the set of variables which are defined
+ /// by an instruction inside the trace, and used in an instruction
+ /// outside the trace (but within that trace's function.)
+ ///
+ static LiveVariableSet getTraceLiveOutSet (Trace &T) {
+   LiveVariableSet S;
+   Function &F = *T.getFunction();
+   for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) {
+     BasicBlock &B = *FI;
+     if (!T.contains (&B)) {
+       for (BasicBlock::iterator BI = B.begin(), BE = B.end(); BI != BE; ++BI) {
+ 	Instruction &I = *BI;
+ 	// I is an instruction in the trace's function, but outside the trace.
+ 	// Check its operands for uses of values defined in the trace.
+ 	for (unsigned i = 0; i < I.getNumOperands (); ++i) {
+ 	  Value *V = I.getOperand (i);
+ 	  // V is used outside the trace by instruction I.
+ 	  if (Instruction *VI = dyn_cast<Instruction> (V))
+ 	    // V is defined by an instruction; not a constant or global.
+ 	    if (T.contains (VI->getParent ()))
+ 	      // V is defined by an instruction inside the trace.
+ 	      S.insert (V);
+ 	}
+       }
+     }
+   }
+   return S;
+ }
+ 
+ /// containsTraceExitingBranch - If B contains a branch instruction BI
+ /// that exits the trace T, returns BI.  Returns NULL otherwise.
+ /// 
+ static BranchInst *containsTraceExitingBranch (BasicBlock *B, Trace T) {
+   TerminatorInst *TI = B->getTerminator ();
+   assert (TI && "Only works on well-formed LLVM basic blocks w/ terminators");
+   if (BranchInst *BI = dyn_cast<BranchInst> (TI))
+     for (unsigned i = 0; i < BI->getNumSuccessors (); ++i) {
+       BasicBlock *BIT = BI->getSuccessor (i);
+       if (!T.contains (BIT))
+ 	return BI;
+     }
+   return NULL;
+ }
+ 
+ /// createLiveOutType - Given the live-out set S of a trace, create a
+ /// pointer-to-structure type that will encapsulate all the live-outs from S.
+ ///
+ static PointerType *createLiveOutType (LiveVariableSet S) {
+   TypeVector T;
+   // For each variable in S, make a new entry in T having its type.
+   for (LiveVariableSet::iterator I = S.begin (), E = S.end (); I != E; ++I) {
+     T.push_back ((*I)->getType ());
+   }
+   return PointerType::get (StructType::get (T));
+ }
+ 
+ /// createFunctionArgTypeVector - Given the live-in set S of a trace,
+ /// create a parameter list containing a parameter for each of the
+ /// variables in S as well as a pointer-to-structure type PST to fill
+ /// in which contains the live-outs. As a side effect, fill in the
+ /// mapping between live-ins and parameters in the global map named
+ /// LiveInToParameterMap.
+ ///
+ TypeVector TraceToFunction::createFunctionArgTypeVector (PointerType *PST,
+ 							 LiveVariableSet S) {
+   TypeVector P;
+   P.push_back (PST);
+ 
+   LiveInToParameterMap.clear ();
+   for (LiveVariableSet::iterator I = S.begin (), E = S.end (); I != E; ++I) {
+     Value *V = *I;
+     P.push_back (V->getType ());
+     LiveInToParameterMap[V] = P.size () - 1;
+   }
+   // Print out mapping of instructions to arg numbers.
+   DEBUG(for (ValueToIntMap::iterator I = LiveInToParameterMap.begin (),
+ 	       E = LiveInToParameterMap.end (); I != E; ++I)
+ 	  std::cerr << I->first << " is parameter " << I->second << "\n");
+   return P;
+ }
+ 
+ /// giveNamesToFunctionArgs - Name the first argument of F "liveOut",
+ /// then use the ordering imposed by S's iterator to name the
+ /// remaining arguments of F.
+ ///
+ static void giveNamesToFunctionArgs (LiveVariableSet S, Function *F) {
+   Function::aiterator argIterator = F->abegin ();
+   unsigned argPosition = 0;
+ 
+   argIterator->setName ("liveOut"); // Arg 0 is always the live-out struct.
+   ++argPosition;
+   ++argIterator;
+   
+   for (LiveVariableSet::iterator I = S.begin (), E = S.end (); I != E; ++I) {
+     std::string name ((*I)->getName ());
+     if (name == "")
+       name = "arg" + utostr (argPosition);
+     argIterator->setName ("liveIn." + name);
+     ++argPosition;
+     ++argIterator;
+   }
+ }
+ 
+ /// numberExitBranchesInTrace - Fill in M with pairs that map each
+ /// trace-exiting branch in T to a unique nonnegative integer.
+ ///
+ static void numberExitBranchesInTrace (Trace &T, BranchNumberMap &M) {
+   int Count = M.size ();
+   for (Trace::iterator I = T.begin (), E = T.end (); I != E; ++I) {
+     BasicBlock *B = *I;
+     BranchInst *BI = containsTraceExitingBranch (B, T);
+     if (BI)
+       M[BI] = Count++;
+   }
+ }
+ 
+ /// getFunctionArg - Return a pointer to F's ARGNOth argument.
+ ///
+ static Argument *getFunctionArg (Function *F, unsigned argno) {
+   Function::aiterator ai = F->abegin ();
+   while (argno) { ++ai; --argno; }
+   return &*ai;
+ }
+ 
+ /// cloneTraceBBsIntoFunction - Copy the BasicBlocks of the trace T into
+ /// the new Function F, which should be initially empty. Correspondences
+ /// between Original instructions (in T) and their Clones (in F) are added
+ /// to O2CMap.
+ ///
+ static void cloneTraceBBsIntoFunction (Trace &T, Function *F, ValueMap &O2CMap){
+   unsigned BBCount = 0;
+   // Clone each basic block into the new function.
+   for (Trace::iterator TI = T.begin (), TE = T.end (); TI != TE; ++TI) {
+     BasicBlock *srcB = *TI;
+     // Create a new BasicBlock dstB that corresponds to srcB in T.
+     BasicBlock *dstB = CloneBasicBlock (srcB, O2CMap, ".ttf");
+     DEBUG(dstB->setName ("trace" + utostr(BBCount++)));
+     // Add dstB to F.
+     F->getBasicBlockList ().push_back (dstB);
+     // Remember the correspondence between srcB and dstB.
+     // FIXME: Should this be something that CloneBasicBlock does?
+     O2CMap[srcB] = dstB; 
+   }
+ }
+ 
+ /// fillInFunctionBody - Clone the BBs of T into F, then do all
+ /// necessary fixups to ensure that F's new contents are internally
+ /// consistent and that the live-outs So get stored in F's first
+ /// argument.
+ ///
+ void TraceToFunction::fillInFunctionBody (Trace &T, Function *F,
+ 					  LiveVariableSet &So) {
+   ValueMap O2CMap;
+   // First copy the basic blocks from the trace.
+   cloneTraceBBsIntoFunction (T, F, O2CMap);
+ 
+   numberExitBranchesInTrace (T, BranchNumber);
+ 
+   // Fix up the cloned basic blocks of the function so that they are
+   // internally consistent.
+   for (Trace::iterator TI = T.begin (), TE = T.end (); TI != TE; ++TI) {
+     BasicBlock *srcB = *TI;
+     assert (O2CMap[srcB] && "Can't find clone of basic block I just cloned");
+     BasicBlock *dstB = dyn_cast<BasicBlock> (O2CMap[srcB]);
+     assert (dstB && "Clone of basic block I just cloned is not a basic block");
+     fixupFunctionBodyBB (T, F, srcB, dstB, O2CMap, So);
+   }
+ }
+ 
+ /// fixupFunctionBodyBB - Given srcB in T and its clone dstB in F, and
+ /// the map O2CMap detailing the correspondences between values in T
+ /// and values in F, fix up dstB so that its contents are internally
+ /// consistent, and so that it stores its live-out values So in F's first
+ /// argument. (This is where all the magic gets done...) 
+ ///
+ void TraceToFunction::fixupFunctionBodyBB (Trace &T, Function *F,
+ 					   BasicBlock *srcB, BasicBlock *dstB,
+ 					   ValueMap &O2CMap,
+ 					   LiveVariableSet &So) {
+   // Additional special handling for trace's entry basic block:
+   // The old entry BB's clone will start with a phi, one of whose args
+   // comes from off-trace (that's the trace entry point.) We can't
+   // leave that there because the off-trace source BB is now out of
+   // the function. So create new entry basic block to serve as source
+   // for old entry's initial phi node.
+   if (srcB == T.getEntryBasicBlock ()) {
+     BasicBlock *FEntry = new BasicBlock ("entryfixup", dstB);
+     FEntry->getInstList ().push_back (new BranchInst (dstB));
+     // Replace the references to the trace's predecessor with a
+     // reference to FEntry now. This is kind of a dodge because we
+     // don't have a pointer to the trace's predecessor, so we have
+     // to guess which one it is. Assume it's any phi value source in
+     // the entry BB which is not in the trace.
+     for (BasicBlock::iterator BI = srcB->begin ();
+ 	 PHINode *PN = dyn_cast<PHINode> (BI); ++BI)
+       for (unsigned i = 0; i < PN->getNumIncomingValues (); ++i)
+ 	if (!T.contains (PN->getIncomingBlock (i))) {
+ 	  // FIXME: Assert that O2CMap[PN]'s value i is live in.
+ 	  Value *V = O2CMap[PN];
+ 	  assert (V && "Can't find clone of Phi node from trace entry BB");
+ 	  PHINode *PNinF = dyn_cast<PHINode> (V);
+ 	  assert (PNinF
+ 		  && "Clone of Phi node from entry BB is not a Phi node");
+ 	  PNinF->setIncomingBlock (i, FEntry);
+ 	}
+   }
+ 
+   // If srcB contains a trace-exiting branch B, fix up B's clone in
+   // dstB to point to a new basic block in F that contains a return
+   // statement. Each return statement in F corresponds to a unique
+   // exit branch in T, and each return statement is numbered.
+   if (BranchInst *BI = containsTraceExitingBranch (srcB, T)) {
+     // Fix up this exit branch.
+     Value *V = O2CMap[BI];
+     assert(V && isa<BranchInst> (V)
+ 	   && "Trace-exiting branch's clone is null, or not a branch?");
+     BranchInst *BIinF = cast<BranchInst> (V);
+     for (unsigned i = 0; i < BI->getNumSuccessors (); ++i) {
+       if (!T.contains (BI->getSuccessor (i))) {
+ 	// This is a trace-exiting destination of branch BI. Create a new
+ 	// basic block FB for its destination in the function.
+ 	std::string name ("exitfixup" + utostr (BranchNumber[BI]) + "_"
+ 			  + utostr (i));
+ 	BasicBlock *FB = new BasicBlock (name, F);
+ 	// Change BI's clone's destination to FB.
+ 	BIinF->setSuccessor (i, FB);
+ 	// Add the getelementptr/store instruction pairs here that
+ 	// correspond to each live-out variable.
+ 	unsigned Slot = 0;
+ 	for (LiveVariableSet::iterator SI = So.begin (), SE = So.end ();
+ 	     SI != SE; ++SI) {
+ 	  std::vector<Value *> Index;
+ 	  Index.push_back (Constant::getNullValue (Type::LongTy)); //long 0
+ 	  Index.push_back (ConstantUInt::get (Type::UByteTy, Slot));//ubyte Slot
+ 	  DEBUG(std::cerr << "About to make a GEP: " << getFunctionArg (F, 0));
+ 	  for (std::vector<Value *>::iterator VI = Index.begin(),
+ 		 VE = Index.end (); VI != VE; ++VI) {
+ 	    DEBUG(std::cerr << ", " << **VI);
+ 	  }
+ 	  DEBUG(std::cerr << "\n");
+ 	  GetElementPtrInst *GEP =
+ 	    new GetElementPtrInst (getFunctionArg (F, 0), Index,
+ 				   "liveOutP" + utostr (BranchNumber[BI])
+ 				   + "_" + utostr (i) + "_" + utostr (Slot));
+ 	  FB->getInstList ().push_back (GEP);
+ 	  FB->getInstList ().push_back (new StoreInst (*SI, GEP));
+ 	  ++Slot;
+ 	}
+ 	// Make FB contain a return instruction that returns the
+ 	// number of the taken exit-branch. Add it to the end of FB:
+ 	// (FIXME: Numbering the branches in this way is probably
+ 	// unnecessary except in DEBUG mode.)
+ 	FB->getInstList ().push_back
+ 	  (new ReturnInst (ConstantUInt::get (Type::UIntTy,
+ 					      BranchNumber[BI])));
+       } else {
+ 	// This is a non-trace-exiting destination of branch BI. Fix up
+ 	// its clone's destination to point to its successor's clone.
+ 	Value *V2 = O2CMap[BI->getSuccessor (i)];
+ 	DEBUG(if (!V2) {
+ 	  std::cerr
+ 	    << "I'm confused: saw non-trace-exiting dest. of branch "
+ 	    << *BI << " whose clone is " << *BIinF
+ 	    << " successor number is " << i << " and successor is "
+ 	    << *BI->getSuccessor (i) << ", but where's its clone?\n";
+ 	  assert(V2 && "Clone of basic block on trace is null?");
+ 	});
+ 	assert(isa<BasicBlock> (V2)
+ 	       && "Clone of basic block on trace is not a basic block?");
+ 	BasicBlock *BIsuccInF = cast<BasicBlock> (V2);
+ 	BIinF->setSuccessor (i, BIsuccInF);
+       }
+     }
+   }
+ 
+   // Fix up operands of each instruction:
+   for (BasicBlock::iterator BI = dstB->begin (), BE = dstB->end ();
+        BI != BE; ++BI) {
+     Instruction &I = *BI;
+     for (unsigned i = 0; i < I.getNumOperands (); ++i) {
+       Value *V = I.getOperand (i);
+       // If the instruction I has an operand which is in the live-in
+       // set of the trace, then we must replace that operand with
+       // the corresponding argument of F. We can find out which
+       // operands to replace by looking them up in
+       // LiveInToParameterMap.
+       if (LiveInToParameterMap.find (V) != LiveInToParameterMap.end ()) {
+ 	DEBUG(std::cerr << *V << " in instruction " << I
+ 	      << " is argument " << LiveInToParameterMap[V]
+ 	      << " in new function\n");
+ 	assert (V->getType () ==
+ 		getFunctionArg (F, LiveInToParameterMap[V])->getType ()
+ 		&& "Live-in Value's type doesn't match corresponding arg type");
+ 	I.setOperand(i, getFunctionArg (F, LiveInToParameterMap[V]));
+       }
+       // If the instruction I has an operand which is in the
+       // trace, that operand will have been cloned into the
+       // function, and I will still reference the version from
+       // outside the function. Replace any reference to an operand
+       // which has had a clone made with a reference to its clone.
+       else if (O2CMap.find (V) != O2CMap.end ()) {
+ 	DEBUG(std::cerr << *V << " in instruction " << I
+ 	      << " is value " << O2CMap[V] << " in new function\n");
+ 	assert (V->getType () == O2CMap[V]->getType ()
+ 		&& "Value's type doesn't match clone's type");
+ 	I.setOperand(i, O2CMap[V]);
+       }
+     }
+     // Make sure that our operand fixups did the Right Thing for
+     // branches.
+     DEBUG(if (BranchInst *BrI = dyn_cast<BranchInst> (&I)) {
+       for (unsigned i = 0; i < BrI->getNumSuccessors (); ++i) {
+ 	assert (BrI->getSuccessor (i)->getParent () == F
+ 		&& "Branch out of function missed by copyTraceToFunction");
+ 	assert (!O2CMap[BrI->getSuccessor (i)]
+ 		&& "Branch's clone found as key in original-->clone map; "
+ 		"no one told me today was opposite day!");
+       }
+     });
+   }
+ 
+   // Fix up Phi nodes:
+   for (BasicBlock::iterator BI = dstB->begin (), BE = dstB->end ();
+        BI != BE; ++BI) {
+     Instruction &I = *BI;
+     // In all cases, if a Phi node source in T was an on-trace basic
+     // block, then it will already have been fixed up to point to
+     // that block's clone, so we find off-trace sources by looking
+     // for source BBs which are not in F.
+     if (PHINode *PN = dyn_cast<PHINode> (&I)) {
+       unsigned onTraceSources = 0;
+       int lastSrcFound = -1;
+       for (unsigned i = 0; i < PN->getNumIncomingValues (); ++i)
+ 	if (PN->getIncomingBlock (i)->getParent () == F) {
+ 	  lastSrcFound = i;
+ 	  ++onTraceSources;
+ 	}
+       // Case 0. If it has 0 sources on the trace, that should really
+       // never happen.
+       assert (onTraceSources != 0
+ 	      && "Phi node on trace has ALL its sources from off-trace!");
+       // Case 1. If it has 1 source S on the trace, replace its uses
+       // with S.
+       if (onTraceSources == 1) {
+ 	DEBUG(std::cerr << "Replacing Phi node" << *PN
+ 	      << " with its lone on-trace input "
+ 	      << *PN->getIncomingValue (lastSrcFound) << "\n");
+ 	PN->replaceAllUsesWith (PN->getIncomingValue (lastSrcFound));
+ 	dstB->getInstList ().erase (BI); // Delete the non-used Phi node
+       } else {
+ 	// Case N. If it has >1 source on the trace, just delete
+ 	// sources from the Phi node that are not on the trace.
+ 	int lastOffTraceSrcFound = -1;
+ 	do {
+ 	  for (unsigned i = 0; i < PN->getNumIncomingValues (); ++i)
+ 	    if (PN->getIncomingBlock (i)->getParent () != F) {
+ 	      lastOffTraceSrcFound = i; // Found an off-trace source.
+ 	      break;
+ 	    }
+ 	  if (lastOffTraceSrcFound != -1) { // Found one?
+ 	    DEBUG(std::cerr << "Removing off-trace input "
+ 		  << *PN->getIncomingValue (lastOffTraceSrcFound)
+ 		  << " from Phi node " << *PN << "\n");
+ 	    PN->removeIncomingValue (lastOffTraceSrcFound); // Delete it.
+ 	  }
+ 	} while (lastOffTraceSrcFound != -1); // Continue until none found.
+       }
+     }
+     // Make sure that our Phi fixups did the Right Thing.
+     DEBUG(if (PHINode *PN = dyn_cast<PHINode> (&I))
+ 	  for (unsigned i = 0; i < PN->getNumIncomingValues (); ++i)
+ 	  assert (PN->getIncomingBlock (i)->getParent () == F &&
+ 		  "Sorry, copyTraceIntoFunction mishandled a Phi node"));
+   }
+ 
+   // Remove calls to first-level instrumentation if we find them.
+   for (BasicBlock::iterator BI = dstB->begin (), BE = dstB->end ();
+        BI != BE; ++BI) {
+     Instruction &I = *BI;
+     if (CallInst *CI = dyn_cast<CallInst> (&I)) {
+       Function *CF = CI->getCalledFunction ();
+       if (CF->getName () == "llvm_first_trigger" && CF->isExternal ()) {
+ 	DEBUG(std::cerr << " (Found a call instruction " << *CI
+ 	      << " ... Smells like llvm_first_trigger.)\n");
+ 	dstB->getInstList ().erase (BI);
+       }
+     }
+   }
+ }
+ 
+ Function *TraceToFunction::traceToFunction (Trace &T) {
+   std::string CurrentFnName = T.getFunction ()->getName ();
+   DEBUG(std::cerr << "In traceToFunction() for " << CurrentFnName << "\n");
+ 
+   // Get some information about the trace's relationship to its parent
+   // function.
+   LiveVariableSet Si = getTraceLiveInSet (T);
+   LiveVariableSet So = getTraceLiveOutSet (T);
+   TypeVector P = createFunctionArgTypeVector (createLiveOutType (So), Si);
+ 
+   // Make a new internal Function with return type int and parameter
+   // list P, in the same Module as the trace's parent function.
+   std::string name (CurrentFnName + ".trace");
+   Function *F = new Function (FunctionType::get (Type::UIntTy, P, false),
+ 			      GlobalValue::InternalLinkage, name,
+ 			      T.getModule ());
+   DEBUG(giveNamesToFunctionArgs (Si, F));
+   fillInFunctionBody (T, F, So);
+   return F;
+ }
+ 
+ /// runTraceToFunction - Entry point for TraceToFunction transformation. 
+ 
+ Function *runTraceToFunction (Trace &T) {
+   TraceToFunction TTF;
+   return TTF.traceToFunction (T);
+ }
+ 





More information about the llvm-commits mailing list