instcombine: Migrate puts optimizations

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

All the simplifiers from simplify-libcalls have now been migrated to
instcombine.  Yay!  Just a few other bits to migrate (prototype attribute
inference and a few statistics) and simplify-libcalls can finally be put
to rest.

llvm-svn: 168925
This commit is contained in:
Meador Inge 2012-11-29 19:15:17 +00:00
parent 59aeece231
commit 75798bb7fe
4 changed files with 58 additions and 54 deletions

View File

@ -81,41 +81,6 @@ public:
} // End anonymous namespace. } // End anonymous namespace.
namespace {
//===----------------------------------------------------------------------===//
// Formatting and IO Optimizations
//===----------------------------------------------------------------------===//
//===---------------------------------------===//
// 'puts' Optimizations
struct PutsOpt : public LibCallOptimization {
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;
// Check for a constant string.
StringRef Str;
if (!getConstantStringInfo(CI->getArgOperand(0), Str))
return 0;
if (Str.empty() && CI->use_empty()) {
// puts("") -> putchar('\n')
Value *Res = EmitPutChar(B.getInt32('\n'), B, TD, TLI);
if (CI->use_empty() || !Res) return Res;
return B.CreateIntCast(Res, CI->getType(), true);
}
return 0;
}
};
} // end anonymous namespace.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// SimplifyLibCalls Pass Implementation // SimplifyLibCalls Pass Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -127,8 +92,6 @@ namespace {
TargetLibraryInfo *TLI; TargetLibraryInfo *TLI;
StringMap<LibCallOptimization*> Optimizations; StringMap<LibCallOptimization*> Optimizations;
// Formatting and IO Optimizations
PutsOpt Puts;
bool Modified; // This is only used by doInitialization. bool Modified; // This is only used by doInitialization.
public: public:
@ -183,8 +146,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,
/// Optimizations - Populate the Optimizations map with all the optimizations /// Optimizations - Populate the Optimizations map with all the optimizations
/// we know. /// we know.
void SimplifyLibCalls::InitOptimizations() { void SimplifyLibCalls::InitOptimizations() {
// Formatting and IO Optimizations
Optimizations["puts"] = &Puts;
} }

View File

@ -1632,6 +1632,31 @@ struct FPutsOpt : public LibCallOptimization {
} }
}; };
struct PutsOpt : public LibCallOptimization {
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;
// Check for a constant string.
StringRef Str;
if (!getConstantStringInfo(CI->getArgOperand(0), Str))
return 0;
if (Str.empty() && CI->use_empty()) {
// puts("") -> putchar('\n')
Value *Res = EmitPutChar(B.getInt32('\n'), B, TD, TLI);
if (CI->use_empty() || !Res) return Res;
return B.CreateIntCast(Res, CI->getType(), true);
}
return 0;
}
};
} // End anonymous namespace. } // End anonymous namespace.
namespace llvm { namespace llvm {
@ -1691,6 +1716,7 @@ class LibCallSimplifierImpl {
FPrintFOpt FPrintF; FPrintFOpt FPrintF;
FWriteOpt FWrite; FWriteOpt FWrite;
FPutsOpt FPuts; FPutsOpt FPuts;
PutsOpt Puts;
void initOptimizations(); void initOptimizations();
void addOpt(LibFunc::Func F, LibCallOptimization* Opt); void addOpt(LibFunc::Func F, LibCallOptimization* Opt);
@ -1819,6 +1845,7 @@ void LibCallSimplifierImpl::initOptimizations() {
addOpt(LibFunc::fprintf, &FPrintF); addOpt(LibFunc::fprintf, &FPrintF);
addOpt(LibFunc::fwrite, &FWrite); addOpt(LibFunc::fwrite, &FWrite);
addOpt(LibFunc::fputs, &FPuts); addOpt(LibFunc::fputs, &FPuts);
addOpt(LibFunc::puts, &Puts);
} }
Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) { Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) {

View File

@ -0,0 +1,31 @@
; Test that the puts library call simplifier works correctly.
;
; RUN: opt < %s -instcombine -S | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
@empty = constant [1 x i8] zeroinitializer
declare i32 @puts(i8*)
; Check puts("") -> putchar('\n').
define void @test_simplify1() {
; CHECK: @test_simplify1
%str = getelementptr [1 x i8]* @empty, i32 0, i32 0
call i32 @puts(i8* %str)
; CHECK-NEXT: call i32 @putchar(i32 10)
ret void
; CHECK-NEXT: ret void
}
; Don't simplify if the return value is used.
define i32 @test_no_simplify1() {
; CHECK: @test_no_simplify1
%str = getelementptr [1 x i8]* @empty, i32 0, i32 0
%ret = call i32 @puts(i8* %str)
; CHECK-NEXT: call i32 @puts(i8* getelementptr inbounds ([1 x i8]* @empty, i32 0, i32 0))
ret i32 %ret
; CHECK-NEXT: ret i32 %ret
}

View File

@ -1,15 +0,0 @@
; Test that the PutsOptimizer works correctly
; RUN: opt < %s -simplify-libcalls -S | FileCheck %s
target datalayout = "p:64:64:64"
@.str = private constant [1 x i8] zeroinitializer
declare i32 @puts(i8*)
define void @foo() {
entry:
; CHECK: call i32 @putchar(i32 10)
%call = call i32 @puts(i8* getelementptr inbounds ([1 x i8]* @.str, i32 0, i32 0))
ret void
}