/// \brief Returns the allocation data for the given value if it is a call to a /// known allocation function, and NULL otherwise. static const AllocFnsTy *getAllocationData(const Value *V, AllocType AllocTy, const TargetLibraryInfo *TLI, bool LookThroughBitCast = false) { // Skip all intrinsics but duetto.allocate if (const IntrinsicInst* II = dyn_cast<IntrinsicInst>(V)) { if (II->getIntrinsicID() == Intrinsic::duetto_allocate) return &AllocationFnData[0]; return 0; } Function *Callee = getCalledFunction(V, LookThroughBitCast); if (!Callee) return 0; // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return 0; unsigned i = 0; bool found = false; for ( ; i < array_lengthof(AllocationFnData); ++i) { if (AllocationFnData[i].Func == TLIFn) { found = true; break; } } if (!found) return 0; const AllocFnsTy *FnData = &AllocationFnData[i]; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) return 0; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return FnData; return 0; }
/// \brief Returns the allocation data for the given value if it is a call to a /// known allocation function, and NULL otherwise. static const AllocFnsTy *getAllocationData(const Value *V, AllocType AllocTy, const TargetLibraryInfo *TLI, bool LookThroughBitCast = false) { // Skip intrinsics if (isa<IntrinsicInst>(V)) return nullptr; Function *Callee = getCalledFunction(V, LookThroughBitCast); if (!Callee) return nullptr; // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return nullptr; const AllocFnsTy *FnData = std::find_if(std::begin(AllocationFnData), std::end(AllocationFnData), [TLIFn](const AllocFnsTy &Fn) { return Fn.Func == TLIFn; }); if (FnData == std::end(AllocationFnData)) return nullptr; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) return nullptr; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return FnData; return nullptr; }
static bool isCallocCall(const CallInst *CI) { if (!CI) return false; Function *Callee = CI->getCalledFunction(); if (Callee == 0 || !Callee->isDeclaration()) return false; if (Callee->getName() != "calloc") return false; // Check malloc prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute exists. FunctionType *FTy = Callee->getFunctionType(); return FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == 2 && ((FTy->getParamType(0)->isIntegerTy(32) && FTy->getParamType(1)->isIntegerTy(32)) || (FTy->getParamType(0)->isIntegerTy(64) && FTy->getParamType(1)->isIntegerTy(64))); }
// TODO Copy-paste static bool isMallocCall(const CallInst* CI) { if (!CI) return false; Function* Callee = CI->getCalledFunction(); if (Callee == 0 || !Callee->isDeclaration()) return false; if (Callee->getName() != "malloc" /*&& Callee->getName() != "my_malloc" && Callee->getName() != "_Znwj" && // operator new(unsigned int) Callee->getName() != "_Znwm" && // operator new(unsigned long) Callee->getName() != "_Znaj" && // operator new[](unsigned int) Callee->getName() != "_Znam"*/) // operator new[](unsigned long) return false; // Check malloc prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute will exist. FunctionType* FTy = Callee->getFunctionType(); return FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == 1 && (FTy->getParamType(0)->isIntegerTy(32) || FTy->getParamType(0)->isIntegerTy(64)); }
/// \brief Returns the allocation data for the given value if it is a call to a /// known allocation function, and NULL otherwise. static const AllocFnsTy *getAllocationData(const Value *V, AllocType AllocTy, bool LookThroughBitCast = false) { Function *Callee = getCalledFunction(V, LookThroughBitCast); if (!Callee) return 0; unsigned i = 0; bool found = false; for ( ; i < array_lengthof(AllocationFnData); ++i) { if (Callee->getName() == AllocationFnData[i].Name) { found = true; break; } } if (!found) return 0; const AllocFnsTy *FnData = &AllocationFnData[i]; if ((FnData->AllocTy & AllocTy) == 0) return 0; // Check function prototype. // FIXME: Check the nobuiltin metadata?? (PR5130) int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return FnData; return 0; }
/// Returns the allocation data for the given value if it's either a call to a /// known allocation function, or a call to a function with the allocsize /// attribute. static Optional<AllocFnsTy> getAllocationDataForFunction(const Function *Callee, AllocType AllocTy, const TargetLibraryInfo *TLI) { // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return None; const auto *Iter = find_if( AllocationFnData, [TLIFn](const std::pair<LibFunc, AllocFnsTy> &P) { return P.first == TLIFn; }); if (Iter == std::end(AllocationFnData)) return None; const AllocFnsTy *FnData = &Iter->second; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) return None; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return *FnData; return None; }
/// DoPromotion - This method actually performs the promotion of the specified /// arguments, and returns the new function. At this point, we know that it's /// safe to do so. CallGraphNode *ArgPromotion::DoPromotion(Function *F, SmallPtrSetImpl<Argument*> &ArgsToPromote, SmallPtrSetImpl<Argument*> &ByValArgsToTransform) { // Start by computing a new prototype for the function, which is the same as // the old function, but has modified arguments. FunctionType *FTy = F->getFunctionType(); std::vector<Type*> Params; typedef std::set<IndicesVector> ScalarizeTable; // ScalarizedElements - If we are promoting a pointer that has elements // accessed out of it, keep track of which elements are accessed so that we // can add one argument for each. // // Arguments that are directly loaded will have a zero element value here, to // handle cases where there are both a direct load and GEP accesses. // std::map<Argument*, ScalarizeTable> ScalarizedElements; // OriginalLoads - Keep track of a representative load instruction from the // original function so that we can tell the alias analysis implementation // what the new GEP/Load instructions we are inserting look like. // We need to keep the original loads for each argument and the elements // of the argument that are accessed. std::map<std::pair<Argument*, IndicesVector>, LoadInst*> OriginalLoads; // Attribute - Keep track of the parameter attributes for the arguments // that we are *not* promoting. For the ones that we do promote, the parameter // attributes are lost SmallVector<AttributeSet, 8> AttributesVec; const AttributeSet &PAL = F->getAttributes(); // Add any return attributes. if (PAL.hasAttributes(AttributeSet::ReturnIndex)) AttributesVec.push_back(AttributeSet::get(F->getContext(), PAL.getRetAttributes())); // First, determine the new argument list unsigned ArgIndex = 1; for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I, ++ArgIndex) { if (ByValArgsToTransform.count(I)) { // Simple byval argument? Just add all the struct element types. Type *AgTy = cast<PointerType>(I->getType())->getElementType(); StructType *STy = cast<StructType>(AgTy); for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) Params.push_back(STy->getElementType(i)); ++NumByValArgsPromoted; } else if (!ArgsToPromote.count(I)) { // Unchanged argument Params.push_back(I->getType()); AttributeSet attrs = PAL.getParamAttributes(ArgIndex); if (attrs.hasAttributes(ArgIndex)) { AttrBuilder B(attrs, ArgIndex); AttributesVec. push_back(AttributeSet::get(F->getContext(), Params.size(), B)); } } else if (I->use_empty()) { // Dead argument (which are always marked as promotable) ++NumArgumentsDead; } else { // Okay, this is being promoted. This means that the only uses are loads // or GEPs which are only used by loads // In this table, we will track which indices are loaded from the argument // (where direct loads are tracked as no indices). ScalarizeTable &ArgIndices = ScalarizedElements[I]; for (User *U : I->users()) { Instruction *UI = cast<Instruction>(U); assert(isa<LoadInst>(UI) || isa<GetElementPtrInst>(UI)); IndicesVector Indices; Indices.reserve(UI->getNumOperands() - 1); // Since loads will only have a single operand, and GEPs only a single // non-index operand, this will record direct loads without any indices, // and gep+loads with the GEP indices. for (User::op_iterator II = UI->op_begin() + 1, IE = UI->op_end(); II != IE; ++II) Indices.push_back(cast<ConstantInt>(*II)->getSExtValue()); // GEPs with a single 0 index can be merged with direct loads if (Indices.size() == 1 && Indices.front() == 0) Indices.clear(); ArgIndices.insert(Indices); LoadInst *OrigLoad; if (LoadInst *L = dyn_cast<LoadInst>(UI)) OrigLoad = L; else // Take any load, we will use it only to update Alias Analysis OrigLoad = cast<LoadInst>(UI->user_back()); OriginalLoads[std::make_pair(I, Indices)] = OrigLoad; } // Add a parameter to the function for each element passed in. for (ScalarizeTable::iterator SI = ArgIndices.begin(), E = ArgIndices.end(); SI != E; ++SI) { // not allowed to dereference ->begin() if size() is 0 Params.push_back(GetElementPtrInst::getIndexedType(I->getType(), *SI)); assert(Params.back()); } if (ArgIndices.size() == 1 && ArgIndices.begin()->empty()) ++NumArgumentsPromoted; else ++NumAggregatesPromoted; } } // Add any function attributes. if (PAL.hasAttributes(AttributeSet::FunctionIndex)) AttributesVec.push_back(AttributeSet::get(FTy->getContext(), PAL.getFnAttributes())); Type *RetTy = FTy->getReturnType(); // Construct the new function type using the new arguments. FunctionType *NFTy = FunctionType::get(RetTy, Params, FTy->isVarArg()); // Create the new function body and insert it into the module. Function *NF = Function::Create(NFTy, F->getLinkage(), F->getName()); NF->copyAttributesFrom(F); // Patch the pointer to LLVM function in debug info descriptor. auto DI = FunctionDIs.find(F); if (DI != FunctionDIs.end()) { DISubprogram SP = DI->second; SP.replaceFunction(NF); // Ensure the map is updated so it can be reused on subsequent argument // promotions of the same function. FunctionDIs.erase(DI); FunctionDIs[NF] = SP; } DEBUG(dbgs() << "ARG PROMOTION: Promoting to:" << *NF << "\n" << "From: " << *F); // Recompute the parameter attributes list based on the new arguments for // the function. NF->setAttributes(AttributeSet::get(F->getContext(), AttributesVec)); AttributesVec.clear(); F->getParent()->getFunctionList().insert(F, NF); NF->takeName(F); // Get the alias analysis information that we need to update to reflect our // changes. AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); // Get the callgraph information that we need to update to reflect our // changes. CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); // Get a new callgraph node for NF. CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF); // Loop over all of the callers of the function, transforming the call sites // to pass in the loaded pointers. // SmallVector<Value*, 16> Args; while (!F->use_empty()) { CallSite CS(F->user_back()); assert(CS.getCalledFunction() == F); Instruction *Call = CS.getInstruction(); const AttributeSet &CallPAL = CS.getAttributes(); // Add any return attributes. if (CallPAL.hasAttributes(AttributeSet::ReturnIndex)) AttributesVec.push_back(AttributeSet::get(F->getContext(), CallPAL.getRetAttributes())); // Loop over the operands, inserting GEP and loads in the caller as // appropriate. CallSite::arg_iterator AI = CS.arg_begin(); ArgIndex = 1; for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I, ++AI, ++ArgIndex) if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) { Args.push_back(*AI); // Unmodified argument if (CallPAL.hasAttributes(ArgIndex)) { AttrBuilder B(CallPAL, ArgIndex); AttributesVec. push_back(AttributeSet::get(F->getContext(), Args.size(), B)); } } else if (ByValArgsToTransform.count(I)) { // Emit a GEP and load for each element of the struct. Type *AgTy = cast<PointerType>(I->getType())->getElementType(); StructType *STy = cast<StructType>(AgTy); Value *Idxs[2] = { ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), nullptr }; for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i); Value *Idx = GetElementPtrInst::Create(*AI, Idxs, (*AI)->getName()+"."+utostr(i), Call); // TODO: Tell AA about the new values? Args.push_back(new LoadInst(Idx, Idx->getName()+".val", Call)); } } else if (!I->use_empty()) { // Non-dead argument: insert GEPs and loads as appropriate. ScalarizeTable &ArgIndices = ScalarizedElements[I]; // Store the Value* version of the indices in here, but declare it now // for reuse. std::vector<Value*> Ops; for (ScalarizeTable::iterator SI = ArgIndices.begin(), E = ArgIndices.end(); SI != E; ++SI) { Value *V = *AI; LoadInst *OrigLoad = OriginalLoads[std::make_pair(I, *SI)]; if (!SI->empty()) { Ops.reserve(SI->size()); Type *ElTy = V->getType(); for (IndicesVector::const_iterator II = SI->begin(), IE = SI->end(); II != IE; ++II) { // Use i32 to index structs, and i64 for others (pointers/arrays). // This satisfies GEP constraints. Type *IdxTy = (ElTy->isStructTy() ? Type::getInt32Ty(F->getContext()) : Type::getInt64Ty(F->getContext())); Ops.push_back(ConstantInt::get(IdxTy, *II)); // Keep track of the type we're currently indexing. ElTy = cast<CompositeType>(ElTy)->getTypeAtIndex(*II); } // And create a GEP to extract those indices. V = GetElementPtrInst::Create(V, Ops, V->getName()+".idx", Call); Ops.clear(); AA.copyValue(OrigLoad->getOperand(0), V); } // Since we're replacing a load make sure we take the alignment // of the previous load. LoadInst *newLoad = new LoadInst(V, V->getName()+".val", Call); newLoad->setAlignment(OrigLoad->getAlignment()); // Transfer the AA info too. AAMDNodes AAInfo; OrigLoad->getAAMetadata(AAInfo); newLoad->setAAMetadata(AAInfo); Args.push_back(newLoad); AA.copyValue(OrigLoad, Args.back()); } } // Push any varargs arguments on the list. for (; AI != CS.arg_end(); ++AI, ++ArgIndex) { Args.push_back(*AI); if (CallPAL.hasAttributes(ArgIndex)) { AttrBuilder B(CallPAL, ArgIndex); AttributesVec. push_back(AttributeSet::get(F->getContext(), Args.size(), B)); } } // Add any function attributes. if (CallPAL.hasAttributes(AttributeSet::FunctionIndex)) AttributesVec.push_back(AttributeSet::get(Call->getContext(), CallPAL.getFnAttributes())); Instruction *New; if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) { New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), Args, "", Call); cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv()); cast<InvokeInst>(New)->setAttributes(AttributeSet::get(II->getContext(), AttributesVec)); } else { New = CallInst::Create(NF, Args, "", Call); cast<CallInst>(New)->setCallingConv(CS.getCallingConv()); cast<CallInst>(New)->setAttributes(AttributeSet::get(New->getContext(), AttributesVec)); if (cast<CallInst>(Call)->isTailCall()) cast<CallInst>(New)->setTailCall(); } New->setDebugLoc(Call->getDebugLoc()); Args.clear(); AttributesVec.clear(); // Update the alias analysis implementation to know that we are replacing // the old call with a new one. AA.replaceWithNewValue(Call, New); // Update the callgraph to know that the callsite has been transformed. CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()]; CalleeNode->replaceCallEdge(Call, New, NF_CGN); if (!Call->use_empty()) { Call->replaceAllUsesWith(New); New->takeName(Call); } // Finally, remove the old call from the program, reducing the use-count of // F. Call->eraseFromParent(); } // Since we have now created the new function, splice the body of the old // function right into the new function, leaving the old rotting hulk of the // function empty. NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList()); // Loop over the argument list, transferring uses of the old arguments over to // the new arguments, also transferring over the names as well. // for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(), I2 = NF->arg_begin(); I != E; ++I) { if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) { // If this is an unmodified argument, move the name and users over to the // new version. I->replaceAllUsesWith(I2); I2->takeName(I); AA.replaceWithNewValue(I, I2); ++I2; continue; } if (ByValArgsToTransform.count(I)) { // In the callee, we create an alloca, and store each of the new incoming // arguments into the alloca. Instruction *InsertPt = NF->begin()->begin(); // Just add all the struct element types. Type *AgTy = cast<PointerType>(I->getType())->getElementType(); Value *TheAlloca = new AllocaInst(AgTy, nullptr, "", InsertPt); StructType *STy = cast<StructType>(AgTy); Value *Idxs[2] = { ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), nullptr }; for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i); Value *Idx = GetElementPtrInst::Create(TheAlloca, Idxs, TheAlloca->getName()+"."+Twine(i), InsertPt); I2->setName(I->getName()+"."+Twine(i)); new StoreInst(I2++, Idx, InsertPt); } // Anything that used the arg should now use the alloca. I->replaceAllUsesWith(TheAlloca); TheAlloca->takeName(I); AA.replaceWithNewValue(I, TheAlloca); // If the alloca is used in a call, we must clear the tail flag since // the callee now uses an alloca from the caller. for (User *U : TheAlloca->users()) { CallInst *Call = dyn_cast<CallInst>(U); if (!Call) continue; Call->setTailCall(false); } continue; } if (I->use_empty()) { AA.deleteValue(I); continue; } // Otherwise, if we promoted this argument, then all users are load // instructions (or GEPs with only load users), and all loads should be // using the new argument that we added. ScalarizeTable &ArgIndices = ScalarizedElements[I]; while (!I->use_empty()) { if (LoadInst *LI = dyn_cast<LoadInst>(I->user_back())) { assert(ArgIndices.begin()->empty() && "Load element should sort to front!"); I2->setName(I->getName()+".val"); LI->replaceAllUsesWith(I2); AA.replaceWithNewValue(LI, I2); LI->eraseFromParent(); DEBUG(dbgs() << "*** Promoted load of argument '" << I->getName() << "' in function '" << F->getName() << "'\n"); } else { GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->user_back()); IndicesVector Operands; Operands.reserve(GEP->getNumIndices()); for (User::op_iterator II = GEP->idx_begin(), IE = GEP->idx_end(); II != IE; ++II) Operands.push_back(cast<ConstantInt>(*II)->getSExtValue()); // GEPs with a single 0 index can be merged with direct loads if (Operands.size() == 1 && Operands.front() == 0) Operands.clear(); Function::arg_iterator TheArg = I2; for (ScalarizeTable::iterator It = ArgIndices.begin(); *It != Operands; ++It, ++TheArg) { assert(It != ArgIndices.end() && "GEP not handled??"); } std::string NewName = I->getName(); for (unsigned i = 0, e = Operands.size(); i != e; ++i) { NewName += "." + utostr(Operands[i]); } NewName += ".val"; TheArg->setName(NewName); DEBUG(dbgs() << "*** Promoted agg argument '" << TheArg->getName() << "' of function '" << NF->getName() << "'\n"); // All of the uses must be load instructions. Replace them all with // the argument specified by ArgNo. while (!GEP->use_empty()) { LoadInst *L = cast<LoadInst>(GEP->user_back()); L->replaceAllUsesWith(TheArg); AA.replaceWithNewValue(L, TheArg); L->eraseFromParent(); } AA.deleteValue(GEP); GEP->eraseFromParent(); } } // Increment I2 past all of the arguments added for this promoted pointer. std::advance(I2, ArgIndices.size()); } // Tell the alias analysis that the old function is about to disappear. AA.replaceWithNewValue(F, NF); NF_CGN->stealCalledFunctionsFrom(CG[F]); // Now that the old function is dead, delete it. If there is a dangling // reference to the CallgraphNode, just leave the dead function around for // someone else to nuke. CallGraphNode *CGN = CG[F]; if (CGN->getNumReferences() == 0) delete CG.removeFunctionFromModule(CGN); else F->setLinkage(Function::ExternalLinkage); return NF_CGN; }
bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, LibFunc::Func F, const DataLayout *DL) const { LLVMContext &Ctx = FTy.getContext(); Type *PCharTy = Type::getInt8PtrTy(Ctx); Type *SizeTTy = DL ? DL->getIntPtrType(Ctx, /*AS=*/0) : nullptr; auto IsSizeTTy = [SizeTTy](Type *Ty) { return SizeTTy ? Ty == SizeTTy : Ty->isIntegerTy(); }; unsigned NumParams = FTy.getNumParams(); switch (F) { case LibFunc::strlen: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isIntegerTy()); case LibFunc::strchr: case LibFunc::strrchr: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1)->isIntegerTy()); case LibFunc::strtol: case LibFunc::strtod: case LibFunc::strtof: case LibFunc::strtoul: case LibFunc::strtoll: case LibFunc::strtold: case LibFunc::strtoull: return ((NumParams == 2 || NumParams == 3) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strcat: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1) == FTy.getReturnType()); case LibFunc::strncat: return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1) == FTy.getReturnType() && FTy.getParamType(2)->isIntegerTy()); case LibFunc::strcpy_chk: case LibFunc::stpcpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::strcpy: case LibFunc::stpcpy: return (NumParams == 2 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy); case LibFunc::strncpy_chk: case LibFunc::stpncpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::strncpy: case LibFunc::stpncpy: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy && FTy.getParamType(2)->isIntegerTy()); case LibFunc::strxfrm: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strcmp: return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1)); case LibFunc::strncmp: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(2)->isIntegerTy()); case LibFunc::strspn: case LibFunc::strcspn: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getReturnType()->isIntegerTy()); case LibFunc::strcoll: case LibFunc::strcasecmp: case LibFunc::strncasecmp: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strstr: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::strpbrk: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1)); case LibFunc::strtok: case LibFunc::strtok_r: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::scanf: case LibFunc::setbuf: case LibFunc::setvbuf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::strdup: case LibFunc::strndup: return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc::sscanf: case LibFunc::stat: case LibFunc::statvfs: case LibFunc::sprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::snprintf: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::setitimer: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::system: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::malloc: return (NumParams == 1 && FTy.getReturnType()->isPointerTy()); case LibFunc::memcmp: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); case LibFunc::memchr: case LibFunc::memrchr: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy(32) && FTy.getParamType(2)->isIntegerTy() && FTy.getReturnType()->isPointerTy()); case LibFunc::modf: case LibFunc::modff: case LibFunc::modfl: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::memcpy_chk: case LibFunc::memmove_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::memcpy: case LibFunc::mempcpy: case LibFunc::memmove: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && IsSizeTTy(FTy.getParamType(2))); case LibFunc::memset_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; // fallthrough case LibFunc::memset: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy() && IsSizeTTy(FTy.getParamType(2))); case LibFunc::memccpy: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::memalign: return (FTy.getReturnType()->isPointerTy()); case LibFunc::realloc: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isPointerTy()); case LibFunc::read: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc::rewind: case LibFunc::rmdir: case LibFunc::remove: case LibFunc::realpath: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::rename: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::readlink: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::write: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc::bcopy: case LibFunc::bcmp: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::bzero: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::calloc: return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); case LibFunc::atof: case LibFunc::atoi: case LibFunc::atol: case LibFunc::atoll: case LibFunc::ferror: case LibFunc::getenv: case LibFunc::getpwnam: case LibFunc::pclose: case LibFunc::perror: case LibFunc::printf: case LibFunc::puts: case LibFunc::uname: case LibFunc::under_IO_getc: case LibFunc::unlink: case LibFunc::unsetenv: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::chmod: case LibFunc::chown: case LibFunc::clearerr: case LibFunc::closedir: case LibFunc::ctermid: case LibFunc::fclose: case LibFunc::feof: case LibFunc::fflush: case LibFunc::fgetc: case LibFunc::fileno: case LibFunc::flockfile: case LibFunc::free: case LibFunc::fseek: case LibFunc::fseeko64: case LibFunc::fseeko: case LibFunc::fsetpos: case LibFunc::ftell: case LibFunc::ftello64: case LibFunc::ftello: case LibFunc::ftrylockfile: case LibFunc::funlockfile: case LibFunc::getc: case LibFunc::getc_unlocked: case LibFunc::getlogin_r: case LibFunc::mkdir: case LibFunc::mktime: case LibFunc::times: return (NumParams != 0 && FTy.getParamType(0)->isPointerTy()); case LibFunc::access: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::fopen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fdopen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fputc: case LibFunc::fstat: case LibFunc::frexp: case LibFunc::frexpf: case LibFunc::frexpl: case LibFunc::fstatvfs: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::fgets: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::fread: return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(3)->isPointerTy()); case LibFunc::fwrite: return (NumParams == 4 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy() && FTy.getParamType(2)->isIntegerTy() && FTy.getParamType(3)->isPointerTy()); case LibFunc::fputs: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fscanf: case LibFunc::fprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fgetpos: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::gets: case LibFunc::getchar: case LibFunc::getitimer: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::ungetc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::utime: case LibFunc::utimes: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::putc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::pread: case LibFunc::pwrite: return (NumParams == 4 && FTy.getParamType(1)->isPointerTy()); case LibFunc::popen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::vscanf: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::vsscanf: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::vfscanf: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::valloc: return (FTy.getReturnType()->isPointerTy()); case LibFunc::vprintf: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::vfprintf: case LibFunc::vsprintf: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::vsnprintf: return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::open: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::opendir: return (NumParams == 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc::tmpfile: return (FTy.getReturnType()->isPointerTy()); case LibFunc::htonl: case LibFunc::htons: case LibFunc::ntohl: case LibFunc::ntohs: case LibFunc::lstat: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::lchown: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy()); case LibFunc::qsort: return (NumParams == 4 && FTy.getParamType(3)->isPointerTy()); case LibFunc::dunder_strdup: case LibFunc::dunder_strndup: return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc::dunder_strtok_r: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc::under_IO_putc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::dunder_isoc99_scanf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc::stat64: case LibFunc::lstat64: case LibFunc::statvfs64: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::dunder_isoc99_sscanf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fopen64: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::tmpfile64: return (FTy.getReturnType()->isPointerTy()); case LibFunc::fstat64: case LibFunc::fstatvfs64: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc::open64: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::gettimeofday: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::Znwj: // new(unsigned int); case LibFunc::Znwm: // new(unsigned long); case LibFunc::Znaj: // new[](unsigned int); case LibFunc::Znam: // new[](unsigned long); case LibFunc::msvc_new_int: // new(unsigned int); case LibFunc::msvc_new_longlong: // new(unsigned long long); case LibFunc::msvc_new_array_int: // new[](unsigned int); case LibFunc::msvc_new_array_longlong: // new[](unsigned long long); return (NumParams == 1); case LibFunc::memset_pattern16: return (!FTy.isVarArg() && NumParams == 3 && isa<PointerType>(FTy.getParamType(0)) && isa<PointerType>(FTy.getParamType(1)) && isa<IntegerType>(FTy.getParamType(2))); // int __nvvm_reflect(const char *); case LibFunc::nvvm_reflect: return (NumParams == 1 && isa<PointerType>(FTy.getParamType(0))); case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl: case LibFunc::cos: case LibFunc::cosf: case LibFunc::cosl: case LibFunc::tan: case LibFunc::tanf: case LibFunc::tanl: case LibFunc::exp: case LibFunc::expf: case LibFunc::expl: case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l: case LibFunc::log: case LibFunc::logf: case LibFunc::logl: case LibFunc::log10: case LibFunc::log10f: case LibFunc::log10l: case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l: case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl: case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl: case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl: case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl: case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl: case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl: case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl: return (NumParams == 1 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl: case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl: case LibFunc::copysign: case LibFunc::copysignf: case LibFunc::copysignl: case LibFunc::pow: case LibFunc::powf: case LibFunc::powl: return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getReturnType() == FTy.getParamType(1)); case LibFunc::ffs: case LibFunc::ffsl: case LibFunc::ffsll: case LibFunc::isdigit: case LibFunc::isascii: case LibFunc::toascii: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isIntegerTy()); case LibFunc::fls: case LibFunc::flsl: case LibFunc::flsll: case LibFunc::abs: case LibFunc::labs: case LibFunc::llabs: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc::cxa_atexit: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc::sinpi: case LibFunc::cospi: return (NumParams == 1 && FTy.getReturnType()->isDoubleTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc::sinpif: case LibFunc::cospif: return (NumParams == 1 && FTy.getReturnType()->isFloatTy() && FTy.getReturnType() == FTy.getParamType(0)); default: // Assume the other functions are correct. // FIXME: It'd be really nice to cover them all. return true; } }
/// Returns the allocation data for the given value if it's either a call to a /// known allocation function, or a call to a function with the allocsize /// attribute. static Optional<AllocFnsTy> getAllocationData(const Value *V, AllocType AllocTy, const TargetLibraryInfo *TLI, bool LookThroughBitCast = false) { // Skip intrinsics if (isa<IntrinsicInst>(V)) return None; const Function *Callee = getCalledFunction(V, LookThroughBitCast); if (!Callee) return None; // If it has allocsize, we can skip checking if it's a known function. // // MallocLike is chosen here because allocsize makes no guarantees about the // nullness of the result of the function, nor does it deal with strings, nor // does it require that the memory returned is zeroed out. LLVM_CONSTEXPR auto AllocSizeAllocTy = MallocLike; if ((AllocTy & AllocSizeAllocTy) == AllocSizeAllocTy && Callee->hasFnAttribute(Attribute::AllocSize)) { Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize); std::pair<unsigned, Optional<unsigned>> Args = Attr.getAllocSizeArgs(); AllocFnsTy Result; Result.AllocTy = AllocSizeAllocTy; Result.NumParams = Callee->getNumOperands(); Result.FstParam = Args.first; Result.SndParam = Args.second.getValueOr(-1); return Result; } // Make sure that the function is available. StringRef FnName = Callee->getName(); LibFunc::Func TLIFn; if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return None; const auto *Iter = std::find_if(std::begin(AllocationFnData), std::end(AllocationFnData), [TLIFn](const std::pair<LibFunc::Func, AllocFnsTy> &P) { return P.first == TLIFn; }); if (Iter == std::end(AllocationFnData)) return None; const AllocFnsTy *FnData = &Iter->second; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) return None; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || FTy->getParamType(FstParam)->isIntegerTy(64))) && (SndParam < 0 || FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return *FnData; return None; }