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
193std::vector<NodeID> NodeIDAllocator::Clusterer::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)
194{
195 assert(pta != nullptr && "Clusterer::cluster: given null BVDataPTAImpl");
196 assert(Options::NodeAllocStrat() == Strategy::DENSE && "Clusterer::cluster: only dense allocation clustering currently supported");
197
199 double fastClusterTime = 0.0;
200 double distanceMatrixTime = 0.0;
201 double dendrogramTraversalTime = 0.0;
202 double regioningTime = 0.0;
203 double evalTime = 0.0;
204
205 // Pair of nodes to their (minimum) distance and the number of occurrences of that distance.
206 Map<std::pair<NodeID, NodeID>, std::pair<unsigned, unsigned>> distances;
207
208 double clkStart = PTAStat::getClk(true);
209
210 // Map points-to sets to occurrences.
212
213 // Objects each object shares at least a points-to set with.
215 for (const std::pair<NodeID, unsigned> &keyOcc : keys)
216 {
217 const PointsTo &pts = pta->getPts(keyOcc.first);
218 const size_t oldSize = pointsToSets.size();
219 pointsToSets[pts] += keyOcc.second;;
220
221 // Edges in this graph have no weight or uniqueness, so we only need to
222 // do this for each points-to set once.
223 if (oldSize != pointsToSets.size())
224 {
225 NodeID firstO = !pts.empty() ? *(pts.begin()) : 0;
227 for (const NodeID o : pts)
228 {
229 if (o != firstO)
230 {
231 firstOsNeighbours.insert(o);
232 coPointeeGraph[o].insert(firstO);
233 }
234 }
235 }
236 }
237
239 overallStats[NumObjects] = std::to_string(numObjects);
240
241 size_t numRegions = 0;
242 std::vector<unsigned> objectsRegion;
244 {
246 }
247 else
248 {
249 // Just a single big region (0).
250 objectsRegion.insert(objectsRegion.end(), numObjects, 0);
251 numRegions = 1;
252 }
253
254 // Set needs to be ordered because getDistanceMatrix, in its n^2 iteration, expects
255 // sets to be ordered (we are building a condensed matrix, not a full matrix, so it
256 // matters). In getDistanceMatrix, doing regionReverseMapping for oi and oj, where
257 // oi < oj, and getting a result moi > moj gives incorrect results.
258 // In the condensed matrix, [b][a] where b >= a, is incorrect.
259 std::vector<OrderedSet<NodeID>> regionsObjects(numRegions);
260 for (NodeID o = 0; o < numObjects; ++o) regionsObjects[objectsRegion[o]].insert(o);
261
262 // Size of the return node mapping. It is potentially larger than the number of
263 // objects because we align each region to NATIVE_INT_SIZE.
264 // size_t numMappings = 0;
265
266 // Maps a region to a mapping which maps 0 to n to all objects
267 // in that region.
268 std::vector<std::vector<NodeID>> regionMappings(numRegions);
269 // The reverse: region to mapping of objects to a 0 to n from above.
270 std::vector<Map<NodeID, unsigned>> regionReverseMappings(numRegions);
271 // We can thus use 0 to n for each region to create smaller distance matrices.
272 for (unsigned region = 0; region < numRegions; ++region)
273 {
274 size_t curr = 0;
275 // With the OrderedSet above, o1 < o2 => map[o1] < map[o2].
277 {
278 // push_back here is just like p...[region][curr] = o.
279 regionMappings[region].push_back(o);
281 }
282
283 // curr is the number of objects. A region with no objects makes no sense.
284 assert(curr != 0);
285
286 // Number of bits needed for this region if we were
287 // to start assigning from 0 rounded up to the fewest needed
288 // native ints. This is added to the number of mappings since
289 // we align each region to a native int.
290 // numMappings += requiredBits(regionsObjects[region].size());
291 }
292
293 // Points-to sets which are relevant to a region, i.e., those whose elements
294 // belong to that region. Pair is for occurrences.
295 std::vector<std::vector<std::pair<const PointsTo *, unsigned>>> regionsPointsTos(numRegions);
297 {
298 const PointsTo &pt = ptocc.first;
299 const unsigned occ = ptocc.second;
300 if (pt.empty()) continue;
301 // Guaranteed that begin() != end() because of the continue above. All objects in pt
302 // will be relevant to the same region.
303 unsigned region = objectsRegion[*(pt.begin())];
304 // In our "graph", objects in the same points-to set have an edge between them,
305 // so they are all in the same connected component/region.
306 regionsPointsTos[region].push_back(std::make_pair(&pt, occ));
307 }
308
309 double clkEnd = PTAStat::getClk(true);
311 overallStats[RegioningTime] = std::to_string(regioningTime);
312 overallStats[NumRegions] = std::to_string(numRegions);
313
314 std::vector<hclust_fast_methods> methods;
316 {
317 methods.push_back(HCLUST_METHOD_SINGLE);
320 }
321 else
322 {
324 }
325
327 {
328 std::vector<NodeID> nodeMap(numObjects, UINT_MAX);
329
330 unsigned numGtIntRegions = 0;
331 unsigned largestRegion = 0;
332 unsigned nonTrivialRegionObjects = 0;
333 unsigned allocCounter = 0;
334 for (unsigned region = 0; region < numRegions; ++region)
335 {
336 const size_t regionNumObjects = regionsObjects[region].size();
337 // Round up to next Word: ceiling of current allocation to get how
338 // many words and multiply to get the number of bits; if we're aligning.
340 {
343 }
344
346
347 // For regions with fewer than 64 objects, we can just allocate them
348 // however as they will be in the one int regardless..
350 {
352 continue;
353 }
354
357
360
362 int *dendrogram = new int[2 * (regionNumObjects - 1)];
363 double *height = new double[regionNumObjects - 1];
365 delete[] distMatrix;
366 delete[] height;
367 clkEnd = PTAStat::getClk(true);
369
371 Set<int> visited;
373 visited, regionNumObjects - 1, regionMappings[region]);
374 delete[] dendrogram;
375 clkEnd = PTAStat::getClk(true);
377 }
378
379 candidates.push_back(std::make_pair(method, nodeMap));
380
381 // Though we "update" these in the loop, they will be the same every iteration.
383 overallStats[LargestRegion] = std::to_string(largestRegion);
385 }
386
387 // Work out which of the mappings we generated looks best.
388 std::pair<hclust_fast_methods, std::vector<NodeID>> bestMapping = determineBestMapping(candidates, pointsToSets,
390
394 overallStats[EvalTime] = std::to_string(evalTime);
396
398 printStats(evalSubtitle + ": overall", overallStats);
399
400 return bestMapping.second;
401}
402
403std::vector<NodeID> NodeIDAllocator::Clusterer::getReverseNodeMapping(const std::vector<NodeID> &nodeMapping)
404{
405 // nodeMapping.size() may not be big enough because we leave some gaps, but it's a start.
406 std::vector<NodeID> reverseNodeMapping(nodeMapping.size(), UINT_MAX);
407 for (size_t i = 0; i < nodeMapping.size(); ++i)
408 {
409 const NodeID mapsTo = nodeMapping.at(i);
410 if (mapsTo >= reverseNodeMapping.size()) reverseNodeMapping.resize(mapsTo + 1, UINT_MAX);
411 reverseNodeMapping.at(mapsTo) = i;
412 }
413
414 return reverseNodeMapping;
415}
416
417size_t NodeIDAllocator::Clusterer::condensedIndex(size_t n, size_t i, size_t j)
418{
419 // From https://stackoverflow.com/a/14839010
420 return n*(n-1)/2 - (n-i)*(n-i-1)/2 + j - i - 1;
421}
422
424{
425 return requiredBits(pts.count());
426}
427
429{
430 if (n == 0) return 0;
431 // Ceiling of number of bits amongst each native integer gives needed native ints,
432 // so we then multiply again by the number of bits in each native int.
433 return ((n - 1) / NATIVE_INT_SIZE + 1) * NATIVE_INT_SIZE;
434}
435
436double *NodeIDAllocator::Clusterer::getDistanceMatrix(const std::vector<std::pair<const PointsTo *, unsigned>> pointsToSets,
437 const size_t numObjects, const Map<NodeID, unsigned> &nodeMap,
438 double &distanceMatrixTime)
439{
440 const double clkStart = PTAStat::getClk(true);
441 size_t condensedSize = (numObjects * (numObjects - 1)) / 2;
442 double *distMatrix = new double[condensedSize];
443 for (size_t i = 0; i < condensedSize; ++i) distMatrix[i] = numObjects * numObjects;
444
445 // TODO: maybe use machine epsilon?
446 // For reducing distance due to extra occurrences.
447 // Can differentiate ~9999 occurrences.
448 double occurrenceEpsilon = 0.0001;
449
450 for (const std::pair<const PointsTo *, unsigned> &ptsOcc : pointsToSets)
451 {
452 const PointsTo *pts = ptsOcc.first;
453 assert(pts != nullptr);
454 const unsigned occ = ptsOcc.second;
455
456 // Distance between each element of pts.
457 unsigned distance = requiredBits(*pts) / NATIVE_INT_SIZE;
458
459 // Use a vector so we can index into pts.
460 std::vector<NodeID> ptsVec;
461 for (const NodeID o : *pts) ptsVec.push_back(o);
462 for (size_t i = 0; i < ptsVec.size(); ++i)
463 {
464 const NodeID oi = ptsVec[i];
466 assert(moi != nodeMap.end());
467 for (size_t j = i + 1; j < ptsVec.size(); ++j)
468 {
469 const NodeID oj = ptsVec[j];
471 assert(moj != nodeMap.end());
472 double &existingDistance = distMatrix[condensedIndex(numObjects, moi->second, moj->second)];
473
474 // Subtract extra occurrenceEpsilon to make upcoming logic simpler.
475 // When existingDistance is never whole, it is always between two distances.
477
478 if (distance == std::ceil(existingDistance))
479 {
480 // We have something like distance == x, existingDistance == x - e, for some e < 1
481 // (potentially even set during this iteration).
482 // So, the new distance is an occurrence the existingDistance being tracked, it just
483 // had some reductions because of multiple occurrences.
484 // If there is not room within this distance to reduce more (increase priority),
485 // just ignore it. TODO: maybe warn?
487 {
489 }
490 else
491 {
492 // Reached minimum.
494 }
495 }
496 }
497 }
498
499 }
500
501 const double clkEnd = PTAStat::getClk(true);
503
504 return distMatrix;
505}
506
507void 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)
508{
509 if (visited.find(index) != visited.end()) return;
510 visited.insert(index);
511
512 int left = dendrogram[index - 1];
513 if (left < 0)
514 {
515 // Reached a leaf.
516 // -1 because the items start from 1 per fastcluster (TODO).
517 nodeMap[regionNodeMap[std::abs(left) - 1]] = allocCounter;
518 ++allocCounter;
519 }
520 else
521 {
522 traverseDendrogram(nodeMap, dendrogram, numObjects, allocCounter, visited, left, regionNodeMap);
523 }
524
525 // Repeat for the right child.
526 int right = dendrogram[(numObjects - 1) + index - 1];
527 if (right < 0)
528 {
529 nodeMap[regionNodeMap[std::abs(right) - 1]] = allocCounter;
530 ++allocCounter;
531 }
532 else
533 {
534 traverseDendrogram(nodeMap, dendrogram, numObjects, allocCounter, visited, right, regionNodeMap);
535 }
536}
537
538std::vector<NodeID> NodeIDAllocator::Clusterer::regionObjects(const Map<NodeID, Set<NodeID>> &graph, size_t numObjects, size_t &numLabels)
539{
540 unsigned label = UINT_MAX;
541 std::vector<NodeID> labels(numObjects, UINT_MAX);
543 for (const Map<NodeID, Set<NodeID>>::value_type &oos : graph)
544 {
545 const NodeID o = oos.first;
546 if (labels[o] != UINT_MAX) continue;
547 std::queue<NodeID> bfsQueue;
548 bfsQueue.push(o);
549 ++label;
550 while (!bfsQueue.empty())
551 {
552 const NodeID o = bfsQueue.front();
553 bfsQueue.pop();
554 if (labels[o] != UINT_MAX)
555 {
556 assert(labels[o] == label);
557 continue;
558 }
559
560 labels[o] = label;
561 Map<NodeID, Set<NodeID>>::const_iterator neighboursIt = graph.find(o);
562 assert(neighboursIt != graph.end());
563 for (const NodeID neighbour : neighboursIt->second) bfsQueue.push(neighbour);
564 }
565 }
566
567 // The remaining objects have no relation with others: they get their own label.
568 for (size_t o = 0; o < numObjects; ++o)
569 {
570 if (labels[o] == UINT_MAX) labels[o] = ++label;
571 }
572
573 numLabels = label + 1;
574
575 return labels;
576}
577
579{
583 u64_t totalNewSbv = 0;
584 u64_t totalNewBv = 0;
585
587 {
588 const PointsTo &pts = ptsOcc.first;
589 const unsigned occ = ptsOcc.second;
590 if (pts.count() == 0) continue;
591
592 u64_t theoretical = requiredBits(pts) / NATIVE_INT_SIZE;
594
595 // Check number of words for original SBV.
596 Set<unsigned> words;
597 // TODO: nasty hardcoding.
598 for (const NodeID o : pts) words.insert(o / 128);
599 u64_t originalSbv = words.size() * 2;
601
602 // Check number of words for original BV.
603 NodeID min = UINT_MAX;
604 NodeID max = 0;
605 for (NodeID o : pts)
606 {
607 if (o < min) min = o;
608 if (o > max) max = o;
609 }
610 words.clear();
611 for (NodeID b = min; b <= max; ++b)
612 {
613 words.insert(b / NATIVE_INT_SIZE);
614 }
615 u64_t originalBv = words.size();
617
618 // Check number of words for new SBV.
619 words.clear();
620 // TODO: nasty hardcoding.
621 for (const NodeID o : pts) words.insert(nodeMap[o] / 128);
622 u64_t newSbv = words.size() * 2;
623 if (accountForOcc) newSbv *= occ;
624
625 // Check number of words for new BV.
626 min = UINT_MAX;
627 max = 0;
628 for (const NodeID o : pts)
629 {
630 const NodeID mappedO = nodeMap[o];
631 if (mappedO < min) min = mappedO;
632 if (mappedO > max) max = mappedO;
633 }
634
635 words.clear();
636 // No nodeMap[b] because min and max and from nodeMap.
637 for (NodeID b = min; b <= max; ++b) words.insert(b / NATIVE_INT_SIZE);
638 u64_t newBv = words.size();
639 if (accountForOcc) newBv *= occ;
640
645 totalNewBv += newBv;
646 }
647
648 stats[TheoreticalNumWords] = std::to_string(totalTheoretical);
649 stats[OriginalSbvNumWords] = std::to_string(totalOriginalSbv);
650 stats[OriginalBvNumWords] = std::to_string(totalOriginalBv);
651 stats[NewSbvNumWords] = std::to_string(totalNewSbv);
652 stats[NewBvNumWords] = std::to_string(totalNewBv);
653}
654
655// Work out which of the mappings we generated looks best.
656std::pair<hclust_fast_methods, std::vector<NodeID>> NodeIDAllocator::Clusterer::determineBestMapping(
657 const std::vector<std::pair<hclust_fast_methods, std::vector<NodeID>>> &candidates,
658 Map<PointsTo, unsigned> pointsToSets, const std::string &evalSubtitle, double &evalTime)
659{
660 // In case we're not comparing anything, set to first "candidate".
661 std::pair<hclust_fast_methods, std::vector<NodeID>> bestMapping = candidates[0];
662 // Number of bits required for the best candidate.
663 size_t bestWords = std::numeric_limits<size_t>::max();
665 {
666 for (const std::pair<hclust_fast_methods, std::vector<NodeID>> &candidate : candidates)
667 {
671 std::vector<NodeID> candidateMapping = candidate.second;
672
673 // TODO: parameterise final arg.
674 const double clkStart = PTAStat::getClk(true);
676 const double clkEnd = PTAStat::getClk(true);
678 printStats(evalSubtitle + ": candidate " + candidateMethodName, candidateStats);
679
680 size_t candidateWords = 0;
681 if (Options::PtType() == PointsTo::SBV) candidateWords = std::stoull(candidateStats[NewSbvNumWords]);
682 else if (Options::PtType() == PointsTo::CBV) candidateWords = std::stoull(candidateStats[NewBvNumWords]);
683 else assert(false && "Clusterer::cluster: unsupported BV type for clustering.");
684
686 {
689 }
690 }
691 }
692
693 return bestMapping;
694}
695
697{
698 // When not in order, it is too hard to compare original/new SBV/BV words, so this array forces an order.
699 static const std::string statKeys[] =
700 {
701 NumObjects, TheoreticalNumWords, OriginalSbvNumWords, OriginalBvNumWords,
702 NewSbvNumWords, NewBvNumWords, NumRegions, NumGtIntRegions,
703 NumNonTrivialRegionObjects, LargestRegion, RegioningTime,
704 DistanceMatrixTime, FastClusterTime, DendrogramTraversalTime,
705 EvalTime, TotalTime, BestCandidate
706 };
707
708 const unsigned fieldWidth = 20;
709 SVFUtil::outs().flags(std::ios::left);
710 SVFUtil::outs() << "****Clusterer Statistics: " << subtitle << "****\n";
711 for (const std::string& statKey : statKeys)
712 {
714 if (stat != stats.end())
715 {
716 SVFUtil::outs() << std::setw(fieldWidth) << statKey << " " << stat->second << "\n";
717 }
718 }
719
720 SVFUtil::outs().flush();
721}
722
723}; // namespace SVF.
#define TIMEINTERVAL
Definition SVFType.h:540
#define NATIVE_INT_SIZE
Size of native integer that we'll use for bit vectors, in bits.
Definition SVFType.h:544
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 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 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 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)
static const std::string BestCandidate
static std::vector< NodeID > getReverseNodeMapping(const std::vector< NodeID > &nodeMapping)
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 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:48
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:248
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:68
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:74
unsigned u32_t
Definition GeneralType.h:47