aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/SimplifyLibCalls.cpp
diff options
context:
space:
mode:
authorReid Spencer <rspencer@reidspencer.com>2005-05-02 23:59:26 +0000
committerReid Spencer <rspencer@reidspencer.com>2005-05-02 23:59:26 +0000
commita1b43909389a06186394cb895ad18a7d25ea050f (patch)
tree21135b67d47638f0c5619297474452ac505e9337 /lib/Transforms/IPO/SimplifyLibCalls.cpp
parent6302abe69f2a741206c7b461776977fc7d4bf822 (diff)
Implement the fprintf optimization which converts calls like this:
fprintf(F,"hello") -> fwrite("hello",strlen("hello"),1,F) fprintf(F,"%s","hello") -> fwrite("hello",strlen("hello"),1,F) fprintf(F,"%c",'x') -> fputc('c',F) This optimization fires severals times in llvm-test: 313 MultiSource/Applications/Burg 302 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC 189 MultiSource/Benchmarks/Prolangs-C/mybison 175 MultiSource/Benchmarks/Prolangs-C/football 130 MultiSource/Benchmarks/Prolangs-C/unix-tbl git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21657 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/IPO/SimplifyLibCalls.cpp')
-rw-r--r--lib/Transforms/IPO/SimplifyLibCalls.cpp133
1 files changed, 126 insertions, 7 deletions
diff --git a/lib/Transforms/IPO/SimplifyLibCalls.cpp b/lib/Transforms/IPO/SimplifyLibCalls.cpp
index 9a4a4f3273..13b58ac490 100644
--- a/lib/Transforms/IPO/SimplifyLibCalls.cpp
+++ b/lib/Transforms/IPO/SimplifyLibCalls.cpp
@@ -858,6 +858,132 @@ public:
}
} PowOptimizer;
+/// This LibCallOptimization will simplify calls to the "fprintf" library
+/// function. It looks for cases where the result of fprintf is not used and the
+/// operation can be reduced to something simpler.
+/// @brief Simplify the pow library function.
+struct FPrintFOptimization : public LibCallOptimization
+{
+public:
+ /// @brief Default Constructor
+ FPrintFOptimization() : LibCallOptimization("fprintf") {}
+
+ /// @brief Destructor
+ virtual ~FPrintFOptimization() {}
+
+ /// @brief Make sure that the "fprintf" function has the right prototype
+ virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC)
+ {
+ // Just make sure this has at least 2 arguments
+ return (f->arg_size() >= 2);
+ }
+
+ /// @brief Perform the fprintf optimization.
+ virtual bool OptimizeCall(CallInst* ci, SimplifyLibCalls& SLC)
+ {
+ // If the call has more than 3 operands, we can't optimize it
+ if (ci->getNumOperands() > 4 || ci->getNumOperands() <= 2)
+ return false;
+
+ // If the result of the fprintf call is used, none of these optimizations
+ // can be made.
+ if (!ci->hasNUses(0))
+ return false;
+
+ // All the optimizations depend on the length of the second argument and the
+ // fact that it is a constant string array. Check that now
+ uint64_t len = 0;
+ ConstantArray* CA = 0;
+ if (!getConstantStringLength(ci->getOperand(2), len, &CA))
+ return false;
+
+ if (ci->getNumOperands() == 3)
+ {
+ // Make sure there's no % in the constant array
+ for (unsigned i = 0; i < len; ++i)
+ {
+ if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(i)))
+ {
+ // Check for the null terminator
+ if (CI->getRawValue() == '%')
+ return false; // we found end of string
+ }
+ else
+ return false;
+ }
+
+ // fprintf(file,fmt) -> fwrite(fmt,strlen(fmt),1file)
+ const Type* FILEptr_type = ci->getOperand(1)->getType();
+ Function* fwrite_func = SLC.get_fwrite(FILEptr_type);
+ if (!fwrite_func)
+ return false;
+ std::vector<Value*> args;
+ args.push_back(ci->getOperand(2));
+ args.push_back(ConstantUInt::get(SLC.getIntPtrType(),len));
+ args.push_back(ConstantUInt::get(SLC.getIntPtrType(),1));
+ args.push_back(ci->getOperand(1));
+ new CallInst(fwrite_func,args,"",ci);
+ ci->eraseFromParent();
+ return true;
+ }
+
+ // The remaining optimizations require the format string to be length 2
+ // "%s" or "%c".
+ if (len != 2)
+ return false;
+
+ // The first character has to be a %
+ if (ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(0)))
+ if (CI->getRawValue() != '%')
+ return false;
+
+ // Get the second character and switch on its value
+ ConstantInt* CI = dyn_cast<ConstantInt>(CA->getOperand(1));
+ switch (CI->getRawValue())
+ {
+ case 's':
+ {
+ uint64_t len = 0;
+ ConstantArray* CA = 0;
+ if (!getConstantStringLength(ci->getOperand(3), len, &CA))
+ return false;
+
+ // fprintf(file,fmt) -> fwrite(fmt,strlen(fmt),1,file)
+ const Type* FILEptr_type = ci->getOperand(1)->getType();
+ Function* fwrite_func = SLC.get_fwrite(FILEptr_type);
+ if (!fwrite_func)
+ return false;
+ std::vector<Value*> args;
+ args.push_back(ci->getOperand(3));
+ args.push_back(ConstantUInt::get(SLC.getIntPtrType(),len));
+ args.push_back(ConstantUInt::get(SLC.getIntPtrType(),1));
+ args.push_back(ci->getOperand(1));
+ new CallInst(fwrite_func,args,"",ci);
+ break;
+ }
+ case 'c':
+ {
+ ConstantInt* CI = dyn_cast<ConstantInt>(ci->getOperand(3));
+ if (!CI)
+ return false;
+
+ const Type* FILEptr_type = ci->getOperand(1)->getType();
+ Function* fputc_func = SLC.get_fputc(FILEptr_type);
+ if (!fputc_func)
+ return false;
+ CastInst* cast = new CastInst(CI,Type::IntTy,CI->getName()+".int",ci);
+ new CallInst(fputc_func,cast,ci->getOperand(1),"",ci);
+ break;
+ }
+ default:
+ return false;
+ }
+ ci->eraseFromParent();
+ return true;
+ }
+} FPrintFOptimizer;
+
+
/// This LibCallOptimization will simplify calls to the "fputs" library
/// function. It looks for cases where the result of fputs is not used and the
/// operation can be reduced to something simpler.
@@ -1083,13 +1209,6 @@ bool getConstantStringLength(Value* V, uint64_t& len, ConstantArray** CA )
// ffs, ffsl, ffsll:
// * ffs(cnst) -> cnst'
//
-// fprintf:
-// * fprintf(file,fmt) -> fputs(fmt,file)
-// (if fmt is constant and constains no % characters)
-// * fprintf(file,"%s",str) -> fputs(orig,str)
-// (only if the fprintf result is not used)
-// * fprintf(file,"%c",chr) -> fputc(chr,file)
-//
// isascii:
// * isascii(c) -> ((c & ~0x7f) == 0)
//