mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
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:
parent
b3e87b2262
commit
0b6cb50738
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user