This is a cleanup commit:

* Correct stale documentation in a few places
* Re-order the file to better associate things and reduce line count
* Make the pass thread safe by caching the Function* objects needed by the
  optimizers in the pass object instead of globally.
* Provide the SimplifyLibCalls pass object to the optimizer classes so they
  can access cached Function* objects and TargetData info
* Make sure the pass resets its cache if the Module passed to runOnModule
  changes
* Rename CallOptimizer LibCallOptimization. All the classes are named
  *Optimization while the objects are *Optimizer.
* Don't cache Function* in the optimizer objects because they could be used
  by multiple PassManager's running in multiple threads
* Add an optimization for strcpy which is similar to strcat
* Add a "TODO" list at the end of the file for ideas on additional libcall
  optimizations that could be added (get ideas from other compilers).

Sorry for the huge diff. Its mostly reorganization of code. That won't
happen again as I believe the design and infrastructure for this pass is
now done or close to it.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21589 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Spencer 2005-04-27 07:54:40 +00:00
parent d651f441ae
commit a16d5a5185

View File

@ -31,192 +31,192 @@
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 {
/// This statistic keeps track of the total number of library calls that have
/// been simplified regardless of which call it is.
Statistic<> SimplifiedLibCalls("simplify-libcalls",
"Number of well-known library calls simplified");
/// We need some target data for accurate signature details that are
/// target dependent. So we require target data in our AnalysisUsage.
virtual void getAnalysisUsage(AnalysisUsage& Info) const;
/// @brief The list of optimizations deriving from LibCallOptimization
class LibCallOptimization;
class SimplifyLibCalls;
hash_map<std::string,LibCallOptimization*> optlist;
/// 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(const char * fname );
virtual ~CallOptimizer();
/// The implementation of this function in subclasses should determine if
/// \p F is suitable for the optimization. This method is called by
/// runOnModule to short circuit visiting all the call sites of such a
/// function if that function is not suitable in the first place.
/// If the called function is suitabe, this method should return true;
/// false, otherwise. This function should also perform any lazy
/// initialization that the CallOptimizer needs to do, if its to return
/// true. This avoids doing initialization until the optimizer is actually
/// going to be called upon to do some optimization.
virtual bool ValidateCalledFunction(
const Function* F, ///< The function that is the target of call sites
const TargetData& TD ///< Information about the target
) = 0;
/// 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, ///< The call instruction that should be optimized.
const TargetData& TD ///< Information about the target
) = 0;
const char * getFunctionName() const { return func_name; }
#ifndef NDEBUG
void activate() { ++activations; }
#endif
private:
const char* func_name;
#ifndef NDEBUG
std::string stat_name;
Statistic<> activations;
#endif
};
/// @brief The list of optimizations deriving from CallOptimizer
hash_map<std::string,CallOptimizer*> optlist;
CallOptimizer::CallOptimizer(const char* fname)
/// This class is the abstract base class for the set of optimizations that
/// corresponds to one library call. The SimplifyLibCall pass will call the
/// ValidateCalledFunction method to ask the optimization if a given Function
/// is the kind that the optimization can handle. It will also call the
/// OptimizeCall method to perform, or attempt to perform, the optimization(s)
/// for the library call. Subclasses of this class are located toward the
/// end of this file.
/// @brief Base class for library call optimizations
struct LibCallOptimization
{
/// @brief Constructor that registers the optimization. The \p fname argument
/// must be the name of the library function being optimized by the subclass.
LibCallOptimization(const char * fname )
: func_name(fname)
#ifndef NDEBUG
, stat_name(std::string("simplify-libcalls:")+fname)
, activations(stat_name.c_str(),"Number of calls simplified")
, occurrences(stat_name.c_str(),"Number of calls simplified")
#endif
{
// Register this call optimizer
optlist[func_name] = this;
}
/// Make sure we get our virtual table in this file.
CallOptimizer::~CallOptimizer() { }
/// @brief Destructor
virtual ~LibCallOptimization() {}
}
/// The implementation of this function in subclasses should determine if
/// \p F is suitable for the optimization. This method is called by
/// runOnModule to short circuit visiting all the call sites of such a
/// function if that function is not suitable in the first place.
/// If the called function is suitabe, this method should return true;
/// false, otherwise. This function should also perform any lazy
/// initialization that the LibCallOptimization needs to do, if its to return
/// true. This avoids doing initialization until the optimizer is actually
/// going to be called upon to do some optimization.
virtual bool ValidateCalledFunction(
const Function* F, ///< The function that is the target of call sites
SimplifyLibCalls& SLC ///< The pass object invoking us
) = 0;
ModulePass *llvm::createSimplifyLibCallsPass()
{
return new SimplifyLibCalls();
}
/// 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, ///< The call instruction that should be optimized.
SimplifyLibCalls& SLC ///< The pass object invoking us
) = 0;
void SimplifyLibCalls::getAnalysisUsage(AnalysisUsage& Info) const
{
// Ask that the TargetData analysis be performed before us so we can use
// the target data.
Info.addRequired<TargetData>();
}
/// @brief Get the name of the library call being optimized
const char * getFunctionName() const { return func_name; }
bool SimplifyLibCalls::runOnModule(Module &M)
{
TargetData& TD = getAnalysis<TargetData>();
bool result = false;
// The call optimizations can be recursive. That is, the optimization might
// generate a call to another function which can also be optimized. This way
// we make the CallOptimizer instances very specific to the case they handle.
// It also means we need to keep running over the function calls in the module
// until we don't get any more optimizations possible.
bool found_optimization = false;
do
{
found_optimization = false;
for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI)
{
// All the "well-known" functions are external and have external linkage
// because they live in a runtime library somewhere and were (probably)
// not compiled by LLVM. So, we only act on external functions that have
// external linkage and non-empty uses.
if (!FI->isExternal() || !FI->hasExternalLinkage() || FI->use_empty())
continue;
// Get the optimization class that pertains to this function
CallOptimizer* CO = optlist[FI->getName().c_str()];
if (!CO)
continue;
// Make sure the called function is suitable for the optimization
if (!CO->ValidateCalledFunction(FI,TD))
continue;
// Loop over each of the uses of the function
for (Value::use_iterator UI = FI->use_begin(), UE = FI->use_end();
UI != UE ; )
{
// If the use of the function is a call instruction
if (CallInst* CI = dyn_cast<CallInst>(*UI++))
{
// Do the optimization on the CallOptimizer.
if (CO->OptimizeCall(CI,TD))
{
++SimplifiedLibCalls;
found_optimization = result = true;
#ifndef NDEBUG
CO->activate();
void occurred() { ++occurrences; }
#endif
private:
const char* func_name; ///< Name of the library call we optimize
#ifndef NDEBUG
std::string stat_name; ///< Holder for debug statistic name
Statistic<> occurrences; ///< debug statistic (-debug-only=simplify-libcalls)
#endif
};
/// 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 is an LLVM Pass that applies each of the LibCallOptimization
/// instances to all the call sites in a module, relatively efficiently. The
/// purpose of this pass is to provide optimizations for calls to well-known
/// functions with well-known semantics, such as those in the c library. The
/// class provides the basic infrastructure for handling runOnModule.
/// Whenever this pass finds a function call, it asks the subclasses to
/// validate the call by calling ValidateLibraryCall. If it is validated, then
/// the OptimizeCall method is called.
/// @brief A ModulePass for optimizing well-known function calls.
struct SimplifyLibCalls : public ModulePass
{
/// We need some target data for accurate signature details that are
/// target dependent. So we require target data in our AnalysisUsage.
virtual void getAnalysisUsage(AnalysisUsage& Info) const
{
// Ask that the TargetData analysis be performed before us so we can use
// the target data.
Info.addRequired<TargetData>();
}
/// For this pass, process all of the function calls in the module, calling
/// ValidateLibraryCall and OptimizeCall as appropriate.
virtual bool runOnModule(Module &M)
{
reset(M);
bool result = false;
// The call optimizations can be recursive. That is, the optimization might
// generate a call to another function which can also be optimized. This way
// we make the LibCallOptimization instances very specific to the case they
// handle. It also means we need to keep running over the function calls in
// the module until we don't get any more optimizations possible.
bool found_optimization = false;
do
{
found_optimization = false;
for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI)
{
// All the "well-known" functions are external and have external linkage
// because they live in a runtime library somewhere and were (probably)
// not compiled by LLVM. So, we only act on external functions that have
// external linkage and non-empty uses.
if (!FI->isExternal() || !FI->hasExternalLinkage() || FI->use_empty())
continue;
// Get the optimization class that pertains to this function
LibCallOptimization* CO = optlist[FI->getName().c_str()];
if (!CO)
continue;
// Make sure the called function is suitable for the optimization
if (!CO->ValidateCalledFunction(FI,*this))
continue;
// Loop over each of the uses of the function
for (Value::use_iterator UI = FI->use_begin(), UE = FI->use_end();
UI != UE ; )
{
// If the use of the function is a call instruction
if (CallInst* CI = dyn_cast<CallInst>(*UI++))
{
// Do the optimization on the LibCallOptimization.
if (CO->OptimizeCall(CI,*this))
{
++SimplifiedLibCalls;
found_optimization = result = true;
#ifndef NDEBUG
CO->occurred();
#endif
}
}
}
}
}
} while (found_optimization);
return result;
}
} while (found_optimization);
return result;
}
namespace {
/// @brief Return the *current* module we're working on.
Module* getModule() { return M; }
/// Provide some functions for accessing standard library prototypes and
/// caching them so we don't have to keep recomputing them
FunctionType* get_strlen(const Type* IntPtrTy)
/// @brief Return the *current* target data for the module we're working on.
TargetData* getTargetData() { return TD; }
/// @brief Return a Function* for the strlen libcall
Function* get_strlen()
{
static FunctionType* strlen_type = 0;
if (!strlen_type)
if (!strlen_func)
{
std::vector<const Type*> args;
args.push_back(PointerType::get(Type::SByteTy));
strlen_type = FunctionType::get(IntPtrTy, args, false);
FunctionType* strlen_type =
FunctionType::get(TD->getIntPtrType(), args, false);
strlen_func = M->getOrInsertFunction("strlen",strlen_type);
}
return strlen_type;
return strlen_func;
}
FunctionType* get_memcpy()
/// @brief Return a Function* for the memcpy libcall
Function* get_memcpy()
{
static FunctionType* memcpy_type = 0;
if (!memcpy_type)
if (!memcpy_func)
{
// Note: this is for llvm.memcpy intrinsic
std::vector<const Type*> args;
@ -224,120 +224,65 @@ namespace {
args.push_back(PointerType::get(Type::SByteTy));
args.push_back(Type::IntTy);
args.push_back(Type::IntTy);
memcpy_type = FunctionType::get(Type::VoidTy, args, false);
FunctionType* memcpy_type = FunctionType::get(Type::VoidTy, args, false);
memcpy_func = M->getOrInsertFunction("llvm.memcpy",memcpy_type);
}
return memcpy_type;
return memcpy_func;
}
/// A function to compute the length of a null-terminated string of integers.
/// This function can't rely on the size of the constant array because there
/// could be a null terminator in the middle of the array. We also have to
/// bail out if we find a non-integer constant initializer of one of the
/// elements or if there is no null-terminator. The logic below checks
bool getConstantStringLength(Value* V, uint64_t& len )
/// @brief Compute length of constant string
bool getConstantStringLength(Value* V, uint64_t& len );
private:
void reset(Module& mod)
{
assert(V != 0 && "Invalid args to getConstantStringLength");
len = 0; // make sure we initialize this
User* GEP = 0;
// If the value is not a GEP instruction nor a constant expression with a
// GEP instruction, then return false because ConstantArray can't occur
// any other way
if (GetElementPtrInst* GEPI = dyn_cast<GetElementPtrInst>(V))
GEP = GEPI;
else if (ConstantExpr* CE = dyn_cast<ConstantExpr>(V))
if (CE->getOpcode() == Instruction::GetElementPtr)
GEP = CE;
else
return false;
else
return false;
// Make sure the GEP has exactly three arguments.
if (GEP->getNumOperands() != 3)
return false;
// Check to make sure that the first operand of the GEP is an integer and
// has value 0 so that we are sure we're indexing into the initializer.
if (ConstantInt* op1 = dyn_cast<ConstantInt>(GEP->getOperand(1)))
{
if (!op1->isNullValue())
return false;
}
else
return false;
// Ensure that the second operand is a ConstantInt. If it isn't then this
// GEP is wonky and we're not really sure what were referencing into and
// better of not optimizing it. While we're at it, get the second index
// value. We'll need this later for indexing the ConstantArray.
uint64_t start_idx = 0;
if (ConstantInt* CI = dyn_cast<ConstantInt>(GEP->getOperand(2)))
start_idx = CI->getRawValue();
else
return false;
// The GEP instruction, constant or instruction, must reference a global
// variable that is a constant and is initialized. The referenced constant
// initializer is the array that we'll use for optimization.
GlobalVariable* GV = dyn_cast<GlobalVariable>(GEP->getOperand(0));
if (!GV || !GV->isConstant() || !GV->hasInitializer())
return false;
// Get the initializer.
Constant* INTLZR = GV->getInitializer();
// Handle the ConstantAggregateZero case
if (ConstantAggregateZero* CAZ = dyn_cast<ConstantAggregateZero>(INTLZR))
{
// This is a degenerate case. The initializer is constant zero so the
// length of the string must be zero.
len = 0;
return true;
}
// Must be a Constant Array
ConstantArray* A = dyn_cast<ConstantArray>(INTLZR);
if (!A)
return false;
// Get the number of elements in the array
uint64_t max_elems = A->getType()->getNumElements();
// Traverse the constant array from start_idx (derived above) which is
// the place the GEP refers to in the array.
for ( len = start_idx; len < max_elems; len++)
{
if (ConstantInt* CI = dyn_cast<ConstantInt>(A->getOperand(len)))
{
// Check for the null terminator
if (CI->isNullValue())
break; // we found end of string
}
else
return false; // This array isn't suitable, non-int initializer
}
if (len >= max_elems)
return false; // This array isn't null terminated
// Subtract out the initial value from the length
len -= start_idx;
return true; // success!
M = &mod;
TD = &getAnalysis<TargetData>();
memcpy_func = 0;
strlen_func = 0;
}
/// This CallOptimizer will find instances of a call to "exit" that occurs
private:
Function* memcpy_func;
Function* strlen_func;
Module* M;
TargetData* TD;
};
// Register the pass
RegisterOpt<SimplifyLibCalls>
X("simplify-libcalls","Simplify well-known library calls");
} // anonymous namespace
// The only public symbol in this file which just instantiates the pass object
ModulePass *llvm::createSimplifyLibCallsPass()
{
return new SimplifyLibCalls();
}
// Classes below here, in the anonymous namespace, are all subclasses of the
// LibCallOptimization class, each implementing all optimizations possible for a
// single well-known library call. Each has a static singleton instance that
// auto registers it into the "optlist" global above.
namespace {
bool getConstantStringLength(Value* V, uint64_t& len );
/// This LibCallOptimization 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
struct ExitInMainOptimization : public LibCallOptimization
{
ExitInMainOptimization() : CallOptimizer("exit") {}
ExitInMainOptimization() : LibCallOptimization("exit") {}
virtual ~ExitInMainOptimization() {}
// Make sure the called function looks like exit (int argument, int return
// type, external linkage, not varargs).
virtual bool ValidateCalledFunction(const Function* f, const TargetData& TD)
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC)
{
if (f->arg_size() >= 1)
if (f->arg_begin()->getType()->isInteger())
@ -345,7 +290,7 @@ struct ExitInMainOptimization : public CallOptimizer
return false;
}
virtual bool OptimizeCall(CallInst* ci, const TargetData& TD)
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC)
{
// To be careful, we check that the call to exit is coming from "main", that
// main has external linkage, and the return type of main and the argument
@ -386,41 +331,23 @@ struct ExitInMainOptimization : public CallOptimizer
}
} ExitInMainOptimizer;
/// This CallOptimizer will simplify a call to the strcat library function. The
/// simplification is possible only if the string being concatenated is a
/// constant array or a constant expression that results in a constant array. In
/// this case, if the array is small, we can generate a series of inline store
/// instructions to effect the concatenation without calling strcat.
/// This LibCallOptimization will simplify a call to the strcat library
/// function. The simplification is possible only if the string being
/// concatenated is a constant array or a constant expression that results in
/// a constant array. In this case, if the array is small, we can generate a
/// series of inline store instructions to effect the concatenation without
/// calling strcat.
/// @brief Simplify the strcat library function.
struct StrCatOptimization : public CallOptimizer
struct StrCatOptimization : public LibCallOptimization
{
private:
Function* strlen_func;
Function* memcpy_func;
public:
StrCatOptimization()
: CallOptimizer("strcat")
, strlen_func(0)
, memcpy_func(0)
{}
StrCatOptimization() : LibCallOptimization("strcat") {}
public:
virtual ~StrCatOptimization() {}
inline Function* get_strlen_func(Module*M,const Type* IntPtrTy)
{
if (strlen_func)
return strlen_func;
return strlen_func = M->getOrInsertFunction("strlen",get_strlen(IntPtrTy));
}
inline Function* get_memcpy_func(Module* M)
{
if (memcpy_func)
return memcpy_func;
return memcpy_func = M->getOrInsertFunction("llvm.memcpy",get_memcpy());
}
/// @brief Make sure that the "strcat" function has the right prototype
virtual bool ValidateCalledFunction(const Function* f, const TargetData& TD)
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC)
{
if (f->getReturnType() == PointerType::get(Type::SByteTy))
if (f->arg_size() == 2)
@ -429,13 +356,6 @@ public:
if (AI++->getType() == PointerType::get(Type::SByteTy))
if (AI->getType() == PointerType::get(Type::SByteTy))
{
// Invalidate the pre-computed strlen_func and memcpy_func Functions
// because, by definition, this method is only called when a new
// Module is being traversed. Invalidation causes re-computation for
// the new Module (if necessary).
strlen_func = 0;
memcpy_func = 0;
// Indicate this is a suitable call type.
return true;
}
@ -443,9 +363,8 @@ public:
return false;
}
/// Perform the optimization if the length of the string concatenated
/// is reasonably short and it is a constant array.
virtual bool OptimizeCall(CallInst* ci, const TargetData& TD)
/// @brief Optimize the strcat library function
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC)
{
// Extract the initializer (while making numerous checks) from the
// source operand of the call to strcat. If we get null back, one of
@ -471,11 +390,10 @@ public:
// We need to find the end of the destination string. That's where the
// memory is to be moved to. We just generate a call to strlen (further
// optimized in another pass). Note that the get_strlen_func() call
// optimized in another pass). Note that the SLC.get_strlen() call
// caches the Function* for us.
CallInst* strlen_inst =
new CallInst(get_strlen_func(M,TD.getIntPtrType()),
ci->getOperand(1),"",ci);
new CallInst(SLC.get_strlen(), ci->getOperand(1),"",ci);
// Now that we have the destination's length, we must index into the
// destination's pointer to get the actual memcpy destination (end of
@ -492,7 +410,7 @@ public:
vals.push_back(ci->getOperand(2)); // source
vals.push_back(ConstantSInt::get(Type::IntTy,len)); // length
vals.push_back(ConstantSInt::get(Type::IntTy,1)); // alignment
CallInst* memcpy_inst = new CallInst(get_memcpy_func(M), vals, "", ci);
CallInst* memcpy_inst = new CallInst(SLC.get_memcpy(), vals, "", ci);
// Finally, substitute the first operand of the strcat call for the
// strcat call itself since strcat returns its first operand; and,
@ -503,19 +421,108 @@ public:
}
} StrCatOptimizer;
/// This CallOptimizer will simplify a call to the strlen library function by
/// This LibCallOptimization will simplify a call to the strcpy library function.
/// Several optimizations are possible:
/// (1) If src and dest are the same and not volatile, just return dest
/// (2) If the src is a constant then we can convert to llvm.memmove
/// @brief Simplify the strcpy library function.
struct StrCpyOptimization : public LibCallOptimization
{
public:
StrCpyOptimization() : LibCallOptimization("strcpy") {}
virtual ~StrCpyOptimization() {}
/// @brief Make sure that the "strcpy" function has the right prototype
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC)
{
if (f->getReturnType() == PointerType::get(Type::SByteTy))
if (f->arg_size() == 2)
{
Function::const_arg_iterator AI = f->arg_begin();
if (AI++->getType() == PointerType::get(Type::SByteTy))
if (AI->getType() == PointerType::get(Type::SByteTy))
{
// Indicate this is a suitable call type.
return true;
}
}
return false;
}
/// @brief Perform the strcpy optimization
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC)
{
// First, check to see if src and destination are the same. If they are,
// then the optimization is to replace the CallInst with the destination
// because the call is a no-op. Note that this corresponds to the
// degenerate strcpy(X,X) case which should have "undefined" results
// according to the C specification. However, it occurs sometimes and
// we optimize it as a no-op.
Value* dest = ci->getOperand(1);
Value* src = ci->getOperand(2);
if (dest == src)
{
ci->replaceAllUsesWith(dest);
ci->eraseFromParent();
return true;
}
// Get the length of the constant string referenced by the second operand,
// the "src" parameter. Fail the optimization if we can't get the length
// (note that getConstantStringLength does lots of checks to make sure this
// is valid).
uint64_t len = 0;
if (!getConstantStringLength(ci->getOperand(2),len))
return false;
// If the constant string's length is zero we can optimize this by just
// doing a store of 0 at the first byte of the destination
if (len == 0)
{
new StoreInst(ConstantInt::get(Type::SByteTy,0),ci->getOperand(1),ci);
ci->replaceAllUsesWith(dest);
ci->eraseFromParent();
return true;
}
// Increment the length because we actually want to memcpy the null
// terminator as well.
len++;
// Extract some information from the instruction
Module* M = ci->getParent()->getParent()->getParent();
// We have enough information to now generate the memcpy call to
// do the concatenation for us.
std::vector<Value*> vals;
vals.push_back(dest); // destination
vals.push_back(src); // source
vals.push_back(ConstantSInt::get(Type::IntTy,len)); // length
vals.push_back(ConstantSInt::get(Type::IntTy,1)); // alignment
CallInst* memcpy_inst = new CallInst(SLC.get_memcpy(), vals, "", ci);
// Finally, substitute the first operand of the strcat call for the
// strcat call itself since strcat returns its first operand; and,
// kill the strcat CallInst.
ci->replaceAllUsesWith(dest);
ci->eraseFromParent();
return true;
}
} StrCpyOptimizer;
/// This LibCallOptimization will simplify a call to the strlen library function by
/// replacing it with a constant value if the string provided to it is a
/// constant array.
/// @brief Simplify the strlen library function.
struct StrLenOptimization : public CallOptimizer
struct StrLenOptimization : public LibCallOptimization
{
StrLenOptimization() : CallOptimizer("strlen") {}
StrLenOptimization() : LibCallOptimization("strlen") {}
virtual ~StrLenOptimization() {}
/// @brief Make sure that the "strlen" function has the right prototype
virtual bool ValidateCalledFunction(const Function* f, const TargetData& TD)
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC)
{
if (f->getReturnType() == TD.getIntPtrType())
if (f->getReturnType() == SLC.getTargetData()->getIntPtrType())
if (f->arg_size() == 1)
if (Function::const_arg_iterator AI = f->arg_begin())
if (AI->getType() == PointerType::get(Type::SByteTy))
@ -524,33 +531,34 @@ struct StrLenOptimization : public CallOptimizer
}
/// @brief Perform the strlen optimization
virtual bool OptimizeCall(CallInst* ci, const TargetData& TD)
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC)
{
// Get the length of the string
uint64_t len = 0;
if (!getConstantStringLength(ci->getOperand(1),len))
return false;
ci->replaceAllUsesWith(ConstantInt::get(TD.getIntPtrType(),len));
ci->replaceAllUsesWith(
ConstantInt::get(SLC.getTargetData()->getIntPtrType(),len));
ci->eraseFromParent();
return true;
}
} StrLenOptimizer;
/// This CallOptimizer will simplify a call to the memcpy library function by
/// expanding it out to a small set of stores if the copy source is a constant
/// array.
/// This LibCallOptimization will simplify a call to the memcpy library function by
/// expanding it out to a single store of size 0, 1, 2, 4, or 8 bytes depending
/// on the length of the string and the alignment.
/// @brief Simplify the memcpy library function.
struct MemCpyOptimization : public CallOptimizer
struct MemCpyOptimization : public LibCallOptimization
{
MemCpyOptimization() : CallOptimizer("llvm.memcpy") {}
MemCpyOptimization() : LibCallOptimization("llvm.memcpy") {}
protected:
MemCpyOptimization(const char* fname) : CallOptimizer(fname) {}
MemCpyOptimization(const char* fname) : LibCallOptimization(fname) {}
public:
virtual ~MemCpyOptimization() {}
/// @brief Make sure that the "memcpy" function has the right prototype
virtual bool ValidateCalledFunction(const Function* f, const TargetData& TD)
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& TD)
{
// Just make sure this has 4 arguments per LLVM spec.
return (f->arg_size() == 4);
@ -562,7 +570,7 @@ public:
/// alignment match the sizes of our intrinsic types so we can do a load and
/// store instead of the memcpy call.
/// @brief Perform the memcpy optimization.
virtual bool OptimizeCall(CallInst* ci, const TargetData& TD)
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& TD)
{
// Make sure we have constant int values to work with
ConstantInt* LEN = dyn_cast<ConstantInt>(ci->getOperand(3));
@ -614,8 +622,7 @@ public:
}
} MemCpyOptimizer;
/// This CallOptimizer will simplify a call to the memmove library function. It
/// is identical to MemCopyOptimization except for the name of the intrinsic.
/// This LibCallOptimization will simplify a call to the memmove library function. /// It is identical to MemCopyOptimization except for the name of the intrinsic.
/// @brief Simplify the memmove library function.
struct MemMoveOptimization : public MemCpyOptimization
{
@ -623,4 +630,102 @@ struct MemMoveOptimization : public MemCpyOptimization
} MemMoveOptimizer;
/// A function to compute the length of a null-terminated string of integers.
/// This function can't rely on the size of the constant array because there
/// could be a null terminator in the middle of the array. We also have to
/// bail out if we find a non-integer constant initializer of one of the
/// elements or if there is no null-terminator. The logic below checks
bool getConstantStringLength(Value* V, uint64_t& len )
{
assert(V != 0 && "Invalid args to getConstantStringLength");
len = 0; // make sure we initialize this
User* GEP = 0;
// If the value is not a GEP instruction nor a constant expression with a
// GEP instruction, then return false because ConstantArray can't occur
// any other way
if (GetElementPtrInst* GEPI = dyn_cast<GetElementPtrInst>(V))
GEP = GEPI;
else if (ConstantExpr* CE = dyn_cast<ConstantExpr>(V))
if (CE->getOpcode() == Instruction::GetElementPtr)
GEP = CE;
else
return false;
else
return false;
// Make sure the GEP has exactly three arguments.
if (GEP->getNumOperands() != 3)
return false;
// Check to make sure that the first operand of the GEP is an integer and
// has value 0 so that we are sure we're indexing into the initializer.
if (ConstantInt* op1 = dyn_cast<ConstantInt>(GEP->getOperand(1)))
{
if (!op1->isNullValue())
return false;
}
else
return false;
// Ensure that the second operand is a ConstantInt. If it isn't then this
// GEP is wonky and we're not really sure what were referencing into and
// better of not optimizing it. While we're at it, get the second index
// value. We'll need this later for indexing the ConstantArray.
uint64_t start_idx = 0;
if (ConstantInt* CI = dyn_cast<ConstantInt>(GEP->getOperand(2)))
start_idx = CI->getRawValue();
else
return false;
// The GEP instruction, constant or instruction, must reference a global
// variable that is a constant and is initialized. The referenced constant
// initializer is the array that we'll use for optimization.
GlobalVariable* GV = dyn_cast<GlobalVariable>(GEP->getOperand(0));
if (!GV || !GV->isConstant() || !GV->hasInitializer())
return false;
// Get the initializer.
Constant* INTLZR = GV->getInitializer();
// Handle the ConstantAggregateZero case
if (ConstantAggregateZero* CAZ = dyn_cast<ConstantAggregateZero>(INTLZR))
{
// This is a degenerate case. The initializer is constant zero so the
// length of the string must be zero.
len = 0;
return true;
}
// Must be a Constant Array
ConstantArray* A = dyn_cast<ConstantArray>(INTLZR);
if (!A)
return false;
// Get the number of elements in the array
uint64_t max_elems = A->getType()->getNumElements();
// Traverse the constant array from start_idx (derived above) which is
// the place the GEP refers to in the array.
for ( len = start_idx; len < max_elems; len++)
{
if (ConstantInt* CI = dyn_cast<ConstantInt>(A->getOperand(len)))
{
// Check for the null terminator
if (CI->isNullValue())
break; // we found end of string
}
else
return false; // This array isn't suitable, non-int initializer
}
if (len >= max_elems)
return false; // This array isn't null terminated
// Subtract out the initial value from the length
len -= start_idx;
return true; // success!
}
// TODO: Additional cases that we need to add to this file:
// 1. memmove -> memcpy if src is a global constant array
}