1 //===- FunctionSummary.h - Stores summaries of functions. -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a summary of a function gathered/used by static analysis.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
14 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
15 
16 #include "clang/AST/Decl.h"
17 #include "clang/Basic/LLVM.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/DenseSet.h"
20 #include "llvm/ADT/SmallBitVector.h"
21 #include <cassert>
22 #include <deque>
23 #include <optional>
24 #include <utility>
25 
26 namespace clang {
27 namespace ento {
28 
29 using SetOfDecls = std::deque<Decl *>;
30 using SetOfConstDecls = llvm::DenseSet<const Decl *>;
31 
32 class FunctionSummariesTy {
33   class FunctionSummary {
34   public:
35     /// Marks the IDs of the basic blocks visited during the analyzes.
36     llvm::SmallBitVector VisitedBasicBlocks;
37 
38     /// Total number of blocks in the function.
39     unsigned TotalBasicBlocks : 30;
40 
41     /// True if this function has been checked against the rules for which
42     /// functions may be inlined.
43     unsigned InlineChecked : 1;
44 
45     /// True if this function may be inlined.
46     unsigned MayInline : 1;
47 
48     /// The number of times the function has been inlined.
49     unsigned TimesInlined : 32;
50 
51     FunctionSummary()
52         : TotalBasicBlocks(0), InlineChecked(0), MayInline(0),
53           TimesInlined(0) {}
54   };
55 
56   using MapTy = llvm::DenseMap<const Decl *, FunctionSummary>;
57   MapTy Map;
58 
59 public:
60   MapTy::iterator findOrInsertSummary(const Decl *D) {
61     MapTy::iterator I = Map.find(D);
62     if (I != Map.end())
63       return I;
64 
65     using KVPair = std::pair<const Decl *, FunctionSummary>;
66 
67     I = Map.insert(KVPair(D, FunctionSummary())).first;
68     assert(I != Map.end());
69     return I;
70   }
71 
72   void markMayInline(const Decl *D) {
73     MapTy::iterator I = findOrInsertSummary(D);
74     I->second.InlineChecked = 1;
75     I->second.MayInline = 1;
76   }
77 
78   void markShouldNotInline(const Decl *D) {
79     MapTy::iterator I = findOrInsertSummary(D);
80     I->second.InlineChecked = 1;
81     I->second.MayInline = 0;
82   }
83 
84   void markReachedMaxBlockCount(const Decl *D) {
85     markShouldNotInline(D);
86   }
87 
88   std::optional<bool> mayInline(const Decl *D) {
89     MapTy::const_iterator I = Map.find(D);
90     if (I != Map.end() && I->second.InlineChecked)
91       return I->second.MayInline;
92     return std::nullopt;
93   }
94 
95   void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) {
96     MapTy::iterator I = findOrInsertSummary(D);
97     llvm::SmallBitVector &Blocks = I->second.VisitedBasicBlocks;
98     assert(ID < TotalIDs);
99     if (TotalIDs > Blocks.size()) {
100       Blocks.resize(TotalIDs);
101       I->second.TotalBasicBlocks = TotalIDs;
102     }
103     Blocks.set(ID);
104   }
105 
106   unsigned getNumVisitedBasicBlocks(const Decl* D) {
107     MapTy::const_iterator I = Map.find(D);
108     if (I != Map.end())
109       return I->second.VisitedBasicBlocks.count();
110     return 0;
111   }
112 
113   unsigned getNumTimesInlined(const Decl* D) {
114     MapTy::const_iterator I = Map.find(D);
115     if (I != Map.end())
116       return I->second.TimesInlined;
117     return 0;
118   }
119 
120   void bumpNumTimesInlined(const Decl* D) {
121     MapTy::iterator I = findOrInsertSummary(D);
122     I->second.TimesInlined++;
123   }
124 
125   /// Get the percentage of the reachable blocks.
126   unsigned getPercentBlocksReachable(const Decl *D) {
127     MapTy::const_iterator I = Map.find(D);
128       if (I != Map.end())
129         return ((I->second.VisitedBasicBlocks.count() * 100) /
130                  I->second.TotalBasicBlocks);
131     return 0;
132   }
133 
134   unsigned getTotalNumBasicBlocks();
135   unsigned getTotalNumVisitedBasicBlocks();
136 };
137 
138 } // namespace ento
139 } // namespace clang
140 
141 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
142