Fix bugs in strncmp.

llvm-svn: 35708
This commit is contained in:
Chris Lattner 2007-04-07 00:06:57 +00:00
parent c9ccc30212
commit f9ee647e86
1 changed files with 52 additions and 62 deletions

View File

@ -688,82 +688,72 @@ public:
"Number of 'strncmp' calls simplified") {} "Number of 'strncmp' calls simplified") {}
/// @brief Make sure that the "strncmp" function has the right prototype /// @brief Make sure that the "strncmp" function has the right prototype
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){ virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
if (f->getReturnType() == Type::Int32Ty && f->arg_size() == 3) const FunctionType *FT = F->getFunctionType();
return true; return FT->getReturnType() == Type::Int32Ty && FT->getNumParams() == 3 &&
FT->getParamType(0) == FT->getParamType(1) &&
FT->getParamType(0) == PointerType::get(Type::Int8Ty) &&
isa<IntegerType>(FT->getParamType(2));
return false; return false;
} }
/// @brief Perform the strncpy optimization /// @brief Perform the strncmp optimization
virtual bool OptimizeCall(CallInst *ci, SimplifyLibCalls &SLC) { virtual bool OptimizeCall(CallInst *CI, SimplifyLibCalls &SLC) {
// First, check to see if src and destination are the same. If they are, // First, check to see if src and destination are the same. If they are,
// then the optimization is to replace the CallInst with a constant 0 // then the optimization is to replace the CallInst with a constant 0
// because the call is a no-op. // because the call is a no-op.
Value* s1 = ci->getOperand(1); Value *Str1P = CI->getOperand(1);
Value* s2 = ci->getOperand(2); Value *Str2P = CI->getOperand(2);
if (s1 == s2) { if (Str1P == Str2P) {
// strncmp(x,x,l) -> 0 // strcmp(x,x) -> 0
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,0)); CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 0));
ci->eraseFromParent(); CI->eraseFromParent();
return true; return true;
} }
// Check the length argument, if it is Constant zero then the strings are // Check the length argument, if it is Constant zero then the strings are
// considered equal. // considered equal.
uint64_t len_arg = 0; ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getOperand(3));
bool len_arg_is_const = false; if (LengthArg && LengthArg->isZero()) {
if (ConstantInt* len_CI = dyn_cast<ConstantInt>(ci->getOperand(3))) { // strncmp(x,y,0) -> 0
len_arg_is_const = true; CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 0));
len_arg = len_CI->getZExtValue(); CI->eraseFromParent();
if (len_arg == 0) { return true;
// strncmp(x,y,0) -> 0
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,0));
ci->eraseFromParent();
return true;
}
} }
bool isstr_1 = false; uint64_t Str1Len, Str1StartIdx;
uint64_t len_1 = 0, StartIdx; ConstantArray *A1;
ConstantArray* A1; bool Str1IsCst = GetConstantStringInfo(Str1P, A1, Str1Len, Str1StartIdx);
if (GetConstantStringInfo(s1, A1, len_1, StartIdx)) { if (Str1IsCst && Str1Len == 0) {
isstr_1 = true; // strcmp("", x) -> *x
if (len_1 == 0) { Value *V = new LoadInst(Str2P, CI->getName()+".load", CI);
// strncmp("",x) -> *x V = new ZExtInst(V, CI->getType(), CI->getName()+".int", CI);
LoadInst* load = new LoadInst(s1,ci->getName()+".load",ci); CI->replaceAllUsesWith(V);
CastInst* cast = CI->eraseFromParent();
CastInst::create(Instruction::SExt, load, Type::Int32Ty, return true;
ci->getName()+".int", ci);
ci->replaceAllUsesWith(cast);
ci->eraseFromParent();
return true;
}
} }
bool isstr_2 = false; uint64_t Str2Len, Str2StartIdx;
uint64_t len_2 = 0;
ConstantArray* A2; ConstantArray* A2;
if (GetConstantStringInfo(s2, A2, len_2, StartIdx)) { bool Str2IsCst = GetConstantStringInfo(Str2P, A2, Str2Len, Str2StartIdx);
isstr_2 = true; if (Str2IsCst && Str2Len == 0) {
if (len_2 == 0) { // strcmp(x,"") -> *x
// strncmp(x,"") -> *x Value *V = new LoadInst(Str1P, CI->getName()+".load", CI);
LoadInst* load = new LoadInst(s2,ci->getName()+".val",ci); V = new ZExtInst(V, CI->getType(), CI->getName()+".int", CI);
CastInst* cast = CI->replaceAllUsesWith(V);
CastInst::create(Instruction::SExt, load, Type::Int32Ty, CI->eraseFromParent();
ci->getName()+".int", ci); return true;
ci->replaceAllUsesWith(cast);
ci->eraseFromParent();
return true;
}
} }
if (isstr_1 && isstr_2 && len_arg_is_const) { if (LengthArg && Str1IsCst && Str2IsCst && A1->isCString() &&
// strncmp(x,y,const) -> constant A2->isCString()) {
std::string str1 = A1->getAsString(); // strcmp(x, y) -> cnst (if both x and y are constant strings)
std::string str2 = A2->getAsString(); std::string S1 = A1->getAsString();
int result = strncmp(str1.c_str(), str2.c_str(), len_arg); std::string S2 = A2->getAsString();
ci->replaceAllUsesWith(ConstantInt::get(Type::Int32Ty,result)); int R = strncmp(S1.c_str()+Str1StartIdx, S2.c_str()+Str2StartIdx,
ci->eraseFromParent(); LengthArg->getZExtValue());
CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), R));
CI->eraseFromParent();
return true; return true;
} }
return false; return false;