[llvm-commits] CVS: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp
Reid Spencer
reid at x10sys.com
Tue May 3 20:20:32 PDT 2005
Changes in directory llvm/lib/Transforms/IPO:
SimplifyLibCalls.cpp updated: 1.29 -> 1.30
---
Log message:
* Correct the function prototypes for some of the functions to match the
actual spec (int -> uint)
* Add the ability to get/cache the strlen function prototype.
* Make sure generated values are appropriately named for debugging purposes
* Add the SPrintFOptimiation for 4 casts of sprintf optimization:
sprintf(str,cstr) -> llvm.memcpy(str,cstr) (if cstr has no %)
sprintf(str,"") -> store sbyte 0, str
sprintf(str,"%s",src) -> llvm.memcpy(str,src) (if src is constant)
sprintf(str,"%c",chr) -> store chr, str ; store sbyte 0, str+1
The sprintf optimization didn't fire as much as I had hoped:
2 MultiSource/Applications/SPASS
5 MultiSource/Benchmarks/McCat/18-imp
22 MultiSource/Benchmarks/Prolangs-C/TimberWolfMC
1 MultiSource/Benchmarks/Prolangs-C/assembler
6 MultiSource/Benchmarks/Prolangs-C/unix-smail
2 MultiSource/Benchmarks/mediabench/mpeg2/mpeg2dec
---
Diffs of the changes: (+172 -9)
SimplifyLibCalls.cpp | 181 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 172 insertions(+), 9 deletions(-)
Index: llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp
diff -u llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.29 llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.30
--- llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp:1.29 Tue May 3 02:23:44 2005
+++ llvm/lib/Transforms/IPO/SimplifyLibCalls.cpp Tue May 3 22:20:21 2005
@@ -257,6 +257,21 @@
}
/// @brief Return a Function* for the strlen libcall
+ Function* get_strcpy()
+ {
+ if (!strcpy_func)
+ {
+ std::vector<const Type*> args;
+ args.push_back(PointerType::get(Type::SByteTy));
+ args.push_back(PointerType::get(Type::SByteTy));
+ FunctionType* strcpy_type =
+ FunctionType::get(PointerType::get(Type::SByteTy), args, false);
+ strcpy_func = M->getOrInsertFunction("strcpy",strcpy_type);
+ }
+ return strcpy_func;
+ }
+
+ /// @brief Return a Function* for the strlen libcall
Function* get_strlen()
{
if (!strlen_func)
@@ -295,8 +310,8 @@
std::vector<const Type*> args;
args.push_back(PointerType::get(Type::SByteTy));
args.push_back(PointerType::get(Type::SByteTy));
- args.push_back(Type::IntTy);
- args.push_back(Type::IntTy);
+ args.push_back(Type::UIntTy);
+ args.push_back(Type::UIntTy);
FunctionType* memcpy_type = FunctionType::get(Type::VoidTy, args, false);
memcpy_func = M->getOrInsertFunction("llvm.memcpy",memcpy_type);
}
@@ -314,6 +329,7 @@
memcpy_func = 0;
memchr_func = 0;
sqrt_func = 0;
+ strcpy_func = 0;
strlen_func = 0;
}
@@ -323,6 +339,7 @@
Function* memcpy_func; ///< Cached llvm.memcpy function
Function* memchr_func; ///< Cached memchr function
Function* sqrt_func; ///< Cached sqrt function
+ Function* strcpy_func; ///< Cached strcpy function
Function* strlen_func; ///< Cached strlen function
Module* M; ///< Cached Module
TargetData* TD; ///< Cached TargetData
@@ -493,8 +510,8 @@
std::vector<Value*> vals;
vals.push_back(gep); // destination
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
+ vals.push_back(ConstantUInt::get(Type::UIntTy,len)); // length
+ vals.push_back(ConstantUInt::get(Type::UIntTy,1)); // alignment
new CallInst(SLC.get_memcpy(), vals, "", ci);
// Finally, substitute the first operand of the strcat call for the
@@ -862,8 +879,8 @@
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
+ vals.push_back(ConstantUInt::get(Type::UIntTy,len)); // length
+ vals.push_back(ConstantUInt::get(Type::UIntTy,1)); // alignment
new CallInst(SLC.get_memcpy(), vals, "", ci);
// Finally, substitute the first operand of the strcat call for the
@@ -1255,7 +1272,8 @@
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);
+ new CallInst(fwrite_func,args,ci->getName(),ci);
+ ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,len));
ci->eraseFromParent();
return true;
}
@@ -1281,7 +1299,7 @@
if (!getConstantStringLength(ci->getOperand(3), len, &CA))
return false;
- // fprintf(file,fmt) -> fwrite(fmt,strlen(fmt),1,file)
+ // fprintf(file,"%s",str) -> 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)
@@ -1291,7 +1309,8 @@
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);
+ new CallInst(fwrite_func,args,ci->getName(),ci);
+ ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,len));
break;
}
case 'c':
@@ -1306,6 +1325,7 @@
return false;
CastInst* cast = new CastInst(CI,Type::IntTy,CI->getName()+".int",ci);
new CallInst(fputc_func,cast,ci->getOperand(1),"",ci);
+ ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,1));
break;
}
default:
@@ -1317,6 +1337,149 @@
} FPrintFOptimizer;
+/// This LibCallOptimization will simplify calls to the "sprintf" library
+/// function. It looks for cases where the result of sprintf is not used and the
+/// operation can be reduced to something simpler.
+/// @brief Simplify the pow library function.
+struct SPrintFOptimization : public LibCallOptimization
+{
+public:
+ /// @brief Default Constructor
+ SPrintFOptimization() : LibCallOptimization("sprintf",
+ "simplify-libcalls:sprintf", "Number of 'sprintf' calls simplified") {}
+
+ /// @brief Destructor
+ virtual ~SPrintFOptimization() {}
+
+ /// @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->getReturnType() == Type::IntTy && f->arg_size() >= 2);
+ }
+
+ /// @brief Perform the sprintf 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() < 3)
+ 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)
+ {
+ if (len == 0)
+ {
+ // If the length is 0, we just need to store a null byte
+ new StoreInst(ConstantInt::get(Type::SByteTy,0),ci->getOperand(1),ci);
+ ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,0));
+ ci->eraseFromParent();
+ return true;
+ }
+
+ // 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 a %, can't optimize
+ }
+ else
+ return false; // initializer is not constant int, can't optimize
+ }
+
+ // Increment length because we want to copy the null byte too
+ len++;
+
+ // sprintf(str,fmt) -> llvm.memcpy(str,fmt,strlen(fmt),1)
+ Function* memcpy_func = SLC.get_memcpy();
+ if (!memcpy_func)
+ return false;
+ std::vector<Value*> args;
+ args.push_back(ci->getOperand(1));
+ args.push_back(ci->getOperand(2));
+ args.push_back(ConstantUInt::get(Type::UIntTy,len));
+ args.push_back(ConstantUInt::get(Type::UIntTy,1));
+ new CallInst(memcpy_func,args,"",ci);
+ ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,len));
+ 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;
+ if (ci->hasNUses(0))
+ {
+ // sprintf(dest,"%s",str) -> strcpy(dest,str)
+ Function* strcpy_func = SLC.get_strcpy();
+ if (!strcpy_func)
+ return false;
+ std::vector<Value*> args;
+ args.push_back(ci->getOperand(1));
+ args.push_back(ci->getOperand(3));
+ new CallInst(strcpy_func,args,"",ci);
+ }
+ else if (getConstantStringLength(ci->getOperand(3),len))
+ {
+ // sprintf(dest,"%s",cstr) -> llvm.memcpy(dest,str,strlen(str),1)
+ len++; // get the null-terminator
+ Function* memcpy_func = SLC.get_memcpy();
+ if (!memcpy_func)
+ return false;
+ std::vector<Value*> args;
+ args.push_back(ci->getOperand(1));
+ args.push_back(ci->getOperand(3));
+ args.push_back(ConstantUInt::get(Type::UIntTy,len));
+ args.push_back(ConstantUInt::get(Type::UIntTy,1));
+ new CallInst(memcpy_func,args,"",ci);
+ ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,len));
+ }
+ break;
+ }
+ case 'c':
+ {
+ // sprintf(dest,"%c",chr) -> store chr, dest
+ CastInst* cast =
+ new CastInst(ci->getOperand(3),Type::SByteTy,"char",ci);
+ new StoreInst(cast, ci->getOperand(1), ci);
+ GetElementPtrInst* gep = new GetElementPtrInst(ci->getOperand(1),
+ ConstantUInt::get(Type::UIntTy,1),ci->getOperand(1)->getName()+".end",
+ ci);
+ new StoreInst(ConstantInt::get(Type::SByteTy,0),gep,ci);
+ ci->replaceAllUsesWith(ConstantSInt::get(Type::IntTy,1));
+ break;
+ }
+ default:
+ return false;
+ }
+ ci->eraseFromParent();
+ return true;
+ }
+} SPrintFOptimizer;
+
/// 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.
More information about the llvm-commits
mailing list