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

Chris Lattner lattner at cs.uiuc.edu
Sun May 23 16:24:10 PDT 2004


Changes in directory llvm/lib/Transforms/IPO:

ArgumentPromotion.cpp updated: 1.5 -> 1.6

---
Log message:

Fairly substantial changes to update the alias analysis we are querying as
we make the transformation.  This allows us to use interprocedural alias
analyses successfully.


---
Diffs of the changes:  (+92 -39)

Index: llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
diff -u llvm/lib/Transforms/IPO/ArgumentPromotion.cpp:1.5 llvm/lib/Transforms/IPO/ArgumentPromotion.cpp:1.6
--- llvm/lib/Transforms/IPO/ArgumentPromotion.cpp:1.5	Sun Mar  7 19:04:36 2004
+++ llvm/lib/Transforms/IPO/ArgumentPromotion.cpp	Sun May 23 16:21:17 2004
@@ -1,4 +1,4 @@
-//===-- ArgumentPromotion.cpp - Promote 'by reference' arguments ----------===//
+//===-- ArgumentPromotion.cpp - Promote by-reference arguments ------------===//
 // 
 //                     The LLVM Compiler Infrastructure
 //
@@ -12,14 +12,14 @@
 // arguments.  If we can prove, through the use of alias analysis, that that an
 // argument is *only* loaded, then we can pass the value into the function
 // instead of the address of the value.  This can cause recursive simplification
-// of code, and lead to the elimination of allocas, especially in C++ template
-// code like the STL.
+// of code and lead to the elimination of allocas (especially in C++ template
+// code like the STL).
 //
 // This pass also handles aggregate arguments that are passed into a function,
 // scalarizing them if the elements of the aggregate are only loaded.  Note that
 // we refuse to scalarize aggregates which would require passing in more than
 // three operands to the function, because we don't want to pass thousands of
-// operands for a large array or something!
+// operands for a large array or structure!
 //
 // Note that this transformation could also be done for arguments that are only
 // stored to (returning the value instead), but we do not currently handle that
@@ -28,6 +28,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#define DEBUG_TYPE "argpromotion"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Constants.h"
 #include "llvm/DerivedTypes.h"
@@ -58,7 +59,7 @@
   class ArgPromotion : public Pass {
     // WorkList - The set of internal functions that we have yet to process.  As
     // we eliminate arguments from a function, we push all callers into this set
-    // so that the by reference argument can be bubbled out as far as possible.
+    // so that the by-reference argument can be bubbled out as far as possible.
     // This set contains only internal functions.
     std::set<Function*> WorkList;
   public:
@@ -128,7 +129,11 @@
   return Changed;
 }
 
-
+/// PromoteArguments - This method checks the specified function to see if there
+/// are any promotable arguments and if it is safe to promote the function (for
+/// example, all callers are direct).  If safe to promote some arguments, it
+/// calls the DoPromotion method.
+///
 bool ArgPromotion::PromoteArguments(Function *F) {
   assert(F->hasInternalLinkage() && "We can only process internal functions!");
 
@@ -144,15 +149,14 @@
   for (Value::use_iterator UI = F->use_begin(), E = F->use_end();
        UI != E; ++UI) {
     CallSite CS = CallSite::get(*UI);
-    if (Instruction *I = CS.getInstruction()) {
-      // Ensure that this call site is CALLING the function, not passing it as
-      // an argument.
-      for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
-           AI != E; ++AI)
-        if (*AI == F) return false;   // Passing the function address in!
-    } else {
-      return false;  // Cannot promote an indirect call!
-    }
+    if (!CS.getInstruction())       // "Taking the address" of the function
+      return false;
+
+    // Ensure that this call site is CALLING the function, not passing it as
+    // an argument.
+    for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
+         AI != E; ++AI)
+      if (*AI == F) return false;   // Passing the function address in!
   }
 
   // Check to see which arguments are promotable.  If an argument is not
@@ -171,6 +175,12 @@
   return true;
 }
 
+
+/// isSafeToPromoteArgument - As you might guess from the name of this method,
+/// it checks to see if it is both safe and useful to promote the argument.
+/// This method limits promotion of aggregates to only promote up to three
+/// elements of the aggregate in order to avoid exploding the number of
+/// arguments passed in.
 bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg) const {
   // We can only promote this argument if all of the uses are loads, or are GEP
   // instructions (with constant indices) that are subsequently loaded.
@@ -185,6 +195,7 @@
       if (GEP->use_empty()) {
         // Dead GEP's cause trouble later.  Just remove them if we run into
         // them.
+        getAnalysis<AliasAnalysis>().deleteValue(GEP);
         GEP->getParent()->getInstList().erase(GEP);
         return isSafeToPromoteArgument(Arg);
       }
@@ -206,12 +217,15 @@
           return false;
         }
 
-      // See if there is already a GEP with these indices.  If so, check to make
-      // sure that we aren't promoting too many elements.  If not, nothing to
-      // do.
+      // See if there is already a GEP with these indices.  If not, check to
+      // make sure that we aren't promoting too many elements.  If so, nothing
+      // to do.
       if (std::find(GEPIndices.begin(), GEPIndices.end(), Operands) ==
           GEPIndices.end()) {
         if (GEPIndices.size() == 3) {
+          DEBUG(std::cerr << "argpromotion disable promoting argument '"
+                << Arg->getName() << "' because it would require adding more "
+                << "than 3 arguments to the function.\n");
           // We limit aggregate promotion to only promoting up to three elements
           // of the aggregate.
           return false;
@@ -222,11 +236,11 @@
       return false;  // Not a load or a GEP.
     }
 
-  if (Loads.empty()) return true;  // No users, dead argument.
+  if (Loads.empty()) return true;  // No users, this is a dead argument.
 
-  // Okay, now we know that the argument is only used by load instructions.
-  // Check to see if the pointer is guaranteed to not be modified from entry of
-  // the function to each of the load instructions.
+  // Okay, now we know that the argument is only used by load instructions.  Use
+  // alias analysis to check to see if the pointer is guaranteed to not be
+  // modified from entry of the function to each of the load instructions.
   Function &F = *Arg->getParent();
 
   // Because there could be several/many load instructions, remember which
@@ -265,7 +279,8 @@
   return true;
 }
 
-
+/// DoPromotion - This method actually performs the promotion of the specified
+/// arguments.  At this point, we know that it's safe to do so.
 void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
   std::set<Argument*> ArgsToPromote(Args2Prom.begin(), Args2Prom.end());
   
@@ -283,10 +298,17 @@
   //
   std::map<Argument*, std::set<std::vector<Value*> > > ScalarizedElements;
 
+  // OriginalLoads - Keep track of a representative load instruction from the
+  // original function so that we can tell the alias analysis implementation
+  // what the new GEP/Load instructions we are inserting look like.
+  std::map<std::vector<Value*>, LoadInst*> OriginalLoads;
+
   for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I)
     if (!ArgsToPromote.count(I)) {
       Params.push_back(I->getType());
-    } else if (!I->use_empty()) {
+    } else if (I->use_empty()) {
+      ++NumArgumentsDead;
+    } else {
       // Okay, this is being promoted.  Check to see if there are any GEP uses
       // of the argument.
       std::set<std::vector<Value*> > &ArgIndices = ScalarizedElements[I];
@@ -294,8 +316,14 @@
            ++UI) {
         Instruction *User = cast<Instruction>(*UI);
         assert(isa<LoadInst>(User) || isa<GetElementPtrInst>(User));
-        ArgIndices.insert(std::vector<Value*>(User->op_begin()+1,
-                                              User->op_end()));
+        std::vector<Value*> Indices(User->op_begin()+1, User->op_end());
+        ArgIndices.insert(Indices);
+        LoadInst *OrigLoad;
+        if (LoadInst *L = dyn_cast<LoadInst>(User))
+          OrigLoad = L;
+        else
+          OrigLoad = cast<LoadInst>(User->use_back());
+        OriginalLoads[Indices] = OrigLoad;
       }
 
       // Add a parameter to the function for each element passed in.
@@ -307,8 +335,6 @@
         ++NumArgumentsPromoted;
       else
         ++NumAggregatesPromoted;
-    } else {
-      ++NumArgumentsDead;
     }
 
   const Type *RetTy = FTy->getReturnType();
@@ -325,7 +351,11 @@
    // Create the new function body and insert it into the module...
   Function *NF = new Function(NFTy, F->getLinkage(), F->getName());
   F->getParent()->getFunctionList().insert(F, NF);
-  
+
+  // Get the alias analysis information that we need to update to reflect our
+  // changes.
+  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
+
   // Loop over all of the callers of the function, transforming the call sites
   // to pass in the loaded pointers.
   //
@@ -334,25 +364,30 @@
     CallSite CS = CallSite::get(F->use_back());
     Instruction *Call = CS.getInstruction();
 
-    // Make sure the caller of this function is revisited.
+    // Make sure the caller of this function is revisited now that we promoted
+    // arguments in a callee of it.
     if (Call->getParent()->getParent()->hasInternalLinkage())
       WorkList.insert(Call->getParent()->getParent());
     
-    // Loop over the operands, deleting dead ones...
+    // Loop over the operands, inserting GEP and loads in the caller as
+    // appropriate.
     CallSite::arg_iterator AI = CS.arg_begin();
     for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I, ++AI)
       if (!ArgsToPromote.count(I))
         Args.push_back(*AI);          // Unmodified argument
       else if (!I->use_empty()) {
-        // Non-dead argument.
+        // Non-dead argument: insert GEPs and loads as appropriate.
         std::set<std::vector<Value*> > &ArgIndices = ScalarizedElements[I];
         for (std::set<std::vector<Value*> >::iterator SI = ArgIndices.begin(),
                E = ArgIndices.end(); SI != E; ++SI) {
           Value *V = *AI;
-          if (!SI->empty())
+          LoadInst *OrigLoad = OriginalLoads[*SI];
+          if (!SI->empty()) {
             V = new GetElementPtrInst(V, *SI, V->getName()+".idx", Call);
-
+            AA.copyValue(OrigLoad->getOperand(0), V);
+          }
           Args.push_back(new LoadInst(V, V->getName()+".val", Call));
+          AA.copyValue(OrigLoad, Args.back());
         }
       }
 
@@ -372,6 +407,10 @@
     }
     Args.clear();
 
+    // Update the alias analysis implementation to know that we are replacing
+    // the old call with a new one.
+    AA.replaceWithNewValue(Call, New);
+
     if (!Call->use_empty()) {
       Call->replaceAllUsesWith(New);
       std::string Name = Call->getName();
@@ -399,8 +438,11 @@
       // new version.
       I->replaceAllUsesWith(I2);
       I2->setName(I->getName());
+      AA.replaceWithNewValue(I, I2);
       ++I2;
-    } else if (!I->use_empty()) {
+    } else if (I->use_empty()) {
+      AA.deleteValue(I);
+    } else {
       // Otherwise, if we promoted this argument, then all users are load
       // instructions, and all loads should be using the new argument that we
       // added.
@@ -412,9 +454,10 @@
                  "Load element should sort to front!");
           I2->setName(I->getName()+".val");
           LI->replaceAllUsesWith(I2);
+          AA.replaceWithNewValue(LI, I2);
           LI->getParent()->getInstList().erase(LI);
-          DEBUG(std::cerr << "*** Promoted argument '" << I->getName()
-                          << "' of function '" << F->getName() << "'\n");
+          DEBUG(std::cerr << "*** Promoted load of argument '" << I->getName()
+                          << "' in function '" << F->getName() << "'\n");
         } else {
           GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->use_back());
           std::vector<Value*> Operands(GEP->op_begin()+1, GEP->op_end());
@@ -442,19 +485,29 @@
           while (!GEP->use_empty()) {
             LoadInst *L = cast<LoadInst>(GEP->use_back());
             L->replaceAllUsesWith(TheArg);
+            AA.replaceWithNewValue(L, TheArg);
             L->getParent()->getInstList().erase(L);
           }
+          AA.deleteValue(GEP);
           GEP->getParent()->getInstList().erase(GEP);
         }
       }
 
       // If we inserted a new pointer type, it's possible that IT could be
-      // promoted too.  Also, increment I2 past all of the arguments for this
-      // pointer.
+      // promoted too.  Also, increment I2 past all of the arguments added for
+      // this promoted pointer.
       for (unsigned i = 0, e = ArgIndices.size(); i != e; ++i, ++I2)
         if (isa<PointerType>(I2->getType()))
           WorkList.insert(NF);
     }
+
+  // Notify the alias analysis implementation that we inserted a new argument.
+  if (ExtraArgHack)
+    AA.copyValue(Constant::getNullValue(Type::IntTy), NF->abegin());
+
+
+  // Tell the alias analysis that the old function is about to disappear.
+  AA.replaceWithNewValue(F, NF);
 
   // Now that the old function is dead, delete it.
   F->getParent()->getFunctionList().erase(F);





More information about the llvm-commits mailing list