Skip to content

Commit

Permalink
instcombine: Migrate fwrite optimizations
Browse files Browse the repository at this point in the history
This patch migrates the fwrite optimizations from the simplify-libcalls
pass into the instcombine library call simplifier.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168892 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
meadori committed Nov 29, 2012
1 parent 28d5291 commit c2e3312
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 51 deletions.
39 changes: 1 addition & 38 deletions lib/Transforms/Scalar/SimplifyLibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,42 +86,6 @@ namespace {
// Formatting and IO Optimizations
//===----------------------------------------------------------------------===//

//===---------------------------------------===//
// '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<ConstantInt>(CI->getArgOperand(1));
ConstantInt *CountC = dyn_cast<ConstantInt>(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

Expand Down Expand Up @@ -189,7 +153,7 @@ namespace {

StringMap<LibCallOptimization*> Optimizations;
// Formatting and IO Optimizations
FWriteOpt FWrite; FPutsOpt FPuts;
FPutsOpt FPuts;
PutsOpt Puts;

bool Modified; // This is only used by doInitialization.
Expand Down Expand Up @@ -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;
}
Expand Down
35 changes: 35 additions & 0 deletions lib/Transforms/Utils/SimplifyLibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConstantInt>(CI->getArgOperand(1));
ConstantInt *CountC = dyn_cast<ConstantInt>(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 {
Expand Down Expand Up @@ -1634,6 +1667,7 @@ class LibCallSimplifierImpl {
PrintFOpt PrintF;
SPrintFOpt SPrintF;
FPrintFOpt FPrintF;
FWriteOpt FWrite;

void initOptimizations();
void addOpt(LibFunc::Func F, LibCallOptimization* Opt);
Expand Down Expand Up @@ -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) {
Expand Down
57 changes: 57 additions & 0 deletions test/Transforms/InstCombine/fwrite-1.ll
Original file line number Diff line number Diff line change
@@ -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
}
13 changes: 0 additions & 13 deletions test/Transforms/SimplifyLibCalls/fwrite.ll

This file was deleted.

0 comments on commit c2e3312

Please sign in to comment.