mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-17 21:29:20 +00:00
fixes for strcpy optimizer
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35709 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7b50c8f278
commit
db895b82a3
@ -705,7 +705,7 @@ public:
|
|||||||
Value *Str1P = CI->getOperand(1);
|
Value *Str1P = CI->getOperand(1);
|
||||||
Value *Str2P = CI->getOperand(2);
|
Value *Str2P = CI->getOperand(2);
|
||||||
if (Str1P == Str2P) {
|
if (Str1P == Str2P) {
|
||||||
// strcmp(x,x) -> 0
|
// strncmp(x,x) -> 0
|
||||||
CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 0));
|
CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 0));
|
||||||
CI->eraseFromParent();
|
CI->eraseFromParent();
|
||||||
return true;
|
return true;
|
||||||
@ -713,8 +713,13 @@ public:
|
|||||||
|
|
||||||
// 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.
|
||||||
ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getOperand(3));
|
uint64_t Length;
|
||||||
if (LengthArg && LengthArg->isZero()) {
|
if (ConstantInt *LengthArg = dyn_cast<ConstantInt>(CI->getOperand(3)))
|
||||||
|
Length = LengthArg->getZExtValue();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Length == 0) {
|
||||||
// strncmp(x,y,0) -> 0
|
// strncmp(x,y,0) -> 0
|
||||||
CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 0));
|
CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 0));
|
||||||
CI->eraseFromParent();
|
CI->eraseFromParent();
|
||||||
@ -725,7 +730,7 @@ public:
|
|||||||
ConstantArray *A1;
|
ConstantArray *A1;
|
||||||
bool Str1IsCst = GetConstantStringInfo(Str1P, A1, Str1Len, Str1StartIdx);
|
bool Str1IsCst = GetConstantStringInfo(Str1P, A1, Str1Len, Str1StartIdx);
|
||||||
if (Str1IsCst && Str1Len == 0) {
|
if (Str1IsCst && Str1Len == 0) {
|
||||||
// strcmp("", x) -> *x
|
// strncmp("", x) -> *x
|
||||||
Value *V = new LoadInst(Str2P, CI->getName()+".load", CI);
|
Value *V = new LoadInst(Str2P, CI->getName()+".load", CI);
|
||||||
V = new ZExtInst(V, CI->getType(), CI->getName()+".int", CI);
|
V = new ZExtInst(V, CI->getType(), CI->getName()+".int", CI);
|
||||||
CI->replaceAllUsesWith(V);
|
CI->replaceAllUsesWith(V);
|
||||||
@ -737,7 +742,7 @@ public:
|
|||||||
ConstantArray* A2;
|
ConstantArray* A2;
|
||||||
bool Str2IsCst = GetConstantStringInfo(Str2P, A2, Str2Len, Str2StartIdx);
|
bool Str2IsCst = GetConstantStringInfo(Str2P, A2, Str2Len, Str2StartIdx);
|
||||||
if (Str2IsCst && Str2Len == 0) {
|
if (Str2IsCst && Str2Len == 0) {
|
||||||
// strcmp(x,"") -> *x
|
// strncmp(x,"") -> *x
|
||||||
Value *V = new LoadInst(Str1P, CI->getName()+".load", CI);
|
Value *V = new LoadInst(Str1P, CI->getName()+".load", CI);
|
||||||
V = new ZExtInst(V, CI->getType(), CI->getName()+".int", CI);
|
V = new ZExtInst(V, CI->getType(), CI->getName()+".int", CI);
|
||||||
CI->replaceAllUsesWith(V);
|
CI->replaceAllUsesWith(V);
|
||||||
@ -745,13 +750,12 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LengthArg && Str1IsCst && Str2IsCst && A1->isCString() &&
|
if (Str1IsCst && Str2IsCst && A1->isCString() &&
|
||||||
A2->isCString()) {
|
A2->isCString()) {
|
||||||
// strcmp(x, y) -> cnst (if both x and y are constant strings)
|
// strncmp(x, y) -> cnst (if both x and y are constant strings)
|
||||||
std::string S1 = A1->getAsString();
|
std::string S1 = A1->getAsString();
|
||||||
std::string S2 = A2->getAsString();
|
std::string S2 = A2->getAsString();
|
||||||
int R = strncmp(S1.c_str()+Str1StartIdx, S2.c_str()+Str2StartIdx,
|
int R = strncmp(S1.c_str()+Str1StartIdx, S2.c_str()+Str2StartIdx, Length);
|
||||||
LengthArg->getZExtValue());
|
|
||||||
CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), R));
|
CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), R));
|
||||||
CI->eraseFromParent();
|
CI->eraseFromParent();
|
||||||
return true;
|
return true;
|
||||||
@ -771,71 +775,57 @@ public:
|
|||||||
"Number of 'strcpy' calls simplified") {}
|
"Number of 'strcpy' calls simplified") {}
|
||||||
|
|
||||||
/// @brief Make sure that the "strcpy" function has the right prototype
|
/// @brief Make sure that the "strcpy" function has the right prototype
|
||||||
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC){
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
||||||
if (f->getReturnType() == PointerType::get(Type::Int8Ty))
|
const FunctionType *FT = F->getFunctionType();
|
||||||
if (f->arg_size() == 2) {
|
return FT->getNumParams() == 2 &&
|
||||||
Function::const_arg_iterator AI = f->arg_begin();
|
FT->getParamType(0) == FT->getParamType(1) &&
|
||||||
if (AI++->getType() == PointerType::get(Type::Int8Ty))
|
FT->getReturnType() == FT->getParamType(0) &&
|
||||||
if (AI->getType() == PointerType::get(Type::Int8Ty)) {
|
FT->getParamType(0) == PointerType::get(Type::Int8Ty);
|
||||||
// Indicate this is a suitable call type.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Perform the strcpy optimization
|
/// @brief Perform the strcpy 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 the destination
|
// then the optimization is to replace the CallInst with the destination
|
||||||
// because the call is a no-op. Note that this corresponds to the
|
// because the call is a no-op. Note that this corresponds to the
|
||||||
// degenerate strcpy(X,X) case which should have "undefined" results
|
// degenerate strcpy(X,X) case which should have "undefined" results
|
||||||
// according to the C specification. However, it occurs sometimes and
|
// according to the C specification. However, it occurs sometimes and
|
||||||
// we optimize it as a no-op.
|
// we optimize it as a no-op.
|
||||||
Value* dest = ci->getOperand(1);
|
Value *Dst = CI->getOperand(1);
|
||||||
Value* src = ci->getOperand(2);
|
Value *Src = CI->getOperand(2);
|
||||||
if (dest == src) {
|
if (Dst == Src) {
|
||||||
ci->replaceAllUsesWith(dest);
|
// strcpy(x, x) -> x
|
||||||
ci->eraseFromParent();
|
CI->replaceAllUsesWith(Dst);
|
||||||
|
CI->eraseFromParent();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the length of the constant string referenced by the second operand,
|
// Get the length of the constant string referenced by the Src operand.
|
||||||
// the "src" parameter. Fail the optimization if we can't get the length
|
uint64_t SrcLen, SrcStartIdx;
|
||||||
// (note that GetConstantStringInfo does lots of checks to make sure this
|
ConstantArray *SrcArr;
|
||||||
// is valid).
|
if (!GetConstantStringInfo(Src, SrcArr, SrcLen, SrcStartIdx))
|
||||||
uint64_t len, StartIdx;
|
|
||||||
ConstantArray *A;
|
|
||||||
if (!GetConstantStringInfo(ci->getOperand(2), A, len, StartIdx))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If the constant string's length is zero we can optimize this by just
|
// If the constant string's length is zero we can optimize this by just
|
||||||
// doing a store of 0 at the first byte of the destination
|
// doing a store of 0 at the first byte of the destination
|
||||||
if (len == 0) {
|
if (SrcLen == 0) {
|
||||||
new StoreInst(ConstantInt::get(Type::Int8Ty,0),ci->getOperand(1),ci);
|
new StoreInst(ConstantInt::get(Type::Int8Ty, 0), Dst, CI);
|
||||||
ci->replaceAllUsesWith(dest);
|
CI->replaceAllUsesWith(Dst);
|
||||||
ci->eraseFromParent();
|
CI->eraseFromParent();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the length because we actually want to memcpy the null
|
|
||||||
// terminator as well.
|
|
||||||
len++;
|
|
||||||
|
|
||||||
// We have enough information to now generate the memcpy call to
|
// We have enough information to now generate the memcpy call to
|
||||||
// do the concatenation for us.
|
// do the concatenation for us.
|
||||||
Value *vals[4] = {
|
Value *MemcpyOps[] = {
|
||||||
dest, src,
|
Dst, Src,
|
||||||
ConstantInt::get(SLC.getIntPtrType(),len), // length
|
ConstantInt::get(SLC.getIntPtrType(), SrcLen), // length including nul.
|
||||||
ConstantInt::get(Type::Int32Ty, 1) // alignment
|
ConstantInt::get(Type::Int32Ty, 1) // alignment
|
||||||
};
|
};
|
||||||
new CallInst(SLC.get_memcpy(), vals, 4, "", ci);
|
new CallInst(SLC.get_memcpy(), MemcpyOps, 4, "", CI);
|
||||||
|
|
||||||
// Finally, substitute the first operand of the strcat call for the
|
CI->replaceAllUsesWith(Dst);
|
||||||
// strcat call itself since strcat returns its first operand; and,
|
CI->eraseFromParent();
|
||||||
// kill the strcat CallInst.
|
|
||||||
ci->replaceAllUsesWith(dest);
|
|
||||||
ci->eraseFromParent();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} StrCpyOptimizer;
|
} StrCpyOptimizer;
|
||||||
@ -849,8 +839,7 @@ struct VISIBILITY_HIDDEN StrLenOptimization : public LibCallOptimization {
|
|||||||
"Number of 'strlen' calls simplified") {}
|
"Number of 'strlen' calls simplified") {}
|
||||||
|
|
||||||
/// @brief Make sure that the "strlen" function has the right prototype
|
/// @brief Make sure that the "strlen" function has the right prototype
|
||||||
virtual bool ValidateCalledFunction(const Function* f, SimplifyLibCalls& SLC)
|
virtual bool ValidateCalledFunction(const Function *F, SimplifyLibCalls &SLC){
|
||||||
{
|
|
||||||
if (f->getReturnType() == SLC.getTargetData()->getIntPtrType())
|
if (f->getReturnType() == SLC.getTargetData()->getIntPtrType())
|
||||||
if (f->arg_size() == 1)
|
if (f->arg_size() == 1)
|
||||||
if (Function::const_arg_iterator AI = f->arg_begin())
|
if (Function::const_arg_iterator AI = f->arg_begin())
|
||||||
|
Loading…
Reference in New Issue
Block a user