Factor checked library call optimization into a common helper class and use it

to unify the almost identical code in CodeGenPrepare and InstCombineCalls.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@98338 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer 2010-03-12 09:27:41 +00:00
parent b3e87b2262
commit 0b6cb50738
4 changed files with 140 additions and 200 deletions

View File

@ -96,6 +96,18 @@ namespace llvm {
/// a pointer, Size is an 'intptr_t', and File is a pointer to FILE.
void EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B,
const TargetData *TD);
/// SimplifyFortifiedLibCalls - Helper class for folding checked library
/// calls (e.g. __strcpy_chk) into their unchecked counterparts.
class SimplifyFortifiedLibCalls {
protected:
CallInst *CI;
virtual void replaceCall(Value *With) = 0;
virtual bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp,
bool isString) const = 0;
public:
bool fold(CallInst *CI, const TargetData *TD);
};
}
#endif

View File

@ -751,117 +751,41 @@ static bool isSafeToEliminateVarargsCast(const CallSite CS,
return true;
}
namespace {
class InstCombineFortifiedLibCalls : public SimplifyFortifiedLibCalls {
InstCombiner *IC;
protected:
void replaceCall(Value *With) {
NewInstruction = IC->ReplaceInstUsesWith(*CI, With);
}
bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp, bool isString) const {
if (ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(SizeCIOp))) {
if (SizeCI->isAllOnesValue())
return true;
if (isString)
return SizeCI->getZExtValue() >=
GetStringLength(CI->getOperand(SizeArgOp));
if (ConstantInt *Arg = dyn_cast<ConstantInt>(CI->getOperand(SizeArgOp)))
return SizeCI->getZExtValue() <= Arg->getZExtValue();
}
return false;
}
public:
InstCombineFortifiedLibCalls(InstCombiner *IC) : IC(IC), NewInstruction(0) { }
Instruction *NewInstruction;
};
} // end anonymous namespace
// Try to fold some different type of calls here.
// Currently we're only working with the checking functions, memcpy_chk,
// mempcpy_chk, memmove_chk, memset_chk, strcpy_chk, stpcpy_chk, strncpy_chk,
// strcat_chk and strncat_chk.
Instruction *InstCombiner::tryOptimizeCall(CallInst *CI, const TargetData *TD) {
if (CI->getCalledFunction() == 0) return 0;
StringRef Name = CI->getCalledFunction()->getName();
BasicBlock *BB = CI->getParent();
IRBuilder<> B(CI->getParent()->getContext());
// Set the builder to the instruction after the call.
B.SetInsertPoint(BB, CI);
if (Name == "__memcpy_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
if (!SizeArg)
return 0;
if (SizeCI->isAllOnesValue() ||
SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
1, B, TD);
return ReplaceInstUsesWith(*CI, CI->getOperand(1));
}
return 0;
}
// Should be similar to memcpy.
if (Name == "__mempcpy_chk") {
return 0;
}
if (Name == "__memmove_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
if (!SizeArg)
return 0;
if (SizeCI->isAllOnesValue() ||
SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
1, B, TD);
return ReplaceInstUsesWith(*CI, CI->getOperand(1));
}
return 0;
}
if (Name == "__memset_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
if (!SizeArg)
return 0;
if (SizeCI->isAllOnesValue() ||
SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
Value *Val = B.CreateIntCast(CI->getOperand(2), B.getInt8Ty(),
false);
EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD);
return ReplaceInstUsesWith(*CI, CI->getOperand(1));
}
return 0;
}
if (Name == "__strcpy_chk" || Name == "__stpcpy_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(3));
if (!SizeCI)
return 0;
// If a) we don't have any length information, or b) we know this will
// fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our
// st[rp]cpy_chk call which may fail at runtime if the size is too long.
// TODO: It might be nice to get a maximum length out of the possible
// string lengths for varying.
if (SizeCI->isAllOnesValue() ||
SizeCI->getZExtValue() >= GetStringLength(CI->getOperand(2))) {
Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD,
Name.substr(2, 6));
return ReplaceInstUsesWith(*CI, Ret);
}
return 0;
}
if (Name == "__strncpy_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
if (!SizeArg)
return 0;
if (SizeCI->isAllOnesValue() ||
SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
Value *Ret = EmitStrNCpy(CI->getOperand(1), CI->getOperand(2),
CI->getOperand(3), B, TD);
return ReplaceInstUsesWith(*CI, Ret);
}
return 0;
}
if (Name == "__strcat_chk") {
return 0;
}
if (Name == "__strncat_chk") {
return 0;
}
return 0;
InstCombineFortifiedLibCalls Simplifier(this);
Simplifier.fold(CI, TD);
return Simplifier.NewInstruction;
}
// visitCallSite - Improvements for call and invoke instructions.

View File

@ -540,9 +540,22 @@ static bool OptimizeCmpExpression(CmpInst *CI) {
return MadeChange;
}
namespace {
class CodeGenPrepareFortifiedLibCalls : public SimplifyFortifiedLibCalls {
protected:
void replaceCall(Value *With) {
CI->replaceAllUsesWith(With);
CI->eraseFromParent();
}
bool isFoldable(unsigned SizeCIOp, unsigned, bool) const {
if (ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(SizeCIOp)))
return SizeCI->isAllOnesValue();
return false;
}
};
} // end anonymous namespace
bool CodeGenPrepare::OptimizeCallInst(CallInst *CI) {
bool MadeChange = false;
// Lower all uses of llvm.objectsize.*
IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI);
if (II && II->getIntrinsicID() == Intrinsic::objectsize) {
@ -561,102 +574,12 @@ bool CodeGenPrepare::OptimizeCallInst(CallInst *CI) {
const TargetData *TD = TLI ? TLI->getTargetData() : 0;
if (!TD) return false;
// Lower all default uses of _chk calls. This is code very similar
// to the code in InstCombineCalls, but here we are only lowering calls
// Lower all default uses of _chk calls. This is very similar
// to what InstCombineCalls does, but here we are only lowering calls
// that have the default "don't know" as the objectsize. Anything else
// should be left alone.
StringRef Name = CI->getCalledFunction()->getName();
BasicBlock *BB = CI->getParent();
IRBuilder<> B(CI->getParent()->getContext());
// Set the builder to the instruction after the call.
B.SetInsertPoint(BB, CI);
if (Name == "__memcpy_chk") {
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, TD);
CI->replaceAllUsesWith(CI->getOperand(1));
CI->eraseFromParent();
return true;
}
return 0;
}
// Should be similar to memcpy.
if (Name == "__mempcpy_chk") {
return 0;
}
if (Name == "__memmove_chk") {
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, TD);
CI->replaceAllUsesWith(CI->getOperand(1));
CI->eraseFromParent();
return true;
}
return 0;
}
if (Name == "__memset_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
if (SizeCI->isAllOnesValue()) {
Value *Val = B.CreateIntCast(CI->getOperand(2), B.getInt8Ty(),
false);
EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD);
CI->replaceAllUsesWith(CI->getOperand(1));
CI->eraseFromParent();
return true;
}
return 0;
}
if (Name == "__strcpy_chk" || Name == "__stpcpy_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(3));
if (!SizeCI)
return 0;
if (SizeCI->isAllOnesValue()) {
Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD,
Name.substr(2, 6));
CI->replaceAllUsesWith(Ret);
CI->eraseFromParent();
return true;
}
return 0;
}
if (Name == "__strncpy_chk") {
ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
if (!SizeCI)
return 0;
if (SizeCI->isAllOnesValue()) {
Value *Ret = EmitStrNCpy(CI->getOperand(1), CI->getOperand(2),
CI->getOperand(3), B, TD);
CI->replaceAllUsesWith(Ret);
CI->eraseFromParent();
return true;
}
return 0;
}
if (Name == "__strcat_chk") {
return 0;
}
if (Name == "__strncat_chk") {
return 0;
}
return MadeChange;
CodeGenPrepareFortifiedLibCalls Simplifier;
return Simplifier.fold(CI, TD);
}
//===----------------------------------------------------------------------===//
// Memory Optimization

View File

@ -342,3 +342,84 @@ void llvm::EmitFWrite(Value *Ptr, Value *Size, Value *File,
if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts()))
CI->setCallingConv(Fn->getCallingConv());
}
bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) {
this->CI = CI;
StringRef Name = CI->getCalledFunction()->getName();
BasicBlock *BB = CI->getParent();
IRBuilder<> B(CI->getParent()->getContext());
// Set the builder to the instruction after the call.
B.SetInsertPoint(BB, CI);
if (Name == "__memcpy_chk") {
if (isFoldable(4, 3, false)) {
EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
1, B, TD);
replaceCall(CI->getOperand(1));
return true;
}
return false;
}
// Should be similar to memcpy.
if (Name == "__mempcpy_chk") {
return false;
}
if (Name == "__memmove_chk") {
if (isFoldable(4, 3, false)) {
EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
1, B, TD);
replaceCall(CI->getOperand(1));
return true;
}
return false;
}
if (Name == "__memset_chk") {
if (isFoldable(4, 3, false)) {
Value *Val = B.CreateIntCast(CI->getOperand(2), B.getInt8Ty(),
false);
EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD);
replaceCall(CI->getOperand(1));
return true;
}
return false;
}
if (Name == "__strcpy_chk" || Name == "__stpcpy_chk") {
// If a) we don't have any length information, or b) we know this will
// fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our
// st[rp]cpy_chk call which may fail at runtime if the size is too long.
// TODO: It might be nice to get a maximum length out of the possible
// string lengths for varying.
if (isFoldable(3, 2, true)) {
Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD,
Name.substr(2, 6));
replaceCall(Ret);
return true;
}
return false;
}
if (Name == "__strncpy_chk") {
if (isFoldable(4, 3, false)) {
Value *Ret = EmitStrNCpy(CI->getOperand(1), CI->getOperand(2),
CI->getOperand(3), B, TD);
replaceCall(Ret);
return true;
}
return false;
}
if (Name == "__strcat_chk") {
return false;
}
if (Name == "__strncat_chk") {
return false;
}
return false;
}