blob: 56f6c9ba05237b76c640c3c14f99b5cf4436a034 [file] [log] [blame]
//===- CodeDuplication.cpp: -----------------------------------------------===//
//
// The SAFECode Compiler
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file performs code duplication analysis and wraps codes into
// functions.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "code_duplication"
#include <set>
#include <iostream>
#include "llvm/Function.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/ADT/Statistic.h"
#include "safecode/VectorListHelper.h"
#include "safecode/CodeDuplication.h"
#include "SCUtils.h"
/*
static llvm::RegisterPass<llvm::CodeDuplicationAnalysis> sCodeDuplicationAnalysisPass("-code-dup-analysis", "Analysis for code duplication", false, false);
static llvm::RegisterPass<llvm::RemoveSelfLoopEdge> sRemoveSelfLoopEdgePass("-break-self-loop-edge", "Break all self-loop edges in basic blocks");
static llvm::RegisterPass<llvm::DuplicateCodeTransform> sDuplicateCodeTransformPass("-duplicate-code-transformation", "Duplicate codes for SAFECode checking");
*/
static llvm::RegisterPass<llvm::DuplicateLoopAnalysis> sDuplicateLoopAnalysis("dup-loop-analysis", "Analysis for duplicating loop", false, false);
namespace {
STATISTIC (DuplicatedLoop, "The number of loops are eligible for duplication");
}
namespace llvm {
char CodeDuplicationAnalysis::ID = 0;
/// Determine whether a basic block is eligible for code duplication
/// Here are the criteria:
///
/// 1. No call instructions (FIXME: what about internal function
/// calls? )
///
/// 2. Memory access patterns and control flows are memory
/// indepdendent, i.e., the results of load instructions in the
/// basic block cannot affect memory addresses and control flows.
///
/// 3. Volative instructions(TODO: Implementation!)
static bool isEligibleforCodeDuplication(BasicBlock * BB) {
std::set<Instruction*> unsafeInstruction;
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
if (isa<CallInst>(I)) {
return false;
}
/* } else if (isa<LoadInst>(I)) {
/// Taint analysis for Load Instructions
LoadInst * inst = dyn_cast<LoadInst>(I);
unsafeInstruction.insert(inst);
for (Value::use_iterator I = inst->use_begin(), E = inst->use_end(); I != E; ++ I) {
if (Instruction * in = dyn_cast<Instruction>(I)) {
if (in->getParent() != BB) {
break;
}
unsafeInstruction.insert(in);
}
}
}
}
/// Check GEP instructions
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
if (isa<GetElementPtrInst>(I) && unsafeInstruction.count(I)) {
return false;
}
}
Instruction * termInst = BB->getTerminator();
return unsafeInstruction.count(termInst) == 0;
*/
}
return true;
}
void CodeDuplicationAnalysis::calculateBBArgument(BasicBlock * BB, InputArgumentsTy & args) {
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
Instruction * inst = &*I;
// Add Phi node and load instructions into input arguments
if (isa<PHINode>(inst) || isa<LoadInst>(inst)) {
args.push_back(inst);
continue;
}
///
for (User::op_iterator op_it = inst->op_begin(), op_end = inst->op_end(); op_it != op_end; ++op_it) {
Value * def = op_it->get();
// Def is outside of the basic block
Instruction * defInst = dyn_cast<Instruction>(def);
if (defInst && defInst->getParent() != BB) {
args.push_back(defInst);
}
}
}
}
bool CodeDuplicationAnalysis::runOnModule(Module & M) {
InputArgumentsTy args;
for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) {
for (Function::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) {
BasicBlock * BB = BI;
args.clear();
if (isEligibleforCodeDuplication(BB)) {
calculateBBArgument(BB, args);
mBlockInfo[BB] = args;
/* // BB->dump();
std::cerr << "=== args ===" << std::endl;
for (size_t i = 0; i < args.size(); ++i) {
// args[i]->getType()->dump();
//args[i]->dump();
std::cerr << std::endl;
}
std::cerr << "====" << std::endl;
*/
}
}
}
return false;
}
bool CodeDuplicationAnalysis::doInitialization(Module & M) {
mBlockInfo.clear();
return false;
}
bool CodeDuplicationAnalysis::doFinalization(Module & M) {
mBlockInfo.clear();
return false;
}
///
/// RemoveSelfLoopEdge Methods
///
char RemoveSelfLoopEdge::ID = 0;
/// A a dummy basic block at the end of the input block to eliminate
/// self-loop edges.
static void removeBBSelfLoopEdge(BasicBlock * BB) {
Instruction * inst = BB->getTerminator();
BranchInst * branchInst = dyn_cast<BranchInst>(inst);
BasicBlock * newEndBB = BasicBlock::Create(getGlobalContext(),
BB->getName() + ".self_loop_edge:");
BranchInst::Create(BB, newEndBB);
Function * F = BB->getParent();
Function::iterator bbIt = BB;
F->getBasicBlockList().insert(++bbIt, newEndBB);
assert(branchInst && "the terminator of input basic block should be a branch instruction");
for (User::op_iterator op_it = branchInst->op_begin(), op_end = branchInst->op_end(); op_it != op_end; ++op_it) {
BasicBlock * bb = dyn_cast<BasicBlock>(op_it->get());
if (BB == bb) {
op_it->set(newEndBB);
}
}
// Deal with PHI Node, from BreakCritcalEdges.cpp
for (BasicBlock::iterator I = BB->begin(); isa<PHINode>(I); ++I) {
PHINode *PN = cast<PHINode>(I);
int BBIdx = PN->getBasicBlockIndex(BB);
PN->setIncomingBlock(BBIdx, newEndBB);
}
}
bool RemoveSelfLoopEdge::runOnFunction(Function & F) {
typedef std::set<BasicBlock* > BasicBlockSetTy;
BasicBlockSetTy toBeProceed;
for (Function::iterator it = F.begin(), it_end = F.end(); it != it_end; ++it) {
Instruction * inst = it->getTerminator();
if (BranchInst * branchInst = dyn_cast<BranchInst>(inst)) {
for (User::op_iterator op_it = branchInst->op_begin(), op_end = branchInst->op_end(); op_it != op_end; ++op_it) {
BasicBlock * bb = dyn_cast<BasicBlock>(op_it->get());
if (bb == &*it) {
toBeProceed.insert(bb);
}
}
}
}
for (BasicBlockSetTy::iterator it = toBeProceed.begin(), it_end = toBeProceed.end(); it != it_end; ++it) {
removeBBSelfLoopEdge(*it);
}
return toBeProceed.size() != 0;
}
/// DuplicateCodeTransform Methods
char DuplicateCodeTransform::ID = 0;
bool DuplicateCodeTransform::runOnModule(Module &M) {
CodeDuplicationAnalysis & CDA = getAnalysis<CodeDuplicationAnalysis>();
for (CodeDuplicationAnalysis::BlockInfoTy::const_iterator it = CDA.getBlockInfo().begin(),
it_end = CDA.getBlockInfo().end(); it != it_end; ++it) {
wrapCheckingRegionAsFunction(M, it->first, it->second);
}
return true;
}
void DuplicateCodeTransform::wrapCheckingRegionAsFunction(Module & M, const BasicBlock * bb,
const CodeDuplicationAnalysis::InputArgumentsTy & args) {
std::vector<const Type *> argType;
for (CodeDuplicationAnalysis::InputArgumentsTy::const_iterator it = args.begin(), end = args.end(); it != end; ++it) {
argType.push_back((*it)->getType());
}
const Type * VoidType = Type::getVoidTy(getGlobalContext());
FunctionType * FTy = FunctionType::get(VoidType, argType, false);
Function * F = Function::Create(FTy, GlobalValue::InternalLinkage, bb->getName() + ".dup", &M);
/// Mapping from original def to function arguments
typedef std::map<Value *, Argument *> DefToArgMapTy;
DefToArgMapTy defToArgMap;
Function::arg_iterator it_arg, it_arg_end;
CodeDuplicationAnalysis::InputArgumentsTy::const_iterator it_arg_val, it_arg_val_end;
for (it_arg = F->arg_begin(), it_arg_end = F->arg_end(), it_arg_val = args.begin(), it_arg_val_end = args.end();
it_arg != it_arg_end; ++it_arg, ++it_arg_val) {
Value * argVal = *it_arg_val;
it_arg->setName(argVal->getName() + ".dup");
defToArgMap[argVal] = it_arg;
}
DenseMap<const Value*, Value*> valMapping;
BasicBlock * newBB = CloneBasicBlock(bb, valMapping, "", F);
Instruction * termInst = newBB->getTerminator();
termInst->eraseFromParent();
ReturnInst::Create(getGlobalContext(), NULL, newBB);
/// Replace defs inside the basic blocks with function arguments
for (CodeDuplicationAnalysis::InputArgumentsTy::const_iterator it = args.begin(), end = args.end(); it != end; ++it) {
if (valMapping.find(*it) != valMapping.end()) {
Instruction * defInst = dyn_cast<Instruction>(valMapping[*it]);
defInst->replaceAllUsesWith(defToArgMap[*it]);
defInst->eraseFromParent();
}
}
/// Eliminate stores
std::set<Instruction *> toBeRemoved;
for (BasicBlock::iterator it = newBB->begin(), end = newBB->end(); it != end; ++it) {
if (isa<StoreInst>(it)) toBeRemoved.insert(it);
}
for (std::set<Instruction *>::iterator it = toBeRemoved.begin(), end = toBeRemoved.end(); it != end; ++it) {
(*it)->removeFromParent();
}
/// Replace all uses whose defs
for (BasicBlock::iterator it = newBB->begin(), end = newBB->end(); it != end; ++it) {
for (DefToArgMapTy::iterator AI = defToArgMap.begin(), AE = defToArgMap.end(); AI != AE; ++AI) {
it->replaceUsesOfWith(AI->first, AI->second);
}
for (DenseMap<const Value *, Value *>::iterator AI = valMapping.begin(), AE = valMapping.end(); AI != AE; ++AI) {
it->replaceUsesOfWith(const_cast<Value*>(AI->first), AI->second);
}
}
}
///
/// Template Helper to remove instructions from loop
///
template <class T>
static void removeInstructionFromLoop(Loop * L) {
T op;
std::vector<Instruction*> toBeRemoved;
for (Loop::block_iterator I = L->block_begin(), E = L->block_end(); I != E; ++I) {
for (BasicBlock::iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) {
if (op(BI)) {
toBeRemoved.push_back(BI);
}
}
}
for(std::vector<Instruction*>::iterator it = toBeRemoved.begin(), end = toBeRemoved.end(); it != end; ++it) {
(*it)->eraseFromParent();
}
}
///
/// Loop Duplication Methods
///
struct StoreInstPred {
bool operator()(Instruction * I) const {
return isa<StoreInst>(I);
}
};
struct ExactCheckCallPred {
bool operator()(Instruction * I) const {
if (CallInst * CI = dyn_cast<CallInst>(I)) {
Function * F = CI->getCalledFunction();
if (F && (F->getName() == "exactcheck" || F->getName() == "exactcheck2")) {
return true;
}
}
return false;
}
};
struct CheckingCallPred {
bool operator()(Instruction * I) const {
if (CallInst * CI = dyn_cast<CallInst>(I)) {
Function * F = CI->getCalledFunction();
if (F && isCheckingCall(F->getName())) {
return true;
}
}
return false;
}
};
template <class T1, class T2>
struct pred_and {
T1 t1; T2 t2;
bool operator()(Instruction * I) const {
return t1(I) && t2(I);
}
};
template <class T>
struct pred_not {
T t;
bool operator()(Instruction * I) const {
return !t(I);
}
};
char DuplicateLoopAnalysis::ID = 0;
bool
DuplicateLoopAnalysis::doInitialization(Module &) {
cloneFunction.clear();
return false;
}
bool
DuplicateLoopAnalysis::runOnFunction(Function & F) {
if (cloneFunction.find(&F) != cloneFunction.end())
return false;
Module * M = F.getParent();
LI = &getAnalysis<LoopInfo>();
for (LoopInfo::iterator it = LI->begin(), end = LI->end(); it != end; ++it) {
duplicateLoop(*it, M);
}
return false;
}
void
DuplicateLoopAnalysis::duplicateLoop(Loop * L, Module * M) {
dupLoopArgument.clear();
cloneValueMap.clear();
if (isEligibleforDuplication(L)) {
calculateArgument(L);
Function * wrapFunction = wrapLoopIntoFunction(L, M);
cloneFunction.insert(wrapFunction);
++DuplicatedLoop;
} else {
// Try all subloops
for(Loop::iterator it = L->begin(), end = L->end(); it != end; ++it) {
duplicateLoop(*it, M);
}
}
}
bool
DuplicateLoopAnalysis::isEligibleforDuplication(const Loop * L) const {
// Loop should have a preheader for adding synchronization points
if (!L->getLoopPreheader())
return false;
// Only duplicate loop with checking calls
bool hasCheckingCalls = false;
for (Loop::block_iterator I = L->block_begin(), E = L->block_end(); I != E; ++I) {
for (BasicBlock::iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) {
if (BI->mayWriteToMemory()) {
if (isa<StoreInst>(BI)) {
// FIXME: Check whether the store instruction is safe or not
continue;
} else if (isa<CallInst>(BI)) {
CallInst * CI = dyn_cast<CallInst>(BI);
Function * F = CI->getCalledFunction();
if (F) {
bool flag = isCheckingCall(F->getName());
hasCheckingCalls |= flag;
if (!flag) {
return false;
}
} else {
return false;
}
}
}
}
}
if (!hasCheckingCalls) return false;
return true;
}
void
DuplicateLoopAnalysis::calculateArgument(const Loop * L) {
assert(dupLoopArgument.size() == 0);
std::set<Value*> argSet;
for (Loop::block_iterator I = L->block_begin(), E = L->block_end(); I != E; ++I) {
for (BasicBlock::iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) {
for(User::const_op_iterator OI = BI->op_begin(), OE = BI->op_end(); OI != OE; ++OI) {
Value * val = *OI;
if (Instruction * I = dyn_cast<Instruction>(val)) {
if (!L->contains(I->getParent())) {
argSet.insert(val);
}
} else if (Argument * arg = dyn_cast<Argument>(val)) {
argSet.insert(arg);
}
}
}
}
for(std::set<Value*>::iterator it = argSet.begin(), end = argSet.end(); it != end; ++it) {
dupLoopArgument.push_back(*it);
}
}
Function *
DuplicateLoopAnalysis::wrapLoopIntoFunction(Loop * L, Module * M) {
std::vector<const Type *> argType;
for (DuplicateLoopAnalysis::InputArgumentsTy::const_iterator it = dupLoopArgument.begin(), end = dupLoopArgument.end(); it != end; ++it) {
argType.push_back((*it)->getType());
}
const Type * VoidType = Type::getVoidTy(getGlobalContext());
StructType * checkArgumentsType=StructType::get(getGlobalContext(),argType);
std::vector<const Type *> funcArgType;
funcArgType.push_back(PointerType::getUnqual(checkArgumentsType));
FunctionType * FTy = FunctionType::get(VoidType, funcArgType, false);
Function * F = Function::Create(FTy, GlobalValue::InternalLinkage, ".codedup", M);
Argument * funcActual = F->arg_begin();
funcActual->setName("args");
/*
/// Mapping from original def to function arguments
typedef std::map<Value *, Argument *> DefToArgMapTy;
DefToArgMapTy defToArgMap;
Function::arg_iterator it_arg, it_arg_end;
DuplicateLoopAnalysis::InputArgumentsTy::const_iterator it_arg_val, it_arg_val_end;
for (it_arg = F->arg_begin(), it_arg_end = F->arg_end(), it_arg_val = args.begin(), it_arg_val_end = args.end();
it_arg != it_arg_end; ++it_arg, ++it_arg_val) {
Value * argVal = *it_arg_val;
it_arg->setName(argVal->getName() + ".dup");
defToArgMap[argVal] = it_arg;
}
*/
// Add codes into the function and clone the loop
BasicBlock * entryBlock = BasicBlock::Create(getGlobalContext(),"entry",F);
BasicBlock * exitBlock= BasicBlock::Create(getGlobalContext(),"loopexit",F);
ReturnInst::Create(getGlobalContext(), NULL, exitBlock);
DenseMap<const Value *, Value*> & valMapping = cloneValueMap;
valMapping[L->getLoopPreheader()] = entryBlock;
SmallVector<BasicBlock*, 8> exitBlocks;
L->getUniqueExitBlocks(exitBlocks);
for (SmallVector<BasicBlock*, 8>::iterator ExitBlocksIt = exitBlocks.begin(), ExitBlocksEnd = exitBlocks.end();
ExitBlocksIt != ExitBlocksEnd; ++ExitBlocksIt) {
valMapping[*ExitBlocksIt] = exitBlock;
}
// Generate loads for arguments
int arg_counter = 0;
for (DuplicateLoopAnalysis::InputArgumentsTy::const_iterator it = dupLoopArgument.begin(), end = dupLoopArgument.end(); it != end; ++it) {
const Type * Int32Type = IntegerType::getInt32Ty(getGlobalContext());
std::vector<Value*> idxVal;
idxVal.push_back(ConstantInt::get(Int32Type, 0));
idxVal.push_back(ConstantInt::get(Int32Type, arg_counter));
GetElementPtrInst * GEP = GetElementPtrInst::Create(funcActual, idxVal.begin(), idxVal.end(), "", entryBlock);
Value * loadArg = new LoadInst(GEP, ".arg", entryBlock);
valMapping[*it] = loadArg;
++arg_counter;
}
// Clone the loop
Loop * NewLoop = new Loop();
for (Loop::block_iterator I = L->block_begin(), E = L->block_end(); I != E; ++I) {
BasicBlock * bb = CloneBasicBlock(*I, valMapping, ".dup", F);
valMapping[*I] = bb;
NewLoop->addBasicBlockToLoop(bb, LI->getBase());
}
BasicBlock * loopHeader = NewLoop->getHeader();
BranchInst::Create(loopHeader, entryBlock);
loopHeader->moveAfter(entryBlock);
exitBlock->moveAfter(&(F->back()));
// Replace all uses in the loop with function arguments
for (Loop::block_iterator I = NewLoop->block_begin(), E = NewLoop->block_end(); I != E; ++I) {
for (BasicBlock::iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) {
for(User::op_iterator OI = BI->op_begin(), OE = BI->op_end(); OI != OE; ++OI) {
DenseMap<const Value*, Value*>::iterator valMapIt = valMapping.find(*OI);
if (valMapIt != valMapping.end()) {
OI->set(valMapIt->second);
}
}
}
}
removeInstructionFromLoop<StoreInstPred>(NewLoop);
removeInstructionFromLoop<ExactCheckCallPred>(NewLoop);
removeInstructionFromLoop<pred_and<CheckingCallPred, pred_not<ExactCheckCallPred> > >(L);
replaceIntrinsic(NewLoop, M);
// Insert checking calls
insertCheckingCallInLoop(L, F, checkArgumentsType, M);
return F;
}
void
DuplicateLoopAnalysis::replaceIntrinsic(Loop * L, Module * M) {
for(Loop::block_iterator BI = L->block_begin(), BE = L->block_end(); BI != BE; ++BI) {
for(BasicBlock::iterator I = (*BI)->begin(), E = (*BI)->end(); I != E; ++I) {
if (CallInst * CI = dyn_cast<CallInst>(I)) {
Function * F = CI->getCalledFunction();
if (!F || !isCheckingCall(F->getName()))
continue;
Constant * newF = M->getOrInsertFunction(F->getName().str() + ".serial" , F->getFunctionType());
CI->setOperand(0, newF);
}
}
}
}
void
DuplicateLoopAnalysis::insertCheckingCallInLoop(Loop * L, Function * checkingFunction, StructType * checkArgumentType, Module * M) {
const Type * VoidType = Type::getVoidTy(getGlobalContext());
static Constant * sFuncWaitForSyncToken =
M->getOrInsertFunction("__sc_par_wait_for_completion",
FunctionType::get
(VoidType, std::vector<const Type*>(), false));
static Constant * sFuncEnqueueCheckingFunction =
M->getOrInsertFunction("__sc_par_enqueue_code_dup",
FunctionType::get
(VoidType, args<const Type*>::list(getVoidPtrType(), getVoidPtrType()), false));
Instruction * termInst = L->getHeader()->getTerminator();
Value * allocaInst = new AllocaInst(checkArgumentType, "checkarg", &L->getHeader()->getParent()->front().front());
size_t arg_counter = 0;
for (InputArgumentsTy::const_iterator it = dupLoopArgument.begin(), end = dupLoopArgument.end(); it !=end; ++it) {
const Type * Int32Type = IntegerType::getInt32Ty(getGlobalContext());
std::vector<Value *> idxVal;
idxVal.push_back(ConstantInt::get(Int32Type, 0));
idxVal.push_back(ConstantInt::get(Int32Type, arg_counter));
GetElementPtrInst * GEP = GetElementPtrInst::Create(allocaInst, idxVal.begin(), idxVal.end(), "", termInst);
new StoreInst(*it, GEP, termInst);
++arg_counter;
}
// enqueue
std::vector<Value*> enqueueArg;
enqueueArg.push_back(new BitCastInst(checkingFunction, getVoidPtrType(), "", termInst));
enqueueArg.push_back(new BitCastInst(allocaInst, getVoidPtrType(), "", termInst));
CallInst::Create(sFuncEnqueueCheckingFunction, enqueueArg.begin(), enqueueArg.end(), "", termInst);
SmallVector<BasicBlock*, 8> exitBlocks;
L->getUniqueExitBlocks(exitBlocks);
for (SmallVector<BasicBlock*, 8>::iterator it = exitBlocks.begin(), end = exitBlocks.end(); it != end; ++it) {
CallInst::Create(sFuncWaitForSyncToken, "", &((*it)->back()));
}
/*
Function * origFunc = L->getHeader()->getParent();
for (Function::iterator it = origFunc->begin(), end = origFunc->end(); it != end; ++it) {
Instruction * TI = it->getTerminator();
if (isa<ReturnInst>(TI) || isa<UnwindInst>(TI)) {
CallInst::Create(sFuncWaitForSyncToken, "", TI);
}
}
*/
}
// Helper Function
bool isCheckingCall(const std::string & name) {
static std::string checkFuncs[] = {
"poolcheck", "poolcheckui", "poolcheckui",
"poolcheckalign", "poolcheckalignui",
"exactcheck", "exactcheck2",
"boundscheck", "boundscheckui",
"funccheck"
};
for (size_t i = 0; i < sizeof(checkFuncs) / sizeof(std::string); ++i) {
if (name == checkFuncs[i]) return true;
}
return false;
}
}