blob: f2ce3981154b388f70a3c2c607b17efc8771920d [file] [log] [blame]
/// The speculative checking pass lowers synchronous calls to
/// speculative checking calls
#ifndef _SPECULATIVE_CHECKING_H_
#define _SPECULATIVE_CHECKING_H_
#include "safecode/SAFECode.h"
#include "llvm/Pass.h"
#include "llvm/IR/Instructions.h"
#include "dsa/CallTargets.h"
#include "dsa/DataStructure.h"
#include "poolalloc/PoolAllocate.h"
#include "safecode/Config/config.h"
#include <map>
#define PAR_CHECKING_ENABLE_INDIRECTCALL_OPT
using namespace llvm;
using dsa::CallTargetFinder;
NAMESPACE_SC_BEGIN
struct DSNodePass;
/**
* This pass analyzes all call instructions in the program and
* determines which calls are "safe", i.e., calls that can be executed
* without synchronizing the checking thread.
*
* It should be run before pool allocation
*
**/
struct ParCheckingCallAnalysis : public ModulePass {
static char ID;
ParCheckingCallAnalysis() : ModulePass((intptr_t) & ID) {};
virtual ~ParCheckingCallAnalysis() {}
virtual const char * getPassName() const { return "Call Safety Analysis for Parallel checking"; }
virtual bool runOnBasicBlock(BasicBlock & BB);
virtual bool runOnModule(Module & M);
virtual void getAnalysisUsage(AnalysisUsage & AU) const {
AU.addRequired<CallTargetFinder<EQTDDataStructures> >();
AU.setPreservesAll();
}
/**
* Whether the call is safe.
**/
bool isSafe(CallSite CS) const;
private:
std::set<CallSite> CallSafetySet;
bool isSafeCallSite(CallSite CS) const;
bool isSafeIndirectCall(CallSite CS) const;
CallTargetFinder<EQTDDataStructures> * CTF;
};
struct SpeculativeCheckingInsertSyncPoints : public BasicBlockPass {
public:
static char ID;
SpeculativeCheckingInsertSyncPoints() : BasicBlockPass((intptr_t) &ID) {};
virtual ~SpeculativeCheckingInsertSyncPoints() {};
virtual bool doInitialization(Module & M);
virtual bool doInitialization(Function &F) { return false; };
virtual bool runOnBasicBlock(BasicBlock & BB);
virtual const char * getPassName() const { return "Insert synchronization points between checking threads and application threads"; };
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
#ifdef PAR_CHECKING_ENABLE_INDIRECTCALL_OPT
/* AU.addRequired<EQTDDataStructures>();
AU.addRequired<PoolAllocateGroup>();
*/ AU.addRequired<DSNodePass>();
AU.addRequired<ParCheckingCallAnalysis>();
#endif
AU.setPreservesAll();
};
private:
bool insertSyncPointsBeforeExternalCall(CallInst * CI);
void removeRedundantSyncPoints(BasicBlock & BB);
CallInst * getOriginalCallInst(CallInst * CI);
DSNodePass * dsnodePass;
ParCheckingCallAnalysis * callSafetyAnalysis;
};
// A pass instruments store instructions to protect the queue
struct SpeculativeCheckStoreCheckPass : public BasicBlockPass {
public:
static char ID;
SpeculativeCheckStoreCheckPass() : BasicBlockPass((uintptr_t)&ID) {};
virtual ~SpeculativeCheckStoreCheckPass() {}
virtual bool doInitialization(Module & M);
virtual bool doInitialization(Function &F) { return false; };
virtual const char * getPassName() const { return "Instrument store instructions to protect the metadata of parallel checking"; }
virtual bool runOnBasicBlock(BasicBlock & BB);
};
///
/// Pool cache transform
/// Try to wrap the checking calls so that we don't need to pass the
/// pool handle into the queue.
///
class GlobalPoolCacheTransform : public ModulePass {
public:
static char ID;
GlobalPoolCacheTransform(): ModulePass((intptr_t)&ID) {}
virtual ~GlobalPoolCacheTransform() {}
virtual const char * getPassName() const { return "Transform checking calls to eliminate passing global pool handle"; }
virtual bool runOnModule(Module &M);
private:
///
/// Create wrapper for a particular global pool.
///
void createWrapper(Value * globalPoolHandle);
///
/// Transform the checking call into wrapper calls
///
void transformCheckingCall(CallInst * CI);
};
NAMESPACE_SC_END
#endif