diff --git a/include/tsar/Analysis/Clang/Passes.h b/include/tsar/Analysis/Clang/Passes.h index 50d9bac4..2d3de0f8 100644 --- a/include/tsar/Analysis/Clang/Passes.h +++ b/include/tsar/Analysis/Clang/Passes.h @@ -149,5 +149,23 @@ void initializeClangIncludeTreeOnlyViewerPass(PassRegistry &Registry); /// Create a pass to display source file tree (filenames instead of /// full paths). ModulePass *createClangIncludeTreeOnlyViewer(); + +/// Initialize a pass to build source control flow graph. +void initializeClangSourceCFGPassPass(PassRegistry &Registry); + +/// Create a pass to build source control flow graph. +FunctionPass *createClangSourceCFGPass(); + +/// Initialize a pass to print source control flow graph to 'dot' file. +void initializeClangSourceCFGPrinterPass(PassRegistry &Registry); + +/// Create a pass to print source control flow graph to 'dot' file. +FunctionPass *createClangSourceCFGPrinter(); + +/// Initialize a pass to display source control flow graph. +void initializeClangSourceCFGViewerPass(PassRegistry &Registry); + +/// Create a pass to display source control flow graph. +FunctionPass *createClangSourceCFGViewer(); } #endif//TSAR_CLANG_ANALYSIS_PASSES_H diff --git a/include/tsar/Analysis/Clang/SourceCFG.h b/include/tsar/Analysis/Clang/SourceCFG.h new file mode 100644 index 00000000..0c1b7ef4 --- /dev/null +++ b/include/tsar/Analysis/Clang/SourceCFG.h @@ -0,0 +1,543 @@ +#ifndef TSAR_CLANG_INCLUDE_SOURCECFG_H +#define TSAR_CLANG_INCLUDE_SOURCECFG_H + +#include "tsar/Analysis/Clang/Passes.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //For Inverse + +namespace tsar { + +class SourceCFGNode; +class SourceCFGEdge; +class SourceCFG; +class SourceCFGBuilder; +using SourceCFGNodeBase=llvm::DGNode; +using SourceCFGEdgeBase=llvm::DGEdge; +using SourceCFGBase=llvm::DirectedGraph; +using StmtStringType=std::string; +class ReferenceNodeOp; +class NativeNodeOp; + +class NodeOp { + friend class ReferenceNodeOp; + friend class NativeNodeOp; + friend class SourceCFGBuilder; +public: + enum class NodeOpKind {Native, Wrapper, Reference}; + NodeOp(NodeOpKind _mKind) : mKind(_mKind), mIsReferred(false) {} + NodeOp(const NodeOp &_N) = default; + NodeOpKind getKind() const { return mKind; }; + void print(StmtStringType &ResStr) const; + std::string getOpAddr() const; + + void printRefDecl(StmtStringType &ResStr) const { + if (mIsReferred) { + ResStr+="getKind()==NodeOpKind::Wrapper; + } + + std::string getOpAddr() const { + return "0x"+(std::stringstream()<()).str(); + } + + ~WrapperNodeOp() { + for (auto L : Leaves) + L->destroy(); + } +private: + clang::DynTypedNode Op; + std::vector Leaves; +}; + +class NativeNodeOp : public NodeOp { + friend class SourceCFGBuilder; +public: + NativeNodeOp(clang::Stmt *_Op) : NodeOp(NodeOpKind::Native), + Op(clang::DynTypedNode::create(*_Op)) {} + NativeNodeOp(clang::VarDecl *_Op) : NodeOp(NodeOpKind::Native), + Op(clang::DynTypedNode::create(*_Op)) {} + NativeNodeOp(const WrapperNodeOp &WNO) : NodeOp(WNO), Op(WNO.Op) { + mKind=NodeOpKind::Native; + } + static bool classof(const NodeOp *Node) { + return Node->getKind()==NodeOpKind::Native; + } + + void print(StmtStringType &ResStr) const { + llvm::raw_string_ostream StrStream(ResStr); + printRefDecl(ResStr); + if (Op.get()) { + Op.getUnchecked().printPretty(StrStream, nullptr, + clang::PrintingPolicy(clang::LangOptions())); + } + else + Op.getUnchecked().print(StrStream); + } + + std::string getOpAddr() const { + return "0x"+(std::stringstream()<()).str(); + } + ~NativeNodeOp() = default; +private: + clang::DynTypedNode Op; +}; + +class ReferenceNodeOp : public NodeOp { + friend class SourceCFGBuilder; +public: + ReferenceNodeOp(NodeOp *_mReferredNode, std::string _mReferenceName) + : NodeOp(NodeOpKind::Reference), mReferredNode(_mReferredNode), + mReferenceName(_mReferenceName) { + mReferredNode->mIsReferred=true; + } + static bool classof(const NodeOp *Node) { + return Node->getKind()==NodeOpKind::Reference; + } + void print(StmtStringType &ResStr) const { + ResStr+="<"+mReferenceName+mReferredNode->getOpAddr()+"_REFERRENCE_>"; + } + std::string getOpAddr() const { + return "0x"+(std::stringstream()<(*mLabel)) + ResStr="default"; + else + ((clang::CaseStmt*)mLabel)->getLHS()->printPretty(StrStream, nullptr, + clang::PrintingPolicy(clang::LangOptions())); + return ResStr; + } + + ~LabeledSCFGEdge() = default; +private: + clang::SwitchCase *mLabel; +}; + +class SourceCFGNode : public SourceCFGNodeBase { + friend class SourceCFG; + friend class SourceCFGBuilder; +public: + using OpStorageType=std::vector; + SourceCFGNode() = default; + std::size_t size() const { return mBlock.size(); } + NodeOp &operator[](int Index) { return *mBlock[Index]; } + void clearBlock() { + for (auto Op : mBlock) + Op->destroy(); + mBlock.clear(); + } + + ~SourceCFGNode() { + clearBlock(); + } + + inline SourceCFGEdge *addNewEdge(SourceCFGNode &TargetNode, + SourceCFGEdge::EdgeKind Ekind) { + SourceCFGEdge *ResEdge=new SourceCFGEdge(TargetNode, Ekind); + if (addEdge(*ResEdge)) + return ResEdge; + else { + delete ResEdge; + return nullptr; + } + } + + void merge(SourceCFGNode &NodeToAttach); + SourceCFG *getParent() { return OwningGraph; } + explicit operator std::string() const; + void printAsOperand(llvm::raw_ostream &OS, bool B) { + OS< + OpStorageType::iterator addOp(It begin, It end) { + for (auto I=begin; I!=end; ++I) + mBlock.push_back(*I); + return mBlock.end()-1; + } + OpStorageType mBlock; +}; + +class SourceCFG : public SourceCFGBase { + friend class SourceCFGBuilder; +public: + SourceCFG(const std::string &_mFunctionName) : mFunctionName(_mFunctionName), + mStartNode(nullptr) {} + + + inline bool addNode(SourceCFGNode &N) { + return SourceCFGBase::addNode(N)?N.OwningGraph=this, true:false; + } + + SourceCFGNode &emplaceNode() { + SourceCFGNode *CurrNode=new SourceCFGNode(); + addNode(*CurrNode); + return *CurrNode; + } + + inline void bindNodes(SourceCFGNode &SourceNode, + SourceCFGNode &TargetNode ) { + connect(SourceNode, TargetNode, *(new DefaultSCFGEdge(TargetNode, + DefaultSCFGEdge::EdgeType::Default))); + } + + inline void bindNodes(SourceCFGNode &SourceNode, SourceCFGNode &TargetNode, + DefaultSCFGEdge::EdgeType EdgeType) { + connect(SourceNode, TargetNode, *(new DefaultSCFGEdge(TargetNode, + EdgeType))); + } + + inline void bindNodes(SourceCFGNode &SourceNode, SourceCFGNode &TargetNode, + clang::SwitchCase *Label) { + connect(SourceNode, TargetNode, *(new LabeledSCFGEdge(TargetNode, Label))); + } + // Needed for GraphTraits + inline SourceCFGNode *getEntryNode() const { return mStartNode; } + inline llvm::StringRef getName() const { return mFunctionName; } + void mergeNodes(SourceCFGNode &AbsorbNode, SourceCFGNode &OutgoingNode); + void deleteNode(SourceCFGNode &_Node); + void deleteEdge(SourceCFGEdge &_Edge); + SourceCFGNode *splitNode(SourceCFGNode &Node, int It); + void recalculatePredMap(); + + std::set &getPredMap(SourceCFGNode *Node) { + return mPredecessorsMap[Node]; + } + + bool findParentNodes(const SourceCFGNode &RequestedNode, + llvm::SmallVectorImpl &ParentNodes) { + bool Result=false; + for (auto N : *this) + if (N->hasEdgeTo(RequestedNode)) { + ParentNodes.push_back(N); + Result=true; + } + return Result; + } + + void view(const SourceCFGNode &SCFGN, + const llvm::Twine &Name="source cfg") const { + llvm::ViewGraph(this, Name, false, + llvm::DOTGraphTraits::getGraphName(this)); + } + + std::string write(const SourceCFGNode &SCFGN, + const llvm::Twine &Name="source cfg") const { + return llvm::WriteGraph(this, Name, false, + llvm::DOTGraphTraits::getGraphName(this)); + } + + ~SourceCFG() { + for (auto N : Nodes) { + for (auto E : N->getEdges()) + E->destroy(); + delete N; + } + } +private: + std::string mFunctionName; + SourceCFGNode *mStartNode; + std::map> mPredecessorsMap; +}; + +class SourceCFGBuilder { +public: + SourceCFGBuilder() : mSCFG(nullptr), mEntryNode(nullptr), + mNodeToAdd(nullptr), mTreeTopParentPtr(nullptr), + mPrevFirstLabel({nullptr, 0}) {} + SourceCFG *populate(clang::FunctionDecl *Decl); +private: + using MarkedOutsType=llvm::DenseMap; + using OutsType=llvm::SmallPtrSet; + + struct LabelInfo { + SourceCFGNode *Node; + size_t LabelIt; + }; + + friend bool operator<(const LabelInfo&, const LabelInfo&); + void parseCompoundStmt(clang::CompoundStmt *Root); + void parseIfStmt(clang::IfStmt *Root); + void parseStmt(clang::Stmt *Root); + void parseDoStmt(clang::DoStmt *Root); + void parseExpr(clang::DynTypedNode Op, NodeOp *ParentOp, bool isFirstCall); + void parseWhileStmt(clang::WhileStmt *Root); + void parseBreakStmt(clang::BreakStmt *Root); + void parseContinueStmt(clang::ContinueStmt *Root); + void parseReturnStmt(clang::ReturnStmt *Root); + void parseLabelStmt(clang::Stmt *Root); + void parseGotoStmt(clang::GotoStmt *Root); + void parseDeclStmt(clang::DeclStmt *Root, NodeOp *ParentOp); + void parseForStmt(clang::ForStmt *Root); + void parseSwitchStmt(clang::SwitchStmt *Root); + void processIndirect(SourceCFGNode *CondStartNode); + void eliminateUnreached(); + void continueFlow(tsar::NodeOp *Op); + void processLabels(); + bool hasConditionalOperator(clang::Stmt *Root); + SourceCFG *mSCFG; + llvm::SmallDenseMap mLabels; + llvm::SmallVector> mGotos; + llvm::SmallVector> mSwitchGotos; + LabelInfo mPrevFirstLabel; + size_t mLastLabelIt; + SourceCFGNode *mEntryNode, *mNodeToAdd; + std::vector mDirectOut; + std::stack mContinueOut, mBreakOut; + std::stack mSwitchNodes; + NodeOp *mTreeTopParentPtr; +}; +} //namespace tsar + +namespace llvm { + +class ClangSourceCFGPass : public FunctionPass, private bcl::Uncopyable { +public: + static char ID; + ClangSourceCFGPass() : FunctionPass(ID), mSCFG(nullptr) { + initializeClangSourceCFGPassPass(*PassRegistry::getPassRegistry()); + } + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; + void releaseMemory() { + mSCFGBuilder=tsar::SourceCFGBuilder(); + if (mSCFG) { + delete mSCFG; + mSCFG=nullptr; + } + } + inline tsar::SourceCFG &getSourceCFG() { return *mSCFG; } +private: + tsar::SourceCFGBuilder mSCFGBuilder; + tsar::SourceCFG *mSCFG; +}; + +template<> struct GraphTraits { + using NodeRef=tsar::SourceCFGNode*; + static tsar::SourceCFGNode *SCFGGetTargetNode(tsar::SourceCFGEdge *E) { + return &E->getTargetNode(); + } + using ChildIteratorType=mapped_iterator; + using ChildEdgeIteratorType=tsar::SourceCFGNode::iterator; + static NodeRef getEntryNode(NodeRef N) { return N; } + static ChildIteratorType child_begin(NodeRef N) { + return ChildIteratorType(N->begin(), &SCFGGetTargetNode); + } + static ChildIteratorType child_end(NodeRef N) { + return ChildIteratorType(N->end(), &SCFGGetTargetNode); + } + static ChildEdgeIteratorType child_edge_begin(NodeRef N) { + return N->begin(); + } + static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); } +}; + +template<> struct GraphTraits : + public GraphTraits { + using nodes_iterator=tsar::SourceCFG::iterator; + static NodeRef getEntryNode(tsar::SourceCFG *mSCFG) { + return mSCFG->getEntryNode(); + } + static nodes_iterator nodes_begin(tsar::SourceCFG *mSCFG) { + return mSCFG->begin(); + } + static nodes_iterator nodes_end(tsar::SourceCFG *mSCFG) { + return mSCFG->end(); + } + using EdgeRef=tsar::SourceCFGEdge*; + static NodeRef edge_dest(EdgeRef E) { return &E->getTargetNode(); } + static unsigned size(tsar::SourceCFG *mSCFG) { return mSCFG->size(); } +}; + +template<> struct GraphTraits { + using NodeRef=const tsar::SourceCFGNode*; + static const tsar::SourceCFGNode *SCFGGetTargetNode( + const tsar::SourceCFGEdge *E) { return &E->getTargetNode(); } + using ChildIteratorType=mapped_iterator; + using ChildEdgeIteratorType=tsar::SourceCFGNode::const_iterator; + static NodeRef getEntryNode(NodeRef N) { return N; } + static ChildIteratorType child_begin(NodeRef N) { + return ChildIteratorType(N->begin(), &SCFGGetTargetNode); + } + static ChildIteratorType child_end(NodeRef N) { + return ChildIteratorType(N->end(), &SCFGGetTargetNode); + } + static ChildEdgeIteratorType child_edge_begin(NodeRef N) { + return N->begin(); + } + static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); } +}; + +template<> struct GraphTraits : + public GraphTraits { + using nodes_iterator=tsar::SourceCFG::const_iterator; + static NodeRef getEntryNode(const tsar::SourceCFG *mSCFG) { + return mSCFG->getEntryNode(); + } + static nodes_iterator nodes_begin(const tsar::SourceCFG *mSCFG) { + return mSCFG->begin(); + } + static nodes_iterator nodes_end(const tsar::SourceCFG *mSCFG) { + return mSCFG->end(); + } + using EdgeRef=const tsar::SourceCFGEdge*; + static NodeRef edge_dest(EdgeRef E) { return &E->getTargetNode(); } + static unsigned size(const tsar::SourceCFG *mSCFG) { return mSCFG->size(); } +}; + +template<> struct GraphTraits> { + using NodeRef=tsar::SourceCFGNode*; + using ChildIteratorType=std::set::iterator; + static ChildIteratorType child_begin(NodeRef N) { + return N->getParent()->getPredMap(N).begin(); + } + static ChildIteratorType child_end(NodeRef N) { + return N->getParent()->getPredMap(N).end(); + } + static NodeRef getEntryNode(NodeRef N) { return N; } +}; + +template<> struct GraphTraits> : + public GraphTraits> { + using nodes_iterator=tsar::SourceCFG::iterator; + static NodeRef getEntryNode(tsar::SourceCFG *SCFG) { + return SCFG->getEntryNode(); + } + static nodes_iterator nodes_begin(Inverse *ISCFG) { + return ISCFG->Graph->begin(); + } + static nodes_iterator nodes_end(Inverse *ISCFG) { + return ISCFG->Graph->end(); + } + unsigned size(Inverse *ISCFG) { + return ISCFG->Graph->size(); + } +}; + +template<> struct DOTGraphTraits : + public DefaultDOTGraphTraits { + DOTGraphTraits(bool IsSimple=false) : DefaultDOTGraphTraits(IsSimple) {} + static std::string getGraphName(const tsar::SourceCFG *SCFG) { + return "Source Control Flow Graph"; + } + std::string getNodeLabel(tsar::SourceCFGNode *Node, tsar::SourceCFG *SCFG) { + return (std::string)*Node; + } + std::string getEdgeSourceLabel(tsar::SourceCFGNode *Node, + GraphTraits::ChildIteratorType It) { + return (std::string)**It.getCurrent(); + } +}; + +} //namespace llvm +#endif//TSAR_CLANG_INCLUDE_SOURCECFG_H \ No newline at end of file diff --git a/include/tsar/Analysis/PDG.h b/include/tsar/Analysis/PDG.h new file mode 100644 index 00000000..17e0f3f6 --- /dev/null +++ b/include/tsar/Analysis/PDG.h @@ -0,0 +1,814 @@ +#ifndef TSAR_INCLUDE_BUILDPDG_H +#define TSAR_INCLUDE_BUILDPDG_H + +#include "tsar/ADT/SpanningTreeRelation.h" +#include "tsar/Analysis/Memory/DependenceAnalysis.h" +#include "tsar/Analysis/Memory/EstimateMemory.h" +#include "tsar/Analysis/Memory/DIEstimateMemory.h" +#include "tsar/Analysis/Memory/DIClientServerInfo.h" +#include "tsar/Analysis/Memory/DIMemoryTrait.h" +#include "tsar/Analysis/Memory/MemoryAccessUtils.h" +#include "tsar/Analysis/Clang/SourceCFG.h" +#include "tsar/Analysis/Passes.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tsar { + +template +class CDGNode; +template +class CDGEdge; +template +class CDGBuilder; + +template +using CDGNodeBase=llvm::DGNode, CDGEdge>; +template +using CDGEdgeBase=llvm::DGEdge, CDGEdge>; +template +using CDGBase=llvm::DirectedGraph, + CDGEdge>; + +template +class CDGEdge : public CDGEdgeBase { +public: + using NodeType=CDGNode; + CDGEdge(NodeType &TargetNode) + : CDGEdgeBase(TargetNode){} +}; + +template +class CDGNode : public CDGNodeBase { +public: + enum class NodeKind {Entry, Default, Region}; + CDGNode(NodeKind Kind) : mKind(Kind) {} + inline NodeKind getKind() const { return mKind; } + void destroy(); +private: + NodeKind mKind; +}; + +template +class EntryCDGNode : public CDGNode { +private: + using Base=CDGNode; +public: + EntryCDGNode() : Base(Base::NodeKind::Entry) {} + static bool classof(const Base *Node) { + return Node->getKind()==Base::NodeKind::Entry; + } +}; + +template +class DefaultCDGNode : public CDGNode { +private: + using Base=CDGNode; +public: + using NodeValueType=CFGNodeType*; + DefaultCDGNode(NodeValueType Block) + : Base(Base::NodeKind::Default), mBlock(Block) {} + static bool classof(const Base *Node) { + return Node->getKind()==Base::NodeKind::Default; + } + inline NodeValueType getBlock() const { return mBlock; } +private: + NodeValueType mBlock; +}; + +template +class ControlDependenceGraph : public CDGBase { +private: + using DefaultNode=DefaultCDGNode; + using EntryNode=EntryCDGNode; +public: + using CFGT=CFGType; + using CFGNodeT=CFGNodeType; + using NodeType=CDGNode; + using EdgeType=CDGEdge; + using NodeValueType=CFGNodeType*; + using CFGNodeMapType=llvm::DenseMap; + + ControlDependenceGraph(const std::string &FunctionName, CFGType *CFG) + : mFunctionName(FunctionName), mCFG(CFG), mEntryNode(new EntryNode()) { + CDGBase::addNode(*mEntryNode); + } + + inline bool addNode(DefaultNode &N) { + if (CDGBase::addNode(N)) { + mBlockToNodeMap.insert({N.getBlock(), &N}); + return true; + } + else + return false; + } + + NodeType &emplaceNode(NodeValueType Block) { + DefaultNode *NewNode=new DefaultNode(Block); + addNode(*NewNode); + return *NewNode; + } + + inline void bindNodes(NodeType &SourceNode, NodeType &TargetNode) { + CDGBase::connect(SourceNode, TargetNode, + *(new CDGEdge(TargetNode))); + } + + inline NodeType *getNode(NodeValueType Block) { + return mBlockToNodeMap[Block]; + } + + inline NodeType *getEntryNode() { return mEntryNode; } + inline CFGType *getCFG() const { return mCFG; } + + ~ControlDependenceGraph() { + for (auto N : CDGBase::Nodes) { + for (auto E : N->getEdges()) + delete E; + delete N; + } + } +private: + EntryNode *mEntryNode; + std::string mFunctionName; + CFGNodeMapType mBlockToNodeMap; + CFGType *mCFG; +}; + +using SourceCDG=ControlDependenceGraph; +using IRCDGNode=CDGNode; +using DefaultIRCDGNode=DefaultCDGNode; +using EntryIRCDGNode=EntryCDGNode; +using IRCDGEdge=CDGEdge; +using IRCDG=ControlDependenceGraph; + +template +class CDGBuilder { +private: + using CFGType=typename CDGType::CFGT; + using CFGNodeType=typename CDGType::CFGNodeT; +public: + using NodeValueType=typename llvm::GraphTraits::NodeRef; + CDGBuilder() : mCDG(nullptr) {} + CDGType *populate(CFGType &_CFG); +private: + inline void processControlDependence(); + CFGType *mCFG; + CDGType *mCDG; + llvm::PostDomTreeBase mPDT; +}; + +class PDGNode; +class PDGEdge; +class ProgramDependencyGraph; +using PDGNodeBase=llvm::DGNode; +using PDGEdgeBase=llvm::DGEdge; +using PDGBase=llvm::DirectedGraph; + +class PDGNode : public PDGNodeBase { +public: + enum class NodeKind { + SingleInstruction, + MultiInstruction, + PiBlock, + Entry, + }; + PDGNode() : mKind(NodeKind::Entry) {} + NodeKind getKind() const { return mKind; } + bool collectInstructions(llvm::function_ref const + &Pred, llvm::SmallVectorImpl &IList) const; + bool collectEdges(llvm::function_ref const &Pred, + llvm::SmallVectorImpl &IList) const; + using PDGNodeBase::findEdgeTo; + void destroy(); + ~PDGNode() = default; +protected: + PDGNode(NodeKind Kind) : mKind(Kind) {} + NodeKind mKind; +}; + +class SimplePDGNode : public PDGNode { + friend class PDGBuilder; +public: + SimplePDGNode(llvm::Instruction &Inst) + :PDGNode(NodeKind::SingleInstruction), mInstructions({&Inst}) {} + template + SimplePDGNode(InputIt First, InputIt Last) + : PDGNode(NodeKind::SingleInstruction), mInstructions(First, Last) { + if (mInstructions.size()>0) + mKind=NodeKind::MultiInstruction; + } + static bool classof(const PDGNode *Node) { + return Node->getKind()==NodeKind::SingleInstruction || + Node->getKind()==NodeKind::MultiInstruction; + } + const llvm::SmallVectorImpl &getInstructions() const { + assert(!mInstructions.empty() && "Instruction List is empty."); + return mInstructions; + } + llvm::SmallVectorImpl &getInstructions() { + return const_cast&>( + static_cast(this)->getInstructions()); + } + llvm::Instruction *getFirstInstruction() const { + return getInstructions().front(); + } + llvm::Instruction *getLastInstruction() const { + return getInstructions().back(); + } + ~SimplePDGNode() = default; +private: + /// Append the list of instructions in \p Input to this node. + void appendInstructions(const llvm::SmallVectorImpl + &Input) { + mKind=mInstructions.size()+Input.size()>1?NodeKind::MultiInstruction: + NodeKind::SingleInstruction; + llvm::append_range(mInstructions, Input); + } + void appendInstructions(const SimplePDGNode &Input) { + appendInstructions(Input.getInstructions()); + } + /// List of instructions associated with a single or multi-instruction node. + llvm::SmallVector mInstructions; +}; + +class PiBlockPDGNode : public PDGNode { +public: + template + PiBlockPDGNode(InputIt First, InputIt Last) + : PDGNode(NodeKind::PiBlock), mInlinedNodes(First, Last) {} + llvm::SmallVectorImpl &getInlinedNodes() { return mInlinedNodes; } + const llvm::SmallVectorImpl &getInlinedNodes() const { + return mInlinedNodes; + } + static bool classof(const PDGNode *Node) { + return Node->getKind()==NodeKind::PiBlock; + } + ~PiBlockPDGNode(); +private: + llvm::SmallVector mInlinedNodes; +}; + +class PDGEdge : public PDGEdgeBase { +public: + enum class DependenceType { + Data, + Control, + Last=Control + }; + enum class EdgeKind { + RegisterDefUse, + Memory, + MixedData, + Control, + ComplexData, + ComplexControl + }; + PDGEdge(PDGNode &TargetNode, DependenceType DT) : PDGEdgeBase(TargetNode), + mKind(DT==DependenceType::Data?EdgeKind::RegisterDefUse: + EdgeKind::Control) {} + EdgeKind getKind() const { return mKind; } + DependenceType getDependenceType() const { + return (mKind==EdgeKind::Control || + mKind==EdgeKind::ComplexControl)?DependenceType::Control: + DependenceType::Data; + } + bool isControl() const { + return getDependenceType()==DependenceType::Control; + } + bool isData() const { return getDependenceType()==DependenceType::Data; } + void destroy(); + ~PDGEdge() = default; +protected: + PDGEdge(PDGNode &TargetNode, EdgeKind Kind) + : PDGEdgeBase(TargetNode), mKind(Kind) {} +private: + EdgeKind mKind; +}; + +class MemoryPDGEdge : public PDGEdge { +public: + using DIDepKind=MemoryDescriptor; + using DIDepT=std::pair; + using DIDepStorageT=llvm::SmallVector; + using MemDepHandle=std::variant; + + MemoryPDGEdge(PDGNode &TargetNode, llvm::Dependence &Dep, bool HasDefUse) + : PDGEdge(TargetNode, HasDefUse?EdgeKind::MixedData:EdgeKind::Memory), + mMemDep(&Dep) {} + MemoryPDGEdge(PDGNode &TargetNode, + const llvm::SmallVectorImpl &DIDep, bool HasDefUse) + : PDGEdge(TargetNode, HasDefUse?EdgeKind::MixedData:EdgeKind::Memory) { + mMemDep.emplace(DIDep.begin(), DIDep.end()); + } + MemoryPDGEdge(PDGNode &TargetNode, const MemDepHandle &DepHandle, + bool HasDefUse) + : PDGEdge(TargetNode, HasDefUse?EdgeKind::MixedData:EdgeKind::Memory), + mMemDep(DepHandle) {} + ~MemoryPDGEdge() { + if (llvm::Dependence **IRDep=std::get_if(&mMemDep)) + delete *IRDep; + } + static bool classof(const PDGEdge *Edge) { + return Edge->getKind()==EdgeKind::Memory || Edge->getKind()== + EdgeKind::MixedData; + } + const MemDepHandle &getMemoryDep() const { return mMemDep; } +private: + MemDepHandle mMemDep; +}; + +class ComplexPDGEdge : public PDGEdge { +public: + enum Direction { + Incoming, // Incoming edges to the SCC + Outgoing, // Edges going ot of the SCC + DirectionCount // To make the enum usable as an array index. + }; + struct EdgeHandle { + size_t SrcNOrdinal, TgtNordinal; + PDGEdge &E; + }; + ComplexPDGEdge(PDGNode &Dst, PDGEdge &EToInline, size_t SCCOrdinal, + const Direction Dir) + : PDGEdge(Dst, EToInline.getDependenceType()==DependenceType::Control? + EdgeKind::ComplexControl:EdgeKind::ComplexData) { + absorbEdge(EToInline, SCCOrdinal, Dir); + } + void absorbEdge(PDGEdge &E, size_t SCCOrdinal, const Direction Dir) { + if (E.getKind()==PDGEdge::EdgeKind::ComplexControl || + E.getKind()==PDGEdge::EdgeKind::ComplexData) { + ComplexPDGEdge &ComplexE=llvm::cast(E); + if (Dir==Incoming) + for (EdgeHandle &EH : ComplexE.mInlinedEdges) + mInlinedEdges.push_back({EH.SrcNOrdinal, SCCOrdinal, EH.E}); + else + for (EdgeHandle &EH : ComplexE.mInlinedEdges) + mInlinedEdges.push_back({SCCOrdinal, EH.TgtNordinal, EH.E}); + ComplexE.mInlinedEdges.clear(); + E.destroy(); + } + else + if (Dir==Incoming) + mInlinedEdges.push_back({0, SCCOrdinal, E}); + else + mInlinedEdges.push_back({SCCOrdinal, 0, E}); + } + static bool classof(const PDGEdge *Edge) { + return Edge->getKind()==EdgeKind::ComplexControl || Edge->getKind()== + EdgeKind::ComplexData; + } + llvm::SmallVectorImpl &getInlinedEdges() { + return mInlinedEdges; + } + const llvm::SmallVectorImpl &getInlinedEdges() const { + return mInlinedEdges; + } + ~ComplexPDGEdge() { + for (EdgeHandle &EH : mInlinedEdges) + EH.E.destroy(); + } +private: + llvm::SmallVector mInlinedEdges; +}; + +class ProgramDependencyGraph : public PDGBase { + friend class PDGBuilder; +public: + using NodeType=PDGNode; + using EdgeType=PDGEdge; + ProgramDependencyGraph(const llvm::Function &F) + : PDGBase(), mF(F), mEntryNode(nullptr) {} + llvm::StringRef getName() const { return mF.getName(); } + PDGNode &getEntryNode() { + assert(mEntryNode); + return *mEntryNode; + } + const PDGNode &getEntryNode() const { + assert(mEntryNode); + return *mEntryNode; + } + bool addEntryNode(PDGNode &EntryNode) { + if (addNode(EntryNode)) { + mEntryNode=&EntryNode; + return true; + } + return false; + } + ~ProgramDependencyGraph() { + for (PDGNode *N : Nodes) { + for (PDGEdge *E : N->getEdges()) + E->destroy(); + N->destroy(); + } + } +private: + const llvm::Function &mF; + PDGNode *mEntryNode; +}; + +llvm::raw_ostream &operator<<(llvm::raw_ostream&, const PDGNode&); +llvm::raw_ostream &operator<<(llvm::raw_ostream&, const PDGNode::NodeKind); +llvm::raw_ostream &operator<<(llvm::raw_ostream&, const PDGEdge&); +llvm::raw_ostream &operator<<(llvm::raw_ostream&, const PDGEdge::EdgeKind); +llvm::raw_ostream &operator<<(llvm::raw_ostream&, + const ProgramDependencyGraph&); + +class PDGBuilder { + using MemoryLocationSet=llvm::SmallDenseSet; +public: + PDGBuilder(ProgramDependencyGraph &G, const llvm::Function &F, + llvm::DependenceInfo &DI, const AliasTree &AT, + DIMemoryClientServerInfo &DIMInfo, const llvm::TargetLibraryInfo &TLI, + const llvm::LoopInfo &LI, bool SolveReachability=true, + bool Simplify=false, bool CreatePiBlocks=false); + ~PDGBuilder() = default; + + void populate() { + computeInstructionOrdinals(); + createFineGrainedNodes(); + createDefUseEdges(); + createMemoryDependenceEdges(); + createControlDependenceEdges(); + // Operation of this function results in memory leak + // simplify(); + createPiBlocks(); + } + + static bool shouldShadow(const llvm::Instruction &I) { + return I.isDebugOrPseudoInst() || I.isLifetimeStartOrEnd(); + } +private: + struct ReachabilityMatrix : public std::vector { + size_t NodesCount; + ReachabilityMatrix() = default; + ReachabilityMatrix(size_t _NodesCount) + : std::vector(_NodesCount*_NodesCount, false), + NodesCount(_NodesCount) {} + std::vector::reference operator()(size_t I, size_t J) { + return this->operator[](I*NodesCount+J); + } + std::vector::const_reference operator()(size_t I, size_t J) const { + return this->operator[](I*NodesCount+J); + } + }; + + bool isReachable(const llvm::BasicBlock &From, const llvm::BasicBlock &To) { + return mReachabilityMatrix(mBBToInd[&From], mBBToInd[&To]); + } + + void solveReachability() { + mReachabilityMatrix=ReachabilityMatrix(mF.size()); + size_t Ind=0; + mBBToInd.init(mF.size()); + for (auto &BB : mF) { + // mReachabilityMatrix(Ind, Ind)=true; + mBBToInd[&BB]=Ind++; + } + for (auto &BB : mF) + for (auto SuccBB : llvm::successors(&BB)) + mReachabilityMatrix(mBBToInd[&BB], mBBToInd[SuccBB])=true; + for (size_t K=0; K(I)); + mGraph.addNode(*NewNode); + return *NewNode; + } + + PDGEdge &createDefUseEdge(PDGNode &Src, PDGNode &Tgt) { + PDGEdge *NewEdge=new PDGEdge(Tgt, PDGEdge::DependenceType::Data); + mGraph.connect(Src, Tgt, *NewEdge); + return *NewEdge; + } + + bool areNodesMergeable(const PDGNode &Src, const PDGNode &Tgt) const { + using namespace llvm; + // Only merge two nodes if they are both simple nodes and the consecutive + // instructions after merging belong to the same BB. + const SimplePDGNode *SimpleSrc=dyn_cast(&Src); + const SimplePDGNode *SimpleTgt=dyn_cast(&Tgt); + if (!SimpleSrc || !SimpleTgt) + return false; + return true; + /*return SimpleSrc->getLastInstruction()->getParent()== + SimpleTgt->getFirstInstruction()->getParent();*/ + } + + void mergeNodes(PDGNode &AbsorbN, PDGNode &OutgoingN) { + using namespace llvm; + PDGEdge &EdgeToFold=AbsorbN.back(); + assert(AbsorbN.getEdges().size()==1 && EdgeToFold.getTargetNode()== + OutgoingN && "Expected A to have a single edge to B."); + assert(isa(&AbsorbN) && isa(&OutgoingN) && + "Expected simple nodes"); + // Copy instructions from B to the end of A. + cast(&AbsorbN)-> + appendInstructions(*cast(&OutgoingN)); + // Move to A any outgoing edges from B. + for (PDGEdge *OutgoingE : OutgoingN) + mGraph.connect(AbsorbN, OutgoingE->getTargetNode(), *OutgoingE); + AbsorbN.removeEdge(EdgeToFold); + EdgeToFold.destroy(); + mGraph.removeNode(OutgoingN); + OutgoingN.destroy(); + } + + PiBlockPDGNode &createPiBlock(const llvm::SmallVectorImpl + &NodeList) { + PiBlockPDGNode *Res=new PiBlockPDGNode(NodeList.begin(), NodeList.end()); + mGraph.addNode(*Res); + return *Res; + } + + size_t getOrdinal(const llvm::Instruction &I) { + assert(mInstOrdinalMap.find(&I) != mInstOrdinalMap.end() && + "No ordinal computed for this instruction."); + return mInstOrdinalMap[&I]; + } + + size_t getOrdinal(PDGNode &N) { + assert(mNodeOrdinalMap.find(&N)!=mNodeOrdinalMap.end() && + "No ordinal computed for this node."); + return mNodeOrdinalMap[&N]; + } + + llvm::DenseMap mIMap; + llvm::DenseMap mInstOrdinalMap; + llvm::DenseMap mNodeOrdinalMap; + llvm::DependenceInfo &mDI; + llvm::SmallVector mBBList; + // + const llvm::LoopInfo &mLI; + ProgramDependencyGraph &mGraph; + const llvm::Function &mF; + const AliasTree &mAT; + const llvm::TargetLibraryInfo &mTLI; + bool mSolvedReachability, mSimplified, mCreatedPiBlocks; + ReachabilityMatrix mReachabilityMatrix; + llvm::DenseMap mBBToInd; + DIMemoryClientServerInfo &mDIMInfo; + std::optional> mServerDIATRel; + SpanningTreeRelation mClientDIATRel; +}; +} //namespace tsar + +namespace llvm { + +class ProgramDependencyGraphPass + : public FunctionPass, private bcl::Uncopyable { +public: + static char ID; + ProgramDependencyGraphPass() + : FunctionPass(ID), mPDGBuilder(nullptr), mPDG(nullptr) { + initializeProgramDependencyGraphPassPass(*PassRegistry::getPassRegistry()); + } + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; + void releaseMemory() override { + if (mPDGBuilder) { + delete mPDGBuilder; + mPDGBuilder=nullptr; + } + if (mPDG) { + delete mPDG; + mPDG=nullptr; + } + } + inline tsar::ProgramDependencyGraph &getPDG() { return *mPDG; } + inline const tsar::ProgramDependencyGraph &getPDG() const { return *mPDG; } +private: + tsar::PDGBuilder *mPDGBuilder; + tsar::ProgramDependencyGraph *mPDG; +}; + +template +struct GraphTraits*> { + using NodeRef=tsar::CDGNode*; + static tsar::CDGNode *CDGGetTargetNode(tsar::CDGEdge< + CFGType, CFGNodeType> *E) { + return &E->getTargetNode(); + } + using ChildIteratorType=mapped_iterator::iterator, decltype(&CDGGetTargetNode)>; + using ChildEdgeIteratorType=typename tsar::CDGNode:: + iterator; + static NodeRef getEntryNode(NodeRef N) { return N; } + static ChildIteratorType child_begin(NodeRef N) { + return ChildIteratorType(N->begin(), &CDGGetTargetNode); + } + static ChildIteratorType child_end(NodeRef N) { + return ChildIteratorType(N->end(), &CDGGetTargetNode); + } + static ChildEdgeIteratorType child_edge_begin(NodeRef N) { + return N->begin(); + } + static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); } +}; + +template +struct GraphTraits*> : + public GraphTraits*> { + using nodes_iterator=typename tsar::ControlDependenceGraph::iterator; + static typename llvm::GraphTraits*>:: + NodeRef getEntryNode(tsar::ControlDependenceGraph + *Graph) { + return Graph->getEntryNode(); + } + static nodes_iterator nodes_begin(tsar::ControlDependenceGraph *Graph) { + return Graph->begin(); + } + static nodes_iterator nodes_end(tsar::ControlDependenceGraph *Graph) { + return Graph->end(); + } + using EdgeRef=tsar::CDGEdge*; + static typename llvm::GraphTraits*>:: + NodeRef edge_dest(EdgeRef E) { return &E->getTargetNode(); } + static unsigned size(tsar::ControlDependenceGraph + *Graph) { return Graph->size(); } +}; + +template +struct DOTGraphTraits*> : + public DOTGraphTraits { +private: + using GTInstanced=GraphTraits*>; +public: + DOTGraphTraits(bool IsSimple=false) : DOTGraphTraits(IsSimple) {} + static std::string getGraphName(const tsar::ControlDependenceGraph *Graph) { + return "Control Dependence Graph"; + } + std::string getNodeLabel(const tsar::CDGNode *Node, + const tsar::ControlDependenceGraph *Graph) { + if (auto *DefNode=dyn_cast>(Node)) + return DOTGraphTraits::getNodeLabel(DefNode->getBlock(), + Graph->getCFG()); + else + return "Entry"; + } + std::string getNodeAttributes(const tsar::CDGNode *Node, tsar::ControlDependenceGraph + *Graph) { + if (auto *DefNode=dyn_cast>(Node)) + return DOTGraphTraits::getNodeAttributes(DefNode->getBlock(), + Graph->getCFG()); + else + return ""; + } + std::string getEdgeSourceLabel(const tsar::CDGNode + *Node, typename GraphTraits*>::ChildIteratorType It) { return ""; } + std::string getEdgeAttributes(const tsar::CDGNode + *Node, typename GTInstanced::ChildIteratorType EdgeIt, + tsar::ControlDependenceGraph *Graph) { + /*return DOTGraphTraits::getEdgeAttributes(Node->getBlock(), + EdgeIt, Graph->getCFG());*/ + return ""; + } + bool isNodeHidden(const tsar::CDGNode *Node, + tsar::ControlDependenceGraph*) { + return false; + } +}; + +template <> struct GraphTraits { + using NodeRef=tsar::PDGNode *; + static tsar::PDGNode *PDGGetTargetNode(DGEdge *P) { + return &P->getTargetNode(); + } + // Provide a mapped iterator so that the GraphTrait-based implementations can + // find the target nodes without having to explicitly go through the edges. + using ChildIteratorType = + mapped_iterator; + using ChildEdgeIteratorType=tsar::PDGNode::iterator; + static NodeRef getEntryNode(NodeRef N) { return N; } + static ChildIteratorType child_begin(NodeRef N) { + return ChildIteratorType(N->begin(), &PDGGetTargetNode); + } + static ChildIteratorType child_end(NodeRef N) { + return ChildIteratorType(N->end(), &PDGGetTargetNode); + } + static ChildEdgeIteratorType child_edge_begin(NodeRef N) { + return N->begin(); + } + static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); } +}; + +template <> +struct GraphTraits + : public GraphTraits { + using nodes_iterator = tsar::ProgramDependencyGraph::iterator; + static NodeRef getEntryNode(tsar::ProgramDependencyGraph *DG) { + return &DG->getEntryNode(); + } + static nodes_iterator nodes_begin(tsar::ProgramDependencyGraph *DG) { + return DG->begin(); + } + static nodes_iterator nodes_end(tsar::ProgramDependencyGraph *DG) { + return DG->end(); + } +}; + +template <> struct GraphTraits { + using NodeRef=const tsar::PDGNode *; + static const tsar::PDGNode *PDGGetTargetNode(const DGEdge *P) { + return &P->getTargetNode(); + } + using ChildIteratorType=mapped_iterator; + using ChildEdgeIteratorType = tsar::PDGNode::const_iterator; + static NodeRef getEntryNode(NodeRef N) { return N; } + static ChildIteratorType child_begin(NodeRef N) { + return ChildIteratorType(N->begin(), &PDGGetTargetNode); + } + static ChildIteratorType child_end(NodeRef N) { + return ChildIteratorType(N->end(), &PDGGetTargetNode); + } + static ChildEdgeIteratorType child_edge_begin(NodeRef N) { + return N->begin(); + } + static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->end(); } +}; + +template <> +struct GraphTraits + : public GraphTraits { + using nodes_iterator=tsar::ProgramDependencyGraph::const_iterator; + static NodeRef getEntryNode(const tsar::ProgramDependencyGraph *DG) { + return &DG->getEntryNode(); + } + static nodes_iterator nodes_begin(const tsar::ProgramDependencyGraph *DG) { + return DG->begin(); + } + static nodes_iterator nodes_end(const tsar::ProgramDependencyGraph *DG) { + return DG->end(); + } +}; + +template <> +struct DOTGraphTraits + : public DefaultDOTGraphTraits { + DOTGraphTraits(bool IsSimple=false) : DefaultDOTGraphTraits(IsSimple) {} + static std::string getGraphName(const tsar::ProgramDependencyGraph *G) { + assert(G && "expected a valid pointer to the graph."); + return "PDG for '"+std::string(G->getName())+"'"; + } + std::string getNodeLabel(const tsar::PDGNode *Node, + const tsar::ProgramDependencyGraph *Graph); + std::string getEdgeAttributes(const tsar::PDGNode *Node, + GraphTraits::ChildIteratorType I, + const tsar::ProgramDependencyGraph *G); + static bool isNodeHidden(const tsar::PDGNode *Node, + const tsar::ProgramDependencyGraph *G); +private: + static std::string getSimpleNodeLabel(const tsar::PDGNode *Node, + const tsar::ProgramDependencyGraph *G); + static std::string getVerboseNodeLabel(const tsar::PDGNode *Node, + const tsar::ProgramDependencyGraph *G); + static std::string getVerboseEdgeAttributes(const tsar::PDGNode *Src, + const tsar::PDGEdge *Edge, const tsar::ProgramDependencyGraph *G); + static std::string getEdgeStyle(const tsar::PDGEdge*); +}; + +using PDGDotGraphTraits=DOTGraphTraits; + +}//namespace llvm + +#endif//TSAR_INCLUDE_BUILDPDG_H \ No newline at end of file diff --git a/include/tsar/Analysis/Passes.h b/include/tsar/Analysis/Passes.h index e73be0f5..6cc7a5e6 100644 --- a/include/tsar/Analysis/Passes.h +++ b/include/tsar/Analysis/Passes.h @@ -117,5 +117,23 @@ ModulePass *createAnalysisCloseConnectionPass(bool ActiveOnly = false); /// Close connection with server (it should be run on client). Client will /// be blocked until server confirms that connection can be closed. ModulePass *createAnalysisCloseConnectionPass(const void * ServerID); + +/// Initialize a pass to build control dependence graph from source code. +void initializeProgramDependencyGraphPassPass(PassRegistry &Registry); + +/// Create a pass to build control dependence graph from source code. +FunctionPass *createProgramDependencyGraphPass(); + +/// Initialize a pass to print control dependence graph from source code to 'dot' file. +void initializePDGPrinterPass(PassRegistry &Registry); + +/// Create a pass to print control dependence graph from source code to 'dot' file. +FunctionPass *createPDGPrinter(); + +/// Initialize a pass to display control dependence graph from source code. +void initializePDGViewerPass(PassRegistry &Registry); + +/// Create a pass to display program dependency graph. +FunctionPass *createPDGViewer(); } #endif//TSAR_ANALYSIS_PASSES_H diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 1bc0ff68..520abe09 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -1,5 +1,5 @@ set(ANALYSIS_SOURCES Passes.cpp PrintUtils.cpp DFRegionInfo.cpp Attributes.cpp - Intrinsics.cpp AnalysisSocket.cpp AnalysisServer.cpp) + Intrinsics.cpp AnalysisSocket.cpp AnalysisServer.cpp PDG.cpp) if(MSVC_IDE) file(GLOB ANALYSIS_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/lib/Analysis/Clang/CMakeLists.txt b/lib/Analysis/Clang/CMakeLists.txt index 9f831e92..f26760ff 100644 --- a/lib/Analysis/Clang/CMakeLists.txt +++ b/lib/Analysis/Clang/CMakeLists.txt @@ -2,7 +2,7 @@ set(ANALYSIS_SOURCES Passes.cpp DIMemoryMatcher.cpp NoMacroAssert.cpp MemoryMatcher.cpp LoopMatcher.cpp ExpressionMatcher.cpp CanonicalLoop.cpp PerfectLoop.cpp GlobalInfoExtractor.cpp ControlFlowTraits.cpp RegionDirectiveInfo.cpp VariableCollector.cpp ASTDependenceAnalysis.cpp - IncludeTree.cpp Utils.cpp) + IncludeTree.cpp Utils.cpp SourceCFG.cpp) if(MSVC_IDE) diff --git a/lib/Analysis/Clang/Passes.cpp b/lib/Analysis/Clang/Passes.cpp index 146f656b..4d9d7234 100644 --- a/lib/Analysis/Clang/Passes.cpp +++ b/lib/Analysis/Clang/Passes.cpp @@ -42,6 +42,9 @@ void llvm::initializeClangAnalysis(PassRegistry &Registry) { initializeClangIncludeTreeOnlyPrinterPass(Registry); initializeClangIncludeTreeViewerPass(Registry); initializeClangIncludeTreeOnlyViewerPass(Registry); + initializeClangSourceCFGPassPass(Registry); + initializeClangSourceCFGPrinterPass(Registry); + initializeClangSourceCFGViewerPass(Registry); // Initialize checkers. initializeClangNoMacroAssertPass(Registry); } diff --git a/lib/Analysis/Clang/SourceCFG.cpp b/lib/Analysis/Clang/SourceCFG.cpp new file mode 100644 index 00000000..554336f6 --- /dev/null +++ b/lib/Analysis/Clang/SourceCFG.cpp @@ -0,0 +1,883 @@ +#include "tsar/Analysis/Clang/SourceCFG.h" +#include "tsar/Support/PassGroupRegistry.h" +#include "tsar/Core/Query.h" +#include "tsar/Analysis/Memory/Utils.h" +#include "tsar/Support/MetadataUtils.h" +#include "tsar/Core/TransformationContext.h" +#include "tsar/Frontend/Clang/TransformationContext.h" +#include + +namespace tsar { +bool operator<(const SourceCFGBuilder::LabelInfo &LI1, + const SourceCFGBuilder::LabelInfo &LI2) { + return LI1.NodeLI2.LabelIt); +} +}; + +using namespace tsar; +using namespace llvm; +using namespace clang; +using namespace std; + +template +void addToMap(MapT &Map, KeyT Key, ValueT Value) { + auto It=Map.find(Key); + if (It!=Map.end()) + Map[Key].push_back(Value); + else + Map.insert({Key, {Value}}); +} + +void NodeOp::print(StmtStringType &ResStr) const { + switch (mKind) { + case NodeOpKind::Native: + ((NativeNodeOp*)this)->print(ResStr); + break; + case NodeOpKind::Wrapper: + ((WrapperNodeOp*)this)->print(ResStr); + break; + case NodeOpKind::Reference: + ((ReferenceNodeOp*)this)->print(ResStr); + break; + } +} + +std::string NodeOp::getOpAddr() const { + switch (mKind) { + case NodeOpKind::Native: + return ((NativeNodeOp*)this)->getOpAddr(); + case NodeOpKind::Wrapper: + return ((WrapperNodeOp*)this)->getOpAddr(); + case NodeOpKind::Reference: + return ((ReferenceNodeOp*)this)->getOpAddr(); + } +} + +void NodeOp::destroy() { + switch (mKind) { + case NodeOpKind::Native: + delete (NativeNodeOp*)this; + break; + case NodeOpKind::Wrapper: + delete (WrapperNodeOp*)this; + break; + case NodeOpKind::Reference: + delete (ReferenceNodeOp*)this; + break; + } +} + +void WrapperNodeOp::print(StmtStringType &ResStr) const { + printRefDecl(ResStr); + if (Op.get()) { + Expr *E=(Expr*)&Op.getUnchecked(); + switch (E->getStmtClass()) { + case Stmt::StmtClass::UnaryOperatorClass: + if (((clang::UnaryOperator*)E)->isPostfix()) { + if (Leaves[0]) + Leaves[0]->print(ResStr); + ResStr+=((clang::UnaryOperator*)E)->getOpcodeStr( + ((clang::UnaryOperator*)E)->getOpcode()); + } + else { + ResStr+=((clang::UnaryOperator*)E)->getOpcodeStr( + ((clang::UnaryOperator*)E)->getOpcode()); + if (Leaves[0]) + Leaves[0]->print(ResStr); + } + break; + case Stmt::StmtClass::CompoundAssignOperatorClass: + case Stmt::StmtClass::BinaryOperatorClass: + if (((clang::BinaryOperator*)E)->isCompoundAssignmentOp() || + !((clang::BinaryOperator*)E)->isAssignmentOp()) { + if (Leaves[0]) + Leaves[0]->print(ResStr); + ResStr+=((clang::BinaryOperator*)E)->getOpcodeStr(); + if (Leaves[1]) + Leaves[1]->print(ResStr); + } + else { + if (Leaves[1]) + Leaves[1]->print(ResStr); + ResStr+=((clang::BinaryOperator*)E)->getOpcodeStr(); + if (Leaves[0]) + Leaves[0]->print(ResStr); + } + break; + case Stmt::StmtClass::DeclRefExprClass: + ResStr+=((DeclRefExpr*)E)->getNameInfo().getAsString(); + break; + case Stmt::StmtClass::IntegerLiteralClass: + { + SmallString<5> BufferStr; + ((IntegerLiteral*)E)->getValue().toString(BufferStr, 10, false); + ResStr+=BufferStr; + } + break; + case Stmt::StmtClass::CStyleCastExprClass: + ResStr+=((Twine)"("+((CStyleCastExpr*)E)->getCastKindName()+")").str(); + break; + case Stmt::StmtClass::ParenExprClass: + ResStr+="("; + if (Leaves[0]) + Leaves[0]->print(ResStr); + ResStr+=")"; + break; + case Stmt::StmtClass::ImplicitCastExprClass: + if (Leaves[0]) + Leaves[0]->print(ResStr); + break; + case Stmt::StmtClass::ConditionalOperatorClass: + ResStr+=" - "; + if (Leaves[0]) + Leaves[0]->print(ResStr); + break; + case Stmt::StmtClass::IfStmtClass: + ResStr+="if ("; + if (Leaves[0]) + Leaves[0]->print(ResStr); + ResStr+=")"; + break; + case Stmt::StmtClass::WhileStmtClass: + case Stmt::StmtClass::DoStmtClass: + ResStr+="while ("; + if (Leaves[0]) + Leaves[0]->print(ResStr); + ResStr+=")"; + break; + case Stmt::StmtClass::ForStmtClass: + ResStr+=" - "; + if (Leaves[0]) + Leaves[0]->print(ResStr); + break; + case Stmt::StmtClass::SwitchStmtClass: + ResStr+="switch ("; + if (Leaves[0]) + Leaves[0]->print(ResStr); + ResStr+=")"; + break; + case Stmt::StmtClass::LabelStmtClass: + ResStr+=((Twine)Op.getUnchecked().getName()+":").str(); + break; + case Stmt::StmtClass::CaseStmtClass: + { + ResStr+="case "; + llvm::raw_string_ostream StrStream(ResStr); + Op.getUnchecked().getLHS()->printPretty(StrStream, nullptr, + clang::PrintingPolicy(clang::LangOptions())); + ResStr+=":"; + } + break; + case Stmt::StmtClass::DefaultStmtClass: + ResStr+="default:"; + break; + default: + ResStr+=Op.get()->getStmtClassName(); + break; + } + } + else { + ResStr+=Op.get()->getNameAsString()+"="; + if (Leaves[0]) + Leaves[0]->print(ResStr); + } +} + +SourceCFGNode::operator std::string() const { + string ResStr; + for (NodeOp *NO : mBlock) { + NO->print(ResStr); + ResStr+="\n"; + } + return ResStr; +} + +void SourceCFG::deleteNode(SourceCFGNode &_Node) { + EdgeListTy EdgesToDelete; + findIncomingEdgesToNode(_Node, EdgesToDelete); + llvm::append_range(EdgesToDelete, _Node.getEdges()); + SourceCFGBase::removeNode(_Node); + for (auto E : EdgesToDelete) + E->destroy(); + if (mStartNode==&_Node) + mStartNode=nullptr; + delete &_Node; +} + +void SourceCFG::deleteEdge(SourceCFGEdge &_Edge) { + for (auto N : Nodes) + for (auto E : N->getEdges()) + if (E==&_Edge) + N->removeEdge(_Edge); + _Edge.destroy(); +} + +/* - Not working +void SourceCFGNode::merge(SourceCFGNode &NodeToAttach) { + for (auto E : NodeToAttach.getEdges()) { + SourceCFGNodeBase::addEdge(*E); + NodeToAttach.removeEdge(*E); + } + SBB.addOp(NodeToAttach.SBB.begin(), NodeToAttach.SBB.end()); +} +*/ + +SourceCFGNode *SourceCFG::splitNode(SourceCFGNode &Node, int It) { + if (It==0) + return &Node; + SourceCFGNode *NewNode=&emplaceNode(); + for (auto E : Node.getEdges()) + NewNode->addEdge(*E); + Node.clear(); + bindNodes(Node, *NewNode); + NewNode->addOp(Node.mBlock.begin()+It, Node.mBlock.end()); + Node.mBlock.resize(It); + return NewNode; +} + +void SourceCFGEdge::destroy() { + switch (mKind) { + case EdgeKind::Default: + delete (DefaultSCFGEdge*)this; + break; + case EdgeKind::Labeled: + delete (LabeledSCFGEdge*)this; + break; + } +} + +SourceCFGEdge::operator std::string() const { + switch (mKind) { + case EdgeKind::Default: + return (string)(*(DefaultSCFGEdge*)this); + case EdgeKind::Labeled: + return (string)(*(LabeledSCFGEdge*)this); + } +} + +void SourceCFG::mergeNodes(SourceCFGNode &AbsorbNode, + SourceCFGNode &OutgoingNode) { + EdgeListTy CommonEdges; + if (AbsorbNode.findEdgesTo(OutgoingNode, CommonEdges)) { + for (auto E : CommonEdges) { + AbsorbNode.removeEdge(*E); + E->destroy(); + } + CommonEdges.clear(); + } + if (OutgoingNode.findEdgesTo(AbsorbNode, CommonEdges)) + for (auto E : CommonEdges) { + AbsorbNode.addEdge(*(new SourceCFGEdge(*E))); + OutgoingNode.removeEdge(*E); + E->destroy(); + } + //AbsorbNode.merge(OutgoingNode); - Not working + SourceCFGBase::removeNode(OutgoingNode); + delete &OutgoingNode; +} + +void markReached(SourceCFGNode *Node, + std::map *NodesList) { + (*NodesList)[Node]=true; + for (auto E : *Node) + if (!(*NodesList)[&E->getTargetNode()]) + markReached(&E->getTargetNode(), NodesList); +} + +void SourceCFG::recalculatePredMap() { + mPredecessorsMap.clear(); + for (auto N : Nodes) { + mPredecessorsMap.insert({N, {}}); + auto OutcomingEdges=N->getEdges(); + for (auto E : OutcomingEdges) { + auto It=mPredecessorsMap.find(&E->getTargetNode()); + if (It!=mPredecessorsMap.end()) + It->second.insert(N); + else + mPredecessorsMap.insert({&E->getTargetNode(), {N}}); + } + } +} + +void SourceCFGBuilder::eliminateUnreached() { + std::map ReachedNodes; + for (auto N : *mSCFG) + ReachedNodes.insert({N, false}); + markReached(mSCFG->getEntryNode(), &ReachedNodes); + for (auto It : ReachedNodes) + if (!It.second) + mSCFG->deleteNode(*It.first); +} + +void SourceCFGBuilder::processLabels() { + std::map>> OrderingMap; + for (auto GotoIt : mGotos) + addToMap(OrderingMap, mLabels[GotoIt.first], pair{GotoIt.second, nullptr}); + for (auto SwitchIt : mSwitchGotos) + addToMap(OrderingMap, mLabels[SwitchIt.first], pair{SwitchIt.second, + SwitchIt.first}); + for (auto It : OrderingMap) { + auto NewNode=mSCFG->splitNode(*It.first.Node, It.first.LabelIt); + for (auto GotoNode : It.second) + if (GotoNode.second) + mSCFG->bindNodes(*GotoNode.first, *NewNode, GotoNode.second); + else + mSCFG->bindNodes(*GotoNode.first, *NewNode); + } +} + +SourceCFG *SourceCFGBuilder::populate(FunctionDecl *Decl) { + if (Decl->hasBody()) { + DeclarationNameInfo Info=Decl->getNameInfo(); + mSCFG=new SourceCFG(Info.getAsString()); + mDirectOut.push_back(MarkedOutsType()); + parseStmt(Decl->getBody()); + mSCFG->mStartNode=mEntryNode; + if (mEntryNode) + processLabels(); + mDirectOut.pop_back(); + eliminateUnreached(); + } + return mSCFG; +} + +bool SourceCFGBuilder::hasConditionalOperator(clang::Stmt *Root) { + if (isa(*Root)) + return true; + else { + for (auto SubExpr : Root->children()) + if (hasConditionalOperator(SubExpr)) + return true; + return false; + } +} + +void SourceCFGBuilder::parseStmt(Stmt *Root) { + Stmt::StmtClass Type=Root->getStmtClass(); + if ((!mEntryNode || !mNodeToAdd) && + Type!=Stmt::StmtClass::CompoundStmtClass) { + mNodeToAdd=&mSCFG->emplaceNode(); + if (!mEntryNode) + mEntryNode=mNodeToAdd; + for (auto Outs : mDirectOut.back()) + mSCFG->bindNodes(*Outs.first, *mNodeToAdd, Outs.second); + mDirectOut.back().clear(); + mDirectOut.back().insert({mNodeToAdd, DefaultSCFGEdge::EdgeType::Default}); + } + switch (Type) { + case Stmt::StmtClass::CompoundStmtClass: + parseCompoundStmt((CompoundStmt*)Root); + break; + case Stmt::StmtClass::IfStmtClass: + parseIfStmt((IfStmt*)Root); + break; + case Stmt::StmtClass::WhileStmtClass: + parseWhileStmt((WhileStmt*)Root); + break; + case Stmt::StmtClass::DoStmtClass: + parseDoStmt((DoStmt*)Root); + break; + case Stmt::StmtClass::ContinueStmtClass: + parseContinueStmt((ContinueStmt*)Root); + break; + case Stmt::StmtClass::BreakStmtClass: + parseBreakStmt((BreakStmt*)Root); + break; + case Stmt::StmtClass::ReturnStmtClass: + parseReturnStmt((ReturnStmt*)Root); + break; + case Stmt::StmtClass::LabelStmtClass: + parseLabelStmt((LabelStmt*)Root); + break; + case Stmt::StmtClass::GotoStmtClass: + parseGotoStmt((GotoStmt*)Root); + break; + case Stmt::StmtClass::DeclStmtClass: + parseDeclStmt((DeclStmt*)Root, nullptr); + break; + case Stmt::StmtClass::ForStmtClass: + parseForStmt((ForStmt*)Root); + break; + case Stmt::StmtClass::SwitchStmtClass: + parseSwitchStmt((SwitchStmt*)Root); + break; + case Stmt::StmtClass::DefaultStmtClass: + mDirectOut[mDirectOut.size()-2].erase(mSwitchNodes.top()); + case Stmt::StmtClass::CaseStmtClass: + parseLabelStmt((LabelStmt*)Root); + mSwitchGotos.push_back({(SwitchCase*)Root, mSwitchNodes.top()}); + break; + default: + if (isa(*Root) && hasConditionalOperator(Root)) + parseExpr(DynTypedNode::create(*Root), nullptr, true); + else { + mNodeToAdd->addOp(new NativeNodeOp(Root)); + mDirectOut.back().insert({mNodeToAdd, + DefaultSCFGEdge::EdgeType::Default}); + } + } +} + +void SourceCFGBuilder::continueFlow(NodeOp *Op) { + if (!mNodeToAdd) { + mNodeToAdd=&mSCFG->emplaceNode(); + mNodeToAdd->addOp(Op); + for (auto Outs : mDirectOut.back()) + mSCFG->bindNodes(*Outs.first, *mNodeToAdd, Outs.second); + mDirectOut.back().clear(); + } + else + mNodeToAdd->addOp(Op); + mDirectOut.back().insert({mNodeToAdd, DefaultSCFGEdge::EdgeType::Default}); +} + +void SourceCFGBuilder::processIndirect(SourceCFGNode *CondStartNode) { + // Processing of continue statements + if (CondStartNode) + for (auto Out : mContinueOut.top()) + mSCFG->bindNodes(*Out, *CondStartNode); + // Processing of break statements + for (auto Out : mBreakOut.top()) + mDirectOut.back().insert({Out, DefaultSCFGEdge::EdgeType::Default}); +} + +void SourceCFGBuilder::parseExpr(clang::DynTypedNode Op, NodeOp *ParentOp, + bool isFirstCall) { + SourceCFGNode *OldNodeToAdd; + WrapperNodeOp *NewNodeOp; + if (Op.get()) { + Stmt::StmtClass Type=Op.getUnchecked().getStmtClass(); + if (Op.get()) { + MarkedOutsType UpperOuts; + SourceCFGNode *ConditionNode, *TrueNode, *FalseNode; + const ConditionalOperator &CO=Op.getUnchecked(); + auto OldEntryNode=mEntryNode; + auto OldTreeTopParentPtr=mTreeTopParentPtr; + NodeOp *CondOp=new WrapperNodeOp(&CO); + if (ParentOp) + ((WrapperNodeOp*)ParentOp)->Leaves.push_back(new ReferenceNodeOp( + CondOp, "cond_res")); + if (mTreeTopParentPtr && ((WrapperNodeOp*)mTreeTopParentPtr)-> + Leaves.size()>0) { + continueFlow(((WrapperNodeOp*)mTreeTopParentPtr)->Leaves[0]); + ((WrapperNodeOp*)mTreeTopParentPtr)->Leaves[0]=new ReferenceNodeOp( + ((WrapperNodeOp*)mTreeTopParentPtr)->Leaves[0], ""); + } + parseExpr(DynTypedNode::create(*CO.getCond()), CondOp, true); + ConditionNode=mNodeToAdd; + mEntryNode=mNodeToAdd=nullptr; + mDirectOut.push_back(MarkedOutsType()); + parseStmt(CO.getTrueExpr()); + TrueNode=mEntryNode; + mSCFG->bindNodes(*ConditionNode, *TrueNode, + DefaultSCFGEdge::EdgeType::True); + UpperOuts=mDirectOut.back(); + mDirectOut.pop_back(); + for (auto It : UpperOuts) + mDirectOut.back().insert(It); + mEntryNode=mNodeToAdd=nullptr; + mDirectOut.push_back(MarkedOutsType()); + parseStmt(CO.getFalseExpr()); + FalseNode=mEntryNode; + mSCFG->bindNodes(*ConditionNode, *FalseNode, + DefaultSCFGEdge::EdgeType::False); + UpperOuts=mDirectOut.back(); + mDirectOut.pop_back(); + for (auto It : UpperOuts) + mDirectOut.back().insert(It); + mDirectOut.back().erase(ConditionNode); + mNodeToAdd=nullptr; + mEntryNode=OldEntryNode; + mTreeTopParentPtr=OldTreeTopParentPtr; + if (isFirstCall && ParentOp && + !((WrapperNodeOp*)ParentOp)->Op.get()) + continueFlow(ParentOp); + return; + } + else { + OldNodeToAdd=mNodeToAdd; + if (isFirstCall) + mTreeTopParentPtr=nullptr; + NewNodeOp=new WrapperNodeOp(&Op.getUnchecked()); + switch (Type) { + case Stmt::StmtClass::CompoundAssignOperatorClass: + parseExpr(DynTypedNode::create(*Op.getUnchecked().getLHS()), NewNodeOp, false); + parseExpr(DynTypedNode::create(*Op.getUnchecked().getRHS()), NewNodeOp, false); + break; + case Stmt::StmtClass::BinaryOperatorClass: + if (Op.getUnchecked().isAssignmentOp()) { + parseExpr(DynTypedNode::create(*Op.getUnchecked().getRHS()), NewNodeOp, false); + parseExpr(DynTypedNode::create(*Op.getUnchecked().getLHS()), NewNodeOp, false); + } + else { + parseExpr(DynTypedNode::create(*Op.getUnchecked().getLHS()), NewNodeOp, false); + parseExpr(DynTypedNode::create(*Op.getUnchecked().getRHS()), NewNodeOp, false); + } + break; + default: + for (auto SubExpr : Op.getUnchecked().children()) + parseExpr(DynTypedNode::create(*SubExpr), NewNodeOp, false); + break; + } + } + } + else { + OldNodeToAdd=mNodeToAdd; + if (isFirstCall) + mTreeTopParentPtr=nullptr; + NewNodeOp=new WrapperNodeOp(&Op.getUnchecked()); + parseExpr(DynTypedNode::create(*Op.getUnchecked().getInit()), + NewNodeOp, false); + } + NodeOp *OpToAdd; + if (mNodeToAdd && OldNodeToAdd==mNodeToAdd) { + OpToAdd=new NativeNodeOp(*NewNodeOp); + delete NewNodeOp; + } + else + OpToAdd=NewNodeOp; + if (isFirstCall) { + if (ParentOp) { + ((WrapperNodeOp*)ParentOp)->Leaves.push_back(OpToAdd); + continueFlow(ParentOp); + } + else + continueFlow(OpToAdd); + mTreeTopParentPtr=nullptr; + } + else { + ((WrapperNodeOp*)ParentOp)->Leaves.push_back(OpToAdd); + mTreeTopParentPtr=ParentOp; + } +} + +void SourceCFGBuilder::parseCompoundStmt(CompoundStmt *Root) { + MarkedOutsType UpperOuts; + SourceCFGNode *ResultEntryNode=mEntryNode; + mDirectOut.push_back(MarkedOutsType()); + for (auto S : Root->body()) { + parseStmt(S); + if (!ResultEntryNode && mEntryNode) + ResultEntryNode=mEntryNode; + } + mEntryNode=ResultEntryNode; + UpperOuts=mDirectOut.back(); + mDirectOut.pop_back(); + for (auto Outs : UpperOuts) + mDirectOut.back().insert(Outs); +} + +void SourceCFGBuilder::parseDoStmt(DoStmt *Root) { + SourceCFGNode *mStartNode=mNodeToAdd, *CondStartNode, *CondEndNode, *Body; + mContinueOut.push(OutsType()); + mBreakOut.push(OutsType()); + mDirectOut.push_back(MarkedOutsType()); + if (mStartNode->size()==0) + Body=mStartNode; + else { + Body=mEntryNode=mNodeToAdd=&mSCFG->emplaceNode(); + mSCFG->bindNodes(*mStartNode, *Body); + } + parseStmt(Root->getBody()); + if (!mContinueOut.top().empty() || !mNodeToAdd) { + CondStartNode=mNodeToAdd=&mSCFG->emplaceNode(); + for (auto Outs : mDirectOut.back()) + mSCFG->bindNodes(*Outs.first, *CondStartNode, Outs.second); + mDirectOut.back().clear(); + } + else + CondStartNode=mNodeToAdd; + parseExpr(DynTypedNode::create(*Root->getCond()), new WrapperNodeOp(Root), + true); + CondEndNode=mNodeToAdd; + mSCFG->bindNodes(*CondEndNode, *Body, DefaultSCFGEdge::EdgeType::True); + mDirectOut.pop_back(); + mDirectOut.back().erase(mStartNode); + mDirectOut.back().insert({CondEndNode, DefaultSCFGEdge::EdgeType::False}); + mNodeToAdd=nullptr; + mEntryNode=mStartNode; + processIndirect(CondStartNode); + mContinueOut.pop(); + mBreakOut.pop(); +} + +void SourceCFGBuilder::parseForStmt(ForStmt *Root) { + SourceCFGNode *mStartNode=mNodeToAdd, *CondStartNode=nullptr, + *CondEndNode=nullptr, *Body=nullptr, *IncStartNode=nullptr, *LoopNode; + MarkedOutsType AfterInitOuts; + mContinueOut.push(OutsType()); + mBreakOut.push(OutsType()); + if (Root->getInit()) + if (isa(*Root->getInit())) + parseDeclStmt((DeclStmt*)Root->getInit(), nullptr); + else + parseExpr(DynTypedNode::create(*Root->getInit()), nullptr, true); + AfterInitOuts=mDirectOut.back(); + if (Root->getCond()) { + if (mNodeToAdd && mNodeToAdd->size()==0) + CondStartNode=mNodeToAdd; + else { + CondStartNode=mNodeToAdd=&mSCFG->emplaceNode(); + for (auto Out : mDirectOut.back()) + mSCFG->bindNodes(*Out.first, *CondStartNode, Out.second); + mDirectOut.back().clear(); + } + parseExpr(DynTypedNode::create(*Root->getCond()), new WrapperNodeOp(Root), + true); + CondEndNode=mNodeToAdd; + } + mDirectOut.back().clear(); + mEntryNode=mNodeToAdd=nullptr; + parseStmt(Root->getBody()); + Body=mEntryNode; + if (CondEndNode) + mSCFG->bindNodes(*CondEndNode, *Body, DefaultSCFGEdge::EdgeType::True); + else + for (auto Out : AfterInitOuts) + mSCFG->bindNodes(*Out.first, *Body, Out.second); + if (Root->getInc()) { + if (!mContinueOut.top().empty()) + mEntryNode=mNodeToAdd=nullptr; + parseStmt(Root->getInc()); + IncStartNode=mEntryNode; + } + LoopNode=CondStartNode?CondStartNode:Body; + for (auto Out : mDirectOut.back()) + mSCFG->bindNodes(*Out.first, *LoopNode, Out.second); + mDirectOut.back().clear(); + if (CondEndNode) + mDirectOut.back().insert({CondEndNode, DefaultSCFGEdge::EdgeType::False}); + mNodeToAdd=nullptr; + mEntryNode=mStartNode; + if (IncStartNode) + processIndirect(IncStartNode); + else + if (CondStartNode) + processIndirect(CondStartNode); + else + processIndirect(Body); + mContinueOut.pop(); + mBreakOut.pop(); +} + +void SourceCFGBuilder::parseSwitchStmt(SwitchStmt *Root) { + mBreakOut.push(OutsType()); + SourceCFGNode *CondStartNode=mNodeToAdd, *CondEndNode; + parseExpr(DynTypedNode::create(*Root->getCond()), new WrapperNodeOp(Root), + true); + CondEndNode=mNodeToAdd; + mSwitchNodes.push(CondEndNode); + mDirectOut.back()[CondEndNode]=DefaultSCFGEdge::EdgeType::ImplicitDefault; + mEntryNode=mNodeToAdd=nullptr; + parseStmt(Root->getBody()); + processIndirect(nullptr); + mSwitchNodes.pop(); + mBreakOut.pop(); +} + +void SourceCFGBuilder::parseWhileStmt(WhileStmt *Root) { + mContinueOut.push(OutsType()); + mBreakOut.push(OutsType()); + mDirectOut.push_back(MarkedOutsType()); + SourceCFGNode *mStartNode=mNodeToAdd, *CondStartNode, *CondEndNode; + if (mStartNode->size()==0) { + CondStartNode=mStartNode; + parseExpr(DynTypedNode::create(*Root->getCond()), new WrapperNodeOp(Root), + true); + } + else { + CondStartNode=mNodeToAdd=&mSCFG->emplaceNode(); + mSCFG->bindNodes(*mStartNode, *CondStartNode); + parseExpr(DynTypedNode::create(*Root->getCond()), new WrapperNodeOp(Root), + true); + } + CondEndNode=mNodeToAdd; + mDirectOut.back().erase(CondEndNode); + mEntryNode=mNodeToAdd=nullptr; + parseStmt(Root->getBody()); + mSCFG->bindNodes(*CondEndNode, *mEntryNode, DefaultSCFGEdge::EdgeType::True); + for (auto Outs : mDirectOut.back()) + mSCFG->bindNodes(*Outs.first, *CondStartNode, Outs.second); + mDirectOut.pop_back(); + mDirectOut.back().erase(mStartNode); + mDirectOut.back().insert({CondEndNode, DefaultSCFGEdge::EdgeType::False}); + mEntryNode=mStartNode; + mNodeToAdd=nullptr; + processIndirect(CondStartNode); + mContinueOut.pop(); + mBreakOut.pop(); +} + +void SourceCFGBuilder::parseIfStmt(IfStmt *Root) { + MarkedOutsType UpperOuts; + SourceCFGNode *CondStartNode=mNodeToAdd, *CondEndNode; + Stmt *ActionStmt; + parseExpr(DynTypedNode::create(*Root->getCond()), new WrapperNodeOp(Root), + true); + CondEndNode=mNodeToAdd; + mDirectOut.push_back(MarkedOutsType()); + mEntryNode=mNodeToAdd=nullptr; + parseStmt(Root->getThen()); + mSCFG->bindNodes(*CondEndNode, *mEntryNode, DefaultSCFGEdge::EdgeType::True); + if ((ActionStmt=Root->getElse())) { + mDirectOut.push_back(MarkedOutsType()); + mEntryNode=mNodeToAdd=nullptr; + parseStmt(ActionStmt); + mSCFG->bindNodes(*CondEndNode, *mEntryNode, + DefaultSCFGEdge::EdgeType::False); + UpperOuts=mDirectOut.back(); + mDirectOut.pop_back(); + for (auto Out : UpperOuts) + mDirectOut.back().insert(Out); + } + else + mDirectOut.back().insert({CondEndNode, DefaultSCFGEdge::EdgeType::False}); + UpperOuts=mDirectOut.back(); + mDirectOut.pop_back(); + mDirectOut.back().erase(CondEndNode); + for (auto Outs : UpperOuts) + mDirectOut.back().insert(Outs); + mEntryNode=CondStartNode; + mNodeToAdd=nullptr; +} + +void SourceCFGBuilder::parseBreakStmt(BreakStmt *Root) { + mNodeToAdd->addOp(new NativeNodeOp(Root)); + mDirectOut.back().erase(mNodeToAdd); + mBreakOut.top().insert(mNodeToAdd); + mNodeToAdd=nullptr; +} + +void SourceCFGBuilder::parseContinueStmt(ContinueStmt *Root) { + mNodeToAdd->addOp(new NativeNodeOp(Root)); + mDirectOut.back().erase(mNodeToAdd); + mContinueOut.top().insert(mNodeToAdd); + mNodeToAdd=nullptr; +} + +void SourceCFGBuilder::parseGotoStmt(GotoStmt *Root) { + mNodeToAdd->addOp(new NativeNodeOp(Root)); + mGotos.push_back({Root->getLabel()->getStmt(), mNodeToAdd}); + mDirectOut.back().erase(mNodeToAdd); + mNodeToAdd=nullptr; +} + +void SourceCFGBuilder::parseLabelStmt(Stmt *Root) { + mNodeToAdd->addOp(new WrapperNodeOp(Root)); + if (!mPrevFirstLabel.Node || mPrevFirstLabel.Node!=mNodeToAdd || + mLastLabelItsize()-2) + mPrevFirstLabel={mNodeToAdd, mNodeToAdd->size()-1}; + mLastLabelIt=mNodeToAdd->size()-1; + mLabels.insert({Root, mPrevFirstLabel}); + if (isa(*Root)) + parseStmt(((LabelStmt*)Root)->getSubStmt()); + else + parseStmt(((SwitchCase*)Root)->getSubStmt()); +} + +void SourceCFGBuilder::parseReturnStmt(ReturnStmt *Root) { + if (Root->getRetValue()) + parseExpr(DynTypedNode::create(*Root->getRetValue()), + new WrapperNodeOp(Root), true); + else + mNodeToAdd->addOp(new NativeNodeOp(Root)); + //mSCFG->bindNodes(*mNodeToAdd, *mSCFG->getStopNode()); + mDirectOut.back().erase(mNodeToAdd); + mNodeToAdd=nullptr; +} + +void SourceCFGBuilder::parseDeclStmt(DeclStmt *Root, NodeOp *ParentOp) { + for (auto D : Root->decls()) + if ((D->getKind()==Decl::Kind::Var) && ((VarDecl*)D)->getInit()) + parseExpr(DynTypedNode::create(*D), ParentOp, true); +} + +char ClangSourceCFGPass::ID=0; + +INITIALIZE_PASS_BEGIN(ClangSourceCFGPass, "clang-source-cfg", + "Source Control Flow Graph (Clang)", false, true) +INITIALIZE_PASS_DEPENDENCY(TransformationEnginePass) +INITIALIZE_PASS_END(ClangSourceCFGPass, "clang-source-cfg", + "Source Control Flow Graph (Clang)", false, true) + +FunctionPass *createClangSourceCFGPass() { return new ClangSourceCFGPass; } + +void ClangSourceCFGPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + AU.setPreservesAll(); +} + +bool ClangSourceCFGPass::runOnFunction(Function &F) { + releaseMemory(); + auto *DISub(findMetadata(&F)); + if (!DISub) + return false; + auto *CU{DISub->getUnit()}; + if (!CU) + return false; + if (!isC(CU->getSourceLanguage())) + return false; + auto &TfmInfo{getAnalysis()}; + auto *TfmCtx{TfmInfo ? dyn_cast_or_null< + ClangTransformationContext>(TfmInfo->getContext(*CU)) : nullptr}; + if (!TfmCtx || !TfmCtx->hasInstance()) + return false; + auto FuncDecl=TfmCtx->getDeclForMangledName(F.getName()); + mSCFG=mSCFGBuilder.populate((FunctionDecl*)FuncDecl); + return false; +} + +namespace { +struct ClangSourceCFGPassGraphTraits { + static tsar::SourceCFG *getGraph(ClangSourceCFGPass *P) { + return &P->getSourceCFG(); + } +}; + +struct ClangSourceCFGPrinter : public DOTGraphTraitsPrinterWrapperPass< + ClangSourceCFGPass, false, tsar::SourceCFG*, + ClangSourceCFGPassGraphTraits> { + static char ID; + ClangSourceCFGPrinter() : DOTGraphTraitsPrinterWrapperPass< + ClangSourceCFGPass, false, tsar::SourceCFG*, + ClangSourceCFGPassGraphTraits>("scfg", ID) { + initializeClangSourceCFGPrinterPass(*PassRegistry::getPassRegistry()); + } +}; +char ClangSourceCFGPrinter::ID = 0; + +struct ClangSourceCFGViewer : public DOTGraphTraitsViewerWrapperPass< + ClangSourceCFGPass, false, tsar::SourceCFG*, + ClangSourceCFGPassGraphTraits> { + static char ID; + ClangSourceCFGViewer() : DOTGraphTraitsViewerWrapperPass("scfg", ID) { + initializeClangSourceCFGViewerPass(*PassRegistry::getPassRegistry()); + } +}; +char ClangSourceCFGViewer::ID = 0; +} //anonymous namespace + +INITIALIZE_PASS_IN_GROUP(ClangSourceCFGViewer, "clang-view-source-cfg", + "View Source Control FLow Graph (Clang)", true, true, + DefaultQueryManager::OutputPassGroup::getPassRegistry()) + +INITIALIZE_PASS_IN_GROUP(ClangSourceCFGPrinter, "clang-print-source-cfg", + "Print Source Control FLow Graph(Clang)", true, true, + DefaultQueryManager::OutputPassGroup::getPassRegistry()) + +FunctionPass *llvm::createClangSourceCFGPrinter() { + return new ClangSourceCFGPrinter; +} + +FunctionPass *llvm::createClangSourceCFGViewer() { + return new ClangSourceCFGViewer; +} + diff --git a/lib/Analysis/PDG.cpp b/lib/Analysis/PDG.cpp new file mode 100644 index 00000000..f92eb3de --- /dev/null +++ b/lib/Analysis/PDG.cpp @@ -0,0 +1,1410 @@ +#include "tsar/Analysis/PDG.h" +#include "tsar/Support/PassGroupRegistry.h" +#include "tsar/Core/Query.h" +#include +#include +#include +#include +#include +#include + +using namespace tsar; +using namespace llvm; + +#undef DEBUG_TYPE +#define DEBUG_TYPE "pdg" + +STATISTIC(TotalGraphs, "Number of dependence graphs created."); +STATISTIC(TotalDefUseEdges, "Number of def-use edges created."); +STATISTIC(TotalMemoryEdges, "Number of memory dependence edges created."); +STATISTIC(TotalFineGrainedNodes, "Number of fine-grained nodes created."); +STATISTIC(TotalPiBlockNodes, "Number of pi-block nodes created."); +STATISTIC(TotalConfusedLLVMEdges, "Number of confused memory dependencies between two nodes."); +STATISTIC(TotalEdgeReversals, "Number of times the source and sink of dependence was reversed to expose cycles in the graph."); + +using PDG=ProgramDependencyGraph; +using InstructionListType=SmallVector; + +namespace llvm { +template<> +struct DOTGraphTraits + : public DOTGraphTraits { + DOTGraphTraits(bool isSimple=false) + : DOTGraphTraits(isSimple) {} + std::string getNodeLabel(const BasicBlock *Node, Function*) { + return DOTGraphTraits::getNodeLabel(Node, nullptr); + } + std::string getNodeAttributes(const BasicBlock *Node, Function *F) { + DOTFuncInfo DOTInfo(F); + return DOTGraphTraits::getNodeAttributes(Node, &DOTInfo); + } + std::string getEdgeAttributes(const BasicBlock *Node, + const_succ_iterator EdgeIt, Function *F) { + DOTFuncInfo DOTInfo(F); + return DOTGraphTraits::getEdgeAttributes(Node, EdgeIt, + &DOTInfo); + } + bool isNodeHidden(const BasicBlock *Node, const Function *F) { + DOTFuncInfo DOTInfo(F); + return DOTGraphTraits::isNodeHidden(Node, &DOTInfo); + } +}; + +template<> struct GraphTraits*> + : public DomTreeGraphTraitsBase, + DomTreeNodeBase::const_iterator> {}; + +template<> struct GraphTraits*> + : public DomTreeGraphTraitsBase, + DomTreeNodeBase::const_iterator> {}; + +template +struct GraphTraits*> + : public GraphTraits*> { +private: + using BaseGT=GraphTraits*>; +public: + static typename BaseGT::NodeRef getEntryNode( + PostDomTreeBase *PDT) { + return PDT->getRootNode(); + } + static typename BaseGT::nodes_iterator nodes_begin( + PostDomTreeBase *PDT) { + return df_begin(getEntryNode(PDT)); + } + static typename BaseGT::nodes_iterator nodes_end( + PostDomTreeBase *PDT) { + return df_end(getEntryNode(PDT)); + } +}; + +template +struct DOTGraphTraits*> + : public DOTGraphTraits:: + ParentPtr> { +private: + using BaseDOTGT=DOTGraphTraits:: + ParentPtr>; +public: + DOTGraphTraits(bool IsSimple=false) : BaseDOTGT(IsSimple) {} + static std::string getGraphName(const PostDomTreeBase *Tree) { + return "Post-Dominator Tree"; + } + std::string getNodeLabel(DomTreeNodeBase *Node, + PostDomTreeBase *Tree) { + if (Tree->isVirtualRoot(Node)) + return "Virtual Root"; + else + return BaseDOTGT::getNodeLabel(Node->getBlock(), Node->getBlock()-> + getParent()); + + } + std::string getEdgeSourceLabel(DomTreeNodeBase *Node, + typename GraphTraits*>:: + ChildIteratorType It) { return ""; } + static bool isNodeHidden(DomTreeNodeBase *Node, + PostDomTreeBase *Tree) { + return false; + } + std::string getNodeAttributes(DomTreeNodeBase *Node, + PostDomTreeBase *Tree) { + if (Tree->isVirtualRoot(Node)) + return ""; + else + return BaseDOTGT::getNodeAttributes(Node->getBlock(), Node->getBlock()-> + getParent()); + } + std::string getEdgeAttributes(DomTreeNodeBase*, + typename GraphTraits*>::ChildIteratorType, + PostDomTreeBase*) { + return ""; + } +}; +}; //namespace llvm + +namespace { +template +void addToMap(std::map &Map, KeyT Key, ValueT Value) { + auto It=Map.find(Key); + if (It!=Map.end()) + Map[Key].insert(Value); + else + Map.insert({Key, {Value}}); +} + +template +bool hasEdgesTo(NodeType *SourceN, NodeType *TargetN) { + for (auto ChildNodeIt=GraphTraits::child_begin(SourceN); + ChildNodeIt!=GraphTraits::child_end(SourceN); ++ChildNodeIt) + if (*ChildNodeIt==TargetN) + return true; + return false; +} +}; //anonymous namespace + +template +inline void CDGBuilder::processControlDependence() { + std::map> DepInfo; + for (auto NIt=GraphTraits::nodes_begin(mCFG); NIt!= + GraphTraits::nodes_end(mCFG); ++NIt) + mCDG->emplaceNode(*NIt); + for (auto SrcNIt=++df_begin(mPDT.getRootNode()); SrcNIt!= + df_end(mPDT.getRootNode()); ++SrcNIt) { + if (SrcNIt->getBlock()==GraphTraits::getEntryNode(mCFG)) + for (unsigned I=SrcNIt.getPathLength()-1; I>0; --I) + addToMap(DepInfo, mCDG->getEntryNode(), SrcNIt.getPath(I)->getBlock()); + for (auto TgtNIt=++df_begin(SrcNIt->getIDom()); + TgtNIt!=df_end(SrcNIt->getIDom()); ++TgtNIt) + if (hasEdgesTo(SrcNIt->getBlock(), TgtNIt->getBlock())) + for (unsigned I=TgtNIt.getPathLength()-1; I>0; --I) + addToMap(DepInfo, mCDG->getNode(SrcNIt->getBlock()), + TgtNIt.getPath(I)->getBlock()); + } + for (auto DIIt : DepInfo) + for (auto TgtNIt : DIIt.second) + mCDG->bindNodes(*DIIt.first, *mCDG->getNode(TgtNIt)); +} + +template +CDGType *CDGBuilder::populate(CFGType &CFG) { + mCFG=&CFG; + mCDG=new CDGType(std::string(CFG.getName()), &CFG); + mPDT=PostDomTreeBase(); + mPDT.recalculate(*mCFG); + /*May be useful + dumpDotGraphToFile(&mPDT, "post-dom-tree.dot", "post-dom-tree"); + */ + processControlDependence(); + return mCDG; +} + +bool PDGNode::collectInstructions(function_ref const &Pred, + SmallVectorImpl &IList) const { + assert(IList.empty() && "Expected the IList to be empty on entry."); + if (isa(this)) { + for (Instruction *I : cast(this)->getInstructions()) + if (Pred(I)) + IList.push_back(I); + } + else + if (isa(this)) { + for (const PDGNode *PN : cast(this)-> + getInlinedNodes()) { + assert(!isa(PN) && + "Nested PiBlocks are not supported."); + SmallVector TmpIList; + PN->collectInstructions(Pred, TmpIList); + llvm::append_range(IList, TmpIList); + } + } + else + llvm_unreachable("unimplemented type of node"); + return !IList.empty(); +} + +void PDGNode::destroy() { + switch (mKind) { + case PDGNode::NodeKind::Entry: + delete this; + break; + case PDGNode::NodeKind::SingleInstruction: + case PDGNode::NodeKind::MultiInstruction: + delete (SimplePDGNode*)this; + break; + case PDGNode::NodeKind::PiBlock: + delete (PiBlockPDGNode*)this; + break; + } +} + +PiBlockPDGNode::~PiBlockPDGNode() { + for (PDGNode *N : mInlinedNodes) { + for (PDGEdge *E : N->getEdges()) + E->destroy(); + N->destroy(); + } +} + +void PDGEdge::destroy() { + switch (mKind) { + case PDGEdge::EdgeKind::RegisterDefUse: + case PDGEdge::EdgeKind::Control: + delete this; + break; + case PDGEdge::EdgeKind::MixedData: + case PDGEdge::EdgeKind::Memory: + delete (MemoryPDGEdge*)this; + break; + case PDGEdge::EdgeKind::ComplexData: + case PDGEdge::EdgeKind::ComplexControl: + delete (ComplexPDGEdge*)this; + break; + } +} + +llvm::raw_ostream &tsar::operator<<(llvm::raw_ostream &OS, const PDGNode &N) { + OS<<"Node Address:"<<&N<<":"<< N.getKind()<<"\n"; + if (isa(N)) { + OS<<" Instructions:\n"; + for (const Instruction *I : cast(N).getInstructions()) + OS.indent(2)<<*I<<"\n"; + } + else + if (isa(&N)) { + OS<<"--- start of nodes in pi-block ---\n"; + const SmallVectorImpl &Nodes=cast(&N)-> + getInlinedNodes(); + unsigned Count=0; + for (const PDGNode *N : Nodes) + OS<<*N<<(++Count==Nodes.size()?"":"\n"); + OS<<"--- end of nodes in pi-block ---\n"; + } + else + if (N.getKind()!=PDGNode::NodeKind::Entry) + llvm_unreachable("Unimplemented type of node"); + OS<<(N.getEdges().empty()?" Edges:none!\n" : " Edges:\n"); + for (const PDGEdge *E : N.getEdges()) + OS.indent(2)<<*E; + return OS; +} + +llvm::raw_ostream &tsar::operator<<(llvm::raw_ostream &OS, + const PDGNode::NodeKind K) { + switch (K) { + case PDGNode::NodeKind::Entry: + OS<<"entry"; + break; + case PDGNode::NodeKind::SingleInstruction: + OS<<"single-instruction"; + break; + case PDGNode::NodeKind::MultiInstruction: + OS<<"multi-instruction"; + break; + case PDGNode::NodeKind::PiBlock: + OS<<"pi-block"; + break; + } + return OS; +} + +llvm::raw_ostream &tsar::operator<<(llvm::raw_ostream &OS, const PDGEdge &E) { + OS<<"["<< E.getKind()<<"] to "<<&E.getTargetNode()<<"\n"; + return OS; +} + +llvm::raw_ostream &tsar::operator<<(llvm::raw_ostream &OS, + const PDGEdge::EdgeKind K) { + switch (K) { + case PDGEdge::EdgeKind::RegisterDefUse: + OS<<"def-use"; + break; + case PDGEdge::EdgeKind::MixedData: + OS<<"mixed data"; + break; + case PDGEdge::EdgeKind::Memory: + OS<<"memory"; + break; + case PDGEdge::EdgeKind::Control: + OS<<"control"; + break; + case PDGEdge::EdgeKind::ComplexData: + OS<<"complex data"; + break; + case PDGEdge::EdgeKind::ComplexControl: + OS<<"complex control"; + break; + } + return OS; +} + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const PDG &G) { + for (const PDGNode *Node : G) + OS<<*Node<<"\n"; + OS<<"\n"; + return OS; +} + +//===--------------------------------------------------------------------===// +// PDG DOT Printer Implementation +//===--------------------------------------------------------------------===// +std::string PDGDotGraphTraits::getNodeLabel(const PDGNode *Node, + const PDG *Graph) { + if (isSimple()) + return getSimpleNodeLabel(Node, Graph); + else + return getVerboseNodeLabel(Node, Graph); +} + +std::string PDGDotGraphTraits::getEdgeAttributes(const PDGNode *Node, + GraphTraits::ChildIteratorType I, const PDG *G) { + const PDGEdge *E=static_cast(*I.getCurrent()); + if (isSimple()) + return getEdgeStyle(E); + else + return getEdgeStyle(E)+" "+getVerboseEdgeAttributes(Node, E, G); +} + +bool PDGDotGraphTraits::isNodeHidden(const PDGNode *Node, const PDG *Graph) { + if (const SimplePDGNode *SimpleNode=dyn_cast(Node)) { + for (const Instruction *I : SimpleNode->getInstructions()) + if (!PDGBuilder::shouldShadow(*I)) + return false; + return true; + } + else + if (const PiBlockPDGNode *PiNode=dyn_cast(Node)) { + for (const PDGNode *InlinedNode : PiNode->getInlinedNodes()) + if (!isNodeHidden(InlinedNode, Graph)) + return false; + return true; + } + else + return false; +} + +std::string PDGDotGraphTraits::getSimpleNodeLabel(const PDGNode *Node, + const PDG *G) { + std::string Str; + raw_string_ostream OS(Str); + if (isa(Node)) { + for (const Instruction *II : static_cast(Node)-> + getInstructions()) + if (!PDGBuilder::shouldShadow(*II)) + OS<<*II<<"\n"; + } + else + if (isa(Node)) { + size_t NotHiddenNodesCount=0; + for (const PDGNode *IN : cast(Node)->getInlinedNodes()) + if (!isNodeHidden(IN, G)) + ++NotHiddenNodesCount; + OS<<"pi-block\nwith\n"<getKind()==PDGNode::NodeKind::Entry) + OS<<"entry\n"; + else + llvm_unreachable("Unimplemented type of node"); + return OS.str(); +} + +std::string PDGDotGraphTraits::getVerboseNodeLabel(const PDGNode *Node, + const PDG *G) { + std::string Str; + raw_string_ostream OS(Str); + OS<<"getKind()<<">\n"; + if (const SimplePDGNode *SimpleNode=dyn_cast(Node)) { + for (const Instruction *II : SimpleNode->getInstructions()) + if (!PDGBuilder::shouldShadow(*II)) + OS<<*II<<"\n"; + } + else + if (const PiBlockPDGNode *PiNode=dyn_cast(Node)) { + OS<<"--- start of nodes in pi-block ---\n"; + unsigned Count=0; + for (const PDGNode *IN : PiNode->getInlinedNodes()) { + ++Count; + if (!isNodeHidden(IN, G)) + OS<getKind()==PDGNode::NodeKind::Entry) + OS<<"entry\n"; + else + llvm_unreachable("Unimplemented type of node"); + return OS.str(); +} + +std::string PDGDotGraphTraits::getVerboseEdgeAttributes(const PDGNode *Src, + const PDGEdge *Edge, const PDG *G) { + std::string Str; + raw_string_ostream OS(Str); + auto PrintMemoryEdge=[&OS](const MemoryPDGEdge &E) { + if (llvm::Dependence * const *Dep=std::get_if(&E. + getMemoryDep())) { + (*Dep)->dump(OS); + OS.str().pop_back(); + } + else { + using namespace trait; + auto PrintDIMemDep=[&OS](const MemoryPDGEdge::DIDepT &Dep) -> void { + auto PrintDistVec=[&OS](const DIMemoryTraitRef &MT) + -> void { + const DIDependence *DistVec=MT->get(); + OS<getKnownLevel()==0) + return; + if (DistVec->getDistance(0).first==DistVec->getDistance(0).second) + OS<getDistance(0).first; + else + OS<<"("<getDistance(0).first<<", "< + getDistance(0).second<<")"; + for (int Level=1; LevelgetKnownLevel(); ++Level) + if (DistVec->getDistance(Level).first==DistVec-> + getDistance(Level).second) + OS<<", "<getDistance(Level).first; + else + OS<<", ("<getDistance(Level).first<<", "< + getDistance(Level).second<<")"; + OS<<">\n"; + }; + if (Dep.second.is()) + PrintDistVec.operator()(Dep.first); + if (Dep.second.is()) + PrintDistVec.operator()(Dep.first); + if (Dep.second.is()) + PrintDistVec.operator()(Dep.first); + if (Dep.second.is()) + OS<()) + OS<()) + OS<()) + OS<()) + OS<(E.getMemoryDep()); + for (auto &DIMemDep : DIDeps) { + PrintDIMemDep(DIMemDep); + OS<<"\n"; + } + } + }; + if (const MemoryPDGEdge *MemDepEdge=dyn_cast(Edge)) { + OS<<"label=\"["; + PrintMemoryEdge(*MemDepEdge); + OS.str().pop_back(); + OS<<"]\""; + } + else + if (const ComplexPDGEdge *ComplexEdge=dyn_cast(Edge)) { + auto StringifyInlinedEdge=[&OS, &PrintMemoryEdge](const PDGEdge &E) -> + std::string { + using EdgeKind=PDGEdge::EdgeKind; + std::string Str; + raw_string_ostream OS(Str); + switch (E.getKind()) { + case EdgeKind::RegisterDefUse: + return "def-use"; + case EdgeKind::MixedData: + OS<<"def-use & "; + case EdgeKind::Memory: + PrintMemoryEdge(cast(E)); + return OS.str(); + case EdgeKind::Control: + return "control"; + default: + llvm_unreachable( + "Only simple edges can be inlined in complex edge"); + } + }; + OS<<"label=\""; + for (const ComplexPDGEdge::EdgeHandle &EH : ComplexEdge-> + getInlinedEdges()) { + if (!isNodeHidden(&EH.E.getTargetNode(), G)) + OS<<"("<getKind()) { + case tsar::PDGEdge::EdgeKind::RegisterDefUse: + return "style=\"solid\" color=\"blue\""; + case tsar::PDGEdge::EdgeKind::MixedData: + return "style=\"solid\" color=\"purple\""; + case tsar::PDGEdge::EdgeKind::Memory: + return "style=\"solid\" color=\"green\""; + case tsar::PDGEdge::EdgeKind::Control: + return "style=\"dotted\""; + case tsar::PDGEdge::EdgeKind::ComplexData: + return "style=\"solid\" color=\"orchid\""; + case tsar::PDGEdge::EdgeKind::ComplexControl: + return "style=\"dashed\""; + } +} +//===--------------------------------------------------------------------===// +// End of PDG DOT Printer Implementation +//===--------------------------------------------------------------------===// +PDGBuilder::PDGBuilder(PDG &G, const Function &F, DependenceInfo &DI, + const AliasTree &AT, DIMemoryClientServerInfo &DIMInfo, + const TargetLibraryInfo &TLI, const LoopInfo &LI, bool SolveReachability, + bool Simplify, bool CreatePiBlocks) + : mGraph(G), mF(F), mDI(DI), mAT(AT), mDIMInfo(DIMInfo), mTLI(TLI), + mLI(LI), mSolvedReachability(SolveReachability), mSimplified(Simplify), + mCreatedPiBlocks(CreatePiBlocks), mClientDIATRel(DIMInfo.ClientDIAT), + mBBList(F.size()) { + if (mDIMInfo.isValid()) + mServerDIATRel=SpanningTreeRelation(mDIMInfo.DIAT); + { + size_t BBIdx=F.size(); + for (auto It=po_begin(&F); It!=po_end(&F); ++It) + mBBList[--BBIdx]=*It; + } + if (SolveReachability) + solveReachability(); + LLVM_DEBUG( + { + DOTFuncInfo DOTCFGInfo(&F); + dumpDotGraphToFile(&DOTCFGInfo, "ircfg.dot", "control flow graph"); + if (!mDIMInfo.isValid()) + return; + // Code below prints DIDependenceInfo, + // which contains a set of DIAliasTraits for each loop in function + // In each DIMemoryTrait it attempts to find NoAccess, ReadOnly, Shared, + // Local, Private, FirstPrivate, SecondToLastPrivate, LastPrivate, + // DynamicPrivate and, finally, Flow, Anti, Output + auto PrintDIDepInfo=[](const DIDependencInfo &DIDepInfo) -> void { + using namespace trait; + dbgs()<<"==== Start of DIDependenceInfo Printing! ===\n"; + for (auto &DepInfoRecord : DIDepInfo) { + for (const DIAliasTrait &AT : DepInfoRecord.second) { + for (const DIMemoryTraitRef &MTRef : AT) { + auto PrintDistanceVector=[](const trait::DIDependence *Dep) + -> std::string { + std::string Result; + llvm::raw_string_ostream OS(Result); + if (Dep->getKnownLevel()==0) + return Result; + OS<<"<"; + if (Dep->getDistance(0).first==Dep->getDistance(0).second) + OS<getDistance(0).first; + else + OS<<"("<getDistance(0).first<<", "<< + Dep->getDistance(0).second<<")"; + for (int Level=1; LevelgetKnownLevel(); ++Level) + if (Dep->getDistance(Level).first== + Dep->getDistance(Level).second) + OS<<", "<getDistance(Level).first; + else + OS<<", ("<getDistance(Level).first<<", "<< + Dep->getDistance(Level).second<<")"; + OS<<">"; + return Result; + }; + if (MTRef->is()) + dbgs()<<"------------NoAccess\n"; + if (MTRef->is()) + dbgs()<<"------------Readonly\n"; + if (MTRef->is()) + dbgs()<<"------------Shared\n"; + /*if (MTRef->is()) + dbgs()<<" - - -Local\n";*/ + if (MTRef->is()) + dbgs()<<"------------Private\n"; + if (MTRef->is()) + dbgs()<<"------------FirstPrivate\n"; + if (MTRef->is()) + dbgs()<<"------------SecondToLastPrivate\n"; + if (MTRef->is()) + dbgs()<<"------------LastPrivate\n"; + if (MTRef->is()) + dbgs()<<"------------DynamicPrivate\n"; + trait::DIDependence *DIFlow=MTRef->get(); + trait::DIDependence *DIAnti=MTRef->get(); + trait::DIDependence *DIOutput=MTRef->get(); + if (DIFlow) + dbgs()<<"------------Flow, "<getCauses().size()<<"\n"; + if (DIAnti) + dbgs()<<"------------Anti, "<getCauses().size()<<"\n"; + if (DIOutput) + dbgs()<<"------------Output, "<getCauses().size()<<"\n"; + dbgs()<<"--------end of di-memory-trait hasNoDep - "<< + hasNoDep(*MTRef)<<", hasSpuriosDep - "<getKind()==PDGNode::NodeKind::Entry) + continue; + SimplePDGNode &InstrNode=*cast(N); + Instruction &VI=*InstrNode.getFirstInstruction(); + // Use a set to mark the targets that we link to N, so we don't add + // duplicate def-use edges when more than one instruction in a target node + // use results of instructions that are contained in N. + SmallPtrSet VisitedTargets; + for (User *U : VI.users()) { + Instruction*UI =dyn_cast(U); + if (!UI) + continue; + PDGNode *DstNode; + if (mIMap.find(UI)!=mIMap.end()) + DstNode=mIMap.find(UI)->second; + else { + // In the case of loops, the scope of the subgraph is all the + // basic blocks (and instructions within them) belonging to the loop. We + // simply ignore all the edges coming from (or going into) instructions + // or basic blocks outside of this range. + LLVM_DEBUG(dbgs()<<"skipped def-use edge since the sink"<<*UI<< + " is outside the range of instructions being considered.\n"); + continue; + } + // Self dependencies are ignored because they are redundant and + // uninteresting. + if (DstNode==N) { + LLVM_DEBUG(dbgs()<< + "skipped def-use edge since the sink and the source ("<getKind()==PDGNode::NodeKind::Entry) + continue; + SimplePDGNode &SrcInstrNode=*cast(*SrcNodeIt); + Instruction &SrcInstr=*SrcInstrNode.getFirstInstruction(); + if (!SrcInstr.mayReadOrWriteMemory()) + continue; + for (auto DstNodeIt=SrcNodeIt; DstNodeIt!=mGraph.end(); ++DstNodeIt) { + SmallVector DefUseEdges; + auto CreateDepEdge=[&DefUseEdges, this](PDGNode &Src, PDGNode &Tgt, + const MemoryPDGEdge::MemDepHandle &Dep) { + if (Src.findEdgesTo(Tgt, DefUseEdges)) { + assert(DefUseEdges.size()==1); + Src.removeEdge(*DefUseEdges.front()); + DefUseEdges.front()->destroy(); + DefUseEdges.clear(); + assert(mGraph.connect(Src, Tgt, *(new MemoryPDGEdge(Tgt, Dep, + true)))); + } + else + assert(mGraph.connect(Src, Tgt, *(new MemoryPDGEdge(Tgt, Dep, + false)))); + ++TotalMemoryEdges; + }; + if (**SrcNodeIt==**DstNodeIt) + continue; + SimplePDGNode &DstInstrNode=*cast(*DstNodeIt); + Instruction &DstInstr=*DstInstrNode.getFirstInstruction(); + if (!DstInstr.mayReadOrWriteMemory()) + continue; + if (!(SrcInstr.getParent()==DstInstr.getParent() || + isReachable(*SrcInstr.getParent(), *DstInstr.getParent()) || + isReachable(*DstInstr.getParent(), *SrcInstr.getParent()))) + continue; + std::unique_ptr Dep=mDI.depends(&SrcInstr, &DstInstr, + true); + MemoryPDGEdge::DIDepStorageT ForwardDIDep, BackwardDIDep; + if (!Dep) + continue; + // If we have a dependence with its left-most non-'=' direction + // being '>' we need to reverse the direction of the edge, because + // the source of the dependence cannot occur after the sink. For + // confused dependencies, we will create edges in both directions to + // represent the possibility of a cycle. + if (Dep->isConfused() && confirmMemoryIntersect(SrcInstr, DstInstr, + ForwardDIDep, BackwardDIDep)) { + if (!ForwardDIDep.empty() || !BackwardDIDep.empty()) { + if (!ForwardDIDep.empty()) + CreateDepEdge(**SrcNodeIt, **DstNodeIt, ForwardDIDep); + if (!BackwardDIDep.empty()) { + CreateDepEdge(**DstNodeIt, **SrcNodeIt, BackwardDIDep); + ++TotalEdgeReversals; + } + } + else { + /*CreateDepEdge(**SrcNodeIt, **DstNodeIt, new Dependence(&SrcInstr, + &DstInstr)); + CreateDepEdge(**DstNodeIt, **SrcNodeIt, new Dependence(&DstInstr, + &SrcInstr));*/ + CreateDepEdge(**SrcNodeIt, **DstNodeIt, Dep.release()); + CreateDepEdge(**DstNodeIt, **SrcNodeIt, mDI.depends(&DstInstr, + &SrcInstr, true).release()); + ++TotalConfusedLLVMEdges; + } + continue; + } + if (Dep->isOrdered()) { + if (!Dep->isLoopIndependent()) { + bool ReversedEdge=false; + for (unsigned Level=1; Level<=Dep->getLevels(); ++Level) { + if (Dep->getDirection(Level)==Dependence::DVEntry::EQ) + continue; + if (Dep->getDirection(Level) == Dependence::DVEntry::GT) { + CreateDepEdge(**DstNodeIt, **SrcNodeIt, Dep.release()); + ReversedEdge=true; + ++TotalEdgeReversals; + break; + } + if (Dep->getDirection(Level)==Dependence::DVEntry::LT) + break; + CreateDepEdge(**SrcNodeIt, **DstNodeIt, Dep.release()); + CreateDepEdge(**DstNodeIt, **SrcNodeIt, mDI.depends(&DstInstr, + &SrcInstr, true).release()); + ReversedEdge=true; + ++TotalConfusedLLVMEdges; + break; + } + if (!ReversedEdge) + CreateDepEdge(**SrcNodeIt, **DstNodeIt, Dep.release()); + } + else + CreateDepEdge(**SrcNodeIt, **DstNodeIt, Dep.release()); + } + } + } +} + +void PDGBuilder::createControlDependenceEdges() { + IRCDG *CDG=CDGBuilder().populate(const_cast(mF)); + PDGNode &EntryPDGNode=*(new PDGNode()); + mGraph.addEntryNode(EntryPDGNode); + for (IRCDGNode *BBNode : *CDG) { + auto LinkControlDependent=[this](PDGNode &SrcNode, + IRCDGNode::EdgeListTy &CDGDependentNodes) { + for (IRCDGEdge *ControlDependence : CDGDependentNodes) { + BasicBlock *TargetBlock=cast(&ControlDependence-> + getTargetNode())->getBlock(); + for (Instruction &I : *TargetBlock) { + auto InstrPDGNodeIt=mIMap.find(&I); + if (InstrPDGNodeIt!=mIMap.end()) { + PDGEdge &NewPDGEdge=*(new PDGEdge(*InstrPDGNodeIt->second, + PDGEdge::DependenceType::Control)); + assert(mGraph.connect(SrcNode, *InstrPDGNodeIt->second, + NewPDGEdge)); + } + } + } + }; + if (isa(BBNode)) + LinkControlDependent(EntryPDGNode, BBNode->getEdges()); + else { + DefaultIRCDGNode &SrcNode=*cast(BBNode); + assert(mIMap.find(SrcNode.getBlock()->getTerminator())!=mIMap.end()); + LinkControlDependent(*mIMap[SrcNode.getBlock()->getTerminator()], + SrcNode.getEdges()); + } + } + delete CDG; +} + +void PDGBuilder::simplify() { + if (!mSimplified) + return; + LLVM_DEBUG(dbgs()<<"==== Start of Graph Simplification ===\n"); + // This algorithm works by first collecting a set of candidate nodes that have + // an out-degree of one (in terms of def-use edges), and then ignoring those + // whose targets have an in-degree more than one. Each node in the resulting + // set can then be merged with its corresponding target and put back into the + // worklist until no further merge candidates are available. + DenseSet CandidateSourceNodes; + // A mapping between nodes and their in-degree. To save space, this map + // only contains nodes that are targets of nodes in the CandidateSourceNodes. + DenseMap TargetInDegreeMap; + for (PDGNode *N : mGraph) { + if (N->getEdges().size()!=1) + continue; + PDGEdge &Edge=N->back(); + if (Edge.getKind()!=PDGEdge::EdgeKind::RegisterDefUse) + continue; + CandidateSourceNodes.insert(N); + // Insert an element into the in-degree map and initialize to zero. The + // count will get updated in the next step. + TargetInDegreeMap.insert({&Edge.getTargetNode(), 0}); + } + LLVM_DEBUG({ + dbgs()<<"Size of candidate src node list:"< CDependentTargets; + for (PDGEdge *E : *N) { + auto RegisterCDNode=[&CDependentTargets](PDGNode &N) { + if (CDependentTargets.contains(&N)) + CDependentTargets.erase(&N); + else + CDependentTargets.insert(&N); + }; + PDGNode &TgtNode=E->getTargetNode(); + auto TgtIt=TargetInDegreeMap.find(&TgtNode); + if (E->isControl()) { + auto SrcIt=CandidateSourceNodes.find(&TgtNode); + if (SrcIt!=CandidateSourceNodes.end()) + RegisterCDNode(TgtNode.back().getTargetNode()); + if (TgtIt!=TargetInDegreeMap.end()) + RegisterCDNode(TgtNode); + } + else + if (TgtIt!=TargetInDegreeMap.end()) + ++(TgtIt->second); + } + for (PDGNode *Target : CDependentTargets) + TargetInDegreeMap[Target]=2; + } + LLVM_DEBUG({ + dbgs()<<"Size of target in-degree map:"< "< Worklist(CandidateSourceNodes.begin(), + CandidateSourceNodes.end()); + while (!Worklist.empty()) { + PDGNode &Src=*Worklist.pop_back_val(); + // As nodes get merged, we need to skip any node that has been removed from + // the candidate set (see below). + if (!CandidateSourceNodes.erase(&Src)) + continue; + assert(Src.getEdges().size()==1 && + "Expected a single edge from the candidate src node."); + PDGNode &Tgt=Src.back().getTargetNode(); + assert(TargetInDegreeMap.find(&Tgt)!=TargetInDegreeMap.end() && + "Expected target to be in the in-degree map."); + // Do not merge if there is also an edge from target to src (immediate + // cycle). + if (TargetInDegreeMap[&Tgt]!=1 || !areNodesMergeable(Src, Tgt) || + Tgt.hasEdgeTo(Src)) + continue; + LLVM_DEBUG(dbgs()<<"Merging:"<(b), (b)->(c), (c)->(d), ...} and the worklist is initially {b, a}, + // then after merging (a) and (b) together, we need to put (a,b) back in + // the worklist so that (c) can get merged in as well resulting in + // {(a,b,c) -> d} + // We also need to remove the old target (b), from the worklist. We first + // remove it from the candidate set here, and skip any item from the + // worklist that is not in the set. + if (CandidateSourceNodes.erase(&Tgt)) { + Worklist.push_back(&Src); + CandidateSourceNodes.insert(&Src); + LLVM_DEBUG(dbgs()<<"Putting "<<&Src<<" back in the worklist.\n"); + } + } + LLVM_DEBUG(dbgs()<<"=== End of Graph Simplification ===\n"); +} + +void PDGBuilder::createPiBlocks() { + using NodeListType=SmallVector; + if (!mCreatedPiBlocks) + return; + LLVM_DEBUG(dbgs()<<"==== Start of Creation of Pi-Blocks ===\n"); + // The overall algorithm is as follows: + // 1. Identify SCCs and for each SCC create a pi-block node containing all + // the nodes in that SCC. + // 2. Identify incoming edges incident to the nodes inside of the SCC and + // reconnect them to the pi-block node. + // 3. Identify outgoing edges from the nodes inside of the SCC to nodes + // outside of it and reconnect them so that the edges are coming out of the + // SCC node instead. + + // Adding nodes as we iterate through the SCCs cause the SCC + // iterators to get invalidated. To prevent this invalidation, we first + // collect a list of nodes that are part of an SCC, and then iterate over + // those lists to create the pi-block nodes. Each element of the list is a + // list of nodes in an SCC. Note: trivial SCCs containing a single node are + // ignored. + SmallVector ListOfSCCs; + for (const std::vector &SCC : make_range(scc_begin(&mGraph), + scc_end(&mGraph))) + if (SCC.size()>1) + ListOfSCCs.emplace_back(SCC.begin(), SCC.end()); + for (NodeListType &NL : ListOfSCCs) { + LLVM_DEBUG(dbgs()<<"Creating pi-block node with "< NodesInSCC(NL.begin(), NL.end()); + // We have the set of nodes in the SCC. We go through the set of nodes + // that are outside of the SCC and look for edges that cross the two sets. + for (auto ExternalNodeIt=mGraph.begin(); ExternalNodeIt!=mGraph.end();) { + // Skip the SCC node. + if (*ExternalNodeIt==&PiNode) { + ++ExternalNodeIt; + continue; + } + // Remove SCC inlined node from graph's node list and skip it. + if (NodesInSCC.count(*ExternalNodeIt)) { + mGraph.Nodes.erase(ExternalNodeIt); + continue; + } + // Use these flags to help us avoid creating redundant edges. If there + // are more than one edges from an outside node to inside nodes, we only + // keep one edge from that node to the pi-block node. Similarly, if + // there are more than one edges from inside nodes to an outside node, + // we only keep one edge from the pi-block node to the outside node. + // There is a flag defined for each direction (incoming vs outgoing) and + // for each type of edge supported, using a two-dimensional boolean + // array. + using Direction=typename ComplexPDGEdge::Direction; + using EdgeKind=typename PDGEdge::EdgeKind; + using DependenceType=typename PDGEdge::DependenceType; + EnumeratedArray + NewEdges[Direction::DirectionCount] {nullptr, nullptr}; + for (size_t SCCNodeI=0; SCCNodeI EL; + Src.findEdgesTo(Dst, EL); + if (EL.empty()) + return; + LLVM_DEBUG(dbgs()<<"reconnecting("<<(Dir==Direction::Incoming? + "incoming)":"outgoing)")<<":\nSrc:"<getDependenceType(); + if (NewEdges[Dir][Type]) { + NewEdges[Dir][Type]->absorbEdge(*OldEdge, SCCNodeI, Dir); + LLVM_DEBUG(dbgs()<<"absorbed old edge between Src and Dst.\n\n"); + } + else { + if (Dir==Direction::Incoming) { + NewEdges[Dir][Type]=new ComplexPDGEdge(PiNode, *OldEdge, + SCCNodeI, Dir); + mGraph.connect(Src, PiNode, *NewEdges[Dir][Type]); + LLVM_DEBUG(dbgs()<< + "created complex edge from Src to PiNode.\n"); + } + else { + NewEdges[Dir][Type]=new ComplexPDGEdge(Dst, *OldEdge, SCCNodeI, + Dir); + mGraph.connect(PiNode, Dst, *NewEdges[Dir][Type]); + LLVM_DEBUG(dbgs()<< + "created complex edge from PiNode to Dst.\n"); + } + } + Src.removeEdge(*OldEdge); + LLVM_DEBUG(dbgs()<<"removed old edge between Src and Dst.\n\n"); + /*if (OldEdge->getKind()==PDGEdge::EdgeKind::ComplexControl + || OldEdge->getKind()==PDGEdge::EdgeKind::ComplexData) { + OldEdge->destroy(); + LLVM_DEBUG(dbgs()<<"released memory from old complex edge \\ + between Src and Dst.\n\n"); + }*/ + } + }; + // Process incoming edges incident to the pi-block node. + ReconnectEdges(**ExternalNodeIt, *NL[SCCNodeI], Direction::Incoming); + // Process edges that are coming out of the pi-block node. + ReconnectEdges(*NL[SCCNodeI], **ExternalNodeIt, Direction::Outgoing); + } + ++ExternalNodeIt; + } + } + // Ordinal maps are no longer needed. + mInstOrdinalMap.clear(); + mNodeOrdinalMap.clear(); + LLVM_DEBUG(dbgs()<<"==== End of Creation of Pi-Blocks ===\n"); +} + +bool PDGBuilder::confirmMemoryIntersect(const Instruction &SrcInst, + const Instruction &DstInst, MemoryPDGEdge::DIDepStorageT &NewForwardDep, + MemoryPDGEdge::DIDepStorageT &NewBackwardDep) { + bool SrcUnknownMemory=false, DstUnknownMemory=false, + *CurrMarker=&SrcUnknownMemory; + MemoryLocationSet SrcMemLocs, DstMemLocs, *CurrSet=&SrcMemLocs; + auto CollectMemory=[&CurrSet](Instruction &I, MemoryLocation &&MemLoc, + unsigned OpInd, AccessInfo IsRead, AccessInfo IsWrite) { + CurrSet->insert(MemLoc); + }; + auto EvaluateUnknown=[&CurrMarker](Instruction&, AccessInfo, AccessInfo) { + *CurrMarker=true; + }; + for_each_memory(const_cast(SrcInst), + const_cast(mTLI), CollectMemory, EvaluateUnknown); + CurrSet=&DstMemLocs; + CurrMarker=&DstUnknownMemory; + for_each_memory(const_cast(DstInst), + const_cast(mTLI), CollectMemory, EvaluateUnknown); + if (SrcMemLocs.empty() || DstMemLocs.empty()) + return !(SrcMemLocs.empty() && !SrcUnknownMemory || DstMemLocs.empty() && + !DstUnknownMemory); + enum InfoType { + Client, + Server, + Last=Server + }; + EnumeratedArray, InfoType> SrcDIMems, + DstDIMems; + /*EnumeratedArray, InfoType> SrcDIMems, + DstDIMems;*/ + auto FillDIMemories=[this, &SrcInst](const MemoryLocationSet &MemLocs, + SmallVectorImpl &ClientDIMems, + SmallVectorImpl &ServerDIMems) { + for (auto &MemLoc : MemLocs) { + const EstimateMemory *EstMem=mAT.find(MemLoc); + const MDNode *Metadata; + while (!(Metadata=getRawDIMemoryIfExists(*EstMem, mF.getContext(), + mF.getParent()->getDataLayout(), mAT.getDomTree()))) + EstMem=EstMem->getParent(); + ClientDIMems.push_back(&*mDIMInfo.ClientDIAT->find(*Metadata)); + if (mDIMInfo.isServerAvailable()) + ServerDIMems.push_back(mDIMInfo.findFromClient(*EstMem, + SrcInst.getModule()->getDataLayout(), + const_cast(mAT.getDomTree())).get()); + } + }; + FillDIMemories(SrcMemLocs, SrcDIMems[Client], SrcDIMems[Server]); + FillDIMemories(DstMemLocs, DstDIMems[Client], DstDIMems[Server]); + bool HasDependence=false; + EnumeratedArray FoundDINode(false); + for (int SrcI=0; SrcI SrcDINode(nullptr); + for (int DstI=0; DstI DstDINode(nullptr); + if ( + mDIMInfo.isServerAvailable() && + SrcDIMems[Server][SrcI] && + DstDIMems[Server][DstI] && + (SrcDINode[Server]=SrcDIMems[Server][SrcI]->getAliasNode()) && + (DstDINode[Server]=DstDIMems[Server][DstI]->getAliasNode()) + ) { + if (mServerDIATRel.value().compare(SrcDINode[Server], + DstDINode[Server])!=TreeRelation::TR_UNREACHABLE) + HasDependence=true; + } + else + if ( + SrcDIMems[Client][SrcI] && + DstDIMems[Client][DstI] && + (SrcDINode[Client]=SrcDIMems[Client][SrcI]->getAliasNode()) && + (DstDINode[Client]=DstDIMems[Client][DstI]->getAliasNode()) && + mClientDIATRel.compare(SrcDINode[Client], DstDINode[Client])!= + TreeRelation::TR_UNREACHABLE) + HasDependence=true; + FoundDINode[Client]|=SrcDINode[Client] && DstDINode[Client]; + FoundDINode[Server]|=SrcDINode[Server] && DstDINode[Server]; + } + } + if (!HasDependence && (FoundDINode[Client] || FoundDINode[Server])) + return false; + // At this point we have memory intersection confirmed by AliasTrees, + // but this fact doesn't mean the presence of loop-carried dependence, so we + // need to observe trait set + auto FindDIDependencies=[this, &SrcInst, &DstInst, &NewForwardDep, + &NewBackwardDep]( + const SmallVectorImpl &SrcDIMems, + const SmallVectorImpl &DstDIMems, + const SpanningTreeRelation &DIATRel) -> bool { + using namespace trait; + using EdgeTraitInfoT=SmallDenseMap; + auto FindCommonLoop=[](const Loop *&SrcL, const Loop *&DstL) + -> const Loop* { + if (!SrcL || !DstL) + return nullptr; + if (SrcL->getLoopDepth()getLoopDepth()) + for (unsigned LargerNL=DstL->getLoopDepth(); LargerNL>SrcL-> + getLoopDepth(); --LargerNL) + DstL=DstL->getParentLoop(); + else + for (unsigned LargerNL=SrcL->getLoopDepth(); LargerNL>DstL-> + getLoopDepth(); --LargerNL) + SrcL=SrcL->getParentLoop(); + while (SrcL!=DstL) { + SrcL=SrcL->getParentLoop(); + DstL=DstL->getParentLoop(); + } + if (SrcL) { + const Loop *Result=SrcL; + SrcL=SrcL->getParentLoop(); + DstL=DstL->getParentLoop(); + return Result; + } + return nullptr; + }; + auto AddTrait=[](EdgeTraitInfoT &EdgeTraits, + const DIMemoryTraitRef &Access) -> void { + auto It=EdgeTraits.find(Access); + if (It!=EdgeTraits.end()) + It->second.set(); + else { + MemoryDescriptor NewDK; + NewDK.set(); + EdgeTraits.insert({Access, NewDK}); + } + }; + EdgeTraitInfoT ForwTraits, BackwTraits; + bool FoundDep=false, FoundTrait=false; + const Loop *SrcL=mLI[SrcInst.getParent()], *DstL=mLI[DstInst.getParent()]; + // Attempting to arrange Instruction's DI-mems sets for possible better + // dependence analysis + const SmallVectorImpl *LowerMem=&SrcDIMems, + *HigherMem=&DstDIMems; + for (int ExitFlag=0, SrcI=0; SrcI + getAliasNode()) && (DstAliasN=DstDIMems[DstI]->getAliasNode())) + if (DIATRel.compare(SrcAliasN, DstAliasN)== + TreeRelation::TR_ANCESTOR) { + LowerMem=&DstDIMems; + HigherMem=&SrcDIMems; + ExitFlag=1; + } + else + if (DIATRel.compare(SrcAliasN, DstAliasN)== + TreeRelation::TR_DESCENDANT) { + LowerMem=&SrcDIMems; + HigherMem=&DstDIMems; + ExitFlag=1; + } + } + while (const Loop *CommonLoop=FindCommonLoop(SrcL, DstL)) { + const DIDependenceSet *DIDepSet=mDIMInfo.findFromClient(*CommonLoop); + if (!DIDepSet) + continue; + for (const DIMemory *LoMem : *LowerMem) + for (const DIAliasTrait &AT : *DIDepSet) { + auto CheckCauses=[&SrcInst, &DstInst, &ForwTraits, &BackwTraits, + &AddTrait](const DIMemoryTraitRef &Access) + -> bool { + DIDependence *Dep=Access->get(); + if (!Dep) + return false; + for (const DIDependence::Cause &C : Dep->getCauses()) + if (C.get()) + if (SrcInst.getDebugLoc() && C.get()== + SrcInst.getDebugLoc()) { + AddTrait.operator()(ForwTraits, Access); + return true; + } + else + if (DstInst.getDebugLoc() && C.get()== + DstInst.getDebugLoc()) { + AddTrait.operator()(BackwTraits, Access); + return true; + } + return false; + }; + auto CheckPrivateTrait=[&ForwTraits, &BackwTraits, &AddTrait] + (const DIMemoryTraitRef &Access) -> bool { + if (Access->is()) { + AddTrait.operator()(ForwTraits, Access); + AddTrait.operator()(BackwTraits, Access); + return true; + } + return false; + }; + auto MemAccessIt=AT.find(LoMem); + if (MemAccessIt==AT.end()) + continue; + const DIMemoryTraitRef &MemAccess=*MemAccessIt; + auto HiMemIt=std::find(HigherMem->begin(), HigherMem->end(), + MemAccess->getMemory()); + if (HiMemIt==HigherMem->end()) + continue; + // 1.: NoAccess, Readonly, Shared - No dependencies + // It is worth to notice, that hasSpuriosDep really excludes some + // of deps (mostly containing unions of private-like and shared + // traits), which would have been showed otherwise + FoundTrait=true; + if (hasNoDep(*MemAccess) /*|| hasSpuriousDep(*MemAccess)*/) + continue; + FoundDep=true; + // 2.: Private, FirstPrivate, SecondToLastPrivate, LastPrivate, + // DynamicPrivate - All dependencies + if (CheckPrivateTrait.operator()(MemAccess) || + CheckPrivateTrait.operator()(MemAccess) || + CheckPrivateTrait.operator()(MemAccess) || + CheckPrivateTrait.operator()(MemAccess) || + CheckPrivateTrait.operator()(MemAccess)) + continue; + // 3.: Flow, Anti, Output - Concrete dependence + if (CheckCauses.operator()(MemAccess) || + CheckCauses.operator()(MemAccess) || + CheckCauses.operator()(MemAccess)) + continue; + const DIMemoryTraitSet &DepTS=MemAccess->getSecond(); + if (SrcInst.mayWriteToMemory() && !SrcInst.mayReadFromMemory()) { + if (DstInst.mayReadFromMemory() && !DstInst.mayWriteToMemory()) { + if (MemAccess->is()) + AddTrait.operator()(ForwTraits, MemAccess); + if (MemAccess->is()) + AddTrait.operator()(BackwTraits, MemAccess); + } + else + if (DstInst.mayWriteToMemory() && !DstInst.mayReadFromMemory() && + MemAccess->is()) { + AddTrait.operator()(ForwTraits, MemAccess); + AddTrait.operator()(BackwTraits, MemAccess); + } + } + else + if (SrcInst.mayReadFromMemory() && !SrcInst.mayWriteToMemory() && + DstInst.mayWriteToMemory() && !DstInst.mayReadFromMemory()) { + if (MemAccess->is()) + AddTrait.operator()(BackwTraits, MemAccess); + if (MemAccess->is()) + AddTrait.operator()(ForwTraits, MemAccess); + } + } + } + NewForwardDep.clear(); + NewBackwardDep.clear(); + for (auto &DepTrait : ForwTraits) + NewForwardDep.push_back(DepTrait); + for (auto &DepTrait : BackwTraits) + NewBackwardDep.push_back(DepTrait); + return FoundDep || !FoundTrait; + }; + if (!mDIMInfo.isValid()) + return true; + if (FoundDINode[Server]) + return FindDIDependencies(SrcDIMems[Server], DstDIMems[Server], + mServerDIATRel.value()); + else + if (FoundDINode[Client]) + return FindDIDependencies(SrcDIMems[Client], DstDIMems[Client], + mClientDIATRel); + else + return true; +} + +char ProgramDependencyGraphPass::ID=0; + +INITIALIZE_PASS_BEGIN(ProgramDependencyGraphPass, "pdg", + "Program Dependency Graph", false, true) +INITIALIZE_PASS_DEPENDENCY(DependenceAnalysisWrapperPass) +INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(EstimateMemoryPass) +INITIALIZE_PASS_DEPENDENCY(DIEstimateMemoryPass) +INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) +INITIALIZE_PASS_END(ProgramDependencyGraphPass, "pdg", + "Program Dependency Graph", false, true) + +FunctionPass *createProgramDependencyGraphPass() { + return new ProgramDependencyGraphPass; +} + +void ProgramDependencyGraphPass::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.setPreservesAll(); +} + +bool ProgramDependencyGraphPass::runOnFunction(Function &F) { + releaseMemory(); + DependenceAnalysisWrapperPass &DIPass= + getAnalysis(); + LoopInfoWrapperPass &LIPass=getAnalysis(); + EstimateMemoryPass &EMPass=getAnalysis(); + DIEstimateMemoryPass &DIEMPass=getAnalysis(); + TargetLibraryInfoWrapperPass &TLIPass= + getAnalysis(); + DIMemoryClientServerInfo DIMInfo(const_cast(DIEMPass. + getAliasTree()), *this, F); + mPDG=new PDG(F); + mPDGBuilder=new PDGBuilder(*mPDG, + F, + DIPass.getDI(), + EMPass.getAliasTree(), + DIMInfo, + TLIPass.getTLI(F), + LIPass.getLoopInfo(), + true); + mPDGBuilder->populate(); + return false; +} + +namespace { +struct PDGPassGraphTraits { + static const PDG *getGraph(ProgramDependencyGraphPass *P) { + return &P->getPDG(); + } +}; + +struct PDGPrinter : public DOTGraphTraitsPrinterWrapperPass< + ProgramDependencyGraphPass, false, const PDG*, PDGPassGraphTraits> { + static char ID; + PDGPrinter() : DOTGraphTraitsPrinterWrapperPass("pdg", ID) { + initializePDGPrinterPass(*PassRegistry::getPassRegistry()); + } +}; +char PDGPrinter::ID=0; + +struct PDGViewer : public DOTGraphTraitsViewerWrapperPass< + ProgramDependencyGraphPass, false, const PDG*, + PDGPassGraphTraits> { + static char ID; + PDGViewer() : DOTGraphTraitsViewerWrapperPass("pdg", ID) { + initializePDGViewerPass(*PassRegistry::getPassRegistry()); + } +}; +char PDGViewer::ID=0; +} //anonymous namespace + +INITIALIZE_PASS_IN_GROUP(PDGViewer, "view-pdg", + "View Program Dependency Graph", true, true, + DefaultQueryManager::OutputPassGroup::getPassRegistry()) +INITIALIZE_PASS_IN_GROUP(PDGPrinter, "print-pdg", + "Print Program Dependency Graph", true, true, + DefaultQueryManager::OutputPassGroup::getPassRegistry()) + +FunctionPass *llvm::createPDGPrinter() { + return new PDGPrinter; +} + +FunctionPass *llvm::createPDGViewer() { + return new PDGViewer; +} diff --git a/lib/Analysis/Passes.cpp b/lib/Analysis/Passes.cpp index 047c04c1..61198016 100644 --- a/lib/Analysis/Passes.cpp +++ b/lib/Analysis/Passes.cpp @@ -29,4 +29,7 @@ using namespace llvm; void llvm::initializeAnalysisBase(PassRegistry &Registry) { initializeDFRegionInfoPassPass(Registry); initializeAnalysisConnectionImmutableWrapperPass(Registry); + initializeProgramDependencyGraphPassPass(Registry); + initializePDGPrinterPass(Registry); + initializePDGViewerPass(Registry); }