/// 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");
+ "Total number of library calls simplified");
// Forward declarations
class LibCallOptimization;
/// The \p fname argument must be the name of the library function being
/// optimized by the subclass.
/// @brief Constructor that registers the optimization.
- LibCallOptimization(const char* fname,
- const char* stat_name, const char* description )
+ LibCallOptimization(const char* fname, const char* description )
: func_name(fname)
#ifndef NDEBUG
- , occurrences(stat_name,description)
+ , occurrences("simplify-libcalls",description)
#endif
{
// Register this call optimizer in the optlist (a hash_map)
struct ExitInMainOptimization : public LibCallOptimization
{
ExitInMainOptimization() : LibCallOptimization("exit",
- "simplify-libcalls:exit","Number of 'exit' calls simplified") {}
+ "Number of 'exit' calls simplified") {}
virtual ~ExitInMainOptimization() {}
// Make sure the called function looks like exit (int argument, int return
public:
/// @brief Default constructor
StrCatOptimization() : LibCallOptimization("strcat",
- "simplify-libcalls:strcat","Number of 'strcat' calls simplified") {}
+ "Number of 'strcat' calls simplified") {}
public:
/// @breif Destructor
{
public:
StrChrOptimization() : LibCallOptimization("strchr",
- "simplify-libcalls:strchr","Number of 'strchr' calls simplified") {}
+ "Number of 'strchr' calls simplified") {}
virtual ~StrChrOptimization() {}
/// @brief Make sure that the "strchr" function has the right prototype
{
public:
StrCmpOptimization() : LibCallOptimization("strcmp",
- "simplify-libcalls:strcmp","Number of 'strcmp' calls simplified") {}
+ "Number of 'strcmp' calls simplified") {}
virtual ~StrCmpOptimization() {}
/// @brief Make sure that the "strcpy" function has the right prototype
{
public:
StrNCmpOptimization() : LibCallOptimization("strncmp",
- "simplify-libcalls:strncmp","Number of 'strncmp' calls simplified") {}
+ "Number of 'strncmp' calls simplified") {}
virtual ~StrNCmpOptimization() {}
/// @brief Make sure that the "strcpy" function has the right prototype
{
public:
StrCpyOptimization() : LibCallOptimization("strcpy",
- "simplify-libcalls:strcpy","Number of 'strcpy' calls simplified") {}
+ "Number of 'strcpy' calls simplified") {}
virtual ~StrCpyOptimization() {}
/// @brief Make sure that the "strcpy" function has the right prototype
struct StrLenOptimization : public LibCallOptimization
{
StrLenOptimization() : LibCallOptimization("strlen",
- "simplify-libcalls:strlen","Number of 'strlen' calls simplified") {}
+ "Number of 'strlen' calls simplified") {}
virtual ~StrLenOptimization() {}
/// @brief Make sure that the "strlen" function has the right prototype
/// @brief Perform the strlen optimization
virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC)
{
- // Get the length of the string
+ // Make sure we're dealing with an sbyte* here.
+ Value* str = ci->getOperand(1);
+ if (str->getType() != PointerType::get(Type::SByteTy))
+ return false;
+
+ // Does the call to strlen have exactly one use?
+ if (ci->hasOneUse())
+ // Is that single use a binary operator?
+ if (BinaryOperator* bop = dyn_cast<BinaryOperator>(ci->use_back()))
+ // Is it compared against a constant integer?
+ if (ConstantInt* CI = dyn_cast<ConstantInt>(bop->getOperand(1)))
+ {
+ // Get the value the strlen result is compared to
+ uint64_t val = CI->getRawValue();
+
+ // If its compared against length 0 with == or !=
+ if (val == 0 &&
+ (bop->getOpcode() == Instruction::SetEQ ||
+ bop->getOpcode() == Instruction::SetNE))
+ {
+ // strlen(x) != 0 -> *x != 0
+ // strlen(x) == 0 -> *x == 0
+ LoadInst* load = new LoadInst(str,str->getName()+".first",ci);
+ BinaryOperator* rbop = BinaryOperator::create(bop->getOpcode(),
+ load, ConstantSInt::get(Type::SByteTy,0),
+ bop->getName()+".strlen", ci);
+ bop->replaceAllUsesWith(rbop);
+ bop->eraseFromParent();
+ ci->eraseFromParent();
+ return true;
+ }
+ }
+
+ // Get the length of the constant string operand
uint64_t len = 0;
if (!getConstantStringLength(ci->getOperand(1),len))
return false;
+ // strlen("xyz") -> 3 (for example)
ci->replaceAllUsesWith(
ConstantInt::get(SLC.getTargetData()->getIntPtrType(),len));
ci->eraseFromParent();
{
/// @brief Default Constructor
LLVMMemCpyOptimization() : LibCallOptimization("llvm.memcpy",
- "simplify-libcalls:llvm.memcpy",
"Number of 'llvm.memcpy' calls simplified") {}
protected:
/// @brief Subclass Constructor
- LLVMMemCpyOptimization(const char* fname, const char* sname, const char* desc)
- : LibCallOptimization(fname, sname, desc) {}
+ LLVMMemCpyOptimization(const char* fname, const char* desc)
+ : LibCallOptimization(fname, desc) {}
public:
/// @brief Destructor
virtual ~LLVMMemCpyOptimization() {}
{
/// @brief Default Constructor
LLVMMemMoveOptimization() : LLVMMemCpyOptimization("llvm.memmove",
- "simplify-libcalls:llvm.memmove",
"Number of 'llvm.memmove' calls simplified") {}
} LLVMMemMoveOptimizer;
{
/// @brief Default Constructor
LLVMMemSetOptimization() : LibCallOptimization("llvm.memset",
- "simplify-libcalls:llvm.memset",
"Number of 'llvm.memset' calls simplified") {}
public:
public:
/// @brief Default Constructor
PowOptimization() : LibCallOptimization("pow",
- "simplify-libcalls:pow", "Number of 'pow' calls simplified") {}
+ "Number of 'pow' calls simplified") {}
/// @brief Destructor
virtual ~PowOptimization() {}
public:
/// @brief Default Constructor
FPrintFOptimization() : LibCallOptimization("fprintf",
- "simplify-libcalls:fprintf", "Number of 'fprintf' calls simplified") {}
+ "Number of 'fprintf' calls simplified") {}
/// @brief Destructor
virtual ~FPrintFOptimization() {}
public:
/// @brief Default Constructor
SPrintFOptimization() : LibCallOptimization("sprintf",
- "simplify-libcalls:sprintf", "Number of 'sprintf' calls simplified") {}
+ "Number of 'sprintf' calls simplified") {}
/// @brief Destructor
virtual ~SPrintFOptimization() {}
public:
/// @brief Default Constructor
PutsOptimization() : LibCallOptimization("fputs",
- "simplify-libcalls:fputs", "Number of 'fputs' calls simplified") {}
+ "Number of 'fputs' calls simplified") {}
/// @brief Destructor
virtual ~PutsOptimization() {}
public:
/// @brief Default Constructor
IsDigitOptimization() : LibCallOptimization("isdigit",
- "simplify-libcalls:isdigit", "Number of 'isdigit' calls simplified") {}
+ "Number of 'isdigit' calls simplified") {}
/// @brief Destructor
virtual ~IsDigitOptimization() {}
public:
/// @brief Default Constructor
ToAsciiOptimization() : LibCallOptimization("toascii",
- "simplify-libcalls:toascii", "Number of 'toascii' calls simplified") {}
+ "Number of 'toascii' calls simplified") {}
/// @brief Destructor
virtual ~ToAsciiOptimization() {}
// * sqrt(Nroot(x)) -> pow(x,1/(2*N))
// * sqrt(pow(x,y)) -> pow(|x|,y*0.5)
//
+// stpcpy:
+// * stpcpy(str, "literal") ->
+// llvm.memcpy(str,"literal",strlen("literal")+1,1)
// strrchr:
// * strrchr(s,c) -> reverse_offset_of_in(c,s)
// (if c is a constant integer and s is a constant string)