/// AddCatchInfo - Extract the personality and type infos from an eh.selector /// call, and add them to the specified machine basic block. void llvm::AddCatchInfo(CallInst &I, MachineModuleInfo *MMI, MachineBasicBlock *MBB) { // Inform the MachineModuleInfo of the personality for this landing pad. ConstantExpr *CE = cast<ConstantExpr>(I.getOperand(2)); assert(CE->getOpcode() == Instruction::BitCast && isa<Function>(CE->getOperand(0)) && "Personality should be a function"); MMI->addPersonality(MBB, cast<Function>(CE->getOperand(0))); // Gather all the type infos for this landing pad and pass them along to // MachineModuleInfo. std::vector<GlobalVariable *> TyInfo; unsigned N = I.getNumOperands(); for (unsigned i = N - 1; i > 2; --i) { if (ConstantInt *CI = dyn_cast<ConstantInt>(I.getOperand(i))) { unsigned FilterLength = CI->getZExtValue(); unsigned FirstCatch = i + FilterLength + !FilterLength; assert (FirstCatch <= N && "Invalid filter length"); if (FirstCatch < N) { TyInfo.reserve(N - FirstCatch); for (unsigned j = FirstCatch; j < N; ++j) TyInfo.push_back(ExtractTypeInfo(I.getOperand(j))); MMI->addCatchTypeInfo(MBB, TyInfo); TyInfo.clear(); } if (!FilterLength) { // Cleanup. MMI->addCleanup(MBB); } else { // Filter. TyInfo.reserve(FilterLength - 1); for (unsigned j = i + 1; j < FirstCatch; ++j) TyInfo.push_back(ExtractTypeInfo(I.getOperand(j))); MMI->addFilterTypeInfo(MBB, TyInfo); TyInfo.clear(); } N = i; } } if (N > 3) { TyInfo.reserve(N - 3); for (unsigned j = 3; j < N; ++j) TyInfo.push_back(ExtractTypeInfo(I.getOperand(j))); MMI->addCatchTypeInfo(MBB, TyInfo); } }
// Return the copied value if the value is a bs copy, otherwise null Value *getBSCopyValue(Value *v) { CallInst *call = dyn_cast<CallInst>(v); if (!call) return nullptr; // This is kind of dubious return call->getName().find(".__rmc_bs_copy") != StringRef::npos? call->getOperand(0) : nullptr; }
// // Function: makeFSParameterCallsComplete() // // Description: // Finds calls to sc.fsparameter and fills in the completeness byte which // is the last argument to such call. The second argument to the function // is the one which is analyzed for completeness. // // Inputs: // M - Reference to the the module to analyze // void CompleteChecks::makeFSParameterCallsComplete(Module &M) { Function *sc_fsparameter = M.getFunction("sc.fsparameter"); if (sc_fsparameter == NULL) return; std::set<CallInst *> toComplete; // // Iterate over all uses of sc.fsparameter and discover which have a complete // pointer argument. // for (Function::use_iterator i = sc_fsparameter->use_begin(); i != sc_fsparameter->use_end(); ++i) { CallInst *CI; CI = dyn_cast<CallInst>(*i); if (CI == 0 || CI->getCalledFunction() != sc_fsparameter) continue; // // Get the parent function to which this call belongs. // Function *P = CI->getParent()->getParent(); Value *PtrOperand = CI->getOperand(2); DSNode *N = getDSNodeHandle(PtrOperand, P).getNode(); if (N == 0 || N->isExternalNode() || N->isIncompleteNode() || N->isUnknownNode() || N->isPtrToIntNode() || N->isIntToPtrNode()) { continue; } toComplete.insert(CI); } // // Fill in a 1 for each call instruction that has a complete pointer // argument. // Type *int8 = Type::getInt8Ty(M.getContext()); Constant *complete = ConstantInt::get(int8, 1); for (std::set<CallInst *>::iterator i = toComplete.begin(); i != toComplete.end(); ++i) { CallInst *CI = *i; CI->setOperand(4, complete); } return; }
CallInst* FunctionCalls::changeFunctionCall(Module &module, Change* change) { FunctionChange *funChange = (FunctionChange*)change; CallInst *oldCallInst = dyn_cast<CallInst>(funChange->getValue()); CallInst *newCallInst = NULL; string oldFunction = oldCallInst->getCalledFunction()->getName(); string newFunction = funChange->getSwitch(); // TODO: use the types vector to not assume signature Function *newCallee = module.getFunction(newFunction); if (newCallee) { errs() << "Changing function call from " << oldFunction << " to " << newFunction << "\n"; if (oldFunction != newFunction) { // retrieving original operand Value *oldOperand = oldCallInst->getOperand(0); // downcasting operand Type *fType = Type::getFloatTy(module.getContext()); FPTruncInst *newOperand = new FPTruncInst(oldOperand, fType, "", oldCallInst); // populating array of operands vector<Value*> operands; operands.push_back(newOperand); ArrayRef<Value*> *arrayRefOperands = new ArrayRef<Value*>(operands); // creating the new CallInst newCallInst = CallInst::Create(newCallee, *arrayRefOperands, "newCall", oldCallInst); // casting result to double Type *dType = Type::getDoubleTy(module.getContext()); FPExtInst *result = new FPExtInst(newCallInst, dType, "", oldCallInst); // replacing all uses of call instruction oldCallInst->replaceAllUsesWith(result); // deleting old callInst oldCallInst->eraseFromParent(); errs() << "\tChange was successful\n"; } else { errs() << "\tNo change required\n"; } } else { errs() << "\tDid not find function " << newFunction << "\n"; } return newCallInst; }
void LLVMDefUseAnalysis::handleCallInst(LLVMNode *node) { CallInst *CI = cast<CallInst>(node->getKey()); if (CI->isInlineAsm()) { handleInlineAsm(node); return; } Function *func = dyn_cast<Function>(CI->getCalledValue()->stripPointerCasts()); if (func) { if (func->isIntrinsic() && !isa<DbgInfoIntrinsic>(CI)) { handleIntrinsicCall(node, CI); return; } // for realloc, we need to make it data dependent on the // memory it reallocates, since that is the memory it copies if (func->size() == 0) { using analysis::AllocationFunction; auto type = _options.getAllocationFunction(func->getName()); if (type == AllocationFunction::REALLOC) { addDataDependence(node, CI, CI->getOperand(0), Offset::UNKNOWN /* FIXME */); } else if (type == AllocationFunction::NONE) { handleUndefinedCall(node, CI); }// else { // we do not want to do anything for the memory // allocation functions // } // the function is undefined, so do not even try to // add the edges from return statements return; } } // add edges from the return nodes of subprocedure // to the call (if the call returns something) for (LLVMDependenceGraph *subgraph : node->getSubgraphs()) addReturnEdge(node, subgraph); }
void LLVMDefUseAnalysis::handleInlineAsm(LLVMNode *callNode) { CallInst *CI = cast<CallInst>(callNode->getValue()); LLVMDependenceGraph *dg = callNode->getDG(); // the last operand is the asm itself, so iterate only to e - 1 for (unsigned i = 0, e = CI->getNumOperands(); i < e - 1; ++i) { Value *opVal = CI->getOperand(i); if (!opVal->getType()->isPointerTy()) continue; LLVMNode *opNode = dg->getNode(opVal->stripInBoundsOffsets()); if (!opNode) { // FIXME: ConstantExpr llvmutils::printerr("WARN: unhandled inline asm operand: ", opVal); continue; } assert(opNode && "Do not have an operand for inline asm"); // if nothing else, this call at least uses the operands opNode->addDataDependence(callNode); } }
void visitCallInst(CallInst &I) { string intrinsic = I.getCalledFunction()->getName().str(); if(intrinsic.find("modmul") != -1) { CallInst *enterMontpro1 = enterMontgomery(I.getOperand(0), I.getOperand(2), &I); CallInst *enterMontpro2 = enterMontgomery(I.getOperand(1), I.getOperand(2), &I); CallInst *mulMontpro = mulMontgomery(I.getName().str(), enterMontpro1, enterMontpro2, I.getOperand(2), &I); CallInst *exitMontpro = leaveMontgomery(mulMontpro, I.getOperand(2), &I); I.replaceAllUsesWith(exitMontpro); I.removeFromParent(); } else if(intrinsic.find("modexp") != -1) { CallInst *enterMontpro1 = enterMontgomery(I.getOperand(0), I.getOperand(2), &I); CallInst *expMontpro = expMontgomery(I.getName().str(), enterMontpro1, I.getOperand(1), I.getOperand(2), &I); CallInst *exitMontpro = leaveMontgomery(expMontpro, I.getOperand(2), &I); I.replaceAllUsesWith(exitMontpro); I.eraseFromParent(); } }
// // Function: makeCStdLibCallsComplete() // // Description: // Fills in completeness information for all calls of a given CStdLib function // assumed to be of the form: // // pool_X(POOL *p1, ..., POOL *pN, void *a1, ..., void *aN, ..., uint8_t c); // // Specifically, this function assumes that there are as many pointer arguments // to check as there are initial pool arguments, and the pointer arguments // follow the pool arguments in corresponding order. Also, it is assumed that // the final argument to the function is a byte sized bit vector. // // This function fills in this final byte with a constant value whose ith // bit is set exactly when the ith pointer argument is complete. // // Inputs: // // F - A pointer to the CStdLib function appearing in the module // (non-null). // PoolArgs - The number of initial pool arguments for which a // corresponding pointer value requires a completeness check // (required to be at most 8). // void CompleteChecks::makeCStdLibCallsComplete(Function *F, unsigned PoolArgs) { assert(F != 0 && "Null function argument!"); assert(PoolArgs <= 8 && \ "Only up to 8 arguments are supported by CStdLib completeness checks!"); Value::use_iterator U = F->use_begin(); Value::use_iterator E = F->use_end(); // // Hold the call instructions that need changing. // typedef std::pair<CallInst *, uint8_t> VectorReplacement; std::set<VectorReplacement> callsToChange; Type *int8ty = Type::getInt8Ty(F->getContext()); FunctionType *F_type = F->getFunctionType(); // // Verify the type of the function is as expected. // // There should be as many pointer parameters to check for completeness // as there are pool parameters. The last parameter should be a byte. // assert(F_type->getNumParams() >= PoolArgs * 2 && \ "Not enough arguments to transformed CStdLib function call!"); for (unsigned arg = PoolArgs; arg < PoolArgs * 2; ++arg) assert(isa<PointerType>(F_type->getParamType(arg)) && \ "Expected pointer argument to function!"); // // This is the position of the vector operand in the call. // unsigned vect_position = F_type->getNumParams(); assert(F_type->getParamType(vect_position - 1) == int8ty && \ "Last parameter to the function should be a byte!"); // // Iterate over all calls of the function in the module, computing the // vectors for each call as it is found. // for (; U != E; ++U) { CallInst *CI; if ((CI = dyn_cast<CallInst>(*U)) && \ CI->getCalledValue()->stripPointerCasts() == F) { uint8_t vector = 0x0; // // Get the parent function to which this instruction belongs. // Function *P = CI->getParent()->getParent(); // // Iterate over the pointer arguments that need completeness checking // and build the completeness vector. // for (unsigned arg = 0; arg < PoolArgs; ++arg) { bool complete = true; // // Go past all the pool arguments to get the pointer to check. // Value *V = CI->getOperand(1 + PoolArgs + arg); // // Check for completeness of the pointer using DSA and // set the bit in the vector accordingly. // DSNode *N; if ((N = getDSNodeHandle(V, P).getNode()) && (N->isExternalNode() || N->isIncompleteNode() || N->isUnknownNode() || N->isIntToPtrNode() || N->isPtrToIntNode()) ) { complete = false; } if (complete) vector |= (1 << arg); } // // Add the instruction and vector to the set of instructions to change. // callsToChange.insert(VectorReplacement(CI, vector)); } } // // Iterate over all call instructions that need changing, modifying the // final operand of the call to hold the bit vector value. // std::set<VectorReplacement>::iterator change = callsToChange.begin(); std::set<VectorReplacement>::iterator change_end = callsToChange.end(); while (change != change_end) { Constant *vect_value = ConstantInt::get(int8ty, change->second); change->first->setOperand(vect_position, vect_value); ++change; } return; }
// // Method: runOnModule() // // Description: // Entry point for this LLVM pass. // Clone functions that take GEPs as arguments // // Inputs: // M - A reference to the LLVM module to transform // // Outputs: // M - The transformed LLVM module. // // Return value: // true - The module was modified. // false - The module was not modified. // bool GEPExprArgs::runOnModule(Module& M) { bool changed; do { changed = false; for (Module::iterator F = M.begin(); F != M.end(); ++F){ for (Function::iterator B = F->begin(), FE = F->end(); B != FE; ++B) { for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { CallInst *CI = dyn_cast<CallInst>(I++); if(!CI) continue; if(CI->hasByValArgument()) continue; // if the GEP calls a function, that is externally defined, // or might be changed, ignore this call site. Function *F = CI->getCalledFunction(); if (!F || (F->isDeclaration() || F->mayBeOverridden())) continue; if(F->hasStructRetAttr()) continue; if(F->isVarArg()) continue; // find the argument we must replace Function::arg_iterator ai = F->arg_begin(), ae = F->arg_end(); unsigned argNum = 1; for(; argNum < CI->getNumOperands();argNum++, ++ai) { if(ai->use_empty()) continue; if (isa<GEPOperator>(CI->getOperand(argNum))) break; } // if no argument was a GEP operator to be changed if(ai == ae) continue; GEPOperator *GEP = dyn_cast<GEPOperator>(CI->getOperand(argNum)); if(!GEP->hasAllConstantIndices()) continue; // Construct the new Type // Appends the struct Type at the beginning std::vector<Type*>TP; TP.push_back(GEP->getPointerOperand()->getType()); for(unsigned c = 1; c < CI->getNumOperands();c++) { TP.push_back(CI->getOperand(c)->getType()); } //return type is same as that of original instruction FunctionType *NewFTy = FunctionType::get(CI->getType(), TP, false); Function *NewF; numSimplified++; if(numSimplified > 800) return true; NewF = Function::Create(NewFTy, GlobalValue::InternalLinkage, F->getName().str() + ".TEST", &M); Function::arg_iterator NI = NewF->arg_begin(); NI->setName("GEParg"); ++NI; ValueToValueMapTy ValueMap; for (Function::arg_iterator II = F->arg_begin(); NI != NewF->arg_end(); ++II, ++NI) { ValueMap[II] = NI; NI->setName(II->getName()); NI->addAttr(F->getAttributes().getParamAttributes(II->getArgNo() + 1)); } NewF->setAttributes(NewF->getAttributes().addAttr( 0, F->getAttributes().getRetAttributes())); // Perform the cloning. SmallVector<ReturnInst*,100> Returns; CloneFunctionInto(NewF, F, ValueMap, false, Returns); std::vector<Value*> fargs; for(Function::arg_iterator ai = NewF->arg_begin(), ae= NewF->arg_end(); ai != ae; ++ai) { fargs.push_back(ai); } NewF->setAttributes(NewF->getAttributes().addAttr( ~0, F->getAttributes().getFnAttributes())); //Get the point to insert the GEP instr. SmallVector<Value*, 8> Ops(CI->op_begin()+1, CI->op_end()); Instruction *InsertPoint; for (BasicBlock::iterator insrt = NewF->front().begin(); isa<AllocaInst>(InsertPoint = insrt); ++insrt) {;} NI = NewF->arg_begin(); SmallVector<Value*, 8> Indices; Indices.append(GEP->op_begin()+1, GEP->op_end()); GetElementPtrInst *GEP_new = GetElementPtrInst::Create(cast<Value>(NI), Indices, "", InsertPoint); fargs.at(argNum)->replaceAllUsesWith(GEP_new); unsigned j = argNum + 1; for(; j < CI->getNumOperands();j++) { if(CI->getOperand(j) == GEP) fargs.at(j)->replaceAllUsesWith(GEP_new); } SmallVector<AttributeWithIndex, 8> AttributesVec; // Get the initial attributes of the call AttrListPtr CallPAL = CI->getAttributes(); Attributes RAttrs = CallPAL.getRetAttributes(); Attributes FnAttrs = CallPAL.getFnAttributes(); if (RAttrs) AttributesVec.push_back(AttributeWithIndex::get(0, RAttrs)); SmallVector<Value*, 8> Args; Args.push_back(GEP->getPointerOperand()); for(unsigned j =1;j<CI->getNumOperands();j++) { Args.push_back(CI->getOperand(j)); // position in the AttributesVec if (Attributes Attrs = CallPAL.getParamAttributes(j)) AttributesVec.push_back(AttributeWithIndex::get(Args.size(), Attrs)); } // Create the new attributes vec. if (FnAttrs != Attribute::None) AttributesVec.push_back(AttributeWithIndex::get(~0, FnAttrs)); AttrListPtr NewCallPAL = AttrListPtr::get(AttributesVec.begin(), AttributesVec.end()); CallInst *CallI = CallInst::Create(NewF,Args,"", CI); CallI->setCallingConv(CI->getCallingConv()); CallI->setAttributes(NewCallPAL); CI->replaceAllUsesWith(CallI); CI->eraseFromParent(); changed = true; } } } } while(changed); return true; }
void TracingNoGiri::visitCallInst(CallInst &CI) { // Attempt to get the called function. Function *CalledFunc = CI.getCalledFunction(); if (!CalledFunc) return; // Do not instrument calls to tracing run-time functions or debug functions. if (isTracerFunction(CalledFunc)) return; if (!CalledFunc->getName().str().compare(0,9,"llvm.dbg.")) return; // Instrument external calls which can have invariants on its return value if (CalledFunc->isDeclaration() && CalledFunc->isIntrinsic()) { // Instrument special external calls which loads/stores // e.g. strlen(), strcpy(), memcpy() etc. visitSpecialCall(CI); return; } // If the called value is inline assembly code, then don't instrument it. if (isa<InlineAsm>(CI.getCalledValue()->stripPointerCasts())) return; instrumentLock(&CI); // Get the ID of the store instruction. Value *CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); // Get the called function value and cast it to a void pointer. Value *FP = castTo(CI.getCalledValue(), VoidPtrType, "", &CI); // Create the call to the run-time to record the call instruction. std::vector<Value *> args = make_vector<Value *>(CallID, FP, 0); // Do not add calls to function call stack for external functions // as return records won't be used/needed for them, so call a special record function // FIXME!!!! Do we still need it after adding separate return records???? Instruction *RC; if (CalledFunc->isDeclaration()) RC = CallInst::Create(RecordExtCall, args, "", &CI); else RC = CallInst::Create(RecordCall, args, "", &CI); instrumentUnlock(RC); // Create the call to the run-time to record the return of call instruction. CallInst *CallInst = CallInst::Create(RecordReturn, args, "", &CI); CI.moveBefore(CallInst); instrumentLock(CallInst); instrumentUnlock(CallInst); ++NumCalls; // Update statistics // The best way to handle external call is to set a flag before calling ext fn and // use that to determine if an internal function is called from ext fn. It flag can be // reset afterwards and restored to its original value before returning to ext code. // FIXME!!!! LATER #if 0 if (CalledFunc->isDeclaration() && CalledFunc->getName().str() == "pthread_create") { // If pthread_create is called then handle it specially as it calls // functions externally and add an extra call for the externally // called functions with the same id so that returns can match with it. // In addition to a function call to pthread_create. // Get the external function pointer operand and cast it to a void pointer Value *FP = castTo(CI.getOperand(2), VoidPtrType, "", &CI); // Create the call to the run-time to record the call instruction. std::vector<Value *> argsExt = make_vector<Value *>(CallID, FP, 0); CallInst = CallInst::Create(RecordCall, argsExt, "", &CI); CI.moveBefore(CallInst); // Update statistics ++Calls; // For, both external functions and internal/ext functions called from // external functions, return records are not useful as they won't be used. // Since, we won't create return records for them, simply update the call // stack to mark the end of function call. //args = make_vector<Value *>(CallID, FP, 0); //CallInst::Create(RecordExtCallRet, args.begin(), args.end(), "", &CI); // Create the call to the run-time to record the return of call instruction. CallInst::Create(RecordReturn, argsExt, "", &CI); } #endif // Instrument special external calls which loads/stores // like strlen, strcpy, memcpy etc. visitSpecialCall(CI); }
bool TracingNoGiri::visitSpecialCall(CallInst &CI) { Function *CalledFunc = CI.getCalledFunction(); // We do not support indirect calls to special functions. if (CalledFunc == nullptr) return false; // Do not consider a function special if it has a function body; in this // case, the programmer has supplied his or her version of the function, and // we will instrument it. if (!CalledFunc->isDeclaration()) return false; // Check the name of the function against a list of known special functions. std::string name = CalledFunc->getName().str(); if (name.substr(0,12) == "llvm.memset.") { instrumentLock(&CI); // Get the destination pointer and cast it to a void pointer. Value *dstPointer = CI.getOperand(0); dstPointer = castTo(dstPointer, VoidPtrType, dstPointer->getName(), &CI); // Get the number of bytes that will be written into the buffer. Value *NumElts = CI.getOperand(2); // Get the ID of the external funtion call instruction. Value *CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); // Create the call to the run-time to record the external call instruction. std::vector<Value *> args = make_vector(CallID, dstPointer, NumElts, 0); CallInst::Create(RecordStore, args, "", &CI); instrumentUnlock(&CI); ++NumExtFuns; // Update statistics return true; } else if (name.substr(0,12) == "llvm.memcpy." || name.substr(0,13) == "llvm.memmove." || name == "strcpy") { instrumentLock(&CI); /* Record Load src, [CI] Load dst [CI] */ // Get the destination and source pointers and cast them to void pointers. Value *dstPointer = CI.getOperand(0); Value *srcPointer = CI.getOperand(1); dstPointer = castTo(dstPointer, VoidPtrType, dstPointer->getName(), &CI); srcPointer = castTo(srcPointer, VoidPtrType, srcPointer->getName(), &CI); // Get the ID of the ext fun call instruction. Value *CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); // Create the call to the run-time to record the loads and stores of // external call instruction. if(name == "strcpy") { // FIXME: If the tracer function should be inserted before or after???? std::vector<Value *> args = make_vector(CallID, srcPointer, 0); CallInst::Create(RecordStrLoad, args, "", &CI); args = make_vector(CallID, dstPointer, 0); CallInst *recStore = CallInst::Create(RecordStrStore, args, "", &CI); CI.moveBefore(recStore); } else { // get the num elements to be transfered Value *NumElts = CI.getOperand(2); std::vector<Value *> args = make_vector(CallID, srcPointer, NumElts, 0); CallInst::Create(RecordLoad, args, "", &CI); args = make_vector(CallID, dstPointer, NumElts, 0); CallInst::Create(RecordStore, args, "", &CI); } instrumentUnlock(&CI); ++NumExtFuns; // Update statistics return true; } else if (name == "strcat") { /* Record Load dst, Load Src, Store dst-end before call inst */ instrumentLock(&CI); // Get the destination and source pointers and cast them to void pointers. Value *dstPointer = CI.getOperand(0); Value *srcPointer = CI.getOperand(1); dstPointer = castTo(dstPointer, VoidPtrType, dstPointer->getName(), &CI); srcPointer = castTo(srcPointer, VoidPtrType, srcPointer->getName(), &CI); // Get the ID of the ext fun call instruction. Value *CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); // Create the call to the run-time to record the loads and stores of // external call instruction. // CHECK: If the tracer function should be inserted before or after???? std::vector<Value *> args = make_vector(CallID, dstPointer, 0); CallInst::Create(RecordStrLoad, args, "", &CI); args = make_vector(CallID, srcPointer, 0); CallInst::Create(RecordStrLoad, args, "", &CI); // Record the addresses before concat as they will be lost after concat args = make_vector(CallID, dstPointer, srcPointer, 0); CallInst::Create(RecordStrcatStore, args, "", &CI); instrumentUnlock(&CI); ++NumExtFuns; // Update statistics return true; } else if (name == "strlen") { /* Record Load */ instrumentLock(&CI); // Get the destination and source pointers and cast them to void pointers. Value *srcPointer = CI.getOperand(0); srcPointer = castTo(srcPointer, VoidPtrType, srcPointer->getName(), &CI); // Get the ID of the ext fun call instruction. Value *CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); std::vector<Value *> args = make_vector(CallID, srcPointer, 0); CallInst::Create(RecordStrLoad, args, "", &CI); instrumentUnlock(&CI); ++NumExtFuns; // Update statistics return true; } else if (name == "calloc") { instrumentLock(&CI); // Get the number of bytes that will be written into the buffer. Value *NumElts = BinaryOperator::Create(BinaryOperator::Mul, CI.getOperand(0), CI.getOperand(1), "calloc par1 * par2", &CI); // Get the destination pointer and cast it to a void pointer. // Instruction * dstPointerInst; Value *dstPointer = castTo(&CI, VoidPtrType, CI.getName(), &CI); /* // To move after call inst, we need to know if cast is a constant expr or inst if ((dstPointerInst = dyn_cast<Instruction>(dstPointer))) { CI.moveBefore(dstPointerInst); // dstPointerInst->insertAfter(&CI); // ((Instruction *)NumElts)->insertAfter(dstPointerInst); } else { CI.moveBefore((Instruction *)NumElts); // ((Instruction *)NumElts)->insertAfter(&CI); } dstPointer = dstPointerInst; // Assign to dstPointer for instrn or non-instrn values */ // Get the ID of the external funtion call instruction. Value *CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); // // Create the call to the run-time to record the external call instruction. // std::vector<Value *> args = make_vector(CallID, dstPointer, NumElts, 0); CallInst *recStore = CallInst::Create(RecordStore, args, "", &CI); CI.moveBefore(recStore); //recStore->insertAfter((Instruction *)NumElts); // Moove cast, #byte computation and store to after call inst CI.moveBefore(cast<Instruction>(NumElts)); instrumentUnlock(&CI); ++NumExtFuns; // Update statistics return true; } else if (name == "tolower" || name == "toupper") { // Not needed as there are no loads and stores /* } else if (name == "strncpy/itoa/stdarg/scanf/fscanf/sscanf/fread/complex/strftime/strptime/asctime/ctime") { */ } else if (name == "fscanf") { // TODO // In stead of parsing format string, can we use the type of the arguments?? } else if (name == "sscanf") { // TODO } else if (name == "sprintf") { instrumentLock(&CI); // Get the pointer to the destination buffer. Value *dstPointer = CI.getOperand(0); dstPointer = castTo(dstPointer, VoidPtrType, dstPointer->getName(), &CI); // Get the ID of the call instruction. Value *CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); // Scan through the arguments looking for what appears to be a character // string. Generate load records for each of these strings. for (unsigned index = 2; index < CI.getNumOperands(); ++index) { if (CI.getOperand(index)->getType() == VoidPtrType) { // Create the call to the run-time to record the load from the string. // What about other loads?? Value *Ptr = CI.getOperand(index); std::vector<Value *> args = make_vector(CallID, Ptr, 0); CallInst::Create(RecordStrLoad, args, "", &CI); ++NumLoadStrings; // Update statistics } } // Create the call to the run-time to record the external call instruction. std::vector<Value *> args = make_vector(CallID, dstPointer, 0); CallInst *recStore = CallInst::Create(RecordStrStore, args, "", &CI); CI.moveBefore(recStore); instrumentUnlock(&CI); ++NumStoreStrings; // Update statistics return true; } else if (name == "fgets") { instrumentLock(&CI); // Get the pointer to the destination buffer. Value * dstPointer = CI.getOperand(0); dstPointer = castTo(dstPointer, VoidPtrType, dstPointer->getName(), &CI); // Get the ID of the ext fun call instruction. Value * CallID = ConstantInt::get(Int32Type, lsNumPass->getID(&CI)); // Create the call to the run-time to record the external call instruction. std::vector<Value *> args = make_vector(CallID, dstPointer, 0); CallInst *recStore = CallInst::Create(RecordStrStore, args, "", &CI); CI.moveBefore(recStore); instrumentUnlock(&CI); // Update statistics ++NumStoreStrings; return true; } return false; }
// // Method: runOnModule() // // Description: // Entry point for this LLVM pass. // Search for all call sites to casted functions. // Check if they only differ in an argument type // Cast the argument, and call the original function // // Inputs: // M - A reference to the LLVM module to transform // // Outputs: // M - The transformed LLVM module. // // Return value: // true - The module was modified. // false - The module was not modified. // bool ArgCast::runOnModule(Module& M) { std::vector<CallInst*> worklist; for (Module::iterator I = M.begin(); I != M.end(); ++I) { if (I->mayBeOverridden()) continue; // Find all uses of this function for(Value::user_iterator ui = I->user_begin(), ue = I->user_end(); ui != ue; ) { // check if is ever casted to a different function type ConstantExpr *CE = dyn_cast<ConstantExpr>(*ui++); if(!CE) continue; if (CE->getOpcode() != Instruction::BitCast) continue; if(CE->getOperand(0) != I) continue; const PointerType *PTy = dyn_cast<PointerType>(CE->getType()); if (!PTy) continue; const Type *ETy = PTy->getElementType(); const FunctionType *FTy = dyn_cast<FunctionType>(ETy); if(!FTy) continue; // casting to a varargs funtion // or function with same number of arguments // possibly varying types of arguments if(FTy->getNumParams() != I->arg_size() && !FTy->isVarArg()) continue; for(Value::user_iterator uii = CE->user_begin(), uee = CE->user_end(); uii != uee; ++uii) { // Find all uses of the casted value, and check if it is // used in a Call Instruction if (CallInst* CI = dyn_cast<CallInst>(*uii)) { // Check that it is the called value, and not an argument if(CI->getCalledValue() != CE) continue; // Check that the number of arguments passed, and expected // by the function are the same. if(!I->isVarArg()) { if(CI->getNumOperands() != I->arg_size() + 1) continue; } else { if(CI->getNumOperands() < I->arg_size() + 1) continue; } // If so, add to worklist worklist.push_back(CI); } } } } // Proces the worklist of potential call sites to transform while(!worklist.empty()) { CallInst *CI = worklist.back(); worklist.pop_back(); // Get the called Function Function *F = cast<Function>(CI->getCalledValue()->stripPointerCasts()); const FunctionType *FTy = F->getFunctionType(); SmallVector<Value*, 8> Args; unsigned i =0; for(i =0; i< FTy->getNumParams(); ++i) { Type *ArgType = CI->getOperand(i+1)->getType(); Type *FormalType = FTy->getParamType(i); // If the types for this argument match, just add it to the // parameter list. No cast needs to be inserted. if(ArgType == FormalType) { Args.push_back(CI->getOperand(i+1)); } else if(ArgType->isPointerTy() && FormalType->isPointerTy()) { CastInst *CastI = CastInst::CreatePointerCast(CI->getOperand(i+1), FormalType, "", CI); Args.push_back(CastI); } else if (ArgType->isIntegerTy() && FormalType->isIntegerTy()) { unsigned SrcBits = ArgType->getScalarSizeInBits(); unsigned DstBits = FormalType->getScalarSizeInBits(); if(SrcBits > DstBits) { CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), FormalType, true, "", CI); Args.push_back(CastI); } else { if (F->getAttributes().hasAttribute(i+1, Attribute::SExt)) { CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), FormalType, true, "", CI); Args.push_back(CastI); } else if (F->getAttributes().hasAttribute(i+1, Attribute::ZExt)) { CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), FormalType, false, "", CI); Args.push_back(CastI); } else { // Use ZExt in default case. // Derived from InstCombine. Also, the only reason this should happen // is mismatched prototypes. // Seen in case of integer constants which get interpreted as i32, // even if being used as i64. // TODO: is this correct? CastInst *CastI = CastInst::CreateIntegerCast(CI->getOperand(i+1), FormalType, false, "", CI); Args.push_back(CastI); } } } else { DEBUG(ArgType->dump()); DEBUG(FormalType->dump()); break; } } // If we found an argument we could not cast, try the next instruction if(i != FTy->getNumParams()) { continue; } if(FTy->isVarArg()) { for(; i< CI->getNumOperands() - 1 ;i++) { Args.push_back(CI->getOperand(i+1)); } } // else replace the call instruction CallInst *CINew = CallInst::Create(F, Args, "", CI); CINew->setCallingConv(CI->getCallingConv()); CINew->setAttributes(CI->getAttributes()); if(!CI->use_empty()) { CastInst *RetCast; if(CI->getType() != CINew->getType()) { if(CI->getType()->isPointerTy() && CINew->getType()->isPointerTy()) RetCast = CastInst::CreatePointerCast(CINew, CI->getType(), "", CI); else if(CI->getType()->isIntOrIntVectorTy() && CINew->getType()->isIntOrIntVectorTy()) RetCast = CastInst::CreateIntegerCast(CINew, CI->getType(), false, "", CI); else if(CI->getType()->isIntOrIntVectorTy() && CINew->getType()->isPointerTy()) RetCast = CastInst::CreatePointerCast(CINew, CI->getType(), "", CI); else if(CI->getType()->isPointerTy() && CINew->getType()->isIntOrIntVectorTy()) RetCast = new IntToPtrInst(CINew, CI->getType(), "", CI); else { // TODO: I'm not sure what right behavior is here, but this case should be handled. llvm_unreachable("Unexpected type conversion in call!"); abort(); } CI->replaceAllUsesWith(RetCast); } else { CI->replaceAllUsesWith(CINew); } } // Debug printing DEBUG(errs() << "ARGCAST:"); DEBUG(errs() << "ERASE:"); DEBUG(CI->dump()); DEBUG(errs() << "ARGCAST:"); DEBUG(errs() << "ADDED:"); DEBUG(CINew->dump()); CI->eraseFromParent(); numChanged++; } return true; }
// // Method: runOnModule() // // Description: // Entry point for this LLVM pass. // If a function returns a struct, make it return // a pointer to the struct. // // Inputs: // M - A reference to the LLVM module to transform // // Outputs: // M - The transformed LLVM module. // // Return value: // true - The module was modified. // false - The module was not modified. // bool StructRet::runOnModule(Module& M) { const llvm::DataLayout targetData(&M); std::vector<Function*> worklist; for (Module::iterator I = M.begin(); I != M.end(); ++I) if (!I->mayBeOverridden()) { if(I->hasAddressTaken()) continue; if(I->getReturnType()->isStructTy()) { worklist.push_back(I); } } while(!worklist.empty()) { Function *F = worklist.back(); worklist.pop_back(); Type *NewArgType = F->getReturnType()->getPointerTo(); // Construct the new Type std::vector<Type*>TP; TP.push_back(NewArgType); for (Function::arg_iterator ii = F->arg_begin(), ee = F->arg_end(); ii != ee; ++ii) { TP.push_back(ii->getType()); } FunctionType *NFTy = FunctionType::get(F->getReturnType(), TP, F->isVarArg()); // Create the new function body and insert it into the module. Function *NF = Function::Create(NFTy, F->getLinkage(), F->getName(), &M); ValueToValueMapTy ValueMap; Function::arg_iterator NI = NF->arg_begin(); NI->setName("ret"); ++NI; for (Function::arg_iterator II = F->arg_begin(); II != F->arg_end(); ++II, ++NI) { ValueMap[II] = NI; NI->setName(II->getName()); AttributeSet attrs = F->getAttributes().getParamAttributes(II->getArgNo() + 1); if (!attrs.isEmpty()) NI->addAttr(attrs); } // Perform the cloning. SmallVector<ReturnInst*,100> Returns; if (!F->isDeclaration()) CloneFunctionInto(NF, F, ValueMap, false, Returns); std::vector<Value*> fargs; for(Function::arg_iterator ai = NF->arg_begin(), ae= NF->arg_end(); ai != ae; ++ai) { fargs.push_back(ai); } NF->setAttributes(NF->getAttributes().addAttributes( M.getContext(), 0, F->getAttributes().getRetAttributes())); NF->setAttributes(NF->getAttributes().addAttributes( M.getContext(), ~0, F->getAttributes().getFnAttributes())); for (Function::iterator B = NF->begin(), FE = NF->end(); B != FE; ++B) { for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;) { ReturnInst * RI = dyn_cast<ReturnInst>(I++); if(!RI) continue; LoadInst *LI = dyn_cast<LoadInst>(RI->getOperand(0)); assert(LI && "Return should be preceded by a load instruction"); IRBuilder<> Builder(RI); Builder.CreateMemCpy(fargs.at(0), LI->getPointerOperand(), targetData.getTypeStoreSize(LI->getType()), targetData.getPrefTypeAlignment(LI->getType())); } } for(Value::use_iterator ui = F->use_begin(), ue = F->use_end(); ui != ue; ) { CallInst *CI = dyn_cast<CallInst>(*ui++); if(!CI) continue; if(CI->getCalledFunction() != F) continue; if(CI->hasByValArgument()) continue; AllocaInst *AllocaNew = new AllocaInst(F->getReturnType(), 0, "", CI); SmallVector<Value*, 8> Args; //this should probably be done in a different manner AttributeSet NewCallPAL=AttributeSet(); // Get the initial attributes of the call AttributeSet CallPAL = CI->getAttributes(); AttributeSet RAttrs = CallPAL.getRetAttributes(); AttributeSet FnAttrs = CallPAL.getFnAttributes(); if (!RAttrs.isEmpty()) NewCallPAL=NewCallPAL.addAttributes(F->getContext(),0, RAttrs); Args.push_back(AllocaNew); for(unsigned j = 0; j < CI->getNumOperands()-1; j++) { Args.push_back(CI->getOperand(j)); // position in the NewCallPAL AttributeSet Attrs = CallPAL.getParamAttributes(j); if (!Attrs.isEmpty()) NewCallPAL=NewCallPAL.addAttributes(F->getContext(),Args.size(), Attrs); } // Create the new attributes vec. if (!FnAttrs.isEmpty()) NewCallPAL=NewCallPAL.addAttributes(F->getContext(),~0, FnAttrs); CallInst *CallI = CallInst::Create(NF, Args, "", CI); CallI->setCallingConv(CI->getCallingConv()); CallI->setAttributes(NewCallPAL); LoadInst *LI = new LoadInst(AllocaNew, "", CI); CI->replaceAllUsesWith(LI); CI->eraseFromParent(); } if(F->use_empty()) F->eraseFromParent(); } return true; }
bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID) { unsigned Op = 0; switch (ID) { default: return false; case Intrinsic::uadd_with_overflow: Op = TargetOpcode::G_UADDE; break; case Intrinsic::sadd_with_overflow: Op = TargetOpcode::G_SADDO; break; case Intrinsic::usub_with_overflow: Op = TargetOpcode::G_USUBE; break; case Intrinsic::ssub_with_overflow: Op = TargetOpcode::G_SSUBO; break; case Intrinsic::umul_with_overflow: Op = TargetOpcode::G_UMULO; break; case Intrinsic::smul_with_overflow: Op = TargetOpcode::G_SMULO; break; case Intrinsic::memcpy: return translateMemcpy(CI); case Intrinsic::eh_typeid_for: { GlobalValue *GV = ExtractTypeInfo(CI.getArgOperand(0)); unsigned Reg = getOrCreateVReg(CI); unsigned TypeID = MIRBuilder.getMF().getMMI().getTypeIDFor(GV); MIRBuilder.buildConstant(Reg, TypeID); return true; } case Intrinsic::objectsize: { // If we don't know by now, we're never going to know. const ConstantInt *Min = cast<ConstantInt>(CI.getArgOperand(1)); MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0); return true; } case Intrinsic::stackguard: getStackGuard(getOrCreateVReg(CI)); return true; case Intrinsic::stackprotector: { MachineFunction &MF = MIRBuilder.getMF(); LLT PtrTy{*CI.getArgOperand(0)->getType(), *DL}; unsigned GuardVal = MRI->createGenericVirtualRegister(PtrTy); getStackGuard(GuardVal); AllocaInst *Slot = cast<AllocaInst>(CI.getArgOperand(1)); MIRBuilder.buildStore( GuardVal, getOrCreateVReg(*Slot), *MF.getMachineMemOperand( MachinePointerInfo::getFixedStack(MF, getOrCreateFrameIndex(*Slot)), MachineMemOperand::MOStore | MachineMemOperand::MOVolatile, PtrTy.getSizeInBits() / 8, 8)); return true; } } LLT Ty{*CI.getOperand(0)->getType(), *DL}; LLT s1 = LLT::scalar(1); unsigned Width = Ty.getSizeInBits(); unsigned Res = MRI->createGenericVirtualRegister(Ty); unsigned Overflow = MRI->createGenericVirtualRegister(s1); auto MIB = MIRBuilder.buildInstr(Op) .addDef(Res) .addDef(Overflow) .addUse(getOrCreateVReg(*CI.getOperand(0))) .addUse(getOrCreateVReg(*CI.getOperand(1))); if (Op == TargetOpcode::G_UADDE || Op == TargetOpcode::G_USUBE) { unsigned Zero = MRI->createGenericVirtualRegister(s1); EntryBuilder.buildConstant(Zero, 0); MIB.addUse(Zero); } MIRBuilder.buildSequence(getOrCreateVReg(CI), Res, 0, Overflow, Width); return true; }
bool TypeChecksOpt::runOnModule(Module &M) { TS = &getAnalysis<dsa::TypeSafety<TDDataStructures> >(); // Create the necessary prototypes VoidTy = IntegerType::getVoidTy(M.getContext()); Int8Ty = IntegerType::getInt8Ty(M.getContext()); Int32Ty = IntegerType::getInt32Ty(M.getContext()); Int64Ty = IntegerType::getInt64Ty(M.getContext()); VoidPtrTy = PointerType::getUnqual(Int8Ty); TypeTagTy = Int8Ty; TypeTagPtrTy = PointerType::getUnqual(TypeTagTy); Constant *memsetF = M.getOrInsertFunction ("llvm.memset.i64", VoidTy, VoidPtrTy, Int8Ty, Int64Ty, Int32Ty, NULL); trackGlobal = M.getOrInsertFunction("trackGlobal", VoidTy, VoidPtrTy,/*ptr*/ TypeTagTy,/*type*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackInitInst = M.getOrInsertFunction("trackInitInst", VoidTy, VoidPtrTy,/*ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackUnInitInst = M.getOrInsertFunction("trackUnInitInst", VoidTy, VoidPtrTy,/*ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); trackStoreInst = M.getOrInsertFunction("trackStoreInst", VoidTy, VoidPtrTy,/*ptr*/ TypeTagTy,/*type*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); checkTypeInst = M.getOrInsertFunction("checkType", VoidTy, TypeTagTy,/*type*/ Int64Ty,/*size*/ TypeTagPtrTy, VoidPtrTy,/*ptr*/ Int32Ty,/*tag*/ NULL); copyTypeInfo = M.getOrInsertFunction("copyTypeInfo", VoidTy, VoidPtrTy,/*dest ptr*/ VoidPtrTy,/*src ptr*/ Int64Ty,/*size*/ Int32Ty,/*tag*/ NULL); setTypeInfo = M.getOrInsertFunction("setTypeInfo", VoidTy, VoidPtrTy,/*dest ptr*/ TypeTagPtrTy,/*metadata*/ Int64Ty,/*size*/ TypeTagTy, VoidPtrTy, Int32Ty,/*tag*/ NULL); trackStringInput = M.getOrInsertFunction("trackStringInput", VoidTy, VoidPtrTy, Int32Ty, NULL); getTypeTag = M.getOrInsertFunction("getTypeTag", VoidTy, VoidPtrTy, /*ptr*/ Int64Ty, /*size*/ TypeTagPtrTy, /*dest for type tag*/ Int32Ty, /*tag*/ NULL); MallocFunc = M.getFunction("malloc"); for(Value::use_iterator User = trackGlobal->use_begin(); User != trackGlobal->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*>Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); Args.push_back(CI->getOperand(4)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = checkTypeInst->use_begin(); User != checkTypeInst->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(4)->stripPointerCasts(), CI->getParent()->getParent())) { toDelete.push_back(CI); } } for(Value::use_iterator User = trackStoreInst->use_begin(); User != trackStoreInst->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { toDelete.push_back(CI); } } // for alloca's if they are type known // assume initialized with TOP for(Value::use_iterator User = trackUnInitInst->use_begin(); User != trackUnInitInst->use_end(); ) { CallInst *CI = dyn_cast<CallInst>(*(User++)); assert(CI); // check if operand is an alloca inst. if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { CI->setCalledFunction(trackInitInst); if(AllocaInst *AI = dyn_cast<AllocaInst>(CI->getOperand(1)->stripPointerCasts())) { // Initialize the allocation to NULL std::vector<Value *> Args2; Args2.push_back(CI->getOperand(1)); Args2.push_back(ConstantInt::get(Int8Ty, 0)); Args2.push_back(CI->getOperand(2)); Args2.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); CallInst::Create(memsetF, Args2, "", CI); } } } if(MallocFunc) { for(Value::use_iterator User = MallocFunc->use_begin(); User != MallocFunc->use_end(); User ++) { CallInst *CI = dyn_cast<CallInst>(*User); if(!CI) continue; if(TS->isTypeSafe(CI, CI->getParent()->getParent())){ CastInst *BCI = BitCastInst::CreatePointerCast(CI, VoidPtrTy); CastInst *Size = CastInst::CreateSExtOrBitCast(CI->getOperand(1), Int64Ty); Size->insertAfter(CI); BCI->insertAfter(Size); std::vector<Value *>Args; Args.push_back(BCI); Args.push_back(Size); Args.push_back(ConstantInt::get(Int32Ty, 0)); CallInst *CINew = CallInst::Create(trackInitInst, Args); CINew->insertAfter(BCI); } } } // also do for mallocs/calloc/other allocators??? // other allocators?? for(Value::use_iterator User = copyTypeInfo->use_begin(); User != copyTypeInfo->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*> Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); // size Args.push_back(CI->getOperand(4)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = setTypeInfo->use_begin(); User != setTypeInfo->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { std::vector<Value*> Args; Args.push_back(CI->getOperand(1)); Args.push_back(CI->getOperand(3)); // size Args.push_back(CI->getOperand(6)); CallInst::Create(trackInitInst, Args, "", CI); toDelete.push_back(CI); } } for(Value::use_iterator User = getTypeTag->use_begin(); User != getTypeTag->use_end(); ++User) { CallInst *CI = dyn_cast<CallInst>(*User); assert(CI); if(TS->isTypeSafe(CI->getOperand(1)->stripPointerCasts(), CI->getParent()->getParent())) { AllocaInst *AI = dyn_cast<AllocaInst>(CI->getOperand(3)->stripPointerCasts()); assert(AI); std::vector<Value*>Args; Args.push_back(CI->getOperand(3)); Args.push_back(ConstantInt::get(Int8Ty, 255)); Args.push_back(CI->getOperand(2)); Args.push_back(ConstantInt::get(Int32Ty, AI->getAlignment())); CallInst::Create(memsetF, Args, "", CI); toDelete.push_back(CI); } } numSafe += toDelete.size(); while(!toDelete.empty()) { Instruction *I = toDelete.back(); toDelete.pop_back(); I->eraseFromParent(); } return (numSafe > 0); }
string esp::parseName(Value *value){ // has existed if(names.find(value) != names.end()) return names[value]; string name = ""; Value *current = value; /* bool continueFlag = true; do{ if(isa<Instruction > (current)){ Instruction* inst = dyn_cast<Instruction>(current); unsigned op = inst->getOpcode(); switch(op){ case Instruction::Ret :{ break; } case Instruction::Br :{ break; } case Instruction::Switch :{ break; } case Instruction::Call :{ CallInst *callinst = (CallInst*) current; if (((CallInst*) current)->getCalledFunction() != NULL) { name += string("@")+((CallInst*) current)->getCalledFunction()->getNameStr() + "("; } else { name += string("@[funcPTR]("); name += ((CallInst*) current)->getCalledValue()->getNameStr(); } for (unsigned i = 1; i < callinst->getNumOperands(); i++) { name += esp::parseName(callinst->getOperand(i)); } name += string(")"); continueFlag = false; break; } case Instruction::PHI :{ name += string("PHI["); name += current->getNameStr(); PHINode *phi = (PHINode*) current; for (unsigned i = 0; i < phi->getNumIncomingValues(); i++) { Value *incoming = phi->getIncomingValue(i); if (i != 0) name += ","; if (!hasLoop(incoming)) { if (!incoming->hasName()) { name += esp::parseName(incoming); } else { name += incoming->getNameStr(); } } } name += std::string("]"); continueFlag = false; break; } case Instruction::Select :{ break; } case Instruction::Add :{ name += "+"; name += parseBinaryOpName(inst); break; } case Instruction::Sub :{ name += "-"; name += parseBinaryOpName(inst); break; } case Instruction::Mul :{ name += "*"; name += parseBinaryOpName(inst); break; } case Instruction::UDiv :{ name += "/"; name += parseBinaryOpName(inst); break; } case Instruction::SDiv :{ name += "//"; name += parseBinaryOpName(inst); break; } case Instruction::And :{ name += "&"; name += parseBinaryOpName(inst); break; } case Instruction::Or :{ name += "|"; name += parseBinaryOpName(inst); break; } case Instruction::Xor :{ name += "^"; name += parseBinaryOpName(inst); break; } case Instruction::Shl :{ name += "<<"; name += parseBinaryOpName(inst); break; } case Instruction::LShr :{ name += ">>"; name += parseBinaryOpName(inst); break; } case Instruction::AShr :{ name += ">>>"; name += parseBinaryOpName(inst); break; } case Instruction::ICmp :{ ICmpInst * icmp = dyn_cast<ICmpInst>(current); if (isa<Constant>(icmp->getOperand(0))) { name += esp::parseName(icmp->getOperand(1)); continueFlag = false; } else { name += esp::parseName(icmp->getOperand(0)); continueFlag = false; } break; } case Instruction::Alloca :{ name += current->getNameStr(); break; } case Instruction::Load :{ if (((LoadInst*) inst)->isVolatile()) name += std::string("@VolatileLoad"); name += "*"; name += esp::parseName(inst->getOperand(0)); continueFlag = false; break; } case Instruction::Store :{ // need to handle continueFlag = false; break; } case Instruction::GetElementPtr :{ GetElementPtrInst * gep = dyn_cast<GetElementPtrInst>(current); unsigned ops = gep->getNumOperands(); name += "["; for (unsigned i = 1; i < ops; i++) { Value *v = gep->getOperand(i); if (ConstantInt * ci = dyn_cast<ConstantInt>(v)) { if (i == 1 && ci->equalsInt(0)) continue; name += "."; name += ci->getValue().toString(10, false); } else { name += "."; name += esp::parseName(v); } } name += "]"; name += esp::parseName(gep->getOperand(0)); continueFlag = false; break; } case Instruction::BitCast:{ name += esp::parseName(inst->getOperand(0)); continueFlag = false; break; } default :{ // Illegal or unsupported instruction name += current->getNameStr(); break; } } }else if(isa<Argument>(current)){ if (arguments.find(current) != arguments.end()) name += std::string("$") + current->getNameStr(); }else if(isa<GlobalValue>(current)){ name += std::string("@") + current->getNameStr(); }else if(isa<ConstantInt>(current)){ ConstantInt * cint = dyn_cast<ConstantInt > (current); name += cint->getValue().toString(10, true); }else if (isa<Constant > (current)) { Constant *c = dyn_cast<Constant > (current); if (c->isNullValue()) { name += "null"; } }else{ // Illegal format } if(!continueFlag) break; current = parents[current]; }while(current); */ //Refactor do { if (isa<LoadInst > (current)) { name += "*"; if (parents[current] == NULL) name += (((LoadInst*) current)->getOperand(0))->getNameStr(); if (((LoadInst*) current)->isVolatile()) name += std::string("@VolatileLoad"); } else if (dyn_cast<GetElementPtrInst > (current)) { GetElementPtrInst * gep = dyn_cast<GetElementPtrInst > (current); unsigned ops = gep->getNumOperands(); name += "["; for (unsigned i = 1; i < ops; i++) { Value *v = gep->getOperand(i); if (dyn_cast<ConstantInt > (current)) { ConstantInt * ci = dyn_cast<ConstantInt > (current); if (i == 1 && ci->equalsInt(0)) continue; name += "."; name += ci->getValue().toString(10, false); } else { name += "."; name += parseName(v); } } name += "]"; name += parseName(gep->getOperand(0)); break; } else if (isa<AllocaInst > (current)) { name += current->getNameStr(); } else if (isa<Argument > (current)) { if (arguments.find(current) != arguments.end()) name += std::string("$") + current->getNameStr(); } else if (isa<GlobalValue > (current)) { name += std::string("@") + current->getNameStr(); } else if (isa<CallInst > (current)) { CallInst *callinst = (CallInst*) current; if (((CallInst*) current)->getCalledFunction() != NULL) { name += std::string("@")+((CallInst*) current)->getCalledFunction()->getNameStr() + "("; } else { name += std::string("@[funcPTR]("); name += ((CallInst*) current)->getCalledValue()->getNameStr(); } for (unsigned i = 1; i < callinst->getNumOperands(); i++) { name += parseName(callinst->getOperand(i)); } name += std::string(")"); break; } else if (isa<CastInst > (current)) { } else if (isa<PHINode > (current)) { /* name += std::string("PHI["); s += parent->getNameStr(); PHINode *phi = (PHINode*) parent; for (unsigned i = 0; i < phi->getNumIncomingValues(); i++) { //s+=phi->getIncomingBlock(i)->getNameStr(); Value *incoming = phi->getIncomingValue(i); if (i != 0) s += ","; if (!hasLoop(incoming)) { DEBUG(errs() << "incoming#" << i << " no loop(i rather doubt it)\n"); if (!incoming->hasName()) { s += parseName(incoming); } else { s += incoming->getNameStr(); } } } // PHI nodes...ugh s += std::string("]"); break; */ } else if (isa<BinaryOperator > (current)) { BinaryOperator *bo = dyn_cast<BinaryOperator > (current); Instruction::BinaryOps opcode = bo->getOpcode(); if (opcode == Instruction::Add) { name.append("+"); } else if (opcode == Instruction::Sub) { name.append("-"); } else if (opcode == Instruction::Or) { name.append("||"); } else if (opcode == Instruction::Mul) { name.append("*"); } else if (opcode == Instruction::Xor) { name.append("^"); } else if (opcode == Instruction::And) { name.append("&&"); } else if (opcode == Instruction::Shl) { name.append("<<"); } else if (opcode == Instruction::AShr) { name.append(">>"); } else if (opcode == Instruction::LShr) { name.append(">>>"); } Value *v0 = bo->getOperand(0); Value *v1 = bo->getOperand(1); if (isa<ConstantInt > (v0)) { name += ((ConstantInt*) v0)->getValue().toString(10, false); } else if (isa<ConstantInt > (v1)) { name += ((ConstantInt*) v1)->getValue().toString(10, false); } else { printDebugMsg("Binary Operation between non-constants\n"); } } else if (dyn_cast<GEPOperator > (current)) { GEPOperator * gep = dyn_cast<GEPOperator > (current); unsigned ops = gep->getNumOperands(); name += "["; for (unsigned i = 1; i < ops; i++) { Value *v = gep->getOperand(i); if (dyn_cast<ConstantInt > (v)) { ConstantInt * ci = dyn_cast<ConstantInt > (v); if (i == 1 && ci->equalsInt(0)) continue; name += "."; name += ci->getValue().toString(10, false); } } name += "]"; name += parseName(gep->getOperand(0)); break; } else if (dyn_cast<ICmpInst > (current)) { ICmpInst * icmp = dyn_cast<ICmpInst > (current); if (isa<Constant > (icmp->getOperand(0))) { name += parseName(icmp->getOperand(1)); break; } else { name += parseName(icmp->getOperand(0)); break; } } else if (dyn_cast<ConstantInt > (current)) { ConstantInt * cint = dyn_cast<ConstantInt > (current); name += cint->getValue().toString(10, true); } else { name += current->getNameStr(); // might not work } } while ((current = parents[current])); names[value] = name; return name; }
bool TailCallElim::ProcessReturningBlock(ReturnInst *Ret, BasicBlock *&OldEntry, bool &TailCallsAreMarkedTail, SmallVector<PHINode*, 8> &ArgumentPHIs, bool CannotTailCallElimCallsMarkedTail) { BasicBlock *BB = Ret->getParent(); Function *F = BB->getParent(); if (&BB->front() == Ret) // Make sure there is something before the ret... return false; // If the return is in the entry block, then making this transformation would // turn infinite recursion into an infinite loop. This transformation is ok // in theory, but breaks some code like: // double fabs(double f) { return __builtin_fabs(f); } // a 'fabs' call // disable this xform in this case, because the code generator will lower the // call to fabs into inline code. if (BB == &F->getEntryBlock()) return false; // Scan backwards from the return, checking to see if there is a tail call in // this block. If so, set CI to it. CallInst *CI; BasicBlock::iterator BBI = Ret; while (1) { CI = dyn_cast<CallInst>(BBI); if (CI && CI->getCalledFunction() == F) break; if (BBI == BB->begin()) return false; // Didn't find a potential tail call. --BBI; } // If this call is marked as a tail call, and if there are dynamic allocas in // the function, we cannot perform this optimization. if (CI->isTailCall() && CannotTailCallElimCallsMarkedTail) return false; // If we are introducing accumulator recursion to eliminate associative // operations after the call instruction, this variable contains the initial // value for the accumulator. If this value is set, we actually perform // accumulator recursion elimination instead of simple tail recursion // elimination. Value *AccumulatorRecursionEliminationInitVal = 0; Instruction *AccumulatorRecursionInstr = 0; // Ok, we found a potential tail call. We can currently only transform the // tail call if all of the instructions between the call and the return are // movable to above the call itself, leaving the call next to the return. // Check that this is the case now. for (BBI = CI, ++BBI; &*BBI != Ret; ++BBI) if (!CanMoveAboveCall(BBI, CI)) { // If we can't move the instruction above the call, it might be because it // is an associative operation that could be tranformed using accumulator // recursion elimination. Check to see if this is the case, and if so, // remember the initial accumulator value for later. if ((AccumulatorRecursionEliminationInitVal = CanTransformAccumulatorRecursion(BBI, CI))) { // Yes, this is accumulator recursion. Remember which instruction // accumulates. AccumulatorRecursionInstr = BBI; } else { return false; // Otherwise, we cannot eliminate the tail recursion! } } // We can only transform call/return pairs that either ignore the return value // of the call and return void, ignore the value of the call and return a // constant, return the value returned by the tail call, or that are being // accumulator recursion variable eliminated. if (Ret->getNumOperands() == 1 && Ret->getReturnValue() != CI && !isa<UndefValue>(Ret->getReturnValue()) && AccumulatorRecursionEliminationInitVal == 0 && !getCommonReturnValue(Ret, CI)) return false; // OK! We can transform this tail call. If this is the first one found, // create the new entry block, allowing us to branch back to the old entry. if (OldEntry == 0) { OldEntry = &F->getEntryBlock(); BasicBlock *NewEntry = BasicBlock::Create(F->getContext(), "", F, OldEntry); NewEntry->takeName(OldEntry); OldEntry->setName("tailrecurse"); BranchInst::Create(OldEntry, NewEntry); // If this tail call is marked 'tail' and if there are any allocas in the // entry block, move them up to the new entry block. TailCallsAreMarkedTail = CI->isTailCall(); if (TailCallsAreMarkedTail) // Move all fixed sized allocas from OldEntry to NewEntry. for (BasicBlock::iterator OEBI = OldEntry->begin(), E = OldEntry->end(), NEBI = NewEntry->begin(); OEBI != E; ) if (AllocaInst *AI = dyn_cast<AllocaInst>(OEBI++)) if (isa<ConstantInt>(AI->getArraySize())) AI->moveBefore(NEBI); // Now that we have created a new block, which jumps to the entry // block, insert a PHI node for each argument of the function. // For now, we initialize each PHI to only have the real arguments // which are passed in. Instruction *InsertPos = OldEntry->begin(); for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) { PHINode *PN = PHINode::Create(I->getType(), I->getName() + ".tr", InsertPos); I->replaceAllUsesWith(PN); // Everyone use the PHI node now! PN->addIncoming(I, NewEntry); ArgumentPHIs.push_back(PN); } } // If this function has self recursive calls in the tail position where some // are marked tail and some are not, only transform one flavor or another. We // have to choose whether we move allocas in the entry block to the new entry // block or not, so we can't make a good choice for both. NOTE: We could do // slightly better here in the case that the function has no entry block // allocas. if (TailCallsAreMarkedTail && !CI->isTailCall()) return false; // Ok, now that we know we have a pseudo-entry block WITH all of the // required PHI nodes, add entries into the PHI node for the actual // parameters passed into the tail-recursive call. for (unsigned i = 0, e = CI->getNumOperands()-1; i != e; ++i) ArgumentPHIs[i]->addIncoming(CI->getOperand(i+1), BB); // If we are introducing an accumulator variable to eliminate the recursion, // do so now. Note that we _know_ that no subsequent tail recursion // eliminations will happen on this function because of the way the // accumulator recursion predicate is set up. // if (AccumulatorRecursionEliminationInitVal) { Instruction *AccRecInstr = AccumulatorRecursionInstr; // Start by inserting a new PHI node for the accumulator. PHINode *AccPN = PHINode::Create(AccRecInstr->getType(), "accumulator.tr", OldEntry->begin()); // Loop over all of the predecessors of the tail recursion block. For the // real entry into the function we seed the PHI with the initial value, // computed earlier. For any other existing branches to this block (due to // other tail recursions eliminated) the accumulator is not modified. // Because we haven't added the branch in the current block to OldEntry yet, // it will not show up as a predecessor. for (pred_iterator PI = pred_begin(OldEntry), PE = pred_end(OldEntry); PI != PE; ++PI) { if (*PI == &F->getEntryBlock()) AccPN->addIncoming(AccumulatorRecursionEliminationInitVal, *PI); else AccPN->addIncoming(AccPN, *PI); } // Add an incoming argument for the current block, which is computed by our // associative accumulator instruction. AccPN->addIncoming(AccRecInstr, BB); // Next, rewrite the accumulator recursion instruction so that it does not // use the result of the call anymore, instead, use the PHI node we just // inserted. AccRecInstr->setOperand(AccRecInstr->getOperand(0) != CI, AccPN); // Finally, rewrite any return instructions in the program to return the PHI // node instead of the "initval" that they do currently. This loop will // actually rewrite the return value we are destroying, but that's ok. for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ++BBI) if (ReturnInst *RI = dyn_cast<ReturnInst>(BBI->getTerminator())) RI->setOperand(0, AccPN); ++NumAccumAdded; } // Now that all of the PHI nodes are in place, remove the call and // ret instructions, replacing them with an unconditional branch. BranchInst::Create(OldEntry, Ret); BB->getInstList().erase(Ret); // Remove return. BB->getInstList().erase(CI); // Remove call. ++NumEliminated; return true; }