48template <
class BaseMRG>
49class ThreadMRG :
public BaseMRG
52 ThreadMRG(BVDataPTAImpl* pta,
bool pointerOnly)
53 : BaseMRG(pta, pointerOnly)
63 const CallICFGNode* cs,
const FunObjVar* callee)
override
66 if (tcg->hasThreadForkEdge(cs))
68 ref = this->getRefSideEffectOfFunction(callee);
82 void propagateAdditionalModRef(CallGraphNode* callGraphNode,
90 if (joinSites.empty())
92 const NodeBS& spawneeMod = this->getModSideEffectOfFunction(callGraphNode->
getFunction());
93 for (
const CallICFGNode* callSite : joinSites)
97 if (this->addUnfilteredModSideEffectOfCallSite(callSite, spawneeMod))
98 worklist.
push(this->getCallGraph()->getCallGraphNode(
99 callSite->getCaller())->getId());
111 return std::make_unique<ThreadMRG<DistinctMRG>>(pta, ptrOnlyMSSA);
113 return std::make_unique<ThreadMRG<IntraDisjointMRG>>(pta, ptrOnlyMSSA);
115 return std::make_unique<ThreadMRG<InterDisjointMRG>>(pta, ptrOnlyMSSA);
117 assert(
false &&
"unrecognised memory partition strategy");
136 svfg->removeSVFGEdge(edge);
144 assert(
svfg !=
nullptr &&
"base SVFG must be built before replacing its overlay");
145 assert(mainMHP !=
nullptr && mainLockAnalysis !=
nullptr &&
146 "thread-aware overlay requires main ILA results");
194 svfg->addSVFGEdge(retEdge);
215 if (formalOut ==
nullptr)
222 if (!mssa->
hasCHI(callSite))
225 svfg->getActualOUTSVFGNodes(callSite);
226 for (
NodeID actualOutId : actualOuts)
230 svfg->getSVFGNode(actualOutId));
232 formalOut, actualOut,
233 svfg->getCallSiteID(callSite, formalOut->
getFun()));
246 const SVFGNode* svfgNode = it->second;
275 "thread-aware overlay edge escaped its construction scope");
284 if (
svfg->addSVFGEdge(indirectEdge))
301 if (
svfg->addSVFGEdge(indirectEdge))
318 return found->second;
324 for (SVFGEdge::SVFGEdgeSetTy::iterator iter = node->
InEdgeBegin();
333 while (!worklist.empty())
335 const SVFGNode* node = *worklist.begin();
336 worklist.erase(worklist.begin());
337 visited.insert(node);
342 for (SVFGEdge::SVFGEdgeSetTy::iterator iter = node->
InEdgeBegin(); iter != node->
InEdgeEnd(); ++iter)
348 visited.find(edge->
getSrcNode()) == visited.end())
365 return found->second;
371 for (SVFGEdge::SVFGEdgeSetTy::iterator iter = node->
OutEdgeBegin();
380 while (!worklist.empty())
382 const SVFGNode* node = *worklist.begin();
383 worklist.erase(worklist.begin());
384 visited.insert(node);
395 visited.find(edge->
getDstNode()) == visited.end())
411 return found->second;
414 for (
NodeID id : predecessors)
434 "tail test only for store nodes");
438 return found->second;
441 for (
NodeID id : successors)
448 if (successorStatement !=
nullptr &&
lockAnalysis->isInSameSpan(
514 const bool mayParallel =
mhp->mayHappenInParallel(storeNode, loadNode);
533 const bool commonLock =
534 lockAnalysis->isProtectedByCommonLock(storeNode, loadNode);
560 const bool mayParallel =
mhp->mayHappenInParallel(firstNode, secondNode);
574 const bool commonLock =
575 lockAnalysis->isProtectedByCommonLock(firstNode, secondNode);
612 candidate.sourceNodeId));
615 candidate.destinationNodeId));
616 assert(src !=
nullptr && dst !=
nullptr &&
617 "thread-aware candidates must reference statement nodes");
619 "thread-aware candidate source must be a store");
621 "thread-aware candidate escaped its selected scope");
631 candidate.sourceNodeId);
632 if (processedStorePairs.insert(canonicalPair).second)
648 for (
NodeID objectId : pta->
getPts(store->getDstNodeID()))
649 objectToStoreIds[objectId].set(store->getId());
651 for (
NodeID objectId : pta->
getPts(load->getSrcNodeID()))
652 objectToLoadIds[objectId].set(load->getId());
658 for (
NodeID objectId : pta->
getPts(store->getDstNodeID()))
660 candidateStores |= objectToStoreIds[objectId];
661 const auto loads = objectToLoadIds.find(objectId);
662 if (loads != objectToLoadIds.end())
663 candidateLoads |= loads->second;
666 for (
NodeID loadId : candidateLoads)
674 const NodeID storeId = store->getId();
675 for (
NodeID otherId : candidateStores)
677 if (otherId <= storeId)
const FunObjVar * getFunction() const
Get function of this call node.
const CallGraphNode * getCallGraphNode(const std::string &name) const
Get call graph node.
bool push(const Data &data)
NodeType * getSrcNode() const
NodeType * getDstNode() const
iterator OutEdgeBegin()
iterators
bool addPointsTo(const NodeBS &c)
Handle memory region.
FIFOWorkList< NodeID > WorkList
const NodeBS & getPointsTo() const
Return points-to of the MR.
const ThreadVFCandidateList * candidates
const SlicedSVFGView * scope
bool recordThreadVFQueries
false = skip [THREAD-VF] recording
void connectMHPEdges(PointerAnalysis *pta)
Connect inter-thread (interference) value-flow edges for MHP pairs.
Map< const StmtSVFGNode *, SVFGNodeIDSet > predecessorCache
SVFGEdgeSet threadAwareEdges
std::unique_ptr< MRGenerator > createMRGenerator(BVDataPTAImpl *pta, bool ptrOnlyMSSA) override
void handleStoreStore(const StmtSVFGNode *firstStore, const StmtSVFGNode *secondStore, PointerAnalysis *pta)
void clearThreadAwareOverlay()
Remove all currently attached thread-aware interference edges.
SVFGEdge * addTDEdge(NodeID srcId, NodeID dstId, const PointsTo &pts)
Add a thread-MHP indirect value-flow edge srcId -> dstId carrying pts.
void connectThreadJoinEdges()
void collectLoadStoreSVFGNodes()
const ThreadVFCandidateList * overlayCandidates
Map< const StmtSVFGNode *, bool > spanTailCache
Map< const StmtSVFGNode *, SVFGNodeIDSet > successorCache
void replaceThreadAwareOverlay(MHP *mhp, LockAnalysis *lockAnalysis, const ThreadVFBuildConfig &config)
bool isInOverlayScope(const SVFGNode *node) const
void addJoinRetEdge(const FormalOUTSVFGNode *formalOut, const ActualOUTSVFGNode *actualOut, CallSiteID callSiteId)
void recordThreadVFSource(const StmtSVFGNode *source, const StmtSVFGNode *destination, bool commonLock)
LockAnalysis * lockAnalysis
bool isHeadOfSpan(const StmtSVFGNode *node)
bool labelInterferenceEdges
false = VFG_pre (sliced-only): omit edge points-to labels
ThreadVFQueryMap threadVFQueryMap
[THREAD-VF] per-edge query map (see getThreadVFQueryMap).
const SlicedSVFGView * overlayScope
Active overlay configuration; defaults suit VFG_pre.
bool isTailOfSpan(const StmtSVFGNode *node)
SVFGNodeIDSet getSuccessorNodes(const StmtSVFGNode *node)
void handleStoreLoad(const StmtSVFGNode *store, const StmtSVFGNode *load, PointerAnalysis *pta)
void buildSVFG() override
Rewrite the SVFG build hook: build the stock SVFG, then add MHP edges.
Map< const StmtSVFGNode *, bool > spanHeadCache
SVFGNodeIDSet getPredecessorNodes(const StmtSVFGNode *node)
Lock-span head/tail tests (non-interference lock-pair pruning).
bool hasCHI(const PAGEdge *inst) const
static const OptionMap< u32_t > MemPar
virtual const PointsTo & getPts(NodeID ptr)=0
Get points-to targets of a pointer. It needs to be implemented in child class.
NodeBS toNodeBS() const
Returns this points-to set as a NodeBS.
std::unique_ptr< SVFG > svfg
NodeBS ActualOUTSVFGNodeSet
NodeID getId() const
Get ID.
bool intersects(const SparseBitVector< ElementSize > *RHS) const
NodeID getSrcNodeID() const
NodeID getDstNodeID() const
OrderedSet< const CallICFGNode *, CallSiteIdCmp > InstSet
void getJoinSites(const CallGraphNode *routine, InstSet &csSet)
bool isIndirectVFGEdge() const
bool isThreadMHPIndirectVFGEdge() const
virtual const FunObjVar * getFun() const
Get the function of this SVFGNode.
virtual const ICFGNode * getICFGNode() const
Return corresponding ICFG node.
VFGNodeIDToNodeMapTy::const_iterator const_iterator
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
LLVM_NODISCARD bool isa(const Y &Val)
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
std::set< Key, Compare, Allocator > OrderedSet
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map