From 10b4880de3a57e384167506648092b5bca806582 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Sun, 13 Sep 2015 06:47:20 +0000 Subject: [PATCH] Do some spring cleaning on FunctionAttrs.cpp with clang-format prior to other refactorings and cleanups here. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247519 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/FunctionAttrs.cpp | 639 +++++++++++++-------------- 1 file changed, 299 insertions(+), 340 deletions(-) diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index 4860608d239..931a54e09f6 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -52,116 +52,114 @@ STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull"); STATISTIC(NumAnnotated, "Number of attributes added to library functions"); namespace { - struct FunctionAttrs : public CallGraphSCCPass { - static char ID; // Pass identification, replacement for typeid - FunctionAttrs() : CallGraphSCCPass(ID) { - initializeFunctionAttrsPass(*PassRegistry::getPassRegistry()); - } +struct FunctionAttrs : public CallGraphSCCPass { + static char ID; // Pass identification, replacement for typeid + FunctionAttrs() : CallGraphSCCPass(ID) { + initializeFunctionAttrsPass(*PassRegistry::getPassRegistry()); + } - // runOnSCC - Analyze the SCC, performing the transformation if possible. - bool runOnSCC(CallGraphSCC &SCC) override; + // runOnSCC - Analyze the SCC, performing the transformation if possible. + bool runOnSCC(CallGraphSCC &SCC) override; - // AddReadAttrs - Deduce readonly/readnone attributes for the SCC. - bool AddReadAttrs(const CallGraphSCC &SCC); + // AddReadAttrs - Deduce readonly/readnone attributes for the SCC. + bool AddReadAttrs(const CallGraphSCC &SCC); - // AddArgumentAttrs - Deduce nocapture attributes for the SCC. - bool AddArgumentAttrs(const CallGraphSCC &SCC); + // AddArgumentAttrs - Deduce nocapture attributes for the SCC. + bool AddArgumentAttrs(const CallGraphSCC &SCC); - // IsFunctionMallocLike - Does this function allocate new memory? - bool IsFunctionMallocLike(Function *F, - SmallPtrSet &) const; + // IsFunctionMallocLike - Does this function allocate new memory? + bool IsFunctionMallocLike(Function *F, SmallPtrSet &) const; - // AddNoAliasAttrs - Deduce noalias attributes for the SCC. - bool AddNoAliasAttrs(const CallGraphSCC &SCC); + // AddNoAliasAttrs - Deduce noalias attributes for the SCC. + bool AddNoAliasAttrs(const CallGraphSCC &SCC); - /// \brief Does this function return null? - bool ReturnsNonNull(Function *F, SmallPtrSet &, - bool &Speculative) const; + /// \brief Does this function return null? + bool ReturnsNonNull(Function *F, SmallPtrSet &, + bool &Speculative) const; - /// \brief Deduce nonnull attributes for the SCC. - bool AddNonNullAttrs(const CallGraphSCC &SCC); + /// \brief Deduce nonnull attributes for the SCC. + bool AddNonNullAttrs(const CallGraphSCC &SCC); - // Utility methods used by inferPrototypeAttributes to add attributes - // and maintain annotation statistics. + // Utility methods used by inferPrototypeAttributes to add attributes + // and maintain annotation statistics. - void setDoesNotAccessMemory(Function &F) { - if (!F.doesNotAccessMemory()) { - F.setDoesNotAccessMemory(); - ++NumAnnotated; - } + void setDoesNotAccessMemory(Function &F) { + if (!F.doesNotAccessMemory()) { + F.setDoesNotAccessMemory(); + ++NumAnnotated; } + } - void setOnlyReadsMemory(Function &F) { - if (!F.onlyReadsMemory()) { - F.setOnlyReadsMemory(); - ++NumAnnotated; - } + void setOnlyReadsMemory(Function &F) { + if (!F.onlyReadsMemory()) { + F.setOnlyReadsMemory(); + ++NumAnnotated; } + } - void setDoesNotThrow(Function &F) { - if (!F.doesNotThrow()) { - F.setDoesNotThrow(); - ++NumAnnotated; - } + void setDoesNotThrow(Function &F) { + if (!F.doesNotThrow()) { + F.setDoesNotThrow(); + ++NumAnnotated; } + } - void setDoesNotCapture(Function &F, unsigned n) { - if (!F.doesNotCapture(n)) { - F.setDoesNotCapture(n); - ++NumAnnotated; - } + void setDoesNotCapture(Function &F, unsigned n) { + if (!F.doesNotCapture(n)) { + F.setDoesNotCapture(n); + ++NumAnnotated; } + } - void setOnlyReadsMemory(Function &F, unsigned n) { - if (!F.onlyReadsMemory(n)) { - F.setOnlyReadsMemory(n); - ++NumAnnotated; - } + void setOnlyReadsMemory(Function &F, unsigned n) { + if (!F.onlyReadsMemory(n)) { + F.setOnlyReadsMemory(n); + ++NumAnnotated; } + } - void setDoesNotAlias(Function &F, unsigned n) { - if (!F.doesNotAlias(n)) { - F.setDoesNotAlias(n); - ++NumAnnotated; - } + void setDoesNotAlias(Function &F, unsigned n) { + if (!F.doesNotAlias(n)) { + F.setDoesNotAlias(n); + ++NumAnnotated; } + } - // inferPrototypeAttributes - Analyze the name and prototype of the - // given function and set any applicable attributes. Returns true - // if any attributes were set and false otherwise. - bool inferPrototypeAttributes(Function &F); + // inferPrototypeAttributes - Analyze the name and prototype of the + // given function and set any applicable attributes. Returns true + // if any attributes were set and false otherwise. + bool inferPrototypeAttributes(Function &F); - // annotateLibraryCalls - Adds attributes to well-known standard library - // call declarations. - bool annotateLibraryCalls(const CallGraphSCC &SCC); + // annotateLibraryCalls - Adds attributes to well-known standard library + // call declarations. + bool annotateLibraryCalls(const CallGraphSCC &SCC); - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesCFG(); - AU.addRequired(); - AU.addRequired(); - CallGraphSCCPass::getAnalysisUsage(AU); - } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + AU.addRequired(); + AU.addRequired(); + CallGraphSCCPass::getAnalysisUsage(AU); + } - private: - TargetLibraryInfo *TLI; - }; +private: + TargetLibraryInfo *TLI; +}; } char FunctionAttrs::ID = 0; INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs", - "Deduce function attributes", false, false) + "Deduce function attributes", false, false) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END(FunctionAttrs, "functionattrs", - "Deduce function attributes", false, false) + "Deduce function attributes", false, false) Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); } - /// AddReadAttrs - Deduce readonly/readnone attributes for the SCC. bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) { - SmallPtrSet SCCNodes; + SmallPtrSet SCCNodes; // Fill SCCNodes with the elements of the SCC. Used for quickly // looking up whether a given CallGraphNode is in this SCC. @@ -299,11 +297,10 @@ bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) { // Clear out any existing attributes. AttrBuilder B; - B.addAttribute(Attribute::ReadOnly) - .addAttribute(Attribute::ReadNone); - F->removeAttributes(AttributeSet::FunctionIndex, - AttributeSet::get(F->getContext(), - AttributeSet::FunctionIndex, B)); + B.addAttribute(Attribute::ReadOnly).addAttribute(Attribute::ReadNone); + F->removeAttributes( + AttributeSet::FunctionIndex, + AttributeSet::get(F->getContext(), AttributeSet::FunctionIndex, B)); // Add in the new attribute. F->addAttribute(AttributeSet::FunctionIndex, @@ -319,123 +316,127 @@ bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) { } namespace { - // For a given pointer Argument, this retains a list of Arguments of functions - // in the same SCC that the pointer data flows into. We use this to build an - // SCC of the arguments. - struct ArgumentGraphNode { - Argument *Definition; - SmallVector Uses; - }; - - class ArgumentGraph { - // We store pointers to ArgumentGraphNode objects, so it's important that - // that they not move around upon insert. - typedef std::map ArgumentMapTy; - - ArgumentMapTy ArgumentMap; - - // There is no root node for the argument graph, in fact: - // void f(int *x, int *y) { if (...) f(x, y); } - // is an example where the graph is disconnected. The SCCIterator requires a - // single entry point, so we maintain a fake ("synthetic") root node that - // uses every node. Because the graph is directed and nothing points into - // the root, it will not participate in any SCCs (except for its own). - ArgumentGraphNode SyntheticRoot; - - public: - ArgumentGraph() { SyntheticRoot.Definition = nullptr; } - - typedef SmallVectorImpl::iterator iterator; - - iterator begin() { return SyntheticRoot.Uses.begin(); } - iterator end() { return SyntheticRoot.Uses.end(); } - ArgumentGraphNode *getEntryNode() { return &SyntheticRoot; } - - ArgumentGraphNode *operator[](Argument *A) { - ArgumentGraphNode &Node = ArgumentMap[A]; - Node.Definition = A; - SyntheticRoot.Uses.push_back(&Node); - return &Node; - } - }; +// For a given pointer Argument, this retains a list of Arguments of functions +// in the same SCC that the pointer data flows into. We use this to build an +// SCC of the arguments. +struct ArgumentGraphNode { + Argument *Definition; + SmallVector Uses; +}; + +class ArgumentGraph { + // We store pointers to ArgumentGraphNode objects, so it's important that + // that they not move around upon insert. + typedef std::map ArgumentMapTy; + + ArgumentMapTy ArgumentMap; + + // There is no root node for the argument graph, in fact: + // void f(int *x, int *y) { if (...) f(x, y); } + // is an example where the graph is disconnected. The SCCIterator requires a + // single entry point, so we maintain a fake ("synthetic") root node that + // uses every node. Because the graph is directed and nothing points into + // the root, it will not participate in any SCCs (except for its own). + ArgumentGraphNode SyntheticRoot; + +public: + ArgumentGraph() { SyntheticRoot.Definition = nullptr; } + + typedef SmallVectorImpl::iterator iterator; + + iterator begin() { return SyntheticRoot.Uses.begin(); } + iterator end() { return SyntheticRoot.Uses.end(); } + ArgumentGraphNode *getEntryNode() { return &SyntheticRoot; } + + ArgumentGraphNode *operator[](Argument *A) { + ArgumentGraphNode &Node = ArgumentMap[A]; + Node.Definition = A; + SyntheticRoot.Uses.push_back(&Node); + return &Node; + } +}; - // This tracker checks whether callees are in the SCC, and if so it does not - // consider that a capture, instead adding it to the "Uses" list and - // continuing with the analysis. - struct ArgumentUsesTracker : public CaptureTracker { - ArgumentUsesTracker(const SmallPtrSet &SCCNodes) +// This tracker checks whether callees are in the SCC, and if so it does not +// consider that a capture, instead adding it to the "Uses" list and +// continuing with the analysis. +struct ArgumentUsesTracker : public CaptureTracker { + ArgumentUsesTracker(const SmallPtrSet &SCCNodes) : Captured(false), SCCNodes(SCCNodes) {} - void tooManyUses() override { Captured = true; } + void tooManyUses() override { Captured = true; } - bool captured(const Use *U) override { - CallSite CS(U->getUser()); - if (!CS.getInstruction()) { Captured = true; return true; } + bool captured(const Use *U) override { + CallSite CS(U->getUser()); + if (!CS.getInstruction()) { + Captured = true; + return true; + } - Function *F = CS.getCalledFunction(); - if (!F || !SCCNodes.count(F)) { Captured = true; return true; } + Function *F = CS.getCalledFunction(); + if (!F || !SCCNodes.count(F)) { + Captured = true; + return true; + } - bool Found = false; - Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end(); - for (CallSite::arg_iterator PI = CS.arg_begin(), PE = CS.arg_end(); - PI != PE; ++PI, ++AI) { - if (AI == AE) { - assert(F->isVarArg() && "More params than args in non-varargs call"); - Captured = true; - return true; - } - if (PI == U) { - Uses.push_back(AI); - Found = true; - break; - } + bool Found = false; + Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end(); + for (CallSite::arg_iterator PI = CS.arg_begin(), PE = CS.arg_end(); + PI != PE; ++PI, ++AI) { + if (AI == AE) { + assert(F->isVarArg() && "More params than args in non-varargs call"); + Captured = true; + return true; + } + if (PI == U) { + Uses.push_back(AI); + Found = true; + break; } - assert(Found && "Capturing call-site captured nothing?"); - (void)Found; - return false; } + assert(Found && "Capturing call-site captured nothing?"); + (void)Found; + return false; + } - bool Captured; // True only if certainly captured (used outside our SCC). - SmallVector Uses; // Uses within our SCC. + bool Captured; // True only if certainly captured (used outside our SCC). + SmallVector Uses; // Uses within our SCC. - const SmallPtrSet &SCCNodes; - }; + const SmallPtrSet &SCCNodes; +}; } namespace llvm { - template<> struct GraphTraits { - typedef ArgumentGraphNode NodeType; - typedef SmallVectorImpl::iterator ChildIteratorType; +template <> struct GraphTraits { + typedef ArgumentGraphNode NodeType; + typedef SmallVectorImpl::iterator ChildIteratorType; - static inline NodeType *getEntryNode(NodeType *A) { return A; } - static inline ChildIteratorType child_begin(NodeType *N) { - return N->Uses.begin(); - } - static inline ChildIteratorType child_end(NodeType *N) { - return N->Uses.end(); - } - }; - template<> struct GraphTraits - : public GraphTraits { - static NodeType *getEntryNode(ArgumentGraph *AG) { - return AG->getEntryNode(); - } - static ChildIteratorType nodes_begin(ArgumentGraph *AG) { - return AG->begin(); - } - static ChildIteratorType nodes_end(ArgumentGraph *AG) { - return AG->end(); - } - }; + static inline NodeType *getEntryNode(NodeType *A) { return A; } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->Uses.begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->Uses.end(); + } +}; +template <> +struct GraphTraits : public GraphTraits { + static NodeType *getEntryNode(ArgumentGraph *AG) { + return AG->getEntryNode(); + } + static ChildIteratorType nodes_begin(ArgumentGraph *AG) { + return AG->begin(); + } + static ChildIteratorType nodes_end(ArgumentGraph *AG) { return AG->end(); } +}; } // Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone. static Attribute::AttrKind determinePointerReadAttrs(Argument *A, - const SmallPtrSet &SCCNodes) { - - SmallVector Worklist; - SmallSet Visited; + const SmallPtrSet &SCCNodes) { + + SmallVector Worklist; + SmallSet Visited; // inalloca arguments are always clobbered by the call. if (A->hasInAllocaAttr()) @@ -538,7 +539,7 @@ determinePointerReadAttrs(Argument *A, bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { bool Changed = false; - SmallPtrSet SCCNodes; + SmallPtrSet SCCNodes; // Fill SCCNodes with the elements of the SCC. Used for quickly // looking up whether a given CallGraphNode is in this SCC. @@ -573,8 +574,8 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { // a value can't capture arguments. Don't analyze them. if (F->onlyReadsMemory() && F->doesNotThrow() && F->getReturnType()->isVoidTy()) { - for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); - A != E; ++A) { + for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E; + ++A) { if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) { A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo() + 1, B)); ++NumNoCapture; @@ -584,9 +585,10 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { continue; } - for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); - A != E; ++A) { - if (!A->getType()->isPointerTy()) continue; + for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A != E; + ++A) { + if (!A->getType()->isPointerTy()) + continue; bool HasNonLocalUses = false; if (!A->hasNoCaptureAttr()) { ArgumentUsesTracker Tracker(SCCNodes); @@ -594,7 +596,8 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { if (!Tracker.Captured) { if (Tracker.Uses.empty()) { // If it's trivially not captured, mark it nocapture now. - A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo()+1, B)); + A->addAttr( + AttributeSet::get(F->getContext(), A->getArgNo() + 1, B)); ++NumNoCapture; Changed = true; } else { @@ -602,8 +605,10 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { // then it must be calling into another function in our SCC. Save // its particulars for Argument-SCC analysis later. ArgumentGraphNode *Node = AG[A]; - for (SmallVectorImpl::iterator UI = Tracker.Uses.begin(), - UE = Tracker.Uses.end(); UI != UE; ++UI) { + for (SmallVectorImpl::iterator + UI = Tracker.Uses.begin(), + UE = Tracker.Uses.end(); + UI != UE; ++UI) { Node->Uses.push_back(AG[*UI]); if (*UI != A) HasNonLocalUses = true; @@ -617,7 +622,7 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { // Note that we don't allow any calls at all here, or else our result // will be dependent on the iteration order through the functions in the // SCC. - SmallPtrSet Self; + SmallPtrSet Self; Self.insert(A); Attribute::AttrKind R = determinePointerReadAttrs(A, Self); if (R != Attribute::None) { @@ -638,10 +643,11 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { // made. If the definition doesn't have a 'nocapture' attribute by now, it // captures. - for (scc_iterator I = scc_begin(&AG); !I.isAtEnd(); ++I) { + for (scc_iterator I = scc_begin(&AG); !I.isAtEnd(); ++I) { const std::vector &ArgumentSCC = *I; if (ArgumentSCC.size() == 1) { - if (!ArgumentSCC[0]->Definition) continue; // synthetic root node + if (!ArgumentSCC[0]->Definition) + continue; // synthetic root node // eg. "void f(int* x) { if (...) f(x); }" if (ArgumentSCC[0]->Uses.size() == 1 && @@ -663,9 +669,10 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { SCCCaptured = true; } } - if (SCCCaptured) continue; + if (SCCCaptured) + continue; - SmallPtrSet ArgumentSCCNodes; + SmallPtrSet ArgumentSCCNodes; // Fill ArgumentSCCNodes with the elements of the ArgumentSCC. Used for // quickly looking up whether a given Argument is in this ArgumentSCC. for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); I != E; ++I) { @@ -675,8 +682,9 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { for (auto I = ArgumentSCC.begin(), E = ArgumentSCC.end(); I != E && !SCCCaptured; ++I) { ArgumentGraphNode *N = *I; - for (SmallVectorImpl::iterator UI = N->Uses.begin(), - UE = N->Uses.end(); UI != UE; ++UI) { + for (SmallVectorImpl::iterator UI = N->Uses.begin(), + UE = N->Uses.end(); + UI != UE; ++UI) { Argument *A = (*UI)->Definition; if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A)) continue; @@ -684,7 +692,8 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { break; } } - if (SCCCaptured) continue; + if (SCCCaptured) + continue; for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { Argument *A = ArgumentSCC[i]->Definition; @@ -721,8 +730,7 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { if (ReadAttr != Attribute::None) { AttrBuilder B, R; B.addAttribute(ReadAttr); - R.addAttribute(Attribute::ReadOnly) - .addAttribute(Attribute::ReadNone); + R.addAttribute(Attribute::ReadOnly).addAttribute(Attribute::ReadNone); for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { Argument *A = ArgumentSCC[i]->Definition; // Clear out existing readonly/readnone attributes @@ -739,8 +747,8 @@ bool FunctionAttrs::AddArgumentAttrs(const CallGraphSCC &SCC) { /// IsFunctionMallocLike - A function is malloc-like if it returns either null /// or a pointer that doesn't alias any other pointer visible to the caller. -bool FunctionAttrs::IsFunctionMallocLike(Function *F, - SmallPtrSet &SCCNodes) const { +bool FunctionAttrs::IsFunctionMallocLike( + Function *F, SmallPtrSet &SCCNodes) const { SmallSetVector FlowsToReturn; for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) if (ReturnInst *Ret = dyn_cast(I->getTerminator())) @@ -761,39 +769,38 @@ bool FunctionAttrs::IsFunctionMallocLike(Function *F, if (Instruction *RVI = dyn_cast(RetVal)) switch (RVI->getOpcode()) { - // Extend the analysis by looking upwards. - case Instruction::BitCast: - case Instruction::GetElementPtr: - case Instruction::AddrSpaceCast: - FlowsToReturn.insert(RVI->getOperand(0)); - continue; - case Instruction::Select: { - SelectInst *SI = cast(RVI); - FlowsToReturn.insert(SI->getTrueValue()); - FlowsToReturn.insert(SI->getFalseValue()); - continue; - } - case Instruction::PHI: { - PHINode *PN = cast(RVI); - for (Value *IncValue : PN->incoming_values()) - FlowsToReturn.insert(IncValue); - continue; - } + // Extend the analysis by looking upwards. + case Instruction::BitCast: + case Instruction::GetElementPtr: + case Instruction::AddrSpaceCast: + FlowsToReturn.insert(RVI->getOperand(0)); + continue; + case Instruction::Select: { + SelectInst *SI = cast(RVI); + FlowsToReturn.insert(SI->getTrueValue()); + FlowsToReturn.insert(SI->getFalseValue()); + continue; + } + case Instruction::PHI: { + PHINode *PN = cast(RVI); + for (Value *IncValue : PN->incoming_values()) + FlowsToReturn.insert(IncValue); + continue; + } - // Check whether the pointer came from an allocation. - case Instruction::Alloca: + // Check whether the pointer came from an allocation. + case Instruction::Alloca: + break; + case Instruction::Call: + case Instruction::Invoke: { + CallSite CS(RVI); + if (CS.paramHasAttr(0, Attribute::NoAlias)) + break; + if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction())) break; - case Instruction::Call: - case Instruction::Invoke: { - CallSite CS(RVI); - if (CS.paramHasAttr(0, Attribute::NoAlias)) - break; - if (CS.getCalledFunction() && - SCCNodes.count(CS.getCalledFunction())) - break; - } // fall-through - default: - return false; // Did not come from an allocation. + } // fall-through + default: + return false; // Did not come from an allocation. } if (PointerMayBeCaptured(RetVal, false, /*StoreCaptures=*/false)) @@ -805,7 +812,7 @@ bool FunctionAttrs::IsFunctionMallocLike(Function *F, /// AddNoAliasAttrs - Deduce noalias attributes for the SCC. bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) { - SmallPtrSet SCCNodes; + SmallPtrSet SCCNodes; // Fill SCCNodes with the elements of the SCC. Used for quickly // looking up whether a given CallGraphNode is in this SCC. @@ -830,7 +837,7 @@ bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) { if (F->isDeclaration() || F->mayBeOverridden()) return false; - // We annotate noalias return values, which are only applicable to + // We annotate noalias return values, which are only applicable to // pointer types. if (!F->getReturnType()->isPointerTy()) continue; @@ -854,12 +861,12 @@ bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) { } bool FunctionAttrs::ReturnsNonNull(Function *F, - SmallPtrSet &SCCNodes, + SmallPtrSet &SCCNodes, bool &Speculative) const { assert(F->getReturnType()->isPointerTy() && "nonnull only meaningful on pointer types"); Speculative = false; - + SmallSetVector FlowsToReturn; for (BasicBlock &BB : *F) if (auto *Ret = dyn_cast(BB.getTerminator())) @@ -873,12 +880,12 @@ bool FunctionAttrs::ReturnsNonNull(Function *F, continue; // Otherwise, we need to look upwards since we can't make any local - // conclusions. + // conclusions. Instruction *RVI = dyn_cast(RetVal); if (!RVI) return false; switch (RVI->getOpcode()) { - // Extend the analysis by looking upwards. + // Extend the analysis by looking upwards. case Instruction::BitCast: case Instruction::GetElementPtr: case Instruction::AddrSpaceCast: @@ -909,7 +916,7 @@ bool FunctionAttrs::ReturnsNonNull(Function *F, return false; } default: - return false; // Unknown source, may be null + return false; // Unknown source, may be null }; llvm_unreachable("should have either continued or returned"); } @@ -918,7 +925,7 @@ bool FunctionAttrs::ReturnsNonNull(Function *F, } bool FunctionAttrs::AddNonNullAttrs(const CallGraphSCC &SCC) { - SmallPtrSet SCCNodes; + SmallPtrSet SCCNodes; // Fill SCCNodes with the elements of the SCC. Used for quickly // looking up whether a given CallGraphNode is in this SCC. @@ -950,7 +957,7 @@ bool FunctionAttrs::AddNonNullAttrs(const CallGraphSCC &SCC) { if (F->isDeclaration() || F->mayBeOverridden()) return false; - // We annotate nonnull return values, which are only applicable to + // We annotate nonnull return values, which are only applicable to // pointer types. if (!F->getReturnType()->isPointerTy()) continue; @@ -1012,8 +1019,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { break; case LibFunc::strchr: case LibFunc::strrchr: - if (FTy->getNumParams() != 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isIntegerTy()) return false; setOnlyReadsMemory(F); @@ -1026,8 +1032,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { case LibFunc::strtoll: case LibFunc::strtold: case LibFunc::strtoull: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(1)->isPointerTy()) + if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); @@ -1039,16 +1044,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { case LibFunc::strncat: case LibFunc::strncpy: case LibFunc::stpncpy: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(1)->isPointerTy()) + if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); setOnlyReadsMemory(F, 2); break; case LibFunc::strxfrm: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1056,15 +1059,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 2); setOnlyReadsMemory(F, 2); break; - case LibFunc::strcmp: //0,1 - case LibFunc::strspn: // 0,1 - case LibFunc::strncmp: // 0,1 - case LibFunc::strcspn: //0,1 - case LibFunc::strcoll: //0,1 - case LibFunc::strcasecmp: // 0,1 - case LibFunc::strncasecmp: // - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + case LibFunc::strcmp: // 0,1 + case LibFunc::strspn: // 0,1 + case LibFunc::strncmp: // 0,1 + case LibFunc::strcspn: // 0,1 + case LibFunc::strcoll: // 0,1 + case LibFunc::strcasecmp: // 0,1 + case LibFunc::strncasecmp: // + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setOnlyReadsMemory(F); @@ -1114,8 +1116,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { break; case LibFunc::stat: case LibFunc::statvfs: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1124,8 +1125,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 1); break; case LibFunc::sscanf: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1135,8 +1135,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::sprintf: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1145,8 +1144,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::snprintf: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(2)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1155,8 +1153,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 3); break; case LibFunc::setitimer: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(1)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() || !FTy->getParamType(2)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1165,23 +1162,20 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::system: - if (FTy->getNumParams() != 1 || - !FTy->getParamType(0)->isPointerTy()) + if (FTy->getNumParams() != 1 || !FTy->getParamType(0)->isPointerTy()) return false; // May throw; "system" is a valid pthread cancellation point. setDoesNotCapture(F, 1); setOnlyReadsMemory(F, 1); break; case LibFunc::malloc: - if (FTy->getNumParams() != 1 || - !FTy->getReturnType()->isPointerTy()) + if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotAlias(F, 0); break; case LibFunc::memcmp: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setOnlyReadsMemory(F); @@ -1199,8 +1193,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { case LibFunc::modf: case LibFunc::modff: case LibFunc::modfl: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(1)->isPointerTy()) + if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); @@ -1208,8 +1201,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { case LibFunc::memcpy: case LibFunc::memccpy: case LibFunc::memmove: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(1)->isPointerTy()) + if (FTy->getNumParams() < 2 || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); @@ -1221,23 +1213,20 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotAlias(F, 0); break; case LibFunc::mkdir: - if (FTy->getNumParams() == 0 || - !FTy->getParamType(0)->isPointerTy()) + if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); setOnlyReadsMemory(F, 1); break; case LibFunc::mktime: - if (FTy->getNumParams() == 0 || - !FTy->getParamType(0)->isPointerTy()) + if (FTy->getNumParams() == 0 || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); break; case LibFunc::realloc: - if (FTy->getNumParams() != 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getReturnType()->isPointerTy()) return false; setDoesNotThrow(F); @@ -1245,15 +1234,13 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 1); break; case LibFunc::read: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(1)->isPointerTy()) + if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy()) return false; // May throw; "read" is a valid pthread cancellation point. setDoesNotCapture(F, 2); break; case LibFunc::rewind: - if (FTy->getNumParams() < 1 || - !FTy->getParamType(0)->isPointerTy()) + if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); @@ -1261,16 +1248,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { case LibFunc::rmdir: case LibFunc::remove: case LibFunc::realpath: - if (FTy->getNumParams() < 1 || - !FTy->getParamType(0)->isPointerTy()) + if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); setOnlyReadsMemory(F, 1); break; case LibFunc::rename: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1280,8 +1265,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::readlink: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1297,8 +1281,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::bcopy: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1307,8 +1290,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 1); break; case LibFunc::bcmp: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1323,8 +1305,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 1); break; case LibFunc::calloc: - if (FTy->getNumParams() != 2 || - !FTy->getReturnType()->isPointerTy()) + if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotAlias(F, 0); @@ -1363,8 +1344,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 1); break; case LibFunc::fopen: - if (FTy->getNumParams() != 2 || - !FTy->getReturnType()->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; @@ -1376,8 +1356,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::fdopen: - if (FTy->getNumParams() != 2 || - !FTy->getReturnType()->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1423,16 +1402,14 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 2); break; case LibFunc::fgets: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(2)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 3); break; case LibFunc::fread: - if (FTy->getNumParams() != 4 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(3)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1440,8 +1417,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 4); break; case LibFunc::fwrite: - if (FTy->getNumParams() != 4 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(3)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1449,8 +1425,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 4); break; case LibFunc::fputs: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1460,8 +1435,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { break; case LibFunc::fscanf: case LibFunc::fprintf: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1470,8 +1444,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::fgetpos: - if (FTy->getNumParams() < 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1538,8 +1511,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { break; case LibFunc::utime: case LibFunc::utimes: - if (FTy->getNumParams() != 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1580,8 +1552,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotThrow(F); break; case LibFunc::popen: - if (FTy->getNumParams() != 2 || - !FTy->getReturnType()->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; @@ -1606,8 +1577,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 1); break; case LibFunc::vsscanf: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(1)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() || !FTy->getParamType(2)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1617,8 +1587,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::vfscanf: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(1)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy() || !FTy->getParamType(2)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1641,8 +1610,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { break; case LibFunc::vfprintf: case LibFunc::vsprintf: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 3 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1651,8 +1619,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::vsnprintf: - if (FTy->getNumParams() != 4 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 4 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(2)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1668,8 +1635,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 1); break; case LibFunc::opendir: - if (FTy->getNumParams() != 1 || - !FTy->getReturnType()->isPointerTy() || + if (FTy->getNumParams() != 1 || !FTy->getReturnType()->isPointerTy() || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1697,8 +1663,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotAccessMemory(F); break; case LibFunc::lstat: - if (FTy->getNumParams() != 2 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1721,8 +1686,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { break; case LibFunc::dunder_strdup: case LibFunc::dunder_strndup: - if (FTy->getNumParams() < 1 || - !FTy->getReturnType()->isPointerTy() || + if (FTy->getNumParams() < 1 || !FTy->getReturnType()->isPointerTy() || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1731,8 +1695,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 1); break; case LibFunc::dunder_strtok_r: - if (FTy->getNumParams() != 3 || - !FTy->getParamType(1)->isPointerTy()) + if (FTy->getNumParams() != 3 || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 2); @@ -1751,8 +1714,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setDoesNotCapture(F, 2); break; case LibFunc::dunder_isoc99_scanf: - if (FTy->getNumParams() < 1 || - !FTy->getParamType(0)->isPointerTy()) + if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy()) return false; setDoesNotThrow(F); setDoesNotCapture(F, 1); @@ -1761,8 +1723,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { case LibFunc::stat64: case LibFunc::lstat64: case LibFunc::statvfs64: - if (FTy->getNumParams() < 1 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1771,8 +1732,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 1); break; case LibFunc::dunder_isoc99_sscanf: - if (FTy->getNumParams() < 1 || - !FTy->getParamType(0)->isPointerTy() || + if (FTy->getNumParams() < 1 || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; setDoesNotThrow(F); @@ -1782,8 +1742,7 @@ bool FunctionAttrs::inferPrototypeAttributes(Function &F) { setOnlyReadsMemory(F, 2); break; case LibFunc::fopen64: - if (FTy->getNumParams() != 2 || - !FTy->getReturnType()->isPointerTy() || + if (FTy->getNumParams() != 2 || !FTy->getReturnType()->isPointerTy() || !FTy->getParamType(0)->isPointerTy() || !FTy->getParamType(1)->isPointerTy()) return false; -- 2.34.1