Static Value-Flow Analysis
Loading...
Searching...
No Matches
NodeIDAllocator.cpp
Go to the documentation of this file.
1//===- NodeIDAllocator.cpp -- Allocates node IDs on request ------------------------//
2
3#include <iomanip>
4#include <iostream>
5#include <queue>
6#include <cmath>
7
10#include "Util/PTAStat.h"
12#include "SVFIR/SVFValue.h"
13#include "SVFIR/SVFType.h"
14#include "Util/SVFUtil.h"
15#include "Util/Options.h"
16
17namespace SVF
18{
23
24NodeIDAllocator *NodeIDAllocator::allocator = nullptr;
25
27{
28 if (allocator == nullptr)
29 {
31 }
32
33 return allocator;
34}
35
37{
38 if (allocator != nullptr)
39 {
40 delete allocator;
41 allocator = nullptr;
42 }
43}
44
45// Initialise counts to 4 because that's how many special nodes we have.
47 : numObjects(4), numValues(4), numSymbols(4), numNodes(4), numType(0), strategy(Options::NodeAllocStrat())
48{ }
49
51{
52 NodeID id = 0;
54 {
55 // We allocate objects from 0(-ish, considering the special nodes) to # of objects.
56 id = numObjects;
57 }
59 {
60 id = UINT_MAX - numObjects;
61 }
62 else if (strategy == Strategy::SEQ)
63 {
64 // Everything is sequential and intermixed.
65 id = numNodes;
66 }
67 else if (strategy == Strategy::DBUG)
68 {
69 // Non-GEPs just grab the next available ID.
70 // We may have "holes" because GEPs increment the total
71 // but allocate far away. This is not a problem because
72 // we don't care about the relative distances between nodes.
73 id = numNodes;
74 }
75 else
76 {
77 assert(false && "NodeIDAllocator::allocateObjectId: unimplemented node allocation strategy.");
78 }
79
81
82 assert(id != 0 && "NodeIDAllocator::allocateObjectId: ID not allocated");
83 return id;
84}
85
86
91
93{
94 NodeID id = 0;
96 {
97 // Nothing different to the other case.
98 id = numObjects;
99 }
101 {
102 id = UINT_MAX - numObjects;
103 }
104 else if (strategy == Strategy::SEQ)
105 {
106 // Everything is sequential and intermixed.
107 id = numNodes;
108 }
109 else if (strategy == Strategy::DBUG)
110 {
111 // For a gep id, base id is set at lower bits, and offset is set at higher bits
112 // e.g., 1100050 denotes base=50 and offset=10
113 // The offset is 10, not 11, because we add 1 to the offset to ensure that the
114 // high bits are never 0. For example, we do not want the gep id to be 50 when
115 // the base is 50 and the offset is 0.
119 )));
120 id = (offset + 1) * gepMultiplier + base;
121 assert(id > numSymbols && "NodeIDAllocator::allocateGepObjectId: GEP allocation clashing with other nodes");
122 }
123 else
124 {
125 assert(false && "NodeIDAllocator::allocateGepObjectId: unimplemented node allocation strategy");
126 }
127
129
130 assert(id != 0 && "NodeIDAllocator::allocateGepObjectId: ID not allocated");
131 return id;
132}
133
135{
136 NodeID id = 0;
138 {
139 // We allocate values from UINT_MAX to UINT_MAX - # of values.
140 // TODO: UINT_MAX does not allow for an easily changeable type
141 // of NodeID (though it is already in use elsewhere).
142 id = UINT_MAX - numValues;
143 }
145 {
146 id = numValues;
147 }
148 else if (strategy == Strategy::SEQ)
149 {
150 // Everything is sequential and intermixed.
151 id = numNodes;
152 }
153 else if (strategy == Strategy::DBUG)
154 {
155 id = numNodes;
156 }
157 else
158 {
159 assert(false && "NodeIDAllocator::allocateValueId: unimplemented node allocation strategy");
160 }
161
162 ++numValues;
163 ++numNodes;
164
165 assert(id != 0 && "NodeIDAllocator::allocateValueId: ID not allocated");
166 return id;
167}
168
174
175const std::string NodeIDAllocator::Clusterer::NumObjects = "NumObjects";
176const std::string NodeIDAllocator::Clusterer::RegioningTime = "RegioningTime";
177const std::string NodeIDAllocator::Clusterer::DistanceMatrixTime = "DistanceMatrixTime";
178const std::string NodeIDAllocator::Clusterer::FastClusterTime = "FastClusterTime";
179const std::string NodeIDAllocator::Clusterer::DendrogramTraversalTime = "DendrogramTravTime";
180const std::string NodeIDAllocator::Clusterer::EvalTime = "EvalTime";
181const std::string NodeIDAllocator::Clusterer::TotalTime = "TotalTime";
182const std::string NodeIDAllocator::Clusterer::TheoreticalNumWords = "TheoreticalWords";
183const std::string NodeIDAllocator::Clusterer::OriginalBvNumWords = "OriginalBvWords";
184const std::string NodeIDAllocator::Clusterer::OriginalSbvNumWords = "OriginalSbvWords";
185const std::string NodeIDAllocator::Clusterer::NewBvNumWords = "NewBvWords";
186const std::string NodeIDAllocator::Clusterer::NewSbvNumWords = "NewSbvWords";
187const std::string NodeIDAllocator::Clusterer::NumRegions = "NumRegions";
188const std::string NodeIDAllocator::Clusterer::NumGtIntRegions = "NumGtIntRegions";
189const std::string NodeIDAllocator::Clusterer::LargestRegion = "LargestRegion";
190const std::string NodeIDAllocator::Clusterer::BestCandidate = "BestCandidate";
191const std::string NodeIDAllocator::Clusterer::NumNonTrivialRegionObjects = "NumNonTrivObj";
192
194 BVDataPTAImpl *pta,
195 const std::vector<std::pair<NodeID, unsigned>> keys,
196 std::vector<std::pair<hclust_fast_methods, std::vector<NodeID>>> &candidates,
197 std::string evalSubtitle,
198 bool printStat
199)
200{
201 assert(pta != nullptr && "Clusterer::cluster: given null BVDataPTAImpl");
202 assert(Options::NodeAllocStrat() == Strategy::DENSE && "Clusterer::cluster: only dense allocation clustering currently supported");
203
205 double fastClusterTime = 0.0;
206 double distanceMatrixTime = 0.0;
207 double dendrogramTraversalTime = 0.0;
208 double regioningTime = 0.0;
209 double evalTime = 0.0;
210
211 // Pair of nodes to their (minimum) distance and the number of occurrences of that distance.
212 Map<std::pair<NodeID, NodeID>, std::pair<unsigned, unsigned>> distances;
213
214 double clkStart = PTAStat::getClk(true);
215
216 // Map points-to sets to occurrences.
218
219 // Objects each object shares at least a points-to set with.
221 for (const std::pair<NodeID, unsigned> &keyOcc : keys)
222 {
223 const PointsTo &pts = pta->getPts(keyOcc.first);
224 const size_t oldSize = pointsToSets.size();
225 pointsToSets[pts] += keyOcc.second;;
226
227 // Edges in this graph have no weight or uniqueness, so we only need to
228 // do this for each points-to set once.
229 if (oldSize != pointsToSets.size())
230 {
231 NodeID firstO = !pts.empty() ? *(pts.begin()) : 0;
233 for (const NodeID o : pts)
234 {
235 if (o != firstO)
236 {
237 firstOsNeighbours.insert(o);
238 coPointeeGraph[o].insert(firstO);
239 }
240 }
241 }
242 }
243
245 overallStats[NumObjects] = std::to_string(numObjects);
246
247 size_t numRegions = 0;
248 std::vector<unsigned> objectsRegion;
250 {
252 }
253 else
254 {
255 // Just a single big region (0).
256 objectsRegion.insert(objectsRegion.end(), numObjects, 0);
257 numRegions = 1;
258 }
259
260 // Set needs to be ordered because getDistanceMatrix, in its n^2 iteration, expects
261 // sets to be ordered (we are building a condensed matrix, not a full matrix, so it
262 // matters). In getDistanceMatrix, doing regionReverseMapping for oi and oj, where
263 // oi < oj, and getting a result moi > moj gives incorrect results.
264 // In the condensed matrix, [b][a] where b >= a, is incorrect.
265 std::vector<OrderedSet<NodeID>> regionsObjects(numRegions);
266 for (NodeID o = 0; o < numObjects; ++o) regionsObjects[objectsRegion[o]].insert(o);
267
268 // Size of the return node mapping. It is potentially larger than the number of
269 // objects because we align each region to NATIVE_INT_SIZE.
270 // size_t numMappings = 0;
271
272 // Maps a region to a mapping which maps 0 to n to all objects
273 // in that region.
274 std::vector<std::vector<NodeID>> regionMappings(numRegions);
275 // The reverse: region to mapping of objects to a 0 to n from above.
276 std::vector<Map<NodeID, unsigned>> regionReverseMappings(numRegions);
277 // We can thus use 0 to n for each region to create smaller distance matrices.
278 for (unsigned region = 0; region < numRegions; ++region)
279 {
280 size_t curr = 0;
281 // With the OrderedSet above, o1 < o2 => map[o1] < map[o2].
283 {
284 // push_back here is just like p...[region][curr] = o.
285 regionMappings[region].push_back(o);
287 }
288
289 // curr is the number of objects. A region with no objects makes no sense.
290 assert(curr != 0);
291
292 // Number of bits needed for this region if we were
293 // to start assigning from 0 rounded up to the fewest needed
294 // native ints. This is added to the number of mappings since
295 // we align each region to a native int.
296 // numMappings += requiredBits(regionsObjects[region].size());
297 }
298
299 // Points-to sets which are relevant to a region, i.e., those whose elements
300 // belong to that region. Pair is for occurrences.
301 std::vector<std::vector<std::pair<const PointsTo *, unsigned>>> regionsPointsTos(numRegions);
303 {
304 const PointsTo &pt = ptocc.first;
305 const unsigned occ = ptocc.second;
306 if (pt.empty()) continue;
307 // Guaranteed that begin() != end() because of the continue above. All objects in pt
308 // will be relevant to the same region.
309 unsigned region = objectsRegion[*(pt.begin())];
310 // In our "graph", objects in the same points-to set have an edge between them,
311 // so they are all in the same connected component/region.
312 regionsPointsTos[region].push_back(std::make_pair(&pt, occ));
313 }
314
315 double clkEnd = PTAStat::getClk(true);
317 overallStats[RegioningTime] = std::to_string(regioningTime);
318 overallStats[NumRegions] = std::to_string(numRegions);
319
320 std::vector<hclust_fast_methods> methods;
322 {
323 methods.push_back(HCLUST_METHOD_SINGLE);
326 }
327 else
328 {
330 }
331
333 {
334 std::vector<NodeID> nodeMap(numObjects, UINT_MAX);
335
336 unsigned numGtIntRegions = 0;
337 unsigned largestRegion = 0;
338 unsigned nonTrivialRegionObjects = 0;
339 unsigned allocCounter = 0;
340 for (unsigned region = 0; region < numRegions; ++region)
341 {
342 const size_t regionNumObjects = regionsObjects[region].size();
343 // Round up to next Word: ceiling of current allocation to get how
344 // many words and multiply to get the number of bits; if we're aligning.
346 {
349 }
350
352
353 // For regions with fewer than 64 objects, we can just allocate them
354 // however as they will be in the one int regardless..
356 {
358 continue;
359 }
360
363
366
368 int *dendrogram = new int[2 * (regionNumObjects - 1)];
369 double *height = new double[regionNumObjects - 1];
371 delete[] distMatrix;
372 delete[] height;
373 clkEnd = PTAStat::getClk(true);
375
377 Set<int> visited;
379 visited, regionNumObjects - 1, regionMappings[region]);
380 delete[] dendrogram;
381 clkEnd = PTAStat::getClk(true);
383 }
384
385 candidates.push_back(std::make_pair(method, nodeMap));
386
387 // Though we "update" these in the loop, they will be the same every iteration.
389 overallStats[LargestRegion] = std::to_string(largestRegion);
391 }
392
393 // Work out which of the mappings we generated looks best.
394 std::pair<hclust_fast_methods, std::vector<NodeID>> bestMapping =
395 determineBestMapping(candidates, pointsToSets, evalSubtitle, evalTime, printStat);
396
400 overallStats[EvalTime] = std::to_string(evalTime);
402
404 if (printStat)
405 {
406 printStats(evalSubtitle + ": overall", overallStats);
407 }
408
409 return bestMapping.second;
410}
411
412std::vector<NodeID> NodeIDAllocator::Clusterer::getReverseNodeMapping(const std::vector<NodeID> &nodeMapping)
413{
414 // nodeMapping.size() may not be big enough because we leave some gaps, but it's a start.
415 std::vector<NodeID> reverseNodeMapping(nodeMapping.size(), UINT_MAX);
416 for (size_t i = 0; i < nodeMapping.size(); ++i)
417 {
418 const NodeID mapsTo = nodeMapping.at(i);
419 if (mapsTo >= reverseNodeMapping.size()) reverseNodeMapping.resize(mapsTo + 1, UINT_MAX);
420 reverseNodeMapping.at(mapsTo) = i;
421 }
422
423 return reverseNodeMapping;
424}
425
426size_t NodeIDAllocator::Clusterer::condensedIndex(size_t n, size_t i, size_t j)
427{
428 // From https://stackoverflow.com/a/14839010
429 return n*(n-1)/2 - (n-i)*(n-i-1)/2 + j - i - 1;
430}
431
433{
434 return requiredBits(pts.count());
435}
436
438{
439 if (n == 0) return 0;
440 // Ceiling of number of bits amongst each native integer gives needed native ints,
441 // so we then multiply again by the number of bits in each native int.
442 return ((n - 1) / NATIVE_INT_SIZE + 1) * NATIVE_INT_SIZE;
443}
444
445double *NodeIDAllocator::Clusterer::getDistanceMatrix(const std::vector<std::pair<const PointsTo *, unsigned>> pointsToSets,
446 const size_t numObjects, const Map<NodeID, unsigned> &nodeMap,
447 double &distanceMatrixTime)
448{
449 const double clkStart = PTAStat::getClk(true);
450 size_t condensedSize = (numObjects * (numObjects - 1)) / 2;
451 double *distMatrix = new double[condensedSize];
452 for (size_t i = 0; i < condensedSize; ++i) distMatrix[i] = numObjects * numObjects;
453
454 // TODO: maybe use machine epsilon?
455 // For reducing distance due to extra occurrences.
456 // Can differentiate ~9999 occurrences.
457 double occurrenceEpsilon = 0.0001;
458
459 for (const std::pair<const PointsTo *, unsigned> &ptsOcc : pointsToSets)
460 {
461 const PointsTo *pts = ptsOcc.first;
462 assert(pts != nullptr);
463 const unsigned occ = ptsOcc.second;
464
465 // Distance between each element of pts.
466 unsigned distance = requiredBits(*pts) / NATIVE_INT_SIZE;
467
468 // Use a vector so we can index into pts.
469 std::vector<NodeID> ptsVec;
470 for (const NodeID o : *pts) ptsVec.push_back(o);
471 for (size_t i = 0; i < ptsVec.size(); ++i)
472 {
473 const NodeID oi = ptsVec[i];
475 assert(moi != nodeMap.end());
476 for (size_t j = i + 1; j < ptsVec.size(); ++j)
477 {
478 const NodeID oj = ptsVec[j];
480 assert(moj != nodeMap.end());
481 double &existingDistance = distMatrix[condensedIndex(numObjects, moi->second, moj->second)];
482
483 // Subtract extra occurrenceEpsilon to make upcoming logic simpler.
484 // When existingDistance is never whole, it is always between two distances.
486
487 if (distance == std::ceil(existingDistance))
488 {
489 // We have something like distance == x, existingDistance == x - e, for some e < 1
490 // (potentially even set during this iteration).
491 // So, the new distance is an occurrence the existingDistance being tracked, it just
492 // had some reductions because of multiple occurrences.
493 // If there is not room within this distance to reduce more (increase priority),
494 // just ignore it. TODO: maybe warn?
496 {
498 }
499 else
500 {
501 // Reached minimum.
503 }
504 }
505 }
506 }
507
508 }
509
510 const double clkEnd = PTAStat::getClk(true);
512
513 return distMatrix;
514}
515
516void NodeIDAllocator::Clusterer::traverseDendrogram(std::vector<NodeID> &nodeMap, const int *dendrogram, const size_t numObjects, unsigned &allocCounter, Set<int> &visited, const int index, const std::vector<NodeID> &regionNodeMap)
517{
518 if (visited.find(index) != visited.end()) return;
519 visited.insert(index);
520
521 int left = dendrogram[index - 1];
522 if (left < 0)
523 {
524 // Reached a leaf.
525 // -1 because the items start from 1 per fastcluster (TODO).
526 nodeMap[regionNodeMap[std::abs(left) - 1]] = allocCounter;
527 ++allocCounter;
528 }
529 else
530 {
531 traverseDendrogram(nodeMap, dendrogram, numObjects, allocCounter, visited, left, regionNodeMap);
532 }
533
534 // Repeat for the right child.
535 int right = dendrogram[(numObjects - 1) + index - 1];
536 if (right < 0)
537 {
538 nodeMap[regionNodeMap[std::abs(right) - 1]] = allocCounter;
539 ++allocCounter;
540 }
541 else
542 {
543 traverseDendrogram(nodeMap, dendrogram, numObjects, allocCounter, visited, right, regionNodeMap);
544 }
545}
546
547std::vector<NodeID> NodeIDAllocator::Clusterer::regionObjects(const Map<NodeID, Set<NodeID>> &graph, size_t numObjects, size_t &numLabels)
548{
549 unsigned label = UINT_MAX;
550 std::vector<NodeID> labels(numObjects, UINT_MAX);
552 for (const Map<NodeID, Set<NodeID>>::value_type &oos : graph)
553 {
554 const NodeID o = oos.first;
555 if (labels[o] != UINT_MAX) continue;
556 std::queue<NodeID> bfsQueue;
557 bfsQueue.push(o);
558 ++label;
559 while (!bfsQueue.empty())
560 {
561 const NodeID o = bfsQueue.front();
562 bfsQueue.pop();
563 if (labels[o] != UINT_MAX)
564 {
565 assert(labels[o] == label);
566 continue;
567 }
568
569 labels[o] = label;
570 Map<NodeID, Set<NodeID>>::const_iterator neighboursIt = graph.find(o);
571 assert(neighboursIt != graph.end());
572 for (const NodeID neighbour : neighboursIt->second) bfsQueue.push(neighbour);
573 }
574 }
575
576 // The remaining objects have no relation with others: they get their own label.
577 for (size_t o = 0; o < numObjects; ++o)
578 {
579 if (labels[o] == UINT_MAX) labels[o] = ++label;
580 }
581
582 numLabels = label + 1;
583
584 return labels;
585}
586
588{
592 u64_t totalNewSbv = 0;
593 u64_t totalNewBv = 0;
594
596 {
597 const PointsTo &pts = ptsOcc.first;
598 const unsigned occ = ptsOcc.second;
599 if (pts.count() == 0) continue;
600
601 u64_t theoretical = requiredBits(pts) / NATIVE_INT_SIZE;
603
604 // Check number of words for original SBV.
605 Set<unsigned> words;
606 // TODO: nasty hardcoding.
607 for (const NodeID o : pts) words.insert(o / 128);
608 u64_t originalSbv = words.size() * 2;
610
611 // Check number of words for original BV.
612 NodeID min = UINT_MAX;
613 NodeID max = 0;
614 for (NodeID o : pts)
615 {
616 if (o < min) min = o;
617 if (o > max) max = o;
618 }
619 words.clear();
620 for (NodeID b = min; b <= max; ++b)
621 {
622 words.insert(b / NATIVE_INT_SIZE);
623 }
624 u64_t originalBv = words.size();
626
627 // Check number of words for new SBV.
628 words.clear();
629 // TODO: nasty hardcoding.
630 for (const NodeID o : pts) words.insert(nodeMap[o] / 128);
631 u64_t newSbv = words.size() * 2;
632 if (accountForOcc) newSbv *= occ;
633
634 // Check number of words for new BV.
635 min = UINT_MAX;
636 max = 0;
637 for (const NodeID o : pts)
638 {
639 const NodeID mappedO = nodeMap[o];
640 if (mappedO < min) min = mappedO;
641 if (mappedO > max) max = mappedO;
642 }
643
644 words.clear();
645 // No nodeMap[b] because min and max and from nodeMap.
646 for (NodeID b = min; b <= max; ++b) words.insert(b / NATIVE_INT_SIZE);
647 u64_t newBv = words.size();
648 if (accountForOcc) newBv *= occ;
649
654 totalNewBv += newBv;
655 }
656
657 stats[TheoreticalNumWords] = std::to_string(totalTheoretical);
658 stats[OriginalSbvNumWords] = std::to_string(totalOriginalSbv);
659 stats[OriginalBvNumWords] = std::to_string(totalOriginalBv);
660 stats[NewSbvNumWords] = std::to_string(totalNewSbv);
661 stats[NewBvNumWords] = std::to_string(totalNewBv);
662}
663
664// Work out which of the mappings we generated looks best.
665std::pair<hclust_fast_methods, std::vector<NodeID>> NodeIDAllocator::Clusterer::determineBestMapping(
666 const std::vector<std::pair<hclust_fast_methods, std::vector<NodeID>>> &candidates,
668 const std::string &evalSubtitle,
669 double &evalTime,
670 bool printStat
671 )
672{
673 // In case we're not comparing anything, set to first "candidate".
674 std::pair<hclust_fast_methods, std::vector<NodeID>> bestMapping = candidates[0];
675 // Number of bits required for the best candidate.
676 size_t bestWords = std::numeric_limits<size_t>::max();
678 {
679 for (const std::pair<hclust_fast_methods, std::vector<NodeID>> &candidate : candidates)
680 {
684 std::vector<NodeID> candidateMapping = candidate.second;
685
686 // TODO: parameterise final arg.
687 const double clkStart = PTAStat::getClk(true);
689 const double clkEnd = PTAStat::getClk(true);
691 if (printStat)
692 {
693 printStats(evalSubtitle + ": candidate " + candidateMethodName, candidateStats);
694 }
695
696 size_t candidateWords = 0;
697 if (Options::PtType() == PointsTo::SBV) candidateWords = std::stoull(candidateStats[NewSbvNumWords]);
698 else if (Options::PtType() == PointsTo::CBV) candidateWords = std::stoull(candidateStats[NewBvNumWords]);
699 else assert(false && "Clusterer::cluster: unsupported BV type for clustering.");
700
702 {
705 }
706 }
707 }
708
709 return bestMapping;
710}
711
713{
714 // When not in order, it is too hard to compare original/new SBV/BV words, so this array forces an order.
715 static const std::string statKeys[] =
716 {
717 NumObjects, TheoreticalNumWords, OriginalSbvNumWords, OriginalBvNumWords,
718 NewSbvNumWords, NewBvNumWords, NumRegions, NumGtIntRegions,
719 NumNonTrivialRegionObjects, LargestRegion, RegioningTime,
720 DistanceMatrixTime, FastClusterTime, DendrogramTraversalTime,
721 EvalTime, TotalTime, BestCandidate
722 };
723
724 const unsigned fieldWidth = 20;
725 SVFUtil::outs().flags(std::ios::left);
726 SVFUtil::outs() << "****Clusterer Statistics: " << subtitle << "****\n";
727 for (const std::string& statKey : statKeys)
728 {
730 if (stat != stats.end())
731 {
732 SVFUtil::outs() << std::setw(fieldWidth) << statKey << " " << stat->second << "\n";
733 }
734 }
735
736 SVFUtil::outs().flush();
737}
738
739}; // namespace SVF.
#define TIMEINTERVAL
Definition SVFType.h:621
#define NATIVE_INT_SIZE
Size of native integer that we'll use for bit vectors, in bits.
Definition SVFType.h:625
buffer offset
Definition cJSON.cpp:1113
cJSON * n
Definition cJSON.cpp:2558
const cJSON *const b
Definition cJSON.h:255
int index
Definition cJSON.h:170
const PointsTo & getPts(NodeID id) override
static const std::string DistanceMatrixTime
static const std::string LargestRegion
static const std::string NumNonTrivialRegionObjects
static const std::string EvalTime
static std::vector< unsigned > regionObjects(const Map< NodeID, Set< NodeID > > &graph, size_t numObjects, size_t &numLabels)
static const std::string TheoreticalNumWords
static const std::string BestCandidate
static std::vector< NodeID > getReverseNodeMapping(const std::vector< NodeID > &nodeMapping)
static std::pair< hclust_fast_methods, std::vector< NodeID > > determineBestMapping(const std::vector< std::pair< hclust_fast_methods, std::vector< NodeID > > > &candidates, Map< PointsTo, unsigned > pointsToSets, const std::string &evalSubtitle, double &evalTime, bool printStat)
static const std::string OriginalSbvNumWords
static const std::string DendrogramTraversalTime
static const std::string NewSbvNumWords
static double * getDistanceMatrix(const std::vector< std::pair< const PointsTo *, unsigned > > pointsToSets, const size_t numObjects, const Map< NodeID, unsigned > &nodeMap, double &distanceMatrixTime)
static unsigned requiredBits(const PointsTo &pts)
Returns the minimum number of bits required to represent pts in a perfect world.
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="", bool printStat=true)
static void traverseDendrogram(std::vector< NodeID > &nodeMap, const int *dendrogram, const size_t numObjects, unsigned &allocCounter, Set< int > &visited, const int index, const std::vector< NodeID > &regionNodeMap)
static void printStats(std::string title, Map< std::string, std::string > &stats)
static const std::string NumRegions
static size_t condensedIndex(size_t n, size_t i, size_t j)
static void evaluate(const std::vector< NodeID > &nodeMap, const Map< PointsTo, unsigned > pointsToSets, Map< std::string, std::string > &stats, bool accountForOcc)
Fills in *NumWords statistics in stats..
static const std::string RegioningTime
static const std::string NumGtIntRegions
static const std::string FastClusterTime
static const std::string OriginalBvNumWords
static const std::string NewBvNumWords
static const std::string NumObjects
static const std::string TotalTime
NodeID numValues
Number of values allocated, including specials.
static const NodeID nullPointerId
NodeID allocateValueId(void)
Allocate a value ID as determined by the strategy.
static NodeIDAllocator * get(void)
Return (singleton) allocator.
NodeID numSymbols
Number of explicit symbols allocated (e.g., llvm::Values), including specials.
enum Strategy strategy
Strategy to allocate with.
static const NodeID blackHolePointerId
NodeID numType
Total number of svftypes.
static NodeIDAllocator * allocator
Single allocator.
static const NodeID constantObjectId
NodeID allocateTypeId(void)
Allocate an type ID as determined by the strategy.
NodeID allocateObjectId(void)
Allocate an object ID as determined by the strategy.
static const NodeID blackHoleObjectId
@ SEQ
Allocate objects objects and values sequentially, intermixed.
NodeID numNodes
Total number of objects and values allocated.
NodeID endSymbolAllocation(void)
Notify the allocator that all symbols have had IDs allocated.
NodeID allocateGepObjectId(NodeID base, u32_t offset, u32_t maxFieldLimit)
NodeIDAllocator(void)
Builds a node ID allocator with the strategy specified on the command line.
static void unset(void)
Deletes the (singleton) allocator.
Carries around command line options.
Definition Options.h:17
static const OptionMap< SVF::NodeIDAllocator::Strategy > NodeAllocStrat
Definition Options.h:32
static const OptionMap< PointsTo::Type > PtType
Type of points-to set to use for all analyses.
Definition Options.h:47
static const Option< bool > RegionAlign
Align identifiers in each region to a word.
Definition Options.h:59
static const Option< bool > RegionedClustering
Cluster partitions separately.
Definition Options.h:56
static const OptionMap< u32_t > ClusterMethod
Definition Options.h:53
bool empty() const
Returns true if set is empty.
Definition PointsTo.cpp:98
void clear()
Empty the set.
Definition PointsTo.cpp:123
const_iterator begin() const
Definition PointsTo.h:128
static double getClk(bool mark=false)
Definition SVFStat.cpp:51
hclust_fast_methods
Definition fastcluster.h:66
@ HCLUST_METHOD_AVERAGE
Definition fastcluster.h:72
@ HCLUST_METHOD_COMPLETE
Definition fastcluster.h:70
@ HCLUST_METHOD_SVF_BEST
Definition fastcluster.h:76
@ HCLUST_METHOD_SINGLE
Definition fastcluster.h:68
int hclust_fast(int n, double *distmat, int method, int *merge, double *height)
std::string hclustMethodToString(hclust_fast_methods method)
Returns a string representation of a hclust method.
Definition SVFUtil.cpp:252
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:70
unsigned long long u64_t
Definition GeneralType.h:49
u32_t NodeID
Definition GeneralType.h:56
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
unsigned u32_t
Definition GeneralType.h:47