mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-25 20:59:51 +00:00
instcombine: Migrate strcmp and strncmp optimizations
This patch migrates the strcmp and strncmp optimizations from the simplify-libcalls pass into the instcombine library call simplifier. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165915 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
baf522ab5f
commit
a239c2e6a7
@ -134,108 +134,6 @@ static bool IsOnlyUsedInEqualityComparison(Value *V, Value *With) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
//===---------------------------------------===//
|
||||
// 'strcmp' Optimizations
|
||||
|
||||
struct StrCmpOpt : public LibCallOptimization {
|
||||
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||
// Verify the "strcmp" function prototype.
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
if (FT->getNumParams() != 2 ||
|
||||
!FT->getReturnType()->isIntegerTy(32) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != B.getInt8PtrTy())
|
||||
return 0;
|
||||
|
||||
Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1);
|
||||
if (Str1P == Str2P) // strcmp(x,x) -> 0
|
||||
return ConstantInt::get(CI->getType(), 0);
|
||||
|
||||
StringRef Str1, Str2;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
||||
|
||||
// strcmp(x, y) -> cnst (if both x and y are constant strings)
|
||||
if (HasStr1 && HasStr2)
|
||||
return ConstantInt::get(CI->getType(), Str1.compare(Str2));
|
||||
|
||||
if (HasStr1 && Str1.empty()) // strcmp("", x) -> -*x
|
||||
return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"),
|
||||
CI->getType()));
|
||||
|
||||
if (HasStr2 && Str2.empty()) // strcmp(x,"") -> *x
|
||||
return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType());
|
||||
|
||||
// strcmp(P, "x") -> memcmp(P, "x", 2)
|
||||
uint64_t Len1 = GetStringLength(Str1P);
|
||||
uint64_t Len2 = GetStringLength(Str2P);
|
||||
if (Len1 && Len2) {
|
||||
// These optimizations require DataLayout.
|
||||
if (!TD) return 0;
|
||||
|
||||
return EmitMemCmp(Str1P, Str2P,
|
||||
ConstantInt::get(TD->getIntPtrType(*Context),
|
||||
std::min(Len1, Len2)), B, TD, TLI);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//===---------------------------------------===//
|
||||
// 'strncmp' Optimizations
|
||||
|
||||
struct StrNCmpOpt : public LibCallOptimization {
|
||||
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||
// Verify the "strncmp" function prototype.
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
if (FT->getNumParams() != 3 ||
|
||||
!FT->getReturnType()->isIntegerTy(32) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != B.getInt8PtrTy() ||
|
||||
!FT->getParamType(2)->isIntegerTy())
|
||||
return 0;
|
||||
|
||||
Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1);
|
||||
if (Str1P == Str2P) // strncmp(x,x,n) -> 0
|
||||
return ConstantInt::get(CI->getType(), 0);
|
||||
|
||||
// Get the length argument if it is constant.
|
||||
uint64_t Length;
|
||||
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getArgOperand(2)))
|
||||
Length = LengthArg->getZExtValue();
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (Length == 0) // strncmp(x,y,0) -> 0
|
||||
return ConstantInt::get(CI->getType(), 0);
|
||||
|
||||
if (TD && Length == 1) // strncmp(x,y,1) -> memcmp(x,y,1)
|
||||
return EmitMemCmp(Str1P, Str2P, CI->getArgOperand(2), B, TD, TLI);
|
||||
|
||||
StringRef Str1, Str2;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
||||
|
||||
// strncmp(x, y) -> cnst (if both x and y are constant strings)
|
||||
if (HasStr1 && HasStr2) {
|
||||
StringRef SubStr1 = Str1.substr(0, Length);
|
||||
StringRef SubStr2 = Str2.substr(0, Length);
|
||||
return ConstantInt::get(CI->getType(), SubStr1.compare(SubStr2));
|
||||
}
|
||||
|
||||
if (HasStr1 && Str1.empty()) // strncmp("", x, n) -> -*x
|
||||
return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"),
|
||||
CI->getType()));
|
||||
|
||||
if (HasStr2 && Str2.empty()) // strncmp(x, "", n) -> *x
|
||||
return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType());
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//===---------------------------------------===//
|
||||
// 'strcpy' Optimizations
|
||||
|
||||
@ -1378,7 +1276,6 @@ namespace {
|
||||
|
||||
StringMap<LibCallOptimization*> Optimizations;
|
||||
// String and Memory LibCall Optimizations
|
||||
StrCmpOpt StrCmp; StrNCmpOpt StrNCmp;
|
||||
StrCpyOpt StrCpy; StrCpyOpt StrCpyChk;
|
||||
StpCpyOpt StpCpy; StpCpyOpt StpCpyChk;
|
||||
StrNCpyOpt StrNCpy;
|
||||
@ -1452,8 +1349,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,
|
||||
/// we know.
|
||||
void SimplifyLibCalls::InitOptimizations() {
|
||||
// String and Memory LibCall Optimizations
|
||||
Optimizations["strcmp"] = &StrCmp;
|
||||
Optimizations["strncmp"] = &StrNCmp;
|
||||
Optimizations["strcpy"] = &StrCpy;
|
||||
Optimizations["strncpy"] = &StrNCpy;
|
||||
Optimizations["stpcpy"] = &StpCpy;
|
||||
|
@ -402,6 +402,101 @@ struct StrRChrOpt : public LibCallOptimization {
|
||||
}
|
||||
};
|
||||
|
||||
struct StrCmpOpt : public LibCallOptimization {
|
||||
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||
// Verify the "strcmp" function prototype.
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
if (FT->getNumParams() != 2 ||
|
||||
!FT->getReturnType()->isIntegerTy(32) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != B.getInt8PtrTy())
|
||||
return 0;
|
||||
|
||||
Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1);
|
||||
if (Str1P == Str2P) // strcmp(x,x) -> 0
|
||||
return ConstantInt::get(CI->getType(), 0);
|
||||
|
||||
StringRef Str1, Str2;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
||||
|
||||
// strcmp(x, y) -> cnst (if both x and y are constant strings)
|
||||
if (HasStr1 && HasStr2)
|
||||
return ConstantInt::get(CI->getType(), Str1.compare(Str2));
|
||||
|
||||
if (HasStr1 && Str1.empty()) // strcmp("", x) -> -*x
|
||||
return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"),
|
||||
CI->getType()));
|
||||
|
||||
if (HasStr2 && Str2.empty()) // strcmp(x,"") -> *x
|
||||
return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType());
|
||||
|
||||
// strcmp(P, "x") -> memcmp(P, "x", 2)
|
||||
uint64_t Len1 = GetStringLength(Str1P);
|
||||
uint64_t Len2 = GetStringLength(Str2P);
|
||||
if (Len1 && Len2) {
|
||||
// These optimizations require DataLayout.
|
||||
if (!TD) return 0;
|
||||
|
||||
return EmitMemCmp(Str1P, Str2P,
|
||||
ConstantInt::get(TD->getIntPtrType(*Context),
|
||||
std::min(Len1, Len2)), B, TD, TLI);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct StrNCmpOpt : public LibCallOptimization {
|
||||
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
|
||||
// Verify the "strncmp" function prototype.
|
||||
FunctionType *FT = Callee->getFunctionType();
|
||||
if (FT->getNumParams() != 3 ||
|
||||
!FT->getReturnType()->isIntegerTy(32) ||
|
||||
FT->getParamType(0) != FT->getParamType(1) ||
|
||||
FT->getParamType(0) != B.getInt8PtrTy() ||
|
||||
!FT->getParamType(2)->isIntegerTy())
|
||||
return 0;
|
||||
|
||||
Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1);
|
||||
if (Str1P == Str2P) // strncmp(x,x,n) -> 0
|
||||
return ConstantInt::get(CI->getType(), 0);
|
||||
|
||||
// Get the length argument if it is constant.
|
||||
uint64_t Length;
|
||||
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getArgOperand(2)))
|
||||
Length = LengthArg->getZExtValue();
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (Length == 0) // strncmp(x,y,0) -> 0
|
||||
return ConstantInt::get(CI->getType(), 0);
|
||||
|
||||
if (TD && Length == 1) // strncmp(x,y,1) -> memcmp(x,y,1)
|
||||
return EmitMemCmp(Str1P, Str2P, CI->getArgOperand(2), B, TD, TLI);
|
||||
|
||||
StringRef Str1, Str2;
|
||||
bool HasStr1 = getConstantStringInfo(Str1P, Str1);
|
||||
bool HasStr2 = getConstantStringInfo(Str2P, Str2);
|
||||
|
||||
// strncmp(x, y) -> cnst (if both x and y are constant strings)
|
||||
if (HasStr1 && HasStr2) {
|
||||
StringRef SubStr1 = Str1.substr(0, Length);
|
||||
StringRef SubStr2 = Str2.substr(0, Length);
|
||||
return ConstantInt::get(CI->getType(), SubStr1.compare(SubStr2));
|
||||
}
|
||||
|
||||
if (HasStr1 && Str1.empty()) // strncmp("", x, n) -> -*x
|
||||
return B.CreateNeg(B.CreateZExt(B.CreateLoad(Str2P, "strcmpload"),
|
||||
CI->getType()));
|
||||
|
||||
if (HasStr2 && Str2.empty()) // strncmp(x, "", n) -> *x
|
||||
return B.CreateZExt(B.CreateLoad(Str1P, "strcmpload"), CI->getType());
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // End anonymous namespace.
|
||||
|
||||
namespace llvm {
|
||||
@ -423,6 +518,8 @@ class LibCallSimplifierImpl {
|
||||
StrNCatOpt StrNCat;
|
||||
StrChrOpt StrChr;
|
||||
StrRChrOpt StrRChr;
|
||||
StrCmpOpt StrCmp;
|
||||
StrNCmpOpt StrNCmp;
|
||||
|
||||
void initOptimizations();
|
||||
public:
|
||||
@ -443,6 +540,8 @@ void LibCallSimplifierImpl::initOptimizations() {
|
||||
Optimizations["__stpcpy_chk"] = &StrCpyChk;
|
||||
Optimizations["__strncpy_chk"] = &StrNCpyChk;
|
||||
Optimizations["__stpncpy_chk"] = &StrNCpyChk;
|
||||
Optimizations["strcmp"] = &StrCmp;
|
||||
Optimizations["strncmp"] = &StrNCmp;
|
||||
|
||||
// String and memory library call optimizations.
|
||||
Optimizations["strcat"] = &StrCat;
|
||||
|
82
test/Transforms/InstCombine/strcmp-1.ll
Normal file
82
test/Transforms/InstCombine/strcmp-1.ll
Normal file
@ -0,0 +1,82 @@
|
||||
; Test that the strcmp 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"
|
||||
|
||||
@hello = constant [6 x i8] c"hello\00"
|
||||
@hell = constant [5 x i8] c"hell\00"
|
||||
@bell = constant [5 x i8] c"bell\00"
|
||||
@null = constant [1 x i8] zeroinitializer
|
||||
|
||||
declare i32 @strcmp(i8*, i8*)
|
||||
|
||||
; strcmp("", x) -> -*x
|
||||
define i32 @test1(i8* %str2) {
|
||||
; CHECK: @test1
|
||||
; CHECK: %strcmpload = load i8* %str
|
||||
; CHECK: %1 = zext i8 %strcmpload to i32
|
||||
; CHECK: %2 = sub i32 0, %1
|
||||
; CHECK: ret i32 %2
|
||||
|
||||
%str1 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0
|
||||
%temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
|
||||
ret i32 %temp1
|
||||
|
||||
}
|
||||
|
||||
; strcmp(x, "") -> *x
|
||||
define i32 @test2(i8* %str1) {
|
||||
; CHECK: @test2
|
||||
; CHECK: %strcmpload = load i8* %str
|
||||
; CHECK: %1 = zext i8 %strcmpload to i32
|
||||
; CHECK: ret i32 %1
|
||||
|
||||
%str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0
|
||||
%temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
; strcmp(x, y) -> cnst
|
||||
define i32 @test3() {
|
||||
; CHECK: @test3
|
||||
; CHECK: ret i32 -1
|
||||
|
||||
%str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0
|
||||
%temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
define i32 @test4() {
|
||||
; CHECK: @test4
|
||||
; CHECK: ret i32 1
|
||||
|
||||
%str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0
|
||||
%temp1 = call i32 @strcmp(i8* %str1, i8* %str2)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
; strcmp(x, y) -> memcmp(x, y, <known length>)
|
||||
; (This transform is rather difficult to trigger in a useful manner)
|
||||
define i32 @test5(i1 %b) {
|
||||
; CHECK: @test5
|
||||
; CHECK: %memcmp = call i32 @memcmp(i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i8* %str2, i32 5)
|
||||
; CHECK: ret i32 %memcmp
|
||||
|
||||
%str1 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0
|
||||
%temp1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%temp2 = getelementptr inbounds [5 x i8]* @bell, i32 0, i32 0
|
||||
%str2 = select i1 %b, i8* %temp1, i8* %temp2
|
||||
%temp3 = call i32 @strcmp(i8* %str1, i8* %str2)
|
||||
ret i32 %temp3
|
||||
}
|
||||
|
||||
; strcmp(x,x) -> 0
|
||||
define i32 @test6(i8* %str) {
|
||||
; CHECK: @test6
|
||||
; CHECK: ret i32 0
|
||||
|
||||
%temp1 = call i32 @strcmp(i8* %str, i8* %str)
|
||||
ret i32 %temp1
|
||||
}
|
20
test/Transforms/InstCombine/strcmp-2.ll
Normal file
20
test/Transforms/InstCombine/strcmp-2.ll
Normal file
@ -0,0 +1,20 @@
|
||||
; Test that the strcmp 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"
|
||||
|
||||
@hello = constant [6 x i8] c"hello\00"
|
||||
@hell = constant [5 x i8] c"hell\00"
|
||||
|
||||
declare i16 @strcmp(i8*, i8*)
|
||||
|
||||
define i16 @test_nosimplify() {
|
||||
; CHECK: @test_nosimplify
|
||||
; CHECK: call i16 @strcmp
|
||||
; CHECK: ret i16 %temp1
|
||||
|
||||
%str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0
|
||||
%temp1 = call i16 @strcmp(i8* %str1, i8* %str2)
|
||||
ret i16 %temp1
|
||||
}
|
97
test/Transforms/InstCombine/strncmp-1.ll
Normal file
97
test/Transforms/InstCombine/strncmp-1.ll
Normal file
@ -0,0 +1,97 @@
|
||||
; Test that the strncmp 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"
|
||||
|
||||
@hello = constant [6 x i8] c"hello\00"
|
||||
@hell = constant [5 x i8] c"hell\00"
|
||||
@bell = constant [5 x i8] c"bell\00"
|
||||
@null = constant [1 x i8] zeroinitializer
|
||||
|
||||
declare i32 @strncmp(i8*, i8*, i32)
|
||||
|
||||
; strncmp("", x, n) -> -*x
|
||||
define i32 @test1(i8* %str2) {
|
||||
; CHECK: @test1
|
||||
; CHECK: %strcmpload = load i8* %str
|
||||
; CHECK: %1 = zext i8 %strcmpload to i32
|
||||
; CHECK: %2 = sub i32 0, %1
|
||||
; CHECK: ret i32 %2
|
||||
|
||||
%str1 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
; strncmp(x, "", n) -> *x
|
||||
define i32 @test2(i8* %str1) {
|
||||
; CHECK: @test2
|
||||
; CHECK: %strcmpload = load i8* %str1
|
||||
; CHECK: %1 = zext i8 %strcmpload to i32
|
||||
; CHECK: ret i32 %1
|
||||
|
||||
%str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
; strncmp(x, y, n) -> cnst
|
||||
define i32 @test3() {
|
||||
; CHECK: @test3
|
||||
; CHECK: ret i32 -1
|
||||
|
||||
%str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
define i32 @test4() {
|
||||
; CHECK: @test4
|
||||
; CHECK: ret i32 1
|
||||
|
||||
%str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%str2 = getelementptr inbounds [1 x i8]* @null, i32 0, i32 0
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 10)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
define i32 @test5() {
|
||||
; CHECK: @test5
|
||||
; CHECK: ret i32 0
|
||||
|
||||
%str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 4)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
; strncmp(x,y,1) -> memcmp(x,y,1)
|
||||
; TODO: Once the memcmp simplifier gets moved into the instcombine pass
|
||||
; the following memcmp will be folded into two loads and a subtract.
|
||||
define i32 @test6(i8* %str1, i8* %str2) {
|
||||
; CHECK: @test6
|
||||
; CHECK: call i32 @memcmp
|
||||
; CHECK: ret i32 %memcmp
|
||||
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 1)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
; strncmp(x,y,0) -> 0
|
||||
define i32 @test7(i8* %str1, i8* %str2) {
|
||||
; CHECK: @test7
|
||||
; CHECK: ret i32 0
|
||||
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 0)
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
; strncmp(x,x,n) -> 0
|
||||
define i32 @test8(i8* %str, i32 %n) {
|
||||
; CHECK: @test8
|
||||
; CHECK: ret i32 0
|
||||
|
||||
%temp1 = call i32 @strncmp(i8* %str, i8* %str, i32 %n)
|
||||
ret i32 %temp1
|
||||
}
|
20
test/Transforms/InstCombine/strncmp-2.ll
Normal file
20
test/Transforms/InstCombine/strncmp-2.ll
Normal file
@ -0,0 +1,20 @@
|
||||
; Test that the strncmp 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"
|
||||
|
||||
@hello = constant [6 x i8] c"hello\00"
|
||||
@hell = constant [5 x i8] c"hell\00"
|
||||
|
||||
declare i16 @strncmp(i8*, i8*, i32)
|
||||
|
||||
define i16 @test_nosimplify() {
|
||||
; CHECK: @test_nosimplify
|
||||
; CHECK: call i16 @strncmp
|
||||
; CHECK: ret i16 %temp1
|
||||
|
||||
%str1 = getelementptr inbounds [5 x i8]* @hell, i32 0, i32 0
|
||||
%str2 = getelementptr inbounds [6 x i8]* @hello, i32 0, i32 0
|
||||
%temp1 = call i16 @strncmp(i8* %str1, i8* %str2, i32 10)
|
||||
ret i16 %temp1
|
||||
}
|
33
test/Transforms/InstCombine/weak-symbols.ll
Normal file
33
test/Transforms/InstCombine/weak-symbols.ll
Normal file
@ -0,0 +1,33 @@
|
||||
; PR4738 - Test that the library call simplifier doesn't assume anything about
|
||||
; weak symbols.
|
||||
;
|
||||
; RUN: opt < %s -instcombine -S | FileCheck %s
|
||||
|
||||
@real_init = weak_odr constant [2 x i8] c"y\00"
|
||||
@fake_init = weak constant [2 x i8] c"y\00"
|
||||
@.str = private constant [2 x i8] c"y\00"
|
||||
|
||||
define i32 @foo() nounwind {
|
||||
; CHECK: define i32 @foo
|
||||
; CHECK: call i32 @strcmp
|
||||
; CHECK: ret i32 %temp1
|
||||
|
||||
entry:
|
||||
%str1 = getelementptr inbounds [2 x i8]* @fake_init, i64 0, i64 0
|
||||
%str2 = getelementptr inbounds [2 x i8]* @.str, i64 0, i64 0
|
||||
%temp1 = call i32 @strcmp(i8* %str1, i8* %str2) nounwind readonly
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
define i32 @bar() nounwind {
|
||||
; CHECK: define i32 @bar
|
||||
; CHECK: ret i32 0
|
||||
|
||||
entry:
|
||||
%str1 = getelementptr inbounds [2 x i8]* @real_init, i64 0, i64 0
|
||||
%str2 = getelementptr inbounds [2 x i8]* @.str, i64 0, i64 0
|
||||
%temp1 = call i32 @strcmp(i8* %str1, i8* %str2) nounwind readonly
|
||||
ret i32 %temp1
|
||||
}
|
||||
|
||||
declare i32 @strcmp(i8*, i8*) nounwind readonly
|
@ -1,65 +0,0 @@
|
||||
; Test that the StrCmpOptimizer works correctly
|
||||
; RUN: opt < %s -simplify-libcalls -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" ; <[6 x i8]*> [#uses=1]
|
||||
@hell = constant [5 x i8] c"hell\00" ; <[5 x i8]*> [#uses=1]
|
||||
@bell = constant [5 x i8] c"bell\00" ; <[5 x i8]*> [#uses=1]
|
||||
@null = constant [1 x i8] zeroinitializer ; <[1 x i8]*> [#uses=1]
|
||||
|
||||
declare i32 @strcmp(i8*, i8*)
|
||||
|
||||
; strcmp("", x) -> -*x
|
||||
define i32 @test1(i8* %str) {
|
||||
%temp1 = call i32 @strcmp(i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i8* %str)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test1
|
||||
; CHECK: %strcmpload = load i8* %str
|
||||
; CHECK: %1 = zext i8 %strcmpload to i32
|
||||
; CHECK: %temp1 = sub i32 0, %1
|
||||
; CHECK: ret i32 %temp1
|
||||
}
|
||||
|
||||
; strcmp(x, "") -> *x
|
||||
define i32 @test2(i8* %str) {
|
||||
%temp1 = call i32 @strcmp(i8* %str, i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0))
|
||||
ret i32 %temp1
|
||||
; CHECK: @test2
|
||||
; CHECK: %strcmpload = load i8* %str
|
||||
; CHECK: %temp1 = zext i8 %strcmpload to i32
|
||||
; CHECK: ret i32 %temp1
|
||||
}
|
||||
|
||||
; strcmp(x, y) -> cnst
|
||||
define i32 @test3() {
|
||||
%temp1 = call i32 @strcmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0))
|
||||
ret i32 %temp1
|
||||
; CHECK: @test3
|
||||
; CHECK: ret i32 -1
|
||||
}
|
||||
define i32 @test4() {
|
||||
%temp1 = call i32 @strcmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0))
|
||||
ret i32 %temp1
|
||||
; CHECK: @test4
|
||||
; CHECK: ret i32 1
|
||||
}
|
||||
|
||||
; strcmp(x, y) -> memcmp(x, y, <known length>)
|
||||
; (This transform is rather difficult to trigger in a useful manner)
|
||||
define i32 @test5(i1 %b) {
|
||||
%sel = select i1 %b, i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8]* @bell, i32 0, i32 0)
|
||||
%temp1 = call i32 @strcmp(i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i8* %sel)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test5
|
||||
; CHECK: %memcmp = call i32 @memcmp(i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i8* %sel, i32 5)
|
||||
; CHECK: ret i32 %memcmp
|
||||
}
|
||||
|
||||
; strcmp(x,x) -> 0
|
||||
define i32 @test6(i8* %str) {
|
||||
%temp1 = call i32 @strcmp(i8* %str, i8* %str)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test6
|
||||
; CHECK: ret i32 0
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
; Test that the StrCmpOptimizer works correctly
|
||||
; RUN: opt < %s -simplify-libcalls -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" ; <[6 x i8]*> [#uses=1]
|
||||
@hell = constant [5 x i8] c"hell\00" ; <[5 x i8]*> [#uses=1]
|
||||
@bell = constant [5 x i8] c"bell\00" ; <[5 x i8]*> [#uses=1]
|
||||
@null = constant [1 x i8] zeroinitializer ; <[1 x i8]*> [#uses=1]
|
||||
|
||||
declare i32 @strncmp(i8*, i8*, i32)
|
||||
|
||||
; strcmp("", x) -> -*x
|
||||
define i32 @test1(i8* %str) {
|
||||
%temp1 = call i32 @strncmp(i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i8* %str, i32 10)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test1
|
||||
; CHECK: %strcmpload = load i8* %str
|
||||
; CHECK: %1 = zext i8 %strcmpload to i32
|
||||
; CHECK: %temp1 = sub i32 0, %1
|
||||
; CHECK: ret i32 %temp1
|
||||
}
|
||||
|
||||
; strcmp(x, "") -> *x
|
||||
define i32 @test2(i8* %str) {
|
||||
%temp1 = call i32 @strncmp(i8* %str, i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i32 10)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test2
|
||||
; CHECK: %strcmpload = load i8* %str
|
||||
; CHECK: %temp1 = zext i8 %strcmpload to i32
|
||||
; CHECK: ret i32 %temp1
|
||||
}
|
||||
|
||||
; strncmp(x, y, n) -> cnst
|
||||
define i32 @test3() {
|
||||
%temp1 = call i32 @strncmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i32 10)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test3
|
||||
; CHECK: ret i32 -1
|
||||
}
|
||||
define i32 @test4() {
|
||||
%temp1 = call i32 @strncmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([1 x i8]* @null, i32 0, i32 0), i32 10)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test4
|
||||
; CHECK: ret i32 1
|
||||
}
|
||||
define i32 @test5() {
|
||||
%temp1 = call i32 @strncmp(i8* getelementptr inbounds ([5 x i8]* @hell, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8]* @hello, i32 0, i32 0), i32 4)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test5
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; strncmp(x,y,1) -> memcmp(x,y,1)
|
||||
define i32 @test6(i8* %str1, i8* %str2) {
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 1)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test6
|
||||
; CHECK: load i8*
|
||||
; CHECK: load i8*
|
||||
; CHECK: sub i32
|
||||
}
|
||||
|
||||
; strncmp(x,y,0) -> 0
|
||||
define i32 @test7(i8* %str1, i8* %str2) {
|
||||
%temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 0)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test7
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; strncmp(x,x,n) -> 0
|
||||
define i32 @test8(i8* %str, i32 %n) {
|
||||
%temp1 = call i32 @strncmp(i8* %str, i8* %str, i32 %n)
|
||||
ret i32 %temp1
|
||||
; CHECK: @test8
|
||||
; CHECK: ret i32 0
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
; RUN: opt < %s -simplify-libcalls -S | FileCheck %s
|
||||
; PR4738
|
||||
|
||||
; SimplifyLibcalls shouldn't assume anything about weak symbols.
|
||||
|
||||
@real_init = weak_odr constant [2 x i8] c"y\00"
|
||||
@fake_init = weak constant [2 x i8] c"y\00"
|
||||
@.str = private constant [2 x i8] c"y\00"
|
||||
|
||||
; CHECK: define i32 @foo
|
||||
; CHECK: call i32 @strcmp
|
||||
define i32 @foo() nounwind {
|
||||
entry:
|
||||
%t0 = call i32 @strcmp(i8* getelementptr inbounds ([2 x i8]* @fake_init, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8]* @.str, i64 0, i64 0)) nounwind readonly
|
||||
ret i32 %t0
|
||||
}
|
||||
|
||||
; CHECK: define i32 @bar
|
||||
; CHECK: ret i32 0
|
||||
define i32 @bar() nounwind {
|
||||
entry:
|
||||
%t0 = call i32 @strcmp(i8* getelementptr inbounds ([2 x i8]* @real_init, i64 0, i64 0), i8* getelementptr inbounds ([2 x i8]* @.str, i64 0, i64 0)) nounwind readonly
|
||||
ret i32 %t0
|
||||
}
|
||||
|
||||
declare i32 @strcmp(i8*, i8*) nounwind readonly
|
Loading…
Reference in New Issue
Block a user