xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/IntervalPartition.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===- IntervalPartition.cpp - CFG Partitioning into Intervals --*- C++ -*-===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric //
9*06c3fb27SDimitry Andric //  This file defines functionality for partitioning a CFG into intervals.
10*06c3fb27SDimitry Andric //
11*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric #include "clang/Analysis/Analyses/IntervalPartition.h"
14*06c3fb27SDimitry Andric #include "clang/Analysis/CFG.h"
15*06c3fb27SDimitry Andric #include "llvm/ADT/BitVector.h"
16*06c3fb27SDimitry Andric #include <queue>
17*06c3fb27SDimitry Andric #include <set>
18*06c3fb27SDimitry Andric #include <vector>
19*06c3fb27SDimitry Andric 
20*06c3fb27SDimitry Andric namespace clang {
21*06c3fb27SDimitry Andric 
22*06c3fb27SDimitry Andric static CFGInterval buildInterval(llvm::BitVector &Partitioned,
23*06c3fb27SDimitry Andric                                  const CFGBlock &Header) {
24*06c3fb27SDimitry Andric   CFGInterval Interval(&Header);
25*06c3fb27SDimitry Andric   Partitioned.set(Header.getBlockID());
26*06c3fb27SDimitry Andric 
27*06c3fb27SDimitry Andric   // Elements must not be null. Duplicates are prevented using `Workset`, below.
28*06c3fb27SDimitry Andric   std::queue<const CFGBlock *> Worklist;
29*06c3fb27SDimitry Andric   llvm::BitVector Workset(Header.getParent()->getNumBlockIDs(), false);
30*06c3fb27SDimitry Andric   for (const CFGBlock *S : Header.succs())
31*06c3fb27SDimitry Andric     if (S != nullptr)
32*06c3fb27SDimitry Andric       if (auto SID = S->getBlockID(); !Partitioned.test(SID)) {
33*06c3fb27SDimitry Andric         // Successors are unique, so we don't test against `Workset` before
34*06c3fb27SDimitry Andric         // adding to `Worklist`.
35*06c3fb27SDimitry Andric         Worklist.push(S);
36*06c3fb27SDimitry Andric         Workset.set(SID);
37*06c3fb27SDimitry Andric       }
38*06c3fb27SDimitry Andric 
39*06c3fb27SDimitry Andric   // Contains successors of blocks in the interval that couldn't be added to the
40*06c3fb27SDimitry Andric   // interval on their first encounter. This occurs when they have a predecessor
41*06c3fb27SDimitry Andric   // that is either definitively outside the interval or hasn't been considered
42*06c3fb27SDimitry Andric   // yet. In the latter case, we'll revisit the block through some other path
43*06c3fb27SDimitry Andric   // from the interval. At the end of processing the worklist, we filter out any
44*06c3fb27SDimitry Andric   // that ended up in the interval to produce the output set of interval
45*06c3fb27SDimitry Andric   // successors. It may contain duplicates -- ultimately, all relevant elements
46*06c3fb27SDimitry Andric   // are added to `Interval.Successors`, which is a set.
47*06c3fb27SDimitry Andric   std::vector<const CFGBlock *> MaybeSuccessors;
48*06c3fb27SDimitry Andric 
49*06c3fb27SDimitry Andric   while (!Worklist.empty()) {
50*06c3fb27SDimitry Andric     const auto *B = Worklist.front();
51*06c3fb27SDimitry Andric     auto ID = B->getBlockID();
52*06c3fb27SDimitry Andric     Worklist.pop();
53*06c3fb27SDimitry Andric     Workset.reset(ID);
54*06c3fb27SDimitry Andric 
55*06c3fb27SDimitry Andric     // Check whether all predecessors are in the interval, in which case `B`
56*06c3fb27SDimitry Andric     // is included as well.
57*06c3fb27SDimitry Andric     bool AllInInterval = true;
58*06c3fb27SDimitry Andric     for (const CFGBlock *P : B->preds())
59*06c3fb27SDimitry Andric       if (Interval.Blocks.find(P) == Interval.Blocks.end()) {
60*06c3fb27SDimitry Andric         MaybeSuccessors.push_back(B);
61*06c3fb27SDimitry Andric         AllInInterval = false;
62*06c3fb27SDimitry Andric         break;
63*06c3fb27SDimitry Andric       }
64*06c3fb27SDimitry Andric     if (AllInInterval) {
65*06c3fb27SDimitry Andric       Interval.Blocks.insert(B);
66*06c3fb27SDimitry Andric       Partitioned.set(ID);
67*06c3fb27SDimitry Andric       for (const CFGBlock *S : B->succs())
68*06c3fb27SDimitry Andric         if (S != nullptr)
69*06c3fb27SDimitry Andric           if (auto SID = S->getBlockID();
70*06c3fb27SDimitry Andric               !Partitioned.test(SID) && !Workset.test(SID)) {
71*06c3fb27SDimitry Andric             Worklist.push(S);
72*06c3fb27SDimitry Andric             Workset.set(SID);
73*06c3fb27SDimitry Andric           }
74*06c3fb27SDimitry Andric     }
75*06c3fb27SDimitry Andric   }
76*06c3fb27SDimitry Andric 
77*06c3fb27SDimitry Andric   // Any block successors not in the current interval are interval successors.
78*06c3fb27SDimitry Andric   for (const CFGBlock *B : MaybeSuccessors)
79*06c3fb27SDimitry Andric     if (Interval.Blocks.find(B) == Interval.Blocks.end())
80*06c3fb27SDimitry Andric       Interval.Successors.insert(B);
81*06c3fb27SDimitry Andric 
82*06c3fb27SDimitry Andric   return Interval;
83*06c3fb27SDimitry Andric }
84*06c3fb27SDimitry Andric 
85*06c3fb27SDimitry Andric CFGInterval buildInterval(const CFG &Cfg, const CFGBlock &Header) {
86*06c3fb27SDimitry Andric   llvm::BitVector Partitioned(Cfg.getNumBlockIDs(), false);
87*06c3fb27SDimitry Andric   return buildInterval(Partitioned, Header);
88*06c3fb27SDimitry Andric }
89*06c3fb27SDimitry Andric 
90*06c3fb27SDimitry Andric std::vector<CFGInterval> partitionIntoIntervals(const CFG &Cfg) {
91*06c3fb27SDimitry Andric   std::vector<CFGInterval> Intervals;
92*06c3fb27SDimitry Andric   llvm::BitVector Partitioned(Cfg.getNumBlockIDs(), false);
93*06c3fb27SDimitry Andric   auto &EntryBlock = Cfg.getEntry();
94*06c3fb27SDimitry Andric   Intervals.push_back(buildInterval(Partitioned, EntryBlock));
95*06c3fb27SDimitry Andric 
96*06c3fb27SDimitry Andric   std::queue<const CFGBlock *> Successors;
97*06c3fb27SDimitry Andric   for (const auto *S : Intervals[0].Successors)
98*06c3fb27SDimitry Andric     Successors.push(S);
99*06c3fb27SDimitry Andric 
100*06c3fb27SDimitry Andric   while (!Successors.empty()) {
101*06c3fb27SDimitry Andric     const auto *B = Successors.front();
102*06c3fb27SDimitry Andric     Successors.pop();
103*06c3fb27SDimitry Andric     if (Partitioned.test(B->getBlockID()))
104*06c3fb27SDimitry Andric       continue;
105*06c3fb27SDimitry Andric 
106*06c3fb27SDimitry Andric     // B has not been partitioned, but it has a predecessor that has.
107*06c3fb27SDimitry Andric     CFGInterval I = buildInterval(Partitioned, *B);
108*06c3fb27SDimitry Andric     for (const auto *S : I.Successors)
109*06c3fb27SDimitry Andric       Successors.push(S);
110*06c3fb27SDimitry Andric     Intervals.push_back(std::move(I));
111*06c3fb27SDimitry Andric   }
112*06c3fb27SDimitry Andric 
113*06c3fb27SDimitry Andric   return Intervals;
114*06c3fb27SDimitry Andric }
115*06c3fb27SDimitry Andric 
116*06c3fb27SDimitry Andric } // namespace clang
117