Add more optimizations for object size checking, enable handling of

object size intrinsic and verify return type is correct. Collect various
code in one place.

llvm-svn: 89523
This commit is contained in:
Eric Christopher 2009-11-21 01:01:30 +00:00
parent e1bbc33355
commit 0c7bd96de2
1 changed files with 144 additions and 35 deletions

View File

@ -81,6 +81,11 @@ public:
Value *EmitMemCpy(Value *Dst, Value *Src, Value *Len,
unsigned Align, IRBuilder<> &B);
/// EmitMemMove - Emit a call to the memmove function to the builder. This
/// always expects that the size has type 'intptr_t' and Dst/Src are pointers.
Value *EmitMemMove(Value *Dst, Value *Src, Value *Len,
unsigned Align, IRBuilder<> &B);
/// EmitMemChr - Emit a call to the memchr function. This assumes that Ptr is
/// a pointer, Val is an i32 value, and Len is an 'intptr_t' value.
Value *EmitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B);
@ -160,6 +165,21 @@ Value *LibCallOptimization::EmitMemCpy(Value *Dst, Value *Src, Value *Len,
ConstantInt::get(Type::getInt32Ty(*Context), Align));
}
/// EmitMemMOve - Emit a call to the memmove function to the builder. This
/// always expects that the size has type 'intptr_t' and Dst/Src are pointers.
Value *LibCallOptimization::EmitMemMove(Value *Dst, Value *Src, Value *Len,
unsigned Align, IRBuilder<> &B) {
Module *M = Caller->getParent();
Intrinsic::ID IID = Intrinsic::memmove;
const Type *Tys[1];
Tys[0] = TD->getIntPtrType(*Context);
Value *MemMove = Intrinsic::getDeclaration(M, IID, Tys, 1);
Value *D = CastToCStr(Dst, B);
Value *S = CastToCStr(Src, B);
Value *A = ConstantInt::get(Type::getInt32Ty(*Context), Align);
return B.CreateCall4(MemMove, D, S, Len, A);
}
/// EmitMemChr - Emit a call to the memchr function. This assumes that Ptr is
/// a pointer, Val is an i32 value, and Len is an 'intptr_t' value.
Value *LibCallOptimization::EmitMemChr(Value *Ptr, Value *Val,
@ -511,27 +531,6 @@ static bool IsOnlyUsedInZeroEqualityComparison(Value *V) {
return true;
}
//===----------------------------------------------------------------------===//
// Miscellaneous LibCall/Intrinsic Optimizations
//===----------------------------------------------------------------------===//
namespace {
struct SizeOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// TODO: We can do more with this, but delaying to here should be no change
// in behavior.
ConstantInt *Const = dyn_cast<ConstantInt>(CI->getOperand(2));
if (!Const) return 0;
if (Const->getZExtValue() < 2)
return Constant::getAllOnesValue(Const->getType());
else
return ConstantInt::get(Const->getType(), 0);
}
};
}
//===----------------------------------------------------------------------===//
// String and Memory LibCall Optimizations
//===----------------------------------------------------------------------===//
@ -1010,16 +1009,7 @@ struct MemMoveOpt : public LibCallOptimization {
return 0;
// memmove(x, y, n) -> llvm.memmove(x, y, n, 1)
Module *M = Caller->getParent();
Intrinsic::ID IID = Intrinsic::memmove;
const Type *Tys[1];
Tys[0] = TD->getIntPtrType(*Context);
Value *MemMove = Intrinsic::getDeclaration(M, IID, Tys, 1);
Value *Dst = CastToCStr(CI->getOperand(1), B);
Value *Src = CastToCStr(CI->getOperand(2), B);
Value *Size = CI->getOperand(3);
Value *Align = ConstantInt::get(Type::getInt32Ty(*Context), 1);
B.CreateCall4(MemMove, Dst, Src, Size, Align);
EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), 1, B);
return CI->getOperand(1);
}
};
@ -1047,6 +1037,118 @@ struct MemSetOpt : public LibCallOptimization {
}
};
//===----------------------------------------------------------------------===//
// Object Size Checking Optimizations
//===----------------------------------------------------------------------===//
//===---------------------------------------===//
// 'object size'
namespace {
struct SizeOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// TODO: We can do more with this, but delaying to here should be no change
// in behavior.
ConstantInt *Const = dyn_cast<ConstantInt>(CI->getOperand(2));
if (!Const) return 0;
const Type *Ty = Callee->getFunctionType()->getReturnType();
if (Const->getZExtValue() < 2)
return Constant::getAllOnesValue(Ty);
else
return ConstantInt::get(Ty, 0);
}
};
}
//===---------------------------------------===//
// 'memcpy_chk' Optimizations
struct MemCpyChkOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// These optimizations require TargetData.
if (!TD) return 0;
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
!isa<PointerType>(FT->getParamType(0)) ||
!isa<PointerType>(FT->getParamType(1)) ||
!isa<IntegerType>(FT->getParamType(3)) ||
FT->getParamType(2) != TD->getIntPtrType(*Context))
return 0;
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
if (SizeCI->isAllOnesValue()) {
EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), 1, B);
return CI->getOperand(1);
}
return 0;
}
};
//===---------------------------------------===//
// 'memset_chk' Optimizations
struct MemSetChkOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// These optimizations require TargetData.
if (!TD) return 0;
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
!isa<PointerType>(FT->getParamType(0)) ||
!isa<IntegerType>(FT->getParamType(1)) ||
!isa<IntegerType>(FT->getParamType(3)) ||
FT->getParamType(2) != TD->getIntPtrType(*Context))
return 0;
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
if (SizeCI->isAllOnesValue()) {
Value *Val = B.CreateIntCast(CI->getOperand(2), Type::getInt8Ty(*Context),
false);
EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B);
return CI->getOperand(1);
}
return 0;
}
};
//===---------------------------------------===//
// 'memmove_chk' Optimizations
struct MemMoveChkOpt : public LibCallOptimization {
virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// These optimizations require TargetData.
if (!TD) return 0;
const FunctionType *FT = Callee->getFunctionType();
if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
!isa<PointerType>(FT->getParamType(0)) ||
!isa<PointerType>(FT->getParamType(1)) ||
!isa<IntegerType>(FT->getParamType(3)) ||
FT->getParamType(2) != TD->getIntPtrType(*Context))
return 0;
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
if (SizeCI->isAllOnesValue()) {
EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
1, B);
return CI->getOperand(1);
}
return 0;
}
};
//===----------------------------------------------------------------------===//
// Math Library Optimizations
//===----------------------------------------------------------------------===//
@ -1586,7 +1688,10 @@ namespace {
// Formatting and IO Optimizations
SPrintFOpt SPrintF; PrintFOpt PrintF;
FWriteOpt FWrite; FPutsOpt FPuts; FPrintFOpt FPrintF;
// Object Size Checking
SizeOpt ObjectSize;
MemCpyChkOpt MemCpyChk; MemSetChkOpt MemSetChk; MemMoveChkOpt MemMoveChk;
bool Modified; // This is only used by doInitialization.
public:
@ -1693,8 +1798,12 @@ void SimplifyLibCalls::InitOptimizations() {
Optimizations["fputs"] = &FPuts;
Optimizations["fprintf"] = &FPrintF;
// Miscellaneous
Optimizations["llvm.objectsize"] = &ObjectSize;
// Object Size Checking
Optimizations["llvm.objectsize.i32"] = &ObjectSize;
Optimizations["llvm.objectsize.i64"] = &ObjectSize;
Optimizations["__memcpy_chk"] = &MemCpyChk;
Optimizations["__memset_chk"] = &MemSetChk;
Optimizations["__memmove_chk"] = &MemMoveChk;
}