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

Reid Spencer reid at x10sys.com
Sun Apr 24 19:53:23 PDT 2005



Changes in directory llvm/lib/Transforms/IPO:

SimplifyLibCalls.cpp added (r1.1)
---
Log message:

A new pass to provide specific optimizations for certain well-known library
calls. The pass visits all external functions in the module and determines
if such function calls can be optimized. The optimizations are specific to
the library calls involved. This initial version only optimizes calls to
exit(3) when they occur in main(): it changes them to ret instructions.


---
Diffs of the changes:  (+167 -0)

 SimplifyLibCalls.cpp |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 167 insertions(+)


Index: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp
diff -c /dev/null llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.1
*** /dev/null	Sun Apr 24 21:53:22 2005
--- llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp	Sun Apr 24 21:53:12 2005
***************
*** 0 ****
--- 1,167 ----
+ //===- SimplifyLibCalls.cpp - Optimize specific well-known librayr calls --===//
+ //
+ //                     The LLVM Compiler Infrastructure
+ //
+ // This file was developed by Reid Spencer group and is distributed under
+ // the University of Illinois Open Source License. See LICENSE.TXT for details.
+ //
+ //===----------------------------------------------------------------------===//
+ //
+ // This file implements a variety of small optimizations for calls to specific
+ // well-known (e.g. runtime library) function calls. For example, a call to the
+ // function "exit(3)" that occurs within the main() function can be transformed
+ // into a simple "return 3" instruction. Many of the ideas for these 
+ // optimizations were taken from GCC's "builtins.c" file but their 
+ // implementation here is completely knew and LLVM-centric
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "llvm/Transforms/IPO.h"
+ #include "llvm/Module.h"
+ #include "llvm/Pass.h"
+ #include "llvm/Instructions.h"
+ #include "llvm/ADT/Statistic.h"
+ using namespace llvm;
+ 
+ namespace {
+   Statistic<> SimplifiedLibCalls("simplified-lib-calls", 
+       "Number of well-known library calls simplified");
+ 
+   /// This class is the base class for a set of small but important 
+   /// optimizations of calls to well-known functions, such as those in the c
+   /// library. This class provides the basic infrastructure for handling 
+   /// runOnModule. Subclasses register themselves and provide two methods:
+   /// RecognizeCall and OptimizeCall. Whenever this class finds a function call,
+   /// it asks the subclasses to recognize the call. If it is recognized, then
+   /// the OptimizeCall method is called on that subclass instance. In this way
+   /// the subclasses implement the calling conditions on which they trigger and
+   /// the action to perform, making it easy to add new optimizations of this
+   /// form.
+   /// @brief A ModulePass for optimizing well-known function calls
+   struct SimplifyLibCalls : public ModulePass {
+ 
+ 
+     /// For this pass, process all of the function calls in the module, calling
+     /// RecognizeCall and OptimizeCall as appropriate.
+     virtual bool runOnModule(Module &M);
+ 
+   };
+ 
+   RegisterOpt<SimplifyLibCalls> 
+     X("simplify-libcalls","Simplify well-known library calls");
+ 
+   struct CallOptimizer
+   {
+     /// @brief Constructor that registers the optimization
+     CallOptimizer();
+ 
+     virtual ~CallOptimizer();
+ 
+     /// The implementations of this function in subclasses is the heart of the 
+     /// SimplifyLibCalls algorithm. Sublcasses of this class implement 
+     /// OptimizeCall to determine if (a) the conditions are right for optimizing
+     /// the call and (b) to perform the optimization. If an action is taken 
+     /// against ci, the subclass is responsible for returning true and ensuring
+     /// that ci is erased from its parent.
+     /// @param ci the call instruction under consideration
+     /// @param f the function that ci calls.
+     /// @brief Optimize a call, if possible.
+     virtual bool OptimizeCall(CallInst* ci, const Function* f) const = 0;
+   };
+ 
+   /// @brief The list of optimizations deriving from CallOptimizer
+   std::vector<struct CallOptimizer*> optlist;
+ 
+   CallOptimizer::CallOptimizer()
+   {
+     // Register this call optimizer
+     optlist.push_back(this);
+   }
+ 
+   /// Make sure we get our virtual table in this file.
+   CallOptimizer::~CallOptimizer() {}
+ }
+ 
+ ModulePass *llvm::createSimplifyLibCallsPass() 
+ { 
+   return new SimplifyLibCalls(); 
+ }
+ 
+ bool SimplifyLibCalls::runOnModule(Module &M) 
+ {
+   for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI)
+   {
+     // All the "well-known" functions are external because they live in a 
+     // runtime library somewhere and were (probably) not compiled by LLVM.
+     // So, we only act on external functions that have non-empty uses.
+     if (FI->isExternal() && !FI->use_empty())
+     {
+       // Loop over each of the uses of the function
+       for (Value::use_iterator UI = FI->use_begin(), UE = FI->use_end(); 
+            UI != UE ; )
+       {
+         CallInst* CI = dyn_cast<CallInst>(*UI);
+         ++UI;
+ 
+         // If the use of the function is a call instruction
+         if (CI)
+         {
+           // Loop over each of the registered optimizations and find the one 
+           // that can optimize this call.
+           std::vector<CallOptimizer*>::iterator OI = optlist.begin();
+           std::vector<CallOptimizer*>::iterator OE = optlist.end();
+           for ( ; OI != OE ; ++OI)
+           {
+             if ((*OI)->OptimizeCall(CI,&(*FI)))
+             {
+               ++SimplifiedLibCalls;
+               break;
+             }
+           }
+         }
+       }
+     }
+   }
+   return true;
+ }
+ 
+ namespace {
+ 
+ /// This CallOptimizer will find instances of a call to "exit" that occurs
+ /// within the "main" function and change it to a simple "ret" instruction with
+ /// the same value as passed to the exit function. It assumes that the 
+ /// instructions after the call to exit(3) can be deleted since they are 
+ /// unreachable anyway.
+ /// @brief Replace calls to exit in main with a simple return
+ struct ExitInMainOptimization : public CallOptimizer
+ {
+ virtual ~ExitInMainOptimization() {}
+ bool OptimizeCall(CallInst* ci, const Function* func) const
+ {
+   // If this isn't the exit function then we don't act
+   if (func->getName() != "exit")
+     return false;
+ 
+   // If the call isn't coming from main then we don't act
+   if (const Function* f = ci->getParent()->getParent())
+     if (f->getName() != "main")
+       return false;
+ 
+   // Okay, time to replace it. Get the basic block of the call instruction
+   BasicBlock* bb = ci->getParent();
+ 
+   // Create a return instruction that we'll replace the call with. Note that
+   // the argument of the return is the argument of the call instruction.
+   ReturnInst* ri = new ReturnInst(ci->getOperand(1), ci);
+ 
+   // Erase everything from the call instruction to the end of the block. There
+   // really shouldn't be anything other than the call instruction, but just in
+   // case there is we delete it all because its now dead.
+   bb->getInstList().erase(ci, bb->end());
+ 
+   return true;
+ }
+ 
+ } ExitInMainOptimizer;
+ 
+ }






More information about the llvm-commits mailing list