instcombine: Migrate printf optimizations

This patch migrates the printf optimizations from the simplify-libcalls
pass into the instcombine library call simplifier.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168604 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Meador Inge
2012-11-26 20:37:20 +00:00
parent 22689b6034
commit d7aa3231f7
6 changed files with 224 additions and 148 deletions

View File

@ -102,6 +102,15 @@ static bool isOnlyUsedInEqualityComparison(Value *V, Value *With) {
return true;
}
static bool callHasFloatingPointArgument(const CallInst *CI) {
for (CallInst::const_op_iterator it = CI->op_begin(), e = CI->op_end();
it != e; ++it) {
if ((*it)->getType()->isFloatingPointTy())
return true;
}
return false;
}
//===----------------------------------------------------------------------===//
// Fortified Library Call Optimizations
//===----------------------------------------------------------------------===//
@ -1312,6 +1321,94 @@ struct ToAsciiOpt : public LibCallOptimization {
}
};
//===----------------------------------------------------------------------===//
// Formatting and IO Library Call Optimizations
//===----------------------------------------------------------------------===//
struct PrintFOpt : public LibCallOptimization {
Value *optimizeFixedFormatString(Function *Callee, CallInst *CI,
IRBuilder<> &B) {
// Check for a fixed format string.
StringRef FormatStr;
if (!getConstantStringInfo(CI->getArgOperand(0), FormatStr))
return 0;
// Empty format string -> noop.
if (FormatStr.empty()) // Tolerate printf's declared void.
return CI->use_empty() ? (Value*)CI :
ConstantInt::get(CI->getType(), 0);
// Do not do any of the following transformations if the printf return value
// is used, in general the printf return value is not compatible with either
// putchar() or puts().
if (!CI->use_empty())
return 0;
// printf("x") -> putchar('x'), even for '%'.
if (FormatStr.size() == 1) {
Value *Res = EmitPutChar(B.getInt32(FormatStr[0]), B, TD, TLI);
if (CI->use_empty() || !Res) return Res;
return B.CreateIntCast(Res, CI->getType(), true);
}
// printf("foo\n") --> puts("foo")
if (FormatStr[FormatStr.size()-1] == '\n' &&
FormatStr.find('%') == std::string::npos) { // no format characters.
// Create a string literal with no \n on it. We expect the constant merge
// pass to be run after this pass, to merge duplicate strings.
FormatStr = FormatStr.drop_back();
Value *GV = B.CreateGlobalString(FormatStr, "str");
Value *NewCI = EmitPutS(GV, B, TD, TLI);
return (CI->use_empty() || !NewCI) ?
NewCI :
ConstantInt::get(CI->getType(), FormatStr.size()+1);
}
// Optimize specific format strings.
// printf("%c", chr) --> putchar(chr)
if (FormatStr == "%c" && CI->getNumArgOperands() > 1 &&
CI->getArgOperand(1)->getType()->isIntegerTy()) {
Value *Res = EmitPutChar(CI->getArgOperand(1), B, TD, TLI);
if (CI->use_empty() || !Res) return Res;
return B.CreateIntCast(Res, CI->getType(), true);
}
// printf("%s\n", str) --> puts(str)
if (FormatStr == "%s\n" && CI->getNumArgOperands() > 1 &&
CI->getArgOperand(1)->getType()->isPointerTy()) {
return EmitPutS(CI->getArgOperand(1), B, TD, TLI);
}
return 0;
}
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Require one fixed pointer argument and an integer/void result.
FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() < 1 || !FT->getParamType(0)->isPointerTy() ||
!(FT->getReturnType()->isIntegerTy() ||
FT->getReturnType()->isVoidTy()))
return 0;
if (Value *V = optimizeFixedFormatString(Callee, CI, B)) {
return V;
}
// printf(format, ...) -> iprintf(format, ...) if no floating point
// arguments.
if (TLI->has(LibFunc::iprintf) && !callHasFloatingPointArgument(CI)) {
Module *M = B.GetInsertBlock()->getParent()->getParent();
Constant *IPrintFFn =
M->getOrInsertFunction("iprintf", FT, Callee->getAttributes());
CallInst *New = cast<CallInst>(CI->clone());
New->setCalledFunction(IPrintFFn);
B.Insert(New);
return New;
}
return 0;
}
};
} // End anonymous namespace.
namespace llvm {
@ -1365,6 +1462,9 @@ class LibCallSimplifierImpl {
IsAsciiOpt IsAscii;
ToAsciiOpt ToAscii;
// Formatting and IO library call optimizations.
PrintFOpt PrintF;
void initOptimizations();
void addOpt(LibFunc::Func F, LibCallOptimization* Opt);
void addOpt(LibFunc::Func F1, LibFunc::Func F2, LibCallOptimization* Opt);
@ -1485,6 +1585,9 @@ void LibCallSimplifierImpl::initOptimizations() {
addOpt(LibFunc::isdigit, &IsDigit);
addOpt(LibFunc::isascii, &IsAscii);
addOpt(LibFunc::toascii, &ToAscii);
// Formatting and IO library call optimizations.
addOpt(LibFunc::printf, &PrintF);
}
Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) {