instcombine: Migrate strcat and strncat optimizations

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165874 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Meador Inge 2012-10-13 16:45:32 +00:00
parent 5e8904576a
commit 73d8a5864f
10 changed files with 311 additions and 165 deletions

View File

@ -133,105 +133,7 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) {
// String and Memory LibCall Optimizations
//===----------------------------------------------------------------------===//
//===---------------------------------------===//
// 'strcat' Optimizations
namespace {
struct StrCatOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Verify the "strcat" function prototype.
FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 2 ||
FT->getReturnType() != B.getInt8PtrTy() ||
FT->getParamType(0) != FT->getReturnType() ||
FT->getParamType(1) != FT->getReturnType())
return 0;
// Extract some information from the instruction
Value *Dst = CI->getArgOperand(0);
Value *Src = CI->getArgOperand(1);
// See if we can get the length of the input string.
uint64_t Len = GetStringLength(Src);
if (Len == 0) return 0;
--Len; // Unbias length.
// Handle the simple, do-nothing case: strcat(x, "") -> x
if (Len == 0)
return Dst;
// These optimizations require DataLayout.
if (!TD) return 0;
return EmitStrLenMemCpy(Src, Dst, Len, B);
}
Value *EmitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len, IRBuilder<> &B) {
// We need to find the end of the destination string. That's where the
// memory is to be moved to. We just generate a call to strlen.
Value *DstLen = EmitStrLen(Dst, B, TD, TLI);
if (!DstLen)
return 0;
// Now that we have the destination's length, we must index into the
// destination's pointer to get the actual memcpy destination (end of
// the string .. we're concatenating).
Value *CpyDst = B.CreateGEP(Dst, DstLen, "endptr");
// We have enough information to now generate the memcpy call to do the
// concatenation for us. Make a memcpy to copy the nul byte with align = 1.
B.CreateMemCpy(CpyDst, Src,
ConstantInt::get(TD->getIntPtrType(*Context), Len + 1), 1);
return Dst;
}
};
//===---------------------------------------===//
// 'strncat' Optimizations
struct StrNCatOpt : public StrCatOpt {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Verify the "strncat" function prototype.
FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 3 ||
FT->getReturnType() != B.getInt8PtrTy() ||
FT->getParamType(0) != FT->getReturnType() ||
FT->getParamType(1) != FT->getReturnType() ||
!FT->getParamType(2)->isIntegerTy())
return 0;
// Extract some information from the instruction
Value *Dst = CI->getArgOperand(0);
Value *Src = CI->getArgOperand(1);
uint64_t Len;
// We don't do anything if length is not constant
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getArgOperand(2)))
Len = LengthArg->getZExtValue();
else
return 0;
// See if we can get the length of the input string.
uint64_t SrcLen = GetStringLength(Src);
if (SrcLen == 0) return 0;
--SrcLen; // Unbias length.
// Handle the simple, do-nothing cases:
// strncat(x, "", c) -> x
// strncat(x, c, 0) -> x
if (SrcLen == 0 || Len == 0) return Dst;
// These optimizations require DataLayout.
if (!TD) return 0;
// We don't optimize this case
if (Len < SrcLen) return 0;
// strncat(x, s, c) -> strcat(x, s)
// s is constant so the strcat can be optimized further
return EmitStrLenMemCpy(Src, Dst, SrcLen, B);
}
};
//===---------------------------------------===//
// 'strchr' Optimizations
@ -1564,7 +1466,7 @@ namespace {
StringMap<LibCallOptimization*> Optimizations;
// String and Memory LibCall Optimizations
StrCatOpt StrCat; StrNCatOpt StrNCat; StrChrOpt StrChr; StrRChrOpt StrRChr;
StrChrOpt StrChr; StrRChrOpt StrRChr;
StrCmpOpt StrCmp; StrNCmpOpt StrNCmp;
StrCpyOpt StrCpy; StrCpyOpt StrCpyChk;
StpCpyOpt StpCpy; StpCpyOpt StpCpyChk;
@ -1639,8 +1541,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,
/// we know.
void SimplifyLibCalls::InitOptimizations() {
// String and Memory LibCall Optimizations
Optimizations["strcat"] = &StrCat;
Optimizations["strncat"] = &StrNCat;
Optimizations["strchr"] = &StrChr;
Optimizations["strrchr"] = &StrRChr;
Optimizations["strcmp"] = &StrCmp;

View File

@ -222,6 +222,104 @@ struct StrNCpyChkOpt : public InstFortifiedLibCallOptimization {
}
};
//===----------------------------------------------------------------------===//
// String and Memory Library Call Optimizations
//===----------------------------------------------------------------------===//
struct StrCatOpt : public LibCallOptimization {
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Verify the "strcat" function prototype.
FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 2 ||
FT->getReturnType() != B.getInt8PtrTy() ||
FT->getParamType(0) != FT->getReturnType() ||
FT->getParamType(1) != FT->getReturnType())
return 0;
// Extract some information from the instruction
Value *Dst = CI->getArgOperand(0);
Value *Src = CI->getArgOperand(1);
// See if we can get the length of the input string.
uint64_t Len = GetStringLength(Src);
if (Len == 0) return 0;
--Len; // Unbias length.
// Handle the simple, do-nothing case: strcat(x, "") -> x
if (Len == 0)
return Dst;
// These optimizations require DataLayout.
if (!TD) return 0;
return emitStrLenMemCpy(Src, Dst, Len, B);
}
Value *emitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len,
IRBuilder<> &B) {
// We need to find the end of the destination string. That's where the
// memory is to be moved to. We just generate a call to strlen.
Value *DstLen = EmitStrLen(Dst, B, TD, TLI);
if (!DstLen)
return 0;
// Now that we have the destination's length, we must index into the
// destination's pointer to get the actual memcpy destination (end of
// the string .. we're concatenating).
Value *CpyDst = B.CreateGEP(Dst, DstLen, "endptr");
// We have enough information to now generate the memcpy call to do the
// concatenation for us. Make a memcpy to copy the nul byte with align = 1.
B.CreateMemCpy(CpyDst, Src,
ConstantInt::get(TD->getIntPtrType(*Context), Len + 1), 1);
return Dst;
}
};
struct StrNCatOpt : public StrCatOpt {
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Verify the "strncat" function prototype.
FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 3 ||
FT->getReturnType() != B.getInt8PtrTy() ||
FT->getParamType(0) != FT->getReturnType() ||
FT->getParamType(1) != FT->getReturnType() ||
!FT->getParamType(2)->isIntegerTy())
return 0;
// Extract some information from the instruction
Value *Dst = CI->getArgOperand(0);
Value *Src = CI->getArgOperand(1);
uint64_t Len;
// We don't do anything if length is not constant
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getArgOperand(2)))
Len = LengthArg->getZExtValue();
else
return 0;
// See if we can get the length of the input string.
uint64_t SrcLen = GetStringLength(Src);
if (SrcLen == 0) return 0;
--SrcLen; // Unbias length.
// Handle the simple, do-nothing cases:
// strncat(x, "", c) -> x
// strncat(x, c, 0) -> x
if (SrcLen == 0 || Len == 0) return Dst;
// These optimizations require DataLayout.
if (!TD) return 0;
// We don't optimize this case
if (Len < SrcLen) return 0;
// strncat(x, s, c) -> strcat(x, s)
// s is constant so the strcat can be optimized further
return emitStrLenMemCpy(Src, Dst, SrcLen, B);
}
};
} // End anonymous namespace.
namespace llvm {
@ -239,6 +337,10 @@ class LibCallSimplifierImpl {
StrCpyChkOpt StrCpyChk;
StrNCpyChkOpt StrNCpyChk;
// String and memory library call optimizations.
StrCatOpt StrCat;
StrNCatOpt StrNCat;
void initOptimizations();
public:
LibCallSimplifierImpl(const DataLayout *TD, const TargetLibraryInfo *TLI) {
@ -258,6 +360,10 @@ void LibCallSimplifierImpl::initOptimizations() {
Optimizations["__stpcpy_chk"] = &StrCpyChk;
Optimizations["__strncpy_chk"] = &StrNCpyChk;
Optimizations["__stpncpy_chk"] = &StrNCpyChk;
// String and memory library call optimizations.
Optimizations["strcat"] = &StrCat;
Optimizations["strncat"] = &StrNCat;
}
Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) {

View File

@ -0,0 +1,38 @@
; Test that the strcat libcall simplifier works correctly per the
; bug found in PR3661.
;
; 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"
@hello = constant [6 x i8] c"hello\00"
@null = constant [1 x i8] zeroinitializer
@null_hello = constant [7 x i8] c"\00hello\00"
declare i8* @strcat(i8*, i8*)
declare i32 @puts(i8*)
define i32 @main() {
; CHECK: @main
; CHECK-NOT: call i8* @strcat
; CHECK: call i32 @puts
%target = alloca [1024 x i8]
%arg1 = getelementptr [1024 x i8]* %target, i32 0, i32 0
store i8 0, i8* %arg1
; rslt1 = strcat(target, "hello\00")
%arg2 = getelementptr [6 x i8]* @hello, i32 0, i32 0
%rslt1 = call i8* @strcat(i8* %arg1, i8* %arg2)
; rslt2 = strcat(rslt1, "\00")
%arg3 = getelementptr [1 x i8]* @null, i32 0, i32 0
%rslt2 = call i8* @strcat(i8* %rslt1, i8* %arg3)
; rslt3 = strcat(rslt2, "\00hello\00")
%arg4 = getelementptr [7 x i8]* @null_hello, i32 0, i32 0
%rslt3 = call i8* @strcat(i8* %rslt2, i8* %arg4)
call i32 @puts( i8* %rslt3 )
ret i32 0
}

View File

@ -0,0 +1,32 @@
; Test that the strcat libcall 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"
@hello = constant [6 x i8] c"hello\00"
@empty = constant [1 x i8] c"\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i8* @strcat(i8*, i8*)
define void @test_simplify1() {
; CHECK: @test_simplify1
; CHECK-NOT: call i8* @strcat
; CHECK: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8]* @hello, i32 0, i32 0
call i8* @strcat(i8* %dst, i8* %src)
ret void
}
define void @test_simplify2() {
; CHECK: @test_simplify2
; CHECK-NEXT: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [1 x i8]* @empty, i32 0, i32 0
call i8* @strcat(i8* %dst, i8* %src)
ret void
}

View File

@ -0,0 +1,22 @@
; Test that the strcat libcall 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"
@hello = constant [6 x i8] c"hello\00"
@empty = constant [1 x i8] c"\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i16* @strcat(i8*, i8*)
define void @test_nosimplify1() {
; CHECK: @test_nosimplify1
; CHECK: call i16* @strcat
; CHECK: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8]* @hello, i32 0, i32 0
call i16* @strcat(i8* %dst, i8* %src)
ret void
}

View File

@ -0,0 +1,37 @@
; Test that the strncat libcall 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"
@hello = constant [6 x i8] c"hello\00"
@null = constant [1 x i8] zeroinitializer
@null_hello = constant [7 x i8] c"\00hello\00"
declare i8* @strncat(i8*, i8*, i32)
declare i32 @puts(i8*)
define i32 @main() {
; CHECK: @main
; CHECK-NOT: call i8* @strncat
; CHECK: call i32 @puts
%target = alloca [1024 x i8]
%arg1 = getelementptr [1024 x i8]* %target, i32 0, i32 0
store i8 0, i8* %arg1
; rslt1 = strncat(target, "hello\00")
%arg2 = getelementptr [6 x i8]* @hello, i32 0, i32 0
%rslt1 = call i8* @strncat(i8* %arg1, i8* %arg2, i32 6)
; rslt2 = strncat(rslt1, "\00")
%arg3 = getelementptr [1 x i8]* @null, i32 0, i32 0
%rslt2 = call i8* @strncat(i8* %rslt1, i8* %arg3, i32 42)
; rslt3 = strncat(rslt2, "\00hello\00")
%arg4 = getelementptr [7 x i8]* @null_hello, i32 0, i32 0
%rslt3 = call i8* @strncat(i8* %rslt2, i8* %arg4, i32 42)
call i32 @puts(i8* %rslt3)
ret i32 0
}

View File

@ -0,0 +1,53 @@
; Test that the strncat libcall 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"
@hello = constant [6 x i8] c"hello\00"
@empty = constant [1 x i8] c"\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i8* @strncat(i8*, i8*, i32)
define void @test_simplify1() {
; CHECK: @test_simplify1
; CHECK-NOT: call i8* @strncat
; CHECK: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8]* @hello, i32 0, i32 0
call i8* @strncat(i8* %dst, i8* %src, i32 13)
ret void
}
define void @test_simplify2() {
; CHECK: @test_simplify2
; CHECK-NEXT: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [1 x i8]* @empty, i32 0, i32 0
call i8* @strncat(i8* %dst, i8* %src, i32 13)
ret void
}
define void @test_simplify3() {
; CHECK: @test_simplify3
; CHECK-NEXT: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8]* @hello, i32 0, i32 0
call i8* @strncat(i8* %dst, i8* %src, i32 0)
ret void
}
define void @test_nosimplify1() {
; CHECK: @test_nosimplify1
; CHECK: call i8* @strncat
; CHECK: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8]* @hello, i32 0, i32 0
call i8* @strncat(i8* %dst, i8* %src, i32 1)
ret void
}

View File

@ -0,0 +1,22 @@
; Test that the strncat libcall 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"
@hello = constant [6 x i8] c"hello\00"
@empty = constant [1 x i8] c"\00"
@a = common global [32 x i8] zeroinitializer, align 1
declare i16* @strncat(i8*, i8*, i32)
define void @test_nosimplify1() {
; CHECK: @test_nosimplify1
; CHECK: call i16* @strncat
; CHECK: ret void
%dst = getelementptr [32 x i8]* @a, i32 0, i32 0
%src = getelementptr [6 x i8]* @hello, i32 0, i32 0
call i16* @strncat(i8* %dst, i8* %src, i32 13)
ret void
}

View File

@ -1,33 +0,0 @@
; Test that the StrCatOptimizer works correctly
; PR3661
; RUN: opt < %s -simplify-libcalls -S | \
; RUN: not grep "call.*strcat"
; RUN: opt < %s -simplify-libcalls -S | \
; RUN: grep "puts.*%arg1"
; This transformation requires the pointer size, as it assumes that size_t is
; the size of a pointer.
target datalayout = "-p:64:64:64"
@hello = constant [6 x i8] c"hello\00" ; <[6 x i8]*> [#uses=1]
@null = constant [1 x i8] zeroinitializer ; <[1 x i8]*> [#uses=1]
@null_hello = constant [7 x i8] c"\00hello\00" ; <[7 x i8]*> [#uses=1]
declare i8* @strcat(i8*, i8*)
declare i32 @puts(i8*)
define i32 @main() {
%target = alloca [1024 x i8] ; <[1024 x i8]*> [#uses=1]
%arg1 = getelementptr [1024 x i8]* %target, i32 0, i32 0 ; <i8*> [#uses=2]
store i8 0, i8* %arg1
%arg2 = getelementptr [6 x i8]* @hello, i32 0, i32 0 ; <i8*> [#uses=1]
%rslt1 = call i8* @strcat( i8* %arg1, i8* %arg2 ) ; <i8*> [#uses=1]
%arg3 = getelementptr [1 x i8]* @null, i32 0, i32 0 ; <i8*> [#uses=1]
%rslt2 = call i8* @strcat( i8* %rslt1, i8* %arg3 ) ; <i8*> [#uses=1]
%arg4 = getelementptr [7 x i8]* @null_hello, i32 0, i32 0 ; <i8*> [#uses=1]
%rslt3 = call i8* @strcat( i8* %rslt2, i8* %arg4 ) ; <i8*> [#uses=1]
call i32 @puts( i8* %rslt3 ) ; <i32>:1 [#uses=0]
ret i32 0
}

View File

@ -1,31 +0,0 @@
; Test that the StrNCatOptimizer works correctly
; RUN: opt < %s -simplify-libcalls -S | \
; RUN: not grep "call.*strncat"
; RUN: opt < %s -simplify-libcalls -S | \
; RUN: grep "puts.*%arg1"
; This transformation requires the pointer size, as it assumes that size_t is
; the size of a pointer.
target datalayout = "-p:64:64:64"
@hello = constant [6 x i8] c"hello\00" ; <[6 x i8]*> [#uses=1]
@null = constant [1 x i8] zeroinitializer ; <[1 x i8]*> [#uses=1]
@null_hello = constant [7 x i8] c"\00hello\00" ; <[7 x i8]*> [#uses=1]
declare i8* @strncat(i8*, i8*, i32)
declare i32 @puts(i8*)
define i32 @main() {
%target = alloca [1024 x i8] ; <[1024 x i8]*> [#uses=1]
%arg1 = getelementptr [1024 x i8]* %target, i32 0, i32 0 ; <i8*> [#uses=2]
store i8 0, i8* %arg1
%arg2 = getelementptr [6 x i8]* @hello, i32 0, i32 0 ; <i8*> [#uses=1]
%rslt1 = call i8* @strncat( i8* %arg1, i8* %arg2, i32 6 ) ; <i8*> [#uses=1]
%arg3 = getelementptr [1 x i8]* @null, i32 0, i32 0 ; <i8*> [#uses=1]
%rslt2 = call i8* @strncat( i8* %rslt1, i8* %arg3, i32 42 ) ; <i8*> [#uses=1]
%arg4 = getelementptr [7 x i8]* @null_hello, i32 0, i32 0 ; <i8*> [#uses=1]
%rslt3 = call i8* @strncat( i8* %rslt2, i8* %arg4, i32 42 ) ; <i8*> [#uses=1]
call i32 @puts( i8* %rslt3 ) ; <i32>:1 [#uses=0]
ret i32 0
}