From bc84d1a4f56ccbe55c37d43e7d7a6814ef238e62 Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Thu, 29 Nov 2012 15:45:39 +0000 Subject: [PATCH] instcombine: Migrate fwrite optimizations This patch migrates the fwrite optimizations from the simplify-libcalls pass into the instcombine library call simplifier. llvm-svn: 168892 --- llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp | 39 +---------------- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp | 35 +++++++++++++++ llvm/test/Transforms/InstCombine/fwrite-1.ll | 57 +++++++++++++++++++++++++ llvm/test/Transforms/SimplifyLibCalls/fwrite.ll | 13 ------ 4 files changed, 93 insertions(+), 51 deletions(-) create mode 100644 llvm/test/Transforms/InstCombine/fwrite-1.ll delete mode 100644 llvm/test/Transforms/SimplifyLibCalls/fwrite.ll diff --git a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp index 61b5725..7e44b03 100644 --- a/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -87,42 +87,6 @@ namespace { //===----------------------------------------------------------------------===// //===---------------------------------------===// -// 'fwrite' Optimizations - -struct FWriteOpt : public LibCallOptimization { - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - // Require a pointer, an integer, an integer, a pointer, returning integer. - FunctionType *FT = Callee->getFunctionType(); - if (FT->getNumParams() != 4 || !FT->getParamType(0)->isPointerTy() || - !FT->getParamType(1)->isIntegerTy() || - !FT->getParamType(2)->isIntegerTy() || - !FT->getParamType(3)->isPointerTy() || - !FT->getReturnType()->isIntegerTy()) - return 0; - - // Get the element size and count. - ConstantInt *SizeC = dyn_cast(CI->getArgOperand(1)); - ConstantInt *CountC = dyn_cast(CI->getArgOperand(2)); - if (!SizeC || !CountC) return 0; - uint64_t Bytes = SizeC->getZExtValue()*CountC->getZExtValue(); - - // If this is writing zero records, remove the call (it's a noop). - if (Bytes == 0) - return ConstantInt::get(CI->getType(), 0); - - // If this is writing one byte, turn it into fputc. - // This optimisation is only valid, if the return value is unused. - if (Bytes == 1 && CI->use_empty()) { // fwrite(S,1,1,F) -> fputc(S[0],F) - Value *Char = B.CreateLoad(CastToCStr(CI->getArgOperand(0), B), "char"); - Value *NewCI = EmitFPutC(Char, CI->getArgOperand(3), B, TD, TLI); - return NewCI ? ConstantInt::get(CI->getType(), 1) : 0; - } - - return 0; - } -}; - -//===---------------------------------------===// // 'fputs' Optimizations struct FPutsOpt : public LibCallOptimization { @@ -189,7 +153,7 @@ namespace { StringMap Optimizations; // Formatting and IO Optimizations - FWriteOpt FWrite; FPutsOpt FPuts; + FPutsOpt FPuts; PutsOpt Puts; bool Modified; // This is only used by doInitialization. @@ -246,7 +210,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2, /// we know. void SimplifyLibCalls::InitOptimizations() { // Formatting and IO Optimizations - AddOpt(LibFunc::fwrite, &FWrite); AddOpt(LibFunc::fputs, &FPuts); Optimizations["puts"] = &Puts; } diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 5d217bb..00a5d89 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1577,6 +1577,39 @@ struct FPrintFOpt : public LibCallOptimization { } }; +struct FWriteOpt : public LibCallOptimization { + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + // Require a pointer, an integer, an integer, a pointer, returning integer. + FunctionType *FT = Callee->getFunctionType(); + if (FT->getNumParams() != 4 || !FT->getParamType(0)->isPointerTy() || + !FT->getParamType(1)->isIntegerTy() || + !FT->getParamType(2)->isIntegerTy() || + !FT->getParamType(3)->isPointerTy() || + !FT->getReturnType()->isIntegerTy()) + return 0; + + // Get the element size and count. + ConstantInt *SizeC = dyn_cast(CI->getArgOperand(1)); + ConstantInt *CountC = dyn_cast(CI->getArgOperand(2)); + if (!SizeC || !CountC) return 0; + uint64_t Bytes = SizeC->getZExtValue()*CountC->getZExtValue(); + + // If this is writing zero records, remove the call (it's a noop). + if (Bytes == 0) + return ConstantInt::get(CI->getType(), 0); + + // If this is writing one byte, turn it into fputc. + // This optimisation is only valid, if the return value is unused. + if (Bytes == 1 && CI->use_empty()) { // fwrite(S,1,1,F) -> fputc(S[0],F) + Value *Char = B.CreateLoad(CastToCStr(CI->getArgOperand(0), B), "char"); + Value *NewCI = EmitFPutC(Char, CI->getArgOperand(3), B, TD, TLI); + return NewCI ? ConstantInt::get(CI->getType(), 1) : 0; + } + + return 0; + } +}; + } // End anonymous namespace. namespace llvm { @@ -1634,6 +1667,7 @@ class LibCallSimplifierImpl { PrintFOpt PrintF; SPrintFOpt SPrintF; FPrintFOpt FPrintF; + FWriteOpt FWrite; void initOptimizations(); void addOpt(LibFunc::Func F, LibCallOptimization* Opt); @@ -1760,6 +1794,7 @@ void LibCallSimplifierImpl::initOptimizations() { addOpt(LibFunc::printf, &PrintF); addOpt(LibFunc::sprintf, &SPrintF); addOpt(LibFunc::fprintf, &FPrintF); + addOpt(LibFunc::fwrite, &FWrite); } Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) { diff --git a/llvm/test/Transforms/InstCombine/fwrite-1.ll b/llvm/test/Transforms/InstCombine/fwrite-1.ll new file mode 100644 index 0000000..528cdec --- /dev/null +++ b/llvm/test/Transforms/InstCombine/fwrite-1.ll @@ -0,0 +1,57 @@ +; Test that the fwrite 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" + +%FILE = type { } + +@str = constant [1 x i8] zeroinitializer +@empty = constant [0 x i8] zeroinitializer + +declare i64 @fwrite(i8*, i64, i64, %FILE *) + +; Check fwrite(S, 1, 1, fp) -> fputc(S[0], fp). + +define void @test_simplify1(%FILE* %fp) { +; CHECK: @test_simplify1 + %str = getelementptr inbounds [1 x i8]* @str, i64 0, i64 0 + call i64 @fwrite(i8* %str, i64 1, i64 1, %FILE* %fp) +; CHECK-NEXT: call i32 @fputc(i32 0, %FILE* %fp) + ret void +; CHECK-NEXT: ret void +} + +define void @test_simplify2(%FILE* %fp) { +; CHECK: @test_simplify2 + %str = getelementptr inbounds [0 x i8]* @empty, i64 0, i64 0 + call i64 @fwrite(i8* %str, i64 1, i64 0, %FILE* %fp) + ret void +; CHECK-NEXT: ret void +} + +define void @test_simplify3(%FILE* %fp) { +; CHECK: @test_simplify3 + %str = getelementptr inbounds [0 x i8]* @empty, i64 0, i64 0 + call i64 @fwrite(i8* %str, i64 0, i64 1, %FILE* %fp) + ret void +; CHECK-NEXT: ret void +} + +define i64 @test_no_simplify1(%FILE* %fp) { +; CHECK: @test_no_simplify1 + %str = getelementptr inbounds [1 x i8]* @str, i64 0, i64 0 + %ret = call i64 @fwrite(i8* %str, i64 1, i64 1, %FILE* %fp) +; CHECK-NEXT: call i64 @fwrite + ret i64 %ret +; CHECK-NEXT: ret i64 %ret +} + +define void @test_no_simplify2(%FILE* %fp, i64 %size) { +; CHECK: @test_no_simplify2 + %str = getelementptr inbounds [1 x i8]* @str, i64 0, i64 0 + call i64 @fwrite(i8* %str, i64 %size, i64 1, %FILE* %fp) +; CHECK-NEXT: call i64 @fwrite + ret void +; CHECK-NEXT: ret void +} diff --git a/llvm/test/Transforms/SimplifyLibCalls/fwrite.ll b/llvm/test/Transforms/SimplifyLibCalls/fwrite.ll deleted file mode 100644 index f0f3dca..0000000 --- a/llvm/test/Transforms/SimplifyLibCalls/fwrite.ll +++ /dev/null @@ -1,13 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s - -%FILE = type { i32 } - -@.str = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 - -define i64 @foo(%FILE* %f) { -; CHECK: %retval = call i64 @fwrite - %retval = call i64 @fwrite(i8* getelementptr inbounds ([1 x i8]* @.str, i64 0, i64 0), i64 1, i64 1, %FILE* %f) - ret i64 %retval -} - -declare i64 @fwrite(i8*, i64, i64, %FILE *) -- 2.7.4