blob: de6576a9e012dca4e681148c0de54d8b2ee0eeda [file] [log] [blame]
//===- OptimizeIdenticalLSChecks.cpp - Remove identical load/store checks -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass removes identical load/store checks by removing all but the
// first instances of repeating (base ptr, access size) pairs in segments of
// basic blocks where the segments are ended by function calls that may
// deallocate memory.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "optimize-identical-ls-checks"
#include "CommonMemorySafetyPasses.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/MSCInfo.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Instrumentation.h"
using namespace llvm;
STATISTIC(MemoryChecksRemoved, "Load/store checks removed");
namespace {
class OptimizeIdenticalLSChecks : public FunctionPass {
bool mayDeallocateMemory(CallInst *CI);
public:
static char ID;
OptimizeIdenticalLSChecks(): FunctionPass(ID) { }
virtual bool runOnFunction(Function &F);
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<MSCInfo>();
AU.setPreservesCFG();
}
virtual const char *getPassName() const {
return "OptimizeIdenticalLSChecks";
}
};
typedef std::pair <Value*, Value*> ValuePair;
} // end anon namespace
char OptimizeIdenticalLSChecks::ID = 0;
INITIALIZE_PASS(OptimizeIdenticalLSChecks, "optimize-identical-ls-checks",
"Remove identical load/store checks where possible", false,
false)
FunctionPass *llvm::createOptimizeIdenticalLSChecksPass() {
return new OptimizeIdenticalLSChecks();
}
bool OptimizeIdenticalLSChecks::runOnFunction(Function &F) {
MSCInfo *MSCI = &getAnalysis<MSCInfo>();
SmallSet <ValuePair, 32> PreviousChecks;
SmallVector <CallInst*, 64> ToRemove;
for (Function::iterator BB = F.begin(), BBE = F.end(); BB != BBE; ++BB) {
for (BasicBlock::iterator I = BB->begin(), IE = BB->end(); I != IE; ++I) {
// Clear cache on atomics intrinsics to be able to catch some concurrency
// bugs where one thread frees the object between two accesses by another
// thread.
if (isa<AtomicCmpXchgInst>(I) || isa<AtomicRMWInst>(I)) {
PreviousChecks.clear();
continue;
}
// InvokeInst can be ignored because it is a terminator and all checks
// should be call instructions.
CallInst *CI = dyn_cast<CallInst>(I);
if (!CI)
continue;
CheckInfoType *Info = MSCI->getCheckInfo(CI->getCalledFunction());
if (Info && Info->isMemoryCheck()) {
ValuePair Pair(CI->getArgOperand(Info->PtrArgNo)->stripPointerCasts(),
CI->getArgOperand(Info->SizeArgNo));
if (PreviousChecks.count(Pair))
ToRemove.push_back(CI);
else
PreviousChecks.insert(Pair);
} else if (mayDeallocateMemory(CI)) {
PreviousChecks.clear();
}
}
PreviousChecks.clear();
}
for (size_t i = 0, N = ToRemove.size(); i != N; ++i) {
ToRemove[i]->eraseFromParent();
++MemoryChecksRemoved;
}
return !ToRemove.empty();
}
bool OptimizeIdenticalLSChecks::mayDeallocateMemory(CallInst *CI) {
// llvm.mem[set|cpy|move].*
if (isa<MemIntrinsic>(CI))
return false;
return true;
}