Static Value-Flow Analysis
VersionedFlowSensitive.cpp
Go to the documentation of this file.
1 //===- VersionedFlowSensitive.cpp -- Versioned flow-sensitive pointer analysis------------//
2 
3 /*
4  * VersionedFlowSensitive.cpp
5  *
6  * Created on: Jun 26, 2020
7  * Author: Mohamad Barbar
8  */
9 
10 #include "WPA/Andersen.h"
12 #include "Util/Options.h"
13 #include "MemoryModel/PointsTo.h"
14 #include <iostream>
15 #include <queue>
16 #include <thread>
17 #include <mutex>
18 
19 using namespace SVF;
20 
23 
25 {
26  assert(version != invalidVersion && "VersionedFlowSensitive::atKey: trying to use an invalid version!");
27  return std::make_pair(var, version);
28 }
29 
31  : FlowSensitive(_pag, type)
32 {
35  // We'll grab vPtD in initialize.
36 
37  for (SVFIR::const_iterator it = pag->begin(); it != pag->end(); ++it)
38  {
39  if (SVFUtil::isa<ObjVar>(it->second)) equivalentObject[it->first] = it->first;
40  }
41 
42  assert(!Options::OPTSVFG() && "VFS: -opt-svfg not currently supported with VFS.");
43 }
44 
46 {
48  // Overwrite the stat FlowSensitive::initialize gave us.
49  delete stat;
50  stat = new VersionedFlowSensitiveStat(this);
51 
53 
56  consume.resize(svfg->getTotalNodeNum());
57  yield.resize(svfg->getTotalNodeNum());
58 
59  prelabel();
60  meldLabel();
61 
63 }
64 
66 {
68  // vPtD->dumpPTData();
69  // dumpReliances();
70  // dumpLocVersionMaps();
71 }
72 
74 {
75  double start = stat->getClk(true);
76  for (SVFG::iterator it = svfg->begin(); it != svfg->end(); ++it)
77  {
78  NodeID l = it->first;
79  const SVFGNode *ln = it->second;
80 
81  if (const StoreSVFGNode *stn = SVFUtil::dyn_cast<StoreSVFGNode>(ln))
82  {
83  // l: *p = q.
84  // If p points to o (Andersen's), l yields a new version for o.
85  NodeID p = stn->getPAGDstNodeID();
86  for (NodeID o : ander->getPts(p))
87  {
88  prelabeledObjects.insert(o);
89  }
90 
91  vWorklist.push(l);
92 
93  if (ander->getPts(p).count() != 0) ++numPrelabeledNodes;
94  }
95  else if (delta(l))
96  {
97  // The outgoing edges are not only what will later be propagated. SVFGOPT may
98  // move around nodes such that there can be an MRSVFGNode with no incoming or
99  // outgoing edges which will be added at runtime. In essence, we can no
100  // longer rely on the outgoing edges of a delta node when SVFGOPT is enabled.
101  const MRSVFGNode *mr = SVFUtil::dyn_cast<MRSVFGNode>(ln);
102  if (mr != nullptr)
103  {
104  for (const NodeID o : mr->getPointsTo())
105  {
106  prelabeledObjects.insert(o);
107  }
108 
109  // Push into worklist because its consume == its yield.
110  vWorklist.push(l);
111  if (mr->getPointsTo().count() != 0) ++numPrelabeledNodes;
112  }
113  }
114  }
115 
116  double end = stat->getClk(true);
117  prelabelingTime = (end - start) / TIMEINTERVAL;
118 }
119 
121 {
122  double start = stat->getClk(true);
123 
124  assert(Options::VersioningThreads() > 0 && "VFS::meldLabel: number of versioning threads must be > 0!");
125 
126  // Nodes which have at least one object on them given a prelabel + the Andersen's points-to
127  // set of interest so we don't keep calling getPts. For Store nodes, we'll fill that in, for
128  // MR nodes, we won't as its getPointsTo is cheap.
129  // TODO: preferably we cache both for ease and to avoid the dyn_cast/isa, but Andersen's points-to
130  // sets are PointsTo and MR's sets are NodeBS, which are incompatible types. Maybe when we can
131  // use std::option.
132  std::vector<std::pair<const SVFGNode *, const PointsTo *>> prelabeledNodes;
133  // Fast query for the above.
134  std::vector<bool> isPrelabeled(svfg->getTotalNodeNum(), false);
135  while (!vWorklist.empty())
136  {
137  const NodeID n = vWorklist.pop();
138  isPrelabeled[n] = true;
139 
140  const SVFGNode *sn = svfg->getSVFGNode(n);
141  const PointsTo *nPts = nullptr;
142  if (const StoreSVFGNode *store = SVFUtil::dyn_cast<StoreSVFGNode>(sn))
143  {
144  const NodeID p = store->getPAGDstNodeID();
145  nPts = &(this->ander->getPts(p));
146  }
147 
148  prelabeledNodes.push_back(std::make_pair(sn, nPts));
149  }
150 
151  // Delta, delta source, store, and load nodes, which require versions during
152  // solving, unlike other nodes with which we can make do with the reliance map.
153  std::vector<NodeID> nodesWhichNeedVersions;
154  for (SVFG::const_iterator it = svfg->begin(); it != svfg->end(); ++it)
155  {
156  const NodeID n = it->first;
157  if (delta(n) || deltaSource(n) || isStore(n) || isLoad(n)) nodesWhichNeedVersions.push_back(n);
158  }
159 
160  std::mutex *versionMutexes = new std::mutex[nodesWhichNeedVersions.size()];
161 
162  // Map of footprints to the canonical object "owning" the footprint.
164 
165  std::queue<NodeID> objectQueue;
166  for (const NodeID o : prelabeledObjects)
167  {
168  // "Touch" maps with o so we don't need to lock on them.
169  versionReliance[o];
170  stmtReliance[o];
171  objectQueue.push(o);
172  }
173 
174  std::mutex objectQueueMutex;
175  std::mutex footprintOwnerMutex;
176 
177  auto meldVersionWorker = [this, &footprintOwner, &objectQueue,
178  &objectQueueMutex, &footprintOwnerMutex, &versionMutexes,
179  &prelabeledNodes, &isPrelabeled, &nodesWhichNeedVersions]
180  (const unsigned thread)
181  {
182  while (true)
183  {
184  NodeID o;
185  {
186  std::lock_guard<std::mutex> guard(objectQueueMutex);
187  // No more objects? Done.
188  if (objectQueue.empty()) return;
189  o = objectQueue.front();
190  objectQueue.pop();
191  }
192 
193  // 1. Compute the SCCs for the nodes on the graph overlay of o.
194  // For starting nodes, we only need those which did prelabeling for o specifically.
195  // TODO: maybe we should move this to prelabel with a map (o -> starting nodes).
196  std::vector<const SVFGNode *> osStartingNodes;
197  for (std::pair<const SVFGNode *, const PointsTo *> snPts : prelabeledNodes)
198  {
199  const SVFGNode *sn = snPts.first;
200  const PointsTo *pts = snPts.second;
201  if (pts != nullptr)
202  {
203  if (pts->test(o)) osStartingNodes.push_back(sn);
204  }
205  else if (const MRSVFGNode *mr = SVFUtil::dyn_cast<MRSVFGNode>(sn))
206  {
207  if (mr->getPointsTo().test(o)) osStartingNodes.push_back(sn);
208  }
209  else
210  {
211  assert(false && "VFS::meldLabel: unexpected prelabeled node!");
212  }
213  }
214 
215  std::vector<int> partOf;
216  std::vector<const IndirectSVFGEdge *> footprint;
217  unsigned numSCCs = SCC::detectSCCs(this, this->svfg, o, osStartingNodes, partOf, footprint);
218 
219  // 2. Skip any further processing of a footprint we have seen before.
220  {
221  std::lock_guard<std::mutex> guard(footprintOwnerMutex);
222  const Map<std::vector<const IndirectSVFGEdge *>, NodeID>::const_iterator canonOwner
223  = footprintOwner.find(footprint);
224  if (canonOwner == footprintOwner.end())
225  {
226  this->equivalentObject[o] = o;
227  footprintOwner[footprint] = o;
228  }
229  else
230  {
231  this->equivalentObject[o] = canonOwner->second;
232  // Same version and stmt reliance as the canonical. During solving we cannot just reuse
233  // the canonical object's reliance because it may change due to on-the-fly call graph
234  // construction. Something like copy-on-write could be good... probably negligible.
235  this->versionReliance.at(o) = this->versionReliance.at(canonOwner->second);
236  this->stmtReliance.at(o) = this->stmtReliance.at(canonOwner->second);
237  continue;
238  }
239  }
240 
241  // 3. a. Initialise the MeldVersion of prelabeled nodes (SCCs).
242  // b. Initialise a todo list of all the nodes we need to version,
243  // sorted according to topological order.
244  // We will use a map of sccs to meld versions for what is consumed.
245  std::vector<MeldVersion> sccToMeldVersion(numSCCs);
246  // At stores, what is consumed is different to what is yielded, so we
247  // maintain that separately.
248  Map<NodeID, MeldVersion> storesYieldedMeldVersion;
249  // SVFG nodes of interest -- those part of an SCC from the starting nodes.
250  std::vector<NodeID> todoList;
251  unsigned bit = 0;
252  // To calculate reachable nodes, we can see what nodes n exist where
253  // partOf[n] != -1. Since the SVFG can be large this can be expensive.
254  // Instead, we can gather this from the edges in the footprint and
255  // the starting nodes (incase such nodes have no edges).
256  // TODO: should be able to do this better: too many redundant inserts.
257  Set<NodeID> reachableNodes;
258  for (const SVFGNode *sn : osStartingNodes) reachableNodes.insert(sn->getId());
259  for (const SVFGEdge *se : footprint)
260  {
261  reachableNodes.insert(se->getSrcNode()->getId());
262  reachableNodes.insert(se->getDstNode()->getId());
263  }
264 
265  for (const NodeID n : reachableNodes)
266  {
267  if (isPrelabeled[n])
268  {
269  if (this->isStore(n)) storesYieldedMeldVersion[n].set(bit);
270  else sccToMeldVersion[partOf[n]].set(bit);
271  ++bit;
272  }
273 
274  todoList.push_back(n);
275  }
276 
277  // Sort topologically so each nodes is only visited once.
278  auto cmp = [&partOf](const NodeID a, const NodeID b)
279  {
280  return partOf[a] > partOf[b];
281  };
282  std::sort(todoList.begin(), todoList.end(), cmp);
283 
284  // 4. a. Do meld versioning.
285  // b. Determine SCC reliances.
286  // c. Build a footprint for o (all edges which it is found on).
287  // d. Determine which SCCs belong to stores.
288 
289  // sccReliance[x] = { y_1, y_2, ... } if there exists an edge from a node
290  // in SCC x to SCC y_i.
291  std::vector<Set<int>> sccReliance(numSCCs);
292  // Maps SCC to the store it corresponds to or -1 if it doesn't. TODO: unsigned vs signed -- nasty.
293  std::vector<int> storeSCC(numSCCs, -1);
294  for (size_t i = 0; i < todoList.size(); ++i)
295  {
296  const NodeID n = todoList[i];
297  const SVFGNode *sn = this->svfg->getSVFGNode(n);
298  const bool nIsStore = this->isStore(n);
299 
300  int nSCC = partOf[n];
301  if (nIsStore) storeSCC[nSCC] = n;
302 
303  // Given n -> m, the yielded version of n will be melded into m.
304  // For stores, that is in storesYieldedMeldVersion, otherwise, consume == yield and
305  // we can just use sccToMeldVersion.
306  const MeldVersion &nMV = nIsStore ? storesYieldedMeldVersion[n] : sccToMeldVersion[nSCC];
307  for (const SVFGEdge *e : sn->getOutEdges())
308  {
309  const IndirectSVFGEdge *ie = SVFUtil::dyn_cast<IndirectSVFGEdge>(e);
310  if (!ie) continue;
311 
312  const NodeID m = ie->getDstNode()->getId();
313  // Ignoreedges which don't involve o.
314  if (!ie->getPointsTo().test(o)) continue;
315 
316  int mSCC = partOf[m];
317 
318  // There is an edge from the SCC n belongs to that m belongs to.
319  sccReliance[nSCC].insert(mSCC);
320 
321  // Ignore edges to delta nodes (prelabeled consume).
322  // No point propagating when n's SCC == m's SCC (same meld version there)
323  // except when it is a store, because we are actually propagating n's yielded
324  // into m's consumed. Store nodes are in their own SCCs, so it is a self
325  // loop on a store node.
326  if (!this->delta(m) && (nSCC != mSCC || nIsStore))
327  {
328  sccToMeldVersion[mSCC] |= nMV;
329  }
330  }
331  }
332 
333  // 5. Transform meld versions belonging to SCCs into versions.
335  std::vector<Version> sccToVersion(numSCCs, invalidVersion);
336  Version curVersion = 0;
337  for (u32_t scc = 0; scc < sccToMeldVersion.size(); ++scc)
338  {
339  const MeldVersion &mv = sccToMeldVersion[scc];
340  Map<MeldVersion, Version>::const_iterator foundVersion = mvv.find(mv);
341  Version v = foundVersion == mvv.end() ? mvv[mv] = ++curVersion : foundVersion->second;
342  sccToVersion[scc] = v;
343  }
344 
345  sccToMeldVersion.clear();
346 
347  // Same for storesYieldedMeldVersion.
348  Map<NodeID, Version> storesYieldedVersion;
349  for (auto const& nmv : storesYieldedMeldVersion)
350  {
351  const NodeID n = nmv.first;
352  const MeldVersion &mv = nmv.second;
353 
354  Map<MeldVersion, Version>::const_iterator foundVersion = mvv.find(mv);
355  Version v = foundVersion == mvv.end() ? mvv[mv] = ++curVersion : foundVersion->second;
356  storesYieldedVersion[n] = v;
357  }
358 
359  storesYieldedMeldVersion.clear();
360 
361  mvv.clear();
362 
363  // 6. From SCC reliance, determine version reliances.
364  Map<Version, std::vector<Version>> &osVersionReliance = this->versionReliance.at(o);
365  for (u32_t scc = 0; scc < numSCCs; ++scc)
366  {
367  if (sccReliance[scc].empty()) continue;
368 
369  // Some consume relies on a yield. When it's a store, we need to pick whether to
370  // use the consume or yield unlike when it is not because they are the same.
371  const Version version
372  = storeSCC[scc] != -1 ? storesYieldedVersion[storeSCC[scc]] : sccToVersion[scc];
373 
374  std::vector<Version> &reliantVersions = osVersionReliance[version];
375  for (const int reliantSCC : sccReliance[scc])
376  {
377  const Version reliantVersion = sccToVersion[reliantSCC];
378  if (version != reliantVersion)
379  {
380  // sccReliance is a set, no need to worry about duplicates.
381  reliantVersions.push_back(reliantVersion);
382  }
383  }
384  }
385 
386  // 7. a. Save versions for nodes which need them.
387  // b. Fill in stmtReliance.
388  // TODO: maybe randomize iteration order for less contention? Needs profiling.
389  Map<Version, NodeBS> &osStmtReliance = this->stmtReliance.at(o);
390  for (size_t i = 0; i < nodesWhichNeedVersions.size(); ++i)
391  {
392  const NodeID n = nodesWhichNeedVersions[i];
393  std::mutex &mutex = versionMutexes[i];
394 
395  const int scc = partOf[n];
396  if (scc == -1) continue;
397 
398  std::lock_guard<std::mutex> guard(mutex);
399 
400  const Version c = sccToVersion[scc];
401  if (c != invalidVersion)
402  {
403  this->setConsume(n, o, c);
404  if (this->isStore(n) || this->isLoad(n)) osStmtReliance[c].set(n);
405  }
406 
407  if (this->isStore(n))
408  {
409  const Map<NodeID, Version>::const_iterator yIt = storesYieldedVersion.find(n);
410  if (yIt != storesYieldedVersion.end()) this->setYield(n, o, yIt->second);
411  }
412  }
413  }
414  };
415 
416  std::vector<std::thread> workers;
417  for (unsigned i = 0; i < Options::VersioningThreads(); ++i) workers.push_back(std::thread(meldVersionWorker, i));
418  for (std::thread &worker : workers) worker.join();
419 
420  delete[] versionMutexes;
421 
422  double end = stat->getClk(true);
423  meldLabelingTime = (end - start) / TIMEINTERVAL;
424 }
425 
427 {
428  // Meld operator is union of bit vectors.
429  return mv1 |= mv2;
430 }
431 
433 {
434  assert(l < deltaMap.size() && "VFS::delta: deltaMap is missing SVFG nodes!");
435  return deltaMap[l];
436 }
437 
439 {
440  assert(l < deltaSourceMap.size() && "VFS::delta: deltaSourceMap is missing SVFG nodes!");
441  return deltaSourceMap[l];
442 }
443 
445 {
446  isStoreMap.resize(svfg->getTotalNodeNum(), false);
447  isLoadMap.resize(svfg->getTotalNodeNum(), false);
448  for (SVFG::const_iterator it = svfg->begin(); it != svfg->end(); ++it)
449  {
450  if (SVFUtil::isa<StoreSVFGNode>(it->second)) isStoreMap[it->first] = true;
451  else if (SVFUtil::isa<LoadSVFGNode>(it->second)) isLoadMap[it->first] = true;
452  }
453 }
454 
456 {
457  assert(l < isStoreMap.size() && "VFS::isStore: isStoreMap is missing SVFG nodes!");
458  return isStoreMap[l];
459 }
460 
462 {
463  assert(l < isLoadMap.size() && "VFS::isLoad: isLoadMap is missing SVFG nodes!");
464  return isLoadMap[l];
465 }
466 
468 {
469  deltaMap.resize(svfg->getTotalNodeNum(), false);
470 
471  // Call block nodes corresponding to all delta nodes.
472  Set<const CallICFGNode *> deltaCBNs;
473 
474  for (SVFG::const_iterator it = svfg->begin(); it != svfg->end(); ++it)
475  {
476  const NodeID l = it->first;
477  const SVFGNode *s = it->second;
478 
479  // Cases:
480  // * Function entry: can get new incoming indirect edges through ind. callsites.
481  // * Callsite returns: can get new incoming indirect edges if the callsite is indirect.
482  // * Otherwise: static.
483  bool isDelta = false;
484  if (const SVFFunction *fn = svfg->isFunEntrySVFGNode(s))
485  {
489  isDelta = !callsites.empty();
490 
491  if (isDelta)
492  {
493  // TODO: could we use deltaCBNs in the call above, avoiding this loop?
494  for (const CallICFGNode *cbn : callsites) deltaCBNs.insert(cbn);
495  }
496  }
497  else if (const CallICFGNode *cbn = svfg->isCallSiteRetSVFGNode(s))
498  {
499  isDelta = cbn->isIndirectCall();
500  if (isDelta) deltaCBNs.insert(cbn);
501  }
502 
503  deltaMap[l] = isDelta;
504  }
505 
506  deltaSourceMap.resize(svfg->getTotalNodeNum(), false);
507 
508  for (SVFG::const_iterator it = svfg->begin(); it != svfg->end(); ++it)
509  {
510  const NodeID l = it->first;
511  const SVFGNode *s = it->second;
512 
513  if (const CallICFGNode *cbn = SVFUtil::dyn_cast<CallICFGNode>(s->getICFGNode()))
514  {
515  if (deltaCBNs.find(cbn) != deltaCBNs.end()) deltaSourceMap[l] = true;
516  }
517 
518  // TODO: this is an over-approximation but it sound, marking every formal out as
519  // a delta-source.
520  if (SVFUtil::isa<FormalOUTSVFGNode>(s)) deltaSourceMap[l] = true;
521  }
522 }
523 
525 {
526  for (SVFG::iterator nodeIt = svfg->begin(); nodeIt != svfg->end(); ++nodeIt)
527  {
528  SVFGNode *sn = nodeIt->second;
529 
530  const SVFGEdgeSetTy &inEdges = sn->getInEdges();
531  std::vector<SVFGEdge *> toDeleteFromIn;
532  for (SVFGEdge *e : inEdges)
533  {
534  if (SVFUtil::isa<IndirectSVFGEdge>(e)) toDeleteFromIn.push_back(e);
535  }
536 
537  for (SVFGEdge *e : toDeleteFromIn) svfg->removeSVFGEdge(e);
538 
539  // Only need to iterate over incoming edges for each node because edges
540  // will be deleted from in/out through removeSVFGEdge.
541  }
542 
543  setGraph(svfg);
544 }
545 
547 {
548  double start = stat->getClk();
549 
550  const std::vector<Version> &reliantVersions = getReliantVersions(o, v);
551  for (Version r : reliantVersions)
552  {
553  propagateVersion(o, v, r, false);
554  }
555 
556  double end = stat->getClk();
557  versionPropTime += (end - start) / TIMEINTERVAL;
558 }
559 
560 void VersionedFlowSensitive::propagateVersion(const NodeID o, const Version v, const Version vp, bool time/*=true*/)
561 {
562  double start = time ? stat->getClk() : 0.0;
563 
564  const VersionedVar srcVar = atKey(o, v);
565  const VersionedVar dstVar = atKey(o, vp);
566  if (vPtD->unionPts(dstVar, srcVar))
567  {
568  // o:vp has changed.
569  // Add the dummy propagation node to tell the solver to propagate it later.
570  const DummyVersionPropSVFGNode *dvp = nullptr;
571  VarToPropNodeMap::const_iterator dvpIt = versionedVarToPropNode.find(dstVar);
572  if (dvpIt == versionedVarToPropNode.end())
573  {
574  dvp = svfg->addDummyVersionPropSVFGNode(o, vp);
575  versionedVarToPropNode[dstVar] = dvp;
576  }
577  else dvp = dvpIt->second;
578 
579  assert(dvp != nullptr && "VFS::propagateVersion: propagation dummy node not found?");
580  pushIntoWorklist(dvp->getId());
581 
582  // Notify nodes which rely on o:vp that it changed.
583  for (NodeID s : getStmtReliance(o, vp)) pushIntoWorklist(s);
584  }
585 
586  double end = time ? stat->getClk() : 0.0;
587  if (time) versionPropTime += (end - start) / TIMEINTERVAL;
588 }
589 
591 {
592  SVFGNode* sn = svfg->getSVFGNode(n);
593  // Handle DummyVersPropSVFGNode here so we don't have to override the long
594  // processSVFGNode. We also don't call propagate based on its result.
595  if (const DummyVersionPropSVFGNode *dvp = SVFUtil::dyn_cast<DummyVersionPropSVFGNode>(sn))
596  {
597  propagateVersion(dvp->getObject(), dvp->getVersion());
598  }
599  else if (processSVFGNode(sn))
600  {
601  propagate(&sn);
602  }
603 }
604 
606 {
607  for (const SVFGEdge *e : newEdges)
608  {
609  SVFGNode *dstNode = e->getDstNode();
610  NodeID src = e->getSrcNode()->getId();
611  NodeID dst = dstNode->getId();
612 
613  if (SVFUtil::isa<PHISVFGNode>(dstNode)
614  || SVFUtil::isa<FormalParmSVFGNode>(dstNode)
615  || SVFUtil::isa<ActualRetSVFGNode>(dstNode))
616  {
617  pushIntoWorklist(dst);
618  }
619  else
620  {
621  const IndirectSVFGEdge *ie = SVFUtil::dyn_cast<IndirectSVFGEdge>(e);
622  assert(ie != nullptr && "VFS::updateConnectedNodes: given direct edge?");
623 
624  assert(delta(dst) && "VFS::updateConnectedNodes: new edges should be to delta nodes!");
625  assert(deltaSource(src) && "VFS::updateConnectedNodes: new indirect edges should be from delta source nodes!");
626 
627  const NodeBS &ept = ie->getPointsTo();
628  // For every o, such that src --o--> dst, we need to set up reliance (and propagate).
629  for (const NodeID o : ept)
630  {
631  Version srcY = getYield(src, o);
632  if (srcY == invalidVersion) continue;
633  Version dstC = getConsume(dst, o);
634  if (dstC == invalidVersion) continue;
635 
636  std::vector<Version> &versionsRelyingOnSrcY = getReliantVersions(o, srcY);
637  if (std::find(versionsRelyingOnSrcY.begin(), versionsRelyingOnSrcY.end(), dstC) == versionsRelyingOnSrcY.end())
638  {
639  versionsRelyingOnSrcY.push_back(dstC);
640  propagateVersion(o, srcY, dstC);
641  }
642  }
643  }
644  }
645 }
646 
648 {
649  double start = stat->getClk();
650 
651  bool changed = false;
652 
653  // l: p = *q
654  NodeID l = load->getId();
655  NodeID p = load->getPAGDstNodeID();
656  NodeID q = load->getPAGSrcNodeID();
657 
658  const PointsTo& qpt = getPts(q);
659  // p = *q, the type of p must be a pointer
660  if (load->getPAGDstNode()->isPointer())
661  {
662  for (NodeID o : qpt)
663  {
664  if (pag->isConstantObj(o)) continue;
665 
666  const Version c = getConsume(l, o);
667  if (c != invalidVersion && vPtD->unionPts(p, atKey(o, c)))
668  {
669  changed = true;
670  }
671 
672  if (isFieldInsensitive(o))
673  {
676  const NodeBS& fields = getAllFieldsObjVars(o);
677  for (NodeID of : fields)
678  {
679  const Version c = getConsume(l, of);
680  if (c != invalidVersion && vPtD->unionPts(p, atKey(of, c)))
681  {
682  changed = true;
683  }
684  }
685  }
686  }
687  }
688  double end = stat->getClk();
689  loadTime += (end - start) / TIMEINTERVAL;
690  return changed;
691 }
692 
694 {
695  NodeID p = store->getPAGDstNodeID();
696  const PointsTo &ppt = getPts(p);
697 
698  if (ppt.empty()) return false;
699 
700  NodeID q = store->getPAGSrcNodeID();
701  const PointsTo &qpt = getPts(q);
702 
703  NodeID l = store->getId();
704  // l: *p = q
705 
706  double start = stat->getClk();
707  bool changed = false;
708  // The version for these objects would be y_l(o).
709  NodeBS changedObjects;
710 
711  if (!qpt.empty())
712  {
713  // *p = q, the type of q must be a pointer
714  if (store->getPAGSrcNode()->isPointer())
715  {
716  for (NodeID o : ppt)
717  {
718  if (pag->isConstantObj(o)) continue;
719 
720  const Version y = getYield(l, o);
721  if (y != invalidVersion && vPtD->unionPts(atKey(o, y), q))
722  {
723  changed = true;
724  changedObjects.set(o);
725  }
726  }
727  }
728  }
729 
730  double end = stat->getClk();
731  storeTime += (end - start) / TIMEINTERVAL;
732 
733  double updateStart = stat->getClk();
734 
735  NodeID singleton = 0;
736  bool isSU = isStrongUpdate(store, singleton);
737  if (isSU) svfgHasSU.set(l);
738  else svfgHasSU.reset(l);
739 
740  // For all objects, perform pts(o:y) = pts(o:y) U pts(o:c) at loc,
741  // except when a strong update is taking place.
742  for (const ObjToVersionMap::value_type &oc : consume[l])
743  {
744  const NodeID o = oc.first;
745  const Version c = oc.second;
746 
747  // Strong-updated; don't propagate.
748  if (isSU && o == singleton) continue;
749 
750  const Version y = getYield(l, o);
751  if (y != invalidVersion && vPtD->unionPts(atKey(o, y), atKey(o, c)))
752  {
753  changed = true;
754  changedObjects.set(o);
755  }
756  }
757 
758  double updateEnd = stat->getClk();
759  updateTime += (updateEnd - updateStart) / TIMEINTERVAL;
760 
761  // Changed objects need to be propagated. Time here should be inconsequential
762  // *except* for time taken for propagateVersion, which will time itself.
763  if (!changedObjects.empty())
764  {
765  for (const NodeID o : changedObjects)
766  {
767  // Definitely has a yielded version (came from prelabelling) as these are
768  // the changed objects which must've been pointed to in Andersen's too.
769  const Version y = getYield(l, o);
770  propagateVersion(o, y);
771 
772  // Some o/v pairs changed: statements need to know.
773  for (NodeID s : getStmtReliance(o, y)) pushIntoWorklist(s);
774  }
775  }
776 
777  return changed;
778 }
779 
781 {
782  std::vector<std::pair<unsigned, unsigned>> keys;
783  for (SVFIR::iterator pit = pag->begin(); pit != pag->end(); ++pit)
784  {
785  unsigned occ = 1;
786  unsigned v = pit->first;
787  if (Options::PredictPtOcc() && pag->getObject(v) != nullptr) occ = stmtReliance[v].size() + 1;
788  assert(occ != 0);
789  keys.push_back(std::make_pair(v, occ));
790  }
791 
792  PointsTo::MappingPtr nodeMapping =
793  std::make_shared<std::vector<NodeID>>(NodeIDAllocator::Clusterer::cluster(ander, keys, candidateMappings, "aux-ander"));
794  PointsTo::MappingPtr reverseNodeMapping =
795  std::make_shared<std::vector<NodeID>>(NodeIDAllocator::Clusterer::getReverseNodeMapping(*nodeMapping));
796 
797  PointsTo::setCurrentBestNodeMapping(nodeMapping, reverseNodeMapping);
798 }
799 
801 {
802  const Map<NodeID, NodeID>::const_iterator canonObjectIt = equivalentObject.find(o);
803  const NodeID op = canonObjectIt == equivalentObject.end() ? o : canonObjectIt->second;
804 
805  const ObjToVersionMap &ovm = lvm[l];
806  const ObjToVersionMap::const_iterator foundVersion = ovm.find(op);
807  return foundVersion == ovm.end() ? invalidVersion : foundVersion->second;
808 }
809 
811 {
812  return getVersion(l, o, consume);
813 }
814 
816 {
817  // Non-store: consume == yield.
818  if (isStore(l)) return getVersion(l, o, yield);
819  else return getVersion(l, o, consume);
820 }
821 
823 {
824  ObjToVersionMap &ovm = lvm[l];
825  ovm[o] = v;
826 }
827 
829 {
830  setVersion(l, o, v, consume);
831 }
832 
833 void VersionedFlowSensitive::setYield(const NodeID l, const NodeID o, const Version v)
834 {
835  // Non-store: consume == yield.
836  if (isStore(l)) setVersion(l, o, v, yield);
837  else setVersion(l, o, v, consume);
838 }
839 
840 std::vector<Version> &VersionedFlowSensitive::getReliantVersions(const NodeID o, const Version v)
841 {
842  return versionReliance[o][v];
843 }
844 
846 {
847  return stmtReliance[o][v];
848 }
849 
851 {
852  SVFUtil::outs() << "# Version reliances\n";
853  for (const Map<NodeID, Map<Version, std::vector<Version>>>::value_type &ovrv : versionReliance)
854  {
855  NodeID o = ovrv.first;
856  SVFUtil::outs() << " Object " << o << "\n";
857  for (const Map<Version, std::vector<Version>>::value_type& vrv : ovrv.second)
858  {
859  Version v = vrv.first;
860  SVFUtil::outs() << " Version " << v << " is a reliance for: ";
861 
862  bool first = true;
863  for (Version rv : vrv.second)
864  {
865  if (!first)
866  {
867  SVFUtil::outs() << ", ";
868  }
869 
870  SVFUtil::outs() << rv;
871  first = false;
872  }
873 
874  SVFUtil::outs() << "\n";
875  }
876  }
877 
878  SVFUtil::outs() << "# Statement reliances\n";
879  for (const Map<NodeID, Map<Version, NodeBS>>::value_type &ovss : stmtReliance)
880  {
881  NodeID o = ovss.first;
882  SVFUtil::outs() << " Object " << o << "\n";
883 
884  for (const Map<Version, NodeBS>::value_type &vss : ovss.second)
885  {
886  Version v = vss.first;
887  SVFUtil::outs() << " Version " << v << " is a reliance for statements: ";
888 
889  const NodeBS &ss = vss.second;
890  bool first = true;
891  for (NodeID s : ss)
892  {
893  if (!first)
894  {
895  SVFUtil::outs() << ", ";
896  }
897 
898  SVFUtil::outs() << s;
899  first = false;
900  }
901 
902  SVFUtil::outs() << "\n";
903  }
904  }
905 }
906 
908 {
909  SVFUtil::outs() << "# LocVersion Maps\n";
910  for (SVFG::iterator it = svfg->begin(); it != svfg->end(); ++it)
911  {
912  const NodeID loc = it->first;
913  bool locPrinted = false;
914  for (const LocVersionMap *lvm :
915  {
916  &consume, &yield
917  })
918  {
919  if (lvm->at(loc).empty()) continue;
920  if (!locPrinted)
921  {
922  SVFUtil::outs() << " " << "SVFG node " << loc << "\n";
923  locPrinted = true;
924  }
925 
926  SVFUtil::outs() << " " << (lvm == &consume ? "Consume " : "Yield ") << ": ";
927 
928  bool first = true;
929  for (const ObjToVersionMap::value_type &ov : lvm->at(loc))
930  {
931  const NodeID o = ov.first;
932  const Version v = ov.second;
933  SVFUtil::outs() << (first ? "" : ", ") << "<" << o << ", " << v << ">";
934  first = false;
935  }
936 
937  SVFUtil::outs() << "\n";
938  }
939  }
940 
941 }
942 
944 {
945  SVFUtil::outs() << "[ ";
946  bool first = true;
947  for (unsigned e : v)
948  {
949  if (!first)
950  {
951  SVFUtil::outs() << ", ";
952  }
953 
954  SVFUtil::outs() << e;
955  first = false;
956  }
957 
958  SVFUtil::outs() << " ]";
959 }
960 
962 {
964  initialize();
966  if(!filename.empty())
967  {
968  SVFUtil::outs() << "Loading versioned pointer analysis results from '" << filename << "'...";
969 
970  std::ifstream F(filename.c_str());
971  if (!F.is_open())
972  {
973  SVFUtil::outs() << " error opening file for reading!\n";
974  return ;
975  }
977 
979 
981 
983 
985 
986  // Update callgraph
988 
989  F.close();
990  SVFUtil::outs() << "\n";
991  }
992 
994  finalize();
995 }
996 
998 {
1000  initialize();
1001  if(!filename.empty())
1002  writeObjVarToFile(filename);
1003  solveConstraints();
1004  if(!filename.empty())
1005  {
1007  writeToFile(filename);
1008  }
1010  finalize();
1011 }
1012 
1014 {
1015  SVFUtil::outs() << "Storing Versioned Analysis Result to '" << filename << "'...";
1016  std::error_code err;
1017  std::fstream f(filename.c_str(), std::ios_base::app);
1018  if (!f.good())
1019  {
1020  SVFUtil::outs() << " error opening file for writing!\n";
1021  return;
1022  }
1023 
1024  for (const VersionedFlowSensitive::LocVersionMap *lvm :
1025  {
1026  &this->consume, &this->yield
1027  })
1028  {
1029  for (const VersionedFlowSensitive::ObjToVersionMap &lov : *lvm)
1030  {
1031  for (const VersionedFlowSensitive::ObjToVersionMap::value_type &ov : lov)
1032  {
1033  const NodeID o = ov.first;
1034  const Version v = ov.second;
1035  if (vPtD->getPts(atKey(o, v)).empty()) continue;
1036 
1037  f <<"[ " <<o <<" " <<v<<" ]"<< " -> { ";
1038  const PointsTo &ovPts = vPtD->getPts(atKey(o, v));
1039  if (!ovPts.empty())
1040  {
1041  for (NodeID n: ovPts)
1042  {
1043  f << n << " ";
1044  }
1045  }
1046  else
1047  {
1048  f << " ";
1049  }
1050  f << "}\n";
1051  }
1052  }
1053  }
1054 
1055  f << "---VERSIONED---\n";
1056 
1057  f.close();
1058  if (f.good())
1059  {
1060  SVFUtil::outs() << "\n";
1061  return;
1062  }
1063 }
1064 
1066 {
1067  std::string line;
1068  std::string delimiter1 = " -> { ";
1069  std::string delimiter2 = " }";
1070  while (F.good())
1071  {
1072  // Parse a single line in the form of "[ var version ] -> { obj1 obj2 obj3 }"
1073  getline(F, line);
1074  if (line == "---VERSIONED---") break;
1075  std::string pair = line.substr(line.find("[ ")+1, line.find(" ]"));
1076 
1077  // Parse VersionKey
1078  std::istringstream ss(pair);
1079  NodeID nodeID;
1080  Version nodeVersion;
1081  ss>> nodeID >> nodeVersion;
1082  VersionedVar keyPair = atKey(nodeID,nodeVersion);
1083 
1084  // Parse Point-to set
1085  size_t pos = line.find(delimiter1);
1086  if (pos == std::string::npos) break;
1087  if (line.back() != '}') break;
1088  pos = pos + delimiter1.length();
1089  size_t len = line.length() - pos - delimiter2.length();
1090  std::string objs = line.substr(pos, len);
1091  PointsTo dstPts;
1092  if (!objs.empty())
1093  {
1094  std::istringstream pt(objs);
1095  NodeID obj;
1096  while (pt.good())
1097  {
1098  pt >> obj;
1099  dstPts.set(obj);
1100  }
1101  }
1102 
1103  // union point-to reuslt
1104  vPtD->unionPts(keyPair, dstPts);
1105  }
1106 
1107 }
1108 
1110  const SVFG *svfg, const NodeID object,
1111  const std::vector<const SVFGNode *> &startingNodes,
1112  std::vector<int> &partOf,
1113  std::vector<const IndirectSVFGEdge *> &footprint)
1114 {
1115  partOf.resize(svfg->getTotalNodeNum());
1116  std::fill(partOf.begin(), partOf.end(), -1);
1117  footprint.clear();
1118 
1119  std::vector<NodeData> nodeData(svfg->getTotalNodeNum(), { -1, -1, false});
1120  std::stack<const SVFGNode *> stack;
1121 
1122  int index = 0;
1123  int currentSCC = 0;
1124 
1125  for (const SVFGNode *v : startingNodes)
1126  {
1127  if (nodeData[v->getId()].index == -1)
1128  {
1129  visit(vfs, object, partOf, footprint, nodeData, stack, index, currentSCC, v);
1130  }
1131  }
1132 
1133  // Make sure footprints with the same edges pass ==/hash the same.
1134  std::sort(footprint.begin(), footprint.end());
1135 
1136  return currentSCC;
1137 }
1138 
1140  const NodeID object,
1141  std::vector<int> &partOf,
1142  std::vector<const IndirectSVFGEdge *> &footprint,
1143  std::vector<NodeData> &nodeData,
1144  std::stack<const SVFGNode *> &stack,
1145  int &index,
1146  int &currentSCC,
1147  const SVFGNode *v)
1148 {
1149  const NodeID vId = v->getId();
1150 
1151  nodeData[vId].index = index;
1152  nodeData[vId].lowlink = index;
1153  ++index;
1154 
1155  stack.push(v);
1156  nodeData[vId].onStack = true;
1157 
1158  for (const SVFGEdge *e : v->getOutEdges())
1159  {
1160  const IndirectSVFGEdge *ie = SVFUtil::dyn_cast<IndirectSVFGEdge>(e);
1161  if (!ie) continue;
1162 
1163  const SVFGNode *w = ie->getDstNode();
1164  const NodeID wId = w->getId();
1165 
1166  // If object is not part of the edge, there is no edge from v to w.
1167  if (!ie->getPointsTo().test(object)) continue;
1168 
1169  // Even if we don't count edges to stores and deltas for SCCs' sake, they
1170  // are relevant to the footprint as a propagation still occurs over such edges.
1171  footprint.push_back(ie);
1172 
1173  // Ignore edges to delta nodes because they are prelabeled so cannot
1174  // be part of the SCC v is in (already in nodesTodo from the prelabeled set).
1175  // Similarly, store nodes.
1176  if (vfs->delta(wId) || vfs->isStore(wId)) continue;
1177 
1178  if (nodeData[wId].index == -1)
1179  {
1180  visit(vfs, object, partOf, footprint, nodeData, stack, index, currentSCC, w);
1181  nodeData[vId].lowlink = std::min(nodeData[vId].lowlink, nodeData[wId].lowlink);
1182  }
1183  else if (nodeData[wId].onStack)
1184  {
1185  nodeData[vId].lowlink = std::min(nodeData[vId].lowlink, nodeData[wId].index);
1186  }
1187  }
1188 
1189  if (nodeData[vId].lowlink == nodeData[vId].index)
1190  {
1191  const SVFGNode *w = nullptr;
1192  do
1193  {
1194  w = stack.top();
1195  stack.pop();
1196  const NodeID wId = w->getId();
1197  nodeData[wId].onStack = false;
1198  partOf[wId] = currentSCC;
1199  }
1200  while (w != v);
1201 
1202  // For the next SCC.
1203  ++currentSCC;
1204  }
1205 }
#define F(f)
#define TIMEINTERVAL
Definition: SVFType.h:512
cJSON * p
Definition: cJSON.cpp:2559
return(char *) p.buffer
newitem type
Definition: cJSON.cpp:2739
cJSON * a
Definition: cJSON.cpp:2560
cJSON * n
Definition: cJSON.cpp:2558
const cJSON *const b
Definition: cJSON.h:255
int index
Definition: cJSON.h:170
const char *const string
Definition: cJSON.h:172
virtual const PointsTo & getPts(NodeID id)
Operation of points-to set.
Definition: Andersen.h:239
virtual void writeToFile(const std::string &filename)
Interface for analysis result storage on filesystem.
virtual void writeObjVarToFile(const std::string &filename)
VersionedPTDataTy * getVersionedPTDataTy() const
virtual void readAndSetObjFieldSensitivity(std::ifstream &f, const std::string &delimiterStr)
const PointsTo & getPts(NodeID id) override
virtual void readPtsResultFromFile(std::ifstream &f)
virtual void readGepObjVarMapFromFile(std::ifstream &f)
const_iterator end(void) const
bool push(const Data &data)
Definition: WorkList.h:165
bool empty() const
Definition: WorkList.h:146
virtual void solveConstraints()
bool isStrongUpdate(const SVFGNode *node, NodeID &singleton)
Return TRUE if this is a strong update STORE statement.
AndersenWaveDiff * ander
SVFG::SVFGEdgeSetTy SVFGEdgeSetTy
Definition: FlowSensitive.h:53
double storeTime
time of store edges
void finalize() override
Finalize analysis.
bool processSVFGNode(SVFGNode *node)
double loadTime
time of load edges
bool updateCallGraph(const CallSiteToFunPtrMap &callsites) override
Update call graph.
void initialize() override
Initialize analysis.
std::vector< std::pair< hclust_fast_methods, std::vector< NodeID > > > candidateMappings
Save candidate mappings for evaluation's sake.
double updateTime
time of strong/weak updates.
NodeType * getDstNode() const
Definition: GenericGraph.h:101
iterator begin()
Iterators.
Definition: GenericGraph.h:627
IDToNodeMapTy::const_iterator const_iterator
Definition: GenericGraph.h:607
u32_t getTotalNodeNum() const
Get total number of node/edge.
Definition: GenericGraph.h:680
IDToNodeMapTy::iterator iterator
Node Iterators.
Definition: GenericGraph.h:606
const GEdgeSetTy & getOutEdges() const
Definition: GenericGraph.h:430
const GEdgeSetTy & getInEdges() const
Definition: GenericGraph.h:434
const NodeBS & getPointsTo() const
Definition: SVFGEdge.h:60
const NodeBS & getPointsTo() const
Return points-to of the MR.
Definition: SVFGNode.h:52
static std::vector< NodeID > cluster(BVDataPTAImpl *pta, const std::vector< std::pair< NodeID, unsigned >> keys, std::vector< std::pair< hclust_fast_methods, std::vector< NodeID >>> &candidates, std::string evalSubtitle="")
static std::vector< NodeID > getReverseNodeMapping(const std::vector< NodeID > &nodeMapping)
static Option< bool > OPTSVFG
Definition: Options.h:149
static const Option< bool > PredictPtOcc
Definition: Options.h:66
static const Option< u32_t > VersioningThreads
Number of threads for the versioning phase.
Definition: Options.h:78
Set< const CallICFGNode * > CallInstSet
Definition: PTACallGraph.h:55
void getIndCallSitesInvokingCallee(const SVFFunction *callee, PTACallGraphEdge::CallInstSet &csSet)
PTATY
Pointer analysis type list.
bool isFieldInsensitive(NodeID id) const
virtual const NodeBS & getAllFieldsObjVars(NodeID id)
PTAStat * stat
Statistics.
PTACallGraph * getCallGraph() const
Return call graph.
static SVFIR * pag
SVFIR.
bool empty() const
Returns true if set is empty.
Definition: PointsTo.cpp:98
std::shared_ptr< std::vector< NodeID > > MappingPtr
Definition: PointsTo.h:42
static void setCurrentBestNodeMapping(MappingPtr newCurrentBestNodeMapping, MappingPtr newCurrentBestReverseNodeMapping)
Definition: PointsTo.cpp:371
u32_t count() const
Returns number of elements.
Definition: PointsTo.cpp:111
void set(u32_t n)
Inserts n in the set.
Definition: PointsTo.cpp:157
bool test(u32_t n) const
Returns true if n is in this set.
Definition: PointsTo.cpp:131
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
Definition: SVFG.h:66
SVFGNode * getSVFGNode(NodeID id) const
Get a SVFG node.
Definition: SVFG.h:150
const DummyVersionPropSVFGNode * addDummyVersionPropSVFGNode(const NodeID object, const NodeID version)
Definition: SVFG.h:263
void removeSVFGEdge(SVFGEdge *edge)
Remove a SVFG edge.
Definition: SVFG.h:238
const CallICFGNode * isCallSiteRetSVFGNode(const SVFGNode *node) const
Whether a node is callsite return SVFGNode.
Definition: SVFG.cpp:732
const SVFFunction * isFunEntrySVFGNode(const SVFGNode *node) const
Whether a node is function entry SVFGNode.
Definition: SVFG.cpp:706
const CallSiteToFunPtrMap & getIndirectCallsites() const
Add/get indirect callsites.
Definition: SVFIR.h:350
const MemObj * getObject(NodeID id) const
Definition: SVFIR.h:395
bool isConstantObj(NodeID id) const
Definition: SVFIR.h:443
static double getClk(bool mark=false)
Definition: SVFStat.cpp:47
virtual bool isPointer() const
Whether it is a pointer.
Definition: SVFVariables.h:106
bool test(unsigned Idx) const
void set(unsigned Idx)
unsigned count() const
void reset(unsigned Idx)
NodeID getPAGDstNodeID() const
Definition: VFGNode.h:157
NodeID getPAGSrcNodeID() const
Definition: VFGNode.h:152
PAGNode * getPAGSrcNode() const
Definition: VFGNode.h:162
PAGNode * getPAGDstNode() const
Definition: VFGNode.h:167
virtual const ICFGNode * getICFGNode() const
Return corresponding ICFG node.
Definition: VFGNode.h:67
static void visit(VersionedFlowSensitive *vfs, const NodeID object, std::vector< int > &partOf, std::vector< const IndirectSVFGEdge * > &footprint, std::vector< NodeData > &nodeData, std::stack< const SVFGNode * > &stack, int &index, int &currentSCC, const SVFGNode *v)
Called by detectSCCs then called recursively.
static unsigned detectSCCs(VersionedFlowSensitive *vfs, const SVFG *svfg, const NodeID object, const std::vector< const SVFGNode * > &startingNodes, std::vector< int > &partOf, std::vector< const IndirectSVFGEdge * > &footprint)
Version getYield(const NodeID l, const NodeID o) const
Returns the yielded version of o at l. If no such version exists, returns invalidVersion.
void dumpLocVersionMaps(void) const
Dumps maps consume and yield.
BVDataPTAImpl::VersionedPTDataTy * vPtD
Points-to DS for working with versions.
LocVersionMap yield
Actual yield map. Yield analogue to consume.
std::vector< bool > isStoreMap
isStoreMap[l] means SVFG node l is a store node.
virtual void updateConnectedNodes(const SVFGEdgeSetTy &newEdges) override
Update nodes connected during updating call graph.
virtual bool processLoad(const LoadSVFGNode *load) override
static bool meld(MeldVersion &mv1, const MeldVersion &mv2)
Melds v2 into v1 (in place), returns whether a change occurred.
VersionRelianceMap versionReliance
o -> (version -> versions which rely on it).
u32_t numPrelabelVersions
Number of versions created during prelabeling.
void removeAllIndirectSVFGEdges(void)
Removes all indirect edges in the SVFG.
Map< NodeID, NodeID > equivalentObject
void readVersionedAnalysisResultFromFile(std::ifstream &F)
virtual void buildDeltaMaps(void)
Fills in deltaMap and deltaSourceMap for the SVFG.
NodeBS & getStmtReliance(const NodeID o, const Version v)
Returns the statements which rely on o:v.
static const Version invalidVersion
If this version appears, there has been an error.
virtual bool deltaSource(const NodeID l) const
double meldLabelingTime
Time to meld label SVFG.
static VersionedFlowSensitive * vfspta
static VersionedVar atKey(NodeID, Version)
Return key into vPtD for address-taken var of a specific version.
Version getVersion(const NodeID l, const NodeID o, const LocVersionMap &lvm) const
Shared code for getConsume and getYield. They wrap this function.
std::vector< bool > isLoadMap
isLoadMap[l] means SVFG node l is a load node.
static void dumpMeldVersion(MeldVersion &v)
Dumps a MeldVersion to stdout.
double prelabelingTime
Time to prelabel SVFG.
void propagateVersion(NodeID o, Version v)
void prelabel(void)
Prelabel the SVFG: set y(o) for stores and c(o) for delta nodes to a new version.
virtual void initialize() override
Initialize analysis.
virtual void processNode(NodeID n) override
Handle various constraints.
virtual void buildIsStoreLoadMaps(void)
Fills in isStoreMap and isLoadMap.
virtual bool isLoad(const NodeID l) const
Returns true if l is a load node.
void dumpReliances(void) const
Dumps versionReliance and stmtReliance.
virtual bool delta(const NodeID l) const
std::vector< ObjToVersionMap > LocVersionMap
virtual bool processStore(const StoreSVFGNode *store) override
void setConsume(const NodeID l, const NodeID o, const Version v)
Sets the consumed version of o at l to v.
virtual bool isStore(const NodeID l) const
Returns true if l is a store node.
void meldLabel(void)
Meld label the prelabeled SVFG.
void writeVersionedAnalysisResultToFile(const std::string &filename)
VersionedFlowSensitive(SVFIR *_pag, PTATY type=VFS_WPA)
Constructor.
void setYield(const NodeID l, const NodeID o, const Version v)
Sets the yielded version of o at l to v.
void solveAndwritePtsToFile(const std::string &filename) override
virtual void finalize() override
Finalize analysis.
void setVersion(const NodeID l, const NodeID o, const Version v, LocVersionMap &lvm)
Shared code for setConsume and setYield. They wrap this function.
FIFOWorkList< NodeID > vWorklist
std::vector< Version > & getReliantVersions(const NodeID o, const Version v)
Returns the versions of o which rely on o:v.
void readPtsFromFile(const std::string &filename) override
virtual void cluster(void) override
Override since we want to assign different weights based on versioning.
Map< NodeID, Map< Version, NodeBS > > stmtReliance
o x version -> statement nodes which rely on that o/version.
double versionPropTime
Time to propagate versions to versions which rely on them.
Version getConsume(const NodeID l, const NodeID o) const
Returns the consumed version of o at l. If no such version exists, returns invalidVersion.
Map< NodeID, Version > ObjToVersionMap
u32_t numPrelabeledNodes
Additional statistics.
virtual bool unionPts(const VersionedKey &dstVar, const VersionedKey &srcVar)=0
virtual const DataSet & getPts(const VersionedKey &vk)=0
std::unique_ptr< SCC > scc
SCC.
Definition: WPASolver.h:193
virtual void pushIntoWorklist(NodeID id)
Definition: WPASolver.h:156
virtual void propagate(GNODE *v)
Definition: WPASolver.h:127
void setGraph(GraphType g)
Definition: WPASolver.h:78
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
std::pair< NodeID, Version > VersionedVar
Definition: GeneralType.h:125
u32_t NodeID
Definition: GeneralType.h:55
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition: GeneralType.h:101
unsigned Version
Definition: GeneralType.h:123
unsigned u32_t
Definition: GeneralType.h:46
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition: GeneralType.h:96