1*06f32e7eSjoerg //==- BlockCounter.h - ADT for counting block visits -------------*- C++ -*-//
2*06f32e7eSjoerg //
3*06f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*06f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06f32e7eSjoerg //
7*06f32e7eSjoerg //===----------------------------------------------------------------------===//
8*06f32e7eSjoerg //
9*06f32e7eSjoerg //  This file defines BlockCounter, an abstract data type used to count
10*06f32e7eSjoerg //  the number of times a given block has been visited along a path
11*06f32e7eSjoerg //  analyzed by CoreEngine.
12*06f32e7eSjoerg //
13*06f32e7eSjoerg //===----------------------------------------------------------------------===//
14*06f32e7eSjoerg 
15*06f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
16*06f32e7eSjoerg #include "llvm/ADT/ImmutableMap.h"
17*06f32e7eSjoerg 
18*06f32e7eSjoerg using namespace clang;
19*06f32e7eSjoerg using namespace ento;
20*06f32e7eSjoerg 
21*06f32e7eSjoerg namespace {
22*06f32e7eSjoerg 
23*06f32e7eSjoerg class CountKey {
24*06f32e7eSjoerg   const StackFrameContext *CallSite;
25*06f32e7eSjoerg   unsigned BlockID;
26*06f32e7eSjoerg 
27*06f32e7eSjoerg public:
CountKey(const StackFrameContext * CS,unsigned ID)28*06f32e7eSjoerg   CountKey(const StackFrameContext *CS, unsigned ID)
29*06f32e7eSjoerg     : CallSite(CS), BlockID(ID) {}
30*06f32e7eSjoerg 
operator ==(const CountKey & RHS) const31*06f32e7eSjoerg   bool operator==(const CountKey &RHS) const {
32*06f32e7eSjoerg     return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID);
33*06f32e7eSjoerg   }
34*06f32e7eSjoerg 
operator <(const CountKey & RHS) const35*06f32e7eSjoerg   bool operator<(const CountKey &RHS) const {
36*06f32e7eSjoerg     return std::tie(CallSite, BlockID) < std::tie(RHS.CallSite, RHS.BlockID);
37*06f32e7eSjoerg   }
38*06f32e7eSjoerg 
Profile(llvm::FoldingSetNodeID & ID) const39*06f32e7eSjoerg   void Profile(llvm::FoldingSetNodeID &ID) const {
40*06f32e7eSjoerg     ID.AddPointer(CallSite);
41*06f32e7eSjoerg     ID.AddInteger(BlockID);
42*06f32e7eSjoerg   }
43*06f32e7eSjoerg };
44*06f32e7eSjoerg 
45*06f32e7eSjoerg }
46*06f32e7eSjoerg 
47*06f32e7eSjoerg typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
48*06f32e7eSjoerg 
GetMap(void * D)49*06f32e7eSjoerg static inline CountMap GetMap(void *D) {
50*06f32e7eSjoerg   return CountMap(static_cast<CountMap::TreeTy*>(D));
51*06f32e7eSjoerg }
52*06f32e7eSjoerg 
GetFactory(void * F)53*06f32e7eSjoerg static inline CountMap::Factory& GetFactory(void *F) {
54*06f32e7eSjoerg   return *static_cast<CountMap::Factory*>(F);
55*06f32e7eSjoerg }
56*06f32e7eSjoerg 
getNumVisited(const StackFrameContext * CallSite,unsigned BlockID) const57*06f32e7eSjoerg unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite,
58*06f32e7eSjoerg                                        unsigned BlockID) const {
59*06f32e7eSjoerg   CountMap M = GetMap(Data);
60*06f32e7eSjoerg   CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
61*06f32e7eSjoerg   return T ? *T : 0;
62*06f32e7eSjoerg }
63*06f32e7eSjoerg 
Factory(llvm::BumpPtrAllocator & Alloc)64*06f32e7eSjoerg BlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) {
65*06f32e7eSjoerg   F = new CountMap::Factory(Alloc);
66*06f32e7eSjoerg }
67*06f32e7eSjoerg 
~Factory()68*06f32e7eSjoerg BlockCounter::Factory::~Factory() {
69*06f32e7eSjoerg   delete static_cast<CountMap::Factory*>(F);
70*06f32e7eSjoerg }
71*06f32e7eSjoerg 
72*06f32e7eSjoerg BlockCounter
IncrementCount(BlockCounter BC,const StackFrameContext * CallSite,unsigned BlockID)73*06f32e7eSjoerg BlockCounter::Factory::IncrementCount(BlockCounter BC,
74*06f32e7eSjoerg                                         const StackFrameContext *CallSite,
75*06f32e7eSjoerg                                         unsigned BlockID) {
76*06f32e7eSjoerg   return BlockCounter(GetFactory(F).add(GetMap(BC.Data),
77*06f32e7eSjoerg                                           CountKey(CallSite, BlockID),
78*06f32e7eSjoerg                              BC.getNumVisited(CallSite, BlockID)+1).getRoot());
79*06f32e7eSjoerg }
80*06f32e7eSjoerg 
81*06f32e7eSjoerg BlockCounter
GetEmptyCounter()82*06f32e7eSjoerg BlockCounter::Factory::GetEmptyCounter() {
83*06f32e7eSjoerg   return BlockCounter(GetFactory(F).getEmptyMap().getRoot());
84*06f32e7eSjoerg }
85